<?php namespace HashOver;

// Copyright (C) 2018-2019 Jacob Barkdull
// This file is part of HashOver.
//
// HashOver 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.
//
// HashOver 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 HashOver.  If not, see <http://www.gnu.org/licenses/>.


class SourceCode
{
	public $files = array (
		array (
			'type' => 'Script',
			'path' => 'admin/blocklist/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/docs/en-us/api/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/docs/en-us/faq/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/docs/en-us/security/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/docs/en-us/settings/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/docs/en-us/setup/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/docs/en-us/technical/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/docs/en-us/use/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/docs/en-us/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/docs/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/example/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/login/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/moderation/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/moderation/threads.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/settings/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/updates/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/url-queries/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/view-setup.php'
		),
		array (
			'type' => 'Script',
			'path' => 'admin/index.php'
		),
		array (
			'type' => 'Script',
			'path' => 'api/backend/count-link-ajax.php'
		),
		array (
			'type' => 'Script',
			'path' => 'api/backend/latest-ajax.php'
		),
		array (
			'type' => 'Script',
			'path' => 'api/count-link.php'
		),
		array (
			'type' => 'Script',
			'path' => 'api/json.php'
		),
		array (
			'type' => 'Script',
			'path' => 'api/latest.php'
		),
		array (
			'type' => 'Script',
			'path' => 'api/rss.php'
		),
		array (
			'type' => 'Class',
			'name' => 'Avatars',
			'path' => 'backend/classes/avatars.php'
		),
		array (
			'type' => 'Class',
			'name' => 'CommentFiles',
			'path' => 'backend/classes/commentfiles.php'
		),
		array (
			'type' => 'Class',
			'name' => 'CommentParser',
			'path' => 'backend/classes/commentparser.php'
		),
		array (
			'type' => 'Class',
			'name' => 'CommentsUI',
			'path' => 'backend/classes/commentsui.php'
		),
		array (
			'type' => 'Class',
			'name' => 'Cookies',
			'path' => 'backend/classes/cookies.php'
		),
		array (
			'type' => 'Class',
			'name' => 'Crypto',
			'path' => 'backend/classes/crypto.php'
		),
		array (
			'type' => 'Class',
			'name' => 'Database',
			'path' => 'backend/classes/database.php'
		),
		array (
			'type' => 'Class',
			'name' => 'DataFiles',
			'path' => 'backend/classes/datafiles.php'
		),
		array (
			'type' => 'Class',
			'name' => 'DefaultLogin',
			'path' => 'backend/classes/defaultlogin.php'
		),
		array (
			'type' => 'Class',
			'name' => 'Email',
			'path' => 'backend/classes/email.php'
		),
		array (
			'type' => 'Class',
			'name' => 'FormUI',
			'path' => 'backend/classes/formui.php'
		),
		array (
			'type' => 'Class',
			'name' => 'HashOver',
			'path' => 'backend/classes/hashover.php'
		),
		array (
			'type' => 'Class',
			'name' => 'HTMLTag',
			'path' => 'backend/classes/htmltag.php'
		),
		array (
			'type' => 'Class',
			'name' => 'JavaScriptBuild',
			'path' => 'backend/classes/javascriptbuild.php'
		),
		array (
			'type' => 'Class',
			'name' => 'JavaScriptMinifier',
			'path' => 'backend/classes/javascriptminifier.php'
		),
		array (
			'type' => 'Class',
			'name' => 'Locale',
			'path' => 'backend/classes/locale.php'
		),
		array (
			'type' => 'Class',
			'name' => 'Login',
			'path' => 'backend/classes/login.php'
		),
		array (
			'type' => 'Class',
			'name' => 'Markdown',
			'path' => 'backend/classes/markdown.php'
		),
		array (
			'type' => 'Class',
			'name' => 'Misc',
			'path' => 'backend/classes/misc.php'
		),
		array (
			'type' => 'Class',
			'name' => 'ParseJSON',
			'path' => 'backend/classes/parsejson.php'
		),
		array (
			'type' => 'Class',
			'name' => 'ParseSQL',
			'path' => 'backend/classes/parsesql.php'
		),
		array (
			'type' => 'Class',
			'name' => 'ParseXML',
			'path' => 'backend/classes/parsexml.php'
		),
		array (
			'type' => 'Class',
			'name' => 'PHPMode',
			'path' => 'backend/classes/phpmode.php'
		),
		array (
			'type' => 'Class',
			'name' => 'FormData',
			'path' => 'backend/classes/formdata.php'
		),
		array (
			'type' => 'Class',
			'name' => 'SafeSettings',
			'path' => 'backend/classes/safesettings.php'
		),
		array (
			'type' => 'Class',
			'name' => 'Sendmail',
			'path' => 'backend/classes/sendmail.php'
		),
		array (
			'type' => 'Class',
			'name' => 'SensitiveSettings',
			'path' => 'backend/classes/sensitivesettings.php'
		),
		array (
			'type' => 'Class',
			'name' => 'SessionLogin',
			'path' => 'backend/classes/sessionlogin.php'
		),
		array (
			'type' => 'Class',
			'name' => 'Settings',
			'path' => 'backend/classes/settings.php'
		),
		array (
			'type' => 'Class',
			'name' => 'Setup',
			'path' => 'backend/classes/setup.php'
		),
		array (
			'type' => 'Class',
			'name' => 'SetupChecks',
			'path' => 'backend/classes/setupchecks.php'
		),
		array (
			'type' => 'Class',
			'name' => 'SMTP',
			'path' => 'backend/classes/smtp.php'
		),
		array (
			'type' => 'Class',
			'name' => 'SourceSode',
			'path' => 'backend/classes/sourcecode.php'
		),
		array (
			'type' => 'Class',
			'name' => 'SpamCheck',
			'path' => 'backend/classes/spamcheck.php'
		),
		array (
			'type' => 'Class',
			'name' => 'Statistics',
			'path' => 'backend/classes/statistics.php'
		),
		array (
			'type' => 'Class',
			'name' => 'Templater',
			'path' => 'backend/classes/templater.php'
		),
		array (
			'type' => 'Class',
			'name' => 'Thread',
			'path' => 'backend/classes/thread.php'
		),
		array (
			'type' => 'Class',
			'name' => 'WriteComments',
			'path' => 'backend/classes/writecomments.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/da-dk.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/de-de.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/el-el.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/en-us.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/es-es.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/fa-ir.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/fr-fr.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/ja-jp.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/ko-kr.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/lt-lt.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/nl-nl.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/eo-eo.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/pl-pl.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/pt-br.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/ro-ro.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/ru-ru.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/tr-tr.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/locales/zh-cn.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/comment-info.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/comments-ajax.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/form-actions.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/javascript-setup.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/json-setup.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/like.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/load-comments.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/nocache-headers.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/php-setup.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/source-viewer.php'
		),
		array (
			'type' => 'Script',
			'path' => 'backend/standard-setup.php'
		),
		array (
			'type' => 'Script',
			'path' => 'comments.php'
		),
		array (
			'type' => 'Script',
			'path' => 'loader.php'
		)
	);

