Passed
Push — master ( d62290...9b4a7c )
by Malte
03:37
created

Message::parseHeader()   D

Complexity

Conditions 11
Paths 384

Size

Total Lines 41
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 18
Bugs 2 Features 6
Metric Value
cc 11
eloc 26
c 18
b 2
f 6
nc 384
nop 0
dl 0
loc 41
rs 4.1833

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 Illuminate\Support\Str;
17
use Webklex\IMAP\Exceptions\InvalidMessageDateException;
18
use Webklex\IMAP\Exceptions\MaskNotFoundException;
19
use Webklex\IMAP\Exceptions\MethodNotFoundException;
20
use Webklex\IMAP\Support\AttachmentCollection;
21
use Webklex\IMAP\Support\FlagCollection;
22
use Webklex\IMAP\Support\Masks\MessageMask;
23
24
/**
25
 * Class Message
26
 *
27
 * @package Webklex\IMAP
28
 *
29
 * @property integer msglist
30
 * @property integer uid
31
 * @property integer msgn
32
 * @property integer priority
33
 * @property string subject
34
 * @property string message_id
35
 * @property string message_no
36
 * @property string references
37
 * @property carbon date
38
 * @property array from
39
 * @property array to
40
 * @property array cc
41
 * @property array bcc
42
 * @property array reply_to
43
 * @property array in_reply_to
44
 * @property array sender
45
 *
46
 * @method integer getMsglist()
47
 * @method integer setMsglist(integer $msglist)
48
 * @method integer getUid()
49
 * @method integer setUid(integer $uid)
50
 * @method integer getMsgn()
51
 * @method integer setMsgn(integer $msgn)
52
 * @method integer getPriority()
53
 * @method integer setPriority(integer $priority)
54
 * @method string getSubject()
55
 * @method string setSubject(string $subject)
56
 * @method string getMessageId()
57
 * @method string setMessageId(string $message_id)
58
 * @method string getMessageNo()
59
 * @method string setMessageNo(string $message_no)
60
 * @method string getReferences()
61
 * @method string setReferences(string $references)
62
 * @method carbon getDate()
63
 * @method carbon setDate(carbon $date)
64
 * @method array getFrom()
65
 * @method array setFrom(array $from)
66
 * @method array getTo()
67
 * @method array setTo(array $to)
68
 * @method array getCc()
69
 * @method array setCc(array $cc)
70
 * @method array getBcc()
71
 * @method array setBcc(array $bcc)
72
 * @method array getReplyTo()
73
 * @method array setReplyTo(array $reply_to)
74
 * @method array getInReplyTo()
75
 * @method array setInReplyTo(array $in_reply_to)
76
 * @method array getSender()
77
 * @method array setSender(array $sender)
78
 */
