mirror of
https://github.com/cytopia/devilbox.git
synced 2025-02-20 17:33:05 +00:00
Fix #5 - Adding postfix catchall functionality
This commit is contained in:
parent
9dba9a3d31
commit
8e2a4b7b78
@ -26,10 +26,15 @@ $MYSQL_HOST_NAME = 'db';
|
||||
$MYSQL_HOST_ADDR = gethostbyname($MYSQL_HOST_NAME);
|
||||
$MYSQL_ROOT_PASS = $ENV['MYSQL_ROOT_PASSWORD'];
|
||||
|
||||
|
||||
// MySQL Connection variables
|
||||
$MY_MYSQL_ERR = NULL;
|
||||
$MY_MYSQL_LINK = NULL;
|
||||
|
||||
// VirtualHost DNS check
|
||||
// Temporarily disable due to:
|
||||
// https://github.com/cytopia/devilbox/issues/8
|
||||
$ENABLE_VHOST_DNS_CHECK = FALSE;
|
||||
|
||||
|
||||
require $MY_DIR . DIRECTORY_SEPARATOR . 'include' . DIRECTORY_SEPARATOR .'functions.php';
|
||||
|
||||
|
@ -105,3 +105,10 @@ nav.navbar {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* mailphp;
|
||||
-------------------------------------------------- */
|
||||
tr.subject {
|
||||
cursor: pointer;
|
||||
}
|
@ -166,6 +166,10 @@
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>Postfix</th>
|
||||
<td><?php echo $ENV['ENABLE_MAIL'] ? '<span class="bg-success">OK</span> Enabled' : '<span class="bg-danger">No</span> Disabled';?></td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
|
144
.devilbox/www/htdocs/mail.php
Normal file
144
.devilbox/www/htdocs/mail.php
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
require '../config.php';
|
||||
|
||||
if (isset($_GET['email']) && isset($_GET['subject']) && isset($_GET['message'])) {
|
||||
$mail = $_GET['email'];
|
||||
$subj = $_GET['subject'];
|
||||
$mess = $_GET['message'];
|
||||
mail($mail, $subj, $mess);
|
||||
header('Location: /mail.php');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
require '../include/vendor/Mail/Mbox.php';
|
||||
require '../include/vendor/Mail/mimeDecode.php';
|
||||
|
||||
$params['include_bodies'] = true;
|
||||
$params['decode_bodies'] = true;
|
||||
$params['decode_headers'] = true;
|
||||
$params['crlf'] = "\r\n";
|
||||
|
||||
$mbox = new Mail_Mbox('/var/mail/mailtrap');
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<?php require '../include/head.php'; ?>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<?php require '../include/navigation.php'; ?>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<h1>Mail</h1>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Send test Email</h3>
|
||||
<br/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
||||
<form class="form-inline">
|
||||
<div class="form-group">
|
||||
<label class="sr-only" for="exampleInputEmail1">Email to</label>
|
||||
<input name="email" type="email" class="form-control" id="exampleInputEmail1" placeholder="Enter to email">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="sr-only" for="exampleInputEmail2">Subject</label>
|
||||
<input name="subject" type="text" class="form-control" id="exampleInputEmail2" placeholder="Subject">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="sr-only" for="exampleInputEmail3">Message</label>
|
||||
<input name="message" type="text" class="form-control" id="exampleInputEmail3" placeholder="Message">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Send Email</button>
|
||||
</form>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Received Emails</h3>
|
||||
<br/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
||||
<?php $mbox->open(); ?>
|
||||
<table class="table table-striped table-hover">
|
||||
<thead class="thead-inverse">
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th style="word-break: normal;">Date</th>
|
||||
<th>To</th>
|
||||
<th>Subject</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php for ($n = ($mbox->size()-1); $n >= 0; $n--): ?>
|
||||
<?php
|
||||
$message = $mbox->get($n);
|
||||
$decode = new Mail_mimeDecode($message, "\r\n");
|
||||
$structure = $decode->decode($params);
|
||||
?>
|
||||
<tr id="<?php echo $n;?>" class="subject">
|
||||
<td><?php echo $n;?></td>
|
||||
<td>
|
||||
<?php echo date('H:i', strtotime($structure->headers['date']));?><br/>
|
||||
<small><?php echo date('Y-m-d', strtotime($structure->headers['date']));?></small>
|
||||
</td>
|
||||
<td><?php echo $structure->headers['x-original-to'];?></td>
|
||||
<td><?php echo $structure->headers['subject'];?></td>
|
||||
</tr>
|
||||
<tr></tr>
|
||||
<tr id="mail-<?php echo $n;?>" style="display:none">
|
||||
<td></td>
|
||||
<td colspan="3">
|
||||
<pre><?php echo $message;?></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endfor; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php $mbox->close(); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div><!-- /.container -->
|
||||
|
||||
<?php require '../include/footer.php'; ?>
|
||||
<script>
|
||||
$(function() {
|
||||
$('.subject').each(function() {
|
||||
$(this).click(function() {
|
||||
var id = ($(this).attr('id'));
|
||||
$('#mail-'+id).toggle();
|
||||
|
||||
})
|
||||
})
|
||||
// Handler for .ready() called.
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -9,6 +9,8 @@
|
||||
|
||||
<?php if ($GLOBALS['MY_MYSQL_LINK']) { my_mysqli_close($GLOBALS['MY_MYSQL_LINK']); } ?>
|
||||
|
||||
<script src="/vendor/jquery/jquery.min.js"></script>
|
||||
|
||||
<?php /*
|
||||
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
||||
<script src="/vendor/jquery/jquery.min.js"></script>
|
||||
|
@ -327,33 +327,31 @@ function checkVirtualHost($vhost)
|
||||
$error[] = 'Missing <strong>htdocs</strong> directory in: <strong>'.$ENV['HOST_PATH_TO_WWW_DOCROOTS'].'/'.$vhost.'/</strong>';
|
||||
}
|
||||
|
||||
// Temporarily comment out due to:
|
||||
// https://github.com/cytopia/devilbox/issues/8
|
||||
//
|
||||
if ($GLOBALS['ENABLE_VHOST_DNS_CHECK']) {
|
||||
|
||||
// 2. Check /etc/resolv DNS entry
|
||||
$output;
|
||||
if (my_exec('getent hosts '.$domain, $output) !== 0) {
|
||||
$error[] = 'Missing entry in <strong>/etc/hosts</strong>:<br/><code>127.0.0.1 '.$domain.'</code>';
|
||||
}
|
||||
|
||||
|
||||
// 2. Check /etc/resolv DNS entry
|
||||
//$output;
|
||||
//if (my_exec('getent hosts '.$domain, $output) !== 0) {
|
||||
// $error[] = 'Missing entry in <strong>/etc/hosts</strong>:<br/><code>127.0.0.1 '.$domain.'</code>';
|
||||
//}
|
||||
|
||||
|
||||
// 3. Check correct /etc/resolv entry
|
||||
//$dns_ip = '127.0.0.1';
|
||||
//if (isset($output[0])) {
|
||||
// $tmp = explode(' ', $output[0]);
|
||||
// if (isset($tmp[0])) {
|
||||
// $dns_ip = $tmp[0];
|
||||
// }
|
||||
//}
|
||||
//if ($dns_ip != '127.0.0.1') {
|
||||
// $error[] = 'Error in <strong>/etc/hosts</strong><br/>'.
|
||||
// 'Found:<br/>'.
|
||||
// '<code>'.$dns_ip.' '.$domain.'</code><br/>'.
|
||||
// 'But it should be:<br/>'.
|
||||
// '<code>127.0.0.1 '.$domain.'</code><br/>';
|
||||
//}
|
||||
// 3. Check correct /etc/resolv entry
|
||||
$dns_ip = '127.0.0.1';
|
||||
if (isset($output[0])) {
|
||||
$tmp = explode(' ', $output[0]);
|
||||
if (isset($tmp[0])) {
|
||||
$dns_ip = $tmp[0];
|
||||
}
|
||||
}
|
||||
if ($dns_ip != '127.0.0.1') {
|
||||
$error[] = 'Error in <strong>/etc/hosts</strong><br/>'.
|
||||
'Found:<br/>'.
|
||||
'<code>'.$dns_ip.' '.$domain.'</code><br/>'.
|
||||
'But it should be:<br/>'.
|
||||
'<code>127.0.0.1 '.$domain.'</code><br/>';
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($error) && count($error)) {
|
||||
return implode('<br/>', $error);
|
||||
|
@ -24,6 +24,13 @@
|
||||
<a class="nav-link" href="<?php echo $file == $current ? '#' : '/'.$file;?>"><?php echo $name;?><?php echo $file == $current ? ' <span class="sr-only">(current)</span>' : '';?></a>
|
||||
</li>
|
||||
|
||||
|
||||
<?php $file = 'mail.php'; $name = 'Mail';?>
|
||||
<li class="nav-item <?php echo $file == $current ? 'active' : '';?>">
|
||||
<a class="nav-link" href="<?php echo $file == $current ? '#' : '/'.$file;?>"><?php echo $name;?><?php echo $file == $current ? ' <span class="sr-only">(current)</span>' : '';?></a>
|
||||
</li>
|
||||
|
||||
|
||||
<?php $file = 'phpinfo.php'; $name = 'PHP info';?>
|
||||
<li class="nav-item <?php echo $file == $current ? 'active' : '';?>">
|
||||
<a class="nav-link" href="<?php echo $file == $current ? '#' : '/'.$file;?>"><?php echo $name;?><?php echo $file == $current ? ' <span class="sr-only">(current)</span>' : '';?></a>
|
||||
|
902
.devilbox/www/include/vendor/Mail/Mbox.php
vendored
Normal file
902
.devilbox/www/include/vendor/Mail/Mbox.php
vendored
Normal file
@ -0,0 +1,902 @@
|
||||
<?php
|
||||
/**
|
||||
* Class to read mbox mail files.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* @category Mail
|
||||
* @package Mail_Mbox
|
||||
* @author Roberto Berto <darkelder@php.net>
|
||||
* @author Christian Weiske <cweiske@php.net>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
|
||||
* @version CVS: $Id: Mbox.php 290486 2009-11-10 20:42:51Z cweiske $
|
||||
* @link http://pear.php.net/package/Mail_Mbox
|
||||
*/
|
||||
require_once 'PEAR.php';
|
||||
|
||||
/**
|
||||
* The file has been modified since it has been opened.
|
||||
* You should close and re-open it.
|
||||
*/
|
||||
define('MAIL_MBOX_ERROR_MODIFIED', 2101);
|
||||
|
||||
/**
|
||||
* The mail mbox file doesn't exist.
|
||||
*/
|
||||
define('MAIL_MBOX_ERROR_FILE_NOT_EXISTING', 2102);
|
||||
|
||||
/**
|
||||
* There is no message with the given number.
|
||||
*/
|
||||
define('MAIL_MBOX_ERROR_MESSAGE_NOT_EXISTING', 2103);
|
||||
|
||||
/**
|
||||
* No permission to access the file.
|
||||
*/
|
||||
define('MAIL_MBOX_ERROR_NO_PERMISSION', 2104);
|
||||
|
||||
/**
|
||||
* The file cannot be opened.
|
||||
*/
|
||||
define('MAIL_MBOX_ERROR_CANNOT_OPEN', 2105);
|
||||
|
||||
/**
|
||||
* The file cannot be closed due to some strange things.
|
||||
*/
|
||||
define('MAIL_MBOX_ERROR_CANNOT_CLOSE', 2106);
|
||||
|
||||
/**
|
||||
* The file cannot be read.
|
||||
*/
|
||||
define('MAIL_MBOX_ERROR_CANNOT_READ', 2107);
|
||||
|
||||
/**
|
||||
* Failed to create a temporary file.
|
||||
*/
|
||||
define('MAIL_MBOX_ERROR_CANNOT_CREATE_TMP', 2108);
|
||||
|
||||
/**
|
||||
* The file cannot be written.
|
||||
*/
|
||||
define('MAIL_MBOX_ERROR_CANNOT_WRITE', 2109);
|
||||
|
||||
/**
|
||||
* The file is not open.
|
||||
*/
|
||||
define('MAIL_MBOX_ERROR_NOT_OPEN', 2110);
|
||||
|
||||
/**
|
||||
* The resource isn't valid anymore.
|
||||
*/
|
||||
define('MAIL_MBOX_ERROR_NO_RESOURCE', 2111);
|
||||
|
||||
/**
|
||||
* Message is invalid and would trash the file
|
||||
*/
|
||||
define('MAIL_MBOX_ERROR_MSG_INVALID', 2112);
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class to read mbox mail files.
|
||||
*
|
||||
* An mbox mail file is contains plain emails concatenated in one
|
||||
* big file. Since each mail starts with "From ", and ends with a newline,
|
||||
* they can be separated from each other.
|
||||
*
|
||||
* This class takes a mbox filename in the constructor, generates an
|
||||
* index where the mails start and end when calling open() and returns
|
||||
* single mails with get(), using the positions in the index.
|
||||
*
|
||||
* With the help of this class, you also can add(), remove() and update()
|
||||
* messages in the mbox file. When calling one of this methods, the class
|
||||
* checks if the file has been modified since the index was created -
|
||||
* changing the file with the wrong positions in the index would very likely
|
||||
* corrupt it.
|
||||
* This check is not done when retrieving single messages via get(), as this
|
||||
* would slow down the process if you retrieve thousands of mails. You can,
|
||||
* however, call hasBeenModified() before using get() to check for modification
|
||||
* yourself. If the method returns true, you should close() and re-open() the
|
||||
* file.
|
||||
*
|
||||
* If something strange happens and you don't know why, activate debugging with
|
||||
* setDebug(true). You also can modify the temporary directory in which changed
|
||||
* mboxes are stored when adding/removing/modifying by using setTmpDir('/path/');
|
||||
*
|
||||
* See @link tags for specifications.
|
||||
*
|
||||
* @category Mail
|
||||
* @package Mail_Mbox
|
||||
* @author Roberto Berto <darkelder@php.net>
|
||||
* @author Christian Weiske <cweiske@php.net>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
|
||||
* @link http://pear.php.net/package/Mail_Mbox
|
||||
* @link http://en.wikipedia.org/wiki/Mbox
|
||||
* @link http://www.qmail.org/man/man5/mbox.html
|
||||
*/
|
||||
class Mail_Mbox extends PEAR
|
||||
{
|
||||
/**
|
||||
* File resource / handle
|
||||
*
|
||||
* @var resource
|
||||
* @access protected
|
||||
*/
|
||||
var $_resource = null;
|
||||
|
||||
/**
|
||||
* Message index. Each mail has its own subarray,
|
||||
* which contains the start position and end position
|
||||
* as first and second subindex.
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $_index = null;
|
||||
|
||||
/**
|
||||
* Timestamp at which the file has been modified last.
|
||||
*
|
||||
* @var int
|
||||
* @access protected
|
||||
*/
|
||||
var $_lastModified = null;
|
||||
|
||||
/**
|
||||
* Debug mode
|
||||
*
|
||||
* Set to true to turn on debug mode.
|
||||
*
|
||||
* @var bool
|
||||
* @access public
|
||||
* @see setDebug()
|
||||
* @see getDebug()
|
||||
*/
|
||||
var $debug = false;
|
||||
|
||||
/**
|
||||
* Directory in which the temporary mbox files are created.
|
||||
* Even if it's a unix directory, it does work on windows as
|
||||
* the only function it's used in is tempnam which automatically
|
||||
* chooses the right temp directory if this here doesn't exist.
|
||||
* So this variable is for special needs only.
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
* @see getTmpDir()
|
||||
* @see setTmpDir()
|
||||
*/
|
||||
var $tmpdir = '/tmp';
|
||||
|
||||
/**
|
||||
* Determines if the file is automatically re-opened and its
|
||||
* structure is parsed after modifying it. Setting this to false
|
||||
* makes you responsible for calling open() by hand, but is
|
||||
* *a lot* faster when appending many messages.
|
||||
*
|
||||
* @var bool
|
||||
* @access public
|
||||
*/
|
||||
var $autoReopen = true;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new Mbox class instance.
|
||||
* After creating it, you should use open().
|
||||
*
|
||||
* @param string $file Filename to open.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function Mail_Mbox($file)
|
||||
{
|
||||
$this->_file = $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the mbox file
|
||||
*
|
||||
* Also, this function will process the Mbox and create a cache
|
||||
* that tells each message start and end bytes.
|
||||
*
|
||||
* @return boolean|PEAR_Error True if all went ok, PEAR_Error on failure
|
||||
* @access public
|
||||
*/
|
||||
function open($create = false)
|
||||
{
|
||||
// check if file exists else return pear error
|
||||
if (!is_file($this->_file)) {
|
||||
if ($create) {
|
||||
$ret = $this->_create();
|
||||
if (PEAR::isError($ret)) {
|
||||
return $ret;
|
||||
}
|
||||
} else {
|
||||
return PEAR::raiseError(
|
||||
'Cannot open the mbox file "'
|
||||
. $this->_file . '": file does not exist.',
|
||||
MAIL_MBOX_ERROR_FILE_NOT_EXISTING
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// opening the file
|
||||
$this->_lastModified = filemtime($this->_file);
|
||||
$this->_resource = fopen($this->_file, 'r');
|
||||
if (!is_resource($this->_resource)) {
|
||||
return PEAR::raiseError(
|
||||
'Cannot open the mbox file: maybe without permission.',
|
||||
MAIL_MBOX_ERROR_NO_PERMISSION
|
||||
);
|
||||
}
|
||||
|
||||
// process the file and get the messages bytes offsets
|
||||
$this->_process();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the file
|
||||
*
|
||||
* @return boolean True if it was created, false if it already
|
||||
* existed. PEAR_Error in case it could not
|
||||
* be created.
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
function _create()
|
||||
{
|
||||
if (is_file($this->_file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//We should maybe try to check if the directory
|
||||
// is writable here. But that's too much fuss for now.
|
||||
touch($this->_file);
|
||||
|
||||
if (is_file($this->_file)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//error
|
||||
return PEAR::raiseError(
|
||||
'File could not be created',
|
||||
MAIL_MBOX_ERROR_CANNOT_WRITE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-opens the file and parses the messages again.
|
||||
* Used by other methods to be able to be able to prevent
|
||||
* re-opening the file.
|
||||
*
|
||||
* @return mixed See open() for return values. Returns true if
|
||||
* $this->autoReopen is false.
|
||||
* @access protected
|
||||
*/
|
||||
function _reopen()
|
||||
{
|
||||
if ($this->autoReopen) {
|
||||
return $this->open();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a Mbox
|
||||
*
|
||||
* Close the Mbox file opened by open()
|
||||
*
|
||||
* @return mixed true on success, else PEAR_Error
|
||||
* @access public
|
||||
*/
|
||||
function close()
|
||||
{
|
||||
if (!is_resource($this->_resource)) {
|
||||
return PEAR::raiseError(
|
||||
'Cannot close the mbox file because it was not open.',
|
||||
MAIL_MBOX_ERROR_NOT_OPEN
|
||||
);
|
||||
}
|
||||
|
||||
if (!fclose($this->_resource)) {
|
||||
return PEAR::raiseError(
|
||||
'Cannot close the mbox, maybe file is being used (?)',
|
||||
MAIL_MBOX_ERROR_CANNOT_CLOSE
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of messages in this mbox
|
||||
*
|
||||
* @return int Number of messages on Mbox (starting on 1,
|
||||
* 0 if no message exists)
|
||||
* @access public
|
||||
*/
|
||||
function size()
|
||||
{
|
||||
if ($this->_index !== null) {
|
||||
return sizeof($this->_index);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a message from the mbox
|
||||
*
|
||||
* Note: Message numbers start from 0.
|
||||
*
|
||||
* @param int $message The number of the message to retrieve
|
||||
*
|
||||
* @return string Return the message, PEAR_Error on error
|
||||
* @access public
|
||||
*/
|
||||
function get($message)
|
||||
{
|
||||
// checking if we have bytes locations for this message
|
||||
if (!is_array($this->_index[$message])) {
|
||||
return PEAR::raiseError(
|
||||
'Message does not exist.',
|
||||
MAIL_MBOX_ERROR_MESSAGE_NOT_EXISTING
|
||||
);
|
||||
}
|
||||
|
||||
// getting bytes locations
|
||||
$bytesStart = $this->_index[$message][0];
|
||||
$bytesEnd = $this->_index[$message][1];
|
||||
|
||||
// a debug feature to show the bytes locations
|
||||
if ($this->debug) {
|
||||
printf("%08d=%08d<br />", $bytesStart, $bytesEnd);
|
||||
}
|
||||
|
||||
if (!is_resource($this->_resource)) {
|
||||
return PEAR::raiseError(
|
||||
'Mbox resource is not valid. Maybe you need to re-open it?',
|
||||
MAIL_MBOX_ERROR_NO_RESOURCE
|
||||
);
|
||||
}
|
||||
|
||||
// seek to start of message
|
||||
if (fseek($this->_resource, $bytesStart) == -1) {
|
||||
return PEAR::raiseError(
|
||||
'Cannot read message bytes',
|
||||
MAIL_MBOX_ERROR_CANNOT_READ
|
||||
);
|
||||
}
|
||||
|
||||
if ($bytesEnd - $bytesStart <= 0) {
|
||||
return PEAR::raiseError(
|
||||
'Message byte length is negative',
|
||||
MAIL_MBOX_ERROR_CANNOT_READ
|
||||
);
|
||||
}
|
||||
|
||||
// reading and returning message
|
||||
// (bytes to read = difference of bytes locations)
|
||||
$msg = fread($this->_resource, $bytesEnd - $bytesStart);
|
||||
return $this->_unescapeMessage($msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a message from Mbox and save it.
|
||||
*
|
||||
* Note: messages start with 0.
|
||||
*
|
||||
* @param int $message The number of the message to remove, or
|
||||
* array of message ids to remove
|
||||
*
|
||||
* @return mixed Return true else PEAR_Error
|
||||
* @access public
|
||||
*/
|
||||
function remove($message)
|
||||
{
|
||||
if ($this->hasBeenModified()) {
|
||||
return PEAR::raiseError(
|
||||
'File has been modified since loading. Re-open the file.',
|
||||
MAIL_MBOX_ERROR_MODIFIED
|
||||
);
|
||||
}
|
||||
|
||||
// convert single message to array
|
||||
if (!is_array($message)) {
|
||||
$message = array($message);
|
||||
}
|
||||
|
||||
// checking if we have bytes locations for this message
|
||||
foreach ($message as $msg) {
|
||||
if (!isset($this->_index[$msg])
|
||||
|| !is_array($this->_index[$msg])
|
||||
) {
|
||||
return PEAR::raiseError(
|
||||
'Message ' . $msg . 'does not exist.',
|
||||
MAIL_MBOX_ERROR_MESSAGE_NOT_EXISTING
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// changing umask for security reasons
|
||||
$umaskOld = umask(077);
|
||||
// creating temp file
|
||||
$ftempname = tempnam($this->tmpdir, 'Mail_Mbox');
|
||||
// returning to old umask
|
||||
umask($umaskOld);
|
||||
|
||||
$ftemp = fopen($ftempname, 'w');
|
||||
if ($ftemp === false) {
|
||||
return PEAR::raiseError(
|
||||
'Cannot create a temp file "' . $ftempname . '".',
|
||||
MAIL_MBOX_ERROR_CANNOT_CREATE_TMP
|
||||
);
|
||||
}
|
||||
|
||||
// writing only undeleted messages
|
||||
$messages = $this->size();
|
||||
|
||||
for ($x = 0; $x < $messages; $x++) {
|
||||
if (in_array($x, $message)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$messageThis = $this->_escapeMessage($this->get($x));
|
||||
if (is_string($messageThis)) {
|
||||
fwrite($ftemp, $messageThis, strlen($messageThis));
|
||||
}
|
||||
}
|
||||
|
||||
// closing file
|
||||
$this->close();
|
||||
fclose($ftemp);
|
||||
|
||||
return $this->_move($ftempname, $this->_file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a message
|
||||
*
|
||||
* Note: messages start with 0.
|
||||
*
|
||||
* @param int $message The number of Message to update
|
||||
* @param string $content The new content of the Message
|
||||
*
|
||||
* @return mixed Return true if all is ok, else PEAR_Error
|
||||
* @access public
|
||||
*/
|
||||
function update($message, $content)
|
||||
{
|
||||
if (!$this->_isValid($content)) {
|
||||
return PEAR::raiseError(
|
||||
'Message is invalid', MAIL_MBOX_ERROR_MSG_INVALID
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->hasBeenModified()) {
|
||||
return PEAR::raiseError(
|
||||
'File has been modified since loading. Re-open the file.',
|
||||
MAIL_MBOX_ERROR_MODIFIED
|
||||
);
|
||||
}
|
||||
|
||||
// checking if we have bytes locations for this message
|
||||
if (!is_array($this->_index[$message])) {
|
||||
return PEAR::raiseError(
|
||||
'Message does not exist.',
|
||||
MAIL_MBOX_ERROR_MESSAGE_NOT_EXISTING
|
||||
);
|
||||
}
|
||||
|
||||
// creating temp file
|
||||
$ftempname = tempnam($this->tmpdir, 'Mail_Mbox');
|
||||
$ftemp = fopen($ftempname, 'w');
|
||||
if ($ftemp === false) {
|
||||
return PEAR::raiseError(
|
||||
'Cannot create temp file "' . $ftempname . '" .',
|
||||
MAIL_MBOX_ERROR_CANNOT_CREATE_TMP
|
||||
);
|
||||
}
|
||||
|
||||
$messages = $this->size();
|
||||
|
||||
for ($x = 0; $x < $messages; $x++) {
|
||||
if ($x == $message) {
|
||||
$messageThis = $content;
|
||||
} else {
|
||||
$messageThis = $this->get($x);
|
||||
}
|
||||
|
||||
if (is_string($messageThis)) {
|
||||
$messageThis = $this->_escapeMessage($messageThis);
|
||||
fwrite($ftemp, $messageThis, strlen($messageThis));
|
||||
}
|
||||
}
|
||||
|
||||
// closing file
|
||||
$this->close();
|
||||
fclose($ftemp);
|
||||
|
||||
return $this->_move($ftempname, $this->_file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a message
|
||||
*
|
||||
* PEAR::Mail_Mbox will insert the message according its offset.
|
||||
* 0 means before the actual message 0. 3 means before the message 3
|
||||
* (Remember: message 3 is the fourth message). The default is put
|
||||
* AFTER the last message (offset = null).
|
||||
*
|
||||
* @param string $content The content of the new message
|
||||
* @param int $offset Before the offset. Default: last message (null)
|
||||
*
|
||||
* @return mixed Return true else PEAR_Error object
|
||||
* @access public
|
||||
*/
|
||||
function insert($content, $offset = null)
|
||||
{
|
||||
if (!$this->_isValid($content)) {
|
||||
return PEAR::raiseError(
|
||||
'Message is invalid', MAIL_MBOX_ERROR_MSG_INVALID
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->hasBeenModified()) {
|
||||
return PEAR::raiseError(
|
||||
'File has been modified since loading. Re-open the file.',
|
||||
MAIL_MBOX_ERROR_MODIFIED
|
||||
);
|
||||
}
|
||||
|
||||
// optimize insert() to use append whenever possible
|
||||
if ($offset < 0 || $offset == $this->size() || $this->size() == 0) {
|
||||
return $this->append($content);
|
||||
}
|
||||
|
||||
// creating temp file
|
||||
$ftempname = tempnam($this->tmpdir, 'Mail_Mbox');
|
||||
$ftemp = fopen($ftempname, 'w');
|
||||
if ($ftemp === false) {
|
||||
return PEAR::raiseError(
|
||||
'Cannot create temp file "' . $ftempname . '".',
|
||||
MAIL_MBOX_ERROR_CANNOT_CREATE_TMP
|
||||
);
|
||||
}
|
||||
|
||||
// writing only undeleted messages
|
||||
$messages = $this->size();
|
||||
$content = $this->_escapeMessage($content);
|
||||
|
||||
if ($messages == 0 && $offset !== null) {
|
||||
fwrite($ftemp, $content, strlen($content));
|
||||
} else {
|
||||
for ($x = 0; $x < $messages; $x++) {
|
||||
if ($offset !== null && $x == $offset) {
|
||||
fwrite($ftemp, $content, strlen($content));
|
||||
}
|
||||
$messageThis = $this->_escapeMessage($this->get($x));
|
||||
|
||||
if (is_string($messageThis)) {
|
||||
fwrite($ftemp, $messageThis, strlen($messageThis));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($offset === null) {
|
||||
fwrite($ftemp, $content, strlen($content));
|
||||
}
|
||||
|
||||
// closing file
|
||||
$this->close();
|
||||
fclose($ftemp);
|
||||
|
||||
return $this->_move($ftempname, $this->_file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a message at the end of the file.
|
||||
*
|
||||
* This method is also used by insert() since it's faster.
|
||||
*
|
||||
* @param string $content The content of the new message
|
||||
*
|
||||
* @return mixed Return true else PEAR_Error object
|
||||
* @access public
|
||||
*/
|
||||
function append($content)
|
||||
{
|
||||
if (!$this->_isValid($content)) {
|
||||
return PEAR::raiseError(
|
||||
'Message is invalid', MAIL_MBOX_ERROR_MSG_INVALID
|
||||
);
|
||||
}
|
||||
|
||||
$this->close();
|
||||
$content = $this->_escapeMessage($content);
|
||||
|
||||
$fp = fopen($this->_file, 'a');
|
||||
if ($fp === false) {
|
||||
return PEAR::raiseError(
|
||||
'Cannot open file "' . $this->_file . '" for appending.',
|
||||
MAIL_MBOX_ERROR_CANNOT_OPEN
|
||||
);
|
||||
}
|
||||
|
||||
if (fwrite($fp, $content, strlen($content)) === false) {
|
||||
return PEAR::raiseError(
|
||||
'Cannot write to file "' . $this->_file. '".',
|
||||
MAIL_MBOX_ERROR_CANNOT_WRITE
|
||||
);
|
||||
}
|
||||
|
||||
return $this->_reopen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given message is valid.
|
||||
* If it was invalid and we'd add it to the file,
|
||||
* it would get unreadable
|
||||
*
|
||||
* @param string $content Message to be added or updated
|
||||
*
|
||||
* @return boolean True if it is valid, false if not
|
||||
*/
|
||||
function _isValid($content)
|
||||
{
|
||||
if (substr($content, 0, 5) != 'From ') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a file to another.
|
||||
*
|
||||
* Used internally to move the content of the temp file to the mbox file.
|
||||
* Note that we can't use rename() internally, as it behaves very, very
|
||||
* strange on windows.
|
||||
*
|
||||
* @param string $ftempname Source file - will be removed
|
||||
* @param string $filename Output file
|
||||
*
|
||||
* @return boolean|PEAR_Error True if everything went fine, PEAR_Error when
|
||||
* an error happened.
|
||||
* @access protected
|
||||
*/
|
||||
function _move($ftempname, $filename)
|
||||
{
|
||||
if (!copy($ftempname, $filename)) {
|
||||
return PEAR::raiseError(
|
||||
'Cannot copy "' . $ftempname . '" to "' . $filename . '".',
|
||||
MAIL_MBOX_ERROR_CANNOT_WRITE
|
||||
);
|
||||
}
|
||||
|
||||
unlink($ftempname);
|
||||
|
||||
// open another resource and substitute it to the old one
|
||||
$this->_file = $filename;
|
||||
return $this->_reopen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the Mbox
|
||||
*
|
||||
* Put start bytes and end bytes of each message into _index array
|
||||
*
|
||||
* @return boolean|PEAR_Error True if all went ok, PEAR_Error on failure
|
||||
* @access protected
|
||||
*/
|
||||
function _process()
|
||||
{
|
||||
$this->_index = array();
|
||||
|
||||
// sanity check
|
||||
if (!is_resource($this->_resource)) {
|
||||
return PEAR::raiseError(
|
||||
'Resource is not valid. Maybe the file has not be opened?',
|
||||
MAIL_MBOX_ERROR_NOT_OPEN
|
||||
);
|
||||
}
|
||||
|
||||
// going to start
|
||||
if (fseek($this->_resource, 0) == -1) {
|
||||
return PEAR::raiseError(
|
||||
'Cannot read mbox',
|
||||
MAIL_MBOX_ERROR_CANNOT_READ
|
||||
);
|
||||
}
|
||||
|
||||
// current start byte position
|
||||
$start = 0;
|
||||
// last start byte position
|
||||
$laststart = 0;
|
||||
// there aren't any message
|
||||
$hasmessage = false;
|
||||
|
||||
while ($line = fgets($this->_resource, 4096)) {
|
||||
// if line start with "From ", it is a new message
|
||||
if (0 === strncmp($line, 'From ', 5)) {
|
||||
// save last start byte position
|
||||
$laststart = $start;
|
||||
|
||||
// new start byte position is the start of the line
|
||||
$start = ftell($this->_resource) - strlen($line);
|
||||
|
||||
// if it is not the first message add message positions
|
||||
if ($start > 0) {
|
||||
$this->_index[] = array($laststart, $start - 1);
|
||||
} else {
|
||||
// tell that there is really a message on the file
|
||||
$hasmessage = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there are just one message, or if it's the last one,
|
||||
// add it to messages positions
|
||||
if (($start == 0 && $hasmessage === true) || ($start > 0)) {
|
||||
$this->_index[] = array($start, ftell($this->_resource));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quotes "From " lines in the midst of the message.
|
||||
* And quoted "From " lines, too :)
|
||||
* Also appends the trailing newline.
|
||||
* After escaping, the message can be written to file.
|
||||
*
|
||||
* @param string $message Message content
|
||||
*
|
||||
* @return string Escaped message
|
||||
*
|
||||
* @access protected
|
||||
* @see _unescapeMessage()
|
||||
*/
|
||||
function _escapeMessage($message)
|
||||
{
|
||||
if (substr($message, -1) == "\n") {
|
||||
$message .= "\n";
|
||||
} else {
|
||||
$message .= "\n\n";
|
||||
}
|
||||
return preg_replace(
|
||||
"/\n([>]*From )/",
|
||||
"\n>$1",
|
||||
$message
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes quoted "From " lines from the message
|
||||
*
|
||||
* @param string $message Message content
|
||||
*
|
||||
* @return string Unescaped message
|
||||
*
|
||||
* @access protected
|
||||
* @see _escapeMessage()
|
||||
*/
|
||||
function _unescapeMessage($message)
|
||||
{
|
||||
return preg_replace(
|
||||
"/\n>([>]*From )/",
|
||||
"\n$1",
|
||||
//the -1 drops the last newline
|
||||
substr($message, 0, -1)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the file was modified since it has been loaded.
|
||||
* If this is true, the file needs to be re-opened.
|
||||
*
|
||||
* @return bool True if it has been modified.
|
||||
* @access public
|
||||
*/
|
||||
function hasBeenModified()
|
||||
{
|
||||
return filemtime($this->_file) > $this->_lastModified;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Dumb getter and setter
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the directory for temporary files.
|
||||
*
|
||||
* @param string $tmpdir The new temporary directory
|
||||
*
|
||||
* @return mixed True if all is ok, PEAR_Error if $tmpdir
|
||||
* is a dir but not writable
|
||||
*
|
||||
* @see Mail_Mbox::$tmpdir
|
||||
*/
|
||||
function setTmpDir($tmpdir)
|
||||
{
|
||||
if (is_dir($tmpdir) && !is_writable($tmpdir)) {
|
||||
return PEAR::raiseError(
|
||||
'"' . $tmpdir . '" is not writable.',
|
||||
MAIL_MBOX_ERROR_CANNOT_WRITE
|
||||
);
|
||||
} else {
|
||||
$this->tmpdir = $tmpdir;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the temporary directory
|
||||
*
|
||||
* @return string The temporary directory
|
||||
*/
|
||||
function getTmpDir()
|
||||
{
|
||||
return $this->tmpdir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the debug flag
|
||||
*
|
||||
* @param bool $debug If debug is on or off
|
||||
*
|
||||
* @return void
|
||||
* @see Mail_Mbox::$debug
|
||||
*/
|
||||
function setDebug($debug)
|
||||
{
|
||||
$this->debug = (bool)$debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the debug flag setting
|
||||
*
|
||||
* @see Mail_Mbox::$debug
|
||||
*
|
||||
* @return bool If debug is enabled.
|
||||
*/
|
||||
function getDebug()
|
||||
{
|
||||
return $this->debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the mbox is reloaded after modification
|
||||
* automatically.
|
||||
*
|
||||
* @param bool $autoReopen If the mbox is reloaded automatically
|
||||
*
|
||||
* @return void
|
||||
* @see Mail_Mbox::$autoReopen
|
||||
*/
|
||||
function setAutoReopen($autoReopen)
|
||||
{
|
||||
$this->autoReopen = (bool)$autoReopen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the automatically reopening setting
|
||||
*
|
||||
* @return bool If the mbox is reloaded automatically.
|
||||
*
|
||||
* @see Mail_Mbox::$autoReopen
|
||||
*/
|
||||
function getAutoReopen()
|
||||
{
|
||||
return $this->autoReopen;
|
||||
}
|
||||
}
|
||||
?>
|
1080
.devilbox/www/include/vendor/Mail/mimeDecode.php
vendored
Executable file
1080
.devilbox/www/include/vendor/Mail/mimeDecode.php
vendored
Executable file
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@ Contributors will be credited within the intranet and on the github page.
|
||||
|
||||
## General
|
||||
|
||||
* [ ] Handle emails sent from PHP dockers [#5](https://github.com/cytopia/devilbox/issues/5)
|
||||
* [X] Handle emails sent from PHP dockers [#5](https://github.com/cytopia/devilbox/issues/5)
|
||||
1. Add another container which is able to display mails: https://github.com/sj26/mailcatcher
|
||||
2. Proxy this webinterface into the Intranet
|
||||
|
||||
@ -50,7 +50,7 @@ Contributors will be credited within the intranet and on the github page.
|
||||
|
||||
## Intranet
|
||||
|
||||
* [ ] View emails sent/received within PHP dockers
|
||||
* [X] View emails sent/received within PHP dockers
|
||||
* [ ] Better layout
|
||||
* [ ] Better logos
|
||||
* [ ] Try to remove as much vendor dependencies as possible
|
||||
|
19
README.md
19
README.md
@ -4,6 +4,8 @@
|
||||
|
||||
There is currently a huge annoyance with docker on OSX resulting in very slow file access, because of directory mounts. Read about the ticket here [Docker Forums #8076](https://forums.docker.com/t/file-access-in-mounted-volumes-extremely-slow-cpu-bound/8076).
|
||||
|
||||
**Latest feature:** `Email support...`
|
||||
|
||||
----
|
||||
|
||||
[Usage](https://github.com/cytopia/devilbox#usage) |
|
||||
@ -73,12 +75,13 @@ No need to install and configure different versions locally. Simply choose your
|
||||
|
||||
## Feature overview
|
||||
|
||||
* Dynamically Configured Mass Virtual Hosting
|
||||
* Configuration overwrites (`my.cnf`, `nginx.conf`, `httpd.conf` or `php.ini`)
|
||||
* Log files available on host computer
|
||||
* Dynamically Configured **Mass Virtual Hosting**
|
||||
* **Email** catch-all (Intercept and view all sent emails)
|
||||
* Configuration **overwrites** (`my.cnf`, `nginx.conf`, `httpd.conf` or `php.ini`)
|
||||
* **Log files** available on host computer
|
||||
* MySQL socket (available on host computer and PHP container)
|
||||
* MySQL connectivity (reachable from host computer and from PHP container via `127.0.0.1` and `localhost`)
|
||||
* Xdebug
|
||||
* **Xdebug**
|
||||
|
||||
|
||||
<!--
|
||||
@ -94,6 +97,7 @@ The devilbox comes with a pre-configured intranet on `http://localhost`
|
||||
|
||||
* Virtua lHost overview
|
||||
* Database overview
|
||||
* Email overview
|
||||
* PHP Info
|
||||
* MySQL Info
|
||||
* PHPMyAdmin
|
||||
@ -136,3 +140,10 @@ Virtual Hosts are considered valid if the following requirements are met (on the
|
||||
Shows you all the databases that are loaded
|
||||
|
||||

|
||||
|
||||
|
||||
**Email overview**
|
||||
|
||||
Shows you all the emails that have been sent. No email will actually be sent outside, but they are all catched by one account and presented here.
|
||||
|
||||

|
||||
|
BIN
doc/img/04_intranet_emails.png
Normal file
BIN
doc/img/04_intranet_emails.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 137 KiB |
@ -147,6 +147,7 @@ services:
|
||||
- HOST_PATH_TO_WWW_DOCROOTS=${HOST_PATH_TO_WWW_DOCROOTS}
|
||||
- HOST_PATH_TO_MYSQL_DATADIR=${HOST_PATH_TO_MYSQL_DATADIR}
|
||||
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
|
||||
- ENABLE_MAIL=1
|
||||
|
||||
networks:
|
||||
app_net:
|
||||
@ -166,6 +167,9 @@ services:
|
||||
# Mount MySQL Socket directory
|
||||
- ./run/mysql:/tmp/mysql
|
||||
|
||||
# Mount Mail directory
|
||||
- ./run/mail:/var/mail
|
||||
|
||||
# Mount devilbox user-defined *.ini files in order
|
||||
# to overwrite the default PHP configuration
|
||||
- ./cfg/${PHP_SERVER}:/etc/php-custom.d
|
||||
|
Loading…
x
Reference in New Issue
Block a user