From: Roland Haeder <roland@mxchange.org>
Date: Tue, 11 May 2010 07:58:56 +0000 (+0000)
Subject: Complete rewrite:
X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=feee76fac45134d75340668005fb2c252e24856d;p=ctracker.git

Complete rewrite:
- Very simple and basic template system (HTML and email) added
- Templates are language-dependent or indepented, this depends on if you call
  crackerTrackerLoadTemplate() or crackerTrackerLoadLocalizedTemplate()
- Email templates are always language-depenent... :-)
- Flexible database auto-update added (please just call your secured script
  normally!)
- Language sub-system added (German and English language is complete)
- Suport ticket added which gives your users, if his IP has recent malicious
  activities on the secured server, a support ticket form where they can request
  help. After the form is sent, the user can fully disable that warning. This is
  done by the script sends him a cookie with his ticket id.
- This support ticket system can be switched off and a little configured in
  the database table 'ctracker_config'. You can currently change the following
  values there:
  + Minimum random delay in seconds (default: 10 seconds)
  + Maximum random delay in seconds (default: 30 seconds)
  + Wether the support ticket system is on/off (default: on)
  + Which language you prefer to read (default: en)
- README updated
---

diff --git a/.gitattributes b/.gitattributes
index f9e49f2..84037be 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -10,8 +10,15 @@ docs/TODO -text
 docs/TODOs.txt -text
 install/install.sql -text
 libs/.htaccess -text
+libs/language/.htaccess -text
 libs/lib_ -text
 libs/lib_connect.php -text
 libs/lib_detector.php -text
 libs/lib_general.php -text
+libs/mails/.htaccess -text
+libs/mails/de/.htaccess -text
+libs/mails/en/.htaccess -text
+libs/templates/.htaccess -text
+libs/templates/de/.htaccess -text
+libs/templates/en/.htaccess -text
 /todo-builder.sh -text
diff --git a/config/db_config.php.dist b/config/db_config.php.dist
index 8821b7f..e3c93b3 100644
--- a/config/db_config.php.dist
+++ b/config/db_config.php.dist
@@ -4,7 +4,7 @@
  *
  * @author		Roland Haeder <webmaster@ship-simu.org>
  * @version		3.0.0
- * @copyright	Copyright (c) 2009 Cracker Tracker Team
+ * @copyright	Copyright (c) 2009, 2010 Cracker Tracker Team
  * @license		GNU GPL 3.0 or any newer version
  * @link		http://www.ship-simu.org
  *
@@ -37,9 +37,6 @@ $GLOBALS['ctracker_password'] = '';
 // Debugging should be disabled by default
 // $GLOBALS['ctracker_debug'] = true;
 
-// Mail headers
-$GLOBALS['ctracker_header'] = 'From: ctracker@domain.invalid';
-
 // Email recipient for all emails
 $GLOBALS['ctracker_email'] = 'you@domain.invalid';
 
diff --git a/ctracker.php b/ctracker.php
index f1fda19..acb5bc5 100644
--- a/ctracker.php
+++ b/ctracker.php
@@ -8,7 +8,7 @@
  *
  * @author		Roland Haeder <webmaster@ship-simu.org>
  * @version		3.0.0
- * @copyright	Copyright (c) 2009 Cracker Tracker Team
+ * @copyright	Copyright (c) 2009, 2010 Cracker Tracker Team
  * @license		GNU GPL 3.0 or any newer version
  * @link		http://www.ship-simu.org
  *
@@ -31,17 +31,19 @@ include('config/db_config.php');
 include('libs/lib_general.php');
 include('libs/lib_detector.php');
 include('libs/lib_connect.php');
+include('libs/lib_updates.php');
 
 // Init
 initCrackerTrackerArrays();
 
-// If no email is defined, asume default. This code should be removed
-if (!defined('__CTRACKER_EMAIL')) {
-	define('__CTRACKER_EMAIL', 'webmaster@mxchange.org');
-} // END - if
+// Get a database link
+aquireCrackerTrackerDatabaseLink();
+
+// Update database scheme
+crackerTrackerUpdateDatabaseScheme();
 
 // If it differs to original and the *whole* request string is not in whitelist
