<?php
/*
 * Copyright 2007-2011 Charles du Jeu <contact (at) cdujeu.me>
 * This file is part of AjaXplorer.
 *
 * AjaXplorer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * AjaXplorer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with AjaXplorer.  If not, see <http://www.gnu.org/licenses/>.
 *
 * The latest code can be found at <http://www.ajaxplorer.info/>.
 */
defined('AJXP_EXEC') or die( 'Access not allowed');

/**
 * AJXP_Plugin to access a remote server that implements AjaXplorer API
 * @package AjaXplorer_Plugins
 * @subpackage Access
 */
class remote_fsAccessWrapper implements AjxpWrapper {
	
	// Instance vars $this->
	protected $host;
	protected $port;
	protected $secure;
	protected $path;
	protected $user;
	protected $password;
	protected $repositoryId;
	protected $fp;
	
	protected $crtMode;
	protected $crtParameters;
	protected $postFileData;
	
    public static function getRealFSReference($path, $persistent = FALSE){
    	$tmpFile = AJXP_Utils::getAjxpTmpDir()."/".md5(time());
    	$tmpHandle = fopen($tmpFile, "wb");
    	self::copyFileInStream($path, $tmpHandle);
    	fclose($tmpHandle);
    	if(!$persistent){
    		register_shutdown_function(array("AJXP_Utils", "silentUnlink"), $tmpFile);
    	}
    	return $tmpFile;
    }	
    
    public static function isRemote(){
    	return true;
    }
    
    public static function copyFileInStream($path, $stream){
    	$fake = new remote_fsAccessWrapper();
    	$parts = $fake->parseUrl($path);
		$client = $fake->createHttpClient();	
		$client->writeContentToStream($stream);
		$client->get($fake->path."?get_action=get_content&file=".AJXP_Utils::securePath($parts["path"]));
		$client->clearContentDestStream();
    }
        
	public function stream_open($url, $mode, $options, &$context){		
		if($mode == "w" || $mode == "rw"){			
			$this->crtMode = 'write';
			$parts = $this->parseUrl($url);
			$this->crtParameters = array(
				"get_action"=>"put_content", 
				"encode"	=> "base64",
				"file" => urldecode(AJXP_Utils::securePath($parts["path"]))
			);
			$tmpFileBuffer = realpath(AJXP_Utils::getAjxpTmpDir()).md5(time());
			$this->postFileData = $tmpFileBuffer;
			$this->fp = fopen($tmpFileBuffer, "w");
		}else{
			$this->crtMode = 'read';			
			$this->fp = tmpfile();
			$this->copyFileInStream($url, $this->fp);			
			rewind($this->fp);
		}
		return ($this->fp !== false);
	}
	
    public function stream_stat(){
    	return fstat($this->fp);
    }	
    
    public function stream_seek($offset , $whence = SEEK_SET){
    	fseek($this->fp, $offset, SEEK_SET);
    }
    
    public function stream_tell(){
    	return ftell($this->fp);
    }	
    
    public function stream_read($count){    	
    	return fread($this->fp, $count);
    }

    public function stream_write($data){
    	fwrite($this->fp, $data, strlen($data));
        return strlen($data);
    }

    public function stream_eof(){
    	return feof($this->fp);
    }
   
    public function stream_close(){
    	if(isSet($this->fp) && $this->fp!=-1 && $this->fp!==false){
    		fclose($this->fp);
    	}
    }
    
    public function stream_flush(){
    	if(isSet($this->fp) && $this->fp!=-1 && $this->fp!==false){
    		if($this->crtMode == 'write'){
    			rewind($this->fp);
    			AJXP_Logger::debug("Http_fput", array("target"=>$this->path));
    			$link = $this->createHttpClient();
    			$this->crtParameters["content"] = base64_encode(implode("", file($this->postFileData)));
    			$link->post($this->path, $this->crtParameters);
    		}else{
		    	fflush($this->fp);
    		}
    	}
    }

    public function url_stat($path, $flags){
    	$parts = $this->parseUrl($path);
    	$client = $this->createHttpClient();
    	$client->get($this->path."?get_action=stat&file=".AJXP_Utils::securePath($parts["path"]));
    	$json = $client->getContent();
    	$decode = json_decode($json, true);
    	return $decode;
    }
    

