diff --git a/CHANGELOG.md b/CHANGELOG.md index be40c17..5dbb905 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - refactored code into multiple php files. - Requires PHP version >=7.2 - make all addresses lowercase #30 +- fixed error when downloading email ### Added - better horizontal spacing for header (from @Spegeli) and style @@ -24,6 +25,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - Blacklist some usernames, configurable #27 - copyToClipboard button #30 - mail counter in title +- rest api option ## [0.1.4] - 2017-04-15 diff --git a/src/pages.php b/src/controller.php similarity index 70% rename from src/pages.php rename to src/controller.php index f4a17f2..1bf3de0 100644 --- a/src/pages.php +++ b/src/controller.php @@ -1,8 +1,19 @@ viewHandler = $outputHandler; + } function invoke(ImapClient $imapClient) { } @@ -23,22 +34,12 @@ abstract class Page { $name = $word . $nr; $domain = $domains[array_rand($domains)]; - header("location: ?$name@$domain"); - } - - /** - * print error and stop program. - * @param $status integer http status - * @param $text string error text - */ - function error($status, $text) { - @http_response_code($status); - die("{\"error\": \"$text\"}"); + $this->viewHandler->newAddress("$name@$domain"); } } -class RedirectToAddressPage extends Page { +class RedirectToAddressController extends Controller { private $username; private $domain; private $config_blocked_usernames; @@ -51,11 +52,11 @@ class RedirectToAddressPage extends Page { function invoke(ImapClient $imapClient) { $user = User::parseUsernameAndDomain($this->username, $this->domain, $this->config_blocked_usernames); - header("location: ?" . $user->username . "@" . $user->domain); + $this->viewHandler->newAddress($user->username . "@" . $user->domain); } } -class DownloadEmailPage extends Page { +class DownloadEmailController extends Controller { private $email_id; private $address; @@ -75,21 +76,18 @@ class DownloadEmailPage extends Page { $this->if_invalid_redirect_to_random($user, $this->config_domains); $download_email_id = filter_var($this->email_id, FILTER_SANITIZE_NUMBER_INT); - if ($imapClient->load_one_email($download_email_id, $user) !== null) { - header("Content-Type: message/rfc822; charset=utf-8"); - header("Content-Disposition: attachment; filename=\"" . $user->address . "-" . $download_email_id . ".eml\""); - - $headers = imap_fetchheader($this->mailbox->getImapStream(), $download_email_id, FT_UID); - $body = imap_body($this->mailbox->getImapStream(), $download_email_id, FT_UID); - print $headers . "\n" . $body; + $full_email = $imapClient->load_one_email_fully($download_email_id, $user); + if ($full_email !== null) { + $filename = $user->address . "-" . $download_email_id . ".eml"; + $this->viewHandler->downloadEmailAsRfc822($full_email, $filename); } else { - $this->error(404, 'download error: invalid username/mailid combination'); + $this->viewHandler->error(404, 'download error: invalid username/mailid combination'); } } } -class DeleteEmailPage extends Page { +class DeleteEmailController extends Controller { private $email_id; private $address; private $config_domains; @@ -108,14 +106,14 @@ class DeleteEmailPage extends Page { $delete_email_id = filter_var($this->email_id, FILTER_SANITIZE_NUMBER_INT); if ($imapClient->delete_email($delete_email_id, $user)) { - header("location: ?" . $user->address); + $this->viewHandler->done($this->address); } else { - $this->error(404, 'delete error: invalid username/mailid combination'); + $this->viewHandler->error(404, 'delete error: invalid username/mailid combination'); } } } -class RedirectToRandomAddressPage extends Page { +class RedirectToRandomAddressController extends Controller { private $config_domains; public function __construct($config_domains) { @@ -128,7 +126,7 @@ class RedirectToRandomAddressPage extends Page { } -class DisplayEmailsPage extends Page { +class DisplayEmailsController extends Controller { private $address; private $config; @@ -142,16 +140,14 @@ class DisplayEmailsPage extends Page { // print emails with html template $user = User::parseDomain($this->address, $this->config['blocked_usernames']); $this->if_invalid_redirect_to_random($user, $this->config['domains']); - - // Set variables for frontend template: $emails = $imapClient->get_emails($user); - $config = $this->config; - require "frontend.template.php"; + + $this->viewHandler->displayEmails($emails, $this->config, $user); } } -class InvalidRequestPage extends Page { +class InvalidRequestController extends Controller { function invoke(ImapClient $imapClient) { - $this->error(400, "Bad Request"); + $this->viewHandler->error(400, "Bad Request"); } } diff --git a/src/frontend.template.php b/src/frontend.template.php index 92e3d59..52b3098 100644 --- a/src/frontend.template.php +++ b/src/frontend.template.php @@ -184,7 +184,7 @@ $purifier = new HTMLPurifier($purifier_config); Delete + href="?action=delete_email&email_id=&address=address ?>">Delete diff --git a/src/imap_client.php b/src/imap_client.php index 913af53..af9780d 100644 --- a/src/imap_client.php +++ b/src/imap_client.php @@ -54,13 +54,25 @@ class ImapClient { } + public function load_one_email_fully($download_email_id, $user) { + if ($this->load_one_email($download_email_id, $user) !== null) { + $headers = imap_fetchheader($this->mailbox->getImapStream(), $download_email_id, FT_UID); + $body = imap_body($this->mailbox->getImapStream(), $download_email_id, FT_UID); + return $headers . "\n" . $body; + } else { + return null; + } + + } + /** * Load emails using the $mail_ids, the mails have to match the $address in TO or CC. * @param $mail_ids array of integer ids * @param $user User * @return array of emails */ - private function _load_emails(array $mail_ids, User $user) { + private + function _load_emails(array $mail_ids, User $user) { $emails = array(); foreach ($mail_ids as $id) { $mail = $this->mailbox->getMail($id); @@ -75,7 +87,8 @@ class ImapClient { /** * deletes messages older than X days. */ - public function delete_old_messages(string $delete_messages_older_than) { + public + function delete_old_messages(string $delete_messages_older_than) { $ids = $this->mailbox->searchMailbox('BEFORE ' . date('d-M-Y', strtotime($delete_messages_older_than))); foreach ($ids as $id) { $this->mailbox->deleteMail($id); diff --git a/src/index.php b/src/index.php index 6d9a6f1..cb8418c 100644 --- a/src/index.php +++ b/src/index.php @@ -7,13 +7,14 @@ require_once './backend-libs/autoload.php'; require_once './user.php'; require_once './imap_client.php'; -require_once './pages.php'; +require_once './controller.php'; require_once './router.php'; $imapClient = new ImapClient($config['imap']['url'], $config['imap']['username'], $config['imap']['password']); $router = new Router($_SERVER['REQUEST_METHOD'], $_GET['action'] ?? NULL, $_GET, $_POST, $_SERVER['QUERY_STRING'], $config); $page = $router->route(); +$page->setViewHandler(new ServerRenderViewHandler()); $page->invoke($imapClient); // delete after each request diff --git a/src/rest.php b/src/rest.php new file mode 100644 index 0000000..5f02cc9 --- /dev/null +++ b/src/rest.php @@ -0,0 +1,23 @@ +route(); +$page->setViewHandler(new JsonViewHandler()); +$page->invoke($imapClient); + +// delete after each request +$imapClient->delete_old_messages($config['delete_messages_older_than']); + +?> \ No newline at end of file diff --git a/src/router.php b/src/router.php index a4eaaa1..6896e5b 100644 --- a/src/router.php +++ b/src/router.php @@ -1,15 +1,15 @@ method = $method; @@ -21,30 +21,30 @@ class Router { } - function route(): Page { + function route(): Controller { if ($this->action === "redirect" && isset($this->post_vars['username']) && isset($this->post_vars['domain'])) { - return new RedirectToAddressPage($this->post_vars['username'], $this->post_vars['domain'], $this->config['blocked_usernames']); + return new RedirectToAddressController($this->post_vars['username'], $this->post_vars['domain'], $this->config['blocked_usernames']); } elseif ($this->action === "download_email" - && isset($this->get_vars['download_email_id']) + && isset($this->get_vars['email_id']) && isset($this->get_vars['address'])) { - return new DownloadEmailPage($this->get_vars['download_email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']); + return new DownloadEmailController($this->get_vars['email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']); } elseif ($this->action === "delete_email" - && isset($this->get_vars['delete_email_id']) + && isset($this->get_vars['email_id']) && isset($this->get_vars['address'])) { - return new DeleteEmailPage($this->get_vars['delete_email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']); + return new DeleteEmailController($this->get_vars['email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']); } elseif ($this->action === 'random') { - return new RedirectToRandomAddressPage($this->config['domains']); + return new RedirectToRandomAddressController($this->config['domains']); } elseif (!empty($this->query_string)) { - return new DisplayEmailsPage($this->query_string, $this->config); + return new DisplayEmailsController($this->query_string, $this->config); } else { - return new RedirectToRandomAddressPage($this->config['domains']); + return new RedirectToRandomAddressController($this->config['domains']); } } } \ No newline at end of file diff --git a/src/router.rest.php b/src/router.rest.php new file mode 100644 index 0000000..b1ebb0f --- /dev/null +++ b/src/router.rest.php @@ -0,0 +1,30 @@ +action === "download_email" + && isset($this->get_vars['email_id']) + && isset($this->get_vars['address'])) { + return new DownloadEmailController($this->get_vars['email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']); + + } elseif ($this->action === "delete_email" + && isset($this->get_vars['email_id']) + && isset($this->get_vars['address'])) { + return new DeleteEmailController($this->get_vars['email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']); + + } elseif ($this->action === 'get_random_username') { + return new RedirectToRandomAddressController($this->config['domains']); + + } elseif ($this->action === 'get_emails' && isset($this->get_vars['address'])) { + return new DisplayEmailsController($this->get_vars['address'], $this->config); + + } else { + return new InvalidRequestController(); + } + } +} \ No newline at end of file diff --git a/src/view.php b/src/view.php new file mode 100644 index 0000000..58bba7e --- /dev/null +++ b/src/view.php @@ -0,0 +1,79 @@ +json(array('status' => "success")); + } + + function error($status, $msg) { + @http_response_code($status); + $this->json(array('status' => "failure", 'error' => $msg)); + } + + function displayEmails($emails, $config, $user) { + $this->json(array('status' => "success", 'emails' => $emails)); + } + + function newAddress($address) { + $this->json(array('status' => "failure", 'address' => $address)); + } + + function downloadEmailAsRfc822($full_email, $filename) { + $this->json(array('status' => "success", 'body' => $full_email)); + } +} + +class ServerRenderViewHandler implements ViewHandler { + function done($address) { + header("location: ?" . $address); + } + + function error($status, $msg) { + @http_response_code($status); + die("{'result': 'error', 'error': '$msg'}"); + } + + function displayEmails($emails, $config, $user) { + // Set variables for frontend template: $emails, $config + require "frontend.template.php"; + } + + function newAddress($address) { + header("location: ?$address"); + } + + function downloadEmailAsRfc822($full_email, $filename) { + header("Content-Type: message/rfc822; charset=utf-8"); + header("Content-Disposition: attachment; filename=\"$filename\""); + print $full_email; + } +}