79
class Message {
80
81
    /**
82
     * Client instance
83
     *
84
     * @var Client
85
     */
86
    private $client = Client::class;
87
88
    /**
89
     * Default mask
90
     * @var string $mask
91
     */
92
    protected $mask = MessageMask::class;
93
94
    /** @var array $config */
95
    protected $config = [];
96
97
    /** @var array $attributes */
98
    protected $attributes = [
99
        'message_id' => '',
100
        'message_no' => null,
101
        'subject' => '',
102
        'references' => null,
103
        'date' => null,
104
        'from' => [],
105
        'to' => [],
106
        'cc' => [],
107
        'bcc' => [],
108
        'reply_to' => [],
109
        'in_reply_to' => '',
110
        'sender' => [],
111
        'priority' => 0,
112
    ];
113
114
    /**
115
     * The message folder path
116
     *
117
     * @var string $folder_path
118
     */
119
    protected $folder_path;
120
121
    /**
122
     * Fetch body options
123
     *
124
     * @var integer
125
     */
126
    public $fetch_options = null;
127
128
    /**
129
     * Fetch body options
130
     *
131
     * @var bool
132
     */
133
    public $fetch_body = null;
134
135
    /**
136
     * Fetch attachments options
137
     *
138
     * @var bool
139
     */
140
    public $fetch_attachment = null;
141
142
    /**
143
     * Fetch flags options
144
     *
145
     * @var bool
146
     */
147
    public $fetch_flags = null;
148
149
    /**
150
     * @var string $header
151
     */
152
    public $header = null;
153
154
    /**
155
     * @var null|object $header_info
156
     */
157
    public $header_info = null;
158
159
    /** @var null|string $raw_body */
160
    public $raw_body = null;
161
162
    /** @var null $structure */
163
    protected $structure = null;
164
165
    /**
166
     * Message body components
167
     *
168
     * @var array   $bodies
169
     * @var AttachmentCollection|array $attachments
170
     * @var FlagCollection|array       $flags
171
     */
172
    public $bodies = [];
173
    public $attachments = [];
174
    public $flags = [];
175
176
    /**
177
     * A list of all available and supported flags
178
     *
179
     * @var array $available_flags
180
     */
181
    private $available_flags = ['recent', 'flagged', 'answered', 'deleted', 'seen', 'draft'];
182
183
    /**
184
     * Message constructor.
185
     *
186
     * @param integer       $uid
187
     * @param integer|null  $msglist
188
     * @param Client        $client
189
     * @param integer|null  $fetch_options
190
     * @param boolean       $fetch_body
191
     * @param boolean       $fetch_attachment
192
     * @param boolean       $fetch_flags
193
     *
194
     * @throws Exceptions\ConnectionFailedException
195
     * @throws InvalidMessageDateException
196
     */
197
    public function __construct($uid, $msglist, Client $client, $fetch_options = null, $fetch_body = false, $fetch_attachment = false, $fetch_flags = false) {
198
199
        $default_mask = $client->getDefaultMessageMask();
200
        if($default_mask != null) {
201
            $this->mask = $default_mask;
202
        }
203
204
        $this->folder_path = $client->getFolderPath();
0 ignored issues
show
Documentation Bug introduced by
It seems like $client->getFolderPath() of type Webklex\IMAP\Folder is incompatible with the declared type string of property $folder_path.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
205
206
        $this->config = config('imap.options');
207
208
        $this->setFetchOption($fetch_options);
209
        $this->setFetchBodyOption($fetch_body);
210
        $this->setFetchAttachmentOption($fetch_attachment);
211
        $this->setFetchFlagsOption($fetch_flags);
212
213
        $this->attachments = AttachmentCollection::make([]);
214
        $this->flags = FlagCollection::make([]);
215
216
        $this->msglist = $msglist;
217
        $this->client = $client;
218
219
        $this->uid =  ($this->fetch_options == IMAP::FT_UID) ? $uid : $uid;
220
        $this->msgn = ($this->fetch_options == IMAP::FT_UID) ? \imap_msgno($this->client->getConnection(), $uid) : $uid;
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_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

220
        $this->msgn = ($this->fetch_options == IMAP::FT_UID) ? \imap_msgno(/** @scrutinizer ignore-type */ $this->client->getConnection(), $uid) : $uid;
Loading history...
221
222
        $this->parseHeader();
223
224
        if ($this->getFetchFlagsOption() === true) {
225
            $this->parseFlags();
226
        }
227
228
        if ($this->getFetchBodyOption() === true) {
229
            $this->parseBody();
230
        }
231
    }
232
233
    /**
234
     * Call dynamic attribute setter and getter methods
235
     * @param string $method
236
     * @param array $arguments
237
     *
238
     * @return mixed
239
     * @throws MethodNotFoundException
240
     */
241
    public function __call($method, $arguments) {
242
        if(strtolower(substr($method, 0, 3)) === 'get') {
243
            $name = Str::snake(substr($method, 3));
244
245
            if(in_array($name, array_keys($this->attributes))) {
246
                return $this->attributes[$name];
247
            }
248
249
        }elseif (strtolower(substr($method, 0, 3)) === 'set') {
250
            $name = Str::snake(substr($method, 3));
251
252
            if(in_array($name, array_keys($this->attributes))) {
253
                $this->attributes[$name] = array_pop($arguments);
254
255
                return $this->attributes[$name];
256
            }
257
258
        }
259
260
        throw new MethodNotFoundException("Method ".self::class.'::'.$method.'() is not supported');
261
    }
262
263
    /**
264
     * @param $name
265
     * @param $value
266
     *
267
     * @return mixed
268
     */
269
    public function __set($name, $value) {
270
        $this->attributes[$name] = $value;
271
272
        return $this->attributes[$name];
273
    }
274
275
    /**
276
     * @param $name
277
     *
278
     * @return mixed|null
279
     */
280
    public function __get($name) {
281
        if(isset($this->attributes[$name])) {
282
            return $this->attributes[$name];
283
        }
284
285
        return null;
286
    }
287
288
    /**
289
     * Copy the current Messages to a mailbox
290
     *
291
     * @param $mailbox
292
     * @param int $options
293
     *
294
     * @return bool
295
     * @throws Exceptions\ConnectionFailedException
296
     */
297
    public function copy($mailbox, $options = 0) {
298
        $this->client->openFolder($this->folder_path);
299
        return \imap_mail_copy($this->client->getConnection(), $this->uid, $mailbox, IMAP::CP_UID);
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_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

299
        return \imap_mail_copy(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, $mailbox, IMAP::CP_UID);
Loading history...
300
    }
301
302
    /**
303
     * Move the current Messages to a mailbox
304
     *
305
     * @param $mailbox
306
     * @param int $options
307
     *
308
     * @return bool
309
     * @throws Exceptions\ConnectionFailedException
310
     */
311
    public function move($mailbox, $options = 0) {
312
        $this->client->openFolder($this->folder_path);
313
        return \imap_mail_move($this->client->getConnection(), $this->uid, $mailbox, IMAP::CP_UID);
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

313
        return \imap_mail_move(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, $mailbox, IMAP::CP_UID);
Loading history...
314
    }
315
316
    /**
317
     * Check if the Message has a text body
318
     *
319
     * @return bool
320
     */
321
    public function hasTextBody() {
322
        return isset($this->bodies['text']);
323
    }
324
325
    /**
326
     * Get the Message text body
327
     *
328
     * @return mixed
329
     */
330
    public function getTextBody() {
331
        if (!isset($this->bodies['text'])) {
332
            return false;
333
        }
334
335
        return $this->bodies['text']->content;
336
    }
337
338
    /**
339
     * Check if the Message has a html body
340
     *
341
     * @return bool
342
     */
343
    public function hasHTMLBody() {
344
        return isset($this->bodies['html']);
345
    }
346
347
    /**
348
     * Get the Message html body
349
     * If $replaceImages is callable it should expect string $body as first parameter, $oAttachment as second and return
350
     * the resulting $body.
351
     *
352
     * @var bool|callable $replaceImages
353
     *
354
     * @return string|null
355
     *
356
     * @deprecated 1.4.0:2.0.0 No longer needed. Use AttachmentMask::getImageSrc() instead
357
     */
358
    public function getHTMLBody($replaceImages = false) {
359
        if (!isset($this->bodies['html'])) {
360
            return null;
361
        }
362
363
        $body = $this->bodies['html']->content;
364
        if ($replaceImages !== false) {
365
            $this->attachments->each(function($oAttachment) use(&$body, $replaceImages) {
366
                /** @var Attachment $oAttachment */
367
                if(is_callable($replaceImages)) {
368
                    $body = $replaceImages($body, $oAttachment);
369
                }elseif(is_string($replaceImages)) {
370
                    call_user_func($replaceImages, [$body, $oAttachment]);
371
                }else{
372
                    if ($oAttachment->id && $oAttachment->getImgSrc() != null) {
0 ignored issues
show
Deprecated Code introduced by
The function Webklex\IMAP\Attachment::getImgSrc() has been deprecated: 1.4.0:2.0.0 No longer needed. Use AttachmentMask::getImageSrc() instead ( Ignorable by Annotation )

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

372
                    if ($oAttachment->id && /** @scrutinizer ignore-deprecated */ $oAttachment->getImgSrc() != null) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
373
                        $body = str_replace('cid:'.$oAttachment->id, $oAttachment->getImgSrc(), $body);
0 ignored issues
show
Deprecated Code introduced by
The function Webklex\IMAP\Attachment::getImgSrc() has been deprecated: 1.4.0:2.0.0 No longer needed. Use AttachmentMask::getImageSrc() instead ( Ignorable by Annotation )

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

373
                        $body = str_replace('cid:'.$oAttachment->id, /** @scrutinizer ignore-deprecated */ $oAttachment->getImgSrc(), $body);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
374
                    }
375
                }
376
            });
377
        }
378
379
        return $body;
380
    }
381
382
    /**
383
     * Parse all defined headers
384
     *
385
     * @return void
386
     * @throws Exceptions\ConnectionFailedException
387
     * @throws InvalidMessageDateException
388
     */
389
    private function parseHeader() {
390
        $this->client->openFolder($this->folder_path);
391
        $this->header = $header = \imap_fetchheader($this->client->getConnection(), $this->uid, IMAP::FT_UID);
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_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

391
        $this->header = $header = \imap_fetchheader(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, IMAP::FT_UID);
Loading history...
392
393
        $this->priority = $this->extractPriority($this->header);
394
395
        if ($this->header) {
396
            $header = \imap_rfc822_parse_headers($this->header);
397
        }
398
399
        if (property_exists($header, 'subject')) {
400
            if($this->config['decoder']['message']['subject'] === 'utf-8') {
401
                $this->subject = \imap_utf8($header->subject);
402
            }elseif($this->config['decoder']['message']['subject'] === 'iconv') {
403
                $this->subject = iconv_mime_decode($header->subject);
404
            }else{
405
                $this->subject = mb_decode_mimeheader($header->subject);
406
            }
407
        }
408
409
        foreach(['from', 'to', 'cc', 'bcc', 'reply_to', 'sender'] as $part){
410
            $this->extractHeaderAddressPart($header, $part);
0 ignored issues
show
Bug introduced by
It seems like $header can also be of type string; however, parameter $header of Webklex\IMAP\Message::extractHeaderAddressPart() does only seem to accept object, 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

410
            $this->extractHeaderAddressPart(/** @scrutinizer ignore-type */ $header, $part);
Loading history...
411
        }
412
413
        if (property_exists($header, 'references')) {
414
            $this->references = $header->references;
415
        }
416
        if (property_exists($header, 'in_reply_to')) {
417
            $this->in_reply_to = str_replace(['<', '>'], '', $header->in_reply_to);
418
        }
419
        if (property_exists($header, 'message_id')) {
420
            $this->message_id = str_replace(['<', '>'], '', $header->message_id);
421
        }
422
        if (property_exists($header, 'Msgno')) {
423
            $messageNo = (int) trim($header->Msgno);
424
            $this->message_no = ($this->fetch_options == IMAP::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 true; 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

424
            $this->message_no = ($this->fetch_options == IMAP::FT_UID) ? $messageNo : \imap_msgno(/** @scrutinizer ignore-type */ $this->client->getConnection(), $messageNo);
Loading history...
425
        } else {
426
            $this->message_no = \imap_msgno($this->client->getConnection(), $this->getUid());
427
        }
428
429
        $this->date = $this->parseDate($header);
0 ignored issues
show
Bug introduced by
It seems like $header can also be of type string; however, parameter $header of Webklex\IMAP\Message::parseDate() does only seem to accept object, 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

429
        $this->date = $this->parseDate(/** @scrutinizer ignore-type */ $header);
Loading history...
430
    }
431
432
    /**
433
     * Try to extract the priority from a given raw header string
434
     * @param string $header
435
     *
436
     * @return int|null
437
     */
438
    private function extractPriority($header) {
439
        if(preg_match('/x\-priority\:.*([0-9]{1,2})/i', $header, $priority)){
440
            $priority = isset($priority[1]) ? (int) $priority[1] : 0;
441
            switch($priority){
442
                case IMAP::MESSAGE_PRIORITY_HIGHEST;
443
                    $priority = IMAP::MESSAGE_PRIORITY_HIGHEST;
444
                    break;
445
                case IMAP::MESSAGE_PRIORITY_HIGH;
446
                    $priority = IMAP::MESSAGE_PRIORITY_HIGH;
447
                    break;
448
                case IMAP::MESSAGE_PRIORITY_NORMAL;
449
                    $priority = IMAP::MESSAGE_PRIORITY_NORMAL;
450
                    break;
451
                case IMAP::MESSAGE_PRIORITY_LOW;
452
                    $priority = IMAP::MESSAGE_PRIORITY_LOW;
453
                    break;
454
                case IMAP::MESSAGE_PRIORITY_LOWEST;
455
                    $priority = IMAP::MESSAGE_PRIORITY_LOWEST;
456
                    break;
457
                default:
458
                    $priority = IMAP::MESSAGE_PRIORITY_UNKNOWN;
459
                    break;
460
            }
461
        }
462
463
        return $priority;
464
    }
465
466
    /**
467
     * Exception handling for invalid dates
468
     *
469
     * Currently known invalid formats:
470
     * ^ Datetime                                   ^ Problem                           ^ Cause
471
     * | Mon, 20 Nov 2017 20:31:31 +0800 (GMT+8:00) | Double timezone specification     | A Windows feature
472
     * | Thu, 8 Nov 2018 08:54:58 -0200 (-02)       |
473
     * |                                            | and invalid timezone (max 6 char) |
474
     * | 04 Jan 2018 10:12:47 UT                    | Missing letter "C"                | Unknown
475
     * | Thu, 31 May 2018 18:15:00 +0800 (added by) | Non-standard details added by the | Unknown
476
     * |                                            | mail server                       |
477
     * | Sat, 31 Aug 2013 20:08:23 +0580            | Invalid timezone                  | PHPMailer bug https://sourceforge.net/p/phpmailer/mailman/message/6132703/
478
     *
479
     * Please report any new invalid timestamps to [#45](https://github.com/Webklex/laravel-imap/issues/45)
480
     *
481
     * @param object $header
482
     *
483
     * @return Carbon|null
484
     * @throws InvalidMessageDateException
485
     */
486
    private function parseDate($header) {
487
        $parsed_date = null;
488
489
        if (property_exists($header, 'date')) {
490
            $date = $header->date;
491
492
            if(preg_match('/\+0580/', $date)) {
493
                $date = str_replace('+0580', '+0530', $date);
494
            }
495
496
            $date = trim(rtrim($date));
497
            try {
498
                $parsed_date = Carbon::parse($date);
499
            } catch (\Exception $e) {
500
                switch (true) {
501
                    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:
502
                    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}\ UT)+$/i', $date) > 0:
503
                        $date .= 'C';
504
                        break;
505
                    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]{2,4}\ \(\+[0-9]{1,2}\))+$/i', $date) > 0:
506
                    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}.*)+$/i', $date) > 0:
