<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');

/***************************************************************************
 *	PROJECT: ZokiSoft Smart Catalog
 *
 *	This program is a commercial software and any kind of using
 *	it must agree to ZokiSoft License Agreement.
 *
 *	This notice may not be removed from the code.
 *
 *	Copyright 2007-2008 ZokiSoft
 *	http://www.zokisoft.com/
 ***************************************************************************/

class Openid extends Catalog_Controller
{

	var $aHeaderVar = array();
	var $aFooterVar = array();

	// path to lib files
	var $sOpenIdLib = 'system/application/scripts/open_id/';
	// path to temporary files storage
	var $sOpenIdTmp = 'system/application/scripts/open_id/tmp/';	

/*
*
*	constructor
*
*/
	function Openid()
	{

		parent::Catalog_Controller();

		// check if openid enabled
		if ( 1 != $this->config->item('openid') )
			show_404();
		
		$this->aHeaderVar['catalog_charset'] = $this->config->item('catalog_charset');

		$this->aSystemVar['template_viewer_root'] = $this->config->item('template_module_viewer');
		$this->aSystemVar['template_viewer_current'] = $this->config->item('template_viewer_openid');

	}


/*
*
*	index
*
*/
	function index()
	{
		redirect('');
	}


/*
*
*	index
*
*/
	function login()
	{
	
		$this->load->library('validation');
		
		$rules['openid_url']			= "trim|required";

		$this->validation->set_rules($rules);
		$this->validation->set_error_delimiters('<div class="error">', '</div>');
		if ($this->validation->run() == FALSE)
		{
			// no POST - no errors :-)
			$this->load->view( $this->aSystemVar['template_viewer_current'] . 'login');
			return true;
		}

// =======================================================================================================
// =======================================================================================================
//	If open id url specified - start autorization
// =======================================================================================================
//========================================================================================================

		// include php-openid library files
		$sOpenIdLib = $this->sOpenIdLib;
		
		require_once($sOpenIdLib.'Auth/OpenID/Consumer.php');
		require_once($sOpenIdLib.'Auth/OpenID/FileStore.php');
		require_once($sOpenIdLib.'Auth/OpenID/SReg.php');

		// i don't know why they need session :-(
		session_start();
		
		$oTmpStore = new Auth_OpenID_FileStore($this->sOpenIdTmp); 
    
		$oConsumer = new Auth_OpenID_Consumer($oTmpStore);

		// set trust root ( url of site )
		$sTrustRoot = base_url(); 
		
		// set return path
		//$sReturnUrl = site_url('openid/complete'); 
		$sReturnUrl = site_url('?c=openid&m=complete'); 

		// get open id
		$sOpenId = $this->input->post('openid_url');
		
		// get open id object to normalize openid url with same function as library
		$oOpenId = new Auth_OpenID();
		$sOpenId = $oOpenId->normalizeUrl($sOpenId);
		
        $oAuthRequest = $oConsumer->begin($sOpenId);

        if (!$oAuthRequest)
		{
            $sErr = "Authentication error: wrong data provided.";
        }
		else
        {
            
			// check if user with given open id already registered.
			// in this case, we dont need additional data from openid server.
			// TODO: now openid and users tables are connected one-to-one.
			// in specification they recomend to have ability connect multiple openids to single user.
			if ( false == $this->_getUserByOpenId($sOpenId) )
			{
				$oSRegRequest = Auth_OpenID_SRegRequest::build(
	                                             // Required
	                                             array('nickname','email'),
	                                             // Optional array('fullname')
	                                             array());
	                                             
	            if ($oSRegRequest)
	                $oAuthRequest->addExtension($oSRegRequest);
			}

			if ($oAuthRequest->shouldSendRedirect()) 
			{
			
	            $sRedirectUrl = $oAuthRequest->redirectURL($sTrustRoot,$sReturnUrl);
	            
	            if( Auth_OpenID::isFailure($sRedirectUrl) )
	                $sErr = "Can not redirect to server: ". $redirect_url->message;
	            else
	            {
	                header("Location: ".$sRedirectUrl);
	                exit;
	            }
			}
			else
			{
				// Generate form markup and render it.
				$form_id = 'openid_message';
				$form_html = $oAuthRequest->htmlMarkup($sTrustRoot,$sReturnUrl,
                                               false, array('id' => $form_id));

				// Display an error if the form markup couldn't be generated;
				// otherwise, render the HTML.
				if (Auth_OpenID::isFailure($form_html)) 
				{
					$sErr = "Could not redirect to server: " . $form_html->message;
				}
				else
				{
					print $form_html;
					exit;
				}			
			}
        }

		echo $sErr;
		
//		$this->load->view( $this->aSystemVar['template_viewer_current'] . 'login', $aData );
		
	}

	
	
