/* * 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::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 ; icode ) { (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 ; icode ) { (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(); // !! dodac parametr do konfiga wlaczajacy te informacje //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; } */