507
                    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}\ \(.*)\)+$/i', $date) > 0:
508
                    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}\ \(.*)\)+$/i', $date) > 0:
509
                    case preg_match('/([0-9]{1,2}\ [A-Z]{2,3}\ [0-9]{2,4}\ [0-9]{2}\:[0-9]{2}\:[0-9]{2}\ [A-Z]{2}\ \-[0-9]{2}\:[0-9]{2}\ \([A-Z]{2,3}\ \-[0-9]{2}:[0-9]{2}\))+$/i', $date) > 0:
510
                        $array = explode('(', $date);
511
                        $array = array_reverse($array);
512
                        $date = trim(array_pop($array));
513
                        break;
514
                }
515
                try{
516
                    $parsed_date = Carbon::parse($date);
517
                } catch (\Exception $_e) {
518
                    throw new InvalidMessageDateException("Invalid message date. ID:".$this->getMessageId(), 1000, $e);
519
                }
520
            }
521
        }
522
523
        return $parsed_date;
524
    }
525
526
    /**
527
     * Parse additional flags
528
     *
529
     * @return void
530
     * @throws Exceptions\ConnectionFailedException
531
     */
532
    private function parseFlags() {
533
        $this->flags = FlagCollection::make([]);
534
535
        $this->client->openFolder($this->folder_path);
536
        $flags = \imap_fetch_overview($this->client->getConnection(), $this->uid, IMAP::FT_UID);
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_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

536
        $flags = \imap_fetch_overview(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, IMAP::FT_UID);
Loading history...
537
        if (is_array($flags) && isset($flags[0])) {
538
            foreach($this->available_flags as $flag) {
539
                $this->parseFlag($flags, $flag);
540
            }
541
        }
542
    }
