diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..c19f4fc --- /dev/null +++ b/Makefile @@ -0,0 +1,46 @@ +CC = g++ +o = templates.o log.o requestcontroller.o main.o misc.o db.o session.o request.o content.o sessionmanager.o httpsimpleparser.o data.o dir.o error.o done.o dircontainer.o ezc.o +CFLAGS = -Wall -pedantic -g -I/usr/local/include -L/usr/local/lib +name = cmslu.fcgi + + +all: $(name) $(mod_cms) + +$(name): $(o) + g++ -o $(name) $(CFLAGS) $(o) -lfcgi -lpq + + + + +.SUFFIXES: .cpp .o + +.cpp.o: + $(CC) -c $(CFLAGS) $< + + + +templates.o: core/templates.cpp core/templates.h core/../../ezc/src/ezc.h core/data.h core/misc.h core/log.h core/item.h core/error.h core/dir.h core/db.h core/dircontainer.h core/request.h core/requesttypes.h core/session.h core/done.h core/getparser.h core/httpsimpleparser.h core/postparser.h core/cookieparser.h +log.o: core/log.cpp core/log.h +requestcontroller.o: core/requestcontroller.cpp core/requestcontroller.h core/data.h core/misc.h core/log.h core/item.h core/error.h core/dir.h core/db.h core/dircontainer.h core/request.h core/requesttypes.h core/session.h core/done.h core/getparser.h core/httpsimpleparser.h core/postparser.h core/cookieparser.h core/content.h core/templates.h core/../../ezc/src/ezc.h core/sessionmanager.h +main.o: core/main.cpp core/requestcontroller.h core/data.h core/misc.h core/log.h core/item.h core/error.h core/dir.h core/db.h core/dircontainer.h core/request.h core/requesttypes.h core/session.h core/done.h core/getparser.h core/httpsimpleparser.h core/postparser.h core/cookieparser.h core/content.h core/templates.h core/../../ezc/src/ezc.h core/sessionmanager.h +misc.o: core/misc.cpp core/misc.h core/log.h core/item.h +db.o: core/db.cpp core/db.h core/log.h core/item.h core/misc.h core/error.h core/dircontainer.h +session.o: core/session.cpp core/session.h core/requesttypes.h core/error.h core/log.h core/item.h core/done.h +request.o: core/request.cpp core/request.h core/requesttypes.h core/log.h core/session.h core/error.h core/item.h core/done.h core/getparser.h core/httpsimpleparser.h core/postparser.h core/cookieparser.h +content.o: core/content.cpp core/content.h core/templates.h core/../../ezc/src/ezc.h core/data.h core/misc.h core/log.h core/item.h core/error.h core/dir.h core/db.h core/dircontainer.h core/request.h core/requesttypes.h core/session.h core/done.h core/getparser.h core/httpsimpleparser.h core/postparser.h core/cookieparser.h +sessionmanager.o: core/sessionmanager.cpp core/sessionmanager.h core/request.h core/requesttypes.h core/log.h core/session.h core/error.h core/item.h core/done.h core/getparser.h core/httpsimpleparser.h core/postparser.h core/cookieparser.h core/data.h core/misc.h core/dir.h core/db.h core/dircontainer.h +httpsimpleparser.o: core/httpsimpleparser.cpp core/httpsimpleparser.h +data.o: core/data.cpp core/data.h core/misc.h core/log.h core/item.h core/error.h core/dir.h core/db.h core/dircontainer.h +dir.o: core/dir.cpp core/dir.h core/item.h core/error.h core/log.h core/db.h core/misc.h core/dircontainer.h +error.o: core/error.cpp core/error.h core/log.h +done.o: core/done.cpp core/done.h +dircontainer.o: core/dircontainer.cpp core/dircontainer.h core/item.h core/log.h + +ezc.o: ../ezc/src/ezc.cpp ../ezc/src/ezc.h + + + +clean: + rm -f *.o + rm -f $(name) + diff --git a/core/content.cpp b/core/content.cpp new file mode 100755 index 0000000..0a76360 --- /dev/null +++ b/core/content.cpp @@ -0,0 +1,477 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include "content.h" + + + + +bool Content::Init() +{ + templates.Read(); + + +return true; +} + + + + + +void Content::AddItem() +{ + if( !request.session->is_logged ) + return; + + try + { + request.session->done = Done::added_item; + +// request.item_table.resize(1); +// Item & item = request.item_table[0]; + + request.item.subject = request.PostVar("subject"); + request.item.content = request.PostVar("content"); + request.item.parent_id = data.dir.GetDirId( request.PostVar("directory") ); + request.item.type = Item::file; + PrepareUrlSubject(request.item); + + request.session->done_status = db.AddItem(request.item); + request.session->done_timer = 1; + + // if( request.session->done_status != Request::added_item ) + //request.item_table.resize(1); + //request.item_table[0] = request.item; + } + catch(const Error & e) + { + request.session->done_status = e; + } +} + + + +void Content::EditItem() +{ + if( !request.session->is_logged ) + return; + + try + { + request.session->done = Done::edited_item; + +// request.item_table.resize(1); +// Item & item = request.item_table[0]; + + request.item.subject = request.PostVar("subject"); + request.item.content = request.PostVar("content"); + request.item.id = atol( request.PostVar("id").c_str() ); + + bool with_subject = false; + + if( request.PostVar("old_subject") != request.item.subject ) + with_subject = true; + + request.item.parent_id = data.dir.GetDirId( request.PostVar("directory") ); + request.item.type = Item::file; + PrepareUrlSubject(request.item); + + request.session->done_status = db.EditItem(request.item, with_subject); + request.session->done_timer = 1; + } + catch(const Error & e) + { + request.session->done_status = e; + } +} + + +void Content::LogUser() +{ + try + { + std::string & login = request.PostVar("login"); + std::string & pass = request.PostVar("password"); + long user_id; + + if( db.CheckUser(login, pass, user_id) ) + { + request.session->is_logged = true; + request.session->user_id = user_id; + request.session->user = login; + + log << log2 << "User " << login << " (id: " << user_id << ") logged" << logend; + } + } + catch(const Error &) + { + } +} + + + +void Content::MakeDirectoryStructure() +{ + GetTable::size_type get_table_len = request.get_table.size(); + long parent = -1; + + for( get_index = 0 ; get_index < get_table_len ; ++get_index) + { + Item * pdir; + + if( !data.dir.GetDir(request.get_table[get_index], parent, &pdir) ) + break; + + parent = pdir->id; + request.cur_dir_table.push_back( *pdir ); + } + + // parent - last directory (or -1 if none) + request.dir = parent; + data.dir.GetDirChilds(parent, request.dir_table); +} + + + + +Request::Result Content::StandardFunction(std::string & name) +{ +Request::Result res = Request::err404; + + // language polish + // in the future there'll be something here + // names of functions should not begin with an underscore '_' + + if( name == "dodaj" ) + res = Request::add_item; + else + if( name == "edytuj" ) + res = Request::edit_item; + else + if( name == "id" ) + res = Request::show_item_by_id; + else + if( name == "usun" ) + res = Request::del_item; + else + if( name == "potwierdz" ) + res = Request::confirm; + else + if( name == "wyloguj" ) + res = Request::logout; + +return res; +} + + + +void Content::PrepareUrlSubject(Item & item) +{ + SetUrlSubjectFromSubject(item); + + if( StandardFunction(item.url_subject) != Request::err404 ) + { + // names of functions should not begin with an underscore '_' + // and we can simply add one '_' at the beginning + // and the name will be unique + item.url_subject.insert(item.url_subject.begin(), '_'); + } +} + + +bool Content::MakeGetCheckDir() +{ + if( get_index == request.get_table.size() ) + { + // request was for a directory + db.GetItems(request.item_table, item); + + + + // !! temporarily + long default_id = -1; + if( request.cur_dir_table.empty() ) + { + default_id = data.dir.root.default_item; + } + else + { + default_id = request.cur_dir_table.back().default_item; + } + + + if( default_id != -1 ) + { + request.result = Request::show_item; + + std::vector::iterator i; + for(i = request.item_table.begin() ; i != request.item_table.end() ; ++i) + { + if( i->id == default_id ) + request.item_table[0] = *i; + } + + request.item_table.resize(1); + } + else + + if( data.one_item_is_showed && + request.item_table.size() == 1 && + request.item_table[0].type == Item::file ) + { + request.result = Request::show_item; + } + else + { + request.result = Request::show_dir; + } + + return true; + } + + +return false; +} + + + +// zrobic tak ze gdzie podajemy cala liste aby nie ladowac contentu z bazy danych do itemow +void Content::MakeGet() +{ + MakeDirectoryStructure(); + + item.Clear(); + + // request.dir is set by MakeDirectoryStructure() + item.parent_id = request.dir; + + if( MakeGetCheckDir() ) + return; + + // request was for an item or a standard function + request.result = StandardFunction( request.get_table[get_index] ); + + if( request.result != Request::err404 ) + { + // request for a standard function + ++get_index; + return; + } + + if( request.get_table[get_index].empty() ) + // we do not have an empty url_subject + // err404 at the end + return; + + // if we want to search by url_subject then request.get_table[get_index] should not be empty + item.url_subject = request.get_table[get_index++]; + db.GetItems(request.item_table, item); + + if( request.item_table.empty() ) + // err404 at the end + return; + + if( get_index == request.get_table.size() ) + { + request.result = Request::show_item; + return; + } + + // there is a standard function at the end + request.result = StandardFunction( request.get_table[get_index++] ); +} + + +void Content::MakeEditItem() +{ + if( !request.item_table.empty() ) + request.item = request.item_table[0]; + else + { + log << log1 << "Content: request.item_table should not be empty" << logend; + request.result = Request::err404; + } +} + + +void Content::AppendCurDir(std::string & dir) +{ + std::vector::size_type a; + + for(a=0 ; ais_logged ) + return; + + + if( request.item_table.empty() ) + { + request.result = Request::err404; + return; + } + + if( get_index == request.get_table.size() ) + { + request.CopyFirstItem(); + request.session->item = request.item; + + if( db.DelItem( request.item.id ) ) + { + request.session->done = Done::deleted_item; + request.session->done_status = Error::ok; + log << log2 << "Content: deleted item: subject: " << request.item.subject << ", id: " << request.item.id << logend; + } + else + { + request.session->done = Done::deleted_item; + request.session->done_status = Error::db_no_item; + } + + request.result = Request::redirect; + request.str = data.base_url; + AppendCurDir(request.str); + request.session->done_timer = 2; + } + else + { + if( StandardFunction( request.get_table[get_index++] ) == Request::confirm ) + { + request.result = Request::del_item_confirm; + request.CopyFirstItem(); + } + else + request.result = Request::err404; + } +} + + +void Content::MakeLogout() +{ + if( request.session->is_logged ) + { + log << log2 << "User " << request.session->user << " (id: " << request.session->user_id << ") logged out" << logend; + + request.session->is_logged = false; + request.session->user.clear(); + request.session->user_id = 0; + } + + request.result = Request::redirect; + std::string path; + data.dir.MakePath(request.dir, path); + request.str = data.base_url + path; + + if( !request.item_table.empty() ) + request.str += request.item_table[0].url_subject; + + request.session->done = Done::loggedout; + request.session->done_timer = 2; +} + + + +void Content::MakeStandardFunction() +{ + if( request.result == Request::edit_item ) + { + MakeEditItem(); + } + else + if( request.result == Request::show_item_by_id ) + { + MakeShowItemById(); + } + else + if( request.result == Request::del_item ) + { + MakeDelItem(); + } + else + if( request.result == Request::logout ) + { + MakeLogout(); + } + + +} + + + +void Content::MakePost() +{ + if( request.IsPostVar("add_item") ) + AddItem(); + else + if( request.IsPostVar("edit_item") ) + EditItem(); + else + if( request.IsPostVar("logging") ) + LogUser(); + + +} + + +void Content::Make() +{ + MakePost(); + MakeGet(); + MakeStandardFunction(); + + templates.Generate(); + + // request.PrintGetTable(); + //request.PrintEnv(); + // request.PrintIn(); +} + + + + + + + + + + + diff --git a/core/content.h b/core/content.h new file mode 100755 index 0000000..da5c840 --- /dev/null +++ b/core/content.h @@ -0,0 +1,73 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfilecontent +#define headerfilecontent + +#include +#include + +#include "templates.h" +#include "request.h" +#include "error.h" +#include "misc.h" +#include "db.h" + + + + + +class Content +{ + // index to request.get_table + // set after calling MakeDirectoryStructure() + // index of the last item which is not a directory (or is equal get_table.size()) + GetTable::size_type get_index; + + + // temporarily object used for some purposes + Item item; + + + Templates templates; + + + + void AddItem(); + void EditItem(); + void LogUser(); + + void MakeDirectoryStructure(); + Request::Result StandardFunction(std::string & name); + void PrepareUrlSubject(Item & item); + bool MakeGetCheckDir(); + + void MakeEditItem(); + void MakeShowItemById(); + void MakeDelItem(); + void MakeLogout(); + void MakeStandardFunction(); + + + void AppendCurDir(std::string & dir); + + void MakePost(); + void MakeGet(); + +public: + + bool Init(); + + void Make(); + + +}; + + +#endif diff --git a/core/cookieparser.h b/core/cookieparser.h new file mode 100755 index 0000000..4f85ecc --- /dev/null +++ b/core/cookieparser.h @@ -0,0 +1,70 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfilecookieparser +#define headerfilecookieparser + +#include +#include "httpsimpleparser.h" +#include "requesttypes.h" + + + + +class CookieParser : public HttpSimpleParser +{ + + const char * cookie_string; + CookieTable & cookie_table; + + +protected: + + + virtual int GetChar() + { + if( !cookie_string || *cookie_string == 0 ) + return -1; + + return (int)(unsigned char)*(cookie_string++); + } + + + virtual void Parameter(std::string & name, std::string & value) + { + // Cookie names are case insensitive according to section 3.1 of RFC 2965 + ToLower(name); + + std::pair res = cookie_table.insert( std::make_pair(name, value) ); + + log << log2 << "Cookie, name: \"" << name << "\", value: \"" << value << "\""; + + if( res.second == false ) + log << log2 << " (skipped)"; + + log << log2 << logend; + } + + +public: + + + CookieParser(const char * cookie_string_, CookieTable & cookie_table_) : cookie_string(cookie_string_), cookie_table(cookie_table_) + { + HttpSimpleParser::separator = ';'; + HttpSimpleParser::value_can_be_quoted = true; + HttpSimpleParser::skip_white_chars = true; + HttpSimpleParser::recognize_special_chars = false; + } + +}; + + + +#endif diff --git a/core/data.cpp b/core/data.cpp new file mode 100755 index 0000000..c93ddec --- /dev/null +++ b/core/data.cpp @@ -0,0 +1,46 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include "data.h" + + + +Data::Data() +{ + // all these data will be reading from a config file + + log_file = "cmslu.log"; + fcgi_socket = "/var/cmslu/s1"; + fcgi_socket_chmod = 0770; + fcgi_socket_user = "tomek"; + fcgi_socket_group = "www"; + + log_level = 2; + log_stdout = true; + + templates = "../httpd/templates"; // templates dir + default_index = "index.html"; + http_session_id_name = "slimaczek_sid"; + db_database = "tomek"; + db_user = "tomek"; + db_pass = "monitorekasd"; + + // !! add a method which will be adding a slash at the end of url-es + base_url = "http://s10.slimaczek.pl/"; // with a slash at the end + + one_item_is_showed = true; + + dir.root.default_item = 134; +} + + + + + + diff --git a/core/data.h b/core/data.h new file mode 100755 index 0000000..fad1ffa --- /dev/null +++ b/core/data.h @@ -0,0 +1,88 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfiledata +#define headerfiledata + +#include +#include +#include + +#include "misc.h" +#include "item.h" +#include "error.h" +#include "dir.h" + + + +class Data +{ + + +public: + + + + // log file name + std::string log_file; + + // 1 - minimum + // 2 - (default) + // 3 - maximum - all logs + int log_level; + + // logging to stdout too + bool log_stdout; + + + // fast cgi: socket (unix domain) + std::string fcgi_socket; + + // fast cgi: socket permissions + int fcgi_socket_chmod; + + // fast cgi: owner of the socket + std::string fcgi_socket_user; + + // fast cgi: group of the socket + std::string fcgi_socket_group; + + std::string templates; + std::string default_index; + + std::string db_database; + std::string db_user; + std::string db_pass; + std::string base_url; + std::string http_session_id_name; + + + + + Dir dir; + + + // if there is one item in a directory + // it will be showed + // (instead of showing directory contents) + bool one_item_is_showed; + + + + Data(); + +}; + + + + +extern Data data; + + +#endif diff --git a/core/db.cpp b/core/db.cpp new file mode 100755 index 0000000..ec4c0e8 --- /dev/null +++ b/core/db.cpp @@ -0,0 +1,668 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include "db.h" + + +Db::Db() +{ + pg_conn = 0; +} + + +Db::~Db() +{ + Close(); +} + + + +void Db::Init(const std::string & d, const std::string & u, const std::string & p) +{ + db_database = d; + db_user = u; + db_pass = p; + + Connect(); +} + + +void Db::Connect() +{ + std::ostringstream buf; + buf << "dbname=" << db_database << " user=" << db_user << " password=" << db_pass; + + pg_conn = PQconnectdb(buf.str().c_str()); + + if( !pg_conn ) + log << log1 << "Db: Fatal error during connecting" << logend; + + if( PQsetClientEncoding(pg_conn, "LATIN2") == -1 ) + log << log1 << "Db: Can't set the proper client encoding" << logend; +} + + + +void Db::Close() +{ + if( pg_conn ) + { + PQfinish(pg_conn); + pg_conn = 0; + } +} + + +void Db::AssertConnection() +{ + if( !pg_conn ) + { + log << log1 << "Db: Trying to connect into the database..."; + Connect(); + + if( !pg_conn ) + // logend from Connect() + throw Error(Error::db_fatal_error_during_connecting); + + log << log1 << "ok" << logend; + } + + + if( PQstatus(pg_conn) != CONNECTION_OK ) + { + log << log2 << "Db: connection into the database is lost, trying to recover..." << logend; + PQreset(pg_conn); + + if( PQstatus(pg_conn) != CONNECTION_OK ) + { + log << log2 << "no" << logend; + throw Error(Error::db_fatal_error_during_connecting); + } + else + { + log << log2 << "ok" << logend; + } + } +} + + + +std::string Db::Escape(const std::string & s) +{ +std::string result; + + result.resize(s.length() * 2 + 1); + + size_t len = PQescapeStringConn(pg_conn, const_cast( result.c_str() ), s.c_str(), s.length(), 0); + result.resize(len); + +return result; +} + + +std::string Db::Escape(const char * s) +{ +std::string result; +int len; + + for(len=0 ; s[len] != 0 ; ++len); + + result.resize(len * 2 + 1); + + size_t len_new = PQescapeStringConn(pg_conn, const_cast( result.c_str() ), s, len, 0); + result.resize(len_new); + +return result; +} + + + +// ------------------ + + + +PGresult * Db::AssertQuery(const std::string & q) +{ + PGresult * r = PQexec(pg_conn, q.c_str()); + + if( !r ) + { + log << log1 << "Db: Problem with query: " << PQerrorMessage(pg_conn) << logend; + throw Error(Error::db_incorrect_query); + } + +return r; +} + + + +void Db::AssertResultStatus(PGresult * r, ExecStatusType t) +{ + if( PQresultStatus(r) != t ) + { + log << "Db: Incorrect result status: " << PQerrorMessage(pg_conn) << logend; + + throw Error(Error::db_incorrent_result_status); + } +} + + + +int Db::AssertColumn(PGresult * r, const char * column_name) +{ + int c = PQfnumber(r, column_name); + + if( c == -1 ) + { + log << log1 << "Db: there is no column: " << column_name << logend; + + throw Error(Error::db_no_column); + } + +return c; +} + + +const char * Db::AssertValue(PGresult * r, int row, int col) +{ + const char * res = PQgetvalue(r, row, col); + + if( !res ) + { + log << log1 << "Db: there is no such an item in the result, row:" << row << ", col:" << col << logend; + + throw Error(Error::db_no_item); + } + +return res; +} + + +void Db::ClearResult(PGresult * r) +{ + if( r ) + PQclear(r); +} + + +bool Db::CheckUser(std::string & login, std::string & password, long & user_id) +{ + PGresult * r = 0; + bool user_ok = false; + + try + { + AssertConnection(); + + std::ostringstream query; + query << "select id from core.user where login='" << Escape(login) << "' and password='" << Escape(password) << "';"; + + r = AssertQuery( query.str() ); + + AssertResultStatus(r, PGRES_TUPLES_OK); + + int rows = PQntuples(r); + + if( rows == 0 ) + throw Error(Error::db_incorrect_login); + + if( rows > 1 ) + { + log << log1 << "Db: there is more than one user: " << login << " (with the same password)" << logend; + throw Error(Error::db_more_than_one_login); + } + + int cuser_id = AssertColumn(r, "id"); + const char * fuser_id = AssertValue(r, 0, cuser_id); + user_id = atol( fuser_id ); + + user_ok = true; + } + catch(const Error &) + { + } + + ClearResult(r); + + +return user_ok; +} + + + + + + + + + + + +bool Db::AddItemCreateUrlSubject(Item & item) +{ +bool is_that_url; +PGresult * r = 0; +int index = 1; +const int max_index = 100; +char appendix[20]; +appendix[0] = 0; + + + try + { + do + { + std::ostringstream query; + + // this Escape can be put at the beginning (performance) + query << "select id from core.item where url_subject='" << Escape(item.url_subject) << appendix << "' and parent_id='" << item.parent_id << "';"; + r = AssertQuery(query.str()); + AssertResultStatus(r, PGRES_TUPLES_OK); + + if( PQntuples(r) != 0 ) + { + sprintf(appendix, "_(%d)", ++index); + is_that_url = true; + } + else + { + item.url_subject += appendix; + is_that_url = false; + } + + ClearResult(r); + r = 0; + } + while( is_that_url && index <= max_index ); + } + catch(const Error &) + { + is_that_url = true; // for return false + } + + + ClearResult(r); + + +return !is_that_url; +} + + +// for testing consistency +void Db::CheckAllUrlSubjectModifyItem(Item & item) +{ + PGresult * r = 0; + + try + { + std::ostringstream query; + query << "update core.item set url_subject="; + + // url_subject + if( AddItemCreateUrlSubject(item) ) + query << '\'' << Escape(item.url_subject) << '\''; + else + { + query << '\'' << item.id << '\''; + item.url_subject.clear(); + } + + query << " where id='" << item.id << "';"; + + r = AssertQuery(query.str()); + AssertResultStatus(r, PGRES_COMMAND_OK); + } + catch(const Error &) + { + } + + ClearResult(r); +} + + + +// for checking consistency +void Db::CheckAllUrlSubject() +{ + PGresult * r = 0; + Item item; + + try + { + AssertConnection(); + std::ostringstream query, query2; + query << "select id, subject from core.item where url_subject is null or url_subject=''"; + + r = AssertQuery(query.str()); + AssertResultStatus(r, PGRES_TUPLES_OK); + + int rows = PQntuples(r); + int cid = AssertColumn(r, "id"); + int csubject = AssertColumn(r, "subject"); + + for(int i = 0 ; i(item.type) << "', "; + query << '\'' << item.parent_id << "' "; + query << ");"; + + r = AssertQuery(query.str()); + AssertResultStatus(r, PGRES_COMMAND_OK); + + item.id = AssertCurrval("core.item_id_seq"); + + if( !url_without_id ) + ToString(item.url_subject, item.id); + + } + catch(const Error & e) + { + result = e; + } + + ClearResult(r); + +return result; +} + + +Error Db::EditItem(Item & item, bool with_subject) +{ + PGresult * r = 0; + Error result = Error::ok; + bool url_without_id = false; + + try + { + AssertConnection(); + std::ostringstream query; + query << "update core.item set ("; + + if( with_subject ) + query << "subject, url_subject, "; + + query << "content, type, parent_id) = ("; + + if( with_subject ) + { + query << '\'' << Escape(item.subject) << "', "; + + // url_subject + url_without_id = AddItemCreateUrlSubject(item); + + if( url_without_id ) + { + query << '\'' << Escape(item.url_subject) << "', "; + } + else + { + query << '\'' << item.id << "', "; + } + } + + query << '\'' << Escape(item.content) << "', "; + + query << '\'' << static_cast(item.type) << "', "; + query << '\'' << item.parent_id << "' "; + query << ") where id='" << item.id << "';"; + + r = AssertQuery(query.str()); + AssertResultStatus(r, PGRES_COMMAND_OK); + + if( with_subject && !url_without_id ) + ToString(item.url_subject, item.id); + } + catch(const Error & e) + { + result = e; + } + + ClearResult(r); + +return result; +} + + + +PGresult * Db::GetItemsQuery(Item & item_ref) +{ + std::ostringstream query; + query << "select * from core.item where type!='0' and parent_id='" << item_ref.parent_id << "'"; + + if( item_ref.id != -1 ) + query << " and id='" << item_ref.id << "'"; + + if( !item_ref.url_subject.empty() ) + query << " and url_subject='" << Escape(item_ref.url_subject) << "'"; + + query << ';'; + +return AssertQuery(query.str()); +} + + + +void Db::GetItems(std::vector & item_table, Item & item_ref) +{ + item_table.clear(); + PGresult * r = 0; + + try + { + AssertConnection(); + + r = GetItemsQuery(item_ref); + AssertResultStatus(r, PGRES_TUPLES_OK); + + Item item; + int rows = PQntuples(r); + + ItemColumns col; + col.SetColumns(r); + + for(int i = 0 ; i & item_table, long id) +{ + PGresult * r = 0; + + try + { + AssertConnection(); + + std::ostringstream query; + query << "select * from core.item where type='1' and id='" << id << "';"; + + r = AssertQuery( query.str() ); + AssertResultStatus(r, PGRES_TUPLES_OK); + + Item item; + int rows = PQntuples(r); + + if( rows > 1 ) + log << log1 << "Db: we have more than one item with id: " << id << logend; + + ItemColumns col; + col.SetColumns(r); + + for(int i = 0 ; i 1 ) + log << log1 << "Db: more than one item were deleted" << logend; + } + } + catch(const Error &) + { + } + + ClearResult(r); + +return rows != 0; +} + + +void Db::GetDirs(DirContainer & dir_table) +{ + PGresult * r = 0; + + try + { + AssertConnection(); + + std::ostringstream query; + query << "select * from core.item where type='0';"; + + r = AssertQuery( query.str() ); + AssertResultStatus(r, PGRES_TUPLES_OK); + + Item item; + int rows = PQntuples(r); + + ItemColumns col; + col.SetColumns(r); + + for(int i = 0 ; i +#include +#include +#include +#include +#include + + +#include "log.h" +#include "item.h" +#include "misc.h" +#include "error.h" +#include "dircontainer.h" + + + +class Db +{ + +protected: + + PGconn * pg_conn; + + std::string db_database, db_user, db_pass; + +public: + +Db(); +~Db(); + +void Init(const std::string & database, const std::string & user, const std::string & pass); +void Connect(); + +void Close(); +void AssertConnection(); +std::string Escape(const std::string & s); +std::string Escape(const char * s); + +PGresult * AssertQuery(const std::string & q); +void AssertResultStatus(PGresult * r, ExecStatusType t); +static int AssertColumn(PGresult * r, const char * column_name); +static const char * AssertValue(PGresult * r, int row, int col); + +void ClearResult(PGresult * r); + +bool CheckUser(std::string & login, std::string & password, long & user_id); + +long AssertCurrval(const char * table); + + +bool AddItemCreateUrlSubject(Item & item); +Error AddItem(Item & item); +Error EditItem(Item & item, bool with_subject = true); + +void CheckAllUrlSubjectModifyItem(Item & item); +void CheckAllUrlSubject(); + +PGresult * GetItemsQuery(Item & item_ref); +void GetItems(std::vector & item_table, Item & item_ref); +void GetItem(std::vector & item_table, long id); + +bool DelItem(long id); + +void GetDirs(DirContainer & dir_table); + + + +struct ItemColumns +{ + int id, subject, content, url_subject, type, parent_id, default_item; + + void SetColumns(PGresult * r) + { + id = Db::AssertColumn(r, "id"); + subject = Db::AssertColumn(r, "subject"); + content = Db::AssertColumn(r, "content"); + url_subject = Db::AssertColumn(r, "url_subject"); + type = Db::AssertColumn(r, "type"); + parent_id = Db::AssertColumn(r, "parent_id"); + default_item = Db::AssertColumn(r, "default_item"); + } + + + void SetItem(PGresult * r, long row, Item & item) + { + item.id = atol( Db::AssertValue(r, row, id) ); + item.subject = Db::AssertValue(r, row, subject); + item.content = Db::AssertValue(r, row, content); + item.url_subject = Db::AssertValue(r, row, url_subject); + item.type = static_cast( atoi( Db::AssertValue(r, row, type) ) ); + item.parent_id = atol( Db::AssertValue(r, row, parent_id) ); + item.default_item = atol( Db::AssertValue(r, row, default_item) ); + } + + +}; + + +}; // class Db + + +extern Db db; + + +#endif + diff --git a/core/dir.cpp b/core/dir.cpp new file mode 100755 index 0000000..4fe5c6f --- /dev/null +++ b/core/dir.cpp @@ -0,0 +1,220 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include "dir.h" + + +void Dir::Clear() +{ + dir_table.Clear(); + + // !! temporarily not clearing + //root.Clear(); + root.id = -1; +} + + +void Dir::ReadDirs() +{ + Clear(); + + db.GetDirs(dir_table); +} + + + + +bool Dir::GetDir(const std::string & name, long parent, Item ** item) +{ + DirContainer::ParentIterator i = dir_table.FindFirstParent(parent); + + for( ; i!=dir_table.ParentEnd() ; i = dir_table.NextParent(i) ) + if( i->second->url_subject == name ) + { + *item = &(*i->second); + return true; + } + +return false; +} + + +bool Dir::ExtractName(const char * & s, std::string & name) +{ + name.clear(); + + // skipping first slashes (can be more than one) + for( ; *s == '/' ; ++s); + + for( ; *s != 0 && *s != '/' ; ++s) + name += *s; + +return !name.empty(); +} + + + + +bool Dir::GetDir(const std::string & path, Item ** item) +{ + long parent = -1; + std::string name; + const char * s = path.c_str(); + Item * pitem = &root; + + while( ExtractName(s, name) ) + { + if( !GetDir(name, parent, &pitem) ) + return false; + } + + *item = pitem; + +return true; +} + + + + +bool Dir::GetDirId(const std::string & path, long * id) +{ +Item * pitem; + + if( !GetDir(path, &pitem) ) + return false; + + *id = pitem->id; + +return true; +} + + +bool Dir::GetDirId(const std::string & name, long parent, long * id) +{ +Item * pitem; + + if( !GetDir(name, parent, &pitem) ) + return false; + + *id = pitem->id; + +return true; +} + + + +bool Dir::IsDir(long id) +{ + if( id == -1 ) + // root directory + return true; + + DirContainer::Iterator i = dir_table.FindId(id); + + if( i == dir_table.End() ) + return false; + +return true; +} + + + + +bool Dir::GetDirChilds(long parent, std::vector & childs_table) +{ + if( !IsDir(parent) ) + return false; + + DirContainer::ParentIterator i = dir_table.FindFirstParent(parent); + + for( ; i != dir_table.ParentEnd() ; i = dir_table.NextParent(i) ) + childs_table.push_back( *i->second ); + +return true; +} + + + + + +// dodatkowo moze metoda AppendPath dodajaca sciezke do biezacego stringa? +// albo tutaj stringa nie czyscic? +// O(m * log n) (m- how many parts are in 'id') +bool Dir::MakePath(long id, std::string & path) +{ +DirContainer::Iterator i; + + path.clear(); + + while( true ) + { + if( id == -1 ) + return true; + + i = dir_table.FindId(id); + + if( i == dir_table.End() ) + return false; + + id = i->parent_id; + path.insert(path.begin(), '/'); + path.insert(0, i->url_subject); + } +} + + + +// with exceptions + +Item * Dir::GetDir(const std::string & path) +{ +Item * pitem; + + if( !GetDir(path, &pitem) ) + throw Error(Error::incorrect_dir); + +return pitem; +} + + +Item * Dir::GetDir(const std::string & name, long parent) +{ +Item * pitem; + + if( !GetDir(name, parent, &pitem) ) + throw Error(Error::incorrect_dir); + +return pitem; + +} + + +long Dir::GetDirId(const std::string & path) +{ +long id; + + if( !GetDirId(path, &id) ) + throw Error(Error::incorrect_dir); + +return id; +} + + +long Dir::GetDirId(const std::string & name, long parent) +{ +long id; + + if( !GetDirId(name, parent, &id) ) + throw Error(Error::incorrect_dir); + +return id; +} + + + diff --git a/core/dir.h b/core/dir.h new file mode 100755 index 0000000..d85a324 --- /dev/null +++ b/core/dir.h @@ -0,0 +1,80 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfiledir +#define headerfiledir + + +#include +#include +#include +#include "item.h" +#include "error.h" +#include "log.h" +#include "db.h" +#include "dircontainer.h" + + +class Dir +{ + +private: +public: // !! temporarily + + + // id = -1; + Item root; + + + DirContainer dir_table; + + + // parent (or -1), item + //typedef std::multimap DirTable; + //DirTable dir_table; + + + bool ExtractName(const char * & s, std::string & name); + + + + +public: + + void Clear(); + void ReadDirs(); + + // without any exceptions + // these methods return false in a case the path or name (with a specific parent) are invalid + // we do not support '..' in a path (for security reason) + + bool IsDir(long id); + + bool GetDir(const std::string & path, Item ** item); + bool GetDir(const std::string & name, long parent, Item ** item); + + bool GetDirId(const std::string & path, long * id); + bool GetDirId(const std::string & name, long parent, long * id); + + bool GetDirChilds(long parent, std::vector & childs_table); // only returns dir-children + + bool MakePath(long id, std::string & path); + + + // with an Error exception + // if the path or name are invalid these methods throw an exception + Item * GetDir(const std::string & path); + Item * GetDir(const std::string & name, long parent); + long GetDirId(const std::string & path); + long GetDirId(const std::string & name, long parent); + +}; + + +#endif diff --git a/core/dircontainer.cpp b/core/dircontainer.cpp new file mode 100755 index 0000000..d654d59 --- /dev/null +++ b/core/dircontainer.cpp @@ -0,0 +1,161 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include "dircontainer.h" + +// !! tutaj ostatecznie ustawic wartosc np okolo 100 +// chwilowo do testow ustawione 2 +DirContainer::DirContainer() +{ +} + + + +DirContainer::Iterator DirContainer::Begin() +{ + return table.begin(); +} + + +DirContainer::Iterator DirContainer::End() +{ + return table.end(); +} + + +DirContainer::SizeType DirContainer::Size() +{ + return table.size(); +} + +bool DirContainer::Empty() +{ + return table.empty(); +} + + +void DirContainer::PushBack(const Item & item) +{ +bool rebuild_indexes = false; + + if( table.size() == table.capacity() ) + rebuild_indexes = true; + + table.push_back(item); + log << log2 << "DirCont: added item, id: " << item.id << ", parent_id: " << item.parent_id << logend; + + if( rebuild_indexes ) + RebuildIndexes(); + else + AddIndexes( --table.end() ); +} + + + + + +void DirContainer::Clear() +{ + table.clear(); + table_id.clear(); + table_parent.clear(); +} + + + + +DirContainer::Iterator DirContainer::FindId(long id) +{ + TableId::iterator i = table_id.find(id); + + if( i == table_id.end() ) + return table.end(); + +return i->second; +} + + + + +void DirContainer::AddIndexes(Iterator item) +{ + table_id.insert( std::make_pair(item->id, item) ); + table_parent.insert( std::make_pair(item->parent_id, item) ); + + log << log2 << "DirCont: added indexes to item, id: " << item->id << ", parent_id: " << item->parent_id << logend; +} + + +void DirContainer::RebuildIndexes() +{ +Iterator i; + + log << log2 << "DirCont: rebuilding indexes" << logend; + + table_id.clear(); + table_parent.clear(); + + for(i=table.begin() ; i!=table.end() ; ++i) + AddIndexes( i ); + + log << log2 << "DirCont: indexes rebuilt, table.size: " << table.size() << ", table_id.size: " << table_id.size() << ", table_parent.size: " << table_parent.size() << logend; +} + + + + +DirContainer::ParentIterator DirContainer::ParentBegin() +{ + return table_parent.begin(); +} + + + +DirContainer::ParentIterator DirContainer::ParentEnd() +{ + return table_parent.end(); +} + + +DirContainer::ParentSizeType DirContainer::ParentSize() +{ + return table_parent.size(); +} + + +bool DirContainer::ParentEmpty() +{ + return table_parent.empty(); +} + + +DirContainer::ParentIterator DirContainer::FindFirstParent(long parent) +{ + ParentIterator i = table_parent.lower_bound(parent); + + if( i == table_parent.end() || i->first != parent ) + return table_parent.end(); + +return i; +} + + +DirContainer::ParentIterator DirContainer::NextParent(ParentIterator i) +{ + if( i == table_parent.end() ) + return table_parent.end(); + + long parent = i->first; + ++i; + + if( i == table_parent.end() || i->first != parent ) + return table_parent.end(); + +return i; +} diff --git a/core/dircontainer.h b/core/dircontainer.h new file mode 100755 index 0000000..6c81210 --- /dev/null +++ b/core/dircontainer.h @@ -0,0 +1,66 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfiledircontainer +#define headerfiledircontainer + +#include +#include +#include "item.h" +#include "log.h" + + +class DirContainer +{ + +public: + typedef std::vector Table; + typedef Table::iterator Iterator; + typedef Table::size_type SizeType; + + typedef std::map TableId; + typedef std::multimap TableParent; + typedef TableParent::iterator ParentIterator; + typedef TableParent::size_type ParentSizeType; + + + DirContainer(); + + Iterator Begin(); + Iterator End(); + SizeType Size(); + bool Empty(); + void PushBack(const Item & item); + void Clear(); + + Iterator FindId(long id); + + ParentIterator ParentBegin(); + ParentIterator ParentEnd(); + ParentSizeType ParentSize(); + bool ParentEmpty(); + ParentIterator FindFirstParent(long parent); + ParentIterator NextParent(ParentIterator pi); + + +private: + + void AddIndexes(Iterator item); + void RebuildIndexes(); + + // main table with dirs + Table table; + + // indexes + TableId table_id; + TableParent table_parent; +}; + + +#endif diff --git a/core/done.cpp b/core/done.cpp new file mode 100755 index 0000000..452f3a2 --- /dev/null +++ b/core/done.cpp @@ -0,0 +1,42 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include "done.h" + + +Done::Done() +{ +} + + +Done::Done(Code c) : code(c) +{ +} + + +Done & Done::operator=(Code c) +{ + code = c; + +return *this; +} + + +bool Done::operator==(Code c) const +{ + return code == c; +} + + + +bool Done::operator!=(Code c) const +{ + return code != c; +} + diff --git a/core/done.h b/core/done.h new file mode 100755 index 0000000..0280dc9 --- /dev/null +++ b/core/done.h @@ -0,0 +1,45 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfiledone +#define headerfiledone + + + +// what have been done +class Done +{ +public: + + enum Code + { + none, + added_item, + edited_item, + deleted_item, + loggedout + }; + + + Done(); + Done(Code c); + Done & operator=(Code c); + bool operator==(Code c) const; + bool operator!=(Code c) const; + + +private: + + Code code; + +}; + + + +#endif diff --git a/core/error.cpp b/core/error.cpp new file mode 100755 index 0000000..2b713f1 --- /dev/null +++ b/core/error.cpp @@ -0,0 +1,73 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include "error.h" + + + +Error::Error() +{ + code = unknown; +} + + +Error::Error(Code c) : code(c) +{ +} + + +Error::Error(int i) +{ + code = static_cast(i); +} + + +Error::operator int() const +{ + return static_cast(code); +} + + +Error & Error::operator=(Code c) +{ + code = c; + return *this; +} + + +bool Error::operator==(Code c) const +{ + return code == c; +} + + +bool Error::operator!=(Code c) const +{ + return code != c; +} + + +std::ostream & operator<<(std::ostream & out, const Error & e) +{ + out << static_cast(e.code); + +return out; +} + + +Log & operator<<(Log & out, const Error & e) +{ + out << static_cast(e.code); + +return out; +} + + + + diff --git a/core/error.h b/core/error.h new file mode 100755 index 0000000..f44235e --- /dev/null +++ b/core/error.h @@ -0,0 +1,71 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfileerror +#define headerfileerror + +#include +#include "log.h" + + + + +class Error +{ + +public: + + enum Code + { + ok = 0, + incorrect_path, + db_fatal_error_during_connecting, + db_incorrect_query, + db_incorrent_result_status, + db_no_column, + db_no_item, + db_incorrect_login, + db_more_than_one_login, + db_err_currval, + + incorrect_dir, + + unknown = 1000 + }; + + + Error(); + Error(Code c); + Error(int i); + Error & operator=(Code c); + + operator int() const; + + bool operator==(Code c) const; + bool operator!=(Code c) const; + + friend std::ostream & operator<<(std::ostream & out, const Error & e); + friend Log & operator<<(Log & out, const Error & e); + + + +private: + + Code code; + +}; + + +std::ostream & operator<<(std::ostream & out, const Error & e); +Log & operator<<(Log & out, const Error & e); + + + + +#endif diff --git a/core/getparser.h b/core/getparser.h new file mode 100755 index 0000000..192c3af --- /dev/null +++ b/core/getparser.h @@ -0,0 +1,57 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfilegetparser +#define headerfilegetparser + +#include "httpsimpleparser.h" +#include "requesttypes.h" + + +class GetParser : public HttpSimpleParser +{ + + const char * get_string; + GetTable & get_table; + +protected: + + virtual int GetChar() + { + if( !get_string || *get_string == 0 ) + return -1; + + return (int)(unsigned char)*(get_string++); + } + + + virtual void Parameter(std::string &, std::string & value) + { + get_table.push_back(value); + + log << log2 << "Get, value: \"" << value << "\"" << logend; + } + + + +public: + + GetParser(const char * get_string_, GetTable & get_table_) : get_string(get_string_), get_table(get_table_) + { + HttpSimpleParser::separator = '/'; + HttpSimpleParser::read_name = false; + + if( get_string && *get_string == separator ) // one '/' at the beginning + ++get_string; + } + +}; + + +#endif diff --git a/core/httpsimpleparser.cpp b/core/httpsimpleparser.cpp new file mode 100755 index 0000000..fac56c9 --- /dev/null +++ b/core/httpsimpleparser.cpp @@ -0,0 +1,231 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include "httpsimpleparser.h" + + +void HttpSimpleParser::ToLower(std::string & s) +{ +std::string::iterator i; + + for(i=s.begin() ; i!= s.end() ; ++i) + { + if( *i>='A' && *i<='Z' ) + *i = *i - 'A' + 'a'; + } +} + + +bool HttpSimpleParser::IsWhite(int c) +{ + if( c==' ' || c=='\t' ) + return true; + +return false; +} + + +void HttpSimpleParser::SkipWhiteChars() +{ + while( IsWhite(last_c) ) + last_c = GetChar(); +} + + + +void HttpSimpleParser::TrimWhiteChars(std::string & s) +{ + if( s.empty() ) + return; + + std::string::size_type i; + + for(i = 0 ; i 0 ) + // there are some white characters at the beginning + s.erase(0, i); + + + // s is not empty now (i was not equal s.size()) + // and we have some non white characters + // we stops at the last non white character + for(i = s.size()-1 ; i>0 && IsWhite(s[i]) ; --i); + + if( i != s.size()-1 ) + // there are some white characters at the end + // we're starting from i+1 even when i==0 (there are some non white characters) + s.erase(i+1, s.size() - i - 1); +} + + + +int HttpSimpleParser::ParseHalfHex(int c) +{ + if( c>='a' && c<='z' ) + c += 'A' - 'a'; // to upper case + + + if( c >= 'A' ) + c = c - 'A' + 10; + else + c = c - '0'; + + c &= 0xf; + + +return c; +} + + + + +void HttpSimpleParser::CheckSpecialChar() +{ + if( last_c == '%' ) + { + int c1 = GetChar(); + int c2 = GetChar(); + + if( c1==-1 || c2==-1 ) + last_c = -1; + + c1 = ParseHalfHex(c1); + c2 = ParseHalfHex(c2); + + last_c = (c1 << 4) + c2; + } + else + if( last_c == '+' ) + { + last_c = ' '; + } +} + + + + + + +void HttpSimpleParser::ReadName() +{ + // we're checking 'separator' and '=' because the string is allowed not having '=' (the value is optional) + + for( ; last_c!=-1 && last_c!=separator && last_c!='=' ; last_c = GetChar() ) + { + if( recognize_special_chars ) + CheckSpecialChar(); + + if( last_c != -1 ) + last_name += last_c; + } + + + if( last_c == '=' ) + last_c = GetChar(); +} + + +void HttpSimpleParser::ReadQuotedValue() +{ + // skipping '"' + last_c = GetChar(); + + + for( ; last_c!=-1 && last_c!='"' ; last_c = GetChar() ) + { + if( recognize_special_chars ) + CheckSpecialChar(); + + if( last_c != -1 ) + last_value += last_c; + } + + + if( last_c == '"' ) + last_c = GetChar(); + + // looking for a separator (skipping) + for( ; last_c!=-1 && last_c!=separator ; last_c = GetChar() ); + +} + + +void HttpSimpleParser::ReadValue() +{ + if( skip_white_chars ) + SkipWhiteChars(); + + if( value_can_be_quoted && last_c == '"' ) + { + ReadQuotedValue(); + } + else + { + for( ; last_c!=-1 && last_c!=separator ; last_c = GetChar() ) + { + if( recognize_special_chars ) + CheckSpecialChar(); + + if( last_c != -1 ) + last_value += last_c; + } + } + + + if( last_c == separator ) + last_c = GetChar(); +} + + + + +void HttpSimpleParser::Parse() +{ + for( last_c = GetChar() ; last_c != -1 ; ) + { + last_name.clear(); + last_value.clear(); + + if( read_name ) + ReadName(); + + ReadValue(); + + if( skip_white_chars ) + { + TrimWhiteChars(last_name); + TrimWhiteChars(last_value); + } + + Parameter(last_name, last_value); // user definied function + } +} + + + + + + + + + + + + + + + diff --git a/core/httpsimpleparser.h b/core/httpsimpleparser.h new file mode 100755 index 0000000..a40994e --- /dev/null +++ b/core/httpsimpleparser.h @@ -0,0 +1,74 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfilehttpsimpleparser +#define headerfilehttpsimpleparser + + +#include + + + +class HttpSimpleParser +{ +protected: + + bool read_name; + bool value_can_be_quoted; + bool skip_white_chars; + bool recognize_special_chars; + + int ParseHalfHex(int c); + void ReadName(); + void ReadQuotedValue(); + void ReadValue(); + + std::string last_name; + std::string last_value; + + int last_c; + int separator; + + // '-1' means end (eof) + virtual int GetChar() = 0; + virtual void Parameter(std::string & last_name, std::string & last_value) = 0; + + void ToLower(std::string & s); + bool IsWhite(int c); + + void SkipWhiteChars(); + void TrimWhiteChars(std::string & s); + void CheckSpecialChar(); + + + + +public: + + + HttpSimpleParser() + { + separator = '&'; + read_name = true; + value_can_be_quoted = false; + skip_white_chars = false; + recognize_special_chars = true; + } + + + void Parse(); + + + + +}; + + + +#endif diff --git a/core/item.h b/core/item.h new file mode 100755 index 0000000..508b146 --- /dev/null +++ b/core/item.h @@ -0,0 +1,73 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfileitem +#define headerfileitem + +#include + + + + +struct Item +{ +long id; + +std::string subject; +std::string content; +std::string url_subject; + +enum Type +{ + dir = 0, + file = 1, + + + + none = 1000 +}; + +Type type; + +//item_type; + +long parent_id; +long default_item; + + + +Item() +{ + Clear(); +} + + + +void Clear() +{ + id = -1; + subject.clear(); + content.clear(); + url_subject.clear(); + + type = none; + parent_id = -1; + default_item = -1; +} + + + + + + +}; + + + +#endif diff --git a/core/log.cpp b/core/log.cpp new file mode 100755 index 0000000..5e4d30a --- /dev/null +++ b/core/log.cpp @@ -0,0 +1,177 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include "log.h" + + + +Log::Log() +{ + log_level = 1; + current_level = 2; + log_file = "cmslu.log"; + log_stdout = true; +} + + +void Log::Init(int log_l, const std::string & log_f, bool log_std) +{ + log_level = log_l; + log_file = log_f; + log_stdout = log_std; +} + +// zrobic templeta z tych metod +// i dla const char * zrobic specjalizacje + +Log & Log::operator<<(const char * s) +{ + if( !s ) + return *this; + + buffer << s; + +return *this; +} + + +Log & Log::operator<<(const std::string & s) +{ + buffer << s; + + return *this; +} + + +Log & Log::operator<<(int s) +{ + buffer << s; + + return *this; +} + + +Log & Log::operator<<(long s) +{ + buffer << s; + + return *this; +} + +/* +Log & Log::operator<<(void * s) +{ + buffer << s; + + return *this; +} +*/ + + +Log & Log::operator<<(char s) +{ + buffer << s; + + return *this; +} + + +Log & Log::operator<<(size_t s) +{ + buffer << s; + + return *this; +} + + +Log & Log::operator<<(Manipulators m) +{ + switch(m) + { + case logend: + SaveLog(); + buffer.str( "" ); + break; + + case log1: + current_level = 1; + break; + + case log2: + current_level = 2; + break; + + case log3: + current_level = 3; + break; + + } + + return *this; +} + + + +void Log::SaveLog() +{ +int attempt = 2; + + if( current_level > log_level ) + return; + + if( log_stdout ) + std::cout << buffer.str() << std::endl; + + + std::ofstream file; + + do + { + file.open( log_file.c_str(), std::ios_base::out | std::ios_base::app ); + +// if( !file ) +// sleep(1); + } + while( --attempt > 0 && !file ); + + if( !file ) + return; + + file << buffer.str() << std::endl; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/log.h b/core/log.h new file mode 100755 index 0000000..4994472 --- /dev/null +++ b/core/log.h @@ -0,0 +1,61 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfilelog +#define headerfilelog + + +#include +#include +#include +#include + + +enum Manipulators { logend, log1, log2, log3 }; + + +class Log +{ +std::ostringstream buffer; +int log_level, current_level; +std::string log_file; +bool log_stdout; + +public: + + + + + Log(); + + void Init(int log_l, const std::string & log_f, bool log_std); + + + Log & operator<<(const char * s); + Log & operator<<(const std::string & s); + Log & operator<<(int s); + Log & operator<<(long s); + //Log & operator<<(void * s); // ?? + Log & operator<<(char s); + Log & operator<<(size_t s); + Log & operator<<(Manipulators m); + + void SaveLog(); + + +}; + + + +extern Log log; + + + +#endif + diff --git a/core/main.cpp b/core/main.cpp new file mode 100755 index 0000000..edd5feb --- /dev/null +++ b/core/main.cpp @@ -0,0 +1,73 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include +#include +#include +#include +#include "requestcontroller.h" +#include "data.h" +#include "log.h" +#include "request.h" +#include "db.h" + + +// singletons +// first 'data' then 'log' then 'request' +Data data; +Log log; +Request request; +Db db; + + + + +void signal_term(int) +{ + log << log1 << "system aborted" << logend; + + exit(0); +} + + + +int main() +{ + std::srand(std::time(0)); + + + log.Init(data.log_level, data.log_file, data.log_stdout); + + +RequestController req_controller; + + //data.read_from_file(); + + + db.Init(data.db_database, data.db_user, data.db_pass); + + if( !req_controller.Init() ) + return 1; + + log << log1 << "system started" << logend; + + signal(SIGTERM, signal_term); + + + log << log1 << "checking for table consistency..."; + db.CheckAllUrlSubject(); + log << log1 << "done" << logend; + + + req_controller.Loop(); + + log << log1 << "system stopped" << logend; + +return 0; +} diff --git a/core/misc.cpp b/core/misc.cpp new file mode 100755 index 0000000..0798a0b --- /dev/null +++ b/core/misc.cpp @@ -0,0 +1,138 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include "misc.h" + + + + +void ToString(std::string & s, int value) +{ +static char buffer[50]; + + sprintf(buffer, "%d", value); + s = buffer; +} + + +void ToString(std::string & s, long value) +{ +static char buffer[50]; + + sprintf(buffer, "%ld", value); + s = buffer; +} + + + +void SetUrlSubjectFromSubject(Item & item) +{ +std::string::iterator i; + + item.url_subject.clear(); + + for(i = item.subject.begin(); i!=item.subject.end() ; ++i) + { + int c = ChangeLocalChar(*i); + + if( (c >= 'a' && c <='z') || + (c >= 'A' && c <='Z') || + (c >= '0' && c <='9') || + (c == '(' || c == ')' || c == '.' || c == ',' || c == '_' ) + ) + { + item.url_subject += c; + } + else + item.url_subject += '_'; + } + + if( item.url_subject.empty() ) + item.url_subject = "bez_nazwy"; + else + if( item.url_subject[0] >= '0' && item.url_subject[0] <= '9' ) + // url_subject must begin with a letter + item.url_subject.insert(item.url_subject.begin(), '_'); +} + + + +int polish_letters_simple[] = +{ 'a', 'A', + 'c', 'C', + 's', 'S', + 'e', 'E', + 'l', 'L', + 'o', 'O', + 'z', 'Z', + 'z', 'Z', + 'n', 'N', 0 }; // 0 - terminating + + +int polish_letters_iso88592[] = +{ 0xb1, 0xa1, + 0xe6, 0xc6, + 0xb6, 0xa6, + 0xea, 0xca, + 0xb3, 0xa3, + 0xf3, 0xd3, + 0xbf, 0xaf, + 0xbc, 0xac, + 0xf1, 0xd1, 0 }; + + + +int ChangeLocalChar(unsigned char c) +{ + // if( language == polish_iso88592 ) + + for(int i = 0 ; polish_letters_iso88592[i] ; ++i) + { + if( polish_letters_simple[i] == 0 ) + { + log << log1 << "localization tables don't have the same size" << logend; + return c; + } + + if( polish_letters_iso88592[i] == c ) + return polish_letters_simple[i]; + } + +return c; +} + + +void HtmlSpecial(std::ostringstream & out, const std::string & in) +{ +std::string::const_iterator i; + + for(i = in.begin() ; i != in.end() ; ++i) + { + if( *i == '<' ) + out << "<"; + else + if( *i == '>' ) + out << ">"; + else + out << *i; + } +} + + +std::string HtmlSpecial(const std::string & in) +{ + std::ostringstream out; + + HtmlSpecial(out, in); + +return out.str(); +} + + + diff --git a/core/misc.h b/core/misc.h new file mode 100755 index 0000000..5254398 --- /dev/null +++ b/core/misc.h @@ -0,0 +1,33 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfilemisc +#define headerfilemisc + + +#include +#include +#include "log.h" +#include "item.h" + +#define MAJOR_VER 0 +#define MINOR_VER 1 +#define REVISION_VER 0 + + +void ToString(std::string & s, int value); +void ToString(std::string & s, long value); +void SetUrlSubjectFromSubject(Item & item); +int ChangeLocalChar(unsigned char c); +void HtmlSpecial(std::ostringstream & out, const std::string & in); +std::string HtmlSpecial(const std::string & in); + + + +#endif diff --git a/core/postparser.h b/core/postparser.h new file mode 100755 index 0000000..ca065da --- /dev/null +++ b/core/postparser.h @@ -0,0 +1,56 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfilepostparser +#define headerfilepostparser + +#include +#include +#include "httpsimpleparser.h" +#include "requesttypes.h" + + +class PostParser : public HttpSimpleParser +{ + + FCGX_Stream * in; + PostTable & post_table; + +protected: + + + virtual int GetChar() + { + return FCGX_GetChar(in); + } + + + virtual void Parameter(std::string & name, std::string & value) + { + std::pair res = post_table.insert( std::make_pair(name, value) ); + + log << log2 << "Method POST, name: \"" << name << "\", value: \"" << value << "\""; + + if( res.second == false ) + log << log2 << " (skipped)"; + + log << log2 << logend; + } + + +public: + + PostParser(FCGX_Stream * in_, PostTable & post_table_) : in(in_), post_table(post_table_) + { + } + +}; + + +#endif diff --git a/core/request.cpp b/core/request.cpp new file mode 100755 index 0000000..7101a28 --- /dev/null +++ b/core/request.cpp @@ -0,0 +1,374 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include "request.h" + + + +Request::Request() +{ + Clear(); +} + + +void Request::Clear() +{ + // warning: don't clear in, out, err, env + + get_table.clear(); + post_table.clear(); + cookie_table.clear(); + + method = none; + + headers.str(""); + page.str(""); + debug.str(""); + + env_request_method = 0; + env_request_uri = 0; + env_http_cookie = 0; + + session = 0; + + result = err404; // tutaj moze cos lepszego, cos w stylu 'not implemented' + + dir = -1; + cur_dir_table.clear(); + item_table.clear(); + dir_table.clear(); + + item.Clear(); + str.clear(); +} + + +void Request::CopyFirstItem() +{ + if( !request.item_table.empty() ) + request.item = request.item_table[0]; + else + { + request.item.Clear(); + + log << log1 << "Request::CopyFirstItem: item_table is empty" << logend; + request.result = err_internal; + } +} + + + + +// value can be null +void Request::SetCookie(const char * name, const char * value) +{ + request.headers << "Set-Cookie: " << name << "="; + + if( value && value[0]!=0 ) + request.headers << value; + else + request.headers << "\"\""; + + request.headers << "; path=/\r\n"; +} + + + +void Request::SetCookie(const char * name, long value) +{ + request.headers << "Set-Cookie: " << name << "=" << value << "; path=/\r\n"; +} + + + + + +bool Request::IsPostVar(const char * var) +{ + PostTable::iterator p; + + p = post_table.find(var); + + if( p == post_table.end() ) + return false; + +return true; +} + + + +std::string & Request::PostVar(const char * var) +{ + PostTable::iterator p; + + p = post_table.find(var); + + if( p == post_table.end() ) + throw Error(); + +return p->second; +} + + + + + + + + +// + + +void Request::PrintGetTable() +{ + debug << "get_table: " << get_table.size() << "\n"; + + for(GetTable::iterator i = get_table.begin() ; i != get_table.end() ; ++i) + debug << " \"" << *i << "\"\n"; + + debug << std::endl; +} + + +void Request::PrintEnv() +{ +char ** e; + + debug << "environment variables:\n"; + + for( e = env ; *e ; ++e ) + debug << ' ' << *e << "\n"; + + debug << std::endl; +} + + + + +void Request::PrintIn() +{ +char buf[100]; +int buf_len = sizeof(buf) / sizeof(char); +int len; + + debug << "fcgi input:\n"; + + do + { + len = FCGX_GetStr(buf, buf_len - 1, in); + + if( len != 0 ) + { + buf[len] = 0; + debug << buf; + } + } + while( len == buf_len - 1 ); + + debug << std::endl; +} + + + +void Request::ReadEnvVariables() +{ + // we store that values because FCGX_GetParam has O(n) complexity + // with this variables (env_*) we have O(1) + + env_request_method = FCGX_GetParam("REQUEST_METHOD", env); + env_request_uri = FCGX_GetParam("REQUEST_URI", env); + env_http_cookie = FCGX_GetParam("HTTP_COOKIE", env); +} + + + +void Request::CheckMethod() +{ + method = none; + + if( !env_request_method ) + return; + + if( env_request_method[0] == 'G' ) + method = get; + else + if( env_request_method[0] == 'P' ) + method = post; +} + + +void Request::ReadParameters() +{ +// some parameters (get) we have always +// if( method == get ) + { + GetParser get_parser(env_request_uri, get_table); + get_parser.Parse(); + } + + if( method == post ) + { + PostParser post_parser(in, post_table); + post_parser.Parse(); + } + + CookieParser cookie_parser(env_http_cookie, cookie_table); + cookie_parser.Parse(); +} + + +// reading everything +void Request::Read() +{ + ReadEnvVariables(); + CheckMethod(); + ReadParameters(); +} + + + +void Request::SendAll() +{ + if( result == redirect ) + { + FCGX_PutS("Status: 301 Moved Permanently\r\n", out); + FCGX_FPrintF(out, "Location: %s\r\n", str.c_str()); + + log << log2 << "Redirect into: " << str << logend; + } + else + { + FCGX_PutS("Status: 200 OK\r\n", out); + FCGX_PutS("Content-Type: Text/Html\r\n", out); + } + + + FCGX_PutS(headers.str().c_str(), out); + FCGX_PutS("\r\n", out); + + + if( result == redirect ) + // if there is a redirect we do not send a content + return; + + FCGX_PutS(page.str().c_str(), out); + + const std::string & d = debug.str(); + + if( !d.empty() ) + { + FCGX_PutS("\n\n", out); + } +} + + + + +// ---------------- + + + + + +/* + + + + +unsigned char Request::tohex(unsigned char polowa) +{ + // polowa z zakresu 0-15 + polowa = polowa & 0xf; + + if(polowa<10) + polowa += '0'; + else + polowa = polowa - 10 + 'A'; + +return polowa; +} + + +// cala wartosc zapisywana jest w postaci hex +string Request::ToHex(const string & dane) +{ +string wynik; +unsigned int i; + + + for(i=0 ; i> 4); + wynik += tohex(dane[i] & 0xf); + } + +return wynik; +} + +string Request::HexToString(const string & dane) +{ +string wynik; +unsigned int i; +unsigned char znak,znak1,znak2; + + if(dane.length()==0) + return wynik; + + for(i=0 ; i='a' && dane[i]<='z') || + (dane[i]>='A' && dane[i]<='Z') || + (dane[i]>='0' && dane[i]<='9') || + dane[i]=='_' ) + { + wynik += dane[i]; + } + else + { + wynik += '%'; + + wynik += tohex(dane[i] >> 4); + wynik += tohex(dane[i] & 0xf); + } + } + +return wynik; +} + + + + + +*/ + + + + diff --git a/core/request.h b/core/request.h new file mode 100755 index 0000000..8c967ac --- /dev/null +++ b/core/request.h @@ -0,0 +1,116 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfilerequest +#define headerfilerequest + +#include +#include +#include +#include "requesttypes.h" +#include "log.h" +#include "session.h" + +#include "getparser.h" +#include "postparser.h" +#include "cookieparser.h" +#include "item.h" +#include "error.h" + + +struct Request +{ + FCGX_Stream * in, * out, * err; + FCGX_ParamArray env; // defined as 'char **' + + + enum Method { get, post, none } method; + + + // headers, page and debug + std::ostringstream headers, page, debug; + + + GetTable get_table; + PostTable post_table; + CookieTable cookie_table; + + const char * env_request_method; + const char * env_request_uri; + const char * env_http_cookie; + + // current session + // is set after calling session_manager.SetSession() + Session * session; + + + // 'done_status' is set if 'done' is different than 'nothing' + Error done_status; + + // what to do + enum Result { err_internal, err404, show_dir, show_item, show_item_by_id, add_item, edit_item, del_item, del_item_confirm, confirm, redirect, logout } result; // zamienic na to_do + //Item item; // bedziemy uzywac tego, item_id i item_url_subject wywalic + + + + // current directory e.g. /foo/bar + std::vector cur_dir_table; + + // id of the last directory (bar) or -1 + long dir; + + // items in the current directory + // maybe without contents? + std::vector item_table; + + // directories in the current directory + std::vector dir_table; + + // this item is used for many purposes such as editing, adding an item etc. + Item item; + + // this string is used for many purposes such as redirecting + std::string str; + + // for debugging + void PrintGetTable(); + void PrintEnv(); + void PrintIn(); + + Request(); + void Clear(); + + + void SetCookie(const char * name, const char * value); + void SetCookie(const char * name, long value); + + bool IsPostVar(const char * var); + std::string & PostVar(const char * var); // with a throw + + + // item_table[0] -> item + void CopyFirstItem(); + + + void ReadEnvVariables(); + void CheckMethod(); + void ReadParameters(); + void Read(); + void SendAll(); + + +}; + + + +extern Request request; + + + +#endif diff --git a/core/requestcontroller.cpp b/core/requestcontroller.cpp new file mode 100755 index 0000000..448cd12 --- /dev/null +++ b/core/requestcontroller.cpp @@ -0,0 +1,137 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include "requestcontroller.h" + + + +RequestController::RequestController() +{ +} + + + + +bool RequestController::Init() +{ + const char * sock = data.fcgi_socket.c_str(); + + unlink(sock); + + + + int s = FCGX_OpenSocket(sock, 10); + + if( s < 0 ) + { + log << log1 << "An error during creating a socket" << logend; + return false; + } + + + chmod(sock, data.fcgi_socket_chmod); + + passwd * pw = getpwnam(data.fcgi_socket_user.c_str()); + + if( !pw ) + { + log << log1 << "There is no user: " << data.fcgi_socket_user << logend; + return false; + } + + group * gr = getgrnam(data.fcgi_socket_group.c_str()); + + if( !gr ) + { + log << log1 << "There is no group: " << data.fcgi_socket_group << logend; + return false; + } + + chown(sock, pw->pw_uid, gr->gr_gid); + + + + if( setuid(pw->pw_uid) < 0 ) + { + log << log1 << "I can't change the user into: " << data.fcgi_socket_user << logend; + return false; + } + + + /* + if( setgid(gr->gr_gid) < 0 ) + { + int e = errno; + + log << log1 << "I can't change the group into: " << data.fcgi_socket_group << " " << gr->gr_gid << logend; + log << log1 << "errno: " << e << logend; + return false; + } + */ + + + dup2(s, 0); + + if( !data.log_stdout ) + close(1); + + close(2); + + +// + + data.dir.ReadDirs(); + +// + + if( !content.Init() ) + return false; + + +return true; +} + + + +void RequestController::Loop() +{ + while( FCGX_Accept(&request.in, &request.out, &request.err, &request.env) == 0 ) + { + log << log2 << "start request" << logend; + + try + { + request.Clear(); + request.Read(); + + session_manager.SetSession(); // setting request.session as well + request.session->CheckTimers(); + + content.Make(); + request.SendAll(); + + } + catch(const std::exception & e) + { + log << log1 << "uncaught std exception: " << e.what() << logend; + } + catch(const Error & e) + { + log << log1 << "uncaught exception: Error: " << e << logend; + } + catch(...) + { + log << log1 << "uncaught exception" << logend; + } + + + log << log2 << "end request" << logend; + log << log2 << "---------------------------------------------------------------------------------" << logend; + } +} diff --git a/core/requestcontroller.h b/core/requestcontroller.h new file mode 100755 index 0000000..d195412 --- /dev/null +++ b/core/requestcontroller.h @@ -0,0 +1,45 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfilerequestcontroller +#define headerfilerequestcontroller + +#include +#include +#include +#include +#include +#include +#include + +#include "data.h" +#include "log.h" +#include "request.h" +#include "content.h" +#include "sessionmanager.h" +#include "postparser.h" +#include "cookieparser.h" + + +class RequestController +{ + Content content; + SessionManager session_manager; + +public: + + RequestController(); + + bool Init(); + void Loop(); + +}; + + +#endif diff --git a/core/requesttypes.h b/core/requesttypes.h new file mode 100755 index 0000000..920822b --- /dev/null +++ b/core/requesttypes.h @@ -0,0 +1,26 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfilerequesttypes +#define headerfilerequesttypes + +#include +#include +#include + + +// some global types used by Request class +typedef std::vector GetTable; +typedef std::map PostTable; +typedef std::map CookieTable; + + + + +#endif diff --git a/core/session.cpp b/core/session.cpp new file mode 100755 index 0000000..1530dfd --- /dev/null +++ b/core/session.cpp @@ -0,0 +1,73 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include "session.h" + + +Session::Session() +{ + Clear(); + + time = std::time(0); +} + + +void Session::Clear() +{ + id = 0; + time = 0; + is_logged = false; + user_id = 0; + user.clear(); + done = Done::none; + done_status = Error::ok; + item.Clear(); + done_timer = 0; +} + +bool Session::operator==(const Session & s) const +{ + return id == s.id; +} + + +bool Session::operator<(const Session & s) const +{ + return id < s.id; +} + + + + +bool Session::DecTimer(int & timer) +{ + if( timer == 0 ) + return false; + + --timer; + + if( timer == 0 ) + return true; // we must clear our variables + +return false; +} + + + +void Session::CheckTimers() +{ + if( DecTimer(done_timer) ) + { + done = Done::none; + done_status = Error::ok; + } +} + + + diff --git a/core/session.h b/core/session.h new file mode 100755 index 0000000..bf5dcd7 --- /dev/null +++ b/core/session.h @@ -0,0 +1,63 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfilecoresession +#define headerfilecoresession + +#include +#include "requesttypes.h" +#include "error.h" +#include "item.h" +#include "done.h" + + + + +struct Session +{ + // 0 - means that there is no session + long id; + int time; + + bool is_logged; + long user_id; // logged user + + std::string user; // user name + + // what is done + Done done; + Error done_status; + + int done_timer; + + + // used for many purposes, depending on 'done' + Item item; + + + // ------------------- + + Session(); + virtual void Clear(); + bool operator==(const Session & s) const; + bool operator<(const Session & s) const; + bool DecTimer(int & timer); + void CheckTimers(); +}; + + + + + + + + + +#endif + diff --git a/core/sessionmanager.cpp b/core/sessionmanager.cpp new file mode 100755 index 0000000..3a18cbe --- /dev/null +++ b/core/sessionmanager.cpp @@ -0,0 +1,161 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include "sessionmanager.h" + + +bool SessionManager::IsSession(long s) +{ + SessionTable::iterator i; + + Session temp; + + temp.id = s; + + i = session_table.find(temp); + + if( i == session_table.end() ) + return false; + + + +return true; +} + + +long SessionManager::CreateSessionId() +{ +long id; + + // make sure to call std::srand() somewhere at the beginning + // id must be != 0 (0 is reserved) + do + { + if( sizeof(long) == 8 ) + { + id = ((unsigned long)std::rand()) << 32 + std::rand(); + } + else + { + id = std::rand(); + } + + id += std::time(0); + + if( id < 0 ) + id = -id; + + } + while( id == 0 ); // 0 reserved for a temporary session + + +return id; +} + + +void SessionManager::CreateTemporarySession() +{ +Session s; + + s.id = 0; + SessionTable::iterator i = session_table.find( s ); // looking for id=0 + + if( i == session_table.end() ) + { + std::pair res = session_table.insert(s); + request.session = const_cast( &(*res.first) ); + } + else + { + request.session = const_cast( &(*i) ); + } +} + + +void SessionManager::CreateSession() +{ +Session s; +int attempts = 100; + + for( ; attempts > 0 ; --attempts ) + { + s.id = CreateSessionId(); + + std::pair res = session_table.insert(s); + + if( res.second == true ) + { + // the insertion took place + + request.session = const_cast( &(*res.first) ); + request.SetCookie(data.http_session_id_name.c_str(), request.session->id); + log << log1 << "created a new session: " << s.id << logend; + + return; + } + } + + // there is a problem with generating a new session id + // we do not set a session cookie + CreateTemporarySession(); + log << log1 << "cannot create a session id (temporary used: with id 0)" << logend; +} + + + +void SessionManager::SetSession() +{ + CookieTable::iterator i = request.cookie_table.find(data.http_session_id_name); + + if( i == request.cookie_table.end() ) + { + CreateSession(); + } + else + { + Session temp; + temp.id = atol(i->second.c_str()); + SessionTable::iterator s = session_table.find(temp); + + if( s != session_table.end() ) + { + // that session is in the table + request.session = const_cast( &(*s) ); + log << log1 << "session: " << s->id << logend; + } + else + { + // there is no such a session + // deleting the old cookie + request.cookie_table.erase(i); + + // and creating a new one + CreateSession(); + } + } + + + + // request.session is set now +} + + + + + + + + + + + + + + + diff --git a/core/sessionmanager.h b/core/sessionmanager.h new file mode 100755 index 0000000..3f4091a --- /dev/null +++ b/core/sessionmanager.h @@ -0,0 +1,45 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfilesessionmanager +#define headerfilesessionmanager + +#include +#include + +#include "request.h" +#include "log.h" +#include "data.h" +#include "session.h" +#include "db.h" + + + + +class SessionManager +{ + // !! zamienic na map + typedef std::set SessionTable; + + SessionTable session_table; + + bool IsSession(long s); + + long CreateSessionId(); + void CreateTemporarySession(); + void CreateSession(); + +public: + + + void SetSession(); +}; + + +#endif diff --git a/core/templates.cpp b/core/templates.cpp new file mode 100755 index 0000000..aa34026 --- /dev/null +++ b/core/templates.cpp @@ -0,0 +1,542 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#include "templates.h" + + + + +namespace TemplatesFunctions +{ +Pattern pat_index; +Pattern pat_item; +Pattern pat_dir; +Pattern pat_item_add_edit; +Pattern pat_item_del_confirm; +Pattern pat_err_404; +Pattern pat_err_internal; + +Functions functions; + + +void language(Info & i) +{ + // at the moment only Polish language + i.out << "pl"; +} + +void title(Info & i) +{ + i.out << ""; +} + + +void charset(Info & i) +{ + i.out << "iso-8859-2"; +} + + +void version_major(Info & i) +{ + i.out << MAJOR_VER; +} + + +void version_minor(Info & i) +{ + i.out << MINOR_VER; +} + + + +void version_revision(Info & i) +{ + i.out << REVISION_VER; +} + + + +void content(Info & i) +{ +Pattern * p; + + switch( request.result ) + { + case Request::add_item: + case Request::edit_item: + p = &pat_item_add_edit; + break; + + case Request::show_dir: + p = &pat_dir; + break; + + case Request::show_item: + p = &pat_item; + break; + + case Request::del_item_confirm: + p = &pat_item_del_confirm; + break; + + case Request::err_internal: + p = &pat_err_internal; + break; + + case Request::err404: + default: + p = &pat_err_404; + } + + Generator gen(i.out, *p, functions); + + gen.Generate(); +} + + +void base_url(Info & i) +{ + i.out << data.base_url; +} + + +void current_url(Info & i) +{ + if( request.env_request_uri ) + i.out << request.env_request_uri; + else + base_url(i); +} + + + + +void user_logged(Info & i) +{ + i.result = request.session->is_logged; +} + + +void user(Info & i) +{ + i.out << request.session->user; +} + + + + + +void item_id(Info & i) +{ + i.out << request.item.id; +} + +void item_subject(Info & i) +{ + i.out << HtmlSpecial(request.item.subject); +} + + +void item_content(Info & i) +{ + //i.out << HtmlSpecial(request.item.content); + i.out << request.item.content; +} + + +void item_url_subject(Info & i) +{ + i.out << request.item.url_subject; +} + + +void item_dir(Info & i) +{ +std::string path; + + if( data.dir.MakePath(request.item.parent_id, path) ) + { + i.out << path; + } + else + { + i.out << "problem with generating a path"; + } +} + + +// --------- + + +void old_item_id(Info & i) +{ + i.out << request.session->item.id; +} + +void old_item_subject(Info & i) +{ + i.out << HtmlSpecial(request.session->item.subject); +} + + +void old_item_content(Info & i) +{ + //i.out << HtmlSpecial(request.session->item.content); +i.out << request.session->item.content; +} + + +void old_item_url_subject(Info & i) +{ + i.out << request.session->item.url_subject; +} + + +void old_item_dir(Info & i) +{ +std::string path; + + if( data.dir.MakePath(request.session->item.parent_id, path) ) + { + i.out << path; + } + else + { + i.out << "problem with generating a path"; + } +} + + + +// ---- + +void full_dir(Info & i) +{ +std::vector::size_type a; + + for(a=0 ; a::size_type item_index, dir_index; + + + +void dir_items(Info & i) +{ + if( i.iter >= (int)request.dir_table.size() ) + { + i.result = false; + } + else + { + i.result = true; + dir_index = i.iter; + } +} + + +void dir_subject2(Info & i) +{ + if( dir_index < request.dir_table.size() ) + { + if( request.dir_table[dir_index].subject.empty() ) + i.out << "bez nazwy"; + else + HtmlSpecial(i.out, request.dir_table[dir_index].subject); + } +} + +void dir_url_subject2(Info & i) +{ + if( dir_index < request.dir_table.size() ) + { + HtmlSpecial(i.out, request.dir_table[dir_index].url_subject); + } +} + + +void items(Info & i) // zamienic na fitems !! +{ + if( i.iter >= (int)request.item_table.size() ) + { + i.result = false; + } + else + { + i.result = true; + item_index = i.iter; + } +} + + +void item_subject2(Info & i) +{ + if( item_index < request.item_table.size() ) + { + if( request.item_table[item_index].subject.empty() ) + i.out << "bez nazwy"; + else + HtmlSpecial(i.out, request.item_table[item_index].subject); + } +} + +void item_url_subject2(Info & i) +{ + if( item_index < request.item_table.size() ) + HtmlSpecial(i.out, request.item_table[item_index].url_subject); +} + +void item_content2(Info & i) +{ + if( item_index < request.item_table.size() ) + //HtmlSpecial(i.out, request.item_table[item_index].content); + i.out << request.item_table[item_index].content; +} + +void item_id2(Info & i) +{ + if( item_index < request.item_table.size() ) + i.out << request.item_table[item_index].id; +} + + + +void incorrect_dir(Info & i) +{ + if( request.session->done_status == Error::incorrect_dir ) + i.result = true; + else + i.result = false; +} + + + +std::vector::size_type current_dir_index; + + + +void fcurrent_dir(Info & i) +{ + if( i.iter < (int)request.cur_dir_table.size() ) + { + current_dir_index = i.iter; + i.result = true; + } + else + i.result = false; +} + + +void current_dir_part_name(Info & i) +{ + if( current_dir_index < request.cur_dir_table.size() ) + i.out << request.cur_dir_table[current_dir_index].subject; +} + + +void current_dir_part_url(Info & i) +{ + std::vector::size_type a; + + i.out << data.base_url; + + for(a = 0 ; a <= current_dir_index && a < request.cur_dir_table.size() ; ++a) + { + i.out << request.cur_dir_table[a].url_subject << '/'; + } +} + + + +void edit_item(Info & i) +{ + i.result = request.result == Request::edit_item; +} + + +void added_item(Info &i) +{ + i.result = request.session->done == Done::added_item; +} + + +void edited_item(Info &i) +{ + i.result = request.session->done == Done::edited_item; +} + +void deleted_item(Info &i) +{ + i.result = request.session->done == Done::deleted_item; +} + + + +// zostawic tylko jedna funkcje done_with_errors (bedzie uzywana do roznych celow) !! +void deleted_item_errors(Info & i) +{ + i.result = request.session->done_status != Error::ok; +} + + +void done_with_errors(Info & i) +{ + i.result = request.session->done_status != Error::ok; +} + + +void done_status(Info & i) +{ + i.out << static_cast( request.session->done_status ); +} + + + +void fitems_in_dir(Info & i) +{ +// i.out << "abc: " << variables["fitems_directory"]; + +} + + +void loggedout(Info & i) +{ + i.result = request.session->done == Done::loggedout; +} + + + +} // namespace TemplatesFunctions + + + + +void Templates::CreateFunctions() +{ + using namespace TemplatesFunctions; + + functions.Clear(); + + functions.Insert("language", language); + functions.Insert("title", title); + functions.Insert("charset", charset); + functions.Insert("content", content); + functions.Insert("version_major", version_major); + functions.Insert("version_minor", version_minor); + functions.Insert("version_revision", version_revision); + functions.Insert("base_url", base_url); + functions.Insert("current_url", current_url); + functions.Insert("user_logged", user_logged); + functions.Insert("user", user); + + functions.Insert("item_id", item_id); + functions.Insert("item_subject", item_subject); + functions.Insert("item_content", item_content); + functions.Insert("item_url_subject", item_url_subject); + functions.Insert("item_dir", item_dir); + + functions.Insert("old_item_id", old_item_id); + functions.Insert("old_item_subject", old_item_subject); + functions.Insert("old_item_content", old_item_content); + functions.Insert("old_item_url_subject", old_item_url_subject); + functions.Insert("old_item_dir", old_item_dir); + + functions.Insert("dir_items", dir_items); + functions.Insert("items", items); + functions.Insert("item_subject2", item_subject2); + functions.Insert("dir_subject2", dir_subject2); + functions.Insert("full_dir", full_dir); + functions.Insert("dir_url_subject2", dir_url_subject2); + functions.Insert("item_url_subject2", item_url_subject2); + functions.Insert("item_content2", item_content2); + functions.Insert("item_id2", item_id2); + + + functions.Insert("edit_item", edit_item); + + + functions.Insert("incorrect_dir", incorrect_dir); + + functions.Insert("fcurrent_dir", fcurrent_dir); + functions.Insert("current_dir_part_name", current_dir_part_name); + functions.Insert("current_dir_part_url", current_dir_part_url); + + functions.Insert("added_item", added_item); + functions.Insert("edited_item", edited_item); + functions.Insert("deleted_item", deleted_item); + functions.Insert("loggedout", loggedout); + functions.Insert("deleted_item_errors", deleted_item_errors); + + + functions.Insert("done_with_errors", done_with_errors); + functions.Insert("done_status", done_status); + + + + + + functions.Insert("fitems_in_dir", fitems_in_dir); + +} + + + + + +void Templates::Read() +{ + using namespace TemplatesFunctions; + + pat_index.Directory(data.templates); + pat_index.ParseFile(data.default_index); + + pat_item.Directory(data.templates); + pat_item.ParseFile("item.html"); + + pat_dir.Directory(data.templates); + pat_dir.ParseFile("dir.html"); + + pat_item_add_edit.Directory(data.templates); + pat_item_add_edit.ParseFile("item_add_edit.html"); + + pat_err_404.Directory(data.templates); + pat_err_404.ParseFile("err_404.html"); + + pat_item_del_confirm.Directory(data.templates); + pat_item_del_confirm.ParseFile("item_del_confirm.html"); + + pat_err_internal.Directory(data.templates); + pat_err_internal.ParseFile("err_internal.html"); + + CreateFunctions(); + +} + + + +void Templates::Generate() +{ + using namespace TemplatesFunctions; + + // clear some variables (indexes for example) + item_index = 0; + current_dir_index = 0; + + + Generator generator(request.page, pat_index, functions); + + generator.Generate(); +} + diff --git a/core/templates.h b/core/templates.h new file mode 100755 index 0000000..7167ad4 --- /dev/null +++ b/core/templates.h @@ -0,0 +1,44 @@ +/* + * This file is a part of CMSLU -- Content Management System like Unix + * and is not publicly distributed + * + * Copyright (c) 2008, Tomasz Sowa + * All rights reserved. + * + */ + +#ifndef headerfiletemplates +#define headerfiletemplates + + +#include "../../ezc/src/ezc.h" +#include "data.h" +#include "request.h" +#include "item.h" +#include "db.h" +#include "error.h" + +using namespace Ezc; + + + + +class Templates +{ + + + +public: + + + void Read(); + void Generate(); + + void CreateFunctions(); + + +}; + + + +#endif