-// then blog the attempt
+// then block the attempt
 if (isCrackerTrackerWormDetected()) {
 	// Send the email, this must be the last line because it contains a die()
 	sendCrackerTrackerMail();
@@ -53,6 +55,12 @@ if (isCrackerTrackerPostAttackDetected()) {
 	sendCrackerTrackerPostMail();
 } // END - if
 
+// Does the current IP produce some blocked requests but not now?
+if ((getCrackerTrackerConfig('ctracker_alert_user') == 'Y') && (isCrackerTrackerIpSuspicious())) {
+	// This IP is suspicious, so we alert him/her
+	crackerTrackerAlertCurrentUser();
+} // END - if
+
 // Close any open database links
 crackerTrackerCloseDatabaseLink();
 
diff --git a/docs/README b/docs/README
index 16fb41e..b2571ed 100644
--- a/docs/README
+++ b/docs/README
@@ -1,6 +1,15 @@
 README
 ------
 
+Diese Software benoetigt InnoDB (kostenlose Datenbank-Engine) unter MySQL, da
+Fremdschluessel verwendet werden. Lassen Sie sich dies von Ihrem Support
+aktivieren! Im Normalfall sollte dies aber bereits aktiv sein.
+
+Sie koennen dies z.B. mit phpMyAdmin sehr komfortabel herausbekommen. Loggen Sie
+sich dazu in phpMyAdmin ein. Auf der Eingangsseite im rechten Frame klicken Sie
+oben auf den Reiter 'Engine'. Sollte dort InnoDB nicht ausgegraut sein
+(Standart-Theme), ist es aktiv.
+
 Zuerst muss ein SVN-Tool installiert werden, TortoiseSVN
 ( http://tortoisesvn.net/downloads ) ist dafuer sehr empfehlenswert und
 kostenlos beziehbar (siehe Link in Klammern). Wer der englischen Sprache nicht
@@ -34,8 +43,11 @@ ausfuehren:
 - Nun sollte alles aktualisiert werden.
 - Einmal OK anklicken und der Vorgang ist abgeschlossen
 
-Nun geht es mit dem Einrichten weiter. Bitte wechseln Sie dazu in das
-Verzeichnis "CTracker-Trunk". Dann geht es weiter: (nur bei Neuinstallation!)
+Nun geht es mit dem Einrichten weiter. Dies brauchen Sie nicht bei jedem Update
+durchfuehren und ist nur bei der Erstinstallation noetig. Bitte wechseln Sie
+dazu in das Verzeichnis "CTracker-Trunk".
+
+Dann geht es wie folgt weiter:
 
 - In das Verzeichnis "config" wechseln
 - Dort die Datei db_config.php.dist kopieren (nicht umbenennen). Meistens geht
diff --git a/libs/language/.htaccess b/libs/language/.htaccess
new file mode 100644
index 0000000..3a42882
--- /dev/null
+++ b/libs/language/.htaccess
@@ -0,0 +1 @@
+Deny from all
diff --git a/libs/language/.php b/libs/language/.php
new file mode 100644
index 0000000..4bc75ad
--- /dev/null
+++ b/libs/language/.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * ??? language file
+ *
+ * @author		Roland Haeder <webmaster@ship-simu.org>
+ * @version		3.0.0
+ * @copyright	Copyright (c) 2009, 2010 Cracker Tracker Team
+ * @license		GNU GPL 3.0 or any newer version
+ * @link		http://www.ship-simu.org
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Add localized messages here
+$GLOBALS['ctracker_localized']['foo_bar'] = 'Some foo-bar string';
+
+// [EOF]
+?>
diff --git a/libs/language/de.php b/libs/language/de.php
new file mode 100644
index 0000000..7b2057d
--- /dev/null
+++ b/libs/language/de.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * German language file
+ *
+ * @author		Roland Haeder <webmaster@ship-simu.org>
+ * @version		3.0.0
+ * @copyright	Copyright (c) 2009, 2010 Cracker Tracker Team
+ * @license		GNU GPL 3.0 or any newer version
+ * @link		http://www.ship-simu.org
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Add localized messages here
+$GLOBALS['ctracker_localized']['ctracker_page_header'] = 'Verd&auml;chtiger/B&ouml;sartiger Traffic Von Ihrer IP-Nummer erkannt';
+$GLOBALS['ctracker_localized']['user_add_ticket_subject'] = 'Ihr ausgef&uuml;lltes Support-Ticket';
+$GLOBALS['ctracker_localized']['webmaster_add_ticket_subject'] = 'Ausgef&uuml;lltes Support-Ticket erhalten';
+
+// [EOF]
+?>
diff --git a/libs/language/en.php b/libs/language/en.php
new file mode 100644
index 0000000..b0dfa20
--- /dev/null
+++ b/libs/language/en.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * English language file
+ *
+ * @author		Roland Haeder <webmaster@ship-simu.org>
+ * @version		3.0.0
+ * @copyright	Copyright (c) 2009, 2010 Cracker Tracker Team
+ * @license		GNU GPL 3.0 or any newer version
+ * @link		http://www.ship-simu.org
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Add localized messages here
+$GLOBALS['ctracker_localized']['ctracker_page_header'] = 'Suspicious/Malicious Traffic Detected From Your IP';
+$GLOBALS['ctracker_localized']['user_add_ticket_subject'] = 'Your filled-out support ticket';
+$GLOBALS['ctracker_localized']['webmaster_add_ticket_subject'] = 'Filled-out support ticket received';
+
+// [EOF]
+?>
diff --git a/libs/lib_ b/libs/lib_
index 4cb27ab..0d8b041 100644
--- a/libs/lib_
+++ b/libs/lib_
@@ -4,7 +4,7 @@
  *
  * @author		Roland Haeder <webmaster@ship-simu.org>
  * @version		3.0.0
- * @copyright	Copyright (c) 2009 Cracker Tracker Team
+ * @copyright	Copyright (c) 2009, 2010 Cracker Tracker Team
  * @license		GNU GPL 3.0 or any newer version
  * @link		http://www.ship-simu.org
  *
diff --git a/libs/lib_connect.php b/libs/lib_connect.php
index b4f3772..175fcbf 100644
--- a/libs/lib_connect.php
+++ b/libs/lib_connect.php
@@ -4,7 +4,7 @@
  *
  * @author		Roland Haeder <webmaster@ship-simu.org>
  * @version		3.0.0
- * @copyright	Copyright (c) 2009 Cracker Tracker Team
+ * @copyright	Copyright (c) 2009, 2010 Cracker Tracker Team
  * @license		GNU GPL 3.0 or any newer version
  * @link		http://www.ship-simu.org
  *
@@ -33,7 +33,10 @@ function aquireCrackerTrackerDatabaseLink () {
 		if (!mysql_select_db($GLOBALS['ctracker_dbname'], $GLOBALS['ctracker_link'])) {
 			// Attempt has failed
 			crackerTrackerDatabaseError(__FUNCTION__, __LINE__);
-		} // END - if
+		} elseif (isCrackerTrackerTableCreated('ctracker_config')) {
+			// Load the config
+			crackerTrackerLoadConfig();
+		}
 	} // END - if
 }
 
@@ -76,18 +79,20 @@ function crackerTrackerCloseDatabaseLink () {
 }
 
 // Inserts given array, if IP/check_worm combination was not found