543
544
    /**
545
     * Extract a possible flag information from a given array
546
     * @param array $flags
547
     * @param string $flag
548
     */
549
    private function parseFlag($flags, $flag) {
550
        $flag = strtolower($flag);
551
552
        if (property_exists($flags[0], strtoupper($flag))) {
553
            $this->flags->put($flag, $flags[0]->{strtoupper($flag)});
554
        } elseif (property_exists($flags[0], ucfirst($flag))) {
555
            $this->flags->put($flag, $flags[0]->{ucfirst($flag)});
556
        } elseif (property_exists($flags[0], $flag)) {
557
            $this->flags->put($flag, $flags[0]->$flag);
558
        }
559
    }
560
561
    /**
562
     * Get the current Message header info
563
     *
564
     * @return object
565
     * @throws Exceptions\ConnectionFailedException
566
     */
567
    public function getHeaderInfo() {
568
        if ($this->header_info == null) {
569
            $this->client->openFolder($this->folder_path);
570
            $this->header_info = \imap_headerinfo($this->client->getConnection(), $this->getMessageNo());
0 ignored issues
show
Bug introduced by
$this->getMessageNo() of type string is incompatible with the type integer expected by parameter $msg_no of imap_headerinfo(). ( Ignorable by Annotation )

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

570
            $this->header_info = \imap_headerinfo($this->client->getConnection(), /** @scrutinizer ignore-type */ $this->getMessageNo());
Loading history...
Bug introduced by
It seems like $this->client->getConnection() can also be of type true; 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

570
            $this->header_info = \imap_headerinfo(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->getMessageNo());
Loading history...
571
        }
572
573
        return $this->header_info;
574
    }
575
576
    /**
577
     * Extract a given part as address array from a given header
578
     * @param object $header
579
     * @param string $part
580
     */
