version 0.3.23
authorSomeDude <SomeDude@NuBL7aaJ6Cn4fB7GXFb9Zfi8w1FhPyW3oKgU9TweZMw>
Tue, 2 Dec 2008 17:38:00 +0000 (18:38 +0100)
committerDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Tue, 2 Dec 2008 17:38:00 +0000 (18:38 +0100)
72 files changed:
CMakeLists.txt
forum-template.htm [new file with mode: 0644]
images/new_posts.png [new file with mode: 0644]
images/no_new_posts.png [new file with mode: 0644]
include/db/sqlite3db/sqlite3db.h
include/db/sqlite3db/sqlite3recordset.h
include/db/sqlite3db/sqlite3statement.h
include/dbconversions.h
include/freenet/iindexinserter.h
include/freenet/iindexrequester.h
include/freenet/introductionpuzzlerequester.h
include/global.h
include/http/ipagehandler.h
include/http/pages/addpeerpage.h
include/http/pages/announceidentitypage.h
include/http/pages/boardspage.h
include/http/pages/browseboardspage.h [new file with mode: 0644]
include/http/pages/browsemessagespage.h [new file with mode: 0644]
include/http/pages/confirmpage.h
include/http/pages/controlboardpage.h
include/http/pages/createidentitypage.h
include/http/pages/execquerypage.h
include/http/pages/forumcreatepostpage.h [new file with mode: 0644]
include/http/pages/forummainpage.h [new file with mode: 0644]
include/http/pages/forumpage.h [new file with mode: 0644]
include/http/pages/forumthreadspage.h [new file with mode: 0644]
include/http/pages/forumviewthreadpage.h [new file with mode: 0644]
include/http/pages/homepage.h
include/http/pages/insertedfilespage.h
include/http/pages/localidentitiespage.h
include/http/pages/optionspage.h
include/http/pages/peerdetailspage.h
include/http/pages/peermaintenancepage.h
include/http/pages/peertrustpage.h
include/http/pages/recentlyaddedpage.h
include/http/pages/showimagepage.h [new file with mode: 0644]
include/http/pages/versioninfopage.h
include/message.h
include/messagethread.h [new file with mode: 0644]
include/threadbuilder.h [new file with mode: 0644]
src/db/sqlite3db.cpp
src/db/sqlite3statement.cpp
src/dbconversions.cpp
src/dbmaintenancethread.cpp
src/dbsetup.cpp
src/fmsapp.cpp
src/freenet/introductionpuzzlerequester.cpp
src/freenet/messageinserter.cpp
src/freenet/messagelistinserter.cpp
src/http/fmshttprequesthandlerfactory.cpp
src/http/ipagehandler.cpp
src/http/pages/announceidentitypage.cpp
src/http/pages/boardspage.cpp
src/http/pages/browseboardspage.cpp [new file with mode: 0644]
src/http/pages/browsemessagespage.cpp [new file with mode: 0644]
src/http/pages/forumcreatepostpage.cpp [new file with mode: 0644]
src/http/pages/forummainpage.cpp [new file with mode: 0644]
src/http/pages/forumthreadspage.cpp [new file with mode: 0644]
src/http/pages/forumviewthreadpage.cpp [new file with mode: 0644]
src/http/pages/homepage.cpp
src/http/pages/localidentitiespage.cpp
src/http/pages/peertrustpage.cpp
src/http/pages/recentlyaddedpage.cpp
src/http/pages/showcaptchapage.cpp
src/http/pages/showimagepage.cpp [new file with mode: 0644]
src/http/pages/versioninfopage.cpp
src/message.cpp
src/messagethread.cpp [new file with mode: 0644]
src/nntp/nntpconnection.cpp
src/nntp/nntplistener.cpp
src/threadbuilder.cpp [new file with mode: 0644]
template.htm

index 7cf50e0..a5aef9e 100644 (file)
@@ -18,33 +18,29 @@ src/base64.cpp
 src/bitmapvalidator.cpp\r
 src/board.cpp\r
 src/boardlist.cpp\r
-src/db\r
 src/dbconversions.cpp\r
 src/dbmaintenancethread.cpp\r
 src/dbsetup.cpp\r
 src/fmsapp.cpp\r
-src/freenet\r
 src/global.cpp\r
 src/hex.cpp\r
-src/http\r
 src/ipaddressacl.cpp\r
 src/localidentity.cpp\r
 src/main.cpp\r
 src/message.cpp\r
 src/messagelist.cpp\r
-src/nntp\r
+src/messagethread.cpp\r
 src/option.cpp\r
 src/optionssetup.cpp\r
 src/socketdefines.cpp\r
 src/stringfunctions.cpp\r
-src/threadwrapper\r
+src/threadbuilder.cpp\r
 src/db/sqlite3db.cpp\r
 src/db/sqlite3recordset.cpp\r
 src/db/sqlite3statement.cpp\r
 src/freenet/boardlistinserter.cpp\r
 src/freenet/boardlistrequester.cpp\r
 src/freenet/boardlistxml.cpp\r
-src/freenet/captcha\r
 src/freenet/fcpv2.cpp\r
 src/freenet/fileinserter.cpp\r
 src/freenet/fmsversionrequester.cpp\r
@@ -71,7 +67,6 @@ src/freenet/trustlistinserter.cpp
 src/freenet/trustlistrequester.cpp\r
 src/freenet/trustlistxml.cpp\r
 src/freenet/unkeyedidcreator.cpp\r
-src/freenet/captcha/easybmp\r
 src/freenet/captcha/simplecaptcha.cpp\r
 src/freenet/captcha/easybmp/EasyBMP.cpp\r
 src/freenet/captcha/easybmp/EasyBMP_Font.cpp\r
@@ -81,14 +76,19 @@ src/http/httpthread.cpp
 src/http/identityexportxml.cpp\r
 src/http/ipagehandler.cpp\r
 src/http/multipartparser.cpp\r
-src/http/pages\r
 src/http/pages/addpeerpage.cpp\r
 src/http/pages/announceidentitypage.cpp\r
 src/http/pages/boardspage.cpp\r
+src/http/pages/browseboardspage.cpp\r
+src/http/pages/browsemessagespage.cpp\r
 src/http/pages/confirmpage.cpp\r
 src/http/pages/controlboardpage.cpp\r
 src/http/pages/createidentitypage.cpp\r
 src/http/pages/execquerypage.cpp\r
+src/http/pages/forumcreatepostpage.cpp\r
+src/http/pages/forummainpage.cpp\r
+src/http/pages/forumthreadspage.cpp\r
+src/http/pages/forumviewthreadpage.cpp\r
 src/http/pages/homepage.cpp\r
 src/http/pages/insertedfilespage.cpp\r
 src/http/pages/localidentitiespage.cpp\r
@@ -98,9 +98,9 @@ src/http/pages/peermaintenancepage.cpp
 src/http/pages/peertrustpage.cpp\r
 src/http/pages/recentlyaddedpage.cpp\r
 src/http/pages/showcaptchapage.cpp\r
+src/http/pages/showimagepage.cpp\r
 src/http/pages/versioninfopage.cpp\r
 src/nntp/extensiontrust.cpp\r
-src/nntp/mime\r
 src/nntp/nntpconnection.cpp\r
 src/nntp/nntplistener.cpp\r
 src/nntp/uwildmat.cpp\r
@@ -211,6 +211,7 @@ IF(NOT WIN32)
 ENDIF(NOT WIN32)\r
 \r
 IF(SQLITE3_LIBRARY)\r
+       MESSAGE(STATUS "Linking against system SQLite3 library.")\r
        TARGET_LINK_LIBRARIES(fms ${SQLITE3_LIBRARY})\r
 ELSE(SQLITE3_LIBRARY)\r
        IF(NOT USE_BUNDLED_SQLITE)\r
diff --git a/forum-template.htm b/forum-template.htm
new file mode 100644 (file)
index 0000000..1877675
--- /dev/null
@@ -0,0 +1,217 @@
+<html>\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\r
+<style>\r
+body   {\r
+                       margin:0px;\r
+                       padding:10px;\r
+                       font-family:Helvetica,Arial;\r
+                       font-size:12px;\r
+               }\r
+               \r
+table  {\r
+                       margin:0px;\r
+                       padding:0px;\r
+                       font-size:12px;\r
+               }\r
+                       \r
+table td       {\r
+                               margin:0px;\r
+                               padding:0px;\r
+                               background-color:#ddeeff;\r
+                       }\r
+                       \r
+table th       {\r
+                               background-color:#003366;\r
+                               color:#ffffff;\r
+                       }\r
+\r
+#outercontainer        {\r
+                                       padding:0px;\r
+                                       margin:0px;\r
+                               }\r
+                               \r
+.error                 {\r
+                                       padding-left:5px;\r
+                                       padding-right:5px;\r
+                                       color:#ff0000;\r
+                                       font-weight:bolder;\r
+                               }\r
+                               \r
+table.header           {\r
+                                               width:100%;\r
+                                       }\r
+\r
+table.header   td      {\r
+                                               text-align:center;\r
+                                               padding:5px;\r
+                                               font-size:1.2em;\r
+                                               font-weight:bolder;\r
+                                       }\r
+\r
+table.foruminfo                {\r
+                                               width:100%;\r
+                                       }\r
+                                       \r
+table.foruminfo td     {\r
+                                               padding-left:5px;\r
+                                               padding-right:5px;\r
+                                               padding-top:2px;\r
+                                               padding-bottom:2px;\r
+                                       }\r
+\r
+table.foruminfo td.newposts    {\r
+                                                               width:32px;\r
+                                                       }\r
+                                                       \r
+table.foruminfo td.forumname   {\r
+                                                                       font-size:1.2em;\r
+                                                                       font-weight:bolder;\r
+                                                               }\r
+\r
+table.foruminfo td.forumname .description      {\r
+                                                                                               font-weight:normal;\r
+                                                                                               font-size:0.7em;\r
+                                                                                       }\r
+                                                                                       \r
+table.foruminfo td.postcount   {\r
+                                                                       width:80px;\r
+                                                               }\r
+                                                               \r
+table.foruminfo td.lastpost            {\r
+                                                                       width:340px;\r
+                                                                       font-size:0.9em;\r
+                                                               }\r
+\r
+table.forumheader                              {\r
+                                                                       width:100%;\r
+                                                               }\r
+                                                               \r
+table.forumheader td                   {\r
+                                                                       font-size:1.1em;\r
+                                                                       font-weight:bolder;\r
+                                                                       padding-left:5px;\r
+                                                                       padding-right:5px;\r
+                                                                       padding-top:2px;\r
+                                                                       padding-bottom:2px;\r
+                                                               }\r
+\r
+table.threadinfo                               {\r
+                                                                       width:100%;\r
+                                                               }\r
+                                                               \r
+table.threadinfo td                            {\r
+                                                                       padding-left:5px;\r
+                                                                       padding-right:5px;\r
+                                                                       padding-top:2px;\r
+                                                                       padding-bottom:2px;\r
+                                                               }\r
+\r
+table.threadinfo td.newposts   {\r
+                                                                       width:32px;\r
+                                                                       text-align:center;\r
+                                                               }\r
+\r
+table.threadinfo td.threadauthor       {\r
+                                                                               width:150px;\r
+                                                                       }\r
+                                                                       \r
+table.threadinfo td.threadreplies      {\r
+                                                                               width:60px;\r
+                                                                       }\r
+\r
+table.threadinfo td.threadlastpost     {\r
+                                                                               width:220px;\r
+                                                                               font-size:0.9em;\r
+                                                                       }\r
+\r
+table.threadinfo td.pages                      {\r
+                                                                               font-weight:bolder;\r
+                                                                       }\r
+\r
+table.threadinfo td.pages form         {\r
+                                                                               margin-left:10px;\r
+                                                                               display:inline;\r
+                                                                       }\r
+\r
+table.threadinfo td.pages input                {\r
+                                                                               width:30px;\r
+                                                                               text-align:center;\r
+                                                                       }\r
+                                                                       \r
+table.thread                                           {\r
+                                                                               width:100%;\r
+                                                                       }\r
+                                                                       \r
+table.thread td                                                {\r
+                                                                               padding:5px;\r
+                                                                       }\r
+                                                                       \r
+table.thread td.from                           {\r
+                                                                               vertical-align:top;\r
+                                                                               font-weight:bolder;\r
+                                                                       }\r
+                                                                       \r
+table.thread td.subject                                {\r
+                                                                               font-size:1.1em;\r
+                                                                               font-weight:bolder;\r
+                                                                               height:20px;\r
+                                                                       }\r
+\r
+table.thread td.body                           {\r
+                                                                               vertical-align:top;\r
+                                                                               overflow:auto;\r
+                                                                       }\r
+table.createpost td                                    {\r
+                                                                               padding-left:5px;\r
+                                                                               padding-right:5px;\r
+                                                                               padding-top:2px;\r
+                                                                               padding-bottom:2px;\r
+                                                                       }\r
+\r
+table.createpost td.identity           {\r
+                                                                               font-weight:bolder;\r
+                                                                               text-align:right;\r
+                                                                       }\r
+\r
+table.createpost td.subject                    {\r
+                                                                               font-weight:bolder;\r
+                                                                               text-align:right;\r
+                                                                       }\r
+\r
+table.createpost td.body                       {\r
+                                                                               font-weight:bolder;\r
+                                                                               text-align:right;\r
+                                                                               vertical-align:top;\r
+                                                                       }\r
+\r
+table.createpost td.send                       {\r
+                                                                               text-align:center;\r
+                                                                       }\r
+\r
+table.trust                                                    {\r
+                                                                               margin-top:10px;\r
+                                                                               margin-left:5px;\r
+                                                                               border-style:solid;\r
+                                                                               border-width:1px;\r
+                                                                       }\r
+                                                                       \r
+table.trust td                                         {\r
+                                                                               padding-left:5px;\r
+                                                                               padding-right:5px;\r
+                                                                               padding-top:2px;\r
+                                                                               padding-bottom:2px;\r
+                                                                       }\r
+\r
+</style>\r
+</head>\r
+<body>\r
+\r
+<div id="outercontainer">\r
+\r
+       [CONTENT]\r
+\r
+</div>\r
+\r
+</body>\r
+</html>\r
diff --git a/images/new_posts.png b/images/new_posts.png
new file mode 100644 (file)
index 0000000..cd61b8b
Binary files /dev/null and b/images/new_posts.png differ
diff --git a/images/no_new_posts.png b/images/no_new_posts.png
new file mode 100644 (file)
index 0000000..52fde59
Binary files /dev/null and b/images/no_new_posts.png differ
index 470ba85..8c2ee39 100644 (file)
@@ -18,7 +18,7 @@ class DB:public Singleton<DB>
 {\r
 public:\r
        DB();\r
-       DB(std::string filename);\r
+       DB(const std::string &filename);\r
        ~DB();\r
        \r
        const bool Open(const std::string &filename);\r
index 06c7919..3489130 100644 (file)
@@ -14,12 +14,12 @@ public:
        virtual ~Recordset();\r
 \r
        virtual void Free() { if(m_rs) { sqlite3_free_table(m_rs); m_rs=NULL; } }\r
-       virtual const bool Empty() { return (m_rs==NULL || m_rows==0) ? true : false ; }\r
+       virtual const bool Empty() const                { return (m_rs==NULL || m_rows==0) ? true : false ; }\r
 \r
-       virtual const int Count() { return m_rows; }\r
-       virtual const bool AtBeginning() { return m_currentrow==0; }\r
-       virtual const bool AtEnd() { return m_currentrow>=m_rows; }\r
-       virtual const int Cols() { return m_cols; }\r
+       virtual const int Count() const                 { return m_rows; }\r
+       virtual const bool AtBeginning() const  { return m_currentrow==0; }\r
+       virtual const bool AtEnd() const                { return m_currentrow>=m_rows; }\r
+       virtual const int Cols() const                  { return m_cols; }\r
 \r
        virtual const bool Next() { if(m_currentrow<m_rows) { m_currentrow++; return true; } else { return false; } }\r
        virtual const bool Previous() { if(m_currentrow-1>=0) { m_currentrow--; return true; } else { return false; } }\r
index bdca9dc..d245d49 100644 (file)
@@ -57,8 +57,6 @@ private:
        long m_lastinsertrowid;\r
 \r
        static std::map<sqlite3_stmt *, long> m_statementcount;\r
-       //std::vector<char *> textptrs;\r
-       //std::vector<std::vector<char> > m_boundtext;\r
 \r
 };     //class\r
 \r
index 8d090f4..4db308c 100644 (file)
@@ -13,6 +13,7 @@ void ConvertDB0109To0110();
 void ConvertDB0110To0111();\r
 void ConvertDB0111To0112();\r
 void ConvertDB0112To0113();\r
+void ConvertDB0113To0114();\r
 \r
 // TODO remove sometime after 0.1.17\r
 void FixCapitalBoardNames();\r
index bb0e9e7..ba5c988 100644 (file)
@@ -73,7 +73,7 @@ void IIndexInserter<IDTYPE>::FCPConnected()
        }\r
        if(m_fcpuniquename.find("|")!=std::string::npos)\r
        {\r
-               m_log->fatal("IIndexInserter<IDTYPE>::FCPConnected fcpuniquename contains | character!  This is not a valid character!");\r
+               m_log->fatal("IIndexInserter<IDTYPE>::FCPConnected fcpuniquename : "+m_fcpuniquename+" contains | character!  This is not a valid character!");\r
        }\r
 \r
        m_inserting.clear();\r
