Passed
Push — master ( b99c9f...d56d2c )
by Malte
04:37
created

Message::getToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

375
                    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...
376
                        $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

376
                        $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...
377
                    }
378
                }
379
            });
380
        }
381
382
        return $body;
383
    }
384
385
    /**
386
     * Parse all defined headers
387
     *
388
     * @return void
389
     * @throws Exceptions\ConnectionFailedException
390
     * @throws InvalidMessageDateException
391
     */
392
    private function parseHeader() {
393
        $this->client->openFolder($this->folder_path);
394
        $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

394
        $this->header = $header = \imap_fetchheader(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, IMAP::FT_UID);
Loading history...
395
396
        $this->priority = $this->extractPriority($this->header);
397
398
        if ($this->header) {
399
            $header = \imap_rfc822_parse_headers($this->header);
400
        }
401
402
        if (property_exists($header, 'subject')) {
403
            if($this->config['decoder']['message']['subject'] === 'utf-8') {
404
                $this->subject = \imap_utf8($header->subject);
405
            }elseif($this->config['decoder']['message']['subject'] === 'iconv') {
406
                $this->subject = iconv_mime_decode($header->subject);
407
            }else{
408
                $this->subject = mb_decode_mimeheader($header->subject);
409
            }
410
        }
411
412
        foreach(['from', 'to', 'cc', 'bcc', 'reply_to', 'sender'] as $part){
413
            $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

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

427
            $this->message_no = ($this->fetch_options == IMAP::FT_UID) ? $messageNo : \imap_msgno(/** @scrutinizer ignore-type */ $this->client->getConnection(), $messageNo);
Loading history...
428
        } else {
429
            $this->message_no = \imap_msgno($this->client->getConnection(), $this->getUid());
430
        }
431
432
        $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

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

539
        $flags = \imap_fetch_overview(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, IMAP::FT_UID);
Loading history...
540
        if (is_array($flags) && isset($flags[0])) {
541
            foreach($this->available_flags as $flag) {
542
                $this->parseFlag($flags, $flag);
543
            }
544
        }
545
    }
546
547
    /**
548
     * Extract a possible flag information from a given array
549
     * @param array $flags
550
     * @param string $flag
551
     */
552
    private function parseFlag($flags, $flag) {
553
        $flag = strtolower($flag);
554
555
        if (property_exists($flags[0], strtoupper($flag))) {
556
            $this->flags->put($flag, $flags[0]->{strtoupper($flag)});
557
        } elseif (property_exists($flags[0], ucfirst($flag))) {
558
            $this->flags->put($flag, $flags[0]->{ucfirst($flag)});
559
        } elseif (property_exists($flags[0], $flag)) {
560
            $this->flags->put($flag, $flags[0]->$flag);
561
        }
562
    }
563
564
    /**
565
     * Get the current Message header info
566
     *
567
     * @return object
568
     * @throws Exceptions\ConnectionFailedException
569
     */
570
    public function getHeaderInfo() {
571
        if ($this->header_info == null) {
572
            $this->client->openFolder($this->folder_path);
573
            $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 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

573
            $this->header_info = \imap_headerinfo(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->getMessageNo());
Loading history...
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

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

623
            $address->full = ($address->personal) ? $address->personal.' <'./** @scrutinizer ignore-type */ $address->mail.'>' : $address->mail;
Loading history...
624
625
            $addresses[] = $address;
626
        }
627
628
        return $addresses;
629
    }
630
631
    /**
632
     * Parse the Message body
633
     *
634
     * @return $this
635
     * @throws Exceptions\ConnectionFailedException
636
     */
637
    public function parseBody() {
638
        $this->client->openFolder($this->folder_path);
639
        $this->structure = \imap_fetchstructure($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_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

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

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

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

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

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

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

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

1091
        $status = \imap_clearflag_full(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->getUid(), $flag, SE_UID);
Loading history...
1092
        $this->parseFlags();
1093
1094
        return $status;
1095
    }
1096
1097
    /**
1098
     * @return null|object|string
1099
     * @throws Exceptions\ConnectionFailedException
1100
     */
1101
    public function getRawBody() {
1102
        if ($this->raw_body === null) {
1103
            $this->client->openFolder($this->folder_path);
1104
1105
            $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

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