581
    private function extractHeaderAddressPart($header, $part) {
582
        if (property_exists($header, $part)) {
583
            $this->$part = $this->parseAddresses($header->$part);
584
        }
585
    }
586
587
    /**
588
     * Parse Addresses
589
     * @param $list
590
     *
591
     * @return array
592
     */
593
    private function parseAddresses($list) {
594
        $addresses = [];
595
596
        foreach ($list as $item) {
597
            $address = (object) $item;
598
599
            if (!property_exists($address, 'mailbox')) {
600
                $address->mailbox = false;
601
            }
602
            if (!property_exists($address, 'host')) {
603
                $address->host = false;
604
            }
605
            if (!property_exists($address, 'personal')) {
606
                $address->personal = false;
607
            } else {
608
                $personalParts = \imap_mime_header_decode($address->personal);
609
610
                if(is_array($personalParts)) {
611
                    $address->personal = '';
612
                    foreach ($personalParts as $p) {
613
                        $encoding = (property_exists($p, 'charset')) ? $p->charset : $this->getEncoding($p->text);
614
                        $address->personal .= $this->convertEncoding($p->text, $encoding);
615
                    }
616
                }
617
            }
618
619
            $address->mail = ($address->mailbox && $address->host) ? $address->mailbox.'@'.$address->host : false;
620
            $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

620
            $address->full = ($address->personal) ? $address->personal.' <'./** @scrutinizer ignore-type */ $address->mail.'>' : $address->mail;
Loading history...
621
622
            $addresses[] = $address;
623
        }
624
625
        return $addresses;
626
    }
627
628
    /**
629
     * Parse the Message body
630
     *
631
     * @return $this
632
     * @throws Exceptions\ConnectionFailedException
633
     */
634
    public function parseBody() {
635
        $this->client->openFolder($this->folder_path);
636
        $this->structure = \imap_fetchstructure($this->client->getConnection(), $this->uid, IMAP::FT_UID);
0 ignored issues
show
Documentation Bug introduced by
It seems like imap_fetchstructure($thi...klex\IMAP\IMAP::FT_UID) of type object is incompatible with the declared type null of property $structure.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
Bug introduced by
It seems like $this->client->getConnection() can also be of type true; 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

636
        $this->structure = \imap_fetchstructure(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, IMAP::FT_UID);
Loading history...
637
638
        if(property_exists($this->structure, 'parts')){
639
            $parts = $this->structure->parts;
640
641
            foreach ($parts as $part)  {
642
                foreach ($part->parameters as $parameter)  {
643
                    if($parameter->attribute == "charset")  {
644
                        $encoding = $parameter->value;
645
646
                        $encoding = preg_replace('/Content-Transfer-Encoding/', '', $encoding);
647
                        $encoding = preg_replace('/iso-8859-8-i/', 'iso-8859-8', $encoding);
648
649
                        $parameter->value = $encoding;
650
                    }
651
                }
652
            }
653
        }
654
655
        $this->fetchStructure($this->structure);
656
657
        return $this;
658
    }
659
660
    /**
661
     * Fetch the Message structure
662
     *
663
     * @param $structure
664
     * @param mixed $partNumber
665
     *
666
     * @throws Exceptions\ConnectionFailedException
667
     */
668
    private function fetchStructure($structure, $partNumber = null) {
669
        $this->client->openFolder($this->folder_path);
670
671
        if ($structure->type == IMAP::MESSAGE_TYPE_TEXT &&
672
            (empty($structure->disposition) || strtolower($structure->disposition) != 'attachment')
673
        ) {
674
            if (strtolower($structure->subtype) == "plain" || strtolower($structure->subtype) == "csv") {
675
                if (!$partNumber) {
676
                    $partNumber = 1;
677
                }
678
679
                $encoding = $this->getEncoding($structure);
680
681
                $content = \imap_fetchbody($this->client->getConnection(), $this->uid, $partNumber, $this->fetch_options | IMAP::FT_UID);
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_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

681
                $content = \imap_fetchbody(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, $partNumber, $this->fetch_options | IMAP::FT_UID);
Loading history...
682
                $content = $this->decodeString($content, $structure->encoding);
683
684
                // We don't need to do convertEncoding() if charset is ASCII (us-ascii):
685
                //     ASCII is a subset of UTF-8, so all ASCII files are already UTF-8 encoded
686
                //     https://stackoverflow.com/a/11303410
687
                //
688
                // us-ascii is the same as ASCII:
689
                //     ASCII is the traditional name for the encoding system; the Internet Assigned Numbers Authority (IANA)
690
                //     prefers the updated name US-ASCII, which clarifies that this system was developed in the US and
691
                //     based on the typographical symbols predominantly in use there.
692
                //     https://en.wikipedia.org/wiki/ASCII
693
                //
694
                // convertEncoding() function basically means convertToUtf8(), so when we convert ASCII string into UTF-8 it gets broken.
695
                if ($encoding != 'us-ascii') {
696
                    $content = $this->convertEncoding($content, $encoding);
697
                }
698
699
                $body = new \stdClass;
700
                $body->type = "text";
701
                $body->content = $content;
702
703
                $this->bodies['text'] = $body;
704
705
                $this->fetchAttachment($structure, $partNumber);
706
707
            } elseif (strtolower($structure->subtype) == "html") {
708
                if (!$partNumber) {
709
                    $partNumber = 1;
710
                }
711
712
                $encoding = $this->getEncoding($structure);
713
714
                $content = \imap_fetchbody($this->client->getConnection(), $this->uid, $partNumber, $this->fetch_options | IMAP::FT_UID);
715
                $content = $this->decodeString($content, $structure->encoding);
716
                if ($encoding != 'us-ascii') {
717
                    $content = $this->convertEncoding($content, $encoding);
718
                }
719
720
                $body = new \stdClass;
721
                $body->type = "html";
722
                $body->content = $content;
723
724
                $this->bodies['html'] = $body;
725
            } elseif ($structure->ifdisposition == 1 && strtolower($structure->disposition) == 'attachment') {
726
                if ($this->getFetchAttachmentOption() === true) {
727
                    $this->fetchAttachment($structure, $partNumber);
728
                }
729
            }
730
        } elseif ($structure->type == IMAP::MESSAGE_TYPE_MULTIPART) {
731
            foreach ($structure->parts as $index => $subStruct) {
732
                $prefix = "";
733
                if ($partNumber) {
734
                    $prefix = $partNumber.".";
735
                }
736
                $this->fetchStructure($subStruct, $prefix.($index + 1));
737
            }
738
        } else {
739
            if ($this->getFetchAttachmentOption() === true) {
740
                $this->fetchAttachment($structure, $partNumber);
741
            }
742
        }
743
    }
