import the first version of cmslu

git-svn-id: svn://ttmath.org/publicrep/cmslu/trunk@460 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2008-12-10 04:42:49 +00:00
parent d4a5f1f963
commit c53e985a92
37 changed files with 4944 additions and 0 deletions

46
Makefile Executable file
View File

@ -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)

477
core/content.cpp Executable file
View File

@ -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<Item>::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<Item>::size_type a;
for(a=0 ; a<request.cur_dir_table.size() ; ++a)
{
dir += request.cur_dir_table[a].url_subject;
dir += '/';
}
}
void Content::MakeShowItemById()
{
if( get_index == request.get_table.size() )
{
request.result = Request::err404;
}
else
{
long id = atol( request.get_table[get_index++].c_str() );
db.GetItem(request.item_table, id);
if( request.item_table.empty() )
request.result = Request::err404;
else
{
request.result = Request::redirect;
std::string path;
data.dir.MakePath(request.item_table[0].parent_id, path);
request.str = data.base_url + path + request.item_table[0].url_subject;
}
}
}
void Content::MakeDelItem()
{
if( !request.session->is_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();
}

73
core/content.h Executable file
View File

@ -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 <cstdlib>
#include <fcgiapp.h>
#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

70
core/cookieparser.h Executable file
View File

@ -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 <fcgiapp.h>
#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<CookieTable::iterator, bool> 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

46
core/data.cpp Executable file
View File

@ -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;
}

88
core/data.h Executable file
View File

@ -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 <string>
#include <vector>
#include <map>
#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

668
core/db.cpp Executable file
View File

@ -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<char*>( 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<char*>( 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<rows ; ++i)
{
item.id = atol( AssertValue(r, i, cid) );
item.subject = AssertValue(r, i, csubject);
CheckAllUrlSubjectModifyItem(item);
}
}
catch(const Error &)
{
}
ClearResult(r);
}
long Db::AssertCurrval(const char * table)
{
PGresult * r;
std::ostringstream query;
query << "select currval('" << table << "');";
r = AssertQuery(query.str());
AssertResultStatus(r, PGRES_TUPLES_OK);
if( PQntuples(r) != 1 )
{
log << log1 << "Db: error (currval) for table: " << table << ", " << PQerrorMessage(pg_conn) << logend;
throw Error(Error::db_err_currval);
}
long res = strtol( AssertValue(r, 0, 0), 0, 10 );
return res;
}
Error Db::AddItem(Item & item)
{
PGresult * r = 0;
Error result = Error::ok;
bool url_without_id = false;
try
{
AssertConnection();
std::ostringstream query;
query << "insert into core.item (subject, content, url_subject, type, parent_id) values (";
query << '\'' << Escape(item.subject) << "', ";
query << '\'' << Escape(item.content) << "', ";
// url_subject
url_without_id = AddItemCreateUrlSubject(item);
if( url_without_id )
{
query << '\'' << Escape(item.url_subject) << "', ";
}
else
{
query << "currval('core.item_id_seq')" << ", ";
}
query << '\'' << static_cast<int>(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<int>(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> & 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<rows ; ++i)
{
col.SetItem(r, i, item);
item_table.push_back(item);
}
}
catch(const Error &)
{
}
ClearResult(r);
}
void Db::GetItem(std::vector<Item> & 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<rows ; ++i)
{
col.SetItem(r, i, item);
item_table.push_back(item);
}
}
catch(const Error &)
{
}
ClearResult(r);
}
bool Db::DelItem(long id)
{
long rows = 0;
PGresult * r = 0;
try
{
AssertConnection();
std::ostringstream query;
query << "delete from core.item where type='1' and id='" << id << "';";
r = AssertQuery( query.str() );
AssertResultStatus(r, PGRES_COMMAND_OK);
const char * crows = PQcmdTuples(r);
if( crows )
{
rows = atol(crows);
if( rows > 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<rows ; ++i)
{
col.SetItem(r, i, item);
dir_table.PushBack( item );
}
}
catch(const Error &)
{
}
ClearResult(r);
}

119
core/db.h Executable file
View File

@ -0,0 +1,119 @@
/*
* 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 headerfilecoredb
#define headerfilecoredb
#include <string>
#include <vector>
#include <map>
#include <sstream>
#include <libpq-fe.h>
#include <cstdio>
#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> & item_table, Item & item_ref);
void GetItem(std::vector<Item> & 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<Item::Type>( 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

220
core/dir.cpp Executable file
View File

@ -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<Item> & 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;
}

80
core/dir.h Executable file
View File

@ -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 <vector>
#include <map>
#include <string>
#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<long, Item> 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<Item> & 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

161
core/dircontainer.cpp Executable file
View File

@ -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;
}

66
core/dircontainer.h Executable file
View File

@ -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 <vector>
#include <map>
#include "item.h"
#include "log.h"
class DirContainer
{
public:
typedef std::vector<Item> Table;
typedef Table::iterator Iterator;
typedef Table::size_type SizeType;
typedef std::map<long, Iterator> TableId;
typedef std::multimap<long, Iterator> 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

42
core/done.cpp Executable file
View File

@ -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;
}

45
core/done.h Executable file
View File

@ -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

73
core/error.cpp Executable file
View File

@ -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<Code>(i);
}
Error::operator int() const
{
return static_cast<int>(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<int>(e.code);
return out;
}
Log & operator<<(Log & out, const Error & e)
{
out << static_cast<int>(e.code);
return out;
}

71
core/error.h Executable file
View File

@ -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 <iostream>
#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

57
core/getparser.h Executable file
View File

@ -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

231
core/httpsimpleparser.cpp Executable file
View File

@ -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<s.size() && IsWhite(s[i]) ; ++i);
if( i == s.size() )
{
// all characters are white
s.clear();
return;
}
if( 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
}
}

74
core/httpsimpleparser.h Executable file
View File

@ -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 <string>
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

73
core/item.h Executable file
View File

@ -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 <string>
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

177
core/log.cpp Executable file
View File

@ -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;
}

61
core/log.h Executable file
View File

@ -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 <sstream>
#include <fstream>
#include <iostream>
#include <string>
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

73
core/main.cpp Executable file
View File

@ -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 <cstdlib>
#include <ctime>
#include <signal.h>
#include <iostream>
#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;
}

138
core/misc.cpp Executable file
View File

@ -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 << "&lt;";
else
if( *i == '>' )
out << "&gt;";
else
out << *i;
}
}
std::string HtmlSpecial(const std::string & in)
{
std::ostringstream out;
HtmlSpecial(out, in);
return out.str();
}

33
core/misc.h Executable file
View File

@ -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 <string>
#include <sstream>
#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

56
core/postparser.h Executable file
View File

@ -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 <fcgiapp.h>
#include <string>
#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<PostTable::iterator, bool> 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

374
core/request.cpp Executable file
View File

@ -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);
FCGX_PutS(d.c_str(), out);
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<dane.length() ; ++i)
{
wynik += tohex(dane[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<dane.length()-1 ; i+=2)
{
znak1 = parsujhex(dane[i]);
znak2 = parsujhex(dane[i+1]);
znak = (znak1 << 4) + znak2;
wynik += znak;
}
return wynik;
}
string Request::ToUrl(const string & dane)
{
string wynik;
unsigned int i;
for(i=0 ; i<dane.length() ; ++i)
{
if( (dane[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;
}
*/

116
core/request.h Executable file
View File

@ -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 <fcgiapp.h>
#include <sstream>
#include <vector>
#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<Item> cur_dir_table;
// id of the last directory (bar) or -1
long dir;
// items in the current directory
// maybe without contents?
std::vector<Item> item_table;
// directories in the current directory
std::vector<Item> 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

137
core/requestcontroller.cpp Executable file
View File

@ -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;
}
}

