winix/core/system.cpp

569 lines
10 KiB
C++
Raw Normal View History

/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010, Tomasz Sowa
* All rights reserved.
*
*/
#include "system.h"
#include "misc.h"
#include "error.h"
#include "notify.h"
#include "templates/templates.h"
void System::SetRequest(Request * prequest)
{
request = prequest;
}
void System::SetConfig(Config * pconfig)
{
config = pconfig;
}
void System::SetDb(Db * pdb)
{
db = pdb;
}
void System::Init()
{
dirs.SetDb(db);
dirs.SetRequest(request);
dirs.ReadDirs();
mounts.SetDirs(&dirs);
mounts.SetDb(db);
mounts.SetRequest(request);
mounts.CreateMounts();
mounts.ReadMounts();
users.SetRequest(request);
users.ReadUsers(db);
users.SetTimeZoneOffset(config->time_zone_offset);
groups.ReadGroups(db); // !! chwilowe przekazanie argumentu, db bedzie zmienione
rebus.SetRequest(request);
rebus.Init();
}
// !! mozna zrobic jakas obsluge kiedy nie mozemy sie redirectnac, np gdy wystapil blad
// !! moze zwracac jakas wartosc?
void System::RedirectTo(const Item & item, const char * postfix)
{
request->redirect_to = config->base_url;
if( item.type == Item::dir )
{
// item_id is pointing to a directory
dirs.MakePath(item.id, path);
request->redirect_to += path;
}
else
{
if( !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 System::RedirectTo(long item_id, const char * postfix)
{
std::string path;
Item * pdir;
request->redirect_to = config->base_url;
pdir = dirs.GetDir(item_id);
if( pdir )
{
// item_id is pointing to a directory
dirs.MakePath(pdir->id, path);
request->redirect_to += path;
}
else
{
// !! zrobic nowy interfejs
// !! GetItem pozamieniac na GetFile
// !! i nie uzywac request->item_tab (zrobic sobie lokalny tutaj)
db->GetItem(request->item_tab, item_id);
if( !request->item_tab.empty() )
{
if( !dirs.MakePath(request->item_tab[0].parent_id, path) )
log << log1 << "Content: Can't redirect: no dirs for item id: "
<< request->item_tab[0].id << ", requested directory id: "
<< request->item_tab[0].parent_id << logend;
request->redirect_to += path + request->item_tab[0].url;
}
else
{
log << log1 << "Content: Can't redirect: no such item: id: " << item_id << logend;
}
}
if( postfix )
request->redirect_to += postfix;
}
void System::RedirectToLastDir()
{
if( !request->dir_tab.empty() )
RedirectTo( *request->dir_tab.back() );
}
void System::RedirectToLastItem()
{
if( request->last_item )
RedirectTo( *request->last_item );
}
bool System::CanChangeUser(const Item & item, long new_user_id)
{
if( !request->session )
// session must be set
return false;
if( request->session->puser && request->session->puser->super_user )
// super user is allowed everything
return true;
if( item.user_id != new_user_id )
// only super user can change the owner of an item
return false;
return true;
}
bool System::CanChangeGroup(const Item & item, long new_group_id)
{
if( !request->session )
// session must be set
return false;
if( request->session->puser && request->session->puser->super_user )
// super user is allowed everything
return true;
if( item.group_id != new_group_id )
{
// user is allowed to change the group only if he is an owner of the item
// he can change only into a group in which he is a member of, or into a 'no_group'
if( !request->session->puser )
return false;
if( request->session->puser->id != item.user_id )
return false;
if( new_group_id == -1 )
return true;
if( !request->session->puser->IsMemberOf(new_group_id) )
return false;
// is logged, is the owner of the item, is the member of the new group
}
return true;
}
bool System::CanChangePrivileges(const Item & item, int new_priv)
{
if( !request->session )
// session must be set
return false;
if( request->session->puser && request->session->puser->super_user )
// super user is allowed everything
return true;
if( item.privileges != new_priv )
{
// the owner of an item is allowed to change the privileges
if( !request->session->puser )
return false;
if( request->session->puser->id != item.user_id )
return false;
}
return true;
}
bool System::HasAccess(const Item & item, int mask)
{
if( !request->session )
// session must be set
return false;
if( request->session->puser && request->session->puser->super_user )
// super user is allowed everything
return true;
if( request->session->puser && request->session->puser->id == item.user_id )
{
// the owner
return ((item.privileges >> 6) & mask) == mask;
}
if( request->session->puser && request->session->puser->IsMemberOf(item.group_id) )
{
// group
return ((item.privileges >> 3) & mask) == mask;
}
// others
return (item.privileges & mask) == mask;
}
bool System::HasReadAccess(const Item & item)
{
return HasAccess(item, 4);
}
bool System::HasWriteAccess(const Item & item)
{
return HasAccess(item, 2);
}
bool System::HasReadWriteAccess(const Item & item)
{
return HasAccess(item, 6); // r+w
}
bool System::HasReadExecAccess(const Item & item)
{
if( request->session && request->session->puser && request->session->puser->super_user )
{
// there must be at least one 'x' (for the root)
return (item.privileges & 0111) != 0;
}
return HasAccess(item, 5); // r+x
}
bool System::HasReadExecAccessToPath(long dir_id)
{
while( true )
{
Item * pdir = dirs.GetDir(dir_id);
if( !pdir )
return false;
if( !HasReadExecAccess(*pdir) )
return false;
dir_id = pdir->parent_id;
if( dir_id == -1 )
return true;
}
}
bool System::DirsHaveReadExecPerm()
{
std::vector<Item*>::iterator i;
for(i = request->dir_tab.begin() ; i!=request->dir_tab.end() ; ++i)
{
if( !HasReadExecAccess(**i) )
return false;
}
return true;
}
// if we don't have access we only remove the item from the table
void System::CheckAccessToItems(std::vector<Item> & item_tab)
{
size_t i = 0;
while( i < item_tab.size() )
{
if( !HasReadAccess(item_tab[i]) )
{
item_tab.erase(item_tab.begin() + i);
}
else
{
i += 1;
}
}
}
bool System::CanUseHtml(long user_id)
{
return IsMemberOfGroup(user_id, "allow_html");
}
bool System::CanUseBBCode(long user_id)
{
// logged users can use bbcode
return (user_id != -1);
}
bool System::CanUseRaw(long user_id)
{
return IsMemberOfGroup(user_id, "allow_raw");
}
bool System::IsMemberOfGroup(long user_id, const char * group_name)
{
User * puser = users.GetUser(user_id);
if( !puser )
return false;
if( puser->super_user )
return true;
long group = groups.GetGroupId(group_name);
if( group == -1 )
// there is no such a group
return false;
if( puser->IsMemberOf(group) )
return true;
return false;
}
bool System::MakePathSimpleFs(std::string & path, long dir_id, bool create_dir)
{
if( config->auth_simplefs_dir.empty() )
{
log << log1 << "System: auth_simplefs_dir is not set in the config file" << logend;
return false;
}
if( !dirs.MakePath(dir_id, path) )
return false;
if( create_dir && !CreateDirs(config->auth_simplefs_dir, path, 0755) )
return false;
path.insert(0, config->auth_simplefs_dir);
return true;
}
// the path depends on id
bool System::MakePathHashFs(std::string & path, long id, bool create_dir)
{
char buffer[50];
char * hash = buffer;
// get 'id' as hexadecimal
buffer[0] = '0';
sprintf(buffer+1, "%lx", (unsigned long)id);
path = config->auth_hashfs_dir;
if( path.empty() )
{
log << log1 << "System: auth_hashfs_dir is not set in the config file" << logend;
return false;
}
path += '/';
// make sure that the length is even
if( (strlen(hash) & 1) != 0 )
hash = buffer + 1; // the first character was zero
// creating dirs without the last part
// the last part is a part of a file
for(size_t i=0 ; hash[i] != 0 ; i+=2)
{
path += hash[i];
path += hash[i+1];
if( hash[i+2] != 0 )
{
if( create_dir && !CreateDir(path, 0755) )
return false;
path += '/';
}
}
// one character more to make sure the path is unique
// (we can have a directory without the character)
path += "_";
return true;
}
// making a complete path to a static file
bool System::MakePath(const Item & item, std::string & path, bool create_dir)
{
bool res;
Mount * pmount = mounts.CalcMount(item.parent_id);
if( !pmount || pmount->fs == mounts.MountFsSimplefs() )
{
res = MakePathSimpleFs(path, item.parent_id, create_dir);
}
else
{
res = MakePathHashFs(path, item.id, create_dir);
}
if( res )
path += item.url;
else
path.clear();
return res;
}
bool System::MakePath(Item & item, bool create_dir)
{
return MakePath(item, item.auth_path, create_dir);
}
Error System::AddFile(Item & item, bool notify)
{
if( item.type == Item::dir )
return WINIX_ERR_FILE_EXPECTED;
Error status = db->AddItem(item);
if( status == WINIX_ERR_OK )
{
log << log2 << "System: added a new file, url: " << item.url << ", id: " << item.id
<< ", parent_id: " << item.parent_id << logend;
if( notify )
request->notify_code |= WINIX_NOTIFY_ITEM_ADD;
}
return status;
}
Error System::EditFile(Item & item, bool with_url, bool notify)
{
if( item.type == Item::dir )
return WINIX_ERR_FILE_EXPECTED;
if( request->session && request->session->puser )
request->item.modification_user_id = request->session->puser->id;
else
request->item.modification_user_id = -1;
item.SetDateModifyToNow();
Error status = db->EditItemById(item, with_url);
if( status == WINIX_ERR_OK )
{
TemplatesFunctions::pattern_cacher.UpdatePattern(item);
log << log2 << "System: modified an item" << logend;
if( notify )
request->notify_code |= WINIX_NOTIFY_ITEM_EDIT;
}
return status;
}
time_t System::LocalTime(time_t gmt_time)
{
int time_offset;
if( request->session && request->session->puser )
time_offset = request->session->puser->time_zone_offset;
else
time_offset = config->time_zone_offset_guest;
return gmt_time + (time_t)time_offset;
}
tm System::LocalTime(const tm * ptm)
{
time_t t;
tm rtm;
t = Time(ptm);
t = LocalTime(t);
rtm = Time(t);
return rtm;
}
tm System::LocalTime(const tm & ptm)
{
return LocalTime(&ptm);
}