<?php
// OpenRat Content Management System
// Copyright (C) 2002-2009 Jan Dankert, cms@jandankert.de
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.



// "Single Entry Point"
// Diese Datei dient als "Dispatcher" und startet den zum Request passenden Controller ("*Action")..
// Jeder Request in der Anwendung läuft durch dieses Skript.
//
// Statische Resourcen (CSS,JS,Bilder,...) gehen nicht über diesen Dispatcher, sondern werden
// direkt geladen.


define('PHP_EXT'         ,'php'    );
require_once( 
"functions/common.inc.".PHP_EXT );

define('IMG_EXT'         ,'.gif'   );
define('IMG_ICON_EXT'    ,'.png'   );
define('MAX_FOLDER_DEPTH',5        );

define('OR_VERSION'      ,'1.1-snapshot'  );
define('OR_TITLE'        ,'OpenRat CMS');

define('OR_TYPE_PAGE'  ,'page'  );
define('OR_TYPE_FILE'  ,'file'  );
define('OR_TYPE_LINK'  ,'link'  );
define('OR_TYPE_FOLDER','folder');

define('OR_ACTIONCLASSES_DIR' ,'./actionClasses/'  );
define('OR_FORMCLASSES_DIR'   ,'./formClasses/'    );
define('OR_OBJECTCLASSES_DIR' ,'./objectClasses/'  );
define('OR_SERVICECLASSES_DIR','./serviceClasses/' );
define('OR_LANGUAGE_DIR'      ,'./language/'       );
define('OR_DBCLASSES_DIR'     ,'./db/'             );
define('OR_DYNAMICCLASSES_DIR','./dynamicClasses/' );
define('OR_TEXTCLASSES_DIR'   ,'./textClasses/'    );
define('OR_PREFERENCES_DIR'   ,defined('OR_EXT_CONFIG_DIR')?OR_EXT_CONFIG_DIR:'./config/');
define('OR_CONFIG_DIR'        ,OR_PREFERENCES_DIR  );
define('OR_THEMES_DIR'        ,'./themes/'         );
define('OR_THEMES_EXT_DIR'    ,defined('OR_BASE_URL')?slashify(OR_BASE_URL).'themes/':OR_THEMES_DIR);
define('OR_TMP_DIR'           ,'./tmp/'            );
define('OR_CONTROLLER_FILE'   ,defined('OR_EXT_CONTROLLER_FILE')?OR_EXT_CONTROLLER_FILE:'do');
define('START_TIME'           ,time()              );

define('REQ_PARAM_TOKEN'          ,'token'          );
define('REQ_PARAM_ACTION'         ,'action'         );
define('REQ_PARAM_SUBACTION'      ,'subaction'      );
define('REQ_PARAM_TARGETSUBACTION','targetSubAction');
define('REQ_PARAM_ID'             ,'id'             );
define('REQ_PARAM_OBJECT_ID'      ,'objectid'       );
define('REQ_PARAM_LANGUAGE_ID'    ,'languageid'     );
define('REQ_PARAM_MODEL_ID'       ,'modelid'        );
define('REQ_PARAM_PROJECT_ID'     ,'projectid'      );
define('REQ_PARAM_ELEMENT_ID'     ,'elementid'      );
define('REQ_PARAM_TEMPLATE_ID'    ,'templateid'     );
define('REQ_PARAM_DATABASE_ID'    ,'dbid'           );

require_once( 
"functions/request.inc.php" );

// Werkzeugklassen einbinden.
require_once( OR_SERVICECLASSES_DIR."include.inc.".PHP_EXT );
require_once( 
OR_OBJECTCLASSES_DIR ."include.inc.".PHP_EXT );
require_once( 
OR_TEXTCLASSES_DIR   ."include.inc.".PHP_EXT );

// Datenbank-Funktionen einbinden.
require_once( OR_DBCLASSES_DIR."db.class.php" );
require_once( 
OR_DBCLASSES_DIR."postgresql.class.php" );
require_once( 
OR_DBCLASSES_DIR."mysql.class.php" );
if (
version_compare(PHP_VERSION'5.0.0''>'))
    require_once( 
OR_DBCLASSES_DIR."mysqli.class.php" );
if (
version_compare(PHP_VERSION'5.0.0''>'))
    require_once( 
OR_DBCLASSES_DIR."sqlite.class.php" );
if (
version_compare(PHP_VERSION'5.3.0''>'))
    require_once( 
OR_DBCLASSES_DIR."sqlite3.class.php" );
if (
version_compare(PHP_VERSION'5.1.0''>'))
    require_once( 
OR_DBCLASSES_DIR."pdo.class.php" );

// Jetzt erst die Sitzung starten (nachdem alle Klassen zur Verfügung stehen).
session_start();
require_once( 
OR_SERVICECLASSES_DIR."Session.class.".PHP_EXT );

// Vorhandene Konfiguration aus der Sitzung lesen.
$conf Session::getConfig();
 