-function crackerTrackerInsertArray ($rowData) {
+function crackerTrackerInsertArray ($table, $rowData) {
 	// Is it found?
 	if (!isCrackerTrackerEntryFound($rowData)) {
-		// Insert first attempt stamp
-		$rowData['first_attempt'] = 'NOW()';
-		$rowData['count'] = '1';
-
 		// Prepare SQL
-		$SQL = 'INSERT INTO `ctracker_data` (`' . implode('`,`', array_keys($rowData)) . '`) VALUES(' . implode_secure($rowData) . ')';
+		$SQL = 'INSERT INTO `' . $table . '` (`' . implode('`,`', array_keys($rowData)) . '`) VALUES(' . implode_secure($rowData) . ')';
+
+		// Reset insert id
+		$GLOBALS['ctracker_last_insert_id'] = false;
 
 		// Run it
 		runCrackerTrackerSql($SQL, __FUNCTION__, __LINE__);
+
+		// Remember the last insert id
+		$GLOBALS['ctracker_last_insert_id'] = mysql_insert_id($GLOBALS['ctracker_link']) or crackerTrackerDatabaseError(__FUNCTION__, __LINE__);
 	} else {
 		// Only update the entry
 		updateCrackerTrackerEntry($rowData);
@@ -151,5 +156,213 @@ function runCrackerTrackerSql ($SQL, $F, $L) {
 	return $GLOBALS['ctracker_last_result'];
 }
 
+// Checks wether a table was found
+function isCrackerTrackerTableCreated ($table) {
+	// Default is not found
+	$found = false;
+
+	// Run the query
+	$result = runCrackerTrackerSql('SHOW TABLES', __FUNCTION__, __LINE__);
+
+	// Is our table there?
+	while (list($tab) = mysql_fetch_row($result)) {
+		// Is the table there?
+		if ($tab == $table) {
+			// Okay, found. So abort
+			$found = true;
+			break;
+		} // END - if
+	} // END - if
+
+	// Free result
+	mysql_free_result($result) or crackerTrackerDatabaseError(__FUNCTION__, __LINE__);
+
+	// Return result
+	return $found;
+}
+
+// Creates the given table with columns
+function crackerTrackerCreateTable ($table, array $columns, array $keys) {
+	// Begin the SQL
+	$SQL = 'CREATE TABLE IF NOT EXISTS `' . $table . '` (';
+
+	// Add table name as first column
+	$SQL .= '`' . $table . '` BIGINT ( 20 ) UNSIGNED NOT NULL AUTO_INCREMENT, ';
+
+	// Add all columns
+	foreach ($columns as $column=>$type) {
+		// Add this entry
+		$SQL .= '`' . $column . '` ' . $type . ', ';
+	} // END - foreach
+
+	// Add table name as primary key
+	$SQL .= 'PRIMARY KEY (`' . $table . '`), ';
+
+	// Add keys
+	foreach ($keys as $key=>$type) {
+		// Add this entry
+		$SQL .= '' . $type . ' (`' . $key . '`), ';
+	} // END - foreach
+
+	// Finish SQL
+	$SQL = substr($SQL, 0, -2) . ') TYPE=InnoDB';
+
+	// And run it
+	runCrackerTrackerSql($SQL);
+}
+
+// Inits a table by inserting 
+function crackerTrackerInitTable ($table) {
+	// Prepare SQL and run it
+	runCrackerTrackerSql('INSERT INTO `' . $table . '` (`' . $table . '`) VALUES (NULL)');
+}
+
+// Updates the database scheme automatically
+function crackerTrackerUpdateDatabaseScheme () {
+	// Is the main config table there?
+	if (!isCrackerTrackerTableCreated('ctracker_config')) {
+		// Then do it for us
+		crackerTrackerCreateTable('ctracker_config', array(
+			'ctracker_db_version' => 'BIGINT ( 20 ) UNSIGNED NOT NULL DEFAULT 0',
+			'ctracker_min_sleep'  => 'SMALLINT ( 5 ) UNSIGNED NOT NULL DEFAULT 10',
+			'ctracker_max_sleep'  => 'SMALLINT ( 5 ) UNSIGNED NOT NULL DEFAULT 30',
+			'ctracker_alert_user' => "ENUM('Y','N') NOT NULL DEFAULT 'Y'",
+			'ctracker_language'   => "CHAR ( 2) NOT NULL DEFAULT 'en'"
+		), array());
+
+		// Init that table
+		crackerTrackerInitTable('ctracker_config');
+	} // END - if
+
+	// Init update array here
+	crackerTrackerInitUpdates();
+
+	// Run any SQL updates recursively
+	while (isset($GLOBALS['ctracker_updates'][getCrackerTrackerConfig('ctracker_db_version')])) {
+		// Run that updates
+		runCrackerTrackerUpdates(getCrackerTrackerConfig('ctracker_db_version'));
+
+		// Update config
+		runCrackerTrackerSql('UPDATE `ctracker_config` SET `ctracker_db_version`=`ctracker_db_version`+1 WHERE `ctracker_config`=1 LIMIT 1', __FUNCTION__, __LINE__);
+
+		// And count it up in the config array
+		$GLOBALS['ctracker_config']['ctracker_db_version']++;
+	} // END - if
+}
+
+// Load the configuration
+function crackerTrackerLoadConfig () {
+	// Construct SQL command and run it
+	$result = runCrackerTrackerSql('SELECT * FROM `ctracker_config` WHERE `ctracker_config`=1 LIMIT 1', __FUNCTION__, __LINE__);
+
+	// And get it
+	$GLOBALS['ctracker_config'] = mysql_fetch_array($result);
+
+	// Free result
+	mysql_free_result($result) or crackerTrackerDatabaseError(__FUNCTION__, __LINE__);
+}
+
+// Getter for config
+function getCrackerTrackerConfig ($entry) {
+	// Is the config entry there?
+	if (!isset($GLOBALS['ctracker_config'][$entry])) {
+		// Then better die here, else we may have an endless loop
+		if (isCrackerTrackerDebug()) {
+			// Nicer message in debug mode
+			die('Configuration entry ' . $entry . ' missing!');
+		} else {
+			// die() on production systems
+			die();
+		}
+	} // END - if
+
+	// Return it
+	return $GLOBALS['ctracker_config'][$entry];
+}
+
+// Did the current IP already generated blocked attempts?
+function isCrackerTrackerIpSuspicious () {
+	// We only need the very last attempt to get!
+	$result = runCrackerTrackerSql("SELECT * FROM `ctracker_data` WHERE `remote_addr`='" . determineCrackerTrackerRealRemoteAddress() . "' ORDER BY `last_attempt` DESC LIMIT 1", __FUNCTION__, __LINE__);
+
+	// Do we have entries?
+	$found = (mysql_num_rows($result) == 1);
+
+	// And again?
+	if ($found === true) {
+		// Cache the entry
+		$GLOBALS['ctracker_last_suspicious_entry'] = mysql_fetch_array($result);
+	} // END - if
+
+	// Free result
+	mysql_free_result($result) or crackerTrackerDatabaseError(__FUNCTION__, __LINE__);
+
+	// Return the result
+	return $found;
+}
+
+// Does the current IP have a ticket?
+function ifCrackerTrackerIpHasTicket () {
+	// We only give one ticket per IP!
+	$result = runCrackerTrackerSql("SELECT * FROM `ctracker_ticket` WHERE `ctracker_ticket_remote_addr`='" . determineCrackerTrackerRealRemoteAddress() . "' LIMIT 1", __FUNCTION__, __LINE__);
+
+	// Do we have a ticket?
+	$found = (mysql_num_rows($result) == 1);
+
+	// And again?
+	if ($found === true) {
+		// Cache the ticket data
+		$GLOBALS['ctracker_last_ticket'] = mysql_fetch_array($result);
+	} // END - if
+
+	// Free result
+	mysql_free_result($result) or crackerTrackerDatabaseError(__FUNCTION__, __LINE__);
+
+	// Return the result
+	return $found;
+}
+
+// Adds a ticket based on given (mostly $_POST) data
+function addCrackerTrackerTicket (array $data) {
+	// Prepare the array
+	$GLOBALS['ctracker_last_ticket'] = array(
+		'ctracker_ticket_remote_addr' => determineCrackerTrackerRealRemoteAddress(),
+		'ctracker_ticket_user_agent'  => crackerTrackerUserAgent(),
+		'ctracker_ticket_name'        => crackerTrackerSecureString($data['name']),
+		'ctracker_ticket_email'       => crackerTrackerSecureString($data['email']),
+		'ctracker_ticket_comment'     => crackerTrackerSecureString($data['comment'])
+	);
+
+	// Insert it
+	crackerTrackerInsertArray('ctracker_ticket', $GLOBALS['ctracker_last_ticket']);
+
+	// Is there an entry?
+	if ((isset($GLOBALS['ctracker_last_insert_id'])) && ($GLOBALS['ctracker_last_insert_id'] > 0)) {
+		// All fine, so prepare the link between ticket<->data
+		$data = array(
+			'ctracker_ticket'  => $GLOBALS['ctracker_last_insert_id'],
+			'ctracker_data_id' => $GLOBALS['ctracker_last_suspicious_entry']['id']
+		);
+
+		// And insert it as well
+		crackerTrackerInsertArray('ctracker_ticket_data', $data);
+
+		// Merge all data for emails
+		$GLOBALS['ctracker_last_ticket'] = array_merge($GLOBALS['ctracker_last_ticket'], $data);
+
+		// Is this also there?
+		if ((isset($GLOBALS['ctracker_last_insert_id'])) && ($GLOBALS['ctracker_last_insert_id'] > 0)) {
+			// All fine, so display "thank you page"
+			crackerTrackerLoadTemplate('add_ticket_thanks');
+		} else {
+			// Did not insert
+			crackerTrackerDie();
+		}
+	} else {
+		// Did not insert
+		crackerTrackerDie();
+	}
+}
+
 // [EOF]
 ?>
diff --git a/libs/lib_detector.php b/libs/lib_detector.php
index e4b21fd..be64007 100644
--- a/libs/lib_detector.php
+++ b/libs/lib_detector.php
@@ -79,16 +79,19 @@ function initCrackerTrackerArrays () {
 		'starhack', 'DeLiMehmet', 'hisset', 'Hisset', 'delimert', 'MecTruy',
 		'busca'
 	);
+
+	// Load email header
+	$GLOBALS['ctracker_header'] = crackerTrackerLoadEmaiLTemplate('header');
 }
 
 // Checks for worms
 function isCrackerTrackerWormDetected () {
 	// Check against the whole list
-	$GLOBALS['ctracker_checkworm'] = str_replace($GLOBALS['ctracker_wormprotector'], '*', $_SERVER['QUERY_STRING']);
+	$GLOBALS['ctracker_checkworm'] = str_replace($GLOBALS['ctracker_wormprotector'], '*', crackerTrackerQueryString());
 
 	// If it differs to original and the *whole* request string is not in whitelist
 	// then blog the attempt
-	return ($GLOBALS['ctracker_checkworm'] != $_SERVER['QUERY_STRING'] && (!in_array($_SERVER['QUERY_STRING'], $GLOBALS['ctracker_whitelist'])));
+	return ($GLOBALS['ctracker_checkworm'] != crackerTrackerQueryString() && (!in_array(crackerTrackerQueryString(), $GLOBALS['ctracker_whitelist'])));
 }
 
 // Checks POST data
@@ -109,12 +112,12 @@ function sendCrackerTrackerMail () {
 	$mail = "Attack detected:
 -----------------------------------------------------
 Remote-IP       : ".determineCrackerTrackerRealRemoteAddress()."
-User-Agent      : ".$_SERVER['HTTP_USER_AGENT']."
-Request-string  : ".$_SERVER['QUERY_STRING']."
+User-Agent      : ".crackerTrackerUserAgent()."
+Request-string  : ".crackerTrackerQueryString()."
 Filtered string : ".$GLOBALS['ctracker_checkworm']."
-Server          : ".$_SERVER['SERVER_NAME']."
-Script          : ".$_SERVER['SCRIPT_NAME']."
-Referrer        : ".$_SERVER['HTTP_REFERRER']."
+Server          : ".crackerTrackerServerName()."
+Script          : ".crackerTrackerScriptName()."
+Referrer        : ".crackerTrackerReferer()."
 -----------------------------------------------------
 ";
 
@@ -129,12 +132,12 @@ Referrer        : ".$_SERVER['HTTP_REFERRER']."
 }
 
 // Sends a mail out
-function crackerTrackerSendMail ($mail) {
+function crackerTrackerSendMail ($mail, $recipient = null, $subject = null) {
 	// Construct dummy array
 	$rowData = array(
 		'remote_addr' => determineCrackerTrackerRealRemoteAddress(),
 		'check_worm'  => $GLOBALS['ctracker_checkworm'],
-		'server_name' => $_SERVER['SERVER_NAME']
+		'server_name' => crackerTrackerServerName()
 	);
 
 	// Only send email if not yet found
@@ -142,10 +145,13 @@ function crackerTrackerSendMail ($mail) {
 		// Send the email out only in non-debug mode
 		if (isCrackerTrackerDebug()) {
 			// Output message
-			print '<pre>' . $mail . '</pre>';
+			print 'Recipient='.$recipient.'<br />Subject='.$subject.'<br />Text=<pre>' . $mail . '</pre>';
 
 			// All fine
 			return true;
+		} elseif (!is_null($recipient)) {
+			// Recipient specified
+			return mail($recipient, $subject, $mail, $GLOBALS['ctracker_header']);
 		} elseif (isset($GLOBALS['ctracker_email'])) {
 			// Send it
 			return mail($GLOBALS['ctracker_email'], 'CTracker: Attack detected!', $mail, $GLOBALS['ctracker_header']);
@@ -162,12 +168,12 @@ function sendCrackerTrackerPostMail () {
 	$mail = "POST-Attack detected:
 -----------------------------------------------------
 Remote-IP            : ".determineCrackerTrackerRealRemoteAddress()."
-User-Agent           : ".$_SERVER['HTTP_USER_AGENT']."
-Request-string       : ".$_SERVER['QUERY_STRING']."
+User-Agent           : ".crackerTrackerUserAgent()."
+Request-string       : ".crackerTrackerQueryString()."
 Filtered string      : ".$GLOBALS['ctracker_checkworm']."
-Server               : ".$_SERVER['SERVER_NAME']."
-Script               : ".$_SERVER['SCRIPT_NAME']."
-Referrer             : ".$_SERVER['HTTP_REFERRER']."
+Server               : ".crackerTrackerServerName()."
+Script               : ".crackerTrackerScriptName()."
+Referrer             : ".crackerTrackerReferer()."
 -----------------------------------------------------
 POST string          : ".$GLOBALS['ctracker_post_track']."
 Filtered POST string : ".$GLOBALS['ctracker_check_post']."
@@ -193,6 +199,9 @@ function crackerTrackerDie () {
 	if (!isCrackerTrackerDebug()) sleep(mt_rand(10,30));
 
 	// Bye, bye...
+	print '<pre>';
+	debug_print_backtrace();
+	die('</pre>');
 	die();
 }
 
@@ -213,14 +222,14 @@ function crackerTrackerLogAttack () {
 	// Prepare array for database insert
 	$rowData = array(
 		'remote_addr' => determineCrackerTrackerRealRemoteAddress(),
-		'user_agent'  => $_SERVER['HTTP_USER_AGENT'],
-		'get_data'    => $_SERVER['QUERY_STRING'],
+		'user_agent'  => crackerTrackerUserAgent(),
+		'get_data'    => crackerTrackerQueryString(),
 		'post_data'   => $GLOBALS['ctracker_post_track'],
 		'check_worm'  => $GLOBALS['ctracker_checkworm'],
 		'check_post'  => $GLOBALS['ctracker_check_post'],
-		'server_name' => $_SERVER['SERVER_NAME'],
-		'script_name' => $_SERVER['SCRIPT_NAME'],
-		'referer'     => $_SERVER['HTTP_REFERER'],
+		'server_name' => crackerTrackerServerName(),
+		'script_name' => crackerTrackerScriptName(),
+		'referer'     => crackerTrackerReferer(),
 		'proxy_used'  => $proxyUsed
 	);
 
@@ -228,5 +237,38 @@ function crackerTrackerLogAttack () {
 	crackerTrackerInsertArray($rowData);
 }
 
+// Alerts the current user about malicious/suspicious traffic
+function crackerTrackerAlertCurrentUser () {
+	// Is there some data?
+	if (isset($GLOBALS['ctracker_last_suspicious_entry'])) {
+		// Does the user have a ticket?
+		if (ifCrackerTrackerIpHasTicket()) {
+			// Should we continue?
+			if (isset($_POST['ctracker_continue'])) {
+				// Set cookie
+				sendCrackerTrackerCookie();
+
+				// And redirect to same URL
+				crackerTrackerRedirectSameUrl();
+			} elseif (ifCrackerTrackerCookieIsSet()) {
+				// Return here to normal program
+				return;
+			} else {
+				// Load "Thank you" template
+				crackerTrackerLoadTemplate('add_ticket_thanks');
+			}
+		} elseif (isset($_POST['ctracker_add_ticket'])) {
+			// Add the ticket
+			addCrackerTrackerTicket($_POST);
+		} else {
+			// Display the form for new ticket
+			crackerTrackerLoadTemplate('add_ticket');
+		}
+	} // END - if
+
+	// And stop here
+	die();
+}
+
 // [EOF]
 ?>
diff --git a/libs/lib_general.php b/libs/lib_general.php
index 85fed70..3e14cb1 100644
--- a/libs/lib_general.php
+++ b/libs/lib_general.php
@@ -4,7 +4,7 @@
  *
  * @author		Roland Haeder <webmaster@ship-simu.org>
  * @version		3.0.0
- * @copyright	Copyright (c) 2009 Cracker Tracker Team
+ * @copyright	Copyright (c) 2009, 2010 Cracker Tracker Team
  * @license		GNU GPL 3.0 or any newer version
  * @link		http://www.ship-simu.org
  *
@@ -112,5 +112,333 @@ function isCrackerTrackerProxyUsed () {
 	return $proxyUsed;
 }
 
+// Detects the user-agent string
+function crackerTrackerUserAgent () {
+	// Default is 'unknown'
+	$ua = 'unknown';
+
+	// Is the entry there?
+	if (isset($_SERVER['HTTP_USER_AGENT'])) {
+		// Then use it
+		$ua = $_SERVER['HTTP_USER_AGENT'];
+	} // END - if
+
+	// Return it
+	return $ua;
+}
+
+// Detects the script name
+function crackerTrackerScriptName () {
+	// Should always be there!
+	return crackerTrackerSecureString($_SERVER['SCRIPT_NAME']);
+}
+
+// Detects the query string
+function crackerTrackerQueryString () {
+	// Should always be there!
+	return crackerTrackerEscapeString($_SERVER['QUERY_STRING']);
+}
+
+// Detects the server's name
+function crackerTrackerServerName () {
+	// Should always be there!
+	return crackerTrackerSecureString($_SERVER['SERVER_NAME']);
+}
+
+// Detects the referer
+function crackerTrackerReferer () {
+	// Default is a dash
+	$referer = '-';
+
+	// Is it there?
+	if (isset($_SERVER['HTTP_REFERER'])) {
+		// Then use it securely
+		$referer = crackerTrackerSecureString($_SERVER['HTTP_REFERER']);
+	} // END - if
+
+	// Return it
+	return $referer;
+}
+
+// Detects the scripts path
+function crackerTrackerScriptPath () {
+	// Should always be there!
+	$path = dirname(crackerTrackerScriptName()) . '/';
+
+	// Return detected path
+	return $path;
+}
+
+// Detects wether we have SSL
+function crackerTrackerSecured () {
+	// Detect it
+	$ssl = ((isset($_SERVER['HTTPS'])) && ($_SERVER['HTTPS'] != 'off'));
+
+	// Return result
+	return $ssl;
+}
+
+// Secures a string by escaping it and passing it through strip_tags,htmlentities-chain
+function crackerTrackerSecureString ($str) {
+	// First escape it
+	$str = crackerTrackerEscapeString($str);
+
+	// Then pass it through the functions
+	$str = htmlentities(strip_tags($str), ENT_QUOTES);
+
+	// Return it
+	return $str;
+}
+
+// Is the file there and readable?
+function isCrackerTrackerFileFound ($FQFN) {
+	// Simply check it
+	return ((file_exists($FQFN)) && (is_readable($FQFN)));
+}
+
+// Loads a given "template" (this is more an include file)
+function crackerTrackerLoadTemplate ($template) {
+	// Create the full-qualified filename (FQFN)
+	$FQFN = sprintf("%s/templates/%s.tpl.php",
+		dirname(__FILE__),
+		$template
+	);
+
+	// Is this template found?
+	if (isCrackerTrackerFileFound($FQFN)) {
+		// Detect language
+		crackerTrackerLanguage();
+
+		// Load it
+		require_once($FQFN);
+	} else {
+		// Not found, so die here
+		crackerTrackerDie();
+	}
+}
+
+// Loads a given "template" (this is more an include file)
+function crackerTrackerLoadLocalizedTemplate ($template) {
+	// Create the full-qualified filename (FQFN)
+	$FQFN = sprintf("%s/templates/%s/%s.tpl.php",
+		dirname(__FILE__),
+		getCrackerTrackerLanguage(),
+		$template
+	);
+
+	// Is this template found?
+	if (isCrackerTrackerFileFound($FQFN)) {
+		// Load it
+		require_once($FQFN);
+	} else {
+		// Not found, so die here
+		crackerTrackerDie();
+	}
+}
+
+// Detects the browser's language file and tries to load it, fall-back on english!
+function crackerTrackerLanguage () {
+	// Default is English
+	$GLOBALS['ctracker_language'] = 'en';
+	$weight = 1;
+
+	// Is the language string there?
+	if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
+		// Then detect it
+		foreach (explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $lang) {
+			// Split it again for q=x.x value
+			$langArray = explode(';', $lang);
+
+			// If there is an entry, we have a weight
+			if ((isset($langArray[1])) && ($langArray[1] > $weight)) {
+				// Use this language/weight instead
+				$GLOBALS['ctracker_language'] = $langArray[0];
+				$weight   = $langArray[1];
+			} // END - if
+		} // END - foreach
+	} // END - if
+
+	// Construct FQFN
+	$FQFN = sprintf("%s/language/%s.php",
+		dirname(__FILE__),
+		getCrackerTrackerLanguage()
+	);
+
+	// Is it not there, switch to "en"
+	if ((getCrackerTrackerLanguage() != 'en') && (!isCrackerTrackerFileFound($FQFN))) {
+		// English is default!
+		$GLOBALS['ctracker_language'] = 'en';
+
+		// Construct FQFN again
+		$FQFN = sprintf("%s/language/en.php",
+			dirname(__FILE__)
+		);
+	} // END - if
+
+	// Load the language file
+	require($FQFN);
+}
+
+// Loads a given email template and passes through $content
+function crackerTrackerLoadEmailTemplate ($template, array $content = array(), $language) {
+	// Init language
+	crackerTrackerLanguage();
+
+	// Generate the FQFN
+	$FQFN = sprintf("%s/mails/%s/%s.tpl",
+		dirname(__FILE__),
+		getCrackerTrackerLanguage($language),
+		$template
+	);
+
+	// So is the file there?
+	if (isCrackerTrackerFileFound($FQFN)) {
+		// Init result
+		$result = 'No result from template ' . $template . '. Please report this at http://forum.ship-simu.org Thank you.';
+
+		// Then load it
+		eval('$result = "' . crackerTrackerCompileCode(file_get_contents($FQFN)) . '";');
+
+		// Return the result
+		return $result;
+	} else {
+		// Not found
+		crackerTrackerDie();
+	}
+}
+
+// Getter for message
+function getCrackerTrackerLocalized ($message) {
+	// Default message
+	$output = '!' . $message . '!';
+
+	// Is the language string there?
+	if (isset($GLOBALS['ctracker_localized'][$message])) {
+		// Use this instead
+		$output = $GLOBALS['ctracker_localized'][$message];
+	} // END - if
+
+	// Return it
+	return $output;
+}
+
+// Tries to find a message and outputs it
+function crackerTrackerOutputLocalized ($message) {
+	// Output it
+	print getCrackerTrackerLocalized($message);
+}
+
+// Compiles the given code
+function crackerTrackerCompileCode ($code) {
+	// Find all $content[foo]
+	preg_match_all('/\$content((\[([a-zA-Z0-9-_]+)\])*)/', $code, $matches);
+
+	// Replace all
+	foreach ($matches[0] as $key=>$match) {
+		// Replace it
+		$code = str_replace($match, "\" . \$content['" . $matches[3][$key] . "'] . \"", $code);
+	} // END - foreach
+
+	// Return it
+	return $code;
+}
+
+// "Getter" for language
+function getCrackerTrackerLanguage ($lang = null) {
+	// Default is from browser
+	$language = $GLOBALS['ctracker_language'];
+
+	// Is $lang set?
+	if (!is_null($lang)) {
+		// Then use this instead
+		$language = $lang;
+	} // END - if
+
+	// Return it
+	return $language;
+}
+
+// "Getter" for ticket id
+function getCrackerTrackerTicketId () {
+	// Default is zero
+	$id = 0;
+
+	// Is it set?
+	if (isset($GLOBALS['ctracker_last_ticket']['ctracker_ticket'])) {
+		// Then use it
+		$id = $GLOBALS['ctracker_last_ticket']['ctracker_ticket'];
+	} // END - if
+
+	// Return the number
+	return $id;
+}
+
+// Sends a cookie to the user that he would not see this security warning again
+function sendCrackerTrackerCookie () {
+	// Set the cookie
+	// @TODO Why can't domain be set to value from crackerTrackerServerName() ?
+	setcookie('ctracker_ticket', getCrackerTrackerTicketId(), (time() + 60*60*24), '/', '', crackerTrackerSecured(), true);
+	$_COOKIE['ctracker_ticket'] = getCrackerTrackerTicketId();
+}
+
+// Is the cookie set?
+function ifCrackerTrackerCookieIsSet () {
+	// Is it set and valid?
+	return ((isset($_COOKIE['ctracker_ticket'])) && ($_COOKIE['ctracker_ticket'] > 0));
+}
+
+// Redirects to the same URL
+function crackerTrackerRedirectSameUrl () {
+	// Construct the url
+	$url = '://' . crackerTrackerServerName() . crackerTrackerScriptName() . '?' . crackerTrackerQueryString();
+
+	// Do we have SSL?
+	if (crackerTrackerSecured()) {
+		// HTTPS
+		$url = 'https' . $url;
+	} else {
+		// HTTP
+		$url = 'http' . $url;
+	}
+
+	// And redirect
+	sendRawRedirect($url);
+}
+
+/**
+ * Send a HTTP redirect to the browser. This function wass taken from DokuWiki
+ * (GNU GPL 2; http://www.dokuwiki.org) and modified to fit into this script.
+ *
+ * ----------------------------------------------------------------------------
+ * If you want to redirect, please use redirectToUrl(); instead
+ * ----------------------------------------------------------------------------
+ *
+ * Works arround Microsoft IIS cookie sending bug. Does exit the script.
+ *
+ * @link    http://support.microsoft.com/kb/q176113/
+ * @author  Andreas Gohr <andi@splitbrain.org>
+ * @access  private
+ */
+function sendRawRedirect ($url) {
+	// always close the session
+	session_write_close();
+
+	// Revert entity &amp;
+	$url = str_replace('&amp;', '&', $url);
+
+	// check if running on IIS < 6 with CGI-PHP
+	if ((isset($_SERVER['SERVER_SOFTWARE'])) && (isset($_SERVER['GATEWAY_INTERFACE'])) &&
+		(strpos($_SERVER['GATEWAY_INTERFACE'],'CGI') !== false) &&
+		(preg_match('|^Microsoft-IIS/(\d)\.\d$|', trim($_SERVER['SERVER_SOFTWARE']), $matches)) &&
+		($matches[1] < 6)) {
+		// Send the IIS header
+		header('Refresh: 0;url=' . $url);
+	} else {
+		// Send generic header
+		header('Location: ' . $url);
+	}
+	exit();
+}
+
 // [EOF]
 ?>
diff --git a/libs/lib_updates.php b/libs/lib_updates.php
new file mode 100644
index 0000000..86cfc76
--- /dev/null
+++ b/libs/lib_updates.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Automatic database updates
+ *
+ * @author		Roland Haeder <webmaster@ship-simu.org>
+ * @version		3.0.0
+ * @copyright	Copyright (c) 2009, 2010 Cracker Tracker Team
+ * @license		GNU GPL 3.0 or any newer version
+ * @link		http://www.ship-simu.org
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Init all updates
+function crackerTrackerInitUpdates () {
+	// Add all
+	$GLOBALS['ctracker_updates'] = array(
+		// Ticket system:
+		0 => array(
+			'CREATE TABLE IF NOT EXISTS `ctracker_ticket` (
+`ctracker_ticket` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+`ctracker_ticket_remote_addr` varchar(15) NOT NULL,
+`ctracker_ticket_user_agent` tinytext NOT NULL,
+`ctracker_ticket_name` varchar(255) NOT NULL,
+`ctracker_ticket_email` varchar(255) NOT NULL,
+`ctracker_ticket_comment` tinytext NOT NULL,
+PRIMARY KEY ( `ctracker_ticket` ),
+UNIQUE KEY (`ctracker_ticket_remote_addr`)
+) TYPE=InnoDB',
+			'CREATE TABLE IF NOT EXISTS `ctracker_ticket_data` (
+`ctracker_ticket_data_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+`ctracker_ticket_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
+`ctracker_data_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
+PRIMARY KEY ( `ctracker_ticket_data_id` ),
+UNIQUE KEY `ctracker_ticket_data` ( `ctracker_ticket_id`,`ctracker_data_id` ),
+INDEX ( `ctracker_data_id` ),
+FOREIGN KEY ( `ctracker_ticket_id` ) REFERENCES `' . $GLOBALS['ctracker_dbname'] . '`.`ctracker_ticket` (
+`ctracker_ticket`
+) ON DELETE CASCADE,
+FOREIGN KEY ( `ctracker_data_id` ) REFERENCES `' . $GLOBALS['ctracker_dbname'] . '`.`ctracker_data` (
+`id`
+) ON DELETE CASCADE
+) TYPE=InnoDB',
+		)
+	);
+}
+
+// Runs the given updates at number X
+function runCrackerTrackerUpdates ($update) {
+	// We assume it is set
+	foreach ($GLOBALS['ctracker_updates'][$update] as $sql) {
+		// Run the SQL command
+		runCrackerTrackerSql($sql, __FUNCTION__, __LINE__);
+	} // END - foreach
+}
+
+// [EOF]
+?>
diff --git a/libs/mails/.htaccess b/libs/mails/.htaccess
new file mode 100644
index 0000000..3a42882
--- /dev/null
+++ b/libs/mails/.htaccess
@@ -0,0 +1 @@
+Deny from all
diff --git a/libs/mails/de/.htaccess b/libs/mails/de/.htaccess
new file mode 100644
index 0000000..3a42882
--- /dev/null
+++ b/libs/mails/de/.htaccess
@@ -0,0 +1 @@
+Deny from all
diff --git a/libs/mails/de/header.tpl b/libs/mails/de/header.tpl
new file mode 100644
index 0000000..a9c3620
--- /dev/null
+++ b/libs/mails/de/header.tpl
@@ -0,0 +1,8 @@
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+X-Mailer: Cracker Tracker Stand-Alone - Enhanced Edition
+Errors-To: $GLOBALS[ctracker_email]
+Bounces-To: $GLOBALS[ctracker_email]
+X-Loop: $GLOBALS[ctracker_email]
+From: "Cracker Tracker Stand-Alone - Enhanced Edition" <$GLOBALS[ctracker_email]>
diff --git a/libs/mails/de/user_add_ticket.tpl b/libs/mails/de/user_add_ticket.tpl
new file mode 100644
index 0000000..dbb9f2d
--- /dev/null
+++ b/libs/mails/de/user_add_ticket.tpl
@@ -0,0 +1,23 @@
+Hallo $content[ctracker_ticket_name],
+
+Sie haben soeben ein Support-Ticket ausgef&uuml;llt und haben dabei folgende Angaben gemacht:
+
+----------------------------------------------------
+Name: $content[ctracker_ticket_name]
+----------------------------------------------------
+Email: $content[ctracker_ticket_email]
+----------------------------------------------------
+Ihre IP: $content[ctracker_ticket_remote_addr]
+----------------------------------------------------
+Ihr Browser: $content[ctracker_ticket_user_agent]
+----------------------------------------------------
+Kommentar:
+$content[ctracker_ticket_comment]
+----------------------------------------------------
+Ticket-Id: $content[ctracker_ticket_id]
+----------------------------------------------------
+Daten-Eintrag: $content[ctracker_data_id]
+----------------------------------------------------
+
+Mit freundlichen Gr&uuml;ssen,
+  $GLOBALS[ctracker_email]
diff --git a/libs/mails/de/webmaster_add_ticket.tpl b/libs/mails/de/webmaster_add_ticket.tpl
new file mode 100644
index 0000000..1d731aa
--- /dev/null
+++ b/libs/mails/de/webmaster_add_ticket.tpl
@@ -0,0 +1,23 @@
+Hallo Administrator,
+
+Soeben hat ein User ein Support-Ticket ausgef&uuml;llt und hat dabei folgende Angaben gemacht:
+
+----------------------------------------------------
+Name: $content[ctracker_ticket_name]
+----------------------------------------------------
+Email: $content[ctracker_ticket_email]
+----------------------------------------------------
+IP: $content[ctracker_ticket_remote_addr]
+----------------------------------------------------
+Browser: $content[ctracker_ticket_user_agent]
+----------------------------------------------------
+Kommentar:
+$content[ctracker_ticket_comment]
+----------------------------------------------------
+Ticket-Id: $content[ctracker_ticket_id]
+----------------------------------------------------
+Daten-Eintrag: $content[ctracker_data_id]
+----------------------------------------------------
+
+Mit freundlichen Gr&uuml;ssen,
+  Cracker Stand-Alone Script
diff --git a/libs/mails/en/.htaccess b/libs/mails/en/.htaccess
new file mode 100644
index 0000000..3a42882
--- /dev/null
+++ b/libs/mails/en/.htaccess
@@ -0,0 +1 @@
+Deny from all
diff --git a/libs/mails/en/header.tpl b/libs/mails/en/header.tpl
new file mode 100644
index 0000000..a9c3620
--- /dev/null
+++ b/libs/mails/en/header.tpl
@@ -0,0 +1,8 @@
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+X-Mailer: Cracker Tracker Stand-Alone - Enhanced Edition
+Errors-To: $GLOBALS[ctracker_email]
+Bounces-To: $GLOBALS[ctracker_email]
+X-Loop: $GLOBALS[ctracker_email]
+From: "Cracker Tracker Stand-Alone - Enhanced Edition" <$GLOBALS[ctracker_email]>
diff --git a/libs/mails/en/user_add_ticket.tpl b/libs/mails/en/user_add_ticket.tpl
new file mode 100644
index 0000000..dcd2447
--- /dev/null
+++ b/libs/mails/en/user_add_ticket.tpl
@@ -0,0 +1,23 @@
+Hello $content[ctracker_ticket_name],
+
+you have filled a support ticket, thank you for contacting us. You gave us the following informations:
+
+----------------------------------------------------
+Name: $content[ctracker_ticket_name]
+----------------------------------------------------
+Email: $content[ctracker_ticket_email]
+----------------------------------------------------
+Your IP: $content[ctracker_ticket_remote_addr]
+----------------------------------------------------
+Your browser: $content[ctracker_ticket_user_agent]
+----------------------------------------------------
+Comments:
+$content[ctracker_ticket_comment]
+----------------------------------------------------
+Ticket id: $content[ctracker_ticket_id]
+----------------------------------------------------
+Data entry: $content[ctracker_data_id]
+----------------------------------------------------
+
+Best regards,
+  $GLOBALS[ctracker_email]
diff --git a/libs/mails/en/webmaster_add_ticket.tpl b/libs/mails/en/webmaster_add_ticket.tpl
new file mode 100644
index 0000000..dfb4abc
--- /dev/null
+++ b/libs/mails/en/webmaster_add_ticket.tpl
@@ -0,0 +1,23 @@
+Hello administrator,
+
+a user has just filled out a support ticket and gave us the following informations:
+
+----------------------------------------------------
+Name: $content[ctracker_ticket_name]
+----------------------------------------------------
+Email: $content[ctracker_ticket_email]
+----------------------------------------------------
+IP: $content[ctracker_ticket_remote_addr]
+----------------------------------------------------
+Browser: $content[ctracker_ticket_user_agent]
+----------------------------------------------------
+Comments:
+$content[ctracker_ticket_comment]
+----------------------------------------------------
+Ticket id: $content[ctracker_ticket_id]
+----------------------------------------------------
+Data entry: $content[ctracker_data_id]
+----------------------------------------------------
+
+Best regards,
+  Cracker Tracker Stand-Alone Script
diff --git a/libs/templates/.htaccess b/libs/templates/.htaccess
new file mode 100644
index 0000000..3a42882
--- /dev/null
+++ b/libs/templates/.htaccess
@@ -0,0 +1 @@
+Deny from all
diff --git a/libs/templates/add_ticket.tpl.php b/libs/templates/add_ticket.tpl.php
new file mode 100644
index 0000000..235f3ba
--- /dev/null
+++ b/libs/templates/add_ticket.tpl.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Template file for adding tickets
+ *
+ * @author		Roland Haeder <webmaster@ship-simu.org>
+ * @version		3.0.0
+ * @copyright	Copyright (c) 2009, 2010 Cracker Tracker Team
+ * @license		GNU GPL 3.0 or any newer version
+ * @link		http://www.ship-simu.org
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Load header
+crackerTrackerLoadTemplate('page_header');
+
+// Load form
+crackerTrackerLoadLocalizedTemplate('add_ticket_form');
+
+// Load footer
+crackerTrackerLoadTemplate('page_footer');
+
+// [EOF]
+?>
diff --git a/libs/templates/add_ticket_thanks.tpl.php b/libs/templates/add_ticket_thanks.tpl.php
new file mode 100644
index 0000000..9680a2e
--- /dev/null
+++ b/libs/templates/add_ticket_thanks.tpl.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Template file "Thank you" for adding tickets
+ *
+ * @author		Roland Haeder <webmaster@ship-simu.org>
+ * @version		3.0.0
+ * @copyright	Copyright (c) 2009, 2010 Cracker Tracker Team
+ * @license		GNU GPL 3.0 or any newer version
+ * @link		http://www.ship-simu.org
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Load header
+crackerTrackerLoadTemplate('page_header');
+
+// Load form
+crackerTrackerLoadLocalizedTemplate('add_ticket_success');
+
+// Load footer
+crackerTrackerLoadTemplate('page_footer');
+
+// [EOF]
+?>
diff --git a/libs/templates/de/.htaccess b/libs/templates/de/.htaccess
new file mode 100644
index 0000000..3a42882
--- /dev/null
+++ b/libs/templates/de/.htaccess
@@ -0,0 +1 @@
+Deny from all
diff --git a/libs/templates/de/add_ticket_form.tpl.php b/libs/templates/de/add_ticket_form.tpl.php
new file mode 100644
index 0000000..baec1d4
--- /dev/null
+++ b/libs/templates/de/add_ticket_form.tpl.php
@@ -0,0 +1,33 @@
+<?php /* Required for my editor... :-( */ ?>
+<form accept-charset="utf-8" action="<?php print crackerTrackerScriptName() . '?' . crackerTrackerQueryString() . '"'; ?> method="post">
+
+<div class="ctracker_add_ticket_header">
+	Bitte f&uuml;llen Sie ein Support-Ticket aus:
+</div>
+
+<div class="ctracker_form_row">
+	Ihr voller Name:<br />
+	<input type="text" class="ctracker_form_text" name="name" size="20" maxlength="255" />
+</div>
+
+<div class="ctracker_form_row">
+	Ihre Email-Adresse: (damit wir Sie kontaktieren k&ouml;nnen)<br />
+	<input type="text" class="ctracker_form_text" name="email" size="30" maxlength="255" />
+</div>
+
+<div class="ctracker_form_row">
+	Ihre Kommentare oder weitere Hinweise? (Optional)<br />
+	<textarea class="ctracker_form_text" name="comment" rows="5" cols="40"></textarea>
+</div>
+
+<div class="ctracker_form_row">
+	Bitte &uuml;berpr&uuml;fen Sie alle Eingaben, bevor Sie dieses Ticket versenden!<br />
+	<input type="reset" class="ctracker_reset" name="reset" value="Reset form data" />
+	<input type="submit" class="ctracker_submit" name="ctracker_add_ticket" value="Submit form data" />
+</div>
+
+<div class="ctracker_form_footer">
+	Ihre IP-Adresse lautet: <span class="ctracker_data"><?php print determineCrackerTrackerRealRemoteAddress(); ?></span>
+</div>
+
+</form>
diff --git a/libs/templates/de/add_ticket_success.tpl.php b/libs/templates/de/add_ticket_success.tpl.php
new file mode 100644
index 0000000..7a651f2
--- /dev/null
+++ b/libs/templates/de/add_ticket_success.tpl.php
@@ -0,0 +1,11 @@
+<?php /* Required for my editor... :-( */ ?>
+<div>
+	Ihr Ticket wurde mit der ID-Nummer <span class="ctracker_data"><?php print getCrackerTrackerTicketId(); ?></span>
+	erstellt. Sie k&ouml;nnen nun fortfahren:
+</div>
+
+<div>
+	<form accept-charset="utf-8" action="<?php print crackerTrackerScriptName() . '?' . crackerTrackerQueryString() . '"'; ?> method="post">
+		<input type="submit" class="submit" name="ctracker_continue" value="Weiter zur eigentlichen Webseite" />
+	</form>
+</div>
diff --git a/libs/templates/de/body_header.tpl.php b/libs/templates/de/body_header.tpl.php
new file mode 100644
index 0000000..4234ae7
--- /dev/null
+++ b/libs/templates/de/body_header.tpl.php
@@ -0,0 +1,16 @@
+<?php /* Required for my editor... :-( */ ?>
+<h2>
+	Sicherheitssperre wurde ausgel&ouml;st
+</h2>
+
+<div class="ctracker_teaser">
+	Die auf diesem Server installierte Sicherheitssoftware &quot;Cracker Tracker
+	Stand-Alone&quot; hat kurz zuvor b&ouml;sartigen oder eben nur
+	verd&auml;chtigen Traffic ausgehend von Ihrer IP-Adresse
+	<span class="ctracker_data"><?php print determineCrackerTrackerRealRemoteAddress(); ?></span>
+	erkannt. Bitte installieren oder aktualisieren Sie nun einen freien
+	Virenscanner Ihrer Wahl lassen Sie einen kompletten Scan Ihres Computers
+	durchf&uuml;hren. Es ist sehr wahrscheinlich dass die Sicherheit Ihres
+	Computers gef&auml;hrdet ist und ein trojanisches Pferd oder Virus Ihren
+	Rechner infiziert hat.
+</div>
diff --git a/libs/templates/en/.htaccess b/libs/templates/en/.htaccess
new file mode 100644
index 0000000..3a42882
--- /dev/null
+++ b/libs/templates/en/.htaccess
@@ -0,0 +1 @@
+Deny from all
diff --git a/libs/templates/en/add_ticket_form.tpl.php b/libs/templates/en/add_ticket_form.tpl.php
new file mode 100644
index 0000000..f325e5d
--- /dev/null
+++ b/libs/templates/en/add_ticket_form.tpl.php
@@ -0,0 +1,33 @@
+<?php /* Required for my editor... :-( */ ?>
+<form accept-charset="utf-8" action="<?php print crackerTrackerScriptName() . '?' . crackerTrackerQueryString() . '"'; ?> method="post">
+
+<div class="ctracker_form_header">
+	Please fill-in a support ticket:
+</div>
+
+<div class="ctracker_form_row">
+	Your full name:<br />
+	<input type="text" class="ctracker_form_text" name="name" size="20" maxlength="255" />
+</div>
+
+<div class="ctracker_form_row">
+	Your email address: (so we can contact you back)<br />
+	<input type="text" class="ctracker_form_text" name="email" size="30" maxlength="255" />
+</div>
+
+<div class="ctracker_form_row">
+	Any comments you like to add? (Optional)<br />
+	<textarea class="ctracker_form_text" name="comment" rows="5" cols="40"></textarea>
+</div>
+
+<div class="ctracker_form_row">
+	Please re-check your input before submitting this form!<br />
+	<input type="reset" class="ctracker_reset" name="reset" value="Reset form data" />
+	<input type="submit" class="ctracker_submit" name="ctracker_add_ticket" value="Submit form data" />
+</div>
+
+<div class="ctracker_form_footer">
+	Your IP is: <span class="ctracker_data"><?php print determineCrackerTrackerRealRemoteAddress(); ?></span>
+</div>
+
+</form>
diff --git a/libs/templates/en/add_ticket_success.tpl.php b/libs/templates/en/add_ticket_success.tpl.php
new file mode 100644
index 0000000..d24f02d
--- /dev/null
+++ b/libs/templates/en/add_ticket_success.tpl.php
@@ -0,0 +1,11 @@
+<?php /* Required for my editor... :-( */ ?>
+<div>
+	Your ticket with the id number <span class="ctracker_data"><?php print getCrackerTrackerTicketId(); ?></span>
+	was just been created. You may continue now:
+</div>
+
+<div>
+	<form accept-charset="utf-8" action="<?php print crackerTrackerScriptName() . '?' . crackerTrackerQueryString() . '"'; ?> method="post">
+		<input type="submit" class="submit" name="ctracker_continue" value="Continue to the origin website" />
+	</form>
+</div>
diff --git a/libs/templates/en/body_header.tpl.php b/libs/templates/en/body_header.tpl.php
new file mode 100644
index 0000000..26dd649
--- /dev/null
+++ b/libs/templates/en/body_header.tpl.php
@@ -0,0 +1,15 @@
+<?php /* Required for my editor... :-( */ ?>
+<h2>
+	Security Lock-Down Due To Suspicious/Malicious Traffic
+</h2>
+
+<div class="ctracker_teaser">
+	The security software &quot;Cracker Tracker Stand-Alone&quot; installed on
+	this server has recently detected some malicious or even suspicious traffic
+	originating from your IP address <span class="ctracker_data">
+	<?php print determineCrackerTrackerRealRemoteAddress(); ?></span>. Please now
+	install or update a free virus scanner (of your choice) and run a full scan
+	on your computer. There is a high possibility that your computer&#39;s
+	security is compromised and a trojan horse or virus has infected your
+	computer.
+</div>
diff --git a/libs/templates/page_footer.tpl.php b/libs/templates/page_footer.tpl.php
new file mode 100644
index 0000000..2996e7b
--- /dev/null
+++ b/libs/templates/page_footer.tpl.php
@@ -0,0 +1,4 @@
+	</div>
+	<!-- From ctracker_content //-->
+</body>
+</html>
diff --git a/libs/templates/page_header.tpl.php b/libs/templates/page_header.tpl.php
new file mode 100644
index 0000000..6260ca0
--- /dev/null
+++ b/libs/templates/page_header.tpl.php
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $GLOBALS['ctracker_language']; ?>" lang="<?php print $GLOBALS['ctracker_language']; ?>">
+<head>
+	<title>
+		Cracker Tracker Stand-Alone - Enhanced Edition: <?php crackerTrackerOutputLocalized('ctracker_page_header'); ?>
+	</title>
+	<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+	<meta http-equiv="content-style-type" content="text/css" />
+	<meta http-equiv="content-script-type" content="text/javascript" />
+	<meta http-equiv="language" content="<?php print $GLOBALS['ctracker_language']; ?>" />
+</head>
+
+<body>
+	<div class="ctracker_body_header">
+		<?php crackerTrackerLoadLocalizedTemplate('body_header'); ?>
+	</div>
+
+	<div class="ctracker_content">