<?php
/*******************************************************************************
 * Copyright (c) 2007-2014 Eclipse Foundation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Denis Roy (Eclipse Foundation)- initial API and implementation
 *    Christopher Guindon (Eclipse Foundation) - Bug 440590 - Improve the flexibility of session.class.php
 *******************************************************************************/
require_once(realpath(dirname(__FILE__) . "/../classes/friends/friend.class.php"));
require_once("app.class.php");
if (!class_exists("EvtLog")) {
  require_once("evt_log.class.php");
}

class Session {

  private $App = NULL;

  private $gid = "";

  private $bugzilla_id = 0;

  private $subnet = "";

  private $updated_at = "";

  private $Friend = NULL;

  private $data = "";

  private $session_name = "";

  private $domain = "";

  private $env = "";

  private $login_page = "";

  private $cookies_sent = FALSE;

  /**
   * Default constructor
   *
   * @return NULL
   */
  public function __construct($persistent=0, $configs = array()) {
   $this->App = new App();
   $domain = $this->App->getEclipseDomain();
   $default = array(
      'domain' => $domain['cookie'] ,
      'session_name' => 'ECLIPSESESSION',
      'env' => 'ECLIPSE_ENV',
      'login_page' => 'https://' . $domain['accounts'] . '/user/login',
    );

    # Set default config values.
    foreach ($default as $key => $value) {
      $this->{$key} = $value;
      if (!empty($configs[$key]) && is_string($configs[$key])) {
        $this->{$key} = $configs[$key];
      }
    }

    $this->validate();
  }

  function getGID() {
    return $this->gid;
  }

  function getBugzillaID() {
    return $this->bugzilla_id;
  }

  function getSubnet() {
    return $this->subnet;
  }

  function getUpdatedAt() {
    return $this->updated_at;
  }

  function getFriend() {
    if($this->Friend == NULL) {
      $this->Friend = new Friend();
    }
    return $this->Friend;
  }

  function getData() {
    return unserialize($this->data);
  }

  function getIsPersistent() {
    if ($this->hasCookieConsent()) {
      return 1;
    }
    return 0;
  }

  function getLoginPageURL() {
    return $this->login_page;
  }

  function getIsLoggedIn() {
    return $this->getGID() !== "";
  }

  /**
   * Verify if consent was given to use cookies
   *
   * @return boolean
   */
  public function hasCookieConsent() {
    $App = new App();
    return $App->hasCookieConsent();
  }


  function setGID($_gid) {
    $this->gid = $_gid;
  }

  function setBugzillaID($_bugzilla_id) {
    if (ctype_digit($_bugzilla_id)) {
      $this->bugzilla_id = $_bugzilla_id;
    }
  }

  function setSubnet($_subnet) {
    $this->subnet = $_subnet;
  }

  function setUpdatedAt($_updated_at) {
    $this->updated_at = $_updated_at;
  }

  function setFriend($_friend) {
    $this->Friend = $_friend;
  }

  function setData($_data) {
    $this->data = serialize($_data);
  }

  /**
   * Set is_persistent
   *
   * @deprecated
   */
  function setIsPersistent($_is_persistent) {
    trigger_error("Deprecated function called.", E_USER_NOTICE);
  }

  /**
   * Validate session based on browser cookie
   *
   * @return boolean
   */
  function validate() {
    $cookie = (isset($_COOKIE[$this->session_name]) ? $_COOKIE[$this->session_name] : "");
    $rValue = FALSE;
    if ($this->load($cookie)) {
      # TODO: update session?
      $rValue = TRUE;
      $this->maintenance();
      $this->setFriend($this->getData());
    }
    return $rValue;
  }

  function destroy($flush_all_sessions = FALSE) {
    $App = new App();
    $Friend = $this->getFriend();

    if ($flush_all_sessions && $Friend->getBugzillaID() > 0) {
      $sql = "DELETE FROM sessions WHERE bugzilla_id = '" . $App->sqlSanitize($Friend->getBugzillaID(), 0) . "'";
    }
    else {
      $sql = "DELETE FROM sessions WHERE gid = '" . $App->sqlSanitize($this->getGID(), NULL) . "' LIMIT 1";
    }
    $App->eclipse_sql($sql);

    # Remove the TAKEMEBACK cookie
    # Should these also be in session() ?
    setcookie("TAKEMEBACK", "", 0, "/", ".eclipse.org");
    setcookie("fud_session_2015", "", 0, "/forums/", ".eclipse.org");
    setcookie($this->session_name, "", 0, "/", $this->domain, 1, TRUE);
    setcookie($this->env, "", 0, "/", $this->domain, 0, TRUE);

    if (!$App->devmode) {
      # Log this event
      $EvtLog = new EvtLog();
      $EvtLog->setLogTable("sessions");
      $EvtLog->setPK1($Friend->getBugzillaID());
      $EvtLog->setPK2($App->getRemoteIPAddress());
      $EvtLog->setLogAction("DELETE");
      $EvtLog->insertModLog("apache");
    }
  }

