<?php

	/*
	*	Gekko - Open Source Web Development Framework
	*	------------------------------------------------------------------------
	*	Copyright (C) 2004-2005, J. Carlos Nieto <xiam@users.sourceforge.net>
	*	This program is Free Software.
	*
	*	@package	Gekko
	*	@license	http://www.gnu.org/copyleft/gpl.html GNU/GPL License 2.0
	*	@author		J. Carlos Nieto <xiam@users.sf.net>
	*	@version	CVS: $Id:$
	*	@link		http://www.gekkoware.org
	*/

	if (!defined("IN-GEKKO")) die("Get a life!");

	require_once "remote.lib.php";

	/*
		*** ftpSession basic usage example ***
		$ftp = new ftpSession("localhost", 21, "user", "pass");
		if ($ftp) {

			$ftp->cd("public_html");
			$ftp->chmod("conf.php", 0777);

			header("content-type: image/png");
			echo $ftp->get("me.png");

			$ftp->bye();
		}

	*/

	class ftpSession {

		var $info = array();
		var $conn;
		var $logged = false;

		function ftpSession($host, $port = 21, $user = "anonymous", $pass = "anonymous@example.com") {
			$this->info["host"] = $host;
			$this->info["port"] = $port ? $port : 21;
			$this->info["user"] = $user ? $user : "anonymous";
			$this->info["pass"] = $pass ? $pass : "anonymous@example.com";
			$this->login();
		}

		// talks with server, expects responses, etc...
		function chat($expects, $answers = null, $avoid_errors = true) {
			$data = $this->conn->read();
			if (substr(trim($data), 0, 3) == $expects) {
				if ($answers) {
					$this->conn->write($answers);
				}
				return true;
			} else {
				if ($avoid_errors) return false;
				trigger_error("S: \"".trim($data)."\", expecting: \"$expects\"", E_USER_ERROR);
			}
		}

		function login() {
			if (!$this->info["host"])
				trigger_error("Please set FTP Account info first!", E_USER_ERROR);
			if (($this->conn = new remoteConnection($this->info["host"], $this->info["port"])) !== false) {
				$this->chat("220", "USER ".$this->info["user"]."\r\n");
				$this->chat("331", "PASS ".$this->info["pass"]."\r\n");
				$this->chat("230") or $this->error('FTP_WRONG_PASSWORD');
				$this->logged = true;
				return true;
			}
		}
		function auth() {
			return $this->logged;
		}
		function mkdir($dirname, $mod = "0775") {
			$this->conn->write("MKD $dirname\r\n");
			return ($this->chat("257") && $this->chmod($dirname, $mod));
		}
		function chmod($filename, $mod) {
			$this->conn->write("SITE CHMOD $mod $filename\r\n");
			return $this->chat("200");
		}
		function cd($dirname) {
			$this->conn->write("CWD $dirname/\r\n");
			return $this->chat("250");
		}
		function delete($filename) {
			$this->conn->write("DELE $filename\r\n");
			return $this->chat("250");
		}
		function rmdir($dirname) {
			$this->conn->write("RMD $dirname/\r\n");
			return $this->chat("250");
		}
		function mtime($file) {
			$this->conn->write("MDTM $file\r\n");
			if ($this->chat("213")) {
				return substr($this->conn->last(), 4);
			}
			return false;
		}
		function pwd() {
			$this->conn->write("PWD\r\n");

			if ($this->chat("257")) {
				return substr($this->conn->last(), 4);
			}
			return false;
		}
		function rename($oldfile, $newfile) {
			$this->conn->write("RNFR $oldfile\r\n");
			if ($this->chat("350")) {
				$this->conn->write("RNTO $newfile\r\n");
				return $this->chat("250");
			}
			return true;
		}
		function get($filename) {

			$this->conn->write("TYPE I\r\n");
			$this->chat("200");

			// switching to passive mode
			$this->conn->write("PASV\r\n");
			$this->chat("227");

			// getting data connection host and port
			preg_match("/\((.*)\)/", $this->conn->last(), $m);
			$m = explode(",", $m[1]);

			$host = $m[0].".".$m[1].".".$m[2].".".$m[3];
			$port = ($m[4]*256)+$m[5];

			// opening connection and downloading data
			if ($dataConn = new remoteConnection($host, $port)) {
				$this->conn->write("RETR $filename\r\n");
				$this->chat("150");
				$data = $dataConn->read();
				$dataConn->close();
			} else {
				$this->error('FTP_DATA_CONNECTION_ERROR');
			}

			if (!$this->chat("226")) {
				$this->error('FTP_NO_FILE');
				return false;
			}

			return $data;
		}
		function error($err) {
			echo "FTP Error: ";
			switch ($err) {
				case 'FTP_WRONG_PASSWORD':
					echo "Wrong username or password.";
				break;
				case 'FTP_DATA_CONNECTION_ERROR':
					echo "Data connection error.";
				break;
				case 'FTP_NO_FILE':
					echo "No such file or directory.";
				break;
				default: echo "Unknown error";
			}
			echo "\n";
			die;
		}
		function bye() {
			$this->conn->write("QUIT\r\n");
			$this->conn->close();
		}
	}

	/*
		*** httpSession basic usage example ***

		if (($http = new httpSession("example.com", "80")) !== false) {
			header("content-type: image/png");
			echo $http->get("/somedir/somefile.png");
			$http->close();
		}
	*/
	class httpSession {

		var $userAgent = "Gekko/0.5";
		var $conn, $info, $body, $header;

		var $headers = Array();

		function status() {
			return $this->conn->status();
		}

		function httpSession($host, $port = 80, $user = null, $pass = null) {
			$this->info["host"] = $host;
			$this->info["port"] = $port ? $port : 80;
			$this->info["user"] = $user;
			$this->info["pass"] = $pass;
			return $this->open($this->info["host"], $this->info["port"]);
		}
		function open($host, $port) {
			if (($this->conn = new remoteConnection($host, $port)) !== false) {
				return true;
			}
			return false;
		}
		function sendRequest($what) {
			$this->conn->write("GET ".($what ? $what : "/")." HTTP/1.0\r\n");
			$this->conn->write("Host: ".$this->info["host"].":".$this->info["port"]."\r\n");
			$this->conn->write("User-Agent: ".$this->userAgent."\r\n");
			if ($this->info["user"]) $this->conn->write("Authorization: Basic ".base64_encode($this->info["user"].":".$this->info["pass"])."\r\n");
			$this->conn->write("Accept: */*\r\n");
			$this->conn->write("Accept-Encoding: gzip,deflate\r\n");
			$this->conn->write("\r\n");
		}
		function getHeaders() {
			$buff = "";
			do {
				$line = fgets($this->conn->socket);
				$buff .= $line;
				if ($line == "\r\n")
					return $buff;
			} while (!feof($this->conn->socket));
		}
		function get($what) {

			if (!$this->status()) return false;

			$this->sendRequest($what);

			$buff = $this->conn->read(true);

			$dlmt = strpos($buff, "\r\n\r\n");

			$this->header = substr($buff, 0, $dlmt);
			$this->body = substr($buff, $dlmt+4);

			$headlines = explode("\n", $this->header);

			// this->head
			$http_response = false;
			//$stop = false;
			foreach ($headlines as $header) {
				if (!$http_response) {
					$http_response = $header;
					// expecting HTTP/1.1 200 OK
					if (!strpos($http_response, "200")) {
						return false;
					}
				} else {
					$del = strpos($header, ":");
					$hdr = strtolower(substr($header, 0, $del));
					$val = trim(substr($header, $del+1));
					$this->head[$hdr] = $val;
				}
			}

			// main mime type
			$mime = isset($this->head["content-type"]) ? substr($this->head["content-type"], 0, strpos($this->head["content-type"], "/")) : false;


			// inflating gzip'ed pages
			if ((isset($this->head["content-encoding"]) && ($this->head["content-encoding"] == "gzip") && ($mime == "text")) || (isset($this->head["vary"]) && $this->head["vary"] == "Accept-Encoding")) {
				// Read http://www.php.net/manual/en/function.gzinflate.php
				$this->body = gzinflate(substr($this->body, 10));

			}

			return $this->body;
		}
		function close() {
			$this->conn->close();
		}
	}

	/*
		Simple Mail Transfer Protocol
		Read: http://www.ietf.org/rfc/rfc0821.txt
	*/
	class smtpSession {
		var $conn;
		var $info;
		function smtpSession($host, $port = "25", $user = null, $pass = null) {
			$this->info["host"] = $host;
			$this->info["port"] = $port ? $port : "25";
			$this->info["user"] = $user;
			$this->info["pass"] = $pass;
			return $this->open();
		}
		function open() {
			$this->conn = new remoteConnection($this->info["host"], $this->info["port"]);
			if ($this->conn->status()) {
				return $this->login();
			} else {
				trigger_error("Couldn't open connection to SMTP server.",E_USER_ERROR);
				return false;
			}
		}
		function login() {
			$this->chat("220", "HELO ".$this->info["host"]."\r\n");
			$this->chat("250");
			if ($this->info["user"]) {
				/* TODO SMTP AUTHENTICATION */
				$this->conn->write("EHLO ".$this->info["host"]."\r\n");
			}
			return true;
		}
		function send($to, $subject, $message, $content_type = "text/plain", $headers = null) {
			$this->conn->write("MAIL FROM: <".conf::getkey("core", "site.contact_mail").">\r\n");

			// can handle multiple recipients
			$ato = explode(",", $to);
			foreach ($ato as $addr) {
				$this->chat("250", "RCPT TO: <".trim($addr).">\r\n");
			}
			// sending message
			$this->chat("250", "DATA\r\n");
			$this->chat("354");
			// headers
			$this->conn->write("Mime-Version: 1.0\r\n");
			$this->conn->write("Content-Type: $content_type\r\n");
			$this->conn->write("Subject: $subject\r\n");
			$this->conn->write("From: ".conf::getkey("core", "site.name")." <".conf::getkey("core", "site.contact_mail").">\r\n");
			$this->conn->write("To: <".$to.">\r\n");
			$this->conn->write("Date: ".date("r")."\r\n");
			$this->conn->write("X-Mailer: Gekko/".GEKKO_VERSION."\r\n");
			$this->conn->write("X-Gekko-Tag: ".(isset($GLOBALS["User"]["ID"]) ? $GLOBALS["User"]["ID"] : "0")."@".getIp()."\r\n");
			if ($headers) $this->conn->write($headers);
			// message body
			$this->conn->write("\r\n");
			$this->conn->write($message);
			$this->conn->write("\r\n.\r\n");
			// expecting confirmation
			$this->chat("250");
		}
		// talks with server, expects responses, etc...
		function chat($expects, $answers = null, $avoid_errors = true) {
			$data = $this->conn->read();
			if (substr(trim($data), 0, 3) == $expects) {
				if ($answers) {
					$this->conn->write($answers);
				}
				return true;
			} else {
				if ($avoid_errors) return false;
				trigger_error("S: \"".trim($data)."\", expecting: \"$expects\"", E_USER_ERROR);
			}
		}
		function bye() {
			$this->conn->write("QUIT\r\n");
			$this->conn->close();
		}
	}

	function sendmail($to, $subject, $message, $content_type = "text/plain", $headers = null) {
		if (conf::getkey("core", "smtp.enable")) {
			$smtp = new smtpSession(conf::getkey("core", "smtp.host"), conf::getkey("core", "smtp.port"), conf::getkey("core", "smtp.user"), conf::getkey("core", "smtp.pass"));
			if ($smtp->conn->status) {
				$smtp->send($to, $subject, $message, $content_type, $headers);
			}
			$smtp->bye();
		} else {
			if (!$headers) $headers = "";
			$headers .= "Mime-Version: 1.0\r\n";
			$headers .= "Content-Type: $content_type\r\n";
			$headers .= "From: ".conf::getkey("core", "site.name")." <".conf::getkey("core", "site.contact_mail").">\r\n";
			$headers .= "X-Gekko-Tag: ".(isset($GLOBALS["User"]["ID"]) ? $GLOBALS["User"]["ID"] : "0")."@".getIP()."\r\n";
			$headers .= "Date: ".date("r")."\r\n";
			mail($to, $subject, $message, $headers);
		}
	}
?>