612 lines
11 KiB
C++
Executable File
612 lines
11 KiB
C++
Executable File
/*
|
|
* 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 "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::SetSynchro(Synchro * psynchro)
|
|
{
|
|
synchro = psynchro;
|
|
}
|
|
|
|
|
|
|
|
|
|
void System::Init()
|
|
{
|
|
dirs.SetDb(db);
|
|
dirs.SetRequest(request);
|
|
dirs.SetNotify(¬ify);
|
|
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();
|
|
|
|
notify.SetSynchro(synchro);
|
|
notify.SetRequest(request);
|
|
notify.SetConfig(config);
|
|
notify.SetUsers(&users);
|
|
notify.SetDirs(&dirs);
|
|
notify.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 wchar_t * 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 wchar_t * postfix)
|
|
{
|
|
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;
|
|
|
|
// !! przeciez to prosciej mozna zapisac
|
|
// albo dac od razu return false
|
|
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, L"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, L"allow_raw");
|
|
}
|
|
|
|
|
|
|
|
bool System::IsMemberOfGroup(long user_id, const wchar_t * group_name)
|
|
{
|
|
User * puser = users.GetUser(user_id);
|
|
|
|
if( !puser )
|
|
return false;
|
|
|
|
if( puser->super_user )
|
|
return true; // !! ?? zakladamy ze administrator jest czlonkiem wszystkich grup? dlaczego?
|
|
|
|
long group = groups.GetGroupId(group_name);
|
|
|
|
if( group == -1 )
|
|
// there is no such a group
|
|
return false;
|
|
|
|
return puser->IsMemberOf(group);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// the path depends on parent_id
|
|
bool System::CreateNewFileSimpleFs(Item & item)
|
|
{
|
|
bool res = dirs.MakePath(item.parent_id, item.file_path);
|
|
|
|
if( res )
|
|
{
|
|
if( !item.file_path.empty() && item.file_path[0] == '/' )
|
|
item.file_path.erase(0, 1);
|
|
}
|
|
else
|
|
{
|
|
log << log1 << "System: CreateNewFileSimpleFs: can't create a path to item.id: " << item.id
|
|
<< ", item.parent_id: " << item.parent_id << logend;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
|
|
// the path depends on id
|
|
bool System::CreateNewFileHashFs(Item & item)
|
|
{
|
|
wchar_t buffer[50];
|
|
wchar_t * hash = buffer;
|
|
size_t buffer_len = sizeof(buffer)/sizeof(wchar_t);
|
|
|
|
// get 'id' as hexadecimal
|
|
buffer[0] = '0';
|
|
swprintf(buffer+1, buffer_len, L"%lx", (unsigned long)item.id);
|
|
|
|
item.file_path.clear();
|
|
|
|
// make sure that the length is even
|
|
if( (wcslen(hash) & 1) != 0 )
|
|
hash = buffer + 1; // the first character was zero
|
|
|
|
for(size_t i=0 ; hash[i] != 0 ; i+=2)
|
|
{
|
|
item.file_path += hash[i];
|
|
item.file_path += hash[i+1];
|
|
|
|
if( hash[i+2] != 0 )
|
|
item.file_path += '/';
|
|
}
|
|
|
|
// one character more to make sure the path is unique
|
|
// (we can have a directory without the character)
|
|
item.file_path += '_';
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
// creating item.file_path and item.file_fs
|
|
// you should set file_type yourself
|
|
// this method uses: item.id, item.url, item.parent_id (for selecting a mountpoint)
|
|
bool System::CreateNewFile(Item & item)
|
|
{
|
|
bool res;
|
|
|
|
if( item.type != Item::file )
|
|
{
|
|
log << log1 << "System: CreateNewFile: the item should be a file" << logend;
|
|
return false;
|
|
}
|
|
|
|
Mount * pmount = mounts.CalcMount(item.parent_id);
|
|
|
|
if( !pmount || pmount->fs != mounts.MountFsHashfs() )
|
|
{
|
|
res = CreateNewFileSimpleFs(item);
|
|
item.file_fs = mounts.MountFsSimplefs();
|
|
}
|
|
else
|
|
{
|
|
res = CreateNewFileHashFs(item);
|
|
item.file_fs = mounts.MountFsHashfs();
|
|
}
|
|
|
|
if( res )
|
|
item.file_path += item.url;
|
|
else
|
|
item.file_path.clear();
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
// making a global file path
|
|
// you should call CreateNewFile before
|
|
bool System::MakeFilePath(const Item & item, std::wstring & path, bool thumb, bool create_dir, int chmod)
|
|
{
|
|
path.clear();
|
|
|
|
if( config->upload_dir.empty() )
|
|
{
|
|
log << log1 << "System: MakePath: upload_dir is not set in the config file" << logend;
|
|
return false;
|
|
}
|
|
|
|
if( item.file_path.empty() || item.file_type == WINIX_ITEM_FILETYPE_NONE )
|
|
{
|
|
log << log1 << "System: MakePath: this item has not a static file" << logend;
|
|
return false;
|
|
}
|
|
|
|
path = config->upload_dir;
|
|
|
|
if( item.file_fs == mounts.MountFsHashfs() )
|
|
path += L"/hashfs";
|
|
else
|
|
path += L"/simplefs";
|
|
|
|
|
|
if( thumb )
|
|
path += L"/thumb";
|
|
else
|
|
path += L"/normal";
|
|
|
|
|
|
if( create_dir && !CreateDirs(path, item.file_path, chmod, true) )
|
|
return false;
|
|
|
|
path += '/';
|
|
path += item.file_path;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Error System::AddFile(Item & item, int notify_code)
|
|
{
|
|
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_code )
|
|
notify.ItemChanged(notify_code, item);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
Error System::EditFile(Item & item, bool with_url, int notify_code)
|
|
{
|
|
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_code )
|
|
notify.ItemChanged(notify_code, item);
|
|
}
|
|
|
|
|
|
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);
|
|
}
|