mirror of
https://github.com/itflow-org/itflow
synced 2026-02-28 02:44:53 +00:00
Reintroduce Webklex IMAP for ticket processing as PHP-IMAP is no longer being developed. This is optional for now and considered beta can be found in cron/ticket_email_parser.php
This commit is contained in:
2
plugins/vendor/webklex/php-imap/.github/FUNDING.yml
vendored
Normal file
2
plugins/vendor/webklex/php-imap/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
ko_fi: webklex
|
||||
custom: ['https://www.buymeacoffee.com/webklex']
|
||||
32
plugins/vendor/webklex/php-imap/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
32
plugins/vendor/webklex/php-imap/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Used config**
|
||||
Please provide the used config, if you are not using the package default config.
|
||||
|
||||
**Code to Reproduce**
|
||||
The troubling code section which produces the reported bug.
|
||||
```php
|
||||
echo "Bug";
|
||||
```
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop / Server (please complete the following information):**
|
||||
- OS: [e.g. Debian 10]
|
||||
- PHP: [e.g. 5.5.9]
|
||||
- Version [e.g. v2.3.1]
|
||||
- Provider [e.g. Gmail, Outlook, Dovecot]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
17
plugins/vendor/webklex/php-imap/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
17
plugins/vendor/webklex/php-imap/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
12
plugins/vendor/webklex/php-imap/.github/ISSUE_TEMPLATE/general-help-request.md
vendored
Normal file
12
plugins/vendor/webklex/php-imap/.github/ISSUE_TEMPLATE/general-help-request.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
name: General help request
|
||||
about: Feel free to ask about any project related stuff
|
||||
|
||||
---
|
||||
|
||||
Please be aware that these issues will be closed if inactive for more then 14 days.
|
||||
|
||||
Also make sure to use https://github.com/Webklex/php-imap/issues/new?template=bug_report.md if you want to report a bug
|
||||
or https://github.com/Webklex/php-imap/issues/new?template=feature_request.md if you want to suggest a feature.
|
||||
|
||||
Still here? Well clean this out and go ahead :)
|
||||
23
plugins/vendor/webklex/php-imap/.github/docker/Dockerfile
vendored
Normal file
23
plugins/vendor/webklex/php-imap/.github/docker/Dockerfile
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
FROM ubuntu:latest
|
||||
LABEL maintainer="Webklex <github@webklex.com>"
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get upgrade -y
|
||||
RUN apt-get install -y sudo dovecot-imapd
|
||||
|
||||
ENV LIVE_MAILBOX=true
|
||||
ENV LIVE_MAILBOX_HOST=mail.example.local
|
||||
ENV LIVE_MAILBOX_PORT=993
|
||||
ENV LIVE_MAILBOX_ENCRYPTION=ssl
|
||||
ENV LIVE_MAILBOX_VALIDATE_CERT=true
|
||||
ENV LIVE_MAILBOX_USERNAME=root@example.local
|
||||
ENV LIVE_MAILBOX_PASSWORD=foobar
|
||||
ENV LIVE_MAILBOX_QUOTA_SUPPORT=true
|
||||
|
||||
EXPOSE 993
|
||||
|
||||
ADD dovecot_setup.sh /root/dovecot_setup.sh
|
||||
RUN chmod +x /root/dovecot_setup.sh
|
||||
|
||||
CMD ["/bin/bash", "-c", "/root/dovecot_setup.sh && tail -f /dev/null"]
|
||||
|
||||
63
plugins/vendor/webklex/php-imap/.github/docker/dovecot_setup.sh
vendored
Normal file
63
plugins/vendor/webklex/php-imap/.github/docker/dovecot_setup.sh
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
|
||||
sudo apt-get -q update
|
||||
sudo apt-get -q -y install dovecot-imapd
|
||||
|
||||
{
|
||||
echo "127.0.0.1 $LIVE_MAILBOX_HOST"
|
||||
} | sudo tee -a /etc/hosts
|
||||
|
||||
SSL_CERT="/etc/ssl/certs/dovecot.crt"
|
||||
SSL_KEY="/etc/ssl/private/dovecot.key"
|
||||
|
||||
sudo openssl req -new -x509 -days 3 -nodes \
|
||||
-out "$SSL_CERT" \
|
||||
-keyout "$SSL_KEY" \
|
||||
-subj "/C=EU/ST=Europe/L=Home/O=Webklex/OU=Webklex DEV/CN=""$LIVE_MAILBOX_HOST"
|
||||
|
||||
sudo chown root:dovecot "$SSL_CERT" "$SSL_KEY"
|
||||
sudo chmod 0440 "$SSL_CERT"
|
||||
sudo chmod 0400 "$SSL_KEY"
|
||||
|
||||
DOVECOT_CONF="/etc/dovecot/local.conf"
|
||||
MAIL_CONF="/etc/dovecot/conf.d/10-mail.conf"
|
||||
IMAP_CONF="/etc/dovecot/conf.d/20-imap.conf"
|
||||
QUOTA_CONF="/etc/dovecot/conf.d/90-quota.conf"
|
||||
sudo touch "$DOVECOT_CONF" "$MAIL_CONF" "$IMAP_CONF" "$QUOTA_CONF"
|
||||
sudo chown root:dovecot "$DOVECOT_CONF" "$MAIL_CONF" "$IMAP_CONF" "$QUOTA_CONF"
|
||||
sudo chmod 0640 "$DOVECOT_CONF" "$MAIL_CONF" "$IMAP_CONF" "$QUOTA_CONF"
|
||||
|
||||
{
|
||||
echo "ssl = required"
|
||||
echo "disable_plaintext_auth = yes"
|
||||
echo "ssl_cert = <""$SSL_CERT"
|
||||
echo "ssl_key = <""$SSL_KEY"
|
||||
echo "ssl_protocols = !SSLv2 !SSLv3"
|
||||
echo "ssl_cipher_list = AES128+EECDH:AES128+EDH"
|
||||
} | sudo tee -a "$DOVECOT_CONF"
|
||||
|
||||
{
|
||||
echo "mail_plugins = \$mail_plugins quota"
|
||||
} | sudo tee -a "$MAIL_CONF"
|
||||
|
||||
{
|
||||
echo "protocol imap {"
|
||||
echo " mail_plugins = \$mail_plugins imap_quota"
|
||||
echo "}"
|
||||
} | sudo tee -a "$IMAP_CONF"
|
||||
|
||||
{
|
||||
echo "plugin {"
|
||||
echo " quota = maildir:User quota"
|
||||
echo " quota_rule = *:storage=1G"
|
||||
echo "}"
|
||||
} | sudo tee -a "$QUOTA_CONF"
|
||||
|
||||
sudo useradd --create-home --shell /bin/false "$LIVE_MAILBOX_USERNAME"
|
||||
echo "$LIVE_MAILBOX_USERNAME"":""$LIVE_MAILBOX_PASSWORD" | sudo chpasswd
|
||||
|
||||
sudo service dovecot restart
|
||||
|
||||
sudo doveadm auth test -x service=imap "$LIVE_MAILBOX_USERNAME" "$LIVE_MAILBOX_PASSWORD"
|
||||
50
plugins/vendor/webklex/php-imap/.github/workflows/tests.yaml
vendored
Normal file
50
plugins/vendor/webklex/php-imap/.github/workflows/tests.yaml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
phpunit:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
php: ['8.0', 8.1, 8.2, 8.3, 8.4]
|
||||
|
||||
name: PHP ${{ matrix.php }}
|
||||
|
||||
env:
|
||||
LIVE_MAILBOX: true
|
||||
LIVE_MAILBOX_DEBUG: true
|
||||
LIVE_MAILBOX_HOST: mail.example.local
|
||||
LIVE_MAILBOX_PORT: 993
|
||||
LIVE_MAILBOX_USERNAME: root@example.local
|
||||
LIVE_MAILBOX_ENCRYPTION: ssl
|
||||
LIVE_MAILBOX_PASSWORD: foobar
|
||||
LIVE_MAILBOX_QUOTA_SUPPORT: true
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: openssl, json, mbstring, iconv, fileinfo, libxml, zip
|
||||
coverage: none
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --prefer-dist --no-interaction --no-progress
|
||||
|
||||
- run: "sh .github/docker/dovecot_setup.sh"
|
||||
|
||||
- name: Execute tests
|
||||
run: vendor/bin/phpunit
|
||||
7
plugins/vendor/webklex/php-imap/.gitignore
vendored
Normal file
7
plugins/vendor/webklex/php-imap/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
vendor
|
||||
composer.lock
|
||||
.idea
|
||||
/build/
|
||||
test.php
|
||||
.phpunit.result.cache
|
||||
phpunit.xml
|
||||
964
plugins/vendor/webklex/php-imap/CHANGELOG.md
vendored
Executable file
964
plugins/vendor/webklex/php-imap/CHANGELOG.md
vendored
Executable file
@@ -0,0 +1,964 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to `webklex/php-imap` will be documented in this file.
|
||||
|
||||
Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
|
||||
|
||||
## [UNRELEASED]
|
||||
### Fixed
|
||||
- NaN
|
||||
|
||||
### Added
|
||||
- NaN
|
||||
|
||||
### Breaking changes
|
||||
- NaN
|
||||
|
||||
## [6.2.0] - 2025-04-25
|
||||
### Fixed
|
||||
- When using the chunk function, some messages do not have an element with index 0 #552 #553 (thanks @zeddmaster)
|
||||
- Get folders list in hierarchical order #560 #561 (thanks @rskrzypczak)
|
||||
- Fix remaining implicit marking of parameters as nullable (PHP 8.4) #566 (thanks @steffenweber)
|
||||
- Fix case sensitivity of folder attribute parsing (\NoSelect, \NoInferiors) #469 #571 (thanks @smajti1)
|
||||
- Fix error on getUid(null) with 0 results (#499) #573 (thanks @pierement)
|
||||
- Fix Date parsing on non-standard format from Aqua Mail #574 #575 (thanks @lm-cmxkonzepte)
|
||||
|
||||
### Added
|
||||
- SSL stream context options added #238 #546 (thanks @llemoine)
|
||||
- Support copy/move Message with utf7 folder path #559 (thanks @loc4l)
|
||||
- Public `Query::search()` method #565 (Thanks @madbob)
|
||||
|
||||
## [6.1.0] - 2025-01-19
|
||||
### Fixed
|
||||
- Filename sanitization is now optional (enabled via default)
|
||||
- Address parsing improved and extended to include more cases
|
||||
- Boundary parsing fixed and improved to support more formats #544
|
||||
- Decode partially encoded address names #511
|
||||
- Enforce RFC822 parsing if enabled #462
|
||||
|
||||
### Added
|
||||
- Security configuration options added
|
||||
- Spoofing detection added #40
|
||||
- RFC4315 MOVE fallback added #123 (thanks @freescout-help-desk)
|
||||
- Content fetching RFC standard support added #510 (thanks @ybizeul)
|
||||
- Support unescaped dates inside the search conditions #542
|
||||
- `Client::clone()` looses account configuration #521 (thanks @netpok)
|
||||
|
||||
## [6.0.0] - 2025-01-17
|
||||
### Fixed
|
||||
- Fixed date issue if timezone is UT and a 2 digit year #429 (thanks @ferrisbuellers)
|
||||
- Make the space optional after a comma separator #437 (thanks @marc0adam)
|
||||
- Fix bug when multipart message getHTMLBody() method returns null #455 (thanks @michalkortas)
|
||||
- Fix: Improve return type hints and return docblocks for query classes #470 (thanks @olliescase)
|
||||
- Fix - Query - Chunked - Resolved infinite loop when start chunk > 1 #477 (thanks @NeekTheNook)
|
||||
- Attachment with symbols in filename #436 (thanks @nuernbergerA)
|
||||
- Ignore possible untagged lines after IDLE and DONE commands #445 (thanks @gazben)
|
||||
- Fix Empty Child Folder Error #474 (thanks @bierpub)
|
||||
- Filename sanitization improved #501 (thanks @neolip)
|
||||
- `Client::getFolderPath()` return null if folder is not set #506 (thanks @arnolem)
|
||||
- Fix implicit marking of parameters as nullable, deprecated in PHP 8.4 #518 (thanks @campbell-m)
|
||||
|
||||
### Added
|
||||
- IMAP STATUS command support added `Folder::status()` #424 (thanks @InterLinked1)
|
||||
- Add attributes and special flags #428 (thanks @sazanof)
|
||||
- Better connection check for IMAP #449 (thanks @thin-k-design)
|
||||
- Config handling moved into a new class `Config::class` to allow class serialization (sponsored by elb-BIT GmbH)
|
||||
- Support for Carbon 3 added #483
|
||||
- Custom decoder support added
|
||||
- Decoding filename with non-standard encoding #535 (thanks @grnsv)
|
||||
|
||||
### Breaking changes
|
||||
- The decoder config has been moved from `options.decoder` to `decoding` and contains now the `decoder` class to used as well as their decoding fallbacks
|
||||
- `Folder::getStatus()` no longer returns the results of `EXAMINE` but `STATUS` instead. If you want to use `EXAMINE` you can use the `Folder::examine()` method instead.
|
||||
- `ClientManager::class` has now longer access to all configs. Config handling has been moved to its own class `Config::class`. If you want to access the config you can use the retriever method `::getConfig()` instead. Example: `$client->getConfig()` or `$message->getConfig()`, etc.
|
||||
- `ClientManager::get` isn't available anymore. Use the regular config accessor instead. Example: `$cm->getConfig()->get($key)`
|
||||
- `M̀essage::getConfig()` now returns the client configuration instead of the fetching options configuration. Please use `$message->getOptions()` instead.
|
||||
- `Attachment::getConfig()` now returns the client configuration instead of the fetching options configuration. Please use `$attachment->getOptions()` instead.
|
||||
- `Header::getConfig()` now returns the client configuration instead of the fetching options configuration. Please use `$header->getOptions()` instead.
|
||||
- `M̀essage::setConfig` now expects the client configuration instead of the fetching options configuration. Please use `$message->setOptions` instead.
|
||||
- `Attachment::setConfig` now expects the client configuration instead of the fetching options configuration. Please use `$attachment->setOptions` instead.
|
||||
- `Header::setConfig` now expects the client configuration instead of the fetching options configuration. Please use `$header->setOptions` instead.
|
||||
- All protocol constructors now require a `Config::class` instance
|
||||
- The `Client::class` constructor now require a `Config::class` instance
|
||||
- The `Part::class` constructor now require a `Config::class` instance
|
||||
- The `Header::class` constructor now require a `Config::class` instance
|
||||
- The `Message::fromFile` method now requires a `Config::class` instance
|
||||
- The `Message::fromString` method now requires a `Config::class` instance
|
||||
- The `Message::boot` method now requires a `Config::class` instance
|
||||
- The `Message::decode` method has been removed. Use `Message::getDecoder()->decode($str)` instead.
|
||||
- The `Message::getEncoding` method has been removed. Use `Message::getDecoder()->getEncoding($str)` instead.
|
||||
- The `Message::convertEncoding` method has been removed. Use `Message::getDecoder()->convertEncoding()` instead.
|
||||
- The `Header::decode` method has been removed. Use `Header::getDecoder()->decode($str)` instead.
|
||||
|
||||
## [5.5.0] - 2023-06-28
|
||||
### Fixed
|
||||
- Error token length mismatch in `ImapProtocol::readResponse` #400
|
||||
- Attachment name parsing fixed #410 #421 (thanks @nuernbergerA)
|
||||
- Additional Attachment name fallback added to prevent missing attachments
|
||||
- Attachment id is now static (based on the raw part content) instead of random
|
||||
- Always parse the attachment description if it is available
|
||||
|
||||
### Added
|
||||
- Attachment content hash added
|
||||
|
||||
|
||||
## [5.4.0] - 2023-06-24
|
||||
### Fixed
|
||||
- Legacy protocol support fixed (object to array conversion) #411
|
||||
- Header value decoding improved #410
|
||||
- Protocol exception handling improved (bad response message added) #408
|
||||
- Prevent fetching singular rfc partials from running indefinitely #407
|
||||
- Subject with colon ";" is truncated #401
|
||||
- Catching and handling iconv decoding exception #397
|
||||
|
||||
### Added
|
||||
- Additional timestamp formats added #198 #392 (thanks @esk-ap)
|
||||
|
||||
|
||||
## [5.3.0] - Security patch - 2023-06-20
|
||||
### Fixed
|
||||
- Potential RCE through path traversal fixed #414 (special thanks @angelej)
|
||||
|
||||
### Security Impact and Mitigation
|
||||
Impacted are all versions below v5.3.0.
|
||||
If possible, update to >= v5.3.0 as soon as possible. Impacted was the `Attachment::save`
|
||||
method which could be used to write files to the local filesystem. The path was not
|
||||
properly sanitized and could be used to write files to arbitrary locations.
|
||||
|
||||
However, the `Attachment::save` method is not used by default and has to be called
|
||||
manually. If you are using this method without providing a sanitized path, you are
|
||||
affected by this vulnerability.
|
||||
If you are not using this method or are providing a sanitized path, you are not affected
|
||||
by this vulnerability and no immediate action is required.
|
||||
|
||||
If you have any questions, please feel welcome to join this issue: https://github.com/Webklex/php-imap/issues/416
|
||||
#### Timeline
|
||||
- 17.06.23 21:30: Vulnerability reported
|
||||
- 18.06.23 19:14: Vulnerability confirmed
|
||||
- 19.06.23 18:41: Vulnerability fixed via PR #414
|
||||
- 20.06.23 13:45: Security patch released
|
||||
- 21.06.23 20:48: CVE-2023-35169 got assigned
|
||||
- 21.06.23 20:58: Advisory released https://github.com/Webklex/php-imap/security/advisories/GHSA-47p7-xfcc-4pv9
|
||||
|
||||
|
||||
## [5.2.0] - 2023-04-11
|
||||
### Fixed
|
||||
- Use all available methods to detect the attachment extension instead of just one
|
||||
- Allow the `LIST` command response to be empty #393
|
||||
- Initialize folder children attributes on class initialization
|
||||
|
||||
### Added
|
||||
- Soft fail option added to all folder fetching methods. If soft fail is enabled, the method will return an empty collection instead of throwing an exception if the folder doesn't exist
|
||||
|
||||
|
||||
## [5.1.0] - 2023-03-16
|
||||
### Fixed
|
||||
- IMAP Quota root command fixed
|
||||
- Prevent line-breaks in folder path caused by special chars
|
||||
- Partial fix for #362 (allow overview response to be empty)
|
||||
- `Message::setConfig()` config parameter type set to array
|
||||
- Reset the protocol uid cache if the session gets expunged
|
||||
- Set the "seen" flag only if the flag isn't set and the fetch option isn't `IMAP::FT_PEEK`
|
||||
- `Message::is()` date comparison fixed
|
||||
- `Message::$client` could not be set to null
|
||||
- `in_reply_to` and `references` parsing fixed
|
||||
- Prevent message body parser from injecting empty lines
|
||||
- Don't parse regular inline message parts without name or filename as attachment
|
||||
- `Message::hasTextBody()` and `Message::hasHtmlBody()` should return `false` if the body is empty
|
||||
- Imap-Protocol "empty response" detection extended to catch an empty response caused by a broken resource stream
|
||||
- `iconv_mime_decode()` is now used with `ICONV_MIME_DECODE_CONTINUE_ON_ERROR` to prevent the decoding from failing
|
||||
- Date decoding rules extended to support more date formats
|
||||
- Unset the currently active folder if it gets deleted (prevent infinite loop)
|
||||
- Attachment name and filename parsing fixed and improved to support more formats
|
||||
- Check if the next uid is available (after copying or moving a message) before fetching it #381
|
||||
- Default pagination `$total` attribute value set to 0 #385 (thanks @hhniao)
|
||||
- Use attachment ID as fallback filename for saving an attachment
|
||||
- Address decoding error detection added #388
|
||||
|
||||
### Added
|
||||
- Extended UTF-7 support added (RFC2060) #383
|
||||
- `Protocol::sizes()` support added (fetch the message byte size via RFC822.SIZE). Accessible through `Message::getSize()` #379 (thanks @didi1357)
|
||||
- `Message::hasFlag()` method added to check if a message has a specific flag
|
||||
- `Message::getConfig()` method added to get the current message configuration
|
||||
- `Folder::select()` method added to select a folder
|
||||
- `Message::getAvailableFlags()` method added to get all available flags
|
||||
- Live mailbox and fixture tests added
|
||||
- `Attribute::map()` method added to map all attribute values
|
||||
- `Header::has()` method added to check if a header attribute / value exist
|
||||
- All part attributes are now accessible via linked attribute
|
||||
- Restore a message from string `Message::fromString()`
|
||||
|
||||
|
||||
## [5.0.1] - 2023-03-01
|
||||
### Fixed
|
||||
- More unique ID generation to prevent multiple attachments with same ID #363 (thanks @Guite)
|
||||
- Not all attachments are pushed to the collection #372 (thanks @AdrianKuriata)
|
||||
- Partial fix for #362 (allow search response to be empty)
|
||||
- Unsafe usage of switch case. #354 #366 (thanks @shuergab)
|
||||
- Fix use of ST_MSGN as sequence method #356 (thanks @gioid)
|
||||
- Prevent infinite loop in ImapProtocol #316 (thanks @thin-k-design)
|
||||
|
||||
|
||||
## [5.0.0] - 2023-01-18
|
||||
### Fixed
|
||||
- The message uid and message number will only be fetched if accessed and wasn't previously set #326 #285 (thanks @szymekjanaczek)
|
||||
- Fix undefined attachment name when headers use "filename*=" format #301 (thanks @JulienChavee)
|
||||
- Fixed `ImapProtocol::logout` always throws 'not connected' Exception after upgraded to 4.1.2 #351
|
||||
- Protocol interface and methods unified
|
||||
- Strict attribute and return types introduced where ever possible
|
||||
- Parallel messages during idle #338
|
||||
- Idle timeout / stale resource stream issue fixed
|
||||
- Syntax updated to support php 8 features
|
||||
- Get the attachment file extension from the filename if no mimetype detection library is available
|
||||
- Prevent the structure parsing from parsing an empty part
|
||||
- Convert all header keys to their lower case representation
|
||||
- Restructure the decode function #355 (thanks @istid)
|
||||
|
||||
### Added
|
||||
- Unit tests added #347 #242 (thanks @sergiy-petrov, @boekkooi-lengoo)
|
||||
- `Client::clone()` method added to clone a client instance
|
||||
- Save an entire message (including its headers) `Message::save()`
|
||||
- Restore a message from a local or remote file `Message::fromFile()`
|
||||
- Protocol resource stream accessor added `Protocol::getStream()`
|
||||
- Protocol resource stream meta data accessor added `Protocol::meta()`
|
||||
- ImapProtocol resource stream reset method added `ImapProtocol::reset()`
|
||||
- Protocol `Response::class` introduced to handle and unify all protocol requests
|
||||
- Static mask config accessor added `ClientManager::getMask()` added
|
||||
- An `Attribute::class` instance can be treated as array
|
||||
- Get the current client account configuration via `Client::getConfig()`
|
||||
- Delete a folder via `Client::deleteFolder()`
|
||||
|
||||
### Breaking changes
|
||||
- PHP ^8.0.2 required
|
||||
- `nesbot/carbon` version bumped to ^2.62.1
|
||||
- `phpunit/phpunit` version bumped to ^9.5.10
|
||||
- `Header::get()` always returns an `Attribute::class` instance
|
||||
- `Attribute::class` accessor methods renamed to shorten their names and improve the readability
|
||||
- All protocol methods that used to return `array|bool` will now always return a `Response::class` instance.
|
||||
- `ResponseException::class` gets thrown if a response is empty or contains errors
|
||||
- Message client is optional and can be null (e.g. if used in combination with `Message::fromFile()`)
|
||||
- The message text or html body is now "" if its empty and not `null`
|
||||
|
||||
|
||||
## [4.1.2] - 2022-12-14
|
||||
### Fixed
|
||||
- Attachment ID can return an empty value #318
|
||||
- Additional message date format added #345 (thanks @amorebietakoUdala)
|
||||
|
||||
|
||||
## [4.1.1] - 2022-11-16
|
||||
### Fixed
|
||||
- Fix for extension recognition #325 (thanks @pwoszczyk)
|
||||
- Missing null check added #327 (thanks @spanjeta)
|
||||
- Leading white-space in response causes an infinite loop #321 (thanks @thin-k-design)
|
||||
- Fix error when creating folders with special chars #319 (thanks @thin-k-design)
|
||||
- `Client::getFoldersWithStatus()` recursive loading fixed #312 (thanks @szymekjanaczek)
|
||||
- Fix Folder name encoding error in `Folder::appendMessage()` #306 #307 (thanks @rskrzypczak)
|
||||
|
||||
|
||||
## [4.1.0] - 2022-10-18
|
||||
### Fixed
|
||||
- Fix assumedNextTaggedLine bug #288 (thanks @Blear)
|
||||
- Fix empty response error for blank lines #274 (thanks @bierpub)
|
||||
- Fix empty body #233 (thanks @latypoff)
|
||||
- Fix imap_reopen folder argument #234 (thanks @latypoff)
|
||||
|
||||
### Added
|
||||
- Added possibility of loading a Folder status #298 (thanks @szymekjanaczek)
|
||||
|
||||
|
||||
## [4.0.2] - 2022-08-26
|
||||
### Fixed
|
||||
- RFC 822 3.1.1. long header fields regular expression fixed #268 #269 (thanks @hbraehne)
|
||||
|
||||
|
||||
## [4.0.1] - 2022-08-25
|
||||
### Fixed
|
||||
- Type casting added to several ImapProtocol return values #261
|
||||
- Remove IMAP::OP_READONLY flag from imap_reopen if POP3 or NNTP protocol is selected #135 (thanks @xianzhe18)
|
||||
- Several statements optimized and redundant checks removed
|
||||
- Check if the Protocol supports the fetch method if extensions are present
|
||||
- Detect `NONEXISTENT` errors while selecting or examining a folder #266
|
||||
- Missing type cast added to `PaginatedCollection::paginate` #267 (thanks @rogerb87)
|
||||
- Fix multiline header unfolding #250 (thanks @sulgie-eitea)
|
||||
- Fix problem with illegal offset error #226 (thanks @szymekjanaczek)
|
||||
- Typos fixed
|
||||
|
||||
### Affected Classes
|
||||
- [Query::class](src/Query/Query.php)
|
||||
- [ImapProtocol::class](src/Connection/Protocols/ImapProtocol.php)
|
||||
- [LegacyProtocol::class](src/Connection/Protocols/LegacyProtocol.php)
|
||||
- [PaginatedCollection::class](src/Support/PaginatedCollection.php)
|
||||
|
||||
|
||||
## [4.0.0] - 2022-08-19
|
||||
### Fixed
|
||||
- PHP dependency updated to support php v8.0 #212 #214 (thanks @freescout-helpdesk)
|
||||
- Method return and argument types added
|
||||
- Imap `DONE` method refactored
|
||||
- UID cache loop fixed
|
||||
- `HasEvent::getEvent` return value set to mixed to allow multiple event types
|
||||
- Protocol line reader changed to `fread` (stream_context timeout issue fixed)
|
||||
- Issue setting the client timeout fixed
|
||||
- IMAP Connection debugging improved
|
||||
- `Folder::idle()` method reworked and several issues fixed #170 #229 #237 #249 #258
|
||||
- Datetime conversion rules extended #189 #173
|
||||
|
||||
### Affected Classes
|
||||
- [Client::class](src/Client.php)
|
||||
- [Folder::class](src/Folder.php)
|
||||
- [ImapProtocol::class](src/Connection/Protocols/ImapProtocol.php)
|
||||
- [HasEvents::class](src/Traits/HasEvents.php)
|
||||
|
||||
### Breaking changes
|
||||
- No longer supports php >=5.5.9 but instead requires at least php v7.0.0.
|
||||
- `HasEvent::getEvent` returns a mixed result. Either an `Event` or a class string representing the event class.
|
||||
- The error message, if the connection fails to read the next line, is now `empty response` instead of `failed to read - connection closed?`.
|
||||
- The `$auto_reconnect` used with `Folder::indle()` is deprecated and doesn't serve any purpose anymore.
|
||||
|
||||
|
||||
## [3.2.0] - 2022-03-07
|
||||
### Fixed
|
||||
- Fix attribute serialization #179 (thanks @netpok)
|
||||
- Use real tls instead of starttls #180 (thanks @netpok)
|
||||
- Allow to fully overwrite default config arrays #194 (thanks @laurent-rizer)
|
||||
- Query::chunked does not loop over the last chunk #196 (thanks @laurent-rizer)
|
||||
- Fix isAttachment that did not properly take in consideration dispositions options #195 (thanks @laurent-rizer)
|
||||
- Extend date parsing error message #173
|
||||
- Fixed 'Where' method replaces the content with uppercase #148
|
||||
- Don't surround numeric search values with quotes
|
||||
- Context added to `InvalidWhereQueryCriteriaException`
|
||||
- Redundant `stream_set_timeout()` removed
|
||||
|
||||
### Added
|
||||
- UID Cache added #204 (thanks @HelloSebastian)
|
||||
- Query::class extended with `getByUidLower`, `getByUidLowerOrEqual` , `getByUidGreaterOrEqual` , `getByUidGreater` to fetch certain ranges of uids #201 (thanks @HelloSebastian)
|
||||
- Check if IDLE is supported if `Folder::idle()` is called #199 (thanks @HelloSebastian)
|
||||
- Fallback date support added. The config option `options.fallback_date` is used as fallback date is it is set. Otherwise, an exception will be thrown #198
|
||||
- UID filter support added
|
||||
- Make boundary regex configurable #169 #150 #126 #121 #111 #152 #108 (thanks @EthraZa)
|
||||
- IMAP ID support added #174
|
||||
- Enable debug mode via config
|
||||
- Custom UID alternative support added
|
||||
- Fetch additional extensions using `Folder::query(["FEATURE_NAME"])`
|
||||
- Optionally move a message during "deletion" instead of just "flagging" it #106 (thanks @EthraZa)
|
||||
- `WhereQuery::where()` accepts now a wide range of criteria / values. #104
|
||||
|
||||
### Affected Classes
|
||||
- [Part::class](src/Part.php)
|
||||
- [Query::class](src/Query/Query.php)
|
||||
- [Client::class](src/Client.php)
|
||||
- [Header::class](src/Header.php)
|
||||
- [Protocol::class](src/Connection/Protocols/Protocol.php)
|
||||
- [ClientManager::class](src/ClientManager.php)
|
||||
|
||||
### Breaking changes
|
||||
- If you are using the legacy protocol to search, the results no longer return false if the search criteria could not be interpreted but instead return an empty array. This will ensure it is compatible to the rest of this library and no longer result in a potential type confusion.
|
||||
- `Folder::idle` will throw an `Webklex\PHPIMAP\Exceptions\NotSupportedCapabilityException` exception if IMAP isn't supported by the mail server
|
||||
- All protocol methods which had a `boolean` `$uid` option no longer support a boolean value. Use `IMAP::ST_UID` or `IMAP::NIL` instead. If you want to use an alternative to `UID` just use the string instead.
|
||||
- Default config option `options.sequence` changed from `IMAP::ST_MSGN` to `IMAP::ST_UID`.
|
||||
- `Folder::query()` no longer accepts a charset string. It has been replaced by an extension array, which provides the ability to automatically fetch additional features.
|
||||
|
||||
|
||||
## [3.1.0-alpha] - 2022-02-03
|
||||
### Fixed
|
||||
- Fix attribute serialization #179 (thanks @netpok)
|
||||
- Use real tls instead of starttls #180 (thanks @netpok)
|
||||
- Allow to fully overwrite default config arrays #194 (thanks @laurent-rizer)
|
||||
- Query::chunked does not loop over the last chunk #196 (thanks @laurent-rizer)
|
||||
- Fix isAttachment that did not properly take in consideration dispositions options #195 (thanks @laurent-rizer)
|
||||
|
||||
### Affected Classes
|
||||
- [Header::class](src/Header.php)
|
||||
- [Protocol::class](src/Connection/Protocols/Protocol.php)
|
||||
- [Query::class](src/Query/Query.php)
|
||||
- [Part::class](src/Part.php)
|
||||
- [ClientManager::class](src/ClientManager.php)
|
||||
|
||||
## [3.0.0-alpha] - 2021-11-04
|
||||
### Fixed
|
||||
- Extend date parsing error message #173
|
||||
- Fixed 'Where' method replaces the content with uppercase #148
|
||||
- Don't surround numeric search values with quotes
|
||||
- Context added to `InvalidWhereQueryCriteriaException`
|
||||
- Redundant `stream_set_timeout()` removed
|
||||
|
||||
### Added
|
||||
- Make boundary regex configurable #169 #150 #126 #121 #111 #152 #108 (thanks @EthraZa)
|
||||
- IMAP ID support added #174
|
||||
- Enable debug mode via config
|
||||
- Custom UID alternative support added
|
||||
- Fetch additional extensions using `Folder::query(["FEATURE_NAME"])`
|
||||
- Optionally move a message during "deletion" instead of just "flagging" it #106 (thanks @EthraZa)
|
||||
- `WhereQuery::where()` accepts now a wide range of criteria / values. #104
|
||||
|
||||
### Affected Classes
|
||||
- [Header::class](src/Header.php)
|
||||
- [Protocol::class](src/Connection/Protocols/Protocol.php)
|
||||
- [Query::class](src/Query/Query.php)
|
||||
- [WhereQuery::class](src/Query/WhereQuery.php)
|
||||
- [Message::class](src/Message.php)
|
||||
|
||||
### Breaking changes
|
||||
- All protocol methods which had a `boolean` `$uid` option no longer support a boolean. Use `IMAP::ST_UID` or `IMAP::NIL` instead. If you want to use an alternative to `UID` just use the string instead.
|
||||
- Default config option `options.sequence` changed from `IMAP::ST_MSGN` to `IMAP::ST_UID`.
|
||||
- `Folder::query()` no longer accepts a charset string. It has been replaced by an extension array, which provides the ability to automatically fetch additional features.
|
||||
|
||||
## [2.7.2] - 2021-09-27
|
||||
### Fixed
|
||||
- Fixed problem with skipping last line of the response. #166 (thanks @szymekjanaczek)
|
||||
|
||||
## [2.7.1] - 2021-09-08
|
||||
### Added
|
||||
- Added `UID` as available search criteria #161 (thanks @szymekjanaczek)
|
||||
|
||||
## [2.7.0] - 2021-09-04
|
||||
### Fixed
|
||||
- Fixes handling of long header lines which are seperated by `\r\n\t` (thanks @Oliver-Holz)
|
||||
- Fixes to line parsing with multiple addresses (thanks @Oliver-Holz)
|
||||
|
||||
### Added
|
||||
- Expose message folder path #154 (thanks @Magiczne)
|
||||
- Adds mailparse_rfc822_parse_addresses integration (thanks @Oliver-Holz)
|
||||
- Added moveManyMessages method (thanks @Magiczne)
|
||||
- Added copyManyMessages method (thanks @Magiczne)
|
||||
|
||||
### Affected Classes
|
||||
- [Header::class](src/Header.php)
|
||||
- [Message::class](src/Message.php)
|
||||
|
||||
## [2.6.0] - 2021-08-20
|
||||
### Fixed
|
||||
- POP3 fixes #151 (thanks @Korko)
|
||||
|
||||
### Added
|
||||
- Added imap 4 handling. #146 (thanks @szymekjanaczek)
|
||||
- Added laravel's conditionable methods. #147 (thanks @szymekjanaczek)
|
||||
|
||||
### Affected Classes
|
||||
- [Query::class](src/Query/Query.php)
|
||||
- [Client::class](src/Client.php)
|
||||
|
||||
## [2.5.1] - 2021-06-19
|
||||
### Fixed
|
||||
- Fix setting default mask from config #133 (thanks @shacky)
|
||||
- Chunked fetch fails in case of less available mails than page size #114
|
||||
- Protocol::createStream() exception information fixed #137
|
||||
- Legacy methods (headers, content, flags) fixed #125
|
||||
- Legacy connection cycle fixed #124 (thanks @zssarkany)
|
||||
|
||||
### Added
|
||||
- Disable rfc822 header parsing via config option #115
|
||||
|
||||
## [2.5.0] - 2021-02-01
|
||||
### Fixed
|
||||
- Attachment saving filename fixed
|
||||
- Unnecessary parameter removed from `Client::getTimeout()`
|
||||
- Missing encryption variable added - could have caused problems with unencrypted communications
|
||||
- Prefer attachment filename attribute over name attribute #82
|
||||
- Missing connection settings added to `Folder:idle()` auto mode #89
|
||||
- Message move / copy expect a folder path #79
|
||||
- `Client::getFolder()` updated to circumvent special edge cases #79
|
||||
- Missing connection status checks added to various methods
|
||||
- Unused default attribute `message_no` removed from `Message::class`
|
||||
|
||||
### Added
|
||||
- Dynamic Attribute access support added (e.g `$message->from[0]`)
|
||||
- Message not found exception added #93
|
||||
- Chunked fetching support added `Query::chunked()`. Just in case you can't fetch all messages at once
|
||||
- "Soft fail" support added
|
||||
- Count method added to `Attribute:class`
|
||||
- Convert an Attribute instance into a Carbon date object #95
|
||||
|
||||
### Affected Classes
|
||||
- [Attachment::class](src/Attachment.php)
|
||||
- [Attribute::class](src/Attribute.php)
|
||||
- [Query::class](src/Query/Query.php)
|
||||
- [Message::class](src/Message.php)
|
||||
- [Client::class](src/Client.php)
|
||||
- [Folder::class](src/Folder.php)
|
||||
|
||||
### Breaking changes
|
||||
- A new exception can occur if a message can't be fetched (`\Webklex\PHPIMAP\Exceptions\MessageNotFoundException::class`)
|
||||
- `Message::move()` and `Message::copy()` no longer accept folder names as folder path
|
||||
- A `Message::class` instance might no longer have a `message_no` attribute
|
||||
|
||||
## [2.4.4] - 2021-01-22
|
||||
### Fixed
|
||||
- Boundary detection simplified #90
|
||||
- Prevent potential body overwriting #90
|
||||
- CSV files are no longer regarded as plain body
|
||||
- Boundary detection overhauled to support "related" and "alternative" multipart messages #90 #91
|
||||
|
||||
### Affected Classes
|
||||
- [Structure::class](src/Structure.php)
|
||||
- [Message::class](src/Message.php)
|
||||
- [Header::class](src/Header.php)
|
||||
- [Part::class](src/Part.php)
|
||||
|
||||
## [2.4.3] - 2021-01-21
|
||||
### Fixed
|
||||
- Attachment detection updated #82 #90
|
||||
- Timeout handling improved
|
||||
- Additional utf-8 checks added to prevent decoding of unencoded values #76
|
||||
|
||||
### Added
|
||||
- Auto reconnect option added to `Folder::idle()` #89
|
||||
|
||||
### Affected Classes
|
||||
- [Folder::class](src/Folder.php)
|
||||
- [Part::class](src/Part.php)
|
||||
- [Client::class](src/Client.php)
|
||||
- [Header::class](src/Header.php)
|
||||
|
||||
## [2.4.2] - 2021-01-09
|
||||
### Fixed
|
||||
- Attachment::save() return error 'A facade root has not been set' #87
|
||||
- Unused dependencies removed
|
||||
- Fix PHP 8 error that changes null back in to an empty string. #88 (thanks @mennovanhout)
|
||||
- Fix regex to be case insensitive #88 (thanks @mennovanhout)
|
||||
|
||||
### Affected Classes
|
||||
- [Attachment::class](src/Attachment.php)
|
||||
- [Address::class](src/Address.php)
|
||||
- [Attribute::class](src/Attribute.php)
|
||||
- [Structure::class](src/Structure.php)
|
||||
|
||||
## [2.4.1] - 2021-01-06
|
||||
### Fixed
|
||||
- Debug line position fixed
|
||||
- Handle incomplete address to string conversion #83
|
||||
- Configured message key gets overwritten by the first fetched message #84
|
||||
|
||||
### Affected Classes
|
||||
- [Address::class](src/Address.php)
|
||||
- [Query::class](src/Query/Query.php)
|
||||
|
||||
## [2.4.0] - 2021-01-03
|
||||
### Fixed
|
||||
- Get partial overview when `IMAP::ST_UID` is set #74
|
||||
- Unnecessary "'" removed from address names
|
||||
- Folder referral typo fixed
|
||||
- Legacy protocol fixed
|
||||
- Treat message collection keys always as strings
|
||||
|
||||
### Added
|
||||
- Configurable supported default flags added
|
||||
- Message attribute class added to unify value handling
|
||||
- Address class added and integrated
|
||||
- Alias `Message::attachments()` for `Message::getAttachments()` added
|
||||
- Alias `Message::addFlag()` for `Message::setFlag()` added
|
||||
- Alias `Message::removeFlag()` for `Message::unsetFlag()` added
|
||||
- Alias `Message::flags()` for `Message::getFlags()` added
|
||||
- New Exception `MessageFlagException::class` added
|
||||
- New method `Message::setSequenceId($id)` added
|
||||
- Optional Header attributizion option added
|
||||
|
||||
### Affected Classes
|
||||
- [Folder::class](src/Folder.php)
|
||||
- [Header::class](src/Header.php)
|
||||
- [Message::class](src/Message.php)
|
||||
- [Address::class](src/Address.php)
|
||||
- [Query::class](src/Query/Query.php)
|
||||
- [Attribute::class](src/Attribute.php)
|
||||
|
||||
### Breaking changes
|
||||
- Stringified message headers are now separated by ", " instead of " ".
|
||||
- All message header values such as subject, message_id, from, to, etc now consists of an `Àttribute::class` instance (should behave the same way as before, but might cause some problem in certain edge cases)
|
||||
- The formal address object "from", "to", etc now consists of an `Address::class` instance (should behave the same way as before, but might cause some problem in certain edge cases)
|
||||
- When fetching or manipulating message flags a `MessageFlagException::class` exception can be thrown if a runtime error occurs
|
||||
- Learn more about the new `Attribute` class here: [www.php-imap.com/api/attribute](https://www.php-imap.com/api/attribute)
|
||||
- Learn more about the new `Address` class here: [www.php-imap.com/api/address](https://www.php-imap.com/api/address)
|
||||
- Folder attribute "referal" is now called "referral"
|
||||
|
||||
## [2.3.1] - 2020-12-30
|
||||
### Fixed
|
||||
- Missing RFC attributes added
|
||||
- Set the message sequence when idling
|
||||
- Missing UID commands added #64
|
||||
|
||||
### Added
|
||||
- Get a message by its message number
|
||||
- Get a message by its uid #72 #66 #63
|
||||
|
||||
### Affected Classes
|
||||
- [Message::class](src/Message.php)
|
||||
- [Folder::class](src/Folder.php)
|
||||
- [Query::class](src/Query/Query.php)
|
||||
|
||||
## [2.3.0] - 2020-12-21
|
||||
### Fixed
|
||||
- Cert validation issue fixed
|
||||
- Allow boundaries ending with a space or semicolon (thanks [@smartilabs](https://github.com/smartilabs))
|
||||
- Ignore IMAP DONE command response #57
|
||||
- Default `options.fetch` set to `IMAP::FT_PEEK`
|
||||
- Address parsing fixed #60
|
||||
- Alternative rfc822 header parsing fixed #60
|
||||
- Parse more than one Received: header #61
|
||||
- Fetch folder overview fixed
|
||||
- `Message::getTextBody()` fallback value fixed
|
||||
|
||||
### Added
|
||||
- Proxy support added
|
||||
- Flexible disposition support added #58
|
||||
- New `options.message_key` option `uid` added
|
||||
- Protocol UID support added
|
||||
- Flexible sequence type support added
|
||||
|
||||
### Affected Classes
|
||||
- [Structure::class](src/Structure.php)
|
||||
- [Query::class](src/Query/Query.php)
|
||||
- [Client::class](src/Client.php)
|
||||
- [Header::class](src/Header.php)
|
||||
- [Folder::class](src/Folder.php)
|
||||
- [Part::class](src/Part.php)
|
||||
|
||||
### Breaking changes
|
||||
- Depending on your configuration, your certificates actually get checked. Which can cause an aborted connection if the certificate can not be validated.
|
||||
- Messages don't get flagged as read unless you are using your own custom config.
|
||||
- All `Header::class` attribute keys are now in a snake_format and no longer minus-separated.
|
||||
- `Message::getTextBody()` no longer returns false if no text body is present. `null` is returned instead.
|
||||
|
||||
## [2.2.5] - 2020-12-11
|
||||
### Fixed
|
||||
- Missing array decoder method added #51 (thanks [@lutchin](https://github.com/lutchin))
|
||||
- Additional checks added to prevent message from getting marked as seen #33
|
||||
- Boundary parsing improved #39 #36 (thanks [@AntonioDiPassio-AppSys](https://github.com/AntonioDiPassio-AppSys))
|
||||
- Idle operation updated #44
|
||||
|
||||
### Added
|
||||
- Force a folder to be opened
|
||||
|
||||
### Affected Classes
|
||||
- [Header::class](src/Header.php)
|
||||
- [Folder::class](src/Folder.php)
|
||||
- [Query::class](src/Query/Query.php)
|
||||
- [Message::class](src/Message.php)
|
||||
- [Structure::class](src/Structure.php)
|
||||
|
||||
## [2.2.4] - 2020-12-08
|
||||
### Fixed
|
||||
- Search performance increased by fetching all headers, bodies and flags at once #42
|
||||
- Legacy protocol support updated
|
||||
- Fix Query pagination. (#52 [@mikemiller891](https://github.com/mikemiller891))
|
||||
|
||||
### Added
|
||||
- Missing message setter methods added
|
||||
- `Folder::overview()` method added to fetch all headers of all messages in the current folder
|
||||
|
||||
### Affected Classes
|
||||
- [Message::class](src/Message.php)
|
||||
- [Folder::class](src/Folder.php)
|
||||
- [Query::class](src/Query/Query.php)
|
||||
- [PaginatedCollection::class](src/Support/PaginatedCollection.php)
|
||||
|
||||
## [2.2.3] - 2020-11-02
|
||||
### Fixed
|
||||
- Text/Html body fetched as attachment if subtype is null #34
|
||||
- Potential header overwriting through header extensions #35
|
||||
- Prevent empty attachments #37
|
||||
|
||||
### Added
|
||||
- Set fetch order during query #41 [@Max13](https://github.com/Max13)
|
||||
|
||||
### Affected Classes
|
||||
- [Message::class](src/Message.php)
|
||||
- [Part::class](src/Part.php)
|
||||
- [Header::class](src/Header.php)
|
||||
- [Query::class](src/Query/Query.php)
|
||||
|
||||
|
||||
## [2.2.2] - 2020-10-20
|
||||
### Fixed
|
||||
- IMAP::FT_PEEK removing "Seen" flag issue fixed #33
|
||||
|
||||
### Affected Classes
|
||||
- [Message::class](src/Message.php)
|
||||
|
||||
## [2.2.1] - 2020-10-19
|
||||
### Fixed
|
||||
- Header decoding problem fixed #31
|
||||
|
||||
### Added
|
||||
- Search for messages by message-Id
|
||||
- Search for messages by In-Reply-To
|
||||
- Message threading added `Message::thread()`
|
||||
- Default folder locations added
|
||||
|
||||
### Affected Classes
|
||||
- [Query::class](src/Query/Query.php)
|
||||
- [Message::class](src/Message.php)
|
||||
- [Header::class](src/Header.php)
|
||||
|
||||
|
||||
## [2.2.0] - 2020-10-16
|
||||
### Fixed
|
||||
- Prevent text bodies from being fetched as attachment #27
|
||||
- Missing variable check added to prevent exception while parsing an address [webklex/laravel-imap #356](https://github.com/Webklex/laravel-imap/issues/356)
|
||||
- Missing variable check added to prevent exception while parsing a part subtype #27
|
||||
- Missing variable check added to prevent exception while parsing a part content-type [webklex/laravel-imap #356](https://github.com/Webklex/laravel-imap/issues/356)
|
||||
- Mixed message header attribute `in_reply_to` "unified" to be always an array #26
|
||||
- Potential message moving / copying problem fixed #29
|
||||
- Move messages by using `Protocol::moveMessage()` instead of `Protocol::copyMessage()` and `Message::delete()` #29
|
||||
|
||||
### Added
|
||||
- `Protocol::moveMessage()` method added #29
|
||||
|
||||
### Affected Classes
|
||||
- [Message::class](src/Message.php)
|
||||
- [Header::class](src/Header.php)
|
||||
- [Part::class](src/Part.php)
|
||||
|
||||
### Breaking changes
|
||||
- Text bodies might no longer get fetched as attachment
|
||||
- `Message::$in_reply_to` type changed from mixed to array
|
||||
|
||||
## [2.1.13] - 2020-10-13
|
||||
### Fixed
|
||||
- Boundary detection problem fixed (#28 [@DasTobbel](https://github.com/DasTobbel))
|
||||
- Content-Type detection problem fixed (#28 [@DasTobbel](https://github.com/DasTobbel))
|
||||
|
||||
### Affected Classes
|
||||
- [Structure::class](src/Structure.php)
|
||||
|
||||
## [2.1.12] - 2020-10-13
|
||||
### Fixed
|
||||
- If content disposition is multiline, implode the array to a simple string (#25 [@DasTobbel](https://github.com/DasTobbel))
|
||||
|
||||
### Affected Classes
|
||||
- [Part::class](src/Part.php)
|
||||
|
||||
## [2.1.11] - 2020-10-13
|
||||
### Fixed
|
||||
- Potential problematic prefixed white-spaces removed from header attributes
|
||||
|
||||
### Added
|
||||
- Expended `Client::getFolder($name, $deleimiter = null)` to accept either a folder name or path ([@DasTobbel](https://github.com/DasTobbel))
|
||||
- Special MS-Exchange header decoding support added
|
||||
|
||||
### Affected Classes
|
||||
- [Client::class](src/Client.php)
|
||||
- [Header::class](src/Header.php)
|
||||
|
||||
## [2.1.10] - 2020-10-09
|
||||
### Added
|
||||
- `ClientManager::make()` method added to support undefined accounts
|
||||
|
||||
### Affected Classes
|
||||
- [ClientManager::class](src/ClientManager.php)
|
||||
|
||||
## [2.1.9] - 2020-10-08
|
||||
### Fixed
|
||||
- Fix inline attachments and embedded images (#22 [@dwalczyk](https://github.com/dwalczyk))
|
||||
|
||||
### Added
|
||||
- Alternative attachment names support added (#20 [@oneFoldSoftware](https://github.com/oneFoldSoftware))
|
||||
- Fetch message content without leaving a "Seen" flag behind
|
||||
|
||||
### Affected Classes
|
||||
- [Attachment::class](src/Attachment.php)
|
||||
- [Message::class](src/Message.php)
|
||||
- [Part::class](src/Part.php)
|
||||
- [Query::class](src/Query/Query.php)
|
||||
|
||||
## [2.1.8] - 2020-10-08
|
||||
### Fixed
|
||||
- Possible error during address decoding fixed (#16 [@Slauta](https://github.com/Slauta))
|
||||
- Flag event dispatching fixed #15
|
||||
|
||||
### Added
|
||||
- Support multiple boundaries (#17, #19 [@dwalczyk](https://github.com/dwalczyk))
|
||||
|
||||
### Affected Classes
|
||||
- [Structure::class](src/Structure.php)
|
||||
|
||||
## [2.1.7] - 2020-10-03
|
||||
### Fixed
|
||||
- Fixed `Query::paginate()` (#13 #14 by [@Max13](https://github.com/Max13))
|
||||
|
||||
### Affected Classes
|
||||
- [Query::class](src/Query/Query.php)
|
||||
|
||||
## [2.1.6] - 2020-10-02
|
||||
### Fixed
|
||||
- `Message::getAttributes()` hasn't returned all parameters
|
||||
|
||||
### Affected Classes
|
||||
- [Message::class](src/Message.php)
|
||||
|
||||
### Added
|
||||
- Part number added to attachment
|
||||
- `Client::getFolderByPath()` added (#12 by [@Max13](https://github.com/Max13))
|
||||
- `Client::getFolderByName()` added (#12 by [@Max13](https://github.com/Max13))
|
||||
- Throws exceptions if the authentication fails (#11 by [@Max13](https://github.com/Max13))
|
||||
|
||||
### Affected Classes
|
||||
- [Client::class](src/Client.php)
|
||||
|
||||
## [2.1.5] - 2020-09-30
|
||||
### Fixed
|
||||
- Wrong message content property reference fixed (#10)
|
||||
|
||||
## [2.1.4] - 2020-09-30
|
||||
### Fixed
|
||||
- Fix header extension values
|
||||
- Part header detection method changed (#10)
|
||||
|
||||
### Affected Classes
|
||||
- [Header::class](src/Header.php)
|
||||
- [Part::class](src/Part.php)
|
||||
|
||||
## [2.1.3] - 2020-09-29
|
||||
### Fixed
|
||||
- Possible decoding problem fixed
|
||||
- `Str::class` dependency removed from `Header::class`
|
||||
|
||||
### Affected Classes
|
||||
- [Header::class](src/Header.php)
|
||||
|
||||
## [2.1.2] - 2020-09-28
|
||||
### Fixed
|
||||
- Dependency problem in `Attachement::getExtension()` fixed (#9)
|
||||
|
||||
### Affected Classes
|
||||
- [Attachment::class](src/Attachment.php)
|
||||
|
||||
## [2.1.1] - 2020-09-23
|
||||
### Fixed
|
||||
- Missing default config parameter added
|
||||
|
||||
### Added
|
||||
- Default account config fallback added
|
||||
|
||||
### Affected Classes
|
||||
- [Client::class](src/Client.php)
|
||||
|
||||
## [2.1.0] - 2020-09-22
|
||||
### Fixed
|
||||
- Quota handling fixed
|
||||
|
||||
### Added
|
||||
- Event system and callbacks added
|
||||
|
||||
### Affected Classes
|
||||
- [Client::class](src/Client.php)
|
||||
- [Folder::class](src/Folder.php)
|
||||
- [Message::class](src/Message.php)
|
||||
|
||||
## [2.0.1] - 2020-09-20
|
||||
### Fixed
|
||||
- Carbon dependency fixed
|
||||
|
||||
## [2.0.0] - 2020-09-20
|
||||
### Fixed
|
||||
- Missing pagination item records fixed
|
||||
|
||||
### Added
|
||||
- php-imap module replaced by direct socket communication
|
||||
- Legacy support added
|
||||
- IDLE support added
|
||||
- oAuth support added
|
||||
- Charset detection method updated
|
||||
- Decoding fallback charsets added
|
||||
|
||||
### Affected Classes
|
||||
- All
|
||||
|
||||
## [1.4.5] - 2019-01-23
|
||||
### Fixed
|
||||
- .csv attachement is not processed
|
||||
- mail part structure property comparison changed to lowercase
|
||||
- Replace helper functions for Laravel 6.0 #4 (@koenhoeijmakers)
|
||||
- Date handling in Folder::appendMessage() fixed
|
||||
- Carbon Exception Parse Data
|
||||
- Convert sender name from non-utf8 to uf8 (@hwilok)
|
||||
- Convert encoding of personal data struct
|
||||
|
||||
### Added
|
||||
- Path prefix option added to Client::getFolder() method
|
||||
- Attachment size handling added
|
||||
- Find messages by custom search criteria
|
||||
|
||||
### Affected Classes
|
||||
- [Query::class](src/Query/WhereQuery.php)
|
||||
- [Mask::class](src/Support/Masks/Mask.php)
|
||||
- [Attachment::class](src/Attachment.php)
|
||||
- [Client::class](src/Client.php)
|
||||
- [Folder::class](src/Folder.php)
|
||||
- [Message::class](src/Message.php)
|
||||
|
||||
## [1.4.2.1] - 2019-07-03
|
||||
### Fixed
|
||||
- Error in Attachment::__construct #3
|
||||
- Examples added
|
||||
|
||||
## [1.4.2] - 2019-07-02
|
||||
### Fixed
|
||||
- Pagination count total bug #213
|
||||
- Changed internal message move and copy methods #210
|
||||
- Query::since() query returning empty response #215
|
||||
- Carbon Exception Parse Data #45
|
||||
- Reading a blank body (text / html) but only from this sender #203
|
||||
- Problem with Message::moveToFolder() and multiple moves #31
|
||||
- Problem with encoding conversion #203
|
||||
- Message null value attribute problem fixed
|
||||
- Client connection path handling changed to be handled inside the calling method #31
|
||||
- iconv(): error suppressor for //IGNORE added #184
|
||||
- Typo Folder attribute fullName changed to full_name
|
||||
- Query scope error fixed #153
|
||||
- Replace embedded image with URL #151
|
||||
- Fix sender name in non-latin emails sent from Gmail (#155)
|
||||
- Fix broken non-latin characters in body in ASCII (us-ascii) charset #156
|
||||
- Message::getMessageId() returns wrong value #197
|
||||
- Message date validation extended #45 #192
|
||||
- Removed "-i" from "iso-8859-8-i" in Message::parseBody #146
|
||||
|
||||
### Added
|
||||
- Message::getFolder() method
|
||||
- Create a fast count method for queries #216
|
||||
- STARTTLS encryption alias added
|
||||
- Mailbox fetching exception added #201
|
||||
- Message::moveToFolder() fetches new Message::class afterwards #31
|
||||
- Message structure accessor added #182
|
||||
- Shadow Imap const class added #188
|
||||
- Connectable "NOT" queries added
|
||||
- Additional where methods added
|
||||
- Message attribute handling changed
|
||||
- Attachment attribute handling changed
|
||||
- Message flag handling updated
|
||||
- Message::getHTMLBody($callback) extended
|
||||
- Masks added (take look at the examples for more information on masks)
|
||||
- More examples added
|
||||
- Query::paginate() method added
|
||||
- Imap client timeout can be modified and read #186
|
||||
- Decoder config options added #175
|
||||
- Message search criteria "NOT" added #181
|
||||
- Invalid message date exception added
|
||||
- Blade examples
|
||||
|
||||
### Breaking changes
|
||||
- Message::moveToFolder() returns either a Message::class instance or null and not a boolean
|
||||
- Folder::fullName is now Folder::full_name
|
||||
- Attachment::image_src might no longer work as expected - use Attachment::getImageSrc() instead
|
||||
|
||||
### Affected Classes
|
||||
- [Folder::class](src/Folder.php)
|
||||
- [Client::class](src/Client.php)
|
||||
- [Message::class](src/Message.php)
|
||||
- [Attachment::class](src/Attachment.php)
|
||||
- [Query::class](src/Query/Query.php)
|
||||
- [WhereQuery::class](src/Query/WhereQuery.php)
|
||||
|
||||
## 0.0.3 - 2018-12-02
|
||||
### Fixed
|
||||
- Folder delimiter check added #137
|
||||
- Config setting not getting loaded
|
||||
- Date parsing updated
|
||||
|
||||
### Affected Classes
|
||||
- [Folder::class](src/IMAP/Client.php)
|
||||
- [Folder::class](src/IMAP/Message.php)
|
||||
|
||||
## 0.0.1 - 2018-08-13
|
||||
### Added
|
||||
- new php-imap package (fork from [webklex/laravel-imap](https://github.com/Webklex/laravel-imap))
|
||||
46
plugins/vendor/webklex/php-imap/CODE_OF_CONDUCT.md
vendored
Normal file
46
plugins/vendor/webklex/php-imap/CODE_OF_CONDUCT.md
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at github@webklex.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
21
plugins/vendor/webklex/php-imap/LICENSE
vendored
Normal file
21
plugins/vendor/webklex/php-imap/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Webklex
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
21
plugins/vendor/webklex/php-imap/LICENSE.md
vendored
Normal file
21
plugins/vendor/webklex/php-imap/LICENSE.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Malte Goldenbaum <info@webklex.com>
|
||||
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
> of this software and associated documentation files (the "Software"), to deal
|
||||
> in the Software without restriction, including without limitation the rights
|
||||
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
> copies of the Software, and to permit persons to whom the Software is
|
||||
> furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in
|
||||
> all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
> THE SOFTWARE.
|
||||
245
plugins/vendor/webklex/php-imap/README.md
vendored
Executable file
245
plugins/vendor/webklex/php-imap/README.md
vendored
Executable file
@@ -0,0 +1,245 @@
|
||||
|
||||
# IMAP Library for PHP
|
||||
|
||||
[![Latest release on Packagist][ico-release]][link-packagist]
|
||||
[![Latest prerelease on Packagist][ico-prerelease]][link-packagist]
|
||||
[![Software License][ico-license]][link-license]
|
||||
[![Total Downloads][ico-downloads]][link-downloads]
|
||||
[![Hits][ico-hits]][link-hits]
|
||||
[![Discord][ico-discord]][link-discord]
|
||||
[![Snyk][ico-snyk]][link-snyk]
|
||||
|
||||
|
||||
## Description
|
||||
PHP-IMAP is a wrapper for common IMAP communication without the need to have the php-imap module installed / enabled.
|
||||
The protocol is completely integrated and therefore supports IMAP IDLE operation and the "new" oAuth authentication
|
||||
process as well.
|
||||
You can enable the `php-imap` module in order to handle edge cases, improve message decoding quality and is required if
|
||||
you want to use legacy protocols such as pop3.
|
||||
|
||||
Official documentation: [php-imap.com](https://www.php-imap.com/)
|
||||
|
||||
Laravel wrapper: [webklex/laravel-imap](https://github.com/Webklex/laravel-imap)
|
||||
|
||||
Discord: [discord.gg/rd4cN9h6][link-discord]
|
||||
|
||||
## Table of Contents
|
||||
- [Documentations](#documentations)
|
||||
- [Compatibility](#compatibility)
|
||||
- [Basic usage example](#basic-usage-example)
|
||||
- [Sponsors](#sponsors)
|
||||
- [Testing](#testing)
|
||||
- [Known issues](#known-issues)
|
||||
- [Support](#support)
|
||||
- [Features & pull requests](#features--pull-requests)
|
||||
- [Alternatives & Different Flavors](#alternatives--different-flavors)
|
||||
- [Security](#security)
|
||||
- [Credits](#credits)
|
||||
- [License](#license)
|
||||
|
||||
|
||||
## Documentations
|
||||
- Legacy (< v2.0.0): [legacy documentation](https://github.com/Webklex/php-imap/tree/1.4.5)
|
||||
- Core documentation: [php-imap.com](https://www.php-imap.com/)
|
||||
|
||||
|
||||
## Compatibility
|
||||
| Version | PHP 5.6 | PHP 7 | PHP 8 |
|
||||
|:--------|:-------:|:-----:|:-----:|
|
||||
| v6.x | / | / | X |
|
||||
| v5.x | / | / | X |
|
||||
| v4.x | / | X | X |
|
||||
| v3.x | / | X | / |
|
||||
| v2.x | X | X | / |
|
||||
| v1.x | X | / | / |
|
||||
|
||||
## Basic usage example
|
||||
This is a basic example, which will echo out all Mails within all imap folders
|
||||
and will move every message into INBOX.read. Please be aware that this should not be
|
||||
tested in real life and is only meant to give an impression on how things work.
|
||||
|
||||
```php
|
||||
use Webklex\PHPIMAP\ClientManager;
|
||||
|
||||
require_once "vendor/autoload.php";
|
||||
|
||||
$cm = new ClientManager('path/to/config/imap.php');
|
||||
|
||||
/** @var \Webklex\PHPIMAP\Client $client */
|
||||
$client = $cm->account('account_identifier');
|
||||
|
||||
//Connect to the IMAP Server
|
||||
$client->connect();
|
||||
|
||||
//Get all Mailboxes
|
||||
/** @var \Webklex\PHPIMAP\Support\FolderCollection $folders */
|
||||
$folders = $client->getFolders();
|
||||
|
||||
//Loop through every Mailbox
|
||||
/** @var \Webklex\PHPIMAP\Folder $folder */
|
||||
foreach($folders as $folder){
|
||||
|
||||
//Get all Messages of the current Mailbox $folder
|
||||
/** @var \Webklex\PHPIMAP\Support\MessageCollection $messages */
|
||||
$messages = $folder->messages()->all()->get();
|
||||
|
||||
/** @var \Webklex\PHPIMAP\Message $message */
|
||||
foreach($messages as $message){
|
||||
echo $message->getSubject().'<br />';
|
||||
echo 'Attachments: '.$message->getAttachments()->count().'<br />';
|
||||
echo $message->getHTMLBody();
|
||||
|
||||
//Move the current Message to 'INBOX.read'
|
||||
if($message->move('INBOX.read') == true){
|
||||
echo 'Message has been moved';
|
||||
}else{
|
||||
echo 'Message could not be moved';
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Sponsors
|
||||
[![elb-BIT][ico-sponsor-elb-bit]][link-sponsor-elb-bit]
|
||||
[![Feline][ico-sponsor-feline]][link-sponsor-feline]
|
||||
|
||||
|
||||
## Testing
|
||||
To run the tests, please execute the following command:
|
||||
```bash
|
||||
composer test
|
||||
```
|
||||
|
||||
### Quick-Test / Static Test
|
||||
To disable all test which require a live mailbox, please copy the `phpunit.xml.dist` to `phpunit.xml` and adjust the configuration:
|
||||
```xml
|
||||
<php>
|
||||
<env name="LIVE_MAILBOX" value="false"/>
|
||||
</php>
|
||||
```
|
||||
|
||||
### Full-Test / Live Mailbox Test
|
||||
To run all tests, you need to provide a valid imap configuration.
|
||||
|
||||
To provide a valid imap configuration, please copy the `phpunit.xml.dist` to `phpunit.xml` and adjust the configuration:
|
||||
```xml
|
||||
<php>
|
||||
<env name="LIVE_MAILBOX" value="true"/>
|
||||
<env name="LIVE_MAILBOX_DEBUG" value="true"/>
|
||||
<env name="LIVE_MAILBOX_HOST" value="mail.example.local"/>
|
||||
<env name="LIVE_MAILBOX_PORT" value="993"/>
|
||||
<env name="LIVE_MAILBOX_VALIDATE_CERT" value="false"/>
|
||||
<env name="LIVE_MAILBOX_QUOTA_SUPPORT" value="true"/>
|
||||
<env name="LIVE_MAILBOX_ENCRYPTION" value="ssl"/>
|
||||
<env name="LIVE_MAILBOX_USERNAME" value="root@example.local"/>
|
||||
<env name="LIVE_MAILBOX_PASSWORD" value="foobar"/>
|
||||
</php>
|
||||
```
|
||||
|
||||
The test account should **not** contain any important data, as it will be deleted during the test.
|
||||
Furthermore, the test account should be able to create new folders, move messages and should **not** be used by any other
|
||||
application during the test.
|
||||
|
||||
It's recommended to use a dedicated test account for this purpose. You can use the provided `Dockerfile` to create an imap server used for testing purposes.
|
||||
|
||||
Build the docker image:
|
||||
```bash
|
||||
cd .github/docker
|
||||
|
||||
docker build -t php-imap-server .
|
||||
```
|
||||
Run the docker image:
|
||||
```bash
|
||||
docker run --name imap-server -p 993:993 --rm -d php-imap-server
|
||||
```
|
||||
Stop the docker image:
|
||||
```bash
|
||||
docker stop imap-server
|
||||
```
|
||||
|
||||
|
||||
### Known issues
|
||||
| Error | Solution |
|
||||
|:---------------------------------------------------------------------------|:----------------------------------------------------------------------------------------|
|
||||
| Kerberos error: No credentials cache file found (try running kinit) (...) | Uncomment "DISABLE_AUTHENTICATOR" inside your config and use the `legacy-imap` protocol |
|
||||
|
||||
|
||||
## Support
|
||||
If you encounter any problems or if you find a bug, please don't hesitate to create a new [issue](https://github.com/Webklex/php-imap/issues).
|
||||
However, please be aware that it might take some time to get an answer.
|
||||
Off-topic, rude or abusive issues will be deleted without any notice.
|
||||
|
||||
If you need **commercial** support, feel free to send me a mail at github@webklex.com.
|
||||
|
||||
|
||||
##### A little notice
|
||||
If you write source code in your issue, please consider to format it correctly. This makes it so much nicer to read
|
||||
and people are more likely to comment and help :)
|
||||
|
||||
```php
|
||||
|
||||
echo 'your php code...';
|
||||
|
||||
```
|
||||
|
||||
will turn into:
|
||||
```php
|
||||
echo 'your php code...';
|
||||
```
|
||||
|
||||
|
||||
## Features & pull requests
|
||||
Everyone can contribute to this project. Every pull request will be considered, but it can also happen to be declined.
|
||||
To prevent unnecessary work, please consider to create a [feature issue](https://github.com/Webklex/php-imap/issues/new?template=feature_request.md)
|
||||
first, if you're planning to do bigger changes. Of course, you can also create a new [feature issue](https://github.com/Webklex/php-imap/issues/new?template=feature_request.md)
|
||||
if you're just wishing a feature ;)
|
||||
|
||||
|
||||
## Alternatives & Different Flavors
|
||||
This library and especially the code flavor It's written in, is certainly not for everyone. If you are looking for a
|
||||
different approach, you might want to check out the following libraries:
|
||||
- [ddeboer/imap](https://github.com/ddeboer/imap)
|
||||
- [barbushin/php-imap](https://github.com/barbushin/php-imap)
|
||||
- [stevebauman/php-imap](https://github.com/stevebauman/php-imap)
|
||||
|
||||
|
||||
## Change log
|
||||
Please see [CHANGELOG][link-changelog] for more information what has changed recently.
|
||||
|
||||
|
||||
## Security
|
||||
If you discover any security related issues, please email github@webklex.com instead of using the issue tracker.
|
||||
|
||||
|
||||
## Credits
|
||||
- [Webklex][link-author]
|
||||
- [All Contributors][link-contributors]
|
||||
|
||||
|
||||
## License
|
||||
The MIT License (MIT). Please see [License File][link-license] for more information.
|
||||
|
||||
|
||||
[ico-release]: https://img.shields.io/packagist/v/Webklex/php-imap.svg?style=flat-square&label=version
|
||||
[ico-prerelease]: https://img.shields.io/github/v/release/webklex/php-imap?include_prereleases&style=flat-square&label=pre-release
|
||||
[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
|
||||
[ico-downloads]: https://img.shields.io/packagist/dt/Webklex/php-imap.svg?style=flat-square
|
||||
[ico-hits]: https://hits.webklex.com/svg/webklex/php-imap
|
||||
[ico-snyk]: https://snyk-widget.herokuapp.com/badge/composer/webklex/php-imap/badge.svg
|
||||
[ico-discord]: https://img.shields.io/static/v1?label=discord&message=open&color=5865f2&style=flat-square
|
||||
|
||||
[link-packagist]: https://packagist.org/packages/Webklex/php-imap
|
||||
[link-downloads]: https://packagist.org/packages/Webklex/php-imap
|
||||
[link-author]: https://github.com/webklex
|
||||
[link-contributors]: https://github.com/Webklex/php-imap/graphs/contributors
|
||||
[link-license]: https://github.com/Webklex/php-imap/blob/master/LICENSE
|
||||
[link-changelog]: https://github.com/Webklex/php-imap/blob/master/CHANGELOG.md
|
||||
[link-hits]: https://hits.webklex.com
|
||||
[link-snyk]: https://snyk.io/vuln/composer:webklex%2Fphp-imap
|
||||
[link-discord]: https://discord.gg/vUHrbfbDr9
|
||||
|
||||
|
||||
[ico-sponsor-feline]: https://cdn.feline.dk/public/feline.png
|
||||
[link-sponsor-feline]: https://www.feline.dk
|
||||
[ico-sponsor-elb-bit]: https://www.elb-bit.de/user/themes/deliver/images/logo_small.png
|
||||
[link-sponsor-elb-bit]: https://www.elb-bit.de?ref=webklex/php-imap
|
||||
1
plugins/vendor/webklex/php-imap/_config.yml
vendored
Normal file
1
plugins/vendor/webklex/php-imap/_config.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
theme: jekyll-theme-cayman
|
||||
61
plugins/vendor/webklex/php-imap/composer.json
vendored
Normal file
61
plugins/vendor/webklex/php-imap/composer.json
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"name": "webklex/php-imap",
|
||||
"type": "library",
|
||||
"description": "PHP IMAP client",
|
||||
"keywords": [
|
||||
"webklex",
|
||||
"imap",
|
||||
"pop3",
|
||||
"php-imap",
|
||||
"mail"
|
||||
],
|
||||
"homepage": "https://github.com/webklex/php-imap",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Malte Goldenbaum",
|
||||
"email": "github@webklex.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.0.2",
|
||||
"ext-openssl": "*",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-zip": "*",
|
||||
"ext-fileinfo": "*",
|
||||
"nesbot/carbon": "^2.62.1|^3.2.4",
|
||||
"symfony/http-foundation": ">=2.8.0",
|
||||
"illuminate/pagination": ">=5.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5.10"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/mime": "Recomended for better extension support",
|
||||
"symfony/var-dumper": "Usefull tool for debugging"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Webklex\\PHPIMAP\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Tests\\": "tests"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phpunit"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "6.0-dev"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
||||
57
plugins/vendor/webklex/php-imap/examples/custom_attachment_mask.php
vendored
Normal file
57
plugins/vendor/webklex/php-imap/examples/custom_attachment_mask.php
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/*
|
||||
* File: custom_message_mask.php
|
||||
* Category: Example
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 14.03.19 18:47
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
class CustomAttachmentMask extends \Webklex\PHPIMAP\Support\Masks\AttachmentMask {
|
||||
|
||||
/**
|
||||
* New custom method which can be called through a mask
|
||||
* @return string
|
||||
*/
|
||||
public function token(): string {
|
||||
return implode('-', [$this->id, $this->getMessage()->getUid(), $this->name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom attachment saving method
|
||||
* @return bool
|
||||
*/
|
||||
public function custom_save(): bool {
|
||||
$path = "foo".DIRECTORY_SEPARATOR."bar".DIRECTORY_SEPARATOR;
|
||||
$filename = $this->token();
|
||||
|
||||
return file_put_contents($path.$filename, $this->getContent()) !== false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$cm = new \Webklex\PHPIMAP\ClientManager('path/to/config/imap.php');
|
||||
|
||||
/** @var \Webklex\PHPIMAP\Client $client */
|
||||
$client = $cm->account('default');
|
||||
$client->connect();
|
||||
$client->setDefaultAttachmentMask(CustomAttachmentMask::class);
|
||||
|
||||
/** @var \Webklex\PHPIMAP\Folder $folder */
|
||||
$folder = $client->getFolder('INBOX');
|
||||
|
||||
/** @var \Webklex\PHPIMAP\Message $message */
|
||||
$message = $folder->query()->limit(1)->get()->first();
|
||||
|
||||
/** @var \Webklex\PHPIMAP\Attachment $attachment */
|
||||
$attachment = $message->getAttachments()->first();
|
||||
|
||||
/** @var CustomAttachmentMask $masked_attachment */
|
||||
$masked_attachment = $attachment->mask();
|
||||
|
||||
echo 'Token for uid ['.$masked_attachment->getMessage()->getUid().']: '.$masked_attachment->token();
|
||||
|
||||
$masked_attachment->custom_save();
|
||||
51
plugins/vendor/webklex/php-imap/examples/custom_message_mask.php
vendored
Normal file
51
plugins/vendor/webklex/php-imap/examples/custom_message_mask.php
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/*
|
||||
* File: custom_message_mask.php
|
||||
* Category: Example
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 14.03.19 18:47
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
class CustomMessageMask extends \Webklex\PHPIMAP\Support\Masks\MessageMask {
|
||||
|
||||
/**
|
||||
* New custom method which can be called through a mask
|
||||
* @return string
|
||||
*/
|
||||
public function token(): string {
|
||||
return implode('-', [$this->message_id, $this->uid, $this->message_no]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of message attachments
|
||||
* @return integer
|
||||
*/
|
||||
public function getAttachmentCount(): int {
|
||||
return $this->getAttachments()->count();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$cm = new \Webklex\PHPIMAP\ClientManager('path/to/config/imap.php');
|
||||
|
||||
/** @var \Webklex\PHPIMAP\Client $client */
|
||||
$client = $cm->account('default');
|
||||
$client->connect();
|
||||
|
||||
/** @var \Webklex\PHPIMAP\Folder $folder */
|
||||
$folder = $client->getFolder('INBOX');
|
||||
|
||||
/** @var \Webklex\PHPIMAP\Message $message */
|
||||
$message = $folder->query()->limit(1)->get()->first();
|
||||
|
||||
/** @var CustomMessageMask $masked_message */
|
||||
$masked_message = $message->mask(CustomMessageMask::class);
|
||||
|
||||
echo 'Token for uid [' . $masked_message->uid . ']: ' . $masked_message->token() . ' @atms:' . $masked_message->getAttachmentCount();
|
||||
|
||||
$masked_message->setFlag('seen');
|
||||
|
||||
42
plugins/vendor/webklex/php-imap/examples/folder_structure.blade.php
vendored
Normal file
42
plugins/vendor/webklex/php-imap/examples/folder_structure.blade.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/*
|
||||
* File: folder_structure.blade.php
|
||||
* Category: View
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 15.09.18 19:53
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
/**
|
||||
* @var \Webklex\PHPIMAP\Support\FolderCollection $paginator
|
||||
* @var \Webklex\PHPIMAP\Folder $folder
|
||||
*/
|
||||
|
||||
?>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Folder</th>
|
||||
<th>Unread messages</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if($paginator->count() > 0): ?>
|
||||
<?php foreach($paginator as $folder): ?>
|
||||
<tr>
|
||||
<td><?php echo $folder->name; ?></td>
|
||||
<td><?php echo $folder->search()->unseen()->setFetchBody(false)->count(); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<tr>
|
||||
<td colspan="4">No folders found</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php echo $paginator->links(); ?>
|
||||
46
plugins/vendor/webklex/php-imap/examples/message_table.blade.php
vendored
Normal file
46
plugins/vendor/webklex/php-imap/examples/message_table.blade.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/*
|
||||
* File: message_table.blade.php
|
||||
* Category: View
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 15.09.18 19:53
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
/**
|
||||
* @var \Webklex\PHPIMAP\Support\FolderCollection $paginator
|
||||
* @var \Webklex\PHPIMAP\Message $message
|
||||
*/
|
||||
|
||||
?>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>UID</th>
|
||||
<th>Subject</th>
|
||||
<th>From</th>
|
||||
<th>Attachments</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if($paginator->count() > 0): ?>
|
||||
<?php foreach($paginator as $message): ?>
|
||||
<tr>
|
||||
<td><?php echo $message->getUid(); ?></td>
|
||||
<td><?php echo $message->getSubject(); ?></td>
|
||||
<td><?php echo $message->getFrom()[0]->mail; ?></td>
|
||||
<td><?php echo $message->getAttachments()->count() > 0 ? 'yes' : 'no'; ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<tr>
|
||||
<td colspan="4">No messages found</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php echo $paginator->links(); ?>
|
||||
35
plugins/vendor/webklex/php-imap/phpunit.xml.dist
vendored
Normal file
35
plugins/vendor/webklex/php-imap/phpunit.xml.dist
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" backupGlobals="false" backupStaticAttributes="false" colors="true" verbose="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
|
||||
<coverage>
|
||||
<include>
|
||||
<directory suffix=".php">src/</directory>
|
||||
</include>
|
||||
<report>
|
||||
<clover outputFile="build/logs/clover.xml"/>
|
||||
<html outputDirectory="build/coverage"/>
|
||||
<text outputFile="build/coverage.txt"/>
|
||||
</report>
|
||||
</coverage>
|
||||
<testsuites>
|
||||
<testsuite name="PHP-IMAP Test Suite">
|
||||
<directory>tests</directory>
|
||||
<directory>tests/fixtures</directory>
|
||||
<directory>tests/issues</directory>
|
||||
<directory>tests/live</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<logging>
|
||||
<junit outputFile="build/report.junit.xml"/>
|
||||
</logging>
|
||||
<php>
|
||||
<env name="LIVE_MAILBOX" value="false"/>
|
||||
<env name="LIVE_MAILBOX_DEBUG" value="false"/>
|
||||
<env name="LIVE_MAILBOX_HOST" value="mail.example.local"/>
|
||||
<env name="LIVE_MAILBOX_PORT" value="993"/>
|
||||
<env name="LIVE_MAILBOX_VALIDATE_CERT" value="false"/>
|
||||
<env name="LIVE_MAILBOX_QUOTA_SUPPORT" value="false"/>
|
||||
<env name="LIVE_MAILBOX_ENCRYPTION" value=""/>
|
||||
<env name="LIVE_MAILBOX_USERNAME" value="root@example.local"/>
|
||||
<env name="LIVE_MAILBOX_PASSWORD" value="foobar"/>
|
||||
</php>
|
||||
</phpunit>
|
||||
108
plugins/vendor/webklex/php-imap/src/Address.php
vendored
Normal file
108
plugins/vendor/webklex/php-imap/src/Address.php
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
/*
|
||||
* File: Address.php
|
||||
* Category: -
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 01.01.21 21:17
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP;
|
||||
|
||||
/**
|
||||
* Class Address
|
||||
*
|
||||
* @package Webklex\PHPIMAP
|
||||
*/
|
||||
class Address {
|
||||
|
||||
/**
|
||||
* Address attributes
|
||||
* @var string $personal
|
||||
* @var string $mailbox
|
||||
* @var string $host
|
||||
* @var string $mail
|
||||
* @var string $full
|
||||
*/
|
||||
public string $personal = "";
|
||||
public string $mailbox = "";
|
||||
public string $host = "";
|
||||
public string $mail = "";
|
||||
public string $full = "";
|
||||
|
||||
/**
|
||||
* Address constructor.
|
||||
* @param object $object
|
||||
*/
|
||||
public function __construct(object $object) {
|
||||
if (property_exists($object, "personal")){ $this->personal = $object->personal ?? ''; }
|
||||
if (property_exists($object, "mailbox")){ $this->mailbox = $object->mailbox ?? ''; }
|
||||
if (property_exists($object, "host")){ $this->host = $object->host ?? ''; }
|
||||
if (property_exists($object, "mail")){ $this->mail = $object->mail ?? ''; }
|
||||
if (property_exists($object, "full")){ $this->full = $object->full ?? ''; }
|
||||
$this->boot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Boot the address
|
||||
*/
|
||||
private function boot(): void {
|
||||
if($this->mail === "" && $this->mailbox !== "" && $this->host !== ""){
|
||||
$this->mail = $this->mailbox . "@" . $this->host;
|
||||
}elseif($this->mail === "" && $this->mailbox !== ""){
|
||||
$this->mail = $this->mailbox;
|
||||
}
|
||||
|
||||
if($this->full === "" && $this->mail !== "" && $this->personal !== ""){
|
||||
$this->full = $this->personal . " <" . $this->mail . ">";
|
||||
}elseif($this->full === "" && $this->mail !== ""){
|
||||
$this->full = $this->mail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the stringified address
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString() {
|
||||
return $this->full ?: "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the serialized address
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function __serialize(){
|
||||
return [
|
||||
"personal" => $this->personal,
|
||||
"mailbox" => $this->mailbox,
|
||||
"host" => $this->host,
|
||||
"mail" => $this->mail,
|
||||
"full" => $this->full,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert instance to array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array {
|
||||
return $this->__serialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the stringified attribute
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toString(): string {
|
||||
return $this->__toString();
|
||||
}
|
||||
}
|
||||
515
plugins/vendor/webklex/php-imap/src/Attachment.php
vendored
Executable file
515
plugins/vendor/webklex/php-imap/src/Attachment.php
vendored
Executable file
@@ -0,0 +1,515 @@
|
||||
<?php
|
||||
/*
|
||||
* File: Attachment.php
|
||||
* Category: -
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 16.03.18 19:37
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Webklex\PHPIMAP\Decoder\DecoderInterface;
|
||||
use Webklex\PHPIMAP\Exceptions\DecoderNotFoundException;
|
||||
use Webklex\PHPIMAP\Exceptions\MaskNotFoundException;
|
||||
use Webklex\PHPIMAP\Exceptions\MethodNotFoundException;
|
||||
use Webklex\PHPIMAP\Support\Masks\AttachmentMask;
|
||||
|
||||
/**
|
||||
* Class Attachment
|
||||
*
|
||||
* @package Webklex\PHPIMAP
|
||||
*
|
||||
* @property integer $part_number
|
||||
* @property integer $size
|
||||
* @property string $content
|
||||
* @property string $type
|
||||
* @property string $content_type
|
||||
* @property string $id
|
||||
* @property string $hash
|
||||
* @property string $name
|
||||
* @property string $description
|
||||
* @property string $filename
|
||||
* @property ?string $disposition
|
||||
* @property string $img_src
|
||||
*
|
||||
* @method integer getPartNumber()
|
||||
* @method integer setPartNumber(integer $part_number)
|
||||
* @method string getContent()
|
||||
* @method string setContent(string $content)
|
||||
* @method string getType()
|
||||
* @method string setType(string $type)
|
||||
* @method string getContentType()
|
||||
* @method string setContentType(string $content_type)
|
||||
* @method string getId()
|
||||
* @method string setId(string $id)
|
||||
* @method string getHash()
|
||||
* @method string setHash(string $hash)
|
||||
* @method string getSize()
|
||||
* @method string setSize(integer $size)
|
||||
* @method string getName()
|
||||
* @method string getDisposition()
|
||||
* @method string setDisposition(string $disposition)
|
||||
* @method string setImgSrc(string $img_src)
|
||||
*/
|
||||
class Attachment {
|
||||
|
||||
/**
|
||||
* @var Message $message
|
||||
*/
|
||||
protected Message $message;
|
||||
|
||||
/**
|
||||
* Used config
|
||||
*
|
||||
* @var Config $config
|
||||
*/
|
||||
protected Config $config;
|
||||
|
||||
/**
|
||||
* Attachment options
|
||||
*
|
||||
* @var array $options
|
||||
*/
|
||||
protected array $options = [];
|
||||
|
||||
/** @var Part $part */
|
||||
protected Part $part;
|
||||
|
||||
/**
|
||||
* Decoder instance
|
||||
*
|
||||
* @var DecoderInterface $decoder
|
||||
*/
|
||||
protected DecoderInterface $decoder;
|
||||
|
||||
/**
|
||||
* Attribute holder
|
||||
*
|
||||
* @var array $attributes
|
||||
*/
|
||||
protected array $attributes = [
|
||||
'content' => null,
|
||||
'hash' => null,
|
||||
'type' => null,
|
||||
'part_number' => 0,
|
||||
'content_type' => null,
|
||||
'id' => null,
|
||||
'name' => null,
|
||||
'filename' => null,
|
||||
'description' => null,
|
||||
'disposition' => null,
|
||||
'img_src' => null,
|
||||
'size' => null,
|
||||
];
|
||||
|
||||
/**
|
||||
* Default mask
|
||||
*
|
||||
* @var string $mask
|
||||
*/
|
||||
protected string $mask = AttachmentMask::class;
|
||||
|
||||
/**
|
||||
* Attachment constructor.
|
||||
* @param Message $message
|
||||
* @param Part $part
|
||||
* @throws DecoderNotFoundException
|
||||
*/
|
||||
public function __construct(Message $message, Part $part) {
|
||||
$this->message = $message;
|
||||
$this->config = $this->message->getConfig();
|
||||
$this->options = $this->config->get('options');
|
||||
$this->decoder = $this->config->getDecoder("attachment");
|
||||
|
||||
$this->part = $part;
|
||||
$this->part_number = $part->part_number;
|
||||
|
||||
if ($this->message->getClient()) {
|
||||
$default_mask = $this->message->getClient()?->getDefaultAttachmentMask();
|
||||
if ($default_mask != null) {
|
||||
$this->mask = $default_mask;
|
||||
}
|
||||
} else {
|
||||
$default_mask = $this->config->getMask("attachment");
|
||||
if ($default_mask != "") {
|
||||
$this->mask = $default_mask;
|
||||
}
|
||||
}
|
||||
|
||||
$this->findType();
|
||||
$this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call dynamic attribute setter and getter methods
|
||||
* @param string $method
|
||||
* @param array $arguments
|
||||
*
|
||||
* @return mixed
|
||||
* @throws MethodNotFoundException
|
||||
*/
|
||||
public function __call(string $method, array $arguments) {
|
||||
if (strtolower(substr($method, 0, 3)) === 'get') {
|
||||
$name = Str::snake(substr($method, 3));
|
||||
|
||||
if (isset($this->attributes[$name])) {
|
||||
return $this->attributes[$name];
|
||||
}
|
||||
|
||||
return null;
|
||||
} elseif (strtolower(substr($method, 0, 3)) === 'set') {
|
||||
$name = Str::snake(substr($method, 3));
|
||||
|
||||
$this->attributes[$name] = array_pop($arguments);
|
||||
|
||||
return $this->attributes[$name];
|
||||
}
|
||||
|
||||
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 mixed|null
|
||||
*/
|
||||
public function __get($name) {
|
||||
if (isset($this->attributes[$name])) {
|
||||
return $this->attributes[$name];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the structure type
|
||||
*/
|
||||
protected function findType(): void {
|
||||
$this->type = match ($this->part->type) {
|
||||
IMAP::ATTACHMENT_TYPE_MESSAGE => 'message',
|
||||
IMAP::ATTACHMENT_TYPE_APPLICATION => 'application',
|
||||
IMAP::ATTACHMENT_TYPE_AUDIO => 'audio',
|
||||
IMAP::ATTACHMENT_TYPE_IMAGE => 'image',
|
||||
IMAP::ATTACHMENT_TYPE_VIDEO => 'video',
|
||||
IMAP::ATTACHMENT_TYPE_MODEL => 'model',
|
||||
IMAP::ATTACHMENT_TYPE_TEXT => 'text',
|
||||
IMAP::ATTACHMENT_TYPE_MULTIPART => 'multipart',
|
||||
default => 'other',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the given attachment
|
||||
*/
|
||||
protected function fetch(): void {
|
||||
$content = $this->part->content;
|
||||
|
||||
$this->content_type = $this->part->content_type;
|
||||
$this->content = $this->decoder->decode($content, $this->part->encoding);
|
||||
|
||||
// Create a hash of the raw part - this can be used to identify the attachment in the message context. However,
|
||||
// it is not guaranteed to be unique and collisions are possible.
|
||||
// Some additional online resources:
|
||||
// - https://en.wikipedia.org/wiki/Hash_collision
|
||||
// - https://www.php.net/manual/en/function.hash.php
|
||||
// - https://php.watch/articles/php-hash-benchmark
|
||||
// Benchmark speeds:
|
||||
// -xxh3 ~15.19(GB/s) (requires php-xxhash extension or >= php8.1)
|
||||
// -crc32c ~14.12(GB/s)
|
||||
// -sha256 ~0.25(GB/s)
|
||||
// xxh3 would be nice to use, because of its extra speed and 32 instead of 8 bytes, but it is not compatible with
|
||||
// php < 8.1. crc32c is the next fastest and is compatible with php >= 5.1. sha256 is the slowest, but is compatible
|
||||
// with php >= 5.1 and is the most likely to be unique. crc32c is the best compromise between speed and uniqueness.
|
||||
// Unique enough for our purposes, but not so slow that it could be a bottleneck.
|
||||
$this->hash = hash("crc32c", $this->part->getHeader()->raw."\r\n\r\n".$this->part->content);
|
||||
|
||||
if (($id = $this->part->id) !== null) {
|
||||
$this->id = str_replace(['<', '>'], '', $id);
|
||||
}else {
|
||||
$this->id = $this->hash;
|
||||
}
|
||||
|
||||
$this->size = $this->part->bytes;
|
||||
$this->disposition = $this->part->disposition;
|
||||
|
||||
if (($filename = $this->part->filename) !== null) {
|
||||
$this->filename = $this->decodeName($filename);
|
||||
}
|
||||
|
||||
if (($description = $this->part->description) !== null) {
|
||||
$this->description = $this->part->getHeader()->getDecoder()->decode($description);
|
||||
}
|
||||
|
||||
if (($name = $this->part->name) !== null) {
|
||||
$this->name = $this->decodeName($name);
|
||||
}
|
||||
|
||||
if (IMAP::ATTACHMENT_TYPE_MESSAGE == $this->part->type) {
|
||||
if ($this->part->ifdescription) {
|
||||
if (!$this->name) {
|
||||
$this->name = $this->part->description;
|
||||
}
|
||||
} else if (!$this->name) {
|
||||
$this->name = $this->part->subtype;
|
||||
}
|
||||
}
|
||||
$this->attributes = array_merge($this->part->getHeader()->getAttributes(), $this->attributes);
|
||||
|
||||
if (!$this->filename) {
|
||||
$this->filename = $this->hash;
|
||||
}
|
||||
|
||||
if (!$this->name && $this->filename != "") {
|
||||
$this->name = $this->filename;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the attachment content to your filesystem
|
||||
* @param string $path
|
||||
* @param string|null $filename
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function save(string $path, ?string $filename = null): bool {
|
||||
$filename = $filename ? $this->decodeName($filename) : $this->filename;
|
||||
|
||||
return file_put_contents($path . DIRECTORY_SEPARATOR . $filename, $this->getContent()) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a given name
|
||||
* @param string|null $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function decodeName(?string $name): string {
|
||||
if ($name !== null) {
|
||||
if (str_contains($name, "''")) {
|
||||
$parts = explode("''", $name);
|
||||
if (EncodingAliases::has($parts[0])) {
|
||||
$encoding = $parts[0];
|
||||
$name = implode("''", array_slice($parts, 1));
|
||||
}
|
||||
}
|
||||
|
||||
$decoder = $this->decoder->getOptions()['message'];
|
||||
if (preg_match('/=\?([^?]+)\?(Q|B)\?(.+)\?=/i', $name, $matches)) {
|
||||
$name = $this->part->getHeader()->getDecoder()->decode($name);
|
||||
} elseif ($decoder === 'utf-8' && extension_loaded('imap')) {
|
||||
$name = \imap_utf8($name);
|
||||
}
|
||||
|
||||
// check if $name is url encoded
|
||||
if (preg_match('/%[0-9A-F]{2}/i', $name)) {
|
||||
$name = urldecode($name);
|
||||
}
|
||||
|
||||
if (isset($encoding)) {
|
||||
$name = EncodingAliases::convert($name, $encoding);
|
||||
}
|
||||
|
||||
if($this->config->get('security.sanitize_filenames', true)) {
|
||||
$name = $this->sanitizeName($name);
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attachment mime type
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getMimeType(): ?string {
|
||||
return (new \finfo())->buffer($this->getContent(), FILEINFO_MIME_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to guess the attachment file extension
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getExtension(): ?string {
|
||||
$extension = null;
|
||||
$guesser = "\Symfony\Component\Mime\MimeTypes";
|
||||
if (class_exists($guesser) !== false) {
|
||||
/** @var Symfony\Component\Mime\MimeTypes $guesser */
|
||||
$extensions = $guesser::getDefault()->getExtensions($this->getMimeType());
|
||||
$extension = $extensions[0] ?? null;
|
||||
}
|
||||
if ($extension === null) {
|
||||
$deprecated_guesser = "\Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser";
|
||||
if (class_exists($deprecated_guesser) !== false) {
|
||||
/** @var \Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser $deprecated_guesser */
|
||||
$extension = $deprecated_guesser::getInstance()->guess($this->getMimeType());
|
||||
}
|
||||
}
|
||||
if ($extension === null) {
|
||||
$parts = explode(".", $this->filename);
|
||||
$extension = count($parts) > 1 ? end($parts) : null;
|
||||
}
|
||||
if ($extension === null) {
|
||||
$parts = explode(".", $this->name);
|
||||
$extension = count($parts) > 1 ? end($parts) : null;
|
||||
}
|
||||
return $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all attributes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAttributes(): array {
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Message
|
||||
*/
|
||||
public function getMessage(): Message {
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default mask
|
||||
* @param $mask
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setMask($mask): Attachment {
|
||||
if (class_exists($mask)) {
|
||||
$this->mask = $mask;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the used default mask
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMask(): string {
|
||||
return $this->mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attachment options
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions(): array {
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the attachment options
|
||||
* @param array $options
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setOptions(array $options): Attachment {
|
||||
$this->options = $options;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the used config
|
||||
*
|
||||
* @return Config
|
||||
*/
|
||||
public function getConfig(): Config {
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the used config
|
||||
* @param Config $config
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setConfig(Config $config): Attachment {
|
||||
$this->config = $config;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a masked instance by providing a mask name
|
||||
* @param string|null $mask
|
||||
*
|
||||
* @return mixed
|
||||
* @throws MaskNotFoundException
|
||||
*/
|
||||
public function mask(?string $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 decoder instance
|
||||
*
|
||||
* @return DecoderInterface
|
||||
*/
|
||||
public function getDecoder(): DecoderInterface {
|
||||
return $this->decoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the decoder instance
|
||||
* @param DecoderInterface $decoder
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDecoder(DecoderInterface $decoder): static {
|
||||
$this->decoder = $decoder;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a given name to prevent common attacks
|
||||
* !!IMPORTANT!! Do not rely on this method alone - this is just the bare minimum. Additional measures should be taken
|
||||
* to ensure that the file is safe to use.
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function sanitizeName(string $name): string {
|
||||
$replaces = [
|
||||
'/\\\\/' => '',
|
||||
'/[\/\0:]+/' => '',
|
||||
'/\.+/' => '.',
|
||||
];
|
||||
$name_starts_with_dots = str_starts_with($name, '..');
|
||||
$name = preg_replace(array_keys($replaces), array_values($replaces), $name);
|
||||
if($name_starts_with_dots) {
|
||||
return substr($name, 1);
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
325
plugins/vendor/webklex/php-imap/src/Attribute.php
vendored
Normal file
325
plugins/vendor/webklex/php-imap/src/Attribute.php
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
<?php
|
||||
/*
|
||||
* File: Attribute.php
|
||||
* Category: -
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 01.01.21 20:17
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP;
|
||||
|
||||
use ArrayAccess;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* Class Attribute
|
||||
*
|
||||
* @package Webklex\PHPIMAP
|
||||
*/
|
||||
class Attribute implements ArrayAccess {
|
||||
|
||||
/** @var string $name */
|
||||
protected string $name;
|
||||
|
||||
/**
|
||||
* Value holder
|
||||
*
|
||||
* @var array $values
|
||||
*/
|
||||
protected array $values = [];
|
||||
|
||||
/**
|
||||
* Attribute constructor.
|
||||
* @param string $name
|
||||
* @param mixed|null $value
|
||||
*/
|
||||
public function __construct(string $name, mixed $value = null) {
|
||||
$this->setName($name);
|
||||
$this->add($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle class invocation calls
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
public function __invoke(): array|string {
|
||||
if ($this->count() > 1) {
|
||||
return $this->toArray();
|
||||
}
|
||||
return $this->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the serialized address
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function __serialize(){
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the stringified attribute
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString() {
|
||||
return implode(", ", $this->values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the stringified attribute
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toString(): string {
|
||||
return $this->__toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert instance to array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array {
|
||||
return $this->__serialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert first value to a date object
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
public function toDate(): Carbon {
|
||||
$date = $this->first();
|
||||
if ($date instanceof Carbon) return $date;
|
||||
|
||||
return Carbon::parse($date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a value exists at a given key.
|
||||
*
|
||||
* @param int|string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function has(mixed $key = 0): bool {
|
||||
return array_key_exists($key, $this->values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a value exists at a given key.
|
||||
*
|
||||
* @param int|string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function exist(mixed $key = 0): bool {
|
||||
return $this->has($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the attribute contains the given value
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function contains(mixed $value): bool {
|
||||
return in_array($value, $this->values, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value by a given key.
|
||||
*
|
||||
* @param int|string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(int|string $key = 0): mixed {
|
||||
return $this->values[$key] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value by a given key.
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param mixed $value
|
||||
* @return Attribute
|
||||
*/
|
||||
public function set(mixed $value, mixed $key = 0): Attribute {
|
||||
if (is_null($key)) {
|
||||
$this->values[] = $value;
|
||||
} else {
|
||||
$this->values[$key] = $value;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset a value by a given key.
|
||||
*
|
||||
* @param int|string $key
|
||||
* @return Attribute
|
||||
*/
|
||||
public function remove(int|string $key = 0): Attribute {
|
||||
if (isset($this->values[$key])) {
|
||||
unset($this->values[$key]);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one or more values to the attribute
|
||||
* @param array|mixed $value
|
||||
* @param boolean $strict
|
||||
*
|
||||
* @return Attribute
|
||||
*/
|
||||
public function add(mixed $value, bool $strict = false): Attribute {
|
||||
if (is_array($value)) {
|
||||
return $this->merge($value, $strict);
|
||||
}elseif ($value !== null) {
|
||||
$this->attach($value, $strict);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge a given array of values with the current values array
|
||||
* @param array $values
|
||||
* @param boolean $strict
|
||||
*
|
||||
* @return Attribute
|
||||
*/
|
||||
public function merge(array $values, bool $strict = false): Attribute {
|
||||
foreach ($values as $value) {
|
||||
$this->attach($value, $strict);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a given value to the current value array
|
||||
* @param $value
|
||||
* @param bool $strict
|
||||
* @return Attribute
|
||||
*/
|
||||
public function attach($value, bool $strict = false): Attribute {
|
||||
if ($strict === true) {
|
||||
if ($this->contains($value) === false) {
|
||||
$this->values[] = $value;
|
||||
}
|
||||
}else{
|
||||
$this->values[] = $value;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the attribute name
|
||||
* @param $name
|
||||
*
|
||||
* @return Attribute
|
||||
*/
|
||||
public function setName($name): Attribute {
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attribute name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function all(): array {
|
||||
reset($this->values);
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first value if possible
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function first(): mixed {
|
||||
return reset($this->values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last value if possible
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function last(): mixed {
|
||||
return end($this->values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of values
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count(): int {
|
||||
return count($this->values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ArrayAccess::offsetExists
|
||||
* @param mixed $offset
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists(mixed $offset): bool {
|
||||
return $this->has($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ArrayAccess::offsetGet
|
||||
* @param mixed $offset
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet(mixed $offset): mixed {
|
||||
return $this->get($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ArrayAccess::offsetSet
|
||||
* @param mixed $offset
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public function offsetSet(mixed $offset, mixed $value): void {
|
||||
$this->set($value, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ArrayAccess::offsetUnset
|
||||
* @param mixed $offset
|
||||
* @return void
|
||||
*/
|
||||
public function offsetUnset(mixed $offset): void {
|
||||
$this->remove($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $callback
|
||||
* @return array
|
||||
*/
|
||||
public function map(callable $callback): array {
|
||||
return array_map($callback, $this->values);
|
||||
}
|
||||
}
|
||||
969
plugins/vendor/webklex/php-imap/src/Client.php
vendored
Executable file
969
plugins/vendor/webklex/php-imap/src/Client.php
vendored
Executable file
@@ -0,0 +1,969 @@
|
||||
<?php
|
||||
/*
|
||||
* File: Client.php
|
||||
* Category: -
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 19.01.17 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP;
|
||||
|
||||
use ErrorException;
|
||||
use Webklex\PHPIMAP\Connection\Protocols\ImapProtocol;
|
||||
use Webklex\PHPIMAP\Connection\Protocols\LegacyProtocol;
|
||||
use Webklex\PHPIMAP\Connection\Protocols\ProtocolInterface;
|
||||
use Webklex\PHPIMAP\Exceptions\AuthFailedException;
|
||||
use Webklex\PHPIMAP\Exceptions\ConnectionFailedException;
|
||||
use Webklex\PHPIMAP\Exceptions\EventNotFoundException;
|
||||
use Webklex\PHPIMAP\Exceptions\FolderFetchingException;
|
||||
use Webklex\PHPIMAP\Exceptions\ImapBadRequestException;
|
||||
use Webklex\PHPIMAP\Exceptions\ImapServerErrorException;
|
||||
use Webklex\PHPIMAP\Exceptions\MaskNotFoundException;
|
||||
use Webklex\PHPIMAP\Exceptions\ProtocolNotSupportedException;
|
||||
use Webklex\PHPIMAP\Exceptions\ResponseException;
|
||||
use Webklex\PHPIMAP\Exceptions\RuntimeException;
|
||||
use Webklex\PHPIMAP\Support\FolderCollection;
|
||||
use Webklex\PHPIMAP\Support\Masks\AttachmentMask;
|
||||
use Webklex\PHPIMAP\Support\Masks\MessageMask;
|
||||
use Webklex\PHPIMAP\Traits\HasEvents;
|
||||
|
||||
/**
|
||||
* Class Client
|
||||
*
|
||||
* @package Webklex\PHPIMAP
|
||||
*/
|
||||
class Client {
|
||||
use HasEvents;
|
||||
|
||||
/**
|
||||
* Connection resource
|
||||
*
|
||||
* @var ?ProtocolInterface
|
||||
*/
|
||||
public ?ProtocolInterface $connection = null;
|
||||
|
||||
/**
|
||||
* Client configuration
|
||||
*
|
||||
* @var Config
|
||||
*/
|
||||
protected Config $config;
|
||||
|
||||
/**
|
||||
* Server hostname.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $host;
|
||||
|
||||
/**
|
||||
* Server port.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public int $port;
|
||||
|
||||
/**
|
||||
* Service protocol.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $protocol;
|
||||
|
||||
/**
|
||||
* Server encryption.
|
||||
* Supported: none, ssl, tls, starttls or notls.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $encryption;
|
||||
|
||||
/**
|
||||
* If server has to validate cert.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public bool $validate_cert = true;
|
||||
|
||||
/**
|
||||
* Proxy settings
|
||||
* @var array
|
||||
*/
|
||||
protected array $proxy = [
|
||||
'socket' => null,
|
||||
'request_fulluri' => false,
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* SSL stream context options
|
||||
*
|
||||
* @see https://www.php.net/manual/en/context.ssl.php for possible options
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected array $ssl_options = [];
|
||||
|
||||
/**
|
||||
* Connection timeout
|
||||
* @var int $timeout
|
||||
*/
|
||||
public int $timeout;
|
||||
|
||||
/**
|
||||
* Account username
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $username;
|
||||
|
||||
/**
|
||||
* Account password.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $password;
|
||||
|
||||
/**
|
||||
* Additional data fetched from the server.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public array $extensions;
|
||||
|
||||
/**
|
||||
* Account rfc.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $rfc;
|
||||
|
||||
/**
|
||||
* Account authentication method.
|
||||
*
|
||||
* @var ?string
|
||||
*/
|
||||
public ?string $authentication;
|
||||
|
||||
/**
|
||||
* Active folder path.
|
||||
*
|
||||
* @var ?string
|
||||
*/
|
||||
protected ?string $active_folder = null;
|
||||
|
||||
/**
|
||||
* Default message mask
|
||||
*
|
||||
* @var string $default_message_mask
|
||||
*/
|
||||
protected string $default_message_mask = MessageMask::class;
|
||||
|
||||
/**
|
||||
* Default attachment mask
|
||||
*
|
||||
* @var string $default_attachment_mask
|
||||
*/
|
||||
protected string $default_attachment_mask = AttachmentMask::class;
|
||||
|
||||
/**
|
||||
* Used default account values
|
||||
*
|
||||
* @var array $default_account_config
|
||||
*/
|
||||
protected array $default_account_config = [
|
||||
'host' => 'localhost',
|
||||
'port' => 993,
|
||||
'protocol' => 'imap',
|
||||
'encryption' => 'ssl',
|
||||
'validate_cert' => true,
|
||||
'username' => '',
|
||||
'password' => '',
|
||||
'rfc' => 'RFC822',
|
||||
'authentication' => null,
|
||||
"extensions" => [],
|
||||
'proxy' => [
|
||||
'socket' => null,
|
||||
'request_fulluri' => false,
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
],
|
||||
'ssl_options' => [],
|
||||
"timeout" => 30,
|
||||
];
|
||||
|
||||
/**
|
||||
* Client constructor.
|
||||
* @param Config $config
|
||||
*
|
||||
* @throws MaskNotFoundException
|
||||
*/
|
||||
public function __construct(Config $config) {
|
||||
$this->setConfig($config);
|
||||
$this->setMaskFromConfig();
|
||||
$this->setEventsFromConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Client destructor
|
||||
*
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function __destruct() {
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the current Client instance
|
||||
*
|
||||
* @return Client
|
||||
* @throws MaskNotFoundException
|
||||
*/
|
||||
public function clone(): Client {
|
||||
$client = new self($this->config);
|
||||
$client->events = $this->events;
|
||||
$client->timeout = $this->timeout;
|
||||
$client->active_folder = $this->active_folder;
|
||||
$client->default_account_config = $this->default_account_config;
|
||||
$config = $this->getAccountConfig();
|
||||
foreach($config as $key => $value) {
|
||||
$client->setAccountConfig($key, $config);
|
||||
}
|
||||
$client->default_message_mask = $this->default_message_mask;
|
||||
$client->default_attachment_mask = $this->default_message_mask;
|
||||
return $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Client configuration
|
||||
* @param Config $config
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setConfig(Config $config): Client {
|
||||
$this->config = $config;
|
||||
$default_account = $this->config->get('default');
|
||||
$default_config = $this->config->get("accounts.$default_account");
|
||||
|
||||
foreach ($this->default_account_config as $key => $value) {
|
||||
$this->setAccountConfig($key, $default_config);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current config
|
||||
*
|
||||
* @return Config
|
||||
*/
|
||||
public function getConfig(): Config {
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific account config
|
||||
* @param string $key
|
||||
* @param array $default_config
|
||||
*/
|
||||
private function setAccountConfig(string $key, array $default_config): void {
|
||||
$value = $this->default_account_config[$key];
|
||||
if(isset($default_config[$key])) {
|
||||
$value = $default_config[$key];
|
||||
}
|
||||
$this->$key = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current account config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAccountConfig(): array {
|
||||
$config = [];
|
||||
foreach($this->default_account_config as $key => $value) {
|
||||
if(property_exists($this, $key)) {
|
||||
$config[$key] = $this->$key;
|
||||
}
|
||||
}
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a possible events in any available config
|
||||
*/
|
||||
protected function setEventsFromConfig(): void {
|
||||
$this->events = $this->config->get("events");
|
||||
if(isset($config['events'])){
|
||||
foreach($config['events'] as $section => $events) {
|
||||
$this->events[$section] = array_merge($this->events[$section], $events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a possible mask in any available config
|
||||
*
|
||||
* @throws MaskNotFoundException
|
||||
*/
|
||||
protected function setMaskFromConfig(): void {
|
||||
$masks = $this->config->get("masks");
|
||||
|
||||
if(isset($masks)){
|
||||
if(isset($masks['message'])) {
|
||||
if(class_exists($masks['message'])) {
|
||||
$this->default_message_mask = $masks['message'];
|
||||
}else{
|
||||
throw new MaskNotFoundException("Unknown mask provided: ".$masks['message']);
|
||||
}
|
||||
}else{
|
||||
$default_mask = $this->config->getMask("message");
|
||||
if($default_mask != ""){
|
||||
$this->default_message_mask = $default_mask;
|
||||
}else{
|
||||
throw new MaskNotFoundException("Unknown message mask provided");
|
||||
}
|
||||
}
|
||||
if(isset($masks['attachment'])) {
|
||||
if(class_exists($masks['attachment'])) {
|
||||
$this->default_attachment_mask = $masks['attachment'];
|
||||
}else{
|
||||
throw new MaskNotFoundException("Unknown mask provided: ". $masks['attachment']);
|
||||
}
|
||||
}else{
|
||||
$default_mask = $this->config->getMask("attachment");
|
||||
if($default_mask != ""){
|
||||
$this->default_attachment_mask = $default_mask;
|
||||
}else{
|
||||
throw new MaskNotFoundException("Unknown attachment mask provided");
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$default_mask = $this->config->getMask("message");
|
||||
if($default_mask != ""){
|
||||
$this->default_message_mask = $default_mask;
|
||||
}else{
|
||||
throw new MaskNotFoundException("Unknown message mask provided");
|
||||
}
|
||||
|
||||
$default_mask = $this->config->getMask("attachment");
|
||||
if($default_mask != ""){
|
||||
$this->default_attachment_mask = $default_mask;
|
||||
}else{
|
||||
throw new MaskNotFoundException("Unknown attachment mask provided");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current imap resource
|
||||
*
|
||||
* @return ProtocolInterface
|
||||
* @throws ConnectionFailedException
|
||||
* @throws AuthFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function getConnection(): ProtocolInterface {
|
||||
$this->checkConnection();
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if connection was established.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isConnected(): bool {
|
||||
return $this->connection && $this->connection->connected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if connection was established and connect if not.
|
||||
* Returns true if the connection was closed and has been reopened.
|
||||
*
|
||||
* @throws ConnectionFailedException
|
||||
* @throws AuthFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function checkConnection(): bool {
|
||||
try {
|
||||
if (!$this->isConnected()) {
|
||||
$this->connect();
|
||||
return true;
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
$this->connect();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the connection to reconnect
|
||||
*
|
||||
* @throws ConnectionFailedException
|
||||
* @throws AuthFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function reconnect(): void {
|
||||
if ($this->isConnected()) {
|
||||
$this->disconnect();
|
||||
}
|
||||
$this->connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to server.
|
||||
*
|
||||
* @return $this
|
||||
* @throws ConnectionFailedException
|
||||
* @throws AuthFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function connect(): Client {
|
||||
$this->disconnect();
|
||||
$protocol = strtolower($this->protocol);
|
||||
|
||||
if (in_array($protocol, ['imap', 'imap4', 'imap4rev1'])) {
|
||||
$this->connection = new ImapProtocol($this->config, $this->validate_cert, $this->encryption);
|
||||
$this->connection->setConnectionTimeout($this->timeout);
|
||||
$this->connection->setProxy($this->proxy);
|
||||
$this->connection->setSslOptions($this->ssl_options);
|
||||
}else{
|
||||
if (extension_loaded('imap') === false) {
|
||||
throw new ConnectionFailedException("connection setup failed", 0, new ProtocolNotSupportedException($protocol." is an unsupported protocol"));
|
||||
}
|
||||
$this->connection = new LegacyProtocol($this->config, $this->validate_cert, $this->encryption);
|
||||
if (str_starts_with($protocol, "legacy-")) {
|
||||
$protocol = substr($protocol, 7);
|
||||
}
|
||||
$this->connection->setProtocol($protocol);
|
||||
}
|
||||
|
||||
if ($this->config->get('options.debug')) {
|
||||
$this->connection->enableDebug();
|
||||
}
|
||||
|
||||
if (!$this->config->get('options.uid_cache')) {
|
||||
$this->connection->disableUidCache();
|
||||
}
|
||||
|
||||
try {
|
||||
$this->connection->connect($this->host, $this->port);
|
||||
} catch (ErrorException|RuntimeException $e) {
|
||||
throw new ConnectionFailedException("connection setup failed", 0, $e);
|
||||
}
|
||||
$this->authenticate();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the current session
|
||||
*
|
||||
* @throws AuthFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
protected function authenticate(): void {
|
||||
if ($this->authentication == "oauth") {
|
||||
if (!$this->connection->authenticate($this->username, $this->password)->validatedData()) {
|
||||
throw new AuthFailedException();
|
||||
}
|
||||
} elseif (!$this->connection->login($this->username, $this->password)->validatedData()) {
|
||||
throw new AuthFailedException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from server.
|
||||
*
|
||||
* @return $this
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function disconnect(): Client {
|
||||
if ($this->isConnected()) {
|
||||
$this->connection->logout();
|
||||
}
|
||||
$this->active_folder = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a folder instance by a folder name
|
||||
* @param string $folder_name
|
||||
* @param string|null $delimiter
|
||||
* @param bool $utf7
|
||||
* @return Folder|null
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws FolderFetchingException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws ResponseException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getFolder(string $folder_name, ?string $delimiter = null, bool $utf7 = false): ?Folder {
|
||||
// Set delimiter to false to force selection via getFolderByName (maybe useful for uncommon folder names)
|
||||
$delimiter = is_null($delimiter) ? $this->config->get('options.delimiter', "/") : $delimiter;
|
||||
|
||||
if (str_contains($folder_name, (string)$delimiter)) {
|
||||
return $this->getFolderByPath($folder_name, $utf7);
|
||||
}
|
||||
|
||||
return $this->getFolderByName($folder_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a folder instance by a folder name
|
||||
* @param $folder_name
|
||||
* @param bool $soft_fail If true, it will return null instead of throwing an exception
|
||||
*
|
||||
* @return Folder|null
|
||||
* @throws FolderFetchingException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws AuthFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function getFolderByName($folder_name, bool $soft_fail = false): ?Folder {
|
||||
return $this->getFolders(false, null, $soft_fail)->where("name", $folder_name)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a folder instance by a folder path
|
||||
* @param $folder_path
|
||||
* @param bool $utf7
|
||||
* @param bool $soft_fail If true, it will return null instead of throwing an exception
|
||||
*
|
||||
* @return Folder|null
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws FolderFetchingException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws ResponseException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getFolderByPath($folder_path, bool $utf7 = false, bool $soft_fail = false): ?Folder {
|
||||
if (!$utf7) $folder_path = EncodingAliases::convert($folder_path, "utf-8", "utf7-imap");
|
||||
return $this->getFolders(false, null, $soft_fail)->where("path", $folder_path)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get folders list.
|
||||
* If hierarchical order is set to true, it will make a tree of folders, otherwise it will return flat array.
|
||||
*
|
||||
* @param boolean $hierarchical
|
||||
* @param string|null $parent_folder
|
||||
* @param bool $soft_fail If true, it will return an empty collection instead of throwing an exception
|
||||
*
|
||||
* @return FolderCollection
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws FolderFetchingException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws ResponseException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getFolders(bool $hierarchical = true, ?string $parent_folder = null, bool $soft_fail = false): FolderCollection {
|
||||
$this->checkConnection();
|
||||
$folders = FolderCollection::make([]);
|
||||
|
||||
$pattern = $parent_folder.($hierarchical ? '%' : '*');
|
||||
$items = $this->connection->folders('', $pattern)->validatedData();
|
||||
|
||||
if(!empty($items)){
|
||||
foreach ($items as $folder_name => $item) {
|
||||
$folder = new Folder($this, $folder_name, $item["delimiter"], $item["flags"]);
|
||||
|
||||
if ($hierarchical && $folder->hasChildren()) {
|
||||
$pattern = $folder->path.$folder->delimiter.'%';
|
||||
|
||||
$children = $this->getFolders(true, $pattern, true);
|
||||
$folder->setChildren($children);
|
||||
}
|
||||
|
||||
$folders->push($folder);
|
||||
}
|
||||
|
||||
return $folders;
|
||||
}else if (!$soft_fail){
|
||||
throw new FolderFetchingException("failed to fetch any folders");
|
||||
}
|
||||
|
||||
return $folders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get folders list.
|
||||
* If hierarchical order is set to true, it will make a tree of folders, otherwise it will return flat array.
|
||||
*
|
||||
* @param boolean $hierarchical
|
||||
* @param string|null $parent_folder
|
||||
* @param bool $soft_fail If true, it will return an empty collection instead of throwing an exception
|
||||
*
|
||||
* @return FolderCollection
|
||||
* @throws FolderFetchingException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws AuthFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function getFoldersWithStatus(bool $hierarchical = true, ?string $parent_folder = null, bool $soft_fail = false): FolderCollection {
|
||||
$this->checkConnection();
|
||||
$folders = FolderCollection::make([]);
|
||||
|
||||
$pattern = $parent_folder.($hierarchical ? '%' : '*');
|
||||
$items = $this->connection->folders('', $pattern)->validatedData();
|
||||
|
||||
if(!empty($items)){
|
||||
foreach ($items as $folder_name => $item) {
|
||||
$folder = new Folder($this, $folder_name, $item["delimiter"], $item["flags"]);
|
||||
|
||||
if ($hierarchical && $folder->hasChildren()) {
|
||||
$pattern = $folder->path.$folder->delimiter.'%';
|
||||
|
||||
$children = $this->getFoldersWithStatus(true, $pattern, true);
|
||||
$folder->setChildren($children);
|
||||
}
|
||||
|
||||
$folder->loadStatus();
|
||||
$folders->push($folder);
|
||||
}
|
||||
|
||||
return $folders;
|
||||
}else if (!$soft_fail){
|
||||
throw new FolderFetchingException("failed to fetch any folders");
|
||||
}
|
||||
|
||||
return $folders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a given folder.
|
||||
* @param string $folder_path
|
||||
* @param boolean $force_select
|
||||
*
|
||||
* @return array
|
||||
* @throws ConnectionFailedException
|
||||
* @throws AuthFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function openFolder(string $folder_path, bool $force_select = false): array {
|
||||
if ($this->active_folder == $folder_path && $this->isConnected() && $force_select === false) {
|
||||
return [];
|
||||
}
|
||||
$this->checkConnection();
|
||||
$this->active_folder = $folder_path;
|
||||
return $this->connection->selectFolder($folder_path)->validatedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set active folder
|
||||
* @param string|null $folder_path
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setActiveFolder(?string $folder_path = null): void {
|
||||
$this->active_folder = $folder_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get active folder
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getActiveFolder(): ?string {
|
||||
return $this->active_folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Folder
|
||||
* @param string $folder_path
|
||||
* @param boolean $expunge
|
||||
* @param bool $utf7
|
||||
* @return Folder
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws EventNotFoundException
|
||||
* @throws FolderFetchingException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws ResponseException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function createFolder(string $folder_path, bool $expunge = true, bool $utf7 = false): Folder {
|
||||
$this->checkConnection();
|
||||
|
||||
if (!$utf7) $folder_path = EncodingAliases::convert($folder_path, "utf-8", "UTF7-IMAP");
|
||||
|
||||
$status = $this->connection->createFolder($folder_path)->validatedData();
|
||||
|
||||
if($expunge) $this->expunge();
|
||||
|
||||
$folder = $this->getFolderByPath($folder_path, true);
|
||||
if($status && $folder) {
|
||||
$this->dispatch("folder", "new", $folder);
|
||||
}
|
||||
|
||||
return $folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a given folder
|
||||
* @param string $folder_path
|
||||
* @param boolean $expunge
|
||||
*
|
||||
* @return array
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws EventNotFoundException
|
||||
* @throws FolderFetchingException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function deleteFolder(string $folder_path, bool $expunge = true): array {
|
||||
$this->checkConnection();
|
||||
|
||||
$folder = $this->getFolderByPath($folder_path);
|
||||
if ($this->active_folder == $folder->path){
|
||||
$this->active_folder = null;
|
||||
}
|
||||
$status = $this->getConnection()->deleteFolder($folder->path)->validatedData();
|
||||
if ($expunge) $this->expunge();
|
||||
|
||||
$this->dispatch("folder", "deleted", $folder);
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a given folder
|
||||
* @param string $folder_path
|
||||
*
|
||||
* @return array
|
||||
* @throws ConnectionFailedException
|
||||
* @throws AuthFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function checkFolder(string $folder_path): array {
|
||||
$this->checkConnection();
|
||||
return $this->connection->examineFolder($folder_path)->validatedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current active folder
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getFolderPath(): ?string {
|
||||
return $this->active_folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exchange identification information
|
||||
* Ref.: https://datatracker.ietf.org/doc/html/rfc2971
|
||||
*
|
||||
* @param array|null $ids
|
||||
* @return array
|
||||
*
|
||||
* @throws ConnectionFailedException
|
||||
* @throws AuthFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function Id(?array $ids = null): array {
|
||||
$this->checkConnection();
|
||||
return $this->connection->ID($ids)->validatedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the quota level settings, and usage statics per mailbox
|
||||
*
|
||||
* @return array
|
||||
* @throws ConnectionFailedException
|
||||
* @throws AuthFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function getQuota(): array {
|
||||
$this->checkConnection();
|
||||
return $this->connection->getQuota($this->username)->validatedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the quota settings per user
|
||||
* @param string $quota_root
|
||||
*
|
||||
* @return array
|
||||
* @throws ConnectionFailedException
|
||||
* @throws AuthFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function getQuotaRoot(string $quota_root = 'INBOX'): array {
|
||||
$this->checkConnection();
|
||||
return $this->connection->getQuotaRoot($quota_root)->validatedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all messages marked for deletion
|
||||
*
|
||||
* @return array
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws AuthFailedException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function expunge(): array {
|
||||
$this->checkConnection();
|
||||
return $this->connection->expunge()->validatedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connection timeout
|
||||
* @param integer $timeout
|
||||
*
|
||||
* @return ProtocolInterface
|
||||
* @throws ConnectionFailedException
|
||||
* @throws AuthFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function setTimeout(int $timeout): ProtocolInterface {
|
||||
$this->timeout = $timeout;
|
||||
if ($this->isConnected()) {
|
||||
$this->connection->setConnectionTimeout($timeout);
|
||||
$this->reconnect();
|
||||
}
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the connection timeout
|
||||
*
|
||||
* @return int
|
||||
* @throws ConnectionFailedException
|
||||
* @throws AuthFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function getTimeout(): int {
|
||||
$this->checkConnection();
|
||||
return $this->connection->getConnectionTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default message mask
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultMessageMask(): string {
|
||||
return $this->default_message_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default events for a given section
|
||||
* @param $section
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDefaultEvents($section): array {
|
||||
if (isset($this->events[$section])) {
|
||||
return is_array($this->events[$section]) ? $this->events[$section] : [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default message mask
|
||||
* @param string $mask
|
||||
*
|
||||
* @return $this
|
||||
* @throws MaskNotFoundException
|
||||
*/
|
||||
public function setDefaultMessageMask(string $mask): Client {
|
||||
if(class_exists($mask)) {
|
||||
$this->default_message_mask = $mask;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
throw new MaskNotFoundException("Unknown mask provided: ".$mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default attachment mask
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultAttachmentMask(): string {
|
||||
return $this->default_attachment_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default attachment mask
|
||||
* @param string $mask
|
||||
*
|
||||
* @return $this
|
||||
* @throws MaskNotFoundException
|
||||
*/
|
||||
public function setDefaultAttachmentMask(string $mask): Client {
|
||||
if(class_exists($mask)) {
|
||||
$this->default_attachment_mask = $mask;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
throw new MaskNotFoundException("Unknown mask provided: ".$mask);
|
||||
}
|
||||
}
|
||||
131
plugins/vendor/webklex/php-imap/src/ClientManager.php
vendored
Normal file
131
plugins/vendor/webklex/php-imap/src/ClientManager.php
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
/*
|
||||
* File: ClientManager.php
|
||||
* Category: -
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 19.01.17 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP;
|
||||
|
||||
/**
|
||||
* Class ClientManager
|
||||
*
|
||||
* @package Webklex\IMAP
|
||||
*/
|
||||
class ClientManager {
|
||||
|
||||
/**
|
||||
* All library config
|
||||
*
|
||||
* @var Config $config
|
||||
*/
|
||||
public Config $config;
|
||||
|
||||
/**
|
||||
* @var array $accounts
|
||||
*/
|
||||
protected array $accounts = [];
|
||||
|
||||
/**
|
||||
* ClientManager constructor.
|
||||
* @param array|string|Config $config
|
||||
*/
|
||||
public function __construct(array|string|Config $config = []) {
|
||||
$this->setConfig($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically pass calls to the default account.
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Exceptions\MaskNotFoundException
|
||||
*/
|
||||
public function __call(string $method, array $parameters) {
|
||||
$callable = [$this->account(), $method];
|
||||
|
||||
return call_user_func_array($callable, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely create a new client instance which is not listed in accounts
|
||||
* @param array $config
|
||||
*
|
||||
* @return Client
|
||||
* @throws Exceptions\MaskNotFoundException
|
||||
*/
|
||||
public function make(array $config): Client {
|
||||
$name = $this->config->getDefaultAccount();
|
||||
$clientConfig = $this->config->all();
|
||||
$clientConfig["accounts"] = [$name => $config];
|
||||
return new Client(Config::make($clientConfig));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a account instance.
|
||||
* @param string|null $name
|
||||
*
|
||||
* @return Client
|
||||
* @throws Exceptions\MaskNotFoundException
|
||||
*/
|
||||
public function account(?string $name = null): Client {
|
||||
$name = $name ?: $this->config->getDefaultAccount();
|
||||
|
||||
// If the connection has not been resolved we will resolve it now as all
|
||||
// the connections are resolved when they are actually needed, so we do
|
||||
// not make any unnecessary connection to the various queue end-points.
|
||||
if (!isset($this->accounts[$name])) {
|
||||
$this->accounts[$name] = $this->resolve($name);
|
||||
}
|
||||
|
||||
return $this->accounts[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve an account.
|
||||
* @param string $name
|
||||
*
|
||||
* @return Client
|
||||
* @throws Exceptions\MaskNotFoundException
|
||||
*/
|
||||
protected function resolve(string $name): Client {
|
||||
$config = $this->config->getClientConfig($name);
|
||||
|
||||
return new Client($config);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merge the vendor settings with the local config
|
||||
*
|
||||
* The default account identifier will be used as default for any missing account parameters.
|
||||
* If however the default account is missing a parameter the package default account parameter will be used.
|
||||
* This can be disabled by setting imap.default in your config file to 'false'
|
||||
*
|
||||
* @param array|string|Config $config
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setConfig(array|string|Config $config): ClientManager {
|
||||
if (!$config instanceof Config) {
|
||||
$config = Config::make($config);
|
||||
}
|
||||
$this->config = $config;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the config instance
|
||||
* @return Config
|
||||
*/
|
||||
public function getConfig(): Config {
|
||||
return $this->config;
|
||||
}
|
||||
}
|
||||
295
plugins/vendor/webklex/php-imap/src/Config.php
vendored
Normal file
295
plugins/vendor/webklex/php-imap/src/Config.php
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
<?php
|
||||
/*
|
||||
* File: Config.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 10.04.24 15:42
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP;
|
||||
|
||||
use Webklex\PHPIMAP\Decoder\DecoderInterface;
|
||||
use Webklex\PHPIMAP\Exceptions\DecoderNotFoundException;
|
||||
|
||||
/**
|
||||
* Class Config
|
||||
*
|
||||
* @package Webklex\PHPIMAP
|
||||
*/
|
||||
class Config {
|
||||
|
||||
/**
|
||||
* Configuration array
|
||||
* @var array $config
|
||||
*/
|
||||
protected array $config = [];
|
||||
|
||||
/**
|
||||
* Config constructor.
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config = []) {
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a dotted config parameter
|
||||
* @param string $key
|
||||
* @param null $default
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function get(string $key, $default = null): mixed {
|
||||
$parts = explode('.', $key);
|
||||
$value = null;
|
||||
foreach ($parts as $part) {
|
||||
if ($value === null) {
|
||||
if (isset($this->config[$part])) {
|
||||
$value = $this->config[$part];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (isset($value[$part])) {
|
||||
$value = $value[$part];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $value === null ? $default : $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a dotted config parameter
|
||||
* @param string $key
|
||||
* @param string|array|mixed$value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set(string $key, mixed $value): void {
|
||||
$parts = explode('.', $key);
|
||||
$config = &$this->config;
|
||||
|
||||
foreach ($parts as $part) {
|
||||
if (!isset($config[$part])) {
|
||||
$config[$part] = [];
|
||||
}
|
||||
$config = &$config[$part];
|
||||
}
|
||||
|
||||
if(is_array($config) && is_array($value)){
|
||||
$config = array_merge($config, $value);
|
||||
}else{
|
||||
$config = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the decoder for a given name
|
||||
* @param $name string Decoder name
|
||||
*
|
||||
* @return DecoderInterface
|
||||
* @throws DecoderNotFoundException
|
||||
*/
|
||||
public function getDecoder(string $name): DecoderInterface {
|
||||
$default_decoders = $this->get('decoding.decoder', [
|
||||
'header' => \Webklex\PHPIMAP\Decoder\HeaderDecoder::class,
|
||||
'message' => \Webklex\PHPIMAP\Decoder\MessageDecoder::class,
|
||||
'attachment' => \Webklex\PHPIMAP\Decoder\AttachmentDecoder::class
|
||||
]);
|
||||
$options = $this->get('decoding.options', [
|
||||
'header' => 'utf-8',
|
||||
'message' => 'utf-8',
|
||||
'attachment' => 'utf-8',
|
||||
]);
|
||||
if (isset($default_decoders[$name])) {
|
||||
if (class_exists($default_decoders[$name])) {
|
||||
return new $default_decoders[$name]($options);
|
||||
}
|
||||
}
|
||||
throw new DecoderNotFoundException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mask for a given section
|
||||
* @param string $section section name such as "message" or "attachment"
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getMask(string $section): ?string {
|
||||
$default_masks = $this->get('masks', []);
|
||||
if (isset($default_masks[$section])) {
|
||||
if (class_exists($default_masks[$section])) {
|
||||
return $default_masks[$section];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the account configuration.
|
||||
* @param string|null $name
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function getClientConfig(?string $name): self {
|
||||
$config = $this->all();
|
||||
$defaultName = $this->getDefaultAccount();
|
||||
$defaultAccount = $this->get('accounts.'.$defaultName, []);
|
||||
|
||||
if ($name === null || $name === 'null' || $name === "") {
|
||||
$account = $defaultAccount;
|
||||
$name = $defaultName;
|
||||
}else{
|
||||
$account = $this->get('accounts.'.$name, $defaultAccount);
|
||||
}
|
||||
|
||||
$config["default"] = $name;
|
||||
$config["accounts"] = [
|
||||
$name => $account
|
||||
];
|
||||
|
||||
return new self($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the default account.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultAccount(): string {
|
||||
return $this->get('default', 'default');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the default account.
|
||||
* @param string $name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setDefaultAccount(string $name): void {
|
||||
$this->set('default', $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the Config class
|
||||
* @param array|string $config
|
||||
* @return Config
|
||||
*/
|
||||
public static function make(array|string $config = []): Config {
|
||||
if (is_array($config) === false) {
|
||||
$config = require $config;
|
||||
}
|
||||
|
||||
$config_key = 'imap';
|
||||
$path = __DIR__ . '/config/' . $config_key . '.php';
|
||||
|
||||
$vendor_config = require $path;
|
||||
$config = self::array_merge_recursive_distinct($vendor_config, $config);
|
||||
|
||||
if (isset($config['default'])) {
|
||||
if (isset($config['accounts']) && $config['default']) {
|
||||
|
||||
$default_config = $vendor_config['accounts']['default'];
|
||||
if (isset($config['accounts'][$config['default']])) {
|
||||
$default_config = array_merge($default_config, $config['accounts'][$config['default']]);
|
||||
}
|
||||
|
||||
if (is_array($config['accounts'])) {
|
||||
foreach ($config['accounts'] as $account_key => $account) {
|
||||
$config['accounts'][$account_key] = array_merge($default_config, $account);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new self($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marge arrays recursively and distinct
|
||||
*
|
||||
* Merges any number of arrays / parameters recursively, replacing
|
||||
* entries with string keys with values from latter arrays.
|
||||
* If the entry or the next value to be assigned is an array, then it
|
||||
* automatically treats both arguments as an array.
|
||||
* Numeric entries are appended, not replaced, but only if they are
|
||||
* unique
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @link http://www.php.net/manual/en/function.array-merge-recursive.php#96201
|
||||
* @author Mark Roduner <mark.roduner@gmail.com>
|
||||
*/
|
||||
private static function array_merge_recursive_distinct(): array {
|
||||
$arrays = func_get_args();
|
||||
$base = array_shift($arrays);
|
||||
|
||||
// From https://stackoverflow.com/a/173479
|
||||
$isAssoc = function(array $arr) {
|
||||
if (array() === $arr) return false;
|
||||
return array_keys($arr) !== range(0, count($arr) - 1);
|
||||
};
|
||||
|
||||
if (!is_array($base)) $base = empty($base) ? array() : array($base);
|
||||
|
||||
foreach ($arrays as $append) {
|
||||
if (!is_array($append)) $append = array($append);
|
||||
|
||||
foreach ($append as $key => $value) {
|
||||
|
||||
if (!array_key_exists($key, $base) and !is_numeric($key)) {
|
||||
$base[$key] = $value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((is_array($value) && $isAssoc($value)) || (is_array($base[$key]) && $isAssoc($base[$key]))) {
|
||||
// If the arrays are not associates we don't want to array_merge_recursive_distinct
|
||||
// else merging $baseConfig['dispositions'] = ['attachment', 'inline'] with $customConfig['dispositions'] = ['attachment']
|
||||
// results in $resultConfig['dispositions'] = ['attachment', 'inline']
|
||||
$base[$key] = self::array_merge_recursive_distinct($base[$key], $value);
|
||||
} else if (is_numeric($key)) {
|
||||
if (!in_array($value, $base)) $base[] = $value;
|
||||
} else {
|
||||
$base[$key] = $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all configuration values
|
||||
* @return array
|
||||
*/
|
||||
public function all(): array {
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a configuration value exists
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $key): bool {
|
||||
return $this->get($key) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all configuration values
|
||||
* @return $this
|
||||
*/
|
||||
public function clear(): static {
|
||||
$this->config = [];
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
1485
plugins/vendor/webklex/php-imap/src/Connection/Protocols/ImapProtocol.php
vendored
Normal file
1485
plugins/vendor/webklex/php-imap/src/Connection/Protocols/ImapProtocol.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
825
plugins/vendor/webklex/php-imap/src/Connection/Protocols/LegacyProtocol.php
vendored
Normal file
825
plugins/vendor/webklex/php-imap/src/Connection/Protocols/LegacyProtocol.php
vendored
Normal file
@@ -0,0 +1,825 @@
|
||||
<?php
|
||||
/*
|
||||
* File: LegacyProtocol.php
|
||||
* Category: Protocol
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 16.09.20 18:27
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Connection\Protocols;
|
||||
|
||||
use Webklex\PHPIMAP\ClientManager;
|
||||
use Webklex\PHPIMAP\Config;
|
||||
use Webklex\PHPIMAP\Exceptions\AuthFailedException;
|
||||
use Webklex\PHPIMAP\Exceptions\ImapBadRequestException;
|
||||
use Webklex\PHPIMAP\Exceptions\MethodNotSupportedException;
|
||||
use Webklex\PHPIMAP\Exceptions\RuntimeException;
|
||||
use Webklex\PHPIMAP\IMAP;
|
||||
|
||||
/**
|
||||
* Class LegacyProtocol
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Connection\Protocols
|
||||
*/
|
||||
class LegacyProtocol extends Protocol {
|
||||
|
||||
protected string $protocol = "imap";
|
||||
protected string $host = "localhost";
|
||||
protected int $port = 993;
|
||||
|
||||
/**
|
||||
* Imap constructor.
|
||||
* @param Config $config
|
||||
* @param bool $cert_validation set to false to skip SSL certificate validation
|
||||
* @param mixed $encryption Connection encryption method
|
||||
*/
|
||||
public function __construct(Config $config, bool $cert_validation = true, mixed $encryption = false) {
|
||||
$this->config = $config;
|
||||
$this->setCertValidation($cert_validation);
|
||||
$this->encryption = $encryption;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public destructor
|
||||
*/
|
||||
public function __destruct() {
|
||||
$this->logout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the information for a nw connection
|
||||
* @param string $host
|
||||
* @param int|null $port
|
||||
*/
|
||||
public function connect(string $host, ?int $port = null): void {
|
||||
if ($this->encryption) {
|
||||
$encryption = strtolower($this->encryption);
|
||||
if ($encryption == "ssl") {
|
||||
$port = $port === null ? 993 : $port;
|
||||
}
|
||||
}
|
||||
$port = $port === null ? 143 : $port;
|
||||
$this->host = $host;
|
||||
$this->port = $port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login to a new session.
|
||||
* @param string $user username
|
||||
* @param string $password password
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function login(string $user, string $password): Response {
|
||||
return $this->response()->wrap(function($response) use ($user, $password) {
|
||||
/** @var Response $response */
|
||||
try {
|
||||
$this->stream = \imap_open(
|
||||
$this->getAddress(),
|
||||
$user,
|
||||
$password,
|
||||
0,
|
||||
$attempts = 3,
|
||||
$this->config->get('options.open')
|
||||
);
|
||||
$response->addCommand("imap_open");
|
||||
} catch (\ErrorException $e) {
|
||||
$errors = \imap_errors();
|
||||
$message = $e->getMessage() . '. ' . implode("; ", (is_array($errors) ? $errors : array()));
|
||||
throw new AuthFailedException($message);
|
||||
}
|
||||
|
||||
if (!$this->stream) {
|
||||
$errors = \imap_errors();
|
||||
$message = implode("; ", (is_array($errors) ? $errors : array()));
|
||||
throw new AuthFailedException($message);
|
||||
}
|
||||
|
||||
$errors = \imap_errors();
|
||||
$response->addCommand("imap_errors");
|
||||
if (is_array($errors)) {
|
||||
$status = $this->examineFolder();
|
||||
$response->stack($status);
|
||||
if ($status->data()['exists'] !== 0) {
|
||||
$message = implode("; ", $errors);
|
||||
throw new RuntimeException($message);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->stream !== false) {
|
||||
return ["TAG" . $response->Noun() . " OK [] Logged in\r\n"];
|
||||
}
|
||||
|
||||
$response->addError("failed to login");
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate your current session.
|
||||
* @param string $user username
|
||||
* @param string $token access token
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function authenticate(string $user, string $token): Response {
|
||||
return $this->login($user, $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get full address of mailbox.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAddress(): string {
|
||||
$address = "{" . $this->host . ":" . $this->port . "/" . $this->protocol;
|
||||
if (!$this->cert_validation) {
|
||||
$address .= '/novalidate-cert';
|
||||
}
|
||||
if (in_array($this->encryption, ['tls', 'notls', 'ssl'])) {
|
||||
$address .= '/' . $this->encryption;
|
||||
} elseif ($this->encryption === "starttls") {
|
||||
$address .= '/tls';
|
||||
}
|
||||
|
||||
$address .= '}';
|
||||
|
||||
return $address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout of the current session
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function logout(): Response {
|
||||
return $this->response()->wrap(function($response) {
|
||||
/** @var Response $response */
|
||||
if ($this->stream) {
|
||||
$this->uid_cache = [];
|
||||
$response->addCommand("imap_close");
|
||||
if (\imap_close($this->stream, IMAP::CL_EXPUNGE)) {
|
||||
$this->stream = false;
|
||||
return [
|
||||
0 => "BYE Logging out\r\n",
|
||||
1 => "TAG" . $response->Noun() . " OK Logout completed (0.001 + 0.000 secs).\r\n",
|
||||
];
|
||||
}
|
||||
$this->stream = false;
|
||||
}
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of available capabilities
|
||||
*
|
||||
* @throws MethodNotSupportedException
|
||||
*/
|
||||
public function getCapabilities(): Response {
|
||||
throw new MethodNotSupportedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the current folder
|
||||
* @param string $folder change to this folder
|
||||
*
|
||||
* @return Response see examineOrselect()
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function selectFolder(string $folder = 'INBOX'): Response {
|
||||
$flags = IMAP::OP_READONLY;
|
||||
if (in_array($this->protocol, ["pop3", "nntp"])) {
|
||||
$flags = IMAP::NIL;
|
||||
}
|
||||
if ($this->stream === false) {
|
||||
throw new RuntimeException("failed to reopen stream.");
|
||||
}
|
||||
|
||||
return $this->response("imap_reopen")->wrap(function($response) use ($folder, $flags) {
|
||||
/** @var Response $response */
|
||||
\imap_reopen($this->stream, $this->getAddress() . $folder, $flags, 3);
|
||||
$this->uid_cache = [];
|
||||
|
||||
$status = $this->examineFolder($folder);
|
||||
$response->stack($status);
|
||||
|
||||
return $status->data();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Examine a given folder
|
||||
* @param string $folder examine this folder
|
||||
*
|
||||
* @return Response
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function examineFolder(string $folder = 'INBOX'): Response {
|
||||
if (str_starts_with($folder, ".")) {
|
||||
throw new RuntimeException("Segmentation fault prevented. Folders starts with an illegal char '.'.");
|
||||
}
|
||||
return $this->response("imap_status")->wrap(function($response) use ($folder) {
|
||||
/** @var Response $response */
|
||||
$status = \imap_status($this->stream, $this->getAddress() . $folder, IMAP::SA_ALL);
|
||||
|
||||
return $status ? [
|
||||
"flags" => [],
|
||||
"exists" => $status->messages,
|
||||
"recent" => $status->recent,
|
||||
"unseen" => $status->unseen,
|
||||
"uidnext" => $status->uidnext,
|
||||
] : [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status of a given folder
|
||||
*
|
||||
* @return Response list of STATUS items
|
||||
* @throws MethodNotSupportedException
|
||||
*/
|
||||
public function folderStatus(string $folder = 'INBOX', $arguments = ['MESSAGES', 'UNSEEN', 'RECENT', 'UIDNEXT', 'UIDVALIDITY']): Response {
|
||||
throw new MethodNotSupportedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch message content
|
||||
* @param int|array $uids
|
||||
* @param string $rfc
|
||||
* @param int|string $uid set to IMAP::ST_UID if you pass message unique identifiers instead of numbers.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function content(int|array $uids, string $rfc = "RFC822", int|string $uid = IMAP::ST_UID): Response {
|
||||
return $this->response()->wrap(function($response) use ($uids, $uid) {
|
||||
/** @var Response $response */
|
||||
|
||||
$result = [];
|
||||
$uids = is_array($uids) ? $uids : [$uids];
|
||||
foreach ($uids as $id) {
|
||||
$response->addCommand("imap_fetchbody");
|
||||
$result[$id] = \imap_fetchbody($this->stream, $id, "", $uid === IMAP::ST_UID ? IMAP::ST_UID : IMAP::NIL);
|
||||
}
|
||||
|
||||
return $result;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch message headers
|
||||
* @param int|array $uids
|
||||
* @param string $rfc
|
||||
* @param int|string $uid set to IMAP::ST_UID if you pass message unique identifiers instead of numbers.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function headers(int|array $uids, string $rfc = "RFC822", int|string $uid = IMAP::ST_UID): Response {
|
||||
return $this->response()->wrap(function($response) use ($uids, $uid) {
|
||||
/** @var Response $response */
|
||||
|
||||
$result = [];
|
||||
$uids = is_array($uids) ? $uids : [$uids];
|
||||
foreach ($uids as $id) {
|
||||
$response->addCommand("imap_fetchheader");
|
||||
$result[$id] = \imap_fetchheader($this->stream, $id, $uid ? IMAP::ST_UID : IMAP::NIL);
|
||||
}
|
||||
|
||||
return $result;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch message flags
|
||||
* @param int|array $uids
|
||||
* @param int|string $uid set to IMAP::ST_UID if you pass message unique identifiers instead of numbers.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function flags(int|array $uids, int|string $uid = IMAP::ST_UID): Response {
|
||||
return $this->response()->wrap(function($response) use ($uids, $uid) {
|
||||
/** @var Response $response */
|
||||
|
||||
$result = [];
|
||||
$uids = is_array($uids) ? $uids : [$uids];
|
||||
foreach ($uids as $id) {
|
||||
$response->addCommand("imap_fetch_overview");
|
||||
$raw_flags = \imap_fetch_overview($this->stream, $id, $uid ? IMAP::ST_UID : IMAP::NIL);
|
||||
$flags = [];
|
||||
if (is_array($raw_flags) && isset($raw_flags[0])) {
|
||||
$raw_flags = (array)$raw_flags[0];
|
||||
foreach ($raw_flags as $flag => $value) {
|
||||
if ($value === 1 && in_array($flag, ["size", "uid", "msgno", "update"]) === false) {
|
||||
$flags[] = "\\" . ucfirst($flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
$result[$id] = $flags;
|
||||
}
|
||||
|
||||
return $result;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch message sizes
|
||||
* @param int|array $uids
|
||||
* @param int|string $uid set to IMAP::ST_UID if you pass message unique identifiers instead of numbers.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function sizes(int|array $uids, int|string $uid = IMAP::ST_UID): Response {
|
||||
return $this->response()->wrap(function($response) use ($uids, $uid) {
|
||||
/** @var Response $response */
|
||||
$result = [];
|
||||
$uids = is_array($uids) ? $uids : [$uids];
|
||||
$uid_text = implode("','", $uids);
|
||||
$response->addCommand("imap_fetch_overview");
|
||||
if ($uid == IMAP::ST_UID) {
|
||||
$raw_overview = \imap_fetch_overview($this->stream, $uid_text, IMAP::FT_UID);
|
||||
} else {
|
||||
$raw_overview = \imap_fetch_overview($this->stream, $uid_text);
|
||||
}
|
||||
if ($raw_overview !== false) {
|
||||
foreach ($raw_overview as $overview_element) {
|
||||
$overview_element = (array)$overview_element;
|
||||
$result[$overview_element[$uid == IMAP::ST_UID ? 'uid' : 'msgno']] = $overview_element['size'];
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get uid for a given id
|
||||
* @param int|null $id message number
|
||||
*
|
||||
* @return Response message number for given message or all messages as array
|
||||
*/
|
||||
public function getUid(?int $id = null): Response {
|
||||
return $this->response()->wrap(function($response) use ($id) {
|
||||
/** @var Response $response */
|
||||
if ($id === null) {
|
||||
if ($this->enable_uid_cache && $this->uid_cache) {
|
||||
return $this->uid_cache;
|
||||
}
|
||||
|
||||
$overview = $this->overview("1:*");
|
||||
$response->stack($overview);
|
||||
$uids = [];
|
||||
foreach ($overview->data() as $set) {
|
||||
$uids[$set->msgno] = $set->uid;
|
||||
}
|
||||
|
||||
$this->setUidCache($uids);
|
||||
return $uids;
|
||||
}
|
||||
|
||||
$response->addCommand("imap_uid");
|
||||
$uid = \imap_uid($this->stream, $id);
|
||||
if ($uid) {
|
||||
return $uid;
|
||||
}
|
||||
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message number of a given uid
|
||||
* @param string $id uid
|
||||
*
|
||||
* @return Response message number
|
||||
*/
|
||||
public function getMessageNumber(string $id): Response {
|
||||
return $this->response("imap_msgno")->wrap(function($response) use ($id) {
|
||||
/** @var Response $response */
|
||||
return \imap_msgno($this->stream, $id);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a message overview
|
||||
* @param string $sequence uid sequence
|
||||
* @param int|string $uid set to IMAP::ST_UID if you pass message unique identifiers instead of numbers.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function overview(string $sequence, int|string $uid = IMAP::ST_UID): Response {
|
||||
return $this->response("imap_fetch_overview")->wrap(function($response) use ($sequence, $uid) {
|
||||
/** @var Response $response */
|
||||
return \imap_fetch_overview($this->stream, $sequence, $uid ? IMAP::ST_UID : IMAP::NIL) ?: [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of available folders
|
||||
* @param string $reference mailbox reference for list
|
||||
* @param string $folder mailbox name match with wildcards
|
||||
*
|
||||
* @return Response folders that matched $folder as array(name => array('delimiter' => .., 'flags' => ..))
|
||||
*/
|
||||
public function folders(string $reference = '', string $folder = '*'): Response {
|
||||
return $this->response("imap_getmailboxes")->wrap(function($response) use ($reference, $folder) {
|
||||
/** @var Response $response */
|
||||
$result = [];
|
||||
|
||||
$items = \imap_getmailboxes($this->stream, $this->getAddress(), $reference . $folder);
|
||||
if (is_array($items)) {
|
||||
foreach ($items as $item) {
|
||||
$name = $this->decodeFolderName($item->name);
|
||||
$result[$name] = ['delimiter' => $item->delimiter, 'flags' => []];
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException(\imap_last_error());
|
||||
}
|
||||
|
||||
return $result;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage flags
|
||||
* @param array|string $flags flags to set, add or remove - see $mode
|
||||
* @param int $from message for items or start message if $to !== null
|
||||
* @param int|null $to if null only one message ($from) is fetched, else it's the
|
||||
* last message, INF means last message available
|
||||
* @param string|null $mode '+' to add flags, '-' to remove flags, everything else sets the flags as given
|
||||
* @param bool $silent if false the return values are the new flags for the wanted messages
|
||||
* @param int|string $uid set to IMAP::ST_UID if you pass message unique identifiers instead of numbers.
|
||||
* @param string|null $item unused attribute
|
||||
*
|
||||
* @return Response new flags if $silent is false, else true or false depending on success
|
||||
*/
|
||||
public function store(array|string $flags, int $from, ?int $to = null, ?string $mode = null, bool $silent = true, int|string $uid = IMAP::ST_UID, ?string $item = null): Response {
|
||||
$flag = trim(is_array($flags) ? implode(" ", $flags) : $flags);
|
||||
|
||||
return $this->response()->wrap(function($response) use ($mode, $from, $flag, $uid, $silent) {
|
||||
/** @var Response $response */
|
||||
|
||||
if ($mode == "+") {
|
||||
$response->addCommand("imap_setflag_full");
|
||||
$status = \imap_setflag_full($this->stream, $from, $flag, $uid ? IMAP::ST_UID : IMAP::NIL);
|
||||
} else {
|
||||
$response->addCommand("imap_clearflag_full");
|
||||
$status = \imap_clearflag_full($this->stream, $from, $flag, $uid ? IMAP::ST_UID : IMAP::NIL);
|
||||
}
|
||||
|
||||
if ($silent === true) {
|
||||
if ($status) {
|
||||
return [
|
||||
"TAG" . $response->Noun() . " OK Store completed (0.001 + 0.000 secs).\r\n"
|
||||
];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->flags($from);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a new message to given folder
|
||||
* @param string $folder name of target folder
|
||||
* @param string $message full message content
|
||||
* @param array|null $flags flags for new message
|
||||
* @param mixed $date date for new message
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function appendMessage(string $folder, string $message, ?array $flags = null, mixed $date = null): Response {
|
||||
return $this->response("imap_append")->wrap(function($response) use ($folder, $message, $flags, $date) {
|
||||
/** @var Response $response */
|
||||
if ($date != null) {
|
||||
if ($date instanceof \Carbon\Carbon) {
|
||||
$date = $date->format('d-M-Y H:i:s O');
|
||||
}
|
||||
if (\imap_append($this->stream, $this->getAddress() . $folder, $message, $flags, $date)) {
|
||||
return [
|
||||
"OK Append completed (0.001 + 0.000 secs).\r\n"
|
||||
];
|
||||
}
|
||||
} else if (\imap_append($this->stream, $this->getAddress() . $folder, $message, $flags)) {
|
||||
return [
|
||||
"OK Append completed (0.001 + 0.000 secs).\r\n"
|
||||
];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy message set from current folder to other folder
|
||||
* @param string $folder destination folder
|
||||
* @param $from
|
||||
* @param int|null $to if null only one message ($from) is fetched, else it's the
|
||||
* last message, INF means last message available
|
||||
* @param int|string $uid set to IMAP::ST_UID if you pass message unique identifiers instead of numbers.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function copyMessage(string $folder, $from, ?int $to = null, int|string $uid = IMAP::ST_UID): Response {
|
||||
return $this->response("imap_mail_copy")->wrap(function($response) use ($from, $folder, $uid) {
|
||||
/** @var Response $response */
|
||||
|
||||
if (\imap_mail_copy($this->stream, $from, $this->getAddress() . $folder, $uid ? IMAP::ST_UID : IMAP::NIL)) {
|
||||
return [
|
||||
"TAG" . $response->Noun() . " OK Copy completed (0.001 + 0.000 secs).\r\n"
|
||||
];
|
||||
}
|
||||
throw new ImapBadRequestException("Invalid ID $from");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy multiple messages to the target folder
|
||||
* @param array $messages List of message identifiers
|
||||
* @param string $folder Destination folder
|
||||
* @param int|string $uid set to IMAP::ST_UID if you pass message unique identifiers instead of numbers.
|
||||
*
|
||||
* @return Response Tokens if operation successful, false if an error occurred
|
||||
*/
|
||||
public function copyManyMessages(array $messages, string $folder, int|string $uid = IMAP::ST_UID): Response {
|
||||
return $this->response()->wrap(function($response) use ($messages, $folder, $uid) {
|
||||
/** @var Response $response */
|
||||
foreach ($messages as $msg) {
|
||||
$copy_response = $this->copyMessage($folder, $msg, null, $uid);
|
||||
$response->stack($copy_response);
|
||||
if (empty($copy_response->data())) {
|
||||
return [
|
||||
"TAG" . $response->Noun() . " BAD Copy failed (0.001 + 0.000 secs).\r\n",
|
||||
"Invalid ID $msg\r\n"
|
||||
];
|
||||
}
|
||||
}
|
||||
return [
|
||||
"TAG" . $response->Noun() . " OK Copy completed (0.001 + 0.000 secs).\r\n"
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a message set from current folder to another folder
|
||||
* @param string $folder destination folder
|
||||
* @param $from
|
||||
* @param int|null $to if null only one message ($from) is fetched, else it's the
|
||||
* last message, INF means last message available
|
||||
* @param int|string $uid set to IMAP::ST_UID if you pass message unique identifiers instead of numbers.
|
||||
*
|
||||
* @return Response success
|
||||
*/
|
||||
public function moveMessage(string $folder, $from, ?int $to = null, int|string $uid = IMAP::ST_UID): Response {
|
||||
return $this->response("imap_mail_move")->wrap(function($response) use ($from, $folder, $uid) {
|
||||
if (\imap_mail_move($this->stream, $from, $this->getAddress() . $folder, $uid ? IMAP::ST_UID : IMAP::NIL)) {
|
||||
return [
|
||||
"TAG" . $response->Noun() . " OK Move completed (0.001 + 0.000 secs).\r\n"
|
||||
];
|
||||
}
|
||||
throw new ImapBadRequestException("Invalid ID $from");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Move multiple messages to the target folder
|
||||
* @param array $messages List of message identifiers
|
||||
* @param string $folder Destination folder
|
||||
* @param int|string $uid set to IMAP::ST_UID if you pass message unique identifiers instead of numbers.
|
||||
*
|
||||
* @return Response Tokens if operation successful, false if an error occurred
|
||||
* @throws ImapBadRequestException
|
||||
*/
|
||||
public function moveManyMessages(array $messages, string $folder, int|string $uid = IMAP::ST_UID): Response {
|
||||
return $this->response()->wrap(function($response) use ($messages, $folder, $uid) {
|
||||
foreach ($messages as $msg) {
|
||||
$move_response = $this->moveMessage($folder, $msg, null, $uid);
|
||||
$response = $response->include($response);
|
||||
if (empty($move_response->data())) {
|
||||
return [
|
||||
"TAG" . $response->Noun() . " BAD Move failed (0.001 + 0.000 secs).\r\n",
|
||||
"Invalid ID $msg\r\n"
|
||||
];
|
||||
}
|
||||
}
|
||||
return [
|
||||
"TAG" . $response->Noun() . " OK Move completed (0.001 + 0.000 secs).\r\n"
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Exchange identification information
|
||||
* Ref.: https://datatracker.ietf.org/doc/html/rfc2971
|
||||
*
|
||||
* @param null $ids
|
||||
* @return Response
|
||||
*
|
||||
* @throws MethodNotSupportedException
|
||||
*/
|
||||
public function ID($ids = null): Response {
|
||||
throw new MethodNotSupportedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new folder (and parent folders if needed)
|
||||
* @param string $folder folder name
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function createFolder(string $folder): Response {
|
||||
return $this->response("imap_createmailbox")->wrap(function($response) use ($folder) {
|
||||
return \imap_createmailbox($this->stream, $this->getAddress() . $folder) ? [
|
||||
0 => "TAG" . $response->Noun() . " OK Create completed (0.004 + 0.000 + 0.003 secs).\r\n",
|
||||
] : [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename an existing folder
|
||||
* @param string $old old name
|
||||
* @param string $new new name
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function renameFolder(string $old, string $new): Response {
|
||||
return $this->response("imap_renamemailbox")->wrap(function($response) use ($old, $new) {
|
||||
return \imap_renamemailbox($this->stream, $this->getAddress() . $old, $this->getAddress() . $new) ? [
|
||||
0 => "TAG" . $response->Noun() . " OK Move completed (0.004 + 0.000 + 0.003 secs).\r\n",
|
||||
] : [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a folder
|
||||
* @param string $folder folder name
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function deleteFolder(string $folder): Response {
|
||||
return $this->response("imap_deletemailbox")->wrap(function($response) use ($folder) {
|
||||
return \imap_deletemailbox($this->stream, $this->getAddress() . $folder) ? [
|
||||
0 => "OK Delete completed (0.004 + 0.000 + 0.003 secs).\r\n",
|
||||
] : [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to a folder
|
||||
* @param string $folder folder name
|
||||
*
|
||||
* @throws MethodNotSupportedException
|
||||
*/
|
||||
public function subscribeFolder(string $folder): Response {
|
||||
throw new MethodNotSupportedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from a folder
|
||||
* @param string $folder folder name
|
||||
*
|
||||
* @throws MethodNotSupportedException
|
||||
*/
|
||||
public function unsubscribeFolder(string $folder): Response {
|
||||
throw new MethodNotSupportedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply session saved changes to the server
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function expunge(): Response {
|
||||
return $this->response("imap_expunge")->wrap(function($response) {
|
||||
return \imap_expunge($this->stream) ? [
|
||||
0 => "TAG" . $response->Noun() . " OK Expunge completed (0.001 + 0.000 secs).\r\n",
|
||||
] : [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send noop command
|
||||
*
|
||||
* @throws MethodNotSupportedException
|
||||
*/
|
||||
public function noop(): Response {
|
||||
throw new MethodNotSupportedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send idle command
|
||||
*
|
||||
* @throws MethodNotSupportedException
|
||||
*/
|
||||
public function idle() {
|
||||
throw new MethodNotSupportedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send done command
|
||||
*
|
||||
* @throws MethodNotSupportedException
|
||||
*/
|
||||
public function done() {
|
||||
throw new MethodNotSupportedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for matching messages
|
||||
* @param array $params
|
||||
* @param int|string $uid set to IMAP::ST_UID if you pass message unique identifiers instead of numbers.
|
||||
*
|
||||
* @return Response message ids
|
||||
*/
|
||||
public function search(array $params, int|string $uid = IMAP::ST_UID): Response {
|
||||
return $this->response("imap_search")->wrap(function($response) use ($params, $uid) {
|
||||
$response->setCanBeEmpty(true);
|
||||
$result = \imap_search($this->stream, $params[0], $uid ? IMAP::ST_UID : IMAP::NIL);
|
||||
return $result ?: [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the debug mode
|
||||
*/
|
||||
public function enableDebug() {
|
||||
$this->debug = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the debug mode
|
||||
*/
|
||||
public function disableDebug() {
|
||||
$this->debug = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode name.
|
||||
* It converts UTF7-IMAP encoding to UTF-8.
|
||||
*
|
||||
* @param $name
|
||||
*
|
||||
* @return array|false|string|string[]|null
|
||||
*/
|
||||
protected function decodeFolderName($name): array|bool|string|null {
|
||||
preg_match('#\{(.*)}(.*)#', $name, $preg);
|
||||
return mb_convert_encoding($preg[2], "UTF-8", "UTF7-IMAP");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getProtocol(): string {
|
||||
return $this->protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the quota level settings, and usage statics per mailbox
|
||||
* @param $username
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getQuota($username): Response {
|
||||
return $this->response("imap_get_quota")->wrap(function($response) use ($username) {
|
||||
$result = \imap_get_quota($this->stream, 'user.' . $username);
|
||||
return $result ?: [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the quota settings per user
|
||||
* @param string $quota_root
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getQuotaRoot(string $quota_root = 'INBOX'): Response {
|
||||
return $this->response("imap_get_quotaroot")->wrap(function($response) use ($quota_root) {
|
||||
$result = \imap_get_quotaroot($this->stream, $this->getAddress() . $quota_root);
|
||||
return $result ?: [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $protocol
|
||||
* @return LegacyProtocol
|
||||
*/
|
||||
public function setProtocol(string $protocol): LegacyProtocol {
|
||||
if (($pos = strpos($protocol, "legacy")) > 0) {
|
||||
$protocol = substr($protocol, 0, ($pos + 2) * -1);
|
||||
}
|
||||
$this->protocol = $protocol;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Response instance
|
||||
* @param string|null $command
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
protected function response(?string $command = ""): Response {
|
||||
return Response::make(0, $command == "" ? [] : [$command], [], $this->debug);
|
||||
}
|
||||
}
|
||||
417
plugins/vendor/webklex/php-imap/src/Connection/Protocols/Protocol.php
vendored
Normal file
417
plugins/vendor/webklex/php-imap/src/Connection/Protocols/Protocol.php
vendored
Normal file
@@ -0,0 +1,417 @@
|
||||
<?php
|
||||
/*
|
||||
* File: ImapProtocol.php
|
||||
* Category: Protocol
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 16.09.20 18:27
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Connection\Protocols;
|
||||
|
||||
use Webklex\PHPIMAP\Config;
|
||||
use Webklex\PHPIMAP\Exceptions\ConnectionFailedException;
|
||||
use Webklex\PHPIMAP\IMAP;
|
||||
|
||||
/**
|
||||
* Class Protocol
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Connection\Protocols
|
||||
*/
|
||||
abstract class Protocol implements ProtocolInterface {
|
||||
|
||||
/**
|
||||
* Default connection timeout in seconds
|
||||
*/
|
||||
protected int $connection_timeout = 30;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected bool $debug = false;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected bool $enable_uid_cache = true;
|
||||
|
||||
/**
|
||||
* @var resource|mixed|boolean|null $stream
|
||||
*/
|
||||
public $stream = false;
|
||||
|
||||
/**
|
||||
* @var Config $config
|
||||
*/
|
||||
protected Config $config;
|
||||
|
||||
/**
|
||||
* Connection encryption method
|
||||
* @var string $encryption
|
||||
*/
|
||||
protected string $encryption = "";
|
||||
|
||||
/**
|
||||
* Set to false to ignore SSL certificate validation
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $cert_validation = true;
|
||||
|
||||
/**
|
||||
* Proxy settings
|
||||
* @var array
|
||||
*/
|
||||
protected array $proxy = [
|
||||
'socket' => null,
|
||||
'request_fulluri' => false,
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
];
|
||||
|
||||
/**
|
||||
* SSL stream context options
|
||||
*
|
||||
* @see https://www.php.net/manual/en/context.ssl.php for possible options
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected array $ssl_options = [];
|
||||
|
||||
/**
|
||||
* Cache for uid of active folder.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected array $uid_cache = [];
|
||||
|
||||
/**
|
||||
* Get an available cryptographic method
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCryptoMethod(): int {
|
||||
// Allow the best TLS version(s) we can
|
||||
$cryptoMethod = STREAM_CRYPTO_METHOD_TLS_CLIENT;
|
||||
|
||||
// PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT
|
||||
// so add them back in manually if we can
|
||||
if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
|
||||
$cryptoMethod = STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
|
||||
}elseif (defined('STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT')) {
|
||||
$cryptoMethod = STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
|
||||
}
|
||||
|
||||
return $cryptoMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable SSL certificate validation
|
||||
*
|
||||
* @return Protocol
|
||||
*/
|
||||
public function enableCertValidation(): Protocol {
|
||||
$this->cert_validation = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable SSL certificate validation
|
||||
* @return Protocol
|
||||
*/
|
||||
public function disableCertValidation(): Protocol {
|
||||
$this->cert_validation = false;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SSL certificate validation
|
||||
* @var int $cert_validation
|
||||
*
|
||||
* @return Protocol
|
||||
*/
|
||||
public function setCertValidation(int $cert_validation): Protocol {
|
||||
$this->cert_validation = $cert_validation;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we validate SSL certificate?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getCertValidation(): bool {
|
||||
return $this->cert_validation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set connection proxy settings
|
||||
* @var array $options
|
||||
*
|
||||
* @return Protocol
|
||||
*/
|
||||
public function setProxy(array $options): Protocol {
|
||||
foreach ($this->proxy as $key => $val) {
|
||||
if (isset($options[$key])) {
|
||||
$this->proxy[$key] = $options[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current proxy settings
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getProxy(): array {
|
||||
return $this->proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SSL context options settings
|
||||
* @var array $options
|
||||
*
|
||||
* @return Protocol
|
||||
*/
|
||||
public function setSslOptions(array $options): Protocol
|
||||
{
|
||||
$this->ssl_options = $options;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current SSL context options settings
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSslOptions(): array {
|
||||
return $this->ssl_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare socket options
|
||||
* @return array
|
||||
*@var string $transport
|
||||
*
|
||||
*/
|
||||
private function defaultSocketOptions(string $transport): array {
|
||||
$options = [];
|
||||
if ($this->encryption) {
|
||||
$options["ssl"] = [
|
||||
'verify_peer_name' => $this->getCertValidation(),
|
||||
'verify_peer' => $this->getCertValidation(),
|
||||
];
|
||||
|
||||
if (count($this->ssl_options)) {
|
||||
/* Get the ssl context options from the config, but prioritize the 'validate_cert' config over the ssl context options */
|
||||
$options["ssl"] = array_replace($this->ssl_options, $options["ssl"]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->proxy["socket"] != null) {
|
||||
$options[$transport]["proxy"] = $this->proxy["socket"];
|
||||
$options[$transport]["request_fulluri"] = $this->proxy["request_fulluri"];
|
||||
|
||||
if ($this->proxy["username"] != null) {
|
||||
$auth = base64_encode($this->proxy["username"].':'.$this->proxy["password"]);
|
||||
|
||||
$options[$transport]["header"] = [
|
||||
"Proxy-Authorization: Basic $auth"
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new resource stream
|
||||
* @param $transport
|
||||
* @param string $host hostname or IP address of IMAP server
|
||||
* @param int $port of IMAP server, default is 143 (993 for ssl)
|
||||
* @param int $timeout timeout in seconds for initiating session
|
||||
*
|
||||
* @return resource The socket created.
|
||||
* @throws ConnectionFailedException
|
||||
*/
|
||||
public function createStream($transport, string $host, int $port, int $timeout) {
|
||||
$socket = "$transport://$host:$port";
|
||||
$stream = stream_socket_client($socket, $errno, $errstr, $timeout,
|
||||
STREAM_CLIENT_CONNECT,
|
||||
stream_context_create($this->defaultSocketOptions($transport))
|
||||
);
|
||||
|
||||
if (!$stream) {
|
||||
throw new ConnectionFailedException($errstr, $errno);
|
||||
}
|
||||
|
||||
if (false === stream_set_timeout($stream, $timeout)) {
|
||||
throw new ConnectionFailedException('Failed to set stream timeout');
|
||||
}
|
||||
|
||||
return $stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current connection timeout
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getConnectionTimeout(): int {
|
||||
return $this->connection_timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connection timeout
|
||||
* @param int $connection_timeout
|
||||
*
|
||||
* @return Protocol
|
||||
*/
|
||||
public function setConnectionTimeout(int $connection_timeout): Protocol {
|
||||
$this->connection_timeout = $connection_timeout;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the UID key string
|
||||
* @param int|string $uid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUIDKey(int|string $uid): string {
|
||||
if ($uid == IMAP::ST_UID || $uid == IMAP::FT_UID) {
|
||||
return "UID";
|
||||
}
|
||||
if (strlen($uid) > 0 && !is_numeric($uid)) {
|
||||
return (string)$uid;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a UID / MSGN command
|
||||
* @param string $command
|
||||
* @param int|string $uid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function buildUIDCommand(string $command, int|string $uid): string {
|
||||
return trim($this->getUIDKey($uid)." ".$command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the uid cache of current active folder
|
||||
*
|
||||
* @param array|null $uids
|
||||
*/
|
||||
public function setUidCache(?array $uids): void {
|
||||
if (is_null($uids)) {
|
||||
$this->uid_cache = [];
|
||||
return;
|
||||
}
|
||||
|
||||
$messageNumber = 1;
|
||||
|
||||
$uid_cache = [];
|
||||
foreach ($uids as $uid) {
|
||||
$uid_cache[$messageNumber++] = (int)$uid;
|
||||
}
|
||||
|
||||
$this->uid_cache = $uid_cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the uid cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enableUidCache(): void {
|
||||
$this->enable_uid_cache = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the uid cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function disableUidCache(): void {
|
||||
$this->enable_uid_cache = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the encryption method
|
||||
* @param string $encryption
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setEncryption(string $encryption): void {
|
||||
$this->encryption = $encryption;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the encryption method
|
||||
* @return string
|
||||
*/
|
||||
public function getEncryption(): string {
|
||||
return $this->encryption;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current session is connected
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function connected(): bool {
|
||||
return (bool)$this->stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves header/metadata from the resource stream
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function meta(): array {
|
||||
if (!$this->stream) {
|
||||
return [
|
||||
"crypto" => [
|
||||
"protocol" => "",
|
||||
"cipher_name" => "",
|
||||
"cipher_bits" => 0,
|
||||
"cipher_version" => "",
|
||||
],
|
||||
"timed_out" => true,
|
||||
"blocked" => true,
|
||||
"eof" => true,
|
||||
"stream_type" => "tcp_socket/unknown",
|
||||
"mode" => "c",
|
||||
"unread_bytes" => 0,
|
||||
"seekable" => false,
|
||||
];
|
||||
}
|
||||
return stream_get_meta_data($this->stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the resource stream
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getStream(): mixed {
|
||||
return $this->stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Config instance
|
||||
*
|
||||
* @return Config
|
||||
*/
|
||||
public function getConfig(): Config {
|
||||
return $this->config;
|
||||
}
|
||||
}
|
||||
458
plugins/vendor/webklex/php-imap/src/Connection/Protocols/ProtocolInterface.php
vendored
Normal file
458
plugins/vendor/webklex/php-imap/src/Connection/Protocols/ProtocolInterface.php
vendored
Normal file
@@ -0,0 +1,458 @@
|
||||
<?php
|
||||
/*
|
||||
* File: ImapProtocol.php
|
||||
* Category: Protocol
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 16.09.20 18:27
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Connection\Protocols;
|
||||
|
||||
use ErrorException;
|
||||
use Webklex\PHPIMAP\Exceptions\AuthFailedException;
|
||||
use Webklex\PHPIMAP\Exceptions\ConnectionFailedException;
|
||||
use Webklex\PHPIMAP\Exceptions\ImapBadRequestException;
|
||||
use Webklex\PHPIMAP\Exceptions\ImapServerErrorException;
|
||||
use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException;
|
||||
use Webklex\PHPIMAP\Exceptions\MessageNotFoundException;
|
||||
use Webklex\PHPIMAP\Exceptions\RuntimeException;
|
||||
use Webklex\PHPIMAP\IMAP;
|
||||
|
||||
/**
|
||||
* Interface ProtocolInterface
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Connection\Protocols
|
||||
*/
|
||||
interface ProtocolInterface {
|
||||
|
||||
/**
|
||||
* Public destructor
|
||||
*
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function __destruct();
|
||||
|
||||
/**
|
||||
* Open a new connection / session
|
||||
* @param string $host hostname or IP address of IMAP server
|
||||
* @param int|null $port of service server
|
||||
*
|
||||
* @throws ErrorException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function connect(string $host, ?int $port = null);
|
||||
|
||||
/**
|
||||
* Login to a new session.
|
||||
*
|
||||
* @param string $user username
|
||||
* @param string $password password
|
||||
*
|
||||
* @return Response
|
||||
*
|
||||
* @throws AuthFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
*/
|
||||
public function login(string $user, string $password): Response;
|
||||
|
||||
/**
|
||||
* Authenticate your current session.
|
||||
* @param string $user username
|
||||
* @param string $token access token
|
||||
*
|
||||
* @return Response
|
||||
* @throws AuthFailedException
|
||||
*/
|
||||
public function authenticate(string $user, string $token): Response;
|
||||
|
||||
/**
|
||||
* Logout of the current server session
|
||||
*
|
||||
* @return Response
|
||||
*
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function logout(): Response;
|
||||
|
||||
/**
|
||||
* Check if the current session is connected
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function connected(): bool;
|
||||
|
||||
/**
|
||||
* Get an array of available capabilities
|
||||
*
|
||||
* @return Response containing a list of capabilities
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getCapabilities(): Response;
|
||||
|
||||
/**
|
||||
* Change the current folder
|
||||
* @param string $folder change to this folder
|
||||
*
|
||||
* @return Response see examineOrSelect()
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function selectFolder(string $folder = 'INBOX'): Response;
|
||||
|
||||
/**
|
||||
* Examine a given folder
|
||||
* @param string $folder
|
||||
*
|
||||
* @return Response
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function examineFolder(string $folder = 'INBOX'): Response;
|
||||
|
||||
/**
|
||||
* Get the status of a given folder
|
||||
*
|
||||
* @return Response list of STATUS items
|
||||
*
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function folderStatus(string $folder = 'INBOX', $arguments = ['MESSAGES', 'UNSEEN', 'RECENT', 'UIDNEXT', 'UIDVALIDITY']): Response;
|
||||
|
||||
/**
|
||||
* Fetch message contents
|
||||
* @param int|array $uids
|
||||
* @param string $rfc
|
||||
* @param int|string $uid set to IMAP::ST_UID or any string representing the UID - set to IMAP::ST_MSGN to use
|
||||
* message numbers instead.
|
||||
*
|
||||
* @return Response
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function content(int|array $uids, string $rfc = "RFC822", int|string $uid = IMAP::ST_UID): Response;
|
||||
|
||||
/**
|
||||
* Fetch message headers
|
||||
* @param int|array $uids
|
||||
* @param string $rfc
|
||||
* @param int|string $uid set to IMAP::ST_UID or any string representing the UID - set to IMAP::ST_MSGN to use
|
||||
* message numbers instead.
|
||||
*
|
||||
* @return Response
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function headers(int|array $uids, string $rfc = "RFC822", int|string $uid = IMAP::ST_UID): Response;
|
||||
|
||||
/**
|
||||
* Fetch message flags
|
||||
* @param int|array $uids
|
||||
* @param int|string $uid set to IMAP::ST_UID or any string representing the UID - set to IMAP::ST_MSGN to use
|
||||
* message numbers instead.
|
||||
*
|
||||
* @return Response
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function flags(int|array $uids, int|string $uid = IMAP::ST_UID): Response;
|
||||
|
||||
/**
|
||||
* Fetch message sizes
|
||||
* @param int|array $uids
|
||||
* @param int|string $uid set to IMAP::ST_UID or any string representing the UID - set to IMAP::ST_MSGN to use
|
||||
* message numbers instead.
|
||||
*
|
||||
* @return Response
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function sizes(int|array $uids, int|string $uid = IMAP::ST_UID): Response;
|
||||
|
||||
/**
|
||||
* Get uid for a given id
|
||||
* @param int|null $id message number
|
||||
*
|
||||
* @return Response containing a message number for given message or all messages as array
|
||||
* @throws MessageNotFoundException
|
||||
*/
|
||||
public function getUid(?int $id = null): Response;
|
||||
|
||||
/**
|
||||
* Get a message number for a uid
|
||||
* @param string $id uid
|
||||
*
|
||||
* @return Response containing the message number
|
||||
* @throws MessageNotFoundException
|
||||
*/
|
||||
public function getMessageNumber(string $id): Response;
|
||||
|
||||
/**
|
||||
* Get a list of available folders
|
||||
* @param string $reference mailbox reference for list
|
||||
* @param string $folder mailbox / folder name match with wildcards
|
||||
*
|
||||
* @return Response containing mailboxes that matched $folder as array(globalName => array('delim' => .., 'flags' => ..))
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function folders(string $reference = '', string $folder = '*'): Response;
|
||||
|
||||
/**
|
||||
* Set message flags
|
||||
* @param array|string $flags flags to set, add or remove
|
||||
* @param int $from message for items or start message if $to !== null
|
||||
* @param int|null $to if null only one message ($from) is fetched, else it's the
|
||||
* last message, INF means last message available
|
||||
* @param string|null $mode '+' to add flags, '-' to remove flags, everything else sets the flags as given
|
||||
* @param bool $silent if false the return values are the new flags for the wanted messages
|
||||
* @param int|string $uid set to IMAP::ST_UID or any string representing the UID - set to IMAP::ST_MSGN to use
|
||||
* message numbers instead.
|
||||
* @param string|null $item command used to store a flag
|
||||
*
|
||||
* @return Response containing the new flags if $silent is false, else true or false depending on success
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function store(array|string $flags, int $from, ?int $to = null, ?string $mode = null, bool $silent = true, int|string $uid = IMAP::ST_UID, ?string $item = null): Response;
|
||||
|
||||
/**
|
||||
* Append a new message to given folder
|
||||
* @param string $folder name of target folder
|
||||
* @param string $message full message content
|
||||
* @param array|null $flags flags for new message
|
||||
* @param string|null $date date for new message
|
||||
*
|
||||
* @return Response
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function appendMessage(string $folder, string $message, ?array $flags = null, ?string $date = null): Response;
|
||||
|
||||
/**
|
||||
* Copy message set from current folder to other folder
|
||||
*
|
||||
* @param string $folder destination folder
|
||||
* @param $from
|
||||
* @param int|null $to if null only one message ($from) is fetched, else it's the
|
||||
* last message, INF means last message available
|
||||
* @param int|string $uid set to IMAP::ST_UID or any string representing the UID - set to IMAP::ST_MSGN to use
|
||||
* message numbers instead.
|
||||
*
|
||||
* @return Response
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function copyMessage(string $folder, $from, ?int $to = null, int|string $uid = IMAP::ST_UID): Response;
|
||||
|
||||
/**
|
||||
* Copy multiple messages to the target folder
|
||||
* @param array<string> $messages List of message identifiers
|
||||
* @param string $folder Destination folder
|
||||
* @param int|string $uid set to IMAP::ST_UID or any string representing the UID - set to IMAP::ST_MSGN to use
|
||||
* message numbers instead.
|
||||
*
|
||||
* @return Response Tokens if operation successful, false if an error occurred
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function copyManyMessages(array $messages, string $folder, int|string $uid = IMAP::ST_UID): Response;
|
||||
|
||||
/**
|
||||
* Move a message set from current folder to another folder
|
||||
* @param string $folder destination folder
|
||||
* @param $from
|
||||
* @param int|null $to if null only one message ($from) is fetched, else it's the
|
||||
* last message, INF means last message available
|
||||
* @param int|string $uid set to IMAP::ST_UID or any string representing the UID - set to IMAP::ST_MSGN to use
|
||||
* message numbers instead.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function moveMessage(string $folder, $from, ?int $to = null, int|string $uid = IMAP::ST_UID): Response;
|
||||
|
||||
/**
|
||||
* Move multiple messages to the target folder
|
||||
*
|
||||
* @param array<string> $messages List of message identifiers
|
||||
* @param string $folder Destination folder
|
||||
* @param int|string $uid set to IMAP::ST_UID or any string representing the UID - set to IMAP::ST_MSGN to use
|
||||
* message numbers instead.
|
||||
*
|
||||
* @return Response Tokens if operation successful, false if an error occurred
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function moveManyMessages(array $messages, string $folder, int|string $uid = IMAP::ST_UID): Response;
|
||||
|
||||
/**
|
||||
* Exchange identification information
|
||||
* Ref.: https://datatracker.ietf.org/doc/html/rfc2971
|
||||
*
|
||||
* @param null $ids
|
||||
* @return Response
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function ID($ids = null): Response;
|
||||
|
||||
/**
|
||||
* Create a new folder
|
||||
*
|
||||
* @param string $folder folder name
|
||||
* @return Response
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function createFolder(string $folder): Response;
|
||||
|
||||
/**
|
||||
* Rename an existing folder
|
||||
*
|
||||
* @param string $old old name
|
||||
* @param string $new new name
|
||||
* @return Response
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function renameFolder(string $old, string $new): Response;
|
||||
|
||||
/**
|
||||
* Delete a folder
|
||||
*
|
||||
* @param string $folder folder name
|
||||
* @return Response
|
||||
*
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function deleteFolder(string $folder): Response;
|
||||
|
||||
/**
|
||||
* Subscribe to a folder
|
||||
*
|
||||
* @param string $folder folder name
|
||||
* @return Response
|
||||
*
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function subscribeFolder(string $folder): Response;
|
||||
|
||||
/**
|
||||
* Unsubscribe from a folder
|
||||
*
|
||||
* @param string $folder folder name
|
||||
* @return Response
|
||||
*
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function unsubscribeFolder(string $folder): Response;
|
||||
|
||||
/**
|
||||
* Send idle command
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function idle();
|
||||
|
||||
/**
|
||||
* Send done command
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function done();
|
||||
|
||||
/**
|
||||
* Apply session saved changes to the server
|
||||
*
|
||||
* @return Response
|
||||
*
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function expunge(): Response;
|
||||
|
||||
/**
|
||||
* Retrieve the quota level settings, and usage statics per mailbox
|
||||
* @param $username
|
||||
*
|
||||
* @return Response
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getQuota($username): Response;
|
||||
|
||||
/**
|
||||
* Retrieve the quota settings per user
|
||||
*
|
||||
* @param string $quota_root
|
||||
*
|
||||
* @return Response
|
||||
* @throws ConnectionFailedException
|
||||
*/
|
||||
public function getQuotaRoot(string $quota_root = 'INBOX'): Response;
|
||||
|
||||
/**
|
||||
* Send noop command
|
||||
*
|
||||
* @return Response
|
||||
*
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function noop(): Response;
|
||||
|
||||
/**
|
||||
* Do a search request
|
||||
*
|
||||
* @param array $params
|
||||
* @param int|string $uid set to IMAP::ST_UID or any string representing the UID - set to IMAP::ST_MSGN to use
|
||||
* message numbers instead.
|
||||
*
|
||||
* @return Response containing the message ids
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function search(array $params, int|string $uid = IMAP::ST_UID): Response;
|
||||
|
||||
/**
|
||||
* Get a message overview
|
||||
* @param string $sequence uid sequence
|
||||
* @param int|string $uid set to IMAP::ST_UID or any string representing the UID - set to IMAP::ST_MSGN to use
|
||||
* message numbers instead.
|
||||
*
|
||||
* @return Response
|
||||
* @throws RuntimeException
|
||||
* @throws MessageNotFoundException
|
||||
* @throws InvalidMessageDateException
|
||||
*/
|
||||
public function overview(string $sequence, int|string $uid = IMAP::ST_UID): Response;
|
||||
|
||||
/**
|
||||
* Enable the debug mode
|
||||
*/
|
||||
public function enableDebug();
|
||||
|
||||
/**
|
||||
* Disable the debug mode
|
||||
*/
|
||||
public function disableDebug();
|
||||
|
||||
/**
|
||||
* Enable uid caching
|
||||
*/
|
||||
public function enableUidCache();
|
||||
|
||||
/**
|
||||
* Disable uid caching
|
||||
*/
|
||||
public function disableUidCache();
|
||||
|
||||
/**
|
||||
* Set the uid cache of current active folder
|
||||
*
|
||||
* @param array|null $uids
|
||||
*/
|
||||
public function setUidCache(?array $uids);
|
||||
}
|
||||
417
plugins/vendor/webklex/php-imap/src/Connection/Protocols/Response.php
vendored
Normal file
417
plugins/vendor/webklex/php-imap/src/Connection/Protocols/Response.php
vendored
Normal file
@@ -0,0 +1,417 @@
|
||||
<?php
|
||||
/*
|
||||
* File: Response.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 30.12.22 19:46
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
|
||||
namespace Webklex\PHPIMAP\Connection\Protocols;
|
||||
|
||||
use Webklex\PHPIMAP\Exceptions\ResponseException;
|
||||
|
||||
/**
|
||||
* Class Response
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Connection\Protocols
|
||||
*/
|
||||
class Response {
|
||||
|
||||
/**
|
||||
* The commands used to fetch or manipulate data
|
||||
* @var array $command
|
||||
*/
|
||||
protected array $commands = [];
|
||||
|
||||
/**
|
||||
* The original response received
|
||||
* @var array $response
|
||||
*/
|
||||
protected array $response = [];
|
||||
|
||||
/**
|
||||
* Errors that have occurred while fetching or parsing the response
|
||||
* @var array $errors
|
||||
*/
|
||||
protected array $errors = [];
|
||||
|
||||
/**
|
||||
* Result to be returned
|
||||
* @var mixed|null $result
|
||||
*/
|
||||
protected mixed $result = null;
|
||||
|
||||
/**
|
||||
* Noun to identify the request / response
|
||||
* @var int $noun
|
||||
*/
|
||||
protected int $noun = 0;
|
||||
|
||||
/**
|
||||
* Other related responses
|
||||
* @var array $response_stack
|
||||
*/
|
||||
protected array $response_stack = [];
|
||||
|
||||
/**
|
||||
* Debug flag
|
||||
* @var bool $debug
|
||||
*/
|
||||
protected bool $debug = false;
|
||||
|
||||
/**
|
||||
* Can the response be empty?
|
||||
* @var bool $can_be_empty
|
||||
*/
|
||||
protected bool $can_be_empty = false;
|
||||
|
||||
/**
|
||||
* Create a new Response instance
|
||||
*/
|
||||
public function __construct(int $noun, bool $debug = false) {
|
||||
$this->debug = $debug;
|
||||
$this->noun = $noun > 0 ? $noun : (int)str_replace(".", "", (string)microtime(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new response instance
|
||||
* @param int $noun
|
||||
* @param array $commands
|
||||
* @param array $responses
|
||||
* @param bool $debug
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public static function make(int $noun, array $commands = [], array $responses = [], bool $debug = false): Response {
|
||||
return (new self($noun, $debug))->setCommands($commands)->setResponse($responses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new empty response
|
||||
* @param bool $debug
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public static function empty(bool $debug = false): Response {
|
||||
return (new self(0, $debug));
|
||||
}
|
||||
|
||||
/**
|
||||
* Stack another response
|
||||
* @param Response $response
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function stack(Response $response): void {
|
||||
$this->response_stack[] = $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the associated response stack
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getStack(): array {
|
||||
return $this->response_stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all assigned commands
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCommands(): array {
|
||||
return $this->commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new command
|
||||
* @param string $command
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function addCommand(string $command): Response {
|
||||
$this->commands[] = $command;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set and overwrite all commands
|
||||
* @param array $commands
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function setCommands(array $commands): Response {
|
||||
$this->commands = $commands;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all set errors
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getErrors(): array {
|
||||
$errors = $this->errors;
|
||||
foreach($this->getStack() as $response) {
|
||||
$errors = array_merge($errors, $response->getErrors());
|
||||
}
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set and overwrite all existing errors
|
||||
* @param array $errors
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function setErrors(array $errors): Response {
|
||||
$this->errors = $errors;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the response
|
||||
* @param string $error
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function addError(string $error): Response {
|
||||
$this->errors[] = $error;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the response
|
||||
* @param array $response
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function addResponse(mixed $response): Response {
|
||||
$this->response[] = $response;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the response
|
||||
* @param array $response
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function setResponse(array $response): Response {
|
||||
$this->response = $response;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the assigned response
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getResponse(): array {
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the result data
|
||||
* @param mixed $result
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function setResult(mixed $result): Response {
|
||||
$this->result = $result;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a result bearing action
|
||||
* @param callable $callback
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function wrap(callable $callback): Response {
|
||||
$this->result = call_user_func($callback, $this);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response data
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function data(): mixed {
|
||||
if ($this->result !== null) {
|
||||
return $this->result;
|
||||
}
|
||||
return $this->getResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response data as array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function array(): array {
|
||||
$data = $this->data();
|
||||
if(is_array($data)){
|
||||
return $data;
|
||||
}
|
||||
return [$data];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response data as string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function string(): string {
|
||||
$data = $this->data();
|
||||
if(is_array($data)){
|
||||
return implode(" ", $data);
|
||||
}
|
||||
return (string)$data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response data as integer
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function integer(): int {
|
||||
$data = $this->data();
|
||||
if(is_array($data) && isset($data[0])){
|
||||
return (int)$data[0];
|
||||
}
|
||||
return (int)$data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response data as boolean
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function boolean(): bool {
|
||||
return (bool)$this->data();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate and retrieve the response data
|
||||
*
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function validatedData(): mixed {
|
||||
return $this->validate()->data();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the response date
|
||||
*
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function validate(): Response {
|
||||
if ($this->failed()) {
|
||||
throw ResponseException::make($this, $this->debug);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Response can be considered successful
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function successful(): bool {
|
||||
foreach(array_merge($this->getResponse(), $this->array()) as $data) {
|
||||
if (!$this->verify_data($data)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
foreach($this->getStack() as $response) {
|
||||
if (!$response->successful()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return ($this->boolean() || $this->canBeEmpty()) && !$this->getErrors();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the Response can be considered failed
|
||||
* @param mixed $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function verify_data(mixed $data): bool {
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $line) {
|
||||
if (is_array($line)) {
|
||||
if(!$this->verify_data($line)){
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
if (!$this->verify_line((string)$line)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if (!$this->verify_line((string)$data)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a single line
|
||||
* @param string $line
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function verify_line(string $line): bool {
|
||||
return !str_starts_with($line, "TAG".$this->noun." BAD ") && !str_starts_with($line, "TAG".$this->noun." NO ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Response can be considered failed
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function failed(): bool {
|
||||
return !$this->successful();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Response noun
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function Noun(): int {
|
||||
return $this->noun;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Response to be allowed to be empty
|
||||
* @param bool $can_be_empty
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setCanBeEmpty(bool $can_be_empty): Response {
|
||||
$this->can_be_empty = $can_be_empty;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Response can be empty
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canBeEmpty(): bool {
|
||||
return $this->can_be_empty;
|
||||
}
|
||||
}
|
||||
25
plugins/vendor/webklex/php-imap/src/Decoder/AttachmentDecoder.php
vendored
Normal file
25
plugins/vendor/webklex/php-imap/src/Decoder/AttachmentDecoder.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/*
|
||||
* File: AttachmentDecoder.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 12.04.24 20:14
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Decoder;
|
||||
|
||||
use Exception;
|
||||
use Webklex\PHPIMAP\EncodingAliases;
|
||||
use Webklex\PHPIMAP\IMAP;
|
||||
|
||||
/**
|
||||
* Class AttachmentDecoder
|
||||
*
|
||||
* @package Webklex\PHPIMAP
|
||||
*/
|
||||
class AttachmentDecoder extends MessageDecoder {
|
||||
}
|
||||
161
plugins/vendor/webklex/php-imap/src/Decoder/Decoder.php
vendored
Normal file
161
plugins/vendor/webklex/php-imap/src/Decoder/Decoder.php
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
/*
|
||||
* File: Decoder.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 12.04.24 20:14
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Decoder;
|
||||
|
||||
use Webklex\PHPIMAP\EncodingAliases;
|
||||
|
||||
/**
|
||||
* Class Decoder
|
||||
*
|
||||
* @package Webklex\PHPIMAP
|
||||
*/
|
||||
abstract class Decoder implements DecoderInterface {
|
||||
|
||||
/**
|
||||
* Decoder constructor.
|
||||
* @param array $options Decoder options
|
||||
* @param string $fallback_encoding Fallback encoding
|
||||
*/
|
||||
public function __construct(
|
||||
/**
|
||||
* Options
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected array $options = [],
|
||||
|
||||
/**
|
||||
* Fallback Encoding
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected string $fallback_encoding = 'UTF-8',
|
||||
) {
|
||||
$this->options = array_merge([
|
||||
'header' => 'utf-8',
|
||||
'message' => 'utf-8',
|
||||
'attachment' => 'utf-8',
|
||||
], $this->options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a given value
|
||||
* @param array|string|null $value
|
||||
* @param string|null $encoding
|
||||
* @return mixed
|
||||
*/
|
||||
public function decode(array|string|null $value, ?string $encoding = null): mixed {
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the encoding
|
||||
* @param string $str The string to convert
|
||||
* @param string $from The source encoding
|
||||
* @param string $to The target encoding
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function convertEncoding(string $str, string $from = "ISO-8859-2", string $to = "UTF-8"): mixed {
|
||||
$from = EncodingAliases::get($from, $this->fallback_encoding);
|
||||
$to = EncodingAliases::get($to, $this->fallback_encoding);
|
||||
|
||||
if ($from === $to) {
|
||||
return $str;
|
||||
}
|
||||
|
||||
return EncodingAliases::convert($str, $from, $to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode MIME header elements
|
||||
* @link https://php.net/manual/en/function.imap-mime-header-decode.php
|
||||
* @param string $text The MIME text
|
||||
*
|
||||
* @return array<int,object> Returns an array of objects. Each *object has two properties, charset and text.
|
||||
*/
|
||||
public function mimeHeaderDecode(string $text): array {
|
||||
if (extension_loaded('imap')) {
|
||||
$result = \imap_mime_header_decode($text);
|
||||
return is_array($result) ? $result : [];
|
||||
}
|
||||
$charset = $this->getEncoding($text);
|
||||
return [(object)[
|
||||
"charset" => $charset,
|
||||
"text" => $this->convertEncoding($text, $charset)
|
||||
]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a given value is utf-8 encoded
|
||||
* @param $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isUTF8($value): bool {
|
||||
return str_starts_with(strtolower($value), '=?utf-8?');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given pair of strings has been decoded
|
||||
* @param $encoded
|
||||
* @param $decoded
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function notDecoded($encoded, $decoded): bool {
|
||||
return str_starts_with($decoded, '=?')
|
||||
&& strlen($decoded) - 2 === strpos($decoded, '?=')
|
||||
&& str_contains($encoded, $decoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the configuration used for decoding
|
||||
* @param array $config
|
||||
*
|
||||
* @return Decoder
|
||||
*/
|
||||
public function setOptions(array $config): static {
|
||||
$this->options = $config;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configuration used for decoding
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions(): array {
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fallback encoding
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFallbackEncoding(): string {
|
||||
return $this->fallback_encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the fallback encoding
|
||||
*
|
||||
* @param string $fallback_encoding
|
||||
* @return Decoder
|
||||
*/
|
||||
public function setFallbackEncoding(string $fallback_encoding): static {
|
||||
$this->fallback_encoding = $fallback_encoding;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
52
plugins/vendor/webklex/php-imap/src/Decoder/DecoderInterface.php
vendored
Normal file
52
plugins/vendor/webklex/php-imap/src/Decoder/DecoderInterface.php
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/*
|
||||
* File: DecoderInterface.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 12.04.24 20:25
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Decoder;
|
||||
|
||||
/**
|
||||
* Interface DecoderInterface
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Decoder
|
||||
*/
|
||||
interface DecoderInterface {
|
||||
|
||||
/**
|
||||
* DecoderInterface constructor.
|
||||
* @param array $options
|
||||
* @param string $fallback_encoding
|
||||
*/
|
||||
public function __construct(array $options = [], string $fallback_encoding = 'UTF-8');
|
||||
|
||||
/**
|
||||
* Decode a given value
|
||||
*
|
||||
* @param array|string|null $value
|
||||
* @param string|null $encoding
|
||||
* @return string|array|null
|
||||
*/
|
||||
public function decode(array|string|null $value, ?string $encoding = null): mixed;
|
||||
|
||||
public function mimeHeaderDecode(string $text): array;
|
||||
|
||||
public function convertEncoding(string $str, string $from = "ISO-8859-2", string $to = "UTF-8"): mixed;
|
||||
|
||||
public function getEncoding(object|string $structure): string;
|
||||
|
||||
public function getOptions(): array;
|
||||
|
||||
public function setOptions(array $config): static;
|
||||
|
||||
public function getFallbackEncoding(): string;
|
||||
|
||||
public function setFallbackEncoding(string $fallback_encoding): static;
|
||||
|
||||
}
|
||||
98
plugins/vendor/webklex/php-imap/src/Decoder/HeaderDecoder.php
vendored
Normal file
98
plugins/vendor/webklex/php-imap/src/Decoder/HeaderDecoder.php
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/*
|
||||
* File: Decoder.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 12.04.24 20:14
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Decoder;
|
||||
|
||||
use Webklex\PHPIMAP\EncodingAliases;
|
||||
|
||||
/**
|
||||
* Class HeaderDecoder
|
||||
*
|
||||
* @package Webklex\PHPIMAP
|
||||
*/
|
||||
class HeaderDecoder extends Decoder {
|
||||
|
||||
public function decode(array|string|null $value, ?string $encoding = null): mixed {
|
||||
if (is_array($value)) {
|
||||
return $this->decodeHeaderArray($value);
|
||||
}
|
||||
$original_value = $value;
|
||||
$decoder = $this->options['header'];
|
||||
|
||||
if ($value !== null) {
|
||||
if ($decoder === 'utf-8') {
|
||||
$decoded_values = $this->mimeHeaderDecode($value);
|
||||
$tempValue = "";
|
||||
foreach ($decoded_values as $decoded_value) {
|
||||
$tempValue .= $this->convertEncoding($decoded_value->text, $decoded_value->charset);
|
||||
}
|
||||
if ($tempValue) {
|
||||
$value = $tempValue;
|
||||
} else if (extension_loaded('imap')) {
|
||||
$value = \imap_utf8($value);
|
||||
} else if (function_exists('iconv_mime_decode')) {
|
||||
$value = iconv_mime_decode($value, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, "UTF-8");
|
||||
} else {
|
||||
$value = mb_decode_mimeheader($value);
|
||||
}
|
||||
} elseif ($decoder === 'iconv') {
|
||||
$value = iconv_mime_decode($value, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, "UTF-8");
|
||||
} else if (self::isUTF8($value)) {
|
||||
$value = mb_decode_mimeheader($value);
|
||||
}
|
||||
|
||||
if (self::notDecoded($original_value, $value)) {
|
||||
$value = $this->convertEncoding($original_value, $this->getEncoding($original_value));
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 == "default" ? EncodingAliases::detectEncoding($parameter->value) : $parameter->value, $this->fallback_encoding);
|
||||
}
|
||||
}
|
||||
} elseif (property_exists($structure, 'charset')) {
|
||||
return EncodingAliases::get($structure->charset == "default" ? EncodingAliases::detectEncoding($structure->charset) : $structure->charset, $this->fallback_encoding);
|
||||
} elseif (is_string($structure) === true) {
|
||||
$result = mb_detect_encoding($structure);
|
||||
return $result === false ? $this->fallback_encoding : $result;
|
||||
}
|
||||
|
||||
return $this->fallback_encoding;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decode a given array
|
||||
* @param array $values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function decodeHeaderArray(array $values): array {
|
||||
foreach ($values as $key => $value) {
|
||||
$values[$key] = $this->decode($value);
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
}
|
||||
119
plugins/vendor/webklex/php-imap/src/Decoder/MessageDecoder.php
vendored
Normal file
119
plugins/vendor/webklex/php-imap/src/Decoder/MessageDecoder.php
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MessageDecoder.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 12.04.24 20:14
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Decoder;
|
||||
|
||||
use Exception;
|
||||
use Webklex\PHPIMAP\EncodingAliases;
|
||||
use Webklex\PHPIMAP\IMAP;
|
||||
|
||||
/**
|
||||
* Class MessageDecoder
|
||||
*
|
||||
* @package Webklex\PHPIMAP
|
||||
*/
|
||||
class MessageDecoder extends Decoder {
|
||||
|
||||
public function decode(array|string|null $value, ?string $encoding = null): mixed {
|
||||
if(is_array($value)) {
|
||||
return array_map(function($item){
|
||||
return $this->decode($item);
|
||||
}, $value);
|
||||
}
|
||||
|
||||
switch ($encoding) {
|
||||
case IMAP::MESSAGE_ENC_BINARY:
|
||||
if (extension_loaded('imap')) {
|
||||
return base64_decode(\imap_binary($value));
|
||||
}
|
||||
return base64_decode($value);
|
||||
case IMAP::MESSAGE_ENC_BASE64:
|
||||
return base64_decode($value);
|
||||
case IMAP::MESSAGE_ENC_QUOTED_PRINTABLE:
|
||||
return quoted_printable_decode($value);
|
||||
case IMAP::MESSAGE_ENC_8BIT:
|
||||
case IMAP::MESSAGE_ENC_7BIT:
|
||||
case IMAP::MESSAGE_ENC_OTHER:
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 $this->fallback_encoding;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the encoding
|
||||
* @param $str
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function convertEncoding($str, string $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) {
|
||||
return @iconv($from, $to, $str);
|
||||
}
|
||||
} else {
|
||||
if (!$from) {
|
||||
return mb_convert_encoding($str, $to);
|
||||
}
|
||||
return mb_convert_encoding($str, $to, $from);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
591
plugins/vendor/webklex/php-imap/src/EncodingAliases.php
vendored
Normal file
591
plugins/vendor/webklex/php-imap/src/EncodingAliases.php
vendored
Normal file
@@ -0,0 +1,591 @@
|
||||
<?php
|
||||
/*
|
||||
* File: EncodingAliases.php
|
||||
* Category: -
|
||||
* Author: S. Todorov (https://github.com/todorowww)
|
||||
* Created: 23.04.18 14:16
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* Contains email encoding aliases, thta can occur when fetching emails. These sometimes can break icvon()
|
||||
* This file attempts to correct this by using a list of aliases and their mappings to supported iconv() encodings
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP;
|
||||
|
||||
/**
|
||||
* Class EncodingAliases
|
||||
*
|
||||
* @package Webklex\PHPIMAP
|
||||
*/
|
||||
class EncodingAliases {
|
||||
|
||||
/**
|
||||
* Contains email encoding mappings
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static array $aliases = [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Email encoding aliases
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Email encoding aliases used to convert to iconv supported charsets
|
||||
|
|
||||
|
|
||||
| This Source Code Form is subject to the terms of the Mozilla Public
|
||||
| License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
| file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
|
||||
| This Original Code has been modified by IBM Corporation.
|
||||
| Modifications made by IBM described herein are
|
||||
| Copyright (c) International Business Machines
|
||||
| Corporation, 1999
|
||||
|
|
||||
| Modifications to Mozilla code or documentation
|
||||
| identified per MPL Section 3.3
|
||||
|
|
||||
| Date Modified by Description of modification
|
||||
| 12/09/1999 IBM Corp. Support for IBM codepages - 850,852,855,857,862,864
|
||||
|
|
||||
| Rule of this file:
|
||||
| 1. key should always be in lower case ascii so we can do case insensitive
|
||||
| comparison in the code faster.
|
||||
| 2. value should be the one used in unicode converter
|
||||
|
|
||||
| 3. If the charset is not used for document charset, but font charset
|
||||
| (e.g. XLFD charset- such as JIS x0201, JIS x0208), don't put here
|
||||
|
|
||||
*/
|
||||
"ascii" => "us-ascii",
|
||||
"us-ascii" => "us-ascii",
|
||||
"ansi_x3.4-1968" => "us-ascii",
|
||||
"646" => "us-ascii",
|
||||
"iso-8859-1" => "ISO-8859-1",
|
||||
"iso-8859-2" => "ISO-8859-2",
|
||||
"iso-8859-3" => "ISO-8859-3",
|
||||
"iso-8859-4" => "ISO-8859-4",
|
||||
"iso-8859-5" => "ISO-8859-5",
|
||||
"iso-8859-6" => "ISO-8859-6",
|
||||
"iso-8859-6-i" => "ISO-8859-6-I",
|
||||
"iso-8859-6-e" => "ISO-8859-6-E",
|
||||
"iso-8859-7" => "ISO-8859-7",
|
||||
"iso-8859-8" => "ISO-8859-8",
|
||||
"iso-8859-8-i" => "ISO-8859-8-I",
|
||||
"iso-8859-8-e" => "ISO-8859-8-E",
|
||||
"iso-8859-9" => "ISO-8859-9",
|
||||
"iso-8859-10" => "ISO-8859-10",
|
||||
"iso-8859-11" => "ISO-8859-11",
|
||||
"iso-8859-13" => "ISO-8859-13",
|
||||
"iso-8859-14" => "ISO-8859-14",
|
||||
"iso-8859-15" => "ISO-8859-15",
|
||||
"iso-8859-16" => "ISO-8859-16",
|
||||
"iso-ir-111" => "ISO-IR-111",
|
||||
"iso-2022-cn" => "ISO-2022-CN",
|
||||
"iso-2022-cn-ext" => "ISO-2022-CN",
|
||||
"iso-2022-kr" => "ISO-2022-KR",
|
||||
"iso-2022-jp" => "ISO-2022-JP",
|
||||
"utf-16be" => "UTF-16BE",
|
||||
"utf-16le" => "UTF-16LE",
|
||||
"utf-16" => "UTF-16",
|
||||
"windows-1250" => "windows-1250",
|
||||
"windows-1251" => "windows-1251",
|
||||
"windows-1252" => "windows-1252",
|
||||
"windows-1253" => "windows-1253",
|
||||
"windows-1254" => "windows-1254",
|
||||
"windows-1255" => "windows-1255",
|
||||
"windows-1256" => "windows-1256",
|
||||
"windows-1257" => "windows-1257",
|
||||
"windows-1258" => "windows-1258",
|
||||
"ibm866" => "IBM866",
|
||||
"ibm850" => "IBM850",
|
||||
"ibm852" => "IBM852",
|
||||
"ibm855" => "IBM855",
|
||||
"ibm857" => "IBM857",
|
||||
"ibm862" => "IBM862",
|
||||
"ibm864" => "IBM864",
|
||||
"utf-8" => "UTF-8",
|
||||
"utf-7" => "UTF-7",
|
||||
"utf-7-imap" => "UTF7-IMAP",
|
||||
"utf7-imap" => "UTF7-IMAP",
|
||||
"shift_jis" => "Shift_JIS",
|
||||
"big5" => "Big5",
|
||||
"euc-jp" => "EUC-JP",
|
||||
"euc-kr" => "EUC-KR",
|
||||
"gb2312" => "GB2312",
|
||||
"gb18030" => "gb18030",
|
||||
"viscii" => "VISCII",
|
||||
"koi8-r" => "KOI8-R",
|
||||
"koi8_r" => "KOI8-R",
|
||||
"cskoi8r" => "KOI8-R",
|
||||
"koi" => "KOI8-R",
|
||||
"koi8" => "KOI8-R",
|
||||
"koi8-u" => "KOI8-U",
|
||||
"tis-620" => "TIS-620",
|
||||
"t.61-8bit" => "T.61-8bit",
|
||||
"hz-gb-2312" => "HZ-GB-2312",
|
||||
"big5-hkscs" => "Big5-HKSCS",
|
||||
"gbk" => "gbk",
|
||||
"cns11643" => "x-euc-tw",
|
||||
//
|
||||
// Aliases for ISO-8859-1
|
||||
//
|
||||
"latin1" => "ISO-8859-1",
|
||||
"iso_8859-1" => "ISO-8859-1",
|
||||
"iso8859-1" => "ISO-8859-1",
|
||||
"iso8859-2" => "ISO-8859-2",
|
||||
"iso8859-3" => "ISO-8859-3",
|
||||
"iso8859-4" => "ISO-8859-4",
|
||||
"iso8859-5" => "ISO-8859-5",
|
||||
"iso8859-6" => "ISO-8859-6",
|
||||
"iso8859-7" => "ISO-8859-7",
|
||||
"iso8859-8" => "ISO-8859-8",
|
||||
"iso8859-9" => "ISO-8859-9",
|
||||
"iso8859-10" => "ISO-8859-10",
|
||||
"iso8859-11" => "ISO-8859-11",
|
||||
"iso8859-13" => "ISO-8859-13",
|
||||
"iso8859-14" => "ISO-8859-14",
|
||||
"iso8859-15" => "ISO-8859-15",
|
||||
"iso_8859-1:1987" => "ISO-8859-1",
|
||||
"iso-ir-100" => "ISO-8859-1",
|
||||
"l1" => "ISO-8859-1",
|
||||
"ibm819" => "ISO-8859-1",
|
||||
"cp819" => "ISO-8859-1",
|
||||
"csisolatin1" => "ISO-8859-1",
|
||||
//
|
||||
// Aliases for ISO-8859-2
|
||||
//
|
||||
"latin2" => "ISO-8859-2",
|
||||
"iso_8859-2" => "ISO-8859-2",
|
||||
"iso_8859-2:1987" => "ISO-8859-2",
|
||||
"iso-ir-101" => "ISO-8859-2",
|
||||
"l2" => "ISO-8859-2",
|
||||
"csisolatin2" => "ISO-8859-2",
|
||||
//
|
||||
// Aliases for ISO-8859-3
|
||||
//
|
||||
"latin3" => "ISO-8859-3",
|
||||
"iso_8859-3" => "ISO-8859-3",
|
||||
"iso_8859-3:1988" => "ISO-8859-3",
|
||||
"iso-ir-109" => "ISO-8859-3",
|
||||
"l3" => "ISO-8859-3",
|
||||
"csisolatin3" => "ISO-8859-3",
|
||||
//
|
||||
// Aliases for ISO-8859-4
|
||||
//
|
||||
"latin4" => "ISO-8859-4",
|
||||
"iso_8859-4" => "ISO-8859-4",
|
||||
"iso_8859-4:1988" => "ISO-8859-4",
|
||||
"iso-ir-110" => "ISO-8859-4",
|
||||
"l4" => "ISO-8859-4",
|
||||
"csisolatin4" => "ISO-8859-4",
|
||||
//
|
||||
// Aliases for ISO-8859-5
|
||||
//
|
||||
"cyrillic" => "ISO-8859-5",
|
||||
"iso_8859-5" => "ISO-8859-5",
|
||||
"iso_8859-5:1988" => "ISO-8859-5",
|
||||
"iso-ir-144" => "ISO-8859-5",
|
||||
"csisolatincyrillic" => "ISO-8859-5",
|
||||
//
|
||||
// Aliases for ISO-8859-6
|
||||
//
|
||||
"arabic" => "ISO-8859-6",
|
||||
"iso_8859-6" => "ISO-8859-6",
|
||||
"iso_8859-6:1987" => "ISO-8859-6",
|
||||
"iso-ir-127" => "ISO-8859-6",
|
||||
"ecma-114" => "ISO-8859-6",
|
||||
"asmo-708" => "ISO-8859-6",
|
||||
"csisolatinarabic" => "ISO-8859-6",
|
||||
//
|
||||
// Aliases for ISO-8859-6-I
|
||||
//
|
||||
"csiso88596i" => "ISO-8859-6-I",
|
||||
//
|
||||
// Aliases for ISO-8859-6-E",
|
||||
//
|
||||
"csiso88596e" => "ISO-8859-6-E",
|
||||
//
|
||||
// Aliases for ISO-8859-7",
|
||||
//
|
||||
"greek" => "ISO-8859-7",
|
||||
"greek8" => "ISO-8859-7",
|
||||
"sun_eu_greek" => "ISO-8859-7",
|
||||
"iso_8859-7" => "ISO-8859-7",
|
||||
"iso_8859-7:1987" => "ISO-8859-7",
|
||||
"iso-ir-126" => "ISO-8859-7",
|
||||
"elot_928" => "ISO-8859-7",
|
||||
"ecma-118" => "ISO-8859-7",
|
||||
"csisolatingreek" => "ISO-8859-7",
|
||||
//
|
||||
// Aliases for ISO-8859-8",
|
||||
//
|
||||
"hebrew" => "ISO-8859-8",
|
||||
"iso_8859-8" => "ISO-8859-8",
|
||||
"visual" => "ISO-8859-8",
|
||||
"iso_8859-8:1988" => "ISO-8859-8",
|
||||
"iso-ir-138" => "ISO-8859-8",
|
||||
"csisolatinhebrew" => "ISO-8859-8",
|
||||
//
|
||||
// Aliases for ISO-8859-8-I",
|
||||
//
|
||||
"csiso88598i" => "ISO-8859-8-I",
|
||||
"iso-8859-8i" => "ISO-8859-8-I",
|
||||
"logical" => "ISO-8859-8-I",
|
||||
//
|
||||
// Aliases for ISO-8859-8-E",
|
||||
//
|
||||
"csiso88598e" => "ISO-8859-8-E",
|
||||
//
|
||||
// Aliases for ISO-8859-9",
|
||||
//
|
||||
"latin5" => "ISO-8859-9",
|
||||
"iso_8859-9" => "ISO-8859-9",
|
||||
"iso_8859-9:1989" => "ISO-8859-9",
|
||||
"iso-ir-148" => "ISO-8859-9",
|
||||
"l5" => "ISO-8859-9",
|
||||
"csisolatin5" => "ISO-8859-9",
|
||||
//
|
||||
// Aliases for UTF-8",
|
||||
//
|
||||
"unicode-1-1-utf-8" => "UTF-8",
|
||||
// nl_langinfo(CODESET) in HP/UX returns 'utf8' under UTF-8 locales",
|
||||
"utf8" => "UTF-8",
|
||||
//
|
||||
// Aliases for Shift_JIS",
|
||||
//
|
||||
"x-sjis" => "Shift_JIS",
|
||||
"shift-jis" => "Shift_JIS",
|
||||
"ms_kanji" => "Shift_JIS",
|
||||
"csshiftjis" => "Shift_JIS",
|
||||
"windows-31j" => "Shift_JIS",
|
||||
"cp932" => "Shift_JIS",
|
||||
"sjis" => "Shift_JIS",
|
||||
//
|
||||
// Aliases for EUC_JP",
|
||||
//
|
||||
"cseucpkdfmtjapanese" => "EUC-JP",
|
||||
"x-euc-jp" => "EUC-JP",
|
||||
//
|
||||
// Aliases for ISO-2022-JP",
|
||||
//
|
||||
"csiso2022jp" => "ISO-2022-JP",
|
||||
// The following are really not aliases ISO-2022-JP, but sharing the same decoder",
|
||||
"iso-2022-jp-2" => "ISO-2022-JP",
|
||||
"csiso2022jp2" => "ISO-2022-JP",
|
||||
//
|
||||
// Aliases for Big5",
|
||||
//
|
||||
"csbig5" => "Big5",
|
||||
"cn-big5" => "Big5",
|
||||
// x-x-big5 is not really a alias for Big5, add it only for MS FrontPage",
|
||||
"x-x-big5" => "Big5",
|
||||
// Sun Solaris",
|
||||
"zh_tw-big5" => "Big5",
|
||||
//
|
||||
// Aliases for EUC-KR",
|
||||
//
|
||||
"cseuckr" => "EUC-KR",
|
||||
"ks_c_5601-1987" => "EUC-KR",
|
||||
"iso-ir-149" => "EUC-KR",
|
||||
"ks_c_5601-1989" => "EUC-KR",
|
||||
"ksc_5601" => "EUC-KR",
|
||||
"ksc5601" => "EUC-KR",
|
||||
"korean" => "EUC-KR",
|
||||
"csksc56011987" => "EUC-KR",
|
||||
"5601" => "EUC-KR",
|
||||
"windows-949" => "EUC-KR",
|
||||
//
|
||||
// Aliases for GB2312",
|
||||
//
|
||||
// The following are really not aliases GB2312, add them only for MS FrontPage",
|
||||
"gb_2312-80" => "GB2312",
|
||||
"iso-ir-58" => "GB2312",
|
||||
"chinese" => "GB2312",
|
||||
"csiso58gb231280" => "GB2312",
|
||||
"csgb2312" => "GB2312",
|
||||
"zh_cn.euc" => "GB2312",
|
||||
// Sun Solaris",
|
||||
"gb_2312" => "GB2312",
|
||||
//
|
||||
// Aliases for windows-125x ",
|
||||
//
|
||||
"x-cp1250" => "windows-1250",
|
||||
"x-cp1251" => "windows-1251",
|
||||
"x-cp1252" => "windows-1252",
|
||||
"x-cp1253" => "windows-1253",
|
||||
"x-cp1254" => "windows-1254",
|
||||
"x-cp1255" => "windows-1255",
|
||||
"x-cp1256" => "windows-1256",
|
||||
"x-cp1257" => "windows-1257",
|
||||
"x-cp1258" => "windows-1258",
|
||||
//
|
||||
// Aliases for windows-874 ",
|
||||
//
|
||||
"windows-874" => "windows-874",
|
||||
"ibm874" => "windows-874",
|
||||
"dos-874" => "windows-874",
|
||||
//
|
||||
// Aliases for macintosh",
|
||||
//
|
||||
"macintosh" => "macintosh",
|
||||
"x-mac-roman" => "macintosh",
|
||||
"mac" => "macintosh",
|
||||
"csmacintosh" => "macintosh",
|
||||
//
|
||||
// Aliases for IBM866",
|
||||
//
|
||||
"cp866" => "IBM866",
|
||||
"cp-866" => "IBM866",
|
||||
"866" => "IBM866",
|
||||
"csibm866" => "IBM866",
|
||||
//
|
||||
// Aliases for IBM850",
|
||||
//
|
||||
"cp850" => "IBM850",
|
||||
"850" => "IBM850",
|
||||
"csibm850" => "IBM850",
|
||||
//
|
||||
// Aliases for IBM852",
|
||||
//
|
||||
"cp852" => "IBM852",
|
||||
"852" => "IBM852",
|
||||
"csibm852" => "IBM852",
|
||||
//
|
||||
// Aliases for IBM855",
|
||||
//
|
||||
"cp855" => "IBM855",
|
||||
"855" => "IBM855",
|
||||
"csibm855" => "IBM855",
|
||||
//
|
||||
// Aliases for IBM857",
|
||||
//
|
||||
"cp857" => "IBM857",
|
||||
"857" => "IBM857",
|
||||
"csibm857" => "IBM857",
|
||||
//
|
||||
// Aliases for IBM862",
|
||||
//
|
||||
"cp862" => "IBM862",
|
||||
"862" => "IBM862",
|
||||
"csibm862" => "IBM862",
|
||||
//
|
||||
// Aliases for IBM864",
|
||||
//
|
||||
"cp864" => "IBM864",
|
||||
"864" => "IBM864",
|
||||
"csibm864" => "IBM864",
|
||||
"ibm-864" => "IBM864",
|
||||
//
|
||||
// Aliases for T.61-8bit",
|
||||
//
|
||||
"t.61" => "T.61-8bit",
|
||||
"iso-ir-103" => "T.61-8bit",
|
||||
"csiso103t618bit" => "T.61-8bit",
|
||||
//
|
||||
// Aliases for UTF-7",
|
||||
//
|
||||
"x-unicode-2-0-utf-7" => "UTF-7",
|
||||
"unicode-2-0-utf-7" => "UTF-7",
|
||||
"unicode-1-1-utf-7" => "UTF-7",
|
||||
"csunicode11utf7" => "UTF-7",
|
||||
//
|
||||
// Aliases for ISO-10646-UCS-2",
|
||||
//
|
||||
"csunicode" => "UTF-16BE",
|
||||
"csunicode11" => "UTF-16BE",
|
||||
"iso-10646-ucs-basic" => "UTF-16BE",
|
||||
"csunicodeascii" => "UTF-16BE",
|
||||
"iso-10646-unicode-latin1" => "UTF-16BE",
|
||||
"csunicodelatin1" => "UTF-16BE",
|
||||
"iso-10646" => "UTF-16BE",
|
||||
"iso-10646-j-1" => "UTF-16BE",
|
||||
//
|
||||
// Aliases for ISO-8859-10",
|
||||
//
|
||||
"latin6" => "ISO-8859-10",
|
||||
"iso-ir-157" => "ISO-8859-10",
|
||||
"l6" => "ISO-8859-10",
|
||||
// Currently .properties cannot handle : in key",
|
||||
//iso_8859-10:1992" => "ISO-8859-10",
|
||||
"csisolatin6" => "ISO-8859-10",
|
||||
//
|
||||
// Aliases for ISO-8859-15",
|
||||
//
|
||||
"iso_8859-15" => "ISO-8859-15",
|
||||
"csisolatin9" => "ISO-8859-15",
|
||||
"l9" => "ISO-8859-15",
|
||||
//
|
||||
// Aliases for ISO-IR-111",
|
||||
//
|
||||
"ecma-cyrillic" => "ISO-IR-111",
|
||||
"csiso111ecmacyrillic" => "ISO-IR-111",
|
||||
//
|
||||
// Aliases for ISO-2022-KR",
|
||||
//
|
||||
"csiso2022kr" => "ISO-2022-KR",
|
||||
//
|
||||
// Aliases for VISCII",
|
||||
//
|
||||
"csviscii" => "VISCII",
|
||||
//
|
||||
// Aliases for x-euc-tw",
|
||||
//
|
||||
"zh_tw-euc" => "x-euc-tw",
|
||||
//
|
||||
// Following names appears in unix nl_langinfo(CODESET)",
|
||||
// They can be compiled as platform specific if necessary",
|
||||
// DONT put things here if it does not look generic enough (like hp15CN)",
|
||||
//
|
||||
"iso88591" => "ISO-8859-1",
|
||||
"iso88592" => "ISO-8859-2",
|
||||
"iso88593" => "ISO-8859-3",
|
||||
"iso88594" => "ISO-8859-4",
|
||||
"iso88595" => "ISO-8859-5",
|
||||
"iso88596" => "ISO-8859-6",
|
||||
"iso88597" => "ISO-8859-7",
|
||||
"iso88598" => "ISO-8859-8",
|
||||
"iso88599" => "ISO-8859-9",
|
||||
"iso885910" => "ISO-8859-10",
|
||||
"iso885911" => "ISO-8859-11",
|
||||
"iso885912" => "ISO-8859-12",
|
||||
"iso885913" => "ISO-8859-13",
|
||||
"iso885914" => "ISO-8859-14",
|
||||
"iso885915" => "ISO-8859-15",
|
||||
"cp1250" => "windows-1250",
|
||||
"cp1251" => "windows-1251",
|
||||
"cp1252" => "windows-1252",
|
||||
"cp1253" => "windows-1253",
|
||||
"cp1254" => "windows-1254",
|
||||
"cp1255" => "windows-1255",
|
||||
"cp1256" => "windows-1256",
|
||||
"cp1257" => "windows-1257",
|
||||
"cp1258" => "windows-1258",
|
||||
"x-gbk" => "gbk",
|
||||
"windows-936" => "gbk",
|
||||
"ansi-1251" => "windows-1251",
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns proper encoding mapping, if exists. If it doesn't, return unchanged $encoding
|
||||
* @param string|null $encoding
|
||||
* @param string|null $fallback
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get(?string $encoding, ?string $fallback = null): string {
|
||||
if (isset(self::$aliases[strtolower($encoding ?? '')])) {
|
||||
return self::$aliases[strtolower($encoding ?? '')];
|
||||
}
|
||||
return $fallback ?: $encoding;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the encoding of a string
|
||||
* @param $str
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function convert($str, string $from = "ISO-8859-2", string $to = "UTF-8"): mixed {
|
||||
$from = self::get($from, self::detectEncoding($str));
|
||||
$to = self::get($to, self::detectEncoding($str));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
try {
|
||||
if (function_exists('iconv') && !self::isUtf7($from) && !self::isUtf7($to)) {
|
||||
return iconv($from, $to, $str);
|
||||
}
|
||||
if (!$from) {
|
||||
return mb_convert_encoding($str, $to);
|
||||
}
|
||||
return mb_convert_encoding($str, $to, $from);
|
||||
} catch (\Exception $e) {
|
||||
if (str_contains($from, '-')) {
|
||||
$from = str_replace('-', '', $from);
|
||||
return self::convert($str, $from, $to);
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to detect the encoding of a string
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function detectEncoding(string $string): string {
|
||||
$encoding = mb_detect_encoding($string, array_filter(self::getEncodings(), function($value){
|
||||
return !in_array($value, [
|
||||
'ISO-8859-6-I', 'ISO-8859-6-E', 'ISO-8859-8-I', 'ISO-8859-8-E',
|
||||
'ISO-8859-11', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16', 'ISO-IR-111',"ISO-2022-CN",
|
||||
"windows-1250", "windows-1253", "windows-1255", "windows-1256", "windows-1257", "windows-1258",
|
||||
"IBM852", "IBM855", "IBM857", "IBM866", "IBM864", "IBM862", "KOI8-R", "KOI8-U",
|
||||
"TIS-620", "ISO-8859-1", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4",
|
||||
"VISCII", "T.61-8bit", "Big5-HKSCS", "windows-874", "macintosh", "ISO-8859-12", "ISO-8859-7",
|
||||
"IMAP-UTF-7"
|
||||
]);
|
||||
}), true);
|
||||
if ($encoding === false) {
|
||||
$encoding = 'UTF-8';
|
||||
}
|
||||
return $encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available encodings
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getEncodings(): array {
|
||||
$encodings = [];
|
||||
foreach (self::$aliases as $encoding) {
|
||||
if (!in_array($encoding, $encodings)) {
|
||||
$encodings[] = $encoding;
|
||||
}
|
||||
}
|
||||
return $encodings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the encoding is UTF-7 like
|
||||
* @param string $encoding
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isUtf7(string $encoding): bool {
|
||||
return str_contains(str_replace("-", "", strtolower($encoding)), "utf7");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an encoding is supported
|
||||
* @param string $encoding
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function has(string $encoding): bool {
|
||||
return isset(self::$aliases[strtolower($encoding)]);
|
||||
}
|
||||
}
|
||||
28
plugins/vendor/webklex/php-imap/src/Events/Event.php
vendored
Normal file
28
plugins/vendor/webklex/php-imap/src/Events/Event.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/*
|
||||
* File: Event.php
|
||||
* Category: Event
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 25.11.20 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Events;
|
||||
|
||||
/**
|
||||
* Class Event
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Events
|
||||
*/
|
||||
abstract class Event {
|
||||
|
||||
/**
|
||||
* Dispatch the event with the given arguments.
|
||||
*/
|
||||
public static function dispatch(): Event {
|
||||
return new static(func_get_args());
|
||||
}
|
||||
}
|
||||
22
plugins/vendor/webklex/php-imap/src/Events/FlagDeletedEvent.php
vendored
Normal file
22
plugins/vendor/webklex/php-imap/src/Events/FlagDeletedEvent.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/*
|
||||
* File: FlagDeletedEvent.php
|
||||
* Category: Event
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 25.11.20 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Events;
|
||||
|
||||
/**
|
||||
* Class FlagDeletedEvent
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Events
|
||||
*/
|
||||
class FlagDeletedEvent extends FlagNewEvent {
|
||||
|
||||
}
|
||||
40
plugins/vendor/webklex/php-imap/src/Events/FlagNewEvent.php
vendored
Normal file
40
plugins/vendor/webklex/php-imap/src/Events/FlagNewEvent.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/*
|
||||
* File: FlagNewEvent.php
|
||||
* Category: Event
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 25.11.20 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Events;
|
||||
|
||||
use Webklex\PHPIMAP\Message;
|
||||
|
||||
/**
|
||||
* Class FlagNewEvent
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Events
|
||||
*/
|
||||
class FlagNewEvent extends Event {
|
||||
|
||||
/** @var Message $message */
|
||||
public Message $message;
|
||||
|
||||
/** @var string $flag */
|
||||
public string $flag;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
* @var array $arguments
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(array $arguments) {
|
||||
$this->message = $arguments[0];
|
||||
$this->flag = $arguments[1];
|
||||
}
|
||||
}
|
||||
22
plugins/vendor/webklex/php-imap/src/Events/FolderDeletedEvent.php
vendored
Normal file
22
plugins/vendor/webklex/php-imap/src/Events/FolderDeletedEvent.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/*
|
||||
* File: FolderDeletedEvent.php
|
||||
* Category: Event
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 25.11.20 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Events;
|
||||
|
||||
/**
|
||||
* Class FolderDeletedEvent
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Events
|
||||
*/
|
||||
class FolderDeletedEvent extends FolderNewEvent {
|
||||
|
||||
}
|
||||
40
plugins/vendor/webklex/php-imap/src/Events/FolderMovedEvent.php
vendored
Normal file
40
plugins/vendor/webklex/php-imap/src/Events/FolderMovedEvent.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/*
|
||||
* File: FolderMovedEvent.php
|
||||
* Category: Event
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 25.11.20 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Events;
|
||||
|
||||
use Webklex\PHPIMAP\Folder;
|
||||
|
||||
/**
|
||||
* Class FolderMovedEvent
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Events
|
||||
*/
|
||||
class FolderMovedEvent extends Event {
|
||||
|
||||
/** @var Folder $old_folder */
|
||||
public Folder $old_folder;
|
||||
|
||||
/** @var Folder $new_folder */
|
||||
public Folder $new_folder;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
* @var Folder[] $folders
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(array $folders) {
|
||||
$this->old_folder = $folders[0];
|
||||
$this->new_folder = $folders[1];
|
||||
}
|
||||
}
|
||||
36
plugins/vendor/webklex/php-imap/src/Events/FolderNewEvent.php
vendored
Normal file
36
plugins/vendor/webklex/php-imap/src/Events/FolderNewEvent.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/*
|
||||
* File: FolderNewEvent.php
|
||||
* Category: Event
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 25.11.20 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Events;
|
||||
|
||||
use Webklex\PHPIMAP\Folder;
|
||||
|
||||
/**
|
||||
* Class FolderNewEvent
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Events
|
||||
*/
|
||||
class FolderNewEvent extends Event {
|
||||
|
||||
/** @var Folder $folder */
|
||||
public Folder $folder;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
* @var Folder[] $folders
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(array $folders) {
|
||||
$this->folder = $folders[0];
|
||||
}
|
||||
}
|
||||
22
plugins/vendor/webklex/php-imap/src/Events/MessageCopiedEvent.php
vendored
Normal file
22
plugins/vendor/webklex/php-imap/src/Events/MessageCopiedEvent.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MessageCopiedEvent.php
|
||||
* Category: Event
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 25.11.20 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Events;
|
||||
|
||||
/**
|
||||
* Class MessageCopiedEvent
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Events
|
||||
*/
|
||||
class MessageCopiedEvent extends MessageMovedEvent {
|
||||
|
||||
}
|
||||
22
plugins/vendor/webklex/php-imap/src/Events/MessageDeletedEvent.php
vendored
Normal file
22
plugins/vendor/webklex/php-imap/src/Events/MessageDeletedEvent.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MessageDeletedEvent.php
|
||||
* Category: Event
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 25.11.20 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Events;
|
||||
|
||||
/**
|
||||
* Class MessageDeletedEvent
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Events
|
||||
*/
|
||||
class MessageDeletedEvent extends MessageNewEvent {
|
||||
|
||||
}
|
||||
40
plugins/vendor/webklex/php-imap/src/Events/MessageMovedEvent.php
vendored
Normal file
40
plugins/vendor/webklex/php-imap/src/Events/MessageMovedEvent.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MessageMovedEvent.php
|
||||
* Category: Event
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 25.11.20 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Events;
|
||||
|
||||
use Webklex\PHPIMAP\Message;
|
||||
|
||||
/**
|
||||
* Class MessageMovedEvent
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Events
|
||||
*/
|
||||
class MessageMovedEvent extends Event {
|
||||
|
||||
/** @var Message $old_message */
|
||||
public Message $old_message;
|
||||
|
||||
/** @var Message $new_message */
|
||||
public Message $new_message;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
* @var Message[] $messages
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(array $messages) {
|
||||
$this->old_message = $messages[0];
|
||||
$this->new_message = $messages[1];
|
||||
}
|
||||
}
|
||||
36
plugins/vendor/webklex/php-imap/src/Events/MessageNewEvent.php
vendored
Normal file
36
plugins/vendor/webklex/php-imap/src/Events/MessageNewEvent.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MessageNewEvent.php
|
||||
* Category: Event
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 25.11.20 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Events;
|
||||
|
||||
use Webklex\PHPIMAP\Message;
|
||||
|
||||
/**
|
||||
* Class MessageNewEvent
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Events
|
||||
*/
|
||||
class MessageNewEvent extends Event {
|
||||
|
||||
/** @var Message $message */
|
||||
public Message $message;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
* @var Message[] $messages
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(array $messages) {
|
||||
$this->message = $messages[0];
|
||||
}
|
||||
}
|
||||
22
plugins/vendor/webklex/php-imap/src/Events/MessageRestoredEvent.php
vendored
Normal file
22
plugins/vendor/webklex/php-imap/src/Events/MessageRestoredEvent.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MessageRestoredEvent.php
|
||||
* Category: Event
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 25.11.20 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Events;
|
||||
|
||||
/**
|
||||
* Class MessageRestoredEvent
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Events
|
||||
*/
|
||||
class MessageRestoredEvent extends MessageNewEvent {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/AuthFailedException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/AuthFailedException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: AuthFailedException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 19.01.17 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class AuthFailedException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class AuthFailedException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/ConnectionFailedException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/ConnectionFailedException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: ConnectionFailedException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 19.01.17 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class ConnectionFailedException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class ConnectionFailedException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/DecoderNotFoundException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/DecoderNotFoundException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: DecoderNotFoundException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 12.04.24 21:24
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class DecoderNotFoundException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class DecoderNotFoundException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/EventNotFoundException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/EventNotFoundException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: EventNotFoundException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 05.03.18 23:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class EventNotFoundException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class EventNotFoundException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/FolderFetchingException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/FolderFetchingException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: FolderFetchingException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 05.03.18 23:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class FolderFetchingException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class FolderFetchingException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/GetMessagesFailedException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/GetMessagesFailedException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: GetMessagesFailedException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 19.01.17 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class GetMessagesFailedException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class GetMessagesFailedException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/ImapBadRequestException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/ImapBadRequestException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: ImapBadRequestException.php
|
||||
* Category: Exception
|
||||
* Author: S. Janaczek
|
||||
* Created: 08.09.22 08:39
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class GetMessagesFailedException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class ImapBadRequestException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/ImapServerErrorException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/ImapServerErrorException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: ImapServerErrorException.php
|
||||
* Category: Exception
|
||||
* Author: S. Janaczek
|
||||
* Created: 08.09.22 08:39
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class GetMessagesFailedException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class ImapServerErrorException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/InvalidMessageDateException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/InvalidMessageDateException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: InvalidMessageDateException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 10.03.19 04:31
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class InvalidMessageDateException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class InvalidMessageDateException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/InvalidWhereQueryCriteriaException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/InvalidWhereQueryCriteriaException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: InvalidWhereQueryCriteriaException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 21.07.18 19:04
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class InvalidWhereQueryCriteriaException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class InvalidWhereQueryCriteriaException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/MaskNotFoundException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/MaskNotFoundException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MaskNotFoundException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 05.03.18 23:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class MaskNotFoundException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class MaskNotFoundException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/MessageContentFetchingException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/MessageContentFetchingException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MessageContentFetchingException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 05.03.18 23:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class MessageContentFetchingException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class MessageContentFetchingException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/MessageFlagException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/MessageFlagException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MessageFlagException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 02.01.21 02:47
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class MessageFlagException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class MessageFlagException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/MessageHeaderFetchingException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/MessageHeaderFetchingException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MessageHeaderFetchingException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 05.03.18 23:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class MessageHeaderFetchingException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class MessageHeaderFetchingException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/MessageNotFoundException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/MessageNotFoundException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MessageNotFoundException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 25.01.21 18:19
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class MessageNotFoundException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class MessageNotFoundException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/MessageSearchValidationException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/MessageSearchValidationException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MessageSearchValidationException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 05.03.18 23:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class MessageSearchValidationException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class MessageSearchValidationException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/MessageSizeFetchingException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/MessageSizeFetchingException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MessageSizeFetchingException.php
|
||||
* Category: Exception
|
||||
* Author: D. Malli
|
||||
* Created: 24.02.23 17:55
|
||||
* Updated: -
|
||||
*
|
||||
* Description: Exception thrown if fetching size for a message failed.
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class MessageSizeFetchingException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class MessageSizeFetchingException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/MethodNotFoundException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/MethodNotFoundException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MethodNotFoundException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 05.03.18 23:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class MethodNotFoundException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class MethodNotFoundException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/MethodNotSupportedException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/MethodNotSupportedException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MethodNotSupportedException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 05.03.18 23:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class MethodNotSupportedException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class MethodNotSupportedException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/NotSupportedCapabilityException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/NotSupportedCapabilityException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: RuntimeException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 19.01.17 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class NotSupportedCapabilityException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class NotSupportedCapabilityException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/ProtocolNotSupportedException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/ProtocolNotSupportedException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: ProtocolNotSupportedException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 19.01.17 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class ProtocolNotSupportedException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class ProtocolNotSupportedException extends Exception {
|
||||
|
||||
}
|
||||
91
plugins/vendor/webklex/php-imap/src/Exceptions/ResponseException.php
vendored
Normal file
91
plugins/vendor/webklex/php-imap/src/Exceptions/ResponseException.php
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/*
|
||||
* File: ResponseException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 19.01.17 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
use Webklex\PHPIMAP\Connection\Protocols\Response;
|
||||
|
||||
/**
|
||||
* Class ResponseException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class ResponseException extends Exception {
|
||||
|
||||
/**
|
||||
* Make a new ResponseException instance
|
||||
* @param Response $response
|
||||
* @param false|boolean $debug
|
||||
* @param Exception|null $exception
|
||||
*
|
||||
* @return ResponseException
|
||||
*/
|
||||
public static function make(Response $response, bool $debug = false, ?Exception $exception = null): ResponseException {
|
||||
$message = "Command failed to process:\n";
|
||||
$message .= "Causes:\n";
|
||||
|
||||
foreach($response->getErrors() as $error) {
|
||||
$message .= "\t- $error\n";
|
||||
}
|
||||
|
||||
if(!$response->data()) {
|
||||
$message .= "\t- Empty response\n";
|
||||
}
|
||||
|
||||
if ($debug) {
|
||||
$message .= self::debug_message($response);
|
||||
}
|
||||
|
||||
foreach($response->getStack() as $_response) {
|
||||
$exception = self::make($_response, $debug, $exception);
|
||||
}
|
||||
|
||||
return new self($message."Error occurred", 0, $exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a debug message containing all commands send and responses received
|
||||
* @param Response $response
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function debug_message(Response $response): string {
|
||||
$commands = $response->getCommands();
|
||||
$message = "Commands send:\n";
|
||||
if ($commands) {
|
||||
foreach($commands as $command) {
|
||||
$message .= "\t".str_replace("\r\n", "\\r\\n", $command)."\n";
|
||||
}
|
||||
}else{
|
||||
$message .= "\tNo command send!\n";
|
||||
}
|
||||
|
||||
$responses = $response->getResponse();
|
||||
$message .= "Responses received:\n";
|
||||
if ($responses) {
|
||||
foreach($responses as $_response) {
|
||||
if (is_array($_response)) {
|
||||
foreach($_response as $value) {
|
||||
$message .= "\t".str_replace("\r\n", "\\r\\n", "$value")."\n";
|
||||
}
|
||||
}else{
|
||||
$message .= "\t".str_replace("\r\n", "\\r\\n", "$_response")."\n";
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$message .= "\tNo responses received!\n";
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/RuntimeException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/RuntimeException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: RuntimeException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 19.01.17 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class RuntimeException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class RuntimeException extends Exception {
|
||||
|
||||
}
|
||||
24
plugins/vendor/webklex/php-imap/src/Exceptions/SpoofingAttemptDetectedException.php
vendored
Normal file
24
plugins/vendor/webklex/php-imap/src/Exceptions/SpoofingAttemptDetectedException.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
* File: SpoofingAttemptDetectedException.php
|
||||
* Category: Exception
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 17.01.25 17:25
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Exceptions;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class SpoofingAttemptDetectedException
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Exceptions
|
||||
*/
|
||||
class SpoofingAttemptDetectedException extends Exception {
|
||||
|
||||
}
|
||||
597
plugins/vendor/webklex/php-imap/src/Folder.php
vendored
Executable file
597
plugins/vendor/webklex/php-imap/src/Folder.php
vendored
Executable file
@@ -0,0 +1,597 @@
|
||||
<?php
|
||||
/*
|
||||
* File: Folder.php
|
||||
* Category: -
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 19.01.17 22:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Webklex\PHPIMAP\Connection\Protocols\Response;
|
||||
use Webklex\PHPIMAP\Exceptions\AuthFailedException;
|
||||
use Webklex\PHPIMAP\Exceptions\ConnectionFailedException;
|
||||
use Webklex\PHPIMAP\Exceptions\EventNotFoundException;
|
||||
use Webklex\PHPIMAP\Exceptions\FolderFetchingException;
|
||||
use Webklex\PHPIMAP\Exceptions\ImapBadRequestException;
|
||||
use Webklex\PHPIMAP\Exceptions\ImapServerErrorException;
|
||||
use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException;
|
||||
use Webklex\PHPIMAP\Exceptions\MessageNotFoundException;
|
||||
use Webklex\PHPIMAP\Exceptions\NotSupportedCapabilityException;
|
||||
use Webklex\PHPIMAP\Exceptions\ResponseException;
|
||||
use Webklex\PHPIMAP\Exceptions\RuntimeException;
|
||||
use Webklex\PHPIMAP\Query\WhereQuery;
|
||||
use Webklex\PHPIMAP\Support\FolderCollection;
|
||||
use Webklex\PHPIMAP\Traits\HasEvents;
|
||||
|
||||
/**
|
||||
* Class Folder
|
||||
*
|
||||
* @package Webklex\PHPIMAP
|
||||
*/
|
||||
class Folder {
|
||||
use HasEvents;
|
||||
|
||||
/**
|
||||
* Client instance
|
||||
*
|
||||
* @var Client
|
||||
*/
|
||||
protected Client $client;
|
||||
|
||||
/**
|
||||
* Folder full path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $path;
|
||||
|
||||
/**
|
||||
* Folder name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $name;
|
||||
|
||||
/**
|
||||
* Folder full name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $full_name;
|
||||
|
||||
/**
|
||||
* Children folders
|
||||
*
|
||||
* @var FolderCollection
|
||||
*/
|
||||
public FolderCollection $children;
|
||||
|
||||
/**
|
||||
* Delimiter for folder
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $delimiter;
|
||||
|
||||
/**
|
||||
* Indicates if folder can't contain any "children".
|
||||
* CreateFolder won't work on this folder.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public bool $no_inferiors;
|
||||
|
||||
/**
|
||||
* Indicates if folder is only container, not a mailbox - you can't open it.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public bool $no_select;
|
||||
|
||||
/**
|
||||
* Indicates if folder is marked. This means that it may contain new messages since the last time it was checked.
|
||||
* Not provided by all IMAP servers.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public bool $marked;
|
||||
|
||||
/**
|
||||
* Indicates if folder contains any "children".
|
||||
* Not provided by all IMAP servers.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public bool $has_children;
|
||||
|
||||
/**
|
||||
* Indicates if folder refers to others.
|
||||
* Not provided by all IMAP servers.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public bool $referral;
|
||||
|
||||
/** @var array */
|
||||
public array $status;
|
||||
|
||||
/**
|
||||
* Folder constructor.
|
||||
* @param Client $client
|
||||
* @param string $folder_name
|
||||
* @param string $delimiter
|
||||
* @param string[] $attributes
|
||||
*/
|
||||
public function __construct(Client $client, string $folder_name, string $delimiter, array $attributes) {
|
||||
$this->client = $client;
|
||||
|
||||
$this->events["message"] = $client->getDefaultEvents("message");
|
||||
$this->events["folder"] = $client->getDefaultEvents("folder");
|
||||
|
||||
$this->setDelimiter($delimiter);
|
||||
$this->path = $folder_name;
|
||||
$this->full_name = $this->decodeName($folder_name);
|
||||
$this->name = $this->getSimpleName($this->delimiter, $this->full_name);
|
||||
$this->children = new FolderCollection();
|
||||
$this->has_children = false;
|
||||
|
||||
$this->parseAttributes($attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new search query instance
|
||||
* @param string[] $extensions
|
||||
*
|
||||
* @return WhereQuery
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function query(array $extensions = []): WhereQuery {
|
||||
$this->getClient()->checkConnection();
|
||||
$this->getClient()->openFolder($this->path);
|
||||
$extensions = count($extensions) > 0 ? $extensions : $this->getClient()->extensions;
|
||||
|
||||
return new WhereQuery($this->getClient(), $extensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new search query instance
|
||||
* @param string[] $extensions
|
||||
*
|
||||
* @return WhereQuery
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function search(array $extensions = []): WhereQuery {
|
||||
return $this->query($extensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new search query instance
|
||||
* @param string[] $extensions
|
||||
*
|
||||
* @return WhereQuery
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function messages(array $extensions = []): WhereQuery {
|
||||
return $this->query($extensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if folder has children.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasChildren(): bool {
|
||||
return $this->has_children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set children.
|
||||
* @param FolderCollection $children
|
||||
*
|
||||
* @return Folder
|
||||
*/
|
||||
public function setChildren(FolderCollection $children): Folder {
|
||||
$this->children = $children;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get children.
|
||||
*
|
||||
* @return FolderCollection
|
||||
*/
|
||||
public function getChildren(): FolderCollection {
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode name.
|
||||
* It converts UTF7-IMAP encoding to UTF-8.
|
||||
* @param $name
|
||||
*
|
||||
* @return string|array|bool|string[]|null
|
||||
*/
|
||||
protected function decodeName($name): string|array|bool|null {
|
||||
$parts = [];
|
||||
foreach (explode($this->delimiter, $name) as $item) {
|
||||
$parts[] = EncodingAliases::convert($item, "UTF7-IMAP");
|
||||
}
|
||||
|
||||
return implode($this->delimiter, $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get simple name (without parent folders).
|
||||
* @param $delimiter
|
||||
* @param $full_name
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
protected function getSimpleName($delimiter, $full_name): string|bool {
|
||||
$arr = explode($delimiter, $full_name);
|
||||
return end($arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse attributes and set it to object properties.
|
||||
* @param $attributes
|
||||
*/
|
||||
protected function parseAttributes($attributes): void {
|
||||
$this->no_inferiors = in_array('\NoInferiors', $attributes, true) || \in_array('\Noinferiors', $attributes, true);
|
||||
$this->no_select = in_array('\NoSelect', $attributes, true) || \in_array('\Noselect', $attributes, true);
|
||||
$this->marked = in_array('\Marked', $attributes);
|
||||
$this->referral = in_array('\Referral', $attributes);
|
||||
$this->has_children = in_array('\HasChildren', $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move or rename the current folder
|
||||
* @param string $new_name
|
||||
* @param boolean $expunge
|
||||
*
|
||||
* @return array
|
||||
* @throws ConnectionFailedException
|
||||
* @throws EventNotFoundException
|
||||
* @throws FolderFetchingException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws AuthFailedException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function move(string $new_name, bool $expunge = true): array {
|
||||
$this->client->checkConnection();
|
||||
$status = $this->client->getConnection()->renameFolder($this->full_name, $new_name)->validatedData();
|
||||
if ($expunge) $this->client->expunge();
|
||||
|
||||
$folder = $this->client->getFolder($new_name);
|
||||
$this->dispatch("folder", "moved", $this, $folder);
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a message overview
|
||||
* @param string|null $sequence uid sequence
|
||||
*
|
||||
* @return array
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws AuthFailedException
|
||||
* @throws InvalidMessageDateException
|
||||
* @throws MessageNotFoundException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function overview(?string $sequence = null): array {
|
||||
$this->client->openFolder($this->path);
|
||||
$sequence = $sequence === null ? "1:*" : $sequence;
|
||||
$uid = $this->client->getConfig()->get('options.sequence', IMAP::ST_MSGN);
|
||||
$response = $this->client->getConnection()->overview($sequence, $uid);
|
||||
return $response->validatedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a string message to the current mailbox
|
||||
* @param string $message
|
||||
* @param array|null $options
|
||||
* @param string|Carbon|null $internal_date
|
||||
*
|
||||
* @return array
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws AuthFailedException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function appendMessage(string $message, ?array $options = null, Carbon|string|null $internal_date = null): array {
|
||||
/**
|
||||
* Check if $internal_date is parsed. If it is null it should not be set. Otherwise, the message can't be stored.
|
||||
* If this parameter is set, it will set the INTERNALDATE on the appended message. The parameter should be a
|
||||
* date string that conforms to the rfc2060 specifications for a date_time value or be a Carbon object.
|
||||
*/
|
||||
|
||||
if ($internal_date instanceof Carbon) {
|
||||
$internal_date = $internal_date->format('d-M-Y H:i:s O');
|
||||
}
|
||||
|
||||
return $this->client->getConnection()->appendMessage($this->path, $message, $options, $internal_date)->validatedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename the current folder
|
||||
* @param string $new_name
|
||||
* @param boolean $expunge
|
||||
*
|
||||
* @return array
|
||||
* @throws ConnectionFailedException
|
||||
* @throws EventNotFoundException
|
||||
* @throws FolderFetchingException
|
||||
* @throws RuntimeException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws AuthFailedException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function rename(string $new_name, bool $expunge = true): array {
|
||||
return $this->move($new_name, $expunge);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the current folder
|
||||
* @param boolean $expunge
|
||||
*
|
||||
* @return array
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws EventNotFoundException
|
||||
* @throws AuthFailedException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function delete(bool $expunge = true): array {
|
||||
$status = $this->client->getConnection()->deleteFolder($this->path)->validatedData();
|
||||
if ($this->client->getActiveFolder() == $this->path){
|
||||
$this->client->setActiveFolder();
|
||||
}
|
||||
|
||||
if ($expunge) $this->client->expunge();
|
||||
|
||||
$this->dispatch("folder", "deleted", $this);
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe the current folder
|
||||
*
|
||||
* @return array
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws AuthFailedException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function subscribe(): array {
|
||||
$this->client->openFolder($this->path);
|
||||
return $this->client->getConnection()->subscribeFolder($this->path)->validatedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe the current folder
|
||||
*
|
||||
* @return array
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws AuthFailedException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function unsubscribe(): array {
|
||||
$this->client->openFolder($this->path);
|
||||
return $this->client->getConnection()->unsubscribeFolder($this->path)->validatedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Idle the current connection
|
||||
* @param callable $callback function(Message $message) gets called if a new message is received
|
||||
* @param integer $timeout max 1740 seconds - recommended by rfc2177 §3. Should not be lower than the servers "* OK Still here" message interval
|
||||
*
|
||||
* @throws ConnectionFailedException
|
||||
* @throws RuntimeException
|
||||
* @throws AuthFailedException
|
||||
* @throws NotSupportedCapabilityException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function idle(callable $callback, int $timeout = 300): void {
|
||||
$this->client->setTimeout($timeout);
|
||||
|
||||
if (!in_array("IDLE", $this->client->getConnection()->getCapabilities()->validatedData())) {
|
||||
throw new Exceptions\NotSupportedCapabilityException("IMAP server does not support IDLE");
|
||||
}
|
||||
|
||||
$idle_client = $this->client->clone();
|
||||
$idle_client->connect();
|
||||
$idle_client->openFolder($this->path, true);
|
||||
$idle_client->getConnection()->idle();
|
||||
|
||||
$last_action = Carbon::now()->addSeconds($timeout);
|
||||
|
||||
$sequence = $this->client->getConfig()->get('options.sequence', IMAP::ST_MSGN);
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
// This polymorphic call is fine - Protocol::idle() will throw an exception beforehand
|
||||
$line = $idle_client->getConnection()->nextLine(Response::empty());
|
||||
} catch (Exceptions\RuntimeException $e) {
|
||||
if(strpos($e->getMessage(), "empty response") >= 0 && $idle_client->getConnection()->connected()) {
|
||||
continue;
|
||||
}
|
||||
if(!str_contains($e->getMessage(), "connection closed")) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
if (($pos = strpos($line, "EXISTS")) !== false) {
|
||||
$msgn = (int)substr($line, 2, $pos - 2);
|
||||
|
||||
// Check if the stream is still alive or should be considered stale
|
||||
if (!$this->client->isConnected() || $last_action->isBefore(Carbon::now())) {
|
||||
// Reset the connection before interacting with it. Otherwise, the resource might be stale which
|
||||
// would result in a stuck interaction. If you know of a way of detecting a stale resource, please
|
||||
// feel free to improve this logic. I tried a lot but nothing seem to work reliably...
|
||||
// Things that didn't work:
|
||||
// - Closing the resource with fclose()
|
||||
// - Verifying the resource with stream_get_meta_data()
|
||||
// - Bool validating the resource stream (e.g.: (bool)$stream)
|
||||
// - Sending a NOOP command
|
||||
// - Sending a null package
|
||||
// - Reading a null package
|
||||
// - Catching the fs warning
|
||||
|
||||
// This polymorphic call is fine - Protocol::idle() will throw an exception beforehand
|
||||
$this->client->getConnection()->reset();
|
||||
// Establish a new connection
|
||||
$this->client->connect();
|
||||
}
|
||||
$last_action = Carbon::now()->addSeconds($timeout);
|
||||
|
||||
// Always reopen the folder - otherwise the new message number isn't known to the current remote session
|
||||
$this->client->openFolder($this->path, true);
|
||||
|
||||
$message = $this->query()->getMessageByMsgn($msgn);
|
||||
$message->setSequence($sequence);
|
||||
$callback($message);
|
||||
|
||||
$this->dispatch("message", "new", $message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get folder status information from the EXAMINE command
|
||||
*
|
||||
* @return array
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws AuthFailedException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function status(): array {
|
||||
return $this->client->getConnection()->folderStatus($this->path)->validatedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get folder status information from the EXAMINE command
|
||||
*
|
||||
* @return array
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws ResponseException
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @deprecated Use Folder::status() instead
|
||||
*/
|
||||
public function getStatus(): array {
|
||||
return $this->status();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load folder status information from the EXAMINE command
|
||||
* @return Folder
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws ResponseException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function loadStatus(): Folder {
|
||||
$this->status = $this->examine();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Examine the current folder
|
||||
*
|
||||
* @return array
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
* @throws AuthFailedException
|
||||
* @throws ResponseException
|
||||
*/
|
||||
public function examine(): array {
|
||||
return $this->client->getConnection()->examineFolder($this->path)->validatedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the current folder
|
||||
*
|
||||
* @return array
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws ResponseException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function select(): array {
|
||||
return $this->client->getConnection()->selectFolder($this->path)->validatedData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current Client instance
|
||||
*
|
||||
* @return Client
|
||||
*/
|
||||
public function getClient(): Client {
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the delimiter
|
||||
* @param $delimiter
|
||||
*/
|
||||
public function setDelimiter($delimiter): void {
|
||||
if (in_array($delimiter, [null, '', ' ', false]) === true) {
|
||||
$delimiter = $this->client->getConfig()->get('options.delimiter', '/');
|
||||
}
|
||||
|
||||
$this->delimiter = $delimiter;
|
||||
}
|
||||
}
|
||||
871
plugins/vendor/webklex/php-imap/src/Header.php
vendored
Normal file
871
plugins/vendor/webklex/php-imap/src/Header.php
vendored
Normal file
@@ -0,0 +1,871 @@
|
||||
<?php
|
||||
/*
|
||||
* File: Header.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 17.09.20 20:38
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Webklex\PHPIMAP\Decoder\DecoderInterface;
|
||||
use Webklex\PHPIMAP\Exceptions\DecoderNotFoundException;
|
||||
use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException;
|
||||
use Webklex\PHPIMAP\Exceptions\MethodNotFoundException;
|
||||
use Webklex\PHPIMAP\Exceptions\SpoofingAttemptDetectedException;
|
||||
|
||||
/**
|
||||
* Class Header
|
||||
*
|
||||
* @package Webklex\PHPIMAP
|
||||
*/
|
||||
class Header {
|
||||
|
||||
/**
|
||||
* Raw header
|
||||
*
|
||||
* @var string $raw
|
||||
*/
|
||||
public string $raw = "";
|
||||
|
||||
/**
|
||||
* Attribute holder
|
||||
*
|
||||
* @var Attribute[]|array $attributes
|
||||
*/
|
||||
protected array $attributes = [];
|
||||
|
||||
/**
|
||||
* Config holder
|
||||
*
|
||||
* @var Config $config
|
||||
*/
|
||||
protected Config $config;
|
||||
|
||||
/**
|
||||
* Config holder
|
||||
*
|
||||
* @var array $options
|
||||
*/
|
||||
protected array $options = [];
|
||||
|
||||
/**
|
||||
* Decoder instance
|
||||
*
|
||||
* @var DecoderInterface $decoder
|
||||
*/
|
||||
protected DecoderInterface $decoder;
|
||||
|
||||
/**
|
||||
* Header constructor.
|
||||
* @param Config $config
|
||||
* @param string $raw_header
|
||||
*
|
||||
* @throws InvalidMessageDateException
|
||||
* @throws DecoderNotFoundException
|
||||
*/
|
||||
public function __construct(string $raw_header, Config $config) {
|
||||
$this->decoder = $config->getDecoder("header");
|
||||
$this->raw = $raw_header;
|
||||
$this->config = $config;
|
||||
$this->options = $this->config->get('options');
|
||||
$this->parse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call dynamic attribute setter and getter methods
|
||||
* @param string $method
|
||||
* @param array $arguments
|
||||
*
|
||||
* @return Attribute|mixed
|
||||
* @throws MethodNotFoundException
|
||||
*/
|
||||
public function __call(string $method, array $arguments) {
|
||||
if (strtolower(substr($method, 0, 3)) === 'get') {
|
||||
$name = preg_replace('/(.)(?=[A-Z])/u', '$1_', substr(strtolower($method), 3));
|
||||
|
||||
if (in_array($name, array_keys($this->attributes))) {
|
||||
return $this->attributes[$name];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
throw new MethodNotFoundException("Method " . self::class . '::' . $method . '() is not supported');
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic getter
|
||||
* @param $name
|
||||
*
|
||||
* @return Attribute|null
|
||||
*/
|
||||
public function __get($name) {
|
||||
return $this->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific header attribute
|
||||
* @param $name
|
||||
*
|
||||
* @return Attribute
|
||||
*/
|
||||
public function get($name): Attribute {
|
||||
$name = str_replace(["-", " "], "_", strtolower($name));
|
||||
if (isset($this->attributes[$name])) {
|
||||
return $this->attributes[$name];
|
||||
}
|
||||
|
||||
return new Attribute($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a specific attribute exists
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $name): bool {
|
||||
$name = str_replace(["-", " "], "_", strtolower($name));
|
||||
return isset($this->attributes[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific attribute
|
||||
* @param string $name
|
||||
* @param array|mixed $value
|
||||
* @param boolean $strict
|
||||
*
|
||||
* @return Attribute|array
|
||||
*/
|
||||
public function set(string $name, mixed $value, bool $strict = false): Attribute|array {
|
||||
if (isset($this->attributes[$name]) && $strict === false) {
|
||||
$this->attributes[$name]->add($value, true);
|
||||
} else {
|
||||
$this->attributes[$name] = new Attribute($name, $value);
|
||||
}
|
||||
|
||||
return $this->attributes[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a regex match all on the raw header and return the first result
|
||||
* @param $pattern
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function find($pattern): mixed {
|
||||
if (preg_match_all($pattern, $this->raw, $matches)) {
|
||||
if (isset($matches[1])) {
|
||||
if (count($matches[1]) > 0) {
|
||||
return $matches[1][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find a boundary if possible
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getBoundary(): ?string {
|
||||
$regex = $this->options["boundary"] ?? "/boundary=(.*?(?=;)|(.*))/i";
|
||||
$boundary = $this->find($regex);
|
||||
|
||||
if ($boundary === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->clearBoundaryString($boundary);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all unwanted chars from a given boundary
|
||||
* @param string $str
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function clearBoundaryString(string $str): string {
|
||||
return str_replace(['"', '\r', '\n', "\n", "\r", ";", "\s"], "", $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the raw headers
|
||||
*
|
||||
* @throws InvalidMessageDateException
|
||||
* @throws SpoofingAttemptDetectedException
|
||||
*/
|
||||
protected function parse(): void {
|
||||
$header = $this->rfc822_parse_headers($this->raw);
|
||||
|
||||
$this->extractAddresses($header);
|
||||
|
||||
if (property_exists($header, 'subject')) {
|
||||
$this->set("subject", $this->decoder->decode($header->subject));
|
||||
}
|
||||
if (property_exists($header, 'references')) {
|
||||
$this->set("references", array_map(function($item) {
|
||||
return str_replace(['<', '>'], '', $item);
|
||||
}, explode(" ", $header->references)));
|
||||
}
|
||||
if (property_exists($header, 'message_id')) {
|
||||
$this->set("message_id", str_replace(['<', '>'], '', $header->message_id));
|
||||
}
|
||||
if (property_exists($header, 'in_reply_to')) {
|
||||
$this->set("in_reply_to", str_replace(['<', '>'], '', $header->in_reply_to));
|
||||
}
|
||||
|
||||
$this->parseDate($header);
|
||||
foreach ($header as $key => $value) {
|
||||
$key = trim(rtrim(strtolower($key)));
|
||||
if (!isset($this->attributes[$key])) {
|
||||
$this->set($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$this->extractHeaderExtensions();
|
||||
$this->findPriority();
|
||||
|
||||
if($this->config->get('security.detect_spoofing', true)) {
|
||||
// Detect spoofing
|
||||
$this->detectSpoofing();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse mail headers from a string
|
||||
* @link https://php.net/manual/en/function.imap-rfc822-parse-headers.php
|
||||
* @param $raw_headers
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function rfc822_parse_headers($raw_headers): object {
|
||||
$headers = [];
|
||||
$imap_headers = [];
|
||||
if (extension_loaded('imap') && $this->options["rfc822"]) {
|
||||
$raw_imap_headers = (array)\imap_rfc822_parse_headers($raw_headers);
|
||||
foreach ($raw_imap_headers as $key => $values) {
|
||||
$key = strtolower(str_replace("-", "_", $key));
|
||||
$imap_headers[$key] = $values;
|
||||
}
|
||||
}
|
||||
$lines = explode("\r\n", preg_replace("/\r\n\s/", ' ', $raw_headers));
|
||||
$prev_header = null;
|
||||
foreach ($lines as $line) {
|
||||
if (str_starts_with($line, "\n")) {
|
||||
$line = substr($line, 1);
|
||||
}
|
||||
|
||||
if (str_starts_with($line, "\t")) {
|
||||
$line = substr($line, 1);
|
||||
$line = trim(rtrim($line));
|
||||
if ($prev_header !== null) {
|
||||
$headers[$prev_header][] = $line;
|
||||
}
|
||||
} elseif (str_starts_with($line, " ")) {
|
||||
$line = substr($line, 1);
|
||||
$line = trim(rtrim($line));
|
||||
if ($prev_header !== null) {
|
||||
if (!isset($headers[$prev_header])) {
|
||||
$headers[$prev_header] = "";
|
||||
}
|
||||
if (is_array($headers[$prev_header])) {
|
||||
$headers[$prev_header][] = $line;
|
||||
} else {
|
||||
$headers[$prev_header] .= $line;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (($pos = strpos($line, ":")) > 0) {
|
||||
$key = trim(rtrim(strtolower(substr($line, 0, $pos))));
|
||||
$key = strtolower(str_replace("-", "_", $key));
|
||||
|
||||
$value = trim(rtrim(substr($line, $pos + 1)));
|
||||
if (isset($headers[$key])) {
|
||||
$headers[$key][] = $value;
|
||||
} else {
|
||||
$headers[$key] = [$value];
|
||||
}
|
||||
$prev_header = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($headers as $key => $values) {
|
||||
if (isset($imap_headers[$key])) {
|
||||
continue;
|
||||
}
|
||||
$value = null;
|
||||
switch ((string)$key) {
|
||||
case 'from':
|
||||
case 'to':
|
||||
case 'cc':
|
||||
case 'bcc':
|
||||
case 'reply_to':
|
||||
case 'sender':
|
||||
$value = $this->decodeAddresses($values);
|
||||
$headers[$key . "address"] = implode(", ", $values);
|
||||
break;
|
||||
case 'subject':
|
||||
$value = implode(" ", $values);
|
||||
break;
|
||||
default:
|
||||
if (is_array($values)) {
|
||||
foreach ($values as $k => $v) {
|
||||
if ($v == "") {
|
||||
unset($values[$k]);
|
||||
}
|
||||
}
|
||||
$available_values = count($values);
|
||||
if ($available_values === 1) {
|
||||
$value = array_pop($values);
|
||||
} elseif ($available_values === 2) {
|
||||
$value = implode(" ", $values);
|
||||
} elseif ($available_values > 2) {
|
||||
$value = array_values($values);
|
||||
} else {
|
||||
$value = "";
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
$headers[$key] = $value;
|
||||
}
|
||||
|
||||
return (object)array_merge($headers, $imap_headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to extract the priority from a given raw header string
|
||||
*/
|
||||
private function findPriority(): void {
|
||||
$priority = $this->get("x_priority");
|
||||
|
||||
$priority = match ((int)"$priority") {
|
||||
IMAP::MESSAGE_PRIORITY_HIGHEST => IMAP::MESSAGE_PRIORITY_HIGHEST,
|
||||
IMAP::MESSAGE_PRIORITY_HIGH => IMAP::MESSAGE_PRIORITY_HIGH,
|
||||
IMAP::MESSAGE_PRIORITY_NORMAL => IMAP::MESSAGE_PRIORITY_NORMAL,
|
||||
IMAP::MESSAGE_PRIORITY_LOW => IMAP::MESSAGE_PRIORITY_LOW,
|
||||
IMAP::MESSAGE_PRIORITY_LOWEST => IMAP::MESSAGE_PRIORITY_LOWEST,
|
||||
default => IMAP::MESSAGE_PRIORITY_UNKNOWN,
|
||||
};
|
||||
|
||||
$this->set("priority", $priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a given part as address array from a given header
|
||||
* @param $values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function decodeAddresses($values): array {
|
||||
$addresses = [];
|
||||
|
||||
if (extension_loaded('mailparse') && $this->options["rfc822"]) {
|
||||
foreach ($values as $address) {
|
||||
foreach (\mailparse_rfc822_parse_addresses($address) as $parsed_address) {
|
||||
if (isset($parsed_address['address'])) {
|
||||
$mail_address = explode('@', $parsed_address['address']);
|
||||
if (count($mail_address) == 2) {
|
||||
$addresses[] = (object)[
|
||||
"personal" => $parsed_address['display'] ?? '',
|
||||
"mailbox" => $mail_address[0],
|
||||
"host" => $mail_address[1],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $addresses;
|
||||
}
|
||||
|
||||
foreach ($values as $address) {
|
||||
foreach (preg_split('/, ?(?=(?:[^"]*"[^"]*")*[^"]*$)/', $address) as $split_address) {
|
||||
$split_address = trim(rtrim($split_address));
|
||||
|
||||
if (strpos($split_address, ",") == strlen($split_address) - 1) {
|
||||
$split_address = substr($split_address, 0, -1);
|
||||
}
|
||||
if (preg_match(
|
||||
'/^(?:(?P<name>.+)\s)?(?(name)<|<?)(?P<email>[^\s]+?)(?(name)>|>?)$/',
|
||||
$split_address,
|
||||
$matches
|
||||
)) {
|
||||
$name = trim(rtrim($matches["name"]));
|
||||
$email = trim(rtrim($matches["email"]));
|
||||
list($mailbox, $host) = array_pad(explode("@", $email), 2, null);
|
||||
$addresses[] = (object)[
|
||||
"personal" => $name,
|
||||
"mailbox" => $mailbox,
|
||||
"host" => $host,
|
||||
];
|
||||
}elseif (preg_match(
|
||||
'/^((?P<name>.+)<)(?P<email>[^<]+?)>$/',
|
||||
$split_address,
|
||||
$matches
|
||||
)) {
|
||||
$name = trim(rtrim($matches["name"]));
|
||||
if(str_starts_with($name, "\"") && str_ends_with($name, "\"")) {
|
||||
$name = substr($name, 1, -1);
|
||||
}elseif(str_starts_with($name, "'") && str_ends_with($name, "'")) {
|
||||
$name = substr($name, 1, -1);
|
||||
}
|
||||
$email = trim(rtrim($matches["email"]));
|
||||
list($mailbox, $host) = array_pad(explode("@", $email), 2, null);
|
||||
$addresses[] = (object)[
|
||||
"personal" => $name,
|
||||
"mailbox" => $mailbox,
|
||||
"host" => $host,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $addresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a given part as address array from a given header
|
||||
* @param object $header
|
||||
*/
|
||||
private function extractAddresses(object $header): void {
|
||||
foreach (['from', 'to', 'cc', 'bcc', 'reply_to', 'sender', 'return_path', 'envelope_from', 'envelope_to', 'delivered_to'] as $key) {
|
||||
if (property_exists($header, $key)) {
|
||||
$this->set($key, $this->parseAddresses($header->$key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse Addresses
|
||||
* @param $list
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function parseAddresses($list): array {
|
||||
$addresses = [];
|
||||
|
||||
if (is_array($list) === false) {
|
||||
if(is_string($list)) {
|
||||
if (preg_match(
|
||||
'/^(?:(?P<name>.+)\s)?(?(name)<|<?)(?P<email>[^\s]+?)(?(name)>|>?)$/',
|
||||
$list,
|
||||
$matches
|
||||
)) {
|
||||
$name = trim(rtrim($matches["name"]));
|
||||
$email = trim(rtrim($matches["email"]));
|
||||
list($mailbox, $host) = array_pad(explode("@", $email), 2, null);
|
||||
if($mailbox === ">") { // Fix trailing ">" in malformed mailboxes
|
||||
$mailbox = "";
|
||||
}
|
||||
if($name === "" && $mailbox === "" && $host === "") {
|
||||
return $addresses;
|
||||
}
|
||||
$list = [
|
||||
(object)[
|
||||
"personal" => $name,
|
||||
"mailbox" => $mailbox,
|
||||
"host" => $host,
|
||||
]
|
||||
];
|
||||
}elseif (preg_match(
|
||||
'/^((?P<name>.+)<)(?P<email>[^<]+?)>$/',
|
||||
$list,
|
||||
$matches
|
||||
)) {
|
||||
$name = trim(rtrim($matches["name"]));
|
||||
$email = trim(rtrim($matches["email"]));
|
||||
if(str_starts_with($name, "\"") && str_ends_with($name, "\"")) {
|
||||
$name = substr($name, 1, -1);
|
||||
}elseif(str_starts_with($name, "'") && str_ends_with($name, "'")) {
|
||||
$name = substr($name, 1, -1);
|
||||
}
|
||||
list($mailbox, $host) = array_pad(explode("@", $email), 2, null);
|
||||
if($mailbox === ">") { // Fix trailing ">" in malformed mailboxes
|
||||
$mailbox = "";
|
||||
}
|
||||
if($name === "" && $mailbox === "" && $host === "") {
|
||||
return $addresses;
|
||||
}
|
||||
$list = [
|
||||
(object)[
|
||||
"personal" => $name,
|
||||
"mailbox" => $mailbox,
|
||||
"host" => $host,
|
||||
]
|
||||
];
|
||||
}else{
|
||||
return $addresses;
|
||||
}
|
||||
}else{
|
||||
return $addresses;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($list as $item) {
|
||||
$address = (object)$item;
|
||||
|
||||
if (!property_exists($address, 'mailbox')) {
|
||||
$address->mailbox = false;
|
||||
}
|
||||
if (!property_exists($address, 'host')) {
|
||||
$address->host = false;
|
||||
}
|
||||
if (!property_exists($address, 'personal')) {
|
||||
$address->personal = false;
|
||||
} else {
|
||||
$personal_slices = explode(" ", $address->personal);
|
||||
$address->personal = "";
|
||||
foreach ($personal_slices as $slice) {
|
||||
$personalParts = $this->decoder->mimeHeaderDecode($slice);
|
||||
|
||||
$personal = '';
|
||||
foreach ($personalParts as $p) {
|
||||
$personal .= $this->decoder->convertEncoding($p->text, $this->decoder->getEncoding($p));
|
||||
}
|
||||
|
||||
if (str_starts_with($personal, "'")) {
|
||||
$personal = str_replace("'", "", $personal);
|
||||
}
|
||||
$personal = $this->decoder->decode($personal);
|
||||
$address->personal .= $personal . " ";
|
||||
}
|
||||
$address->personal = trim(rtrim($address->personal));
|
||||
}
|
||||
|
||||
if ($address->host == ".SYNTAX-ERROR.") {
|
||||
$address->host = "";
|
||||
}elseif ($address->host == "UNKNOWN") {
|
||||
$address->host = "";
|
||||
}
|
||||
if ($address->mailbox == "UNEXPECTED_DATA_AFTER_ADDRESS") {
|
||||
$address->mailbox = "";
|
||||
}elseif ($address->mailbox == "MISSING_MAILBOX_TERMINATOR") {
|
||||
$address->mailbox = "";
|
||||
}
|
||||
|
||||
$addresses[] = new Address($address);
|
||||
}
|
||||
|
||||
return $addresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search and extract potential header extensions
|
||||
*/
|
||||
private function extractHeaderExtensions(): void {
|
||||
foreach ($this->attributes as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$value = implode(", ", $value);
|
||||
} else {
|
||||
$value = (string)$value;
|
||||
}
|
||||
// Only parse strings and don't parse any attributes like the user-agent
|
||||
if (!in_array($key, ["user-agent", "subject", "received"])) {
|
||||
if (str_contains($value, ";") && str_contains($value, "=")) {
|
||||
$_attributes = $this->read_attribute($value);
|
||||
foreach($_attributes as $_key => $_value) {
|
||||
if($_value === "") {
|
||||
$this->set($key, $_key);
|
||||
}
|
||||
if (!isset($this->attributes[$_key])) {
|
||||
$this->set($_key, $_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a given attribute string
|
||||
* - this isn't pretty, but it works - feel free to improve :)
|
||||
* @param string $raw_attribute
|
||||
* @return array
|
||||
*/
|
||||
private function read_attribute(string $raw_attribute): array {
|
||||
$attributes = [];
|
||||
$key = '';
|
||||
$value = '';
|
||||
$inside_word = false;
|
||||
$inside_key = true;
|
||||
$escaped = false;
|
||||
foreach (str_split($raw_attribute) as $char) {
|
||||
if($escaped) {
|
||||
$escaped = false;
|
||||
continue;
|
||||
}
|
||||
if($inside_word) {
|
||||
if($char === '\\') {
|
||||
$escaped = true;
|
||||
}elseif($char === "\"" && $value !== "") {
|
||||
$inside_word = false;
|
||||
}else{
|
||||
$value .= $char;
|
||||
}
|
||||
}else{
|
||||
if($inside_key) {
|
||||
if($char === '"') {
|
||||
$inside_word = true;
|
||||
}elseif($char === ';'){
|
||||
$attributes[$key] = $value;
|
||||
$key = '';
|
||||
$value = '';
|
||||
$inside_key = true;
|
||||
}elseif($char === '=') {
|
||||
$inside_key = false;
|
||||
}else{
|
||||
$key .= $char;
|
||||
}
|
||||
}else{
|
||||
if($char === '"' && $value === "") {
|
||||
$inside_word = true;
|
||||
}elseif($char === ';'){
|
||||
$attributes[$key] = $value;
|
||||
$key = '';
|
||||
$value = '';
|
||||
$inside_key = true;
|
||||
}else{
|
||||
$value .= $char;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$attributes[$key] = $value;
|
||||
$result = [];
|
||||
|
||||
foreach($attributes as $key => $value) {
|
||||
if (($pos = strpos($key, "*")) !== false) {
|
||||
$key = substr($key, 0, $pos);
|
||||
}
|
||||
$key = trim(rtrim(strtolower($key)));
|
||||
|
||||
if(!isset($result[$key])) {
|
||||
$result[$key] = "";
|
||||
}
|
||||
$value = trim(rtrim(str_replace(["\r", "\n"], "", $value)));
|
||||
if(str_starts_with($value, "\"") && str_ends_with($value, "\"")) {
|
||||
$value = substr($value, 1, -1);
|
||||
}
|
||||
$result[$key] .= $value;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception handling for invalid dates
|
||||
*
|
||||
* Known bad and "invalid" formats:
|
||||
* ^ Datetime ^ Problem ^ Cause
|
||||
* | Mon, 20 Nov 2017 20:31:31 +0800 (GMT+8:00) | Double timezone specification | A Windows feature
|
||||
* | Thu, 8 Nov 2018 08:54:58 -0200 (-02) |
|
||||
* | | and invalid timezone (max 6 char) |
|
||||
* | 04 Jan 2018 10:12:47 UT | Missing letter "C" | Unknown
|
||||
* | Thu, 31 May 2018 18:15:00 +0800 (added by) | Non-standard details added by the | Unknown
|
||||
* | | mail server |
|
||||
* | Sat, 31 Aug 2013 20:08:23 +0580 | Invalid timezone | PHPMailer bug https://sourceforge.net/p/phpmailer/mailman/message/6132703/
|
||||
* | Mi., 23 Apr. 2025 09:48:37 +0200 (MESZ) | Non-standard localized format | Aqua Mail S/MIME implementation
|
||||
*
|
||||
* Please report any new invalid timestamps to [#45](https://github.com/Webklex/php-imap/issues)
|
||||
*
|
||||
* @param object $header
|
||||
*
|
||||
* @throws InvalidMessageDateException
|
||||
*/
|
||||
private function parseDate(object $header): void {
|
||||
|
||||
if (property_exists($header, 'date')) {
|
||||
$date = $header->date;
|
||||
|
||||
if (preg_match('/\+0580/', $date)) {
|
||||
$date = str_replace('+0580', '+0530', $date);
|
||||
}
|
||||
|
||||
$date = trim(rtrim($date));
|
||||
try {
|
||||
if (str_contains($date, ' ')) {
|
||||
$date = str_replace(' ', ' ', $date);
|
||||
}
|
||||
if (str_contains($date, ' UT ')) {
|
||||
$date = str_replace(' UT ', ' UTC ', $date);
|
||||
}
|
||||
$parsed_date = Carbon::parse($date);
|
||||
} catch (\Exception $e) {
|
||||
switch (true) {
|
||||
case preg_match('/([0-9]{4}\.[0-9]{1,2}\.[0-9]{1,2}\-[0-9]{1,2}\.[0-9]{1,2}.[0-9]{1,2})+$/i', $date) > 0:
|
||||
$date = Carbon::createFromFormat("Y.m.d-H.i.s", $date);
|
||||
break;
|
||||
case preg_match('/([0-9]{2} [A-Z]{3} [0-9]{4} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2} [+-][0-9]{1,4} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2} [+-][0-9]{1,4})+$/i', $date) > 0:
|
||||
$parts = explode(' ', $date);
|
||||
array_splice($parts, -2);
|
||||
$date = implode(' ', $parts);
|
||||
break;
|
||||
case preg_match('/([A-Z]{2,4}\,\ [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:
|
||||
$array = explode(',', $date);
|
||||
array_shift($array);
|
||||
$date = Carbon::createFromFormat("d M Y H:i:s O", trim(implode(',', $array)));
|
||||
break;
|
||||
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:
|
||||
case preg_match('/([A-Z]{2,3}\,\ [0-9]{1,2}\ [A-Z]{2,3}\ ([0-9]{2}|[0-9]{4})\ [0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\ UT)+$/i', $date) > 0:
|
||||
$date .= 'C';
|
||||
break;
|
||||
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:
|
||||
$date = str_replace(',', '', $date);
|
||||
break;
|
||||
// match case for: Di., 15 Feb. 2022 06:52:44 +0100 (MEZ)/Di., 15 Feb. 2022 06:52:44 +0100 (MEZ) and Mi., 23 Apr. 2025 09:48:37 +0200 (MESZ)
|
||||
case preg_match('/([A-Z]{2,3}\.\,\ [0-9]{1,2}\ [A-Z]{2,3}\.\ [0-9]{4}\ [0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\ [\-|\+][0-9]{4}\ \([A-Z]{3,4}\))(\/([A-Z]{2,3}\.\,\ [0-9]{1,2}\ [A-Z]{2,3}\.\ [0-9]{4}\ [0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\ [\-|\+][0-9]{4}\ \([A-Z]{3,4}\))+)?$/i', $date) > 0:
|
||||
$dates = explode('/', $date);
|
||||
$date = array_shift($dates);
|
||||
$array = explode(',', $date);
|
||||
array_shift($array);
|
||||
$date = trim(implode(',', $array));
|
||||
$array = explode(' ', $date);
|
||||
array_pop($array);
|
||||
$date = trim(implode(' ', $array));
|
||||
$date = Carbon::createFromFormat("d M. Y H:i:s O", $date);
|
||||
break;
|
||||
// match case for: fr., 25 nov. 2022 06:27:14 +0100/fr., 25 nov. 2022 06:27:14 +0100
|
||||
case preg_match('/([A-Z]{2,3}\.\,\ [0-9]{1,2}\ [A-Z]{2,3}\.\ [0-9]{4}\ [0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\ [\-|\+][0-9]{4})\/([A-Z]{2,3}\.\,\ [0-9]{1,2}\ [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:
|
||||
$dates = explode('/', $date);
|
||||
$date = array_shift($dates);
|
||||
$array = explode(',', $date);
|
||||
array_shift($array);
|
||||
$date = trim(implode(',', $array));
|
||||
$date = Carbon::createFromFormat("d M. Y H:i:s O", $date);
|
||||
break;
|
||||
case preg_match('/([A-Z]{2,3}\,\ [0-9]{1,2}\ [A-Z]{2,3}\ [0-9]{4}\ [0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\ \+[0-9]{2,4}\ \(\+[0-9]{1,2}\))+$/i', $date) > 0:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
$array = explode('(', $date);
|
||||
$array = array_reverse($array);
|
||||
$date = trim(array_pop($array));
|
||||
break;
|
||||
}
|
||||
try {
|
||||
$parsed_date = Carbon::parse($date);
|
||||
} catch (\Exception $_e) {
|
||||
if (!isset($this->options["fallback_date"])) {
|
||||
throw new InvalidMessageDateException("Invalid message date. ID:" . $this->get("message_id") . " Date:" . $header->date . "/" . $date, 1100, $e);
|
||||
} else {
|
||||
$parsed_date = Carbon::parse($this->options["fallback_date"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->set("date", $parsed_date);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available attributes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAttributes(): array {
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all header attributes
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Header
|
||||
*/
|
||||
public function setAttributes(array $attributes): Header {
|
||||
$this->attributes = $attributes;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the configuration used for parsing a raw header
|
||||
* @param array $config
|
||||
*
|
||||
* @return Header
|
||||
*/
|
||||
public function setOptions(array $config): Header {
|
||||
$this->options = $config;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configuration used for parsing a raw header
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions(): array {
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the configuration used for parsing a raw header
|
||||
* @param Config $config
|
||||
*
|
||||
* @return Header
|
||||
*/
|
||||
public function setConfig(Config $config): Header {
|
||||
$this->config = $config;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configuration used for parsing a raw header
|
||||
*
|
||||
* @return Config
|
||||
*/
|
||||
public function getConfig(): Config {
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the decoder instance
|
||||
*
|
||||
* @return DecoderInterface
|
||||
*/
|
||||
public function getDecoder(): DecoderInterface {
|
||||
return $this->decoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the decoder instance
|
||||
* @param DecoderInterface $decoder
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDecoder(DecoderInterface $decoder): static {
|
||||
$this->decoder = $decoder;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect spoofing by checking the from, reply_to, return_path, sender and envelope_from headers
|
||||
* @throws SpoofingAttemptDetectedException
|
||||
*/
|
||||
private function detectSpoofing(): void {
|
||||
$header_keys = ["from", "reply_to", "return_path", "sender", "envelope_from"];
|
||||
$potential_senders = [];
|
||||
foreach($header_keys as $key) {
|
||||
$header = $this->get($key);
|
||||
foreach ($header->toArray() as $address) {
|
||||
$potential_senders[] = $address->mailbox . "@" . $address->host;
|
||||
}
|
||||
}
|
||||
if(count($potential_senders) > 1) {
|
||||
$this->set("spoofed", true);
|
||||
if($this->config->get('security.detect_spoofing_exception', false)) {
|
||||
throw new SpoofingAttemptDetectedException("Potential spoofing detected. Message ID: " . $this->get("message_id") . " Senders: " . implode(", ", $potential_senders));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
375
plugins/vendor/webklex/php-imap/src/IMAP.php
vendored
Normal file
375
plugins/vendor/webklex/php-imap/src/IMAP.php
vendored
Normal file
@@ -0,0 +1,375 @@
|
||||
<?php
|
||||
/*
|
||||
* File: IMAP.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 14.03.19 18:22
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP;
|
||||
|
||||
/**
|
||||
* Class IMAP
|
||||
*
|
||||
* Independent imap const holder
|
||||
*/
|
||||
class IMAP {
|
||||
|
||||
/**
|
||||
* Message const
|
||||
*
|
||||
* @const integer TYPE_TEXT
|
||||
* @const integer TYPE_MULTIPART
|
||||
*
|
||||
* @const integer ENC_7BIT
|
||||
* @const integer ENC_8BIT
|
||||
* @const integer ENC_BINARY
|
||||
* @const integer ENC_BASE64
|
||||
* @const integer ENC_QUOTED_PRINTABLE
|
||||
* @const integer ENC_OTHER
|
||||
*/
|
||||
const MESSAGE_TYPE_TEXT = 0;
|
||||
const MESSAGE_TYPE_MULTIPART = 1;
|
||||
|
||||
const MESSAGE_ENC_7BIT = 0;
|
||||
const MESSAGE_ENC_8BIT = 1;
|
||||
const MESSAGE_ENC_BINARY = 2;
|
||||
const MESSAGE_ENC_BASE64 = 3;
|
||||
const MESSAGE_ENC_QUOTED_PRINTABLE = 4;
|
||||
const MESSAGE_ENC_OTHER = 5;
|
||||
|
||||
const MESSAGE_PRIORITY_UNKNOWN = 0;
|
||||
const MESSAGE_PRIORITY_HIGHEST = 1;
|
||||
const MESSAGE_PRIORITY_HIGH = 2;
|
||||
const MESSAGE_PRIORITY_NORMAL = 3;
|
||||
const MESSAGE_PRIORITY_LOW = 4;
|
||||
const MESSAGE_PRIORITY_LOWEST = 5;
|
||||
|
||||
/**
|
||||
* Attachment const
|
||||
*
|
||||
* @const integer TYPE_TEXT
|
||||
* @const integer TYPE_MULTIPART
|
||||
* @const integer TYPE_MESSAGE
|
||||
* @const integer TYPE_APPLICATION
|
||||
* @const integer TYPE_AUDIO
|
||||
* @const integer TYPE_IMAGE
|
||||
* @const integer TYPE_VIDEO
|
||||
* @const integer TYPE_MODEL
|
||||
* @const integer TYPE_OTHER
|
||||
*/
|
||||
const ATTACHMENT_TYPE_TEXT = 0;
|
||||
const ATTACHMENT_TYPE_MULTIPART = 1;
|
||||
const ATTACHMENT_TYPE_MESSAGE = 2;
|
||||
const ATTACHMENT_TYPE_APPLICATION = 3;
|
||||
const ATTACHMENT_TYPE_AUDIO = 4;
|
||||
const ATTACHMENT_TYPE_IMAGE = 5;
|
||||
const ATTACHMENT_TYPE_VIDEO = 6;
|
||||
const ATTACHMENT_TYPE_MODEL = 7;
|
||||
const ATTACHMENT_TYPE_OTHER = 8;
|
||||
|
||||
/**
|
||||
* Client const
|
||||
*
|
||||
* @const integer CLIENT_OPENTIMEOUT
|
||||
* @const integer CLIENT_READTIMEOUT
|
||||
* @const integer CLIENT_WRITETIMEOUT
|
||||
* @const integer CLIENT_CLOSETIMEOUT
|
||||
*/
|
||||
const CLIENT_OPENTIMEOUT = 1;
|
||||
const CLIENT_READTIMEOUT = 2;
|
||||
const CLIENT_WRITETIMEOUT = 3;
|
||||
const CLIENT_CLOSETIMEOUT = 4;
|
||||
|
||||
/**
|
||||
* Generic imap const
|
||||
*
|
||||
* @const integer NIL
|
||||
* @const integer IMAP_OPENTIMEOUT
|
||||
* @const integer IMAP_READTIMEOUT
|
||||
* @const integer IMAP_WRITETIMEOUT
|
||||
* @const integer IMAP_CLOSETIMEOUT
|
||||
* @const integer OP_DEBUG
|
||||
* @const integer OP_READONLY
|
||||
* @const integer OP_ANONYMOUS
|
||||
* @const integer OP_SHORTCACHE
|
||||
* @const integer OP_SILENT
|
||||
* @const integer OP_PROTOTYPE
|
||||
* @const integer OP_HALFOPEN
|
||||
* @const integer OP_EXPUNGE
|
||||
* @const integer OP_SECURE
|
||||
* @const integer CL_EXPUNGE
|
||||
* @const integer FT_UID
|
||||
* @const integer FT_PEEK
|
||||
* @const integer FT_NOT
|
||||
* @const integer FT_INTERNAL
|
||||
* @const integer FT_PREFETCHTEXT
|
||||
* @const integer ST_UID
|
||||
* @const integer ST_SILENT
|
||||
* @const integer ST_SET
|
||||
* @const integer CP_UID
|
||||
* @const integer CP_MOVE
|
||||
* @const integer SE_UID
|
||||
* @const integer SE_FREE
|
||||
* @const integer SE_NOPREFETCH
|
||||
* @const integer SO_FREE
|
||||
* @const integer SO_NOSERVER
|
||||
* @const integer SA_MESSAGES
|
||||
* @const integer SA_RECENT
|
||||
* @const integer SA_UNSEEN
|
||||
* @const integer SA_UIDNEXT
|
||||
* @const integer SA_UIDVALIDITY
|
||||
* @const integer SA_ALL
|
||||
* @const integer LATT_NOINFERIORS
|
||||
* @const integer LATT_NOSELECT
|
||||
* @const integer LATT_MARKED
|
||||
* @const integer LATT_UNMARKED
|
||||
* @const integer LATT_REFERRAL
|
||||
* @const integer LATT_HASCHILDREN
|
||||
* @const integer LATT_HASNOCHILDREN
|
||||
* @const integer SORTDATE
|
||||
* @const integer SORTARRIVAL
|
||||
* @const integer SORTFROM
|
||||
* @const integer SORTSUBJECT
|
||||
* @const integer SORTTO
|
||||
* @const integer SORTCC
|
||||
* @const integer SORTSIZE
|
||||
* @const integer TYPETEXT
|
||||
* @const integer TYPEMULTIPART
|
||||
* @const integer TYPEMESSAGE
|
||||
* @const integer TYPEAPPLICATION
|
||||
* @const integer TYPEAUDIO
|
||||
* @const integer TYPEIMAGE
|
||||
* @const integer TYPEVIDEO
|
||||
* @const integer TYPEMODEL
|
||||
* @const integer TYPEOTHER
|
||||
* @const integer ENC7BIT
|
||||
* @const integer ENC8BIT
|
||||
* @const integer ENCBINARY
|
||||
* @const integer ENCBASE64
|
||||
* @const integer ENCQUOTEDPRINTABLE
|
||||
* @const integer ENCOTHER
|
||||
* @const integer IMAP_GC_ELT
|
||||
* @const integer IMAP_GC_ENV
|
||||
* @const integer IMAP_GC_TEXTS
|
||||
*/
|
||||
|
||||
const NIL = 0;
|
||||
const IMAP_OPENTIMEOUT = 1;
|
||||
const IMAP_READTIMEOUT = 2;
|
||||
const IMAP_WRITETIMEOUT = 3;
|
||||
const IMAP_CLOSETIMEOUT = 4;
|
||||
const OP_DEBUG = 1;
|
||||
|
||||
/**
|
||||
* Open mailbox read-only
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const OP_READONLY = 2;
|
||||
|
||||
/**
|
||||
* Don't use or update a .newsrc for news
|
||||
* (NNTP only)
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const OP_ANONYMOUS = 4;
|
||||
const OP_SHORTCACHE = 8;
|
||||
const OP_SILENT = 16;
|
||||
const OP_PROTOTYPE = 32;
|
||||
|
||||
/**
|
||||
* For IMAP and NNTP
|
||||
* names, open a connection but don't open a mailbox.
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const OP_HALFOPEN = 64;
|
||||
const OP_EXPUNGE = 128;
|
||||
const OP_SECURE = 256;
|
||||
|
||||
/**
|
||||
* silently expunge the mailbox before closing when
|
||||
* calling <b>imap_close</b>
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const CL_EXPUNGE = 32768;
|
||||
|
||||
/**
|
||||
* The parameter is a UID
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const FT_UID = 1;
|
||||
|
||||
/**
|
||||
* Do not set the \Seen flag if not already set
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const FT_PEEK = 2;
|
||||
const FT_NOT = 4;
|
||||
|
||||
/**
|
||||
* The return string is in internal format, will not canonicalize to CRLF.
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const FT_INTERNAL = 8;
|
||||
const FT_PREFETCHTEXT = 32;
|
||||
|
||||
/**
|
||||
* The sequence argument contains UIDs instead of sequence numbers
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const ST_UID = 1;
|
||||
const ST_SILENT = 2;
|
||||
const ST_MSGN = 3;
|
||||
const ST_SET = 4;
|
||||
|
||||
/**
|
||||
* the sequence numbers contain UIDS
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const CP_UID = 1;
|
||||
|
||||
/**
|
||||
* Delete the messages from the current mailbox after copying
|
||||
* with <b>imap_mail_copy</b>
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const CP_MOVE = 2;
|
||||
|
||||
/**
|
||||
* Return UIDs instead of sequence numbers
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const SE_UID = 1;
|
||||
const SE_FREE = 2;
|
||||
|
||||
/**
|
||||
* Don't prefetch searched messages
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const SE_NOPREFETCH = 4;
|
||||
const SO_FREE = 8;
|
||||
const SO_NOSERVER = 16;
|
||||
const SA_MESSAGES = 1;
|
||||
const SA_RECENT = 2;
|
||||
const SA_UNSEEN = 4;
|
||||
const SA_UIDNEXT = 8;
|
||||
const SA_UIDVALIDITY = 16;
|
||||
const SA_ALL = 31;
|
||||
|
||||
/**
|
||||
* This mailbox has no "children" (there are no
|
||||
* mailboxes below this one).
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const LATT_NOINFERIORS = 1;
|
||||
|
||||
/**
|
||||
* This is only a container, not a mailbox - you
|
||||
* cannot open it.
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const LATT_NOSELECT = 2;
|
||||
|
||||
/**
|
||||
* This mailbox is marked. Only used by UW-IMAPD.
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const LATT_MARKED = 4;
|
||||
|
||||
/**
|
||||
* This mailbox is not marked. Only used by
|
||||
* UW-IMAPD.
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const LATT_UNMARKED = 8;
|
||||
const LATT_REFERRAL = 16;
|
||||
const LATT_HASCHILDREN = 32;
|
||||
const LATT_HASNOCHILDREN = 64;
|
||||
|
||||
/**
|
||||
* Sort criteria for <b>imap_sort</b>:
|
||||
* message Date
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const SORTDATE = 0;
|
||||
|
||||
/**
|
||||
* Sort criteria for <b>imap_sort</b>:
|
||||
* arrival date
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const SORTARRIVAL = 1;
|
||||
|
||||
/**
|
||||
* Sort criteria for <b>imap_sort</b>:
|
||||
* mailbox in first From address
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const SORTFROM = 2;
|
||||
|
||||
/**
|
||||
* Sort criteria for <b>imap_sort</b>:
|
||||
* message subject
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const SORTSUBJECT = 3;
|
||||
|
||||
/**
|
||||
* Sort criteria for <b>imap_sort</b>:
|
||||
* mailbox in first To address
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const SORTTO = 4;
|
||||
|
||||
/**
|
||||
* Sort criteria for <b>imap_sort</b>:
|
||||
* mailbox in first cc address
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const SORTCC = 5;
|
||||
|
||||
/**
|
||||
* Sort criteria for <b>imap_sort</b>:
|
||||
* size of message in octets
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const SORTSIZE = 6;
|
||||
const TYPETEXT = 0;
|
||||
const TYPEMULTIPART = 1;
|
||||
const TYPEMESSAGE = 2;
|
||||
const TYPEAPPLICATION = 3;
|
||||
const TYPEAUDIO = 4;
|
||||
const TYPEIMAGE = 5;
|
||||
const TYPEVIDEO = 6;
|
||||
const TYPEMODEL = 7;
|
||||
const TYPEOTHER = 8;
|
||||
const ENC7BIT = 0;
|
||||
const ENC8BIT = 1;
|
||||
const ENCBINARY = 2;
|
||||
const ENCBASE64 = 3;
|
||||
const ENCQUOTEDPRINTABLE = 4;
|
||||
const ENCOTHER = 5;
|
||||
|
||||
/**
|
||||
* Garbage collector, clear message cache elements.
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const IMAP_GC_ELT = 1;
|
||||
|
||||
/**
|
||||
* Garbage collector, clear envelopes and bodies.
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const IMAP_GC_ENV = 2;
|
||||
|
||||
/**
|
||||
* Garbage collector, clear texts.
|
||||
* @link http://php.net/manual/en/imap.constants.php
|
||||
*/
|
||||
const IMAP_GC_TEXTS = 4;
|
||||
|
||||
}
|
||||
1674
plugins/vendor/webklex/php-imap/src/Message.php
vendored
Executable file
1674
plugins/vendor/webklex/php-imap/src/Message.php
vendored
Executable file
File diff suppressed because it is too large
Load Diff
324
plugins/vendor/webklex/php-imap/src/Part.php
vendored
Normal file
324
plugins/vendor/webklex/php-imap/src/Part.php
vendored
Normal file
@@ -0,0 +1,324 @@
|
||||
<?php
|
||||
/*
|
||||
* File: Part.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 17.09.20 20:38
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP;
|
||||
|
||||
|
||||
use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException;
|
||||
|
||||
/**
|
||||
* Class Part
|
||||
*
|
||||
* @package Webklex\PHPIMAP
|
||||
*/
|
||||
class Part {
|
||||
|
||||
/**
|
||||
* Raw part
|
||||
*
|
||||
* @var string $raw
|
||||
*/
|
||||
public string $raw = "";
|
||||
|
||||
/**
|
||||
* Part type
|
||||
*
|
||||
* @var int $type
|
||||
*/
|
||||
public int $type = IMAP::MESSAGE_TYPE_TEXT;
|
||||
|
||||
/**
|
||||
* Part content
|
||||
*
|
||||
* @var string $content
|
||||
*/
|
||||
public string $content = "";
|
||||
|
||||
/**
|
||||
* Part subtype
|
||||
*
|
||||
* @var ?string $subtype
|
||||
*/
|
||||
public ?string $subtype = null;
|
||||
|
||||
/**
|
||||
* Part charset - if available
|
||||
*
|
||||
* @var string $charset
|
||||
*/
|
||||
public string $charset = "utf-8";
|
||||
|
||||
/**
|
||||
* Part encoding method
|
||||
*
|
||||
* @var int $encoding
|
||||
*/
|
||||
public int $encoding = IMAP::MESSAGE_ENC_OTHER;
|
||||
|
||||
/**
|
||||
* Alias to check if the part is an attachment
|
||||
*
|
||||
* @var boolean $ifdisposition
|
||||
*/
|
||||
public bool $ifdisposition = false;
|
||||
|
||||
/**
|
||||
* Indicates if the part is an attachment
|
||||
*
|
||||
* @var ?string $disposition
|
||||
*/
|
||||
public ?string $disposition = null;
|
||||
|
||||
/**
|
||||
* Alias to check if the part has a description
|
||||
*
|
||||
* @var boolean $ifdescription
|
||||
*/
|
||||
public bool $ifdescription = false;
|
||||
|
||||
/**
|
||||
* Part description if available
|
||||
*
|
||||
* @var ?string $description
|
||||
*/
|
||||
public ?string $description = null;
|
||||
|
||||
/**
|
||||
* Part filename if available
|
||||
*
|
||||
* @var ?string $filename
|
||||
*/
|
||||
public ?string $filename = null;
|
||||
|
||||
/**
|
||||
* Part name if available
|
||||
*
|
||||
* @var ?string $name
|
||||
*/
|
||||
public ?string $name = null;
|
||||
|
||||
/**
|
||||
* Part id if available
|
||||
*
|
||||
* @var ?string $id
|
||||
*/
|
||||
public ?string $id = null;
|
||||
|
||||
/**
|
||||
* The part number of the current part
|
||||
*
|
||||
* @var integer $part_number
|
||||
*/
|
||||
public int $part_number = 0;
|
||||
|
||||
/**
|
||||
* Part length in bytes
|
||||
*
|
||||
* @var integer $bytes
|
||||
*/
|
||||
public int $bytes;
|
||||
|
||||
/**
|
||||
* Part content type
|
||||
*
|
||||
* @var string|null $content_type
|
||||
*/
|
||||
public ?string $content_type = null;
|
||||
|
||||
/**
|
||||
* @var ?Header $header
|
||||
*/
|
||||
private ?Header $header;
|
||||
|
||||
/**
|
||||
* @var Config $config
|
||||
*/
|
||||
protected Config $config;
|
||||
|
||||
/**
|
||||
* Part constructor.
|
||||
* @param string $raw_part
|
||||
* @param Config $config
|
||||
* @param Header|null $header
|
||||
* @param integer $part_number
|
||||
*
|
||||
* @throws InvalidMessageDateException
|
||||
*/
|
||||
public function __construct(string $raw_part, Config $config, ?Header $header = null, int $part_number = 0) {
|
||||
$this->raw = $raw_part;
|
||||
$this->config = $config;
|
||||
$this->header = $header;
|
||||
$this->part_number = $part_number;
|
||||
$this->parse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the raw parts
|
||||
*
|
||||
* @throws InvalidMessageDateException
|
||||
*/
|
||||
protected function parse(): void {
|
||||
if ($this->header === null) {
|
||||
$body = $this->findHeaders();
|
||||
}else{
|
||||
$body = $this->raw;
|
||||
}
|
||||
|
||||
$this->parseDisposition();
|
||||
$this->parseDescription();
|
||||
$this->parseEncoding();
|
||||
|
||||
$this->charset = $this->header->get("charset")->first();
|
||||
$this->name = $this->header->get("name");
|
||||
$this->filename = $this->header->get("filename");
|
||||
|
||||
if($this->header->get("id")->exist()) {
|
||||
$this->id = $this->header->get("id");
|
||||
} else if($this->header->get("x_attachment_id")->exist()){
|
||||
$this->id = $this->header->get("x_attachment_id");
|
||||
} else if($this->header->get("content_id")->exist()){
|
||||
$this->id = strtr($this->header->get("content_id"), [
|
||||
'<' => '',
|
||||
'>' => ''
|
||||
]);
|
||||
}
|
||||
|
||||
$content_types = $this->header->get("content_type")->all();
|
||||
if(!empty($content_types)){
|
||||
$this->subtype = $this->parseSubtype($content_types);
|
||||
$content_type = $content_types[0];
|
||||
$parts = explode(';', $content_type);
|
||||
$this->content_type = trim($parts[0]);
|
||||
}
|
||||
|
||||
$this->content = trim(rtrim($body));
|
||||
$this->bytes = strlen($this->content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all available headers and return the leftover body segment
|
||||
*
|
||||
* @return string
|
||||
* @throws InvalidMessageDateException
|
||||
*/
|
||||
private function findHeaders(): string {
|
||||
$body = $this->raw;
|
||||
while (($pos = strpos($body, "\r\n")) > 0) {
|
||||
$body = substr($body, $pos + 2);
|
||||
}
|
||||
$headers = substr($this->raw, 0, strlen($body) * -1);
|
||||
$body = substr($body, 0, -2);
|
||||
|
||||
$this->header = new Header($headers, $this->config);
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to parse the subtype if any is present
|
||||
* @param $content_type
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
private function parseSubtype($content_type): ?string {
|
||||
if (is_array($content_type)) {
|
||||
foreach ($content_type as $part){
|
||||
if ((strpos($part, "/")) !== false){
|
||||
return $this->parseSubtype($part);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (($pos = strpos($content_type, "/")) !== false){
|
||||
return substr(explode(";", $content_type)[0], $pos + 1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to parse the disposition if any is present
|
||||
*/
|
||||
private function parseDisposition(): void {
|
||||
$content_disposition = $this->header->get("content_disposition")->first();
|
||||
if($content_disposition) {
|
||||
$this->ifdisposition = true;
|
||||
$this->disposition = (is_array($content_disposition)) ? implode(' ', $content_disposition) : explode(";", $content_disposition)[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to parse the description if any is present
|
||||
*/
|
||||
private function parseDescription(): void {
|
||||
$content_description = $this->header->get("content_description")->first();
|
||||
if($content_description) {
|
||||
$this->ifdescription = true;
|
||||
$this->description = $content_description;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to parse the encoding if any is present
|
||||
*/
|
||||
private function parseEncoding(): void {
|
||||
$encoding = $this->header->get("content_transfer_encoding")->first();
|
||||
if($encoding) {
|
||||
$this->encoding = match (strtolower($encoding)) {
|
||||
"quoted-printable" => IMAP::MESSAGE_ENC_QUOTED_PRINTABLE,
|
||||
"base64" => IMAP::MESSAGE_ENC_BASE64,
|
||||
"7bit" => IMAP::MESSAGE_ENC_7BIT,
|
||||
"8bit" => IMAP::MESSAGE_ENC_8BIT,
|
||||
"binary" => IMAP::MESSAGE_ENC_BINARY,
|
||||
default => IMAP::MESSAGE_ENC_OTHER,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current part represents an attachment
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAttachment(): bool {
|
||||
$valid_disposition = in_array(strtolower($this->disposition ?? ''), $this->config->get('options.dispositions'));
|
||||
|
||||
if ($this->type == IMAP::MESSAGE_TYPE_TEXT && ($this->ifdisposition == 0 || empty($this->disposition) || !$valid_disposition)) {
|
||||
if (($this->subtype == null || in_array((strtolower($this->subtype)), ["plain", "html"])) && $this->filename == null && $this->name == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->disposition === "inline" && $this->filename == null && $this->name == null && !$this->header->has("content_id")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the part header
|
||||
*
|
||||
* @return Header|null
|
||||
*/
|
||||
public function getHeader(): ?Header {
|
||||
return $this->header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Config instance
|
||||
*
|
||||
* @return Config
|
||||
*/
|
||||
public function getConfig(): Config {
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
}
|
||||
1103
plugins/vendor/webklex/php-imap/src/Query/Query.php
vendored
Normal file
1103
plugins/vendor/webklex/php-imap/src/Query/Query.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
555
plugins/vendor/webklex/php-imap/src/Query/WhereQuery.php
vendored
Executable file
555
plugins/vendor/webklex/php-imap/src/Query/WhereQuery.php
vendored
Executable file
@@ -0,0 +1,555 @@
|
||||
<?php
|
||||
/*
|
||||
* File: Query.php
|
||||
* Category: -
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 21.07.18 18:54
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Query;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Support\Str;
|
||||
use Webklex\PHPIMAP\Exceptions\InvalidWhereQueryCriteriaException;
|
||||
use Webklex\PHPIMAP\Exceptions\MethodNotFoundException;
|
||||
use Webklex\PHPIMAP\Exceptions\MessageSearchValidationException;
|
||||
|
||||
/**
|
||||
* Class WhereQuery
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Query
|
||||
*
|
||||
* @method WhereQuery all()
|
||||
* @method WhereQuery answered()
|
||||
* @method WhereQuery deleted()
|
||||
* @method WhereQuery new()
|
||||
* @method WhereQuery old()
|
||||
* @method WhereQuery recent()
|
||||
* @method WhereQuery seen()
|
||||
* @method WhereQuery unanswered()
|
||||
* @method WhereQuery undeleted()
|
||||
* @method WhereQuery unflagged()
|
||||
* @method WhereQuery unseen()
|
||||
* @method WhereQuery not()
|
||||
* @method WhereQuery unkeyword($value)
|
||||
* @method WhereQuery to($value)
|
||||
* @method WhereQuery text($value)
|
||||
* @method WhereQuery subject($value)
|
||||
* @method WhereQuery since($date)
|
||||
* @method WhereQuery on($date)
|
||||
* @method WhereQuery keyword($value)
|
||||
* @method WhereQuery from($value)
|
||||
* @method WhereQuery flagged()
|
||||
* @method WhereQuery cc($value)
|
||||
* @method WhereQuery body($value)
|
||||
* @method WhereQuery before($date)
|
||||
* @method WhereQuery bcc($value)
|
||||
* @method WhereQuery inReplyTo($value)
|
||||
* @method WhereQuery messageId($value)
|
||||
*
|
||||
* @mixin Query
|
||||
*/
|
||||
class WhereQuery extends Query {
|
||||
|
||||
/**
|
||||
* @var array $available_criteria
|
||||
*/
|
||||
protected array $available_criteria = [
|
||||
'OR', 'AND',
|
||||
'ALL', 'ANSWERED', 'BCC', 'BEFORE', 'BODY', 'CC', 'DELETED', 'FLAGGED', 'FROM', 'KEYWORD',
|
||||
'NEW', 'NOT', 'OLD', 'ON', 'RECENT', 'SEEN', 'SINCE', 'SUBJECT', 'TEXT', 'TO',
|
||||
'UNANSWERED', 'UNDELETED', 'UNFLAGGED', 'UNKEYWORD', 'UNSEEN', 'UID'
|
||||
];
|
||||
|
||||
/**
|
||||
* Magic method in order to allow alias usage of all "where" methods in an optional connection with "NOT"
|
||||
* @param string $name
|
||||
* @param array|null $arguments
|
||||
*
|
||||
* @return mixed
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
* @throws MethodNotFoundException
|
||||
*/
|
||||
public function __call(string $name, ?array $arguments) {
|
||||
$that = $this;
|
||||
|
||||
$name = Str::camel($name);
|
||||
|
||||
if (strtolower(substr($name, 0, 3)) === 'not') {
|
||||
$that = $that->whereNot();
|
||||
$name = substr($name, 3);
|
||||
}
|
||||
|
||||
if (!str_contains(strtolower($name), "where")) {
|
||||
$method = 'where' . ucfirst($name);
|
||||
} else {
|
||||
$method = lcfirst($name);
|
||||
}
|
||||
|
||||
if (method_exists($this, $method) === true) {
|
||||
return call_user_func_array([$that, $method], $arguments);
|
||||
}
|
||||
|
||||
throw new MethodNotFoundException("Method " . self::class . '::' . $method . '() is not supported');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a given criteria
|
||||
* @param $criteria
|
||||
*
|
||||
* @return string
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
protected function validate_criteria($criteria): string {
|
||||
$command = strtoupper($criteria);
|
||||
if (str_starts_with($command, "CUSTOM ")) {
|
||||
return substr($criteria, 7);
|
||||
}
|
||||
if (in_array($command, $this->available_criteria) === false) {
|
||||
throw new InvalidWhereQueryCriteriaException("Invalid imap search criteria: $command");
|
||||
}
|
||||
|
||||
return $criteria;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register search parameters
|
||||
* @param mixed $criteria
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*
|
||||
* Examples:
|
||||
* $query->from("someone@email.tld")->seen();
|
||||
* $query->whereFrom("someone@email.tld")->whereSeen();
|
||||
* $query->where([["FROM" => "someone@email.tld"], ["SEEN"]]);
|
||||
* $query->where(["FROM" => "someone@email.tld"])->where(["SEEN"]);
|
||||
* $query->where(["FROM" => "someone@email.tld", "SEEN"]);
|
||||
* $query->where("FROM", "someone@email.tld")->where("SEEN");
|
||||
*/
|
||||
public function where(mixed $criteria, mixed $value = null): static {
|
||||
if (is_array($criteria)) {
|
||||
foreach ($criteria as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$this->where($value);
|
||||
}else{
|
||||
$this->where($key, $value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->push_search_criteria($criteria, $value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a given search criteria and value pair to the search query
|
||||
* @param $criteria string
|
||||
* @param $value mixed
|
||||
*
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
protected function push_search_criteria(string $criteria, mixed $value): void {
|
||||
$criteria = $this->validate_criteria($criteria);
|
||||
$value = $this->parse_value($value);
|
||||
|
||||
if ($value === '') {
|
||||
$this->query->push([$criteria]);
|
||||
} else {
|
||||
$this->query->push([$criteria, $value]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Closure|null $closure
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function orWhere(?Closure $closure = null): static {
|
||||
$this->query->push(['OR']);
|
||||
if ($closure !== null) $closure($this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Closure|null $closure
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function andWhere(?Closure $closure = null): static {
|
||||
$this->query->push(['AND']);
|
||||
if ($closure !== null) $closure($this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereAll(): static {
|
||||
return $this->where('ALL');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereAnswered(): static {
|
||||
return $this->where('ANSWERED');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereBcc(string $value): static {
|
||||
return $this->where('BCC', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
* @throws MessageSearchValidationException
|
||||
*/
|
||||
public function whereBefore(mixed $value): static {
|
||||
$date = $this->parse_date($value);
|
||||
return $this->where('BEFORE', $date);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereBody(string $value): static {
|
||||
return $this->where('BODY', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereCc(string $value): static {
|
||||
return $this->where('CC', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereDeleted(): static {
|
||||
return $this->where('DELETED');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereFlagged(string $value): static {
|
||||
return $this->where('FLAGGED', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereFrom(string $value): static {
|
||||
return $this->where('FROM', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereKeyword(string $value): static {
|
||||
return $this->where('KEYWORD', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereNew(): static {
|
||||
return $this->where('NEW');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereNot(): static {
|
||||
return $this->where('NOT');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereOld(): static {
|
||||
return $this->where('OLD');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return $this
|
||||
* @throws MessageSearchValidationException
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereOn(mixed $value): static {
|
||||
$date = $this->parse_date($value);
|
||||
return $this->where('ON', $date);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereRecent(): static {
|
||||
return $this->where('RECENT');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereSeen(): static {
|
||||
return $this->where('SEEN');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return $this
|
||||
* @throws MessageSearchValidationException
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereSince(mixed $value): static {
|
||||
$date = $this->parse_date($value);
|
||||
return $this->where('SINCE', $date);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereSubject(string $value): static {
|
||||
return $this->where('SUBJECT', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereText(string $value): static {
|
||||
return $this->where('TEXT', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereTo(string $value): static {
|
||||
return $this->where('TO', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereUnkeyword(string $value): static {
|
||||
return $this->where('UNKEYWORD', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereUnanswered(): static {
|
||||
return $this->where('UNANSWERED');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereUndeleted(): static {
|
||||
return $this->where('UNDELETED');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereUnflagged(): static {
|
||||
return $this->where('UNFLAGGED');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereUnseen(): static {
|
||||
return $this->where('UNSEEN');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereNoXSpam(): static {
|
||||
return $this->where("CUSTOM X-Spam-Flag NO");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereIsXSpam(): static {
|
||||
return $this->where("CUSTOM X-Spam-Flag YES");
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for a specific header value
|
||||
* @param $header
|
||||
* @param $value
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereHeader($header, $value): static {
|
||||
return $this->where("CUSTOM HEADER $header $value");
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for a specific message id
|
||||
* @param $messageId
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereMessageId($messageId): static {
|
||||
return $this->whereHeader("Message-ID", $messageId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for a specific message id
|
||||
* @param $messageId
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereInReplyTo($messageId): static {
|
||||
return $this->whereHeader("In-Reply-To", $messageId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $country_code
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereLanguage($country_code): static {
|
||||
return $this->where("Content-Language $country_code");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get message be it UID.
|
||||
*
|
||||
* @param int|string $uid
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereUid(int|string $uid): static {
|
||||
return $this->where('UID', $uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get messages by their UIDs.
|
||||
*
|
||||
* @param array<int, int> $uids
|
||||
*
|
||||
* @return $this
|
||||
* @throws InvalidWhereQueryCriteriaException
|
||||
*/
|
||||
public function whereUidIn(array $uids): static {
|
||||
$uids = implode(',', $uids);
|
||||
return $this->where('UID', $uids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the callback if the given "value" is truthy.
|
||||
* copied from @url https://github.com/laravel/framework/blob/8.x/src/Illuminate/Support/Traits/Conditionable.php
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param callable $callback
|
||||
* @param callable|null $default
|
||||
* @return $this|null
|
||||
*/
|
||||
public function when(mixed $value, callable $callback, ?callable $default = null): mixed {
|
||||
if ($value) {
|
||||
return $callback($this, $value) ?: $this;
|
||||
} elseif ($default) {
|
||||
return $default($this, $value) ?: $this;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the callback if the given "value" is falsy.
|
||||
* copied from @url https://github.com/laravel/framework/blob/8.x/src/Illuminate/Support/Traits/Conditionable.php
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param callable $callback
|
||||
* @param callable|null $default
|
||||
* @return $this|mixed
|
||||
*/
|
||||
public function unless(mixed $value, callable $callback, ?callable $default = null): mixed {
|
||||
if (!$value) {
|
||||
return $callback($this, $value) ?: $this;
|
||||
} elseif ($default) {
|
||||
return $default($this, $value) ?: $this;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available search criteria
|
||||
*
|
||||
* @return array|string[]
|
||||
*/
|
||||
public function getAvailableCriteria(): array {
|
||||
return $this->available_criteria;
|
||||
}
|
||||
}
|
||||
172
plugins/vendor/webklex/php-imap/src/Structure.php
vendored
Normal file
172
plugins/vendor/webklex/php-imap/src/Structure.php
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
/*
|
||||
* File: Structure.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 17.09.20 20:38
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP;
|
||||
|
||||
|
||||
use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException;
|
||||
use Webklex\PHPIMAP\Exceptions\MessageContentFetchingException;
|
||||
|
||||
/**
|
||||
* Class Structure
|
||||
*
|
||||
* @package Webklex\PHPIMAP
|
||||
*/
|
||||
class Structure {
|
||||
|
||||
/**
|
||||
* Raw structure
|
||||
*
|
||||
* @var string $raw
|
||||
*/
|
||||
public string $raw = "";
|
||||
|
||||
/**
|
||||
* @var Header $header
|
||||
*/
|
||||
private Header $header;
|
||||
|
||||
/**
|
||||
* Message type (if multipart or not)
|
||||
*
|
||||
* @var int $type
|
||||
*/
|
||||
public int $type = IMAP::MESSAGE_TYPE_TEXT;
|
||||
|
||||
/**
|
||||
* All available parts
|
||||
*
|
||||
* @var Part[] $parts
|
||||
*/
|
||||
public array $parts = [];
|
||||
|
||||
/**
|
||||
* Options holder
|
||||
*
|
||||
* @var array $options
|
||||
*/
|
||||
protected array $options = [];
|
||||
|
||||
/**
|
||||
* Structure constructor.
|
||||
* @param $raw_structure
|
||||
* @param Header $header
|
||||
*
|
||||
* @throws MessageContentFetchingException
|
||||
* @throws InvalidMessageDateException
|
||||
*/
|
||||
public function __construct($raw_structure, Header $header) {
|
||||
$this->raw = $raw_structure;
|
||||
$this->header = $header;
|
||||
$this->options = $header->getConfig()->get('options');
|
||||
$this->parse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given raw structure
|
||||
*
|
||||
* @throws MessageContentFetchingException
|
||||
* @throws InvalidMessageDateException
|
||||
*/
|
||||
protected function parse(): void {
|
||||
$this->findContentType();
|
||||
$this->parts = $this->find_parts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the message content type
|
||||
*/
|
||||
public function findContentType(): void {
|
||||
$content_type = $this->header->get("content_type")->first();
|
||||
if($content_type && stripos($content_type, 'multipart') === 0) {
|
||||
$this->type = IMAP::MESSAGE_TYPE_MULTIPART;
|
||||
}else{
|
||||
$this->type = IMAP::MESSAGE_TYPE_TEXT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all available headers and return the leftover body segment
|
||||
* @var string $context
|
||||
* @var integer $part_number
|
||||
*
|
||||
* @return Part[]
|
||||
* @throws InvalidMessageDateException
|
||||
*/
|
||||
private function parsePart(string $context, int $part_number = 0): array {
|
||||
$body = $context;
|
||||
while (($pos = strpos($body, "\r\n")) > 0) {
|
||||
$body = substr($body, $pos + 2);
|
||||
}
|
||||
$headers = substr($context, 0, strlen($body) * -1);
|
||||
$body = substr($body, 0, -2);
|
||||
|
||||
$config = $this->header->getConfig();
|
||||
$headers = new Header($headers, $config);
|
||||
if (($boundary = $headers->getBoundary()) !== null) {
|
||||
$parts = $this->detectParts($boundary, $body, $part_number);
|
||||
|
||||
if(count($parts) > 1) {
|
||||
return $parts;
|
||||
}
|
||||
}
|
||||
|
||||
return [new Part($body, $this->header->getConfig(), $headers, $part_number)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $boundary
|
||||
* @param string $context
|
||||
* @param int $part_number
|
||||
*
|
||||
* @return array
|
||||
* @throws InvalidMessageDateException
|
||||
*/
|
||||
private function detectParts(string $boundary, string $context, int $part_number = 0): array {
|
||||
$base_parts = explode( "--".$boundary, $context);
|
||||
if(count($base_parts) == 0) {
|
||||
$base_parts = explode($boundary, $context);
|
||||
}
|
||||
$final_parts = [];
|
||||
foreach($base_parts as $ctx) {
|
||||
$ctx = substr($ctx, 2);
|
||||
if ($ctx !== "--" && $ctx != "" && $ctx != "\r\n") {
|
||||
$parts = $this->parsePart($ctx, $part_number);
|
||||
foreach ($parts as $part) {
|
||||
$final_parts[] = $part;
|
||||
$part_number = $part->part_number;
|
||||
}
|
||||
$part_number++;
|
||||
}
|
||||
}
|
||||
return $final_parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all available parts
|
||||
*
|
||||
* @return array
|
||||
* @throws MessageContentFetchingException
|
||||
* @throws InvalidMessageDateException
|
||||
*/
|
||||
public function find_parts(): array {
|
||||
if($this->type === IMAP::MESSAGE_TYPE_MULTIPART) {
|
||||
if (($boundary = $this->header->getBoundary()) === null) {
|
||||
throw new MessageContentFetchingException("no content found", 0);
|
||||
}
|
||||
|
||||
return $this->detectParts($boundary, $this->raw);
|
||||
}
|
||||
|
||||
return [new Part($this->raw, $this->header->getConfig(), $this->header)];
|
||||
}
|
||||
}
|
||||
26
plugins/vendor/webklex/php-imap/src/Support/AttachmentCollection.php
vendored
Normal file
26
plugins/vendor/webklex/php-imap/src/Support/AttachmentCollection.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/*
|
||||
* File: AttachmentCollection.php
|
||||
* Category: Collection
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 16.03.18 03:13
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Support;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Webklex\PHPIMAP\Attachment;
|
||||
|
||||
/**
|
||||
* Class AttachmentCollection
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Support
|
||||
* @implements Collection<int, Attachment>
|
||||
*/
|
||||
class AttachmentCollection extends PaginatedCollection {
|
||||
|
||||
}
|
||||
25
plugins/vendor/webklex/php-imap/src/Support/FlagCollection.php
vendored
Normal file
25
plugins/vendor/webklex/php-imap/src/Support/FlagCollection.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/*
|
||||
* File: FlagCollection.php
|
||||
* Category: Collection
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 21.07.18 23:10
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Support;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class FlagCollection
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Support
|
||||
* @implements Collection<string, string>
|
||||
*/
|
||||
class FlagCollection extends PaginatedCollection {
|
||||
|
||||
}
|
||||
26
plugins/vendor/webklex/php-imap/src/Support/FolderCollection.php
vendored
Normal file
26
plugins/vendor/webklex/php-imap/src/Support/FolderCollection.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/*
|
||||
* File: FolderCollection.php
|
||||
* Category: Collection
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 18.03.18 02:21
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Support;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Webklex\PHPIMAP\Folder;
|
||||
|
||||
/**
|
||||
* Class FolderCollection
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Support
|
||||
* @implements Collection<int, Folder>
|
||||
*/
|
||||
class FolderCollection extends PaginatedCollection {
|
||||
|
||||
}
|
||||
45
plugins/vendor/webklex/php-imap/src/Support/Masks/AttachmentMask.php
vendored
Normal file
45
plugins/vendor/webklex/php-imap/src/Support/Masks/AttachmentMask.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/*
|
||||
* File: AttachmentMask.php
|
||||
* Category: Mask
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 14.03.19 20:49
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Support\Masks;
|
||||
|
||||
use Webklex\PHPIMAP\Attachment;
|
||||
|
||||
/**
|
||||
* Class AttachmentMask
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Support\Masks
|
||||
* @mixin Attachment
|
||||
*/
|
||||
class AttachmentMask extends Mask {
|
||||
|
||||
/** @var Attachment $parent */
|
||||
protected mixed $parent;
|
||||
|
||||
/**
|
||||
* Get the attachment content base64 encoded
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getContentBase64Encoded(): ?string {
|
||||
return base64_encode($this->parent->content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a base64 image src string
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getImageSrc(): ?string {
|
||||
return 'data:'.$this->parent->content_type.';base64,'.$this->getContentBase64Encoded();
|
||||
}
|
||||
}
|
||||
137
plugins/vendor/webklex/php-imap/src/Support/Masks/Mask.php
vendored
Executable file
137
plugins/vendor/webklex/php-imap/src/Support/Masks/Mask.php
vendored
Executable file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/*
|
||||
* File: Mask.php
|
||||
* Category: Mask
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 14.03.19 20:49
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Support\Masks;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Webklex\PHPIMAP\Exceptions\MethodNotFoundException;
|
||||
|
||||
/**
|
||||
* Class Mask
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Support\Masks
|
||||
*/
|
||||
class Mask {
|
||||
|
||||
/**
|
||||
* Available attributes
|
||||
*
|
||||
* @var array $attributes
|
||||
*/
|
||||
protected array $attributes = [];
|
||||
|
||||
/**
|
||||
* Parent instance
|
||||
*
|
||||
* @var mixed $parent
|
||||
*/
|
||||
protected mixed $parent;
|
||||
|
||||
/**
|
||||
* Mask constructor.
|
||||
* @param $parent
|
||||
*/
|
||||
public function __construct($parent) {
|
||||
$this->parent = $parent;
|
||||
|
||||
if(method_exists($this->parent, 'getAttributes')){
|
||||
$this->attributes = array_merge($this->attributes, $this->parent->getAttributes());
|
||||
}
|
||||
|
||||
$this->boot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Boot method made to be used by any custom mask
|
||||
*/
|
||||
protected function boot(): void {}
|
||||
|
||||
/**
|
||||
* Call dynamic attribute setter and getter methods and inherit the parent calls
|
||||
* @param string $method
|
||||
* @param array $arguments
|
||||
*
|
||||
* @return mixed
|
||||
* @throws MethodNotFoundException
|
||||
*/
|
||||
public function __call(string $method, array $arguments) {
|
||||
if(strtolower(substr($method, 0, 3)) === 'get') {
|
||||
$name = Str::snake(substr($method, 3));
|
||||
|
||||
if(isset($this->attributes[$name])) {
|
||||
return $this->attributes[$name];
|
||||
}
|
||||
|
||||
}elseif (strtolower(substr($method, 0, 3)) === 'set') {
|
||||
$name = Str::snake(substr($method, 3));
|
||||
|
||||
if(isset($this->attributes[$name])) {
|
||||
$this->attributes[$name] = array_pop($arguments);
|
||||
|
||||
return $this->attributes[$name];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(method_exists($this->parent, $method) === true){
|
||||
return call_user_func_array([$this->parent, $method], $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 mixed|null
|
||||
*/
|
||||
public function __get($name) {
|
||||
if(isset($this->attributes[$name])) {
|
||||
return $this->attributes[$name];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent instance
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getParent(): mixed {
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available attributes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAttributes(): array {
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
}
|
||||
87
plugins/vendor/webklex/php-imap/src/Support/Masks/MessageMask.php
vendored
Normal file
87
plugins/vendor/webklex/php-imap/src/Support/Masks/MessageMask.php
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MessageMask.php
|
||||
* Category: Mask
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 14.03.19 20:49
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Support\Masks;
|
||||
|
||||
use Webklex\PHPIMAP\Attachment;
|
||||
use Webklex\PHPIMAP\Message;
|
||||
|
||||
/**
|
||||
* Class MessageMask
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Support\Masks
|
||||
* @mixin Message
|
||||
*/
|
||||
class MessageMask extends Mask {
|
||||
|
||||
/** @var Message $parent */
|
||||
protected mixed $parent;
|
||||
|
||||
/**
|
||||
* Get the message html body
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function getHtmlBody(){
|
||||
$bodies = $this->parent->getBodies();
|
||||
if (!isset($bodies['html'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if(is_object($bodies['html']) && property_exists($bodies['html'], 'content')) {
|
||||
return $bodies['html']->content;
|
||||
}
|
||||
return $bodies['html'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Message html body filtered by an optional callback
|
||||
* @param callable|null $callback
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getCustomHTMLBody(?callable $callback = null): ?string {
|
||||
$body = $this->getHtmlBody();
|
||||
if($body === null) return null;
|
||||
|
||||
if ($callback !== null) {
|
||||
$aAttachment = $this->parent->getAttachments();
|
||||
$aAttachment->each(function($oAttachment) use(&$body, $callback) {
|
||||
/** @var Attachment $oAttachment */
|
||||
if(is_callable($callback)) {
|
||||
$body = $callback($body, $oAttachment);
|
||||
}elseif(is_string($callback)) {
|
||||
call_user_func($callback, [$body, $oAttachment]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Message html body with embedded base64 images
|
||||
* the resulting $body.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getHTMLBodyWithEmbeddedBase64Images(): ?string {
|
||||
return $this->getCustomHTMLBody(function($body, $oAttachment){
|
||||
/** @var Attachment $oAttachment */
|
||||
if ($oAttachment->id) {
|
||||
$body = str_replace('cid:'.$oAttachment->id, 'data:'.$oAttachment->getContentType().';base64, '.base64_encode($oAttachment->getContent()), $body);
|
||||
}
|
||||
|
||||
return $body;
|
||||
});
|
||||
}
|
||||
}
|
||||
26
plugins/vendor/webklex/php-imap/src/Support/MessageCollection.php
vendored
Normal file
26
plugins/vendor/webklex/php-imap/src/Support/MessageCollection.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MessageCollection.php
|
||||
* Category: Collection
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 16.03.18 03:13
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Support;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Webklex\PHPIMAP\Message;
|
||||
|
||||
/**
|
||||
* Class MessageCollection
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Support
|
||||
* @implements Collection<int, Message>
|
||||
*/
|
||||
class MessageCollection extends PaginatedCollection {
|
||||
|
||||
}
|
||||
82
plugins/vendor/webklex/php-imap/src/Support/PaginatedCollection.php
vendored
Normal file
82
plugins/vendor/webklex/php-imap/src/Support/PaginatedCollection.php
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/*
|
||||
* File: PaginatedCollection.php
|
||||
* Category: Collection
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 16.03.18 03:13
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Support;
|
||||
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Pagination\Paginator;
|
||||
|
||||
/**
|
||||
* Class PaginatedCollection
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Support
|
||||
*/
|
||||
class PaginatedCollection extends Collection {
|
||||
|
||||
/**
|
||||
* Number of total entries
|
||||
*
|
||||
* @var int $total
|
||||
*/
|
||||
protected int $total = 0;
|
||||
|
||||
/**
|
||||
* Paginate the current collection.
|
||||
* @param int $per_page
|
||||
* @param int|null $page
|
||||
* @param string $page_name
|
||||
* @param boolean $prepaginated
|
||||
*
|
||||
* @return LengthAwarePaginator
|
||||
*/
|
||||
public function paginate(int $per_page = 15, ?int $page = null, string $page_name = 'page', bool $prepaginated = false): LengthAwarePaginator {
|
||||
$page = $page ?: Paginator::resolveCurrentPage($page_name);
|
||||
|
||||
$total = $this->total ?: $this->count();
|
||||
|
||||
$results = !$prepaginated && $total ? $this->forPage($page, $per_page)->toArray() : $this->all();
|
||||
|
||||
return $this->paginator($results, $total, $per_page, $page, [
|
||||
'path' => Paginator::resolveCurrentPath(),
|
||||
'pageName' => $page_name,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new length-aware paginator instance.
|
||||
* @param array $items
|
||||
* @param int $total
|
||||
* @param int $per_page
|
||||
* @param int|null $current_page
|
||||
* @param array $options
|
||||
*
|
||||
* @return LengthAwarePaginator
|
||||
*/
|
||||
protected function paginator(array $items, int $total, int $per_page, ?int $current_page, array $options): LengthAwarePaginator {
|
||||
return new LengthAwarePaginator($items, $total, $per_page, $current_page, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get and set the total amount
|
||||
* @param null $total
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function total($total = null): ?int {
|
||||
if($total === null) {
|
||||
return $this->total;
|
||||
}
|
||||
|
||||
return $this->total = $total;
|
||||
}
|
||||
}
|
||||
86
plugins/vendor/webklex/php-imap/src/Traits/HasEvents.php
vendored
Normal file
86
plugins/vendor/webklex/php-imap/src/Traits/HasEvents.php
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
/*
|
||||
* File: HasEvents.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 21.09.20 22:46
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Webklex\PHPIMAP\Traits;
|
||||
|
||||
|
||||
use Webklex\PHPIMAP\Events\Event;
|
||||
use Webklex\PHPIMAP\Exceptions\EventNotFoundException;
|
||||
|
||||
/**
|
||||
* Trait HasEvents
|
||||
*
|
||||
* @package Webklex\PHPIMAP\Traits
|
||||
*/
|
||||
trait HasEvents {
|
||||
|
||||
/**
|
||||
* Event holder
|
||||
*
|
||||
* @var array $events
|
||||
*/
|
||||
protected array $events = [];
|
||||
|
||||
/**
|
||||
* Set a specific event
|
||||
* @param string $section
|
||||
* @param string $event
|
||||
* @param mixed $class
|
||||
*/
|
||||
public function setEvent(string $section, string $event, mixed $class): void {
|
||||
if (isset($this->events[$section])) {
|
||||
$this->events[$section][$event] = $class;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all events
|
||||
* @param array $events
|
||||
*/
|
||||
public function setEvents(array $events): void {
|
||||
$this->events = $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific event callback
|
||||
* @param string $section
|
||||
* @param string $event
|
||||
*
|
||||
* @return Event|string
|
||||
* @throws EventNotFoundException
|
||||
*/
|
||||
public function getEvent(string $section, string $event): Event|string {
|
||||
if (isset($this->events[$section])) {
|
||||
return $this->events[$section][$event];
|
||||
}
|
||||
throw new EventNotFoundException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all events
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getEvents(): array {
|
||||
return $this->events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a specific event.
|
||||
* @throws EventNotFoundException
|
||||
*/
|
||||
public function dispatch(string $section, string $event, mixed ...$args): void {
|
||||
$event = $this->getEvent($section, $event);
|
||||
$event::dispatch(...$args);
|
||||
}
|
||||
|
||||
}
|
||||
274
plugins/vendor/webklex/php-imap/src/config/imap.php
vendored
Normal file
274
plugins/vendor/webklex/php-imap/src/config/imap.php
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
<?php
|
||||
/*
|
||||
* File: imap.php
|
||||
* Category: config
|
||||
* Author: M. Goldenbaum
|
||||
* Created: 24.09.16 22:36
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default date format
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The default date format is used to convert any given Carbon::class object into a valid date string.
|
||||
| These are currently known working formats: "d-M-Y", "d-M-y", "d M y"
|
||||
|
|
||||
*/
|
||||
'date_format' => 'd-M-Y',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default account
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The default account identifier. It will be used as default for any missing account parameters.
|
||||
| If however the default account is missing a parameter the package default will be used.
|
||||
| Set to 'false' [boolean] to disable this functionality.
|
||||
|
|
||||
*/
|
||||
'default' => 'default',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Security options
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| You can enable or disable certain security features here by setting them to true or false to enable or disable
|
||||
| them.
|
||||
| -detect_spoofing:
|
||||
| Detect spoofing attempts by checking the message sender against the message headers.
|
||||
| Default TRUE
|
||||
| -detect_spoofing_exception:
|
||||
| Throw an exception if a spoofing attempt is detected.
|
||||
| Default FALSE
|
||||
| -sanitize_filenames:
|
||||
| Sanitize attachment filenames by removing any unwanted and potentially dangerous characters. This is not a
|
||||
| 100% secure solution, but it should help to prevent some common attacks. Please sanitize the filenames
|
||||
| again if you need a more secure solution.
|
||||
| Default TRUE
|
||||
|
|
||||
*/
|
||||
'security' => [
|
||||
"detect_spoofing" => true,
|
||||
"detect_spoofing_exception" => false,
|
||||
"sanitize_filenames" => true,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Available accounts
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Please list all IMAP accounts which you are planning to use within the
|
||||
| array below.
|
||||
|
|
||||
*/
|
||||
'accounts' => [
|
||||
|
||||
'default' => [// account identifier
|
||||
'host' => 'localhost',
|
||||
'port' => 993,
|
||||
'protocol' => 'imap', //might also use imap, [pop3 or nntp (untested)]
|
||||
'encryption' => 'ssl', // Supported: false, 'ssl', 'tls'
|
||||
'validate_cert' => true,
|
||||
'username' => 'root@example.com',
|
||||
'password' => '',
|
||||
'authentication' => null,
|
||||
'rfc' => 'RFC822', // If you are using iCloud, you might want to set this to 'BODY'
|
||||
'proxy' => [
|
||||
'socket' => null,
|
||||
'request_fulluri' => false,
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
],
|
||||
"timeout" => 30,
|
||||
"extensions" => []
|
||||
],
|
||||
|
||||
/*
|
||||
'gmail' => [ // account identifier
|
||||
'host' => 'imap.gmail.com',
|
||||
'port' => 993,
|
||||
'encryption' => 'ssl',
|
||||
'validate_cert' => true,
|
||||
'username' => 'example@gmail.com',
|
||||
'password' => 'PASSWORD',
|
||||
'authentication' => 'oauth',
|
||||
],
|
||||
|
||||
'another' => [ // account identifier
|
||||
'host' => '',
|
||||
'port' => 993,
|
||||
'encryption' => false,
|
||||
'validate_cert' => true,
|
||||
'username' => '',
|
||||
'password' => '',
|
||||
'authentication' => null,
|
||||
]
|
||||
*/
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Available IMAP options
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Available php imap config parameters are listed below
|
||||
| -Delimiter (optional):
|
||||
| This option is only used when calling $oClient->
|
||||
| You can use any supported char such as ".", "/", (...)
|
||||
| -Fetch option:
|
||||
| IMAP::FT_UID - Message marked as read by fetching the body message
|
||||
| IMAP::FT_PEEK - Fetch the message without setting the "seen" flag
|
||||
| -Fetch sequence id:
|
||||
| IMAP::ST_UID - Fetch message components using the message uid
|
||||
| IMAP::ST_MSGN - Fetch message components using the message number
|
||||
| -Body download option
|
||||
| Default TRUE
|
||||
| -Flag download option
|
||||
| Default TRUE
|
||||
| -Soft fail
|
||||
| Default FALSE - Set to TRUE if you want to ignore certain exception while fetching bulk messages
|
||||
| -RFC822
|
||||
| Default TRUE - Set to FALSE to prevent the usage of \imap_rfc822_parse_headers().
|
||||
| See https://github.com/Webklex/php-imap/issues/115 for more information.
|
||||
| -Debug enable to trace communication traffic
|
||||
| -UID cache enable the UID cache
|
||||
| -Fallback date is used if the given message date could not be parsed
|
||||
| -Boundary regex used to detect message boundaries. If you are having problems with empty messages, missing
|
||||
| attachments or anything like this. Be advised that it likes to break which causes new problems..
|
||||
| -Message key identifier option
|
||||
| You can choose between the following:
|
||||
| 'id' - Use the MessageID as array key (default, might cause hickups with yahoo mail)
|
||||
| 'number' - Use the message number as array key (isn't always unique and can cause some interesting behavior)
|
||||
| 'list' - Use the message list number as array key (incrementing integer (does not always start at 0 or 1)
|
||||
| 'uid' - Use the message uid as array key (isn't always unique and can cause some interesting behavior)
|
||||
| -Fetch order
|
||||
| 'asc' - Order all messages ascending (probably results in oldest first)
|
||||
| 'desc' - Order all messages descending (probably results in newest first)
|
||||
| -Disposition types potentially considered an attachment
|
||||
| Default ['attachment', 'inline']
|
||||
| -Common folders
|
||||
| Default folder locations and paths assumed if none is provided
|
||||
| -Open IMAP options:
|
||||
| DISABLE_AUTHENTICATOR - Disable authentication properties.
|
||||
| Use 'GSSAPI' if you encounter the following
|
||||
| error: "Kerberos error: No credentials cache
|
||||
| file found (try running kinit) (...)"
|
||||
| or ['GSSAPI','PLAIN'] if you are using outlook mail
|
||||
|
|
||||
*/
|
||||
'options' => [
|
||||
'delimiter' => '/',
|
||||
'fetch' => \Webklex\PHPIMAP\IMAP::FT_PEEK,
|
||||
'sequence' => \Webklex\PHPIMAP\IMAP::ST_UID,
|
||||
'fetch_body' => true,
|
||||
'fetch_flags' => true,
|
||||
'soft_fail' => false,
|
||||
'rfc822' => true,
|
||||
'debug' => false,
|
||||
'unescaped_search_dates' => false,
|
||||
'uid_cache' => true,
|
||||
// 'fallback_date' => "01.01.1970 00:00:00",
|
||||
'boundary' => '/boundary=(.*?(?=;)|(.*))/i',
|
||||
'message_key' => 'list',
|
||||
'fetch_order' => 'asc',
|
||||
'dispositions' => ['attachment', 'inline'],
|
||||
'common_folders' => [
|
||||
"root" => "INBOX",
|
||||
"junk" => "INBOX/Junk",
|
||||
"draft" => "INBOX/Drafts",
|
||||
"sent" => "INBOX/Sent",
|
||||
"trash" => "INBOX/Trash",
|
||||
],
|
||||
'open' => [
|
||||
// 'DISABLE_AUTHENTICATOR' => 'GSSAPI'
|
||||
]
|
||||
],
|
||||
|
||||
/**
|
||||
* |--------------------------------------------------------------------------
|
||||
* | Available decoding options
|
||||
* |--------------------------------------------------------------------------
|
||||
* |
|
||||
* | Available php imap config parameters are listed below
|
||||
* | -options: Decoder options (currently only the message subject and attachment name decoder can be set)
|
||||
* | 'utf-8' - Uses imap_utf8($string) to decode a string
|
||||
* | 'mimeheader' - Uses mb_decode_mimeheader($string) to decode a string
|
||||
* | -decoder: Decoder to be used. Can be replaced by custom decoders if needed.
|
||||
* | 'header' - HeaderDecoder
|
||||
* | 'message' - MessageDecoder
|
||||
* | 'attachment' - AttachmentDecoder
|
||||
*/
|
||||
'decoding' => [
|
||||
'options' => [
|
||||
'header' => 'utf-8', // mimeheader
|
||||
'message' => 'utf-8', // mimeheader
|
||||
'attachment' => 'utf-8' // mimeheader
|
||||
],
|
||||
'decoder' => [
|
||||
'header' => \Webklex\PHPIMAP\Decoder\HeaderDecoder::class,
|
||||
'message' => \Webklex\PHPIMAP\Decoder\MessageDecoder::class,
|
||||
'attachment' => \Webklex\PHPIMAP\Decoder\AttachmentDecoder::class
|
||||
]
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Available flags
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| List all available / supported flags. Set to null to accept all given flags.
|
||||
*/
|
||||
'flags' => ['recent', 'flagged', 'answered', 'deleted', 'seen', 'draft'],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Available events
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
*/
|
||||
'events' => [
|
||||
"message" => [
|
||||
'new' => \Webklex\PHPIMAP\Events\MessageNewEvent::class,
|
||||
'moved' => \Webklex\PHPIMAP\Events\MessageMovedEvent::class,
|
||||
'copied' => \Webklex\PHPIMAP\Events\MessageCopiedEvent::class,
|
||||
'deleted' => \Webklex\PHPIMAP\Events\MessageDeletedEvent::class,
|
||||
'restored' => \Webklex\PHPIMAP\Events\MessageRestoredEvent::class,
|
||||
],
|
||||
"folder" => [
|
||||
'new' => \Webklex\PHPIMAP\Events\FolderNewEvent::class,
|
||||
'moved' => \Webklex\PHPIMAP\Events\FolderMovedEvent::class,
|
||||
'deleted' => \Webklex\PHPIMAP\Events\FolderDeletedEvent::class,
|
||||
],
|
||||
"flag" => [
|
||||
'new' => \Webklex\PHPIMAP\Events\FlagNewEvent::class,
|
||||
'deleted' => \Webklex\PHPIMAP\Events\FlagDeletedEvent::class,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Available masking options
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By using your own custom masks you can implement your own methods for
|
||||
| a better and faster access and less code to write.
|
||||
|
|
||||
| Checkout the two examples custom_attachment_mask and custom_message_mask
|
||||
| for a quick start.
|
||||
|
|
||||
| The provided masks below are used as the default masks.
|
||||
*/
|
||||
'masks' => [
|
||||
'message' => \Webklex\PHPIMAP\Support\Masks\MessageMask::class,
|
||||
'attachment' => \Webklex\PHPIMAP\Support\Masks\AttachmentMask::class
|
||||
]
|
||||
];
|
||||
72
plugins/vendor/webklex/php-imap/tests/AddressTest.php
vendored
Normal file
72
plugins/vendor/webklex/php-imap/tests/AddressTest.php
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/*
|
||||
* File: AddressTest.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 28.12.22 18:11
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Webklex\PHPIMAP\Address;
|
||||
|
||||
class AddressTest extends TestCase {
|
||||
|
||||
/**
|
||||
* Test data
|
||||
*
|
||||
* @var array|string[] $data
|
||||
*/
|
||||
protected array $data = [
|
||||
"personal" => "Username",
|
||||
"mailbox" => "info",
|
||||
"host" => "domain.tld",
|
||||
"mail" => "info@domain.tld",
|
||||
"full" => "Username <info@domain.tld>",
|
||||
];
|
||||
|
||||
/**
|
||||
* Address test
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAddress(): void {
|
||||
$address = new Address((object)$this->data);
|
||||
|
||||
self::assertSame("Username", $address->personal);
|
||||
self::assertSame("info", $address->mailbox);
|
||||
self::assertSame("domain.tld", $address->host);
|
||||
self::assertSame("info@domain.tld", $address->mail);
|
||||
self::assertSame("Username <info@domain.tld>", $address->full);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Address to string conversion
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAddressToStringConversion(): void {
|
||||
$address = new Address((object)$this->data);
|
||||
|
||||
self::assertSame("Username <info@domain.tld>", (string)$address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Address serialization
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAddressSerialization(): void {
|
||||
$address = new Address((object)$this->data);
|
||||
|
||||
foreach($address as $key => $value) {
|
||||
self::assertSame($this->data[$key], $value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
37
plugins/vendor/webklex/php-imap/tests/AttachmentTest.php
vendored
Normal file
37
plugins/vendor/webklex/php-imap/tests/AttachmentTest.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Tests\fixtures\FixtureTestCase;
|
||||
use Webklex\PHPIMAP\Attachment;
|
||||
|
||||
class AttachmentTest extends FixtureTestCase
|
||||
{
|
||||
protected Attachment $attachment;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$message = $this->getFixture("attachment_encoded_filename.eml");
|
||||
$this->attachment = $message->getAttachments()->first();
|
||||
}
|
||||
/**
|
||||
* @dataProvider decodeNameDataProvider
|
||||
*/
|
||||
public function testDecodeName(string $input, string $output): void
|
||||
{
|
||||
$name = $this->attachment->decodeName($input);
|
||||
$this->assertEquals($output, $name);
|
||||
}
|
||||
|
||||
public function decodeNameDataProvider(): array
|
||||
{
|
||||
return [
|
||||
['../../../../../../../../../../../var/www/shell.php', 'varwwwshell.php'],
|
||||
['test..xml', 'test.xml'],
|
||||
[chr(0), ''],
|
||||
['C:\\file.txt', 'Cfile.txt'],
|
||||
];
|
||||
}
|
||||
}
|
||||
75
plugins/vendor/webklex/php-imap/tests/AttributeTest.php
vendored
Normal file
75
plugins/vendor/webklex/php-imap/tests/AttributeTest.php
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/*
|
||||
* File: AttributeTest.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 28.12.22 18:11
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Webklex\PHPIMAP\Attribute;
|
||||
|
||||
class AttributeTest extends TestCase {
|
||||
|
||||
/**
|
||||
* String Attribute test
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStringAttribute(): void {
|
||||
$attribute = new Attribute("foo", "bar");
|
||||
|
||||
self::assertSame("bar", $attribute->toString());
|
||||
self::assertSame("foo", $attribute->getName());
|
||||
self::assertSame("foos", $attribute->setName("foos")->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Date Attribute test
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDateAttribute(): void {
|
||||
$attribute = new Attribute("foo", "2022-12-26 08:07:14 GMT-0800");
|
||||
|
||||
self::assertInstanceOf(Carbon::class, $attribute->toDate());
|
||||
self::assertSame("2022-12-26 08:07:14 GMT-0800", $attribute->toDate()->format("Y-m-d H:i:s T"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Array Attribute test
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testArrayAttribute(): void {
|
||||
$attribute = new Attribute("foo", ["bar"]);
|
||||
|
||||
self::assertSame("bar", $attribute->toString());
|
||||
|
||||
$attribute->add("bars");
|
||||
self::assertSame(true, $attribute->has(1));
|
||||
self::assertSame("bars", $attribute->get(1));
|
||||
self::assertSame(true, $attribute->contains("bars"));
|
||||
self::assertSame("foo, bars", $attribute->set("foo", 0)->toString());
|
||||
|
||||
$attribute->remove(0);
|
||||
self::assertSame("bars", $attribute->toString());
|
||||
|
||||
self::assertSame("bars, foos", $attribute->merge(["foos", "bars"], true)->toString());
|
||||
self::assertSame("bars, foos, foos, donk", $attribute->merge(["foos", "donk"], false)->toString());
|
||||
|
||||
self::assertSame(4, $attribute->count());
|
||||
|
||||
self::assertSame("donk", $attribute->last());
|
||||
self::assertSame("bars", $attribute->first());
|
||||
|
||||
self::assertSame(["bars", "foos", "foos", "donk"], array_values($attribute->all()));
|
||||
}
|
||||
}
|
||||
94
plugins/vendor/webklex/php-imap/tests/ClientManagerTest.php
vendored
Normal file
94
plugins/vendor/webklex/php-imap/tests/ClientManagerTest.php
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/*
|
||||
* File: ClientManagerTest.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 28.12.22 18:11
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Webklex\PHPIMAP\Client;
|
||||
use Webklex\PHPIMAP\ClientManager;
|
||||
use Webklex\PHPIMAP\Config;
|
||||
use Webklex\PHPIMAP\Exceptions\MaskNotFoundException;
|
||||
use Webklex\PHPIMAP\IMAP;
|
||||
|
||||
class ClientManagerTest extends TestCase {
|
||||
|
||||
/** @var ClientManager $cm */
|
||||
protected ClientManager $cm;
|
||||
|
||||
/**
|
||||
* Setup the test environment.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp(): void {
|
||||
$this->cm = new ClientManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the config can be accessed
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testConfigAccessorAccount(): void {
|
||||
$config = $this->cm->getConfig();
|
||||
self::assertInstanceOf(Config::class, $config);
|
||||
self::assertSame("default", $config->get("default"));
|
||||
self::assertSame("d-M-Y", $config->get("date_format"));
|
||||
self::assertSame(IMAP::FT_PEEK, $config->get("options.fetch"));
|
||||
self::assertSame([], $config->get("options.open"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creating a client instance
|
||||
*
|
||||
* @throws MaskNotFoundException
|
||||
*/
|
||||
public function testMakeClient(): void {
|
||||
self::assertInstanceOf(Client::class, $this->cm->make([]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test accessing accounts
|
||||
*
|
||||
* @throws MaskNotFoundException
|
||||
*/
|
||||
public function testAccountAccessor(): void {
|
||||
self::assertSame("default", $this->cm->getConfig()->getDefaultAccount());
|
||||
self::assertNotEmpty($this->cm->account("default"));
|
||||
|
||||
$this->cm->getConfig()->setDefaultAccount("foo");
|
||||
self::assertSame("foo", $this->cm->getConfig()->getDefaultAccount());
|
||||
$this->cm->getConfig()->setDefaultAccount("default");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setting a config
|
||||
*
|
||||
* @throws MaskNotFoundException
|
||||
*/
|
||||
public function testSetConfig(): void {
|
||||
$config = [
|
||||
"default" => "foo",
|
||||
"options" => [
|
||||
"fetch" => IMAP::ST_MSGN,
|
||||
"open" => "foo"
|
||||
]
|
||||
];
|
||||
$cm = new ClientManager($config);
|
||||
|
||||
self::assertSame("foo", $cm->getConfig()->getDefaultAccount());
|
||||
self::assertInstanceOf(Client::class, $cm->account("foo"));
|
||||
self::assertSame(IMAP::ST_MSGN, $cm->getConfig()->get("options.fetch"));
|
||||
self::assertSame(false, is_array($cm->getConfig()->get("options.open")));
|
||||
|
||||
}
|
||||
}
|
||||
348
plugins/vendor/webklex/php-imap/tests/ClientTest.php
vendored
Normal file
348
plugins/vendor/webklex/php-imap/tests/ClientTest.php
vendored
Normal file
@@ -0,0 +1,348 @@
|
||||
<?php
|
||||
/*
|
||||
* File: ClientTest.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 28.12.22 18:11
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Webklex\PHPIMAP\Client;
|
||||
use Webklex\PHPIMAP\Config;
|
||||
use Webklex\PHPIMAP\Connection\Protocols\ImapProtocol;
|
||||
use Webklex\PHPIMAP\Connection\Protocols\Response;
|
||||
use Webklex\PHPIMAP\Exceptions\AuthFailedException;
|
||||
use Webklex\PHPIMAP\Exceptions\ConnectionFailedException;
|
||||
use Webklex\PHPIMAP\Exceptions\ImapBadRequestException;
|
||||
use Webklex\PHPIMAP\Exceptions\ImapServerErrorException;
|
||||
use Webklex\PHPIMAP\Exceptions\MaskNotFoundException;
|
||||
use Webklex\PHPIMAP\Exceptions\RuntimeException;
|
||||
use Webklex\PHPIMAP\Folder;
|
||||
use Webklex\PHPIMAP\Support\Masks\AttachmentMask;
|
||||
use Webklex\PHPIMAP\Support\Masks\MessageMask;
|
||||
|
||||
class ClientTest extends TestCase {
|
||||
|
||||
/** @var Client $client */
|
||||
protected Client $client;
|
||||
|
||||
/** @var MockObject ImapProtocol mockup */
|
||||
protected MockObject $protocol;
|
||||
|
||||
/**
|
||||
* Setup the test environment.
|
||||
*
|
||||
* @return void
|
||||
* @throws MaskNotFoundException
|
||||
*/
|
||||
public function setUp(): void {
|
||||
$config = Config::make([
|
||||
"accounts" => [
|
||||
"default" => [
|
||||
'protocol' => 'imap',
|
||||
'encryption' => 'ssl',
|
||||
'username' => 'foo@domain.tld',
|
||||
'password' => 'bar',
|
||||
'proxy' => [
|
||||
'socket' => null,
|
||||
'request_fulluri' => false,
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
],
|
||||
]]
|
||||
]);
|
||||
$this->client = new Client($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Client test
|
||||
*
|
||||
* @return void
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function testClient(): void {
|
||||
$this->createNewProtocolMockup();
|
||||
|
||||
self::assertInstanceOf(ImapProtocol::class, $this->client->getConnection());
|
||||
self::assertSame(true, $this->client->isConnected());
|
||||
self::assertSame(false, $this->client->checkConnection());
|
||||
self::assertSame(30, $this->client->getTimeout());
|
||||
self::assertSame(MessageMask::class, $this->client->getDefaultMessageMask());
|
||||
self::assertSame(AttachmentMask::class, $this->client->getDefaultAttachmentMask());
|
||||
self::assertArrayHasKey("new", $this->client->getDefaultEvents("message"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MaskNotFoundException
|
||||
*/
|
||||
public function testClientClone(): void {
|
||||
$config = Config::make([
|
||||
"accounts" => [
|
||||
"default" => [
|
||||
'host' => 'example.com',
|
||||
'port' => 993,
|
||||
'protocol' => 'imap', //might also use imap, [pop3 or nntp (untested)]
|
||||
'encryption' => 'ssl', // Supported: false, 'ssl', 'tls'
|
||||
'validate_cert' => true,
|
||||
'username' => 'root@example.com',
|
||||
'password' => 'foo',
|
||||
'authentication' => null,
|
||||
'rfc' => 'RFC822', // If you are using iCloud, you might want to set this to 'BODY'
|
||||
'proxy' => [
|
||||
'socket' => null,
|
||||
'request_fulluri' => false,
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
],
|
||||
"timeout" => 30,
|
||||
"extensions" => []
|
||||
]]
|
||||
]);
|
||||
$client = new Client($config);
|
||||
$clone = $client->clone();
|
||||
self::assertInstanceOf(Client::class, $clone);
|
||||
self::assertSame($client->getConfig(), $clone->getConfig());
|
||||
self::assertSame($client->getAccountConfig(), $clone->getAccountConfig());
|
||||
self::assertSame($client->host, $clone->host);
|
||||
}
|
||||
|
||||
public function testClientLogout(): void {
|
||||
$this->createNewProtocolMockup();
|
||||
|
||||
$this->protocol->expects($this->any())->method('logout')->willReturn(Response::empty()->setResponse([
|
||||
0 => "BYE Logging out\r\n",
|
||||
1 => "OK Logout completed (0.001 + 0.000 secs).\r\n",
|
||||
]));
|
||||
self::assertInstanceOf(Client::class, $this->client->disconnect());
|
||||
|
||||
}
|
||||
|
||||
public function testClientExpunge(): void {
|
||||
$this->createNewProtocolMockup();
|
||||
$this->protocol->expects($this->any())->method('expunge')->willReturn(Response::empty()->setResponse([
|
||||
0 => "OK",
|
||||
1 => "Expunge",
|
||||
2 => "completed",
|
||||
3 => [
|
||||
0 => "0.001",
|
||||
1 => "+",
|
||||
2 => "0.000",
|
||||
3 => "secs).",
|
||||
],
|
||||
]));
|
||||
self::assertNotEmpty($this->client->expunge());
|
||||
|
||||
}
|
||||
|
||||
public function testClientFolders(): void {
|
||||
$this->createNewProtocolMockup();
|
||||
$this->protocol->expects($this->any())->method('expunge')->willReturn(Response::empty()->setResponse([
|
||||
0 => "OK",
|
||||
1 => "Expunge",
|
||||
2 => "completed",
|
||||
3 => [
|
||||
0 => "0.001",
|
||||
1 => "+",
|
||||
2 => "0.000",
|
||||
3 => "secs).",
|
||||
],
|
||||
]));
|
||||
|
||||
$this->protocol->expects($this->any())->method('selectFolder')->willReturn(Response::empty()->setResponse([
|
||||
"flags" => [
|
||||
0 => [
|
||||
0 => "\Answered",
|
||||
1 => "\Flagged",
|
||||
2 => "\Deleted",
|
||||
3 => "\Seen",
|
||||
4 => "\Draft",
|
||||
5 => "NonJunk",
|
||||
6 => "unknown-1",
|
||||
],
|
||||
],
|
||||
"exists" => 139,
|
||||
"recent" => 0,
|
||||
"unseen" => 94,
|
||||
"uidvalidity" => 1488899637,
|
||||
"uidnext" => 278,
|
||||
]));
|
||||
self::assertNotEmpty($this->client->openFolder("INBOX"));
|
||||
self::assertSame("INBOX", $this->client->getFolderPath());
|
||||
|
||||
$this->protocol->expects($this->any())->method('examineFolder')->willReturn(Response::empty()->setResponse([
|
||||
"flags" => [
|
||||
0 => [
|
||||
0 => "\Answered",
|
||||
1 => "\Flagged",
|
||||
2 => "\Deleted",
|
||||
3 => "\Seen",
|
||||
4 => "\Draft",
|
||||
5 => "NonJunk",
|
||||
6 => "unknown-1",
|
||||
],
|
||||
],
|
||||
"exists" => 139,
|
||||
"recent" => 0,
|
||||
"unseen" => 94,
|
||||
"uidvalidity" => 1488899637,
|
||||
"uidnext" => 278,
|
||||
]));
|
||||
self::assertNotEmpty($this->client->checkFolder("INBOX"));
|
||||
|
||||
$this->protocol->expects($this->any())->method('folders')->with($this->identicalTo(""), $this->identicalTo("*"))->willReturn(Response::empty()->setResponse([
|
||||
"INBOX" => [
|
||||
"delimiter" => ".",
|
||||
"flags" => [
|
||||
0 => "\HasChildren",
|
||||
],
|
||||
],
|
||||
"INBOX.new" => [
|
||||
"delimiter" => ".",
|
||||
"flags" => [
|
||||
0 => "\HasNoChildren",
|
||||
],
|
||||
],
|
||||
"INBOX.9AL56dEMTTgUKOAz" => [
|
||||
"delimiter" => ".",
|
||||
"flags" => [
|
||||
0 => "\HasNoChildren",
|
||||
],
|
||||
],
|
||||
"INBOX.U9PsHCvXxAffYvie" => [
|
||||
"delimiter" => ".",
|
||||
"flags" => [
|
||||
0 => "\HasNoChildren",
|
||||
],
|
||||
],
|
||||
"INBOX.Trash" => [
|
||||
"delimiter" => ".",
|
||||
"flags" => [
|
||||
0 => "\HasNoChildren",
|
||||
1 => "\Trash",
|
||||
],
|
||||
],
|
||||
"INBOX.processing" => [
|
||||
"delimiter" => ".",
|
||||
"flags" => [
|
||||
0 => "\HasNoChildren",
|
||||
],
|
||||
],
|
||||
"INBOX.Sent" => [
|
||||
"delimiter" => ".",
|
||||
"flags" => [
|
||||
0 => "\HasNoChildren",
|
||||
1 => "\Sent",
|
||||
],
|
||||
],
|
||||
"INBOX.OzDWCXKV3t241koc" => [
|
||||
"delimiter" => ".",
|
||||
"flags" => [
|
||||
0 => "\HasNoChildren",
|
||||
],
|
||||
],
|
||||
"INBOX.5F3bIVTtBcJEqIVe" => [
|
||||
"delimiter" => ".",
|
||||
"flags" => [
|
||||
0 => "\HasNoChildren",
|
||||
],
|
||||
],
|
||||
"INBOX.8J3rll6eOBWnTxIU" => [
|
||||
"delimiter" => ".",
|
||||
"flags" => [
|
||||
0 => "\HasNoChildren",
|
||||
],
|
||||
],
|
||||
"INBOX.Junk" => [
|
||||
"delimiter" => ".",
|
||||
"flags" => [
|
||||
0 => "\HasNoChildren",
|
||||
1 => "\Junk",
|
||||
],
|
||||
],
|
||||
"INBOX.Drafts" => [
|
||||
"delimiter" => ".",
|
||||
"flags" => [
|
||||
0 => "\HasNoChildren",
|
||||
1 => "\Drafts",
|
||||
],
|
||||
],
|
||||
"INBOX.test" => [
|
||||
"delimiter" => ".",
|
||||
"flags" => [
|
||||
0 => "\HasNoChildren",
|
||||
],
|
||||
],
|
||||
]));
|
||||
|
||||
$this->protocol->expects($this->any())->method('createFolder')->willReturn(Response::empty()->setResponse([
|
||||
0 => "OK Create completed (0.004 + 0.000 + 0.003 secs).\r\n",
|
||||
]));
|
||||
self::assertNotEmpty($this->client->createFolder("INBOX.new"));
|
||||
|
||||
$this->protocol->expects($this->any())->method('deleteFolder')->willReturn(Response::empty()->setResponse([
|
||||
0 => "OK Delete completed (0.007 + 0.000 + 0.006 secs).\r\n",
|
||||
]));
|
||||
self::assertNotEmpty($this->client->deleteFolder("INBOX.new"));
|
||||
|
||||
self::assertInstanceOf(Folder::class, $this->client->getFolderByPath("INBOX.new"));
|
||||
self::assertInstanceOf(Folder::class, $this->client->getFolderByName("new"));
|
||||
self::assertInstanceOf(Folder::class, $this->client->getFolder("INBOX.new", "."));
|
||||
self::assertInstanceOf(Folder::class, $this->client->getFolder("new"));
|
||||
}
|
||||
|
||||
public function testClientId(): void {
|
||||
$this->createNewProtocolMockup();
|
||||
$this->protocol->expects($this->any())->method('ID')->willReturn(Response::empty()->setResponse([
|
||||
0 => "ID (\"name\" \"Dovecot\")\r\n",
|
||||
1 => "OK ID completed (0.001 + 0.000 secs).\r\n"
|
||||
|
||||
]));
|
||||
self::assertSame("ID (\"name\" \"Dovecot\")\r\n", $this->client->Id()[0]);
|
||||
|
||||
}
|
||||
|
||||
public function testClientConfig(): void {
|
||||
$config = $this->client->getConfig()->get("accounts.".$this->client->getConfig()->getDefaultAccount());
|
||||
self::assertSame("foo@domain.tld", $config["username"]);
|
||||
self::assertSame("bar", $config["password"]);
|
||||
self::assertSame("localhost", $config["host"]);
|
||||
self::assertSame(true, $config["validate_cert"]);
|
||||
self::assertSame(993, $config["port"]);
|
||||
|
||||
$this->client->getConfig()->set("accounts.".$this->client->getConfig()->getDefaultAccount(), [
|
||||
"host" => "domain.tld",
|
||||
'password' => 'bar',
|
||||
]);
|
||||
$config = $this->client->getConfig()->get("accounts.".$this->client->getConfig()->getDefaultAccount());
|
||||
|
||||
self::assertSame("bar", $config["password"]);
|
||||
self::assertSame("domain.tld", $config["host"]);
|
||||
self::assertSame(true, $config["validate_cert"]);
|
||||
}
|
||||
|
||||
protected function createNewProtocolMockup() {
|
||||
$this->protocol = $this->createMock(ImapProtocol::class);
|
||||
|
||||
$this->protocol->expects($this->any())->method('connected')->willReturn(true);
|
||||
$this->protocol->expects($this->any())->method('getConnectionTimeout')->willReturn(30);
|
||||
|
||||
$this->protocol
|
||||
->expects($this->any())
|
||||
->method('createStream')
|
||||
//->will($this->onConsecutiveCalls(true));
|
||||
->willReturn(true);
|
||||
|
||||
$this->client->connection = $this->protocol;
|
||||
}
|
||||
}
|
||||
204
plugins/vendor/webklex/php-imap/tests/HeaderTest.php
vendored
Normal file
204
plugins/vendor/webklex/php-imap/tests/HeaderTest.php
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
/*
|
||||
* File: HeaderTest.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 28.12.22 18:11
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Webklex\PHPIMAP\Address;
|
||||
use Webklex\PHPIMAP\Attribute;
|
||||
use Webklex\PHPIMAP\Config;
|
||||
use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException;
|
||||
use Webklex\PHPIMAP\Header;
|
||||
use Webklex\PHPIMAP\IMAP;
|
||||
|
||||
class HeaderTest extends TestCase {
|
||||
|
||||
/** @var Config $config */
|
||||
protected Config $config;
|
||||
|
||||
/**
|
||||
* Setup the test environment.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp(): void {
|
||||
$this->config = Config::make();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test parsing email headers
|
||||
*
|
||||
* @throws InvalidMessageDateException
|
||||
*/
|
||||
public function testHeaderParsing(): void {
|
||||
$email = file_get_contents(implode(DIRECTORY_SEPARATOR, [__DIR__, "messages", "1366671050@github.com.eml"]));
|
||||
if (!str_contains($email, "\r\n")) {
|
||||
$email = str_replace("\n", "\r\n", $email);
|
||||
}
|
||||
|
||||
$raw_header = substr($email, 0, strpos($email, "\r\n\r\n"));
|
||||
|
||||
$header = new Header($raw_header, $this->config);
|
||||
$subject = $header->get("subject");
|
||||
$returnPath = $header->get("return_path");
|
||||
/** @var Carbon $date */
|
||||
$date = $header->get("date")->first();
|
||||
/** @var Address $from */
|
||||
$from = $header->get("from")->first();
|
||||
/** @var Address $to */
|
||||
$to = $header->get("to")->first();
|
||||
|
||||
self::assertSame($raw_header, $header->raw);
|
||||
self::assertSame([
|
||||
0 => 'from mx.domain.tld by localhost with LMTP id SABVMNfGqWP+PAAA0J78UA (envelope-from <noreply@github.com>) for <someone@domain.tld>; Mon, 26 Dec 2022 17:07:51 +0100',
|
||||
1 => 'from localhost (localhost [127.0.0.1]) by mx.domain.tld (Postfix) with ESMTP id C3828140227 for <someone@domain.tld>; Mon, 26 Dec 2022 17:07:51 +0100 (CET)',
|
||||
2 => 'from mx.domain.tld ([127.0.0.1]) by localhost (mx.domain.tld [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id JcIS9RuNBTNx for <someone@domain.tld>; Mon, 26 Dec 2022 17:07:21 +0100 (CET)',
|
||||
3 => 'from smtp.github.com (out-26.smtp.github.com [192.30.252.209]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx.domain.tld (Postfix) with ESMTPS id 6410B13FEB2 for <someone@domain.tld>; Mon, 26 Dec 2022 17:07:21 +0100 (CET)',
|
||||
4 => 'from github-lowworker-891b8d2.va3-iad.github.net (github-lowworker-891b8d2.va3-iad.github.net [10.48.109.104]) by smtp.github.com (Postfix) with ESMTP id 176985E0200 for <someone@domain.tld>; Mon, 26 Dec 2022 08:07:14 -0800 (PST)',
|
||||
], $header->get("received")->toArray());
|
||||
self::assertInstanceOf(Attribute::class, $subject);
|
||||
self::assertSame("Re: [Webklex/php-imap] Read all folders? (Issue #349)", $subject->toString());
|
||||
self::assertSame("Re: [Webklex/php-imap] Read all folders? (Issue #349)", (string)$header->subject);
|
||||
self::assertSame("noreply@github.com", $returnPath->toString());
|
||||
self::assertSame("return_path", $returnPath->getName());
|
||||
self::assertSame("-4.299", (string)$header->get("X-Spam-Score"));
|
||||
self::assertSame("Webklex/php-imap/issues/349/1365266070@github.com", (string)$header->get("Message-ID"));
|
||||
self::assertSame(5, $header->get("received")->count());
|
||||
self::assertSame(IMAP::MESSAGE_PRIORITY_UNKNOWN, (int)$header->get("priority")());
|
||||
|
||||
self::assertSame("Username", $from->personal);
|
||||
self::assertSame("notifications", $from->mailbox);
|
||||
self::assertSame("github.com", $from->host);
|
||||
self::assertSame("notifications@github.com", $from->mail);
|
||||
self::assertSame("Username <notifications@github.com>", $from->full);
|
||||
|
||||
self::assertSame("Webklex/php-imap", $to->personal);
|
||||
self::assertSame("php-imap", $to->mailbox);
|
||||
self::assertSame("noreply.github.com", $to->host);
|
||||
self::assertSame("php-imap@noreply.github.com", $to->mail);
|
||||
self::assertSame("Webklex/php-imap <php-imap@noreply.github.com>", $to->full);
|
||||
|
||||
self::assertInstanceOf(Carbon::class, $date);
|
||||
self::assertSame("2022-12-26 08:07:14 GMT-0800", $date->format("Y-m-d H:i:s T"));
|
||||
|
||||
self::assertSame(51, count($header->getAttributes()));
|
||||
}
|
||||
|
||||
public function testRfc822ParseHeaders() {
|
||||
$mock = $this->getMockBuilder(Header::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods([])
|
||||
->getMock();
|
||||
|
||||
$config = new \ReflectionProperty($mock, 'options');
|
||||
$config->setAccessible(true);
|
||||
$config->setValue($mock, $this->config->get("options"));
|
||||
|
||||
$mockHeader = "Content-Type: text/csv; charset=WINDOWS-1252; name*0=\"TH_Is_a_F ile name example 20221013.c\"; name*1=sv\r\nContent-Transfer-Encoding: quoted-printable\r\nContent-Disposition: attachment; filename*0=\"TH_Is_a_F ile name example 20221013.c\"; filename*1=\"sv\"\r\n";
|
||||
|
||||
$expected = new \stdClass();
|
||||
$expected->content_type = 'text/csv; charset=WINDOWS-1252; name*0="TH_Is_a_F ile name example 20221013.c"; name*1=sv';
|
||||
$expected->content_transfer_encoding = 'quoted-printable';
|
||||
$expected->content_disposition = 'attachment; filename*0="TH_Is_a_F ile name example 20221013.c"; filename*1="sv"';
|
||||
|
||||
$this->assertEquals($expected, $mock->rfc822_parse_headers($mockHeader));
|
||||
}
|
||||
|
||||
public function testExtractHeaderExtensions() {
|
||||
$mock = $this->getMockBuilder(Header::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods([])
|
||||
->getMock();
|
||||
|
||||
$method = new \ReflectionMethod($mock, 'extractHeaderExtensions');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$mockAttributes = [
|
||||
'content_type' => new Attribute('content_type', 'text/csv; charset=WINDOWS-1252; name*0="TH_Is_a_F ile name example 20221013.c"; name*1=sv'),
|
||||
'content_transfer_encoding' => new Attribute('content_transfer_encoding', 'quoted-printable'),
|
||||
'content_disposition' => new Attribute('content_disposition', 'attachment; filename*0="TH_Is_a_F ile name example 20221013.c"; filename*1="sv"; attribute_test=attribute_test_value'),
|
||||
];
|
||||
|
||||
$attributes = new \ReflectionProperty($mock, 'attributes');
|
||||
$attributes->setAccessible(true);
|
||||
$attributes->setValue($mock, $mockAttributes);
|
||||
|
||||
$method->invoke($mock);
|
||||
|
||||
$this->assertArrayHasKey('filename', $mock->getAttributes());
|
||||
$this->assertArrayNotHasKey('filename*0', $mock->getAttributes());
|
||||
$this->assertEquals('TH_Is_a_F ile name example 20221013.csv', $mock->get('filename'));
|
||||
|
||||
$this->assertArrayHasKey('name', $mock->getAttributes());
|
||||
$this->assertArrayNotHasKey('name*0', $mock->getAttributes());
|
||||
$this->assertEquals('TH_Is_a_F ile name example 20221013.csv', $mock->get('name'));
|
||||
|
||||
$this->assertArrayHasKey('content_type', $mock->getAttributes());
|
||||
$this->assertEquals('text/csv', $mock->get('content_type')->last());
|
||||
|
||||
$this->assertArrayHasKey('charset', $mock->getAttributes());
|
||||
$this->assertEquals('WINDOWS-1252', $mock->get('charset')->last());
|
||||
|
||||
$this->assertArrayHasKey('content_transfer_encoding', $mock->getAttributes());
|
||||
$this->assertEquals('quoted-printable', $mock->get('content_transfer_encoding'));
|
||||
|
||||
$this->assertArrayHasKey('content_disposition', $mock->getAttributes());
|
||||
$this->assertEquals('attachment', $mock->get('content_disposition')->last());
|
||||
$this->assertEquals('quoted-printable', $mock->get('content_transfer_encoding'));
|
||||
|
||||
$this->assertArrayHasKey('attribute_test', $mock->getAttributes());
|
||||
$this->assertEquals('attribute_test_value', $mock->get('attribute_test'));
|
||||
}
|
||||
|
||||
public function testExtractHeaderExtensions2() {
|
||||
$mock = $this->getMockBuilder(Header::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods([])
|
||||
->getMock();
|
||||
|
||||
$method = new \ReflectionMethod($mock, 'extractHeaderExtensions');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$mockAttributes = [
|
||||
'content_type' => new Attribute('content_type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; name="=?utf-8?Q?=D0=A2=D0=B8=D0=BF=D0=BE=D0=B2=D0=BE=D0=B9_?= =?utf-8?Q?=D1=80=D0=B0=D1=81=D1=87=D0=B5=D1=82_=D0=BF?= =?utf-8?Q?=D0=BE=D1=82=D1=80=D0=B5=D0=B1=D0=BB=D0=B5=D0=BD?= =?utf-8?Q?=D0=B8=D1=8F_=D1=8D=D0=BB=D0=B5=D0=BA=D1=82?= =?utf-8?Q?=D1=80=D0=BE=D1=8D=D0=BD=D0=B5=D1=80=D0=B3=D0=B8=D0=B8_=D0=B2_?= =?utf-8?Q?=D0=9A=D0=9F_=D0=97=D0=B2=D0=B5=D0=B7=D0=B4?= =?utf-8?Q?=D0=BD=D1=8B=D0=B9=2Exlsx?="'),
|
||||
'content_transfer_encoding' => new Attribute('content_transfer_encoding', 'base64'),
|
||||
'content_disposition' => new Attribute('content_disposition', 'attachment; name*0*=utf-8\'\'%D0%A2%D0%B8%D0%BF%D0%BE%D0%B2%D0%BE%D0%B9%20; name*1*=%D1%80%D0%B0%D1%81%D1%87%D0%B5%D1%82%20%D0%BF; name*2*=%D0%BE%D1%82%D1%80%D0%B5%D0%B1%D0%BB%D0%B5%D0%BD; name*3*=%D0%B8%D1%8F%20%D1%8D%D0%BB%D0%B5%D0%BA%D1%82; name*4*=%D1%80%D0%BE%D1%8D%D0%BD%D0%B5%D1%80%D0%B3%D0%B8; name*5*=%D0%B8%20%D0%B2%20%D0%9A%D0%9F%20%D0%97%D0%B2%D0%B5%D0%B7%D0%B4; name*6*=%D0%BD%D1%8B%D0%B9.xlsx; filename*0*=utf-8\'\'%D0%A2%D0%B8%D0%BF%D0%BE%D0%B2%D0%BE%D0%B9%20; filename*1*=%D1%80%D0%B0%D1%81%D1%87%D0%B5%D1%82%20%D0%BF; filename*2*=%D0%BE%D1%82%D1%80%D0%B5%D0%B1%D0%BB%D0%B5%D0%BD; filename*3*=%D0%B8%D1%8F%20%D1%8D%D0%BB%D0%B5%D0%BA%D1%82; filename*4*=%D1%80%D0%BE%D1%8D%D0%BD%D0%B5%D1%80%D0%B3%D0%B8; filename*5*=%D0%B8%20%D0%B2%20%D0%9A%D0%9F%20%D0%97; filename*6*=%D0%B2%D0%B5%D0%B7%D0%B4%D0%BD%D1%8B%D0%B9.xlsx; attribute_test=attribute_test_value'),
|
||||
];
|
||||
|
||||
$attributes = new \ReflectionProperty($mock, 'attributes');
|
||||
$attributes->setAccessible(true);
|
||||
$attributes->setValue($mock, $mockAttributes);
|
||||
|
||||
$method->invoke($mock);
|
||||
|
||||
$this->assertArrayHasKey('filename', $mock->getAttributes());
|
||||
$this->assertArrayNotHasKey('filename*0', $mock->getAttributes());
|
||||
$this->assertEquals('utf-8\'\'%D0%A2%D0%B8%D0%BF%D0%BE%D0%B2%D0%BE%D0%B9%20%D1%80%D0%B0%D1%81%D1%87%D0%B5%D1%82%20%D0%BF%D0%BE%D1%82%D1%80%D0%B5%D0%B1%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F%20%D1%8D%D0%BB%D0%B5%D0%BA%D1%82%D1%80%D0%BE%D1%8D%D0%BD%D0%B5%D1%80%D0%B3%D0%B8%D0%B8%20%D0%B2%20%D0%9A%D0%9F%20%D0%97%D0%B2%D0%B5%D0%B7%D0%B4%D0%BD%D1%8B%D0%B9.xlsx', $mock->get('filename'));
|
||||
|
||||
$this->assertArrayHasKey('name', $mock->getAttributes());
|
||||
$this->assertArrayNotHasKey('name*0', $mock->getAttributes());
|
||||
$this->assertEquals('=?utf-8?Q?=D0=A2=D0=B8=D0=BF=D0=BE=D0=B2=D0=BE=D0=B9_?= =?utf-8?Q?=D1=80=D0=B0=D1=81=D1=87=D0=B5=D1=82_=D0=BF?= =?utf-8?Q?=D0=BE=D1=82=D1=80=D0=B5=D0=B1=D0=BB=D0=B5=D0=BD?= =?utf-8?Q?=D0=B8=D1=8F_=D1=8D=D0=BB=D0=B5=D0=BA=D1=82?= =?utf-8?Q?=D1=80=D0=BE=D1=8D=D0=BD=D0=B5=D1=80=D0=B3=D0=B8=D0=B8_=D0=B2_?= =?utf-8?Q?=D0=9A=D0=9F_=D0=97=D0=B2=D0=B5=D0=B7=D0=B4?= =?utf-8?Q?=D0=BD=D1=8B=D0=B9=2Exlsx?=', $mock->get('name'));
|
||||
|
||||
$this->assertArrayHasKey('content_type', $mock->getAttributes());
|
||||
$this->assertEquals('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', $mock->get('content_type')->last());
|
||||
|
||||
$this->assertArrayHasKey('content_transfer_encoding', $mock->getAttributes());
|
||||
$this->assertEquals('base64', $mock->get('content_transfer_encoding'));
|
||||
|
||||
$this->assertArrayHasKey('content_disposition', $mock->getAttributes());
|
||||
$this->assertEquals('attachment', $mock->get('content_disposition')->last());
|
||||
|
||||
$this->assertArrayHasKey('attribute_test', $mock->getAttributes());
|
||||
$this->assertEquals('attribute_test_value', $mock->get('attribute_test'));
|
||||
}
|
||||
}
|
||||
64
plugins/vendor/webklex/php-imap/tests/ImapProtocolTest.php
vendored
Normal file
64
plugins/vendor/webklex/php-imap/tests/ImapProtocolTest.php
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/*
|
||||
* File: ImapProtocolTest.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 28.12.22 18:11
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Webklex\PHPIMAP\Config;
|
||||
use Webklex\PHPIMAP\Connection\Protocols\ImapProtocol;
|
||||
use Webklex\PHPIMAP\Exceptions\ConnectionFailedException;
|
||||
|
||||
class ImapProtocolTest extends TestCase {
|
||||
|
||||
/** @var Config $config */
|
||||
protected Config $config;
|
||||
|
||||
/**
|
||||
* Setup the test environment.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp(): void {
|
||||
$this->config = Config::make();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ImapProtocol test
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testImapProtocol(): void {
|
||||
|
||||
$protocol = new ImapProtocol($this->config, false);
|
||||
self::assertSame(false, $protocol->getCertValidation());
|
||||
self::assertSame("", $protocol->getEncryption());
|
||||
|
||||
$protocol->setCertValidation(true);
|
||||
$protocol->setEncryption("ssl");
|
||||
|
||||
self::assertSame(true, $protocol->getCertValidation());
|
||||
self::assertSame("ssl", $protocol->getEncryption());
|
||||
|
||||
$protocol->setSslOptions([
|
||||
'verify_peer' => true,
|
||||
'cafile' => '/dummy/path/for/testing',
|
||||
'peer_fingerprint' => ['md5' => 40],
|
||||
]);
|
||||
|
||||
self::assertSame([
|
||||
'verify_peer' => true,
|
||||
'cafile' => '/dummy/path/for/testing',
|
||||
'peer_fingerprint' => ['md5' => 40],
|
||||
], $protocol->getSslOptions());
|
||||
}
|
||||
}
|
||||
302
plugins/vendor/webklex/php-imap/tests/MessageTest.php
vendored
Normal file
302
plugins/vendor/webklex/php-imap/tests/MessageTest.php
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
<?php
|
||||
/*
|
||||
* File: MessageTest.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 28.12.22 18:11
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use ReflectionException;
|
||||
use Webklex\PHPIMAP\Attachment;
|
||||
use Webklex\PHPIMAP\Attribute;
|
||||
use Webklex\PHPIMAP\Client;
|
||||
use Webklex\PHPIMAP\Config;
|
||||
use Webklex\PHPIMAP\Connection\Protocols\Response;
|
||||
use Webklex\PHPIMAP\Exceptions\EventNotFoundException;
|
||||
use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException;
|
||||
use Webklex\PHPIMAP\Exceptions\MessageContentFetchingException;
|
||||
use Webklex\PHPIMAP\Exceptions\MessageFlagException;
|
||||
use Webklex\PHPIMAP\Exceptions\MessageNotFoundException;
|
||||
use Webklex\PHPIMAP\Exceptions\MessageSizeFetchingException;
|
||||
use Webklex\PHPIMAP\Exceptions\ResponseException;
|
||||
use Webklex\PHPIMAP\IMAP;
|
||||
use Webklex\PHPIMAP\Message;
|
||||
use Webklex\PHPIMAP\Connection\Protocols\ImapProtocol;
|
||||
use Webklex\PHPIMAP\Exceptions\AuthFailedException;
|
||||
use Webklex\PHPIMAP\Exceptions\ConnectionFailedException;
|
||||
use Webklex\PHPIMAP\Exceptions\ImapBadRequestException;
|
||||
use Webklex\PHPIMAP\Exceptions\ImapServerErrorException;
|
||||
use Webklex\PHPIMAP\Exceptions\MaskNotFoundException;
|
||||
use Webklex\PHPIMAP\Exceptions\RuntimeException;
|
||||
|
||||
class MessageTest extends TestCase {
|
||||
|
||||
/** @var Message $message */
|
||||
protected Message $message;
|
||||
|
||||
/** @var Client $client */
|
||||
protected Client $client;
|
||||
|
||||
/** @var MockObject ImapProtocol mockup */
|
||||
protected MockObject $protocol;
|
||||
|
||||
/**
|
||||
* Setup the test environment.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp(): void {
|
||||
$config = Config::make([
|
||||
"accounts" => [
|
||||
"default" => [
|
||||
'protocol' => 'imap',
|
||||
'encryption' => 'ssl',
|
||||
'username' => 'foo@domain.tld',
|
||||
'password' => 'bar',
|
||||
'proxy' => [
|
||||
'socket' => null,
|
||||
'request_fulluri' => false,
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
],
|
||||
]]
|
||||
]);
|
||||
$this->client = new Client($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Message test
|
||||
*
|
||||
* @return void
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws EventNotFoundException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws InvalidMessageDateException
|
||||
* @throws MessageContentFetchingException
|
||||
* @throws MessageFlagException
|
||||
* @throws MessageNotFoundException
|
||||
* @throws MessageSizeFetchingException
|
||||
* @throws ReflectionException
|
||||
* @throws ResponseException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function testMessage(): void {
|
||||
$this->createNewProtocolMockup();
|
||||
|
||||
$email = file_get_contents(implode(DIRECTORY_SEPARATOR, [__DIR__, "messages", "1366671050@github.com.eml"]));
|
||||
if(!str_contains($email, "\r\n")){
|
||||
$email = str_replace("\n", "\r\n", $email);
|
||||
}
|
||||
|
||||
$raw_header = substr($email, 0, strpos($email, "\r\n\r\n"));
|
||||
$raw_body = substr($email, strlen($raw_header)+8);
|
||||
|
||||
$this->protocol->expects($this->any())->method('getUid')->willReturn(Response::empty()->setResult(22));
|
||||
$this->protocol->expects($this->any())->method('getMessageNumber')->willReturn(Response::empty()->setResult(21));
|
||||
$this->protocol->expects($this->any())->method('flags')->willReturn(Response::empty()->setResult([22 => [0 => "\\Seen"]]));
|
||||
|
||||
self::assertNotEmpty($this->client->openFolder("INBOX"));
|
||||
|
||||
$message = Message::make(22, null, $this->client, $raw_header, $raw_body, [0 => "\\Seen"], IMAP::ST_UID);
|
||||
|
||||
self::assertInstanceOf(Client::class, $message->getClient());
|
||||
self::assertSame(22, $message->uid);
|
||||
self::assertSame(21, $message->msgn);
|
||||
self::assertContains("Seen", $message->flags()->toArray());
|
||||
|
||||
$subject = $message->get("subject");
|
||||
$returnPath = $message->get("Return-Path");
|
||||
|
||||
self::assertInstanceOf(Attribute::class, $subject);
|
||||
self::assertSame("Re: [Webklex/php-imap] Read all folders? (Issue #349)", $subject->toString());
|
||||
self::assertSame("Re: [Webklex/php-imap] Read all folders? (Issue #349)", (string)$message->subject);
|
||||
self::assertSame("noreply@github.com", $returnPath->toString());
|
||||
self::assertSame("return_path", $returnPath->getName());
|
||||
self::assertSame("-4.299", (string)$message->get("X-Spam-Score"));
|
||||
self::assertSame("Webklex/php-imap/issues/349/1365266070@github.com", (string)$message->get("Message-ID"));
|
||||
self::assertSame(5, $message->get("received")->count());
|
||||
self::assertSame(IMAP::MESSAGE_PRIORITY_UNKNOWN, (int)$message->get("priority")());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getMessageNumber
|
||||
*
|
||||
* @return void
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws MessageNotFoundException
|
||||
* @throws ResponseException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function testGetMessageNumber(): void {
|
||||
$this->createNewProtocolMockup();
|
||||
$this->protocol->expects($this->any())->method('getMessageNumber')->willReturn(Response::empty()->setResult(""));
|
||||
|
||||
self::assertNotEmpty($this->client->openFolder("INBOX"));
|
||||
|
||||
try {
|
||||
$this->client->getConnection()->getMessageNumber(21)->validatedData();
|
||||
$this->fail("Message number should not exist");
|
||||
} catch (ResponseException $e) {
|
||||
self::assertTrue(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test loadMessageFromFile
|
||||
*
|
||||
* @return void
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws InvalidMessageDateException
|
||||
* @throws MaskNotFoundException
|
||||
* @throws MessageContentFetchingException
|
||||
* @throws MessageNotFoundException
|
||||
* @throws ReflectionException
|
||||
* @throws ResponseException
|
||||
* @throws RuntimeException
|
||||
* @throws MessageSizeFetchingException
|
||||
*/
|
||||
public function testLoadMessageFromFile(): void {
|
||||
$filename = implode(DIRECTORY_SEPARATOR, [__DIR__, "messages", "1366671050@github.com.eml"]);
|
||||
$message = Message::fromFile($filename);
|
||||
|
||||
$subject = $message->get("subject");
|
||||
$returnPath = $message->get("Return-Path");
|
||||
|
||||
self::assertInstanceOf(Attribute::class, $subject);
|
||||
self::assertSame("Re: [Webklex/php-imap] Read all folders? (Issue #349)", $subject->toString());
|
||||
self::assertSame("Re: [Webklex/php-imap] Read all folders? (Issue #349)", (string)$message->subject);
|
||||
self::assertSame("noreply@github.com", $returnPath->toString());
|
||||
self::assertSame("return_path", $returnPath->getName());
|
||||
self::assertSame("-4.299", (string)$message->get("X-Spam-Score"));
|
||||
self::assertSame("Webklex/php-imap/issues/349/1365266070@github.com", (string)$message->get("Message-ID"));
|
||||
self::assertSame(5, $message->get("received")->count());
|
||||
self::assertSame(IMAP::MESSAGE_PRIORITY_UNKNOWN, (int)$message->get("priority")());
|
||||
|
||||
self::assertNull($message->getClient());
|
||||
self::assertSame(0, $message->uid);
|
||||
|
||||
$filename = implode(DIRECTORY_SEPARATOR, [__DIR__, "messages", "example_attachment.eml"]);
|
||||
$message = Message::fromFile($filename);
|
||||
|
||||
$subject = $message->get("subject");
|
||||
$returnPath = $message->get("Return-Path");
|
||||
|
||||
self::assertInstanceOf(Attribute::class, $subject);
|
||||
self::assertSame("ogqMVHhz7swLaq2PfSWsZj0k99w8wtMbrb4RuHdNg53i76B7icIIM0zIWpwGFtnk", $subject->toString());
|
||||
self::assertSame("ogqMVHhz7swLaq2PfSWsZj0k99w8wtMbrb4RuHdNg53i76B7icIIM0zIWpwGFtnk", (string)$message->subject);
|
||||
self::assertSame("someone@domain.tld", $returnPath->toString());
|
||||
self::assertSame("return_path", $returnPath->getName());
|
||||
self::assertSame("1.103", (string)$message->get("X-Spam-Score"));
|
||||
self::assertSame("d3a5e91963cb805cee975687d5acb1c6@swift.generated", (string)$message->get("Message-ID"));
|
||||
self::assertSame(4, $message->get("received")->count());
|
||||
self::assertSame(IMAP::MESSAGE_PRIORITY_HIGHEST, (int)$message->get("priority")());
|
||||
|
||||
self::assertNull($message->getClient());
|
||||
self::assertSame(0, $message->uid);
|
||||
self::assertSame(1, $message->getAttachments()->count());
|
||||
|
||||
/** @var Attachment $attachment */
|
||||
$attachment = $message->getAttachments()->first();
|
||||
self::assertSame("attachment", $attachment->disposition);
|
||||
self::assertSame("znk551MP3TP3WPp9Kl1gnLErrWEgkJFAtvaKqkTgrk3dKI8dX38YT8BaVxRcOERN", $attachment->content);
|
||||
self::assertSame("application/octet-stream", $attachment->content_type);
|
||||
self::assertSame("6mfFxiU5Yhv9WYJx.txt", $attachment->name);
|
||||
self::assertSame(2, $attachment->part_number);
|
||||
self::assertSame("text", $attachment->type);
|
||||
self::assertNotEmpty($attachment->id);
|
||||
self::assertSame(90, $attachment->size);
|
||||
self::assertSame("txt", $attachment->getExtension());
|
||||
self::assertInstanceOf(Message::class, $attachment->getMessage());
|
||||
self::assertSame("text/plain", $attachment->getMimeType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test issue #348
|
||||
*
|
||||
* @return void
|
||||
* @throws AuthFailedException
|
||||
* @throws ConnectionFailedException
|
||||
* @throws ImapBadRequestException
|
||||
* @throws ImapServerErrorException
|
||||
* @throws InvalidMessageDateException
|
||||
* @throws MaskNotFoundException
|
||||
* @throws MessageContentFetchingException
|
||||
* @throws ReflectionException
|
||||
* @throws ResponseException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function testIssue348() {
|
||||
$filename = implode(DIRECTORY_SEPARATOR, [__DIR__, "messages", "issue-348.eml"]);
|
||||
$message = Message::fromFile($filename);
|
||||
|
||||
self::assertSame(1, $message->getAttachments()->count());
|
||||
|
||||
/** @var Attachment $attachment */
|
||||
$attachment = $message->getAttachments()->first();
|
||||
|
||||
self::assertSame("attachment", $attachment->disposition);
|
||||
self::assertSame("application/pdf", $attachment->content_type);
|
||||
self::assertSame("Kelvinsong—Font_test_page_bold.pdf", $attachment->name);
|
||||
self::assertSame(1, $attachment->part_number);
|
||||
self::assertSame("text", $attachment->type);
|
||||
self::assertNotEmpty($attachment->id);
|
||||
self::assertSame(92384, $attachment->size);
|
||||
self::assertSame("pdf", $attachment->getExtension());
|
||||
self::assertInstanceOf(Message::class, $attachment->getMessage());
|
||||
self::assertSame("application/pdf", $attachment->getMimeType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new protocol mockup
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function createNewProtocolMockup(): void {
|
||||
$this->protocol = $this->createMock(ImapProtocol::class);
|
||||
|
||||
$this->protocol->expects($this->any())->method('createStream')->willReturn(true);
|
||||
$this->protocol->expects($this->any())->method('connected')->willReturn(true);
|
||||
$this->protocol->expects($this->any())->method('getConnectionTimeout')->willReturn(30);
|
||||
$this->protocol->expects($this->any())->method('logout')->willReturn(Response::empty()->setResponse([
|
||||
0 => "BYE Logging out\r\n",
|
||||
1 => "OK Logout completed (0.001 + 0.000 secs).\r\n",
|
||||
]));
|
||||
$this->protocol->expects($this->any())->method('selectFolder')->willReturn(Response::empty()->setResponse([
|
||||
"flags" => [
|
||||
0 => [
|
||||
0 => "\Answered",
|
||||
1 => "\Flagged",
|
||||
2 => "\Deleted",
|
||||
3 => "\Seen",
|
||||
4 => "\Draft",
|
||||
5 => "NonJunk",
|
||||
6 => "unknown-1",
|
||||
],
|
||||
],
|
||||
"exists" => 139,
|
||||
"recent" => 0,
|
||||
"unseen" => 94,
|
||||
"uidvalidity" => 1488899637,
|
||||
"uidnext" => 278,
|
||||
]));
|
||||
|
||||
$this->client->connection = $this->protocol;
|
||||
}
|
||||
}
|
||||
107
plugins/vendor/webklex/php-imap/tests/PartTest.php
vendored
Normal file
107
plugins/vendor/webklex/php-imap/tests/PartTest.php
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/*
|
||||
* File: StructureTest.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 28.12.22 18:11
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Webklex\PHPIMAP\Config;
|
||||
use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException;
|
||||
use Webklex\PHPIMAP\Exceptions\MessageContentFetchingException;
|
||||
use Webklex\PHPIMAP\Header;
|
||||
use Webklex\PHPIMAP\Part;
|
||||
use Webklex\PHPIMAP\Structure;
|
||||
use Webklex\PHPIMAP\IMAP;
|
||||
|
||||
class PartTest extends TestCase {
|
||||
|
||||
/** @var Config $config */
|
||||
protected Config $config;
|
||||
|
||||
/**
|
||||
* Setup the test environment.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp(): void {
|
||||
$this->config = Config::make();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test parsing a text Part
|
||||
* @throws InvalidMessageDateException
|
||||
*/
|
||||
public function testTextPart(): void {
|
||||
$raw_headers = "Content-Type: text/plain;\r\n charset=UTF-8\r\nContent-Transfer-Encoding: 7bit\r\n";
|
||||
$raw_body = "\r\nAny updates?";
|
||||
|
||||
$headers = new Header($raw_headers, $this->config);
|
||||
$part = new Part($raw_body, $this->config, $headers, 0);
|
||||
|
||||
self::assertSame("UTF-8", $part->charset);
|
||||
self::assertSame("text/plain", $part->content_type);
|
||||
self::assertSame(12, $part->bytes);
|
||||
self::assertSame(0, $part->part_number);
|
||||
self::assertSame(false, $part->ifdisposition);
|
||||
self::assertSame(false, $part->isAttachment());
|
||||
self::assertSame("Any updates?", $part->content);
|
||||
self::assertSame(IMAP::MESSAGE_TYPE_TEXT, $part->type);
|
||||
self::assertSame(IMAP::MESSAGE_ENC_7BIT, $part->encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test parsing a html Part
|
||||
* @throws InvalidMessageDateException
|
||||
*/
|
||||
public function testHTMLPart(): void {
|
||||
$raw_headers = "Content-Type: text/html;\r\n charset=UTF-8\r\nContent-Transfer-Encoding: 7bit\r\n";
|
||||
$raw_body = "\r\n<p></p>\r\n<p dir=\"auto\">Any updates?</p>";
|
||||
|
||||
$headers = new Header($raw_headers, $this->config);
|
||||
$part = new Part($raw_body, $this->config, $headers, 0);
|
||||
|
||||
self::assertSame("UTF-8", $part->charset);
|
||||
self::assertSame("text/html", $part->content_type);
|
||||
self::assertSame(39, $part->bytes);
|
||||
self::assertSame(0, $part->part_number);
|
||||
self::assertSame(false, $part->ifdisposition);
|
||||
self::assertSame(false, $part->isAttachment());
|
||||
self::assertSame("<p></p>\r\n<p dir=\"auto\">Any updates?</p>", $part->content);
|
||||
self::assertSame(IMAP::MESSAGE_TYPE_TEXT, $part->type);
|
||||
self::assertSame(IMAP::MESSAGE_ENC_7BIT, $part->encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test parsing a html Part
|
||||
* @throws InvalidMessageDateException
|
||||
*/
|
||||
public function testBase64Part(): void {
|
||||
$raw_headers = "Content-Type: application/octet-stream; name=6mfFxiU5Yhv9WYJx.txt\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment; filename=6mfFxiU5Yhv9WYJx.txt\r\n";
|
||||
$raw_body = "em5rNTUxTVAzVFAzV1BwOUtsMWduTEVycldFZ2tKRkF0dmFLcWtUZ3JrM2RLSThkWDM4WVQ4QmFW\r\neFJjT0VSTg==";
|
||||
|
||||
$headers = new Header($raw_headers, $this->config);
|
||||
$part = new Part($raw_body, $this->config, $headers, 0);
|
||||
|
||||
self::assertSame("", $part->charset);
|
||||
self::assertSame("application/octet-stream", $part->content_type);
|
||||
self::assertSame(90, $part->bytes);
|
||||
self::assertSame(0, $part->part_number);
|
||||
self::assertSame("znk551MP3TP3WPp9Kl1gnLErrWEgkJFAtvaKqkTgrk3dKI8dX38YT8BaVxRcOERN", base64_decode($part->content));
|
||||
self::assertSame(true, $part->ifdisposition);
|
||||
self::assertSame("attachment", $part->disposition);
|
||||
self::assertSame("6mfFxiU5Yhv9WYJx.txt", $part->name);
|
||||
self::assertSame("6mfFxiU5Yhv9WYJx.txt", $part->filename);
|
||||
self::assertSame(true, $part->isAttachment());
|
||||
self::assertSame(IMAP::MESSAGE_TYPE_TEXT, $part->type);
|
||||
self::assertSame(IMAP::MESSAGE_ENC_BASE64, $part->encoding);
|
||||
}
|
||||
}
|
||||
68
plugins/vendor/webklex/php-imap/tests/StructureTest.php
vendored
Normal file
68
plugins/vendor/webklex/php-imap/tests/StructureTest.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/*
|
||||
* File: StructureTest.php
|
||||
* Category: -
|
||||
* Author: M.Goldenbaum
|
||||
* Created: 28.12.22 18:11
|
||||
* Updated: -
|
||||
*
|
||||
* Description:
|
||||
* -
|
||||
*/
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Webklex\PHPIMAP\Config;
|
||||
use Webklex\PHPIMAP\Exceptions\InvalidMessageDateException;
|
||||
use Webklex\PHPIMAP\Exceptions\MessageContentFetchingException;
|
||||
use Webklex\PHPIMAP\Header;
|
||||
use Webklex\PHPIMAP\Structure;
|
||||
|
||||
class StructureTest extends TestCase {
|
||||
|
||||
/** @var Config $config */
|
||||
protected Config $config;
|
||||
|
||||
/**
|
||||
* Setup the test environment.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp(): void {
|
||||
$this->config = Config::make();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test parsing email headers
|
||||
*
|
||||
* @throws InvalidMessageDateException
|
||||
* @throws MessageContentFetchingException
|
||||
*/
|
||||
public function testStructureParsing(): void {
|
||||
$email = file_get_contents(implode(DIRECTORY_SEPARATOR, [__DIR__, "messages", "1366671050@github.com.eml"]));
|
||||
if(!str_contains($email, "\r\n")){
|
||||
$email = str_replace("\n", "\r\n", $email);
|
||||
}
|
||||
|
||||
$raw_header = substr($email, 0, strpos($email, "\r\n\r\n"));
|
||||
$raw_body = substr($email, strlen($raw_header)+8);
|
||||
|
||||
$header = new Header($raw_header, $this->config);
|
||||
$structure = new Structure($raw_body, $header);
|
||||
|
||||
self::assertSame(2, count($structure->parts));
|
||||
|
||||
$textPart = $structure->parts[0];
|
||||
|
||||
self::assertSame("UTF-8", $textPart->charset);
|
||||
self::assertSame("text/plain", $textPart->content_type);
|
||||
self::assertSame(278, $textPart->bytes);
|
||||
|
||||
$htmlPart = $structure->parts[1];
|
||||
|
||||
self::assertSame("UTF-8", $htmlPart->charset);
|
||||
self::assertSame("text/html", $htmlPart->content_type);
|
||||
self::assertSame(1478, $htmlPart->bytes);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user