Passed
Push — master ( 6990ab...b50988 )
by Malte
03:01
created

Message::__construct()   B

Complexity

Conditions 6
Paths 32

Size

Total Lines 33
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

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

219
        $this->msgn = ($this->fetch_options == IMAP::FT_UID) ? imap_msgno(/** @scrutinizer ignore-type */ $this->client->getConnection(), $uid) : $uid;
Loading history...
220
221
        $this->parseHeader();
222
223
        if ($this->getFetchFlagsOption() === true) {
224
            $this->parseFlags();
225
        }
226
227
        if ($this->getFetchBodyOption() === true) {
228
            $this->parseBody();
229
        }
230
    }
231
232
    /**
233
     * Call dynamic attribute setter and getter methods
234
     * @param string $method
235
     * @param array $arguments
236
     *
237
     * @return mixed
238
     * @throws MethodNotFoundException
239
     */
240
    public function __call($method, $arguments) {
241
        if(strtolower(substr($method, 0, 3)) === 'get') {
242
            $name = snake_case(substr($method, 3));
0 ignored issues
show
Deprecated Code introduced by
The function snake_case() has been deprecated: Str::snake() should be used directly instead. Will be removed in Laravel 5.9. ( Ignorable by Annotation )

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

242
            $name = /** @scrutinizer ignore-deprecated */ snake_case(substr($method, 3));

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...
243
244
            if(in_array($name, array_keys($this->attributes))) {
245
                return $this->attributes[$name];
246
            }
247
248
        }elseif (strtolower(substr($method, 0, 3)) === 'set') {
249
            $name = snake_case(substr($method, 3));
0 ignored issues
show
Deprecated Code introduced by
The function snake_case() has been deprecated: Str::snake() should be used directly instead. Will be removed in Laravel 5.9. ( Ignorable by Annotation )

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

249
            $name = /** @scrutinizer ignore-deprecated */ snake_case(substr($method, 3));

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...
250
251
            if(in_array($name, array_keys($this->attributes))) {
252
                $this->attributes[$name] = array_pop($arguments);
253
254
                return $this->attributes[$name];
255
            }
256
257
        }
258
259
        throw new MethodNotFoundException("Method ".self::class.'::'.$method.'() is not supported');
260
    }
261
262
    /**
263
     * @param $name
264
     * @param $value
265
     *
266
     * @return mixed
267
     */
268
    public function __set($name, $value) {
269
        $this->attributes[$name] = $value;
270
271
        return $this->attributes[$name];
272
    }
273
274
    /**
275
     * @param $name
276
     *
277
     * @return mixed|null
278
     */
279
    public function __get($name) {
280
        if(isset($this->attributes[$name])) {
281
            return $this->attributes[$name];
282
        }
283
284
        return null;
285
    }
286
287
    /**
288
     * Copy the current Messages to a mailbox
289
     *
290
     * @param $mailbox
291
     * @param int $options
292
     *
293
     * @return bool
294
     * @throws Exceptions\ConnectionFailedException
295
     */
296
    public function copy($mailbox, $options = 0) {
297
        $this->client->openFolder($this->folder_path);
298
        return imap_mail_copy($this->client->getConnection(), $this->msglist, $mailbox, $options);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type 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

298
        return imap_mail_copy(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->msglist, $mailbox, $options);
Loading history...
299
    }
300
301
    /**
302
     * Move the current Messages to a mailbox
303
     *
304
     * @param $mailbox
305
     * @param int $options
306
     *
307
     * @return bool
308
     * @throws Exceptions\ConnectionFailedException
309
     */
310
    public function move($mailbox, $options = 0) {
311
        $this->client->openFolder($this->folder_path);
312
        return imap_mail_move($this->client->getConnection(), $this->msglist, $mailbox, $options);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type true; however, parameter $imap_stream of imap_mail_move() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

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

371
                    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...
372
                        $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

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

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

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

421
            $this->message_no = ($this->fetch_options == IMAP::FT_UID) ? $messageNo : imap_msgno(/** @scrutinizer ignore-type */ $this->client->getConnection(), $messageNo);
Loading history...
422
        } else {
423
            $this->message_no = imap_msgno($this->client->getConnection(), $this->getUid());
424
        }
