580 lines
12 KiB
C++
Executable File
580 lines
12 KiB
C++
Executable File
/*
|
|
* This file is a part of Winix
|
|
* and is not publicly distributed
|
|
*
|
|
* Copyright (c) 2008-2010, Tomasz Sowa
|
|
* All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include "content.h"
|
|
#include "../core/request.h"
|
|
#include "../core/error.h"
|
|
#include "../core/db.h"
|
|
#include "../core/data.h"
|
|
#include "../core/misc.h"
|
|
#include "../core/plugin.h"
|
|
|
|
|
|
|
|
bool Content::Init()
|
|
{
|
|
templates.ReadIndexFileNames();
|
|
templates.ReadTemplates();
|
|
templates.CreateFunctions();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Content::DirsHaveReadExecPerm()
|
|
{
|
|
std::vector<Item*>::iterator i;
|
|
|
|
for(i = request.dir_table.begin() ; i!=request.dir_table.end() ; ++i)
|
|
{
|
|
if( !request.HasReadExecAccess(**i) )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
void Content::SetDefaultFunctionForFile()
|
|
{
|
|
if( request.item.auth != Item::auth_none )
|
|
request.pfunction = data.functions.GetFunction(FUN_DOWNLOAD);
|
|
else
|
|
if( request.HasReadExecAccess(request.item) )
|
|
request.pfunction = data.functions.GetFunction(FUN_RUN);
|
|
else
|
|
request.pfunction = data.functions.GetFunction(FUN_CAT);
|
|
|
|
if( request.pfunction )
|
|
log << log3 << "Content: default function: " << request.pfunction->item.url << logend;
|
|
}
|
|
|
|
|
|
|
|
|
|
void Content::SetDefaultFunctionForDir()
|
|
{
|
|
long default_item = request.dir_table.back()->default_item;
|
|
|
|
if( default_item != -1 )
|
|
{
|
|
log << log3 << "Content: Default item: id: " << default_item << logend;
|
|
RedirectTo(default_item);
|
|
return;
|
|
}
|
|
|
|
|
|
if( data.mounts.pmount->type == Mount::thread )
|
|
{
|
|
request.pfunction = data.functions.GetFunction(FUN_THREAD);
|
|
|
|
if( request.pfunction )
|
|
log << log3 << "Content: default function: " << request.pfunction->item.url << logend;
|
|
}
|
|
else
|
|
if( data.mounts.pmount->type == Mount::ticket )
|
|
{
|
|
request.pfunction = data.functions.GetFunction(FUN_TICKET);
|
|
|
|
if( request.pfunction )
|
|
log << log3 << "Content: default function: " << request.pfunction->item.url << logend;
|
|
}
|
|
else
|
|
{
|
|
// cms
|
|
request.pfunction = data.functions.GetFunction(FUN_LS);
|
|
|
|
if( request.pfunction )
|
|
log << log3 << "Content: default function: " << request.pfunction->item.url << logend;
|
|
}
|
|
}
|
|
|
|
|
|
void Content::SetDefaultFunction()
|
|
{
|
|
if( request.is_item )
|
|
{
|
|
SetDefaultFunctionForFile();
|
|
}
|
|
else
|
|
{
|
|
SetDefaultFunctionForDir();
|
|
}
|
|
}
|
|
|
|
|
|
void Content::FunNothing()
|
|
{
|
|
/* do nothing */
|
|
}
|
|
|
|
|
|
void Content::CallFunction()
|
|
{
|
|
static FunItem tab[] = {
|
|
{FUN_LOGOUT, &Content::FunLogout},
|
|
{FUN_CAT, &Content::FunCat},
|
|
{FUN_LS, &Content::FunLs},
|
|
{FUN_EMACS, &Content::FunEmacs},
|
|
{FUN_MKDIR, &Content::FunMkdir},
|
|
{FUN_DEFAULT, &Content::FunDefault},
|
|
{FUN_PRIV, &Content::FunPriv},
|
|
{FUN_RM, &Content::FunRm},
|
|
{FUN_RUN, &Content::FunRun},
|
|
{FUN_NODE, &Content::FunNode},
|
|
{FUN_WHO, &Content::FunWho},
|
|
{FUN_LAST, &Content::FunLast},
|
|
{FUN_THREAD, &Content::FunThread},
|
|
{FUN_RELOAD, &Content::FunReload},
|
|
{FUN_UPLOAD, &Content::FunUpload},
|
|
{FUN_TICKET, &Content::FunTicket},
|
|
{FUN_CKEDITOR, &Content::FunEmacs},
|
|
{FUN_TINYMCE, &Content::FunEmacs},
|
|
{FUN_LOGIN, &Content::FunLogin},
|
|
{FUN_MV, &Content::FunMv},
|
|
{FUN_UNAME, &Content::FunUname},
|
|
{FUN_CHMOD, &Content::FunPriv},
|
|
{FUN_CHOWN, &Content::FunPriv},
|
|
{FUN_DOWNLOAD, &Content::FunDownload},
|
|
{FUN_ADDUSER, &Content::FunAddUser},
|
|
{FUN_SUBJECT, &Content::FunSubject},
|
|
{FUN_CP, &Content::FunCp},
|
|
{FUN_UPTIME, &Content::FunNothing},
|
|
{FUN_EDITTICKET,&Content::FunEditTicket},
|
|
{FUN_CREATETHREAD, &Content::FunCreateThread},
|
|
{FUN_CREATETICKET, &Content::FunCreateTicket}
|
|
};
|
|
|
|
size_t len = sizeof(tab) / sizeof(FunItem);
|
|
size_t i;
|
|
|
|
for(i=0 ; i<len ; ++i)
|
|
{
|
|
if( tab[i].code == request.pfunction->code )
|
|
{
|
|
(this->*tab[i].fun)();
|
|
return;
|
|
}
|
|
}
|
|
|
|
request.status = WINIX_ERR_PERMISSION_DENIED;
|
|
}
|
|
|
|
|
|
void Content::MakeStandardFunction()
|
|
{
|
|
if( request.role == Request::authorizer )
|
|
{
|
|
// in authorizer mode only cat function is available
|
|
// (and must be default)
|
|
|
|
if( request.pfunction )
|
|
{
|
|
request.status = WINIX_ERR_NO_ITEM;
|
|
log << log1 << "Content: in authorizer mode only 'cat' funtion is available and must "
|
|
"be default (not in the url)" << logend;
|
|
return;
|
|
}
|
|
|
|
request.pfunction = data.functions.GetFunction(FUN_CAT);
|
|
}
|
|
|
|
if( !request.pfunction )
|
|
SetDefaultFunction();
|
|
|
|
if( !request.redirect_to.empty() )
|
|
return;
|
|
|
|
if( !request.pfunction )
|
|
{
|
|
request.status = WINIX_ERR_NO_FUNCTION;
|
|
log << log1 << "Content: no function (neither cat nor ls)" << logend;
|
|
return;
|
|
}
|
|
|
|
CallFunction();
|
|
}
|
|
|
|
|
|
|
|
|
|
void Content::CallPostFunction()
|
|
{
|
|
static FunItem tab[] = {
|
|
{FUN_RUN, &Content::PostFunRun},
|
|
{FUN_EMACS, &Content::PostFunEmacs},
|
|
{FUN_MKDIR, &Content::PostFunMkdir},
|
|
{FUN_DEFAULT, &Content::PostFunDefault},
|
|
{FUN_PRIV, &Content::PostFunPriv},
|
|
{FUN_CHMOD, &Content::PostFunPriv},
|
|
{FUN_CHOWN, &Content::PostFunPriv},
|
|
{FUN_LOGIN, &Content::PostFunLogin},
|
|
{FUN_UPLOAD, &Content::PostFunUpload},
|
|
{FUN_EDITTICKET,&Content::PostFunEditTicket},
|
|
{FUN_CKEDITOR, &Content::PostFunEmacs},
|
|
{FUN_TINYMCE, &Content::PostFunEmacs},
|
|
{FUN_ADDUSER, &Content::PostFunAddUser},
|
|
{FUN_MV, &Content::PostFunMv},
|
|
{FUN_SUBJECT, &Content::PostFunSubject},
|
|
{FUN_CP, &Content::PostFunCp},
|
|
{FUN_CREATETHREAD, &Content::PostFunCreateThread},
|
|
{FUN_CREATETICKET, &Content::PostFunCreateTicket}
|
|
};
|
|
|
|
size_t len = sizeof(tab) / sizeof(FunItem);
|
|
size_t i;
|
|
|
|
for(i=0 ; i<len ; ++i)
|
|
{
|
|
if( tab[i].code == request.pfunction->code )
|
|
{
|
|
(this->*tab[i].fun)();
|
|
return;
|
|
}
|
|
}
|
|
|
|
log << log1 << "Content: unknown post function" << logend;
|
|
request.status = WINIX_ERR_PERMISSION_DENIED;
|
|
}
|
|
|
|
|
|
void Content::MakePost()
|
|
{
|
|
if( request.role == Request::authorizer )
|
|
{
|
|
request.status = WINIX_ERR_PERMISSION_DENIED;
|
|
return;
|
|
}
|
|
|
|
if( !request.pfunction )
|
|
SetDefaultFunction();
|
|
|
|
if( !request.pfunction )
|
|
{
|
|
request.status = WINIX_ERR_NO_FUNCTION;
|
|
log << log1 << "Content: MakePost: no function" << logend;
|
|
return;
|
|
}
|
|
|
|
CallPostFunction();
|
|
}
|
|
|
|
|
|
void Content::MakePage()
|
|
{
|
|
bool sent = false;
|
|
|
|
if( !request.redirect_to.empty() ||
|
|
!request.x_sendfile.empty() )
|
|
return;
|
|
|
|
|
|
if( request.is_item && request.item.auth == Item::auth_none &&
|
|
request.item.content_type == Item::ct_raw && request.status == WINIX_ERR_OK && request.pfunction )
|
|
{
|
|
if( request.pfunction->code == FUN_CAT )
|
|
{
|
|
request.page << request.item.content;
|
|
sent = true;
|
|
}
|
|
else
|
|
if( request.pfunction->code == FUN_RUN )
|
|
{
|
|
templates.GenerateRunRaw();
|
|
sent = true;
|
|
}
|
|
}
|
|
|
|
if( !sent )
|
|
{
|
|
templates.Generate();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Content::Make()
|
|
{
|
|
if( request.dir_table.empty() )
|
|
{
|
|
log << log1 << "Content: there is no a root dir (dir_table is empty)" << logend;
|
|
return;
|
|
}
|
|
|
|
// request.status can be changed by function_parser
|
|
if( request.status == WINIX_ERR_OK )
|
|
{
|
|
if( DirsHaveReadExecPerm() )
|
|
{
|
|
if( request.method == Request::post )
|
|
MakePost();
|
|
|
|
if( request.redirect_to.empty() && request.status == WINIX_ERR_OK )
|
|
MakeStandardFunction();
|
|
}
|
|
else
|
|
request.status = WINIX_ERR_PERMISSION_DENIED;
|
|
}
|
|
|
|
if( request.session->spam_score > 0 )
|
|
log << log1 << "Content: spam score: " << request.session->spam_score << logend;
|
|
|
|
if( request.IsParam("noredirect") )
|
|
request.redirect_to.clear();
|
|
|
|
if( !request.redirect_to.empty() )
|
|
return;
|
|
|
|
if( request.dir_table.empty() )
|
|
{
|
|
log << log1 << "Content: there is no a root dir (dir_table is empty -- after calling some standard functions)" << logend;
|
|
return;
|
|
}
|
|
|
|
plugin.Call(WINIX_CONTENT_MAKE);
|
|
MakePage();
|
|
|
|
//request.PrintGetTable();
|
|
//request.PrintEnv();
|
|
//request.PrintIn();
|
|
}
|
|
|
|
|
|
|
|
|
|
// !! mozna zrobic jakas obsluge kiedy nie mozemy sie redirectnac, np gdy wystapil blad
|
|
// !! moze zwracac jakas wartosc?
|
|
void Content::RedirectTo(const Item & item, const char * postfix)
|
|
{
|
|
std::string path;
|
|
|
|
request.redirect_to = data.base_url;
|
|
|
|
|
|
if( item.type == Item::dir )
|
|
{
|
|
// item_id is pointing to a directory
|
|
data.dirs.MakePath(item.id, path);
|
|
request.redirect_to += path;
|
|
}
|
|
else
|
|
{
|
|
if( !data.dirs.MakePath(item.parent_id, path) )
|
|
log << log1 << "Content: Can't redirect: no dirs for item id: " << item.id << logend;
|
|
|
|
request.redirect_to += path;
|
|
request.redirect_to += item.url;
|
|
}
|
|
|
|
if( postfix )
|
|
request.redirect_to += postfix;
|
|
}
|
|
|
|
|
|
|
|
void Content::RedirectTo(long item_id, const char * postfix)
|
|
{
|
|
std::string path;
|
|
Item * pdir;
|
|
|
|
request.redirect_to = data.base_url;
|
|
pdir = data.dirs.GetDir(item_id);
|
|
|
|
|
|
if( pdir )
|
|
{
|
|
// item_id is pointing to a directory
|
|
data.dirs.MakePath(pdir->id, path);
|
|
request.redirect_to += path;
|
|
}
|
|
else
|
|
{
|
|
// !! zrobic nowy interfejs
|
|
// !! GetItem pozamieniac na GetFile
|
|
db.GetItem(request.item_table, item_id);
|
|
|
|
if( !request.item_table.empty() )
|
|
{
|
|
if( !data.dirs.MakePath(request.item_table[0].parent_id, path) )
|
|
log << log1 << "Content: Can't redirect: no dirs for item id: " << request.item_table[0].id << ", requested directory id: " << request.item_table[0].parent_id << logend;
|
|
|
|
request.redirect_to += path + request.item_table[0].url;
|
|
}
|
|
else
|
|
{
|
|
log << log1 << "Content: Can't redirect: no such item: id: " << item_id << logend;
|
|
}
|
|
}
|
|
|
|
if( postfix )
|
|
request.redirect_to += postfix;
|
|
}
|
|
|
|
|
|
void Content::RedirectToLastDir()
|
|
{
|
|
RedirectTo( *request.dir_table.back() );
|
|
}
|
|
|
|
|
|
|
|
void Content::ReadAdditionalInfo()
|
|
{
|
|
if( request.dir_table.empty() )
|
|
return;
|
|
|
|
if( data.mounts.pmount->type == Mount::thread )
|
|
{
|
|
if( db.GetThreadByDirId(request.dir_table.back()->id, request.thread) == WINIX_ERR_OK )
|
|
request.is_thread = true;
|
|
}
|
|
else
|
|
if( data.mounts.pmount->type == Mount::ticket )
|
|
{
|
|
if( db.GetTicketByDirId(request.dir_table.back()->id, request.ticket) == WINIX_ERR_OK )
|
|
{
|
|
request.is_ticket = true;
|
|
|
|
if( !request.is_item && (!request.pfunction || request.pfunction->code == FUN_TICKET) )
|
|
{
|
|
db.GetItemById(request.ticket.item_id, request.item);
|
|
// don't set request.is_item here
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Content::PrepareUrl(Item & item)
|
|
{
|
|
TrimWhite(item.url);
|
|
|
|
if( item.url.empty() )
|
|
item.url = item.subject; // if the subject is empty then the url will be corrected by CorrectUrlOnlyAllowedChar()
|
|
|
|
CorrectUrlOnlyAllowedChar(item.url);
|
|
|
|
if( data.functions.GetFunction(item.url) )
|
|
{
|
|
// the name provided by an user is the same as a name of a function
|
|
// we add one underscore character at the beginning
|
|
|
|
// 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.insert(item.url.begin(), '_');
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool Content::CheckRebus()
|
|
{
|
|
if( request.session->puser )
|
|
// logged user don't have to use the rebus
|
|
return true;
|
|
|
|
if( request.session->rebus_checked )
|
|
return true;
|
|
|
|
request.session->rebus_checked = true;
|
|
|
|
if( !request.session->rebus_item )
|
|
{
|
|
log << log1 << "Content: rebus not set" << logend;
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
std::string * answer = request.PostVar("rebus");
|
|
|
|
if( answer && data.rebus.IsAnswerOk(request.session->rebus_item, *answer) )
|
|
return true;
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
}
|
|
|
|
log << log1 << "Content: rebus has an incorrect answer" << logend;
|
|
// don't add request.session->spam_score when the rebus has incorrect answer
|
|
// a user could have made a mistake
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
void Content::SetUser(Item & item)
|
|
{
|
|
if( request.session->puser )
|
|
{
|
|
item.user_id = request.session->puser->id;
|
|
item.guest_name.clear();
|
|
}
|
|
else
|
|
{
|
|
item.user_id = -1;
|
|
request.PostVar("guestname", item.guest_name);
|
|
}
|
|
|
|
item.group_id = request.dir_table.back()->group_id;
|
|
}
|
|
|
|
|
|
|
|
void Content::CheckGetPostTimes(time_t difference)
|
|
{
|
|
time_t now = std::time(0);
|
|
|
|
if( request.session->puser )
|
|
return;
|
|
|
|
if( request.method != Request::post )
|
|
return;
|
|
|
|
if( now - request.session->last_time_get >= (time_t)difference )
|
|
return;
|
|
|
|
if( request.AllPostVarEmpty() )
|
|
return;
|
|
|
|
request.session->spam_score += 1;
|
|
log << log1 << "Content: spam +1: POST after GET sent too fast" << logend;
|
|
}
|
|
|
|
|
|
/*
|
|
bool Content::CreateFile(const std::string & path, const std::string & content)
|
|
{
|
|
std::ofstream file(path.c_str(), std::ios_base::binary | std::ios_base::out);
|
|
|
|
if( !file )
|
|
{
|
|
log << log1 << "Content: can't create file: " << path << logend;
|
|
return false;
|
|
}
|
|
|
|
file << content;
|
|
|
|
file.close();
|
|
|
|
// !! dodac sprawdzenie prawidlowosci zapisania pliku
|
|
|
|
return true;
|
|
}
|
|
*/
|
|
|
|
|
|
|