<?php
/**
 * CodeIgniter Controller
 *
 * @category CodeIgniter
 * @license /_licenses/untermStrich/agb_normal.pdf
 * @author Christian Koller
 * @copyright 2009 untermStrich
 * @package controllers
 * @version $Id$
*/

/**
 * The main controller for untermStrich
 */
class Start extends My_Controller
{
    /**
     * The main function
     * 
     * @return void
     */
    public function index()
    {
        if ( !$this->login->is_logged_in() ) {
            redirect($this->config->item('sess_login_page'));
        } elseif (US_MAJOR_VERSION<15) {
            $this->_open_do('main', 'index');
        } else {
            redirect('/q');
        }
    }
    
    /**
     * The main function directly after login
     * 
     * @return void
     */
    public function index_after_login()
    {
        if ( !$this->login->is_logged_in() ) {
            redirect($this->config->item('sess_login_page'));
        } else {
            $this->load->library('After_login', '', 'after_login');
            $this->after_login->do();

            $this->_open_do('main', 'index_after_login');
        }
    }

    /**
     * Opens a page by native XMLHttpRequest for e.g. chunked data (progress bars)
     *
     * <pre>
     * uri->rsegment string section   Section
     * uri->rsegment string page      Page
     * uri->rsegment string xjxcookie Xajax cookie
     * </pre>
     * 
     * @return void
     */    
    public function openxhr()
    {
        if (!defined('US_XHR_MODE')) {
            define('US_XHR_MODE', 1);
        }

        $this->open();
    }
    
    /**
     * Opens a page
     *
     * <pre>
     * uri->rsegment string section   Section
     * uri->rsegment string page      Page
     * uri->rsegment string xjxcookie Xajax cookie
     * </pre>
     * 
     * @return void
     */
    public function open()
    {
        $this->load->library('form_validation');
        $this->load->helper('cookie');

        $map = array('start', 'open', 'section', 'page', 'xjxcookie');
        $ok = $this->form_validation->map_my_vars($this->uri->rsegment_array(), $map);

        if ($this->input->post('open') === 'openxhr') { //see $this->openxhr()
            $_POST['open'] = 'open';
        }

        if ($this->form_validation->run('start_open_page') == false) {
            basic_error(print_r(validation_errors(), true), self::M_DIRECT, __CLASS__.'::'.__FUNCTION__, 400);
        }

        if ( !$this->login->is_logged_in() ) {
            redirect($this->config->item('sess_login_page'));
            return;
        }
        
        
        set_cookie('last_action', '', 'now');
        
        $this->_open_do($this->input->post('section'), $this->input->post('page'));
    }
    
    /**
     * Opens a page
     *
     * @param string    $section Section
     * @param string    $page    Page
     * @return void
     */
    private function _open_do($section, $page)
    {
        header_no_cache();
        
        $mode = (defined('US_XHR_MODE')) ? self::M_XHR : self::M_DIRECT;

        $allowed = array(
            'index',
            'index_after_login',
            'result_process', #reporting
            'view', #reporting
            'show_list', #workinput_overtime
            'vcard', #addressesandcontacts
            'vcard_qr', #addressesandcontacts
        );
        if ($section==='Start'): $section = 'Butlerpage_1'; endif;
        if (!in_array($page, $allowed)) {
            $this->login->restrict_xsrf($this->input->post('xjxcookie'), $mode);
        }
        
        try {
            $this->load->page($section, $page, $mode);
        } catch (O365_filesystem_creatorException $exc) {
            $_error =& load_class('Exceptions', 'core');
            $this->load->library('Oauth_tools', '', 'oauth_tools');
            $msg = $this->oauth_tools->check_o365_token();
            echo $_error->show_error('Fehler/Error', $msg, 'error_general', $exc->getCode());
        } catch (Exception $exc) {
            $_error =& load_class('Exceptions', 'core');
            echo $_error->show_error('Fehler/Error in page "'.$section.'::'.$page.'"', $exc->getMessage(), 'error_general', $exc->getCode());
        }
    }
    