	function complete()
	{

		// include php-openid library files
		$sOpenIdLib = $this->sOpenIdLib;
		
		require_once($sOpenIdLib.'Auth/OpenID/Consumer.php');
		require_once($sOpenIdLib.'Auth/OpenID/FileStore.php');
		require_once($sOpenIdLib.'Auth/OpenID/SReg.php');

		// i don't know why they need session :-(
		session_start();
	
		$oTmpStore = new Auth_OpenID_FileStore($this->sOpenIdTmp); 
    
		$oConsumer = new Auth_OpenID_Consumer($oTmpStore);

		// set return path
		//$sReturnUrl = site_url('openid/complete'); 
		$sReturnUrl = site_url('?c=openid&m=complete'); 

		$oResponse = $oConsumer->complete($sReturnUrl);
/*
print_r($_GET);
echo '<hr />';
print_r($_SESSION);
*/
		// check answer
		if ($oResponse->status == Auth_OpenID_CANCEL)
		{
			$sErr = 'Authentication canceled .';
		}
		else if ($oResponse->status == Auth_OpenID_FAILURE) 
		{
			$sErr = "Authentication failed: " . $oResponse->message;
		}
		else if ($oResponse->status == Auth_OpenID_SUCCESS) 
		{
			// everything ok. Get identify url and user data
			$sOpenId = $oResponse->getDisplayIdentifier();
         
			// try to login by given openid ( if this openid already registered )
			if( !$this->_loginbyOpenId($sOpenId) )
			{
				//Получаем данные о пользователе
			    $oRegData = Auth_OpenID_SRegResponse::fromSuccessResponse($oResponse);

				$aRegData = $oRegData->contents();

//=================================== debug
/*
$sOpenId = 'http://bulat.myopenid.com';
$sOpenId = '\' OR 1/*';

$aRegData = array(
	'fullname' => 'Vladislav2',
	'nickname' => 'bulat2',
	'email' => 'xxx@ddd.com',
	);
	
$aRegData = array(
	'nickname' => '\' OR 1/*',
	'email' => '\' OR 1/*',
	);
*/
// =========================================

				$aData['data']['User'] = array(
						'openid'	=> $sOpenId,
						'fullname'	=> @$aRegData['fullname']
					);

				// unique nickname check
				$aData['data']['User']['nickname'] = $this->_unique_nickname_check(@$aRegData['nickname'])?$aRegData['nickname']:'';
				
				// unique email check
				$aData['data']['User']['email'] = $this->_unique_email_check(@$aRegData['email'])?$aRegData['email']:'';

				// prepare registration page
				$this->aHeaderVar['page_title'] = $this->lang->line('_user_registration');

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

				$this->load->view( $this->aSystemVar['template_viewer_current'] . 'registration', $aData );
				
				return true;

			}
			else
			{
				// login successfully
				redirect();
			}
		}

		echo $sErr;
		return false;
	
	}


	function saveuser()
	{

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

		$rules['OpenId']		= "trim|required|callback__unique_openid_check";
		$rules['Name']			= "trim|required|min_length[" . $this->config->item('user_nick_min') . "]|max_length[" . $this->config->item('user_nick_max') . "]|alpha_numeric|callback__unique_nickname_check";
		$rules['Email'] 		= "trim|required|valid_email|xss_clean|callback__unique_email_check";

		$this->validation->set_rules($rules);
		$this->validation->set_error_delimiters('<div class="error">', '</div>');
		if( $this->validation->run() == FALSE )
		{

			$aData['data']['User'] = array (
				'openid'	=>	$this->input->post( 'OpenId' ),
				'nickname'	=>	$this->input->post( 'Name' ),
				'email'		=>	$this->input->post( 'Email' ),
			);

			$this->load->view( $this->aSystemVar['template_viewer_current'] . 'registration', $aData );
			
			return false;
		}

		$sOpenId = $this->input->post('OpenId');
		
// create user folder if it not exist yet
		$sUserDataPath = $this->config->item('user_data_path');
		$sUserFolder = strtoupper(substr($this->input->post('Name'),0,1)) . '/' . $this->input->post('Name') . '/';
		$this->Catalog_model->createFolder($sUserFolder,$sUserDataPath);

		$aUser = array (
			'Name'		=>	$this->input->post( 'Name', true ),
			'Email'		=>	$this->input->post( 'Email', true ),
			'Time'		=>	date($this->config->item('long_date_format')),
			'UserFolder'=>	$sUserFolder
		);

// save user
		$aUser['Status'] = ( '1' == $this->config->item('confirmation_mail') ? 'unconfirmed' : $this->config->item('newbie_status') );
		$this->db->insert( 'zok_user', $aUser );
		$iUserId = $this->db->insert_id();
		
// add user's OpenId
		$this->db->insert( 'zok_user_openid', array('OpenId' => $sOpenId, 'UserId' => $iUserId));


// AUTOLOGIN user:
		$this->_loginbyOpenId($sOpenId);

// if confirmation mail enabled
		if ( '1' == $this->config->item('confirmation_mail') )
		{
			$this->_sendConfirmationMail($iUserId);
			redirect( 'user/confirmation/' );
		}
		else
		{

			$aMailVars = array();
			$aMailVars['user_nick'] = $aUser['Name'];
			$aMailVars['user_email'] = $aUser['Email'];

			$this->Catalog_model->SendTMail('registration', '', $aUser['Email'], $aMailVars );

			redirect('');

		}

	}