  function create() {
    # create session in the database.
    $Friend = $this->getFriend();
    $this->setData($Friend);

    # need to have a LDAP ID to log in.
    if ($Friend->getUID()) {
      $App = new App();
      $this->setGID(md5(uniqid(rand(), TRUE)));
      $this->setSubnet($this->getClientSubnet());
      $this->setUpdatedAt($App->getCURDATE());

      // Bugzilla id is missing, let's try to find it.
      if (!$Friend->getBugzillaID() && $Friend->getEmail()) {
        $Friend->setBugzillaID($Friend->getBugzillaIDFromEmail($Friend->getEmail()));
      }

      $this->setBugzillaID($Friend->getBugzillaID());
      //$Friend->insertUpdateFriend();

      $sql = "INSERT INTO sessions (
            gid,
            bugzilla_id,
            subnet,
            updated_at,
            data,
            is_persistent)
            VALUES (
              " . $App->returnQuotedString($this->getGID()) . ",
              " . $App->sqlSanitize($Friend->getBugzillaID(), NULL) . ",
              " . $App->returnQuotedString($this->getSubnet()) . ",
              NOW(),
              '" . $App->sqlSanitize($this->data) . "',
              '" . $App->sqlSanitize($this->getIsPersistent(), NULL) . "')";

      $App->eclipse_sql($sql);

      if (!$App->devmode) {
        # Log this event
        $EvtLog = new EvtLog();
        $EvtLog->setLogTable("sessions");
        $EvtLog->setPK1($Friend->getBugzillaID());
        $EvtLog->setPK2($App->getRemoteIPAddress());
        $EvtLog->setLogAction("INSERT");
        $EvtLog->insertModLog("apache");
      }
      $this->setEclipseSessionCookies();
    }
  }

  /**
   * Set Eclipse Session Cookies
   *
   * @return boolean
   */
  public function setEclipseSessionCookies(){
    $gid = $this->getGID();
    if (empty($gid) || $this->cookies_sent) {
      return FALSE;
    }
    $this->cookies_sent = TRUE;
    $cookie_time = 0;
    if ($this->getIsPersistent()) {
      $cookie_time = time()+3600*24*7;
    }

    setcookie($this->session_name, $this->getGID(), $cookie_time, "/", $this->domain, 1, TRUE);
    # 422767 Session broken between http and https
    # Set to "S" for Secure.  We could eventually append more environment data, separated by semicolons and such
    setcookie($this->env, "S", $cookie_time, "/", $this->domain, 0, TRUE);
    return TRUE;
  }

  function load($_gid) {
    # need to have a bugzilla ID to log in
    $rValue = FALSE;
    if (!empty($_gid)) {
      $App = new App();
      $sql = "SELECT /* USE MASTER */ gid, bugzilla_id, subnet, updated_at, data,  is_persistent
        FROM sessions
        WHERE gid = " . $App->returnQuotedString($App->sqlSanitize($_gid, NULL)) . "
        AND subnet = " . $App->returnQuotedString($this->getClientSubnet());

      $result = $App->eclipse_sql($sql);
      if ($result && mysql_num_rows($result) > 0) {
        $rValue = TRUE;
        $myrow = mysql_fetch_assoc($result);
        $this->setGID($_gid);
        $this->setBugzillaID($myrow['bugzilla_id']);
        $this->setSubnet($myrow['subnet']);
        $this->setUpdatedAt($myrow['updated_at']);
        $this->data = $myrow['data'];

        # touch this session
        $sql = "UPDATE sessions SET updated_at = NOW(), is_persistent = '" . $App->sqlSanitize($this->getIsPersistent(), NULL) . "' WHERE gid = '" . $App->sqlSanitize($_gid, NULL) . "'";
        $App->eclipse_sql($sql);
        $this->setEclipseSessionCookies();
      }
    }
    return $rValue;
  }

  function maintenance() {
    $App = new App();
    // Sessions are re-generated by visiting accounts.eclipse.org
    $sql = "DELETE FROM sessions WHERE updated_at < DATE_SUB(NOW(), INTERVAL 8 DAY)";
    $App->eclipse_sql($sql);
  }

  function getClientSubnet() {
    # return class-c subnet
    $App = new App();
    return substr($App->getRemoteIPAddress(), 0, strrpos($App->getRemoteIPAddress(), ".")) . ".0";
  }

  function redirectToLogin() {
    $this->App->preventCaching();
    header("Location: " . $this->login_page, 303);
    exit;
  }

  /**
   * Determine if this session is logged in.
   * @author droy
   * @since 2014-07-03
   * @return boolean
   */
  function isLoggedIn() {
    return $this->getGID() != "";
  }

  /**
   * Update Friend object in Sessions table.
   *
   * @param object $Friend
   * @return boolean
   */
  function updateSessionData($Friend = NULL) {
    if (is_null($Friend)) {
      $Friend = $this->getFriend();
    }

   if (is_a($Friend, 'Friend') && $gid = $this->getGID()) {
      $this->setFriend($Friend);
      $this->setData($Friend);

      $sql = "UPDATE sessions SET updated_at = NOW(),
        data = '" . $this->App->sqlSanitize($this->data) . "'
        WHERE gid = '" . $this->App->sqlSanitize($gid, NULL) . "'";
       $this->App->eclipse_sql($sql);
       return TRUE;
    }

    return FALSE;
  }
}