    /**
     * Opens a page XAJAX
     *
     * <pre>
     * $_POST string section   Section
     * $_POST string page      Page
     * $_POST string xjxcookie Xajax cookie
     * </pre>
     * 
     * @return void
     */
    public function openajax()
    {
        /* 
         * xjxfun is not defined - Das ist nicht der eigentliche Fehler. 
         * Der Fehler kommt daher, dass die Firefox Entwickler Konsole beim Anklicken den Request noch mal als GET ohne passende Parameter sendet. 
         * Verwendet stattdessen die Netzwerkübersicht dafür!
         */
        $xjxfun = $this->input->post('xjxfun');
        if ($xjxfun!=='openx' && $xjxfun!=='openxauto' && $xjxfun!=='openxping') {
            $msg = 'XAJAX asked for an unknown function "'.strip_tags($_POST['xjxfun'] ?? '').'"';
            $this->load->library('US_Xajax_response', '', 'xajax');
            $this->xajax->message($msg, US_Xajax_response::MSGM_ERROR);
            $this->xajax->write();
            log_message('error', $msg);
            return;
        }
        
        if ( !$this->login->is_logged_in() ) {
            $this->load->library('US_Xajax_response', '', 'xajax');
            $this->xajax->redirect(site_url($this->config->item('sess_login_page')));
            $this->xajax->write();
            return;
        }
        
        $this->login->restrict_xsrf($this->input->post('xjxcookie'), self::M_XAJAX);

        $this->load->library('form_validation');

        $map = array('section', 'page');
        $ok = $this->form_validation->map_my_vars($_POST['xjxargs'], $map, true);
        if (!$ok) {
            basic_error('Parameter missing. Need: '.print_r($map, true), self::M_XAJAX, __CLASS__.'::'.__FUNCTION__, 400);
        }

        if ($this->form_validation->run('start_open_page') == false) {
            basic_error(print_r(validation_errors(), true), self::M_XAJAX, __CLASS__.'::'.__FUNCTION__, 400);
        }
        
        $section = $this->input->post('section');
        if ($section=='Portlet') {
            $this->_openx_do('Portletprocess', 'index');
        } elseif ($section=='Reportportlet') {
            $this->_openx_do('Reporting_portlet', 'load_process');
        } else {
            $this->_openx_do($section, $this->input->post('page'));
        }
    }
    
    /**
     * Opens a page XAJAX
     *
     * @param string $section Section
     * @param string $page    Page
     * @return void
     */
    private function _openx_do($section, $page)
    {
        if (empty($page)): $page = 'index'; endif;
        if ($section==='Datacollection'): $section = 'Butlerpage_3'; endif;
        if ($section==='Start'): $section = 'Butlerpage_1'; endif;
        
        if ($page==='index' || $page==='update_data_table') {
            header_no_cache();
        }
        
        try {
            $this->load->page($section, $page, self::M_XAJAX);
        } catch (O365_filesystem_creatorException $exc) {
            $this->load->library('US_Xajax_response', '', 'xajax');
            $this->load->library('Oauth_tools', '', 'oauth_tools');
            $msg = $this->oauth_tools->check_o365_token();
            $this->xajax->message('Fehler/Error<br><br>'.$msg, US_Xajax_response::MSGM_ERROR);
            $this->xajax->write();            
        } catch (Exception $exc) {
            $this->load->library('US_Xajax_response', '', 'xajax');
            $this->xajax->message('Fehler/Error in pagex "'.$section.'::'.$page.'" '.$exc->getCode().': '.$exc->getMessage(), US_Xajax_response::MSGM_ERROR);
            $this->xajax->write();
        }
    }

    /**
     * Uploads a file
     *
     * @return  void
     */
    public function upload()
    {
        if ( !$this->login->is_logged_in() ) {
            $msg = $this->lang->line('auth_no_login');
            echo $msg; die();
        }

        $targetinfo = $this->input->post('targetinfo');
        if (!$targetinfo) {
            $targetinfo = $this->input->server('HTTP_X_UNTERMSTRICH_TARGETINFO');
        }
        if (!$targetinfo) {
            $msg = 'Parameter missing. Need: targetinfo';
            log_message('error', $msg);
            echo $msg; die();
        }

        $targetinfoarray = explode(';', base64_decode($targetinfo));
        if (count($targetinfoarray)!==2) {
            $msg = 'Parameter invalid. Need: targettype;targetdata';
            log_message('error', $msg);
            echo $msg; die();
        }
        list ($targettype, $targetdata) = $targetinfoarray;

        switch ($targettype) {
            case 'image':
                $this->load->library('US_Images', '', 'images');
                $this->images->upload($targetdata);
                break;
            case 'addidata':
            case 'files':
                $this->load->library('US_Files', '', 'files');
                $this->files->upload($targetdata);
                break;
            case 'attachment':
                $this->load->library('US_Attachments', '', 'attachments');
                $this->attachments->upload($targetdata);                
                break;
            case 'correspondence':
                $this->load->library('US_Correspondence', '', 'us_correspondence');
                $this->us_correspondence->upload($targetdata);                
                break;
            case 'ical':
                $this->load->library('US_Icalendar_upload', null, 'icalendar_upload');
                $this->icalendar_upload->upload($targetdata, 'personalapp');
                break;
            case 'opta':
                $this->load->library('US_Icalendar_upload', null, 'icalendar_upload');
                $this->icalendar_upload->upload($targetdata, 'opentasks');
                break;
            case 'addr':
                $this->load->library('US_Addresses_upload', null, 'addresses_upload');
                $this->addresses_upload->upload($targetdata);
                break;
            case 'zip_to_name':
                $this->load->library('US_zip_to_name_upload', null, 'zip_to_name_upload');
                $this->zip_to_name_upload->upload($targetdata);
                break;
            case 'portlet':
                $this->load->library('US_Portlet_upload', null, 'portlet_upload');
                $this->portlet_upload->upload($targetdata);
                break;
            case 'sendmail_attachments':
                $this->load->library('US_Sendmail_attachments', null, 'sendmail_attachments');
                $this->sendmail_attachments->upload($targetdata);
                break;
            case 'file_to_import':
                $this->load->library('US_Import_Files', '', 'import_files');
                $this->import_files->upload($targetdata);
                break;     
            default:
                $msg = 'Parameter invalid. Unknown targettype';
                log_message('error', $msg);
                echo $msg; die();
        }
    }

