\r
#include <Poco/Util/ServerApplication.h>\r
\r
+#include <map>\r
+\r
// main FMS application class\r
class FMSApp:public Poco::Util::ServerApplication\r
{\r
void handleHelp(const std::string &name, const std::string &value);\r
void displayHelp();\r
void handleLogOption(const std::string &name, const std::string &value);\r
+ void handleShowOptions(const std::string &name, const std::string &value);\r
+ void showOptions();\r
+ void handleSetOption(const std::string &name, const std::string &value);\r
+ void setOptions();\r
\r
bool m_displayhelp;\r
+ bool m_showoptions;\r
+ bool m_setoption;\r
+ std::map<std::string,std::string> m_setoptions;\r
std::string m_logtype;\r
\r
ThreadedExecutor m_threads;\r
\r
#define VERSION_MAJOR "0"\r
#define VERSION_MINOR "3"\r
-#define VERSION_RELEASE "3"\r
+#define VERSION_RELEASE "4"\r
#define FMS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_RELEASE\r
\r
typedef Poco::ScopedLock<Poco::FastMutex> Guard;\r
want. You will need to manually start the service unless you change the\r
startup type in the service properties.\r
\r
+If you are experiencing a problem with FMS that you can't solve, and you've\r
+already rebooted your machine, restarted FMS, and have reproduced the problem\r
+with a brand new database, follow these instructions. Set the logging option\r
+to trace and restart FMS. Create a post on the fms group that contains the\r
+operating system you are using, along with a description of the problem, what\r
+you have tried already, if you are using a precompiled binary, the startup\r
+lines from the log file as well as the portion that corresponds to the problem\r
+you are experiencing, and any other information you have that pertains to the\r
+problem. Make sure to anonymize any IP addresses, host names, subnet masks,\r
+and keys from the log that you don't want people to know about.\r
+\r
EXITING\r
-------\r
To exit FMS running in console mode, press CTRL+C while at the console. You\r
char *outptr=&outvec[0];\r
size_t insize=invec.size();\r
size_t outsize=outvec.size();\r
+\r
size_t rval=0;\r
\r
rval=iconv(m_iconv,&inptr,&insize,&outptr,&outsize);\r
#include "../include/dbmaintenancethread.h"\r
#include "../include/freenet/freenetmasterthread.h"\r
#include "../include/threadwrapper/threadedexecutor.h"\r
+#include "../include/db/sqlite3db.h"\r
\r
#include <Poco/Util/HelpFormatter.h>\r
#include <Poco/FileChannel.h>\r
#include <unistd.h>\r
#endif\r
\r
-//debug\r
-#include <Poco/ScopedLock.h>\r
-#include <Poco/Runnable.h>\r
-#include <Poco/Thread.h>\r
-#include <Poco/ThreadPool.h>\r
-#include "../include/threadwrapper/cancelablerunnable.h"\r
-#include "../include/threadwrapper/cancelablethread.h"\r
-\r
-Poco::FastMutex m1;\r
-class TestRunner:public CancelableRunnable\r
-{\r
-public:\r
- void run()\r
- {\r
- do\r
- {\r
-\r
- }while(!IsCancelled());\r
- }\r
-};\r
-\r
-FMSApp::FMSApp():m_displayhelp(false),m_logtype("file")\r
+FMSApp::FMSApp():m_displayhelp(false),m_showoptions(false),m_setoption(false),m_logtype("file")\r
{\r
\r
}\r
ServerApplication::defineOptions(options);\r
\r
// add command line options here\r
- options.addOption(Poco::Util::Option("help","?","display help for command line arguments",false).repeatable(false).callback(Poco::Util::OptionCallback<FMSApp>(this,&FMSApp::handleHelp)));\r
- options.addOption(Poco::Util::Option("log","l","select type of log output (file|stdout|stderr)",false,"type",true).repeatable(false).callback(Poco::Util::OptionCallback<FMSApp>(this,&FMSApp::handleLogOption)));\r
+ options.addOption(Poco::Util::Option("help","?","Display help for command line arguments.",false).repeatable(false).callback(Poco::Util::OptionCallback<FMSApp>(this,&FMSApp::handleHelp)));\r
+ options.addOption(Poco::Util::Option("log","l","Select type of log output (file|stdout|stderr).",false,"type",true).repeatable(false).callback(Poco::Util::OptionCallback<FMSApp>(this,&FMSApp::handleLogOption)));\r
+ options.addOption(Poco::Util::Option("showoptions","","Show all options that can be set and their current values.",false).repeatable(false).callback(Poco::Util::OptionCallback<FMSApp>(this,&FMSApp::handleShowOptions)));\r
+ options.addOption(Poco::Util::Option("setoption","","Set an option. Values are not validated, so be sure to set them correctly.",false,"option=value",true).repeatable(true).callback(Poco::Util::OptionCallback<FMSApp>(this,&FMSApp::handleSetOption)));\r
}\r
\r
void FMSApp::displayHelp()\r
}\r
}\r
\r
+void FMSApp::handleSetOption(const std::string &name, const std::string &value)\r
+{\r
+ std::vector<std::string> valueparts;\r
+ StringFunctions::Split(value,"=",valueparts);\r
+\r
+ if(valueparts.size()==2)\r
+ {\r
+ m_setoptions[valueparts[0]]=valueparts[1];\r
+ }\r
+ else\r
+ {\r
+ std::cout << "Expected option=value but found " << value << std::endl;\r
+ }\r
+\r
+ m_setoption=true;\r
+}\r
+\r
+void FMSApp::handleShowOptions(const std::string &name, const std::string &value)\r
+{\r
+ m_showoptions=true;\r
+}\r
+\r
void FMSApp::initialize(Poco::Util::Application &self)\r
{\r
ServerApplication::initialize(self);\r
}\r
}\r
\r
- setLogger(Poco::Logger::create("logfile",formatter,initiallevel));\r
+ setLogger(Poco::Logger::create("logfile",formatter,Poco::Message::PRIO_INFORMATION));\r
+ Poco::Logger::get("logfile").information("LogLevel set to "+tempval);\r
+ Poco::Logger::get("logfile").setLevel(initiallevel);\r
}\r
\r
int FMSApp::main(const std::vector<std::string> &args)\r
// set working directory to program directory\r
int rval=chdir(config().getString("application.dir").c_str());\r
\r
- if(m_displayhelp==false)\r
+ if(m_displayhelp)\r
+ {\r
+ }\r
+ else if(m_showoptions)\r
+ {\r
+ showOptions();\r
+ }\r
+ else if(m_setoption)\r
+ {\r
+ setOptions();\r
+ }\r
+ else\r
{\r
logger().information("FMS startup v"FMS_VERSION);\r
\r
\r
waitForTerminationRequest();\r
\r
+ logger().trace("FMSApp::main cancelling threads");\r
m_threads.Cancel();\r
+ logger().trace("FMSApp::main joining threads");\r
m_threads.Join();\r
\r
logger().information("FMS shutdown");\r
return FMSApp::EXIT_OK;\r
}\r
\r
+void FMSApp::setOptions()\r
+{\r
+ for(std::map<std::string,std::string>::iterator i=m_setoptions.begin(); i!=m_setoptions.end(); i++)\r
+ {\r
+ std::string tempval="";\r
+ if(Option::Instance()->Get((*i).first,tempval))\r
+ {\r
+ Option::Instance()->Set((*i).first,(*i).second);\r
+ std::cout << "Option " << (*i).first << " set to " << (*i).second << std::endl;\r
+ }\r
+ else\r
+ {\r
+ std::cout << "Unknown option " << (*i).first << std::endl;\r
+ }\r
+ }\r
+}\r
+\r
+void FMSApp::showOptions()\r
+{\r
+ SQLite3DB::Statement st=SQLite3DB::DB::Instance()->Prepare("SELECT Option, OptionValue FROM tblOption;");\r
+ st.Step();\r
+ while(st.RowReturned())\r
+ {\r
+ std::string option="";\r
+ std::string optionvalue="";\r
+ st.ResultText(0,option);\r
+ st.ResultText(1,optionvalue);\r
+\r
+ std::cout << option << " = " << optionvalue << std::endl;\r
+\r
+ st.Step();\r
+ }\r
+}\r
+\r
void FMSApp::StartThreads()\r
{\r
std::string tempval="";\r
\r
// always start the DB maintenance thread\r
+ logger().trace("FMSApp::StartThreads starting DBMaintenanceThread");\r
m_threads.Start(new DBMaintenanceThread());\r
\r
Option::Instance()->Get("StartHTTP",tempval);\r
if(tempval=="true")\r
{\r
+ logger().trace("FMSApp::StartThreads starting HTTPThread");\r
m_threads.Start(new HTTPThread());\r
}\r
\r
Option::Instance()->Get("StartNNTP",tempval);\r
if(tempval=="true")\r
{\r
+ logger().trace("FMSApp::StartThreads starting NNTPListener");\r
m_threads.Start(new NNTPListener());\r
}\r
\r
Option::Instance()->Get("StartFreenetUpdater",tempval);\r
if(tempval=="true")\r
{\r
+ logger().trace("FMSApp::StartThreads starting FreenetMasterThread");\r
m_threads.Start(new FreenetMasterThread());\r
}\r
\r
std::string portstr;\r
Option::Instance()->Get("HTTPListenPort",portstr);\r
StringFunctions::Convert(portstr,m_listenport);\r
-\r
- // push back page handlers\r
- /*\r
- m_pagehandlers.push_back(new ShowCaptchaPage());\r
- m_pagehandlers.push_back(new OptionsPage(templatestr));\r
- m_pagehandlers.push_back(new LocalIdentitiesPage(templatestr));\r
- m_pagehandlers.push_back(new CreateIdentityPage(templatestr));\r
- m_pagehandlers.push_back(new AnnounceIdentityPage(templatestr));\r
- m_pagehandlers.push_back(new AddPeerPage(templatestr));\r
- m_pagehandlers.push_back(new PeerTrustPage(templatestr));\r
- m_pagehandlers.push_back(new ControlBoardPage(templatestr));\r
- m_pagehandlers.push_back(new PeerDetailsPage(templatestr));\r
- m_pagehandlers.push_back(new PeerMaintenancePage(templatestr));\r
- m_pagehandlers.push_back(new ExecQueryPage(templatestr));\r
- m_pagehandlers.push_back(new BoardsPage(templatestr));\r
- m_pagehandlers.push_back(new InsertedFilesPage(templatestr));\r
- m_pagehandlers.push_back(new ConfirmPage(templatestr));\r
- // homepage must be last - catch all page handler\r
- m_pagehandlers.push_back(new HomePage(templatestr));\r
- */\r
- \r
}\r
\r
-/*\r
-void HTTPThread::PageCallback(shttpd_arg *arg)\r
-{\r
-\r
- HTTPThread *thread=(HTTPThread *)arg->user_data;\r
-\r
- for(std::vector<IPageHandler *>::iterator i=thread->m_pagehandlers.begin(); i!=thread->m_pagehandlers.end(); )\r
- {\r
- if((*i)->Handle(arg)==true)\r
- {\r
- i=thread->m_pagehandlers.end();\r
- }\r
- else\r
- {\r
- i++;\r
- }\r
- }\r
-\r
-}\r
-*/\r
void HTTPThread::run()\r
{\r
m_log->debug("HTTPThread::run thread started.");\r
m_log->trace("Trying to stop HTTPServer");\r
srv.stop();\r
m_log->trace("Stopped HTTPServer");\r
+ \r
+ m_log->trace("Waiting for current HTTP requests to finish");\r
+ while(srv.currentConnections()>0)\r
+ {\r
+ Poco::Thread::sleep(500);\r
+ }\r
\r
m_log->debug("HTTPThread::run thread exiting.");\r
\r
vars[(*i).first]=(*i).second;\r
}\r
\r
+ // for a POST method, the HTMLForm won't grab vars off the query string so we\r
+ // temporarily set the method to GET and parse with the HTMLForm again\r
+ if(request.getMethod()=="POST")\r
+ {\r
+ request.setMethod("GET");\r
+ Poco::Net::HTMLForm form1(request,request.stream(),mpp);\r
+ for(Poco::Net::HTMLForm::ConstIterator i=form1.begin(); i!=form1.end(); i++)\r
+ {\r
+ vars[(*i).first]=(*i).second;\r
+ }\r
+ request.setMethod("POST");\r
+ }\r
+\r
// get any multiparts\r
std::map<std::string,std::string> mpvars=mpp.GetVars();\r
for(std::map<std::string,std::string>::iterator i=mpvars.begin(); i!=mpvars.end(); i++)\r
content+="</b><br>";\r
\r
bool showgenericupdate=true;\r
- SQLite3DB::Statement st=m_db->Prepare("SELECT Major, Minor, Release, PageKey FROM tblFMSVersion ORDER BY Major DESC, Minor DESC, Release DESC;");\r
+ SQLite3DB::Statement st=m_db->Prepare("SELECT Major, Minor, Release, PageKey FROM tblFMSVersion ORDER BY Major DESC, Minor DESC, Release DESC LIMIT 1;");\r
st.Step();\r
if(st.RowReturned())\r
{\r
\r
if(showgenericupdate)\r
{\r
- content+="Check for new versions at the <a href=\"http://"+fcphost+":"+fproxyport+"/USK@0npnMrqZNKRCRoGojZV93UNHCMN-6UU3rRSAmP6jNLE,~BG-edFtdCC1cSH4O3BWdeIYa8Sw5DfyrSV-TKdO5ec,AQACAAE/fms/60/\">FMS Freesite</a><br>";\r
+ content+="Check for new versions at the <a href=\"http://"+fcphost+":"+fproxyport+"/USK@0npnMrqZNKRCRoGojZV93UNHCMN-6UU3rRSAmP6jNLE,~BG-edFtdCC1cSH4O3BWdeIYa8Sw5DfyrSV-TKdO5ec,AQACAAE/fms/63/\">FMS Freesite</a><br>";\r
}\r
\r
content+="Use these pages to administer your FMS installation.";\r
#include "../../include/global.h"\r
#include "../../include/stringfunctions.h"\r
\r
+#include <Poco/Net/SocketAddress.h>\r
+\r
#include <cstring>\r
\r
#ifdef _WIN32\r
{\r
for(current=result; current!=NULL; current=current->ai_next)\r
{\r
+ Poco::Net::SocketAddress sa(current->ai_addr,current->ai_addrlen);\r
+ m_log->debug("NNTPListener::StartListen trying to create socket, bind, and listen on "+sa.toString());\r
+\r
sock=socket(current->ai_family,current->ai_socktype,current->ai_protocol);\r
if(sock!=INVALID_SOCKET)\r
{\r
#ifndef _WIN32\r
const char optval='1';\r
- setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&optval,1);\r
+ setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval));\r
#endif\r
if(bind(sock,current->ai_addr,current->ai_addrlen)==0)\r
{\r
if(listen(sock,10)==0)\r
{\r
- m_log->information("NNTPListener::StartListen started listening at "+(*i)+":"+nntpport);\r
+ m_log->information("NNTPListener::StartListen started listening on "+sa.toString());\r
m_listensockets.push_back(sock);\r
}\r
else\r
upd.Reset();\r
\r
st.Bind(0,"FMSVersionEdition");\r
- st.Bind(1,"0");\r
+ st.Bind(1,"3");\r
st.Step();\r
upd.Bind(0,"Program");\r
upd.Bind(1,order++);\r