	// Checks if a given file is a HashOver file
	protected function isHashOverFile ($path)
	{
		// Run through HashOver files array
		foreach ($this->files as $file) {
			// Check if the given file path matches the current file
			if ($path === $file['path']) {
				// If so, return true
				return true;
			}
		}

		// Otherwise return false
		return false;
	}

	// Sets content type header based on user request
	protected function setContentType ($file, $type)
	{
		// Switch between return types
		switch ($type) {
			// Display as plain text
			case 'text': {
				// Set content type header to plain text
				header ('Content-type: text/plain; charset=UTF-8');
				break;
			}

			// Display as HTML
			case 'html': {
				// Set content type header to HTML
				header ('Content-type: text/html; charset=UTF-8');
				break;
			}

			// Download source code
			case 'download': {
				// File name
				$file_name = basename ($file);

				// Set headers to trigger file download
				header ('Content-type: application/octet-stream');
				header ('Content-Disposition: attachment; filename="' . $file_name . '"');
				header ('Content-Length: ' . filesize ($file));

				break;
			}

			// Default to displaying an error
			default: {
				// Set content type header to plain text
				header ('Content-type: text/plain; charset=UTF-8');
				break;
			}
		}
	}

	// Format source code based on content type
	protected function format ($name, $source, $type)
	{
		// Switch between return types
		switch ($type) {
			// Display as HTML
			case 'html': {
				// Conform HTML highlighting to coding standard
				$source = str_replace ("\t", '/*_TAB_*/', $source);
				$source = highlight_string ($source, true);
				$source = str_replace ('/*_TAB_*/', "&#9;", $source);
				$source = str_replace ('&nbsp;', ' ', $source);
				$source = str_replace ("\n", '', $source);

				// Return highlighted source code
				return implode (PHP_EOL, array (
					'<!DOCTYPE html>',
					'<html lang="en" dir="ltr">',
					"\t" . '<head>',
					"\t\t" . '<title>' . $name . '</title>',
					"\t\t" . '<meta name="robots" content="noindex">',
					"\t" . '</head>',
					"\t" . '<body>',
					"\t\t" . '<pre>' . $source . '</pre>',
					"\t" . '</body>',
					'</html>'
				));
			}

			// Default to displaying as plain text
			default: {
				return $source;
			}
		}
	}

	// Display source code
	public function display ($file, $type = 'text')
	{
		// Check if the given file is a known HashOver file
		if ($this->isHashOverFile ($file) === true) {
			// If so, add directory change to file path
			$file = '../' . $file;

			// Set header for search engines to ignore file
			header ('X-Robots-Tag: noindex');

			// Set content type header
			$this->setContentType ($file, $type);

			// Load PHP file
			$source = @file_get_contents ($file);

			// File name
			$name = basename ($file);

			// Check if file read successfully
			if ($source !== false) {
				// If so, display formatted source code
				echo $this->format ($name, $source, $type);
			} else {
				// If not, display error
				echo 'Error! Failed to read HashOver file!';
			}
		} else {
			// If not, display error
			echo 'Error! Not a known HashOver file!';
		}
	}
}