/* * 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(); thumb.SetSynchro(synchro); thumb.SetConvertCmd(config->convert_cmd); thumb.SetDb(db); } // !! 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::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_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); }