mirror of
https://github.com/freescout-helpdesk/freescout.git
synced 2024-11-25 03:43:33 +01:00
576 lines
15 KiB
PHP
576 lines
15 KiB
PHP
<?php
|
|
/*
|
|
* File: Client.php
|
|
* Category: -
|
|
* Author: M. Goldenbaum
|
|
* Created: 19.01.17 22:21
|
|
* Updated: -
|
|
*
|
|
* Description:
|
|
* -
|
|
*/
|
|
|
|
namespace Webklex\IMAP;
|
|
|
|
use Webklex\IMAP\Exceptions\ConnectionFailedException;
|
|
use Webklex\IMAP\Exceptions\GetMessagesFailedException;
|
|
use Webklex\IMAP\Exceptions\MessageSearchValidationException;
|
|
use Webklex\IMAP\Support\FolderCollection;
|
|
use Webklex\IMAP\Support\MessageCollection;
|
|
|
|
/**
|
|
* Class Client
|
|
*
|
|
* @package Webklex\IMAP
|
|
*/
|
|
class Client {
|
|
|
|
/**
|
|
* @var boolean|resource
|
|
*/
|
|
public $connection = false;
|
|
|
|
/**
|
|
* Server hostname.
|
|
*
|
|
* @var string
|
|
*/
|
|
public $host;
|
|
|
|
/**
|
|
* Server port.
|
|
*
|
|
* @var int
|
|
*/
|
|
public $port;
|
|
|
|
/**
|
|
* Service protocol.
|
|
*
|
|
* @var int
|
|
*/
|
|
public $protocol;
|
|
|
|
/**
|
|
* Server encryption.
|
|
* Supported: none, ssl or tls.
|
|
*
|
|
* @var string
|
|
*/
|
|
public $encryption;
|
|
|
|
/**
|
|
* If server has to validate cert.
|
|
*
|
|
* @var mixed
|
|
*/
|
|
public $validate_cert;
|
|
|
|
/**
|
|
* Account username/
|
|
*
|
|
* @var mixed
|
|
*/
|
|
public $username;
|
|
|
|
/**
|
|
* Account password.
|
|
*
|
|
* @var string
|
|
*/
|
|
public $password;
|
|
|
|
/**
|
|
* Read only parameter.
|
|
*
|
|
* @var bool
|
|
*/
|
|
protected $read_only = false;
|
|
|
|
/**
|
|
* Active folder.
|
|
*
|
|
* @var Folder
|
|
*/
|
|
protected $activeFolder = false;
|
|
|
|
/**
|
|
* Connected parameter
|
|
*
|
|
* @var bool
|
|
*/
|
|
protected $connected = false;
|
|
|
|
/**
|
|
* IMAP errors that might have ben occurred
|
|
*
|
|
* @var array $errors
|
|
*/
|
|
protected $errors = [];
|
|
|
|
/**
|
|
* All valid and available account config parameters
|
|
*
|
|
* @var array $validConfigKeys
|
|
*/
|
|
protected $validConfigKeys = ['host', 'port', 'encryption', 'validate_cert', 'username', 'password','protocol'];
|
|
|
|
/**
|
|
* Client constructor.
|
|
*
|
|
* @param array $config
|
|
*/
|
|
public function __construct($config = []) {
|
|
$this->setConfig($config);
|
|
}
|
|
|
|
/**
|
|
* Client destructor
|
|
*/
|
|
public function __destruct() {
|
|
$this->disconnect();
|
|
}
|
|
|
|
/**
|
|
* Set the Client configuration
|
|
*
|
|
* @param array $config
|
|
*
|
|
* @return self
|
|
*/
|
|
public function setConfig(array $config) {
|
|
$defaultAccount = config('imap.default');
|
|
$defaultConfig = config("imap.accounts.$defaultAccount");
|
|
|
|
foreach ($this->validConfigKeys as $key) {
|
|
$this->$key = isset($config[$key]) ? $config[$key] : $defaultConfig[$key];
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get the current imap resource
|
|
*
|
|
* @return bool|resource
|
|
* @throws ConnectionFailedException
|
|
*/
|
|
public function getConnection() {
|
|
$this->checkConnection();
|
|
return $this->connection;
|
|
}
|
|
|
|
/**
|
|
* Set read only property and reconnect if it's necessary.
|
|
*
|
|
* @param bool $readOnly
|
|
*
|
|
* @return self
|
|
*/
|
|
public function setReadOnly($readOnly = true) {
|
|
$this->read_only = $readOnly;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Determine if connection was established.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isConnected() {
|
|
return $this->connected;
|
|
}
|
|
|
|
/**
|
|
* Determine if connection is in read only mode.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isReadOnly() {
|
|
return $this->read_only;
|
|
}
|
|
|
|
/**
|
|
* Determine if connection was established and connect if not.
|
|
*
|
|
* @throws ConnectionFailedException
|
|
*/
|
|
public function checkConnection() {
|
|
if (!$this->isConnected() || $this->connection === false) {
|
|
$this->connect();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Connect to server.
|
|
*
|
|
* @param int $attempts
|
|
*
|
|
* @return $this
|
|
* @throws ConnectionFailedException
|
|
*/
|
|
public function connect($attempts = 3) {
|
|
$this->disconnect();
|
|
|
|
try {
|
|
$this->connection = imap_open(
|
|
$this->getAddress(),
|
|
$this->username,
|
|
$this->password,
|
|
$this->getOptions(),
|
|
$attempts,
|
|
config('imap.options.open')
|
|
);
|
|
$this->connected = !!$this->connection;
|
|
} catch (\ErrorException $e) {
|
|
$errors = imap_errors();
|
|
$message = $e->getMessage().'. '.implode("; ", (is_array($errors) ? $errors : array()));
|
|
|
|
throw new ConnectionFailedException($message);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Disconnect from server.
|
|
*
|
|
* @return $this
|
|
*/
|
|
public function disconnect() {
|
|
if ($this->isConnected() && $this->connection !== false && is_integer($this->connection) === false) {
|
|
$this->errors = array_merge($this->errors, imap_errors() ?: []);
|
|
$this->connected = !imap_close($this->connection, CL_EXPUNGE);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get a folder instance by a folder name
|
|
* ---------------------------------------------
|
|
* PLEASE NOTE: This is an experimental function
|
|
* ---------------------------------------------
|
|
* @param string $folder_name
|
|
* @param int $attributes
|
|
* @param null|string $delimiter
|
|
*
|
|
* @return Folder
|
|
*/
|
|
public function getFolder($folder_name, $attributes = 32, $delimiter = null) {
|
|
|
|
$delimiter = $delimiter === null ? config('imap.options.delimiter', '/') : $delimiter;
|
|
|
|
$oFolder = new Folder($this, (object) [
|
|
'name' => $this->getAddress().$folder_name,
|
|
'attributes' => $attributes,
|
|
'delimiter' => $delimiter
|
|
]);
|
|
|
|
return $oFolder;
|
|
}
|
|
|
|
/**
|
|
* Get folders list.
|
|
* If hierarchical order is set to true, it will make a tree of folders, otherwise it will return flat array.
|
|
*
|
|
* @param boolean $hierarchical
|
|
* @param string|null $parent_folder
|
|
*
|
|
* @return FolderCollection
|
|
* @throws ConnectionFailedException
|
|
*/
|
|
public function getFolders($hierarchical = true, $parent_folder = null) {
|
|
$this->checkConnection();
|
|
$folders = FolderCollection::make([]);
|
|
|
|
$pattern = $parent_folder.($hierarchical ? '%' : '*');
|
|
|
|
$items = imap_getmailboxes($this->connection, $this->getAddress(), $pattern);
|
|
|
|
// FreeScout fix
|
|
if (!$items) {
|
|
return $folders;
|
|
}
|
|
|
|
foreach ($items as $item) {
|
|
$folder = new Folder($this, $item);
|
|
|
|
if ($hierarchical && $folder->hasChildren()) {
|
|
$pattern = $folder->fullName.$folder->delimiter.'%';
|
|
|
|
$children = $this->getFolders(true, $pattern);
|
|
$folder->setChildren($children);
|
|
}
|
|
|
|
$folders->push($folder);
|
|
}
|
|
|
|
return $folders;
|
|
}
|
|
|
|
/**
|
|
* Open folder.
|
|
*
|
|
* @param Folder $folder
|
|
* @param int $attempts
|
|
*
|
|
* @throws ConnectionFailedException
|
|
*/
|
|
public function openFolder(Folder $folder, $attempts = 3) {
|
|
$this->checkConnection();
|
|
|
|
if ($this->activeFolder !== $folder) {
|
|
$this->activeFolder = $folder;
|
|
|
|
imap_reopen($this->getConnection(), $folder->path, $this->getOptions(), $attempts);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a new Folder
|
|
* @param string $name
|
|
* @param boolean $expunge
|
|
*
|
|
* @return bool
|
|
* @throws ConnectionFailedException
|
|
*/
|
|
public function createFolder($name, $expunge = true) {
|
|
$this->checkConnection();
|
|
$status = imap_createmailbox($this->getConnection(), $this->getAddress() . imap_utf7_encode($name));
|
|
if($expunge) $this->expunge();
|
|
|
|
return $status;
|
|
}
|
|
|
|
/**
|
|
* Rename Folder
|
|
* @param string $old_name
|
|
* @param string $new_name
|
|
* @param boolean $expunge
|
|
*
|
|
* @return bool
|
|
* @throws ConnectionFailedException
|
|
*/
|
|
public function renameFolder($old_name, $new_name, $expunge = true) {
|
|
$this->checkConnection();
|
|
$status = imap_renamemailbox($this->getConnection(), $this->getAddress() . imap_utf7_encode($old_name), $this->getAddress() . imap_utf7_encode($new_name));
|
|
if($expunge) $this->expunge();
|
|
|
|
return $status;
|
|
}
|
|
|
|
/**
|
|
* Delete Folder
|
|
* @param string $name
|
|
* @param boolean $expunge
|
|
*
|
|
* @return bool
|
|
* @throws ConnectionFailedException
|
|
*/
|
|
public function deleteFolder($name, $expunge = true) {
|
|
$this->checkConnection();
|
|
$status = imap_deletemailbox($this->getConnection(), $this->getAddress() . imap_utf7_encode($name));
|
|
if($expunge) $this->expunge();
|
|
|
|
return $status;
|
|
}
|
|
|
|
/**
|
|
* Get messages from folder.
|
|
*
|
|
* @param Folder $folder
|
|
* @param string $criteria
|
|
* @param int|null $fetch_options
|
|
* @param boolean $fetch_body
|
|
* @param boolean $fetch_attachment
|
|
*
|
|
* @return MessageCollection
|
|
* @throws ConnectionFailedException
|
|
* @throws GetMessagesFailedException
|
|
* @throws MessageSearchValidationException
|
|
*
|
|
* @deprecated 1.0.5.2:2.0.0 No longer needed. Use Folder::getMessages() instead
|
|
* @see Folder::getMessages()
|
|
*/
|
|
public function getMessages(Folder $folder, $criteria = 'ALL', $fetch_options = null, $fetch_body = true, $fetch_attachment = true, $fetch_flags = false) {
|
|
return $folder->getMessages($criteria, $fetch_options, $fetch_body, $fetch_attachment, $fetch_flags);
|
|
}
|
|
|
|
/**
|
|
* Get all unseen messages from folder
|
|
*
|
|
* @param Folder $folder
|
|
* @param string $criteria
|
|
* @param int|null $fetch_options
|
|
* @param boolean $fetch_body
|
|
* @param boolean $fetch_attachment
|
|
*
|
|
* @return MessageCollection
|
|
* @throws ConnectionFailedException
|
|
* @throws GetMessagesFailedException
|
|
* @throws MessageSearchValidationException
|
|
*
|
|
* @deprecated 1.0.5:2.0.0 No longer needed. Use Folder::getMessages('UNSEEN') instead
|
|
* @see Folder::getMessages()
|
|
*/
|
|
public function getUnseenMessages(Folder $folder, $criteria = 'UNSEEN', $fetch_options = null, $fetch_body = true, $fetch_attachment = true, $fetch_flags = false) {
|
|
return $folder->getUnseenMessages($criteria, $fetch_options, $fetch_body, $fetch_attachment, $fetch_flags);
|
|
}
|
|
|
|
/**
|
|
* Search messages by a given search criteria
|
|
*
|
|
* @param array $where
|
|
* @param Folder $folder
|
|
* @param int|null $fetch_options
|
|
* @param boolean $fetch_body
|
|
* @param string $charset
|
|
* @param boolean $fetch_attachment
|
|
*
|
|
* @return MessageCollection
|
|
* @throws ConnectionFailedException
|
|
* @throws GetMessagesFailedException
|
|
* @throws MessageSearchValidationException
|
|
*
|
|
* @deprecated 1.0.5:2.0.0 No longer needed. Use Folder::searchMessages() instead
|
|
* @see Folder::searchMessages()
|
|
*
|
|
*/
|
|
public function searchMessages(array $where, Folder $folder, $fetch_options = null, $fetch_body = true, $charset = "UTF-8", $fetch_attachment = true, $fetch_flags = false) {
|
|
return $folder->searchMessages($where, $fetch_options, $fetch_body, $charset, $fetch_attachment, $fetch_flags);
|
|
}
|
|
|
|
/**
|
|
* Get option for imap_open and imap_reopen.
|
|
* It supports only isReadOnly feature.
|
|
*
|
|
* @return int
|
|
*/
|
|
protected function getOptions() {
|
|
return ($this->isReadOnly()) ? OP_READONLY : 0;
|
|
}
|
|
|
|
/**
|
|
* Get full address of mailbox.
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function getAddress() {
|
|
$address = "{".$this->host.":".$this->port."/".($this->protocol ? $this->protocol : 'imap');
|
|
if (!$this->validate_cert) {
|
|
$address .= '/novalidate-cert';
|
|
}
|
|
if (in_array($this->encryption,['tls','ssl'])) {
|
|
$address .= '/'.$this->encryption;
|
|
}
|
|
$address .= '}';
|
|
|
|
return $address;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the quota level settings, and usage statics per mailbox
|
|
*
|
|
* @return array
|
|
* @throws ConnectionFailedException
|
|
*/
|
|
public function getQuota() {
|
|
$this->checkConnection();
|
|
return imap_get_quota($this->getConnection(), 'user.'.$this->username);
|
|
}
|
|
|
|
/**
|
|
* Retrieve the quota settings per user
|
|
*
|
|
* @param string $quota_root
|
|
*
|
|
* @return array
|
|
* @throws ConnectionFailedException
|
|
*/
|
|
public function getQuotaRoot($quota_root = 'INBOX') {
|
|
$this->checkConnection();
|
|
return imap_get_quotaroot($this->getConnection(), $quota_root);
|
|
}
|
|
|
|
/**
|
|
* Gets the number of messages in the current mailbox
|
|
*
|
|
* @return int
|
|
* @throws ConnectionFailedException
|
|
*/
|
|
public function countMessages() {
|
|
$this->checkConnection();
|
|
return imap_num_msg($this->connection);
|
|
}
|
|
|
|
/**
|
|
* Gets the number of recent messages in current mailbox
|
|
*
|
|
* @return int
|
|
* @throws ConnectionFailedException
|
|
*/
|
|
public function countRecentMessages() {
|
|
$this->checkConnection();
|
|
return imap_num_recent($this->connection);
|
|
}
|
|
|
|
/**
|
|
* Returns all IMAP alert messages that have occurred
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getAlerts() {
|
|
return imap_alerts();
|
|
}
|
|
|
|
/**
|
|
* Returns all of the IMAP errors that have occurred
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getErrors() {
|
|
$this->errors = array_merge($this->errors, imap_errors() ?: []);
|
|
|
|
return $this->errors;
|
|
}
|
|
|
|
/**
|
|
* Gets the last IMAP error that occurred during this page request
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getLastError() {
|
|
return imap_last_error();
|
|
}
|
|
|
|
/**
|
|
* Delete all messages marked for deletion
|
|
*
|
|
* @return bool
|
|
* @throws ConnectionFailedException
|
|
*/
|
|
public function expunge() {
|
|
$this->checkConnection();
|
|
return imap_expunge($this->connection);
|
|
}
|
|
|
|
/**
|
|
* Check current mailbox
|
|
*
|
|
* @return object {
|
|
* Date [string(37) "Wed, 8 Mar 2017 22:17:54 +0100 (CET)"] current system time formatted according to » RFC2822
|
|
* Driver [string(4) "imap"] protocol used to access this mailbox: POP3, IMAP, NNTP
|
|
* Mailbox ["{root@example.com:993/imap/user="root@example.com"}INBOX"] the mailbox name
|
|
* Nmsgs [int(1)] number of messages in the mailbox
|
|
* Recent [int(0)] number of recent messages in the mailbox
|
|
* }
|
|
* @throws ConnectionFailedException
|
|
*/
|
|
public function checkCurrentMailbox() {
|
|
$this->checkConnection();
|
|
return imap_check($this->connection);
|
|
}
|
|
}
|