	function _getUserByOpenId($sOpenId)
	{
	
		$this->db->select('`zok_user`.*, `zok_user_openid`.`OpenId`');
		$this->db->where('`OpenId`=\''.$sOpenId.'\'');
		$this->db->join('`zok_user`','`zok_user`.`Id`=`zok_user_openid`.`UserId`');
		$rRes = $this->db->get('`zok_user_openid`');
		
		$aUser = $rRes->result_array();
	
		// no user found
		if ( 0 == count($aUser) )
			return false;

		return $aUser;	
	}
	
	
	function _loginbyOpenId($sOpenId)
	{
	
		$this->db->select('`zok_user`.*, `zok_user_openid`.`OpenId`');
		$this->db->where('`OpenId`=\''.$sOpenId.'\'');
		$this->db->join('`zok_user`','`zok_user`.`Id`=`zok_user_openid`.`UserId`');
		$rRes = $this->db->get('`zok_user_openid`');
		
		$aUser = $rRes->row_array();
	
		// no user found
		if ( 0 == count($aUser) )
		{
			return false;
		}

		// if user with specified openid exist - login him

		$aData = array(
			'userid'	=>	$aUser['Id'],
			'username'	=>	$aUser['Name'],
			'usergroup'	=>	$aUser['UserGroup'],
			'loggedin'	=>	true
		);

		$this->session->set_userdata($aData);
	
		return true;
	}
	
	
	function _unique_openid_check($sOpenId = '')
	{

		if ( empty($sOpenId))
			return FALSE;

		$this->db->select('`zok_user_openid`.`OpenId`');
		$this->db->where('`zok_user_openid`.`OpenId` = \''.mysql_real_escape_string($sOpenId).'\'');
		$rRes = $this->db->get('`zok_user_openid`');

		if ( 0 < $rRes->num_rows() )
		{
			$this->validation->set_message('_unique_openid_check', 'given openid url already exists !!' );
			return FALSE;
		}
		else
		{
			return TRUE;
		}

	}
	
	
	function _unique_nickname_check($sNick = '')
	{

		if ( !preg_match('/^\w+$/', $sNick) )
			return FALSE;

		$iLength = strlen( $sNick );

		if ( $iLength > $this->config->item('user_nick_max') || $iLength < $this->config->item('user_nick_min') )
		{
			return FALSE;
		}

		$this->db->select('`zok_user`.`Id`');
		$this->db->where('`zok_user`.`Name` = \'' . $sNick . '\'');
		$rRes = $this->db->get('`zok_user`');

		if ( 0 < $rRes->num_rows() )
		{
			$this->validation->set_message('_unique_nickname_check', $this->lang->line('unique_nickname_check') );
			return FALSE;
		}
		else
		{
			return TRUE;
		}

	}


	function _unique_email_check( $sEmail = '', $bValidation = true )
	{

		if ( empty($sEmail) )
			return false;

		$this->db->select('`zok_user`.`Id`');
		$this->db->where('`zok_user`.`Email` = \'' . $sEmail . '\'');
		$rRes = $this->db->get('`zok_user`');

		if ( 0 < $rRes->num_rows() )
		{
			if ( $bValidation )
				$this->validation->set_message('_unique_email_check', $this->lang->line('unique_email_check') );
			return FALSE;
		}
		else
		{
			return TRUE;
		}

	}
	
	
	function _sendConfirmationMail($iUserId)
	{

		$aUser = $this->Catalog_model->GetUserArrayById($iUserId);
		if ( 0 == count($aUser) )
			return false;

	   	$sConfirmationCode = md5( time() );

// clear old records from confirmation table;
    	$this->db->where(' DATE_ADD( `zok_user_confirmation`.`Date`, INTERVAL 3 DAY ) < NOW() ');
		$this->db->delete(' `zok_user_confirmation` ');

    	$this->db->select('`zok_user_confirmation`.`Id`');
    	$this->db->where('`zok_user_confirmation`.`UserId` = \'' . $aUser['Id'] . '\'');
    	$rRes = $this->db->get('`zok_user_confirmation`');

		$aData = array(
			'UserId'	=>	$aUser['Id'],
			'Hash'		=>	$sConfirmationCode,
			'Date'		=>	date("Y-m-d")
		);

		if ( 0 < $rRes->num_rows() )
    	{
			$this->db->where('`zok_user_confirmation`.`UserId` = \'' .  $aUser['Id'] . '\'');
    		$this->db->update('`zok_user_confirmation`', $aData);
		}
		else
		{
			$this->db->insert('`zok_user_confirmation`', $aData);
		}

		$aAddVar = array(	'user_name' => $aUser['Name'],
							'confirmation_code' => $sConfirmationCode,
							'confirmation_code_link' => site_url('user/confirmation/' . $sConfirmationCode)
					);


		return $this->Catalog_model->SendTMail( 'confirm_email', '', $aUser['Email'], $aAddVar );

	}
	

}

/* End of file user.php */
/* Location: ./system/application/controllers/user.php */