744
745
    /**
746
     * Fetch the Message attachment
747
     *
748
     * @param object $structure
749
     * @param mixed  $partNumber
750
     *
751
     * @throws Exceptions\ConnectionFailedException
752
     */
753
    protected function fetchAttachment($structure, $partNumber) {
754
755
        $oAttachment = new Attachment($this, $structure, $partNumber);
756
757
        if ($oAttachment->getName() !== null) {
0 ignored issues
show
introduced by
The condition $oAttachment->getName() !== null is always true.
Loading history...
758
            if ($oAttachment->getId() !== null) {
0 ignored issues
show
introduced by
The condition $oAttachment->getId() !== null is always true.
Loading history...
759
                $this->attachments->put($oAttachment->getId(), $oAttachment);
760
            } else {
761
                $this->attachments->push($oAttachment);
762
            }
763
        }
764
    }
765
766
    /**
767
     * Fail proof setter for $fetch_option
768
     *
769
     * @param $option
770
     *
771
     * @return $this
772
     */
773
    public function setFetchOption($option) {
774
        if (is_long($option) === true) {
775
            $this->fetch_options = $option;
776
        } elseif (is_null($option) === true) {
777
            $config = config('imap.options.fetch', IMAP::FT_UID);
778
            $this->fetch_options = is_long($config) ? $config : 1;
779
        }
780
781
        return $this;
782
    }
783
784
    /**
785
     * Fail proof setter for $fetch_body
786
     *
787
     * @param $option
788
     *
789
     * @return $this
790
     */
791
    public function setFetchBodyOption($option) {
792
        if (is_bool($option)) {
793
            $this->fetch_body = $option;
794
        } elseif (is_null($option)) {
795
            $config = config('imap.options.fetch_body', true);
796
            $this->fetch_body = is_bool($config) ? $config : true;
797
        }
798
799
        return $this;
800
    }
801
802
    /**
803
     * Fail proof setter for $fetch_attachment
804
     *
805
     * @param $option
806
     *
807
     * @return $this
808
     */
809
    public function setFetchAttachmentOption($option) {
810
        if (is_bool($option)) {
811
            $this->fetch_attachment = $option;
812
        } elseif (is_null($option)) {
813
            $config = config('imap.options.fetch_attachment', true);
814
            $this->fetch_attachment = is_bool($config) ? $config : true;
815
        }
816
817
        return $this;
818
    }
819
820
    /**
821
     * Fail proof setter for $fetch_flags
822
     *
823
     * @param $option
824
     *
825
     * @return $this
826
     */
827
    public function setFetchFlagsOption($option) {
828
        if (is_bool($option)) {
829
            $this->fetch_flags = $option;
830
        } elseif (is_null($option)) {
831
            $config = config('imap.options.fetch_flags', true);
832
            $this->fetch_flags = is_bool($config) ? $config : true;
833
        }
834
835
        return $this;
836
    }
837
838
    /**
839
     * Decode a given string
840
     *
841
     * @param $string
842
     * @param $encoding
843
     *
844
     * @return string
845
     */
846
    public function decodeString($string, $encoding) {
847
        switch ($encoding) {
848
            case IMAP::MESSAGE_ENC_7BIT:
849
                return $string;
850
            case IMAP::MESSAGE_ENC_8BIT:
851
                return quoted_printable_decode(\imap_8bit($string));
852
            case IMAP::MESSAGE_ENC_BINARY:
853
                return \imap_binary($string);
854
            case IMAP::MESSAGE_ENC_BASE64:
855
                return \imap_base64($string);
856
            case IMAP::MESSAGE_ENC_QUOTED_PRINTABLE:
857
                return quoted_printable_decode($string);
858
            case IMAP::MESSAGE_ENC_OTHER:
859
                return $string;
860
            default:
861
                return $string;
862
        }
863
    }
864
865
    /**
866
     * Convert the encoding
867
     *
868
     * @param $str
869
     * @param string $from
870
     * @param string $to
871
     *
872
     * @return mixed|string
873
     */
