From 6df4b8055a0e63b554ed211760ab1aa5cb431306 Mon Sep 17 00:00:00 2001 From: Michael Rasmussen Date: Sun, 31 May 2015 14:50:20 +0200 Subject: [PATCH] initial release --- auth.php | 87 ++++++++++++++ config.php | 31 +++++ css/auth.css | 198 ++++++++++++++++++++++++++++++++ css/styles.css | 133 ++++++++++++++++++++++ index.php | 101 +++++++++++++++++ js/timer.js | 20 ++++ lib/db_factory.php | 15 +++ lib/db_implementation.php | 14 +++ lib/db_mysqli.inc.php | 151 +++++++++++++++++++++++++ lib/utils.inc.php | 232 ++++++++++++++++++++++++++++++++++++++ mail_report.php | 142 +++++++++++++++++++++++ message_view.php | 99 ++++++++++++++++ pics/delete.png | Bin 0 -> 443 bytes pics/release.png | Bin 0 -> 747 bytes quarantine.php | 93 +++++++++++++++ show_headers.php | 59 ++++++++++ 16 files changed, 1375 insertions(+) create mode 100644 auth.php create mode 100644 config.php create mode 100644 css/auth.css create mode 100644 css/styles.css create mode 100644 index.php create mode 100644 js/timer.js create mode 100644 lib/db_factory.php create mode 100644 lib/db_implementation.php create mode 100644 lib/db_mysqli.inc.php create mode 100644 lib/utils.inc.php create mode 100644 mail_report.php create mode 100644 message_view.php create mode 100644 pics/delete.png create mode 100644 pics/release.png create mode 100644 quarantine.php create mode 100644 show_headers.php diff --git a/auth.php b/auth.php new file mode 100644 index 0000000..120f84b --- /dev/null +++ b/auth.php @@ -0,0 +1,87 @@ +root . 'lib/utils.inc.php'; + + $auth_url = $_SERVER['PHP_SELF'] . '?op=login'; + $login = $_SERVER['PHP_SELF']; + $login_form = << + + + + Login + + + +
+
+

Login

+
+
+ + + + +
+
+
+ +
+ + +LF; + + $login_error = << + + + + Error + + + +
+
+

ERROR

+
+

__ERROR__

+

Login