// Wenn Konfiguration noch nicht in Session vorhanden, dann
// aus Datei lesen.
if    ( !is_array$conf ) || isset($REQ['reload']) )
{
    
// Da die Konfiguration neu eingelesen wird, sollten wir auch die Sitzung komplett leeren.
    
session_unset();
    
    
$prefs = new Preferences();
    
$conf $prefs->load();
    
$conf['action'] = $prefs->load(OR_ACTIONCLASSES_DIR);
    
$conf['build'] = parse_ini_file('build.ini');
    
// Sprache lesen und zur Konfiguration hinzufuegen

    
if    ( $conf['i18n']['use_http'] )
        
// Die vom Browser angeforderten Sprachen ermitteln     
        
$languages Http::getLanguages();
    else
        
// Nur Default-Sprache erlauben
        
$languages = array();

    if    ( isset(
$_COOKIE['or_language']) )
        
$languages = array($_COOKIE['or_language']) + $languages;
        
    
// Default-Sprache hinzufuegen.
    // Wird dann verwendet, wenn die vom Browser angeforderten Sprachen
    // nicht vorhanden sind
    
$languages[] = $conf['i18n']['default'];
    
$available explode(',',$conf['i18n']['available']);

    foreach( 
$languages as $l )
    {
        if    ( !
in_array($l,$available) )
            continue;

        
// Pruefen, ob Sprache vorhanden ist.
        
$langFile OR_LANGUAGE_DIR.$l.'.ini.'.PHP_EXT;

        if    ( !
file_exists$langFile ) )
            
Http::serverError("File does not exist: ".$langFile);

        
$conf['language'] = parse_ini_file$langFile );
        
$conf['language']['language_code'] = $l;
        break;
    }


    if    ( !isset(
$conf['language']) )
        
Http::serverError('no language found! (languages='.implode(',',$languages).')' );
    
    
// Schreibt die Konfiguration in die Sitzung. Diese wird anschliessend nicht
    // mehr veraendert.
    
Session::setConfig$conf );
}

if    ( !empty(
$conf['security']['umask']) )
    
umaskoctdec($conf['security']['umask']) );

if    ( !empty(
$conf['interface']['timeout']) )
    
set_time_limitintval($conf['interface']['timeout']) );

if    ( 
config('security','use_post_token') && $_SERVER['REQUEST_METHOD'] == 'POST' && $REQ[REQ_PARAM_TOKEN]!=token() )
    
Http::notAuthorized("Token mismatch");
    
define('FILE_SEP',$conf['interface']['file_separator']);

define('TEMPLATE_DIR',OR_THEMES_DIR.$conf['interface']['theme'].'/templates');
define('CSS_DIR'     ,OR_THEMES_DIR.$conf['interface']['theme'].'/css'      );
define('IMAGE_DIR'   ,OR_THEMES_DIR.$conf['interface']['theme'].'/images'   );

require_once( 
OR_SERVICECLASSES_DIR."Logger.class.".PHP_EXT );
require_once( 
"functions/config.inc.php" );
require_once( 
"functions/language.inc.".PHP_EXT );
require_once( 
"functions/db.inc.".PHP_EXT );

header'Content-Type: text/html; charset='.lang('CHARSET') );

// Request-Variablen in Session speichern
//request_into_session('action'    );
//request_into_session('subaction' );
//request_into_session('objectid'  );
//request_into_session('templateid');
//request_into_session('elementid' );
//request_into_session('projectid' );
//request_into_session('modelid'   );
//request_into_session('userid'    );
//request_into_session('groupid'   );
//request_into_session('languageid');

//if    ( isset($REQ['objectid']) )
//{
//    $o = new Object( $REQ['objectid'] );
//    Session::setObject($o);
//}

// Verbindung zur Datenbank
//
$db Session::getDatabase();
if    ( 
is_object$db ) )
{
    
$ok $db->connect();
    if    ( !
$ok )
        
Http::sendStatus('503','Service Unavailable','Database is not available: '.$db->error);

    
Session::setDatabase$db );
    
$db->start();
}


if    ( !empty(
$REQ[REQ_PARAM_ACTION]) )
    
$action $REQ[REQ_PARAM_ACTION];
else    
$action 'index';

Session::set('action',$action);

if    ( !empty( 
$REQ[REQ_PARAM_SUBACTION] ) )
    
$subaction $REQ[REQ_PARAM_SUBACTION];
else
{
    
$sl Session::getSubaction();
    if    ( 
is_array($sl) && isset($sl[$action]) )
        
$subaction $sl[$action];
    else
        
$subaction '';
}

$actionClassName strtoupper(substr($action,0,1)).substr($action,1).'Action';

if    ( !isset(
$conf['action'][$actionClassName]) )
    
Http::serverError("Action '$action' is undefined.");

require( 
OR_ACTIONCLASSES_DIR.'/Action.class.php' );
require( 
OR_ACTIONCLASSES_DIR.'/ObjectAction.class.php' );
require( 
OR_ACTIONCLASSES_DIR.'/'.$actionClassName.'.class.php' );

