winix/content/content.cpp

617 lines
12 KiB
C++
Executable File

/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2009, 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.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 )
{
request.session->IncrementTimersIfExist();
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::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;
}
if( request.pfunction->code == FUN_LOGOUT )
FunLogout();
else
if( request.pfunction->code == FUN_CAT )
FunCat();
else
if( request.pfunction->code == FUN_LS )
FunLs();
else
if( request.pfunction->code == FUN_EMACS )
FunEmacs();
else
if( request.pfunction->code == FUN_MKDIR )
FunMkdir();
else
if( request.pfunction->code == FUN_DEFAULT )
FunDefault();
else
if( request.pfunction->code == FUN_PRIV )
FunPriv();
else
if( request.pfunction->code == FUN_RM )
FunRm();
else
if( request.pfunction->code == FUN_RUN )
FunRun();
else
if( request.pfunction->code == FUN_NODE )
FunNode();
else
if( request.pfunction->code == FUN_WHO )
FunWho();
else
if( request.pfunction->code == FUN_LAST )
FunLast();
else
if( request.pfunction->code == FUN_THREAD )
FunThread();
else
if( request.pfunction->code == FUN_RELOAD )
FunReload();
else
if( request.pfunction->code == FUN_CREATETHREAD )
FunCreateThread();
else
if( request.pfunction->code == FUN_UPLOAD )
FunUpload();
else
if( request.pfunction->code == FUN_CREATETICKET )
FunCreateTicket();
else
if( request.pfunction->code == FUN_EDITTICKET )
FunEditTicket();
else
if( request.pfunction->code == FUN_TICKET )
FunTicket();
else
if( request.pfunction->code == FUN_CKEDITOR )
FunEmacs();
else
if( request.pfunction->code == FUN_LOGIN )
FunLogin();
else
if( request.pfunction->code == FUN_UPTIME )
{ /* do nothing */ }
/* else
if( request.pfunction->code == FUN_MV )
FunMv();
else
if( request.pfunction->code == FUN_UNAME )
FunUname();
*/
else
if( request.pfunction->code == FUN_CHMOD )
FunPriv();
else
if( request.pfunction->code == FUN_CHOWN )
FunPriv();
else
if( request.pfunction->code == FUN_DOWNLOAD )
FunDownload();
else
if( request.pfunction->code == FUN_ADDUSER )
FunAddUser();
else
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;
}
switch( request.pfunction->code )
{
case FUN_RUN:
PostFunRun();
break;
case FUN_EMACS:
PostFunEmacs();
break;
case FUN_MKDIR:
PostFunMkdir();
break;
case FUN_DEFAULT:
PostFunDefault();
break;
case FUN_PRIV:
case FUN_CHMOD:
case FUN_CHOWN:
PostFunPriv();
break;
case FUN_LOGIN:
PostFunLogin();
break;
case FUN_CREATETHREAD:
PostFunCreateThread();
break;
case FUN_UPLOAD:
PostFunUpload();
break;
case FUN_CREATETICKET:
PostFunCreateTicket();
break;
case FUN_EDITTICKET:
PostFunEditTicket();
break;
case FUN_CKEDITOR:
PostFunEmacs();
break;
case FUN_ADDUSER:
PostFunAddUser();
break;
default:
log << log1 << "Content: unknown post function" << logend;
break;
}
}
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.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)
{
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;
}
}
void Content::RedirectTo(long item_id)
{
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;
}
}
}
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);
}
}
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;
}
*/