@@ -91,6 +91,8 @@ const bool IIndexInserter<IDTYPE>::HandleMessage(FCPMessage &message)
 \r
        if(message["Identifier"].find(m_fcpuniquename)==0)\r
        {\r
+               m_log->trace("IIndexInserter<IDTYPE>::HandleMessage "+m_fcpuniquename+" received "+message.GetName()+"  ID="+message["Identifier"]+"  URI="+message["URI"]);\r
+\r
                if(message.GetName()=="URIGenerated")\r
                {\r
                        return true;\r
index 678e43e..6173868 100644 (file)
@@ -14,6 +14,8 @@
 #include <Poco/Timestamp.h>\r
 #include <Poco/Timespan.h>\r
 \r
+#include <algorithm>\r
+\r
 #ifdef XMEM\r
        #include <xmem.h>\r
 #endif\r
@@ -82,7 +84,7 @@ void IIndexRequester<IDTYPE>::FCPConnected()
        }\r
        if(m_fcpuniquename.find("|")!=std::string::npos)\r
        {\r
-               m_log->fatal("IIndexRequester<IDTYPE>::FCPConnected fcpuniquename contains | character!  This is not a valid character!");\r
+               m_log->fatal("IIndexRequester<IDTYPE>::FCPConnected fcpuniquename "+m_fcpuniquename+" contains | character!  This is not a valid character!");\r
        }\r
 \r
        m_lastreceived=Poco::Timestamp();\r
@@ -208,11 +210,16 @@ void IIndexRequester<IDTYPE>::RegisterWithThread(FreenetMasterThread *thread)
 template <class IDTYPE>\r
 void IIndexRequester<IDTYPE>::RemoveFromRequestList(const IDTYPE id)\r
 {\r
+/*\r
        typename std::vector<IDTYPE>::iterator i=m_requesting.begin();\r
        while(i!=m_requesting.end() && (*i)!=id)\r
        {\r
                i++;\r
        }\r
+*/\r
+       // better\r
+       typename std::vector<IDTYPE>::iterator i=std::find(m_requesting.begin(),m_requesting.end(),id);\r
+\r
        if(i!=m_requesting.end())\r
        {\r
                m_requesting.erase(i);\r
index 2be2d0e..dc24327 100644 (file)
@@ -11,9 +11,6 @@ public:
        IntroductionPuzzleRequester();\r
        IntroductionPuzzleRequester(FCPv2 *fcp);\r
 \r
-       void FCPDisconnected();\r
-       void FCPConnected();\r
-\r
 private:\r
        void Initialize();\r
        void StartRequest(const long &identityid);\r
index acf93ed..aff023f 100644 (file)
@@ -7,10 +7,10 @@
 \r
 #define VERSION_MAJOR          "0"\r
 #define VERSION_MINOR          "3"\r
-#define VERSION_RELEASE                "22"\r
+#define VERSION_RELEASE                "23"\r
 #define FMS_VERSION                    VERSION_MAJOR"."VERSION_MINOR"."VERSION_RELEASE\r
-#define FMS_FREESITE_USK       "USK@0npnMrqZNKRCRoGojZV93UNHCMN-6UU3rRSAmP6jNLE,~BG-edFtdCC1cSH4O3BWdeIYa8Sw5DfyrSV-TKdO5ec,AQACAAE/fms/82/"\r
-#define FMS_VERSION_EDITION    "24"\r
+#define FMS_FREESITE_USK       "USK@0npnMrqZNKRCRoGojZV93UNHCMN-6UU3rRSAmP6jNLE,~BG-edFtdCC1cSH4O3BWdeIYa8Sw5DfyrSV-TKdO5ec,AQACAAE/fms/84/"\r
+#define FMS_VERSION_EDITION    "25"\r
 \r
 typedef Poco::ScopedLock<Poco::FastMutex> Guard;\r
 \r
index 11bdc22..16afb7c 100644 (file)
@@ -16,9 +16,9 @@ class IPageHandler:public Poco::Net::HTTPRequestHandler,public ILogger
 {\r
 public:\r
        IPageHandler()  {}\r
-       IPageHandler(const std::string &templatestr)    { m_template=templatestr; }\r
+       IPageHandler(const std::string &templatestr, const std::string &pagename):m_template(templatestr),m_pagename(pagename)  {  }\r
        virtual ~IPageHandler() {}\r
-       virtual const bool WillHandleURI(const std::string &uri)=0;\r
+       virtual const bool WillHandleURI(const std::string &uri);\r
 \r
        virtual IPageHandler *New()=0;  // returns a new instance of the object\r
 \r
@@ -41,6 +41,7 @@ protected:
        const std::string SanitizeOutput(const std::string &input);\r
 \r
        std::string m_template;\r
+       std::string m_pagename;\r
 \r
 };\r
 \r
index ac050e2..1425b10 100644 (file)
@@ -7,7 +7,7 @@
 class AddPeerPage:public IPageHandler,public IDatabase\r
 {\r
 public:\r
-       AddPeerPage(const std::string &templatestr):IPageHandler(templatestr)   {}\r
+       AddPeerPage(const std::string &templatestr):IPageHandler(templatestr,"addpeer.htm")     {}\r
 \r
        IPageHandler *New()     { return new AddPeerPage(m_template); }\r
 \r
index 0ac5be9..b4bf78a 100644 (file)
@@ -7,7 +7,7 @@
 class AnnounceIdentityPage:public IPageHandler,public IDatabase\r
 {\r
 public:\r
-       AnnounceIdentityPage(const std::string &templatestr):IPageHandler(templatestr)  {}\r
+       AnnounceIdentityPage(const std::string &templatestr):IPageHandler(templatestr,"announceidentity.htm")   {}\r
 \r
        IPageHandler *New()     { return new AnnounceIdentityPage(m_template); }\r
 \r
index a8e1c1a..0e4383c 100644 (file)
@@ -7,7 +7,7 @@
 class BoardsPage:public IPageHandler,public IDatabase\r
 {\r
 public:\r
-       BoardsPage(const std::string &templatestr):IPageHandler(templatestr)    {}\r
+       BoardsPage(const std::string &templatestr):IPageHandler(templatestr,"boards.htm")       {}\r
        \r
        IPageHandler *New()     { return new BoardsPage(m_template); }\r
 \r
diff --git a/include/http/pages/browseboardspage.h b/include/http/pages/browseboardspage.h
new file mode 100644 (file)
index 0000000..5a3c266
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _browseboardspage_\r
+#define _browseboardspage_\r
+\r
+#include "../ipagehandler.h"\r
+#include "../../idatabase.h"\r
+\r
+class BrowseBoardsPage:public IPageHandler,public IDatabase\r
+{\r
+public:\r
+       BrowseBoardsPage(const std::string &templatestr):IPageHandler(templatestr,"boardsbrowse.htm")   {}\r
+       \r
+       IPageHandler *New()     { return new BrowseBoardsPage(m_template); }\r
+       \r
+private:\r
+       const std::string GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars);\r
+\r
+       const std::string BuildQueryString(const long startrow, const std::string &boardsearch, const std::string &sortby, const std::string &sortorder);\r
+       const std::string ReverseSort(const std::string &sortname, const std::string &currentsortby, const std::string &currentsortorder);\r
+};\r
+\r
+#endif // _browseboardspage_\r
diff --git a/include/http/pages/browsemessagespage.h b/include/http/pages/browsemessagespage.h
new file mode 100644 (file)
index 0000000..da67947
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _browsemessagespage_\r
+#define _browsemessagespage_\r
+\r
+#include "../ipagehandler.h"\r
+#include "../../idatabase.h"\r
+\r
+class BrowseMessagesPage:public IPageHandler,public IDatabase\r
+{\r
+public:\r
+       BrowseMessagesPage(const std::string &templatestr):IPageHandler(templatestr,"browsemessages.htm")       {}\r
+       \r
+       IPageHandler *New()     { return new BrowseMessagesPage(m_template); }\r
+       \r
+private:\r
+       const std::string GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars);\r
+       const std::string BuildQueryString(const long startrow, const std::string &boardidstr, const std::string &messageidstr);\r
+};\r
+\r
+#endif // _browsemessagespage_\r
index 2ad4ed9..aaf0c78 100644 (file)
@@ -6,7 +6,7 @@
 class ConfirmPage:public IPageHandler\r
 {\r
 public:\r
-       ConfirmPage(const std::string &templatestr):IPageHandler(templatestr)           {}\r
+       ConfirmPage(const std::string &templatestr):IPageHandler(templatestr,"confirm.htm")             {}\r
 \r
        IPageHandler *New()     { return new ConfirmPage(m_template); }\r
 \r
index 7484989..0f8fcde 100644 (file)
@@ -7,7 +7,7 @@
 class ControlBoardPage:public IPageHandler,public IDatabase\r
 {\r
 public:\r
-       ControlBoardPage(const std::string &templatestr):IPageHandler(templatestr)      {}\r
+       ControlBoardPage(const std::string &templatestr):IPageHandler(templatestr,"controlboard.htm")   {}\r
 \r
        IPageHandler *New()     { return new ControlBoardPage(m_template); }\r
 \r
index e6d938c..a1a912f 100644 (file)
@@ -7,7 +7,7 @@
 class CreateIdentityPage:public IPageHandler,public IDatabase\r
 {\r
 public:\r
-       CreateIdentityPage(const std::string &templatestr):IPageHandler(templatestr)    {}\r
+       CreateIdentityPage(const std::string &templatestr):IPageHandler(templatestr,"createidentity.htm")       {}\r
 \r
        IPageHandler *New()     { return new CreateIdentityPage(m_template); }\r
 \r
index 37255b9..caedd08 100644 (file)
@@ -7,7 +7,7 @@
 class ExecQueryPage:public IPageHandler,public IDatabase\r
 {\r
 public:\r
-       ExecQueryPage(const std::string &templatestr):IPageHandler(templatestr)         {}\r
+       ExecQueryPage(const std::string &templatestr):IPageHandler(templatestr,"execquery.htm")         {}\r
 \r
        IPageHandler *New()     { return new ExecQueryPage(m_template); }\r
 \r
diff --git a/include/http/pages/forumcreatepostpage.h b/include/http/pages/forumcreatepostpage.h
new file mode 100644 (file)
index 0000000..7f2b592
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _forumcreatepostpage_\r
+#define _forumcreatepostpage_\r
+\r
+#include "forumpage.h"\r
+\r
+class ForumCreatePostPage:public ForumPage\r
+{\r
+public:\r
+       ForumCreatePostPage(const std::string &templatestr):ForumPage(templatestr,"forumcreatepost.htm")        {}\r
+\r
+       IPageHandler *New()             { return new ForumCreatePostPage(m_template); }\r
+private:\r
+       const std::string GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars);\r
+\r
+       const std::string LocalIdentityDropDown(const std::string &name, const std::string &selectedid);\r
+       \r
+};\r
+\r
+#endif // _forumcreatepostpage_\r
diff --git a/include/http/pages/forummainpage.h b/include/http/pages/forummainpage.h
new file mode 100644 (file)
index 0000000..63af3c5
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _forummainpage_\r
+#define _forummainpage_\r
+\r
+#include "forumpage.h"\r
+\r
+class ForumMainPage:public ForumPage\r
+{\r
+public:\r
+       ForumMainPage(const std::string &templatestr):ForumPage(templatestr,"forummain.htm")    {}\r
+\r
+       IPageHandler *New()     { return new ForumMainPage(m_template); }\r
+\r
+private:\r
+       const std::string GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars);\r
+};\r
+\r
+#endif // _forummainpage_\r
diff --git a/include/http/pages/forumpage.h b/include/http/pages/forumpage.h
new file mode 100644 (file)
index 0000000..3124b9e
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef _forumpage_\r
+#define _forumpage_\r
+\r
+#include "../ipagehandler.h"\r
+#include "../../idatabase.h"\r
+\r
+class ForumPage:public IPageHandler,public IDatabase\r
+{\r
+public:\r
+       ForumPage(const std::string &templatestr, const std::string &pagename):IPageHandler(templatestr,pagename)       {}\r
+\r
+       virtual IPageHandler *New()=0;  // returns a new instance of the object\r
+\r
+protected:\r
+       const std::string FixFromName(const std::string &fromname)\r
+       {\r
+               std::string tempname=fromname;\r
+               if(tempname.size()>30)\r
+               {\r
+                       tempname.erase(27);\r
+                       tempname+="...";\r
+               }\r
+               tempname=SanitizeOutput(tempname);\r
+               return tempname;\r
+       }\r
+\r
+       const std::string FixSubject(const std::string &subject)\r
+       {\r
+               std::string tempsubject=subject;\r
+               if(tempsubject.size()>30)\r
+               {\r
+                       tempsubject.erase(27);\r
+                       tempsubject+="...";\r
+               }\r
+               tempsubject=SanitizeOutput(tempsubject);\r
+               return tempsubject;\r
+       }\r
+\r
+       const std::string CreateForumHeader()\r
+       {\r
+               std::string content="<table class=\"header\">\r\n";\r
+               content+="<tr><td><a href=\"index.htm\">Home</a> | <a href=\"forummain.htm\">Browse Forums</a></td></tr>\r\n";\r
+               content+="</table>\r\n";\r
+               return content;\r
+       }\r
+\r
+private:\r
+       virtual const std::string GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars)=0;\r
+\r
+};\r
+\r
+#endif // _forumpage_\r
diff --git a/include/http/pages/forumthreadspage.h b/include/http/pages/forumthreadspage.h
new file mode 100644 (file)
index 0000000..71131c1
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _forumthreads_page_\r
+#define _forumthreads_page_\r
+\r
+#include "forumpage.h"\r
+\r
+class ForumThreadsPage:public ForumPage\r
+{\r
+public:\r
+       ForumThreadsPage(const std::string &templatestr):ForumPage(templatestr,"forumthreads.htm")      {}\r
+\r
+       IPageHandler *New()     { return new ForumThreadsPage(m_template); }\r
+\r
+private:\r
+       const std::string GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars);\r
+};\r
+\r
+#endif // _forumthreads_page_\r
diff --git a/include/http/pages/forumviewthreadpage.h b/include/http/pages/forumviewthreadpage.h
new file mode 100644 (file)
index 0000000..78c2e2c
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _forumviewthreadpage_\r
+#define _forumviewthreadpage_\r
+\r
+#include "forumpage.h"\r
+\r
+class ForumViewThreadPage:public ForumPage\r
+{\r
+public:\r
+       ForumViewThreadPage(const std::string &templatestr):ForumPage(templatestr,"forumviewthread.htm")        {}\r
+\r
+       IPageHandler *New()             { return new ForumViewThreadPage(m_template); }\r
+private:\r
+       const std::string GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars);\r
+\r
+       const std::string FixBody(const std::string &body);\r
+\r
+};\r
+\r
+#endif // _forumviewthreadpage_\r
index 1a4b832..0b8c5e2 100644 (file)
@@ -7,7 +7,7 @@
 class HomePage:public IPageHandler,public IDatabase\r
 {\r
 public:\r
-       HomePage(const std::string &templatestr):IPageHandler(templatestr) {}\r
+       HomePage(const std::string &templatestr):IPageHandler(templatestr,"index.htm") {}\r
 \r
        IPageHandler *New()     { return new HomePage(m_template); }\r
 \r
index 80c4b0e..d9d4832 100644 (file)
@@ -7,7 +7,7 @@
 class InsertedFilesPage:public IPageHandler,public IDatabase\r
 {\r
 public:\r
-       InsertedFilesPage(const std::string &templatestr):IPageHandler(templatestr)             {}\r
+       InsertedFilesPage(const std::string &templatestr):IPageHandler(templatestr,"insertedfiles.htm")         {}\r
 \r
        IPageHandler *New()     { return new InsertedFilesPage(m_template); }\r
 \r
index d994fd2..162777c 100644 (file)
@@ -7,7 +7,7 @@
 class LocalIdentitiesPage:public IPageHandler,public IDatabase\r
 {\r
 public:\r
-       LocalIdentitiesPage(const std::string &templatestr):IPageHandler(templatestr)   {}\r
+       LocalIdentitiesPage(const std::string &templatestr):IPageHandler(templatestr,"localidentities.htm")     {}\r
 \r
        IPageHandler *New()     { return new LocalIdentitiesPage(m_template); }\r
 \r
index 447b00f..9589205 100644 (file)
@@ -7,7 +7,7 @@
 class OptionsPage:public IPageHandler,public IDatabase\r
 {\r
 public:\r
-       OptionsPage(const std::string &templatestr):IPageHandler(templatestr)   {}\r
+       OptionsPage(const std::string &templatestr):IPageHandler(templatestr,"options.htm")     {}\r
        \r
        IPageHandler *New()     { return new OptionsPage(m_template); }\r
 \r
index 20d9149..1c69303 100644 (file)
@@ -7,7 +7,7 @@
 class PeerDetailsPage:public IPageHandler,public IDatabase\r
 {\r
 public:\r
-       PeerDetailsPage(const std::string templatestr):IPageHandler(templatestr)        {}\r
+       PeerDetailsPage(const std::string templatestr):IPageHandler(templatestr,"peerdetails.htm")      {}\r
 \r
        IPageHandler *New()     { return new PeerDetailsPage(m_template); }\r
 \r
index 95e4966..efacffa 100644 (file)
@@ -7,7 +7,7 @@
 class PeerMaintenancePage:public IPageHandler,public IDatabase\r
 {\r
 public:\r
-       PeerMaintenancePage(const std::string &templatestr):IPageHandler(templatestr)   {}\r
+       PeerMaintenancePage(const std::string &templatestr):IPageHandler(templatestr,"peermaintenance.htm")     {}\r
 \r
        IPageHandler *New()     { return new PeerMaintenancePage(m_template); }\r
 \r
index cce9ae6..a62ad68 100644 (file)
@@ -7,12 +7,11 @@
 class PeerTrustPage:public IPageHandler,public IDatabase\r
 {\r
 public:\r
-       PeerTrustPage(const std::string &templatestr):IPageHandler(templatestr)         {}\r
+       PeerTrustPage(const std::string &templatestr):IPageHandler(templatestr,"peertrust.htm")         {}\r
 \r
        IPageHandler *New()     { return new PeerTrustPage(m_template); }\r
 \r
 private:\r
-       const bool WillHandleURI(const std::string &uri);\r
        const std::string GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars);\r
 \r
        const std::string GetClassString(const std::string &trustlevel);\r
index ec9c1cc..9f00760 100644 (file)
@@ -7,12 +7,11 @@
 class RecentlyAddedPage:public IPageHandler,public IDatabase\r
 {\r
 public:\r
-       RecentlyAddedPage(const std::string &templatestr):IPageHandler(templatestr)             {}\r
+       RecentlyAddedPage(const std::string &templatestr):IPageHandler(templatestr,"recentlyadded.htm")         {}\r
 \r
        IPageHandler *New()     { return new RecentlyAddedPage(m_template); }\r
 \r
 private:\r
-       const bool WillHandleURI(const std::string &uri);\r
        const std::string GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars);\r
 \r
 };\r
diff --git a/include/http/pages/showimagepage.h b/include/http/pages/showimagepage.h
new file mode 100644 (file)
index 0000000..2c8c648
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _showimagepage_\r
+#define _showimagepage_\r
+\r
+#include "../ipagehandler.h"\r
+\r
+class ShowImagePage:public IPageHandler\r
+{\r
+public:\r
+\r
+       void handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response);\r
+\r
+       IPageHandler *New()     { return new ShowImagePage; }\r
+\r
+private:\r
+       const bool WillHandleURI(const std::string &uri);\r
+       const std::string GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars) {return "";}\r
+\r
+       static std::map<std::string,std::vector<char> > m_imagecache;\r
+\r
+};\r
+\r
+#endif // _showcaptchapage_\r
index 1d87554..9f22d4e 100644 (file)
@@ -7,12 +7,11 @@
 class VersionInfoPage:public IPageHandler,public IDatabase\r
 {\r
 public:\r
-       VersionInfoPage(const std::string &templatestr):IPageHandler(templatestr)               {}\r
+       VersionInfoPage(const std::string &templatestr):IPageHandler(templatestr,"versioninfo.htm")             {}\r
 \r
        IPageHandler *New()     { return new VersionInfoPage(m_template); }\r
 \r
 private:\r
-       const bool WillHandleURI(const std::string &uri);\r
        const std::string GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars);\r
 \r
 };\r
index cfc8734..8c56633 100644 (file)
@@ -46,6 +46,7 @@ public:
        const bool Load(const std::string &messageuuid);\r
        \r
        const bool ParseNNTPMessage(const std::string &nntpmessage);\r
+       const bool Create(const long localidentityid, const long boardid, const std::string &subject, const std::string &body, const std::string &references);\r
 \r
        const bool PostedToAdministrationBoard()                { return CheckForAdministrationBoard(m_boards); }\r
 \r
diff --git a/include/messagethread.h b/include/messagethread.h
new file mode 100644 (file)
index 0000000..0dfe628
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef _messagethread_\r
+#define _messagethread_\r
+\r
+#include "idatabase.h"\r
+\r
+class MessageThread:public IDatabase\r
+{\r
+public:\r
+       struct threadnode\r
+       {\r
+               long m_messageid;\r
+               long m_level;\r
+               std::string m_subject;\r
+               std::string m_fromname;\r
+               std::string m_date;\r
+       };\r
+       \r
+       void Clear()                                                                    { m_nodes.clear(); }\r
+\r
+       const bool Load(const std::string &messageidstr, const long boardid, const bool bydate=false);\r
+       const bool Load(const long messageid, const long boardid, const bool bydate=false);\r
+       \r
+       const std::vector<threadnode> GetNodes()                { return m_nodes; }\r
+       \r
+private:\r
+       const threadnode GetOriginalMessageNode(const long messageid, const long boardid);\r
+       void AddChildren(const long messageid, const long level, const long boardid);\r
+\r
+       class datecompare\r
+       {\r
+       public:\r
+               const bool operator()(const threadnode &node1, const threadnode &node2) const\r
+               {\r
+                       return node1.m_date<node2.m_date;\r
+               }\r
+       };\r
+\r
+       std::vector<threadnode> m_nodes;\r
+};\r
+\r
+#endif // _messagethread_\r
diff --git a/include/threadbuilder.h b/include/threadbuilder.h
new file mode 100644 (file)
index 0000000..5c0fc42
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _threadbuilder_\r
+#define _threadbuilder_\r
+\r
+#include "idatabase.h"\r
+\r
+class ThreadBuilder:public IDatabase\r
+{\r
+public:\r
+\r
+       const bool Build(const long messageid, const long boardid, const bool bydate=false);\r
+\r
+private:\r
+\r
+};\r
+\r
+#endif // _threadbuilder_\r
index 86a4f87..f8bb003 100644 (file)
@@ -12,7 +12,7 @@ DB::DB()
        Initialize();\r
 }\r
 \r
-DB::DB(std::string filename)\r
+DB::DB(const std::string &filename)\r
 {\r
        Initialize();\r
        Open(filename);\r
@@ -22,7 +22,7 @@ DB::~DB()
 {\r
        if(IsOpen())\r
        {\r
-               Close();        \r
+               Close();\r
        }\r
 }\r
 \r
@@ -39,12 +39,12 @@ const bool DB::Close()
                }\r
                else\r
                {\r
-                       return false;   \r
+                       return false;\r
                }\r
        }\r
        else\r
        {\r
-               return false;   \r
+               return false;\r
        }\r
 }\r
 \r
@@ -60,7 +60,7 @@ const bool DB::Execute(const std::string &sql)
                }\r
                else\r
                {\r
-                       return false;   \r
+                       return false;\r
                }\r
        }\r
        else\r
