Completed
Pull Request — master (#98)
by
unknown
03:34
created

Message::parseFlags()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 2
nop 0
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/*
3
* File:     Message.php
4
* Category: -
5
* Author:   M. Goldenbaum
6
* Created:  19.01.17 22:21
7
* Updated:  -
8
*
9
* Description:
10
*  -
11
*/
12
13
namespace Webklex\IMAP;
14
15
use Carbon\Carbon;
16
use Webklex\IMAP\Support\AttachmentCollection;
17
18
/**
19
 * Class Message
20
 *
21
 * @package Webklex\IMAP
22
 */
23
class Message {
24
25
    /**
26
     * Client instance
27
     *
28
     * @var Client
29
     */
30
    private $client = Client::class;
31
32
    /**
33
     * U ID
34
     *
35
     * @var integer
36
     */
37
    public $uid = '';
38
39
    /**
40
     * Fetch body options
41
     *
42
     * @var integer
43
     */
44
    public $fetch_options = null;
45
46
    /**
47
     * Fetch body options
48
     *
49
     * @var bool
50
     */
51
    public $fetch_body = null;
52
53
    /**
54
     * Fetch attachments options
55
     *
56
     * @var bool
57
     */
58
    public $fetch_attachment = null;
59
60
    /**
61
     * @var int $msglist
62
     */
63
    public $msglist = 1;
64
65
    /**
66
     * @var string $header
67
     */
68
    public $header = null;
69
70
    /**
71
     * @var null|object $header_info
72
     */
73
    public $header_info = null;
74
75
    /** @var null|string $raw_body */
76
    public $raw_body = null;
77
78
    /**
79
     * Message header components
80
     *
81
     * @var string  $message_id
82
     * @var mixed   $message_no
83
     * @var string  $subject
84
     * @var mixed   $references
85
     * @var mixed   $date
86
     * @var array   $from
87
     * @var array   $to
88
     * @var array   $cc
89
     * @var array   $bcc
90
     * @var array   $reply_to
91
     * @var string  $in_reply_to
92
     * @var array   $sender
93
     * @var array   $flags
94
     */
95
    public $message_id = '';
96
    public $message_no = null;
97
    public $subject = '';
98
    public $references = null;
99
    public $date = null;
100
    public $from = [];
101
    public $to = [];
102
    public $cc = [];
103
    public $bcc = [];
104
    public $reply_to = [];
105
    public $in_reply_to = '';
106
    public $sender = [];
107
    public $flags = [];
108
109
    /**
110
     * Message body components
111
     *
112
     * @var array   $bodies
113
     * @var AttachmentCollection|array  $attachments
114
     */
115
    public $bodies = [];
116
    public $attachments = [];
117
118
    /**
119
     * Message const
120
     *
121
     * @const integer   TYPE_TEXT
122
     * @const integer   TYPE_MULTIPART
123
     *
124
     * @const integer   ENC_7BIT
125
     * @const integer   ENC_8BIT
126
     * @const integer   ENC_BINARY
127
     * @const integer   ENC_BASE64
128
     * @const integer   ENC_QUOTED_PRINTABLE
129
     * @const integer   ENC_OTHER
130
     */
131
    const TYPE_TEXT = 0;
132
    const TYPE_MULTIPART = 1;
133
134
    const ENC_7BIT = 0;
135
    const ENC_8BIT = 1;
136
    const ENC_BINARY = 2;
137
    const ENC_BASE64 = 3;
138
    const ENC_QUOTED_PRINTABLE = 4;
139
    const ENC_OTHER = 5;
140
141
    /**
142
     * Message constructor.
143
     *
144
     * @param integer       $uid
145
     * @param integer|null  $msglist
146
     * @param Client        $client
147
     * @param integer|null  $fetch_options
148
     * @param boolean       $fetch_body
149
     * @param boolean       $fetch_attachment
150
     */
151
    public function __construct($uid, $msglist, Client $client, $fetch_options = null, $fetch_body = false, $fetch_attachment = false) {
152
        $this->setFetchOption($fetch_options);
153
        $this->setFetchBodyOption($fetch_body);
154
        $this->setFetchAttachmentOption($fetch_attachment);
155
156
        $this->attachments = AttachmentCollection::make([]);
157
        
158
        $this->msglist = $msglist;
159
        $this->client = $client;
160
        $this->uid = ($this->fetch_options == FT_UID) ? $uid : imap_msgno($this->client->getConnection(), $uid);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type boolean; however, parameter $imap_stream of imap_msgno() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

160
        $this->uid = ($this->fetch_options == FT_UID) ? $uid : imap_msgno(/** @scrutinizer ignore-type */ $this->client->getConnection(), $uid);
Loading history...
161
        
162
        $this->parseHeader();
163
        $this->parseFlags();
164
165
        if ($this->getFetchBodyOption() === true) {
166
            $this->parseBody();
167
        }
168
    }
169
170
    /**
171
     * Copy the current Messages to a mailbox
172
     *
173
     * @param $mailbox
174
     * @param int $options
175
     *
176
     * @return bool
177
     */
178
    public function copy($mailbox, $options = 0) {
179
        return imap_mail_copy($this->client->getConnection(), $this->msglist, $mailbox, $options);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type boolean; however, parameter $imap_stream of imap_mail_copy() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

179
        return imap_mail_copy(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->msglist, $mailbox, $options);
Loading history...
180
    }
181
182
    /**
183
     * Move the current Messages to a mailbox
184
     *
185
     * @param $mailbox
186
     * @param int $options
187
     *
188
     * @return bool
189
     */
190
    public function move($mailbox, $options = 0) {
191
        return imap_mail_move($this->client->getConnection(), $this->msglist, $mailbox, $options);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type boolean; however, parameter $imap_stream of imap_mail_move() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

191
        return imap_mail_move(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->msglist, $mailbox, $options);
Loading history...
192
    }
193
194
    /**
195
     * Check if the Message has a text body
196
     *
197
     * @return bool
198
     */
199
    public function hasTextBody() {
200
        return isset($this->bodies['text']);
201
    }
202
203
    /**
204
     * Get the Message text body
205
     *
206
     * @return mixed
207
     */
208
    public function getTextBody() {
209
        if (!isset($this->bodies['text'])) {
210
            return false;
211
        }
212
213
        return $this->bodies['text']->content;
214
    }
215
216
    /**
217
     * Check if the Message has a html body
218
     *
219
     * @return bool
220
     */
221
    public function hasHTMLBody() {
222
        return isset($this->bodies['html']);
223
    }
224
225
    /**
226
     * Get the Message html body
227
     *
228
     * @var bool $replaceImages
229
     *
230
     * @return mixed
231
     */
232
    public function getHTMLBody($replaceImages = false) {
233
        if (!isset($this->bodies['html'])) {
234
            return false;
235
        }
236
237
        $body = $this->bodies['html']->content;
238
        if ($replaceImages) {
239
            $this->attachments->each(function($oAttachment) use(&$body){
240
                if ($oAttachment->id && isset($oAttachment->img_src)) {
241
                    $body = str_replace('cid:'.$oAttachment->id, $oAttachment->img_src, $body);
242
                }
243
            });
244
        }
245
246
        return $body;
247
    }
248
249
    /**
250
     * Parse all defined headers
251
     *
252
     * @return void
253
     */
254
    private function parseHeader() {
255
        $this->header = $header = imap_fetchheader($this->client->getConnection(), $this->uid, $this->fetch_options);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type boolean; however, parameter $imap_stream of imap_fetchheader() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

255
        $this->header = $header = imap_fetchheader(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, $this->fetch_options);
Loading history...
256
        if ($this->header) {
257
            $header = imap_rfc822_parse_headers($this->header);
258
        }
259
260
        if (property_exists($header, 'subject')) {
261
            $this->subject = imap_utf8($header->subject);
262
        }
263
        if (property_exists($header, 'date')) {
264
            $date = $header->date;
265
266
            /**
267
             * Exception handling for invalid dates
268
             * Will be extended in the future
269
             *
270
             * Currently known invalid formats:
271
             * ^ Datetime                                   ^ Problem                           ^ Cause                 
272
             * | Mon, 20 Nov 2017 20:31:31 +0800 (GMT+8:00) | Double timezone specification     | A Windows feature
273
             * |                                            | and invalid timezone (max 6 char) |
274
             * | 04 Jan 2018 10:12:47 UT                    | Missing letter "C"                | Unknown
275
             *
276
             * Please report any new invalid timestamps to [#45](https://github.com/Webklex/laravel-imap/issues/45)
277
             */
278
            try {
279
                $this->date = Carbon::parse($date);
280
            } catch (\Exception $e) {
281
                switch (true) {
282
                    case preg_match('/([A-Z]{2,3}\,\ [0-9]{1,2}\ [A-Z]{2,3}\ [0-9]{4}\ [0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\ \+[0-9]{4}\ \([A-Z]{2,3}\+[0-9]{1,2}\:[0-9]{1,2})\)+$/i', $date) > 0:
283
                        $array = explode('(', $date);
284
                        $array = array_reverse($array);
285
                        $date = trim(array_pop($array));
286
                        break;
287
                    case preg_match('/([0-9]{1,2}\ [A-Z]{2,3}\ [0-9]{4}\ [0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\ UT)+$/i', $date) > 0:
288
                        $date .= 'C';
289
                        break;
290
                }
291
                $this->date = Carbon::parse($date);
292
            }
293
        }
294
295
        if (property_exists($header, 'from')) {
296
            $this->from = $this->parseAddresses($header->from);
297
        }
298
        if (property_exists($header, 'to')) {
299
            $this->to = $this->parseAddresses($header->to);
300
        }
301
        if (property_exists($header, 'cc')) {
302
            $this->cc = $this->parseAddresses($header->cc);
303
        }
304
        if (property_exists($header, 'bcc')) {
305
            $this->bcc = $this->parseAddresses($header->bcc);
306
        }
307
        if (property_exists($header, 'references')) {
308
            $this->references = $header->references;
309
        }
310
311
        if (property_exists($header, 'reply_to')) {
312
            $this->reply_to = $this->parseAddresses($header->reply_to);
313
        }
314
        if (property_exists($header, 'in_reply_to')) {
315
            $this->in_reply_to = str_replace(['<', '>'], '', $header->in_reply_to);
316
        }
317
        if (property_exists($header, 'sender')) {
318
            $this->sender = $this->parseAddresses($header->sender);
319
        }
320
321
        if (property_exists($header, 'message_id')) {
322
            $this->message_id = str_replace(['<', '>'], '', $header->message_id);
323
        }
324
        if (property_exists($header, 'Msgno')) {
325
            $messageNo = (int) trim($header->Msgno);
326
            $this->message_no = ($this->fetch_options == FT_UID) ? $messageNo : imap_msgno($this->client->getConnection(), $messageNo);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type boolean; however, parameter $imap_stream of imap_msgno() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

326
            $this->message_no = ($this->fetch_options == FT_UID) ? $messageNo : imap_msgno(/** @scrutinizer ignore-type */ $this->client->getConnection(), $messageNo);
Loading history...
327
        } else {
328
            $this->message_no = imap_msgno($this->client->getConnection(), $this->getUid());
329
        }
330
    }
331
332
     /**
333
     * Parse additional flags
334
     *
335
     * @return void
336
     */
337
    private function parseFlags() {
338
    	$flags = imap_fetch_overview($this->client->getConnection(), $this->uid, $this->fetch_options);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type boolean; however, parameter $imap_stream of imap_fetch_overview() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

338
    	$flags = imap_fetch_overview(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, $this->fetch_options);
Loading history...
339
    	if (is_array($flags) && isset($flags[0]))
340
    	{
341
    	    $this->flags = $flags[0];
342
    	}
343
    }
344
    
345
    /**
346
     * Get the current Message header info
347
     *
348
     * @return object
349
     */
350
    public function getHeaderInfo() {
351
        if ($this->header_info == null) {
352
            $this->header_info =
353
            $this->header_info = imap_headerinfo($this->client->getConnection(), $this->getMessageNo()); ;
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type boolean; however, parameter $stream_id of imap_headerinfo() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

353
            $this->header_info = imap_headerinfo(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->getMessageNo()); ;
Loading history...
354
        }
355
356
        return $this->header_info;
357
    }
358
359
    /**
360
     * Parse Addresses
361
     *
362
     * @param $list
363
     *
364
     * @return array
365
     */
366
    private function parseAddresses($list) {
367
        $addresses = [];
368
369
        foreach ($list as $item) {
370
            $address = (object) $item;
371
372
            if (!property_exists($address, 'mailbox')) {
373
                $address->mailbox = false;
374
            }
375
            if (!property_exists($address, 'host')) {
376
                $address->host = false;
377
            }
378
            if (!property_exists($address, 'personal')) {
379
                $address->personal = false;
380
            }
381
382
            $address->personal = imap_utf8($address->personal);
383
384
            $address->mail = ($address->mailbox && $address->host) ? $address->mailbox.'@'.$address->host : false;
385
            $address->full = ($address->personal) ? $address->personal.' <'.$address->mail.'>' : $address->mail;
0 ignored issues
show
Bug introduced by
Are you sure $address->mail of type false|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

385
            $address->full = ($address->personal) ? $address->personal.' <'./** @scrutinizer ignore-type */ $address->mail.'>' : $address->mail;
Loading history...
386
387
            $addresses[] = $address;
388
        }
389
390
        return $addresses;
391
    }
392
393
    /**
394
     * Parse the Message body
395
     *
396
     * @return $this
397
     */
398
    public function parseBody() {
399
        $structure = imap_fetchstructure($this->client->getConnection(), $this->uid, $this->fetch_options);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type boolean; however, parameter $imap_stream of imap_fetchstructure() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

399
        $structure = imap_fetchstructure(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, $this->fetch_options);
Loading history...
400
401
        $this->fetchStructure($structure);
402
403
        return $this;
404
    }
405
406
    /**
407
     * Fetch the Message structure
408
     *
409
     * @param $structure
410
     * @param mixed $partNumber
411
     */
412
    private function fetchStructure($structure, $partNumber = null) {
413
        if ($structure->type == self::TYPE_TEXT &&
414
            ($structure->ifdisposition == 0 ||
415
                ($structure->ifdisposition == 1 && !isset($structure->parts) && $partNumber == null)
416
            )
417
        ) {
418
            if ($structure->subtype == "PLAIN") {
419
                if (!$partNumber) {
420
                    $partNumber = 1;
421
                }
422
423
                $encoding = $this->getEncoding($structure);
424
425
                $content = imap_fetchbody($this->client->getConnection(), $this->uid, $partNumber, $this->fetch_options);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type boolean; however, parameter $imap_stream of imap_fetchbody() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

425
                $content = imap_fetchbody(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, $partNumber, $this->fetch_options);
Loading history...
426
                $content = $this->decodeString($content, $structure->encoding);
427
                $content = $this->convertEncoding($content, $encoding);
428
429
                $body = new \stdClass;
430
                $body->type = "text";
431
                $body->content = $content;
432
433
                $this->bodies['text'] = $body;
434
435
                $this->fetchAttachment($structure, $partNumber);
436
437
            } elseif ($structure->subtype == "HTML") {
438
                if (!$partNumber) {
439
                    $partNumber = 1;
440
                }
441
442
                $encoding = $this->getEncoding($structure);
443
444
                $content = imap_fetchbody($this->client->getConnection(), $this->uid, $partNumber, $this->fetch_options);
445
                $content = $this->decodeString($content, $structure->encoding);
446
                $content = $this->convertEncoding($content, $encoding);
447
448
                $body = new \stdClass;
449
                $body->type = "html";
450
                $body->content = $content;
451
452
                $this->bodies['html'] = $body;
453
            }
454
        } elseif ($structure->type == self::TYPE_MULTIPART) {
455
            foreach ($structure->parts as $index => $subStruct) {
456
                $prefix = "";
457
                if ($partNumber) {
458
                    $prefix = $partNumber.".";
459
                }
460
                $this->fetchStructure($subStruct, $prefix.($index + 1));
461
            }
462
        } else {
463
            if ($this->getFetchAttachmentOption() === true) {
464
                $this->fetchAttachment($structure, $partNumber);
465
            }
466
        }
467
    }
468
469
    /**
470
     * Fetch the Message attachment
471
     *
472
     * @param object $structure
473
     * @param mixed  $partNumber
474
     */
475
    protected function fetchAttachment($structure, $partNumber) {
476
477
        $oAttachment = new Attachment($this, $structure, $partNumber);
478
479
        if ($oAttachment->getName() !== null) {
480
            if ($oAttachment->getId() !== null) {
481
                $this->attachments->put($oAttachment->getId(), $oAttachment);
482
            } else {
483
                $this->attachments->push($oAttachment);
484
            }
485
        }
486
    }
487
488
    /**
489
     * Fail proof setter for $fetch_option
490
     *
491
     * @param $option
492
     *
493
     * @return $this
494
     */
495
    public function setFetchOption($option) {
496
        if (is_long($option) === true) {
497
            $this->fetch_options = $option;
498
        } elseif (is_null($option) === true) {
499
            $config = config('imap.options.fetch', FT_UID);
500
            $this->fetch_options = is_long($config) ? $config : 1;
501
        }
502
503
        return $this;
504
    }
505
506
    /**
507
     * Fail proof setter for $fetch_body
508
     *
509
     * @param $option
510
     *
511
     * @return $this
512
     */
513
    public function setFetchBodyOption($option) {
514
        if (is_bool($option)) {
515
            $this->fetch_body = $option;
516
        } elseif (is_null($option)) {
517
            $config = config('imap.options.fetch_body', true);
518
            $this->fetch_body = is_bool($config) ? $config : true;
519
        }
520
521
        return $this;
522
    }
523
524
    /**
525
     * Fail proof setter for $fetch_attachment
526
     *
527
     * @param $option
528
     *
529
     * @return $this
530
     */
531
    public function setFetchAttachmentOption($option) {
532
        if (is_bool($option)) {
533
            $this->fetch_attachment = $option;
534
        } elseif (is_null($option)) {
535
            $config = config('imap.options.fetch_attachment', true);
536
            $this->fetch_attachment = is_bool($config) ? $config : true;
537
        }
538
539
        return $this;
540
    }
541
542
    /**
543
     * Decode a given string
544
     *
545
     * @param $string
546
     * @param $encoding
547
     *
548
     * @return string
549
     */
550
    public function decodeString($string, $encoding) {
551
        switch ($encoding) {
552
            case self::ENC_7BIT:
553
                return $string;
554
            case self::ENC_8BIT:
555
                return quoted_printable_decode(imap_8bit($string));
556
            case self::ENC_BINARY:
557
                return imap_binary($string);
558
            case self::ENC_BASE64:
559
                return imap_base64($string);
560
            case self::ENC_QUOTED_PRINTABLE:
561
                return quoted_printable_decode($string);
562
            case self::ENC_OTHER:
563
                return $string;
564
            default:
565
                return $string;
566
        }
567
    }
568
    
569
    /**
570
     * Convert the encoding
571
     *
572
     * @param $str
573
     * @param string $from
574
     * @param string $to
575
     *
576
     * @return mixed|string
577
     */
578
    private function convertEncoding($str, $from = "ISO-8859-2", $to = "UTF-8") {
579
        if (function_exists('iconv') && $from != 'UTF-7' && $to != 'UTF-7') {
580
            return iconv(EncodingAliases::get($from), $to.'//IGNORE', $str);
581
        } else {
582
            if (!$from) {
583
                return mb_convert_encoding($str, $to);
584
            }
585
            return mb_convert_encoding($str, $to, $from);
586
        }
587
    }
588
589
    /**
590
     * Get the encoding of a given abject
591
     *
592
     * @param object $structure
593
     *
594
     * @return null|string
595
     */
596
    private function getEncoding($structure) {
597
        if (property_exists($structure, 'parameters')) {
598
            foreach ($structure->parameters as $parameter) {
599
                if (strtolower($parameter->attribute) == "charset") {
600
                    return strtoupper($parameter->value);
601
                }
602
            }
603
        }
604
        return null;
605
    }
606
607
    /**
608
     * Find the folder containing this message.
609
     *
610
     * @param null|Folder $folder where to start searching from (top-level inbox by default)
611
     * @return null|Folder
612
     */
613
    public function getContainingFolder(Folder $folder = null)
614
    {
615
        $folder = $folder ?: $this->client->getFolders()->first();
616
        $this->client->checkConnection();
617
618
        // Try finding the message by uid in the current folder
619
        $client = new Client;
620
        $client->openFolder($folder);
621
        $uidMatches = imap_fetch_overview($client->getConnection(), $this->uid, $this->fetch_options);
0 ignored issues
show
Bug introduced by
It seems like $client->getConnection() can also be of type true; however, parameter $imap_stream of imap_fetch_overview() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

621
        $uidMatches = imap_fetch_overview(/** @scrutinizer ignore-type */ $client->getConnection(), $this->uid, $this->fetch_options);
Loading history...
622
        $uidMatch = count($uidMatches)
623
            ? new Message($uidMatches[0]->uid, $uidMatches[0]->msgno, $client)
624
            : null;
625
        $client->disconnect();
626
627
        // imap_fetch_overview() on a parent folder will return the matching message
628
        // even when the message is in a child folder so we need to recursively
629
        // search the children
630
        foreach ($folder->children as $child) {
631
            $childFolder = $this->getContainingFolder($child);
632
633
            if ($childFolder) {
634
                return $childFolder;
635
            }
636
        }
637
638
        // before returning the parent
639
        if ($this->is($uidMatch)) {
640
            return $folder;
641
        }
642
643
        // or signalling that the message was not found in any folder
644
        return null;
645
    }
646
647
    /**
648
     * Move the Message into an other Folder
649
     *
650
     * @param string  $mailbox
651
     * @param integer $options [optional]
652
     *
653
     * @return bool
654
     */
655
    public function moveToFolder($mailbox = 'INBOX', $options = 0) {
656
        $this->client->createFolder($mailbox);
657
658
        return imap_mail_move($this->client->getConnection(), $this->msglist, $mailbox, $options);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type true; however, parameter $imap_stream of imap_mail_move() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

658
        return imap_mail_move(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->msglist, $mailbox, $options);
Loading history...
659
    }
660
661
    /**
662
     * Delete the current Message
663
     *
664
     * @return bool
665
     */
666
    public function delete() {
667
        $status = imap_delete($this->client->getConnection(), $this->uid, $this->fetch_options);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type boolean; however, parameter $imap_stream of imap_delete() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

667
        $status = imap_delete(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, $this->fetch_options);
Loading history...
668
        $this->client->expunge();
669
670
        return $status;
671
    }
672
673
    /**
674
     * Restore a deleted Message
675
     *
676
     * @return bool
677
     */
678
    public function restore() {
679
        return imap_undelete($this->client->getConnection(), $this->message_no);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type boolean; however, parameter $imap_stream of imap_undelete() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

679
        return imap_undelete(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->message_no);
Loading history...
680
    }
681
682
    /**
683
     * Get all message attachments.
684
     *
685
     * @return AttachmentCollection
686
     */
687
    public function getAttachments() {
688
        return $this->attachments;
689
    }
690
691
    /**
692
     * Checks if there are any attachments present
693
     *
694
     * @return boolean
695
     */
696
    public function hasAttachments() {
697
        return $this->attachments->isEmpty() === false;
698
    }
699
700
    /**
701
     * Set a given flag
702
     * @param string|array $flag
703
     *
704
     * @return bool
705
     */
706
    public function setFlag($flag) {
707
        $flag = "\\".trim(is_array($flag) ? implode(" \\", $flag) : $flag);
708
        return imap_setflag_full($this->client->getConnection(), $this->getUid(), $flag, SE_UID);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type boolean; however, parameter $imap_stream of imap_setflag_full() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

708
        return imap_setflag_full(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->getUid(), $flag, SE_UID);
Loading history...
709
    }
710
711
    /**
712
     * Unset a given flag
713
     * @param string|array $flag
714
     *
715
     * @return bool
716
     */
717
    public function unsetFlag($flag) {
718
        $flag = "\\".trim(is_array($flag) ? implode(" \\", $flag) : $flag);
719
        return imap_clearflag_full($this->client->getConnection(), $this->getUid(), "\\$flag", SE_UID);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type boolean; however, parameter $imap_stream of imap_clearflag_full() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

719
        return imap_clearflag_full(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->getUid(), "\\$flag", SE_UID);
Loading history...
720
    }
721
722
    /**
723
     * @return null|object|string
724
     */
725
    public function getRawBody() {
726
        if ($this->raw_body === null) {
727
            $this->raw_body = imap_fetchbody($this->client->getConnection(), $this->getMessageNo(), '');
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type boolean; however, parameter $imap_stream of imap_fetchbody() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

727
            $this->raw_body = imap_fetchbody(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->getMessageNo(), '');
Loading history...
728
        }
729
730
        return $this->raw_body;
731
    }
732
733
    /**
734
     * @return string
735
     */
736
    public function getHeader() {
737
        return $this->header;
738
    }
739
740
    /**
741
     * @return Client
742
     */
743
    public function getClient() {
744
        return $this->client;
745
    }
746
747
    /**
748
     * @return integer
749
     */
750
    public function getUid() {
751
        return $this->uid;
752
    }
753
754
    /**
755
     * @return integer
756
     */
757
    public function getFetchOptions() {
758
        return $this->fetch_options;
759
    }
760
761
    /**
762
     * @return boolean
763
     */
764
    public function getFetchBodyOption() {
765
        return $this->fetch_body;
766
    }
767
768
    /**
769
     * @return boolean
770
     */
771
    public function getFetchAttachmentOption() {
772
        return $this->fetch_attachment;
773
    }
774
775
    /**
776
     * @return int
777
     */
778
    public function getMsglist() {
779
        return $this->msglist;
780
    }
781
782
    /**
783
     * @return mixed
784
     */
785
    public function getMessageId() {
786
        return $this->message_id;
787
    }
788
789
    /**
790
     * @return int
791
     */
792
    public function getMessageNo() {
793
        return $this->message_no;
794
    }
795
796
    /**
797
     * @return string
798
     */
799
    public function getSubject() {
800
        return $this->subject;
801
    }
802
803
    /**
804
     * @return mixed
805
     */
806
    public function getReferences() {
807
        return $this->references;
808
    }
809
810
    /**
811
     * @return Carbon|null
812
     */
813
    public function getDate() {
814
        return $this->date;
815
    }
816
817
    /**
818
     * @return array
819
     */
820
    public function getFrom() {
821
        return $this->from;
822
    }
823
824
    /**
825
     * @return array
826
     */
827
    public function getTo() {
828
        return $this->to;
829
    }
830
831
    /**
832
     * @return array
833
     */
834
    public function getCc() {
835
        return $this->cc;
836
    }
837
838
    /**
839
     * @return array
840
     */
841
    public function getBcc() {
842
        return $this->bcc;
843
    }
844
845
    /**
846
     * @return array
847
     */
848
    public function getReplyTo() {
849
        return $this->reply_to;
850
    }
851
    
852
    /**
853
     * @return string
854
     */
855
    public function getInReplyTo() {
856
        return $this->in_reply_to;
857
    }
858
859
    /**
860
     * @return array
861
     */
862
    public function getSender() {
863
        return $this->sender;
864
    }
865
866
    /**
867
     * @return mixed
868
     */
869
    public function getBodies() {
870
        return $this->bodies;
871
    }
872
    
873
     /**
874
     * @return array
875
     */
876
    public function getFlags() {
877
        return $this->flags;
878
    }
879
880
    /**
881
     * Does this message match another one?
882
     *
883
     * A match means same uid, message id, subject and date/time.
884
     *
885
     * @param  null|static $message
886
     * @return boolean
887
     */
888
    public function is(Message $message = null)
889
    {
890
        if (is_null($message)) {
891
            return false;
892
        }
893
894
        return $this->uid == $message->uid
895
            && $this->message_id == $message->message_id
896
            && $this->subject == $message->subject
897
            && $this->date->eq($message->date);
898
    }
899
}
900