    // NOT IMPLEMENTED
    public static function changeMode($path, $chmodValue){
    }    
    
    public function unlink($url){
    }
    
    public function rmdir($url, $options){
    }
    
    public function mkdir($url, $mode, $options){
    }
    
    public function rename($from, $to){
    }
    
	
	public function dir_opendir ($url , $options ){
	}
	
	public function dir_closedir  (){
	}	
	
	public function dir_readdir (){
	}	
	
	public function dir_rewinddir (){
	}
	    
	
	
	protected function parseUrl($url){
		// URL MAY BE ajxp.ftp://username:password@host/path
		$urlParts = parse_url($url);
		$this->repositoryId = $urlParts["host"];
		$repository = ConfService::getRepositoryById($this->repositoryId);		
		// Get USER/PASS
		// 1. Try from URL
		if(isSet($urlParts["user"]) && isset($urlParts["pass"])){
			$this->user = $urlParts["user"];
			$this->password = $urlParts["pass"];			
		}
		// 2. Try from user wallet
		if(!isSet($this->user) || $this->user==""){
			$loggedUser = AuthService::getLoggedUser();
			if($loggedUser != null){
				$wallet = $loggedUser->getPref("AJXP_WALLET");
				if(is_array($wallet) && isSet($wallet[$this->repositoryId]["AUTH_USER"])){
					$this->user = $wallet[$this->repositoryId]["AUTH_USER"];
					$this->password = $loggedUser->decodeUserPassword($wallet[$this->repositoryId]["AUTH_PASS"]);
				}
			}
		}
		// 3. Try from repository config
		if(!isSet($this->user) || $this->user==""){
			$this->user = $repository->getOption("AUTH_USER");
			$this->password = $repository->getOption("AUTH_PASS");
		}
		if(!isSet($this->user) || $this->user==""){
			throw new AJXP_Exception("Cannot find user/pass for Http access!");
		}
		
		$this->host = $repository->getOption("HOST");
		$this->path = $repository->getOption("URI");
		$this->auth_path = $repository->getOption("AUTH_URI");
		$this->use_auth = $repository->getOption("USE_AUTH");
		
		$urlParts["path"] = urlencode($urlParts["path"]);
		
        return $urlParts;
	}
	
	/**
	 * Initialize and return the HttpClient
	 *
	 * @return HttpClient
	 */
    protected function createHttpClient(){
    	
		require_once(AJXP_BIN_FOLDER."/class.HttpClient.php");
		$httpClient = new HttpClient($this->host);
		$httpClient->cookie_host = $this->host;
		$httpClient->timeout = 50;
		AJXP_Logger::debug("Creating Http client", array());
		//$httpClient->setDebug(true);
		if(!$this->use_auth){
			return $httpClient;
		}
		
		$uri = "";
		if($this->auth_path != ""){
			$httpClient->setAuthorization($this->user, $this->password);			
			$uri = $this->auth_path;
		}
		if(!isSet($_SESSION["AJXP_REMOTE_SESSION"])){		
			if($uri == ""){
				// Retrieve a seed!
				$httpClient->get($this->path."?get_action=get_seed");
				$seed = $httpClient->getContent();
				$user = $this->user;
				$pass = $this->password;
				$pass = md5(md5($pass).$seed);
				$uri = $this->path."?get_action=login&userid=".$user."&password=".$pass."&login_seed=$seed";
			}
			$httpClient->setHeadersOnly(true);
			$httpClient->get($uri);
			$httpClient->setHeadersOnly(false);
			$cookies = $httpClient->getCookies();		
			if(isSet($cookies["AjaXplorer"])){
				$_SESSION["AJXP_REMOTE_SESSION"] = $cookies["AjaXplorer"];
				$remoteSessionId = $cookies["AjaXplorer"];
			}
		}else{
			$remoteSessionId = $_SESSION["AJXP_REMOTE_SESSION"];
			$httpClient->setCookies(array("AjaXplorer"=>$remoteSessionId));
		}
		AJXP_Logger::debug("Http Client created", array());
		return $httpClient;    	
    }	
    
    
}
?>
