Commit a922990e authored by Roman Mátyus's avatar Roman Mátyus
Browse files

v0.2

parent 3485f93f
......@@ -20,7 +20,8 @@ use Nette\Object,
* setup:
* - $tempDir(%appDir%/../temp/mails)
*
* @author Roman Mátyus
* @author Jan Drábek, Roman Mátyus
* @copyright (c) Jan Drábek 2013
* @copyright (c) Roman Mátyus 2013
* @license MIT
* @package FileMailer
......@@ -47,8 +48,10 @@ class FileMailer extends Object implements IMailer
{
$this->checkRequirements();
$content = $message->generateMessage();
$message_id = self::mailParser($content)->message_id;
$path = $this->tempDir."/".$this->prefix.$message_id;
preg_match('/Message-ID: <(?<message_id>\w+)@\w+>/', $content, $matches);
$path = $this->tempDir."/".$this->prefix.$matches['message_id'];
if ($bytes = file_put_contents($path, $content))
return $bytes;
else
......@@ -71,34 +74,56 @@ class FileMailer extends Object implements IMailer
throw new InvalidArgumentException("Directory '".$this->tempDir."' is not writeable.");
}
public function getPrefix()
{
return $this->prefix;
}
/**
* Parser of stored files.
* @param string $content
* @param string $filename
* @return StdClass
*/
public static function mailParser($content)
public static function mailParser($content, $filename = NULL)
{
preg_match("/Message-ID: <[a-zA-Z0-9-]*@[a-zA-Z0-9-]*>/", $content, $match);
$message_id = (isset($match[0])) ? substr($match[0], 13, -2) : NULL;
$message_id = explode("@",$message_id);
$message_id = $message_id[0];
$mess = explode("\r\n\r\n", $content);
preg_match_all("/[a-zA-Z-]*: .*/", $mess[0], $matches);
$header = array();
foreach ($matches[0] as $line) {
$temp = explode(": ",$line);
$header[strtolower($temp[0])] = iconv_mime_decode(str_replace(array("\r","\n","\r\n"),"",$temp[1]));
$header[strtolower($temp[0])] = iconv_mime_decode(Strings::trim($temp[1]));
}
if (isset($header["date"]))
$header["date"] = new DateTime($header["date"]);
if (preg_match("/\r\n\r\n----------/", $content)) { // html mail
$message_id = explode("@",$header['message-id']);
$message_id = substr($message_id[0], 1);
$attachments = array();
$mess = array(
"plain" => NULL,
"html" => NULL,
);
if (preg_match("/multipart\/mixed/", $content)) { // mail with attachments
foreach (explode("----------",$content) as $part) {
if (preg_match("/Content-Type: text\/plain; charset=UTF-8/", $part)) {
$tmp = explode("\r\n\r\n", $part);
$mess["plain"] = Strings::trim($tmp[1]);
} elseif (preg_match("/Content-Type: text\/html; charset=UTF-8/", $part)) {
$tmp = explode("\r\n\r\n", $part);
$mess["html"] = Strings::trim($tmp[1]);
} elseif (preg_match("/Content-Disposition: attachment;/", $part)) {
$tmp = explode("\r\n", $part);
unset($tmp[0]);
$part = implode("\r\n", $tmp);
$tmp = explode("\r\n\r\n", $part);
$tmp_header = explode("\r\n", $tmp[0]);
$output = array(
"type" => substr($tmp_header[0], 14),
"encoding" => substr($tmp_header[1], 27),
"filename" => substr($tmp_header[2], 43, -1),
"data" => $tmp[1],
);
$attachments[md5($output['type'].$output['encoding'].$output['filename'].$output['data'])] = (object) $output;
}
}
} elseif (preg_match("/multipart\/alternative/", $content)) { // html mail
$mess = explode("\r\n\r\n----------", $content);
$mess = substr($mess[1], 10, -22);
$mess = explode("----------", $mess);
......@@ -118,22 +143,29 @@ class FileMailer extends Object implements IMailer
$temp_mess[$type] = implode("\r\n",$temp_mess[$type]);
}
$mess = $temp_mess;
} else {
} elseif (preg_match("/text\/plain/", $content)) { // plaintext mail
$mess = array(
"plain" => $mess[1],
"plain" => $mess[1],
"html" => NULL,
);
}
return (object) array_merge(
array(
"filename" => $filename,
"message_id" => $message_id,
"header" => $header,
"plain" => $mess['plain'],
"html" => $mess['html'],
"raw" => $content,
"attachments" => $attachments,
),
$header
);
}
}
public function getPrefix()
{
return $this->prefix;
}
}
\ No newline at end of file
{*
* Template for MailPanel.
*
* @author Roman Mátyus
* @author Jan Drábek, Roman Mátyus
* @copyright (c) Jan Drábek 2013
* @copyright (c) Roman Mátyus 2013
* @license MIT
* @package FileMailer
......@@ -19,17 +20,17 @@
position: relative;
}
#mailpanel-count {
background: red;
border-radius: 8px;
font-size: 8px;
color: white;
font-weight: 800;
margin-left: -8px;
z-index: 2;
position: absolute;
width: 15px;
height: 15px;
text-align: center;
background: red;
border-radius: 8px;
font-size: 8px;
color: white;
font-weight: 800;
margin-left: -8px;
z-index: 2;
position: absolute;
width: 15px;
height: 15px;
text-align: center;
}
img#mailpanel-icon {
z-index: 1;
......@@ -39,12 +40,22 @@ img#mailpanel-icon {
#nette-debug div.nette-mailPanel-box {
border:1px solid silver;
}
#nette-debug a.nette-mailPanel-highlight {
color: red;
}
#nette-debug a.nette-mailPanel-highlight:focus,
#nette-debug a.nette-mailPanel-highlight:active,
#nette-debug a.nette-mailPanel-highlight:hover {
color: white;
}
</style>
<h1>MailPanel: {if $countAll==0}no{else}{$countAll}{/if} mail{if $countAll>1}s{/if}, {$countNew} new</h1>
<div n:if="$countAll>0"><a href="/?mail-panel=delete-all">Delete All</a></div>
<div n:if="$countAll>0" class="nette-inner">
<div n:foreach="$messages as $message">
<a class="nette-toggler" rel="#nette-mailPanel-message-{$message->message_id}" href="#">{$message->date} {$message->subject} ►</a>
<a class="nette-toggler{if $iterator->counter<=$countNew} nette-mailPanel-highlight{/if}" rel="#nette-mailPanel-message-{$message->message_id}" href="#" >{$message->date|date:"d.m.Y H:i:s"} {$message->subject} ►</a>
<div id="nette-mailPanel-message-{$message->message_id}" class="nette-collapsed">
<table n:if="!empty($show)" n:inner-foreach="$show as $item">
<tr n:if="$message->$item">
......@@ -54,14 +65,12 @@ img#mailpanel-icon {
</table>
<a class="nette-toggler" rel="#nette-mailPanel-message-header-{$message->message_id}" href="#">header ►</a>
<span id="nette-mailPanel-message-header-{$message->message_id}" class="nette-collapsed">
<div class="nette-mailPanel-box">
<table n:inner-foreach="$message->header as $key => $value">
<tr>
<td>{$key}</td>
<td>{$value}</td>
</tr>
</table>
</div>
<table n:inner-foreach="$message->header as $key => $value">
<tr>
<td>{$key|firstUpper}:</td>
<td>{$value}</td>
</tr>
</table>
</span>
<a class="nette-toggler" rel="#nette-mailPanel-message-plain-{$message->message_id}" href="#">plain ►</a>
<span id="nette-mailPanel-message-plain-{$message->message_id}" class="nette-collapsed">
......@@ -72,7 +81,11 @@ img#mailpanel-icon {
<a n:if="$message->html" class="nette-toggler" rel="#nette-mailPanel-message-html-{$message->message_id}" href="#">html ►</a>
<span n:if="$message->html" id="nette-mailPanel-message-html-{$message->message_id}" class="nette-collapsed">
<div class="nette-mailPanel-box">
{!$message->html}
{var $mailContent = str_replace(array("'","\n","\r","\t"),array("&apos;","","",""),$message->html)}
<iframe id="nette-mailPanel-message-html-iframe-{$message->message_id}"></iframe>
<script type="text/javascript">
document.getElementById('nette-mailPanel-message-html-iframe-{!$message->message_id}').contentWindow.document.write('{!$mailContent}');
</script>
</div>
</span>
<a class="nette-toggler" rel="#nette-mailPanel-message-raw-{$message->message_id}" href="#">raw ►</a>
......@@ -81,6 +94,18 @@ img#mailpanel-icon {
<pre>{$message->raw}</pre>
</div>
</span>
<a n:if="$message->attachments" class="nette-toggler" rel="#nette-mailPanel-message-attachments-{$message->message_id}" href="#">attachments ►</a>
<span n:if="$message->attachments" id="nette-mailPanel-message-attachments-{$message->message_id}" class="nette-collapsed">
<div class="nette-mailPanel-box">
<ul n:inner-foreach="$message->attachments as $filehash => $attachment">
<li>
<a href="/?mail-panel=download&mail-panel-mail={$message->filename}&mail-panel-file={$filehash}">
{$attachment->filename}
</a>
</li>
</ul>
</div>
</span>
</div>
</div>
</div>
</div>
\ No newline at end of file
<?php
namespace RM;
use Nette\Application\UI\Control,
Nette\Diagnostics\IBarPanel,
Nette\Http\Request,
use Nette\DateTime,
Nette\Application\Application,
Nette\Utils\Finder,
Nette\DateTime,
Nette\Application\UI\Control,
Nette\Diagnostics\IBarPanel,
Nette\Caching\Cache,
Nette\Caching\IStorage;
Nette\Caching\IStorage,
Nette\Http\Response,
Nette\Http\Request,
Nette\Utils\Finder;
/**
* Bar panel showing stored mails.
......@@ -42,7 +43,8 @@ use Nette\Application\UI\Control,
* - $show( [from,to] )
* - $hideEmpty(TRUE)
*
* @author Roman Mátyus
* @author Jan Drábek, Roman Mátyus
* @copyright (c) Jan Drábek 2013
* @copyright (c) Roman Mátyus 2013
* @license MIT
* @package FileMailer
......@@ -61,6 +63,9 @@ class MailPanel extends Control implements IBarPanel {
/** @var Cache */
private $cache;
/** @var Response */
private $response;
/** @var integer */
private $countAll = 0;
......@@ -89,16 +94,20 @@ class MailPanel extends Control implements IBarPanel {
/** @var bool */
public $hideEmpty = TRUE;
public function __construct(Application $application, Request $request, FileMailer $fileMailer, IStorage $cacheStorage)
public function __construct(Application $application, Request $request, FileMailer $fileMailer, IStorage $cacheStorage, Response $response)
{
$this->application = $application;
$this->request = $request;
$this->fileMailer = $fileMailer;
$this->cache = new Cache($cacheStorage, "MailPanel");
$this->response = $response;
switch($request->getQuery("mail-panel")) {
case 'delete-all':
$this->handleDeleteAll();
break;
case 'download':
$this->handleDownload($request->getQuery("mail-panel-mail"),$request->getQuery("mail-panel-file"));
break;
default:
break;
}
......@@ -135,24 +144,8 @@ class MailPanel extends Control implements IBarPanel {
return ob_get_clean();
}
/**
* Delete all stored mails from filesystem an cache.
*/
public function handleDeleteAll()
{
foreach (Finder::findFiles('*')->in($this->fileMailer->tempDir) as $file)
unlink($file);
$this->cache->clean(
array(
Cache::ALL => TRUE,
));
header("Location: ".$this->request->getReferer());
exit;
}
/**
* Process all messages.
* @return mixed
*/
private function processMessage()
{
......@@ -164,7 +157,7 @@ class MailPanel extends Control implements IBarPanel {
foreach (Finder::findFiles('*')->in($this->fileMailer->tempDir) as $file) {
$message = $this->cache->load($file->getFilename());
if ($message === NULL) {
$message = FileMailer::mailParser(file_get_contents($file));
$message = FileMailer::mailParser(file_get_contents($file),$file->getFilename());
$this->cache->save($file->getFilename(),$message);
}
$time = new DateTime;
......@@ -173,7 +166,10 @@ class MailPanel extends Control implements IBarPanel {
$this->countAll++;
$this->messages[] = $message;
}
return TRUE;
usort($this->messages, function($a1, $a2) {
return $a2->date->getTimestamp() - $a1->date->getTimestamp();
});
}
/**
......@@ -195,4 +191,32 @@ class MailPanel extends Control implements IBarPanel {
}
}
/**
* Delete all stored mails from filesystem an cache.
*/
public function handleDeleteAll()
{
foreach (Finder::findFiles('*')->in($this->fileMailer->tempDir) as $file)
unlink($file);
$this->cache->clean(
array(
Cache::ALL => TRUE,
));
header("Location: ".$this->request->getReferer());
exit;
}
/**
* Download attachment from file.
*/
public function handleDownload($filename, $filehash)
{
$message = $this->cache->load($filename);
$file = $message->attachments[$filehash];
$this->response->setContentType($file->type, 'UTF-8');
$this->response->setHeader('Content-Disposition', 'attachment; filename="' . $file->filename . '"');
$this->response->setHeader('Content-Length', strlen($file->data));
print base64_decode($file->data);
exit;
}
}
#FileMailer
Addon for catching mails in Nette to filesystem and showing it in debug bar.
Addon for catching e-mails in Nette FW to filesystem and showing it in the Debug Bar.
```
After configuring this addon is e-mails not sended, but ONLY stored to filesystem and showed in Debug Bar!
......@@ -95,4 +95,19 @@ Options for addon customization.
| $newMessageTime | string | `-10 seconds` | no | By this time limit is defined new messages. |
| $show | array | `array("subject", "from", "to")` | no | Array of default displayed headers. |
| $autoremove | bool/string | `FALSE` | no | Define limit for automatic remove old e-mails. E.g. `-2 minutes` |
| $hideEmpty | bool | `TRUE` | no | Hide empty panel? |
\ No newline at end of file
| $hideEmpty | bool | `TRUE` | no | Hide empty panel? |
##Changelog
###Version 0.2
- Add support of e-mail attachments
- Sort e-mails by date
- HTML e-mails showed into iframe
- Refactoring
- Fix copyright
- Many bug fixes
###Version 0.1
- Initial commit
\ No newline at end of file
{
"name": "rm/filemailer",
"type": "library",
"version": "0.1",
"description": "Addon for catch in Nette mails to filesystem and showing it in debug bar.",
"keywords": ["nette", "mailer", "mail", "debugbar"],
"version": "0.2",
"description": "Addon for catching e-mails in Nette FW to filesystem and showing it in the Debug Bar.",
"keywords": ["nette", "mailer", "mail", "debugbar", "debuging"],
"homepage": "https://github.com/romanmatyus/FileMailer",
"license": ["MIT"],
"authors": [
{
"name": "Jan Drábek",
"name": "Roman Mátyus"
}
],
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment