diff --git a/composer.json b/composer.json
index b1a9f6e8c..4df7e16ee 100644
--- a/composer.json
+++ b/composer.json
@@ -46,6 +46,7 @@
"ext-openssl": "*",
"ext-session": "*",
"ezyang/htmlpurifier": "^4.17",
+ "garethp/php-ews": "dev-master",
"henrique-borba/php-sieve-manager": "^1.0",
"league/commonmark": "^2.4",
"paragonie/random_compat": "^2.0.18",
diff --git a/composer.lock b/composer.lock
index 963936305..d9357206d 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "e11d399af68ed7416340c63ab7a213d6",
+ "content-hash": "6a75aa856405dde3a37887d21821e90a",
"packages": [
{
"name": "bacon/bacon-qr-code",
@@ -121,23 +121,23 @@
},
{
"name": "dasprid/enum",
- "version": "1.0.5",
+ "version": "1.0.6",
"source": {
"type": "git",
"url": "https://github.com/DASPRiD/Enum.git",
- "reference": "6faf451159fb8ba4126b925ed2d78acfce0dc016"
+ "reference": "8dfd07c6d2cf31c8da90c53b83c026c7696dda90"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/6faf451159fb8ba4126b925ed2d78acfce0dc016",
- "reference": "6faf451159fb8ba4126b925ed2d78acfce0dc016",
+ "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/8dfd07c6d2cf31c8da90c53b83c026c7696dda90",
+ "reference": "8dfd07c6d2cf31c8da90c53b83c026c7696dda90",
"shasum": ""
},
"require": {
"php": ">=7.1 <9.0"
},
"require-dev": {
- "phpunit/phpunit": "^7 | ^8 | ^9",
+ "phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11",
"squizlabs/php_codesniffer": "*"
},
"type": "library",
@@ -165,22 +165,22 @@
],
"support": {
"issues": "https://github.com/DASPRiD/Enum/issues",
- "source": "https://github.com/DASPRiD/Enum/tree/1.0.5"
+ "source": "https://github.com/DASPRiD/Enum/tree/1.0.6"
},
- "time": "2023-08-25T16:18:39+00:00"
+ "time": "2024-08-09T14:30:48+00:00"
},
{
"name": "dflydev/dot-access-data",
- "version": "v3.0.2",
+ "version": "v3.0.3",
"source": {
"type": "git",
"url": "https://github.com/dflydev/dflydev-dot-access-data.git",
- "reference": "f41715465d65213d644d3141a6a93081be5d3549"
+ "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/f41715465d65213d644d3141a6a93081be5d3549",
- "reference": "f41715465d65213d644d3141a6a93081be5d3549",
+ "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/a23a2bf4f31d3518f3ecb38660c95715dfead60f",
+ "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f",
"shasum": ""
},
"require": {
@@ -240,26 +240,26 @@
],
"support": {
"issues": "https://github.com/dflydev/dflydev-dot-access-data/issues",
- "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.2"
+ "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.3"
},
- "time": "2022-10-27T11:44:00+00:00"
+ "time": "2024-07-08T12:26:09+00:00"
},
{
"name": "ezyang/htmlpurifier",
- "version": "v4.17.0",
+ "version": "v4.18.0",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
- "reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c"
+ "reference": "cb56001e54359df7ae76dc522d08845dc741621b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/bbc513d79acf6691fa9cf10f192c90dd2957f18c",
- "reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c",
+ "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/cb56001e54359df7ae76dc522d08845dc741621b",
+ "reference": "cb56001e54359df7ae76dc522d08845dc741621b",
"shasum": ""
},
"require": {
- "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0"
+ "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
},
"require-dev": {
"cerdic/css-tidy": "^1.7 || ^2.0",
@@ -301,22 +301,335 @@
],
"support": {
"issues": "https://github.com/ezyang/htmlpurifier/issues",
- "source": "https://github.com/ezyang/htmlpurifier/tree/v4.17.0"
+ "source": "https://github.com/ezyang/htmlpurifier/tree/v4.18.0"
+ },
+ "time": "2024-11-01T03:51:45+00:00"
+ },
+ {
+ "name": "garethp/http-playback",
+ "version": "v2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Garethp/HttpPlayback.git",
+ "reference": "50fd7b75c3d08ac0548df6d834a60ac65fc365df"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Garethp/HttpPlayback/zipball/50fd7b75c3d08ac0548df6d834a60ac65fc365df",
+ "reference": "50fd7b75c3d08ac0548df6d834a60ac65fc365df",
+ "shasum": ""
+ },
+ "require": {
+ "guzzlehttp/guzzle": "~7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~9.5",
+ "squizlabs/php_codesniffer": "~3.6"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "garethp\\HttpPlayback\\": "src/",
+ "garethp\\HttpPlayback\\Test\\": "tests/src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "support": {
+ "issues": "https://github.com/Garethp/HttpPlayback/issues",
+ "source": "https://github.com/Garethp/HttpPlayback/tree/v2.0"
+ },
+ "time": "2021-05-10T01:13:55+00:00"
+ },
+ {
+ "name": "garethp/php-ews",
+ "version": "dev-master",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Garethp/php-ews.git",
+ "reference": "3d0d9e23e1e3f9077403266c256fb3c1219eef16"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Garethp/php-ews/zipball/3d0d9e23e1e3f9077403266c256fb3c1219eef16",
+ "reference": "3d0d9e23e1e3f9077403266c256fb3c1219eef16",
+ "shasum": ""
+ },
+ "require": {
+ "ext-curl": "*",
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "ext-simplexml": "*",
+ "ext-soap": "*",
+ "garethp/http-playback": "^2.0"
+ },
+ "require-dev": {
+ "goetas/xsd-reader": "^2.0-dev",
+ "goetas/xsd2php": "^2.1",
+ "mockery/mockery": "^1.3",
+ "phpunit/phpunit": "^9.4 || ^8.5",
+ "squizlabs/php_codesniffer": "~3.6.0"
+ },
+ "default-branch": true,
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/Utilities/ensureIsArray.php",
+ "src/Utilities/ensureIsDateTime.php",
+ "src/Utilities/cloneValue.php",
+ "src/Utilities/getFolderIds.php"
+ ],
+ "psr-4": {
+ "garethp\\ews\\": "src/",
+ "garethp\\ews\\Test\\": "tests/src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "A PHP Library to interact with the Exchange SOAP service",
+ "keywords": [
+ "Microsoft Exchange",
+ "NTLM",
+ "calendar",
+ "contacts",
+ "email",
+ "ews",
+ "exchange web services",
+ "php",
+ "push notification",
+ "soap"
+ ],
+ "support": {
+ "issues": "https://github.com/Garethp/php-ews/issues",
+ "source": "https://github.com/Garethp/php-ews/tree/v0.10.2"
+ },
+ "time": "2024-12-14T14:36:26+00:00"
+ },
+ {
+ "name": "guzzlehttp/guzzle",
+ "version": "7.9.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/guzzle.git",
+ "reference": "d281ed313b989f213357e3be1a179f02196ac99b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b",
+ "reference": "d281ed313b989f213357e3be1a179f02196ac99b",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "guzzlehttp/promises": "^1.5.3 || ^2.0.3",
+ "guzzlehttp/psr7": "^2.7.0",
+ "php": "^7.2.5 || ^8.0",
+ "psr/http-client": "^1.0",
+ "symfony/deprecation-contracts": "^2.2 || ^3.0"
+ },
+ "provide": {
+ "psr/http-client-implementation": "1.0"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.8.2",
+ "ext-curl": "*",
+ "guzzle/client-integration-tests": "3.0.2",
+ "php-http/message-factory": "^1.1",
+ "phpunit/phpunit": "^8.5.39 || ^9.6.20",
+ "psr/log": "^1.1 || ^2.0 || ^3.0"
+ },
+ "suggest": {
+ "ext-curl": "Required for CURL handler support",
+ "ext-intl": "Required for Internationalized Domain Name (IDN) support",
+ "psr/log": "Required for using the Log middleware"
+ },
+ "type": "library",
+ "extra": {
+ "bamarni-bin": {
+ "bin-links": true,
+ "forward-command": false
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "GuzzleHttp\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Jeremy Lindblom",
+ "email": "jeremeamia@gmail.com",
+ "homepage": "https://github.com/jeremeamia"
+ },
+ {
+ "name": "George Mponos",
+ "email": "gmponos@gmail.com",
+ "homepage": "https://github.com/gmponos"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com",
+ "homepage": "https://github.com/sagikazarmark"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "Guzzle is a PHP HTTP client library",
+ "keywords": [
+ "client",
+ "curl",
+ "framework",
+ "http",
+ "http client",
+ "psr-18",
+ "psr-7",
+ "rest",
+ "web service"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/guzzle/issues",
+ "source": "https://github.com/guzzle/guzzle/tree/7.9.2"
},
- "time": "2023-11-17T15:01:25+00:00"
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/Nyholm",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-07-24T11:22:20+00:00"
+ },
+ {
+ "name": "guzzlehttp/promises",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/promises.git",
+ "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
+ "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5 || ^8.0"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.8.2",
+ "phpunit/phpunit": "^8.5.39 || ^9.6.20"
+ },
+ "type": "library",
+ "extra": {
+ "bamarni-bin": {
+ "bin-links": true,
+ "forward-command": false
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Promise\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "Guzzle promises library",
+ "keywords": [
+ "promise"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/promises/issues",
+ "source": "https://github.com/guzzle/promises/tree/2.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/Nyholm",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-10-17T10:06:22+00:00"
},
{
"name": "guzzlehttp/psr7",
- "version": "2.6.2",
+ "version": "2.7.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
- "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221"
+ "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221",
- "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
+ "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
"shasum": ""
},
"require": {
@@ -331,8 +644,8 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
- "http-interop/http-factory-tests": "^0.9",
- "phpunit/phpunit": "^8.5.36 || ^9.6.15"
+ "http-interop/http-factory-tests": "0.9.0",
+ "phpunit/phpunit": "^8.5.39 || ^9.6.20"
},
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
@@ -403,7 +716,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
- "source": "https://github.com/guzzle/psr7/tree/2.6.2"
+ "source": "https://github.com/guzzle/psr7/tree/2.7.0"
},
"funding": [
{
@@ -419,7 +732,7 @@
"type": "tidelift"
}
],
- "time": "2023-12-03T20:05:35+00:00"
+ "time": "2024-07-18T11:15:46+00:00"
},
{
"name": "henrique-borba/php-sieve-manager",
@@ -492,16 +805,16 @@
},
{
"name": "league/commonmark",
- "version": "2.4.2",
+ "version": "2.6.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/commonmark.git",
- "reference": "91c24291965bd6d7c46c46a12ba7492f83b1cadf"
+ "reference": "d150f911e0079e90ae3c106734c93137c184f932"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/91c24291965bd6d7c46c46a12ba7492f83b1cadf",
- "reference": "91c24291965bd6d7c46c46a12ba7492f83b1cadf",
+ "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d150f911e0079e90ae3c106734c93137c184f932",
+ "reference": "d150f911e0079e90ae3c106734c93137c184f932",
"shasum": ""
},
"require": {
@@ -514,8 +827,8 @@
},
"require-dev": {
"cebe/markdown": "^1.0",
- "commonmark/cmark": "0.30.3",
- "commonmark/commonmark.js": "0.30.0",
+ "commonmark/cmark": "0.31.1",
+ "commonmark/commonmark.js": "0.31.1",
"composer/package-versions-deprecated": "^1.8",
"embed/embed": "^4.4",
"erusev/parsedown": "^1.0",
@@ -526,8 +839,9 @@
"phpstan/phpstan": "^1.8.2",
"phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0",
"scrutinizer/ocular": "^1.8.1",
- "symfony/finder": "^5.3 | ^6.0 || ^7.0",
- "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 || ^7.0",
+ "symfony/finder": "^5.3 | ^6.0 | ^7.0",
+ "symfony/process": "^5.4 | ^6.0 | ^7.0",
+ "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0",
"unleashedtech/php-coding-standard": "^3.1.1",
"vimeo/psalm": "^4.24.0 || ^5.0.0"
},
@@ -537,7 +851,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "2.5-dev"
+ "dev-main": "2.7-dev"
}
},
"autoload": {
@@ -594,7 +908,7 @@
"type": "tidelift"
}
],
- "time": "2024-02-02T11:59:32+00:00"
+ "time": "2024-12-07T15:34:16+00:00"
},
{
"name": "league/config",
@@ -680,31 +994,31 @@
},
{
"name": "nette/schema",
- "version": "v1.2.5",
+ "version": "v1.3.2",
"source": {
"type": "git",
"url": "https://github.com/nette/schema.git",
- "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a"
+ "reference": "da801d52f0354f70a638673c4a0f04e16529431d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/schema/zipball/0462f0166e823aad657c9224d0f849ecac1ba10a",
- "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a",
+ "url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d",
+ "reference": "da801d52f0354f70a638673c4a0f04e16529431d",
"shasum": ""
},
"require": {
- "nette/utils": "^2.5.7 || ^3.1.5 || ^4.0",
- "php": "7.1 - 8.3"
+ "nette/utils": "^4.0",
+ "php": "8.1 - 8.4"
},
"require-dev": {
- "nette/tester": "^2.3 || ^2.4",
+ "nette/tester": "^2.5.2",
"phpstan/phpstan-nette": "^1.0",
- "tracy/tracy": "^2.7"
+ "tracy/tracy": "^2.8"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.2-dev"
+ "dev-master": "1.3-dev"
}
},
"autoload": {
@@ -736,35 +1050,36 @@
],
"support": {
"issues": "https://github.com/nette/schema/issues",
- "source": "https://github.com/nette/schema/tree/v1.2.5"
+ "source": "https://github.com/nette/schema/tree/v1.3.2"
},
- "time": "2023-10-05T20:37:59+00:00"
+ "time": "2024-10-06T23:10:23+00:00"
},
{
"name": "nette/utils",
- "version": "v3.2.10",
+ "version": "v4.0.5",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
- "reference": "a4175c62652f2300c8017fb7e640f9ccb11648d2"
+ "reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/utils/zipball/a4175c62652f2300c8017fb7e640f9ccb11648d2",
- "reference": "a4175c62652f2300c8017fb7e640f9ccb11648d2",
+ "url": "https://api.github.com/repos/nette/utils/zipball/736c567e257dbe0fcf6ce81b4d6dbe05c6899f96",
+ "reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96",
"shasum": ""
},
"require": {
- "php": ">=7.2 <8.4"
+ "php": "8.0 - 8.4"
},
"conflict": {
- "nette/di": "<3.0.6"
+ "nette/finder": "<3",
+ "nette/schema": "<1.2.2"
},
"require-dev": {
"jetbrains/phpstorm-attributes": "dev-master",
- "nette/tester": "~2.0",
+ "nette/tester": "^2.5",
"phpstan/phpstan": "^1.0",
- "tracy/tracy": "^2.3"
+ "tracy/tracy": "^2.9"
},
"suggest": {
"ext-gd": "to use Image",
@@ -772,13 +1087,12 @@
"ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
"ext-json": "to use Nette\\Utils\\Json",
"ext-mbstring": "to use Strings::lower() etc...",
- "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()",
- "ext-xml": "to use Strings::length() etc. when mbstring is not available"
+ "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.2-dev"
+ "dev-master": "4.0-dev"
}
},
"autoload": {
@@ -822,9 +1136,9 @@
],
"support": {
"issues": "https://github.com/nette/utils/issues",
- "source": "https://github.com/nette/utils/tree/v3.2.10"
+ "source": "https://github.com/nette/utils/tree/v4.0.5"
},
- "time": "2023-07-30T15:38:18+00:00"
+ "time": "2024-08-07T15:39:19+00:00"
},
{
"name": "paragonie/random_compat",
@@ -1036,22 +1350,74 @@
},
"time": "2019-01-08T18:20:26+00:00"
},
+ {
+ "name": "psr/http-client",
+ "version": "1.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-client.git",
+ "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
+ "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0 || ^8.0",
+ "psr/http-message": "^1.0 || ^2.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Client\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP clients",
+ "homepage": "https://github.com/php-fig/http-client",
+ "keywords": [
+ "http",
+ "http-client",
+ "psr",
+ "psr-18"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/http-client"
+ },
+ "time": "2023-09-23T14:17:50+00:00"
+ },
{
"name": "psr/http-factory",
- "version": "1.0.2",
+ "version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
- "reference": "e616d01114759c4c489f93b099585439f795fe35"
+ "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
- "reference": "e616d01114759c4c489f93b099585439f795fe35",
+ "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
+ "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"shasum": ""
},
"require": {
- "php": ">=7.0.0",
+ "php": ">=7.1",
"psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
@@ -1075,7 +1441,7 @@
"homepage": "https://www.php-fig.org/"
}
],
- "description": "Common interfaces for PSR-7 HTTP message factories",
+ "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
"keywords": [
"factory",
"http",
@@ -1087,9 +1453,9 @@
"response"
],
"support": {
- "source": "https://github.com/php-fig/http-factory/tree/1.0.2"
+ "source": "https://github.com/php-fig/http-factory"
},
- "time": "2023-04-10T20:10:41+00:00"
+ "time": "2024-04-15T12:06:14+00:00"
},
{
"name": "psr/http-message",
@@ -1190,25 +1556,25 @@
},
{
"name": "symfony/deprecation-contracts",
- "version": "v2.5.3",
+ "version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "80d075412b557d41002320b96a096ca65aa2c98d"
+ "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/80d075412b557d41002320b96a096ca65aa2c98d",
- "reference": "80d075412b557d41002320b96a096ca65aa2c98d",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
+ "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=8.1"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "2.5-dev"
+ "dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -1237,7 +1603,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.3"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1"
},
"funding": [
{
@@ -1253,7 +1619,7 @@
"type": "tidelift"
}
],
- "time": "2023-01-24T14:02:46+00:00"
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/dotenv",
@@ -1328,20 +1694,20 @@
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.29.0",
+ "version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
- "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"provide": {
"ext-ctype": "*"
@@ -1352,8 +1718,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -1387,7 +1753,7 @@
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
},
"funding": [
{
@@ -1403,24 +1769,24 @@
"type": "tidelift"
}
],
- "time": "2024-01-29T20:11:03+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-iconv",
- "version": "v1.29.0",
+ "version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-iconv.git",
- "reference": "cd4226d140ecd3d0f13d32ed0a4a095ffe871d2f"
+ "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/cd4226d140ecd3d0f13d32ed0a4a095ffe871d2f",
- "reference": "cd4226d140ecd3d0f13d32ed0a4a095ffe871d2f",
+ "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/48becf00c920479ca2e910c22a5a39e5d47ca956",
+ "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"provide": {
"ext-iconv": "*"
@@ -1467,7 +1833,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-iconv/tree/v1.29.0"
+ "source": "https://github.com/symfony/polyfill-iconv/tree/v1.31.0"
},
"funding": [
{
@@ -1483,24 +1849,24 @@
"type": "tidelift"
}
],
- "time": "2024-01-29T20:11:03+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.29.0",
+ "version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
+ "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
- "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
+ "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"provide": {
"ext-mbstring": "*"
@@ -1511,8 +1877,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -1547,7 +1913,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
},
"funding": [
{
@@ -1563,30 +1929,30 @@
"type": "tidelift"
}
],
- "time": "2024-01-29T20:11:03+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-php80",
- "version": "v1.29.0",
+ "version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
- "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
+ "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
- "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
+ "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.2"
},
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -1627,7 +1993,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0"
},
"funding": [
{
@@ -1643,20 +2009,20 @@
"type": "tidelift"
}
],
- "time": "2024-01-29T20:11:03+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/yaml",
- "version": "v6.4.8",
+ "version": "v6.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
- "reference": "52903de178d542850f6f341ba92995d3d63e60c9"
+ "reference": "e99b4e94d124b29ee4cf3140e1b537d2dad8cec9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/52903de178d542850f6f341ba92995d3d63e60c9",
- "reference": "52903de178d542850f6f341ba92995d3d63e60c9",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/e99b4e94d124b29ee4cf3140e1b537d2dad8cec9",
+ "reference": "e99b4e94d124b29ee4cf3140e1b537d2dad8cec9",
"shasum": ""
},
"require": {
@@ -1699,7 +2065,7 @@
"description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/yaml/tree/v6.4.8"
+ "source": "https://github.com/symfony/yaml/tree/v6.4.13"
},
"funding": [
{
@@ -1715,7 +2081,7 @@
"type": "tidelift"
}
],
- "time": "2024-05-31T14:49:08+00:00"
+ "time": "2024-09-25T14:18:03+00:00"
},
{
"name": "thomaspark/bootswatch",
@@ -2115,16 +2481,16 @@
"packages-dev": [
{
"name": "myclabs/deep-copy",
- "version": "1.11.1",
+ "version": "1.12.1",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
+ "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
- "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
+ "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
"shasum": ""
},
"require": {
@@ -2132,11 +2498,12 @@
},
"conflict": {
"doctrine/collections": "<1.6.8",
- "doctrine/common": "<2.13.3 || >=3,<3.2.2"
+ "doctrine/common": "<2.13.3 || >=3 <3.2.2"
},
"require-dev": {
"doctrine/collections": "^1.6.8",
"doctrine/common": "^2.13.3 || ^3.2.2",
+ "phpspec/prophecy": "^1.10",
"phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
},
"type": "library",
@@ -2162,7 +2529,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
- "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
},
"funding": [
{
@@ -2170,30 +2537,31 @@
"type": "tidelift"
}
],
- "time": "2023-03-08T13:26:56+00:00"
+ "time": "2024-11-08T17:47:46+00:00"
},
{
"name": "nikic/php-parser",
- "version": "v5.0.2",
+ "version": "v5.3.1",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13"
+ "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13",
- "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b",
+ "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b",
"shasum": ""
},
"require": {
+ "ext-ctype": "*",
"ext-json": "*",
"ext-tokenizer": "*",
"php": ">=7.4"
},
"require-dev": {
"ircmaxell/php-yacc": "^0.0.7",
- "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
+ "phpunit/phpunit": "^9.0"
},
"bin": [
"bin/php-parse"
@@ -2225,9 +2593,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1"
},
- "time": "2024-03-05T20:51:40+00:00"
+ "time": "2024-10-08T18:51:32+00:00"
},
{
"name": "phar-io/manifest",
@@ -2349,32 +2717,32 @@
},
{
"name": "phpunit/php-code-coverage",
- "version": "10.1.14",
+ "version": "10.1.16",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b"
+ "reference": "7e308268858ed6baedc8704a304727d20bc07c77"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
- "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77",
+ "reference": "7e308268858ed6baedc8704a304727d20bc07c77",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
- "nikic/php-parser": "^4.18 || ^5.0",
+ "nikic/php-parser": "^4.19.1 || ^5.1.0",
"php": ">=8.1",
- "phpunit/php-file-iterator": "^4.0",
- "phpunit/php-text-template": "^3.0",
- "sebastian/code-unit-reverse-lookup": "^3.0",
- "sebastian/complexity": "^3.0",
- "sebastian/environment": "^6.0",
- "sebastian/lines-of-code": "^2.0",
- "sebastian/version": "^4.0",
- "theseer/tokenizer": "^1.2.0"
+ "phpunit/php-file-iterator": "^4.1.0",
+ "phpunit/php-text-template": "^3.0.1",
+ "sebastian/code-unit-reverse-lookup": "^3.0.0",
+ "sebastian/complexity": "^3.2.0",
+ "sebastian/environment": "^6.1.0",
+ "sebastian/lines-of-code": "^2.0.2",
+ "sebastian/version": "^4.0.1",
+ "theseer/tokenizer": "^1.2.3"
},
"require-dev": {
"phpunit/phpunit": "^10.1"
@@ -2386,7 +2754,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "10.1-dev"
+ "dev-main": "10.1.x-dev"
}
},
"autoload": {
@@ -2415,7 +2783,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.14"
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16"
},
"funding": [
{
@@ -2423,7 +2791,7 @@
"type": "github"
}
],
- "time": "2024-03-12T15:33:41+00:00"
+ "time": "2024-08-22T04:31:57+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -2670,16 +3038,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "10.5.20",
+ "version": "10.5.39",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "547d314dc24ec1e177720d45c6263fb226cc2ae3"
+ "reference": "4e89eff200b801db58f3d580ad7426431949eaa9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/547d314dc24ec1e177720d45c6263fb226cc2ae3",
- "reference": "547d314dc24ec1e177720d45c6263fb226cc2ae3",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4e89eff200b801db58f3d580ad7426431949eaa9",
+ "reference": "4e89eff200b801db58f3d580ad7426431949eaa9",
"shasum": ""
},
"require": {
@@ -2689,26 +3057,26 @@
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
- "myclabs/deep-copy": "^1.10.1",
- "phar-io/manifest": "^2.0.3",
- "phar-io/version": "^3.0.2",
+ "myclabs/deep-copy": "^1.12.1",
+ "phar-io/manifest": "^2.0.4",
+ "phar-io/version": "^3.2.1",
"php": ">=8.1",
- "phpunit/php-code-coverage": "^10.1.5",
- "phpunit/php-file-iterator": "^4.0",
- "phpunit/php-invoker": "^4.0",
- "phpunit/php-text-template": "^3.0",
- "phpunit/php-timer": "^6.0",
- "sebastian/cli-parser": "^2.0",
- "sebastian/code-unit": "^2.0",
- "sebastian/comparator": "^5.0",
- "sebastian/diff": "^5.0",
- "sebastian/environment": "^6.0",
- "sebastian/exporter": "^5.1",
- "sebastian/global-state": "^6.0.1",
- "sebastian/object-enumerator": "^5.0",
- "sebastian/recursion-context": "^5.0",
- "sebastian/type": "^4.0",
- "sebastian/version": "^4.0"
+ "phpunit/php-code-coverage": "^10.1.16",
+ "phpunit/php-file-iterator": "^4.1.0",
+ "phpunit/php-invoker": "^4.0.0",
+ "phpunit/php-text-template": "^3.0.1",
+ "phpunit/php-timer": "^6.0.0",
+ "sebastian/cli-parser": "^2.0.1",
+ "sebastian/code-unit": "^2.0.0",
+ "sebastian/comparator": "^5.0.3",
+ "sebastian/diff": "^5.1.1",
+ "sebastian/environment": "^6.1.0",
+ "sebastian/exporter": "^5.1.2",
+ "sebastian/global-state": "^6.0.2",
+ "sebastian/object-enumerator": "^5.0.0",
+ "sebastian/recursion-context": "^5.0.0",
+ "sebastian/type": "^4.0.0",
+ "sebastian/version": "^4.0.1"
},
"suggest": {
"ext-soap": "To be able to generate mocks based on WSDL files"
@@ -2751,7 +3119,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.20"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.39"
},
"funding": [
{
@@ -2767,7 +3135,7 @@
"type": "tidelift"
}
],
- "time": "2024-04-24T06:32:35+00:00"
+ "time": "2024-12-11T10:51:07+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -2939,16 +3307,16 @@
},
{
"name": "sebastian/comparator",
- "version": "5.0.1",
+ "version": "5.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "2db5010a484d53ebf536087a70b4a5423c102372"
+ "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372",
- "reference": "2db5010a484d53ebf536087a70b4a5423c102372",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e",
+ "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e",
"shasum": ""
},
"require": {
@@ -2959,7 +3327,7 @@
"sebastian/exporter": "^5.0"
},
"require-dev": {
- "phpunit/phpunit": "^10.3"
+ "phpunit/phpunit": "^10.5"
},
"type": "library",
"extra": {
@@ -3004,7 +3372,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"security": "https://github.com/sebastianbergmann/comparator/security/policy",
- "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1"
+ "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3"
},
"funding": [
{
@@ -3012,7 +3380,7 @@
"type": "github"
}
],
- "time": "2023-08-14T13:18:12+00:00"
+ "time": "2024-10-18T14:56:07+00:00"
},
{
"name": "sebastian/complexity",
@@ -3738,7 +4106,9 @@
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {
+ "garethp/php-ews": 20
+ },
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
@@ -3756,5 +4126,5 @@
"platform-overrides": {
"php": "8.1"
},
- "plugin-api-version": "2.6.0"
+ "plugin-api-version": "2.3.0"
}
diff --git a/lib/servers.php b/lib/servers.php
index 1bd5fbf15..9e37fdb96 100644
--- a/lib/servers.php
+++ b/lib/servers.php
@@ -179,8 +179,8 @@ trait Hm_Server_List {
Hm_Repository::get as repo_get;
}
- public static function init($name, $user_config) {
- self::initRepo($name, $user_config, self::$server_list);
+ public static function init($name, $user_config, $session) {
+ self::initRepo($name, $user_config, $session, self::$server_list);
}
/**
diff --git a/modules/advanced_search/modules.php b/modules/advanced_search/modules.php
index eaf230250..752ffc9ef 100644
--- a/modules/advanced_search/modules.php
+++ b/modules/advanced_search/modules.php
@@ -73,13 +73,12 @@ public function process() {
$charset = $this->request->post['charset'];
}
- $cache = Hm_IMAP_List::get_cache($this->cache, $this->imap_id);
- $imap = Hm_IMAP_List::connect($this->imap_id, $cache);
- if (!imap_authed($imap)) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($this->imap_id, $this->cache);
+ if (! $mailbox || ! $mailbox->authed()) {
return;
}
if ($charset) {
- $imap->search_charset = $charset;
+ $mailbox->set_search_charset($charset);
}
$params = array(
array('SENTBEFORE', date('j-M-Y', strtotime($form['adv_end']))),
@@ -95,59 +94,62 @@ public function process() {
$searchInSpecialFolders = $this->request->post['all_special_folders'] ?? false;
$includeSubfolders = $this->request->post['include_subfolders'] ?? false;
if ($searchInAllFolders) {
- $msg_list = $this->all_folders_search($imap, $flags, $params, $limit);
+ $msg_list = $this->all_folders_search($mailbox, $flags, $params, $limit);
} elseif ($searchInSpecialFolders) {
- $msg_list = $this->special_folders_search($imap, $flags, $params, $limit);
+ $msg_list = $this->special_folders_search($mailbox, $flags, $params, $limit);
} else if ($includeSubfolders) {
- $msg_list = $this->all_folders_search($imap, $flags, $params, $limit, $this->folder);
- } else if (!$imap->select_mailbox($this->folder)) {
+ $msg_list = $this->all_folders_search($mailbox, $flags, $params, $limit, $this->folder);
+ } else if (! $mailbox->select_mailbox($this->folder)) {
return;
} else {
- $msg_list = $this->imap_search($flags, $imap, $params, $limit);
+ $msg_list = $this->imap_search($flags, $mailbox, $params, $limit);
}
$this->out('imap_search_results', $msg_list);
- $this->out('folder_status', $imap->folder_state);
+ $this->out('folder_status', $mailbox->get_folder_state());
$this->out('imap_server_ids', array($this->imap_id));
}
- private function all_folders_search($imap, $flags, $params, $limit, $parent = '') {
- $folders = $imap->get_mailbox_list(mailbox:$parent);
+ private function all_folders_search($mailbox, $flags, $params, $limit, $parent = '') {
+ if ($parent) {
+ $folders = $mailbox->get_subfolders($parent);
+ } else {
+ $folders = $mailbox->get_folders();
+ }
$msg_list = array();
foreach ($folders as $folder) {
$this->folder = $folder['name'];
- $imap->select_mailbox($this->folder);
- $msgs = $this->imap_search($flags, $imap, $params, $limit);
+ $msgs = $this->imap_search($flags, $mailbox, $params, $limit);
$msg_list = array_merge($msg_list, $msgs);
}
return $msg_list;
}
- private function special_folders_search($imap, $flags, $params, $limit) {
+ private function special_folders_search($mailbox, $flags, $params, $limit) {
$specials = $this->user_config->get('special_imap_folders', array());
$folders = $specials[$this->imap_id] ?? [];
$msg_list = array();
foreach ($folders as $folder) {
$this->folder = $folder;
- $imap->select_mailbox($this->folder);
- $msgs = $this->imap_search($flags, $imap, $params, $limit);
+ $mailbox->select_mailbox($this->folder);
+ $msgs = $this->imap_search($flags, $mailbox, $params, $limit);
$msg_list = array_merge($msg_list, $msgs);
}
return $msg_list;
}
- private function imap_search($flags, $imap, $params, $limit) {
+ private function imap_search($flags, $mailbox, $params, $limit) {
$msg_list = array();
$exclude_deleted = true;
if (in_array('deleted', $flags, true)) {
$exclude_deleted = false;
}
- $msgs = $imap->search($flags, false, $params, array(), $exclude_deleted);
+ $msgs = $mailbox->search($this->folder, $flags, false, $params, array(), $exclude_deleted);
if (!$msgs) {
return $msg_list;
}
$server_details = Hm_IMAP_List::dump($this->imap_id);
- foreach ($imap->get_message_list($msgs) as $msg) {
+ foreach ($mailbox->get_message_list($this->folder, $msgs) as $msg) {
if (array_key_exists('content-type', $msg) && mb_stristr($msg['content-type'], 'multipart/mixed')) {
$msg['flags'] .= ' \Attachment';
}
diff --git a/modules/core/handler_modules.php b/modules/core/handler_modules.php
index 17e837a03..a42115653 100644
--- a/modules/core/handler_modules.php
+++ b/modules/core/handler_modules.php
@@ -60,8 +60,8 @@ public function process() {
$current['pass'] = $form['password'];
unset($current['nopass']);
Hm_IMAP_List::edit($server['id'], $current);
- $imap = Hm_IMAP_List::connect($server['id'], false);
- if ($imap->get_state() == 'authenticated') {
+ $mailbox = Hm_IMAP_List::connect($server['id'], false);
+ if ($mailbox && $mailbox->authed()) {
Hm_Msgs::add('Password Updated');
$this->out('connect_status', true);
}
@@ -1086,7 +1086,7 @@ public function process() {
Hm_Msgs::add("ERRSMTP module is not enabled");
return;
}
- $this->smtp_server_id = connect_to_smtp_server($smtpAddress, $profileName, $smtpPort, $email, $password, $smtpTls, $smtpServerId);
+ $this->smtp_server_id = connect_to_smtp_server($smtpAddress, $profileName, $smtpPort, $email, $password, $smtpTls, 'smtp', $smtpServerId);
if(!isset($this->smtp_server_id)){
Hm_Msgs::add("ERRCould not save server");
return;
@@ -1133,7 +1133,7 @@ public function process() {
return;
}
- add_profile($profileName, $profileSignature, $profileReplyTo, $profileIsDefault, $email, $imapAddress, $this->smtp_server_id, $this->imap_server_id, $this);
+ add_profile($profileName, $profileSignature, $profileReplyTo, $profileIsDefault, $email, $imapAddress, $email, $this->smtp_server_id, $this->imap_server_id, $this);
}
if ($this->module_is_supported('imap_folders')) {
diff --git a/modules/core/hm-mailbox.php b/modules/core/hm-mailbox.php
new file mode 100644
index 000000000..1a5a9ea63
--- /dev/null
+++ b/modules/core/hm-mailbox.php
@@ -0,0 +1,589 @@
+server_id = $server_id;
+ $this->user_config = $user_config;
+ $this->session = $session;
+ }
+
+ public function connect(array $config) {
+ if (array_key_exists('type', $config) && $config['type'] == 'smtp') {
+ $this->type = self::TYPE_SMTP;
+ $this->connection = new Hm_SMTP($config);
+ return $this->connection->connect();
+ } elseif (array_key_exists('type', $config) && $config['type'] == 'jmap') {
+ $this->type = self::TYPE_JMAP;
+ $this->connection = new Hm_JMAP();
+ return $this->connection->connect($config);
+ } elseif (array_key_exists('type', $config) && $config['type'] == 'ews') {
+ $this->type = self::TYPE_EWS;
+ $this->connection = new Hm_EWS();
+ return $this->connection->connect($config);
+ } else {
+ $this->type = self::TYPE_IMAP;
+ $this->connection = new Hm_IMAP();
+ return $this->connection->connect($config);
+ }
+ }
+
+ public function get_connection() {
+ return $this->connection;
+ }
+
+ public function is_imap() {
+ return $this->type === self::TYPE_IMAP || $this->type === self::TYPE_JMAP;
+ }
+
+ public function is_smtp() {
+ return $this->type === self::TYPE_SMTP;
+ }
+
+ public function server_type() {
+ switch ($this->type) {
+ case self::TYPE_IMAP:
+ return 'IMAP';
+ case self::TYPE_JMAP:
+ return 'JMAP';
+ case self::TYPE_EWS:
+ return 'EWS';
+ }
+ }
+
+ public function authed() {
+ if ($this->is_imap()) {
+ return $this->connection->get_state() == 'authenticated' || $this->connection->get_state() == 'selected';
+ } elseif ($this->is_smtp()) {
+ return $this->connection->state == 'authed';
+ } else {
+ return $this->connection->authed();
+ }
+ }
+
+ public function state() {
+ if ($this->is_imap()) {
+ return $this->connection->get_state();
+ } elseif ($this->is_smtp()) {
+ return $this->connection->state;
+ } else {
+ return null;
+ }
+ }
+
+ public function get_folder_status($folder) {
+ if (! $this->authed()) {
+ return;
+ }
+ if ($this->is_imap()) {
+ return $this->connection->get_mailbox_status($folder);
+ } else {
+ return $this->connection->get_folder_status($folder);
+ }
+ }
+
+ public function get_folder_name($folder) {
+ if ($this->is_imap()) {
+ return $folder;
+ } else {
+ $result = $this->connection->get_folder_status($folder);
+ return $result['name'];
+ }
+ }
+
+ public function create_folder($folder, $parent = null) {
+ if (! $this->authed()) {
+ return;
+ }
+ if ($this->is_imap()) {
+ $new_folder = prep_folder_name($this->connection, $folder, false, $parent);
+ if ($this->connection->create_mailbox($new_folder)) {
+ return $new_folder;
+ } else {
+ return false;
+ }
+ } else {
+ return $this->connection->create_folder($folder, $parent);
+ }
+ }
+
+ public function rename_folder($folder, $new_name, $parent = null) {
+ if (! $this->authed()) {
+ return;
+ }
+ if ($this->is_imap()) {
+ $old_folder = prep_folder_name($this->connection, $folder, true);
+ $new_folder = prep_folder_name($this->connection, $new_name, false, $parent);
+ return $this->connection->rename_mailbox($old_folder, $new_folder);
+ } else {
+ $folder = decode_folder_str($folder);
+ if ($parent) {
+ $parent = decode_folder_str($parent);
+ }
+ return $this->connection->rename_folder($folder, $new_name, $parent);
+ }
+ }
+
+ public function delete_folder($folder) {
+ if (! $this->authed()) {
+ return;
+ }
+ if ($this->is_imap()) {
+ $del_folder = prep_folder_name($this->connection, $folder, true);
+ return $this->connection->delete_mailbox($del_folder);
+ } else {
+ $del_folder = decode_folder_str($folder);
+ return $this->connection->delete_folder($del_folder);
+ }
+ }
+
+ public function prep_folder_name($folder) {
+ if ($this->is_imap()) {
+ return prep_folder_name($this->connection, $folder, true);
+ } else {
+ if (substr_count($folder, '_') >= 2) {
+ return decode_folder_str($folder);
+ } else {
+ return $folder;
+ }
+ }
+ }
+
+ public function folder_subscription($folder, $action) {
+ if (! $this->authed()) {
+ return;
+ }
+ if ($this->is_imap()) {
+ return $this->connection->mailbox_subscription($folder, $action);
+ } else {
+ // emulate folder subscription via settings
+ $config = $this->user_config->get('unsubscribed_folders');
+ if (! isset($config[$this->server_id])) {
+ $config[$this->server_id] = [];
+ }
+ if ($action) {
+ $index = array_search($folder, $config[$this->server_id]);
+ if ($index !== false) {
+ unset($config[$this->server_id][$index]);
+ }
+ } else {
+ if (! in_array($folder, $config[$this->server_id])) {
+ $config[$this->server_id][] = $folder;
+ }
+ }
+ $this->user_config->set('unsubscribed_folders', $config);
+ $this->session->set('user_data', $this->user_config->dump());
+ $this->session->record_unsaved('Folder subscription updated');
+ return true;
+ }
+ }
+
+ public function get_folders($only_subscribed = false) {
+ if (! $this->authed()) {
+ return;
+ }
+ if ($this->is_imap()) {
+ return $this->connection->get_mailbox_list($only_subscribed);
+ } else {
+ return $this->connection->get_folders(null, $only_subscribed, $this->user_config->get('unsubscribed_folders')[$this->server_id] ?? []);
+ }
+ }
+
+ public function get_subfolders($folder, $only_subscribed = false, $with_input = false) {
+ if (! $this->authed()) {
+ return;
+ }
+ if ($this->is_imap()) {
+ return $this->connection->get_folder_list_by_level($folder, $only_subscribed, $with_input);
+ } else {
+ return $this->connection->get_folders($folder, $only_subscribed, $this->user_config->get('unsubscribed_folders')[$this->server_id] ?? [], $with_input);
+ }
+ }
+
+ public function get_folder_state() {
+ if ($this->is_imap()) {
+ return $this->connection->folder_state;
+ } else {
+ return $this->folder_state;
+ }
+ }
+
+ public function get_selected_folder() {
+ if ($this->is_imap()) {
+ return $this->connection->selected_mailbox;
+ } else {
+ return $this->selected_folder;
+ }
+ }
+
+ public function get_special_use_mailboxes($folder = false) {
+ if (! $this->authed()) {
+ return;
+ }
+ if ($this->is_imap()) {
+ return $this->connection->get_special_use_mailboxes($folder);
+ } else {
+ return $this->connection->get_special_use_folders($folder);
+ }
+ }
+
+ /**
+ * Get messages in a folder applying filters, sorting and pagination
+ * @return array - [total results found, results for a single page]
+ */
+ public function get_messages($folder, $sort, $reverse, $flag_filter, $offset=0, $limit=50, $keyword=false, $trusted_senders=[], $include_preview = false) {
+ if (! $this->select_folder($folder)) {
+ return;
+ }
+ if ($this->is_imap()) {
+ $messages = $this->connection->get_mailbox_page($folder, $sort, $reverse, $flag_filter, $offset, $limit, $keyword, $trusted_senders, $include_preview);
+ } else {
+ $messages = $this->connection->get_messages($folder, $sort, $reverse, $flag_filter, $offset, $limit, $keyword, $trusted_senders, $include_preview);
+ $folder = $this->selected_folder['id'];
+ }
+ foreach ($messages[1] as &$msg) {
+ $msg['folder'] = bin2hex($folder);
+ }
+ return $messages;
+ }
+
+ public function get_message_headers($folder, $msg_id) {
+ if (! $this->select_folder($folder)) {
+ return;
+ }
+ if ($this->is_imap()) {
+ return $this->connection->get_message_headers($msg_id);
+ } else {
+ return $this->connection->get_message_headers($msg_id);
+ }
+
+ }
+
+ public function get_message_content($folder, $msg_id, $part = 0) {
+ if (! $this->authed()) {
+ return;
+ }
+ if (! $this->select_folder($folder)) {
+ return;
+ }
+ if ($this->is_imap()) {
+ return $this->connection->get_message_content($msg_id, $part);
+ } else {
+ return $this->connection->get_message_content($msg_id, $part);
+ }
+ }
+
+ public function get_structured_message($folder, $msg_id, $part, $text_only) {
+ if (! $this->select_folder($folder)) {
+ return;
+ }
+ if ($this->is_imap()) {
+ $msg_struct = $this->connection->get_message_structure($msg_id);
+ if ($part !== false) {
+ if ($part == 0) {
+ $max = 500000;
+ }
+ else {
+ $max = false;
+ }
+ $struct = $this->connection->search_bodystructure($msg_struct, array('imap_part_number' => $part));
+ $msg_struct_current = array_shift($struct);
+ $msg_text = $this->connection->get_message_content($msg_id, $part, $max, $msg_struct_current);
+ }
+ else {
+ if (! $text_only) {
+ list($part, $msg_text) = $this->connection->get_first_message_part($msg_id, 'text', 'html', $msg_struct);
+ if (!$part) {
+ list($part, $msg_text) = $this->connection->get_first_message_part($msg_id, 'text', false, $msg_struct);
+ }
+ }
+ else {
+ list($part, $msg_text) = $this->connection->get_first_message_part($msg_id, 'text', false, $msg_struct);
+ }
+ $struct = $this->connection->search_bodystructure($msg_struct, array('imap_part_number' => $part));
+ $msg_struct_current = array_shift($struct);
+ if (! trim($msg_text)) {
+ if (is_array($msg_struct_current) && array_key_exists('subtype', $msg_struct_current)) {
+ if ($msg_struct_current['subtype'] == 'plain') {
+ $subtype = 'html';
+ }
+ else {
+ $subtype = 'plain';
+ }
+ list($part, $msg_text) = $this->connection->get_first_message_part($msg_id, 'text', $subtype, $msg_struct);
+ $struct = $this->connection->search_bodystructure($msg_struct, array('imap_part_number' => $part));
+ $msg_struct_current = array_shift($struct);
+ }
+ }
+ }
+ if (isset($msg_struct_current['subtype']) && mb_strtolower($msg_struct_current['subtype'] == 'html')) {
+ $msg_text = add_attached_images($msg_text, $msg_id, $msg_struct, $this->connection);
+ }
+ return [$msg_struct, $msg_struct_current, $msg_text, $part];
+ } else {
+ return $this->connection->get_structured_message($msg_id, $part, $text_only);
+ }
+ }
+
+ public function store_message($folder, $msg, $seen = true, $draft = false) {
+ if (! $this->authed()) {
+ return false;
+ }
+ if ($this->is_imap()) {
+ if ($this->connection->append_start($folder, mb_strlen($msg), $seen, $draft)) {
+ $this->connection->append_feed($msg."\r\n");
+ return $this->connection->append_end();
+ }
+ } else {
+ return $this->connection->store_message($folder, $msg, $seen, $draft);
+ }
+ return false;
+ }
+
+ public function delete_message($folder, $msg_id, $trash_folder) {
+ if (! $this->select_folder($folder)) {
+ return;
+ }
+ if ($this->is_imap() && $trash_folder && $trash_folder != $folder) {
+ if ($this->connection->message_action('MOVE', [$msg_id], $trash_folder)['status']) {
+ return true;
+ }
+ }
+ else {
+ if ($this->connection->message_action('DELETE', array($msg_id))['status']) {
+ $this->connection->message_action('EXPUNGE', array($msg_id));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public function message_action($folder, $action, $uids, $mailbox=false, $keyword=false) {
+ if (! $this->select_folder($folder)) {
+ return ['status' => false, 'responses' => []];
+ }
+ return $this->connection->message_action($action, $uids, $mailbox, $keyword);
+ }
+
+ public function stream_message_part($folder, $msg_id, $part_id, $start_cb) {
+ if (! $this->select_folder($folder)) {
+ return;
+ }
+ if ($this->is_imap()) {
+ $msg_struct = $this->connection->get_message_structure($msg_id);
+ $struct = $this->connection->search_bodystructure($msg_struct, array('imap_part_number' => $part_id));
+ if (! empty($struct)) {
+ $part_struct = array_shift($struct);
+ $encoding = false;
+ if (array_key_exists('encoding', $part_struct)) {
+ $encoding = trim(mb_strtolower($part_struct['encoding']));
+ }
+ $stream_size = $this->connection->start_message_stream($msg_id, $part_id);
+ if ($stream_size > 0) {
+ $part_name = get_imap_part_name($part_struct, $msg_id, $part_id);
+ $charset = '';
+ if (array_key_exists('attributes', $part_struct)) {
+ if (is_array($part_struct['attributes']) && array_key_exists('charset', $part_struct['attributes'])) {
+ $charset = '; charset='.$part_struct['attributes']['charset'];
+ }
+ }
+ $start_cb($part_struct['type'] . '/' . $part_struct['subtype'] . $charset, $part_name);
+ $output_line = '';
+ while($line = $this->connection->read_stream_line()) {
+ if ($encoding == 'quoted-printable') {
+ $line = quoted_printable_decode($line);
+ }
+ elseif ($encoding == 'base64') {
+ $line = base64_decode($line);
+ }
+ echo $output_line;
+ $output_line = $line;
+ }
+ if ($part_struct['type'] == 'text') {
+ $output_line = preg_replace("/\)(\r\n)$/m", '$1', $output_line);
+ }
+ echo $output_line;
+ }
+ }
+ } else {
+ return $this->connection->stream_message_part($msg_id, $part_id, $start_cb);
+ }
+ }
+
+ public function remove_attachment($folder, $msg_id, $part_id) {
+ if (! $this->select_folder($folder)) {
+ return;
+ }
+ if ($this->is_imap()) {
+ $msg = $this->connection->get_message_content($msg_id, 0, false, false);
+ if ($msg) {
+ $struct = $this->connection->get_message_structure($msg_id);
+ $attachment_id = get_attachment_id_for_mail_parser($struct, $part_id);
+ if ($attachment_id !== false) {
+ $msg = remove_attachment($attachment_id, $msg);
+ if ($this->connection->append_start($folder, mb_strlen($msg))) {
+ $this->connection->append_feed($msg."\r\n");
+ if ($this->connection->append_end()) {
+ if ($this->connection->message_action('DELETE', array($uid))['status']) {
+ $this->connection->message_action('EXPUNGE', array($uid));
+ return true;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ $message = $this->connection->get_mime_message_by_id($msg_id);
+ $result = $this->connection->get_structured_message($msg_id, false, false);
+ $struct = $result[0];
+ $attachment_id = get_attachment_id_for_mail_parser($struct, $part_id);
+ if ($attachment_id !== false) {
+ $message->removeAttachmentPart($attachment_id);
+ if ($this->connection->store_message($folder, (string) $message)) {
+ $this->connection->message_action('HARDDELETE', [$msg_id]);
+ return true;
+ }
+ }
+ }
+ }
+
+ public function get_quota($folder, $root = false) {
+ if ($this->is_imap()) {
+ if ($root) {
+ return $this->connection->get_quota_root($folder);
+ } else {
+ return $this->connection->get_quota($folder);
+ }
+ } else {
+ // not supported by EWS
+ return [];
+ }
+ }
+
+ public function get_debug() {
+ if ($this->is_imap()) {
+ return $this->connection->show_debug(true, true, true);
+ } else {
+ return [];
+ }
+ }
+
+ public function use_cache() {
+ if ($this->is_imap()) {
+ return $this->connection->use_cache;
+ } else {
+ return false;
+ }
+ }
+
+ public function dump_cache($type = 'string') {
+ if ($this->is_imap()) {
+ return $this->connection->dump_cache($type);
+ } else {
+ return null;
+ }
+ }
+
+ public function get_state() {
+ if ($this->is_imap()) {
+ return $this->connection->get_state();
+ } else {
+ return $this->authed() ? 'authenticated' : 'disconnected';
+ }
+ }
+
+ public function get_capability() {
+ return $this->connection->get_capability();
+ }
+
+ public function set_read_only($read_only) {
+ if ($this->is_imap()) {
+ $this->connection->read_only = $read_only;
+ }
+ }
+
+ public function set_search_charset($charset) {
+ if ($this->is_imap()) {
+ $this->connection->search_charset = $charset;
+ }
+ }
+
+ public function search($folder, $target='ALL', $uids=false, $terms=array(), $esearch=array(), $exclude_deleted=true, $exclude_auto_bcc=true, $only_auto_bcc=false) {
+ if (! $this->select_folder($folder)) {
+ return;
+ }
+ if ($this->is_imap()) {
+ return $this->connection->search($target, $uids, $terms, $esearch, $exclude_deleted, $exclude_auto_bcc, $only_auto_bcc);
+ } else {
+ // deleted flag, auto-bcc feature - not supported by EWS
+ list($total, $itemIds) = $this->connection->search($folder, false, false, $target, 0, 9999, $terms, []);
+ return $itemIds;
+ }
+ }
+
+ public function get_message_list($folder, $msg_ids) {
+ if (! $this->select_folder($folder)) {
+ return [];
+ }
+ if ($this->is_imap()) {
+ return $this->connection->get_message_list($msg_ids);
+ } else {
+ return $this->connection->get_message_list($msg_ids);
+ }
+ }
+
+ public function send_message($from, $recipients, $message, $delivery_receipt = false) {
+ if ($this->is_smtp()) {
+ if ($delivery_receipt) {
+ $from_params = 'RET=HDRS';
+ $recipients_params = 'NOTIFY=SUCCESS,FAILURE';
+ } else {
+ $from_params = '';
+ $recipients_params = '';
+ }
+ return $this->connection->send_message($from, $recipients, $message, $from_params, $recipients_params);
+ } else {
+ return $this->connection->send_message($from, $recipients, $message, $delivery_receipt);
+ }
+ }
+
+ protected function select_folder($folder) {
+ if ($this->is_imap()) {
+ if (isset($this->connection->selected_mailbox['name']) && $this->connection->selected_mailbox['name'] == $folder) {
+ return true;
+ }
+ if (! $this->connection->select_mailbox($folder)) {
+ return false;
+ }
+ } else {
+ $this->folder_state = $this->get_folder_status($folder);
+ if (! $this->folder_state) {
+ return false;
+ }
+ $this->selected_folder = ['id' => $folder, 'name' => $this->folder_state['name'], 'detail' => []];
+ }
+ return true;
+ }
+}
diff --git a/modules/core/message_list_functions.php b/modules/core/message_list_functions.php
index 793bc398d..02c2d61de 100644
--- a/modules/core/message_list_functions.php
+++ b/modules/core/message_list_functions.php
@@ -167,10 +167,10 @@ function human_readable_interval($date_str) {
$t['month'] = $t['day']*30;
$t['year'] = $t['week']*52;
- if ($interval < 0) {
+ if ($interval < -300) {
return 'From the future!';
}
- elseif ($interval == 0) {
+ elseif ($interval <= 0) {
return 'Just now';
}
foreach (array_reverse($t) as $name => $val) {
@@ -458,17 +458,17 @@ function list_sources($sources, $output_mod) {
if (array_key_exists('nodisplay', $src) && $src['nodisplay']) {
continue;
}
- if ($src['type'] == 'imap' && !array_key_exists('folder', $src)) {
- $folder = '_INBOX';
+ if ($src['type'] == 'imap' && !array_key_exists('folder_name', $src)) {
+ $folder = 'INBOX';
}
- elseif (!array_key_exists('folder', $src)) {
+ elseif (!array_key_exists('folder_name', $src)) {
$folder = '';
}
else {
- $folder = '_'.hex2bin($src['folder']);
+ $folder = $src['folder_name'];
}
$res .= '
'.$output_mod->html_safe($src['type']).' '.$output_mod->html_safe($src['name']);
- $res .= ' '.$output_mod->html_safe(str_replace('_', '', $folder));
+ $res .= ' '.$output_mod->html_safe($folder);
$res .= '
';
}
$res .= '';
diff --git a/modules/core/modules.php b/modules/core/modules.php
index dd980474e..8f520565d 100644
--- a/modules/core/modules.php
+++ b/modules/core/modules.php
@@ -17,3 +17,4 @@
require APP_PATH.'modules/core/message_list_functions.php';
require APP_PATH.'modules/core/handler_modules.php';
require APP_PATH.'modules/core/output_modules.php';
+require_once APP_PATH.'modules/core/hm-mailbox.php';
diff --git a/modules/core/output_modules.php b/modules/core/output_modules.php
index 4225ea1c2..a22d43c8b 100644
--- a/modules/core/output_modules.php
+++ b/modules/core/output_modules.php
@@ -2226,7 +2226,7 @@ protected function output() {
$hasJmapActivated = in_array('jmap', $this->get('router_module_list'), true);
if($hasImapActivated){
- $imap_servers_count = count(array_filter($this->get('imap_servers', array()), function($v) { return !array_key_exists('type', $v) || $v['type'] != 'jmap'; }));
+ $imap_servers_count = count(array_filter($this->get('imap_servers', array()), function($v) { return !array_key_exists('type', $v) || $v['type'] == 'imap'; }));
$accordionTitle .= 'IMAP';
$configuredText .= ' ' . $imap_servers_count .' IMAP';
$hasEssentialModuleActivated = true;
diff --git a/modules/core/site.js b/modules/core/site.js
index cb42a5cac..58cd6e638 100644
--- a/modules/core/site.js
+++ b/modules/core/site.js
@@ -2001,9 +2001,9 @@ function resetQuickSetupForm() {
function handleCreateProfileCheckboxChange(checkbox) {
if(checkbox.checked) {
- $('#srv_setup_stepper_profile_bloc').show();
+ $(checkbox).closest('.form-check').next().show();
}else{
- $('#srv_setup_stepper_profile_bloc').hide();
+ $(checkbox).closest('.form-check').next().hide();
}
}
diff --git a/modules/imap/functions.php b/modules/imap/functions.php
index 03349bf3a..524a58501 100644
--- a/modules/imap/functions.php
+++ b/modules/imap/functions.php
@@ -29,13 +29,13 @@ function imap_sources($mod, $folder = 'sent') {
}
$folders = get_special_folders($mod, $index);
if (array_key_exists($folder, $folders) && $folders[$folder]) {
- $sources[] = array('folder' => bin2hex($folders[$folder]), 'type' => 'imap', 'name' => $vals['name'], 'id' => $index);
+ $sources[] = array('folder' => bin2hex($folders[$folder]), 'folder_name' => $folders[$folder], 'type' => $vals['type'] ?? 'imap', 'name' => $vals['name'], 'id' => $index);
}
elseif ($inbox) {
- $sources[] = array('folder' => bin2hex('INBOX'), 'type' => 'imap', 'name' => $vals['name'], 'id' => $index);
+ $sources[] = array('folder' => bin2hex('INBOX'), 'folder_name' => 'INBOX', 'type' => $vals['type'] ?? 'imap', 'name' => $vals['name'], 'id' => $index);
}
else {
- $sources[] = array('folder' => bin2hex('SPECIAL_USE_CHECK'), 'nodisplay' => true, 'type' => 'imap', 'name' => $vals['name'], 'id' => $index);
+ $sources[] = array('folder' => bin2hex('SPECIAL_USE_CHECK'), 'folder_name' => 'SPECIAL_USE_CHECK', 'nodisplay' => true, 'type' => $vals['type'] ?? 'imap', 'name' => $vals['name'], 'id' => $index);
}
}
return $sources;
@@ -57,7 +57,7 @@ function imap_data_sources($custom=array()) {
if (!array_key_exists('user', $vals)) {
continue;
}
- $sources[] = array('folder' => bin2hex('INBOX'), 'type' => 'imap', 'name' => $vals['name'], 'id' => $index);
+ $sources[] = array('folder' => bin2hex('INBOX'), 'folder_name' => 'INBOX', 'type' => $vals['type'] ?? 'imap', 'name' => $vals['name'], 'id' => $index);
}
foreach ($custom as $path => $type) {
$parts = explode('_', $path, 3);
@@ -66,7 +66,14 @@ function imap_data_sources($custom=array()) {
if ($type == 'add') {
$details = Hm_IMAP_List::dump($parts[1]);
if ($details) {
- $sources[] = array('folder' => $parts[2], 'type' => 'imap', 'name' => $details['name'], 'id' => $parts[1]);
+ $folder_name = $parts[2];
+ if (! empty($details['type']) && $details['type'] == 'ews') {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($details['id']);
+ if ($mailbox && $mailbox->authed()) {
+ $folder_name = $mailbox->get_folder_name(hex2bin($folder_name));
+ }
+ }
+ $sources[] = array('folder' => $parts[2], 'folder_name' => $folder_name, 'type' => $details['type'] ?? 'imap', 'name' => $details['name'], 'id' => $parts[1]);
}
}
elseif ($type == 'remove') {
@@ -134,10 +141,10 @@ function format_imap_folder_section($folders, $id, $output_mod, $with_input = fa
'" href="?page=message_list&list_path='.
urlencode('imap_'.$id.'_'.$output_mod->html_safe($folder_name)).'"';
}
- if (mb_strlen($output_mod->html_safe($folder['basename']))>15) {
+ if (mb_strlen($folder['basename'])>15) {
$results .= ''.mb_substr($output_mod->html_safe($folder['basename']),0,15).'...';
+ '">'.$output_mod->html_safe(mb_substr($folder['basename'],0,15)).'...';
}
else {
$results .= ''.$output_mod->html_safe($folder['basename']).'';
@@ -508,20 +515,18 @@ function remove_attachment($att_id, $msg) {
/*
* ZBateson\MailMimeParser uses 0-based index for attachments
* Which mixes embedded images and attachments
- * @param Hm_IMAP $imap Imap object
- * @param int $msg message id
- * @param string $msg_id message part
+ * @param array $struct Imap structure
+ * @param string $part_id message part
* @return int
*/
if (!hm_exists('get_attachment_id_for_mail_parser')) {
- function get_attachment_id_for_mail_parser($imap, $uid, $msg_id) {
+ function get_attachment_id_for_mail_parser($struct, $part_id) {
$count = -1;
$id = false;
- $struct = $imap->get_message_structure($uid);
foreach ($struct[0]['subs'] as $key => $sub) {
if (! empty($sub['file_attributes'])) {
$count++;
- if ($key == $msg_id && isset($sub['file_attributes']['attachment'])) {
+ if ($key == $part_id && isset($sub['file_attributes']['attachment'])) {
$id = $count;
break;
}
@@ -738,13 +743,12 @@ function merge_imap_search_results($ids, $search_type, $session, $hm_cache, $fol
$sent_results = array();
$status = array();
foreach($ids as $index => $id) {
- $cache = Hm_IMAP_List::get_cache($hm_cache, $id);
- $imap = Hm_IMAP_List::connect($id, $cache);
- if (imap_authed($imap)) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($id, $hm_cache);
+ if ($mailbox && $mailbox->authed()) {
$server_details = Hm_IMAP_List::dump($id);
$folder = $folders[$index];
if ($sent) {
- $sent_folder = $imap->get_special_use_mailboxes('sent');
+ $sent_folder = $mailbox->get_special_use_mailboxes('sent');
if (array_key_exists('sent', $sent_folder)) {
list($sent_status, $sent_results) = merge_imap_search_results($ids, $search_type, $session, $hm_cache, array($sent_folder['sent']), $limit, $terms, false);
$status = array_merge($status, $sent_status);
@@ -753,44 +757,42 @@ function merge_imap_search_results($ids, $search_type, $session, $hm_cache, $fol
continue;
}
}
- if ($imap->select_mailbox($folder)) {
- $status['imap_'.$id.'_'.bin2hex($folder)] = $imap->folder_state;
- if (!empty($terms)) {
- foreach ($terms as $term) {
- if (preg_match('/(?:[^\x00-\x7F])/', $term[1]) === 1) {
- $imap->search_charset = 'UTF-8';
- break;
- }
- }
- if ($sent) {
- $msgs = $imap->search($search_type, false, $terms, array(), true, false, true);
- }
- else {
- $msgs = $imap->search($search_type, false, $terms);
+ if (!empty($terms)) {
+ foreach ($terms as $term) {
+ if (preg_match('/(?:[^\x00-\x7F])/', $term[1]) === 1) {
+ $mailbox->set_search_charset('UTF-8');
+ break;
}
}
+ if ($sent) {
+ $msgs = $mailbox->search($folder, $search_type, false, $terms, array(), true, false, true);
+ }
else {
- $msgs = $imap->search($search_type);
+ $msgs = $mailbox->search($folder, $search_type, false, $terms);
+ }
+ }
+ else {
+ $msgs = $mailbox->search($folder, $search_type);
+ }
+ if ($msgs) {
+ if ($limit) {
+ rsort($msgs);
+ $msgs = array_slice($msgs, 0, $limit);
}
- if ($msgs) {
- if ($limit) {
- rsort($msgs);
- $msgs = array_slice($msgs, 0, $limit);
+ foreach ($mailbox->get_message_list($folder, $msgs) as $msg) {
+ if (array_key_exists('content-type', $msg) && mb_stristr($msg['content-type'], 'multipart/mixed')) {
+ $msg['flags'] .= ' \Attachment';
}
- foreach ($imap->get_message_list($msgs) as $msg) {
- if (array_key_exists('content-type', $msg) && mb_stristr($msg['content-type'], 'multipart/mixed')) {
- $msg['flags'] .= ' \Attachment';
- }
- if (mb_stristr($msg['flags'], 'deleted')) {
- continue;
- }
- $msg['server_id'] = $id;
- $msg['folder'] = bin2hex($folder);
- $msg['server_name'] = $server_details['name'];
- $msg_list[] = $msg;
+ if (mb_stristr($msg['flags'], 'deleted')) {
+ continue;
}
+ $msg['server_id'] = $id;
+ $msg['folder'] = bin2hex($folder);
+ $msg['server_name'] = $server_details['name'];
+ $msg_list[] = $msg;
}
}
+ $status['imap_'.$id.'_'.bin2hex($folder)] = $mailbox->get_folder_state();
}
else {
$connection_failed = true;
@@ -881,17 +883,16 @@ function imap_move_same_server($ids, $action, $hm_cache, $dest_path, $screen_ema
$responses = [];
$keys = array_keys($ids);
$server_id = array_pop($keys);
- $cache = Hm_IMAP_List::get_cache($hm_cache, $server_id);
- $imap = Hm_IMAP_List::connect($server_id, $cache);
- foreach ($ids[$server_id] as $folder => $msgs) {
- if (imap_authed($imap) && $imap->select_mailbox(hex2bin($folder))) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($server_id, $hm_cache);
+ if ($mailbox && $mailbox->authed()) {
+ foreach ($ids[$server_id] as $folder => $msgs) {
if ($screen_emails) {
foreach ($msgs as $msg) {
$moved[] = sprintf('imap_%s_%s_%s', $server_id, $msg, $folder);
- $email = current(array_column(process_address_fld($imap->get_message_headers($msg)['From']), "email"));
- $uids = $imap->search('ALL', false, array(array('FROM', $email)));
+ $email = current(array_column(process_address_fld($mailbox->get_message_headers(hex2bin($folder), $msg)['From']), "email"));
+ $uids = $mailbox->search(hex2bin($folder), 'ALL', false, array(array('FROM', $email)));
foreach ($uids as $uid) {
- $result = $imap->message_action(mb_strtoupper($action), $uid, hex2bin($dest_path[2]));
+ $result = $mailbox->message_action(hex2bin($folder), mb_strtoupper($action), $uid, hex2bin($dest_path[2]));
if ($result['status']) {
$response = $result['responses'][0];
$responses[] = [
@@ -906,7 +907,7 @@ function imap_move_same_server($ids, $action, $hm_cache, $dest_path, $screen_ema
}
}
} else {
- $result = $imap->message_action(mb_strtoupper($action), $msgs, hex2bin($dest_path[2]));
+ $result = $mailbox->message_action(hex2bin($folder), mb_strtoupper($action), $msgs, hex2bin($dest_path[2]));
if ($result['status']) {
foreach ($msgs as $index => $msg) {
$response = $result['responses'][$index];
@@ -940,16 +941,14 @@ function imap_move_same_server($ids, $action, $hm_cache, $dest_path, $screen_ema
function imap_move_different_server($ids, $action, $dest_path, $hm_cache) {
$moved = [];
$responses = [];
- $cache = Hm_IMAP_List::get_cache($hm_cache, $dest_path[1]);
- $dest_imap = Hm_IMAP_List::connect($dest_path[1], $cache);
- if ($dest_imap) {
+ $dest_mailbox = Hm_IMAP_List::get_connected_mailbox($dest_path[1], $hm_cache);
+ if ($dest_mailbox && $dest_mailbox->authed()) {
foreach ($ids as $server_id => $folders) {
- $cache = Hm_IMAP_List::get_cache($hm_cache, $server_id);
- $imap = Hm_IMAP_List::connect($server_id, $cache);
- foreach ($folders as $folder => $msg_ids) {
- if (imap_authed($imap) && $imap->select_mailbox(hex2bin($folder))) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($server_id, $hm_cache);
+ if ($mailbox && $mailbox->authed()) {
+ foreach ($folders as $folder => $msg_ids) {
foreach ($msg_ids as $msg_id) {
- $detail = $imap->get_message_list(array($msg_id));
+ $detail = $mailbox->get_message_list(hex2bin($folder), array($msg_id));
if (array_key_exists($msg_id, $detail)) {
if (mb_stristr($detail[$msg_id]['flags'], 'seen')) {
$seen = true;
@@ -958,33 +957,29 @@ function imap_move_different_server($ids, $action, $dest_path, $hm_cache) {
$seen = false;
}
}
- $msg = $imap->get_message_content($msg_id, 0);
+ $msg = $mailbox->get_message_content(hex2bin($folder), $msg_id);
$msg = str_replace("\r\n", "\n", $msg);
$msg = str_replace("\n", "\r\n", $msg);
$msg = rtrim($msg)."\r\n";
if (!$seen) {
- $imap->message_action('UNREAD', array($msg_id));
+ $mailbox->message_action(hex2bin($folder), 'UNREAD', array($msg_id));
}
- if ($dest_imap->append_start(hex2bin($dest_path[2]), mb_strlen($msg), $seen)) {
- $dest_imap->append_feed($msg."\r\n");
- $uid = $dest_imap->append_end();
- if ($uid) {
- if ($action == 'move') {
- $deleteResult = $imap->message_action('DELETE', array($msg_id));
- if ($deleteResult['status']) {
- $imap->message_action('EXPUNGE', array($msg_id));
- }
+ if ($uid = $dest_mailbox->store_message(hex2bin($dest_path[2]), $msg, $seen)) {
+ if ($action == 'move') {
+ $deleteResult = $mailbox->message_action(hex2bin($folder), 'DELETE', array($msg_id));
+ if ($deleteResult['status']) {
+ $mailbox->message_action(hex2bin($folder), 'EXPUNGE', array($msg_id));
}
- $moved[] = sprintf('imap_%s_%s_%s', $server_id, $msg_id, $folder);
- $responses[] = [
- 'oldUid' => $msg_id,
- 'newUid' => $uid,
- 'oldFolder' => hex2bin($folder),
- 'newFolder' => hex2bin($dest_path[2]),
- 'oldServer' => $server_id,
- 'newServer' => $dest_path[1],
- ];
}
+ $moved[] = sprintf('imap_%s_%s_%s', $server_id, $msg_id, $folder);
+ $responses[] = [
+ 'oldUid' => $msg_id,
+ 'newUid' => $uid,
+ 'oldFolder' => hex2bin($folder),
+ 'newFolder' => hex2bin($dest_path[2]),
+ 'oldServer' => $server_id,
+ 'newServer' => $dest_path[1],
+ ];
}
}
}
@@ -1118,16 +1113,6 @@ function clear_existing_reply_details($session) {
}
}}
-/**
- * @subpackage imap/functions
- * @param object $imap imap library object
- * @return bool
- */
-if (!hm_exists('imap_authed')) {
-function imap_authed($imap) {
- return is_object($imap) && ($imap->get_state() == 'authenticated' || $imap->get_state() == 'selected');
-}}
-
/**
* @subpackage imap/functions
*/
@@ -1331,14 +1316,11 @@ function get_request_params($request) {
}}
if (!hm_exists('snooze_message')) {
-function snooze_message($imap, $msg_id, $folder, $snooze_tag) {
- if (!$imap->select_mailbox($folder)) {
- return false;
- }
+function snooze_message($mailbox, $msg_id, $folder, $snooze_tag) {
if (!$snooze_tag) {
- $imap->message_action('UNREAD', array($msg_id));
+ $mailbox->message_action($folder, 'UNREAD', array($msg_id));
}
- $msg = $imap->get_message_content($msg_id, 0);
+ $msg = $mailbox->get_message_content($folder, $msg_id);
preg_match("/^X-Snoozed:.*(\r?\n[ \t]+.*)*\r?\n?/im", $msg, $matches);
if (count($matches)) {
$msg = str_replace($matches[0], '', $msg);
@@ -1355,34 +1337,27 @@ function snooze_message($imap, $msg_id, $folder, $snooze_tag) {
$res = false;
$snooze_folder = 'Snoozed';
if ($snooze_tag) {
- if (!count($imap->get_mailbox_status($snooze_folder))) {
- $imap->create_mailbox($snooze_folder);
- }
- if ($imap->select_mailbox($snooze_folder) && $imap->append_start($snooze_folder, mb_strlen($msg))) {
- $imap->append_feed($msg."\r\n");
- if ($imap->append_end()) {
- if ($imap->select_mailbox($folder)) {
- $deleteResult = $imap->message_action('DELETE', array($msg_id));
- if ($deleteResult['status']) {
- $imap->message_action('EXPUNGE', array($msg_id));
- $res = true;
- }
- }
+ $status = $mailbox->get_folder_status($snooze_folder);
+ if (! count($status)) {
+ $snooze_folder = $mailbox->create_folder($snooze_folder);
+ } else {
+ $snooze_folder = $status['id'];
+ }
+ if ($mailbox->store_message($snooze_folder, $msg)) {
+ $deleteResult = $mailbox->message_action($folder, 'DELETE', array($msg_id));
+ if ($deleteResult['status']) {
+ $mailbox->message_action($folder, 'EXPUNGE', array($msg_id));
+ $res = true;
}
}
} else {
$snooze_headers = parse_snooze_header($matches[0]);
$original_folder = $snooze_headers['from'];
- if ($imap->select_mailbox($original_folder) && $imap->append_start($original_folder, mb_strlen($msg))) {
- $imap->append_feed($msg."\r\n");
- if ($imap->append_end()) {
- if ($imap->select_mailbox($snooze_folder)) {
- $deleteResult = $imap->message_action('DELETE', array($msg_id));
- if ($deleteResult['status']) {
- $imap->message_action('EXPUNGE', array($msg_id));
- $res = true;
- }
- }
+ if ($mailbox->store_message($original_folder, $msg)) {
+ $deleteResult = $mailbox->message_action($snooze_folder, 'DELETE', array($msg_id));
+ if ($deleteResult['status']) {
+ $mailbox->message_action($snooze_folder, 'EXPUNGE', array($msg_id));
+ $res = true;
}
}
}
@@ -1539,6 +1514,7 @@ function connect_to_imap_server($address, $name, $port, $user, $pass, $tls, $ima
$imap_list = array(
'name' => $name,
'server' => $address,
+ 'type' => $type,
'hide' => $hidden,
'port' => $port,
'user' => $user,
@@ -1549,8 +1525,6 @@ function connect_to_imap_server($address, $name, $port, $user, $pass, $tls, $ima
}
if ($type === 'jmap') {
- $imap_list['type'] = 'jmap';
- $imap_list['hide'] = $hidden;
$imap_list['port'] = false;
$imap_list['tls'] = false;
}
@@ -1567,7 +1541,7 @@ function connect_to_imap_server($address, $name, $port, $user, $pass, $tls, $ima
}
} else {
$imap_server_id = Hm_IMAP_List::add($imap_list);
- if (! can_save_last_added_server('Hm_IMAP_List', $user)) {
+ if ($type != 'ews' && ! can_save_last_added_server('Hm_IMAP_List', $user)) {
return;
}
}
@@ -1598,9 +1572,9 @@ function connect_to_imap_server($address, $name, $port, $user, $pass, $tls, $ima
}
}
- $imap = Hm_IMAP_List::connect($imap_server_id, false);
+ $mailbox = Hm_IMAP_List::connect($imap_server_id, false);
- if (imap_authed($imap)) {
+ if ($mailbox->authed()) {
return $imap_server_id;
} else {
Hm_IMAP_List::del($imap_server_id);
diff --git a/modules/imap/handler_modules.php b/modules/imap/handler_modules.php
index 658c1c290..a44ebfd46 100644
--- a/modules/imap/handler_modules.php
+++ b/modules/imap/handler_modules.php
@@ -37,15 +37,11 @@ public function process() {
if (!$filepath) {
return;
}
- $cache = Hm_IMAP_List::get_cache($this->cache, $path[1]);
- $imap = Hm_IMAP_List::connect($path[1], $cache);
- if (!imap_authed($imap)) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($path[1], $this->cache);
+ if (! $mailbox) {
return;
}
- if (!$imap->select_mailbox(hex2bin($path[2]))) {
- return;
- }
- $content = $imap->get_message_content($uid, 0);
+ $content = $mailbox->get_message_content(hex2bin($path[2]), $uid);
if (!$content) {
return;
}
@@ -71,10 +67,9 @@ class Hm_Handler_imap_folder_status extends Hm_Handler_Module {
public function process() {
list($success, $form) = $this->process_form(array('imap_server_id', 'folder'));
if ($success) {
- $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);
- $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache);
- if (imap_authed($imap)) {
- $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $imap->get_mailbox_status(hex2bin($form['folder']))));
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $mailbox->get_folder_status(hex2bin($form['folder']))));
}
}
}
@@ -255,16 +250,17 @@ public function process() {
$screen = false;
$parts = explode("_", $this->request->get['list_path']);
$imap_server_id = $parts[1] ?? '';
- $cache = Hm_IMAP_List::get_cache($this->cache, $imap_server_id);
- $imap = Hm_IMAP_List::connect($imap_server_id, $cache);
if ($form['imap_move_action'] == "screen_mail") {
- $form['imap_move_action'] = "move";
- $screen = true;
- $screen_folder = 'Screen emails';
- if (!count($imap->get_mailbox_status($screen_folder))) {
- $imap->create_mailbox($screen_folder);
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($imap_server_id, $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ $form['imap_move_action'] = "move";
+ $screen = true;
+ $screen_folder = 'Screen emails';
+ if (! count($mailbox->get_folder_status($screen_folder))) {
+ $mailbox->create_folder($screen_folder);
+ }
+ $form['imap_move_to'] = $parts[0] ."_". $parts[1] ."_".bin2hex($screen_folder);
}
- $form['imap_move_to'] = $parts[0] ."_". $parts[1] ."_".bin2hex($screen_folder);
}
list($msg_ids, $dest_path, $same_server_ids, $other_server_ids) = process_move_to_arguments($form);
@@ -332,18 +328,17 @@ public function process() {
$msg = str_replace("\r\n", "\n", $msg);
$msg = str_replace("\n", "\r\n", $msg);
$msg = rtrim($msg)."\r\n";
- $cache = Hm_IMAP_List::get_cache($this->cache, $imap_id);
- $imap = Hm_IMAP_List::connect($imap_id, $cache);
$imap_details = Hm_IMAP_List::dump($imap_id);
$sent_folder = false;
- if (imap_authed($imap)) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($imap_id, $this->cache);
+ if ($mailbox && $mailbox->authed()) {
$specials = get_special_folders($this, $imap_id);
if (array_key_exists('sent', $specials) && $specials['sent']) {
$sent_folder = $specials['sent'];
}
if (!$sent_folder) {
- $auto_sent = $imap->get_special_use_mailboxes('sent');
+ $auto_sent = $mailbox->get_special_use_mailboxes('sent');
if (!array_key_exists('sent', $auto_sent)) {
return;
}
@@ -354,16 +349,13 @@ public function process() {
}
if ($sent_folder) {
Hm_Debug::add(sprintf("Attempting to save sent message for IMAP server %s in folder %s", $imap_details['server'], $sent_folder));
- if ($imap->append_start($sent_folder, mb_strlen($msg), true)) {
- $imap->append_feed($msg."\r\n");
- if (!$imap->append_end()) {
- Hm_Msgs::add('ERRAn error occurred saving the sent message');
- }
+ if (! $mailbox->store_message($sent_folder, $msg)) {
+ Hm_Msgs::add('ERRAn error occurred saving the sent message');
}
$uid = null;
- $mailbox_page = $imap->get_mailbox_page($sent_folder, 'ARRIVAL', true, 'ALL', 0, 10);
+ $mailbox_page = $mailbox->get_messages($sent_folder, 'ARRIVAL', true, 'ALL', 0, 10);
foreach ($mailbox_page[1] as $mail) {
- $msg_header = $imap->get_message_headers($mail['uid']);
+ $msg_header = $mailbox->get_message_headers($sent_folder, $mail['uid']);
if ($msg_header['Message-Id'] === $mime->get_headers()['Message-Id']) {
$uid = $mail['uid'];
break;
@@ -388,10 +380,9 @@ public function process() {
if ($success) {
$path = explode('_', $form['compose_msg_path']);
if (count($path) == 3 && $path[0] == 'imap') {
- $cache = Hm_IMAP_List::get_cache($this->cache, $path[1]);
- $imap = Hm_IMAP_List::connect($path[1], $cache);
- if (imap_authed($imap) && $imap->select_mailbox(hex2bin($path[2]))) {
- $imap->message_action('UNFLAG', array($form['compose_msg_uid']));
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($path[1], $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ $mailbox->message_action(hex2bin($path[2]), 'UNFLAG', array($form['compose_msg_uid']));
}
}
}
@@ -410,11 +401,10 @@ public function process() {
if ($success) {
$path = explode('_', $form['compose_msg_path']);
if (count($path) == 3 && $path[0] == 'imap') {
- $cache = Hm_IMAP_List::get_cache($this->cache, $path[1]);
- $imap = Hm_IMAP_List::connect($path[1], $cache);
- if (imap_authed($imap) && $imap->select_mailbox(hex2bin($path[2]))) {
- $this->out('folder_status', array('imap_'.$path[1].'_'.$path[2] => $imap->folder_state));
- $imap->message_action('ANSWERED', array($form['compose_msg_uid']));
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($path[1], $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ $this->out('folder_status', array('imap_'.$path[1].'_'.$path[2] => $mailbox->get_folder_state()));
+ $mailbox->message_action(hex2bin($path[2]), 'ANSWERED', array($form['compose_msg_uid']));
}
}
}
@@ -433,11 +423,10 @@ class Hm_Handler_imap_mark_as_read extends Hm_Handler_Module {
public function process() {
list($success, $form) = $this->process_form(array('imap_server_id', 'imap_msg_uid', 'folder'));
if ($success) {
- $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);
- $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache);
- if (imap_authed($imap) && $imap->select_mailbox(hex2bin($form['folder']))) {
- $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $imap->folder_state));
- $imap->message_action('READ', array($form['imap_msg_uid']));
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $mailbox->get_folder_state()));
+ $mailbox->message_action(hex2bin($form['folder']), 'READ', array($form['imap_msg_uid']));
}
}
}
@@ -494,49 +483,14 @@ public function process() {
$msg_id = preg_replace("/^0.{1}/", '', $this->request->get['imap_msg_part']);
}
if ($server_id !== NULL && $uid !== NULL && $folder !== NULL && $msg_id !== NULL) {
- $cache = Hm_IMAP_List::get_cache($this->cache, $server_id);
- $imap = Hm_IMAP_List::connect($server_id, $cache);
- if (imap_authed($imap)) {
- if ($imap->select_mailbox($folder)) {
- $msg_struct = $imap->get_message_structure($uid);
- $struct = $imap->search_bodystructure($msg_struct, array('imap_part_number' => $msg_id));
- if (!empty($struct)) {
- $part_struct = array_shift($struct);
- $encoding = false;
- if (array_key_exists('encoding', $part_struct)) {
- $encoding = trim(mb_strtolower($part_struct['encoding']));
- }
- $stream_size = $imap->start_message_stream($uid, $msg_id);
- if ($stream_size > 0) {
- $charset = '';
- if (array_key_exists('attributes', $part_struct)) {
- if (is_array($part_struct['attributes']) && array_key_exists('charset', $part_struct['attributes'])) {
- $charset = '; charset='.$part_struct['attributes']['charset'];
- }
- }
- header('Content-Type: '.$part_struct['type'].'/'.$part_struct['subtype'].$charset);
- header('Content-Transfer-Encoding: binary');
- ob_end_clean();
- $output_line = '';
- while($line = $imap->read_stream_line()) {
- if ($encoding == 'quoted-printable') {
- $line = quoted_printable_decode($line);
- }
- elseif ($encoding == 'base64') {
- $line = base64_decode($line);
- }
- echo $output_line;
- $output_line = $line;
-
- }
- if ($part_struct['type'] == 'text') {
- $output_line = preg_replace("/\)(\r\n)$/m", '$1', $output_line);
- }
- echo $output_line;
- Hm_Functions::cease();
- }
- }
- }
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($server_id, $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ $mailbox->stream_message_part($folder, $uid, $msg_id, function ($content_type) {
+ header('Content-Type: ' . $content_type);
+ header('Content-Transfer-Encoding: binary');
+ ob_end_clean();
+ });
+ Hm_Functions::cease();
}
}
Hm_Msgs::add('ERRAn Error occurred trying to download the message');
@@ -557,50 +511,15 @@ public function process() {
list($server_id, $uid, $folder, $msg_id) = get_request_params($this->request->get);
if ($server_id !== NULL && $uid !== NULL && $folder !== NULL && $msg_id !== NULL) {
- $cache = Hm_IMAP_List::get_cache($this->cache, $server_id);
- $imap = Hm_IMAP_List::connect($server_id, $cache);
- if (imap_authed($imap)) {
- if ($imap->select_mailbox($folder)) {
- $msg_struct = $imap->get_message_structure($uid);
- $struct = $imap->search_bodystructure($msg_struct, array('imap_part_number' => $msg_id));
- if (!empty($struct)) {
- $part_struct = array_shift($struct);
- $encoding = false;
- if (array_key_exists('encoding', $part_struct)) {
- $encoding = trim(mb_strtolower($part_struct['encoding']));
- }
- $stream_size = $imap->start_message_stream($uid, $msg_id);
- if ($stream_size > 0) {
- $name = get_imap_part_name($part_struct, $uid, $msg_id);
- header('Content-Disposition: attachment; filename="'.$name.'"');
- $charset = '';
- if (array_key_exists('attributes', $part_struct)) {
- if (is_array($part_struct['attributes']) && array_key_exists('charset', $part_struct['attributes'])) {
- $charset = '; charset='.$part_struct['attributes']['charset'];
- }
- }
- header('Content-Type: '.$part_struct['type'].'/'.$part_struct['subtype'].$charset);
- header('Content-Transfer-Encoding: binary');
- ob_end_clean();
- $output_line = '';
- while($line = $imap->read_stream_line()) {
- if ($encoding == 'quoted-printable') {
- $line = quoted_printable_decode($line);
- }
- elseif ($encoding == 'base64') {
- $line = base64_decode($line);
- }
- echo $output_line;
- $output_line = $line;
- }
- if ($part_struct['type'] == 'text') {
- $output_line = preg_replace("/\)(\r\n)$/m", '$1', $output_line);
- }
- echo $output_line;
- Hm_Functions::cease();
- }
- }
- }
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($server_id, $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ $mailbox->stream_message_part($folder, $uid, $msg_id, function ($content_type, $part_name) {
+ header('Content-Disposition: attachment; filename="' . $part_name . '"');
+ header('Content-Type: ' . $content_type);
+ header('Content-Transfer-Encoding: binary');
+ ob_end_clean();
+ });
+ Hm_Functions::cease();
}
}
Hm_Msgs::add('ERRAn Error occurred trying to download the message');
@@ -651,7 +570,13 @@ public function process() {
else {
$folder = hex2bin($parts[2]);
}
- $title = array('IMAP', $details['name'], $folder);
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($details['id'], $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ $label = $mailbox->get_folder_name($folder);
+ } else {
+ $label = $folder;
+ }
+ $title = array(strtoupper($details['type'] ?? 'IMAP'), $details['name'], $label);
if ($this->get('list_page', 0)) {
$title[] = sprintf('Page %d', $this->get('list_page', 0));
}
@@ -695,29 +620,12 @@ public function process() {
if (array_key_exists('imap_remove_attachment', $this->request->get) && $this->request->get['imap_remove_attachment']) {
list($server_id, $uid, $folder, $msg_id) = get_request_params($this->request->get);
if ($server_id !== NULL && $uid !== NULL && $folder !== NULL && $msg_id !== NULL) {
- $cache = Hm_IMAP_List::get_cache($this->cache, $server_id);
- $imap = Hm_IMAP_List::connect($server_id, $cache);
- if (imap_authed($imap)) {
- if ($imap->select_mailbox($folder)) {
- $msg = $imap->get_message_content($uid, 0, false, false);
- if ($msg) {
- $attachment_id = get_attachment_id_for_mail_parser($imap, $uid, $this->request->get['imap_msg_part']);
- if ($attachment_id !== false) {
- $msg = remove_attachment($attachment_id, $msg);
- if ($imap->append_start($folder, mb_strlen($msg))) {
- $imap->append_feed($msg."\r\n");
- if ($imap->append_end()) {
- if ($imap->message_action('DELETE', array($uid))['status']) {
- $imap->message_action('EXPUNGE', array($uid));
- Hm_Msgs::add('Attachment deleted');
- $this->out('redirect_url', '?page=message_list&list_path='.$this->request->get['list_path']);
- return;
- }
- }
- }
- }
-
- }
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($server_id, $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ if ($mailbox->remove_attachment($folder, $uid, $this->request->get['imap_msg_part'])) {
+ Hm_Msgs::add('Attachment deleted');
+ $this->out('redirect_url', '?page=message_list&list_path=' . $this->request->get['list_path']);
+ return;
}
}
}
@@ -750,13 +658,12 @@ public function process() {
$this->session->set('imap_prefetched_ids', array_unique($prefetched, SORT_STRING));
}
$with_subscription = isset($this->request->post['subscription_state']) && $this->request->post['subscription_state'];
- $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);
- $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache);
- $this->out('can_share_folders', stripos($imap->get_capability(), 'ACL') !== false);
- if (imap_authed($imap)) {
- $quota_root = $imap->get_quota_root($folder ? $folder : 'INBOX');
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ $this->out('can_share_folders', stripos($mailbox->get_capability(), 'ACL') !== false);
+ $quota_root = $mailbox->get_quota($folder ? $folder : 'INBOX', true);
if ($quota_root && isset($quota_root[0]['name'])) {
- $quota = $imap->get_quota($quota_root[0]['name']);
+ $quota = $mailbox->get_quota($quota_root[0]['name'], false);
if ($quota) {
$current = floatval($quota[0]['current']);
$max = floatval($quota[0]['max']);
@@ -775,12 +682,12 @@ public function process() {
$this->out('folder', $folder);
return;
}
- if (imap_authed($imap)) {
+ if ($mailbox && $mailbox->authed()) {
$only_subscribed = $this->user_config->get('only_subscribed_folders_setting', false);
if ($with_subscription) {
$only_subscribed = false;
}
- $msgs = $imap->get_folder_list_by_level(hex2bin($folder), $only_subscribed, $with_subscription);
+ $msgs = $mailbox->get_subfolders(hex2bin($folder), $only_subscribed, $with_subscription);
if (isset($msgs[$folder])) {
unset($msgs[$folder]);
}
@@ -792,7 +699,7 @@ public function process() {
$this->out('folder', $folder);
}
else {
- Hm_Msgs::add(sprintf('ERRCould not authenticate to the selected %s server (%s)', $imap->server_type, $this->user_config->get('imap_servers')[$form['imap_server_id']]['user']));
+ Hm_Msgs::add(sprintf('ERRCould not authenticate to the selected %s server (%s)', $mailbox->server_type(), $this->user_config->get('imap_servers')[$form['imap_server_id']]['user']));
}
}
}
@@ -839,9 +746,8 @@ public function process() {
}
$path = sprintf("imap_%s_%s", $form['imap_server_id'], $form['folder']);
$details = Hm_IMAP_List::dump($form['imap_server_id']);
- $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);
- $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache);
- if (imap_authed($imap)) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $this->cache);
+ if ($mailbox && $mailbox->authed()) {
$this->out('imap_mailbox_page_path', $path);
if (isset($this->request->get['screen_emails']) && hex2bin($form['folder']) == 'INBOX' && $this->module_is_supported("contacts")) {
$contacts = $this->get('contact_store');
@@ -850,9 +756,9 @@ public function process() {
$existingEmails = array_map(function($c){
return $c->value('email_address');
},$contact_list);
- list($total, $results) = $imap->get_mailbox_page(hex2bin($form['folder']), $sort, $rev, $filter, $offset, $limit, $keyword, $existingEmails, $include_content_body);
+ list($total, $results) = $mailbox->get_messages(hex2bin($form['folder']), $sort, $rev, $filter, $offset, $limit, $keyword, $existingEmails, $include_content_body);
} else {
- list($total, $results) = $imap->get_mailbox_page(hex2bin($form['folder']), $sort, $rev, $filter, $offset, $limit, $keyword, null, $include_content_body);
+ list($total, $results) = $mailbox->get_messages(hex2bin($form['folder']), $sort, $rev, $filter, $offset, $limit, $keyword, null, $include_content_body);
}
foreach ($results as $msg) {
$msg['server_id'] = $form['imap_server_id'];
@@ -864,8 +770,8 @@ public function process() {
if ($this->isCeoFraud($msg['to'], $msg['subject'], $msg['preview_msg'])) {
$folder = "Suspicious emails";
- if (!count($imap->get_mailbox_status($folder))) {
- $imap->create_mailbox($folder);
+ if (!count($mailbox->get_mailbox_status($folder))) {
+ $mailbox->create_folder($folder);
}
$dest_folder = bin2hex($folder);
$server_ids = array(
@@ -885,14 +791,12 @@ public function process() {
}
$msgs[] = $msg;
}
-
}
-
- if ($imap->selected_mailbox) {
- $imap->selected_mailbox['detail']['exists'] = $total;
- $this->out('imap_folder_detail', array_merge($imap->selected_mailbox, array('offset' => $offset, 'limit' => $limit)));
+ if ($folder = $mailbox->get_selected_folder()) {
+ $folder['detail']['exists'] = $total;
+ $this->out('imap_folder_detail', array_merge($folder, array('offset' => $offset, 'limit' => $limit)));
}
- $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $imap->folder_state));
+ $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $mailbox->get_folder_state()));
}
$this->out('imap_mailbox_page', $msgs);
$this->out('list_page', $list_page);
@@ -989,29 +893,17 @@ public function process() {
list($success, $form) = $this->process_form(array('imap_msg_uid', 'imap_server_id', 'folder'));
if ($success) {
$del_result = false;
- $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);
- $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache);
$trash_folder = false;
$specials = get_special_folders($this, $form['imap_server_id']);
if (array_key_exists('trash', $specials) && $specials['trash']) {
$trash_folder = $specials['trash'];
}
- if (imap_authed($imap)) {
- if ($imap->select_mailbox(hex2bin($form['folder']))) {
- $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $imap->folder_state));
- if ($trash_folder && $trash_folder != hex2bin($form['folder'])) {
- $moveResult = $imap->message_action('MOVE', array($form['imap_msg_uid']), $trash_folder);
- if ($moveResult['status']) {
- $del_result = true;
- }
- }
- else {
- if ($imap->message_action('DELETE', array($form['imap_msg_uid']))['status']) {
- $del_result = true;
- $imap->message_action('EXPUNGE', array($form['imap_msg_uid']));
- }
- }
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ if ($mailbox->delete_message(hex2bin($form['folder']), $form['imap_msg_uid'], $trash_folder)) {
+ $del_result = true;
}
+ $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $mailbox->get_folder_state()));
}
if (!$del_result) {
Hm_Msgs::add('ERRAn error occurred trying to delete this message');
@@ -1040,62 +932,64 @@ public function process() {
if (!$success) {
return;
}
- $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);
- $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache);
+
$archive_folder = false;
+ $form_folder = hex2bin($form['folder']);
$errors = 0;
+ $status = null;
$specials = get_special_folders($this, $form['imap_server_id']);
if (array_key_exists('archive', $specials) && $specials['archive']) {
$archive_folder = $specials['archive'];
}
- if (!$archive_folder) {
- Hm_Msgs::add('No archive folder configured for this IMAP server');
- $errors++;
- }
- if (!$errors && imap_authed($imap)) {
- $archive_exists = count($imap->get_mailbox_status($archive_folder));
- if (!$archive_exists) {
- Hm_Msgs::add('Configured archive folder for this IMAP server does not exist');
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $this->cache);
+ if ($mailbox && ! $mailbox->is_imap() && empty($archive_folder)) {
+ // EWS supports archiving to user archive folders
+ $status = $mailbox->message_action($form_folder, 'ARCHIVE', array($form['imap_msg_uid']))['status'];
+ } else {
+ if (!$archive_folder) {
+ Hm_Msgs::add('No archive folder configured for this IMAP server');
$errors++;
}
- $form_folder = hex2bin($form['folder']);
-
- /* select source folder */
- if ($errors || !$imap->select_mailbox($form_folder)) {
- Hm_Msgs::add('ERRAn error occurred archiving the message');
- $errors++;
- }
+ if (! $errors && $mailbox && $mailbox->authed()) {
+ $archive_exists = count($mailbox->get_folder_status($archive_folder));
+ if (!$archive_exists) {
+ Hm_Msgs::add('Configured archive folder for this IMAP server does not exist');
+ $errors++;
+ }
- /* path according to original option setting */
- if ($this->user_config->get('original_folder_setting', false)) {
- $archive_folder .= '/'.$form_folder;
- if (!count($imap->get_mailbox_status($archive_folder))) {
- if (! $imap->create_mailbox($archive_folder)) {
- $debug = $imap->show_debug(true, true, true);
- if (! empty($debug['debug'])) {
- Hm_Msgs::add('ERR' . array_pop($debug['debug']));
- } else {
- Hm_Msgs::add('ERRCould not create configured archive folder for the original folder of the message');
+ /* path according to original option setting */
+ if ($this->user_config->get('original_folder_setting', false)) {
+ $archive_folder .= '/' . $form_folder;
+ if (!count($mailbox->get_folder_status($archive_folder))) {
+ if (! $mailbox->create_folder($archive_folder)) {
+ $debug = $mailbox->get_debug();
+ if (! empty($debug['debug'])) {
+ Hm_Msgs::add('ERR' . array_pop($debug['debug']));
+ } else {
+ Hm_Msgs::add('ERRCould not create configured archive folder for the original folder of the message');
+ }
+ $errors++;
}
- $errors++;
}
}
- }
- /* try to move the message */
- if (!$errors) {
- $moveResult = $imap->message_action('MOVE', array($form['imap_msg_uid']), $archive_folder);
- if ($moveResult['status']) {
- Hm_Msgs::add("Message archived");
+ /* try to move the message */
+ if (! $errors) {
+ $status = $mailbox->message_action($form_folder, 'MOVE', array($form['imap_msg_uid']), $archive_folder)['status'];
}
}
- else {
- Hm_Msgs::add('ERRAn error occurred archiving the message');
- }
}
+
+ if ($status) {
+ Hm_Msgs::add("Message archived");
+ } else {
+ Hm_Msgs::add('ERRAn error occurred archiving the message');
+ }
+
+ $this->save_hm_msgs();
}
}
@@ -1111,21 +1005,18 @@ public function process() {
list($success, $form) = $this->process_form(array('imap_flag_state', 'imap_msg_uid', 'imap_server_id', 'folder'));
if ($success) {
$flag_result = false;
- $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);
- $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache);
- if (imap_authed($imap)) {
- if ($imap->select_mailbox(hex2bin($form['folder']))) {
- $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $imap->folder_state));
- if ($form['imap_flag_state'] == 'flagged') {
- $cmd = 'UNFLAG';
- }
- else {
- $cmd = 'FLAG';
- }
- if ($imap->message_action($cmd, array($form['imap_msg_uid']))['status']) {
- $flag_result = true;
- }
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ if ($form['imap_flag_state'] == 'flagged') {
+ $cmd = 'UNFLAG';
+ }
+ else {
+ $cmd = 'FLAG';
+ }
+ if ($mailbox->message_action(hex2bin($form['folder']), $cmd, array($form['imap_msg_uid']))['status']) {
+ $flag_result = true;
}
+ $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $mailbox->get_folder_state()));
}
if (!$flag_result) {
Hm_Msgs::add('ERRAn error occurred trying to flag this message');
@@ -1157,11 +1048,10 @@ public function process() {
$ids = explode(',', $form['imap_snooze_ids']);
foreach ($ids as $msg_part) {
list($imap_server_id, $msg_id, $folder) = explode('_', $msg_part);
- $cache = Hm_IMAP_List::get_cache($this->cache, $imap_server_id);
- $imap = Hm_IMAP_List::connect($imap_server_id, $cache);
- if (imap_authed($imap)) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($imap_server_id, $this->cache);
+ if ($mailbox && $mailbox->authed()) {
$folder = hex2bin($folder);
- if (snooze_message($imap, $msg_id, $folder, $snooze_tag)) {
+ if (snooze_message($mailbox, $msg_id, $folder, $snooze_tag)) {
$snoozed_messages[] = $msg_id;
}
}
@@ -1190,21 +1080,22 @@ class Hm_Handler_imap_unsnooze_message extends Hm_Handler_Module {
public function process() {
$servers = Hm_IMAP_List::dump();
foreach (array_keys($servers) as $server_id) {
- $cache = Hm_IMAP_List::get_cache($this->cache, $server_id);
- $imap = Hm_IMAP_List::connect($server_id, $cache);
- if (imap_authed($imap)) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($server_id, $this->cache);
+ if ($mailbox && $mailbox->authed()) {
$folder = 'Snoozed';
- if (!count($imap->get_mailbox_status($folder))) {
+ $status = $mailbox->get_folder_status($folder);
+ if (! count($status)) {
continue;
}
- $ret = $imap->get_mailbox_page($folder, 'DATE', false, 'ALL');
+ $folder = $status['id'];
+ $ret = $mailbox->get_messages($folder, 'DATE', false, 'ALL');
foreach ($ret[1] as $msg) {
- $msg_headers = $imap->get_message_headers($msg['uid']);
+ $msg_headers = $mailbox->get_message_headers($folder, $msg['uid']);
if (isset($msg_headers['X-Snoozed'])) {
try {
$snooze_headers = parse_snooze_header($msg_headers['X-Snoozed']);
if (new DateTime($snooze_headers['until']) <= new DateTime()) {
- snooze_message($imap, $msg['uid'], $folder, null);
+ snooze_message($mailbox, $msg['uid'], $folder, null);
}
} catch (Exception $e) {
Hm_Debug::add(sprintf('ERR Cannot unsnooze message: %s', $msg_headers['subject']));
@@ -1237,15 +1128,14 @@ public function process() {
$specials = get_special_folders($this, $server);
$trash_folder = false;
$archive_folder = false;
- $cache = Hm_IMAP_List::get_cache($this->cache, $server);
- $imap = Hm_IMAP_List::connect($server, $cache);
- if (imap_authed($imap)) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($server, $this->cache);
+ if ($mailbox && $mailbox->authed()) {
$server_details = $this->user_config->get('imap_servers')[$server];
if ($form['action_type'] == 'delete') {
if (array_key_exists('trash', $specials)) {
if ($specials['trash']) {
$trash_folder = $specials['trash'];
- } else {
+ } elseif ($mailbox->is_imap()) {
Hm_Msgs::add(sprintf('ERRNo trash folder configured for %s', $server_details['name']));
}
}
@@ -1254,53 +1144,51 @@ public function process() {
if(array_key_exists('archive', $specials)) {
if($specials['archive']) {
$archive_folder = $specials['archive'];
- } else {
+ } elseif ($mailbox->is_imap()) {
Hm_Msgs::add(sprintf('ERRNo archive folder configured for %s', $server_details['name']));
}
}
}
foreach ($folders as $folder => $uids) {
- if ($imap->select_mailbox(hex2bin($folder))) {
- $status['imap_'.$server.'_'.$folder] = $imap->folder_state;
+ $status['imap_'.$server.'_'.$folder] = $imap->folder_state;
- if ($form['action_type'] == 'delete' && $trash_folder && $trash_folder != hex2bin($folder)) {
- if (!$imap->message_action('MOVE', $uids, $trash_folder)['status']) {
- $errs++;
- }
- else {
- foreach ($uids as $uid) {
- $moved[] = sprintf("imap_%s_%s_%s", $server, $uid, $folder);
- }
- }
+ if ($mailbox->is_imap() && $form['action_type'] == 'delete' && $trash_folder && $trash_folder != hex2bin($folder)) {
+ if (! $mailbox->message_action(hex2bin($folder), 'MOVE', $uids, $trash_folder)['status']) {
+ $errs++;
}
- elseif ($form['action_type'] == 'archive' && $archive_folder && $archive_folder != hex2bin($folder)) {
- /* path according to original option setting */
- if ($this->user_config->get('original_folder_setting', false)) {
- $archive_folder .= '/'.hex2bin($folder);
- $dest_path_exists = count($imap->get_mailbox_status($archive_folder));
- if (!$dest_path_exists) {
- $imap->create_mailbox($archive_folder);
- }
- }
- if (!$imap->message_action('MOVE', $uids, $archive_folder)['status']) {
- $errs++;
+ else {
+ foreach ($uids as $uid) {
+ $moved[] = sprintf("imap_%s_%s_%s", $server, $uid, $folder);
}
- else {
- foreach ($uids as $uid) {
- $moved[] = sprintf("imap_%s_%s_%s", $server, $uid, $folder);
- }
+ }
+ }
+ elseif ($mailbox->is_imap() && $form['action_type'] == 'archive' && $archive_folder && $archive_folder != hex2bin($folder)) {
+ /* path according to original option setting */
+ if ($this->user_config->get('original_folder_setting', false)) {
+ $archive_folder .= '/' . hex2bin($folder);
+ $dest_path_exists = count($mailbox->get_folder_status($archive_folder));
+ if (!$dest_path_exists) {
+ $mailbox->create_folder($archive_folder);
}
}
+ if (! $mailbox->message_action(hex2bin($folder), 'MOVE', $uids, $archive_folder)['status']) {
+ $errs++;
+ }
else {
- if (!$imap->message_action(mb_strtoupper($form['action_type']), $uids)['status']) {
- $errs++;
+ foreach ($uids as $uid) {
+ $moved[] = sprintf("imap_%s_%s_%s", $server, $uid, $folder);
}
- else {
- $msgs += count($uids);
- if ($form['action_type'] == 'delete') {
- $imap->message_action('EXPUNGE', $uids);
- }
+ }
+ }
+ else {
+ if (! $mailbox->message_action(hex2bin($folder), mb_strtoupper($form['action_type']), $uids)['status']) {
+ $errs++;
+ }
+ else {
+ $msgs += count($uids);
+ if ($form['action_type'] == 'delete') {
+ $mailbox->message_action(hex2bin($folder), 'EXPUNGE', $uids);
}
}
}
@@ -1434,13 +1322,12 @@ public function process() {
if ($success) {
$ids = explode(',', $form['imap_server_ids']);
foreach ($ids as $id) {
- $cache = Hm_IMAP_List::get_cache($this->cache, $id);
$start_time = microtime(true);
- $imap = Hm_IMAP_List::connect($id, $cache);
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($id, $this->cache);
$this->out('imap_connect_time', microtime(true) - $start_time);
- if (imap_authed($imap)) {
- $this->out('imap_capabilities_list', $imap->get_capability());
- $this->out('imap_connect_status', $imap->get_state());
+ if ($mailbox && $mailbox->authed()) {
+ $this->out('imap_capabilities_list', $mailbox->get_capability());
+ $this->out('imap_connect_status', $mailbox->get_state());
$this->out('imap_status_server_id', $id);
}
else {
@@ -1592,7 +1479,7 @@ public function process() {
$cache = array();
foreach ($servers as $index => $server) {
if (isset($server['object']) && is_object($server['object'])) {
- if ($server['object']->use_cache) {
+ if ($server['object']->use_cache()) {
$cache[$index] = $server['object']->dump_cache('array');
}
}
@@ -1605,6 +1492,81 @@ public function process() {
}
}
+/**
+ * Save EWS server details
+ * @subpackage imap/handler
+ */
+class Hm_Handler_save_ews_server extends Hm_Handler_Module {
+ public function process() {
+ list($success, $form) = $this->process_form(array(
+ 'ews_profile_name',
+ 'ews_email',
+ 'ews_password',
+ 'ews_server',
+ 'ews_server_id',
+ 'ews_hide_from_c_page',
+ 'ews_create_profile',
+ 'ews_profile_signature',
+ 'ews_profile_reply_to',
+ 'ews_profile_is_default',
+ ));
+ if ($success) {
+ $imap_server_id = connect_to_imap_server(
+ $form['ews_server'],
+ $form['ews_profile_name'],
+ null,
+ $form['ews_email'],
+ $form['ews_password'],
+ null,
+ null,
+ null,
+ 'ews',
+ $this,
+ $form['ews_hide_from_c_page'],
+ $form['ews_server_id'],
+ );
+ if(empty($imap_server_id)) {
+ Hm_Msgs::add("ERRCould not save server");
+ return;
+ }
+ $smtp_server_id = connect_to_smtp_server(
+ $form['ews_server'],
+ $form['ews_profile_name'],
+ null,
+ $form['ews_email'],
+ $form['ews_password'],
+ null,
+ 'ews',
+ $form['ews_server_id'],
+ );
+ if ($form['ews_create_profile'] && $imap_server_id && $smtp_server_id) {
+ if (! strstr($form['ews_email'], '@')) {
+ $address = $form['ews_email'] . '@' . $form['ews_server'];
+ } else {
+ $address = $form['ews_email'];
+ }
+ add_profile($form['ews_profile_name'], $form['ews_profile_signature'], $form['ews_profile_reply_to'], $form['ews_profile_is_default'], $address, $form['ews_server'], $form['ews_email'], $smtp_server_id, $imap_server_id, $this);
+ }
+ // auto-assign special folders
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($imap_server_id, $this->cache);
+ if (is_object($mailbox) && $mailbox->authed()) {
+ $specials = $this->user_config->get('special_imap_folders', array());
+ $exposed = $mailbox->get_special_use_mailboxes();
+ $specials[$imap_server_id] = [
+ 'sent' => $exposed['sent'] ?? '',
+ 'draft' => $exposed['drafts'] ?? '',
+ 'trash' => $exposed['trash'] ?? '',
+ 'archive' => $exposed['archive'] ?? '',
+ 'junk' => $exposed['junk'] ?? ''
+ ];
+ $this->user_config->set('special_imap_folders', $specials);
+ }
+ $this->session->record_unsaved('EWS server added');
+ $this->session->secure_cookie($this->request, 'hm_reload_folders', '1');
+ }
+ }
+}
+
/**
* Save IMAP servers
* @subpackage imap/handler
@@ -1889,14 +1851,22 @@ public function process() {
}
}
+ $mailbox = false;
$cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);
- $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache, $imap_details['user'], $imap_details['pass']);
- if (imap_authed($imap)) {
- Hm_Msgs::add(sprintf("Successfully authenticated to the %s server : %s", $imap->server_type, $imap_details['user']));
- return;
+ $mailbox = Hm_IMAP_List::connect($form['imap_server_id'], $cache, $form['imap_user'], $form['imap_pass']);
+ if ($mailbox) {
+ if ($mailbox->authed()) {
+ Hm_Msgs::add(sprintf("Successfully authenticated to the %s server : %s", $mailbox->server_type(), $form['imap_user']));
+ }
+ else {
+ Hm_Msgs::add(sprintf("ERRFailed to authenticate to the %s server : %s", $mailbox->server_type(), $form['imap_user']));
+ }
+ }
+ else {
+ Hm_Msgs::add('ERRUsername and password are required');
+ $this->out('old_form', $form);
}
}
- Hm_Msgs::add("ERRFailed to authenticate to IMAP server");
}
}
}
@@ -1934,97 +1904,54 @@ public function process() {
$this->out('header_allow_images', $this->config->get('allow_external_image_sources'));
$this->out('images_whitelist', explode(',', $this->user_config->get('images_whitelist_setting')));
- $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);
- $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache);
- if (imap_authed($imap)) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $this->cache);
+ if ($mailbox && $mailbox->authed()) {
if ($this->user_config->get('unread_on_open_setting', false)) {
- $imap->read_only = true;
+ $mailbox->set_read_only(true);
}
else {
- $imap->read_only = $prefetch;
- }
- if ($imap->select_mailbox(hex2bin($form['folder']))) {
- $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $imap->folder_state));
- $msg_struct = $imap->get_message_structure($form['imap_msg_uid']);
- $this->out('msg_struct', $msg_struct);
- if ($part !== false) {
- if ($part == 0) {
- $max = 500000;
- }
- else {
- $max = false;
- }
- $struct = $imap->search_bodystructure($msg_struct, array('imap_part_number' => $part));
- $msg_struct_current = array_shift($struct);
- $msg_text = $imap->get_message_content($form['imap_msg_uid'], $part, $max, $msg_struct_current);
- }
- else {
- if (!$this->user_config->get('text_only_setting', false)) {
- list($part, $msg_text) = $imap->get_first_message_part($form['imap_msg_uid'], 'text', 'html', $msg_struct);
- if (!$part) {
- list($part, $msg_text) = $imap->get_first_message_part($form['imap_msg_uid'], 'text', false, $msg_struct);
- }
- }
- else {
- list($part, $msg_text) = $imap->get_first_message_part($form['imap_msg_uid'], 'text', false, $msg_struct);
- }
- $struct = $imap->search_bodystructure( $msg_struct, array('imap_part_number' => $part));
- $msg_struct_current = array_shift($struct);
- if (!trim($msg_text)) {
- if (is_array($msg_struct_current) && array_key_exists('subtype', $msg_struct_current)) {
- if ($msg_struct_current['subtype'] == 'plain') {
- $subtype = 'html';
- }
- else {
- $subtype = 'plain';
- }
- list($part, $msg_text) = $imap->get_first_message_part($form['imap_msg_uid'], 'text', $subtype, $msg_struct);
- $struct = $imap->search_bodystructure($msg_struct, array('imap_part_number' => $part));
- $msg_struct_current = array_shift($struct);
- }
- }
- }
- if (isset($msg_struct_current['subtype']) && mb_strtolower($msg_struct_current['subtype'] == 'html')) {
- $msg_text = add_attached_images($msg_text, $form['imap_msg_uid'], $msg_struct, $imap);
- }
- $save_reply_text = false;
- if ($part == 0 || (isset($msg_struct_current['type']) && mb_strtolower($msg_struct_current['type'] == 'text'))) {
- $save_reply_text = true;
- }
- $msg_headers = $imap->get_message_headers($form['imap_msg_uid']);
- $this->out('list_headers', get_list_headers($msg_headers));
- $this->out('msg_headers', $msg_headers);
- $this->out('imap_prefecth', $prefetch);
- $this->out('imap_msg_part', "$part");
- $this->out('use_message_part_icons', $this->user_config->get('msg_part_icons_setting', false));
- $this->out('simple_msg_part_view', $this->user_config->get('simple_msg_parts_setting', DEFAULT_SIMPLE_MSG_PARTS));
- $this->out('allow_delete_attachment', $this->user_config->get('allow_delete_attachment_setting', false));
- if ($msg_struct_current) {
- $this->out('msg_struct_current', $msg_struct_current);
- }
- $this->out('msg_text', $msg_text);
- $download_args = sprintf("page=message&uid=%s&list_path=imap_%s_%s", $form['imap_msg_uid'], $form['imap_server_id'], $form['folder']);
- $this->out('msg_download_args', $download_args.'&imap_download_message=1');
- $this->out('msg_attachment_remove_args', $download_args.'&imap_remove_attachment=1');
- $this->out('msg_show_args', sprintf("page=message&uid=%s&list_path=imap_%s_%s&imap_show_message=1", $form['imap_msg_uid'], $form['imap_server_id'], $form['folder']));
-
- if ($this->get('imap_allow_images', false)) {
- if ($this->module_is_supported('contacts') && $this->user_config->get('contact_auto_collect_setting', false)) {
- $this->out('collect_contacts', true);
- $this->out('collected_contact_email', $msg_headers["Return-Path"]);
- $this->out('collected_contact_name', $msg_headers["From"]);
- }
+ $mailbox->set_read_only($prefetch);
+ }
+ list($msg_struct, $msg_struct_current, $msg_text, $part) = $mailbox->get_structured_message(hex2bin($form['folder']), $form['imap_msg_uid'], $part, $this->user_config->get('text_only_setting', false));
+ $save_reply_text = false;
+ if ($part == 0 || (isset($msg_struct_current['type']) && mb_strtolower($msg_struct_current['type'] == 'text'))) {
+ $save_reply_text = true;
+ }
+ $msg_headers = $mailbox->get_message_headers(hex2bin($form['folder']), $form['imap_msg_uid']);
+ $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $mailbox->get_folder_state()));
+ $this->out('msg_struct', $msg_struct);
+ $this->out('list_headers', get_list_headers($msg_headers));
+ $this->out('msg_headers', $msg_headers);
+ $this->out('imap_prefecth', $prefetch);
+ $this->out('imap_msg_part', "$part");
+ $this->out('use_message_part_icons', $this->user_config->get('msg_part_icons_setting', false));
+ $this->out('simple_msg_part_view', $this->user_config->get('simple_msg_parts_setting', DEFAULT_SIMPLE_MSG_PARTS));
+ $this->out('allow_delete_attachment', $this->user_config->get('allow_delete_attachment_setting', false));
+ if ($msg_struct_current) {
+ $this->out('msg_struct_current', $msg_struct_current);
+ }
+ $this->out('msg_text', $msg_text);
+ $download_args = sprintf("page=message&uid=%s&list_path=imap_%s_%s", $form['imap_msg_uid'], $form['imap_server_id'], $form['folder']);
+ $this->out('msg_download_args', $download_args.'&imap_download_message=1');
+ $this->out('msg_attachment_remove_args', $download_args.'&imap_remove_attachment=1');
+ $this->out('msg_show_args', sprintf("page=message&uid=%s&list_path=imap_%s_%s&imap_show_message=1", $form['imap_msg_uid'], $form['imap_server_id'], $form['folder']));
+
+ if ($this->get('imap_allow_images', false)) {
+ if ($this->module_is_supported('contacts') && $this->user_config->get('contact_auto_collect_setting', false)) {
+ $this->out('collect_contacts', true);
+ $this->out('collected_contact_email', $msg_headers["Return-Path"]);
+ $this->out('collected_contact_name', $msg_headers["From"]);
}
+ }
- if (!$prefetch) {
- clear_existing_reply_details($this->session);
- if ($part == 0) {
- $msg_struct_current['type'] = 'text';
- $msg_struct_current['subtype'] = 'plain';
- }
- $this->session->set(sprintf('reply_details_imap_%s_%s_%s', $form['imap_server_id'], $form['folder'], $form['imap_msg_uid']),
- array('ts' => time(), 'msg_struct' => $msg_struct_current, 'msg_text' => ($save_reply_text ? $msg_text : ''), 'msg_headers' => $msg_headers));
+ if (!$prefetch) {
+ clear_existing_reply_details($this->session);
+ if ($part == 0) {
+ $msg_struct_current['type'] = 'text';
+ $msg_struct_current['subtype'] = 'plain';
}
+ $this->session->set(sprintf('reply_details_imap_%s_%s_%s', $form['imap_server_id'], $form['folder'], $form['imap_msg_uid']),
+ array('ts' => time(), 'msg_struct' => $msg_struct_current, 'msg_text' => ($save_reply_text ? $msg_text : ''), 'msg_headers' => $msg_headers));
}
}
}
@@ -2040,10 +1967,9 @@ public function process() {
$imap_msg_uid = $this->request->get['imap_msg_uid'];
$folder = $this->request->get['imap_folder'];
if ($imap_server_id && $imap_msg_uid && $folder) {
- $cache = Hm_IMAP_List::get_cache($this->cache, $imap_server_id);
- $imap = Hm_IMAP_List::connect($imap_server_id, $cache);
- if ($imap->select_mailbox(hex2bin($folder))) {
- $msg_source = $imap->get_message_content($imap_msg_uid, 0, false);
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($imap_server_id, $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ $msg_source = $mailbox->get_message_content(hex2bin($folder), $imap_msg_uid);
$this->out('msg_source', $msg_source);
}
}
@@ -2082,11 +2008,21 @@ public function process() {
if (isset($this->request->post['imap_delete'])) {
list($success, $form) = $this->process_form(array('imap_server_id'));
if ($success) {
+ $type = imap_server_type($form['imap_server_id']);
+ if (strtolower($type) == 'ews') {
+ $details = Hm_IMAP_List::dump($form['imap_server_id']);
+ foreach (Hm_Profiles::getAll() as $profile) {
+ if ($details['user'] == $profile['user'] && $details['server'] == $profile['server']) {
+ Hm_Profiles::del($profile['id']);
+ Hm_SMTP_List::del($profile['smtp_id']);
+ }
+ }
+ }
$res = Hm_IMAP_List::del($form['imap_server_id']);
if ($res) {
$this->out('deleted_server_id', $form['imap_server_id']);
Hm_Msgs::add('Server deleted');
- $this->session->record_unsaved(sprintf('%s server deleted', imap_server_type($form['imap_server_id'])));
+ $this->session->record_unsaved(sprintf('%s server deleted', $type));
}
}
else {
diff --git a/modules/imap/hm-ews.php b/modules/imap/hm-ews.php
new file mode 100644
index 000000000..9b34fa702
--- /dev/null
+++ b/modules/imap/hm-ews.php
@@ -0,0 +1,1093 @@
+ews = ExchangeWebServices::fromUsernameAndPassword($config['server'], $config['username'], $config['password'], ['version' => ExchangeWebServices::VERSION_2016, 'trace' => 1]);
+ $this->api = new MailAPI($this->ews);
+ $this->api->getFolderByDistinguishedId(Enumeration\DistinguishedFolderIdNameType::INBOX);
+ $this->authed = true;
+ return true;
+ } catch (Exception\UnauthorizedException $e) {
+ return false;
+ }
+ }
+
+ public function authed() {
+ return $this->authed;
+ }
+
+ public function get_capability() {
+ // IMAP extra capabilities not supported here
+ return '';
+ }
+
+ public function get_folders($folder = null, $only_subscribed = false, $unsubscribed_folders = [], $with_input = false) {
+ $result = [];
+ if (empty($folder)) {
+ $folder = new Type\DistinguishedFolderIdType(Enumeration\DistinguishedFolderIdNameType::MESSAGE_ROOT);
+ } else {
+ $folder = new Type\FolderIdType($folder);
+ }
+ $request = array(
+ 'Traversal' => 'Shallow',
+ 'FolderShape' => array(
+ 'BaseShape' => 'AllProperties',
+ ),
+ 'ParentFolderIds' => $folder->toArray(true)
+ );
+ $resp = $this->ews->FindFolder($request);
+ $folders = $resp->get('folders')->get('folder');
+ if ($folders) {
+ $special = $this->get_special_use_folders();
+ if ($folders instanceof Type\FolderType) {
+ $folders = [$folders];
+ }
+ foreach($folders as $folder) {
+ $id = $folder->get('folderId')->get('id');
+ $name = $folder->get('displayName');
+ if ($only_subscribed && in_array($id, $unsubscribed_folders)) {
+ continue;
+ }
+ $result[$id] = array(
+ 'id' => $id,
+ 'parent' => $folder->get('parentFolderId')->get('id'),
+ 'delim' => false,
+ 'name' => $name,
+ 'name_parts' => [],
+ 'basename' => $name,
+ 'realname' => $name,
+ 'namespace' => '',
+ 'marked' => false, // doesn't seem to be used anywhere but imap returns it
+ 'noselect' => false, // all EWS folders are selectable
+ 'can_have_kids' => true,
+ 'has_kids' => $folder->get('childFolderCount') > 0,
+ 'children' => $folder->get('childFolderCount'),
+ 'special' => in_array($id, $special),
+ 'clickable' => ! $with_input && ! in_array($id, $unsubscribed_folders),
+ 'subscribed' => ! in_array($id, $unsubscribed_folders),
+ );
+ }
+ }
+ return $result;
+ }
+
+ public function get_special_use_folders($folder = false) {
+ $special = [
+ 'trash' => Enumeration\DistinguishedFolderIdNameType::DELETED,
+ 'sent' => Enumeration\DistinguishedFolderIdNameType::SENT,
+ 'flagged' => false,
+ 'all' => false,
+ 'junk' => Enumeration\DistinguishedFolderIdNameType::JUNKEMAIL,
+ 'archive' => false,
+ 'drafts' => Enumeration\DistinguishedFolderIdNameType::DRAFTS,
+ ];
+ foreach ($special as $type => $folderId) {
+ if ($folderId) {
+ try {
+ $distinguishedFolder = $this->api->getFolderByDistinguishedId($folderId);
+ if ($distinguishedFolder) {
+ $special[$type] = $distinguishedFolder->get('folderId')->get('id');
+ }
+ } catch (\Exception $e) {
+ Hm_Msgs::add('ERR' . $e->getMessage());
+ }
+ }
+ }
+ $special = array_filter($special);
+ if (isset($special[$folder])) {
+ return [$folder => $special[$folder]];
+ } else {
+ return $special;
+ }
+ }
+
+ public function get_folder_status($folder) {
+ try {
+ if ($this->is_distinguished_folder($folder)) {
+ $folder = new Type\DistinguishedFolderIdType($folder);
+ $result = $this->api->getFolder($folder->toArray(true));
+ } elseif (base64_encode(base64_decode($folder, true)) === $folder) {
+ $folder = new Type\FolderIdType($folder);
+ $result = $this->api->getFolder($folder->toArray(true));
+ } else {
+ $result = $this->api->getFolderByDisplayName($folder, Enumeration\DistinguishedFolderIdNameType::MESSAGE_ROOT);
+ if (! $result) {
+ throw new Exception('Folder not found.');
+ }
+ }
+ return [
+ 'id' => $result->get('folderId')->get('id'),
+ 'name' => $result->get('displayName'),
+ 'messages' => $result->get('totalCount'),
+ 'uidvalidity' => false,
+ 'uidnext' => false,
+ 'recent' => false,
+ 'unseen' => $result->get('unreadCount'),
+ ];
+ } catch (Exception\ExchangeException $e) {
+ // since this is used for missing folders check, we skip error reporting
+ return [];
+ } catch (\Exception $e) {
+ Hm_Msgs::add('ERR' . $e->getMessage());
+ return [];
+ }
+ }
+
+ public function create_folder($folder, $parent = null) {
+ if (empty($parent)) {
+ $parent = new Type\DistinguishedFolderIdType(Enumeration\DistinguishedFolderIdNameType::MESSAGE_ROOT);
+ } else {
+ $parent = new Type\FolderIdType($parent);
+ }
+ try {
+ $request = [
+ 'Folders' => ['Folder' => [
+ 'DisplayName' => $folder
+ ]],
+ 'ParentFolderId' => $parent->toArray(true),
+ ];
+ $result = $this->ews->CreateFolder($request);
+ return $result->get('id');
+ } catch(\Exception $e) {
+ Hm_Msgs::add('ERR' . $e->getMessage());
+ return false;
+ }
+ }
+
+ public function rename_folder($folder, $new_name, $parent = null) {
+ $result = [];
+ if ($this->is_distinguished_folder($folder)) {
+ $folder = new Type\DistinguishedFolderIdType($folder);
+ } else {
+ $folder = new Type\FolderIdType($folder);
+ }
+ $new_folder = new Type\FolderType();
+ $new_folder->displayName = $new_name;
+ $request = [
+ 'FolderChanges' => [
+ 'FolderChange' => [
+ 'FolderId' => $folder->toArray(false),
+ 'Updates' => [
+ 'SetFolderField' => [
+ 'FieldURI' => [
+ 'FieldURI' => 'folder:DisplayName',
+ ],
+ 'Folder' => $new_folder,
+ ],
+ ],
+ ],
+ ],
+ ];
+ try {
+ $request = Type::buildFromArray($request);
+ $this->ews->UpdateFolder($request);
+ } catch (\Exception $e) {
+ Hm_Msgs::add('ERR' . $e->getMessage());
+ return false;
+ }
+ if ($parent) {
+ if ($this->is_distinguished_folder($parent)) {
+ $parent = new Type\DistinguishedFolderIdType($parent);
+ } else {
+ $parent = new Type\FolderIdType($parent);
+ }
+ $request = [
+ 'FolderIds' => Utilities\getFolderIds([$folder]),
+ 'ToFolderId' => $parent->toArray(true),
+ ];
+ try {
+ $request = Type::buildFromArray($request);
+ $this->ews->MoveFolder($request);
+ } catch (\Exception $e) {
+ Hm_Msgs::add('ERR' . $e->getMessage());
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public function delete_folder($folder) {
+ try {
+ return $this->api->deleteFolder(new Type\FolderIdType($folder));
+ } catch(\Exception $e) {
+ Hm_Msgs::add('ERR' . $e->getMessage());
+ return false;
+ }
+ }
+
+ public function send_message($from, $recipients, $message, $delivery_receipt = false) {
+ try {
+ $msg = new Type\MessageType();
+ $msg->setFrom($from);
+ $msg->setToRecipients($recipients);
+ $msg->setMimeContent(base64_encode($message));
+ if ($delivery_receipt) {
+ $msg->setIsDeliveryReceiptRequested($delivery_receipt);
+ }
+ $this->api->sendMail($msg, [
+ 'MessageDisposition' => 'SendOnly', // saving to sent items is handled by the imap module depending on the chosen sent folder
+ ]);
+ return;
+ } catch (\Exception $e) {
+ return $e->getMessage();
+ }
+ }
+
+ public function store_message($folder, $message, $seen = true, $draft = false) {
+ try {
+ if ($this->is_distinguished_folder($folder)) {
+ $folder = new Type\DistinguishedFolderIdType($folder);
+ } else {
+ $folder = new Type\FolderIdType($folder);
+ }
+ $msg = new Type\MessageType();
+ $msg->setMimeContent(base64_encode($message));
+ $flags = 0;
+ if ($seen) {
+ $flags |= self::PID_TAG_MESSAGE_READ;
+ }
+ if ($draft) {
+ $flags |= self::PID_TAG_MESSAGE_DRAFT;
+ }
+ $msg->addExtendedProperty(Type\ExtendedPropertyType::buildFromArray([
+ 'ExtendedFieldURI' => [
+ 'PropertyTag' => self::PID_TAG_MESSAGE_FLAGS,
+ 'PropertyType' => Enumeration\MapiPropertyTypeType::INTEGER,
+ ],
+ 'Value' => $flags,
+ ]));
+ $result = $this->api->sendMail($msg, [
+ 'MessageDisposition' => 'SaveOnly',
+ 'SavedItemFolderId' => $folder->toArray(true),
+ ]);
+ return $result->get('id');
+ } catch (\Exception $e) {
+ Hm_Msgs::add('ERR' . $e->getMessage());
+ return false;
+ }
+ }
+
+ /**
+ * Performs an EWS search using FindItem operation and supplies sorting + pagination arguments.
+ * Search can be perfomed using Advanced Query Syntax when keyword is an array containing terms
+ * searching in specific fields (e.g. advanced search) or Restrictions list when requesting
+ * filtering by extended properties as answered or unanswered emails.
+ */
+ public function search($folder, $sort, $reverse, $flag_filter, $offset, $limit, $keyword, $trusted_senders) {
+ if ($this->is_distinguished_folder(strtolower($folder))) {
+ $folder = new Type\DistinguishedFolderIdType(strtolower($folder));
+ } else {
+ $folder = new Type\FolderIdType($folder);
+ }
+ $request = array(
+ 'Traversal' => 'Shallow',
+ 'ItemShape' => array(
+ 'BaseShape' => 'IdOnly'
+ ),
+ 'IndexedPageItemView' => [
+ 'MaxEntriesReturned' => $limit,
+ 'Offset' => $offset,
+ 'BasePoint' => 'Beginning',
+ ],
+ 'ParentFolderIds' => $folder->toArray(true)
+ );
+ if (! empty($sort)) {
+ switch ($sort) {
+ case 'ARRIVAL':
+ $fieldURI = 'item:DateTimeCreated';
+ break;
+ case 'DATE':
+ $fieldURI = 'item:DateTimeReceived';
+ break;
+ case 'CC':
+ // TODO: figure out a way to sort by something not availalbe in FindItem operation
+ $fieldURI = null;
+ break;
+ case 'TO':
+ // TODO: figure out a way to sort by something not availalbe in FindItem operation
+ $fieldURI = null;
+ break;
+ case 'SUBJECT':
+ $fieldURI = 'item:Subject';
+ break;
+ case 'FROM':
+ $fieldURI = 'message:From';
+ break;
+ case 'SIZE':
+ $fieldURI = 'item:Size';
+ break;
+ default:
+ $fieldURI = null;
+ }
+ if ($fieldURI) {
+ $request['SortOrder'] = [
+ 'FieldOrder' => [
+ 'Order' => $reverse ? 'Descending' : 'Ascending',
+ 'FieldURI' => [
+ 'FieldURI' => $fieldURI,
+ ],
+ ]
+ ];
+ }
+ }
+ $qs = [];
+ if (is_array($keyword)) {
+ foreach ($keyword as $term) {
+ switch ($term[0]) {
+ case 'SINCE':
+ $qs[] = "Received:>$term[1]";
+ break;
+ case 'FROM':
+ $qs[] = "From:($term[1])";
+ break;
+ case 'TO':
+ $qs[] = "To:($term[1])";
+ break;
+ case 'CC':
+ $qs[] = "Cc:($term[1])";
+ break;
+ case 'TEXT':
+ $qs[] = "(Subject:($term[1]) OR Body:($term[1]))";
+ break;
+ case 'BODY':
+ $qs[] = "Body:($term[1])";
+ break;
+ case 'SUBJECT':
+ $qs[] = "Subject:($term[1])";
+ break;
+ default:
+ // noop
+ }
+ }
+ } elseif (! empty($keyword)) {
+ $qs[] = $keyword;
+ }
+ switch ($flag_filter) {
+ case 'UNSEEN':
+ $qs[] = 'isRead:false';
+ break;
+ case 'SEEN':
+ $qs[] = 'isRead:true';
+ break;
+ case 'FLAGGED':
+ $qs[] = 'isFlagged:true';
+ break;
+ case 'UNFLAGGED':
+ $qs[] = 'isFlagged:false';
+ break;
+ case 'ANSWERED':
+ $request['Restriction'] = [
+ 'IsEqualTo' => [
+ 'ExtendedFieldURI' => [
+ 'PropertyTag' => self::PID_TAG_ICON_INDEX,
+ 'PropertyType' => Enumeration\MapiPropertyTypeType::INTEGER,
+ ],
+ 'FieldURIOrConstant' => [
+ 'Constant' => ['Value' => self::PID_TAG_ICON_REPLIED],
+ ],
+ ],
+ ];
+ break;
+ case 'UNANSWERED':
+ $request['Restriction'] = [
+ 'IsNotEqualTo' => [
+ 'ExtendedFieldURI' => [
+ 'PropertyTag' => self::PID_TAG_ICON_INDEX,
+ 'PropertyType' => Enumeration\MapiPropertyTypeType::INTEGER,
+ ],
+ 'FieldURIOrConstant' => [
+ 'Constant' => ['Value' => self::PID_TAG_ICON_REPLIED],
+ ],
+ ],
+ ];
+ break;
+ break;
+ case 'ALL':
+ default:
+ // noop
+ }
+ if ($qs && empty($request['Restriction'])) {
+ $request['QueryString'] = implode(' ', $qs);
+ } elseif ($keyword && ! empty($request['Restriction'])) {
+ $restriction = ['And' => $request['Restriction']];
+ $restriction['And']['Or'] = [
+ [
+ 'Contains' => [
+ 'FieldURI' => ['FieldURI' => 'item:Subject'],
+ 'Constant' => ['Value' => $keyword],
+ ],
+ ],
+ [
+ 'Contains' => [
+ 'FieldURI' => ['FieldURI' => 'item:Body'],
+ 'Constant' => ['Value' => $keyword],
+ ],
+ ],
+ ];
+ $request['Restriction'] = $restriction;
+ }
+ $request = Type::buildFromArray($request);
+ $result = $this->ews->FindItem($request);
+ $messages = $result->get('items')->get('message') ?? [];
+ if ($messages instanceof Type\MessageType) {
+ $messages = [$messages];
+ }
+ $itemIds = array_map(function($msg) {
+ return $msg->get('itemId')->get('id');
+ }, $messages);
+ return [$result->get('totalItemsInView'), $itemIds];
+ }
+
+ public function get_messages($folder, $sort, $reverse, $flag_filter, $offset, $limit, $keyword, $trusted_senders, $include_preview = false) {
+ list ($total, $itemIds) = $this->search($folder, $sort, $reverse, $flag_filter, $offset, $limit, $keyword, $trusted_senders);
+ return [$total, $this->get_message_list($itemIds, $include_preview)];
+ }
+
+ public function get_message_list($itemIds, $include_preview = false) {
+ if (empty($itemIds)) {
+ return [];
+ }
+ $request = array(
+ 'ItemShape' => array(
+ 'BaseShape' => 'AllProperties',
+ 'AdditionalProperties' => [
+ 'ExtendedFieldURI' => [
+ [
+ 'PropertyTag' => self::PID_TAG_FLAG_STATUS, //check flagged msg
+ 'PropertyType' => Enumeration\MapiPropertyTypeType::INTEGER,
+ ],
+ [
+ 'PropertyTag' => self::PID_TAG_ICON_INDEX, // check if replied/answered
+ 'PropertyType' => Enumeration\MapiPropertyTypeType::INTEGER,
+ ],
+ ],
+ ],
+ ),
+ 'ItemIds' => [
+ 'ItemId' => array_map(function($id) {
+ return ['Id' => $id];
+ }, $itemIds),
+ ],
+ );
+ $request = Type::buildFromArray($request);
+ $result = $this->ews->GetItem($request);
+ if ($result instanceof Type\MessageType) {
+ $result = [$result];
+ }
+ $messages = [];
+ foreach ($result as $message) {
+ $flags = $this->extract_flags($message);
+ $uid = bin2hex($message->get('itemId')->get('id'));
+ $msg = [
+ 'uid' => $uid,
+ 'flags' => implode(' ', $flags),
+ 'internal_date' => $message->get('dateTimeCreated'),
+ 'size' => $message->get('size'),
+ 'date' => $message->get('dateTimeReceived'),
+ 'from' => $this->extract_mailbox($message->get('from')),
+ 'to' => $this->extract_mailbox($message->get('toRecipients')),
+ 'subject' => $message->get('subject'),
+ 'content-type' => null,
+ 'timestamp' => time(),
+ 'charset' => null,
+ 'x-priority' => null,
+ 'google_msg_id' => null,
+ 'google_thread_id' => null,
+ 'google_labels' => null,
+ 'list_archive' => null,
+ 'references' => $message->get('references'),
+ 'message_id' => $message->get('internetMessageId'),
+ 'x_auto_bcc' => null,
+ 'x_snoozed' => null,
+ ];
+ foreach ($message->get('internetMessageHeaders')->InternetMessageHeader as $header) {
+ foreach (['x-gm-msgid' => 'google_msg_id', 'x-gm-thrid' => 'google_thread_id', 'x-gm-labels' => 'google_labels', 'x-auto-bcc' => 'x_auto_bcc', 'message-id' => 'message_id', 'references' => 'references', 'x-snoozed' => 'x_snoozed', 'list-archive' => 'list_archive', 'content-type' => 'content-type', 'x-priority' => 'x-priority'] as $hname => $key) {
+ if (strtolower($header->get('headerName')) == $hname) {
+ $msg[$key] = (string) $header;
+ }
+ }
+ }
+ $cset = '';
+ if (mb_stristr($msg['content-type'], 'charset=')) {
+ if (preg_match("/charset\=([^\s;]+)/", $msg['content-type'], $matches)) {
+ $cset = trim(mb_strtolower(str_replace(array('"', "'"), '', $matches[1])));
+ }
+ }
+ $msg['charset'] = $cset;
+ $msg['preview_msg'] = $include_preview ? strip_tags($message->get('body')) : "";
+ $messages[$uid] = $msg;
+ }
+ return $messages;
+ }
+
+ public function message_action($action, $itemIds, $folder=false, $keyword=false) {
+ if (empty($itemIds)) {
+ return ['status' => true, 'responses' => []];
+ }
+ if (! is_array($itemIds)) {
+ $itemIds = [$itemIds];
+ }
+ $change = null;
+ $status = false;
+ $responses = [];
+ switch ($action) {
+ case 'ARCHIVE':
+ $status = $this->archive_items($itemIds);
+ break;
+ case 'DELETE':
+ $status = $this->delete_items($itemIds);
+ break;
+ case 'HARDDELETE':
+ $status = $this->delete_items($itemIds, true);
+ break;
+ case 'COPY':
+ $newIds = $this->copy_items($itemIds, $folder);
+ if ($newIds) {
+ foreach ($newIds as $key => $newId) {
+ $responses[] = ['oldUid' => $itemIds[$key], 'newUid' => $newId];
+ }
+ $status = true;
+ }
+ break;
+ case 'MOVE':
+ $newIds = $this->move_items($itemIds, $folder);
+ if ($newIds) {
+ foreach ($newIds as $key => $newId) {
+ $responses[] = ['oldUid' => $itemIds[$key], 'newUid' => $newId];
+ }
+ $status = true;
+ }
+ break;
+ case 'READ':
+ $change = ItemUpdateBuilder::buildUpdateItemChanges('Message', 'message', ['IsRead' => true]);
+ break;
+ case 'UNREAD':
+ $change = ItemUpdateBuilder::buildUpdateItemChanges('Message', 'message', ['IsRead' => false]);
+ break;
+ case 'FLAG':
+ $change = [
+ 'SetItemField' => [
+ 'ExtendedFieldURI' => [
+ 'PropertyTag' => self::PID_TAG_FLAG_STATUS,
+ 'PropertyType' => Enumeration\MapiPropertyTypeType::INTEGER,
+ ],
+ 'Message' => [
+ 'ExtendedProperty' => [
+ 'ExtendedFieldURI' => [
+ 'PropertyTag' => self::PID_TAG_FLAG_STATUS,
+ 'PropertyType' => Enumeration\MapiPropertyTypeType::INTEGER,
+ ],
+ 'Value' => self::PID_TAG_FLAG_FLAGGED,
+ ],
+ ],
+ ],
+ ];
+ break;
+ case 'UNFLAG':
+ $change = [
+ 'DeleteItemField' => [
+ 'ExtendedFieldURI' => [
+ 'PropertyTag' => self::PID_TAG_FLAG_STATUS,
+ 'PropertyType' => Enumeration\MapiPropertyTypeType::INTEGER,
+ ],
+ ],
+ ];
+ break;
+ case 'ANSWERED':
+ case 'UNDELETE':
+ case 'CUSTOM':
+ // TODO: unsupported out of the box, we can emulate via custom extended properties
+ $change = null;
+ $status = true;
+ break;
+ case 'EXPUNGE':
+ // not needed for EWS
+ return ['status' => true, 'responses' => $responses];
+ default:
+ $change = null;
+ }
+
+ if ($change) {
+ $changes = ['ItemChange' => []];
+ foreach ($itemIds as $itemId) {
+ $changes['ItemChange'][] = [
+ 'ItemId' => (new Type\ItemIdType(hex2bin($itemId)))->toArray(),
+ 'Updates' => $change,
+ ];
+ }
+ $status = $this->api->updateItems($changes);
+ }
+
+ return ['status' => $status, 'responses' => $responses];
+ }
+
+ public function get_message_headers($itemId) {
+ $request = array(
+ 'ItemShape' => array(
+ 'BaseShape' => 'AllProperties',
+ 'AdditionalProperties' => [
+ 'ExtendedFieldURI' => [
+ [
+ 'PropertyTag' => self::PID_TAG_FLAG_STATUS, //check flagged msg
+ 'PropertyType' => Enumeration\MapiPropertyTypeType::INTEGER,
+ ],
+ [
+ 'PropertyTag' => self::PID_TAG_ICON_INDEX, // check if replied/answered
+ 'PropertyType' => Enumeration\MapiPropertyTypeType::INTEGER,
+ ],
+ ],
+ ],
+ ),
+ 'ItemIds' => [
+ 'ItemId' => ['Id' => hex2bin($itemId)],
+ ],
+ );
+ $request = Type::buildFromArray($request);
+ $message = $this->ews->GetItem($request);
+ $sender = $message->get('sender');
+ $from = $message->get('from');
+ $headers = [];
+ $headers['Arrival Date'] = $message->get('dateTimeCreated');
+ if ($sender && $from) {
+ $headers['From'] = $message->get('sender')->get('mailbox')->get('name') . ' <' . $message->get('from')->get('mailbox')->get('emailAddress') . '>';
+ } elseif ($sender) {
+ $headers['From'] = $this->extract_mailbox($sender);
+ } elseif ($from) {
+ $headers['From'] = $this->extract_mailbox($from);
+ } else {
+ $headers['From'] = null;
+ }
+ $headers['To'] = $this->extract_mailbox($message->get('toRecipients'));
+ if ($message->get('ccRecipients')) {
+ $headers['Cc'] = $this->extract_mailbox($message->get('ccRecipients'));
+ }
+ if ($message->get('bccRecipients')) {
+ $headers['Bcc'] = $this->extract_mailbox($message->get('bccRecipients'));
+ }
+ $headers['Flags'] = implode(' ', $this->extract_flags($message));
+ foreach ($message->get('internetMessageHeaders')->InternetMessageHeader as $header) {
+ $name = $header->get('headerName');
+ if (isset($headers[$name])) {
+ if (! is_array($headers[$name])) {
+ $headers[$name] = [$headers[$name]];
+ }
+ $headers[$name][] = (string) $header;
+ } else {
+ $headers[$name] = (string) $header;
+ }
+ }
+ if (! $message->isRead()) {
+ $this->api->updateMailItem($message->getItemId(), [
+ 'IsRead' => true,
+ ]);
+ }
+ return $headers;
+ }
+
+ public function get_message_content($itemId, $part) {
+ if ($part) {
+ list($msg_struct, $msg_struct_current, $msg_text, $part) = $this->get_structured_message($itemId, $part, false);
+ return $msg_text;
+ } else {
+ $message = $this->get_mime_message_by_id($itemId);
+ $content = (string) $message;
+ return $content;
+ }
+ }
+
+ public function stream_message_part($itemId, $part, $start_cb) {
+ if ($part !== '0' && $part) {
+ // imap handler modules strip this prefix
+ $part = '0.' . $part;
+ }
+ list($msg_struct, $part_struct, $msg_text, $part) = $this->get_structured_message($itemId, $part, false);
+ $charset = '';
+ if (! empty($part_struct['attributes']['charset'])) {
+ $charset = '; charset=' . $part_struct['attributes']['charset'];
+ }
+ $part_name = get_imap_part_name($part_struct, $itemId, $part);
+ $start_cb($part_struct['type'] . '/' . $part_struct['subtype'] . $charset, $part_name);
+ if (! $charset) {
+ $charset = 'UTF-8';
+ } else {
+ $charset = $part_struct['attributes']['charset'];
+ }
+ $stream = $part_struct['mime_object']->getContentStream($charset);
+ if ($stream) {
+ while (! $stream->eof()) {
+ echo $stream->read(1024);
+ }
+ }
+ }
+
+ public function get_structured_message($itemId, $part, $text_only) {
+ $message = $this->get_mime_message_by_id($itemId);
+ $msg_struct = [];
+ $this->parse_mime_part($message, $msg_struct, 0);
+ if ($part !== false) {
+ $struct = $this->search_mime_part_in_struct($msg_struct, ['part_id' => $part], true);
+ } else {
+ $struct = null;
+ if (! $text_only) {
+ $struct = $this->search_mime_part_in_struct($msg_struct, ['type' => 'text', 'subtype' => 'html']);
+ }
+ if (! $struct) {
+ $struct = $this->search_mime_part_in_struct($msg_struct, ['type' => 'text']);
+ }
+ }
+ if ($struct) {
+ $part = array_key_first($struct);
+ $msg_struct_current = $struct[$part];
+ $msg_text = $msg_struct_current['mime_object']->getContent();
+ } else {
+ $part = false;
+ $msg_struct_current = null;
+ $msg_text = '';
+ }
+ if (isset($msg_struct_current['subtype']) && mb_strtolower($msg_struct_current['subtype'] == 'html')) {
+ // add inline images
+ if (preg_match_all("/src=('|\"|)cid:([^\s'\"]+)/", $msg_text, $matches)) {
+ $cids = array_pop($matches);
+ foreach ($cids as $id) {
+ $struct = $this->search_mime_part_in_struct($msg_struct, ['id' => $id, 'type' => 'image']);
+ if ($struct) {
+ $struct = array_shift($struct);
+ $msg_text = str_replace('cid:'.$id, 'data:image/'.$struct['subtype'].';base64,'.base64_encode($struct['mime_object']->getContent()), $msg_text);
+ }
+ }
+ }
+ }
+ return [$msg_struct, $msg_struct_current, $msg_text, $part];
+ }
+
+ public function get_mime_message_by_id($itemId) {
+ $request = array(
+ 'ItemShape' => array(
+ 'BaseShape' => 'IdOnly',
+ 'IncludeMimeContent' => true,
+ ),
+ 'ItemIds' => [
+ 'ItemId' => ['Id' => hex2bin($itemId)],
+ ],
+ );
+ $request = Type::buildFromArray($request);
+ $message = $this->ews->GetItem($request);
+ $mime = $message->get('mimeContent');
+ $content = base64_decode($mime);
+ if (strtoupper($mime->get('characterSet')) != 'UTF-8') {
+ $content = mb_convert_encoding($content, 'UTF-8', $mime->get('characterSet'));
+ }
+ $parser = new MailMimeParser();
+ return $parser->parse($content, false);
+ }
+
+ protected function parse_mime_part($part, &$struct, $part_num) {
+ $struct[$part_num] = [];
+ list($struct[$part_num]['type'], $struct[$part_num]['subtype']) = explode('/', $part->getContentType());
+ if ($part->isMultiPart()) {
+ $boundary = $part->getHeaderParameter('Content-Type', 'boundary');
+ if ($boundary) {
+ $struct[$part_num]['attributes'] = ['boundary' => $boundary];
+ }
+ $struct[$part_num]['disposition'] = $part->getContentDisposition();
+ $struct[$part_num]['language'] = '';
+ $struct[$part_num]['location'] = '';
+ } else {
+ $content = $part->getContent();
+ $charset = $part->getCharset();
+ if ($charset) {
+ $struct[$part_num]['attributes'] = ['charset' => $charset];
+ }
+ $struct[$part_num]['id'] = $part->getContentId();
+ $struct[$part_num]['description'] = $part->getHeaderValue('Content-Description');
+ $struct[$part_num]['encoding'] = $part->getContentTransferEncoding();
+ $struct[$part_num]['size'] = strlen($content);
+ $struct[$part_num]['lines'] = substr_count($content, "\n");
+ $struct[$part_num]['md5'] = '';
+ $struct[$part_num]['disposition'] = $part->getContentDisposition();
+ if ($filename = $part->getFilename()) {
+ $struct[$part_num]['file_attributes'] = ['filename' => $filename];
+ if ($part->getContentDisposition() == 'attachment') {
+ $struct[$part_num]['file_attributes']['attachment'] = true;
+ }
+ } else {
+ $struct[$part_num]['file_attributes'] = '';
+ }
+ $struct[$part_num]['language'] = '';
+ $struct[$part_num]['location'] = '';
+ }
+ $struct[$part_num]['mime_object'] = $part;
+ if ($part->getChildCount() > 0) {
+ $struct[$part_num]['subs'] = [];
+ foreach ($part->getChildParts() as $i => $child) {
+ $this->parse_mime_part($child, $struct[$part_num]['subs'], $part_num . '.' . ($i+1));
+ }
+ }
+ }
+
+ protected function search_mime_part_in_struct($struct, $conditions, $all = false) {
+ $found = [];
+ foreach ($struct as $part_id => $sub) {
+ $matches = 0;
+ if (isset($conditions['part_id']) && $part_id == $conditions['part_id']) {
+ $matches++;
+ }
+ foreach ($conditions as $name => $value) {
+ if (isset($sub[$name]) && mb_stristr($sub[$name], $value)) {
+ $matches++;
+ }
+ }
+ if ($matches === count($conditions)) {
+ $part = $sub;
+ if (isset($part['subs'])) {
+ $part['subs'] = count($part['subs']);
+ }
+ $found[$part_id] = $part;
+ if (! $all) {
+ break;
+ }
+ }
+ if (isset($sub['subs'])) {
+ $found = array_merge($found, $this->search_mime_part_in_struct($sub['subs'], $conditions, $all));
+ }
+ if (! $all && $found) {
+ break;
+ }
+ }
+ return $found;
+ }
+
+ protected function extract_mailbox($data) {
+ if (is_array($data)) {
+ $result = [];
+ foreach ($data as $mailbox) {
+ $result[] = $this->extract_mailbox($mailbox);
+ }
+ return $result;
+ } elseif (is_object($data) && $data->Mailbox) {
+ return $data->Mailbox->get('name') . ' <' . $data->Mailbox->get('emailAddress') . '>';
+ } elseif (is_object($data) && $data->get('mailbox')) {
+ return $data->get('mailbox')->get('name') . ' <' . $data->get('mailbox')->get('emailAddress') . '>';
+ } else {
+ return (string) $data;
+ }
+ }
+
+ protected function extract_flags($message) {
+ // note about flags: EWS - doesn't support the \Deleted flag
+ $flags = [];
+ if ($message->get('isRead')) {
+ $flags[] = '\\Seen';
+ }
+ if ($message->get('isDraft')) {
+ $flags[] = '\\Draft';
+ }
+ if ($extended_properties = $message->get('extendedProperty')) {
+ if ($extended_properties instanceof Type\ExtendedPropertyType) {
+ $extended_properties = [$extended_properties];
+ }
+ foreach ($extended_properties as $prop) {
+ if (hexdec($prop->get('extendedFieldURI')->get('propertyTag')) == self::PID_TAG_FLAG_STATUS && $prop->get('value') > 0) {
+ $flags[] = '\\Flagged';
+ }
+ if (hexdec($prop->get('extendedFieldURI')->get('propertyTag')) == self::PID_TAG_ICON_INDEX && $prop->get('value') == self::PID_TAG_ICON_REPLIED) {
+ $flags[] = '\\Answered';
+ }
+ }
+ }
+ return $flags;
+ }
+
+ protected function is_distinguished_folder($folder) {
+ $oClass = new ReflectionClass(new Enumeration\DistinguishedFolderIdNameType());
+ $constants = $oClass->getConstants();
+ return in_array($folder, $constants);
+ }
+
+ protected function archive_items($itemIds) {
+ $result = true;
+ $folders = $this->get_parent_folders_of_items($itemIds);
+ foreach ($folders as $folder => $itemIds) {
+ if ($this->is_distinguished_folder($folder)) {
+ $folder = new Type\DistinguishedFolderIdType($folder);
+ } else {
+ $folder = new Type\FolderIdType($folder);
+ }
+ $request = [
+ 'ArchiveSourceFolderId' => $folder->toArray(true),
+ 'ItemIds' => [
+ 'ItemId' => $itemIds = array_map(function($itemId) {
+ return (new Type\ItemIdType($itemId))->toArray();
+ }, $itemIds),
+ ]
+ ];
+ $request = Type::buildFromArray($request);
+ try {
+ $result = $result && $this->ews->ArchiveItem($request);
+ } catch (\Exception $e) {
+ Hm_Msgs::add('ERR' . $e->getMessage());
+ $result = false;
+ }
+ }
+ return $result;
+ }
+
+ protected function delete_items($itemIds, $hard = false) {
+ $result = true;
+ try {
+ if ($hard) {
+ $result = $this->api->deleteItems(array_map(function($itemId) {
+ return (new Type\ItemIdType(hex2bin($itemId)))->toArray();
+ }, $itemIds), [
+ 'DeleteType' => 'HardDelete',
+ ]);
+ } else {
+ $trash = $this->api->getFolderByDistinguishedId(Type\DistinguishedFolderIdNameType::DELETED);
+ $folders = $this->get_parent_folders_of_items($itemIds);
+ foreach ($folders as $folder => $itemIds) {
+ if ($trash && $folder == $trash->get('folderId')->get('id')) {
+ $options = ['DeleteType' => 'HardDelete'];
+ } else {
+ $options = [];
+ }
+ $result = $result && $this->api->deleteItems($itemIds, $options);
+ }
+ }
+ } catch (\Exception $e) {
+ Hm_Msgs::add('ERR' . $e->getMessage());
+ $result = false;
+ }
+ return $result;
+ }
+
+ protected function copy_items($itemIds, $folder) {
+ if ($this->is_distinguished_folder($folder)) {
+ $folder = new Type\DistinguishedFolderIdType($folder);
+ } else {
+ $folder = new Type\FolderIdType($folder);
+ }
+ $request = [
+ 'ToFolderId' => $folder->toArray(true),
+ 'ItemIds' => [
+ 'ItemId' => array_map(function($itemId) {
+ return (new Type\ItemIdType(hex2bin($itemId)))->toArray();
+ }, $itemIds),
+ ]
+ ];
+ $request = Type::buildFromArray($request);
+ try {
+ $result = $this->ews->CopyItem($request);
+ if (! is_array($result)) {
+ $result = [$result];
+ }
+ $result = array_map(function($itemId) {
+ return $itemId->get('id');
+ }, $result);
+ } catch (\Exception $e) {
+ Hm_Msgs::add('ERR' . $e->getMessage());
+ $result = [];
+ }
+ return $result;
+ }
+
+ protected function move_items($itemIds, $folder) {
+ if ($this->is_distinguished_folder($folder)) {
+ $folder = new Type\DistinguishedFolderIdType($folder);
+ } else {
+ $folder = new Type\FolderIdType($folder);
+ }
+ $request = [
+ 'ToFolderId' => $folder->toArray(true),
+ 'ItemIds' => [
+ 'ItemId' => array_map(function($itemId) {
+ return (new Type\ItemIdType(hex2bin($itemId)))->toArray();
+ }, $itemIds),
+ ],
+ 'ReturnNewItemIds' => false,
+ ];
+ $request = Type::buildFromArray($request);
+ try {
+ $result = $this->ews->MoveItem($request);
+ if (! is_array($result)) {
+ $result = [$result];
+ }
+ $result = array_map(function($itemId) {
+ return $itemId->get('id');
+ }, $result);
+ } catch (\Exception $e) {
+ Hm_Msgs::add('ERR' . $e->getMessage());
+ $result = [];
+ }
+ return $result;
+ }
+
+ protected function get_parent_folders_of_items($itemIds) {
+ $itemIds = array_map(function($itemId) {
+ return (new Type\ItemIdType(hex2bin($itemId)))->toArray();
+ }, $itemIds);
+ $folders = null;
+ $request = [
+ 'ItemShape' => [
+ 'BaseShape' => 'IdOnly',
+ 'AdditionalProperties' => [
+ 'FieldURI' => ['FieldURI' => 'item:ParentFolderId'],
+ ],
+ ],
+ 'ItemIds' => [
+ 'ItemId' => $itemIds,
+ ],
+ ];
+ $request = Type::buildFromArray($request);
+ $result = $this->ews->GetItem($request);
+ if ($result instanceof Type\MessageType) {
+ $result = [$result];
+ }
+ foreach ($result as $message) {
+ $folder = $message->get('ParentFolderId')->get('id');
+ if (! isset($folders[$folder])) {
+ $folders[$folder] = [];
+ }
+ $folders[$folder][] = $message->getItemId();
+ }
+ return $folders;
+ }
+}
diff --git a/modules/imap/hm-imap.php b/modules/imap/hm-imap.php
index 645082fd7..3e8759c32 100644
--- a/modules/imap/hm-imap.php
+++ b/modules/imap/hm-imap.php
@@ -11,6 +11,7 @@
require_once('hm-imap-cache.php');
require_once('hm-imap-bodystructure.php');
require_once('hm-jmap.php');
+require_once('hm-ews.php');
/**
* IMAP connection manager
@@ -21,18 +22,17 @@ class Hm_IMAP_List {
use Hm_Server_List;
public static $use_cache = true;
+ protected static $user_config;
+ protected static $session;
public static function init($user_config, $session) {
self::initRepo('imap_servers', $user_config, $session, self::$server_list);
+ self::$user_config = $user_config;
+ self::$session = $session;
}
public static function service_connect($id, $server, $user, $pass, $cache=false) {
- if (array_key_exists('type', $server) && $server['type'] == 'jmap') {
- self::$server_list[$id]['object'] = new Hm_JMAP();
- }
- else {
- self::$server_list[$id]['object'] = new Hm_IMAP();
- }
+ self::$server_list[$id]['object'] = new Hm_Mailbox($id, self::$user_config, self::$session);
if (self::$use_cache && $cache && is_array($cache)) {
self::$server_list[$id]['object']->load_cache($cache, 'array');
}
@@ -58,6 +58,15 @@ public static function get_cache($hm_cache, $id) {
$res = $hm_cache->get('imap'.$id);
return $res;
}
+
+ public static function get_connected_mailbox($id, $hm_cache = null) {
+ if ($hm_cache) {
+ $cache = self::get_cache($hm_cache, $id);
+ } else {
+ $cache = false;
+ }
+ return self::connect($id, $cache);
+ }
}
/* for testing */
@@ -827,6 +836,7 @@ public function get_mailbox_status($mailbox, $args=array('UNSEEN', 'UIDVALIDITY'
if ($this->check_response($response, true)) {
$attributes = $this->parse_status_response($response);
$this->check_mailbox_state_change($attributes);
+ $attributes['id'] = $mailbox;
}
return $attributes;
}
diff --git a/modules/imap/output_modules.php b/modules/imap/output_modules.php
index c09551330..c72420fc6 100644
--- a/modules/imap/output_modules.php
+++ b/modules/imap/output_modules.php
@@ -185,7 +185,7 @@ protected function output() {
if ($this->get('msg_headers')) {
$txt = '';
$small_headers = array('subject', 'x-snoozed', 'date', 'from', 'to', 'reply-to', 'cc', 'flags');
- $reply_args = sprintf('&list_path=%s&uid=%d',
+ $reply_args = sprintf('&list_path=%s&uid=%s',
$this->html_safe($this->get('msg_list_path')),
$this->html_safe($this->get('msg_text_uid'))
);
@@ -458,6 +458,10 @@ protected function output() {
$type = 'JMAP';
}
+ if (array_key_exists('type', $vals) && $vals['type'] == 'ews') {
+ continue;
+ }
+
if (array_key_exists('user', $vals) && !array_key_exists('nopass', $vals)) {
$disabled = 'disabled="disabled"';
$user_pc = $vals['user'];
@@ -725,7 +729,7 @@ class Hm_Output_display_imap_status extends Hm_Output_Module {
protected function output() {
$res = '';
foreach ($this->get('imap_servers', array()) as $index => $vals) {
- $res .= 'IMAP | '.$vals['name'].' | | '.
+ $res .= '
'.(strtoupper($vals['type'] ?? 'IMAP')).' | '.$vals['name'].' | | '.
' |
';
}
return $res;
@@ -1449,6 +1453,166 @@ protected function output() {
}
}
+class Hm_Output_server_config_ews extends Hm_Output_Module {
+ protected function output() {
+ $hasEWSActivated = in_array('imap', $this->get('router_module_list'), true);
+
+ if(! $hasEWSActivated){
+ return '';
+ }
+
+ $ews_servers_count = count(array_filter($this->get('imap_servers', array()), function($v) { return array_key_exists('type', $v) && $v['type'] == 'ews'; }));
+
+ $res = '
+
+
+
+
';
+
+ $list = $this->get('imap_servers', array());
+ foreach ($list as $index => $vals) {
+ if (! array_key_exists('type', $vals) || $vals['type'] != 'ews') {
+ continue;
+ }
+
+ $server_id = $vals['id'];
+
+ if (array_key_exists('user', $vals) && !array_key_exists('nopass', $vals)) {
+ $disabled = 'disabled="disabled"';
+ $user_pc = $vals['user'];
+ $pass_pc = $this->trans('[saved]');
+ $pass_value = '*************';
+ }
+ elseif (array_key_exists('nopass', $vals)) {
+ if (array_key_exists('user', $vals)) {
+ $user_pc = $vals['user'];
+ }
+ else {
+ $user_pc = '';
+ }
+ $pass_pc = $this->trans('Password');
+ $disabled = '';
+ $pass_value = '';
+ }
+ else {
+ $user_pc = '';
+ $pass_pc = $this->trans('Password');
+ $disabled = '';
+ $pass_value = '';
+ }
+ $res .= '
';
+ }
+
+ $res .= '
+
+
';
+
+ return $res;
+ }
+}
+
/**
* Option to set the per page count for IMAP folder views
* @subpackage imap/output
diff --git a/modules/imap/setup.php b/modules/imap/setup.php
index 0aab24b11..4a75d5985 100644
--- a/modules/imap/setup.php
+++ b/modules/imap/setup.php
@@ -19,15 +19,19 @@
add_output('info', 'imap_server_ids', true, 'imap', 'page_js', 'before');
/* servers page data */
+add_handler('servers', 'profile_data', true, 'profiles', 'load_user_data', 'after');
+add_handler('servers', 'compose_profile_data', true, 'profiles', 'profile_data', 'after');
add_handler('servers', 'process_add_imap_server', true, 'imap', 'message_list_type', 'after');
add_handler('servers', 'process_add_jmap_server', true, 'imap', 'process_add_imap_server', 'after');
add_handler('servers', 'save_imap_servers', true, 'imap', 'process_add_jmap_server', 'after');
+add_handler('servers', 'save_ews_server', true, 'imap', 'save_imap_servers', 'after');
add_output('servers', 'display_configured_imap_servers', true, 'imap', 'server_config_stepper_accordion_end_part', 'before');
add_output('servers', 'imap_server_ids', true, 'imap', 'page_js', 'before');
add_output('servers', 'stepper_setup_server_jmap', true, 'imap', 'server_config_stepper_end_part', 'before');
add_output('servers', 'stepper_setup_server_imap', true, 'imap', 'server_config_stepper_end_part', 'before');
add_output('servers', 'stepper_setup_server_jmap_imap_common', true, 'imap', 'server_config_stepper_end_part', 'before');
+add_output('servers', 'server_config_ews', true, 'imap', 'server_config_stepper_accordion_end_part', 'after');
/* settings page data */
add_handler('settings', 'process_sent_since_setting', true, 'imap', 'date', 'after');
@@ -118,6 +122,10 @@
/* ajax server setup callback data */
setup_base_ajax_page('ajax_imap_debug', 'core');
+add_handler('ajax_imap_debug', 'profile_data', true, 'profiles', 'load_user_data', 'after');
+add_handler('ajax_imap_debug', 'compose_profile_data', true, 'profiles', 'profile_data', 'after');
+add_handler('ajax_imap_debug', 'profile_data', true, 'smtp', 'compose_profile_data', 'after');
+add_handler('ajax_imap_debug', 'load_smtp_servers_from_config', true, 'smtp', 'profile_data', 'after');
add_handler('ajax_imap_debug', 'load_imap_servers_from_config', true);
add_handler('ajax_imap_debug', 'imap_oauth2_token_check', true);
add_handler('ajax_imap_debug', 'imap_hide', true);
@@ -442,6 +450,16 @@
'tag_id' => FILTER_DEFAULT,
'first_time_screen_emails' => FILTER_VALIDATE_INT,
'move_messages_in_screen_email' => FILTER_VALIDATE_BOOLEAN,
+ 'ews_server_id' => FILTER_DEFAULT,
+ 'ews_profile_name' => FILTER_DEFAULT,
+ 'ews_email' => FILTER_DEFAULT,
+ 'ews_password' => FILTER_UNSAFE_RAW,
+ 'ews_server' => FILTER_DEFAULT,
+ 'ews_hide_from_c_page' => FILTER_VALIDATE_INT,
+ 'ews_create_profile' => FILTER_VALIDATE_INT,
+ 'ews_profile_is_default' => FILTER_VALIDATE_INT,
+ 'ews_profile_signature' => FILTER_DEFAULT,
+ 'ews_profile_reply_to' => FILTER_DEFAULT,
'imap_folder_uid' => FILTER_DEFAULT,
'imap_folder' => FILTER_DEFAULT,
'identifier' => FILTER_DEFAULT,
diff --git a/modules/imap/site.js b/modules/imap/site.js
index 4dbfb7817..c751439a6 100644
--- a/modules/imap/site.js
+++ b/modules/imap/site.js
@@ -75,6 +75,7 @@ var imapServersPageHandler = function() {
$('.hide_imap_connection').on('click', imap_hide);
$('.unhide_imap_connection').on('click', imap_unhide);
$('.test_imap_connect').on('click', imap_test_action);
+ $('.edit_ews_server_connection').on('click', ews_edit_action);
var dsp = Hm_Utils.get_from_local_storage('.imap_section');
if (dsp === 'block' || dsp === 'none') {
@@ -84,6 +85,26 @@ var imapServersPageHandler = function() {
if (jdsp === 'block' || jdsp === 'none') {
$('.jmap_section').css('display', jdsp);
}
+
+ $('.ews-btn').on('click', function() {
+ $(this).hide().prev().removeClass('d-none');
+ });
+};
+
+var ews_edit_action = function(event) {
+ event.preventDefault();
+ Hm_Notices.hide(true);
+ var details = $(this).data('server-details');
+
+ $('.ews-btn').trigger('click');
+ $('#ews_profile_name').val(details.name).trigger('focus');
+ $('#ews_email').val(details.user);
+ $('#ews_password').val('');
+ $('#ews_profile_reply_to').val('');
+ $('#ews_create_profile').trigger("click", true);
+ $('#ews_server').val(details.server);
+ $('#ews_server_id').val(details.id);
+ $('#ews_hide_from_c_page').prop("checked", details.hide);
};
var set_message_content = function(path, msg_uid) {
diff --git a/modules/imap_folders/modules.php b/modules/imap_folders/modules.php
index 4e926b7d4..7daa5f982 100644
--- a/modules/imap_folders/modules.php
+++ b/modules/imap_folders/modules.php
@@ -98,15 +98,13 @@ public function process() {
if (!$success || !in_array($form['special_folder_type'], array('sent', 'draft', 'trash', 'archive', 'junk'), true)) {
return;
}
- $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);
- $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache);
-
- if (!is_object($imap) || $imap->get_state() != 'authenticated') {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $this->cache);
+ if (!is_object($mailbox) || ! $mailbox->authed()) {
Hm_Msgs::add('ERRUnable to connect to the selected IMAP server');
return;
}
- $new_folder = prep_folder_name($imap, $form['folder'], true);
- if (!$new_folder || !$imap->select_mailbox($new_folder)) {
+ $new_folder = $mailbox->prep_folder_name($form['folder']);
+ if (! $new_folder || ! $mailbox->get_folder_status($new_folder)) {
Hm_Msgs::add('ERRSelected folder not found');
return;
}
@@ -132,15 +130,13 @@ public function process() {
list($success, $form) = $this->process_form(array('imap_server_id', 'imap_service_name'));
if ($success) {
- $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);
- $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache);
-
- if (!is_object($imap) || $imap->get_state() != 'authenticated') {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $this->cache);
+ if (!is_object($mailbox) || ! $mailbox->authed()) {
Hm_Msgs::add('ERRUnable to connect to the selected IMAP server');
return;
}
$specials = $this->user_config->get('special_imap_folders', array());
- $exposed = $imap->get_special_use_mailboxes();
+ $exposed = $mailbox->get_special_use_mailboxes();
if ($form['imap_service_name'] == 'gandi') {
$specials[$form['imap_server_id']] = array(
'sent' => 'Sent',
@@ -178,15 +174,12 @@ public function process() {
list($success, $form) = $this->process_form(array('folder', 'imap_server_id'));
if ($success) {
$parent = false;
- $parent_str = false;
if (array_key_exists('parent', $this->request->post) && trim($this->request->post['parent'])) {
- $parent_str = decode_folder_str($this->request->post['parent']);
+ $parent = decode_folder_str($this->request->post['parent']);
}
- $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);
- $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache);
- if (is_object($imap) && $imap->get_state() == 'authenticated') {
- $new_folder = prep_folder_name($imap, $form['folder'], false, $parent_str);
- if ($new_folder && $imap->create_mailbox($new_folder)) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ if ($form['folder'] && $mailbox->create_folder($form['folder'], $parent)) {
Hm_Msgs::add('Folder created');
$this->cache->del('imap_folders_imap_'.$form['imap_server_id'].'_');
$this->out('imap_folders_success', true);
@@ -206,17 +199,14 @@ class Hm_Handler_process_folder_rename extends Hm_Handler_Module {
public function process() {
list($success, $form) = $this->process_form(array('imap_server_id', 'folder', 'new_folder'));
if ($success) {
- $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);
- $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache);
- $parent_str = false;
+ $parent = false;
if (array_key_exists('parent', $this->request->post)) {
- $parent_str = $this->request->post['parent'];
+ $parent = $this->request->post['parent'];
}
- if (is_object($imap) && $imap->get_state() == 'authenticated') {
- $old_folder = prep_folder_name($imap, $form['folder'], true);
- $new_folder = prep_folder_name($imap, $form['new_folder'], false, $parent_str);
- if ($new_folder && $old_folder && $imap->rename_mailbox($old_folder, $new_folder)) {
- if ($this->module_is_supported('sievefilters') && $this->user_config->get('enable_sieve_filter_setting', DEFAULT_ENABLE_SIEVE_FILTER)) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ if ($form['folder'] && $form['new_folder'] && $mailbox->rename_folder($form['folder'], $form['new_folder'], $parent)) {
+ if ($this->module_is_supported('sievefilters') && $this->user_config->get('enable_sieve_filter_setting', DEFAULT_ENABLE_SIEVE_FILTER) && $mailbox->is_imap()) {
$imap_servers = $this->user_config->get('imap_servers');
$imap_account = $imap_servers[$form['imap_server_id']];
$linked_mailboxes = get_sieve_linked_mailbox($imap_account, $this);
@@ -271,17 +261,16 @@ class Hm_Handler_process_folder_delete extends Hm_Handler_Module {
public function process() {
list($success, $form) = $this->process_form(array('imap_server_id', 'folder'));
if ($success) {
- $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);
- $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache);
- if (is_object($imap) && $imap->get_state() == 'authenticated') {
- $del_folder = prep_folder_name($imap, $form['folder'], true);
- if ($this->module_is_supported('sievefilters') && $this->user_config->get('enable_sieve_filter_setting', DEFAULT_ENABLE_SIEVE_FILTER)) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ if ($this->module_is_supported('sievefilters') && $this->user_config->get('enable_sieve_filter_setting', DEFAULT_ENABLE_SIEVE_FILTER) && $mailbox->is_imap()) {
+ $del_folder = prep_folder_name($mailbox->get_connection(), $form['folder'], true);
if (is_mailbox_linked_with_filters($del_folder, $form['imap_server_id'], $this)) {
Hm_Msgs::add('ERRThis folder can\'t be deleted because it is used in a filter.');
return;
}
}
- if ($del_folder && $imap->delete_mailbox($del_folder)) {
+ if ($form['folder'] && $mailbox->delete_folder($form['folder'])) {
Hm_Msgs::add('Folder deleted');
$this->cache->del('imap_folders_imap_'.$form['imap_server_id'].'_');
$this->out('imap_folders_success', true);
@@ -307,6 +296,14 @@ public function process() {
$this->out('archive_folder', $specials[$this->request->get['imap_server_id']]['archive']);
$this->out('draft_folder', $specials[$this->request->get['imap_server_id']]['draft']);
$this->out('junk_folder', $specials[$this->request->get['imap_server_id']]['junk']);
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($this->request->get['imap_server_id'], $this->cache);
+ if ($mailbox && $mailbox->authed()) {
+ $folder_names = [];
+ foreach ($specials[$this->request->get['imap_server_id']] as $name => $folder) {
+ $folder_names[$name] = $mailbox->get_folder_name($folder);
+ }
+ $this->out('special_folder_names', $folder_names);
+ }
}
}
else {
@@ -344,13 +341,12 @@ public function process() {
list($success, $form) = $this->process_form(array('folder', 'subscription_state'));
if ($success) {
$imap_server_id = $this->request->get['imap_server_id'];
- $cache = Hm_IMAP_List::get_cache($this->cache, $imap_server_id);
- $imap = Hm_IMAP_List::connect($imap_server_id, $cache);
- if (imap_authed($imap)) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($imap_server_id, $this->cache);
+ if ($mailbox && $mailbox->authed()) {
$folder = hex2bin($form['folder']);
- $success = $imap->mailbox_subscription($folder, $form['subscription_state']);
+ $success = $mailbox->folder_subscription($folder, $form['subscription_state']);
if ($success) {
- Hm_Msgs::add(sprintf('%s to %s', $form['subscription_state']? 'Subscribed': 'Unsubscribed', $folder));
+ Hm_Msgs::add(sprintf('%s to %s', $form['subscription_state']? 'Subscribed': 'Unsubscribed', $mailbox->get_folder_name($folder)));
$this->cache->del('imap_folders_imap_'.$imap_server_id.'_');
} else {
Hm_Msgs::add(sprintf('ERRAn error occurred %s to %s', $form['subscription_state']? 'subscribing': 'unsubscribing', $folder));
@@ -489,13 +485,15 @@ protected function output() {
}
$sent_folder = $this->get('sent_folder', $this->trans('Not set'));
- if (!$sent_folder) {
- $sent_folder = $this->trans('Not set');
+ if (! $sent_folder) {
+ $folder_name = $this->trans('Not set');
+ } else {
+ $folder_name = $this->get('special_folder_names')['sent'] ?? $sent_folder;
}
$res = '';
$res .= '
';
$res .= '
@@ -533,13 +531,15 @@ protected function output() {
}
$archive_folder = $this->get('archive_folder', $this->trans('Not set'));
- if (!$archive_folder) {
- $archive_folder = $this->trans('Not set');
+ if (! $archive_folder) {
+ $folder_name = $this->trans('Not set');
+ } else {
+ $folder_name = $this->get('special_folder_names')['archive'] ?? $archive_folder;
}
$res = '
';
$res .= '
';
$res .= '
@@ -577,13 +577,15 @@ protected function output() {
}
$draft_folder = $this->get('draft_folder', $this->trans('Not set'));
- if (!$draft_folder) {
- $draft_folder = $this->trans('Not set');
+ if (! $draft_folder) {
+ $folder_name = $this->trans('Not set');
+ } else {
+ $folder_name = $this->get('special_folder_names')['draft'] ?? $draft_folder;
}
$res = '
';
$res .= '
';
$res .= '
@@ -621,13 +623,15 @@ protected function output() {
}
$trash_folder = $this->get('trash_folder', $this->trans('Not set'));
- if (!$trash_folder) {
- $trash_folder = $this->trans('Not set');
+ if (! $trash_folder) {
+ $folder_name = $this->trans('Not set');
+ } else {
+ $folder_name = $this->get('special_folder_names')['trash'] ?? $trash_folder;
}
$res = '
';
$res .= '
';
$res .= '
';
$res .= '
@@ -662,13 +666,15 @@ protected function output() {
}
$junk_folder = $this->get('junk_folder', $this->trans('Not set'));
- if (!$junk_folder) {
- $junk_folder = $this->trans('Not set');
+ if (! $junk_folder) {
+ $folder_name = $this->trans('Not set');
+ } else {
+ $folder_name = $this->get('special_folder_names')['junk'] ?? $junk_folder;
}
$res = '
';
$res .= '
';
$res .= '
';
diff --git a/modules/nux/modules.php b/modules/nux/modules.php
index f1b4378a9..f3942401a 100644
--- a/modules/nux/modules.php
+++ b/modules/nux/modules.php
@@ -65,6 +65,8 @@ class Hm_Handler_nux_homepage_data extends Hm_Handler_Module {
public function process() {
$imap_servers = NULL;
+ $jmap_servers = NULL;
+ $ews_servers = NULL;
$smtp_servers = NULL;
$feed_servers = NULL;
$profiles = NULL;
@@ -72,13 +74,17 @@ public function process() {
$modules = $this->config->get_modules();
if (data_source_available($modules, 'imap')) {
- $imap_servers = count(Hm_IMAP_List::dump(false));
+ $servers = Hm_IMAP_List::dump(false);
+ $imap_servers = count(array_filter($servers, function($server) { return empty($server['type']) || $server['type'] === 'imap'; }));
+ $jmap_servers = count(array_filter($servers, function($server) { return @$server['type'] === 'jmap'; }));
+ $ews_servers = count(array_filter($servers, function($server) { return @$server['type'] === 'ews'; }));
}
if (data_source_available($modules, 'feeds')) {
$feed_servers = count(Hm_Feed_List::dump(false));
}
if (data_source_available($modules, 'smtp')) {
- $smtp_servers = count(Hm_SMTP_List::dump(false));
+ $servers = Hm_SMTP_List::dump(false);
+ $smtp_servers = count(array_filter($servers, function($server) { return empty($server['type']) || $server['type'] === 'smtp'; }));
}
if (data_source_available($modules, 'profiles')) {
Hm_Profiles::init($this);
@@ -87,6 +93,8 @@ public function process() {
$this->out('nux_server_setup', array(
'imap' => $imap_servers,
+ 'jmap' => $jmap_servers,
+ 'ews' => $ews_servers,
'feeds' => $feed_servers,
'smtp' => $smtp_servers,
'profiles' => $profiles
@@ -183,8 +191,8 @@ public function process() {
if (! can_save_last_added_server('Hm_IMAP_List', $form['nux_email'])) {
return;
}
- $imap = Hm_IMAP_List::connect($new_id, false);
- if ($imap && $imap->get_state() == 'authenticated') {
+ $mailbox = Hm_IMAP_List::connect($new_id, false);
+ if ($mailbox && $mailbox->authed()) {
if (isset($details['smtp'])) {
Hm_SMTP_List::add(array(
'name' => $details['name'],
@@ -404,6 +412,7 @@ public function process()
$server['profile']['is_default'],
$server['username'],
($server['jmap']['server'] ?? $server['imap']['server']),
+ $server['username'],
$smtp_server_id,
($jmap_server_id ?? $imap_server_id),
$this
@@ -558,7 +567,7 @@ protected function output() {
}
$server_data = $this->get('nux_server_setup', array());
$tz = $this->get('tzone');
- $protos = array('imap', 'smtp', 'feeds', 'profiles');
+ $protos = array('imap', 'jmap', 'ews', 'smtp', 'feeds', 'profiles');
$res = '
'.$this->trans('Welcome to Cypht').'
';
$res .= '
'.$this->trans('Add a popular E-mail source quickly and easily').'
';
diff --git a/modules/profiles/functions.php b/modules/profiles/functions.php
index bb7abe014..dcfc10005 100644
--- a/modules/profiles/functions.php
+++ b/modules/profiles/functions.php
@@ -3,7 +3,7 @@
if (!defined('DEBUG_MODE')) { die(); }
if (!hm_exists('add_profile')) {
- function add_profile($name, $signature, $reply_to, $is_default, $email, $server_mail, $smtp_server_id, $imap_server_id, $context, $remark = '') {
+ function add_profile($name, $signature, $reply_to, $is_default, $email, $server, $user, $smtp_server_id, $imap_server_id, $context, $remark = '') {
$profile = array(
'name' => $name,
'sig' => $signature,
@@ -12,11 +12,13 @@ function add_profile($name, $signature, $reply_to, $is_default, $email, $server_
'replyto' => $reply_to,
'default' => $is_default,
'address' => $email,
- 'server' => $server_mail,
- 'user' => $email,
+ 'server' => $server,
+ 'user' => $user,
'type' => 'imap'
);
-
- Hm_Profiles::add($profile);
+ $id = Hm_Profiles::add($profile);
+ if ($is_default) {
+ Hm_Profiles::setDefault($id);
+ }
}
}
diff --git a/modules/sievefilters/modules.php b/modules/sievefilters/modules.php
index 35b157931..8568b7fee 100644
--- a/modules/sievefilters/modules.php
+++ b/modules/sievefilters/modules.php
@@ -291,14 +291,13 @@ public function process() {
$imap_server_id = $idx;
}
}
- $cache = Hm_IMAP_List::get_cache($this->cache, $imap_server_id);
- $imap = Hm_IMAP_List::connect($imap_server_id, $cache);
- if (!imap_authed($imap)) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($imap_server_id, $this->cache);
+ if (! $mailbox || ! $mailbox->authed()) {
Hm_Msgs::add('ERRIMAP Authentication Failed');
return;
}
$mailboxes = [];
- foreach ($imap->get_mailbox_list() as $idx => $mailbox) {
+ foreach ($mailbox->get_folders() as $idx => $mailbox) {
$mailboxes[] = $mailbox['name'];
}
$this->out('mailboxes', json_encode($mailboxes));
@@ -452,17 +451,12 @@ public function process() {
if (isset($this->request->post['imap_msg_uid'])) {
$form['imap_msg_uid'] = $this->request->post['imap_msg_uid'];
- $imap = Hm_IMAP_List::connect($this->request->post['imap_server_id']);
-
- if (!imap_authed($imap)) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($this->request->post['imap_server_id'], $this->cache);
+ if (! $mailbox || ! $mailbox->authed()) {
Hm_Msgs::add('ERRIMAP Authentication Failed');
return;
}
- if (!$imap->select_mailbox(hex2bin($this->request->post['folder']))) {
- Hm_Msgs::add('ERRIMAP Mailbox select error');
- return;
- }
- $msg_header = $imap->get_message_headers($form['imap_msg_uid']);
+ $msg_header = $mailbox->get_message_headers(hex2bin($this->request->post['folder']), $form['imap_msg_uid']);
$test_pattern = "/(?:[a-z0-9!#$%&'*+=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+=?^_`{|}~-]+)*|\"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/";
preg_match_all($test_pattern, $msg_header['From'], $email_sender);
$email_sender = $email_sender[0][0];
diff --git a/modules/smtp/functions.php b/modules/smtp/functions.php
index 260ad84e8..68a8db3b1 100644
--- a/modules/smtp/functions.php
+++ b/modules/smtp/functions.php
@@ -4,10 +4,11 @@
if (!defined('DEBUG_MODE')) { die(); }
if (!hm_exists('connect_to_smtp_server')) {
- function connect_to_smtp_server($address, $name, $port, $user, $pass, $tls, $server_id = false) {
+ function connect_to_smtp_server($address, $name, $port, $user, $pass, $tls, $type, $server_id = false) {
$smtp_list = array(
'name' => $name,
'server' => $address,
+ 'type' => $type,
'hide' => false,
'port' => $port,
'user' => $user,
@@ -25,13 +26,13 @@ function connect_to_smtp_server($address, $name, $port, $user, $pass, $tls, $ser
}
} else {
$smtp_server_id = Hm_SMTP_List::add($smtp_list);
- if (! can_save_last_added_server('Hm_SMTP_List', $user)) {
+ if ($type != 'ews' && ! can_save_last_added_server('Hm_SMTP_List', $user)) {
return;
}
}
- $smtp = Hm_SMTP_List::connect($smtp_server_id, false);
- if (smtp_authed($smtp)) {
+ $mailbox = Hm_SMTP_List::connect($smtp_server_id, false);
+ if ($mailbox->authed()) {
return $smtp_server_id;
}
else {
diff --git a/modules/smtp/hm-smtp.php b/modules/smtp/hm-smtp.php
index ace96b306..779bb4c5e 100644
--- a/modules/smtp/hm-smtp.php
+++ b/modules/smtp/hm-smtp.php
@@ -14,8 +14,13 @@ class Hm_SMTP_List {
use Hm_Server_List;
+ protected static $user_config;
+ protected static $session;
+
public static function init($user_config, $session) {
self::initRepo('smtp_servers', $user_config, $session, self::$server_list);
+ self::$user_config = $user_config;
+ self::$session = $session;
}
public static function service_connect($id, $server, $user, $pass, $cache=false) {
@@ -25,7 +30,8 @@ public static function service_connect($id, $server, $user, $pass, $cache=false)
'port' => $server['port'],
'tls' => $server['tls'],
'username' => $user,
- 'password' => $pass
+ 'password' => $pass,
+ 'type' => array_key_exists('type', $server) ? $server['type'] : 'smtp',
);
if (array_key_exists('auth', $server)) {
$config['auth'] = $server['auth'];
@@ -33,16 +39,17 @@ public static function service_connect($id, $server, $user, $pass, $cache=false)
if (array_key_exists('no_auth', $server)) {
$config['no_auth'] = true;
}
- self::$server_list[$id]['object'] = new Hm_SMTP($config);
-
- if (!self::$server_list[$id]['object']->connect()) {
+ self::$server_list[$id]['object'] = new Hm_Mailbox($id, self::$user_config, self::$session);
+ if (! self::$server_list[$id]['object']->connect($config)) {
return self::$server_list[$id]['object'];
}
return false;
}
+
public static function get_cache($session, $id) {
return false;
}
+
public static function address_list() {
$addrs = array();
foreach (self::$server_list as $server) {
diff --git a/modules/smtp/modules.php b/modules/smtp/modules.php
index 6d2adb9ee..5142ce3e3 100644
--- a/modules/smtp/modules.php
+++ b/modules/smtp/modules.php
@@ -56,11 +56,10 @@ public function process() {
&& array_key_exists('list_path', $this->request->get)
&& array_key_exists('uid', $this->request->get)) {
$path = explode('_', $this->request->get['list_path']);
- $imap = Hm_IMAP_List::connect($path[1]);
- if ($imap->select_mailbox(hex2bin($path[2]))) {
- $msg_struct = $imap->get_message_structure($this->request->get['uid']);
- list($part, $msg_text) = $imap->get_first_message_part($this->request->get['uid'], 'text', 'plain', $msg_struct);
- $msg_header = $imap->get_message_headers($this->request->get['uid']);
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($path[1]);
+ if ($mailbox && $mailbox->authed()) {
+ list ($msg_struct, $msg_struct_first, $msg_text, $part) = $mailbox->get_structured_message(hex2bin($path[2]), $this->request->get['uid'], false, true);
+ $msg_header = $mailbox->get_message_headers(hex2bin($path[2]), $this->request->get['uid']);
if (!array_key_exists('From', $msg_header) || count($msg_header) == 0) {
return;
}
@@ -78,7 +77,7 @@ public function process() {
$new_attachment['size'] = $sub['size'];
$new_attachment['type'] = $sub['type'];
$file_path = $this->config->get('attachment_dir').DIRECTORY_SEPARATOR.$new_attachment['name'];
- $content = Hm_Crypt::ciphertext($imap->get_message_content($this->request->get['uid'], $ind), Hm_Request_Key::generate());
+ $content = Hm_Crypt::ciphertext($mailbox->get_message_content(hex2bin($path[2]), $this->request->get['uid'], $ind), Hm_Request_Key::generate());
file_put_contents($file_path, $content);
$new_attachment['tmp_name'] = $file_path;
$new_attachment['filename'] = $file_path;
@@ -126,14 +125,13 @@ public function process() {
if (array_key_exists('forward_as_attachment', $this->request->get)) {
$path = explode('_', $this->request->get['list_path']);
- $imap = Hm_IMAP_List::connect($path[1]);
- if ($imap && $imap->select_mailbox(hex2bin($path[2]))) {
- $msg_struct = $imap->get_message_structure($this->request->get['uid']);
- $msg_header = $imap->get_message_headers($this->request->get['uid']);
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($path[1]);
+ if ($mailbox && $mailbox->authed()) {
+ $msg_header = $mailbox->get_message_headers(hex2bin($path[2]), $this->request->get['uid']);
if (!array_key_exists('From', $msg_header) || count($msg_header) == 0) {
return;
}
- $content = $imap->get_message_content($this->request->get['uid'], 0, false, false);
+ $content = $mailbox->get_message_content(hex2bin($path[2]), $this->request->get['uid']);
# Attachment Download
$attached_files = [];
@@ -143,7 +141,7 @@ public function process() {
if (!is_dir($file_dir)) {
mkdir($file_dir);
}
- $name = $msg_header['subject'] . '.eml';
+ $name = $msg_header['Subject'] . '.eml';
$file_path = $file_dir . $name;
$attached_files[$this->request->get['uid']][] = array(
'name' => $name,
@@ -151,8 +149,9 @@ public function process() {
'size' => strlen($content),
'tmp_name' => $file_path,
'filename' => $file_path,
- 'basename' => $msg_header['subject']
+ 'basename' => $msg_header['Subject']
);
+ $content = Hm_Crypt::ciphertext($content, Hm_Request_Key::generate());
file_put_contents($file_path, $content);
$this->session->set('uploaded_files', $attached_files);
$this->out('as_attr', true);
@@ -172,11 +171,10 @@ public function process() {
}
if (array_key_exists('forward', $this->request->get)) {
$path = explode('_', $this->request->get['list_path']);
- $imap = Hm_IMAP_List::connect($path[1]);
- if ($imap && $imap->select_mailbox(hex2bin($path[2]))) {
- $msg_struct = $imap->get_message_structure($this->request->get['uid']);
- list($part, $msg_text) = $imap->get_first_message_part($this->request->get['uid'], 'text', 'plain', $msg_struct);
- $msg_header = $imap->get_message_headers($this->request->get['uid']);
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($path[1]);
+ if ($mailbox && $mailbox->authed()) {
+ list ($msg_struct, $msg_struct_first, $msg_text, $part) = $mailbox->get_structured_message(hex2bin($path[2]), $this->request->get['uid'], false, true);
+ $msg_header = $mailbox->get_message_headers(hex2bin($path[2]), $this->request->get['uid']);
if (!array_key_exists('From', $msg_header) || count($msg_header) == 0) {
return;
}
@@ -196,7 +194,7 @@ public function process() {
$new_attachment['size'] = $sub['size'];
$new_attachment['type'] = $sub['type'];
$file_path = $file_dir . $new_attachment['name'];
- $content = Hm_Crypt::ciphertext($imap->get_message_content($this->request->get['uid'], $ind), Hm_Request_Key::generate());
+ $content = Hm_Crypt::ciphertext($mailbox->get_message_content(hex2bin($path[2]), $this->request->get['uid'], $ind), Hm_Request_Key::generate());
file_put_contents($file_path, $content);
$new_attachment['tmp_name'] = $file_path;
$new_attachment['filename'] = $file_path;
@@ -518,13 +516,17 @@ public function process() {
}
}
}
- $smtp = Hm_SMTP_List::connect($form['smtp_server_id'], false, $smtp_details['user'], $smtp_details['pass']);
- if (smtp_authed($smtp)) {
+ $mailbox = Hm_SMTP_List::connect($form['smtp_server_id'], false, $smtp_details['user'], $smtp_details['pass']);
+ if ($mailbox && $mailbox->authed()) {
Hm_Msgs::add("Successfully authenticated to the SMTP server");
- return;
+ }
+ elseif ($mailbox && $mailbox->state() == 'connected') {
+ Hm_Msgs::add("ERRConnected, but failed to authenticate to the SMTP server");
+ }
+ else {
+ Hm_Msgs::add("ERRFailed to authenticate to the SMTP server");
}
}
- Hm_Msgs::add("ERRFailed to authenticate to the SMTP server");
}
}
}
@@ -660,8 +662,6 @@ public function process() {
'draft_subject' => $form['compose_subject'],
'draft_smtp' => $smtp_id
);
- $from_params = '';
- $recipients_params = '';
/* parse attachments */
$uploaded_files = [];
@@ -679,11 +679,6 @@ public function process() {
/* msg details */
list($body, $cc, $bcc, $in_reply_to, $draft) = get_outbound_msg_detail($this->request->post, $draft, $body_type);
- if ($this->user_config->get('enable_compose_delivery_receipt_setting', false) && !empty($this->request->post['compose_delivery_receipt'])) {
- $from_params = 'RET=HDRS';
- $recipients_params = 'NOTIFY=SUCCESS,FAILURE';
- }
-
/* smtp server details */
$smtp_details = Hm_SMTP_List::dump($smtp_id, true);
if (!$smtp_details) {
@@ -703,8 +698,8 @@ public function process() {
list($from, $reply_to) = outbound_address_check($this, $from, $reply_to);
/* try to connect */
- $smtp = Hm_SMTP_List::connect($smtp_id, false);
- if (!smtp_authed($smtp)) {
+ $mailbox = Hm_SMTP_List::connect($smtp_id, false);
+ if (! $mailbox || ! $mailbox->authed()) {
Hm_Msgs::add("ERRFailed to authenticate to the SMTP server");
repopulate_compose_form($draft, $this);
return;
@@ -726,7 +721,7 @@ public function process() {
}
/* send the message */
- $err_msg = $smtp->send_message($from, $recipients, $mime->get_mime_msg(), $from_params, $recipients_params);
+ $err_msg = $mailbox->send_message($from, $recipients, $mime->get_mime_msg(), $this->user_config->get('enable_compose_delivery_receipt_setting', false) && !empty($this->request->post['compose_delivery_receipt']));
if ($err_msg) {
Hm_Msgs::add(sprintf("ERR%s", $err_msg));
repopulate_compose_form($draft, $this);
@@ -737,7 +732,7 @@ public function process() {
$auto_bcc = $this->user_config->get('smtp_auto_bcc_setting', DEFAULT_SMTP_AUTO_BCC);
if ($auto_bcc) {
$mime->set_auto_bcc($from);
- $bcc_err_msg = $smtp->send_message($from, array($from), $mime->get_mime_msg());
+ $bcc_err_msg = $mailbox->send_message($from, array($from), $mime->get_mime_msg());
}
/* check for associated IMAP server to save a copy */
@@ -757,13 +752,13 @@ public function process() {
$msg_path = explode('_', $this->request->post['compose_msg_path']);
$msg_uid = $this->request->post['compose_msg_uid'];
- $imap = Hm_IMAP_List::connect($msg_path[1]);
- if ($imap->select_mailbox(hex2bin($msg_path[2]))) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($msg_path[1]);
+ if ($mailbox && $mailbox->authed()) {
$specials = get_special_folders($this, $msg_path[1]);
if (array_key_exists('archive', $specials) && $specials['archive']) {
$archive_folder = $specials['archive'];
- $imap->message_action('ARCHIVE', array($msg_uid));
- $imap->message_action('MOVE', array($msg_uid), $archive_folder);
+ $mailbox->message_action(hex2bin($msg_path[2]), 'ARCHIVE', array($msg_uid));
+ $mailbox->message_action(hex2bin($msg_path[2]), 'MOVE', array($msg_uid), $archive_folder);
}
}
}
@@ -1405,6 +1400,10 @@ protected function output() {
$no_edit = false;
+ if (array_key_exists('type', $vals) && $vals['type'] == 'ews') {
+ continue;
+ }
+
if (array_key_exists('user', $vals) && !array_key_exists('nopass', $vals)) {
$disabled = 'disabled="disabled"';
$user_pc = $vals['user'];
@@ -1732,13 +1731,10 @@ function get_primary_recipient($profiles, $headers, $smtp_servers, $is_draft=Fal
*/
if (!hm_exists('delete_draft')) {
function delete_draft($id, $cache, $imap_server_id, $folder) {
- $imap = Hm_IMAP_List::connect($imap_server_id);
- if (! imap_authed($imap)) {
- return false;
- }
- if ($imap->select_mailbox($folder)) {
- if ($imap->message_action('DELETE', array($id))['status']) {
- $imap->message_action('EXPUNGE', array($id));
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($imap_server_id);
+ if ($mailbox && $mailbox->authed()) {
+ if ($mailbox->message_action($folder, 'DELETE', array($id))['status']) {
+ $mailbox->message_action($folder, 'EXPUNGE', array($id));
return true;
}
}
@@ -1858,7 +1854,9 @@ function get_uploaded_files_from_array($uploaded_files) {
}
function prepare_draft_mime($atts, $uploaded_files, $from = false, $name = '') {
- $uploaded_files = get_uploaded_files_from_array($uploaded_files);
+ if (! empty($uploaded_files) && ! is_array($uploaded_files[0])) {
+ $uploaded_files = get_uploaded_files_from_array($uploaded_files);
+ }
$mime = new Hm_MIME_Msg(
$atts['draft_to'],
$atts['draft_subject'],
@@ -1912,9 +1910,10 @@ function save_imap_draft($atts, $id, $session, $mod, $mod_cache, $uploaded_files
Hm_Msgs::add('ERRThere is no draft directory configured for this account.');
return -1;
}
- $cache = Hm_IMAP_List::get_cache($mod_cache, $imap_profile['id']);
- $imap = Hm_IMAP_List::connect($imap_profile['id'], $cache);
- $draft_folder = $imap->select_mailbox($specials['draft']);
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($imap_profile['id'], $mod_cache);
+ if (! $mailbox || ! $mailbox->authed()) {
+ return -1;
+ }
$mime = prepare_draft_mime($atts, $uploaded_files, $from, $name);
$res = $mime->process_attachments();
@@ -1923,24 +1922,21 @@ function save_imap_draft($atts, $id, $session, $mod, $mod_cache, $uploaded_files
$msg = str_replace("\n", "\r\n", $msg);
$msg = rtrim($msg)."\r\n";
- if ($imap->append_start($specials['draft'], mb_strlen($msg), false, true)) {
- $imap->append_feed($msg."\r\n");
- if (!$imap->append_end()) {
- Hm_Msgs::add('ERRAn error occurred saving the draft message');
- return -1;
- }
+ if (! $mailbox->store_message($specials['draft'], $msg, false, true)) {
+ Hm_Msgs::add('ERRAn error occurred saving the draft message');
+ return -1;
}
- $mailbox_page = $imap->get_mailbox_page($specials['draft'], 'ARRIVAL', true, 'DRAFT', 0, 10);
+ $messages = $mailbox->get_messages($specials['draft'], 'ARRIVAL', true, 'DRAFT', 0, 10);
// Remove old version from the mailbox
if ($id) {
- $imap->message_action('DELETE', array($id));
- $imap->message_action('EXPUNGE', array($id));
+ $mailbox->message_action($specials['draft'], 'DELETE', array($id));
+ $mailbox->message_action($specials['draft'], 'EXPUNGE', array($id));
}
- foreach ($mailbox_page[1] as $mail) {
- $msg_header = $imap->get_message_headers($mail['uid']);
+ foreach ($messages[1] as $mail) {
+ $msg_header = $mailbox->get_message_headers($specials['draft'], $mail['uid']);
// Convert all header keys to lowercase
$msg_header_lower = array_change_key_case($msg_header, CASE_LOWER);
$mime_headers_lower = array_change_key_case($mime->get_headers(), CASE_LOWER);
@@ -2138,14 +2134,6 @@ function profile_from_compose_smtp_id($profiles, $id) {
return false;
}}
-/**
- * @subpackage smtp/functions
- */
-if (!hm_exists('smtp_authed')) {
-function smtp_authed($smtp) {
- return is_object($smtp) && $smtp->state == 'authed';
-}}
-
/**
* @subpackage smtp/functions
*/
@@ -2188,6 +2176,7 @@ function default_smtp_server($user_config, $session, $request, $config, $user, $
$attributes = array(
'name' => $config->get('default_smtp_name', 'Default'),
'default' => true,
+ 'type' => 'smtp',
'server' => $smtp_server,
'port' => $smtp_port,
'tls' => $smtp_tls,
diff --git a/modules/smtp/setup.php b/modules/smtp/setup.php
index 954926634..916bf9e61 100644
--- a/modules/smtp/setup.php
+++ b/modules/smtp/setup.php
@@ -27,7 +27,7 @@
add_handler('profiles', 'add_smtp_servers_to_page_data', true, 'smtp', 'load_smtp_servers_from_config', 'after');
/* servers page */
-add_handler('servers', 'load_smtp_servers_from_config', true, 'smtp', 'language', 'after');
+add_handler('servers', 'load_smtp_servers_from_config', true, 'smtp', 'load_user_data', 'after');
add_handler('servers', 'process_add_smtp_server', true, 'smtp', 'load_smtp_servers_from_config', 'after');
add_handler('servers', 'add_smtp_servers_to_page_data', true, 'smtp', 'process_add_smtp_server', 'after');
add_handler('servers', 'save_smtp_servers', true, 'smtp', 'add_smtp_servers_to_page_data', 'after');
@@ -120,7 +120,7 @@
'reply_all' => FILTER_VALIDATE_INT,
'forward' => FILTER_VALIDATE_INT,
'forward_as_attachment' => FILTER_VALIDATE_INT,
- 'draft_id' => FILTER_VALIDATE_INT,
+ 'draft_id' => FILTER_DEFAULT,
'hm_ajax_hook' => FILTER_DEFAULT,
'compose_to' => FILTER_DEFAULT,
'mailto_uri' => FILTER_DEFAULT,
@@ -139,7 +139,7 @@
'allowed_output' => array(
'file_details' => array(FILTER_UNSAFE_RAW, false),
'draft_subject' => array(FILTER_DEFAULT, false),
- 'draft_id' => array(FILTER_VALIDATE_INT, false),
+ 'draft_id' => array(FILTER_DEFAULT, false),
'profile_value' => array(FILTER_DEFAULT, false),
'msg_sent_and_archived' => array(FILTER_VALIDATE_BOOLEAN, false),
'sent_msg_id' => array(FILTER_VALIDATE_BOOLEAN, false),
@@ -171,7 +171,7 @@
'compose_delivery_receipt' => FILTER_VALIDATE_BOOLEAN,
'enable_compose_delivery_receipt' => FILTER_VALIDATE_INT,
'compose_smtp_id' => FILTER_DEFAULT,
- 'draft_id' => FILTER_VALIDATE_INT,
+ 'draft_id' => FILTER_DEFAULT,
'draft_body' => FILTER_UNSAFE_RAW,
'draft_subject' => FILTER_UNSAFE_RAW,
'draft_to' => FILTER_UNSAFE_RAW,
diff --git a/modules/smtp/site.js b/modules/smtp/site.js
index 44c62b2bb..30a6bce69 100644
--- a/modules/smtp/site.js
+++ b/modules/smtp/site.js
@@ -336,13 +336,14 @@ var is_valid_recipient = function(recipient) {
var process_compose_form = function(){
var msg_uid = getMessageUidParam();
- var detail = Hm_Utils.parse_folder_path(getListPathParam(), 'imap');
- var class_name = 'imap_' + detail.server_id + '_' + msg_uid + '_' + detail.folder;
- var key = 'imap_' + Hm_Utils.get_url_page_number() + '_' + getListPathParam();
- var next_message = Hm_Message_List.prev_next_links(key, class_name)[1];
-
- if (next_message) {
- $('.compose_next_email_data').val(next_message);
+ if (getListPathParam()) {
+ var detail = Hm_Utils.parse_folder_path(getListPathParam(), 'imap');
+ var class_name = 'imap_' + detail.server_id + '_' + msg_uid + '_' + detail.folder;
+ var key = 'imap_' + Hm_Utils.get_url_page_number() + '_' + getListPathParam();
+ var next_message = Hm_Message_List.prev_next_links(key, class_name)[1];
+ if (next_message) {
+ $('.compose_next_email_data').val(next_message);
+ }
}
var uploaded_files = $("input[name='uploaded_files[]']").map(function () { return $(this).val(); }).get();
@@ -352,6 +353,7 @@ var process_compose_form = function(){
$('.smtp_send_archive').addClass('disabled_input');
$('.smtp_send').on("click", function () { return false; });
}
+
var force_send_message = function() {
// Check if the force_send input already exists
var forceSendInput = document.getElementById('force_send');
diff --git a/modules/tags/handler_modules.php b/modules/tags/handler_modules.php
index 53c735225..8836e6d52 100644
--- a/modules/tags/handler_modules.php
+++ b/modules/tags/handler_modules.php
@@ -33,6 +33,7 @@ public function process() {
foreach ($ids as $msg_part) {
list($imap_server_id, $msg_id, $folder) = explode('_', $msg_part);
$folder = hex2bin($folder);
+ $msg_id = hex2bin($msg_id);
$tagged = Hm_Tags::addMessage($form['tag_id'], $imap_server_id, $folder, $msg_id);
if ($tagged) {
$taged_messages++;
@@ -135,18 +136,16 @@ public function process() {
foreach ($ids as $serverId) {
$folders = Hm_Tags::getFolders($tag_id, $serverId);
if (!empty($folders)) {
- $cache = Hm_IMAP_List::get_cache($this->cache, $serverId);
- $imap = Hm_IMAP_List::connect($serverId, $cache);
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($serverId, $this->cache);
$server_details = Hm_IMAP_List::dump($serverId);
- if (imap_authed($imap)) {
+ if ($mailbox && $mailbox->authed()) {
foreach ($folders as $folder => $messageIds) {
- $imap->select_mailbox($folder);
$messages = array_map(function($msg) use ($serverId, $folder, $server_details) {
$msg['server_id'] = $serverId;
$msg['folder'] = bin2hex($folder);
$msg['server_name'] = $server_details['name'];
return $msg;
- }, $imap->get_message_list($messageIds));
+ }, $mailbox->get_message_list($folder, $messageIds));
$msg_list = array_merge($msg_list, $messages);
}
}
diff --git a/modules/tags/hm-tags.php b/modules/tags/hm-tags.php
index 5155b8632..d79580f79 100644
--- a/modules/tags/hm-tags.php
+++ b/modules/tags/hm-tags.php
@@ -39,16 +39,8 @@ public static function addMessage($tagId, $serverId, $folder, $messageId) {
public static function registerFolder($tag_id, $serverId, $folder) {
$tag = self::get($tag_id);
- if (isset($tag['server'])) {
- if (isset($tag['server'][$serverId])) {
- if (!in_array($folder, $tag['server'][$serverId])) {
- $tag['server'][$serverId][] = $folder;
- }
- } else {
- $tag['server'][$serverId] = array($folder);
- }
- } else {
- $tag['server'] = [$serverId => [$folder]];
+ if (! isset($tag['server'][$serverId][$folder])) {
+ $tag['server'][$serverId][$folder] = [];
}
self::edit($tag_id, $tag);
}
diff --git a/tests/phpunit/helpers.php b/tests/phpunit/helpers.php
index 513671fc6..07028b61f 100644
--- a/tests/phpunit/helpers.php
+++ b/tests/phpunit/helpers.php
@@ -98,10 +98,11 @@ public static function change_state($val) {
class Hm_IMAP_List extends Hm_Server_Wrapper {
public static $state = false;
public static function connect($id, $cache=false, $user=false, $pass=false, $save_credentials=false) {
+ global $user_config, $session;
Hm_IMAP::$allow_connection = self::$state;
Hm_IMAP::$allow_auth = self::$state;
- self::$server_list[$id]['object'] = new Hm_IMAP();
- self::$server_list[$id]['object']->connect();
+ self::$server_list[$id]['object'] = new Hm_Mailbox($id, $user_config, $session);
+ self::$server_list[$id]['object']->connect([]);
self::$server_list[$id]['connected'] = true;
return self::$server_list[$id]['object'];
}
diff --git a/tests/phpunit/modules/core/message_list_functions.php b/tests/phpunit/modules/core/message_list_functions.php
index 9d8330ec3..4da49bec6 100644
--- a/tests/phpunit/modules/core/message_list_functions.php
+++ b/tests/phpunit/modules/core/message_list_functions.php
@@ -124,7 +124,7 @@ public function test_message_since_dropdown() {
public function test_list_sources() {
$mod = new Hm_Output_Test(array('foo' => 'bar', 'bar' => 'foo'), array('bar'));
$this->assertEquals('
', list_sources(array(array('group' => 'background', 'type' => 'imap', 'folder' => 'foo')), $mod));
- $this->assertEquals('
', list_sources(array(array('name' => 'blah', 'type' => 'imap', 'folder' => bin2hex('foo'))), $mod));
+ $this->assertEquals('
', list_sources(array(array('name' => 'blah', 'type' => 'imap', 'folder' => bin2hex('foo'), 'folder_name' => 'foo')), $mod));
$this->assertEquals('
', list_sources(array(array('name' => 'blah', 'type' => 'imap')), $mod));
}
/**