--- /dev/null
+<?php
+/* vim: set ts=4 tw=0 sw=4 noet: */
+ require_once 'config.php';
+ require_once $CFG->root . 'lib/utils.inc.php';
+
+ $auth_url = $_SERVER['PHP_SELF'] . '?op=login';
+ $login = $_SERVER['PHP_SELF'];
+ $login_form = <<<LF
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+ <title>Login</title>
+ <link rel="stylesheet" href="css/auth.css">
+ </head>
+ <body>
+ <div class="container">
+ <div id="login-form">
+ <h3>Login</h3>
+ <fieldset>
+ <form action="$auth_url" method="post">
+ <input type="email" name="user" required value="Email" onBlur="if(this.value=='')this.value='Email'" onFocus="if(this.value=='Email')this.value='' "/>
+ <input type="password" name="password" required value="Password" onBlur="if(this.value=='')this.value='Password'" onFocus="if(this.value=='Password')this.value='' "/>
+ <input type="submit" value="Login"/>
+<!-- <footer class="clearfix">
+ <p><span class="info">?</span><a href="#">Forgot Password</a></p>
+ </footer>-->
+ </form>
+ </fieldset>
+ </div> <!-- end login-form -->
+ <p class="footer">Powered by <a href="https://qtadmin.datanom.net">
+ QtAdmin</a>. © 2015 by Michael Rasmussen</p>
+ </div>
+ </body>
+</html>
+LF;
+
+ $login_error = <<<LE
+<DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+ <title>Error</title>
+ <link rel="stylesheet" href="css/auth.css">
+ </head>
+ <body>
+ <div class="container">
+ <div id="greeting">
+ <h3>ERROR</h3>
+ <fieldset>
+ <p><span class="error">__ERROR__<span></p>
+ <p><a href="$login">Login</a></p>
+ </fieldset>
+ </div> <!-- end login-form -->
+ <p class="footer">Powered by <a href="https://qtadmin.datanom.net">
+ QtAdmin</a>. © 2015 by Michael Rasmussen</p>
+ </div>
+ </body>
+</html>
+LE;
+
+ $util = Utils::getInstance();
+ if (isset($_GET['op']))
+ $action = $_GET['op'];
+ else
+ $action = 'default';
+
+ if ($action == 'logout') {
+ // logout
+ $util->logout();
+ echo $login_form;
+ } else if ($action == 'login') {
+ // login
+ $user = $_POST['user'];
+ $password = $_POST['password'];
+ if ($util->login($user, $password)) {
+ header('Location: index.php');
+ } else {
+ $error = $util->getLoginStatus();
+ $error = str_replace('__ERROR__', $error, $login_error);
+ echo $error;
+ }
+ } else {
+ echo $login_form;
+ }
+?>
+
--- /dev/null
+<?php
+/* vim: set ts=4 tw=0 sw=4 noet: */
+$CFG = new stdClass;
+
+// Amavis
+$CFG->amavisd_db_host = "127.0.0.1";
+$CFG->amavisd_db_port = 3306;
+$CFG->amavisd_db_name = "amavisd";
+$CFG->amavisd_db_user = "amavisd";
+$CFG->amavisd_db_password = "suFt3oEEmmXTjFq1bjTXRNIPXhF41a";
+$CFG->amavis_policy_port = 9998;
+// LDAP
+$CFG->ldap_dsn = "ldap://127.0.0.1:389";
+$CFG->ldap_base_dn = "o=domains,dc=datanom,dc=net";
+
+$CFG->root = '/usr/share/quarantine-admin/';
+$CFG->wwwroot = '/qtadmin/';
+
+// HTTP_AUTH or LDAP
+$CFG->auth_method = 'LDAP';
+// If HTTP_AUTH is chosen configure admin user here
+//$CFG->admin_user = 'some_admin';
+
+$CFG->db_driver = 'mysqli';
+$DB = null;
+
+// Session timeout in minuts
+// Default timeout is 20 minuts
+$CFG->session_timeout = 60;
+
+?>
--- /dev/null
+/* ---------- GENERAL ---------- */
+* {
+ box-sizing: border-box;
+}
+*:before, *:after {
+ box-sizing: border-box;
+}
+
+body {
+ background: #eaeaea;
+ color: #999;
+ font: 400 16px/1.5em sans-serif;
+ margin: 0;
+}
+
+h3 {
+ margin: 0;
+}
+
+a {
+ color: #999;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #1dabb8;
+}
+
+fieldset {
+ border: none;
+ margin: 0;
+}
+
+input {
+ border: none;
+ font-family: inherit;
+ font-size: inherit;
+ margin: 0;
+ -webkit-appearance: none;
+}
+
+input:focus {
+ outline: none;
+}
+
+input[type="submit"] {
+ cursor: pointer;
+}
+
+.clearfix {
+ *zoom: 1;
+}
+.clearfix:before, .clearfix:after {
+ content: ' ';
+ display: table;
+}
+.clearfix:after {
+ clear: both;
+}
+
+.container {
+ left: 50%;
+ position: fixed;
+ top: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+}
+
+.footer {
+ text-align: center;
+ margin-top: 10px;
+ margin-bottom: 10px;
+ font-size: 0.7em;
+ background: #ECECAC;
+ color: black;
+}
+
+/* ---------- LOGIN-FORM ---------- */
+#login-form {
+ width: 300px;
+}
+
+#login-form h3 {
+ background-color: #282830;
+ border-radius: 5px 5px 0 0;
+ color: #fff;
+ font-size: 14px;
+ padding: 20px;
+ text-align: center;
+ text-transform: uppercase;
+}
+
+#login-form fieldset {
+ background: #fff;
+ border-radius: 0 0 5px 5px;
+ padding: 20px;
+ position: relative;
+}
+
+#login-form fieldset:before {
+ background-color: #fff;
+ content: "";
+ height: 8px;
+ left: 50%;
+ margin: -4px 0 0 -4px;
+ position: absolute;
+ top: 0;
+ -webkit-transform: rotate(45deg);
+ -ms-transform: rotate(45deg);
+ transform: rotate(45deg);
+ width: 8px;
+}
+
+#login-form input {
+ font-size: 14px;
+}
+
+#login-form input[type="email"],
+#login-form input[type="password"] {
+ border: 1px solid #dcdcdc;
+ padding: 12px 10px;
+ width: 100%;
+}
+
+#login-form input[type="email"] {
+ border-radius: 3px 3px 0 0;
+}
+
+#login-form input[type="password"] {
+ border-top: none;
+ border-radius: 0px 0px 3px 3px;
+}
+
+#login-form input[type="submit"] {
+ background: #1dabb8;
+ border-radius: 3px;
+ color: #fff;
+ float: right;
+ font-weight: bold;
+ margin-top: 20px;
+ padding: 12px 20px;
+}
+
+#login-form input[type="submit"]:hover {
+ background: #198d98;
+}
+
+#login-form footer {
+ font-size: 12px;
+ margin-top: 16px;
+}
+
+.info {
+ background: #e5e5e5;
+ border-radius: 50%;
+ display: inline-block;
+ height: 20px;
+ line-height: 20px;
+ margin: 0 10px 0 0;
+ text-align: center;
+ width: 20px;
+}
+
+/* ---------- GREETING ---------- */
+#greeting {
+ width: 300px;
+}
+
+#greeting fieldset {
+ background: #fff;
+ border-radius: 0 0 5px 5px;
+ padding: 20px;
+ position: relative;
+}
+
+#greeting h3 {
+ background-color: #282830;
+ border-radius: 5px 5px 0 0;
+ color: #fff;
+ font-size: 14px;
+ padding: 20px;
+ text-align: center;
+ text-transform: uppercase;
+}
+
+#greeting p {
+ text-align: center;
+ color: navy;
+}
+
+#greeting a {
+ color: green;
+}
+
+.error {
+ color: red;
+}
--- /dev/null
+/* vim: set ts=4 tw=0 sw=4 noet: */
+.h1 {
+ text-align: center;
+ color: navy;
+}
+
+.user {
+ float: right;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 0.8em;
+ margin-bottom: 10px;
+}
+
+.bg_odd {
+ background: lightgray;
+}
+
+.bg_even {
+ background: white;
+}
+
+table {
+ border-collapse: collapse;
+ width: 100%;
+}
+
+table, th, td {
+ border: 1px solid green;
+}
+
+th {
+ background: navy;
+ color: white;
+ font-weight: bold;
+}
+
+td {
+ padding: 2px 6px;
+}
+
+body {
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 0.9em;
+ color: #3D658C;
+ background: white;
+}
+
+.total-rows {
+ color: red;
+ font-size: 0.8em;
+}
+
+.page-nav {
+ float: right;
+ margin-top: 5px;
+}
+
+.mail-purge {
+ margin-top: 5px;
+}
+
+.footer {
+ text-align: center;
+ margin-top: 20px;
+ margin-bottom: 10px;
+ font-size: 0.7em;
+ background: #ECECAC;
+ color: black;
+}
+
+.whitefooter {
+ color: green;
+}
+
+img {
+ border: 0;
+}
+
+.nav-img {
+ width: 24px;
+ height: 24px;
+}
+
+.nav-action {
+ text-align: center;
+ width: 53px;
+}
+
+.label {
+ color: black;
+ background: lightgray;
+ font-weight: bold;
+ width: 10%;
+}
+
+.value {
+ color: black;
+ background: white;
+ font-size: 0.8em;
+}
+
+.ruler {
+ color: white;
+ background: black;
+ font-size: 1.4em;
+ font-weight: bold;
+ text-align: center;
+}
+
+.button-menu {
+ width: 100%;
+ border: 0;
+ margin-bottom: 10px;
+}
+
+.button {
+ text-align: center;
+ border: 0 solid white;
+ background: white;
+ width: 25%;
+}
+
+input.btn-input {
+ width: 150px;
+}
+
+.time {
+ float: right;
+ color: white;
+ background: green;
+ font-size: 0.7em;
+}
+
--- /dev/null
+<?php
+/* vim: set ts=4 tw=0 sw=4 noet: */
+ require_once 'config.php';
+ require_once $CFG->root . 'lib/db_factory.php';
+ require_once $CFG->root . 'lib/utils.inc.php';
+
+ $util = Utils::getInstance();
+ unset($_SESSION['mailInfo']);
+
+ if ($util->isLoggedIn()) {
+ if (isset($_GET['rowsperpage'])) {
+ $rowsPerPage = $_GET['rowsperpage'];
+ } else {
+ $rowsPerPage = 20;
+ }
+
+ $pageNum = 1;
+ if (isset($_GET['page'])) {
+ $pageNum = $_GET['page'];
+ }
+
+ $offset = ($pageNum - 1) * $rowsPerPage;
+
+ $util->setHeading('Quarantine Administration');
+ echo $util->getHeader();
+ echo $util->getHeading();
+
+ echo "<span class=\"user\">{$util->getUser()}
+ <a href=\"auth.php?op=logout\">Logout</a></span>";
+ $which = ($util->isAdmin() == true) ? 'all' : $util->getUser();
+ $rows = $DB->getQMails($offset, $rowsPerPage, $which);
+ $numrows = $DB->numRows();
+ echo "<span class=\"total-rows\">$numrows quarantined mail(s)</span>";
+ echo "<table><tr>";
+ echo "<table><tr><th>Received</th><th>Cause</th>";
+ echo "<th>Sender</th><th>Recipient</th><th>Subject</th><th>Action</th>";
+ echo "</tr>";
+
+ $mailInfo = array();
+ $i = 0;
+ foreach ($rows as $row) {
+ if ($i % 2)
+ echo '<tr class="bg_odd">';
+ else
+ echo '<tr class="bg_even">';
+ $id = $row->mail_id;
+ $mailInfo[$id] = serialize($row);
+ $url = urlencode($id);
+ $recipient = "<a href=\"mail_report.php?id=$url\">{$row->recipient}</a>";
+ $action = "<a href=\"quarantine.php?id=$url&op=release\">";
+ $action .= "<img class=\"nav-img\" src=\"pics/release.png\" alt=\"Release\" /></a>";
+ $action .= " <a href=\"quarantine.php?id=$url&op=delete\">";
+ $action .= "<img class=\"nav-img\" src=\"pics/delete.png\" alt=\"Delete\" /></a>";
+ $sender = $row->sender;
+ $received = strftime("%c", $row->time_iso);
+ $quaratinefor = $util->convertContent($row->quaratinefor);
+ $subject = $row->subject;
+ echo "<td>$received</td><td class=\"nav-action\">".
+ "$quaratinefor</td><td>$sender</td><td>$recipient</td>".
+ "<td>$subject</td><td class=\"nav-action\">$action</td></tr>";
+ $i++;
+ }
+ $_SESSION['mailInfo'] = $mailInfo;
+ echo "</table>";
+
+ $maxPage = ceil($numrows/$rowsPerPage);
+ $self = $_SERVER['PHP_SELF'];
+
+ if ($pageNum > 1) {
+ $page = $pageNum - 1;
+ $prev = " <a href=\"$self?page=$page&rowsperpage=$rowsPerPage\"
+ class='whitefooter'>[Prev]</a>";
+ $first = " <a href=\"$self?page=1&rowsperpage=$rowsPerPage\"
+ class='whitefooter'>[First Page]</a> ";
+ } else {
+ $prev = ' '; // we're on page one, don't print previous link
+ $first = ' '; // nor the first page link
+ }
+
+ if ($pageNum < $maxPage) {
+ $page = $pageNum + 1;
+ $next = " <a href=\"$self?page=$page&rowsperpage=$rowsPerPage\"
+ class='whitefooter'>[Next]</a>";
+ $last = "<a href=\"$self?page=$maxPage&rowsperpage=$rowsPerPage\"
+ class='whitefooter'>[Last Page]</a> ";
+ } else {
+ $next = ' '; // we're on the last page, don't print next link
+ $last = ' '; // nor the last page link
+ }
+ $marked = $DB->getMarked($which);
+ $_SESSION['marked'] = serialize($marked);
+ echo '<input class="mail-purge" type="button" value="Purge Mails ('.
+ count($marked).')" onclick="javascript: location.href=\'quarantine.php?op=purge\'"/>';
+ echo "<p class=\"page-nav\">$first$prev Showing page $pageNum of
+ $maxPage pages $next$last</p>";
+
+ echo $util->getFooter();
+ } else {
+ header('Location: auth.php');
+ }
+?>
--- /dev/null
+/* vim: set ts=4 tw=0 sw=4 noet: */
+var timerRef=setInterval(function(){myTimer()},1000);
+var timeStart = new Date().getTime() + timeout;
+
+function myTimer() {
+ var elapsed = new Date().getTime();
+ var expire = timeStart - elapsed;
+ var timeLeft = Math.round(((expire % 86400000) % 3600000) / 60000);
+
+ if (timeLeft < 0) {
+ timeLeft = 'Expired';
+ document.getElementById("time").style.background = "red";
+ clearInterval(timerRef);
+ } else {
+ timeLeft += 1;
+ timeLeft = '< ' + timeLeft + ' min';
+ }
+
+ document.getElementById("timer").innerHTML = timeLeft;
+}
--- /dev/null
+<?php
+/* vim: set ts=4 tw=0 sw=4 noet: */
+if (isset($CFG->db_driver)) {
+ switch ($CFG->db_driver) {
+ case 'mysqli':
+ require_once $CFG->root . 'lib/db_mysqli.inc.php';
+ $DB = DBMysqli::getInstance();
+ break;
+ default:
+ die ('Unknow database driver: ' . $CFG->db_driver);
+ }
+} else {
+ die ('Missing config file');
+}
+?>
--- /dev/null
+<?php
+/* vim: set ts=4 tw=0 sw=4 noet: */
+abstract class DBImpl {
+
+ private function __clone() {}
+
+ abstract protected static function getInstance();
+ abstract protected function getQMails($offset = -1, $rowsPerPage = -1, $recipient = 'all');
+ abstract protected function getMarked($recipient = 'all');
+ abstract protected function numRows();
+ abstract protected function getMail($id);
+ abstract protected function setCharset($charset = 'utf8');
+ abstract protected function update($sql);
+}
--- /dev/null
+<?php
+/* vim: set ts=4 tw=0 sw=4 noet: */
+require_once $CFG->root .'lib/db_implementation.php';
+
+class DBMysqli extends DBImpl {
+
+ private static $_instance = null;
+ private $con = null;
+ private $charset = 'utf8';
+ private $numRows = -1;
+
+ private function __construct() {
+ $this->connect();
+ }
+
+ function __destruct() {
+ if ($this->con) {
+ $this->con->close();
+ $this->con = null;
+ }
+ }
+
+ private function __clone() {}
+
+ public static function getInstance() {
+ if (!is_object(self::$_instance)) {
+ self::$_instance = new DBMysqli();
+ }
+ return self::$_instance;
+ }
+
+ private function connect() {
+ global $CFG;
+
+ if (!$this->con) {
+ $this->con = new mysqli($CFG->amavisd_db_host, $CFG->amavisd_db_user,
+ $CFG->amavisd_db_password, $CFG->amavisd_db_name,
+ $CFG->amavisd_db_port);
+ if ($this->con->connect_error) {
+ die ('Connect error ('.$this->con->connect_errno.') '.
+ $this->con->connect_error);
+ }
+ }
+ }
+
+ public function setCharset($charset = 'utf8') {
+ $this->charset = $charset;
+ }
+
+ private function changeCharset() {
+ if (!$this->con->set_charset($this->charset)) {
+ printf("Error loading character set %s: %s\n", $this->charset, $this->con->error);
+ }
+ }
+
+ public function update($sql) {
+ $success = true;
+
+ if (! is_array($sql)) {
+ $sql = array($sql);
+ }
+
+ $this->con->autocommit(false);
+ foreach ($sql as $query) {
+ $this->con->query($query) ? null : $success = false;
+ }
+ $success ? $this->con->commit() : $this->con->rollback();
+ $this->con->autocommit(true);
+
+ return $success;
+ }
+
+ function getMarked($recipient = 'all') {
+ $all = array();
+
+ $query = "select distinct m.mail_id as id from quarantine q, msgrcpt m, msgs s, maddr r ";
+ $query .= "where m.mail_id = q.mail_id and q.mail_id = s.mail_id and m.rid = r.id ";
+ $query .= "and (m.rs = 'R' or m.rs = 'D')";
+
+ if ($recipient != 'all') {
+ $query .= " and email = '$recipient'";
+ }
+
+ if ($result = $this->con->query($query)) {
+ while ($row = $result->fetch_object()) {
+ $all[] = $row->id;
+ }
+ }
+
+ return $all;
+ }
+
+ public function getQMails($offset = -1, $rowsPerPage = -1, $recipient = 'all') {
+ $row = array();
+ $this->changeCharset();
+ $query = "SELECT DISTINCT quarantine.mail_id, secret_id, rs, bspam_level, ";
+ $query .= "(UNIX_TIMESTAMP(time_iso) + (3600 * 2)) AS time_iso, ";
+ $query .= "SUBSTRING(sender.email,1,35) AS sender, ";
+ $query .= "SUBSTRING(recipient.email,1,28) AS recipient, size, msgrcpt.content ";
+ $query .= "AS quaratinefor, SUBSTRING( subject, 1, 25) AS subject FROM ";
+ $query .= "`quarantine` LEFT JOIN msgrcpt ON msgrcpt.mail_id = quarantine.mail_id ";
+ $query .= "LEFT JOIN msgs ON msgs.mail_id = quarantine.mail_id LEFT JOIN maddr AS ";
+ $query .= "recipient ON msgrcpt.rid = recipient.id LEFT JOIN maddr AS sender ON ";
+ $query .= "msgs.sid = sender.id WHERE msgrcpt.rs != 'R' AND msgrcpt.rs != 'D'";
+
+ if ($recipient != 'all') {
+ $query .= " and recipient.email = '$recipient'";
+ }
+
+ if ($offset >= 0 && $rowsPerPage >= 0) {
+ $result = $this->con->query($query, MYSQLI_STORE_RESULT);
+ if ($result) {
+ $this->numRows = $result->num_rows;
+ $result->free();
+ } else {
+ $this->numRows = 0;
+ }
+ $query .= " ORDER BY time_iso DESC LIMIT $offset, $rowsPerPage";
+ }
+
+ if ($result = $this->con->query($query, MYSQLI_USE_RESULT)) {
+ if ($this->numRows < 0)
+ $this->numRows = $result->num_rows;
+ while ($obj = $result->fetch_object()) {
+ $row[] = $obj;
+ }
+ $result->free();
+ }
+
+ return $row;
+ }
+
+ public function numRows() {
+ return $this->numRows;
+ }
+
+ public function getMail($id) {
+ $row = null;
+
+ $this->changeCharset();
+ $query = "SELECT * FROM quarantine WHERE mail_id = '$id'";
+ if ($result = $this->con->query($query, MYSQLI_USE_RESULT)) {
+ $row = $result->fetch_object();
+ }
+
+ return $row;
+ }
+
+}
+
+?>
--- /dev/null
+<?php
+/* vim: set ts=4 tw=0 sw=4 noet: */
+require_once $CFG->root .'config.php';
+
+class Utils {
+
+ private static $_instance = null;
+ private $server;
+ private $user;
+ private $is_admin;
+ private $loginStatus;
+ private $header = '<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" href="css/styles.css">
+ <script>
+ var timeout = __TIMEOUT__;
+ </script>
+ <script src="__ROOT__js/timer.js"></script>
+ <title>__TITLE__</title>
+</head>
+<body>';
+ private $footer = '<p class="footer">Powered by <a href="https://qtadmin.datanom.net">
+ QtAdmin</a>. © 2015 by Michael Rasmussen</p></body></html>';
+ private $heading = '<p id="time" class="time">Session timeout:
+ <span id="timer"></span></p><h1 class="h1">__TITLE__</h1>';
+
+ private function __construct() {
+ global $CFG;
+
+ $this->server = $_SERVER;
+ session_start();
+
+ $this->user = null;
+ $this->is_admin = false;
+ $this->loginStatus = 'Not logged in';
+
+ if (isset($_SESSION['user'])) {
+ $this->user = $_SESSION['user'];
+ $this->loginStatus = 'OK';
+ $this->is_admin = $_SESSION['is_admin'];
+ } else {
+ if ($CFG->auth_method == 'HTTP_AUTH') {
+ if (isset($this->server['PHP_AUTH_USER'])) {
+ $this->user = $this->server['PHP_AUTH_USER'];
+ $this->loginStatus = 'OK';
+ if ($CFG->admin_user == $this->user)
+ $this->is_admin = true;
+ }
+ }
+ }
+ $_SESSION['user'] = $this->user;
+ $_SESSION['is_admin'] = $this->is_admin;
+ }
+
+ private function __clone() {}
+
+ public static function getInstance() {
+ global $CFG;
+
+ if (!is_object(self::$_instance)) {
+ self::$_instance = new Utils();
+ }
+ // Session timeout handler
+ if ('' == session_id())
+ session_start();
+ if (isset($CFG->session_timeout)) {
+ $timeout = $CFG->session_timeout * 60;
+ } else {
+ $timeout = 20 * 60;
+ }
+
+ if (ini_get('session.gc_maxlifetime') != $timeout)
+ ini_set('session.gc_maxlifetime', $timeout);
+ if (ini_get('session.cookie_lifetime') != $timeout)
+ ini_set('session.cookie_lifetime', $timeout);
+ $time = $_SERVER['REQUEST_TIME'];
+ if (isset($_SESSION['LAST_ACTIVITY']) && ($time - $_SESSION['LAST_ACTIVITY']) >= $timeout) {
+ session_unset();
+ session_destroy();
+ session_start();
+ self::$_instance->user = null;
+ self::$_instance->is_admin = false;
+ }
+ $_SESSION['LAST_ACTIVITY'] = $time;
+
+ return self::$_instance;
+ }
+
+ public function logout() {
+ $_SESSION = array();
+ if (ini_get('session.use_cookies')) {
+ $params = session_get_cookie_params();
+ setcookie(session_name(), '', time() - 42000,
+ $params['path'], $params['domain'],
+ $params['secure'], $params['httponly']);
+ }
+ session_unset();
+ session_destroy();
+ $this->user = null;
+ $this->is_admin = false;
+ }
+
+ public function isAdmin() {
+ //file_put_contents('/tmp/login.txt', var_export($this, true));
+ return $this->is_admin;
+ }
+
+ public function login($user, $pw) {
+ global $CFG;
+ $result = false;
+
+ unset($_SESSION['user']);
+ unset($_SESSION['is_admin']);
+ $this->user = null;
+ $this->is_admin = false;
+
+ $p = explode('@', $user);
+ if (count($p) != 2) {
+ $this->loginStatus = 'Bad username';
+ return false;
+ }
+ $domain = $p[1];
+ $dn = "mail=$user,ou=Users,domainName=$domain,$CFG->ldap_base_dn";
+ $filter = "(&(objectclass=mailUser)(accountStatus=active)(mail=$user))";
+ $ds = @ldap_connect($CFG->ldap_dsn);
+ if ($ds) {
+ @ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
+ $r = @ldap_bind($ds, $dn, $pw);
+ if ($r) {
+ $sr = @ldap_search($ds, $CFG->ldap_base_dn, $filter, array('mail','domainglobaladmin'));
+ $info = @ldap_get_entries($ds, $sr); // array
+ if ($info['count'] > 0) {
+ $_SESSION['user'] = $user;
+ $this->user = $user;
+ $result = true;
+ $this->loginStatus = 'OK';
+ $admin = 'NO';
+ if (isset($info[0]['domainglobaladmin'])) {
+ $admin = $info[0]['domainglobaladmin'][0];
+ $admin = strtoupper($admin);
+ }
+ $this->is_admin = ($admin == 'YES') ? true : false;
+ $_SESSION['is_admin'] = $this->is_admin;
+ } else {
+ $this->loginStatus = 'Login failed';
+ }
+ } else {
+ $this->loginStatus = ldap_error($ds);
+ }
+ @ldap_close($ds);
+ } else {
+ $this->loginStatus = 'Connect to LDAP server failed';
+ }
+
+ return $result;
+ }
+
+ public function getLoginStatus() {
+ return $this->loginStatus;
+ }
+
+ public function isLoggedIn() {
+ global $CFG;
+ $loggedIn = false;
+
+ if ($this->user) {
+ $loggedIn = true;
+ } else if (isset($_SESSION['user'])) {
+ $this->user = $_SESSION['user'];
+ $loggedIn = true;
+ } else {
+ if ($CFG->auth_method == 'HTTP_AUTH') {
+ if (isset($this->server['PHP_AUTH_USER'])) {
+ $this->user = $this->server['PHP_AUTH_USER'];
+ $loggedIn = true;
+ }
+ }
+ }
+
+ return $loggedIn;
+ }
+
+ public function getUser() {
+ $this->isLoggedIn();
+ return $this->user;
+ }
+
+ public function getHeader() {
+ return $this->header;
+ }
+
+ public function getFooter() {
+ return $this->footer;
+ }
+
+ public function getHeading() {
+ return $this->heading;
+ }
+
+ public function setHeading($heading) {
+ global $CFG;
+
+ $timeout = $CFG->session_timeout * 60 * 1000;
+ $this->heading = str_replace('__TITLE__', $heading, $this->heading);
+ $this->header = str_replace('__TITLE__', $heading, $this->header);
+ $this->header = str_replace('__ROOT__', $CFG->wwwroot, $this->header);
+ $this->header = str_replace('__TIMEOUT__', $timeout, $this->header);
+ }
+
+ public function convertContent($code) {
+ $table = array(
+ 'V' => 'Virus',
+ 'B' => 'Banned',
+ 'U' => 'Unchecked',
+ 'S' => 'Spam',
+ 'Y' => 'Spammy',
+ 'M' => 'Bad Mime',
+ 'H' => 'Bad Header',
+ 'O' => 'Over sized',
+ 'T' => 'MTA err',
+ 'C' => 'Clean'
+ );
+
+ $string = $table[$code];
+ if (empty($string))
+ $string = 'Unknown';
+
+ return $string;
+ }
+}
--- /dev/null
+<?php
+/* vim: set ts=4 tw=0 sw=4 noet: */
+ require_once 'Mail/mimeDecode.php';
+ require_once 'config.php';
+ require_once $CFG->root . 'lib/db_factory.php';
+ require_once $CFG->root . 'lib/utils.inc.php';
+
+ $util = Utils::getInstance();
+ $loggedIn = $util->isLoggedIn();
+ if ($loggedIn && isset($_GET['id'])) {
+ $util->setHeading('Spam Report');
+ echo $util->getHeader();
+ echo $util->getHeading();
+
+ $id = $_GET['id'];
+ $mail = unserialize($_SESSION['mailInfo'][$id]);
+
+ $row = $DB->getMail($id);
+ $string = $row->mail_text;
+ $sa_tests = null;
+ $params['include_bodies'] = false;
+ $params['decode_bodies'] = true;
+ $params['decode_headers'] = true;
+ $params['input'] = $string;
+ $params['crlf'] = "\r\n";
+
+ $structure = Mail_mimeDecode::decode($params);
+ $headers = $structure->headers;
+ $rows = array();
+ foreach ($headers as $header => $value) {
+ if ($header == 'x-spam-status') {
+ if (preg_match('/^(.*),\s*score=([\d\.]+).*tests=\[(.*)\].*/',
+ $value, $matches)) {
+ $sa_tests = array('x-spam-status' => $matches[1],
+ 'score' => $matches[2], 'tests' => $matches[3]);
+ }
+ } else if ($header == 'x-spam-flag') {
+ $value = str_replace("<", "<", $value);
+ $value = str_replace(">", ">", $value);
+ $rows['spam'] = "<tr><td class=\"label\">Spam</td><td class=\"value\">$value</td></tr>";
+ } else if ($header == 'x-spam-score') {
+ $value = str_replace("<", "<", $value);
+ $value = str_replace(">", ">", $value);
+ $rows['score'] = "<tr><td class=\"label\">Spam Score</td><td class=\"value\">$value</td></tr>";
+ } else if ($header == 'x-spam-level') {
+ $value = str_replace("<", "<", $value);
+ $value = str_replace(">", ">", $value);
+ $rows['level'] = "<tr><td class=\"label\">Spam Level</td><td class=\"value\">$value</td></tr>";
+ } else if ($header == 'date') {
+ $value = str_replace("<", "<", $value);
+ $value = str_replace(">", ">", $value);
+ $rows['date'] = "<tr><td class=\"label\">Date</td><td class=\"value\">$value</td></tr>";
+ } else if ($header == 'from') {
+ $value = str_replace("<", "<", $value);
+ $value = str_replace(">", ">", $value);
+ $rows['from'] = "<tr><td class=\"label\">From</td><td class=\"value\">$value</td></tr>";
+ } else if ($header == 'reply-to') {
+ $value = str_replace("<", "<", $value);
+ $value = str_replace(">", ">", $value);
+ $rows['reply-to'] = "<tr><td class=\"label\">Reply-to</td><td class=\"value\">$value</td></tr>";
+ } else if ($header == 'to') {
+ $value = str_replace("<", "<", $value);
+ $value = str_replace(">", ">", $value);
+ $rows['to'] = "<tr><td class=\"label\">To</td><td class=\"value\">$value</td></tr>";
+ } else if ($header == 'subject') {
+ $value = str_replace("<", "<", $value);
+ $value = str_replace(">", ">", $value);
+ $rows['subject'] = "<tr><td class=\"label\">Subject</td><td class=\"value\">$value</td></tr>";
+ } else if ($header == 'received') {
+ $headers = '';
+ foreach ($value as $val) {
+ $val = str_replace("<", "<", $val);
+ $val = str_replace(">", ">", $val);
+ $headers .= ($headers == '') ? "$val" : "<br/><br/>$val";
+ }
+ $rows['headers'] = "<tr><td class=\"label\">Headers</td><td class=\"value\">$headers</td></tr>";
+ }
+ }
+ $bayes = array();
+ if ($sa_tests) {
+ $sa_tests['tests'] = str_replace(" ","",$sa_tests['tests']);
+ $sa_rules = explode(",",$sa_tests['tests']);
+ $sa_count = count($sa_rules);
+ for ($i = 0; $i < $sa_count; $i++) {
+ $sa_rule = explode("=", $sa_rules[$i]);
+ $bayes[$i] = "<tr><td class=\"label\">$sa_rule[0]</td><td class=\"value\">$sa_rule[1]</td></tr>";
+ }
+ $bayes['total'] = "<tr><td class=\"label\">TOTAL</td><td class=\"value\">".$sa_tests['score']."</td></tr>";
+ } else {
+ $bayes['total'] = "<tr><td class=\"label\">TOTAL</td><td class=\"value\">-</td></tr>";
+ }
+ $plain = "?id=$id&format=plain";
+ $html = "?id=$id&format=html";
+ echo '<p class="ruler">Message ID : ' . $mail->mail_id . '</p>';
+ echo '<table class="button-menu">';
+ echo '<tr class="button-row">';
+ echo '<td class="button"><input class="btn-input" type="button" value="Return"
+ onclick="javascript: history.back();"/></td>';
+ echo '<td class="button"><input class="btn-input" type="button" value="View HTML"
+ onclick="javascript: window.location.href=\'message_view.php'.$html.'\'"/></td>';
+ echo '<td class="button"><input class="btn-input" type="button" value="View Plain Text"
+ onclick="javascript: window.location.href=\'message_view.php'.$plain.'\'"/></td>';
+ echo '<td class="button"><input class="btn-input" type="button" value="View Full Headers"
+ onclick="javascript: window.location.href=\'show_headers.php?id='.$id.'\'"/></td>';
+ echo '</tr></table>';
+ echo '<table>';
+ if (isset($rows['spam']))
+ echo $rows['spam'];
+ if (isset($rows['score']))
+ echo $rows['score'];
+ if (isset($rows['level']))
+ echo $rows['level'];
+ if (isset($rows['headers']))
+ echo $rows['headers'];
+ if (isset($rows['date']))
+ echo $rows['date'];
+ if (isset($rows['from']))
+ echo $rows['from'];
+ if (isset($rows['reply-to']))
+ echo $rows['reply-to'];
+ if (isset($rows['to']))
+ echo $rows['to'];
+ if (isset($rows['subject']))
+ echo $rows['subject'];
+ echo '</table>';
+ echo '<p class="ruler">Spamassassin Report</p>';
+ echo '<table><tr><th>Rule</th><th>Score</th></tr>';
+ foreach ($bayes as $key => $row) {
+ if ($key != 'total') {
+ echo $row;
+ }
+ }
+ echo $bayes['total'];
+ echo '</table>';
+ echo $util->getFooter();
+ } else if ($loggedIn) {
+ header('Location: index.php');
+ } else {
+ header('Location: auth.php');
+ }
+
+?>
--- /dev/null
+<?php
+/* vim: set ts=4 tw=0 sw=4 noet: */
+ require_once 'Mail/mimeDecode.php';
+ require_once 'config.php';
+ require_once $CFG->root . 'lib/db_factory.php';
+ require_once $CFG->root . 'lib/utils.inc.php';
+
+ $util = Utils::getInstance();
+ $loggedIn = $util->isLoggedIn();
+ if ($loggedIn && isset($_GET['id'])) {
+ $id = $_GET['id'];
+ $id = urldecode($id);
+
+ $util->setHeading("Message ID : $id");
+ echo $util->getHeader();
+ echo $util->getHeading();
+
+ $mail = unserialize($_SESSION['mailInfo'][$id]);
+
+ $row = $DB->getMail($id);
+ $string = $row->mail_text;
+ $sa_tests = null;
+ $params['include_bodies'] = true;
+ $params['decode_bodies'] = true;
+ $params['decode_headers'] = true;
+ $params['input'] = $string;
+ $params['crlf'] = "\r\n";
+
+ $structure = Mail_mimeDecode::decode($params);
+ $headers = $structure->headers;
+
+ echo '<table class="button-menu">';
+ echo '<tr class="button-row">';
+ echo '<td class="button"><input class="btn-input" type="button" value="Return"
+ onclick="javascript: history.back();"/></td>';
+ echo '</tr></table>';
+
+ echo '<table><tr>';
+ $from = $headers['from'];
+ $from = str_replace("<", "<", $from);
+ $from = str_replace(">", ">", $from);
+ echo "<tr><td class=\"label\">From</td><td class=\"value\">$from</td></tr>";
+ $to = $headers['to'];
+ $to = str_replace("<", "<", $to);
+ $to = str_replace(">", ">", $to);
+ echo "<tr><td class=\"label\">To</td><td class=\"value\">$to</td></tr>";
+ $date = $headers['date'];
+ $date = str_replace("<", "<", $date);
+ $date = str_replace(">", ">", $date);
+ echo "<tr><td class=\"label\">Date</td><td class=\"value\">$date</td></tr>";
+ echo "<tr><td class=\"label\">Subject</td><td class=\"value\">".$headers['subject']."</td></tr>";
+ echo '<tr><td class="label">Body</td><td class="value">';
+ if (isset($structure->parts)) {
+ foreach ($structure->parts as $part) {
+ if ($_GET['format'] == 'html') {
+ if ($part->ctype_primary=="text" and $part->ctype_secondary=="html") {
+ $bodytext = str_replace("\n", " ",$part->body);
+ $bodytext = str_replace("<body>", "", $bodytext);
+ $bodytext = str_replace("</body>", "", $bodytext);
+ $bodytext = str_replace("<head>", "", $bodytext);
+ $bodytext = str_replace("</head>", "", $bodytext);
+ $bodytext = str_replace("<html>", "", $bodytext);
+ $bodytext = str_replace("</html>", "", $bodytext);
+ echo $bodytext;
+ }
+ } else {
+ if ($part->ctype_primary=="text" and $part->ctype_secondary=="plain") {
+ $bodytext = str_replace("\n", "<br />",$part->body);
+ echo $bodytext;
+ }
+ }
+ }
+ } else {
+ if ($_GET['format'] == 'html') {
+ $bodytext = str_replace("\n", " ",$structure->body);
+ $bodytext = str_replace("<body>", "", $bodytext);
+ $bodytext = str_replace("</body>", "", $bodytext);
+ $bodytext = str_replace("<head>", "", $bodytext);
+ $bodytext = str_replace("</head>", "", $bodytext);
+
+ $bodytext = str_replace("<html>", "", $bodytext);
+ $bodytext = str_replace("</html>", "", $bodytext);
+ echo $bodytext;
+ } else {
+ $bodytext = $structure->body;
+ $bodytext = wordwrap($bodytext, 90, "<br/>");
+ echo $bodytext;
+ }
+ }
+ echo '</td></tr></table>';
+ echo $util->getFooter();
+ } else if ($loggedIn) {
+ header('Location: index.php');
+ } else {
+ header('Location: auth.php');
+ }
+
+?>
+
--- /dev/null
+<?php
+/* vim: set ts=4 tw=0 sw=4 noet: */
+ require_once 'config.php';
+ require_once $CFG->root . 'lib/db_factory.php';
+ require_once $CFG->root . 'lib/utils.inc.php';
+
+ function error($error) {
+ $util = Utils::getInstance();
+ $util->setHeading("Error");
+ echo $util->getHeader();
+ echo $util->getHeading();
+ echo "<p style=\"color: red;\">$error</p>";
+ echo '<a href="index.php">Return</a>';
+ echo $util->getFooter();
+ }
+
+ $util = Utils::getInstance();
+ $loggedIn = $util->isLoggedIn();
+ $request = isset($_GET['op']) ? $_GET['op'] : '';
+ if ($loggedIn && isset($_GET['id'])) {
+ $mail_id = urldecode($_GET['id']);
+ $mail = unserialize($_SESSION['mailInfo']["$mail_id"]);
+ $secret_id = $mail->secret_id;
+ $recipient = $mail->recipient;
+
+ $query = array();
+ if ($request == 'release') {
+ $amavisserver = $CFG->amavisd_db_host;
+ $policy_port = $CFG->amavis_policy_port;
+
+ $fp = fsockopen($amavisserver, $policy_port, $errno, $errstr, 30);
+ if (!$fp) {
+ error("$errstr ($errno)");
+ exit;
+ }
+ $out = "request=" . $request . "\r\n";
+ $out .= "mail_id=" . $mail_id . "\r\n";
+ $out .= "recipient=" . $recipient . "\r\n";
+ $out .= "secret_id=" . $secret_id . "\r\n\r\n";
+ fwrite($fp, $out);
+ $response = fread($fp, 8192);
+ fclose($fp);
+ $response = urldecode($response);
+ if (! preg_match("/^setreply=250\s+([\d\.]+)\s+(.*)/", $response, $matches)) {
+ error("Request to release failed [$out][$response]");
+ exit;
+ }
+ if ($matches[1] != '2.0.0') {
+ error($matches[2]);
+ exit;
+ }
+
+ $query[] = "UPDATE msgrcpt SET rs = 'R' WHERE mail_id = '$mail_id'";
+ } else if ($request == 'delete') {
+ $query[] = "UPDATE msgrcpt SET rs = 'D' WHERE mail_id = '$mail_id'";
+ } else {
+ error("Unknown operation [$request]");
+ exit;
+ }
+ $success = $DB->update($query);
+ if (! $success) {
+ error("Message not released, contact administrator [$query]");
+ exit;
+ }
+ header('Location: index.php');
+ } else if ($loggedIn && $request == 'purge') {
+ $marked = unserialize($_SESSION['marked']);
+ unset($_SESSION['marked']);
+ $query = array();
+ $error = array();
+ foreach ($marked as $mail_id) {
+ $query[] = "delete from msgs where mail_id = '$mail_id'";
+ $query[] = "delete from msgrcpt where mail_id = '$mail_id'";
+ $query[] = "delete from quarantine where mail_id = '$mail_id'";
+ $success = $DB->update($query);
+ if (! $success) {
+ $error[] = $mail_id;
+ }
+ }
+ if (count($error) > 0) {
+ $str = implode(', ', $error);
+ error("The following messages was not purged [$str], contact administrator");
+ exit;
+ }
+ header('Location: index.php');
+ } else if ($loggedIn) {
+ header('Location: index.php');
+ } else {
+ header('Location: auth.php');
+ }
+
+?>
+
--- /dev/null
+<?php
+/* vim: set ts=4 tw=0 sw=4 noet: */
+ require_once 'Mail/mimeDecode.php';
+ require_once 'config.php';
+ require_once $CFG->root . 'lib/db_factory.php';
+ require_once $CFG->root . 'lib/utils.inc.php';
+
+ $util = Utils::getInstance();
+ $loggedIn = $util->isLoggedIn();
+ if ($loggedIn && isset($_GET['id'])) {
+ $util->setHeading('Full Headers Report');
+ echo $util->getHeader();
+ echo $util->getHeading();
+
+ $id = $_GET['id'];
+ $mail = unserialize($_SESSION['mailInfo'][$id]);
+
+ $row = $DB->getMail($id);
+ $string = $row->mail_text;
+ $sa_tests = null;
+ $params['include_bodies'] = false;
+ $params['decode_bodies'] = true;
+ $params['decode_headers'] = true;
+ $params['input'] = $string;
+ $params['crlf'] = "\r\n";
+
+ $structure = Mail_mimeDecode::decode($params);
+ $headers = $structure->headers;
+ $output = '<table><tr><th>Header</th><th>Value</th></tr>';
+ foreach ($headers as $header => $value) {
+ if (is_array($value)) {
+ $text = '';
+ foreach ($value as $val) {
+ if ($text == '') {
+ $text = $val;
+ } else {
+ $text .= "<br/><br/>$val";
+ }
+ }
+ } else {
+ $text = $value;
+ }
+ $output .= "<tr><td class=\"label\">$header</td><td class=\"value\">$text</td></tr>";
+ }
+ $output .= '</table>';
+ echo '<table class="button-menu">';
+ echo '<tr class="button-row">';
+ echo '<td class="button"><input class="btn-input" type="button" value="Return"
+ onclick="javascript: history.back();"/></td>';
+ echo '</tr></table>';
+ echo $output;
+ echo $util->getFooter();
+ } else if ($loggedIn) {
+ header('Location: index.php');
+ } else {
+ header('Location: auth.php');
+ }
+
+?>