<?php
/*
* Copyright (c) 2009-2010 ATMAIL. All rights reserved
* See http://atmail.com/license.php for license agreement
*/

require_once('Atmail/Password.php');
require_once('Zend/Auth.php');

class Atmail_Session_SaveHandler_DbUserSession implements Zend_Session_SaveHandler_Interface
{
	public static $_sessionStore;
	private static $_Account = null;
	private static $_md5 = array();
	private static $_cryptFunction = Atmail_Enum::PASSWORD_PLAIN;

	public function Atmail_Session_SaveHandler_DbUserSession()
	{
		self::$_sessionStore = new Atmail_Db_Table( array('name' => 'UserSession') );	
	}	

	public function open($save_path, $name)
	{
		Zend_Registry::get('log')->debug( __METHOD__ . ' #' . __LINE__ . ':  Open called');
		self::$_cryptFunction = Atmail_Password::sessionCryptFunction();
		Zend_Registry::get('log')->debug( __METHOD__ . ' #' . __LINE__ . ':  Session crypt mode = ' . self::$_cryptFunction);

		return true;
	}

	public function close()
	{
		return true;
	}

	public function read($SessionID)
	{
		// sanity check the sessionid
		if (!$SessionID || $SessionID == '' || !ctype_alnum($SessionID))
		{
			return '';
		}

		
		$row = self::$_sessionStore->fetchRow( self::$_sessionStore->select()->where('SessionID = ?',$SessionID) );
		if ( $row && isset($row->SessionData) )
		{
			if(self::$_cryptFunction != Atmail_Enum::PASSWORD_PLAIN)
			{
				// some sort of password crypt maybe enabled
				if(isset($row->SessionData) && $row->SessionData != '')
				{
					$row->SessionData = Atmail_Password::hexaes_decrypt($row->SessionData);
				}
			}
			self::$_Account = $row->Account;
			self::$_md5[$SessionID] = md5($row->SessionData);
			Zend_Registry::get('log')->info('Read session data for ' . $SessionID);
			return $row->SessionData;
		}
		else
		{
			return '';
		}
	}

	public function write($id, $SessionData, $account = null)
	{		
		// ignore writing data if it has not changed
		if( isset(self::$_md5) && array_key_exists($id, self::$_md5) && self::$_md5[$id] == md5($SessionData) )
		{
			return true;
		}
		
		if($SessionData != '' && self::$_cryptFunction != Atmail_Enum::PASSWORD_PLAIN)
		{
			// some sort of password crypt maybe enabled
			// make sure we are not storing passwords etc
			$SessionData = Atmail_Password::hexaes_encrypt($SessionData);
		}
		
		if($account == null)
		{
			$authData = Zend_Auth::getInstance()->getIdentity();
			$account = $authData['Account'];
		}

		if(!is_null($account) && strlen($account) > 1)
		{
			Zend_Registry::get('log')->info('Write session data for ' . $id);

			//only store session for valid Account
			self::$_Account = $account;
			self::$_sessionStore->update(	array('SessionID' => $id, 'SessionData' => $SessionData, 'modified' => time()),
			self::$_sessionStore->getAdapter()->quoteInto( 'Account = ?', self::$_Account) );
		}
		return true;
	}

	public function destroy($id)
	{
		self::$_sessionStore->update(	array('SessionID' => 0, 'SessionData' => null, 'modified' => time()),
		self::$_sessionStore->getAdapter()->quoteInto( 'Account = ?', self::$_Account) );
		return true;
	}

	public function gc($maxLifetime)
	{
		self::$_sessionStore->update(	array( 'SessionID' => 0, 'SessionData' => null, 'modified' => time() ), 'LENGTH(`SessionID`) > 0 AND (' . time() . ' - modified) > ' . intval($maxLifetime) );
		return true;
	}

	public function enforceUniqueSID( $username )
	{
		$currentSessionId = session_id();
		$retriesLeft = 3;
		while(
			$retriesLeft-- > 0
			&& self::$_sessionStore->fetchRow( self::$_sessionStore->select()->where('SessionID = ?', $currentSessionId)->where('Account != ?', $username))
			)
		{
			session_regenerate_id();
			$currentSessionId = session_id();
		}
	}
	
	public static function enableEncryptedSessions($sSecretKey)
	{
		if(!isset(self::$_sessionStore))
		{
			self::$_sessionStore = new Atmail_Db_Table( array('name' => 'UserSession') );
		}
		
		$sessions = self::$_sessionStore->fetchAll(self::$_sessionStore->select());
		
		self::$_cryptFunction = Atmail_Enum::PASSWORD_ENCRYPTED;
		Atmail_Password::setTempSecretKey($sSecretKey);

		foreach($sessions as $session)
		{
			if($session['SessionID'] == '' || $session['SessionData'] == '') continue;
			self::write($session['SessionID'], $session['SessionData'], $session['Account']);
		}
	}
}