@@ -82,7 +82,7 @@ const bool DB::ExecuteInsert(const std::string &sql, long &insertid)
                }\r
                else\r
                {\r
-                       return false;   \r
+                       return false;\r
                }\r
        }\r
        else\r
@@ -106,7 +106,7 @@ const int DB::GetLastError(std::string &errormessage)
        }\r
        else\r
        {\r
-               return SQLITE_OK;       \r
+               return SQLITE_OK;\r
        }\r
 }\r
 \r
@@ -119,7 +119,7 @@ void DB::Initialize()
 const bool DB::IsOpen()\r
 {\r
        Poco::ScopedLock<Poco::FastMutex> g(m_mutex);\r
-       return m_db ? true : false; \r
+       return m_db ? true : false;\r
 }\r
 \r
 const bool DB::Open(const std::string &filename)\r
@@ -138,12 +138,12 @@ const bool DB::Open(const std::string &filename)
                }\r
                else\r
                {\r
-                       return false;   \r
+                       return false;\r
                }\r
        }\r
        else\r
        {\r
-               return false;   \r
+               return false;\r
        }\r
 }\r
 \r
index 789afb1..31c6ea5 100644 (file)
@@ -9,63 +9,36 @@ namespace SQLite3DB
 \r
 std::map<sqlite3_stmt *, long> Statement::m_statementcount;\r
 \r
-Statement::Statement()\r
+Statement::Statement():m_statement(0),m_parametercount(0),m_resultcolumncount(0),m_rowreturned(false),m_lastinsertrowid(-1)\r
 {\r
-       m_statement=NULL;\r
-       m_parametercount=0;\r
-       m_resultcolumncount=0;\r
-       m_rowreturned=false;\r
-       m_lastinsertrowid=-1;\r
+\r
 }\r
 \r
-Statement::Statement(sqlite3_stmt *statement)\r
+Statement::Statement(sqlite3_stmt *statement):m_statement(statement),m_rowreturned(false),m_lastinsertrowid(-1)\r
 {\r
-       m_statement=statement;\r
        m_parametercount=sqlite3_bind_parameter_count(m_statement);\r
        m_resultcolumncount=sqlite3_column_count(m_statement);\r
-       m_rowreturned=false;\r
-       m_lastinsertrowid=-1;\r
-       \r
+\r
        if(m_statement)\r
        {\r
                m_statementcount[m_statement]++;\r
        }\r
 }\r
 \r