874
    public function convertEncoding($str, $from = "ISO-8859-2", $to = "UTF-8") {
875
876
        $from = EncodingAliases::get($from);
877
        $to = EncodingAliases::get($to);
878
879
        if ($from === $to) {
880
            return $str;
881
        }
882
883
        // We don't need to do convertEncoding() if charset is ASCII (us-ascii):
884
        //     ASCII is a subset of UTF-8, so all ASCII files are already UTF-8 encoded
885
        //     https://stackoverflow.com/a/11303410
886
        //
887
        // us-ascii is the same as ASCII:
888
        //     ASCII is the traditional name for the encoding system; the Internet Assigned Numbers Authority (IANA)
889
        //     prefers the updated name US-ASCII, which clarifies that this system was developed in the US and
890
        //     based on the typographical symbols predominantly in use there.
891
        //     https://en.wikipedia.org/wiki/ASCII
892
        //
893
        // convertEncoding() function basically means convertToUtf8(), so when we convert ASCII string into UTF-8 it gets broken.
894
        if (strtolower($from) == 'us-ascii' && $to == 'UTF-8') {
895
            return $str;
896
        }
897
898
        if (function_exists('iconv') && $from != 'UTF-7' && $to != 'UTF-7') {
899
            return @iconv($from, $to.'//IGNORE', $str);
900
        } else {
901
            if (!$from) {
902
                return mb_convert_encoding($str, $to);
903
            }
904
            return mb_convert_encoding($str, $to, $from);
905
        }
906
    }
907
908
    /**
909
     * Get the encoding of a given abject
910
     *
911
     * @param object|string $structure
912
     *
913
     * @return string
914
     */
915
    public function getEncoding($structure) {
916
        if (property_exists($structure, 'parameters')) {
917
            foreach ($structure->parameters as $parameter) {
918
                if (strtolower($parameter->attribute) == "charset") {
919
                    return EncodingAliases::get($parameter->value);
920
                }
921
            }
922
        }elseif (is_string($structure) === true){
923
            return mb_detect_encoding($structure);
924
        }
925
926
        return 'UTF-8';
927
    }
928
929
    /**
930
     * Find the folder containing this message.
931
     * @param null|Folder $folder where to start searching from (top-level inbox by default)
932
     *
933
     * @return mixed|null|Folder
934
     * @throws Exceptions\ConnectionFailedException
935
     * @throws Exceptions\MailboxFetchingException
936
     * @throws InvalidMessageDateException
937
     * @throws MaskNotFoundException
938
     */
939
    public function getContainingFolder(Folder $folder = null) {
940
        $folder = $folder ?: $this->client->getFolders()->first();
941
        $this->client->checkConnection();
942
943
        // Try finding the message by uid in the current folder
944
        $client = new Client;
945
        $client->openFolder($folder->path);
946
        $uidMatches = \imap_fetch_overview($client->getConnection(), $this->uid, IMAP::FT_UID);
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

946
        $uidMatches = \imap_fetch_overview(/** @scrutinizer ignore-type */ $client->getConnection(), $this->uid, IMAP::FT_UID);
Loading history...
947
        $uidMatch = count($uidMatches)
948
            ? new Message($uidMatches[0]->uid, $uidMatches[0]->msgno, $client)
949
            : null;
950
        $client->disconnect();
951
952
        // \imap_fetch_overview() on a parent folder will return the matching message
953
        // even when the message is in a child folder so we need to recursively
954
        // search the children
955
        foreach ($folder->children as $child) {
956
            $childFolder = $this->getContainingFolder($child);
957
958
            if ($childFolder) {
959
                return $childFolder;
960
            }
961
        }
962
963
        // before returning the parent
964
        if ($this->is($uidMatch)) {
965
            return $folder;
966
        }
967
968
        // or signalling that the message was not found in any folder
969
        return null;
970
    }
971
972
    public function getFolder(){
973
        return $this->client->getFolder($this->folder_path);
974
    }
975
976
    /**
977
     * Move the Message into an other Folder
978
     * @param string $mailbox
979
     * @param bool $expunge
980
     * @param bool $create_folder
981
     *
982
     * @return null|Message
983
     * @throws Exceptions\ConnectionFailedException
984
     * @throws InvalidMessageDateException
985
     */
986
    public function moveToFolder($mailbox = 'INBOX', $expunge = false, $create_folder = true) {
987
988
        if($create_folder) $this->client->createFolder($mailbox, true);
989
990
        $target_folder = $this->client->getFolder($mailbox);
991
        $target_status = $target_folder->getStatus(IMAP::SA_ALL);
992
993
        $this->client->openFolder($this->folder_path);
994
        $status = \imap_mail_move($this->client->getConnection(), $this->uid, $mailbox, IMAP::CP_UID);
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

994
        $status = \imap_mail_move(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, $mailbox, IMAP::CP_UID);
Loading history...
995
996
        if($status === true){
997
            if($expunge) $this->client->expunge();
998
            $this->client->openFolder($target_folder->path);
999
1000
            return $target_folder->getMessage($target_status->uidnext, null, $this->fetch_options, $this->fetch_body, $this->fetch_attachment, $this->fetch_flags);
1001
        }
1002
1003
        return null;
1004
    }
1005
1006
    /**
1007
     * Delete the current Message
1008
     * @param bool $expunge
1009
     *
1010
     * @return bool
1011
     * @throws Exceptions\ConnectionFailedException
1012
     */
1013
    public function delete($expunge = true) {
1014
        $this->client->openFolder($this->folder_path);
1015
1016
        $status = \imap_delete($this->client->getConnection(), $this->uid, IMAP::FT_UID);
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_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

1016
        $status = \imap_delete(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, IMAP::FT_UID);
Loading history...
1017
        if($expunge) $this->client->expunge();
1018
1019
        return $status;
1020
    }
1021
1022
    /**
1023
     * Restore a deleted Message
1024
     * @param boolean $expunge
1025
     *
1026
     * @return bool
1027
     * @throws Exceptions\ConnectionFailedException
1028
     */