45
core/requestcontroller.h Executable file
View File

@ -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 <unistd.h>
#include <sys/stat.h>
#include <iostream>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#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

26
core/requesttypes.h Executable file
View File

@ -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 <string>
#include <vector>
#include <map>
// some global types used by Request class
typedef std::vector<std::string> GetTable;
typedef std::map<std::string, std::string> PostTable;
typedef std::map<std::string, std::string> CookieTable;
#endif

73
core/session.cpp Executable file
View File

@ -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;
}
}

63
core/session.h Executable file
View File

@ -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 <ctime>
#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

161
core/sessionmanager.cpp Executable file
View File

@ -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<SessionTable::iterator,bool> res = session_table.insert(s);
request.session = const_cast<Session*>( &(*res.first) );
}
else
{
request.session = const_cast<Session*>( &(*i) );
}
}
void SessionManager::CreateSession()
{
Session s;
int attempts = 100;
for( ; attempts > 0 ; --attempts )
{
s.id = CreateSessionId();
std::pair<SessionTable::iterator,bool> res = session_table.insert(s);
if( res.second == true )
{
// the insertion took place
request.session = const_cast<Session*>( &(*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<Session*>( &(*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
}

45
core/sessionmanager.h Executable file
View File

@ -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 <set>
#include <ctime>
#include "request.h"
#include "log.h"
#include "data.h"
#include "session.h"
#include "db.h"
class SessionManager
{
// !! zamienic na map
typedef std::set<Session> SessionTable;
SessionTable session_table;
bool IsSession(long s);
long CreateSessionId();
void CreateTemporarySession();
void CreateSession();
public:
void SetSession();
};
#endif

542
core/templates.cpp Executable file
View File

@ -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<Item>::size_type a;
for(a=0 ; a<request.cur_dir_table.size() ; ++a)
{
i.out << request.cur_dir_table[a].url_subject << '/';
}
}
std::vector<Item>::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<Item>::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<Item>::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<int>( 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();
}

44
core/templates.h Executable file
View File

@ -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