    /**
     * Loads an image
     *
     * <pre>
     * uri->rsegment string section   Image section
     * uri->rsegment string page      Name of image file to load
     * </pre>
     * 
     * Global does not need a login!!
     * 
     * @return void
     */
    public function image()
    {
        $this->load->library('form_validation');

        $map = array('start', 'image', 'section', 'name');
        $ok = $this->form_validation->map_my_vars($this->uri->rsegment_array(), $map);

        if ($this->form_validation->run('start_image') == false) {
            basic_error(print_r(validation_errors(), true), self::M_DIRECT, __CLASS__.'::'.__FUNCTION__, 422);
        }
        
        $section = $this->input->post('section');
        $name = $this->input->post('name');
        
        if ($section!=='global') {
            if ( !$this->login->is_logged_in() ) {
                echo $this->lang->line('auth_no_login');
                return;
            }
        }

        $this->load->library('US_Images', '', 'images');

        $this->images->show($section, $name);
    }

    /**
     * Loads a file
     *
     * <pre>
     * uri->rsegment string name      Base64 Name of file to load
     * </pre>
     * 
     * @return void
     */
    public function file()
    {
        if ( !$this->login->is_logged_in() ) {
            echo 'Not logged in';
            return;
        }

        $this->load->library('form_validation');

        $map = array('start', 'file', 'action', 'data');
        $ok = $this->form_validation->map_my_vars($this->uri->rsegment_array(), $map);

        if ($this->form_validation->run('start_file') == false) {
            basic_error(print_r(validation_errors(), true), self::M_DIRECT, __CLASS__.'::'.__FUNCTION__, 422);
        }

        $this->lang->load('files', $this->web_settings->getLanguage());

        $this->load->library('US_Files', '', 'files');
        $this->load->helper('crypt');

        $action = strtoupper(Two_way_crypt::decode($this->input->post('action')));
        $data = Two_way_crypt::decode($this->input->post('data'));
        log_message('debug', 'FILE OPEN '.$action.': '.$data);

        switch ($action) {
            case 'OPENFOLDER':
                $this->files->open_file(
                    $data,
                    self::M_DIRECT,
                    'folder'
                );
                break;
            case 'OPEN':
                $this->files->open_file(
                    $data,
                    self::M_DIRECT
                );
                break;
            case 'OPEN_ENC_CORR':
                $this->files->open_file(
                    $data,
                    self::M_DIRECT,
                    'enc_corr',
                    $this->input->post('val1')
                );
                break;
            case 'OPENSEC1':
            case 'OPENSEC2':
            case 'OPEN_CORR_TYPE_SEC1':
            case 'OPEN_CORR_TYPE_SEC2':
                $type = ($action === 'OPEN_CORR_TYPE_SEC1' || $action === 'OPEN_CORR_TYPE_SEC2') ? 'zip_corr_type' : 'zip_corr';
                $this->files->open_file(
                    $data,
                    self::M_DIRECT,
                    $type,
                    $this->input->post('val1')
                );
                break;            
            case 'OPENPDF':
                $this->files->open_file(
                    $data,
                    self::M_DIRECT,
                    'pdf'
                );
                break;
            case 'OPENMSG':
                $this->files->open_file(
                    $data,
                    self::M_DIRECT,
                    'msg'
                );
                break;
            default:
                basic_error('Unknown action to process: '.$action, self::M_DIRECT, __CLASS__.'::'.__FUNCTION__);
        }
    }

