diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index db2a251..e0c1529 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -17,28 +17,14 @@ jobs: tools: phive coverage: xdebug - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache composer dependencies - uses: actions/cache@v3 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- - - name: Install Composer dependencies - run: | - composer install --no-progress --prefer-dist --optimize-autoloader + run: composer install --no-progress --prefer-dist --optimize-autoloader - name: Install Phive dependencies - run: | - phive install --force-accept-unsigned --trust-gpg-keys 0xE82B2FB314E9906E + run: phive install --trust-gpg-keys 2DF45277AEF09A2F,E82B2FB314E9906E - name: Compile phar - run: | - composer run build + run: composer run build - name: Run phar run: ./imap-tester.phar diff --git a/.phive/phars.xml b/.phive/phars.xml index 96a9055..79b5d41 100644 --- a/.phive/phars.xml +++ b/.phive/phars.xml @@ -1,5 +1,5 @@ - + diff --git a/Dockerfile b/Dockerfile index e216af0..2cc9332 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,8 @@ FROM composer:2.3 AS composer FROM php:8.0-alpine -RUN apk --no-cache add openssl-dev imap-dev gnupg icu-dev && \ - docker-php-ext-configure imap --with-imap --with-imap-ssl && \ - docker-php-ext-install imap intl && \ +RUN apk --no-cache add gnupg icu-dev && \ + docker-php-ext-install intl && \ wget -O phive.phar "https://phar.io/releases/phive.phar" && \ wget -O phive.phar.asc "https://phar.io/releases/phive.phar.asc" && \ gpg --keyserver hkps://keys.openpgp.org --recv-keys 0x6AF725270AB81E04D79442549D8A98B29B2D5D79 && \ diff --git a/README.md b/README.md index 3b6a07f..f2c4e96 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,16 @@ # imap-tester Provides a test utility for [docker-mailserver](https://github.com/jeboehm/docker-mailserver). -Do not use. +## Installation + +Download phar from the [latest release](https://github.com/jeboehm/imap-tester/releases/tag/v1.1.0). + +## Usage + +``` +$ imap-tester.phar list + +test:count Count messages in a folder +test:move Move messages from one folder to another +``` diff --git a/composer.json b/composer.json index 0628aac..d40db2d 100644 --- a/composer.json +++ b/composer.json @@ -3,9 +3,8 @@ "description": "Tests imap and pop3 mailboxes.", "require": { "php": "^8.0", - "ext-imap": "*", "symfony/console": "~5.4", - "php-imap/php-imap": "~5.0" + "bytestream/horde-imap-client": "^2.31" }, "license": "MIT", "autoload": { diff --git a/src/Command/AbstractCommand.php b/src/Command/AbstractCommand.php index 5ec2637..9daf992 100644 --- a/src/Command/AbstractCommand.php +++ b/src/Command/AbstractCommand.php @@ -20,11 +20,11 @@ abstract class AbstractCommand extends Command { protected function configure(): void { - $this->addArgument('host', InputArgument::REQUIRED); - $this->addArgument('port', InputArgument::REQUIRED); - $this->addArgument('username', InputArgument::REQUIRED); - $this->addArgument('password', InputArgument::REQUIRED); - $this->addArgument('folder', InputArgument::REQUIRED); + $this->addArgument('host', InputArgument::REQUIRED, 'POP3 / IMAP host'); + $this->addArgument('port', InputArgument::REQUIRED, 'POP3 / IMAP port'); + $this->addArgument('username', InputArgument::REQUIRED, 'Username'); + $this->addArgument('password', InputArgument::REQUIRED, 'Password'); + $this->addArgument('folder', InputArgument::REQUIRED, 'Folder to take action on (e.g. INBOX)'); } final protected function getImapService(InputInterface $input): ImapService diff --git a/src/Command/CountCommand.php b/src/Command/CountCommand.php index 3df3676..b6f26ee 100644 --- a/src/Command/CountCommand.php +++ b/src/Command/CountCommand.php @@ -20,6 +20,7 @@ protected function configure(): void parent::configure(); $this->setName('test:count'); + $this->setDescription('Count messages in a folder'); } protected function execute(InputInterface $input, OutputInterface $output): int diff --git a/src/Command/MoveCommand.php b/src/Command/MoveCommand.php index 58a3510..212ab86 100644 --- a/src/Command/MoveCommand.php +++ b/src/Command/MoveCommand.php @@ -21,8 +21,9 @@ protected function configure(): void parent::configure(); $this->setName('test:move'); - $this->addArgument('messageIndex', InputArgument::REQUIRED); - $this->addArgument('targetFolder', InputArgument::REQUIRED); + $this->setDescription('Move messages from one folder to another'); + $this->addArgument('messageIndex', InputArgument::REQUIRED, 'Message index (positive integer)'); + $this->addArgument('targetFolder', InputArgument::REQUIRED, 'Target folder to move the mail to'); } protected function execute(InputInterface $input, OutputInterface $output): int diff --git a/src/Service/ImapService.php b/src/Service/ImapService.php index 92498b1..f466758 100644 --- a/src/Service/ImapService.php +++ b/src/Service/ImapService.php @@ -10,13 +10,10 @@ namespace Service; -use InvalidArgumentException; -use PhpImap\Mailbox; -use RuntimeException; - class ImapService { - private Mailbox $mailbox; + /** @var \Horde_Imap_Client_Socket_Pop3|\Horde_Imap_Client_Socket */ + private \Horde_Imap_Client_Base $client; public function __construct($host, $port, $username, $password) { @@ -41,42 +38,45 @@ public function __construct($host, $port, $username, $password) break; default: - throw new InvalidArgumentException('Port not known'); + throw new \InvalidArgumentException('Port not known'); } - $this->mailbox = new Mailbox( - sprintf( - '{%s:%s/%s/%s/novalidate-cert}', - $host, - $port, - $serverType, - $sslType, - ), - $username, - $password - ); - - $this->mailbox->setConnectionArgs(CL_EXPUNGE); + $options = [ + 'username' => $username, + 'password' => $password, + 'hostspec' => $host, + 'port' => $port, + 'secure' => $sslType, + ]; + + if ('pop3' === $serverType) { + $this->client = new \Horde_Imap_Client_Socket_Pop3($options); + } else { + $this->client = new \Horde_Imap_Client_Socket($options); + } } public function doCount(string $folder): int { - $this->mailbox->switchMailbox($folder); + $results = $this->client->search($folder)['match']; - return $this->mailbox->countMails(); + return is_countable($results) ? count($results) : 0; } public function doMove(string $folder, int $messageIndex, string $targetFolder): bool { - $this->mailbox->switchMailbox($folder); - $mailsIds = $this->mailbox->searchMailbox(); + $mails = $this->client->search($folder)['match']; - if (!array_key_exists($messageIndex, $mailsIds)) { - throw new RuntimeException('Mail was not found.'); + if (!array_key_exists($messageIndex, $mails->ids)) { + throw new \RuntimeException('Mail was not found.'); } $countBefore = $this->doCount($folder); - $this->mailbox->moveMail($mailsIds[0], $targetFolder); + $this->client->copy($folder, $targetFolder, [ + 'ids' => new \Horde_Imap_Client_Ids($mails->ids[$messageIndex]), + 'move' => true, + ]); + $this->client->close(); return $this->doCount($folder) !== $countBefore; }