// Erzeugen der Action-Klasse
$do = new $actionClassName;
$do->actionConfig $conf['action'][$actionClassName];
$do->actionClassName $actionClassName
$do->actionName      $action;
if    ( 
$subaction == '' )
    
$subaction $do->actionConfig['default']['goto'];
    
$do->subActionName   $subaction;


$do->init();

if    ( !isset(
$do->actionConfig[$subaction]) )
{
    
Logger::warn"Action $action has no configured method named $subaction");
    
Http::serverError("Action '$action' has no accessable method '$subaction'.");
    exit;
}
    
$subactionConfig $do->actionConfig[$subaction];
//Logger::trace("controller is calling subaction '$subaction'");

// Eine Subaktion ohne "guest=true" verlangt einen angemeldeten Benutzer.
if    ( !isset($subactionConfig['guest']) || !$subactionConfig['guest'] )
    if    ( !
is_object($do->currentUser) )
    {
        
Logger::debug('No session and no guest action occured, maybe session expired');
        
Http::notAuthorizedlang('SESSION_EXPIRED') );
        exit;
    }

// Eine Aktion mit "admin=true" verlangt einen Administrator als Benutzer.
if    ( isset($do->actionConfig['admin']) && $do->actionConfig['admin'] )
    if    ( !
$do->currentUser->isAdmin )
    {
        
Logger::debug('Admin action, but user '.$do->currentUser->name.' is not an admin');
        
Http::notAuthorizedlang('SESSION_EXPIRED') );
        exit;
    }


// Aktuelle Subaction in Sitzung merken
if    ( isset($do->actionConfig[$subaction]['menu']) || isset($do->actionConfig[$subaction]['direct']) )
{
    
$sl Session::getSubaction();
    if    ( !
is_array($sl))
        
$sl = array();
    
$sl[$action] = $subaction;
    
Session::setSubaction$sl );
}


// Alias-Methode aufrufen.
if    ( isset($do->actionConfig[$do->subActionName]['alias']) )
{
    
$subaction $do->actionConfig[$do->subActionName]['alias'];
//    $do->subActionName = $subaction;
}


// Alias-Methode aufrufen.
if    ( isset($do->actionConfig[$do->subActionName]['write']) )
{
    
//Html::debug($_SERVER);
    
if    ( $_SERVER['REQUEST_METHOD'] == 'POST' )
    {
        
$subactionAction $subaction.'Action';
        
$do->$subactionAction();
        
        if    ( 
$conf['interface']['redirect'] )
        {
            
// Wenn Validierungsfehler aufgetrete sind, auf keinen Fall einen Redirect machen, da sonst
            // im nächste Request die Eingabedaten fehlen.
            
if    ( empty($do->templateVars['errors']) )
            {
                
header'HTTP/1.0 303 See other');
                
// Absoluten Pfad kann auch der Client erg�nzen.
                
header'Location: '.Html::url($action,$subaction,$do->getRequestId()) );
                exit;
            }
        }
    }
    
    
$subactionView $subaction.'View';
    
$do->$subactionView();
}
else
{
    
// Aufruf der Subaction
    
$do->$subaction();
}


// Aufruf der n�chsten Subaction (falls vorhanden)
if    ( isset($do->actionConfig[$do->subActionName]['goto']) )
{
    
/* Achtung: Redirect fuehrt zu Problemen beim Login sowie der Anzeige von Notices */
    
if    ( $conf['interface']['redirect'] )
    {
        
// Wenn Validierungsfehler aufgetrete sind, auf keinen Fall einen Redirect machen, da sonst
        // im naechsten Request die Eingabedaten fehlen.
        
if    ( empty($do->templateVars['errors']) )
        {
            
$subActionName     $do->actionConfig[$do->subActionName]['goto'];
            
header'HTTP/1.0 303 See other');
            
// Absoluten Pfad kann auch der Client ergaenzen.
            
header'Location: '.Html::url($action,$do->actionConfig[$do->subActionName]['goto'],$do->getRequestId()) );
            exit;
        }
    }
    
    
$subActionName     $do->actionConfig[$do->subActionName]['goto'];

    
$do->subActionName $subActionName;
    
$subaction $subActionName;

    
// Auf Alias pr�fen.
    
if    ( isset($do->actionConfig[$do->subActionName]['alias']) )
    {
        
$subaction $do->actionConfig[$do->subActionName]['alias'];
    }
    
    
Logger::trace("controller is calling next subaction '$subaction'");
    
// Alias-Methode aufrufen.
    
if    ( isset($do->actionConfig[$subActionName]['write']) )
    {
        
$subActionView $subActionName.'View';
        
$do->$subActionView();
    }
    else
    {
        
$do->$subaction();
    }
}

$do->setMenu(); // Menue erzeugen

$do->forward(); // Anzeige rendern

// fertig :)
?>