+
+
+ +
+ + +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; + } +?> + diff --git a/config.php b/config.php new file mode 100644 index 0000000..2380794 --- /dev/null +++ b/config.php @@ -0,0 +1,31 @@ +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; + +?> diff --git a/css/auth.css b/css/auth.css new file mode 100644 index 0000000..0494280 --- /dev/null +++ b/css/auth.css @@ -0,0 +1,198 @@ +/* ---------- 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; +} diff --git a/css/styles.css b/css/styles.css new file mode 100644 index 0000000..6d1951a --- /dev/null +++ b/css/styles.css @@ -0,0 +1,133 @@ +/* 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; +} + diff --git a/index.php b/index.php new file mode 100644 index 0000000..9bbd08d --- /dev/null +++ b/index.php @@ -0,0 +1,101 @@ +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 "{$util->getUser()} + Logout"; + $which = ($util->isAdmin() == true) ? 'all' : $util->getUser(); + $rows = $DB->getQMails($offset, $rowsPerPage, $which); + $numrows = $DB->numRows(); + echo "$numrows quarantined mail(s)"; + echo ""; + echo "
"; + echo ""; + echo ""; + + $mailInfo = array(); + $i = 0; + foreach ($rows as $row) { + if ($i % 2) + echo ''; + else + echo ''; + $id = $row->mail_id; + $mailInfo[$id] = serialize($row); + $url = urlencode($id); + $recipient = "{$row->recipient}"; + $action = ""; + $action .= "\"Release\""; + $action .= " "; + $action .= "\"Delete\""; + $sender = $row->sender; + $received = strftime("%c", $row->time_iso); + $quaratinefor = $util->convertContent($row->quaratinefor); + $subject = $row->subject; + echo "". + ""; + $i++; + } + $_SESSION['mailInfo'] = $mailInfo; + echo "
ReceivedCauseSenderRecipientSubjectAction
$received". + "$quaratinefor$sender$recipient$subject$action
"; + + $maxPage = ceil($numrows/$rowsPerPage); + $self = $_SERVER['PHP_SELF']; + + if ($pageNum > 1) { + $page = $pageNum - 1; + $prev = " [Prev]"; + $first = " [First Page] "; + } 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 = " [Next]"; + $last = "[Last Page] "; + } 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 ''; + echo "

$first$prev Showing page $pageNum of + $maxPage pages $next$last

"; + + echo $util->getFooter(); + } else { + header('Location: auth.php'); + } +?> diff --git a/js/timer.js b/js/timer.js new file mode 100644 index 0000000..a7e9c1d --- /dev/null +++ b/js/timer.js @@ -0,0 +1,20 @@ +/* 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; +} diff --git a/lib/db_factory.php b/lib/db_factory.php new file mode 100644 index 0000000..68b1ee5 --- /dev/null +++ b/lib/db_factory.php @@ -0,0 +1,15 @@ +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'); +} +?> diff --git a/lib/db_implementation.php b/lib/db_implementation.php new file mode 100644 index 0000000..c35754f --- /dev/null +++ b/lib/db_implementation.php @@ -0,0 +1,14 @@ +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; + } + +} + +?> diff --git a/lib/utils.inc.php b/lib/utils.inc.php new file mode 100644 index 0000000..ec842b8 --- /dev/null +++ b/lib/utils.inc.php @@ -0,0 +1,232 @@ +root .'config.php'; + +class Utils { + + private static $_instance = null; + private $server; + private $user; + private $is_admin; + private $loginStatus; + private $header = ' + + + + + + + __TITLE__ + +'; + private $footer = ''; + private $heading = '

Session timeout: +

__TITLE__

'; + + 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; + } +} diff --git a/mail_report.php b/mail_report.php new file mode 100644 index 0000000..e40f229 --- /dev/null +++ b/mail_report.php @@ -0,0 +1,142 @@ +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'] = "Spam$value"; + } else if ($header == 'x-spam-score') { + $value = str_replace("<", "<", $value); + $value = str_replace(">", ">", $value); + $rows['score'] = "Spam Score$value"; + } else if ($header == 'x-spam-level') { + $value = str_replace("<", "<", $value); + $value = str_replace(">", ">", $value); + $rows['level'] = "Spam Level$value"; + } else if ($header == 'date') { + $value = str_replace("<", "<", $value); + $value = str_replace(">", ">", $value); + $rows['date'] = "Date$value"; + } else if ($header == 'from') { + $value = str_replace("<", "<", $value); + $value = str_replace(">", ">", $value); + $rows['from'] = "From$value"; + } else if ($header == 'reply-to') { + $value = str_replace("<", "<", $value); + $value = str_replace(">", ">", $value); + $rows['reply-to'] = "Reply-to$value"; + } else if ($header == 'to') { + $value = str_replace("<", "<", $value); + $value = str_replace(">", ">", $value); + $rows['to'] = "To$value"; + } else if ($header == 'subject') { + $value = str_replace("<", "<", $value); + $value = str_replace(">", ">", $value); + $rows['subject'] = "Subject$value"; + } else if ($header == 'received') { + $headers = ''; + foreach ($value as $val) { + $val = str_replace("<", "<", $val); + $val = str_replace(">", ">", $val); + $headers .= ($headers == '') ? "$val" : "

$val"; + } + $rows['headers'] = "Headers$headers"; + } + } + $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] = "$sa_rule[0]$sa_rule[1]"; + } + $bayes['total'] = "TOTAL".$sa_tests['score'].""; + } else { + $bayes['total'] = "TOTAL-"; + } + $plain = "?id=$id&format=plain"; + $html = "?id=$id&format=html"; + echo '

Message ID : ' . $mail->mail_id . '

'; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo '
'; + echo ''; + 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 '
'; + echo '

Spamassassin Report

'; + echo ''; + foreach ($bayes as $key => $row) { + if ($key != 'total') { + echo $row; + } + } + echo $bayes['total']; + echo '
RuleScore
'; + echo $util->getFooter(); + } else if ($loggedIn) { + header('Location: index.php'); + } else { + header('Location: auth.php'); + } + +?> diff --git a/message_view.php b/message_view.php new file mode 100644 index 0000000..03cced9 --- /dev/null +++ b/message_view.php @@ -0,0 +1,99 @@ +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 ''; + echo ''; + echo ''; + echo '
'; + + echo ''; + $from = $headers['from']; + $from = str_replace("<", "<", $from); + $from = str_replace(">", ">", $from); + echo ""; + $to = $headers['to']; + $to = str_replace("<", "<", $to); + $to = str_replace(">", ">", $to); + echo ""; + $date = $headers['date']; + $date = str_replace("<", "<", $date); + $date = str_replace(">", ">", $date); + echo ""; + echo ""; + echo '
From$from
To$to
Date$date
Subject".$headers['subject']."
Body'; + 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("", "", $bodytext); + $bodytext = str_replace("", "", $bodytext); + $bodytext = str_replace("", "", $bodytext); + $bodytext = str_replace("", "", $bodytext); + $bodytext = str_replace("", "", $bodytext); + $bodytext = str_replace("", "", $bodytext); + echo $bodytext; + } + } else { + if ($part->ctype_primary=="text" and $part->ctype_secondary=="plain") { + $bodytext = str_replace("\n", "
",$part->body); + echo $bodytext; + } + } + } + } else { + if ($_GET['format'] == 'html') { + $bodytext = str_replace("\n", " ",$structure->body); + $bodytext = str_replace("", "", $bodytext); + $bodytext = str_replace("", "", $bodytext); + $bodytext = str_replace("", "", $bodytext); + $bodytext = str_replace("", "", $bodytext); + + $bodytext = str_replace("", "", $bodytext); + $bodytext = str_replace("", "", $bodytext); + echo $bodytext; + } else { + $bodytext = $structure->body; + $bodytext = wordwrap($bodytext, 90, "
"); + echo $bodytext; + } + } + echo '
'; + echo $util->getFooter(); + } else if ($loggedIn) { + header('Location: index.php'); + } else { + header('Location: auth.php'); + } + +?> + diff --git a/pics/delete.png b/pics/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..31150da18d02b5e2bf6b372cbf415bb7fd0401c8 GIT binary patch literal 443 zcmV;s0Yv_ZP)lf<^k6sK!*+zp zeKb_rAIEo9$*c=St6l1FY zUYAV=v!55h7bq_n8UmZvm&oMFxOe|2LqB(EA?*0 zK2{y8N(hWw^zO+Y(h`OD3qXytNHkKozz_1(>bhAPIMPb2)h|((s53RmyK)`ljCI lh3@mX1M_8JJ`4_Z=O=9Is~NKzFLM9@002ovPDHLkV1oa6y@&t+ literal 0 HcmV?d00001 diff --git a/pics/release.png b/pics/release.png new file mode 100644 index 0000000000000000000000000000000000000000..6e2541cebcc9a42559cdb7670b6cf860a5e2dfe8 GIT binary patch literal 747 zcmVCvx%Uz}jS>h1oOZkY z7T^VfAP#dJNAT;wfZR90r`>LMlcwqFbX|+{Xf%4nY&Jg!^axI;UKMa>G#Z^R7K?9G z6L`H|o7?Tq1Nu~M`QGVt5~>LjiNqa)!LTky31JcG4yHeas1E=i2h>ZlxvQEWl}hbk z-%(*BhZ3BnDC(8eCLWJpHX4l&Bm`eo6Qt8=2FfK&KWDSqsNBY8vk{?Cs0yIHo za{7TFbYjDZSh^;xvzSx8UTZK(MK^D+nqgKIdQFT|fY7!0nIN~MRIGnhw!=$FyHyVz{xjr#rm$#S{; zZebS@gZl{N>cUEd14!cHIw;QhyT9FT z?`tI(L$?u`NB5rsAFrWKfnWs$l$_u_B0Isd?2UXrzopfAEEYRsGMSzsgC1J=5L$Ws z7Xcpf3?6d6*Nrf0N}fP9mmS|-ULGUBYY6b3Jb>wK%9B_umJLAuO(iuXz+zD2@pz+9 dC_GX!_yw%Ew5SXYr(^&C002ovPDHLkV1krcRs;Y5 literal 0 HcmV?d00001 diff --git a/quarantine.php b/quarantine.php new file mode 100644 index 0000000..be89417 --- /dev/null +++ b/quarantine.php @@ -0,0 +1,93 @@ +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 "

$error

"; + echo 'Return'; + 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'); + } + +?> + diff --git a/show_headers.php b/show_headers.php new file mode 100644 index 0000000..0c0197c --- /dev/null +++ b/show_headers.php @@ -0,0 +1,59 @@ +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 = ''; + foreach ($headers as $header => $value) { + if (is_array($value)) { + $text = ''; + foreach ($value as $val) { + if ($text == '') { + $text = $val; + } else { + $text .= "

$val"; + } + } + } else { + $text = $value; + } + $output .= ""; + } + $output .= '
HeaderValue
$header$text
'; + echo ''; + echo ''; + echo ''; + echo '
'; + echo $output; + echo $util->getFooter(); + } else if ($loggedIn) { + header('Location: index.php'); + } else { + header('Location: auth.php'); + } + +?> -- 2.39.2