    /**
     * Calls the us file manager desktop client
     *
     * @return  void
     */
    public function file_manager()
    {
        $this->load->library('form_validation');
        $this->load->helper('crypt');

        $map = array('start', 'file_manager', 'xjxcookie');
        $ok = $this->form_validation->map_my_vars($this->uri->segment_array(), $map);

        $this->login->restrict_xsrf($this->input->post('xjxcookie'), self::M_DIRECT);
        
        $url = $this->web_settings->get_connector_url();
        switch ($this->input->post('val1')) {
            case 'no_https':
                break;
            default:
                if ($this->input->server('HTTPS')==='on' || stripos($this->config->item('base_url'), 'HTTPS')===0) {
                $url .= '/https';
                }
        }
        
        $data = array(
            'url'       => $url,
            'title'     => $this->lang->line('basic_file_manager_connect'),
            'margintop' => 1,
            'wait'      => 400,
        );
        
        $this->load->view('Files/file_manager_connect', $data);
    }

    /**
     * Create the connector jnlp
     *
     * @return  void
     */
    public function connector_jnlp()
    {
        header('Content-type: application/x-java-jnlp-file');
        header('Content-disposition: attachment; filename="untermstrich_connector.jnlp"');
        echo '<?xml version="1.0" encoding="utf-8"?>';
        $this->load->view('Files/file_manager_jnlp');
    }
    
    /**
     * Log the user out
     * 
     * @return void
     */
    public function logout()
    {
        $this->login->restrict_xsrf($this->uri->rsegment(3), self::M_DIRECT);

        $this->auth->do_logout();
        redirect($this->config->item('sess_login_page'));
    }
    
    /**
     * Mustache example
     * 
     * @return void
     */
    public function hello()
    {
        $this->load->library('Mustache_Engine', null, 'mustache');
        
        echo $this->mustache->render('Hello {{planet}}', array('planet' => 'World!'));
    }
    
    /**
     * Load a pub_... file from butler
     */
    public function pub_file()
    {
        $portletname = $this->uri->rsegment(3);
        if (preg_match("/^[a-z0-9_]+$/", $portletname) !== 1) {
            basic_error('Invalid portletname', self::M_DIRECT, __CLASS__.'::'.__FUNCTION__, 422);
        }
        
        $portlet_sub1 = $this->uri->rsegment(4);
        if ($portlet_sub1!=='views') {
            basic_error('Only views path allowed', self::M_DIRECT, __CLASS__.'::'.__FUNCTION__, 422);
        }
        
        $url_segments = $this->uri->total_rsegments();
        if ($url_segments>=6) {
            $portlet_sub2 = $this->uri->rsegment(5);
            $file_name = $this->uri->rsegment(6);
        } elseif ($url_segments===5) {
            $portlet_sub2 = false;
            $file_name = $this->uri->rsegment(5);
        }
        
        if (strpos($file_name, 'pub_')!==0) {
            basic_error('Unknown file name', self::M_DIRECT, __CLASS__.'::'.__FUNCTION__, 422);
        }
        $file_ending_pos = strpos($file_name, '_', 5);
        if ($file_ending_pos===false) {
            basic_error('File name misses extension', self::M_DIRECT, __CLASS__.'::'.__FUNCTION__, 422);
        }
        $file_name[$file_ending_pos] = '.';
        $file_ending = substr($file_name, $file_ending_pos+1);
        
        $external_portlet_path = $this->config->item('portlet_packages');
        
        if ($portlet_sub2===false) {
            $file_path = $external_portlet_path.$portletname.'/'.$portlet_sub1.'/'.$file_name;
        } else {
            $file_path = $external_portlet_path.$portletname.'/'.$portlet_sub1.'/'.$portlet_sub2.'/'.$file_name;
        }
        
        if (file_exists($file_path)) {
            switch ($file_ending) {
                case '':
                    basic_error('File name has empty extension', self::M_DIRECT, __CLASS__.'::'.__FUNCTION__, 422);
                    break;
                case 'php':
                case 'java':
                    basic_error('File extension .'.$file_ending.' is invalid', self::M_DIRECT, __CLASS__.'::'.__FUNCTION__, 422);
                    break;
                case 'js':
                    header('Content-type: text/javascript');
                    break;
                default:
                    break;
            }
            readfile($file_path);
        } else {
            basic_error('File name '.$file_name.' not found', self::M_DIRECT, __CLASS__.'::'.__FUNCTION__, 422);
        }
    }


    /**
     * Show error while db is updating.
     * Only in SaaS V2 mode: see method _ensure_code_db_version_match()
     * 
     * @param   string      $msg    The error/info message
     * @return void
     */    
    protected function _error_while_updating($msg)
    {
        header_remove();
        header("refresh: 30", true, 503);
        exit($msg);    
    }   
    
} // END class Start