1029
    public function restore($expunge = true) {
1030
        $this->client->openFolder($this->folder_path);
1031
1032
        $status = \imap_undelete($this->client->getConnection(), $this->uid, IMAP::FT_UID);
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_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

1032
        $status = \imap_undelete(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, IMAP::FT_UID);
Loading history...
1033
        if($expunge) $this->client->expunge();
1034
1035
        return $status;
1036
    }
1037
1038
    /**
1039
     * Get all message attachments.
1040
     *
1041
     * @return AttachmentCollection
1042
     */
1043
    public function getAttachments() {
1044
        return $this->attachments;
1045
    }
1046
1047
    /**
1048
     * Checks if there are any attachments present
1049
     *
1050
     * @return boolean
1051
     */
1052
    public function hasAttachments() {
1053
        return $this->attachments->isEmpty() === false;
1054
    }
1055
1056
    /**
1057
     * Set a given flag
1058
     * @param string|array $flag
1059
     *
1060
     * @return bool
1061
     * @throws Exceptions\ConnectionFailedException
1062
     */
1063
    public function setFlag($flag) {
1064
        $this->client->openFolder($this->folder_path);
1065
1066
        $flag = "\\".trim(is_array($flag) ? implode(" \\", $flag) : $flag);
1067
        $status = \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 true; 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

1067
        $status = \imap_setflag_full(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->getUid(), $flag, SE_UID);
Loading history...
1068
        $this->parseFlags();
1069
1070
        return $status;
1071
    }
1072
1073
    /**
1074
     * Unset a given flag
1075
     * @param string|array $flag
1076
     *
1077
     * @return bool
1078
     * @throws Exceptions\ConnectionFailedException
1079
     */
1080
    public function unsetFlag($flag) {
1081
        $this->client->openFolder($this->folder_path);
1082
1083
        $flag = "\\".trim(is_array($flag) ? implode(" \\", $flag) : $flag);
1084
        $status = \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 true; 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

1084
        $status = \imap_clearflag_full(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->getUid(), $flag, SE_UID);
Loading history...
1085
        $this->parseFlags();
1086
1087
        return $status;
1088
    }
1089
1090
    /**
1091
     * @return null|object|string
1092
     * @throws Exceptions\ConnectionFailedException
1093
     */
1094
    public function getRawBody() {
1095
        if ($this->raw_body === null) {
1096
            $this->client->openFolder($this->folder_path);
1097
1098
            $this->raw_body = \imap_fetchbody($this->client->getConnection(), $this->getUid(), '', $this->fetch_options | IMAP::FT_UID);
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_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

1098
            $this->raw_body = \imap_fetchbody(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->getUid(), '', $this->fetch_options | IMAP::FT_UID);
Loading history...
1099
        }
1100
1101
        return $this->raw_body;
1102
    }
1103
1104
    /**
1105
     * @return string
1106
     */
1107
    public function getHeader() {
1108
        return $this->header;
1109
    }
1110
1111
    /**
1112
     * @return Client
1113
     */
1114
    public function getClient() {
1115
        return $this->client;
1116
    }
1117
1118
    /**
1119
     * @return integer
1120
     */
1121
    public function getFetchOptions() {
1122
        return $this->fetch_options;
1123
    }
1124
1125
    /**
1126
     * @return boolean
1127
     */
1128
    public function getFetchBodyOption() {
1129
        return $this->fetch_body;
1130
    }
1131
1132
    /**
1133
     * @return boolean
1134
     */
1135
    public function getFetchAttachmentOption() {
1136
        return $this->fetch_attachment;
1137
    }
1138
1139
    /**
1140
     * @return boolean
1141
     */
1142
    public function getFetchFlagsOption() {
1143
        return $this->fetch_flags;
1144
    }
1145
1146
    /**
1147
     * @return mixed
1148
     */
1149
    public function getBodies() {
1150
        return $this->bodies;
1151
    }
1152
1153
    /**
1154
     * @return FlagCollection
1155
     */
1156
    public function getFlags() {
1157
        return $this->flags;
1158
    }
1159
1160
    /**
1161
     * @return object|null
1162
     */
1163
    public function getStructure(){
1164
        return $this->structure;
1165
    }
1166
1167
    /**
1168
     * Does this message match another one?
1169
     *
1170
     * A match means same uid, message id, subject and date/time.
1171
     *
1172
     * @param  null|Message $message
1173
     * @return boolean
1174
     */
1175
    public function is(Message $message = null) {
1176
        if (is_null($message)) {
1177
            return false;
1178
        }
1179
1180
        return $this->uid == $message->uid
1181
            && $this->message_id == $message->message_id
1182
            && $this->subject == $message->subject
1183
            && $this->date->eq($message->date);
1184
    }
1185
1186
    /**
1187
     * @return array
1188
     */
1189
    public function getAttributes(){
1190
        return $this->attributes;
1191
    }
1192
1193
    /**
1194
     * @param $mask
1195
     * @return $this
1196
     */
1197
    public function setMask($mask){
1198
        if(class_exists($mask)){
1199
            $this->mask = $mask;
1200
        }
1201
1202
        return $this;
1203
    }
1204
1205
    /**
1206
     * @return string
1207
     */
1208
    public function getMask(){
1209
        return $this->mask;
1210
    }
1211
1212
    /**
1213
     * Get a masked instance by providing a mask name
1214
     * @param string|null $mask
1215
     *
1216
     * @return mixed
1217
     * @throws MaskNotFoundException
1218
     */
1219
    public function mask($mask = null){
1220
        $mask = $mask !== null ? $mask : $this->mask;
1221
        if(class_exists($mask)){
1222
            return new $mask($this);
1223
        }
1224
1225
        throw new MaskNotFoundException("Unknown mask provided: ".$mask);
1226
    }
1227
}
1228