-Statement::Statement(const Statement &rhs)\r
+Statement::Statement(const Statement &rhs):m_statement(0),m_parametercount(0),m_resultcolumncount(0),m_rowreturned(false),m_lastinsertrowid(-1)\r
 {\r
-       m_statement=NULL;\r
-       m_parametercount=0;\r
-       m_resultcolumncount=0;\r
-       m_rowreturned=false;\r
-       m_lastinsertrowid=-1;\r
        *this=rhs;\r
 }\r
 \r
 Statement::~Statement()\r
 {\r
-       \r
        Finalize();\r
-       \r
-       /*\r
-       std::vector<char *>::iterator i;\r
-       for(i=textptrs.begin(); i!=textptrs.end(); i++)\r
-       {\r
-               if((*i))\r
-               {\r
-                       delete [] (*i);\r
-               }\r
-       }\r
-       */\r
-\r
 }\r
 \r
 const bool Statement::Bind(const int column)\r
 {\r
        if(Valid() && column>=0 && column<m_parametercount)\r
        {\r
-               //ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
-               //PThread::Guard g(DB::Instance()->m_mutex);\r
                if(sqlite3_bind_null(m_statement,column+1)==SQLITE_OK)\r
                {\r
                        return true;\r
@@ -85,8 +58,6 @@ const bool Statement::Bind(const int column, const int value)
 {\r
        if(Valid() && column>=0 && column<m_parametercount)\r
        {\r
-               //ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
-               //PThread::Guard g(DB::Instance()->m_mutex);\r
                if(sqlite3_bind_int(m_statement,column+1,value)==SQLITE_OK)\r
                {\r
                        return true;\r
@@ -106,8 +77,6 @@ const bool Statement::Bind(const int column, const double value)
 {\r
        if(Valid() && column>=0 && column<m_parametercount)\r
        {\r
-               //ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
-               //PThread::Guard g(DB::Instance()->m_mutex);\r
                if(sqlite3_bind_double(m_statement,column+1,value)==SQLITE_OK)\r
                {\r
                        return true;\r
@@ -127,8 +96,6 @@ const bool Statement::Bind(const int column, const std::string &value)
 {\r
        if(Valid() && column>=0 && column<m_parametercount)\r
        {\r
-               //ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
-               //PThread::Guard g(DB::Instance()->m_mutex);\r
                if(sqlite3_bind_text(m_statement,column+1,value.c_str(),value.size(),SQLITE_TRANSIENT)==SQLITE_OK)\r
                {\r
                        return true;\r
@@ -148,8 +115,6 @@ const bool Statement::Bind(const int column, const void *data, const int length)
 {\r
        if(Valid() && column>=0 && column<m_parametercount)\r
        {\r
-               //ZThread::Guard<ZThread::Mutex> g(DB::instance()->m_mutex);\r
-               //PThread::Guard g(DB::Instance()->m_mutex);\r
                if(sqlite3_bind_blob(m_statement,column+1,data,length,SQLITE_TRANSIENT)==SQLITE_OK)\r
                {\r
                        return true;\r
@@ -190,6 +155,7 @@ Statement &Statement::operator=(const Statement &rhs)
                m_parametercount=rhs.m_parametercount;\r
                m_resultcolumncount=rhs.m_resultcolumncount;\r
                m_rowreturned=rhs.m_rowreturned;\r
+               m_lastinsertrowid=rhs.m_lastinsertrowid;\r
 \r
                if(m_statement)\r
                {\r
index 1fa11cd..b0cb73e 100644 (file)
@@ -233,6 +233,16 @@ void ConvertDB0112To0113()
        db->Execute("UPDATE tblDBVersion SET Major=1, Minor=13;");\r
 }\r
 \r
+void ConvertDB0113To0114()\r
+{\r
+       SQLite3DB::DB *db=SQLite3DB::DB::Instance();\r
+\r
+       db->Execute("ALTER TABLE tblBoard ADD COLUMN Forum TEXT CHECK(Forum IN ('true','false')) DEFAULT 'false';");\r
+       db->Execute("ALTER TABLE tblMessage ADD COLUMN Read INTEGER CHECK(Read IN (0,1)) DEFAULT 0;");\r
+\r
+       db->Execute("UPDATE tblDBVersion SET Major=1, Minor=14;");\r
+}\r
+\r
 void FixCapitalBoardNames()\r
 {\r
        SQLite3DB::DB *db=SQLite3DB::DB::Instance();\r
index f8c3357..3f4bdbc 100644 (file)
@@ -1,6 +1,7 @@
 #include "../include/dbmaintenancethread.h"\r
 #include "../include/stringfunctions.h"\r
 #include "../include/option.h"\r
+#include "../include/threadbuilder.h"\r
 \r
 #include <Poco/Timestamp.h>\r
 #include <Poco/Timespan.h>\r
@@ -36,12 +37,62 @@ DBMaintenanceThread::DBMaintenanceThread()
 void DBMaintenanceThread::Do10MinuteMaintenance()\r
 {\r
 \r
+       ThreadBuilder tb;\r
+       SQLite3DB::Statement boardst=m_db->Prepare("SELECT BoardID FROM tblBoard WHERE Forum='true';");\r
+       // select messages for a board that aren't in a thread\r
+       SQLite3DB::Statement selectst=m_db->Prepare("SELECT tblMessage.MessageID FROM tblMessage \\r
+                                                                                               INNER JOIN tblMessageBoard ON tblMessage.MessageID=tblMessageBoard.MessageID\\r
+                                                                                               LEFT JOIN tblThreadPost ON tblMessage.MessageID=tblThreadPost.MessageID \\r
+                                                                                               LEFT JOIN tblThread ON tblThreadPost.ThreadID=tblThread.ThreadID\\r
+                                                                                               WHERE tblMessageBoard.BoardID=? AND tblThread.BoardID IS NULL;");\r
+\r
+       boardst.Step();\r
+       while(boardst.RowReturned())\r
+       {\r
+               int boardid=-1;\r
+\r
+               boardst.ResultInt(0,boardid);\r
+\r
+               selectst.Bind(0,boardid);\r
+               selectst.Step();\r
+\r
+               while(selectst.RowReturned())\r
+               {\r
+                       int messageid=-1;\r
+\r
+                       selectst.ResultInt(0,messageid);\r
+\r
+                       tb.Build(messageid,boardid,true);\r
+\r
+                       selectst.Step();\r
+               }\r
+               selectst.Reset();\r
+\r
+               boardst.Step();\r
+       }\r
+\r
+       // now rebuild threads where the message has been deleted\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT tblThreadPost.MessageID, tblThread.BoardID FROM tblThreadPost INNER JOIN tblThread ON tblThreadPost.ThreadID=tblThread.ThreadID LEFT JOIN tblMessage ON tblThreadPost.MessageID=tblMessage.MessageID WHERE tblMessage.MessageID IS NULL;");\r
+       st.Step();\r
+       while(st.RowReturned())\r
+       {\r
+               int messageid=-1;\r
+               int boardid=-1;\r
+\r
+               st.ResultInt(0,messageid);\r
+               st.ResultInt(1,boardid);\r
+\r
+               tb.Build(messageid,boardid,true);\r
+\r
+               st.Step();\r
+       }\r
+\r
        m_log->debug("PeriodicDBMaintenance::Do10MinuteMaintenance");\r
 }\r
 \r
 void DBMaintenanceThread::Do30MinuteMaintenance()\r
 {\r
-\r
+       // UNCOMMENT method in run when code is placed here\r
        m_log->debug("PeriodicDBMaintenance::Do30MinuteMaintenance");\r
 }\r
 \r
@@ -283,6 +334,7 @@ void DBMaintenanceThread::run()
        m_log->debug("DBMaintenanceThread::run thread started.");\r
 \r
        Poco::DateTime now;\r
+       int i=0;\r
 \r
        do\r
        {\r
@@ -293,11 +345,13 @@ void DBMaintenanceThread::run()
                        Do10MinuteMaintenance();\r
                        m_last10minute=Poco::Timestamp();\r
                }\r
+               /*\r
                if((m_last30minute+Poco::Timespan(0,0,30,0,0))<=now)\r
                {\r
                        Do30MinuteMaintenance();\r
                        m_last30minute=Poco::Timestamp();\r
                }\r
+               */\r
                if((m_last1hour+Poco::Timespan(0,1,0,0,0))<=now)\r
                {\r
                        Do1HourMaintenance();\r
@@ -314,7 +368,12 @@ void DBMaintenanceThread::run()
                        m_last1day=Poco::Timestamp();\r
                }\r
 \r
-               Poco::Thread::sleep(1000);\r
+               i=0;\r
+               while(i++<5 && !IsCancelled())\r
+               {\r
+                       Poco::Thread::sleep(1000);\r
+               }\r
+\r
        }while(!IsCancelled());\r
 \r
        m_log->debug("DBMaintenanceThread::run thread exiting.");\r
index 5f4c129..1b037f7 100644 (file)
@@ -104,13 +104,19 @@ void SetupDB()
                        major=1;\r
                        minor=13;\r
                }\r
+               if(major==1 && minor==13)\r
+               {\r
+                       ConvertDB0113To0114();\r
+                       major=1;\r
+                       minor=14;\r
+               }\r
        }\r
        else\r
        {\r
-               db->Execute("INSERT INTO tblDBVersion(Major,Minor) VALUES(1,13);");\r
+               db->Execute("INSERT INTO tblDBVersion(Major,Minor) VALUES(1,14);");\r
        }\r
 \r
-       db->Execute("UPDATE tblDBVersion SET Major=1, Minor=13;");\r
+       db->Execute("UPDATE tblDBVersion SET Major=1, Minor=14;");\r
 \r
        db->Execute("CREATE TABLE IF NOT EXISTS tblFMSVersion(\\r
                                Major                           INTEGER,\\r
@@ -283,13 +289,14 @@ void SetupDB()
                                BoardDescription                TEXT,\\r
                                DateAdded                               DATETIME,\\r
                                SaveReceivedMessages    BOOL CHECK(SaveReceivedMessages IN('true','false')) DEFAULT 'true',\\r
-                               AddedMethod                             TEXT\\r
+                               AddedMethod                             TEXT,\\r
+                               Forum                                   TEXT CHECK(Forum IN('true','false')) DEFAULT 'false'\\r
                                );");\r
 \r
-       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded,AddedMethod) VALUES('fms','Freenet Message System','2007-12-01 12:00:00','Initial Board');");\r
-       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded,AddedMethod) VALUES('freenet','Discussion about Freenet','2007-12-01 12:00:00','Initial Board');");\r
-       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded,AddedMethod) VALUES('public','Public discussion','2007-12-01 12:00:00','Initial Board');");\r
-       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded,AddedMethod) VALUES('test','Test board','2007-12-01 12:00:00','Initial Board');");\r
+       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded,AddedMethod,Forum) VALUES('fms','Freenet Message System','2007-12-01 12:00:00','Initial Board','true');");\r
+       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded,AddedMethod,Forum) VALUES('freenet','Discussion about Freenet','2007-12-01 12:00:00','Initial Board','true');");\r
+       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded,AddedMethod,Forum) VALUES('public','Public discussion','2007-12-01 12:00:00','Initial Board','true');");\r
+       db->Execute("INSERT INTO tblBoard(BoardName,BoardDescription,DateAdded,AddedMethod,Forum) VALUES('test','Test board','2007-12-01 12:00:00','Initial Board','true');");\r
 \r
        db->Execute("CREATE TABLE IF NOT EXISTS tblMessage(\\r
                                MessageID                       INTEGER PRIMARY KEY,\\r
@@ -301,7 +308,8 @@ void SetupDB()
                                MessageUUID                     TEXT UNIQUE,\\r
                                ReplyBoardID            INTEGER,\\r
                                Body                            TEXT,\\r
-                               MessageIndex            INTEGER\\r
+                               MessageIndex            INTEGER,\\r
+                               Read                            INTEGER CHECK(Read IN(0,1)) DEFAULT 0\\r
                                );");\r
 \r
        db->Execute("CREATE INDEX IF NOT EXISTS idxMessage_IdentityID ON tblMessage (IdentityID);");\r
@@ -313,6 +321,7 @@ void SetupDB()
                                );");\r
 \r
        db->Execute("CREATE INDEX IF NOT EXISTS idxMessageReplyTo_MessageID ON tblMessageReplyTo (MessageID);");\r
+       db->Execute("CREATE INDEX IF NOT EXISTS idxMessageReplyTo_ReplyToMessageUUID ON tblMessageReplyTo (ReplyToMessageUUID);");\r
 \r
        db->Execute("CREATE TABLE IF NOT EXISTS tblMessageBoard(\\r
                                MessageID                       INTEGER,\\r
@@ -389,7 +398,35 @@ void SetupDB()
                                Day                                     DATE,\\r
                                RequestIndex            INTEGER,\\r
                                Found                           BOOL CHECK(Found IN('true','false')) DEFAULT 'false'\\r
-                               );");   \r
+                               );");\r
+\r
+       // begin thread db schema\r
+       db->Execute("CREATE TABLE IF NOT EXISTS tblThread(\\r
+                               ThreadID                INTEGER PRIMARY KEY,\\r
+                               BoardID                 INTEGER,\\r
+                               FirstMessageID  INTEGER,\\r
+                               LastMessageID   INTEGER\\r
+                               );");\r
+\r
+       db->Execute("CREATE INDEX IF NOT EXISTS idxThread_BoardID ON tblThread(BoardID);");\r
+       db->Execute("CREATE INDEX IF NOT EXISTS idxThread_FirstMessageID ON tblThread(FirstMessageID);");\r
+       db->Execute("CREATE INDEX IF NOT EXISTS idxThread_LastMessageID ON tblThread(LastMessageID);");\r
+\r
+       db->Execute("CREATE TABLE IF NOT EXISTS tblThreadPost(\\r
+                               ThreadID                INTEGER,\\r
+                               MessageID               INTEGER,\\r
+                               PostOrder               INTEGER\\r
+                               );");\r
+\r
+       db->Execute("CREATE INDEX IF NOT EXISTS idxThreadPost_ThreadID ON tblThreadPost(ThreadID);");\r
+       db->Execute("CREATE INDEX IF NOT EXISTS idxThreadPost_MessageID ON tblThreadPost(MessageID);");\r
+\r
+       db->Execute("CREATE TRIGGER IF NOT EXISTS trgDeleteOnThread AFTER DELETE ON tblThread\\r
+                               FOR EACH ROW\\r
+                               BEGIN\\r
+                                       DELETE FROM tblThreadPost WHERE ThreadID=old.ThreadID;\\r
+                               END;");\r
+       // end thread db schema\r
 \r
        // MessageInserter will insert a record into this temp table which the MessageListInserter will query for and insert a MessageList when needed\r
        db->Execute("CREATE TEMPORARY TABLE IF NOT EXISTS tmpMessageListInsert(\\r
index 01fcf9a..9737299 100644 (file)
@@ -262,6 +262,10 @@ void FMSApp::StartThreads()
        {\r
                logger().trace("FMSApp::StartThreads starting HTTPThread");\r
                m_threads.Start(new HTTPThread());\r
+               if(isInteractive())\r
+               {\r
+                       std::cout << "Started HTTP Thread" << std::endl;\r
+               }\r
        }\r
        else\r
        {\r
@@ -274,6 +278,10 @@ void FMSApp::StartThreads()
        {\r
                logger().trace("FMSApp::StartThreads starting NNTPListener");\r
                m_threads.Start(new NNTPListener());\r
+               if(isInteractive())\r
+               {\r
+                       std::cout << "Started NNTP Thread" << std::endl;\r
+               }\r
        }\r
        else\r
        {\r
@@ -286,6 +294,10 @@ void FMSApp::StartThreads()
        {\r
                logger().trace("FMSApp::StartThreads starting FreenetMasterThread");\r
                m_threads.Start(new FreenetMasterThread());\r
+               if(isInteractive())\r
+               {\r
+                       std::cout << "Started Freenet FCP Thread" << std::endl;\r
+               }\r
        }\r
        else\r
        {\r
index c1efe0f..80aacb1 100644 (file)
@@ -24,17 +24,6 @@ IntroductionPuzzleRequester::IntroductionPuzzleRequester(FCPv2 *fcp):IIndexReque
        Initialize();\r
 }\r
 \r
-void IntroductionPuzzleRequester::FCPConnected()\r
-{\r
-       m_requesting.clear();\r
-       PopulateIDList();\r
-}\r
-\r
-void IntroductionPuzzleRequester::FCPDisconnected()\r
-{\r
-       \r
-}\r
-\r
 const bool IntroductionPuzzleRequester::HandleAllData(FCPMessage &message)\r
 {\r
        Poco::DateTime now;\r
index 0c03204..d248cd3 100644 (file)
@@ -65,6 +65,8 @@ const bool MessageInserter::HandlePutFailed(FCPMessage &message)
                st.Step();\r
        }\r
 \r
+       m_log->trace("MessageInserter::HandlePutFailed error code "+message["Code"]+" fatal="+message["Fatal"]);\r
+\r
        RemoveFromInsertList(idparts[1]);\r
 \r
        return true;\r
index 9307b19..aa1e814 100644 (file)
@@ -168,7 +168,7 @@ const bool MessageListInserter::StartInsert(const long &localidentityid)
        date-=Poco::Timespan(m_daysbackward,0,0,0,0);\r
        StringFunctions::Convert(localidentityid,localidentityidstr);\r
 \r
-       SQLite3DB::Statement st=m_db->Prepare("SELECT Day, InsertIndex, MessageXML, PrivateKey FROM tblMessageInserts INNER JOIN tblLocalIdentity ON tblMessageInserts.LocalIdentityID=tblLocalIdentity.LocalIdentityID WHERE tblLocalIdentity.LocalIdentityID=? AND Day>=?;");\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT Day, InsertIndex, MessageXML, PrivateKey FROM tblMessageInserts INNER JOIN tblLocalIdentity ON tblMessageInserts.LocalIdentityID=tblLocalIdentity.LocalIdentityID WHERE tblLocalIdentity.LocalIdentityID=? AND Day>=? AND tblMessageInserts.MessageUUID IS NOT NULL;");\r
        st.Bind(0,localidentityid);\r
        st.Bind(1,Poco::DateTimeFormatter::format(date,"%Y-%m-%d"));\r
        st.Step();\r
index 6adb09f..c4606c0 100644 (file)
 #include "../../include/http/pages/peertrustpage.h"\r
 #include "../../include/http/pages/versioninfopage.h"\r
 #include "../../include/http/pages/recentlyaddedpage.h"\r
+#include "../../include/http/pages/browseboardspage.h"\r
+#include "../../include/http/pages/browsemessagespage.h"\r
+#include "../../include/http/pages/forummainpage.h"\r
+#include "../../include/http/pages/showimagepage.h"\r
+#include "../../include/http/pages/forumthreadspage.h"\r
+#include "../../include/http/pages/forumviewthreadpage.h"\r
+#include "../../include/http/pages/forumcreatepostpage.h"\r
 \r
 FMSHTTPRequestHandlerFactory::FMSHTTPRequestHandlerFactory()\r
 {\r
@@ -39,6 +46,24 @@ FMSHTTPRequestHandlerFactory::FMSHTTPRequestHandlerFactory()
                m_log->error("HTTPThread::HTTPThread could not open template.htm");\r
        }\r
 \r
+       // load forum template\r
+       std::string forumtemplate="<html><head></head><body><a href=\"home.htm\">Home</a><br><h1>Could not open forum-template.htm!  Place in program directory and restart!</h1><br>[CONTENT]</body></html>";\r
+       infile=fopen("forum-template.htm","rb");\r
+       if(infile)\r
+       {\r
+               fseek(infile,0,SEEK_END);\r
+               long len=ftell(infile);\r
+               std::vector<char> data(len,0);\r
+               fseek(infile,0,SEEK_SET);\r
+               fread(&data[0],1,len,infile);\r
+               fclose(infile);\r
+               forumtemplate.assign(data.begin(),data.end());\r
+       }\r
+       else\r
+       {\r
+               m_log->error("HTTPThread::HTTPThread could not open forum-template.htm");\r
+       }\r
+\r
        // push back page handlers\r
        m_pagehandlers.push_back(new OptionsPage(templatestr));\r
        m_pagehandlers.push_back(new CreateIdentityPage(templatestr));\r
@@ -56,6 +81,13 @@ FMSHTTPRequestHandlerFactory::FMSHTTPRequestHandlerFactory()
        m_pagehandlers.push_back(new PeerTrustPage(templatestr));\r
        m_pagehandlers.push_back(new VersionInfoPage(templatestr));\r
        m_pagehandlers.push_back(new RecentlyAddedPage(templatestr));\r
+       m_pagehandlers.push_back(new BrowseBoardsPage(templatestr));\r
+       m_pagehandlers.push_back(new BrowseMessagesPage(templatestr));\r
+       m_pagehandlers.push_back(new ShowImagePage());\r
+       m_pagehandlers.push_back(new ForumMainPage(forumtemplate));\r
+       m_pagehandlers.push_back(new ForumThreadsPage(forumtemplate));\r
+       m_pagehandlers.push_back(new ForumViewThreadPage(forumtemplate));\r
+       m_pagehandlers.push_back(new ForumCreatePostPage(forumtemplate));\r
        // homepage must be last - catch all page handler\r
        m_pagehandlers.push_back(new HomePage(templatestr));\r
 \r
index c9e4a1a..52e96f6 100644 (file)
@@ -197,3 +197,15 @@ const bool IPageHandler::ValidateFormPassword(const std::map<std::string,std::st
                return false;\r
        }\r
 }\r
+\r
+const bool IPageHandler::WillHandleURI(const std::string &uri)\r
+{\r
+       if(uri.find(m_pagename)!=std::string::npos)\r
+       {\r
+               return true;\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
index 2fbe97c..e8f7fd4 100644 (file)
@@ -89,7 +89,7 @@ const std::string AnnounceIdentityPage::GeneratePage(const std::string &method,
        content+="<tr><td colspan=\"4\"><center>Select Identity : ";\r
        content+=CreateLocalIdentityDropDown("localidentityid","");\r
        content+="</td></tr>";\r
-       content+="<tr><td colspan=\"4\"><center>Type the answers of a few of the following puzzles.  You don't need to get them all correct, but remember that they are case sensitive.  Getting announced will take some time.  DO NOT continuously solve captchas.  Solve 30 at most, wait a day, and if your identity has not been announced, repeat until it is.</td></tr>";\r
+       content+="<tr><td colspan=\"4\"><center>Type the answers of a few of the following puzzles.  You don't need to get them all correct, but remember that they are case sensitive.  Getting announced will take some time and you must assign trust to other identities to see yourself announced.  DO NOT continuously solve captchas.  Solve 30 at most, wait a day, and if your identity has not been announced, repeat until it is.</td></tr>";\r
        content+="<tr>";\r
 \r
        date-=Poco::Timespan(1,0,0,0,0);\r
@@ -98,7 +98,7 @@ const std::string AnnounceIdentityPage::GeneratePage(const std::string &method,
 \r
        if(st.RowReturned()==false)\r
        {\r
-               content+="<td colspan=\"4\"><center>You must wait for some puzzles to be downloaded.  Check back later.</td>";\r
+               content+="<td colspan=\"4\"><center>You must wait for some puzzles to be downloaded.  Make sure you have assigned trust to some other identities' trust lists and check back later.</td>";\r
        }\r
        \r
        while(st.RowReturned() && shown<20)\r
index e9cc2a3..397aefa 100644 (file)
@@ -75,23 +75,29 @@ const std::string BoardsPage::GeneratePage(const std::string &method, const std:
                        std::vector<std::string> descriptions;\r
                        std::vector<std::string> oldsavemessages;\r
                        std::vector<std::string> savemessages;\r
+                       std::vector<std::string> oldforums;\r
+                       std::vector<std::string> forums;\r
 \r
                        CreateArgArray(queryvars,"boardid",boardids);\r
                        CreateArgArray(queryvars,"oldboarddescription",olddescriptions);\r
                        CreateArgArray(queryvars,"boarddescription",descriptions);\r
                        CreateArgArray(queryvars,"oldsavereceivedmessages",oldsavemessages);\r
                        CreateArgArray(queryvars,"savereceivedmessages",savemessages);\r
+                       CreateArgArray(queryvars,"oldforum",oldforums);\r
+                       CreateArgArray(queryvars,"forum",forums);\r
 \r
                        olddescriptions.resize(boardids.size(),"");\r
                        descriptions.resize(boardids.size(),"");\r
                        oldsavemessages.resize(boardids.size(),"");\r
                        savemessages.resize(boardids.size(),"");\r
+                       oldforums.resize(boardids.size(),"");\r
+                       forums.resize(boardids.size(),"");\r
 \r
-                       SQLite3DB::Statement updatest=m_db->Prepare("UPDATE tblBoard SET BoardDescription=?, SaveReceivedMessages=? WHERE BoardID=?;");\r
+                       SQLite3DB::Statement updatest=m_db->Prepare("UPDATE tblBoard SET BoardDescription=?, SaveReceivedMessages=?, Forum=? WHERE BoardID=?;");\r
                        \r
                        for(int i=0; i<boardids.size(); i++)\r
                        {\r
-                               if(olddescriptions[i]!=descriptions[i] || oldsavemessages[i]!=savemessages[i])\r
+                               if(olddescriptions[i]!=descriptions[i] || oldsavemessages[i]!=savemessages[i] || oldforums[i]!=forums[i])\r
                                {\r
                                        updatest.Bind(0,descriptions[i]);\r
                                        if(savemessages[i]!="true")\r
@@ -102,9 +108,17 @@ const std::string BoardsPage::GeneratePage(const std::string &method, const std:
                                        {\r
                                                updatest.Bind(1,"true");\r
                                        }\r
+                                       if(forums[i]!="true")\r
+                                       {\r
+                                               updatest.Bind(2,"false");\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               updatest.Bind(2,"true");\r
+                                       }\r
                                        boardid=0;\r
                                        StringFunctions::Convert(boardids[i],boardid);\r
-                                       updatest.Bind(2,boardid);\r
+                                       updatest.Bind(3,boardid);\r
                                        updatest.Step();\r
                                        updatest.Reset();\r
                                }\r
@@ -154,7 +168,7 @@ const std::string BoardsPage::GeneratePage(const std::string &method, const std:
        st.Finalize();\r
 \r
 \r
-       sql="SELECT BoardID,BoardName,BoardDescription,SaveReceivedMessages,AddedMethod FROM tblBoard WHERE BoardID NOT IN (SELECT BoardID FROM tblAdministrationBoard)";\r
+       sql="SELECT BoardID,BoardName,BoardDescription,SaveReceivedMessages,AddedMethod,Forum FROM tblBoard WHERE BoardID NOT IN (SELECT BoardID FROM tblAdministrationBoard)";\r
        if(boardsearch!="")\r
        {\r
                sql+=" AND (BoardName LIKE '%' || ? || '%' OR BoardDescription LIKE '%' || ? || '%')";\r
@@ -170,7 +184,7 @@ const std::string BoardsPage::GeneratePage(const std::string &method, const std:
        }\r
        st.Step();\r
 \r
-       content+="<table>";\r
+       content+="<table class=\"small90\">";\r
 \r
        content+="<tr>";\r
        content+="<td colspan=\"3\"><center>";\r
@@ -190,7 +204,7 @@ const std::string BoardsPage::GeneratePage(const std::string &method, const std:
 \r
        content+="<tr><td colspan=\"4\"><hr><form name=\"frmboards\" method=\"POST\"><input type=\"hidden\" name=\"formaction\" value=\"update\">"+CreateFormPassword()+"</td></tr>";\r
        content+="<tr>";\r
-       content+="<th>Name</th><th>Description</th><th>Save Received Messages *</th><th>Added Method</th>";\r
+       content+="<th>Name</th><th>Description</th><th>Save Received Messages *</th><th>Forum</th><th>Added Method</th>";\r
        content+="</tr>";       \r
        while(st.RowReturned() && rownum<rowsperpage)\r
        {\r
@@ -200,12 +214,14 @@ const std::string BoardsPage::GeneratePage(const std::string &method, const std:
                std::string boarddescription="";\r
                std::string savereceivedmessages="";\r
                std::string addedmethod="";\r
+               std::string forum="";\r
 \r
                st.ResultText(0,boardidstr);\r
                st.ResultText(1,boardname);\r
                st.ResultText(2,boarddescription);\r
                st.ResultText(3,savereceivedmessages);\r
                st.ResultText(4,addedmethod);\r
+               st.ResultText(5,forum);\r
 \r
                StringFunctions::Convert(rownum,rownumstr);\r
 \r
@@ -223,7 +239,16 @@ const std::string BoardsPage::GeneratePage(const std::string &method, const std:
                }\r
                content+=">";\r
                content+="</td>";\r
-               content+="<td class=\"smaller\">"+SanitizeOutput(addedmethod)+"</td>";\r
+               content+="<td>";\r
+               content+="<input type=\"hidden\" name=\"oldforum["+rownumstr+"]\" value=\""+forum+"\">";\r
+               content+="<input type=\"checkbox\" name=\"forum["+rownumstr+"]\" value=\"true\"";\r
+               if(forum=="true")\r
+               {\r
+                       content+=" CHECKED";\r
+               }\r
+               content+=">";\r
+               content+="</td>";\r
+               content+="<td>"+SanitizeOutput(addedmethod)+"</td>";\r
                content+="</tr>\r\n";\r
                st.Step();\r
                rownum++;\r
@@ -238,17 +263,17 @@ const std::string BoardsPage::GeneratePage(const std::string &method, const std:
                if(startrow>0)\r
                {\r
                        StringFunctions::Convert(startrow-rowsperpage,tempstr);\r
-                       content+="<td colspan=\"1\" align=\"left\"><a href=\"boards.htm?"+BuildQueryString(startrow-rowsperpage,boardsearch)+"\"><-- Previous Page</a></td>";\r
-                       cols+=1;\r
+                       content+="<td colspan=\"2\" style=\"text-align:left;\"><a href=\"boards.htm?"+BuildQueryString(startrow-rowsperpage,boardsearch)+"\"><-- Previous Page</a></td>";\r
+                       cols+=2;\r
                }\r
                if(startrow+rowsperpage<boardcount)\r
                {\r
-                       while(cols<3)\r
+                       while(cols<4)\r
                        {\r
                                content+="<td></td>";\r
                                cols++;\r
                        }\r
-                       content+="<td colspan=\"1\" align=\"right\"><a href=\"boards.htm?"+BuildQueryString(startrow+rowsperpage,boardsearch)+"\">Next Page --></a></td>";\r
+                       content+="<td colspan=\"1\" style=\"text-align:left;\"><a href=\"boards.htm?"+BuildQueryString(startrow+rowsperpage,boardsearch)+"\">Next Page --></a></td>";\r
                }\r
                content+="</tr>";\r
        }\r
diff --git a/src/http/pages/browseboardspage.cpp b/src/http/pages/browseboardspage.cpp
new file mode 100644 (file)
index 0000000..e759cd6
--- /dev/null
@@ -0,0 +1,212 @@
+#include "../../../include/http/pages/browseboardspage.h"\r
+#include "../../../include/stringfunctions.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+const std::string BrowseBoardsPage::BuildQueryString(const long startrow, const std::string &boardsearch, const std::string &sortby, const std::string &sortorder)\r
+{\r
+       std::string returnval="";\r
+       std::string tempval="";\r
+\r
+       if(startrow>=0)\r
+       {\r
+               StringFunctions::Convert(startrow,tempval);\r
+               returnval+="startrow="+tempval;\r
+       }\r
+\r
+       if(boardsearch!="")\r
+       {\r
+               if(returnval!="")\r
+               {\r
+                       returnval+="&";\r
+               }\r
+               returnval+="boardsearch="+boardsearch;\r
+       }\r
+\r
+       if(sortby!="")\r
+       {\r
+               if(returnval!="")\r
+               {\r
+                       returnval+="&";\r
+               }\r
+               returnval+="sortby="+sortby;\r
+               if(sortorder=="ASC" || sortorder=="DESC")\r
+               {\r
+                       if(returnval!="")\r
+                       {\r
+                               returnval+="&";\r
+                       }\r
+                       returnval+="sortorder="+sortorder;\r
+               }\r
+               else\r
+               {\r
+                       if(returnval!="")\r
+                       {\r
+                               returnval+="&";\r
+                       }\r
+                       returnval+="sortorder=ASC";\r
+               }\r
+       }\r
+\r
+       return returnval;\r
+\r
+}\r
+\r
+const std::string BrowseBoardsPage::GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars)\r
+{\r
+       std::string content="";\r
+       std::string sql="";\r
+       std::string boardname="";\r
+       int rowsperpage=25;\r
+       std::string rowsperpagestr="26";        // 1 more than rowsperpage so we know if there are more boards\r
+       long startrow=0;\r
+       std::string startrowstr="0";\r
+       int messagecount=0;\r
+       std::string messagecountstr="0";\r
+       std::string lastdate="";\r
+       int count=0;\r
+       std::string boardsearch="";\r
+       std::string sortby="";\r
+       std::string sortorder="";\r
+\r
+       // if startrow is specified\r
+       if(queryvars.find("startrow")!=queryvars.end())\r
+       {\r
+               startrowstr=(*queryvars.find("startrow")).second;\r
+               // convert back and forth, just in case a number wasn't passed in startrow\r
+               StringFunctions::Convert(startrowstr,startrow);\r
+               if(startrow<0)\r
+               {\r
+                       startrow=0;\r
+               }\r
+               StringFunctions::Convert(startrow,startrowstr);\r
+       }\r
+       if(queryvars.find("boardsearch")!=queryvars.end())\r
+       {\r
+               boardsearch=(*queryvars.find("boardsearch")).second;\r
+       }\r
+       if(queryvars.find("sortby")!=queryvars.end() && queryvars.find("sortorder")!=queryvars.end())\r
+       {\r
+               sortby=(*queryvars.find("sortby")).second;\r
+               sortorder=(*queryvars.find("sortorder")).second;\r
+               if(sortby!="BoardName" && sortby!="MessageCount" && sortby!="LastMessage")\r
+               {\r
+                       sortby="BoardName";\r
+               }\r
+               if(sortorder!="ASC" && sortorder!="DESC")\r
+               {\r
+                       sortorder="ASC";\r
+               }\r
+       }\r
+       else\r
+       {\r
+               sortby="BoardName";\r
+               sortorder="ASC";\r
+       }\r
+\r
+       content="<h2>Browse Messages</h2>";\r
+       content+="<form name=\"frmfilter\" method=\"post\" action=\""+m_pagename+"\">";\r
+       content+="<input type=\"text\" name=\"boardsearch\" value=\""+SanitizeOutput(boardsearch)+"\">";\r
+       content+="<input type=\"submit\" value=\"Filter\">";\r
+       content+="</form>";\r
+\r
+       content+="<table class=\"small90\">";\r
+       content+="<tr>";\r
+       content+="<th><a href=\""+m_pagename+"?"+BuildQueryString(startrow,boardsearch,"BoardName",ReverseSort("BoardName",sortby,sortorder))+"\">Board</a></th>";\r
+       content+="<th><a href=\""+m_pagename+"?"+BuildQueryString(startrow,boardsearch,"MessageCount",ReverseSort("MessageCount",sortby,sortorder))+"\">Message Count</a></th>";\r
+       content+="<th><a href=\""+m_pagename+"?"+BuildQueryString(startrow,boardsearch,"LastMessage",ReverseSort("LastMessage",sortby,sortorder))+"\">Last Message</a></th>";\r
+       content+="</tr>";\r
+\r
+       sql="SELECT tblBoard.BoardID, tblBoard.BoardName, COUNT(tblMessageBoard.MessageID) AS 'MessageCount', MAX(tblMessage.MessageDate || ' ' || tblMessage.MessageTime) AS 'LastMessage'";\r
+       sql+="FROM tblBoard LEFT JOIN tblMessageBoard ON tblBoard.BoardID=tblMessageBoard.BoardID ";\r
+       sql+="LEFT JOIN tblMessage ON tblMessageBoard.MessageID=tblMessage.MessageID ";\r
+       sql+="WHERE (tblMessageBoard.MessageID>=0 OR tblMessageBoard.MessageID IS NULL) ";\r
+       if(boardsearch!="")\r
+       {\r
+               sql+="AND tblBoard.BoardName LIKE '%' || ? || '%' ";\r
+       }\r
+       sql+="GROUP BY tblBoard.BoardID ";\r
+       sql+="ORDER BY "+sortby+" COLLATE NOCASE "+sortorder+" ";\r
+       sql+="LIMIT "+startrowstr+","+rowsperpagestr+";";\r
+       \r
+       SQLite3DB::Statement st=m_db->Prepare(sql);\r
+       if(boardsearch!="")\r
+       {\r
+               st.Bind(0,boardsearch);\r
+       }\r
+       \r
+       st.Step();\r
+       while(st.RowReturned() && count++<rowsperpage)\r
+       {\r
+               boardname="";\r
+               messagecount=0;\r
+               lastdate="";\r
+               std::string boardidstr="0";\r
+               st.ResultText(0,boardidstr);\r
+               st.ResultText(1,boardname);\r
+               st.ResultInt(2,messagecount);\r
+               st.ResultText(3,lastdate);\r
+\r
+               StringFunctions::Convert(messagecount,messagecountstr);\r
+\r
+               content+="<tr>";\r
+               content+="<td><a href=\"browsemessages.htm?boardid="+boardidstr+"\">"+SanitizeOutput(boardname)+"</a></td>";\r
+               content+="<td>"+SanitizeOutput(messagecountstr)+"</td>";\r
+               content+="<td>"+SanitizeOutput(lastdate)+"</td>";\r
+               content+="</tr>\r\n";\r
+               st.Step();\r
+       }\r
+\r
+       if(startrow>0 || st.RowReturned())\r
+       {\r
+               content+="<tr>";\r
+\r
+               if(startrow>0)\r
+               {\r
+                       int thisstartrow=startrow-rowsperpage;\r
+                       if(thisstartrow<0)\r
+                       {\r
+                               thisstartrow=0;\r
+                       }\r
+                       content+="<td><a href=\"boardsbrowse.htm?"+BuildQueryString(thisstartrow,boardsearch,sortby,sortorder)+"\">&lt;--</a></td>";\r
+               }\r
+               else\r
+               {\r
+                       content+="<td></td>";\r
+               }\r
+\r
+               content+="<td></td>";\r
+\r
+               if(st.RowReturned())\r
+               {\r
+                       int thisstartrow=startrow+rowsperpage;\r
+                       content+="<td><a href=\"boardsbrowse.htm?"+BuildQueryString(thisstartrow,boardsearch,sortby,sortorder)+"\">--&gt;</a></td>";\r
+               }\r
+\r
+               content+="</tr>";\r
+       }\r
+       content+="</table>";\r
+       \r
+       return StringFunctions::Replace(m_template,"[CONTENT]",content);\r
+}\r
+\r
+const std::string BrowseBoardsPage::ReverseSort(const std::string &sortname, const std::string &currentsortby, const std::string &currentsortorder)\r
+{\r
+       if(sortname==currentsortby)\r
+       {\r
+               if(currentsortorder=="ASC")\r
+               {\r
+                       return "DESC";\r
+               }\r
+               else\r
+               {\r
+                       return "ASC";\r
+               }\r
+       }\r
+       else\r
+       {\r
+               return currentsortorder;\r
+       }\r
+}\r
diff --git a/src/http/pages/browsemessagespage.cpp b/src/http/pages/browsemessagespage.cpp
new file mode 100644 (file)
index 0000000..9601064
--- /dev/null
@@ -0,0 +1,265 @@
+#include "../../../include/http/pages/browsemessagespage.h"\r
+#include "../../../include/stringfunctions.h"\r
+#include "../../../include/global.h"\r
+#include "../../../include/messagethread.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+const std::string BrowseMessagesPage::BuildQueryString(const long startrow, const std::string &boardidstr, const std::string &messageidstr)\r
+{\r
+       std::string returnval="";\r
+       std::string tempval="";\r
+\r
+       if(startrow>=0)\r
+       {\r
+               StringFunctions::Convert(startrow,tempval);\r
+               returnval+="startrow="+tempval;\r
+       }\r
+\r
+       if(boardidstr!="")\r
+       {\r
+               if(returnval!="")\r
+               {\r
+                       returnval+="&";\r
+               }\r
+               returnval+="boardid="+boardidstr;\r
+       }\r
+\r
+       if(messageidstr!="")\r
+       {\r
+               if(returnval!="")\r
+               {\r
+                       returnval+="&";\r
+               }       \r
+               returnval+="messageid="+messageidstr;\r
+       }\r
+\r
+       return returnval;\r
+\r
+}\r
+\r
+const std::string BrowseMessagesPage::GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars)\r
+{\r
+       std::string content="";\r
+       long boardid=-1;\r
+       std::string boardidstr="";\r
+       std::string messageidstr="";\r
+       int startrow=0;\r
+       std::string startrowstr="0";\r
+       int rowsperpage=50;\r
+       std::string rowsperpagestr="51";        // one more than rowsperpage so we can know if there are more messages\r
+       std::string sql="";\r
+       int rowcount=0;\r
+       int page=0;\r
+\r
+       // if startrow is specified\r
+       if(queryvars.find("startrow")!=queryvars.end())\r
+       {\r
+               startrowstr=(*queryvars.find("startrow")).second;\r
+               // convert back and forth, just in case a number wasn't passed in startrow\r
+               StringFunctions::Convert(startrowstr,startrow);\r
+               if(startrow<0)\r
+               {\r
+                       startrow=0;\r
+               }\r
+               StringFunctions::Convert(startrow,startrowstr);\r
+       }\r
+       if(queryvars.find("boardid")!=queryvars.end())\r
+       {\r
+               boardidstr=(*queryvars.find("boardid")).second;\r
+               StringFunctions::Convert(boardidstr,boardid);\r
+       }\r
+       if(queryvars.find("messageid")!=queryvars.end())\r
+       {\r
+               messageidstr=(*queryvars.find("messageid")).second;\r
+               page=1;\r
+       }\r
+\r
+       if(page==0)\r
+       {\r
+               sql="SELECT Subject, FromName, MessageDate || ' ' || MessageTime, Body, tblMessage.MessageID ";\r
+               sql+="FROM tblMessage INNER JOIN tblMessageBoard ON tblMessage.MessageID=tblMessageBoard.MessageID ";\r
+               if(boardidstr!="")\r
+               {\r
+                       sql+="WHERE tblMessageBoard.BoardID=? ";\r
+               }\r
+               sql+="ORDER BY MessageDate || ' ' || MessageTime DESC ";\r
+               sql+="LIMIT "+startrowstr+","+rowsperpagestr+";";\r
+\r
+               SQLite3DB::Statement st=m_db->Prepare(sql);\r
+               if(boardidstr!="")\r
+               {\r
+                       st.Bind(0,boardidstr);\r
+               }\r
+               st.Step();\r
+\r
+               content+="<table class=\"small90\">";\r
+               content+="<tr><th>Subject</th><th>From</th><th>Date</th></tr>";\r
+\r
+               rowcount=0;\r
+               while(st.RowReturned() && rowcount++<rowsperpage)\r
+               {\r
+                       std::string subject="";\r
+                       std::string fromname="";\r
+                       std::string messagedate="";\r
+                       std::string body="";\r
+                       std::string messageidstr="";\r
+\r
+                       st.ResultText(0,subject);\r
+                       st.ResultText(1,fromname);\r
+                       st.ResultText(2,messagedate);\r
+                       st.ResultText(3,body);\r
+                       st.ResultText(4,messageidstr);\r
+\r
+                       if(body.size()>400)\r
+                       {\r
+                               body.erase(400);\r
+                               body+="...";\r
+                       }\r
+\r
+                       content+="<tr>";\r
+                       content+="<td title=\""+StringFunctions::Replace(SanitizeOutput(body),"\n","\r\n")+"\"><a href=\""+m_pagename+"?"+BuildQueryString(startrow,boardidstr,messageidstr)+"\">"+SanitizeOutput(subject)+"</a></td>";\r
+                       content+="<td>"+fromname+"</td>";\r
+                       content+="<td>"+SanitizeOutput(messagedate)+"</td>";\r
+                       content+="</tr>\r\n";\r
+\r
+                       st.Step();\r
+               }\r
+               \r
+               if(startrow>0 || st.RowReturned())\r
+               {\r
+                       content+="<tr>";\r
+\r
+                       if(startrow>0)\r
+                       {\r
+                               int thisstartrow=startrow-rowsperpage;\r
+                               if(thisstartrow<0)\r
+                               {\r
+                                       thisstartrow=0;\r
+                               }\r
+                               content+="<td><a href=\""+m_pagename+"?"+BuildQueryString(thisstartrow,boardidstr,"")+"\">&lt;--</a></td>";\r
+                       }\r
+                       else\r
+                       {\r
+                               content+="<td></td>";\r
+                       }\r
+\r
+                       content+="<td></td>";\r
+\r
+                       if(st.RowReturned())\r
+                       {\r
+                               int thisstartrow=startrow+rowsperpage;\r
+                               content+="<td><a href=\""+m_pagename+"?"+BuildQueryString(thisstartrow,boardidstr,"")+"\">--&gt;</a></td>";\r
+                       }\r
+                       content+="</tr>";\r
+               }\r
+\r
+               content+="</table>";\r
+       }\r
+       else if(page==1)\r
+       {\r
+               sql="SELECT Body, FromName, MessageDate || ' ' || MessageTime, Subject FROM tblMessage WHERE MessageID=?;";\r
+               SQLite3DB::Statement st=m_db->Prepare(sql);\r
+               st.Bind(0,messageidstr);\r
+\r
+               st.Step();\r
+               if(st.RowReturned())\r
+               {\r
+                       std::string body="";\r
+                       std::string fromname="";\r
+                       std::string messagedate="";\r
+                       std::string subject="";\r
+                       std::string boards="";\r
+\r
+                       st.ResultText(0,body);\r
+                       st.ResultText(1,fromname);\r
+                       st.ResultText(2,messagedate);\r
+                       st.ResultText(3,subject);\r
+\r
+                       // get boards message was posted to\r
+                       SQLite3DB::Statement st2=m_db->Prepare("SELECT tblBoard.BoardID, tblBoard.BoardName FROM tblBoard INNER JOIN tblMessageBoard ON tblBoard.BoardID=tblMessageBoard.BoardID WHERE tblMessageBoard.MessageID=?;");\r
+                       st2.Bind(0,messageidstr);\r
+                       st2.Step();\r
+                       while(st2.RowReturned())\r
+                       {\r
+                               std::string boardname="";\r
+                               std::string innerboardidstr="";\r
+\r
+                               st2.ResultText(0,innerboardidstr);\r
+                               st2.ResultText(1,boardname);\r
+                               \r
+                               if(boards!="")\r
+                               {\r
+                                       boards+=",&nbsp;";\r
+                               }\r
+\r
+                               boards+="<a href=\""+m_pagename+"?"+BuildQueryString(0,innerboardidstr,"")+"\">"+SanitizeOutput(boardname)+"</a>";\r
+\r
+                               st2.Step();\r
+                       }\r
+\r
+                       content+="<div class=\"post\">";\r
+                       content+="<div class=\"postboards\">";\r
+                       content+=boards;\r
+                       content+="</div>";\r
+                       content+="<div class=\"postsubject\">";\r
+                       content+=SanitizeOutput(subject);\r
+                       content+="</div>";\r
+                       content+="<div class=\"postfrom\">";\r
+                       content+=SanitizeOutput(fromname);\r
+                       content+="</div>";\r
+                       content+="<div class=\"postdate\">";\r
+                       content+=SanitizeOutput(messagedate);\r
+                       content+="</div>";\r
+                       content+="<div class=\"postbody\">";\r
+                       content+=SanitizeOutput(body);\r
+                       content+="</div>";\r
+                       content+="</div>\r\n";\r
+\r
+                       long currentlevel=0;\r
+                       MessageThread thread;\r
+                       thread.Load(messageidstr,boardid);\r
+\r
+                       std::vector<MessageThread::threadnode> nodes=thread.GetNodes();\r
+                       if(nodes.size()>1)\r
+                       {\r
+                               content+="<ul class=\"messagethread\">";\r
+                               for(std::vector<MessageThread::threadnode>::const_iterator i=nodes.begin(); i!=nodes.end(); i++)\r
+                               {\r
+                                       if((*i).m_level>currentlevel)\r
+                                       {\r
+                                               content+="<ul class=\"messagethread\">";\r
+                                       }\r
+                                       else if((*i).m_level<currentlevel)\r
+                                       {\r
+                                               content+="</ul>";\r
+                                       }\r
+                                       currentlevel=(*i).m_level;\r
+\r
+                                       std::string tempstr="";\r
+                                       StringFunctions::Convert((*i).m_messageid,tempstr);\r
+\r
+                                       content+="<li>";\r
+                                       if(tempstr!=messageidstr)\r
+                                       {\r
+                                               content+="<a href=\""+m_pagename+"?"+BuildQueryString(0,boardidstr,tempstr)+"\">"+SanitizeOutput((*i).m_subject)+"</a> - "+SanitizeOutput((*i).m_fromname);\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               content+=SanitizeOutput((*i).m_subject)+" - "+SanitizeOutput((*i).m_fromname);\r
+                                       }\r
+                                       content+="</li>\r\n";\r
+                               }\r
+                               while(currentlevel-->0)\r
+                               {\r
+                                       content+="</ul>";\r
+                               }\r
+                               content+="</ul>\r\n";\r
+                       }\r
+               }\r
+       }\r
+\r
+       return StringFunctions::Replace(m_template,"[CONTENT]",content);\r
+}\r
diff --git a/src/http/pages/forumcreatepostpage.cpp b/src/http/pages/forumcreatepostpage.cpp
new file mode 100644 (file)
index 0000000..ac9ed16
--- /dev/null
@@ -0,0 +1,227 @@
+#include "../../../include/http/pages/forumcreatepostpage.h"\r
+#include "../../../include/stringfunctions.h"\r
+#include "../../../include/message.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+const std::string ForumCreatePostPage::GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars)\r
+{\r
+       int page=0;\r
+       std::string content="";\r
+       std::string boardidstr="";\r
+       std::string currentpagestr="";\r
+       std::string threadidstr="";\r
+       std::string replytomessageidstr="";\r
+       std::string error="";\r
+       std::string boardname="";\r
+       std::string subject="";\r
+       std::string body="";\r
+       std::string localidentityidstr="";\r
+\r
+       if(queryvars.find("boardid")!=queryvars.end())\r
+       {\r
+               boardidstr=(*queryvars.find("boardid")).second;\r
+       }\r
+       if(queryvars.find("currentpage")!=queryvars.end())\r
+       {\r
+               currentpagestr=(*queryvars.find("currentpage")).second;\r
+       }\r
+       if(queryvars.find("threadid")!=queryvars.end())\r
+       {\r
+               threadidstr=(*queryvars.find("threadid")).second;\r
+       }\r
+       if(queryvars.find("replytomessageid")!=queryvars.end())\r
+       {\r
+               replytomessageidstr=(*queryvars.find("replytomessageid")).second;\r
+       }\r
+\r
+       if(queryvars.find("formaction")!=queryvars.end() && (*queryvars.find("formaction")).second=="send")\r
+       {\r
+               if(queryvars.find("localidentityid")!=queryvars.end() && (*queryvars.find("localidentityid")).second!="")\r
+               {\r
+                       localidentityidstr=(*queryvars.find("localidentityid")).second;\r
+               }\r
+               else\r
+               {\r
+                       error="You must select a local identity as the sender<br />";\r
+               }\r
+\r
+               if(queryvars.find("subject")!=queryvars.end() && (*queryvars.find("subject")).second!="")\r
+               {\r
+                       subject=(*queryvars.find("subject")).second;\r
+               }\r
+               else\r
+               {\r
+                       error+="You must enter a subject<br />";\r
+               }\r
+\r
+               if(queryvars.find("body")!=queryvars.end() && (*queryvars.find("body")).second!="")\r
+               {\r
+                       body=(*queryvars.find("body")).second;\r
+                       body=StringFunctions::Replace(body,"\r\n","\n");\r
+               }\r
+               else\r
+               {\r
+                       error+="You must enter a message body</br />";\r
+               }\r
+\r
+               if(error=="")\r
+               {\r
+                       Message mess;\r
+                       \r
+                       long localidentityid=-1;\r
+                       long boardid=-1;\r
+                       std::string references="";\r
+\r
+                       StringFunctions::Convert(localidentityidstr,localidentityid);\r
+                       StringFunctions::Convert(boardidstr,boardid);\r
+\r
+                       if(replytomessageidstr!="")\r
+                       {\r
+                               SQLite3DB::Statement st=m_db->Prepare("SELECT MessageUUID FROM tblMessage WHERE MessageID=?;");\r
+                               st.Bind(0,replytomessageidstr);\r
+                               st.Step();\r
+                               if(st.RowReturned())\r
+                               {\r
+                                       st.ResultText(0,references);\r
+                               }\r
+                       }\r
+\r
+                       if(mess.Create(localidentityid,boardid,subject,body,references))\r
+                       {\r
+                               if(mess.PostedToAdministrationBoard()==true)\r
+                               {\r
+                                       mess.HandleAdministrationMessage();\r
+                               }\r
+                               if(mess.StartFreenetInsert())\r
+                               {\r
+                                       page=1;\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               error="Could not create message";\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               if(replytomessageidstr!="")\r
+               {\r
+                       SQLite3DB::Statement replyst=m_db->Prepare("SELECT Subject, Body FROM tblMessage WHERE MessageID=?;");\r
+                       replyst.Bind(0,replytomessageidstr);\r
+                       replyst.Step();\r
+                       if(replyst.RowReturned())\r
+                       {\r
+                               replyst.ResultText(0,subject);\r
+                               replyst.ResultText(1,body);\r
+\r
+                               if(subject.size()<3 || (subject.substr(0,2)!="re:" && subject.substr(0,2)!="Re:"))\r
+                               {\r
+                                       subject="Re: "+subject;\r
+                               }\r
+\r
+                               if(body.size()>0)\r
+                               {\r
+                                       if(body[0]=='>')\r
+                                       {\r
+                                               body=">"+body;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               body="> "+body;\r
+                                       }\r
+                                       std::string::size_type pos=body.find("\n");\r
+                                       while(pos!=std::string::npos)\r
+                                       {\r
+                                               if(pos+1<body.size() && body[pos+1]=='>')\r
+                                               {\r
+                                                       body.insert(pos+1,">");\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       body.insert(pos+1,"> ");\r
+                                               }\r
+                                               pos=body.find("\n",pos+2);\r
+                                       }\r
+                                       body+="\n";\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       SQLite3DB::Statement boardnamest=m_db->Prepare("SELECT BoardName FROM tblBoard WHERE BoardID=?;");\r
+       boardnamest.Bind(0,boardidstr);\r
+       boardnamest.Step();\r
+       if(boardnamest.RowReturned())\r
+       {\r
+               boardnamest.ResultText(0,boardname);\r
+       }\r
+\r
+       content+=CreateForumHeader();\r
+\r
+       content+="<table class=\"forumheader\">";\r
+       content+="<tr>";\r
+       content+="<td>Forum : <a href=\"forumthreads.htm?boardid="+boardidstr+"&currentpage="+currentpagestr+"\">"+SanitizeOutput(boardname)+"</a></td>";\r
+       content+="</tr>";\r
+       content+="</table>\r\n";\r
+\r
+       if(error!="")\r
+       {\r
+               content+="<div class=\"error\">"+error+"</div>\r\n";\r
+       }\r
+\r
+       if(page==0)\r
+       {\r
+               content+="<form name=\"frmcreatemessage\" method=\"post\" action=\"forumcreatepost.htm\">";\r
+               content+="<input type=\"hidden\" name=\"boardid\" value=\""+boardidstr+"\">";\r
+               content+="<input type=\"hidden\" name=\"currentpage\" value=\""+currentpagestr+"\">";\r
+               content+="<input type=\"hidden\" name=\"threadid\" value=\""+threadidstr+"\">";\r
+               content+="<input type=\"hidden\" name=\"replytomessageid\" value=\""+replytomessageidstr+"\">";\r
+               content+="<input type=\"hidden\" name=\"formaction\" value=\"send\">";\r
+               content+="<table class=\"createpost\">";\r
+               content+="<tr><td class=\"identity\">From</td><td>"+LocalIdentityDropDown("localidentityid",localidentityidstr)+"</td></tr>";\r
+               content+="<tr><td class=\"subject\">Subject</td><td><input type=\"text\" name=\"subject\" maxlength=\"60\" size=\"60\" value=\""+SanitizeOutput(subject)+"\"></td></tr>";\r
+               content+="<tr><td class=\"body\">Message</td><td><textarea name=\"body\" cols=\"80\" rows=\"30\">"+SanitizeOutput(body)+"</textarea></td></tr>";\r
+               content+="<tr><td colspan=\"2\" class=\"send\"><input type=\"submit\" value=\"Send\"></td></tr>";\r
+               content+="</table>\r\n";\r
+               content+="</form>";\r
+       }\r
+       else if(page==1)\r
+       {\r
+               content+="You have sent your message.  It will show up in the thread after it has been successfully inserted and retrieved by FMS.";\r
+       }\r
+\r
+       return StringFunctions::Replace(m_template,"[CONTENT]",content);\r
+}\r
+\r
+const std::string ForumCreatePostPage::LocalIdentityDropDown(const std::string &name, const std::string &selectedid)\r
+{\r
+       std::string html="<select name=\""+name+"\">";\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT LocalIdentityID, Name FROM tblLocalIdentity ORDER BY Name COLLATE NOCASE ASC;");\r
+\r
+       if(selectedid=="")\r
+       {\r
+               html+="<option value=\"\" selected></option>";\r
+       }\r
+\r
+       st.Step();\r
+       while(st.RowReturned())\r
+       {\r
+               std::string id="";\r
+               std::string name="";\r
+               st.ResultText(0,id);\r
+               st.ResultText(1,name);\r
+               html+="<option value=\""+id+"\"";\r
+               if(id==selectedid)\r
+               {\r
+                       html+=" selected";\r
+               }\r
+               html+=">"+FixFromName(name)+"</option>";\r
+               st.Step();\r
+       }\r
+       html+="</select>";\r
+       return html;\r
+}\r
diff --git a/src/http/pages/forummainpage.cpp b/src/http/pages/forummainpage.cpp
new file mode 100644 (file)
index 0000000..ae97874
--- /dev/null
@@ -0,0 +1,93 @@
+#include "../../../include/http/pages/forummainpage.h"\r
+#include "../../../include/stringfunctions.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+const std::string ForumMainPage::GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars)\r
+{\r
+       std::string content="";\r
+\r
+       content+=CreateForumHeader();\r
+\r
+       content+="<table class=\"foruminfo\">\r\n";\r
+       content+="<thead><tr><th>New</th><th>Forum</th><th>Posts</th><th>Last Post</th></tr></thead>\r\n";\r
+\r
+       SQLite3DB::Statement newmessagesst=m_db->Prepare("SELECT tblMessage.MessageID FROM tblMessage INNER JOIN tblMessageBoard ON tblMessage.MessageID=tblMessageBoard.MessageID INNER JOIN tblThreadPost ON tblMessage.MessageID=tblThreadPost.MessageID WHERE tblMessageBoard.BoardID=? AND tblMessage.Read=0 LIMIT 0,1;");\r
+       SQLite3DB::Statement lastmessagest=m_db->Prepare("SELECT tblMessage.MessageID, tblMessage.IdentityID, tblMessage.FromName, tblMessage.Subject, tblMessage.MessageDate || ' ' || tblMessage.MessageTime, tblThread.ThreadID FROM tblMessage INNER JOIN tblThreadPost ON tblMessage.MessageID=tblThreadPost.MessageID INNER JOIN tblThread ON tblThreadPost.ThreadID=tblThread.ThreadID WHERE tblThread.BoardID=? ORDER BY tblMessage.MessageDate || tblMessage.MessageTime DESC LIMIT 0,1;");\r
+       \r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT tblBoard.BoardID, BoardName, BoardDescription, COUNT(tblThreadPost.MessageID) FROM tblBoard LEFT JOIN tblThread ON tblBoard.BoardID=tblThread.BoardID LEFT JOIN tblThreadPost ON tblThread.ThreadID=tblThreadPost.ThreadID WHERE Forum='true' GROUP BY tblBoard.BoardID ORDER BY BoardName COLLATE NOCASE;");\r
+       st.Step();\r
+       while(st.RowReturned())\r
+       {\r
+               int boardid=-1;\r
+               std::string boardidstr="-1";\r
+               std::string boardname="";\r
+               std::string boarddescription="";\r
+               std::string postcountstr="";\r
+\r
+               st.ResultInt(0,boardid);\r
+               st.ResultText(0,boardidstr);\r
+               st.ResultText(1,boardname);\r
+               st.ResultText(2,boarddescription);\r
+               st.ResultText(3,postcountstr);\r
+\r
+               content+="<tr>";\r
+               content+="<td class=\"newposts\">";\r
+\r
+               newmessagesst.Bind(0,boardid);\r
+               newmessagesst.Step();\r
+               if(newmessagesst.RowReturned())\r
+               {\r
+                       content+="<img src=\"showimage.htm?image=images/new_posts.png\" title=\"New Posts\">";\r
+               }\r
+               else\r
+               {\r
+                       content+="<img src=\"showimage.htm?image=images/no_new_posts.png\" title=\"No New Posts\">";\r
+               }\r
+               newmessagesst.Reset();\r
+\r
+               content+="</td>";\r
+\r
+               content+="<td class=\"forumname\">";\r
+               content+="<a href=\"forumthreads.htm?boardid="+boardidstr+"\">"+SanitizeOutput(boardname)+"</a><br />";\r
+               content+="<span class=\"description\">"+SanitizeOutput(boarddescription)+"</span>";\r
+               content+="</td>";\r
+               content+="<td class=\"postcount\">";\r
+               content+=postcountstr+" posts";\r
+               content+="</td>";\r
+\r
+               lastmessagest.Bind(0,boardid);\r
+               lastmessagest.Step();\r
+               content+="<td class=\"lastpost\">";\r
+               if(lastmessagest.RowReturned())\r
+               {\r
+                       std::string messageidstr="";\r
+                       std::string identityidstr="";\r
+                       std::string fromname="";\r
+                       std::string messagedate="";\r
+                       std::string subject="";\r
+                       std::string threadidstr="";\r
+\r
+                       lastmessagest.ResultText(0,messageidstr);\r
+                       lastmessagest.ResultText(1,identityidstr);\r
+                       lastmessagest.ResultText(2,fromname);\r
+                       lastmessagest.ResultText(3,subject);\r
+                       lastmessagest.ResultText(4,messagedate);\r
+                       lastmessagest.ResultText(5,threadidstr);\r
+\r
+                       content+="Last post on "+messagedate+" in<br />";\r
+                       content+="<a href=\"forumviewthread.htm?threadid="+threadidstr+"&boardid="+boardidstr+"#"+messageidstr+"\">"+FixSubject(subject)+"</a> by <a href=\"peerdetails.htm?identityid="+identityidstr+"\" title=\""+SanitizeOutput(fromname)+"\">"+FixFromName(fromname)+"</a>";\r
+               }\r
+               content+="</td>";\r
+               lastmessagest.Reset();\r
+\r
+               content+="</tr>\r\n";\r
+               st.Step();\r
+       }\r
+\r
+       content+="</table>\r\n";\r
+\r
+       return StringFunctions::Replace(m_template,"[CONTENT]",content);\r
+}\r
diff --git a/src/http/pages/forumthreadspage.cpp b/src/http/pages/forumthreadspage.cpp
new file mode 100644 (file)
index 0000000..0777fe1
--- /dev/null
@@ -0,0 +1,197 @@
+#include "../../../include/http/pages/forumthreadspage.h"\r
+#include "../../../include/stringfunctions.h"\r
+#include <cmath>\r
+\r
+const std::string ForumThreadsPage::GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars)\r
+{\r
+       int currentpage=1;\r
+       std::string currentpagestr="1";\r
+       std::string content="";\r
+       int startrow=0;\r
+       std::string startrowstr="0";\r
+       int rowsperpage=25;\r
+       std::string rowsperpagestr="25";\r
+       std::string sql="";\r
+       int boardid=-1;\r
+       std::string boardidstr="-1";\r
+       int count=0;\r
+       int threadcount=0;\r
+       SQLite3DB::Statement newthreadpostst=m_db->Prepare("SELECT tblMessage.MessageID FROM tblThreadPost INNER JOIN tblMessage ON tblThreadPost.MessageID=tblMessage.MessageID WHERE tblThreadPost.ThreadID=? AND tblMessage.Read=0 LIMIT 0,1;");\r
+       SQLite3DB::Statement replycountst=m_db->Prepare("SELECT COUNT(*)-1 FROM tblThreadPost WHERE ThreadID=?;");\r
+       SQLite3DB::Statement boardnamest=m_db->Prepare("SELECT tblBoard.BoardName FROM tblBoard WHERE BoardID=?;");\r
+       SQLite3DB::Statement threadcountst=m_db->Prepare("SELECT COUNT(*) FROM tblThread WHERE BoardID=?;");\r
+\r
+       if(queryvars.find("boardid")!=queryvars.end())\r
+       {\r
+               boardidstr=(*queryvars.find("boardid")).second;\r
+               StringFunctions::Convert(boardidstr,boardid);\r
+       }\r
+       if(queryvars.find("currentpage")!=queryvars.end())\r
+       {\r
+               currentpagestr=(*queryvars.find("currentpage")).second;\r
+               StringFunctions::Convert(currentpagestr,currentpage);\r
+               if(currentpage<0)\r
+               {\r
+                       currentpage=0;\r
+               }\r
+               StringFunctions::Convert(currentpage,currentpagestr);\r
+       }\r
+       if(queryvars.find("formaction")!=queryvars.end() && (*queryvars.find("formaction")).second=="markallread" && boardid!=-1)\r
+       {\r
+               SQLite3DB::Statement markst=m_db->Prepare("UPDATE tblMessage SET Read=1 WHERE tblMessage.Read=0 AND tblMessage.MessageID IN (SELECT MessageID FROM tblThread INNER JOIN tblThreadPost ON tblThread.ThreadID=tblThreadPost.ThreadID WHERE tblThread.BoardID=?);");\r
+               markst.Bind(0,boardid);\r
+               markst.Step();\r
+       }\r
+\r
+       startrow=(currentpage-1)*rowsperpage;\r
+       StringFunctions::Convert(startrow,startrowstr);\r
+\r
+       content+=CreateForumHeader();\r
+\r
+       content+="<table class=\"forumheader\">";\r
+       content+="<tr>";\r
+\r
+       boardnamest.Bind(0,boardid);\r
+       boardnamest.Step();\r
+       if(boardnamest.RowReturned())\r
+       {\r
+               std::string boardname="";\r
+               boardnamest.ResultText(0,boardname);\r
+               content+="<td>Forum : <a href=\"forumthreads.htm?boardid="+boardidstr+"\">"+SanitizeOutput(boardname)+"</a></td>";\r
+       }\r
+       content+="<td><a href=\"forumthreads.htm?boardid="+boardidstr+"&currentpage="+currentpagestr+"&formaction=markallread\">Mark All Read</a></td>";\r
+       content+="<td><a href=\"forumcreatepost.htm?boardid="+boardidstr+"&currentpage="+currentpagestr+"\">New Post</a></td>";\r
+       content+="</tr>";\r
+       content+="</table>\r\n";\r
+\r
+       content+="<table class=\"threadinfo\">";\r
+       content+="<thead><tr><th>New</th><th>Subject</th><th>Started By</th><th>Replies</th><th>Last Post</th></tr></thread>\r\n";\r
+       \r
+       sql="SELECT tblThread.ThreadID, tblThread.LastMessageID, tblLastMessage.FromName, tblLastMessage.MessageDate || ' ' || tblLastMessage.MessageTime, tblFirstMessage.Subject, tblFirstMessage.FromName, tblFirstMessage.IdentityID, tblLastMessage.IdentityID";\r
+       sql+=" FROM tblThread INNER JOIN tblMessage AS tblLastMessage ON tblThread.LastMessageID=tblLastMessage.MessageID INNER JOIN tblMessage AS tblFirstMessage ON tblThread.FirstMessageID=tblFirstMessage.MessageID";\r
+       sql+=" WHERE tblThread.BoardID=?";\r
+       sql+=" ORDER BY tblLastMessage.MessageDate || tblLastMessage.MessageTime DESC";\r
+       sql+=" LIMIT "+startrowstr+","+rowsperpagestr+";";\r
+\r
+       SQLite3DB::Statement threadst=m_db->Prepare(sql);\r
+       threadst.Bind(0,boardid);\r
+       threadst.Step();\r
+       count=0;\r
+       while(threadst.RowReturned() && count++<rowsperpage)\r
+       {\r
+               std::string threadidstr="";\r
+               std::string lastmessageidstr="";\r
+               std::string lastmessagefromname="";\r
+               std::string lastmessagedate="";\r
+               std::string firstmessagesubject="";\r
+               std::string firstmessagefromname="";\r
+               std::string firstmessageidentityidstr="";\r
+               std::string lastmessageidentityidstr="";\r
+\r
+               threadst.ResultText(0,threadidstr);\r
+               threadst.ResultText(1,lastmessageidstr);\r
+               threadst.ResultText(2,lastmessagefromname);\r
+               threadst.ResultText(3,lastmessagedate);\r
+               threadst.ResultText(4,firstmessagesubject);\r
+               threadst.ResultText(5,firstmessagefromname);\r
+               threadst.ResultText(6,firstmessageidentityidstr);\r
+               threadst.ResultText(7,lastmessageidentityidstr);\r
+\r
+               content+="<tr>";\r
+               content+="<td class=\"newposts\">";\r
+\r
+               newthreadpostst.Bind(0,threadidstr);\r
+               newthreadpostst.Step();\r
+               if(newthreadpostst.RowReturned())\r
+               {\r
+                       content+="<img src=\"showimage.htm?image=images/new_posts.png\" title=\"New Posts\">";\r
+               }\r
+               else\r
+               {\r
+                       content+="<img src=\"showimage.htm?image=images/no_new_posts.png\" title=\"No New Posts\">";\r
+               }\r
+               newthreadpostst.Reset();\r
+\r
+               content+="</td>";\r
+               content+="<td class=\"threadsubject\">";\r
+               content+="<a href=\"forumviewthread.htm?threadid="+threadidstr+"&currentpage="+currentpagestr+"&boardid="+boardidstr+"\">"+SanitizeOutput(firstmessagesubject)+"</a>";\r
+               content+="</td>";\r
+               content+="<td class=\"threadauthor\">";\r
+               content+="<a href=\"peerdetails.htm?identityid="+firstmessageidentityidstr+"\">"+FixFromName(firstmessagefromname)+"</a>";\r
+               content+="</td>";\r
+\r
+               content+="<td class=\"threadreplies\">";\r
+\r
+               replycountst.Bind(0,threadidstr);\r
+               replycountst.Step();\r
+               if(replycountst.RowReturned())\r
+               {\r
+                       std::string count="0";\r
+                       replycountst.ResultText(0,count);\r
+                       content+=count;\r
+               }\r
+               else\r
+               {\r
+                       content+="0";\r
+               }\r
+               replycountst.Reset();\r
+\r
+               content+="</td>";\r
+\r
+               content+="<td class=\"threadlastpost\">";\r
+               content+=lastmessagedate+"<br />by <a href=\"peerdetails.htm?identityid="+lastmessageidentityidstr+"\">"+FixFromName(lastmessagefromname)+"</a>";\r
+               content+="</td>";\r
+\r
+               content+="</tr>\r\n";\r
+\r
+               threadst.Step();\r
+       }\r
+\r
+       threadcountst.Bind(0,boardid);\r
+       threadcountst.Step();\r
+       if(threadcountst.RowReturned())\r
+       {\r
+               threadcountst.ResultInt(0,threadcount);\r
+       }\r
+\r
+       if(threadcount>=rowsperpage)\r
+       {\r
+               int totalpages=ceil(static_cast<float>(threadcount)/static_cast<float>(rowsperpage));\r
+               int lastwrote=0;\r
+               content+="<tr>";\r
+               \r
+               content+="<td class=\"pages\" colspan=\"7\">Pages : ";\r
+\r
+               for(int i=1; i<=totalpages; i++)\r
+               {\r
+                       if(i==1 || (i>currentpage-3 && i<currentpage+3) || i==totalpages)\r
+                       {\r
+                               std::string pagestr="";\r
+                               StringFunctions::Convert(i,pagestr);\r
+                               if(lastwrote!=i-1)\r
+                               {\r
+                                       content+="&nbsp;...";\r
+                               }\r
+                               if(i!=currentpage)\r
+                               {\r
+                                       content+="&nbsp;<a href=\"forumthreads.htm?boardid="+boardidstr+"&currentpage="+pagestr+"\">"+pagestr+"</a>";\r
+                               }\r
+                               else\r
+                               {\r
+                                       content+="&nbsp;"+pagestr;\r
+                               }\r
+                               lastwrote=i;\r
+                       }\r
+               }\r
+\r
+               content+="<form><input type=\"hidden\" name=\"boardid\" value=\""+boardidstr+"\"><input type=\"text\" name=\"currentpage\"><input type=\"submit\" value=\"Go\"></form>";\r
+               \r
+               content+="</td>";\r
+\r
+               content+="</tr>\r\n";\r
+       }\r
+       \r
+       content+="</table>\r\n";\r
+\r
+       return StringFunctions::Replace(m_template,"[CONTENT]",content);\r
+}\r
diff --git a/src/http/pages/forumviewthreadpage.cpp b/src/http/pages/forumviewthreadpage.cpp
new file mode 100644 (file)
index 0000000..0b69926
--- /dev/null
@@ -0,0 +1,158 @@
+#include "../../../include/http/pages/forumviewthreadpage.h"\r
+#include "../../../include/stringfunctions.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+const std::string ForumViewThreadPage::FixBody(const std::string &body)\r
+{\r
+       static std::string whitespace=" \t\r\n";\r
+       std::string output=body;\r
+\r
+       // put \n after 80 contiguous characters in the body\r
+       std::string::size_type prevpos=0;\r
+       std::string::size_type pos=output.find_first_of(whitespace);\r
+       while(pos!=std::string::npos)\r
+       {\r
+               while(pos-prevpos>80)\r
+               {\r
+                       output.insert(prevpos+80,"\n");\r
+                       prevpos+=81;    // 81 because of the extra newline we just inserted\r
+               }\r
+               prevpos=pos;\r
+               pos=output.find_first_of(whitespace,pos+1);\r
+       }\r
+       while(output.size()-prevpos>80) // check the last line of the message (no whitespace after it)\r
+       {\r
+               output.insert(prevpos+80,"\n");\r
+               prevpos+=81;\r
+       }\r
+\r
+       output=StringFunctions::Replace(output,"<","&lt;");\r
+       output=StringFunctions::Replace(output,">","&gt;");\r
+       output=StringFunctions::Replace(output,"\n","<br />");\r
+       return output;\r
+}\r
+\r
+const std::string ForumViewThreadPage::GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars)\r
+{\r
+       std::string content="";\r
+       std::string threadidstr="";\r
+       std::string boardidstr="";\r
+       std::string currentpagestr="";\r
+       std::string boardname="";\r
+\r
+       if(queryvars.find("threadid")!=queryvars.end())\r
+       {\r
+               threadidstr=(*queryvars.find("threadid")).second;\r
+       }\r
+       if(queryvars.find("currentpage")!=queryvars.end())\r
+       {\r
+               currentpagestr=(*queryvars.find("currentpage")).second;\r
+       }\r
+       if(queryvars.find("boardid")!=queryvars.end())\r
+       {\r
+               boardidstr=(*queryvars.find("boardid")).second;\r
+       }\r
+\r
+       content+=CreateForumHeader();\r
+\r
+       SQLite3DB::Statement updateread=m_db->Prepare("UPDATE tblMessage SET Read=1 WHERE tblMessage.MessageID IN (SELECT MessageID FROM tblThreadPost WHERE ThreadID=?);");\r
+       updateread.Bind(0,threadidstr);\r
+       updateread.Step();\r
+\r
+       SQLite3DB::Statement trustst=m_db->Prepare("SELECT LocalMessageTrust, LocalTrustListTrust, PeerMessageTrust, PeerTrustListTrust, Name FROM tblIdentity WHERE IdentityID=?;");\r
+\r
+       SQLite3DB::Statement boardnamest=m_db->Prepare("SELECT tblBoard.BoardName FROM tblBoard INNER JOIN tblThread ON tblBoard.BoardID=tblThread.BoardID WHERE tblThread.ThreadID=?;");\r
+       boardnamest.Bind(0,threadidstr);\r
+       boardnamest.Step();\r
+\r
+       if(boardnamest.RowReturned())\r
+       {\r
+               boardnamest.ResultText(0,boardname);\r
+       }\r
+\r
+       content+="<table class=\"forumheader\">";\r
+       content+="<tr>";\r
+       content+="<td> Forum : <a href=\"forumthreads.htm?boardid="+boardidstr+"&currentpage="+currentpagestr+"\">"+SanitizeOutput(boardname)+"</a></td>";\r
+       content+="</tr>";\r
+       content+="</table>\r\n";\r
+\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT tblMessage.MessageID, tblMessage.IdentityID, tblMessage.FromName, tblMessage.Subject, tblMessage.MessageDate || ' ' || tblMessage.MessageTime, tblMessage.Body FROM tblMessage INNER JOIN tblThreadPost ON tblMessage.MessageID=tblThreadPost.MessageID WHERE tblThreadPost.ThreadID=? ORDER BY tblThreadPost.PostOrder;");\r
+       st.Bind(0,threadidstr);\r
+\r
+       content+="<table class=\"thread\">";\r
+       st.Step();\r
+       while(st.RowReturned())\r
+       {\r
+               std::string messageidstr="";\r
+               std::string identityidstr="";\r
+               std::string fromname="";\r
+               std::string subject="";\r
+               std::string datetime="";\r
+               std::string body="";\r
+               \r
+               st.ResultText(0,messageidstr);\r
+               st.ResultText(1,identityidstr);\r
+               st.ResultText(2,fromname);\r
+               st.ResultText(3,subject);\r
+               st.ResultText(4,datetime);\r
+               st.ResultText(5,body);\r
+\r
+               content+="<tr>";\r
+               content+="<td rowspan=\"2\" class=\"from\">";\r
+               content+="<a name=\""+messageidstr+"\"></a>";\r
+               content+="<a href=\"peerdetails.htm?identityid="+identityidstr+"\">"+FixFromName(fromname)+"</a><br />";\r
+\r
+               trustst.Bind(0,identityidstr);\r
+               trustst.Step();\r
+               if(trustst.RowReturned())\r
+               {\r
+                       std::string localmessagetrust="";\r
+                       std::string localtrustlisttrust="";\r
+                       std::string peermessagetrust="";\r
+                       std::string peertrustlisttrust="";\r
+                       std::string name="";\r
+\r
+                       trustst.ResultText(0,localmessagetrust);\r
+                       trustst.ResultText(1,localtrustlisttrust);\r
+                       trustst.ResultText(2,peermessagetrust);\r
+                       trustst.ResultText(3,peertrustlisttrust);\r
+                       trustst.ResultText(4,name);\r
+\r
+                       content+="<table class=\"trust\">";\r
+                       content+="<tr>";\r
+                       content+="<td colspan=\"3\" style=\"text-align:center;\"><a href=\"peertrust.htm?namesearch="+name+"\">Trust</a></td>";\r
+                       content+="</tr>";\r
+                       content+="<tr>";\r
+                       content+="<td></td><td>Local</td><td>Peer</td>";\r
+                       content+="</tr>";\r
+                       content+="<tr>";\r
+                       content+="<td>Message</td><td>"+localmessagetrust+"</td><td>"+peermessagetrust+"</td>";\r
+                       content+="</tr>";\r
+                       content+="<tr>";\r
+                       content+="<td>Trust List</td><td>"+localtrustlisttrust+"</td><td>"+peertrustlisttrust+"</td>";\r
+                       content+="</tr>";\r
+                       content+="</table>";\r
+               }\r
+\r
+               content+="</td>";\r
+               content+="<td class=\"subject\">";\r
+               content+=SanitizeOutput(subject)+" on "+datetime;\r
+               content+="</td>";\r
+               content+="<td><a href=\"forumcreatepost.htm?replytomessageid="+messageidstr+"&threadid="+threadidstr+"&boardid="+boardidstr+"&currentpage="+currentpagestr+"\">Reply</a></td>";\r
+               content+="</tr>\r\n";\r
+               content+="<tr>";\r
+               content+="<td class=\"body\" colspan=\"2\">";\r
+               content+=FixBody(body);\r
+               content+="</td>";\r
+               content+="</tr>";\r
+               trustst.Reset();\r
+\r
+               st.Step();\r
+       }\r
+       content+="</table>";\r
+\r
+       return StringFunctions::Replace(m_template,"[CONTENT]",content);\r
+}\r
index 3ebe2f1..ec4ea32 100644 (file)
@@ -66,6 +66,10 @@ const std::string HomePage::GeneratePage(const std::string &method, const std::m
                        content+="You can see the release info <a href=\"versioninfo.htm?Major="+majorstr+"&Minor="+minorstr+"&Release="+releasestr+"\">here</a><br>";\r
                        showgenericupdate=false;\r
                }\r
+               else\r
+               {\r
+                       content+="<a href=\"versioninfo.htm\">Release info</a><br>";\r
+               }\r
 \r
        }\r
 \r
index 400260f..7910789 100644 (file)
@@ -33,7 +33,7 @@ const std::string LocalIdentitiesPage::GeneratePage(const std::string &method, c
 \r
        content+="<hr>";\r
 \r
-       content+="<table><tr><th>Name</th><th>Single Use</th><th>Publish Trust List</th><th>Publish Board List</th><th>Publish Freesite</th><th>Min Message Delay</th><th>Max Message Delay</th><th>Announced? *</th></tr>";\r
+       content+="<table class=\"small90\"><tr><th>Name</th><th>Single Use</th><th>Publish Trust List</th><th>Publish Board List</th><th>Publish Freesite</th><th>Min Message Delay</th><th>Max Message Delay</th><th>Announced? *</th></tr>";\r
 \r
        SQLite3DB::Statement st=m_db->Prepare("SELECT LocalIdentityID,tblLocalIdentity.Name,tblLocalIdentity.PublicKey,tbLLocalIdentity.PublishTrustList,tblLocalIdentity.SingleUse,tblLocalIdentity.PublishBoardList,tblIdentity.IdentityID,tblLocalIdentity.PublishFreesite,tblLocalIdentity.MinMessageDelay,tblLocalIdentity.MaxMessageDelay FROM tblLocalIdentity LEFT JOIN tblIdentity ON tblLocalIdentity.PublicKey=tblIdentity.PublicKey ORDER BY tblLocalIdentity.Name;");\r
        st.Step();\r
@@ -116,7 +116,7 @@ const std::string LocalIdentitiesPage::GeneratePage(const std::string &method, c
        }\r
 \r
        content+="</table>";\r
-       content+="<p class=\"paragraph\">* An identity is considered successfully announced when you have downloaded a trust list from someone that contains the identity.  The number in parenthesis is how many trust lists that identity appears in.</p>";\r
+       content+="<p class=\"paragraph\">* An identity is considered successfully announced when you have downloaded a trust list from someone that contains the identity.  You must trust other identities' trust lists for this to happen.  The number in parenthesis is how many trust lists the identity appears in.</p>";\r
        content+="<p class=\"paragraph\">Single Use Identities will automatically be deleted 7 days after creation.</p>";\r
        content+="<p class=\"paragraph\">Messages that each identity sends may be delayed by a random number of minutes between min and max.  Set both to 0 to send messages as soon as possible.</p>";\r
 \r
index fe03c91..d80ae18 100644 (file)
@@ -261,14 +261,14 @@ const std::string PeerTrustPage::GeneratePage(const std::string &method, const s
 \r
        // search drop down\r
        content+="<div style=\"text-align:center;margin-bottom:5px;\">";\r
-       content+="<form name=\"frmsearch\" method=\"POST\" action=\"peertrust.htm?"+BuildQueryString(0,"","","",localidentityid)+"\">";\r
+       content+="<form name=\"frmsearch\" method=\"POST\" action=\""+m_pagename+"?"+BuildQueryString(0,"","","",localidentityid)+"\">";\r
        content+="<input type=\"text\" name=\"namesearch\" value=\""+SanitizeOutput(namesearch)+"\">";\r
        content+="<input type=\"submit\" value=\"Search\">";\r
        content+="</form>";\r
        content+="</div>";\r
 \r
        content+="<div style=\"text-align:center;\">";\r
-       content+="<form name=\"frmlocalidentity\" method=\"POST\" action=\"peertrust.htm?"+BuildQueryString(startrow,namesearch,sortby,sortorder,-1)+"\">";\r
+       content+="<form name=\"frmlocalidentity\" method=\"POST\" action=\""+m_pagename+"?"+BuildQueryString(startrow,namesearch,sortby,sortorder,-1)+"\">";\r
        content+="Load Trust List of ";\r
        content+=CreateLocalIdentityDropDown("localidentityid",localidentityid);\r
        content+="<input type=\"submit\" value=\"Load List\">";\r
@@ -285,14 +285,14 @@ const std::string PeerTrustPage::GeneratePage(const std::string &method, const s
                content+="<input type=\"hidden\" name=\"namesearch\" value=\""+SanitizeOutput(namesearch)+"\">";\r
        }\r
        content+="<table class=\"small90\">";\r
-       content+="<tr><th><a href=\"peertrust.htm?"+BuildQueryString(startrow,namesearch,"Name",ReverseSort("Name",sortby,sortorder),localidentityid)+"\">Name</a></th>";\r
-       content+="<th><a href=\"peertrust.htm?"+BuildQueryString(startrow,namesearch,"tblIdentityTrust.LocalMessageTrust",ReverseSort("tblIdentityTrust.LocalMessageTrust",sortby,sortorder),localidentityid)+"\">Local Message Trust</a></th>";\r
+       content+="<tr><th><a href=\""+m_pagename+"?"+BuildQueryString(startrow,namesearch,"Name",ReverseSort("Name",sortby,sortorder),localidentityid)+"\">Name</a></th>";\r
+       content+="<th><a href=\""+m_pagename+"?"+BuildQueryString(startrow,namesearch,"tblIdentityTrust.LocalMessageTrust",ReverseSort("tblIdentityTrust.LocalMessageTrust",sortby,sortorder),localidentityid)+"\">Local Message Trust</a></th>";\r
        content+="<th>Message Comment</th>";\r
-       content+="<th><a href=\"peertrust.htm?"+BuildQueryString(startrow,namesearch,"PeerMessageTrust",ReverseSort("PeerMessageTrust",sortby,sortorder),localidentityid)+"\">Peer Message Trust</a></th>";\r
-       content+="<th><a href=\"peertrust.htm?"+BuildQueryString(startrow,namesearch,"tblIdentityTrust.LocalTrustListTrust",ReverseSort("tblIdentityTrust.LocalTrustListTrust",sortby,sortorder),localidentityid)+"\">Local Trust List Trust</a></th>";\r
+       content+="<th><a href=\""+m_pagename+"?"+BuildQueryString(startrow,namesearch,"PeerMessageTrust",ReverseSort("PeerMessageTrust",sortby,sortorder),localidentityid)+"\">Peer Message Trust</a></th>";\r
+       content+="<th><a href=\""+m_pagename+"?"+BuildQueryString(startrow,namesearch,"tblIdentityTrust.LocalTrustListTrust",ReverseSort("tblIdentityTrust.LocalTrustListTrust",sortby,sortorder),localidentityid)+"\">Local Trust List Trust</a></th>";\r
        content+="<th>Trust Comment</th>";\r
-       content+="<th><a href=\"peertrust.htm?"+BuildQueryString(startrow,namesearch,"PeerTrustListTrust",ReverseSort("PeerTrustListTrust",sortby,sortorder),localidentityid)+"\">Peer Trust List Trust</a></th>";\r
-       content+="<th><a href=\"peertrust.htm?"+BuildQueryString(startrow,namesearch,"MessageCount",ReverseSort("MessageCount",sortby,sortorder),localidentityid)+"\">Message Count</a></th>";\r
+       content+="<th><a href=\""+m_pagename+"?"+BuildQueryString(startrow,namesearch,"PeerTrustListTrust",ReverseSort("PeerTrustListTrust",sortby,sortorder),localidentityid)+"\">Peer Trust List Trust</a></th>";\r
+       content+="<th><a href=\""+m_pagename+"?"+BuildQueryString(startrow,namesearch,"MessageCount",ReverseSort("MessageCount",sortby,sortorder),localidentityid)+"\">Message Count</a></th>";\r
        content+="</tr>\r\n";\r
        \r
        // get count of identities we are showing\r
@@ -425,7 +425,7 @@ const std::string PeerTrustPage::GeneratePage(const std::string &method, const s
                if(startrow>0)\r
                {\r
                        StringFunctions::Convert(startrow-rowsperpage,tempstr);\r
-                       content+="<td colspan=\"3\" align=\"left\"><a href=\"peertrust.htm?"+BuildQueryString(startrow-rowsperpage,namesearch,sortby,sortorder,localidentityid)+"\"><-- Previous Page</a></td>";\r
+                       content+="<td colspan=\"3\" align=\"left\"><a href=\""+m_pagename+"?"+BuildQueryString(startrow-rowsperpage,namesearch,sortby,sortorder,localidentityid)+"\"><-- Previous Page</a></td>";\r
                        cols+=3;\r
                }\r
                if(startrow+rowsperpage<identitycount)\r
@@ -435,7 +435,7 @@ const std::string PeerTrustPage::GeneratePage(const std::string &method, const s
                                content+="<td></td>";\r
                                cols++;\r
                        }\r
-                       content+="<td colspan=\"3\" align=\"right\"><a href=\"peertrust.htm?"+BuildQueryString(startrow+rowsperpage,namesearch,sortby,sortorder,localidentityid)+"\">Next Page --></a></td>";\r
+                       content+="<td colspan=\"3\" align=\"right\"><a href=\""+m_pagename+"?"+BuildQueryString(startrow+rowsperpage,namesearch,sortby,sortorder,localidentityid)+"\">Next Page --></a></td>";\r
                }\r
                content+="</tr>";\r
        }\r
@@ -484,15 +484,3 @@ const std::string PeerTrustPage::ReverseSort(const std::string &sortname, const
                return currentsortorder;\r
        }\r
 }\r
-\r
-const bool PeerTrustPage::WillHandleURI(const std::string &uri)\r
-{\r
-       if(uri.find("peertrust.")!=std::string::npos)\r
-       {\r
-               return true;\r
-       }\r
-       else\r
-       {\r
-               return false;\r
-       }\r
-}\r
index 2b09ce8..313544e 100644 (file)
@@ -81,15 +81,3 @@ const std::string RecentlyAddedPage::GeneratePage(const std::string &method, con
 \r
        return StringFunctions::Replace(m_template,"[CONTENT]",content);\r
 }\r
-\r
-const bool RecentlyAddedPage::WillHandleURI(const std::string &uri)\r
-{\r
-       if(uri.find("recentlyadded.")!=std::string::npos)\r
-       {\r
-               return true;\r
-       }\r
-       else\r
-       {\r
-               return false;\r
-       }\r
-}\r
index 088fffa..736ba85 100644 (file)
@@ -13,7 +13,10 @@ void ShowCaptchaPage::handleRequest(Poco::Net::HTTPServerRequest &request, Poco:
        std::map<std::string,std::string> queryvars;\r
        CreateQueryVarMap(request,queryvars);\r
 \r
-       response.setChunkedTransferEncoding(true);\r
+       if(request.getVersion()==Poco::Net::HTTPRequest::HTTP_1_1)\r
+       {\r
+               response.setChunkedTransferEncoding(true);\r
+       }\r
 \r
        std::string content="";\r
        if(queryvars.find("UUID")!=queryvars.end())\r
diff --git a/src/http/pages/showimagepage.cpp b/src/http/pages/showimagepage.cpp
new file mode 100644 (file)
index 0000000..8b653ee
--- /dev/null
@@ -0,0 +1,64 @@
+#include "../../../include/http/pages/showimagepage.h"\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+std::map<std::string,std::vector<char> > ShowImagePage::m_imagecache;\r
+\r
+void ShowImagePage::handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response)\r
+{\r
+       m_log->trace("ShowImagePage::handleRequest from "+request.clientAddress().toString());\r
+\r
+       std::map<std::string,std::string> queryvars;\r
+       CreateQueryVarMap(request,queryvars);\r
+\r
+       if(request.getVersion()==Poco::Net::HTTPRequest::HTTP_1_1)\r
+       {\r
+               response.setChunkedTransferEncoding(true);\r
+       }\r
+\r
+       std::string content="";\r
+       if(queryvars.find("image")!=queryvars.end())\r
+       {\r
+               if(m_imagecache.find((*queryvars.find("image")).second)!=m_imagecache.end())\r
+               {\r
+                       content+=std::string(m_imagecache[(*queryvars.find("image")).second].begin(),m_imagecache[(*queryvars.find("image")).second].end());\r
+               }\r
+               else\r
+               {\r
+                       FILE *infile=fopen((*queryvars.find("image")).second.c_str(),"rb");\r
+                       if(infile)\r
+                       {\r
+                               fseek(infile,0,SEEK_END);\r
+                               long filelen=ftell(infile);\r
+                               fseek(infile,0,SEEK_SET);\r
+\r
+                               if(filelen>0)\r
+                               {\r
+                                       std::vector<char> data(filelen,0);\r
+                                       fread(&data[0],1,data.size(),infile);\r
+                                       content+=std::string(data.begin(),data.end());\r
+                                       m_imagecache[(*queryvars.find("image")).second]=data;\r
+                               }\r
+\r
+                               fclose(infile);\r
+                       }\r
+               }\r
+       }\r
+\r
+       std::ostream &ostr = response.send();\r
+       ostr << content;\r
+}\r
+\r
+const bool ShowImagePage::WillHandleURI(const std::string &uri)\r
+{\r
+       if(uri.find("showimage.htm")!=std::string::npos)\r
+       {\r
+               return true;\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
index 670e9da..13b88ba 100644 (file)
@@ -4,59 +4,71 @@
 \r
 #include <string>\r
 \r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
 const std::string VersionInfoPage::GeneratePage(const std::string &method, const std::map<std::string,std::string> &queryvars)\r
 {\r
        std::string content="";\r
 \r
+       bool hascriteria=false;\r
        std::string major=VERSION_MAJOR;\r
        std::string minor=VERSION_MINOR;\r
        std::string release=VERSION_RELEASE;\r
+       std::string sql="";\r
 \r
        if(queryvars.find("Major")!=queryvars.end())\r
        {\r
                major=(*queryvars.find("Major")).second;\r
+               hascriteria=true;\r
        }\r
        if(queryvars.find("Minor")!=queryvars.end())\r
        {\r
                minor=(*queryvars.find("Minor")).second;\r
+               hascriteria=true;\r
        }\r
        if(queryvars.find("Release")!=queryvars.end())\r
        {\r
                release=(*queryvars.find("Release")).second;\r
+               hascriteria=true;\r
        }\r
 \r
-       SQLite3DB::Statement st=m_db->Prepare("SELECT Notes, Changes FROM tblFMSVersion WHERE Major=? AND Minor=? AND Release=?;");\r
-       st.Bind(0,major);\r
-       st.Bind(1,minor);\r
-       st.Bind(2,release);\r
+       sql="SELECT Notes, Changes, Major, Minor, Release FROM tblFMSVersion ";\r
+       if(hascriteria==true)\r
+       {\r
+               sql+="WHERE Major=? AND Minor=? AND Release=? ";\r
+       }\r
+       sql+="ORDER BY Major DESC, Minor DESC, Release DESC;";\r
+       SQLite3DB::Statement st=m_db->Prepare(sql);\r
+       if(hascriteria==true)\r
+       {\r
+               st.Bind(0,major);\r
+               st.Bind(1,minor);\r
+               st.Bind(2,release);\r
+       }\r
        st.Step();\r
 \r
-       if(st.RowReturned())\r
+       while(st.RowReturned())\r
        {\r
                std::string notes="";\r
                std::string changes="";\r
 \r
                st.ResultText(0,notes);\r
                st.ResultText(1,changes);\r
+               st.ResultText(2,major);\r
+               st.ResultText(3,minor);\r
+               st.ResultText(4,release);\r
 \r
+               content+="<div style=\"margin-bottom:20px;\">";\r
                content+="<h2>Release "+major+"."+minor+"."+release+"</h2>";\r
                content+="<h3>Notes</h3>";\r
                content+=StringFunctions::Replace(notes,"\n","<br>");\r
                content+="<h3>Changes</h3>";\r
                content+=StringFunctions::Replace(changes,"\n","<br>");\r
+               content+="</div>";\r
+               st.Step();\r
        }\r
 \r
        return StringFunctions::Replace(m_template,"[CONTENT]",content);\r
 }\r
-\r
-const bool VersionInfoPage::WillHandleURI(const std::string &uri)\r
-{\r
-       if(uri.find("versioninfo.")!=std::string::npos)\r
-       {\r
-               return true;\r
-       }\r
-       else\r
-       {\r
-               return false;\r
-       }\r
-}\r
index 8a3935d..0445e29 100644 (file)
@@ -49,6 +49,63 @@ const bool Message::CheckForAdministrationBoard(const std::vector<std::string> &
        return false;\r
 }\r
 \r
+const bool Message::Create(const long localidentityid, const long boardid, const std::string &subject, const std::string &body, const std::string &references)\r
+{\r
+       Initialize();\r
+\r
+       Poco::UUIDGenerator uuidgen;\r
+       Poco::UUID uuid;\r
+\r
+       // get header info\r
+       // date is always set to now regardless of what message has\r
+       m_datetime=Poco::Timestamp();\r
+\r
+       // messageuuid is always a unique id we generate regardless of message message-id\r
+       try\r
+       {\r
+               uuid=uuidgen.createRandom();\r
+               m_messageuuid=uuid.toString();\r
+               StringFunctions::UpperCase(m_messageuuid,m_messageuuid);\r
+       }\r
+       catch(...)\r
+       {\r
+               m_log->fatal("Message::ParseNNTPMessage could not create UUID");\r
+       }\r
+       \r
+       // get from\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT Name FROM tblLocalIdentity WHERE LocalIdentityID=?;");\r
+       st.Bind(0,localidentityid);\r
+       st.Step();\r
+       if(st.RowReturned())\r
+       {\r
+               st.ResultText(0,m_fromname);\r
+       }\r
+\r
+       // get boards posted to\r
+       std::string boardname="";\r
+       SQLite3DB::Statement boardst=m_db->Prepare("SELECT BoardName FROM tblBoard WHERE BoardID=?;");\r
+       boardst.Bind(0,boardid);\r
+       boardst.Step();\r
+       if(boardst.RowReturned())\r
+       {\r
+               boardst.ResultText(0,boardname);\r
+       }\r
+\r
+       m_boards.push_back(boardname);\r
+       m_replyboardname=boardname;\r
+\r
+       m_subject=subject;\r
+\r
+       m_body=body;\r
+\r
+       if(references!="")\r
+       {\r
+               m_inreplyto[0]=references;\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
 const int Message::FindLocalIdentityID(const std::string &name)\r
 {\r
        SQLite3DB::Statement st=m_db->Prepare("SELECT LocalIdentityID FROM tblLocalIdentity WHERE Name=?;");\r
diff --git a/src/messagethread.cpp b/src/messagethread.cpp
new file mode 100644 (file)
index 0000000..37e3693
--- /dev/null
@@ -0,0 +1,120 @@
+#include "../include/messagethread.h"\r
+#include "../include/stringfunctions.h"\r
+\r
+#include <algorithm>\r
+\r
+#ifdef XMEM\r
+       #include <xmem.h>\r
+#endif\r
+\r
+void MessageThread::AddChildren(const long messageid, const long level, const long boardid)\r
+{\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT tblMessageReplyTo.MessageID, tblMessage1.Subject, tblMessage1.FromName, tblMessage1.MessageDate || ' ' || tblMessage1.MessageTime FROM tblMessage INNER JOIN tblMessageReplyTo ON tblMessage.MessageUUID=tblMessageReplyTo.ReplyToMessageUUID INNER JOIN tblMessage AS 'tblMessage1' ON tblMessageReplyTo.MessageID=tblMessage1.MessageID INNER JOIN tblMessageBoard ON tblMessage1.MessageID=tblMessageBoard.MessageID WHERE tblMessage.MessageID=? AND tblMessageBoard.BoardID=? AND tblMessageReplyTo.ReplyOrder=0 ORDER BY tblMessage1.MessageDate || ' ' || tblMessage1.MessageTime;");\r
+       st.Bind(0,messageid);\r
+       st.Bind(1,boardid);\r
+       st.Step();\r
+       while(st.RowReturned())\r
+       {\r
+               int childid=0;\r
+               std::string subject="";\r
+               std::string fromname="";\r
+               std::string datetime="";\r
+               st.ResultInt(0,childid);\r
+               st.ResultText(1,subject);\r
+               st.ResultText(2,fromname);\r
+               st.ResultText(3,datetime);\r
+               \r
+               threadnode node;\r
+               node.m_messageid=childid;\r
+               node.m_level=level;\r
+               node.m_subject=subject;\r
+               node.m_fromname=fromname;\r
+               node.m_date=datetime;\r
+               m_nodes.push_back(node);\r
+               \r
+               AddChildren(childid,level+1,boardid);\r
+               \r
+               st.Step();\r
+       }       \r
+}\r
+\r
+const MessageThread::threadnode MessageThread::GetOriginalMessageNode(const long messageid, const long boardid)\r
+{\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT tblMessage.MessageID, tblMessage.Subject, tblMessage.FromName, tblMessage.MessageDate || ' ' || tblMessage.MessageTime FROM tblMessageReplyTo INNER JOIN tblMessage ON tblMessageReplyTo.ReplyToMessageUUID=tblMessage.MessageUUID INNER JOIN tblMessageBoard ON tblMessage.MessageID=tblMessageBoard.MessageID WHERE tblMessageReplyTo.ReplyOrder=0 AND tblMessageReplyTo.MessageID=? AND tblMessageBoard.BoardID=?;");\r
+       st.Bind(0,messageid);\r
+       st.Bind(1,boardid);\r
+       st.Step();\r
+       if(st.RowReturned())\r
+       {\r
+               int id=0;\r
+               std::string subject="";\r
+               std::string fromname="";\r
+               std::string datetime="";\r
+               st.ResultInt(0,id);\r
+               st.ResultText(1,subject);\r
+               st.ResultText(2,fromname);\r
+               st.ResultText(3,datetime);\r
+\r
+               threadnode node;\r
+               node.m_messageid=id;\r
+               node.m_level=0;\r
+               node.m_subject=subject;\r
+               node.m_fromname=fromname;\r
+               node.m_date=datetime;\r
+\r
+               return GetOriginalMessageNode(node.m_messageid,boardid);\r
+       }\r
+       else\r
+       {\r
+               threadnode node;\r
+               node.m_messageid=-1;\r
+               node.m_level=0;\r
+               node.m_subject="";\r
+               node.m_fromname="";\r
+               node.m_date="";\r
+\r
+               SQLite3DB::Statement st2=m_db->Prepare("SELECT Subject, FromName, MessageDate || ' ' || MessageTime FROM tblMessage WHERE MessageID=?;");\r
+               st2.Bind(0,messageid);\r
+               st2.Step();\r
+\r
+               if(st2.RowReturned())\r
+               {\r
+                       node.m_messageid=messageid;\r
+                       st2.ResultText(0,node.m_subject);\r
+                       st2.ResultText(1,node.m_fromname);\r
+                       st2.ResultText(2,node.m_date);\r
+               }\r
+\r
+               return node;\r
+       }\r
+}\r
+\r
+const bool MessageThread::Load(const long messageid, const long boardid, const bool bydate)\r
+{\r
+       threadnode originalmessagenode=GetOriginalMessageNode(messageid,boardid);\r
+       \r
+       if(originalmessagenode.m_messageid>=0)\r
+       {\r
+               m_nodes.push_back(originalmessagenode);\r
+               \r
+               AddChildren(originalmessagenode.m_messageid,1,boardid);\r
+\r
+               if(bydate==true)\r
+               {\r
+                       std::sort(m_nodes.begin(),m_nodes.end(),datecompare());\r
+               }\r
+\r
+               return true;\r
+       }\r
+       else\r
+       {\r
+               return false;\r
+       }\r
+}\r
+\r
+const bool MessageThread::Load(const std::string &messageidstr, const long boardid, const bool bydate)\r
+{\r
+       long messageid=0;\r
+       StringFunctions::Convert(messageidstr,messageid);\r
+       return Load(messageid,boardid,bydate);\r
+}\r
index 84d07ff..0212e23 100644 (file)
        #include <xmem.h>\r
 #endif\r
 \r
-NNTPConnection::NNTPConnection(SOCKET sock)\r
+NNTPConnection::NNTPConnection(SOCKET sock):m_socket(sock)\r
 {\r
-       std::string tempval;\r
+       std::string tempval("");\r
 \r
-       m_socket=sock;\r
        m_tempbuffer.resize(32768);\r
        \r
        m_status.m_isposting=false;\r
index 6355ebc..04fa1e1 100644 (file)
@@ -159,7 +159,7 @@ void NNTPListener::StartListen()
                                                        }\r
                                                        else\r
                                                        {\r
-                                                               m_log->error("NNTPListener::StartListen socket listen failed");\r
+                                                               m_log->error("NNTPListener::StartListen socket listen failed on "+sa.toString());\r
                                                                #ifdef _WIN32\r
                                                                closesocket(sock);\r
                                                                #else\r
@@ -169,7 +169,7 @@ void NNTPListener::StartListen()
                                                }\r
                                                else\r
                                                {\r
-                                                       m_log->error("NNTPListener::StartListen socket bind failed");\r
+                                                       m_log->error("NNTPListener::StartListen socket bind failed on "+sa.toString());\r
                                                        #ifdef _WIN32\r
                                                        closesocket(sock);\r
                                                        #else\r
@@ -179,7 +179,7 @@ void NNTPListener::StartListen()
                                        }\r
                                        else\r
                                        {\r
-                                               m_log->error("NNTPListener::StartListen couldn't create socket");\r
+                                               m_log->error("NNTPListener::StartListen couldn't create socket on "+sa.toString());\r
                                        }\r
                                }\r
                                catch(Poco::Exception &e)\r
diff --git a/src/threadbuilder.cpp b/src/threadbuilder.cpp
new file mode 100644 (file)
index 0000000..521cccc
--- /dev/null
@@ -0,0 +1,85 @@
+#include "../include/threadbuilder.h"\r
+#include "../include/messagethread.h"\r
+\r
+const bool ThreadBuilder::Build(const long messageid, const long boardid, const bool bydate)\r
+{\r
+       int count=0;\r
+       int threadid=-1;\r
+       MessageThread mt;\r
+       std::vector<MessageThread::threadnode> m_threadmessages;\r
+\r
+       mt.Load(messageid,boardid,bydate);\r
+       m_threadmessages=mt.GetNodes();\r
+\r
+       // find threadid of this thread if it already exists in a thread\r
+       SQLite3DB::Statement st=m_db->Prepare("SELECT tblThread.ThreadID FROM tblThread INNER JOIN tblThreadPost ON tblThread.ThreadID=tblThreadPost.ThreadID WHERE tblThread.BoardID=? AND tblThreadPost.MessageID=?;");\r
+       st.Bind(0,boardid);\r
+       st.Bind(1,messageid);\r
+\r
+       st.Step();\r
+       if(st.RowReturned())\r
+       {\r
+               st.ResultInt(0,threadid);\r
+       }\r
+       else\r
+       {\r
+               st.Reset();\r
+               // message doesn't exist in a thread, try to find a message in the thread that is already in a thread\r
+               for(std::vector<MessageThread::threadnode>::const_iterator i=m_threadmessages.begin(); i!=m_threadmessages.end() && threadid==-1; i++)\r
+               {\r
+                       st.Bind(0,boardid);\r
+                       st.Bind(1,(*i).m_messageid);\r
+                       st.Step();\r
+\r
+                       if(st.RowReturned())\r
+                       {\r
+                               st.ResultInt(0,threadid);\r
+                       }\r
+\r
+                       st.Reset();\r
+\r
+               }\r
+\r
+               // thread doesn't exist - create it\r
+               if(threadid==-1)\r
+               {\r
+                       st=m_db->Prepare("INSERT INTO tblThread(BoardID) VALUES(?);");\r
+                       st.Bind(0,boardid);\r
+                       st.Step(true);\r
+                       threadid=st.GetLastInsertRowID();\r
+               }\r
+       }\r
+\r
+       if(m_threadmessages.size()>0)\r
+       {\r
+               st=m_db->Prepare("UPDATE tblThread SET FirstMessageID=?, LastMessageID=? WHERE ThreadID=?;");\r
+               st.Bind(0,m_threadmessages[0].m_messageid);\r
+               st.Bind(1,m_threadmessages[m_threadmessages.size()-1].m_messageid);\r
+               st.Bind(2,threadid);\r
+               st.Step();\r
+\r
+               st=m_db->Prepare("DELETE FROM tblThreadPost WHERE ThreadID=?;");\r
+               st.Bind(0,threadid);\r
+               st.Step();\r
+\r
+               count=0;\r
+               st=m_db->Prepare("INSERT INTO tblThreadPost(ThreadID,MessageID,PostOrder) VALUES(?,?,?);");\r
+               for(std::vector<MessageThread::threadnode>::const_iterator i=m_threadmessages.begin(); i!=m_threadmessages.end(); i++, count++)\r
+               {\r
+                       st.Bind(0,threadid);\r
+                       st.Bind(1,(*i).m_messageid);\r
+                       st.Bind(2,count);\r
+                       st.Step();\r
+                       st.Reset();\r
+               }\r
+       }\r
+       else\r
+       {\r
+               st=m_db->Prepare("DELETE FROM tblThread WHERE ThreadID=?;");\r
+               st.Bind(0,threadid);\r
+               st.Step();\r
+       }\r
+\r
+       return true;\r
+\r
+}\r
index 7509afd..248c006 100644 (file)
@@ -1,7 +1,7 @@
 <html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">\r
 <head>\r
-<title>FMS : Freenet Message System</title>\r
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\r
+<title>FMS : Freenet Message System</title>\r
 <style type="text/css">\r
 body {\r
        background-color: #FFF;\r
@@ -212,6 +212,41 @@ td         { padding-left:5px; padding-right:5px; }
 .small70       {\r
                                font-size:70%;\r
                        }\r
+                       \r
+.post                  {\r
+                                       margin-bottom:2em;\r
+                               }\r
+                               \r
+.post .postsubject     {\r
+                                               font-size:1.2em;\r
+                                               font-style:bolder;\r
+                                       }\r
+                                       \r
+.post .postboards      {\r
+                                               font-size:1.2em;\r
+                                               font-style:bolder;\r
+                                       }\r
+                               \r
+.post .postbody        {\r
+                                       font-size:0.8em;\r
+                                       white-space:pre;\r
+                               }\r
+                               \r
+.post .postfrom        {\r
+                                       font-size:1.2em;\r
+                                       font-style:bolder;\r
+                               }\r
+                               \r
+.post .postdate        {\r
+                                       font-size:1.2em;\r
+                                       font-style:bolder;\r
+                               }\r
+\r
+ul.messagethread       {\r
+                                               list-style:none;\r
+                                               margin-left:8px;\r
+                                               font-size:9pt;\r
+                                       }\r
 \r
 </style>\r
 </head>\r
@@ -236,9 +271,10 @@ td         { padding-left:5px; padding-right:5px; }
                        <li><a href="addpeer.htm">Add Peer</a></li>\r
                        <li><a href="peermaintenance.htm">Peer Maintenance</a></li>\r
                        <li><a href="peertrust.htm">Peer Trust</a></li>\r
-                       <li><a href="boards.htm">Boards</a></li>\r
+                       <li><a href="boards.htm">Board Maintenance</a></li>\r
                        <li><a href="controlboard.htm">Control Boards</a></li>\r
                        <li><a href="insertedfiles.htm">Inserted Files</a></li>\r
+                       <li><a href="forummain.htm">Browse Forums</a></li>\r
                </ul>\r
                </div>\r
        \r