Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions MailLibrary/ContactList.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
class ContactList implements Iterator, Countable
{
/** @var Contact[] */
protected $contacts;
protected $contacts = [];

protected $builtContacts;
protected $builtContacts = [];

public function addContact($mailbox = NULL, $host = NULL, $personal = NULL, $adl = NULL)
{
Expand Down
16 changes: 10 additions & 6 deletions MailLibrary/Drivers/ImapDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use greeny\MailLibrary\Mailbox;
use greeny\MailLibrary\Structures\IStructure;
use greeny\MailLibrary\Structures\ImapStructure;
use Nette\Utils\Strings;
use greeny\MailLibrary\Mail;
use DateTime;

Expand Down Expand Up @@ -227,18 +228,21 @@ public function checkFilter($key, $value = NULL) {
public function getHeaders($mailId)
{
$raw = imap_fetchheader($this->resource, $mailId, FT_UID);
$lines = explode("\n", $raw);
$lines = explode("\n", Strings::fixEncoding($raw));
$headers = array();
$lastHeader = NULL;

// normalize headers
foreach($lines as $line) {
if(mb_substr($line, 0, 1, 'UTF-8') === " ") {
$headers[$lastHeader] .= $line;
$firstCharacter = mb_substr($line, 0, 1, 'UTF-8'); // todo: correct assumption that string must be UTF-8 encoded?
if(preg_match('/[\pZ\pC]/u', $firstCharacter) === 1) { // search for UTF-8 whitespaces
$headers[$lastHeader] .= " " . Strings::trim($line);
} else {
$parts = explode(':', $line);
$name = $parts[0];
$name = Strings::trim($parts[0]);
unset($parts[0]);

$headers[$name] = implode(':', $parts);
$headers[$name] = Strings::trim(implode(':', $parts));
$lastHeader = $name;
}
}
Expand All @@ -254,7 +258,7 @@ public function getHeaders($mailId)
$text = '';
foreach($decoded as $part) {
if($part->charset !== 'UTF-8' && $part->charset !== 'default') {
$text .= mb_convert_encoding($part->text, 'UTF-8', $part->charset);
$text .= @mb_convert_encoding($part->text, 'UTF-8', $part->charset); // todo: handle this more properly
} else {
$text .= $part->text;
}
Expand Down
59 changes: 45 additions & 14 deletions MailLibrary/Mail.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

namespace greeny\MailLibrary;

use greeny\MailLibrary\Structures\IStructure;
use Nette\Utils\Strings;

class Mail {
const ANSWERED = 'ANSWERED';
const BCC = 'BCC';
Expand Down Expand Up @@ -39,10 +42,10 @@ class Mail {
const ORDER_CC = SORTCC;
const ORDER_SIZE = SORTSIZE;

/** @var \greeny\MailLibrary\Connection */
/** @var Connection */
protected $connection;

/** @var \greeny\MailLibrary\Mailbox */
/** @var Mailbox */
protected $mailbox;

/** @var int */
Expand All @@ -51,7 +54,7 @@ class Mail {
/** @var array */
protected $headers = NULL;

/** @var \greeny\MailLibrary\Structures\IStructure */
/** @var IStructure */
protected $structure = NULL;

/** @var array */
Expand All @@ -78,18 +81,27 @@ public function __construct(Connection $connection, Mailbox $mailbox, $id)
public function __isset($name)
{
$this->headers !== NULL || $this->initializeHeaders();
return isset($this->headers[$this->formatHeaderName($name)]);
$key = $this->normalizeHeaderName($this->lowerCamelCaseToHeaderName($name));
return isset($this->headers[$key]);
}

/**
* Header getter
*
* @param string $name
* @return mixed
* @deprecated
*/
public function __get($name)
{
return $this->getHeader($name);
\trigger_error(\E_USER_DEPRECATED, 'use array access with execat header name instead');
return $this->getHeader(
$this->normalizeHeaderName($this->lowerCamelCaseToHeaderName($name))
);
}

public function __set($name, $value) {
throw new \Exception('Mail headers are read-only.');
}

/**
Expand Down Expand Up @@ -124,7 +136,12 @@ public function getHeaders()
public function getHeader($name)
{
$this->headers !== NULL || $this->initializeHeaders();
return $this->headers[$this->formatHeaderName($name)];
$index = $this->normalizeHeaderName($name);
if(isset($this->headers[$index])) {
return $this->headers[$index];
}

return NULL;
}

/**
Expand All @@ -135,9 +152,9 @@ public function getSender() {
if($from) {
$contacts = $from->getContactsObjects();
return (count($contacts) ? $contacts[0] : NULL);
} else {
return NULL;
}

return NULL;
}

/**
Expand Down Expand Up @@ -230,7 +247,7 @@ protected function initializeHeaders()
$this->headers = array();
$this->connection->getDriver()->switchMailbox($this->mailbox->getName());
foreach($this->connection->getDriver()->getHeaders($this->id) as $key => $value) {
$this->headers[$this->formatHeaderName($key)] = $value;
$this->headers[$this->normalizeHeaderName($key)] = $value;
}
}

Expand All @@ -247,15 +264,29 @@ protected function initializeFlags()
}

/**
* Formats header name (X-Received-From => xReceivedFrom)
* Formats header name (X-Received-From => x-recieved-from)
*
* @param string $name
* @param string $name Header name (with dashes, valid UTF-8 string)
* @return string
*/
protected function formatHeaderName($name)
protected function normalizeHeaderName($name)
{
return lcfirst(preg_replace_callback("~-.~", function($matches){
return Strings::normalize(Strings::lower($name));
}

/**
* Converts camel cased name to normalized header name (xReceivedFrom => x-recieved-from)
*
* @param string $camelCasedName
* @return string name with dashes
*/
protected function lowerCamelCaseToHeaderName($camelCasedName) {
// todo: test this
// todo: use something like this instead http://stackoverflow.com/a/1993772
$dashedName = lcfirst(preg_replace_callback("~-.~", function($matches){
return ucfirst(substr($matches[0], 1));
}, $name));
}, $camelCasedName));

return $this->normalizeHeaderName($dashedName);
}
}
36 changes: 18 additions & 18 deletions MailLibrary/loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,24 @@
require_once "exceptions.php";

spl_autoload_register(function ($type) {
static $paths = array(
'greeny\maillibrary\connection' => 'Connection.php',
'greeny\maillibrary\mailbox' => 'Mailbox.php',
'greeny\maillibrary\selection' => 'Selection.php',
'greeny\maillibrary\mail' => 'Mail.php',
'greeny\maillibrary\contactlist' => 'ContactList.php',
'greeny\maillibrary\contact' => 'Contact.php',
'greeny\maillibrary\attachment' => 'Attachment.php',
'greeny\maillibrary\structures\istructure' => 'Structures/IStructure.php',
'greeny\maillibrary\structures\imapstructure' => 'Structures/ImapStructure.php',
'greeny\maillibrary\drivers\idriver' => 'Drivers/IDriver.php',
'greeny\maillibrary\drivers\imapdriver' => 'Drivers/ImapDriver.php',
'greeny\maillibrary\extensions\maillibraryextension' => 'Extensions/MailLibraryExtension.php',
);
static $paths = array(
'greeny\maillibrary\connection' => 'Connection.php',
'greeny\maillibrary\mailbox' => 'Mailbox.php',
'greeny\maillibrary\selection' => 'Selection.php',
'greeny\maillibrary\mail' => 'Mail.php',
'greeny\maillibrary\contactlist' => 'ContactList.php',
'greeny\maillibrary\contact' => 'Contact.php',
'greeny\maillibrary\attachment' => 'Attachment.php',
'greeny\maillibrary\structures\istructure' => 'Structures/IStructure.php',
'greeny\maillibrary\structures\imapstructure' => 'Structures/ImapStructure.php',
'greeny\maillibrary\drivers\idriver' => 'Drivers/IDriver.php',
'greeny\maillibrary\drivers\imapdriver' => 'Drivers/ImapDriver.php',
'greeny\maillibrary\extensions\maillibraryextension' => 'Extensions/MailLibraryExtension.php',
);

$type = ltrim(strtolower($type), '\\'); // PHP namespace bug #49143
$type = ltrim(strtolower($type), '\\'); // PHP namespace bug #49143

if (isset($paths[$type])) {
require_once __DIR__ . '/' . $paths[$type];
}
if (isset($paths[$type])) {
require_once __DIR__ . '/' . $paths[$type];
}
});
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,17 @@ MailLibrary

A PHP library for downloading mails from server.

Documentation can be found at http://greeny.github.io/MailLibrary/.
Documentation can be found at http://greeny.github.io/MailLibrary/.

Testing
-------

Install dependencies using composer and then run following in library root directory.

````cmd
# Unix
vendor\bin\tester -c tests\php-unix.ini tests

# Windows
vendor\bin\tester -c tests\php-windows.ini tests
````
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
"files": ["MailLibrary/loader.php"]
},
"require": {
"php": ">= 5.3.0"
"php": ">= 5.3.0",
"ext-imap": "*",
"nette/utils": "~2.2"
},
"require-dev": {
"nette/tester": "@dev"
}
}
}
5 changes: 5 additions & 0 deletions tests/php-unix.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[PHP]
;extension_dir = "./ext"
extension=mbstring.so
extension=imap.so
date.timezone = "Europe/Prague"
5 changes: 5 additions & 0 deletions tests/php-windows.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[PHP]
extension_dir = "./ext"
extension=php_mbstring.dll
extension=php_imap.dll
date.timezone = "Europe/Prague"