<?
  error_reporting(E_ALL & ~E_NOTICE);
  ini_set('display_errors','On');

  if (preg_match('/MSIE (\d+)/',$_SERVER['HTTP_USER_AGENT'],$ma) && $ma[1]<8) {
    echo('This browser is not good for you. Please use an IE >= 9, or Firefox, or Chrome');
    exit;
  }

  $engine_base = realpath(dirname(__FILE__) . "/..");
  $includes    = '/Includes';

  require_once($engine_base . $includes . "/TransformationEngine.php");
  require_once($engine_base . $includes . "/CEWebSAdministration.php");

  class CEWebS extends TransformationEngine {
    private $par = NULL;
    private $conf;
    private $menu = '';
    private $breadcrumbnavigation = '';
    private $activemenupoint = '';
    private $user;
    private $login;
    private $user_name;
    private $user_admin = NULL;
    private $user_report = NULL;
    private $key;
    private $anmeld;
    private $url;
    private $cookieprefix;

    function __construct($mime="text/html",$debug=false,$time=false) {
      global $includes;
      global $web_base;
      global $engine_base;
      $this->conf = array(
        'mode' => 'm',
        'target' => 't',
        'command' => 'c',
        'registry' => 'r',
        'report' => 'CEWebSInternalReport',
        'administration' => 'CEWebSInternalAdministration',
        'search' => 'search',
        'searchresults' => 20,
        'admin_sub' => 'CEWebS_s',
        'admin_target' => 'CEWebS_t',
        'report_target' => 'CEWebS_t',
        'data' => './Data',
        'cache' => './Data',
        'script' => basename($_SERVER['SCRIPT_NAME']),
        'icons' => '/Tango',
        'styles' => '/Styles',
        'config' => '/Config',
        'includes' => $includes,
        'url' => 'http' . ($_SERVER['HTTPS'] == 'on' ? 's' : '') . '://' . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . dirname($_SERVER['SCRIPT_NAME']),
        'url_data' => './Data',
        'dtd' => $includes . '/CEWebSDelivery_V1.dtd',
        'admin_wsdl' => $includes . '/CEWebSAdministration.wsdl',
        'web_base' => $web_base,
        'engine_base' => $engine_base
      );
      $this->cookieprefix = md5($this->conf['url']);
      $this->uri = htmlentities($this->conf['url'] . (dirname($_SERVER['SCRIPT_NAME']) == '/' ? '' : '/') . $this->conf['script'] . (count($_GET) > 0 ? '?' : '') . http_build_query($_GET));

      //TODO move into transformationengine
      if ($_GET[$this->conf['mode']] == 'ADMINWSDL') {
        header('Content-Type: text/xml');
        $xml = file_get_contents($this->conf['engine_base'] . $this->conf['admin_wsdl']);
        print preg_replace("/address\s+location\s*=\s*\"[^\"]+\"/","address location=\"" . $this->conf['url'] . '/' . $this->conf['script'] . '?' . $this->conf['mode'] . '=ADMINSOAP"',$xml);
        exit;
      }
      if ($_GET[$this->conf['mode']] == 'ADMINSOAP') {
        ini_set('soap.wsdl_cache_enabled', '1');
        $server = new SoapServer($this->conf['url'] . '/' . $this->conf['script'] . '?' . $this->conf['mode'] . '=ADMINWSDL');
        $server->setClass('CEWebSAdministration',$this->conf);
        $server->handle();
        exit;
      }

      # move configuration if it not exists
      foreach (scandir($this->conf['engine_base'] . $this->conf['config']) as $f) {
        if ($f != '.' and $f != '..') {
          if (!file_exists($this->conf['data'] . '/' . $f)) {
            copy($this->conf['engine_base'] . $this->conf['config'] . '/' . $f, $this->conf['data'] . '/' . $f);
          }
        }
      }

      # create user cache if it does not exist
      $cache = $this->conf['cache'] . '/CacheU/'; if (!file_exists($cache)) @mkdir($cache);
      $cache = $this->conf['cache'] . '/CacheU/';

      if ($_GET['lang']) {
        setCookie($this->cookieprefix . 'LANG', $_GET['lang'], time() + (60*60*24*365), '', '', 0);
        $_COOKIE[$this->cookieprefix . 'LANG'] = $_GET['lang'];
      }

      if (array_key_exists('PHP_AUTH_USER',$_SERVER) && array_key_exists('PHP_AUTH_PW',$_SERVER)) {
        $_REQUEST['user'] = $_SERVER['PHP_AUTH_USER'];
        $_REQUEST['key'] = $_SERVER['PHP_AUTH_PW'];
      }

      if (($_REQUEST['user'] != '') && ($_REQUEST['key'] != '')) {
        $this->user = trim(preg_replace("/'|\"/",'',$_REQUEST['user']));
        $this->login = $this->user;
        if (get_magic_quotes_gpc()) {
          $this->key = stripslashes($_REQUEST['key']);
        } else{
          $this->key = $_REQUEST['key'];
        }
        $this->anmeld = $_POST['anmeld'] == 'A' ? time() + (60*60*24*365) : 0;

        $found = false;
        if (!$this->par)
          $this->par = simplexml_load_file($this->conf['data'] . '/persons.xml');

        foreach ($this->par->xpath("//person[translate(@internal,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='" . strtolower($this->user) . "' and not(@internal='')]") as $w) {
          $this->user = $w['id'];
        }

        if ($this->par->xpath("//person[translate(@id,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='" . strtolower($this->user) . "']")) {
          if ($this->par->xpath("//person[translate(@id,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='" . strtolower($this->user) . "']/@pass")) {
            $pkey = preg_replace("/\"/",'&quot;',$this->key);
            $pkey = preg_replace("/'/",'&apos;',$pkey);
            foreach ($this->par->xpath("//person[translate(@id,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='" . strtolower($this->user) . "' and @pass='" . $pkey .  "']") as $w)
              $found = true;
          } else {
            $found = $this->check_credentials($this->login,$this->key);
          }
        }
        # let ALL students in
        if (!$found && $this->par->xpath("//person[@id='university_student']")) {
          if (preg_match("/^[a-z][0-9]{7}/", strtolower($this->user))) {
            $found = $this->check_credentials($this->login,$this->key);
          }
        }
        if ($found) {
          do {
            $eCOOK = $this->uniqstr(48);
          } while (file_exists($cache . $eCOOK));
          $out = "<? \$this->user = \"" . $this->user . "\"; ?>";
          if (!$handle = fopen($cache . $eCOOK, 'w')) { print "Cannot open file (${cache}${eCOOK})"; exit; }
          if (!fwrite($handle, $out)) { print "Cannot write to file (${cache}${eCOOK})"; exit; }
          fclose($handle);

          setCookie($this->cookieprefix . 'CEWebSUser', $eCOOK, $this->anmeld, '', '', 0);
        } else {
          $this->user = '';
        }
      } else { $this->user = ''; }

      if (array_key_exists('BASIC',$_REQUEST) && $this->user == '') {
        header('WWW-Authenticate: Basic realm="CEWebS Realm"');
        header('HTTP/1.0 401 Unauthorized');
        exit;
      }

      if ((isset($_COOKIE)) && (array_key_exists($this->cookieprefix . 'CEWebSUser',$_COOKIE))) {
        if ($_REQUEST[$this->conf['mode']] == 'LOGOUT')  {
          setCookie($this->cookieprefix . 'CEWebSUser', $_COOKIE[$this->cookieprefix . 'CEWebSUser'], time()-1, '', '', 0);
          $this->user = '';
        } else
          if (file_exists($cache . $_COOKIE[$this->cookieprefix . 'CEWebSUser'])) {
            include($cache . $_COOKIE[$this->cookieprefix . 'CEWebSUser']);
            if (!$this->par)
              $this->par = simplexml_load_file($this->conf['data'] . '/persons.xml');
            if (
                 !($this->par->xpath("//person[translate(@id,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='" . strtolower($this->user) . "']")) &&
                 !($this->par->xpath("//person[@id='university_student']") && preg_match("/^[a-z][0-9]{7}/", strtolower($this->user)))
               ) {
              $this->user = '';
            }
          } else { $this->user = ''; }
      }

      # internally ignore cas
      $this->user = strtolower($this->user);

      parent::__construct(
        $_POST,
        $_GET,
        $_FILES,
        $_COOKIE[$this->cookieprefix . 'LANG'] ? $_COOKIE[$this->cookieprefix . 'LANG'] : $_SERVER['HTTP_ACCEPT_LANGUAGE'],
        $this->conf,
        $_COOKIE[$this->cookieprefix . 'CEWebSMenu'],
        $this->user,
        $mime,
        $this->get_user_admin(),
        $this->get_user_report(),
        $debug,
        $time
      );

      if (($_REQUEST[$this->conf['mode']] == 'ADMIN_SERVICES_SAVE') && ($this->get_user_admin()))
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_administration_services_save.php');
      if (($_REQUEST[$this->conf['mode']] == 'ADMIN_SERVICES_DELETE') && ($this->get_user_admin()))
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_administration_services_delete.php');
      if (($_REQUEST[$this->conf['mode']] == 'ADMIN_SERVICES_LOCK') && ($this->get_user_admin()))
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_administration_services_lock.php');
      if (($_REQUEST[$this->conf['mode']] == 'ADMIN_MENUPOINTS') && ($this->get_user_admin()))
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_administration_menupoints.php');
      if (($_REQUEST[$this->conf['mode']] == 'ADMIN_MENUPOINTS_ORDER') && ($this->get_user_admin()))
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_administration_menupoints_order.php');
      if (($_REQUEST[$this->conf['mode']] == 'ADMIN_MENUPOINTS_DELETE') && ($this->get_user_admin()))
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_administration_menupoints_delete.php');
      if (($_REQUEST[$this->conf['mode']] == 'ADMIN_ENTRY_POINTS') && ($this->get_user_admin()))
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_administration_entry_points.php');
      if (($_REQUEST[$this->conf['mode']] == 'ADMIN_REGISTERED_SERVICES') && ($this->get_user_admin()))
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_administration_registered_services.php');
      if (($_REQUEST[$this->conf['mode']] == 'ADMIN_MENUPOINTS_ADD') && ($this->get_user_admin()))
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_administration_menupoints_add.php');

      $this->set_headers();
      if ($this->get_mode() == 'F' || $this->get_mode() == 'C') {
        print $this->get_data();
        exit;
      }
      $this->menu = trim("\n" . $this->create_menu($this->get_menupoints()));
      foreach ($this->get_menucrumbs() as $p) {
        if ($this->breadcrumbnavigation != '') $this->breadcrumbnavigation .= ' &#187; ';
        if ($p->clickable) {
          if ($p->name == $this->conf['administration'] )
            $this->breadcrumbnavigation .= "<a href='" . $this->conf['script'] . "?{$this->conf['target']}={$p->name}&amp;{$this->conf['mode']}=ADMIN'>";
          elseif ($p->name == $this->conf['report'] )
            $this->breadcrumbnavigation .= "<a href='" . $this->conf['script'] . "?{$this->conf['target']}={$p->name}&amp;{$this->conf['mode']}=REPORT'>";
          else
            $this->breadcrumbnavigation .= "<a href='" . $this->conf['script'] . "?{$this->conf['target']}={$p->name}'>";
        }
                           $this->breadcrumbnavigation .= $p->description;
        if ($p->clickable) $this->breadcrumbnavigation .= "</a>";
      }
      foreach ($this->get_breadcrumbs() as $p) {
        if ($this->breadcrumbnavigation != '') $this->breadcrumbnavigation .= ' &#187; ';
        $this->breadcrumbnavigation .= $p;
      }
    }
    public function get_data() {
      if ($_REQUEST[$this->conf['mode']] == 'EMAIL')
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_email.php');
      elseif ($_REQUEST[$this->conf['mode']] == 'SEARCH')
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_search.php');
      elseif ($_REQUEST[$this->conf['mode']] == 'CHANGE')
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_change.php');
      elseif (($_REQUEST[$this->conf['mode']] == 'ADMIN') && ($this->get_user_admin()))
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_administration.php');
      elseif (($_REQUEST[$this->conf['mode']] == 'ADMIN_SERVICES') && ($this->get_user_admin()))
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_administration_services.php');
      elseif (($_REQUEST[$this->conf['mode']] == 'ADMIN_MENUPOINTS') && ($this->get_user_admin()))
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_administration_menupoints.php');
      elseif (($_REQUEST[$this->conf['mode']] == 'REPORT') && ($this->get_user_report()))
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_report.php');
      elseif ($_REQUEST[$this->conf['mode']] == 'LOGIN' || $this->needs_authentication())
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_login.php');
      elseif ($_REQUEST[$this->conf['mode']] == 'ADMIN_CEWEBS_LINK_INFO' && ($this->get_user_admin()))
        $this->data = $this->include_part($this->conf['engine_base'] . $this->conf['includes'] . '/part_administration_cewebs_link_info.php');
      return $this->data;
    }

    public function get_conf($what) {
      return $this->conf[$what];
    }

    private function get_search_results() {
      $search = $this->conf['cache'] . '/CacheSearch';
      $ret = array();
      if (file_exists($search)) {
        // TODO
      }
      return $ret;
    }

    public function get_menu() {
      return $this->menu;
    }
    public function get_breadcrumbnavigation() {
      return $this->breadcrumbnavigation;
    }
    public function get_activemenupoint() {
      return $this->activemenupoint;
    }

    public function set_uri($ary,$xamp='&amp;') {
      $out = $this->conf['url'] . (dirname($_SERVER['SCRIPT_NAME']) == '/' ? '' : '/') . $this->conf['script'];
      $first = true;
      foreach ($ary as $name => $value) {
        if ($first) {
          $out .= "?$name=$value";
          $first = false;
        } else
        $out .= "$xamp$name=$value";
      }
      return $out;
    }
    public function change_uri($name,$value) {
      if (preg_match("/({$name}=)(.*?)(&|\z)/",$this->uri))
        return $this->uri = preg_replace("/({$name}=)(.*?)(&|\z)/","\\1{$value}\\3",$this->uri);
      else
        if (preg_match("/\?/",$this->uri))
          return $this->uri .= '&amp;' . $name . "=" . $value;
        else
          return $this->uri .= '?' . $name . "=" . $value;
    }
    public function get_uri() {
      return $this->uri;
    }

    private function change_pass($oldpass,$newpass) {
      $doc = new DomDocument;
      $doc->preserveWhiteSpace = false;
      $doc->formatOutput = true;
      $doc->load($this->conf['data'] . '/persons.xml');
      $context = new DOMXPath($doc);

      $nodes = $context->query("/persons/person[@id='{$this->user}' and @pass='{$oldpass}']");
      if ($nodes->length > 0) {
        $nodes->item(0)->setAttribute('pass', $newpass);
        $doc->save($this->conf['data'] . '/persons.xml');
        return true;
      }
      return false;
    }

    private function send_pass($user) {
      $doc = simplexml_load_file($this->conf['data'] . '/persons.xml');
      $nds = $doc->xpath("/persons/person[@id='" . strtolower(trim($user)) . "']");
      if (count($nds) > 0) {
        foreach($nds as $node) {
          if (!$node['pass']) return 2;
          $to      = strtolower($node['email']);
          $subject = $this->string('sendsubject');
          $message = sprintf($this->string('sendmessage'),$node['name'],$node['pass']);
          $headers = 'From: ' . $this->string('sender') . "\r\n" .
            'Content-type: text/plain; charset=utf-8' . "\r\n" .
            'Reply-To: ' . $this->string('sender') . "\r\n" .
            'X-Mailer: PHP/' . phpversion();
          $subject = preg_replace('/[^\x09\x20-\x3C\x3E-\x7E]/e', 'sprintf("=%02X", ord("$0"));', $subject);
          $subject = str_replace(' ', '_', $subject);
          $subject = '=?utf-8?q?' . $subject . '?=';
          mail($to, $subject, $message, $headers);
        }
        return 1;
      }
      return 0;
    }

    public function get_user() {
      return $this->user;
    }
    public function get_user_name() {
      if (!$this->par)
        $this->par = simplexml_load_file($this->conf['data'] . '/persons.xml');
      if ($this->user_name == '')
        if ($this->user != '')
          foreach ($this->par->xpath("//person[@id='" . $this->user . "']") as $w)
            $this->user_name = $w['name'];
      return $this->user_name;
    }
    public function get_user_admin() {
      if (!$this->par)
        $this->par = simplexml_load_file($this->conf['data'] . '/persons.xml');
      if ($this->user_admin == NULL)
        if ($this->user != '')
          foreach ($this->par->xpath("//person[@id='" . $this->user . "']") as $w) {
            $this->user_admin = ($w['admin'] == 'true' ? true : false);
          }
      return $this->user_admin;
    }
    public function get_user_report() {
      if (!$this->par)
        $this->par = simplexml_load_file($this->conf['data'] . '/persons.xml');
      if ($this->user_report == NULL)
        if ($this->user != '')
          foreach ($this->par->xpath("//person[@id='" . $this->user . "']") as $w) {
            $this->user_report = ($w['admin'] == 'true' || $w['admin'] == 'limited' ? true : false);
          }
      return $this->user_report;
    }

    private function include_part($part) {
      if (is_file($part)) {
        ob_start();
        include $part;
        return ob_get_clean();
      }
      return '';
    }

    private function uniqstr($len) {
      $pwd = '';
      for($i=0;$i<$len;$i++){
        $num=rand(48,122);
        if(($num > 97 && $num < 122)){
            $pwd.=chr($num);
        }else if(($num > 65 && $num < 90)){
                $pwd.=chr($num);
        }else if(($num >48 && $num < 57)){
                $pwd.=chr($num);
        }else if($num==95){
            $pwd.=chr($num);
        }else{
            $i--;
        }
      }
      return $pwd;
    }
    private function create_menu($points,$space='  ') {
      $menu = '';
      foreach ($points as $p) {
        if ($p->registry == -2) {
          $menu .= "<li class='spacer'>&#160;</li>\n";
        } else {
          if ($p->active) {
            setCookie($this->cookieprefix . 'CEWebSMenu', $p->name, time() + (60*60*24*365), '', '', 0);
            $this->activemenupoint = $p->description;
          }
          $tam = ($p->active && $this->get_mode() == 'D' && $this->get_target() != $this->conf['report']);
          $tpam = false;
          if (count($p->children)) {
            foreach($p->children as $c) {
              if ($c->active && $this->get_mode() == 'D' && $this->get_target() != $this->conf['report']) {
                $tpam = true;
              }
            }
          }
          $menu .= "$space<li class='menu".($tam ? ' theActiveMenuPoint' : '').($tpam ? ' theParentActiveMenuPoint' : '')."'>";
          if ($p->clickable) {
            if ($p->registry == -1)
              $menu .= "<a target='_blank' href='" . $p->command . "'>";
            elseif ($p->registry == -2)
              $menu .= "<a href='" . $this->conf['script'] . '?' . $this->get_conf('target') . "={$p->name}'>";
            else
              $menu .= "<a href='" . $this->conf['script'] . '?' . $this->get_conf('target') . "={$p->name}'>";
          }
          $menu .= $p->description;
          if ($p->clickable)
            $menu .= '</a>';
          if (count($p->children))
            $menu .= "$space<ul>\n".$this->create_menu($p->children,$space.'  ')."$space</ul>\n";
          $menu .= "</li>\n";
        }
      }
      return $menu;
    }

    private function get_menupointDescription($point) {
      return $this->create_menupointDescription_rec($this->get_menupoints(),$point);
    }

    private function create_menupointDescription_rec($points,$point) {
      foreach ($points as $p) {
        if ($point == $p->name)
          return $p->description;
        if (count($p->children))
          $desc = $this->create_menupointDescription_rec($p->children, $point);
        if ($desc != NULL)
          return $desc;
      }
      return NULL;
    }

    private function check_credentials_server_parse($socket, $response) {
      $server_response = '';
      while (substr($server_response, 3, 1) != ' ') {
        if (!($server_response = fgets($socket, 256))) {
          throw new Exception("Error: Couldn't get mail server response codes");
        }
      }
      if (!(substr($server_response, 0, 3) == $response)) {
        throw new Exception("Error: $server_response");
      }
    }

    private function check_credentials($user,$pass) {
      $result = true;
      $socket = fsockopen('tcp://mail.univie.ac.at', 587, $errno, $errstr,30);
      if (!$socket) $result = false; // die("Unable to connect: $errstr ($errno)");
      if ($result) {
        try {
          $this->check_credentials_server_parse($socket, '220');
          fputs($socket, "EHLO [mail.univie.ac.at]\r\n");
          $this->check_credentials_server_parse($socket, '250');
          fputs($socket, "STARTTLS\r\n");
          $this->check_credentials_server_parse($socket, '220');
          stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
          fputs($socket, "EHLO [mail.univie.ac.at]\r\n");
          $this->check_credentials_server_parse($socket, '250');
          fputs($socket, "AUTH LOGIN\r\n");
          $this->check_credentials_server_parse($socket, '334');
          fputs($socket, base64_encode($user) . "\r\n");
          $this->check_credentials_server_parse($socket, '334');
          fputs($socket, base64_encode($pass) . "\r\n");
          $this->check_credentials_server_parse($socket, '235');
        } catch (Exception $e) {
          $result = false;
        }
        fputs($socket, "QUIT\r\n");
        fclose($socket);
      }
      return $result;
    }

  }
?>