425
426
        $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

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

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

565
            $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

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

612
            $address->full = ($address->personal) ? $address->personal.' <'./** @scrutinizer ignore-type */ $address->mail.'>' : $address->mail;
Loading history...
613
614
            $addresses[] = $address;
615
        }
616
617
        return $addresses;
618
    }
619
620
    /**
621
     * Parse the Message body
622
     *
623
     * @return $this
624
     * @throws Exceptions\ConnectionFailedException
625
     */
626
    public function parseBody() {
627
        $this->client->openFolder($this->folder_path);
628
        $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

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

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

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

980
        $status = imap_mail_move(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, $mailbox, IMAP::CP_UID);
Loading history...
981
982
        if($status === true){
983
            if($expunge) $this->client->expunge();
984
            $this->client->openFolder($target_folder->path);
985
986
            return $target_folder->getMessage($target_status->uidnext);
987
        }
988
989
        return null;
990
    }
991
992
    /**
993
     * Delete the current Message
994
     * @param bool $expunge
995
     *
996
     * @return bool
997
     * @throws Exceptions\ConnectionFailedException
998
     */
999
    public function delete($expunge = true) {
1000
        $this->client->openFolder($this->folder_path);
1001
1002
        $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

1002
        $status = imap_delete(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, IMAP::FT_UID);
Loading history...
1003
        if($expunge) $this->client->expunge();
1004
1005
        return $status;
1006
    }
1007
1008
    /**
1009
     * Restore a deleted Message
1010
     * @param boolean $expunge
1011
     *
1012
     * @return bool
1013
     * @throws Exceptions\ConnectionFailedException
1014
     */
1015
    public function restore($expunge = true) {
1016
        $this->client->openFolder($this->folder_path);
1017
1018
        $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

1018
        $status = imap_undelete(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->uid, IMAP::FT_UID);
Loading history...
1019
        if($expunge) $this->client->expunge();
1020
1021
        return $status;
1022
    }
1023
1024
    /**
1025
     * Get all message attachments.
1026
     *
1027
     * @return AttachmentCollection
1028
     */
1029
    public function getAttachments() {
1030
        return $this->attachments;
1031
    }
1032
1033
    /**
1034
     * Checks if there are any attachments present
1035
     *
1036
     * @return boolean
1037
     */
1038
    public function hasAttachments() {
1039
        return $this->attachments->isEmpty() === false;
1040
    }
1041
1042
    /**
1043
     * Set a given flag
1044
     * @param string|array $flag
1045
     *
1046
     * @return bool
1047
     * @throws Exceptions\ConnectionFailedException
1048
     */
1049
    public function setFlag($flag) {
1050
        $this->client->openFolder($this->folder_path);
1051
1052
        $flag = "\\".trim(is_array($flag) ? implode(" \\", $flag) : $flag);
1053
        $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

1053
        $status = imap_setflag_full(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->getUid(), $flag, SE_UID);
Loading history...
1054
        $this->parseFlags();
1055
1056
        return $status;
1057
    }
1058
1059
    /**
1060
     * Unset a given flag
1061
     * @param string|array $flag
1062
     *
1063
     * @return bool
1064
     * @throws Exceptions\ConnectionFailedException
1065
     */
1066
    public function unsetFlag($flag) {
1067
        $this->client->openFolder($this->folder_path);
1068
1069
        $flag = "\\".trim(is_array($flag) ? implode(" \\", $flag) : $flag);
1070
        $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

1070
        $status = imap_clearflag_full(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->getUid(), $flag, SE_UID);
Loading history...
1071
        $this->parseFlags();
1072
1073
        return $status;
1074
    }
1075
1076
    /**
1077
     * @return null|object|string
1078
     * @throws Exceptions\ConnectionFailedException
1079
     */
1080
    public function getRawBody() {
1081
        if ($this->raw_body === null) {
1082
            $this->client->openFolder($this->folder_path);
1083
1084
            $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

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