| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419 |
- <?php
- /*
- * File: Message.php
- * Category: -
- * Author: M. Goldenbaum
- * Created: 19.01.17 22:21
- * Updated: -
- *
- * Description:
- * -
- */
- namespace Webklex\PHPIMAP;
- use ReflectionClass;
- use ReflectionException;
- use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException;
- use Webklex\PHPIMAP\Exceptions\MaskNotFoundException;
- use Webklex\PHPIMAP\Exceptions\MessageContentFetchingException;
- use Webklex\PHPIMAP\Exceptions\MessageFlagException;
- use Webklex\PHPIMAP\Exceptions\MessageHeaderFetchingException;
- use Webklex\PHPIMAP\Exceptions\MethodNotFoundException;
- use Webklex\PHPIMAP\Support\AttachmentCollection;
- use Webklex\PHPIMAP\Support\FlagCollection;
- use Webklex\PHPIMAP\Support\Masks\MessageMask;
- use Illuminate\Support\Str;
- use Webklex\PHPIMAP\Support\MessageCollection;
- use Webklex\PHPIMAP\Traits\HasEvents;
- /**
- * Class Message
- *
- * @package Webklex\PHPIMAP
- *
- * @property integer msglist
- * @property integer uid
- * @property integer msgn
- * @property Attribute subject
- * @property Attribute message_id
- * @property Attribute message_no
- * @property Attribute references
- * @property Attribute date
- * @property Attribute from
- * @property Attribute to
- * @property Attribute cc
- * @property Attribute bcc
- * @property Attribute reply_to
- * @property Attribute in_reply_to
- * @property Attribute sender
- *
- * @method integer getMsglist()
- * @method integer setMsglist($msglist)
- * @method integer getUid()
- * @method integer getMsgn()
- * @method Attribute getPriority()
- * @method Attribute getSubject()
- * @method Attribute getMessageId()
- * @method Attribute getMessageNo()
- * @method Attribute getReferences()
- * @method Attribute getDate()
- * @method Attribute getFrom()
- * @method Attribute getTo()
- * @method Attribute getCc()
- * @method Attribute getBcc()
- * @method Attribute getReplyTo()
- * @method Attribute getInReplyTo()
- * @method Attribute getSender()
- */
- class Message {
- use HasEvents;
- /**
- * Client instance
- *
- * @var Client
- */
- private $client = Client::class;
- /**
- * Default mask
- *
- * @var string $mask
- */
- protected $mask = MessageMask::class;
- /**
- * Used config
- *
- * @var array $config
- */
- protected $config = [];
- /**
- * Attribute holder
- *
- * @var Attribute[]|mixed[] $attributes
- */
- protected $attributes = [];
- /**
- * The message folder path
- *
- * @var string $folder_path
- */
- protected $folder_path;
- /**
- * Fetch body options
- *
- * @var integer
- */
- public $fetch_options = null;
- /**
- * @var integer
- */
- protected $sequence = IMAP::NIL;
- /**
- * Fetch body options
- *
- * @var bool
- */
- public $fetch_body = null;
- /**
- * Fetch flags options
- *
- * @var bool
- */
- public $fetch_flags = null;
- /**
- * @var Header $header
- */
- public $header = null;
- /**
- * Raw message body
- *
- * @var null|string $raw_body
- */
- public $raw_body = null;
- /**
- * Message structure
- *
- * @var Structure $structure
- */
- protected $structure = null;
- /**
- * Message body components
- *
- * @var array $bodies
- */
- public $bodies = [];
- /** @var AttachmentCollection $attachments */
- public $attachments;
- /** @var FlagCollection $flags */
- public $flags;
- /**
- * A list of all available and supported flags
- *
- * @var array $available_flags
- */
- private $available_flags = null;
- /**
- * Message constructor.
- * @param integer $uid
- * @param integer|null $msglist
- * @param Client $client
- * @param integer|null $fetch_options
- * @param boolean $fetch_body
- * @param boolean $fetch_flags
- * @param integer $sequence
- *
- * @throws Exceptions\ConnectionFailedException
- * @throws InvalidMessageDateException
- * @throws Exceptions\RuntimeException
- * @throws MessageHeaderFetchingException
- * @throws MessageContentFetchingException
- * @throws Exceptions\EventNotFoundException
- * @throws MessageFlagException
- * @throws Exceptions\MessageNotFoundException
- */
- public function __construct($uid, $msglist, Client $client, $fetch_options = null, $fetch_body = false, $fetch_flags = false, $sequence = null) {
- $this->boot();
- $default_mask = $client->getDefaultMessageMask();
- if($default_mask != null) {
- $this->mask = $default_mask;
- }
- $this->events["message"] = $client->getDefaultEvents("message");
- $this->events["flag"] = $client->getDefaultEvents("flag");
- $this->folder_path = $client->getFolderPath();
- $this->setSequence($sequence);
- $this->setFetchOption($fetch_options);
- $this->setFetchBodyOption($fetch_body);
- $this->setFetchFlagsOption($fetch_flags);
- $this->client = $client;
- $this->client->openFolder($this->folder_path);
- $this->setSequenceId($uid, $msglist);
- if ($this->fetch_options == IMAP::FT_PEEK) {
- $this->parseFlags();
- }
- $this->parseHeader();
- if ($this->getFetchBodyOption() === true) {
- $this->parseBody();
- }
- if ($this->getFetchFlagsOption() === true && $this->fetch_options !== IMAP::FT_PEEK) {
- $this->parseFlags();
- }
- }
- /**
- * Create a new instance without fetching the message header and providing them raw instead
- * @param int $uid
- * @param int|null $msglist
- * @param Client $client
- * @param string $raw_header
- * @param string $raw_body
- * @param array $raw_flags
- * @param null $fetch_options
- * @param null $sequence
- *
- * @return Message
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\EventNotFoundException
- * @throws InvalidMessageDateException
- * @throws MessageContentFetchingException
- * @throws ReflectionException
- * @throws MessageFlagException
- * @throws Exceptions\RuntimeException
- * @throws Exceptions\MessageNotFoundException
- */
- public static function make($uid, $msglist, Client $client, $raw_header, $raw_body, $raw_flags, $fetch_options = null, $sequence = null){
- $reflection = new ReflectionClass(self::class);
- /** @var self $instance */
- $instance = $reflection->newInstanceWithoutConstructor();
- $instance->boot();
- $default_mask = $client->getDefaultMessageMask();
- if($default_mask != null) {
- $instance->setMask($default_mask);
- }
- $instance->setEvents([
- "message" => $client->getDefaultEvents("message"),
- "flag" => $client->getDefaultEvents("flag"),
- ]);
- $instance->setFolderPath($client->getFolderPath());
- $instance->setSequence($sequence);
- $instance->setFetchOption($fetch_options);
- $instance->setClient($client);
- $instance->setSequenceId($uid, $msglist);
- $instance->parseRawHeader($raw_header);
- $instance->parseRawFlags($raw_flags);
- $instance->parseRawBody($raw_body);
- $instance->peek();
- return $instance;
- }
- /**
- * Boot a new instance
- */
- public function boot(){
- $this->attributes = [];
- $this->config = ClientManager::get('options');
- $this->available_flags = ClientManager::get('flags');
- $this->attachments = AttachmentCollection::make([]);
- $this->flags = FlagCollection::make([]);
- }
- /**
- * Call dynamic attribute setter and getter methods
- * @param string $method
- * @param array $arguments
- *
- * @return mixed
- * @throws MethodNotFoundException
- */
- public function __call($method, $arguments) {
- if(strtolower(substr($method, 0, 3)) === 'get') {
- $name = Str::snake(substr($method, 3));
- return $this->get($name);
- }elseif (strtolower(substr($method, 0, 3)) === 'set') {
- $name = Str::snake(substr($method, 3));
- if(in_array($name, array_keys($this->attributes))) {
- return $this->__set($name, array_pop($arguments));
- }
- }
- throw new MethodNotFoundException("Method ".self::class.'::'.$method.'() is not supported');
- }
- /**
- * Magic setter
- * @param $name
- * @param $value
- *
- * @return mixed
- */
- public function __set($name, $value) {
- $this->attributes[$name] = $value;
- return $this->attributes[$name];
- }
- /**
- * Magic getter
- * @param $name
- *
- * @return Attribute|mixed|null
- */
- public function __get($name) {
- return $this->get($name);
- }
- /**
- * Get an available message or message header attribute
- * @param $name
- *
- * @return Attribute|mixed|null
- */
- public function get($name) {
- if(isset($this->attributes[$name])) {
- return $this->attributes[$name];
- }
- return $this->header->get($name);
- }
- /**
- * Check if the Message has a text body
- *
- * @return bool
- */
- public function hasTextBody() {
- return isset($this->bodies['text']);
- }
- /**
- * Get the Message text body
- *
- * @return mixed
- */
- public function getTextBody() {
- if (!isset($this->bodies['text'])) {
- return null;
- }
- return $this->bodies['text'];
- }
- /**
- * Check if the Message has a html body
- *
- * @return bool
- */
- public function hasHTMLBody() {
- return isset($this->bodies['html']);
- }
- /**
- * Get the Message html body
- *
- * @return string|null
- */
- public function getHTMLBody() {
- if (!isset($this->bodies['html'])) {
- return null;
- }
- return $this->bodies['html'];
- }
- /**
- * Parse all defined headers
- *
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\RuntimeException
- * @throws InvalidMessageDateException
- * @throws MessageHeaderFetchingException
- */
- private function parseHeader() {
- $sequence_id = $this->getSequenceId();
- $headers = $this->client->getConnection()->headers([$sequence_id], "RFC822", $this->sequence === IMAP::ST_UID);
- if (!isset($headers[$sequence_id])) {
- throw new MessageHeaderFetchingException("no headers found", 0);
- }
- $this->parseRawHeader($headers[$sequence_id]);
- }
- /**
- * @param string $raw_header
- *
- * @throws InvalidMessageDateException
- */
- public function parseRawHeader($raw_header){
- $this->header = new Header($raw_header);
- }
- /**
- * Parse additional raw flags
- * @param array $raw_flags
- */
- public function parseRawFlags($raw_flags) {
- $this->flags = FlagCollection::make([]);
- foreach($raw_flags as $flag) {
- if (strpos($flag, "\\") === 0){
- $flag = substr($flag, 1);
- }
- $flag_key = strtolower($flag);
- if ($this->available_flags === null || in_array($flag_key, $this->available_flags)) {
- $this->flags->put($flag_key, $flag);
- }
- }
- }
- /**
- * Parse additional flags
- *
- * @return void
- * @throws Exceptions\ConnectionFailedException
- * @throws MessageFlagException
- * @throws Exceptions\RuntimeException
- */
- private function parseFlags() {
- $this->client->openFolder($this->folder_path);
- $this->flags = FlagCollection::make([]);
- $sequence_id = $this->getSequenceId();
- try {
- $flags = $this->client->getConnection()->flags([$sequence_id], $this->sequence === IMAP::ST_UID);
- } catch (Exceptions\RuntimeException $e) {
- throw new MessageFlagException("flag could not be fetched", 0, $e);
- }
- if (isset($flags[$sequence_id])) {
- $this->parseRawFlags($flags[$sequence_id]);
- }
- }
- /**
- * Parse the Message body
- *
- * @return $this
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\MessageContentFetchingException
- * @throws InvalidMessageDateException
- * @throws Exceptions\EventNotFoundException
- * @throws MessageFlagException
- * @throws Exceptions\RuntimeException
- */
- public function parseBody() {
- $this->client->openFolder($this->folder_path);
- $sequence_id = $this->getSequenceId();
- try {
- $contents = $this->client->getConnection()->content([$sequence_id], "RFC822", $this->sequence === IMAP::ST_UID);
- } catch (Exceptions\RuntimeException $e) {
- throw new MessageContentFetchingException("failed to fetch content", 0);
- }
- if (!isset($contents[$sequence_id])) {
- throw new MessageContentFetchingException("no content found", 0);
- }
- $content = $contents[$sequence_id];
- $body = $this->parseRawBody($content);
- $this->peek();
- return $body;
- }
- /**
- * Handle auto "Seen" flag handling
- *
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\EventNotFoundException
- * @throws MessageFlagException
- * @throws Exceptions\RuntimeException
- */
- public function peek(){
- if ($this->fetch_options == IMAP::FT_PEEK) {
- if ($this->getFlags()->get("seen") == null) {
- $this->unsetFlag("Seen");
- }
- }elseif ($this->getFlags()->get("seen") != null) {
- $this->setFlag("Seen");
- }
- }
- /**
- * Parse a given message body
- * @param string $raw_body
- *
- * @return $this
- * @throws Exceptions\ConnectionFailedException
- * @throws InvalidMessageDateException
- * @throws MessageContentFetchingException
- * @throws Exceptions\RuntimeException
- */
- public function parseRawBody($raw_body) {
- $this->structure = new Structure($raw_body, $this->header);
- $this->fetchStructure($this->structure);
- return $this;
- }
- /**
- * Fetch the Message structure
- * @param Structure $structure
- *
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\RuntimeException
- */
- private function fetchStructure($structure) {
- $this->client->openFolder($this->folder_path);
- foreach ($structure->parts as $part) {
- $this->fetchPart($part);
- }
- }
- /**
- * Fetch a given part
- * @param Part $part
- */
- private function fetchPart(Part $part) {
- if ($part->isAttachment()) {
- $this->fetchAttachment($part);
- }else{
- $encoding = $this->getEncoding($part);
- $content = $this->decodeString($part->content, $part->encoding);
- // We don't need to do convertEncoding() if charset is ASCII (us-ascii):
- // ASCII is a subset of UTF-8, so all ASCII files are already UTF-8 encoded
- // https://stackoverflow.com/a/11303410
- //
- // us-ascii is the same as ASCII:
- // ASCII is the traditional name for the encoding system; the Internet Assigned Numbers Authority (IANA)
- // prefers the updated name US-ASCII, which clarifies that this system was developed in the US and
- // based on the typographical symbols predominantly in use there.
- // https://en.wikipedia.org/wiki/ASCII
- //
- // convertEncoding() function basically means convertToUtf8(), so when we convert ASCII string into UTF-8 it gets broken.
- if ($encoding != 'us-ascii') {
- $content = $this->convertEncoding($content, $encoding);
- }
- $subtype = strtolower($part->subtype);
- $subtype = $subtype == "plain" || $subtype == "" ? "text" : $subtype;
- if (isset($this->bodies[$subtype])) {
- $this->bodies[$subtype] .= "\n".$content;
- }else{
- $this->bodies[$subtype] = $content;
- }
- }
- }
- /**
- * Fetch the Message attachment
- * @param Part $part
- */
- protected function fetchAttachment($part) {
- $oAttachment = new Attachment($this, $part);
- if ($oAttachment->getName() !== null && $oAttachment->getSize() > 0) {
- if ($oAttachment->getId() !== null) {
- $this->attachments->put($oAttachment->getId(), $oAttachment);
- } else {
- $this->attachments->push($oAttachment);
- }
- }
- }
- /**
- * Fail proof setter for $fetch_option
- * @param $option
- *
- * @return $this
- */
- public function setFetchOption($option) {
- if (is_long($option) === true) {
- $this->fetch_options = $option;
- } elseif (is_null($option) === true) {
- $config = ClientManager::get('options.fetch', IMAP::FT_UID);
- $this->fetch_options = is_long($config) ? $config : 1;
- }
- return $this;
- }
- /**
- * Set the sequence type
- * @param int $sequence
- *
- * @return $this
- */
- public function setSequence($sequence) {
- if (is_long($sequence)) {
- $this->sequence = $sequence;
- } elseif (is_null($sequence)) {
- $config = ClientManager::get('options.sequence', IMAP::ST_MSGN);
- $this->sequence = is_long($config) ? $config : IMAP::ST_MSGN;
- }
- return $this;
- }
- /**
- * Fail proof setter for $fetch_body
- * @param $option
- *
- * @return $this
- */
- public function setFetchBodyOption($option) {
- if (is_bool($option)) {
- $this->fetch_body = $option;
- } elseif (is_null($option)) {
- $config = ClientManager::get('options.fetch_body', true);
- $this->fetch_body = is_bool($config) ? $config : true;
- }
- return $this;
- }
- /**
- * Fail proof setter for $fetch_flags
- * @param $option
- *
- * @return $this
- */
- public function setFetchFlagsOption($option) {
- if (is_bool($option)) {
- $this->fetch_flags = $option;
- } elseif (is_null($option)) {
- $config = ClientManager::get('options.fetch_flags', true);
- $this->fetch_flags = is_bool($config) ? $config : true;
- }
- return $this;
- }
- /**
- * Decode a given string
- * @param $string
- * @param $encoding
- *
- * @return string
- */
- public function decodeString($string, $encoding) {
- switch ($encoding) {
- case IMAP::MESSAGE_ENC_BINARY:
- if (extension_loaded('imap')) {
- return base64_decode(\imap_binary($string));
- }
- return base64_decode($string);
- case IMAP::MESSAGE_ENC_BASE64:
- return base64_decode($string);
- case IMAP::MESSAGE_ENC_QUOTED_PRINTABLE:
- return quoted_printable_decode($string);
- case IMAP::MESSAGE_ENC_8BIT:
- case IMAP::MESSAGE_ENC_7BIT:
- case IMAP::MESSAGE_ENC_OTHER:
- default:
- return $string;
- }
- }
- /**
- * Convert the encoding
- * @param $str
- * @param string $from
- * @param string $to
- *
- * @return mixed|string
- */
- public function convertEncoding($str, $from = "ISO-8859-2", $to = "UTF-8") {
- $from = EncodingAliases::get($from);
- $to = EncodingAliases::get($to);
- if ($from === $to) {
- return $str;
- }
- // We don't need to do convertEncoding() if charset is ASCII (us-ascii):
- // ASCII is a subset of UTF-8, so all ASCII files are already UTF-8 encoded
- // https://stackoverflow.com/a/11303410
- //
- // us-ascii is the same as ASCII:
- // ASCII is the traditional name for the encoding system; the Internet Assigned Numbers Authority (IANA)
- // prefers the updated name US-ASCII, which clarifies that this system was developed in the US and
- // based on the typographical symbols predominantly in use there.
- // https://en.wikipedia.org/wiki/ASCII
- //
- // convertEncoding() function basically means convertToUtf8(), so when we convert ASCII string into UTF-8 it gets broken.
- if (strtolower($from) == 'us-ascii' && $to == 'UTF-8') {
- return $str;
- }
- if (function_exists('iconv') && $from != 'UTF-7' && $to != 'UTF-7') {
- return @iconv($from, $to.'//IGNORE', $str);
- } else {
- if (!$from) {
- return mb_convert_encoding($str, $to);
- }
- return mb_convert_encoding($str, $to, $from);
- }
- }
- /**
- * Get the encoding of a given abject
- * @param object|string $structure
- *
- * @return string
- */
- public function getEncoding($structure) {
- if (property_exists($structure, 'parameters')) {
- foreach ($structure->parameters as $parameter) {
- if (strtolower($parameter->attribute) == "charset") {
- return EncodingAliases::get($parameter->value);
- }
- }
- }elseif (property_exists($structure, 'charset')){
- return EncodingAliases::get($structure->charset);
- }elseif (is_string($structure) === true){
- return mb_detect_encoding($structure);
- }
- return 'UTF-8';
- }
- /**
- * Get the messages folder
- *
- * @return mixed
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\FolderFetchingException
- * @throws Exceptions\RuntimeException
- */
- public function getFolder(){
- return $this->client->getFolderByPath($this->folder_path);
- }
- /**
- * Create a message thread based on the current message
- * @param Folder|null $sent_folder
- * @param MessageCollection|null $thread
- * @param Folder|null $folder
- *
- * @return MessageCollection|null
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\FolderFetchingException
- * @throws Exceptions\GetMessagesFailedException
- * @throws Exceptions\RuntimeException
- */
- public function thread($sent_folder = null, &$thread = null, $folder = null){
- $thread = $thread ? $thread : MessageCollection::make([]);
- $folder = $folder ? $folder : $this->getFolder();
- $sent_folder = $sent_folder ? $sent_folder : $this->client->getFolderByPath(ClientManager::get("options.common_folders.sent", "INBOX/Sent"));
- /** @var Message $message */
- foreach($thread as $message) {
- if ($message->message_id->first() == $this->message_id->first()) {
- return $thread;
- }
- }
- $thread->push($this);
- $this->fetchThreadByInReplyTo($thread, $this->message_id, $folder, $folder, $sent_folder);
- $this->fetchThreadByInReplyTo($thread, $this->message_id, $sent_folder, $folder, $sent_folder);
- if (is_array($this->in_reply_to)) {
- foreach($this->in_reply_to as $in_reply_to) {
- $this->fetchThreadByMessageId($thread, $in_reply_to, $folder, $folder, $sent_folder);
- $this->fetchThreadByMessageId($thread, $in_reply_to, $sent_folder, $folder, $sent_folder);
- }
- }
- return $thread;
- }
- /**
- * Fetch a partial thread by message id
- * @param MessageCollection $thread
- * @param string $in_reply_to
- * @param Folder $primary_folder
- * @param Folder $secondary_folder
- * @param Folder $sent_folder
- *
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\GetMessagesFailedException
- * @throws Exceptions\RuntimeException
- */
- protected function fetchThreadByInReplyTo(&$thread, $in_reply_to, $primary_folder, $secondary_folder, $sent_folder){
- $primary_folder->query()->inReplyTo($in_reply_to)
- ->setFetchBody($this->getFetchBodyOption())
- ->leaveUnread()->get()->each(function($message) use(&$thread, $secondary_folder, $sent_folder){
- /** @var Message $message */
- $message->thread($sent_folder, $thread, $secondary_folder);
- });
- }
- /**
- * Fetch a partial thread by message id
- * @param MessageCollection $thread
- * @param string $message_id
- * @param Folder $primary_folder
- * @param Folder $secondary_folder
- * @param Folder $sent_folder
- *
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\GetMessagesFailedException
- * @throws Exceptions\RuntimeException
- */
- protected function fetchThreadByMessageId(&$thread, $message_id, $primary_folder, $secondary_folder, $sent_folder){
- $primary_folder->query()->messageId($message_id)
- ->setFetchBody($this->getFetchBodyOption())
- ->leaveUnread()->get()->each(function($message) use(&$thread, $secondary_folder, $sent_folder){
- /** @var Message $message */
- $message->thread($sent_folder, $thread, $secondary_folder);
- });
- }
- /**
- * Copy the current Messages to a mailbox
- * @param string $folder_path
- * @param boolean $expunge
- *
- * @return null|Message
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\FolderFetchingException
- * @throws Exceptions\RuntimeException
- * @throws InvalidMessageDateException
- * @throws MessageContentFetchingException
- * @throws MessageHeaderFetchingException
- * @throws Exceptions\EventNotFoundException
- * @throws MessageFlagException
- * @throws Exceptions\MessageNotFoundException
- */
- public function copy($folder_path, $expunge = false) {
- $this->client->openFolder($folder_path);
- $status = $this->client->getConnection()->examineFolder($folder_path);
- if (isset($status["uidnext"])) {
- $next_uid = $status["uidnext"];
- /** @var Folder $folder */
- $folder = $this->client->getFolderByPath($folder_path);
- $this->client->openFolder($this->folder_path);
- if ($this->client->getConnection()->copyMessage($folder->path, $this->getSequenceId(), null, $this->sequence === IMAP::ST_UID) == true) {
- return $this->fetchNewMail($folder, $next_uid, "copied", $expunge);
- }
- }
- return null;
- }
- /**
- * Move the current Messages to a mailbox
- * @param string $folder_path
- * @param boolean $expunge
- *
- * @return Message|null
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\FolderFetchingException
- * @throws Exceptions\RuntimeException
- * @throws InvalidMessageDateException
- * @throws MessageContentFetchingException
- * @throws MessageHeaderFetchingException
- * @throws Exceptions\EventNotFoundException
- * @throws MessageFlagException
- * @throws Exceptions\MessageNotFoundException
- */
- public function move($folder_path, $expunge = false) {
- $this->client->openFolder($folder_path);
- $status = $this->client->getConnection()->examineFolder($folder_path);
- if (isset($status["uidnext"])) {
- $next_uid = $status["uidnext"];
- /** @var Folder $folder */
- $folder = $this->client->getFolderByPath($folder_path);
- $this->client->openFolder($this->folder_path);
- if ($this->client->getConnection()->moveMessage($folder->path, $this->getSequenceId(), null, $this->sequence === IMAP::ST_UID) == true) {
- return $this->fetchNewMail($folder, $next_uid, "moved", $expunge);
- }
- }
- return null;
- }
- /**
- * Fetch a new message and fire a given event
- * @param Folder $folder
- * @param int $next_uid
- * @param string $event
- * @param boolean $expunge
- *
- * @return mixed
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\EventNotFoundException
- * @throws Exceptions\MessageNotFoundException
- * @throws Exceptions\RuntimeException
- * @throws InvalidMessageDateException
- * @throws MessageContentFetchingException
- * @throws MessageFlagException
- * @throws MessageHeaderFetchingException
- */
- protected function fetchNewMail($folder, $next_uid, $event, $expunge){
- if($expunge) $this->client->expunge();
- $this->client->openFolder($folder->path);
- if ($this->sequence === IMAP::ST_UID) {
- $sequence_id = $next_uid;
- }else{
- $sequence_id = $this->client->getConnection()->getMessageNumber($next_uid);
- }
- $message = $folder->query()->getMessage($sequence_id, null, $this->sequence);
- $event = $this->getEvent("message", $event);
- $event::dispatch($this, $message);
- return $message;
- }
- /**
- * Delete the current Message
- * @param bool $expunge
- *
- * @return bool
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\EventNotFoundException
- * @throws MessageFlagException
- * @throws Exceptions\RuntimeException
- */
- public function delete($expunge = true) {
- $status = $this->setFlag("Deleted");
- if($expunge) $this->client->expunge();
- $event = $this->getEvent("message", "deleted");
- $event::dispatch($this);
- return $status;
- }
- /**
- * Restore a deleted Message
- * @param boolean $expunge
- *
- * @return bool
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\EventNotFoundException
- * @throws MessageFlagException
- * @throws Exceptions\RuntimeException
- */
- public function restore($expunge = true) {
- $status = $this->unsetFlag("Deleted");
- if($expunge) $this->client->expunge();
- $event = $this->getEvent("message", "restored");
- $event::dispatch($this);
- return $status;
- }
- /**
- * Set a given flag
- * @param string|array $flag
- *
- * @return bool
- * @throws Exceptions\ConnectionFailedException
- * @throws MessageFlagException
- * @throws Exceptions\EventNotFoundException
- * @throws Exceptions\RuntimeException
- */
- public function setFlag($flag) {
- $this->client->openFolder($this->folder_path);
- $flag = "\\".trim(is_array($flag) ? implode(" \\", $flag) : $flag);
- $sequence_id = $this->getSequenceId();
- try {
- $status = $this->client->getConnection()->store([$flag], $sequence_id, $sequence_id, "+", true, $this->sequence === IMAP::ST_UID);
- } catch (Exceptions\RuntimeException $e) {
- throw new MessageFlagException("flag could not be set", 0, $e);
- }
- $this->parseFlags();
- $event = $this->getEvent("flag", "new");
- $event::dispatch($this, $flag);
- return $status;
- }
- /**
- * Unset a given flag
- * @param string|array $flag
- *
- * @return bool
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\EventNotFoundException
- * @throws MessageFlagException
- * @throws Exceptions\RuntimeException
- */
- public function unsetFlag($flag) {
- $this->client->openFolder($this->folder_path);
- $flag = "\\".trim(is_array($flag) ? implode(" \\", $flag) : $flag);
- $sequence_id = $this->getSequenceId();
- try {
- $status = $this->client->getConnection()->store([$flag], $sequence_id, $sequence_id, "-", true, $this->sequence === IMAP::ST_UID);
- } catch (Exceptions\RuntimeException $e) {
- throw new MessageFlagException("flag could not be removed", 0, $e);
- }
- $this->parseFlags();
- $event = $this->getEvent("flag", "deleted");
- $event::dispatch($this, $flag);
- return $status;
- }
- /**
- * Set a given flag
- * @param string|array $flag
- *
- * @return bool
- * @throws Exceptions\ConnectionFailedException
- * @throws MessageFlagException
- * @throws Exceptions\EventNotFoundException
- * @throws Exceptions\RuntimeException
- */
- public function addFlag($flag) {
- return $this->setFlag($flag);
- }
- /**
- * Unset a given flag
- * @param string|array $flag
- *
- * @return bool
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\EventNotFoundException
- * @throws MessageFlagException
- * @throws Exceptions\RuntimeException
- */
- public function removeFlag($flag) {
- return $this->unsetFlag($flag);
- }
- /**
- * Get all message attachments.
- *
- * @return AttachmentCollection
- */
- public function getAttachments() {
- return $this->attachments;
- }
- /**
- * Get all message attachments.
- *
- * @return AttachmentCollection
- */
- public function attachments(){
- return $this->getAttachments();
- }
- /**
- * Checks if there are any attachments present
- *
- * @return boolean
- */
- public function hasAttachments() {
- return $this->attachments->isEmpty() === false;
- }
- /**
- * Get the raw body
- *
- * @return string
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\RuntimeException
- */
- public function getRawBody() {
- if ($this->raw_body === null) {
- $this->client->openFolder($this->folder_path);
- $this->raw_body = $this->structure->raw;
- }
- return $this->raw_body;
- }
- /**
- * Get the message header
- *
- * @return Header
- */
- public function getHeader() {
- return $this->header;
- }
- /**
- * Get the current client
- *
- * @return Client
- */
- public function getClient() {
- return $this->client;
- }
- /**
- * Get the used fetch option
- *
- * @return integer
- */
- public function getFetchOptions() {
- return $this->fetch_options;
- }
- /**
- * Get the used fetch body option
- *
- * @return boolean
- */
- public function getFetchBodyOption() {
- return $this->fetch_body;
- }
- /**
- * Get the used fetch flags option
- *
- * @return boolean
- */
- public function getFetchFlagsOption() {
- return $this->fetch_flags;
- }
- /**
- * Get all available bodies
- *
- * @return array
- */
- public function getBodies() {
- return $this->bodies;
- }
- /**
- * Get all set flags
- *
- * @return FlagCollection
- */
- public function getFlags() {
- return $this->flags;
- }
- /**
- * Get all set flags
- *
- * @return FlagCollection
- */
- public function flags(){
- return $this->getFlags();
- }
- /**
- * Get the fetched structure
- *
- * @return Structure|null
- */
- public function getStructure(){
- return $this->structure;
- }
- /**
- * Check if a message matches an other by comparing basic attributes
- *
- * @param null|Message $message
- * @return boolean
- */
- public function is(Message $message = null) {
- if (is_null($message)) {
- return false;
- }
- return $this->uid == $message->uid
- && $this->message_id->first() == $message->message_id->first()
- && $this->subject->first() == $message->subject->first()
- && $this->date->toDate()->eq($message->date);
- }
- /**
- * Get all message attributes
- *
- * @return array
- */
- public function getAttributes(){
- return array_merge($this->attributes, $this->header->getAttributes());
- }
- /**
- * Set the message mask
- * @param $mask
- *
- * @return $this
- */
- public function setMask($mask){
- if(class_exists($mask)){
- $this->mask = $mask;
- }
- return $this;
- }
- /**
- * Get the used message mask
- *
- * @return string
- */
- public function getMask(){
- return $this->mask;
- }
- /**
- * Get a masked instance by providing a mask name
- * @param string|null $mask
- *
- * @return mixed
- * @throws MaskNotFoundException
- */
- public function mask($mask = null){
- $mask = $mask !== null ? $mask : $this->mask;
- if(class_exists($mask)){
- return new $mask($this);
- }
- throw new MaskNotFoundException("Unknown mask provided: ".$mask);
- }
- /**
- * Get the message path aka folder path
- *
- * @return string
- */
- public function getFolderPath(){
- return $this->folder_path;
- }
- /**
- * Set the message path aka folder path
- * @param $folder_path
- *
- * @return $this
- */
- public function setFolderPath($folder_path){
- $this->folder_path = $folder_path;
- return $this;
- }
- /**
- * Set the config
- * @param $config
- *
- * @return $this
- */
- public function setConfig($config){
- $this->config = $config;
- return $this;
- }
- /**
- * Set the available flags
- * @param $available_flags
- *
- * @return $this
- */
- public function setAvailableFlags($available_flags){
- $this->available_flags = $available_flags;
- return $this;
- }
- /**
- * Set the attachment collection
- * @param $attachments
- *
- * @return $this
- */
- public function setAttachments($attachments){
- $this->attachments = $attachments;
- return $this;
- }
- /**
- * Set the flag collection
- * @param $flags
- *
- * @return $this
- */
- public function setFlags($flags){
- $this->flags = $flags;
- return $this;
- }
- /**
- * Set the client
- * @param $client
- *
- * @return $this
- * @throws Exceptions\RuntimeException
- * @throws Exceptions\ConnectionFailedException
- */
- public function setClient($client){
- $this->client = $client;
- $this->client->openFolder($this->folder_path);
- return $this;
- }
- /**
- * Set the message number
- * @param int $uid
- *
- * @return $this
- * @throws Exceptions\MessageNotFoundException
- * @throws Exceptions\ConnectionFailedException
- */
- public function setUid($uid){
- $this->uid = $uid;
- $this->msgn = $this->client->getConnection()->getMessageNumber($this->uid);
- $this->msglist = null;
- return $this;
- }
- /**
- * Set the message number
- * @param $msgn
- * @param int|null $msglist
- *
- * @return $this
- * @throws Exceptions\MessageNotFoundException
- * @throws Exceptions\ConnectionFailedException
- */
- public function setMsgn($msgn, $msglist = null){
- $this->msgn = $msgn;
- $this->msglist = $msglist;
- $this->uid = $this->client->getConnection()->getUid($this->msgn);
- return $this;
- }
- /**
- * Get the current sequence type
- *
- * @return int
- */
- public function getSequence(){
- return $this->sequence;
- }
- /**
- * Set the sequence type
- *
- * @return int
- */
- public function getSequenceId(){
- return $this->sequence === IMAP::ST_UID ? $this->uid : $this->msgn;
- }
- /**
- * Set the sequence id
- * @param $uid
- * @param int|null $msglist
- *
- * @throws Exceptions\ConnectionFailedException
- * @throws Exceptions\MessageNotFoundException
- */
- public function setSequenceId($uid, $msglist = null){
- if ($this->getSequence() === IMAP::ST_UID) {
- $this->setUid($uid);
- $this->setMsglist($msglist);
- }else{
- $this->setMsgn($uid, $msglist);
- }
- }
- }
|