From a4e314a7b04a4d75713cac5d3b1d4f29dc206fa1 Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 10 Jun 2023 00:32:19 +0200 Subject: [PATCH] (Grav GitSync) Automatic Commit from dan --- plugins/admin/CHANGELOG.md | 22 + plugins/admin/blueprints.yaml | 4 +- plugins/admin/classes/plugin/Admin.php | 19 +- plugins/admin/classes/plugin/ScssCompiler.php | 11 +- plugins/admin/composer.json | 2 +- plugins/admin/composer.lock | 47 +- .../vendor/composer/InstalledVersions.php | 17 +- plugins/admin/vendor/composer/installed.php | 4 +- plugins/email/CHANGELOG.md | 48 + plugins/email/README.md | 199 +- plugins/email/blueprints.yaml | 199 +- plugins/email/classes/Email.php | 670 ++-- plugins/email/classes/Message.php | 97 + .../email/cli/ClearQueueFailuresCommand.php | 29 +- plugins/email/cli/FlushQueueCommand.php | 30 +- plugins/email/cli/TestEmailCommand.php | 2 - plugins/email/composer.json | 3 +- plugins/email/composer.lock | 1043 ++++- plugins/email/email.php | 55 +- plugins/email/email.yaml | 12 +- plugins/email/languages.yaml | 64 +- plugins/email/vendor/autoload.php | 5 + .../vendor/composer/InstalledVersions.php | 16 +- .../vendor/composer/autoload_classmap.php | 7 +- .../email/vendor/composer/autoload_files.php | 5 +- .../vendor/composer/autoload_namespaces.php | 2 +- .../email/vendor/composer/autoload_psr4.php | 15 +- .../email/vendor/composer/autoload_real.php | 31 +- .../email/vendor/composer/autoload_static.php | 76 +- plugins/email/vendor/composer/installed.json | 1090 ++++- plugins/email/vendor/composer/installed.php | 167 +- .../egulias/email-validator/CONTRIBUTING.md | 8 +- .../egulias/email-validator/composer.lock | 1964 +++++---- .../email-validator/src/EmailLexer.php | 178 +- .../email-validator/src/MessageIDParser.php | 1 - .../src/Parser/DomainLiteral.php | 31 +- .../email-validator/src/Parser/DomainPart.php | 4 +- .../src/Parser/DoubleQuote.php | 9 +- .../src/Parser/FoldingWhiteSpace.php | 14 +- .../src/Parser/IDRightPart.php | 4 +- .../email-validator/src/Parser/LocalPart.php | 23 +- .../src/Result/Reason/UnOpenedComment.php | 2 +- .../src/Validation/DNSCheckValidation.php | 84 +- .../src/Validation/DNSGetRecordWrapper.php | 28 + .../src/Validation/DNSRecords.php | 35 + .../Validation/MultipleValidationWithAnd.php | 2 +- .../email-validator/src/Warning/Warning.php | 2 +- plugins/email/vendor/psr/container/.gitignore | 3 + plugins/email/vendor/psr/container/LICENSE | 21 + plugins/email/vendor/psr/container/README.md | 13 + .../email/vendor/psr/container/composer.json | 22 + .../src/ContainerExceptionInterface.php | 10 + .../psr/container/src/ContainerInterface.php | 36 + .../src/NotFoundExceptionInterface.php | 10 + .../vendor/psr/event-dispatcher/.editorconfig | 15 + .../vendor/psr/event-dispatcher/.gitignore | 2 + .../email/vendor/psr/event-dispatcher/LICENSE | 21 + .../vendor/psr/event-dispatcher/README.md | 6 + .../vendor/psr/event-dispatcher/composer.json | 26 + .../src/EventDispatcherInterface.php | 21 + .../src/ListenerProviderInterface.php | 19 + .../src/StoppableEventInterface.php | 26 + .../swiftmailer/swiftmailer/.gitattributes | 11 - .../swiftmailer/.github/ISSUE_TEMPLATE.md | 19 - .../.github/PULL_REQUEST_TEMPLATE.md | 14 - .../swiftmailer/.github/workflows/tests.yml | 55 - .../vendor/swiftmailer/swiftmailer/.gitignore | 9 - .../swiftmailer/swiftmailer/.php_cs.dist | 21 - .../vendor/swiftmailer/swiftmailer/CHANGES | 391 -- .../vendor/swiftmailer/swiftmailer/README.md | 25 - .../swiftmailer/swiftmailer/composer.json | 44 - .../swiftmailer/swiftmailer/doc/headers.rst | 621 --- .../swiftmailer/swiftmailer/doc/index.rst | 12 - .../swiftmailer/doc/introduction.rst | 67 - .../swiftmailer/swiftmailer/doc/japanese.rst | 19 - .../swiftmailer/swiftmailer/doc/messages.rst | 949 ----- .../swiftmailer/swiftmailer/doc/plugins.rst | 337 -- .../swiftmailer/swiftmailer/doc/sending.rst | 464 --- .../swiftmailer/lib/classes/Swift.php | 78 - .../lib/classes/Swift/AddressEncoder.php | 25 - .../AddressEncoder/Utf8AddressEncoder.php | 36 - .../classes/Swift/AddressEncoderException.php | 32 - .../lib/classes/Swift/Attachment.php | 54 - .../AbstractFilterableInputStream.php | 176 - .../Swift/ByteStream/ArrayByteStream.php | 178 - .../Swift/ByteStream/FileByteStream.php | 214 - .../ByteStream/TemporaryFileByteStream.php | 52 - .../lib/classes/Swift/CharacterReader.php | 67 - .../GenericFixedWidthReader.php | 97 - .../Swift/CharacterReader/UsAsciiReader.php | 84 - .../Swift/CharacterReader/Utf8Reader.php | 176 - .../classes/Swift/CharacterReaderFactory.php | 26 - .../SimpleCharacterReaderFactory.php | 124 - .../lib/classes/Swift/CharacterStream.php | 87 - .../CharacterStream/ArrayCharacterStream.php | 291 -- .../CharacterStream/NgCharacterStream.php | 262 -- .../lib/classes/Swift/ConfigurableSpool.php | 63 - .../lib/classes/Swift/DependencyContainer.php | 387 -- .../lib/classes/Swift/DependencyException.php | 27 - .../lib/classes/Swift/EmbeddedFile.php | 53 - .../swiftmailer/lib/classes/Swift/Encoder.php | 28 - .../classes/Swift/Encoder/Base64Encoder.php | 58 - .../classes/Swift/Encoder/Rfc2231Encoder.php | 90 - .../lib/classes/Swift/Events/CommandEvent.php | 64 - .../classes/Swift/Events/CommandListener.php | 22 - .../lib/classes/Swift/Events/Event.php | 38 - .../classes/Swift/Events/EventDispatcher.php | 70 - .../classes/Swift/Events/EventListener.php | 18 - .../lib/classes/Swift/Events/EventObject.php | 61 - .../classes/Swift/Events/ResponseEvent.php | 64 - .../classes/Swift/Events/ResponseListener.php | 22 - .../lib/classes/Swift/Events/SendEvent.php | 126 - .../lib/classes/Swift/Events/SendListener.php | 27 - .../Swift/Events/SimpleEventDispatcher.php | 142 - .../Swift/Events/TransportChangeEvent.php | 27 - .../Swift/Events/TransportChangeListener.php | 37 - .../Swift/Events/TransportExceptionEvent.php | 43 - .../Events/TransportExceptionListener.php | 22 - .../lib/classes/Swift/FailoverTransport.php | 33 - .../lib/classes/Swift/FileSpool.php | 208 - .../lib/classes/Swift/FileStream.php | 24 - .../lib/classes/Swift/Filterable.php | 31 - .../lib/classes/Swift/IdGenerator.php | 22 - .../swiftmailer/lib/classes/Swift/Image.php | 43 - .../lib/classes/Swift/InputByteStream.php | 75 - .../lib/classes/Swift/IoException.php | 28 - .../lib/classes/Swift/KeyCache.php | 104 - .../classes/Swift/KeyCache/ArrayKeyCache.php | 197 - .../classes/Swift/KeyCache/DiskKeyCache.php | 294 -- .../Swift/KeyCache/KeyCacheInputStream.php | 47 - .../classes/Swift/KeyCache/NullKeyCache.php | 113 - .../KeyCache/SimpleKeyCacheInputStream.php | 123 - .../classes/Swift/LoadBalancedTransport.php | 33 - .../swiftmailer/lib/classes/Swift/Mailer.php | 98 - .../Swift/Mailer/ArrayRecipientIterator.php | 53 - .../Swift/Mailer/RecipientIterator.php | 32 - .../lib/classes/Swift/MemorySpool.php | 110 - .../swiftmailer/lib/classes/Swift/Message.php | 279 -- .../lib/classes/Swift/Mime/Attachment.php | 144 - .../classes/Swift/Mime/CharsetObserver.php | 24 - .../lib/classes/Swift/Mime/ContentEncoder.php | 34 - .../ContentEncoder/Base64ContentEncoder.php | 101 - .../ContentEncoder/NativeQpContentEncoder.php | 121 - .../ContentEncoder/NullContentEncoder.php | 79 - .../ContentEncoder/PlainContentEncoder.php | 164 - .../Mime/ContentEncoder/QpContentEncoder.php | 134 - .../ContentEncoder/QpContentEncoderProxy.php | 96 - .../Mime/ContentEncoder/RawContentEncoder.php | 65 - .../lib/classes/Swift/Mime/EmbeddedFile.php | 41 - .../classes/Swift/Mime/EncodingObserver.php | 22 - .../lib/classes/Swift/Mime/Header.php | 93 - .../HeaderEncoder/Base64HeaderEncoder.php | 55 - .../Mime/HeaderEncoder/QpHeaderEncoder.php | 65 - .../Swift/Mime/Headers/AbstractHeader.php | 486 --- .../classes/Swift/Mime/Headers/DateHeader.php | 113 - .../Mime/Headers/IdentificationHeader.php | 189 - .../Swift/Mime/Headers/MailboxHeader.php | 358 -- .../Swift/Mime/Headers/OpenDKIMHeader.php | 135 - .../Mime/Headers/ParameterizedHeader.php | 255 -- .../classes/Swift/Mime/Headers/PathHeader.php | 153 - .../Swift/Mime/Headers/UnstructuredHeader.php | 109 - .../lib/classes/Swift/Mime/IdGenerator.php | 54 - .../lib/classes/Swift/Mime/MimePart.php | 199 - .../Swift/Mime/SimpleHeaderFactory.php | 195 - .../classes/Swift/Mime/SimpleHeaderSet.php | 399 -- .../lib/classes/Swift/Mime/SimpleMessage.php | 642 --- .../classes/Swift/Mime/SimpleMimeEntity.php | 826 ---- .../lib/classes/Swift/MimePart.php | 45 - .../lib/classes/Swift/NullTransport.php | 26 - .../lib/classes/Swift/OutputByteStream.php | 46 - .../classes/Swift/Plugins/AntiFloodPlugin.php | 137 - .../Swift/Plugins/BandwidthMonitorPlugin.php | 154 - .../Swift/Plugins/Decorator/Replacements.php | 31 - .../classes/Swift/Plugins/DecoratorPlugin.php | 200 - .../Swift/Plugins/ImpersonatePlugin.php | 65 - .../lib/classes/Swift/Plugins/Logger.php | 36 - .../classes/Swift/Plugins/LoggerPlugin.php | 126 - .../Swift/Plugins/Loggers/ArrayLogger.php | 72 - .../Swift/Plugins/Loggers/EchoLogger.php | 58 - .../classes/Swift/Plugins/MessageLogger.php | 70 - .../Swift/Plugins/Pop/Pop3Connection.php | 31 - .../Swift/Plugins/Pop/Pop3Exception.php | 27 - .../Swift/Plugins/PopBeforeSmtpPlugin.php | 242 -- .../Swift/Plugins/RedirectingPlugin.php | 201 - .../lib/classes/Swift/Plugins/Reporter.php | 31 - .../classes/Swift/Plugins/ReporterPlugin.php | 57 - .../Swift/Plugins/Reporters/HitReporter.php | 58 - .../Swift/Plugins/Reporters/HtmlReporter.php | 38 - .../lib/classes/Swift/Plugins/Sleeper.php | 24 - .../classes/Swift/Plugins/ThrottlerPlugin.php | 196 - .../lib/classes/Swift/Plugins/Timer.php | 24 - .../lib/classes/Swift/Preferences.php | 100 - .../Swift/ReplacementFilterFactory.php | 27 - .../classes/Swift/RfcComplianceException.php | 27 - .../lib/classes/Swift/SendmailTransport.php | 33 - .../swiftmailer/lib/classes/Swift/Signer.php | 19 - .../lib/classes/Swift/Signers/BodySigner.php | 31 - .../lib/classes/Swift/Signers/DKIMSigner.php | 682 ---- .../classes/Swift/Signers/DomainKeySigner.php | 504 --- .../classes/Swift/Signers/HeaderSigner.php | 61 - .../classes/Swift/Signers/OpenDKIMSigner.php | 183 - .../lib/classes/Swift/Signers/SMimeSigner.php | 542 --- .../lib/classes/Swift/SmtpTransport.php | 45 - .../swiftmailer/lib/classes/Swift/Spool.php | 53 - .../lib/classes/Swift/SpoolTransport.php | 33 - .../lib/classes/Swift/StreamFilter.php | 35 - .../ByteArrayReplacementFilter.php | 166 - .../StreamFilters/StringReplacementFilter.php | 70 - .../StringReplacementFilterFactory.php | 45 - .../lib/classes/Swift/SwiftException.php | 28 - .../lib/classes/Swift/Transport.php | 76 - .../Swift/Transport/AbstractSmtpTransport.php | 541 --- .../Esmtp/Auth/CramMd5Authenticator.php | 75 - .../Esmtp/Auth/LoginAuthenticator.php | 45 - .../Esmtp/Auth/NTLMAuthenticator.php | 681 ---- .../Esmtp/Auth/PlainAuthenticator.php | 44 - .../Esmtp/Auth/XOAuth2Authenticator.php | 64 - .../Swift/Transport/Esmtp/AuthHandler.php | 268 -- .../Swift/Transport/Esmtp/Authenticator.php | 36 - .../Transport/Esmtp/EightBitMimeHandler.php | 113 - .../Swift/Transport/Esmtp/SmtpUtf8Handler.php | 107 - .../classes/Swift/Transport/EsmtpHandler.php | 86 - .../Swift/Transport/EsmtpTransport.php | 446 --- .../Swift/Transport/FailoverTransport.php | 103 - .../lib/classes/Swift/Transport/IoBuffer.php | 65 - .../Swift/Transport/LoadBalancedTransport.php | 192 - .../classes/Swift/Transport/NullTransport.php | 98 - .../Swift/Transport/SendmailTransport.php | 158 - .../lib/classes/Swift/Transport/SmtpAgent.php | 36 - .../Swift/Transport/SpoolTransport.php | 120 - .../classes/Swift/Transport/StreamBuffer.php | 319 -- .../lib/classes/Swift/TransportException.php | 28 - .../lib/dependency_maps/cache_deps.php | 23 - .../lib/dependency_maps/message_deps.php | 9 - .../lib/dependency_maps/mime_deps.php | 134 - .../lib/dependency_maps/transport_deps.php | 97 - .../swiftmailer/lib/mime_types.php | 1007 ----- .../swiftmailer/lib/preferences.php | 19 - .../swiftmailer/lib/swift_required.php | 22 - .../lib/swiftmailer_generate_mimes_config.php | 182 - .../symfony/amqp-messenger/CHANGELOG.md | 21 + .../amqp-messenger}/LICENSE | 2 +- .../vendor/symfony/amqp-messenger/README.md | 12 + .../amqp-messenger/Transport/AmqpFactory.php | 39 + .../Transport/AmqpReceivedStamp.php | 43 + .../amqp-messenger/Transport/AmqpReceiver.php | 150 + .../amqp-messenger/Transport/AmqpSender.php | 86 + .../amqp-messenger/Transport/AmqpStamp.php | 94 + .../Transport/AmqpTransport.php | 107 + .../Transport/AmqpTransportFactory.php | 38 + .../amqp-messenger/Transport/Connection.php | 583 +++ .../symfony/amqp-messenger/composer.json | 36 + .../symfony/deprecation-contracts/.gitignore | 3 + .../deprecation-contracts/CHANGELOG.md | 5 + .../symfony/deprecation-contracts/LICENSE | 19 + .../symfony/deprecation-contracts/README.md | 26 + .../deprecation-contracts/composer.json | 35 + .../deprecation-contracts/function.php | 27 + .../symfony/doctrine-messenger/CHANGELOG.md | 8 + .../vendor/symfony/doctrine-messenger/LICENSE | 19 + .../symfony/doctrine-messenger/README.md | 12 + .../Transport/Connection.php | 508 +++ .../Transport/DoctrineReceivedStamp.php | 36 + .../Transport/DoctrineReceiver.php | 175 + .../Transport/DoctrineSender.php | 60 + .../Transport/DoctrineTransport.php | 135 + .../Transport/DoctrineTransportFactory.php | 68 + .../Transport/PostgreSqlConnection.php | 150 + .../symfony/doctrine-messenger/composer.json | 40 + .../event-dispatcher-contracts/.gitignore | 3 + .../event-dispatcher-contracts/CHANGELOG.md | 5 + .../event-dispatcher-contracts/Event.php | 54 + .../EventDispatcherInterface.php | 31 + .../event-dispatcher-contracts/LICENSE | 19 + .../event-dispatcher-contracts/README.md | 9 + .../event-dispatcher-contracts/composer.json | 38 + .../Attribute/AsEventListener.php | 29 + .../symfony/event-dispatcher/CHANGELOG.md | 91 + .../Debug/TraceableEventDispatcher.php | 366 ++ .../Debug/WrappedListener.php | 127 + .../AddEventAliasesPass.php | 46 + .../RegisterListenersPass.php | 238 ++ .../event-dispatcher/EventDispatcher.php | 280 ++ .../EventDispatcherInterface.php | 70 + .../EventSubscriberInterface.php | 49 + .../symfony/event-dispatcher/GenericEvent.php | 182 + .../ImmutableEventDispatcher.php | 91 + .../vendor/symfony/event-dispatcher/LICENSE | 19 + .../LegacyEventDispatcherProxy.php | 31 + .../vendor/symfony/event-dispatcher/README.md | 15 + .../symfony/event-dispatcher/composer.json | 52 + .../email/vendor/symfony/mailer/CHANGELOG.md | 61 + .../DataCollector/MessageDataCollector.php | 68 + .../vendor/symfony/mailer/DelayedEnvelope.php | 98 + .../email/vendor/symfony/mailer/Envelope.php | 88 + .../symfony/mailer/Event/MessageEvent.php | 67 + .../symfony/mailer/Event/MessageEvents.php | 67 + .../mailer/EventListener/EnvelopeListener.php | 68 + .../mailer/EventListener/MessageListener.php | 134 + .../EventListener/MessageLoggerListener.php | 57 + .../mailer/Exception/ExceptionInterface.php | 21 + .../Exception/HttpTransportException.php | 40 + .../Exception/IncompleteDsnException.php | 19 + .../Exception/InvalidArgumentException.php | 19 + .../mailer/Exception/LogicException.php | 19 + .../mailer/Exception/RuntimeException.php | 19 + .../mailer/Exception/TransportException.php | 30 + .../Exception/TransportExceptionInterface.php | 22 + .../Exception/UnsupportedSchemeException.php | 81 + .../symfony/mailer/Header/MetadataHeader.php | 34 + .../symfony/mailer/Header/TagHeader.php | 25 + plugins/email/vendor/symfony/mailer/LICENSE | 19 + .../email/vendor/symfony/mailer/Mailer.php | 73 + .../vendor/symfony/mailer/MailerInterface.php | 30 + .../mailer/Messenger/MessageHandler.php | 33 + .../mailer/Messenger/SendEmailMessage.php | 40 + plugins/email/vendor/symfony/mailer/README.md | 74 + .../vendor/symfony/mailer/SentMessage.php | 95 + .../mailer/Test/Constraint/EmailCount.php | 73 + .../mailer/Test/Constraint/EmailIsQueued.php | 46 + .../mailer/Test/TransportFactoryTestCase.php | 117 + .../email/vendor/symfony/mailer/Transport.php | 206 + .../mailer/Transport/AbstractApiTransport.php | 46 + .../Transport/AbstractHttpTransport.php | 79 + .../mailer/Transport/AbstractTransport.php | 110 + .../Transport/AbstractTransportFactory.php | 61 + .../vendor/symfony/mailer/Transport/Dsn.php | 89 + .../mailer/Transport/FailoverTransport.php | 41 + .../Transport/NativeTransportFactory.php | 63 + .../mailer/Transport/NullTransport.php | 31 + .../mailer/Transport/NullTransportFactory.php | 34 + .../mailer/Transport/RoundRobinTransport.php | 121 + .../mailer/Transport/SendmailTransport.php | 123 + .../Transport/SendmailTransportFactory.php | 34 + .../Smtp/Auth/AuthenticatorInterface.php | 35 + .../Smtp/Auth/CramMd5Authenticator.php | 62 + .../Smtp/Auth/LoginAuthenticator.php | 39 + .../Smtp/Auth/PlainAuthenticator.php | 37 + .../Smtp/Auth/XOAuth2Authenticator.php | 39 + .../mailer/Transport/Smtp/EsmtpTransport.php | 200 + .../Transport/Smtp/EsmtpTransportFactory.php | 70 + .../mailer/Transport/Smtp/SmtpTransport.php | 361 ++ .../Transport/Smtp/Stream/AbstractStream.php | 138 + .../Transport/Smtp/Stream/ProcessStream.php | 65 + .../Transport/Smtp/Stream/SocketStream.php | 193 + .../Transport/TransportFactoryInterface.php | 29 + .../mailer/Transport/TransportInterface.php | 35 + .../symfony/mailer/Transport/Transports.php | 75 + .../email/vendor/symfony/mailer/composer.json | 43 + .../messenger/Attribute/AsMessageHandler.php | 30 + .../vendor/symfony/messenger/CHANGELOG.md | 212 + .../Command/AbstractFailedMessagesCommand.php | 298 ++ .../Command/ConsumeMessagesCommand.php | 267 ++ .../messenger/Command/DebugCommand.php | 150 + .../Command/FailedMessagesRemoveCommand.php | 104 + .../Command/FailedMessagesRetryCommand.php | 226 ++ .../Command/FailedMessagesShowCommand.php | 153 + .../Command/SetupTransportsCommand.php | 95 + .../messenger/Command/StopWorkersCommand.php | 75 + .../DataCollector/MessengerDataCollector.php | 149 + .../DependencyInjection/MessengerPass.php | 402 ++ .../vendor/symfony/messenger/Envelope.php | 131 + .../Event/AbstractWorkerMessageEvent.php | 45 + .../Event/SendMessageToTransportsEvent.php | 45 + .../Event/WorkerMessageFailedEvent.php | 47 + .../Event/WorkerMessageHandledEvent.php | 21 + .../Event/WorkerMessageReceivedEvent.php | 31 + .../Event/WorkerMessageRetriedEvent.php | 21 + .../messenger/Event/WorkerRunningEvent.php | 44 + .../messenger/Event/WorkerStartedEvent.php | 34 + .../messenger/Event/WorkerStoppedEvent.php | 34 + .../AddErrorDetailsStampListener.php | 38 + .../DispatchPcntlSignalListener.php | 37 + .../EventListener/ResetServicesListener.php | 50 + .../SendFailedMessageForRetryListener.php | 173 + ...ailedMessageToFailureTransportListener.php | 104 + ...topWorkerOnCustomStopExceptionListener.php | 57 + .../StopWorkerOnFailureLimitListener.php | 63 + .../StopWorkerOnMemoryLimitListener.php | 55 + .../StopWorkerOnMessageLimitListener.php | 57 + .../StopWorkerOnRestartSignalListener.php | 71 + .../StopWorkerOnSigtermSignalListener.php | 51 + .../StopWorkerOnTimeLimitListener.php | 58 + .../DelayedMessageHandlingException.php | 48 + .../Exception/ExceptionInterface.php | 21 + .../Exception/HandlerFailedException.php | 67 + .../Exception/InvalidArgumentException.php | 19 + .../messenger/Exception/LogicException.php | 19 + .../MessageDecodingFailedException.php | 19 + .../NoHandlerForMessageException.php | 19 + .../RecoverableExceptionInterface.php | 24 + .../RecoverableMessageHandlingException.php | 21 + .../RejectRedeliveredMessageException.php | 19 + .../messenger/Exception/RuntimeException.php | 19 + .../Exception/StopWorkerException.php | 23 + .../StopWorkerExceptionInterface.php | 19 + .../Exception/TransportException.php | 19 + .../UnrecoverableExceptionInterface.php | 24 + .../UnrecoverableMessageHandlingException.php | 21 + .../Exception/ValidationFailedException.php | 41 + .../vendor/symfony/messenger/HandleTrait.php | 61 + .../messenger/Handler/Acknowledger.php | 83 + .../Handler/BatchHandlerInterface.php | 34 + .../messenger/Handler/BatchHandlerTrait.php | 75 + .../messenger/Handler/HandlerDescriptor.php | 78 + .../messenger/Handler/HandlersLocator.php | 89 + .../Handler/HandlersLocatorInterface.php | 29 + .../Handler/MessageHandlerInterface.php | 21 + .../Handler/MessageSubscriberInterface.php | 49 + .../email/vendor/symfony/messenger/LICENSE | 19 + .../vendor/symfony/messenger/MessageBus.php | 79 + .../symfony/messenger/MessageBusInterface.php | 28 + .../Middleware/ActivationMiddleware.php | 46 + .../Middleware/AddBusNameStampMiddleware.php | 39 + .../DispatchAfterCurrentBusMiddleware.php | 133 + .../FailedMessageProcessingMiddleware.php | 36 + .../Middleware/HandleMessageMiddleware.php | 145 + .../Middleware/MiddlewareInterface.php | 22 + .../RejectRedeliveredMessageMiddleware.php | 50 + .../Middleware/RouterContextMiddleware.php | 88 + .../Middleware/SendMessageMiddleware.php | 79 + .../messenger/Middleware/StackInterface.php | 25 + .../messenger/Middleware/StackMiddleware.php | 92 + .../Middleware/TraceableMiddleware.php | 97 + .../Middleware/ValidationMiddleware.php | 50 + .../email/vendor/symfony/messenger/README.md | 29 + .../Retry/MultiplierRetryStrategy.php | 91 + .../Retry/RetryStrategyInterface.php | 34 + .../symfony/messenger/RoutableMessageBus.php | 68 + .../symfony/messenger/Stamp/AckStamp.php | 35 + .../symfony/messenger/Stamp/BusNameStamp.php | 32 + .../messenger/Stamp/ConsumedByWorkerStamp.php | 19 + .../symfony/messenger/Stamp/DelayStamp.php | 46 + .../Stamp/DispatchAfterCurrentBusStamp.php | 23 + .../messenger/Stamp/ErrorDetailsStamp.php | 96 + .../Stamp/FlushBatchHandlersStamp.php | 30 + .../symfony/messenger/Stamp/HandledStamp.php | 62 + .../messenger/Stamp/NoAutoAckStamp.php | 32 + .../Stamp/NonSendableStampInterface.php | 21 + .../symfony/messenger/Stamp/ReceivedStamp.php | 39 + .../messenger/Stamp/RedeliveryStamp.php | 92 + .../messenger/Stamp/RouterContextStamp.php | 79 + .../symfony/messenger/Stamp/SentStamp.php | 41 + .../Stamp/SentToFailureTransportStamp.php | 32 + .../messenger/Stamp/SerializerStamp.php | 30 + .../messenger/Stamp/StampInterface.php | 23 + .../Stamp/TransportMessageIdStamp.php | 35 + .../messenger/Stamp/ValidationStamp.php | 35 + .../Test/Middleware/MiddlewareTestCase.php | 60 + .../symfony/messenger/TraceableMessageBus.php | 108 + .../Transport/AmqpExt/AmqpFactory.php | 27 + .../Transport/AmqpExt/AmqpReceivedStamp.php | 27 + .../Transport/AmqpExt/AmqpReceiver.php | 27 + .../Transport/AmqpExt/AmqpSender.php | 27 + .../messenger/Transport/AmqpExt/AmqpStamp.php | 27 + .../Transport/AmqpExt/AmqpTransport.php | 27 + .../AmqpExt/AmqpTransportFactory.php | 27 + .../Transport/AmqpExt/Connection.php | 27 + .../Transport/Doctrine/Connection.php | 27 + .../Doctrine/DoctrineReceivedStamp.php | 27 + .../Transport/Doctrine/DoctrineReceiver.php | 27 + .../Transport/Doctrine/DoctrineSender.php | 27 + .../Transport/Doctrine/DoctrineTransport.php | 27 + .../Doctrine/DoctrineTransportFactory.php | 27 + .../messenger/Transport/InMemoryTransport.php | 166 + .../Transport/InMemoryTransportFactory.php | 57 + .../Receiver/ListableReceiverInterface.php | 40 + .../Receiver/MessageCountAwareInterface.php | 26 + .../Receiver/QueueReceiverInterface.php | 31 + .../Transport/Receiver/ReceiverInterface.php | 61 + .../Receiver/SingleMessageReceiver.php | 55 + .../Transport/RedisExt/Connection.php | 27 + .../Transport/RedisExt/RedisReceivedStamp.php | 27 + .../Transport/RedisExt/RedisReceiver.php | 27 + .../Transport/RedisExt/RedisSender.php | 27 + .../Transport/RedisExt/RedisTransport.php | 27 + .../RedisExt/RedisTransportFactory.php | 27 + .../Transport/Sender/SenderInterface.php | 30 + .../Transport/Sender/SendersLocator.php | 60 + .../Sender/SendersLocatorInterface.php | 30 + .../Normalizer/FlattenExceptionNormalizer.php | 100 + .../Transport/Serialization/PhpSerializer.php | 92 + .../Transport/Serialization/Serializer.php | 183 + .../Serialization/SerializerInterface.php | 48 + .../Transport/SetupableTransportInterface.php | 23 + .../Transport/Sync/SyncTransport.php | 65 + .../Transport/Sync/SyncTransportFactory.php | 40 + .../messenger/Transport/TransportFactory.php | 67 + .../Transport/TransportFactoryInterface.php | 26 + .../Transport/TransportInterface.php | 22 + .../email/vendor/symfony/messenger/Worker.php | 268 ++ .../symfony/messenger/WorkerMetadata.php | 47 + .../vendor/symfony/messenger/composer.json | 57 + plugins/email/vendor/symfony/mime/Address.php | 149 + .../symfony/mime/BodyRendererInterface.php | 20 + .../email/vendor/symfony/mime/CHANGELOG.md | 26 + .../vendor/symfony/mime/CharacterStream.php | 218 + .../symfony/mime/Crypto/DkimOptions.php | 97 + .../vendor/symfony/mime/Crypto/DkimSigner.php | 220 + .../vendor/symfony/mime/Crypto/SMime.php | 111 + .../symfony/mime/Crypto/SMimeEncrypter.php | 63 + .../symfony/mime/Crypto/SMimeSigner.php | 65 + .../AddMimeTypeGuesserPass.php | 50 + plugins/email/vendor/symfony/mime/Email.php | 630 +++ .../mime/Encoder/AddressEncoderInterface.php | 28 + .../mime/Encoder/Base64ContentEncoder.php | 45 + .../symfony/mime/Encoder/Base64Encoder.php | 41 + .../mime/Encoder/Base64MimeHeaderEncoder.php | 43 + .../mime/Encoder/ContentEncoderInterface.php | 30 + .../mime/Encoder/EightBitContentEncoder.php | 35 + .../symfony/mime/Encoder/EncoderInterface.php | 26 + .../mime/Encoder}/IdnAddressEncoder.php | 24 +- .../Encoder/MimeHeaderEncoderInterface.php} | 15 +- .../symfony/mime/Encoder/QpContentEncoder.php | 60 + .../mime}/Encoder/QpEncoder.php | 167 +- .../mime/Encoder/QpMimeHeaderEncoder.php | 40 + .../symfony/mime/Encoder/Rfc2231Encoder.php | 50 + .../Exception/AddressEncoderException.php | 19 + .../mime/Exception/ExceptionInterface.php | 19 + .../Exception/InvalidArgumentException.php | 19 + .../symfony/mime/Exception/LogicException.php | 19 + .../mime/Exception/RfcComplianceException.php | 19 + .../mime/Exception/RuntimeException.php | 19 + .../mime/FileBinaryMimeTypeGuesser.php | 93 + .../symfony/mime/FileinfoMimeTypeGuesser.php | 69 + .../symfony/mime/Header/AbstractHeader.php | 284 ++ .../vendor/symfony/mime/Header/DateHeader.php | 66 + .../symfony/mime/Header/HeaderInterface.php | 65 + .../vendor/symfony/mime/Header/Headers.php | 307 ++ .../mime/Header/IdentificationHeader.php | 110 + .../symfony/mime/Header/MailboxHeader.php | 85 + .../symfony/mime/Header/MailboxListHeader.php | 136 + .../mime/Header/ParameterizedHeader.php | 191 + .../vendor/symfony/mime/Header/PathHeader.php | 62 + .../mime/Header/UnstructuredHeader.php | 69 + plugins/email/vendor/symfony/mime/LICENSE | 19 + plugins/email/vendor/symfony/mime/Message.php | 160 + .../vendor/symfony/mime/MessageConverter.php | 125 + .../symfony/mime/MimeTypeGuesserInterface.php | 33 + .../email/vendor/symfony/mime/MimeTypes.php | 3537 +++++++++++++++++ .../symfony/mime/MimeTypesInterface.php | 32 + .../mime/Part/AbstractMultipartPart.php | 99 + .../vendor/symfony/mime/Part/AbstractPart.php | 65 + .../vendor/symfony/mime/Part/DataPart.php | 183 + .../vendor/symfony/mime/Part/MessagePart.php | 62 + .../mime/Part/Multipart/AlternativePart.php | 25 + .../mime/Part/Multipart/DigestPart.php | 31 + .../mime/Part/Multipart/FormDataPart.php | 112 + .../symfony/mime/Part/Multipart/MixedPart.php | 25 + .../mime/Part/Multipart/RelatedPart.php | 55 + .../vendor/symfony/mime/Part/SMimePart.php | 121 + .../vendor/symfony/mime/Part/TextPart.php | 215 + plugins/email/vendor/symfony/mime/README.md | 13 + .../email/vendor/symfony/mime/RawMessage.php | 91 + .../mime/Resources/bin/update_mime_types.php | 161 + .../Test/Constraint/EmailAddressContains.php | 74 + .../Test/Constraint/EmailAttachmentCount.php | 60 + .../mime/Test/Constraint/EmailHasHeader.php | 57 + .../mime/Test/Constraint/EmailHeaderSame.php | 69 + .../Test/Constraint/EmailHtmlBodyContains.php | 58 + .../Test/Constraint/EmailTextBodyContains.php | 58 + .../email/vendor/symfony/mime/composer.json | 46 + .../symfony/polyfill-intl-idn/README.md | 2 +- .../symfony/polyfill-intl-idn/composer.json | 2 +- .../polyfill-intl-normalizer/README.md | 2 +- .../polyfill-intl-normalizer/composer.json | 2 +- .../vendor/symfony/polyfill-php80/LICENSE | 19 + .../vendor/symfony/polyfill-php80/Php80.php | 115 + .../symfony/polyfill-php80/PhpToken.php | 103 + .../vendor/symfony/polyfill-php80/README.md | 25 + .../Resources/stubs/Attribute.php | 22 + .../Resources/stubs/PhpToken.php | 7 + .../Resources/stubs/Stringable.php | 11 + .../Resources/stubs/UnhandledMatchError.php | 7 + .../Resources/stubs/ValueError.php | 7 + .../symfony/polyfill-php80/bootstrap.php | 42 + .../symfony/polyfill-php80/composer.json | 40 + .../symfony/redis-messenger/CHANGELOG.md | 34 + .../vendor/symfony/redis-messenger/LICENSE | 19 + .../vendor/symfony/redis-messenger/README.md | 12 + .../redis-messenger/Transport/Connection.php | 596 +++ .../Transport/RedisClusterProxy.php | 42 + .../redis-messenger/Transport/RedisProxy.php | 43 + .../Transport/RedisReceivedStamp.php | 36 + .../Transport/RedisReceiver.php | 102 + .../redis-messenger/Transport/RedisSender.php | 53 + .../Transport/RedisTransport.php | 90 + .../Transport/RedisTransportFactory.php | 39 + .../symfony/redis-messenger/composer.json | 34 + .../symfony/service-contracts/.gitignore | 3 + .../service-contracts/Attribute/Required.php | 25 + .../Attribute/SubscribedService.php | 33 + .../symfony/service-contracts/CHANGELOG.md | 5 + .../vendor/symfony/service-contracts/LICENSE | 19 + .../symfony/service-contracts/README.md | 9 + .../service-contracts/ResetInterface.php | 30 + .../service-contracts/ServiceLocatorTrait.php | 128 + .../ServiceProviderInterface.php | 36 + .../ServiceSubscriberInterface.php | 53 + .../ServiceSubscriberTrait.php | 109 + .../Test/ServiceLocatorTest.php | 95 + .../symfony/service-contracts/composer.json | 42 + plugins/flex-objects/CHANGELOG.md | 6 + .../types/default/buttons/add.html.twig | 2 +- .../default/buttons/export-csv.html.twig | 2 +- .../types/default/buttons/export.html.twig | 4 +- .../types/default/buttons/preview.html.twig | 2 +- .../flex-objects/types/default/list.html.twig | 4 +- .../types/default/titlebar/list.html.twig | 2 +- .../types/pages/buttons/preview.html.twig | 2 +- plugins/flex-objects/blueprints.yaml | 2 +- plugins/form/CHANGELOG.md | 8 + plugins/form/blueprints.yaml | 4 +- plugins/form/form.php | 4 +- .../templates/forms/default/form.html.twig | 2 +- .../forms/fields/file/file.html.twig | 8 +- plugins/langswitcher/CHANGELOG.md | 6 + plugins/langswitcher/blueprints.yaml | 2 +- plugins/langswitcher/langswitcher.php | 4 +- plugins/login/CHANGELOG.md | 8 + plugins/login/blueprints.yaml | 6 +- .../classes/TwoFactorAuth/BaconQrProvider.php | 14 +- plugins/login/composer.json | 2 +- plugins/login/composer.lock | 82 +- plugins/login/vendor/autoload.php | 18 + .../vendor/bacon/bacon-qr-code/.gitignore | 9 - .../vendor/bacon/bacon-qr-code/.travis.yml | 14 - .../vendor/bacon/bacon-qr-code/CHANGELOG.md | 37 - .../login/vendor/bacon/bacon-qr-code/LICENSE | 2 +- .../vendor/bacon/bacon-qr-code/Module.php | 37 - .../vendor/bacon/bacon-qr-code/README.md | 37 +- .../bacon/bacon-qr-code/autoload_classmap.php | 43 - .../bacon/bacon-qr-code/autoload_function.php | 12 - .../bacon/bacon-qr-code/autoload_register.php | 2 - .../vendor/bacon/bacon-qr-code/composer.json | 29 +- .../bacon/bacon-qr-code/phpunit.xml.dist | 13 + .../src/BaconQrCode/Common/AbstractEnum.php | 115 - .../src/BaconQrCode/Common/BitArray.php | 435 -- .../src/BaconQrCode/Common/BitMatrix.php | 350 -- .../src/BaconQrCode/Common/BitUtils.php | 51 - .../BaconQrCode/Common/CharacterSetEci.php | 134 - .../src/BaconQrCode/Common/EcBlock.php | 65 - .../src/BaconQrCode/Common/EcBlocks.php | 101 - .../Common/ErrorCorrectionLevel.php | 62 - .../BaconQrCode/Common/FormatInformation.php | 236 -- .../src/BaconQrCode/Common/Mode.php | 70 - .../BaconQrCode/Common/ReedSolomonCodec.php | 476 --- .../src/BaconQrCode/Common/Version.php | 687 ---- .../src/BaconQrCode/Encoder/BlockPair.php | 64 - .../src/BaconQrCode/Encoder/ByteMatrix.php | 158 - .../src/BaconQrCode/Encoder/Encoder.php | 687 ---- .../src/BaconQrCode/Encoder/MaskUtil.php | 291 -- .../src/BaconQrCode/Encoder/MatrixUtil.php | 580 --- .../src/BaconQrCode/Encoder/QrCode.php | 201 - .../Exception/ExceptionInterface.php | 14 - .../Exception/InvalidArgumentException.php | 14 - .../Exception/OutOfBoundsException.php | 14 - .../Exception/RuntimeException.php | 14 - .../Exception/UnexpectedValueException.php | 14 - .../BaconQrCode/Exception/WriterException.php | 14 - .../src/BaconQrCode/Renderer/Color/Cmyk.php | 160 - .../Renderer/Color/ColorInterface.php | 37 - .../src/BaconQrCode/Renderer/Color/Gray.php | 84 - .../src/BaconQrCode/Renderer/Color/Rgb.php | 148 - .../Renderer/Image/AbstractRenderer.php | 338 -- .../Image/Decorator/DecoratorInterface.php | 63 - .../Image/Decorator/FinderPattern.php | 210 - .../src/BaconQrCode/Renderer/Image/Eps.php | 152 - .../src/BaconQrCode/Renderer/Image/Png.php | 115 - .../Renderer/Image/RendererInterface.php | 61 - .../src/BaconQrCode/Renderer/Image/Svg.php | 146 - .../Renderer/RendererInterface.php | 26 - .../src/BaconQrCode/Renderer/Text/Html.php | 91 - .../src/BaconQrCode/Renderer/Text/Plain.php | 150 - .../bacon-qr-code/src/BaconQrCode/Writer.php | 105 - .../src/Common/CharacterSetEci.php | 3 + .../src/Common/FormatInformation.php | 2 +- .../bacon/bacon-qr-code/src/Common/Mode.php | 3 + .../bacon-qr-code/src/Encoder/Encoder.php | 20 +- .../bacon-qr-code/src/Encoder/MaskUtil.php | 2 +- .../src/Renderer/Eye/CompositeEye.php | 2 +- .../Renderer/Image/ImagickImageBackEnd.php | 9 +- .../src/Renderer/Image/SvgImageBackEnd.php | 4 +- .../Renderer/Image/TransformationMatrix.php | 5 +- .../Module/EdgeIterator/EdgeIterator.php | 2 +- .../src/Renderer/Path/EllipticArc.php | 2 +- .../bacon-qr-code/src/Renderer/Path/Move.php | 2 +- .../vendor/bacon/bacon-qr-code/src/Writer.php | 11 +- .../test/Common/BitArrayTest.php | 222 ++ .../Common/BitMatrixTest.php | 72 +- .../test/Common/BitUtilsTest.php | 25 + .../test/Common/ErrorCorrectionLevelTest.php | 25 + .../test/Common/FormatInformationTest.php | 94 + .../bacon-qr-code/test/Common/ModeTest.php | 19 + .../test/Common/ReedSolomonCodecTest.php | 96 + .../bacon-qr-code/test/Common/VersionTest.php | 78 + .../test/Encoder/EncoderTest.php | 487 +++ .../test/Encoder/MaskUtilTest.php | 251 ++ .../Encoder/MatrixUtilTest.php | 115 +- .../test/Integration/ImagickRenderingTest.php | 72 + ...ickRenderingTest__testGenericQrCode__1.png | Bin 0 -> 3111 bytes .../ImagickRenderingTest__testIssue79__1.png | Bin 0 -> 8366 bytes .../tests/BaconQrCode/Common/BitArrayTest.php | 201 - .../tests/BaconQrCode/Common/BitUtilsTest.php | 30 - .../Common/ErrorCorrectionLevelTest.php | 40 - .../Common/FormatInformationTest.php | 104 - .../tests/BaconQrCode/Common/ModeTest.php | 42 - .../Common/ReedSolomonCodecTest.php | 111 - .../tests/BaconQrCode/Common/VersionTest.php | 88 - .../tests/BaconQrCode/Encoder/EncoderTest.php | 468 --- .../BaconQrCode/Encoder/MaskUtilTest.php | 281 -- .../BaconQrCode/Renderer/Text/HtmlTest.php | 99 - .../BaconQrCode/Renderer/Text/TextTest.php | 149 - .../bacon/bacon-qr-code/tests/bootstrap.php | 10 - .../bacon/bacon-qr-code/tests/phpunit.xml | 11 - plugins/login/vendor/composer/ClassLoader.php | 41 +- .../vendor/composer/InstalledVersions.php | 33 +- .../vendor/composer/autoload_classmap.php | 2 +- .../login/vendor/composer/autoload_files.php | 2 +- .../vendor/composer/autoload_namespaces.php | 3 +- .../login/vendor/composer/autoload_psr4.php | 4 +- .../login/vendor/composer/autoload_real.php | 56 +- .../login/vendor/composer/autoload_static.php | 20 +- plugins/login/vendor/composer/installed.json | 87 +- plugins/login/vendor/composer/installed.php | 29 +- .../login/vendor/dasprid/enum/.coveralls.yml | 2 - .../dasprid/enum/.github/workflows/tests.yml | 47 + plugins/login/vendor/dasprid/enum/.gitignore | 3 - plugins/login/vendor/dasprid/enum/.travis.yml | 41 - plugins/login/vendor/dasprid/enum/LICENSE | 22 + plugins/login/vendor/dasprid/enum/README.md | 30 +- .../login/vendor/dasprid/enum/composer.json | 10 +- plugins/login/vendor/dasprid/enum/phpcs.xml | 30 - .../vendor/dasprid/enum/src/AbstractEnum.php | 6 +- .../login/vendor/dasprid/enum/src/EnumMap.php | 42 +- .../vendor/dasprid/enum/src/NullValue.php | 2 +- .../dasprid/enum/test/AbstractEnumTest.php | 2 +- plugins/page-toc/CHANGELOG.md | 13 + plugins/page-toc/README.md | 16 + plugins/page-toc/blueprints.yaml | 2 +- plugins/page-toc/classes/HtmlHelper.php | 3 +- .../templates/components/page-toc.html.twig | 7 +- plugins/pagination/CHANGELOG.md | 6 + plugins/pagination/blueprints.yaml | 2 +- .../classes/plugin/PaginationHelper.php | 2 +- plugins/readingtime/CHANGELOG.md | 6 + plugins/readingtime/blueprints.yaml | 2 +- .../classes/TwigReadingTimeFilters.php | 2 +- plugins/readingtime/composer.lock | 3 +- plugins/readingtime/vendor/autoload.php | 18 + .../vendor/composer/ClassLoader.php | 190 +- .../vendor/composer/InstalledVersions.php | 359 ++ .../vendor/composer/autoload_classmap.php | 3 +- .../vendor/composer/autoload_namespaces.php | 2 +- .../vendor/composer/autoload_psr4.php | 2 +- .../vendor/composer/autoload_real.php | 30 +- .../vendor/composer/autoload_static.php | 1 + .../vendor/composer/installed.json | 6 +- .../readingtime/vendor/composer/installed.php | 23 + .../vendor/composer/platform_check.php | 26 + themes/mytheme/css/style.css | 4 +- 761 files changed, 36153 insertions(+), 34720 deletions(-) create mode 100644 plugins/email/classes/Message.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Validation/DNSGetRecordWrapper.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Validation/DNSRecords.php create mode 100644 plugins/email/vendor/psr/container/.gitignore create mode 100644 plugins/email/vendor/psr/container/LICENSE create mode 100644 plugins/email/vendor/psr/container/README.md create mode 100644 plugins/email/vendor/psr/container/composer.json create mode 100644 plugins/email/vendor/psr/container/src/ContainerExceptionInterface.php create mode 100644 plugins/email/vendor/psr/container/src/ContainerInterface.php create mode 100644 plugins/email/vendor/psr/container/src/NotFoundExceptionInterface.php create mode 100644 plugins/email/vendor/psr/event-dispatcher/.editorconfig create mode 100644 plugins/email/vendor/psr/event-dispatcher/.gitignore create mode 100644 plugins/email/vendor/psr/event-dispatcher/LICENSE create mode 100644 plugins/email/vendor/psr/event-dispatcher/README.md create mode 100644 plugins/email/vendor/psr/event-dispatcher/composer.json create mode 100644 plugins/email/vendor/psr/event-dispatcher/src/EventDispatcherInterface.php create mode 100644 plugins/email/vendor/psr/event-dispatcher/src/ListenerProviderInterface.php create mode 100644 plugins/email/vendor/psr/event-dispatcher/src/StoppableEventInterface.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/.gitattributes delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/.github/ISSUE_TEMPLATE.md delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/.github/PULL_REQUEST_TEMPLATE.md delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/.github/workflows/tests.yml delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/.gitignore delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/.php_cs.dist delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/CHANGES delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/README.md delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/composer.json delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/doc/headers.rst delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/doc/index.rst delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/doc/introduction.rst delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/doc/japanese.rst delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/doc/messages.rst delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/doc/plugins.rst delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/doc/sending.rst delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoder.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoder/Utf8AddressEncoder.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoderException.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Attachment.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory/SimpleCharacterReaderFactory.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/ArrayCharacterStream.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ConfigurableSpool.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyException.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/EmbeddedFile.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Base64Encoder.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandEvent.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandListener.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/Event.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/EventDispatcher.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/EventListener.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/EventObject.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseListener.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendEvent.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendListener.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SimpleEventDispatcher.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionEvent.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FailoverTransport.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileSpool.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileStream.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Filterable.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/IdGenerator.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Image.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/InputByteStream.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/IoException.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/ArrayKeyCache.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/NullKeyCache.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/SimpleKeyCacheInputStream.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Message.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Attachment.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/Base64ContentEncoder.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NullContentEncoder.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Header.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/Base64HeaderEncoder.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/AbstractHeader.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/IdGenerator.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/MimePart.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderFactory.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MimePart.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/NullTransport.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/OutputByteStream.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/AntiFloodPlugin.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/DecoratorPlugin.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Logger.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/LoggerPlugin.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Exception.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/PopBeforeSmtpPlugin.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporter.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ReporterPlugin.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ThrottlerPlugin.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Timer.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Preferences.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/RfcComplianceException.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SendmailTransport.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signer.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/BodySigner.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SmtpTransport.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Spool.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SpoolTransport.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilter.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/ByteArrayReplacementFilter.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SwiftException.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/EightBitMimeHandler.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/SmtpUtf8Handler.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpHandler.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/LoadBalancedTransport.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/NullTransport.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SmtpAgent.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SpoolTransport.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/TransportException.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/cache_deps.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/message_deps.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/mime_deps.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/transport_deps.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/mime_types.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/preferences.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/swift_required.php delete mode 100644 plugins/email/vendor/swiftmailer/swiftmailer/lib/swiftmailer_generate_mimes_config.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/CHANGELOG.md rename plugins/email/vendor/{swiftmailer/swiftmailer => symfony/amqp-messenger}/LICENSE (96%) create mode 100644 plugins/email/vendor/symfony/amqp-messenger/README.md create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpFactory.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpReceivedStamp.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpReceiver.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpSender.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpStamp.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpTransport.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpTransportFactory.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/Connection.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/composer.json create mode 100644 plugins/email/vendor/symfony/deprecation-contracts/.gitignore create mode 100644 plugins/email/vendor/symfony/deprecation-contracts/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/deprecation-contracts/LICENSE create mode 100644 plugins/email/vendor/symfony/deprecation-contracts/README.md create mode 100644 plugins/email/vendor/symfony/deprecation-contracts/composer.json create mode 100644 plugins/email/vendor/symfony/deprecation-contracts/function.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/LICENSE create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/README.md create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/Transport/Connection.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineReceivedStamp.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineReceiver.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineSender.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineTransport.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineTransportFactory.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/Transport/PostgreSqlConnection.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/composer.json create mode 100644 plugins/email/vendor/symfony/event-dispatcher-contracts/.gitignore create mode 100644 plugins/email/vendor/symfony/event-dispatcher-contracts/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/event-dispatcher-contracts/Event.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher-contracts/LICENSE create mode 100644 plugins/email/vendor/symfony/event-dispatcher-contracts/README.md create mode 100644 plugins/email/vendor/symfony/event-dispatcher-contracts/composer.json create mode 100644 plugins/email/vendor/symfony/event-dispatcher/Attribute/AsEventListener.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/Debug/WrappedListener.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/EventDispatcher.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/EventDispatcherInterface.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/EventSubscriberInterface.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/GenericEvent.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/LICENSE create mode 100644 plugins/email/vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/README.md create mode 100644 plugins/email/vendor/symfony/event-dispatcher/composer.json create mode 100644 plugins/email/vendor/symfony/mailer/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/mailer/DataCollector/MessageDataCollector.php create mode 100644 plugins/email/vendor/symfony/mailer/DelayedEnvelope.php create mode 100644 plugins/email/vendor/symfony/mailer/Envelope.php create mode 100644 plugins/email/vendor/symfony/mailer/Event/MessageEvent.php create mode 100644 plugins/email/vendor/symfony/mailer/Event/MessageEvents.php create mode 100644 plugins/email/vendor/symfony/mailer/EventListener/EnvelopeListener.php create mode 100644 plugins/email/vendor/symfony/mailer/EventListener/MessageListener.php create mode 100644 plugins/email/vendor/symfony/mailer/EventListener/MessageLoggerListener.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/ExceptionInterface.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/HttpTransportException.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/IncompleteDsnException.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/InvalidArgumentException.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/LogicException.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/RuntimeException.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/TransportException.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/TransportExceptionInterface.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/UnsupportedSchemeException.php create mode 100644 plugins/email/vendor/symfony/mailer/Header/MetadataHeader.php create mode 100644 plugins/email/vendor/symfony/mailer/Header/TagHeader.php create mode 100644 plugins/email/vendor/symfony/mailer/LICENSE create mode 100644 plugins/email/vendor/symfony/mailer/Mailer.php create mode 100644 plugins/email/vendor/symfony/mailer/MailerInterface.php create mode 100644 plugins/email/vendor/symfony/mailer/Messenger/MessageHandler.php create mode 100644 plugins/email/vendor/symfony/mailer/Messenger/SendEmailMessage.php create mode 100644 plugins/email/vendor/symfony/mailer/README.md create mode 100644 plugins/email/vendor/symfony/mailer/SentMessage.php create mode 100644 plugins/email/vendor/symfony/mailer/Test/Constraint/EmailCount.php create mode 100644 plugins/email/vendor/symfony/mailer/Test/Constraint/EmailIsQueued.php create mode 100644 plugins/email/vendor/symfony/mailer/Test/TransportFactoryTestCase.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/AbstractApiTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/AbstractHttpTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/AbstractTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/AbstractTransportFactory.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Dsn.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/FailoverTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/NativeTransportFactory.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/NullTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/NullTransportFactory.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/RoundRobinTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/SendmailTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/SendmailTransportFactory.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/AuthenticatorInterface.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/CramMd5Authenticator.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/LoginAuthenticator.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/PlainAuthenticator.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/EsmtpTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/EsmtpTransportFactory.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/SmtpTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Stream/AbstractStream.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Stream/ProcessStream.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Stream/SocketStream.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/TransportFactoryInterface.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/TransportInterface.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Transports.php create mode 100644 plugins/email/vendor/symfony/mailer/composer.json create mode 100644 plugins/email/vendor/symfony/messenger/Attribute/AsMessageHandler.php create mode 100644 plugins/email/vendor/symfony/messenger/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/messenger/Command/AbstractFailedMessagesCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/Command/ConsumeMessagesCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/Command/DebugCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/Command/FailedMessagesRemoveCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/Command/FailedMessagesRetryCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/Command/FailedMessagesShowCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/Command/SetupTransportsCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/Command/StopWorkersCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/DataCollector/MessengerDataCollector.php create mode 100644 plugins/email/vendor/symfony/messenger/DependencyInjection/MessengerPass.php create mode 100644 plugins/email/vendor/symfony/messenger/Envelope.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/AbstractWorkerMessageEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/SendMessageToTransportsEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/WorkerMessageFailedEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/WorkerMessageHandledEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/WorkerMessageReceivedEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/WorkerMessageRetriedEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/WorkerRunningEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/WorkerStartedEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/WorkerStoppedEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/AddErrorDetailsStampListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/DispatchPcntlSignalListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/ResetServicesListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/SendFailedMessageForRetryListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/SendFailedMessageToFailureTransportListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnCustomStopExceptionListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnFailureLimitListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnMemoryLimitListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnMessageLimitListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnRestartSignalListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnSigtermSignalListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnTimeLimitListener.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/DelayedMessageHandlingException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/ExceptionInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/HandlerFailedException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/InvalidArgumentException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/LogicException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/MessageDecodingFailedException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/NoHandlerForMessageException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/RecoverableExceptionInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/RecoverableMessageHandlingException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/RejectRedeliveredMessageException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/RuntimeException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/StopWorkerException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/StopWorkerExceptionInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/TransportException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/UnrecoverableExceptionInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/UnrecoverableMessageHandlingException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/ValidationFailedException.php create mode 100644 plugins/email/vendor/symfony/messenger/HandleTrait.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/Acknowledger.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/BatchHandlerInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/BatchHandlerTrait.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/HandlerDescriptor.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/HandlersLocator.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/HandlersLocatorInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/MessageHandlerInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/MessageSubscriberInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/LICENSE create mode 100644 plugins/email/vendor/symfony/messenger/MessageBus.php create mode 100644 plugins/email/vendor/symfony/messenger/MessageBusInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/ActivationMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/AddBusNameStampMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/DispatchAfterCurrentBusMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/FailedMessageProcessingMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/HandleMessageMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/MiddlewareInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/RejectRedeliveredMessageMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/RouterContextMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/SendMessageMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/StackInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/StackMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/TraceableMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/ValidationMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/README.md create mode 100644 plugins/email/vendor/symfony/messenger/Retry/MultiplierRetryStrategy.php create mode 100644 plugins/email/vendor/symfony/messenger/Retry/RetryStrategyInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/RoutableMessageBus.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/AckStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/BusNameStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/ConsumedByWorkerStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/DelayStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/DispatchAfterCurrentBusStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/ErrorDetailsStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/FlushBatchHandlersStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/HandledStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/NoAutoAckStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/NonSendableStampInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/ReceivedStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/RedeliveryStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/RouterContextStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/SentStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/SentToFailureTransportStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/SerializerStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/StampInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/TransportMessageIdStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/ValidationStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Test/Middleware/MiddlewareTestCase.php create mode 100644 plugins/email/vendor/symfony/messenger/TraceableMessageBus.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpFactory.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpReceivedStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpReceiver.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpSender.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpTransport.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpTransportFactory.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/Connection.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Doctrine/Connection.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineReceivedStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineReceiver.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineSender.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineTransport.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineTransportFactory.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/InMemoryTransport.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/InMemoryTransportFactory.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Receiver/ListableReceiverInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Receiver/MessageCountAwareInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Receiver/QueueReceiverInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Receiver/ReceiverInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Receiver/SingleMessageReceiver.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/RedisExt/Connection.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisReceivedStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisReceiver.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisSender.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisTransport.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisTransportFactory.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Sender/SenderInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Sender/SendersLocator.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Sender/SendersLocatorInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Serialization/Normalizer/FlattenExceptionNormalizer.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Serialization/PhpSerializer.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Serialization/Serializer.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Serialization/SerializerInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/SetupableTransportInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Sync/SyncTransport.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Sync/SyncTransportFactory.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/TransportFactory.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/TransportFactoryInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/TransportInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Worker.php create mode 100644 plugins/email/vendor/symfony/messenger/WorkerMetadata.php create mode 100644 plugins/email/vendor/symfony/messenger/composer.json create mode 100644 plugins/email/vendor/symfony/mime/Address.php create mode 100644 plugins/email/vendor/symfony/mime/BodyRendererInterface.php create mode 100644 plugins/email/vendor/symfony/mime/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/mime/CharacterStream.php create mode 100644 plugins/email/vendor/symfony/mime/Crypto/DkimOptions.php create mode 100644 plugins/email/vendor/symfony/mime/Crypto/DkimSigner.php create mode 100644 plugins/email/vendor/symfony/mime/Crypto/SMime.php create mode 100644 plugins/email/vendor/symfony/mime/Crypto/SMimeEncrypter.php create mode 100644 plugins/email/vendor/symfony/mime/Crypto/SMimeSigner.php create mode 100644 plugins/email/vendor/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php create mode 100644 plugins/email/vendor/symfony/mime/Email.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/AddressEncoderInterface.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/Base64ContentEncoder.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/Base64Encoder.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/Base64MimeHeaderEncoder.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/ContentEncoderInterface.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/EightBitContentEncoder.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/EncoderInterface.php rename plugins/email/vendor/{swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoder => symfony/mime/Encoder}/IdnAddressEncoder.php (50%) rename plugins/email/vendor/{swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder.php => symfony/mime/Encoder/MimeHeaderEncoderInterface.php} (52%) create mode 100644 plugins/email/vendor/symfony/mime/Encoder/QpContentEncoder.php rename plugins/email/vendor/{swiftmailer/swiftmailer/lib/classes/Swift => symfony/mime}/Encoder/QpEncoder.php (61%) create mode 100644 plugins/email/vendor/symfony/mime/Encoder/QpMimeHeaderEncoder.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/Rfc2231Encoder.php create mode 100644 plugins/email/vendor/symfony/mime/Exception/AddressEncoderException.php create mode 100644 plugins/email/vendor/symfony/mime/Exception/ExceptionInterface.php create mode 100644 plugins/email/vendor/symfony/mime/Exception/InvalidArgumentException.php create mode 100644 plugins/email/vendor/symfony/mime/Exception/LogicException.php create mode 100644 plugins/email/vendor/symfony/mime/Exception/RfcComplianceException.php create mode 100644 plugins/email/vendor/symfony/mime/Exception/RuntimeException.php create mode 100644 plugins/email/vendor/symfony/mime/FileBinaryMimeTypeGuesser.php create mode 100644 plugins/email/vendor/symfony/mime/FileinfoMimeTypeGuesser.php create mode 100644 plugins/email/vendor/symfony/mime/Header/AbstractHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Header/DateHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Header/HeaderInterface.php create mode 100644 plugins/email/vendor/symfony/mime/Header/Headers.php create mode 100644 plugins/email/vendor/symfony/mime/Header/IdentificationHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Header/MailboxHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Header/MailboxListHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Header/ParameterizedHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Header/PathHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Header/UnstructuredHeader.php create mode 100644 plugins/email/vendor/symfony/mime/LICENSE create mode 100644 plugins/email/vendor/symfony/mime/Message.php create mode 100644 plugins/email/vendor/symfony/mime/MessageConverter.php create mode 100644 plugins/email/vendor/symfony/mime/MimeTypeGuesserInterface.php create mode 100644 plugins/email/vendor/symfony/mime/MimeTypes.php create mode 100644 plugins/email/vendor/symfony/mime/MimeTypesInterface.php create mode 100644 plugins/email/vendor/symfony/mime/Part/AbstractMultipartPart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/AbstractPart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/DataPart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/MessagePart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/Multipart/AlternativePart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/Multipart/DigestPart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/Multipart/FormDataPart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/Multipart/MixedPart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/Multipart/RelatedPart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/SMimePart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/TextPart.php create mode 100644 plugins/email/vendor/symfony/mime/README.md create mode 100644 plugins/email/vendor/symfony/mime/RawMessage.php create mode 100644 plugins/email/vendor/symfony/mime/Resources/bin/update_mime_types.php create mode 100644 plugins/email/vendor/symfony/mime/Test/Constraint/EmailAddressContains.php create mode 100644 plugins/email/vendor/symfony/mime/Test/Constraint/EmailAttachmentCount.php create mode 100644 plugins/email/vendor/symfony/mime/Test/Constraint/EmailHasHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Test/Constraint/EmailHeaderSame.php create mode 100644 plugins/email/vendor/symfony/mime/Test/Constraint/EmailHtmlBodyContains.php create mode 100644 plugins/email/vendor/symfony/mime/Test/Constraint/EmailTextBodyContains.php create mode 100644 plugins/email/vendor/symfony/mime/composer.json create mode 100644 plugins/email/vendor/symfony/polyfill-php80/LICENSE create mode 100644 plugins/email/vendor/symfony/polyfill-php80/Php80.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/PhpToken.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/README.md create mode 100644 plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/bootstrap.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/composer.json create mode 100644 plugins/email/vendor/symfony/redis-messenger/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/redis-messenger/LICENSE create mode 100644 plugins/email/vendor/symfony/redis-messenger/README.md create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/Connection.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/RedisClusterProxy.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/RedisProxy.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/RedisReceivedStamp.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/RedisReceiver.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/RedisSender.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/RedisTransport.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/RedisTransportFactory.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/composer.json create mode 100644 plugins/email/vendor/symfony/service-contracts/.gitignore create mode 100644 plugins/email/vendor/symfony/service-contracts/Attribute/Required.php create mode 100644 plugins/email/vendor/symfony/service-contracts/Attribute/SubscribedService.php create mode 100644 plugins/email/vendor/symfony/service-contracts/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/service-contracts/LICENSE create mode 100644 plugins/email/vendor/symfony/service-contracts/README.md create mode 100644 plugins/email/vendor/symfony/service-contracts/ResetInterface.php create mode 100644 plugins/email/vendor/symfony/service-contracts/ServiceLocatorTrait.php create mode 100644 plugins/email/vendor/symfony/service-contracts/ServiceProviderInterface.php create mode 100644 plugins/email/vendor/symfony/service-contracts/ServiceSubscriberInterface.php create mode 100644 plugins/email/vendor/symfony/service-contracts/ServiceSubscriberTrait.php create mode 100644 plugins/email/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php create mode 100644 plugins/email/vendor/symfony/service-contracts/composer.json delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/.gitignore delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/.travis.yml delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/CHANGELOG.md delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/Module.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/autoload_classmap.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/autoload_function.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/autoload_register.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/phpunit.xml.dist delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/AbstractEnum.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitArray.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitMatrix.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitUtils.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/CharacterSetEci.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlock.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlocks.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ErrorCorrectionLevel.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/FormatInformation.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Mode.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ReedSolomonCodec.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Version.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/BlockPair.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/ByteMatrix.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/Encoder.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MaskUtil.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MatrixUtil.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/QrCode.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/ExceptionInterface.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/InvalidArgumentException.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/OutOfBoundsException.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/RuntimeException.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/UnexpectedValueException.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/WriterException.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Cmyk.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/ColorInterface.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Gray.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Rgb.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/AbstractRenderer.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/FinderPattern.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Eps.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Png.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/RendererInterface.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Svg.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/RendererInterface.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Html.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Plain.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Writer.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Common/BitArrayTest.php rename plugins/login/vendor/bacon/bacon-qr-code/{tests/BaconQrCode => test}/Common/BitMatrixTest.php (50%) create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Common/BitUtilsTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Common/ErrorCorrectionLevelTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Common/FormatInformationTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Common/ModeTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Common/ReedSolomonCodecTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Common/VersionTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Encoder/EncoderTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Encoder/MaskUtilTest.php rename plugins/login/vendor/bacon/bacon-qr-code/{tests/BaconQrCode => test}/Encoder/MatrixUtilTest.php (78%) create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Integration/ImagickRenderingTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Integration/__snapshots__/files/ImagickRenderingTest__testGenericQrCode__1.png create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue79__1.png delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitArrayTest.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitUtilsTest.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ErrorCorrectionLevelTest.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/FormatInformationTest.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ModeTest.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ReedSolomonCodecTest.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/VersionTest.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/EncoderTest.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MaskUtilTest.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/HtmlTest.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/TextTest.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/tests/bootstrap.php delete mode 100644 plugins/login/vendor/bacon/bacon-qr-code/tests/phpunit.xml delete mode 100644 plugins/login/vendor/dasprid/enum/.coveralls.yml create mode 100644 plugins/login/vendor/dasprid/enum/.github/workflows/tests.yml delete mode 100644 plugins/login/vendor/dasprid/enum/.gitignore delete mode 100644 plugins/login/vendor/dasprid/enum/.travis.yml create mode 100644 plugins/login/vendor/dasprid/enum/LICENSE delete mode 100644 plugins/login/vendor/dasprid/enum/phpcs.xml create mode 100644 plugins/readingtime/vendor/composer/InstalledVersions.php create mode 100644 plugins/readingtime/vendor/composer/installed.php create mode 100644 plugins/readingtime/vendor/composer/platform_check.php diff --git a/plugins/admin/CHANGELOG.md b/plugins/admin/CHANGELOG.md index eefddfc..5183336 100644 --- a/plugins/admin/CHANGELOG.md +++ b/plugins/admin/CHANGELOG.md @@ -1,3 +1,25 @@ +# v1.10.41.2 +## 05/11/2023 + +1. [](#improved) + * Fixed an issue with `lastBackup()` that caused admin dashboard to fail with an error. + +# v1.10.41.1 +## 05/09/2023 + +1. [](#improved) + * Fixed another Toolbox deprecation error for `lastBackup()` + +# v1.10.41 +## 05/09/2023 + +1. [](#new) + * Updated to use new `BaconQRCode` version `2.0.8` for new SVG features + PHP 8.2+ fixes +1. [](#improved) + * Require Grav `v1.7.41` + * Fixed a deprecated message where `Admin::$routes` was being dynamically defined + * Fixes to use non-deprecated methods in `ScssCompiler` + # v1.10.40 ## 03/22/2023 diff --git a/plugins/admin/blueprints.yaml b/plugins/admin/blueprints.yaml index 89d0500..ab6f115 100644 --- a/plugins/admin/blueprints.yaml +++ b/plugins/admin/blueprints.yaml @@ -1,7 +1,7 @@ name: Admin Panel slug: admin type: plugin -version: 1.10.40 +version: 1.10.41.2 description: Adds an advanced administration panel to manage your site icon: empire author: @@ -15,7 +15,7 @@ docs: https://github.com/getgrav/grav-plugin-admin/blob/develop/README.md license: MIT dependencies: - - { name: grav, version: '>=1.7.32' } + - { name: grav, version: '>=1.7.41' } - { name: form, version: '>=6.0.1' } - { name: login, version: '>=3.7.0' } - { name: email, version: '>=3.1.6' } diff --git a/plugins/admin/classes/plugin/Admin.php b/plugins/admin/classes/plugin/Admin.php index 1d6dee8..4f465c9 100644 --- a/plugins/admin/classes/plugin/Admin.php +++ b/plugins/admin/classes/plugin/Admin.php @@ -102,6 +102,9 @@ class Admin /** @var array */ public $languages_enabled = []; /** @var Uri $uri */ + + /** @var array */ + public $routes = []; protected $uri; /** @var array */ protected $pages = []; @@ -1435,9 +1438,15 @@ class Admin */ public function lastBackup() { - $file = JsonFile::instance($this->grav['locator']->findResource('log://backup.log')); - $content = $file->content(); - if (empty($content)) { + $backup_file = $this->grav['locator']->findResource('log://backup.log'); + $content = null; + + if ($backup_file) { + $file = JsonFile::instance((string) $backup_file); + $content = $file->content() ?? null; + } + + if (!file_exists($backup_file) || is_null($content) || !isset($content['time'])) { return [ 'days' => '∞', 'chart_fill' => 100, @@ -1448,10 +1457,8 @@ class Admin $backup = new \DateTime(); $backup->setTimestamp($content['time']); $diff = $backup->diff(new \DateTime()); - - $days = $diff->days; + $days = $diff->days; $chart_fill = $days > 30 ? 100 : round($days / 30 * 100); - return [ 'days' => $days, 'chart_fill' => $chart_fill, diff --git a/plugins/admin/classes/plugin/ScssCompiler.php b/plugins/admin/classes/plugin/ScssCompiler.php index 66f0179..f8aac97 100644 --- a/plugins/admin/classes/plugin/ScssCompiler.php +++ b/plugins/admin/classes/plugin/ScssCompiler.php @@ -10,6 +10,7 @@ namespace Grav\Plugin\Admin; use ScssPhp\ScssPhp\Compiler; +use ScssPhp\ScssPhp\ValueConverter; class ScssCompiler { @@ -31,7 +32,13 @@ class ScssCompiler public function setVariables(array $variables) { - $this->compiler()->setVariables($variables); +// $parsed = ValueConverter::fromPhp($variables); + $parsed = []; + foreach ($variables as $key => $value) { + $parsed[$key] = ValueConverter::parseValue($value); + } + + $this->compiler()->addVariables($parsed); return $this; } @@ -55,7 +62,7 @@ class ScssCompiler foreach ($input_paths as $input_file) { $input .= trim(file_get_contents($input_file)) . "\n\n"; } - $output = $this->compiler()->compile($input); + $output = $this->compiler()->compileString($input)->getCss(); file_put_contents($output_file, $output); return $this; } diff --git a/plugins/admin/composer.json b/plugins/admin/composer.json index 3d53295..328482a 100644 --- a/plugins/admin/composer.json +++ b/plugins/admin/composer.json @@ -22,7 +22,7 @@ "require": { "php": "^7.3.6 || ^8.0", "ext-json": "*", - "scssphp/scssphp": "^1.7", + "scssphp/scssphp": "^1.11", "laminas/laminas-zendframework-bridge": "^1.4", "p3k/picofeed": "@stable" }, diff --git a/plugins/admin/composer.lock b/plugins/admin/composer.lock index 49bfa02..633fd39 100644 --- a/plugins/admin/composer.lock +++ b/plugins/admin/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": "1f6a6bec99c3a85ac753a1548c22f5d7", + "content-hash": "bc8a9ba032ce28a2c93282b6f1a6e7b9", "packages": [ { "name": "laminas/laminas-xml", @@ -900,16 +900,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.9.0", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318" + "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", - "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/e4490cabc77465aaee90b20cfc9a770f8c04be6b", + "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b", "shasum": "" }, "require": { @@ -928,11 +928,6 @@ "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.9-dev" - } - }, "autoload": { "files": [ "src/functions_include.php" @@ -990,7 +985,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/1.9.0" + "source": "https://github.com/guzzle/psr7/tree/1.9.1" }, "funding": [ { @@ -1006,7 +1001,7 @@ "type": "tidelift" } ], - "time": "2022-06-20T21:43:03+00:00" + "time": "2023-04-17T16:00:37+00:00" }, { "name": "myclabs/deep-copy", @@ -1834,25 +1829,25 @@ }, { "name": "psr/http-message", - "version": "1.0.1", + "version": "1.1", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { @@ -1881,9 +1876,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/master" + "source": "https://github.com/php-fig/http-message/tree/1.1" }, - "time": "2016-08-06T14:39:51+00:00" + "time": "2023-04-04T09:50:52+00:00" }, { "name": "ralouphie/getallheaders", @@ -2060,16 +2055,16 @@ }, { "name": "sebastian/diff", - "version": "3.0.3", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211" + "reference": "6296a0c086dd0117c1b78b059374d7fcbe7545ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/14f72dd46eaf2f2293cbe79c93cc0bc43161a211", - "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/6296a0c086dd0117c1b78b059374d7fcbe7545ae", + "reference": "6296a0c086dd0117c1b78b059374d7fcbe7545ae", "shasum": "" }, "require": { @@ -2114,7 +2109,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/diff/tree/3.0.4" }, "funding": [ { @@ -2122,7 +2117,7 @@ "type": "github" } ], - "time": "2020-11-30T07:59:04+00:00" + "time": "2023-05-07T05:30:20+00:00" }, { "name": "sebastian/environment", diff --git a/plugins/admin/vendor/composer/InstalledVersions.php b/plugins/admin/vendor/composer/InstalledVersions.php index c6b54af..51e734a 100644 --- a/plugins/admin/vendor/composer/InstalledVersions.php +++ b/plugins/admin/vendor/composer/InstalledVersions.php @@ -98,7 +98,7 @@ class InstalledVersions { foreach (self::getInstalled() as $installed) { if (isset($installed['versions'][$packageName])) { - return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; } } @@ -119,7 +119,7 @@ class InstalledVersions */ public static function satisfies(VersionParser $parser, $packageName, $constraint) { - $constraint = $parser->parseConstraints($constraint); + $constraint = $parser->parseConstraints((string) $constraint); $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); return $provided->matches($constraint); @@ -328,7 +328,9 @@ class InstalledVersions if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (is_file($vendorDir.'/composer/installed.php')) { - $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require $vendorDir.'/composer/installed.php'; + $installed[] = self::$installedByVendor[$vendorDir] = $required; if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { self::$installed = $installed[count($installed) - 1]; } @@ -340,12 +342,17 @@ class InstalledVersions // only require the installed.php file if this file is loaded from its dumped location, // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 if (substr(__DIR__, -8, 1) !== 'C') { - self::$installed = require __DIR__ . '/installed.php'; + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; } else { self::$installed = array(); } } - $installed[] = self::$installed; + + if (self::$installed !== array()) { + $installed[] = self::$installed; + } return $installed; } diff --git a/plugins/admin/vendor/composer/installed.php b/plugins/admin/vendor/composer/installed.php index fa3c034..df62166 100644 --- a/plugins/admin/vendor/composer/installed.php +++ b/plugins/admin/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'getgrav/grav-plugin-admin', 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', - 'reference' => '5f1b3e1e4a413bf5e45e99b8d5aa174b6806c12c', + 'reference' => 'be85fb4194474700fbd8fe60b48b27613b47ce59', 'type' => 'grav-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -13,7 +13,7 @@ 'getgrav/grav-plugin-admin' => array( 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', - 'reference' => '5f1b3e1e4a413bf5e45e99b8d5aa174b6806c12c', + 'reference' => 'be85fb4194474700fbd8fe60b48b27613b47ce59', 'type' => 'grav-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), diff --git a/plugins/email/CHANGELOG.md b/plugins/email/CHANGELOG.md index b43d05f..f892ce1 100644 --- a/plugins/email/CHANGELOG.md +++ b/plugins/email/CHANGELOG.md @@ -1,3 +1,51 @@ +# v4.0.1 +## 05/20/2023 + +1. [](#bugfix) + * Fixed a bug with Email 4.0 ignoring `template:` parameter when dealing with multiple body sections + +# v4.0.0 +## 05/09/2023 + +1. [](#new) + * Migrated from `Swiftmailer` (which has been deprecated) to `Symfony/Mailer`, a more modern and extensible mailing library. + * Built-in support for `SMTP`, `SMTPS`, `Sendmail` and `Native` (uses best solution per-platform) engines + * Added ability to have 3rd party plugins that provide new engines (e.g. `SendGrid`, `MailJet`, etc.) with `SMTP`, `API` or `HTTPS` transports for faster and more reliable email sending + * More flexible options for email formatting including RFC822 `name-addr` format (`Joe Bloggs `) and simple arrays (`[user@example.com, Joe Bloggs]`) + * Support `tags` and `metadata` in `Email::buildMessage()` + * Two new events `onEmailEngines` and `onEmailTransportDsn` to facilitate the integration of custom engines via plugins + +# v4.0.0-rc.4 +## 02/27/2023 + +1. [](#bugfix) + * Fixed for multiple recipients [#167](https://github.com/getgrav/grav-plugin-email/issues/167) + * Fix for simple array format with names which wasn't working + +# v4.0.0-rc.3 +## 10/27/2022 + +1. [](#bugfix) + * Fixed an issue with array based email address + +# v4.0.0-rc.2 +## 10/19/2022 + +1. [](#improved) + * Set `sendmail` as default engine to provide better fallback for unsupported `mailer` option + * Added info about available engine plugins in `README.md` + +# v4.0.0-rc.1 +## 10/05/2022 + +1. [](#new) + * Migrated from `Swiftmailer` (which has been deprecated) to `Symfony/Mailer`, a more modern and extensible mailing library. + * Built-in support for `SMTP`, `SMTPS`, `Sendmail` and `Native` (uses best solution per-platform) engines + * Added ability to have 3rd party plugins that provide new engines (e.g. `SendGrid`, `MailJet`, etc.) with `SMTP`, `API` or `HTTPS` transports for faster and more reliable email sending + * More flexible options for email formatting including RFC822 `name-addr` format (`Joe Bloggs `) and simple arrays (`[user@example.com, Joe Bloggs]`) + * Support `tags` and `metadata` in `Email::buildMessage()` + * Two new events `onEmailEngines` and `onEmailTransportDsn` to facilitate the integration of custom engines via plugins + # v3.2.0 ## 03/28/2022 diff --git a/plugins/email/README.md b/plugins/email/README.md index ec37e95..794b2e6 100644 --- a/plugins/email/README.md +++ b/plugins/email/README.md @@ -1,6 +1,8 @@ # Grav Email Plugin -The **email plugin** for [Grav](http://github.com/getgrav/grav) adds the ability to send email. This is particularly useful for the **admin** and **login** plugins. +The **email plugin** for [Grav](http://github.com/getgrav/grav) adds the ability to send email utilizing the `symfony/mailer` package. This is particularly useful for the **admin** and **login** plugins. + +> IMPORTANT: **Version 4.0** replaced the old deprecated **SwiftMailer** library with **Symfony/Mailer** package. This is a modern and well supported library that also has the capability to support 3rd party transport engines such as `SendGrid`, `MailJet`, `MailGun`, `MailChimp`, etc. This library should be backwards compatible with existing configurations, but please create an issue if you run into any problems. # Installation @@ -12,28 +14,20 @@ $ bin/gpm install email # Configuration -By default, the plugin uses PHP Mail as the mail engine. +The plugin uses `sendmail` binary as the default mail engine. ``` enabled: true from: -from_name: to: -to_name: -queue: - enabled: true - flush_frequency: '* * * * *' - flush_msg_limit: 10 - flush_time_limit: 100 mailer: engine: sendmail smtp: server: localhost port: 25 encryption: none - user: '' - password: '' - auth_mode: '' + user: + password: sendmail: bin: '/usr/sbin/sendmail -bs' content_type: text/html @@ -48,9 +42,51 @@ The first setting you'd likely change is your `Email from` / `Email to` names an Also, you'd likely want to setup a SMTP server instead of using PHP Mail, as the latter is not 100% reliable and you might experience problems with emails. -Valid values for `auth_mode` include `plain`, `login`, `cram-md5`, or `null`. +## Built-in Engines -> NOTE: `engine: mail` has been deprecated from the SwiftMail library that this plugin uses as it does not funtion at all. Please use `smtp` if at all possibe, and `sendmail` if SMTP is not an option. +By default Email 4.0 supports 4 native engines: + +* SMTP - Standard "Simple Mail Transport Protocol" - The default for most providers +* SMTPS - "Simple Mail Transport Protocol Secure" - Not very commonly used +* Sendmail - Uses the built-in `sendmail` binary file available on many Linux and Mac systems +* Native - Uses `sendmail_path` of `php.ini` for Mac + Linux, and `smtp` and `smtp_port` on Windows + +Due to the modular nature of Symfony/Mailer, 3rd party engines are supported via Grav plugins. + +## 3rd-Party Engines Plugin Support + +Along with the **Email** `v4.0` release, there has also been several custom provider plugins released to provide support for `SMTP`, `API`, and sometimes even `HTTPS` support for 3rd party providers such as **Sendgrid**, **MailJet**, **MailGun**, **Amazon SES**, **Mailchimp/Mandrill**, and others! `API` or `HTTPS` will provide a faster email sending experience compared to `SMTP` which is an older protocol and requires more back-and-forth negotiation and communication compared to the single-request of `API` or `HTTPS` solutions. + +Examples of the currently available plugins include: + +* https://github.com/getgrav/grav-plugin-email-sendgrid - Sengrid Mailer +* https://github.com/getgrav/grav-plugin-email-amazon - Amazon SES +* https://github.com/getgrav/grav-plugin-email-mandrill - Mailchimp Mandrill Mailer +* https://github.com/getgrav/grav-plugin-email-mailersend - Mailersend Mailer + +More plugins will be released soon to support `Gmail`, `Mailgun`, `Mailjet`, `OhMySMTP`, `Postmark`, and `SendInBlue`. + +## SMTP Configurations for popular solutions: + +### Google Email + +A popular option for sending email is to simply use your Google Accounts SMTP server. To set this up you will need to do 2 things first: + +As Gmail no longer supports the "allow less secure apps" option, you now need to have 2FA enabled on the account and setup an "App Password" to create a specific password rather than your general account password. Follow these instructions: [https://support.google.com/accounts/answer/185833](https://support.google.com/accounts/answer/185833) + +Then configure the Email plugin: + +``` +mailer: + engine: smtp + smtp: + server: smtp.gmail.com + port: 587 + user: 'YOUR_GOOGLE_EMAIL_ADDRESS' + password: 'YOUR_GOOGLE_PASSWORD' +``` + +> NOTE: Check your email sending limits: https://support.google.com/a/answer/166852?hl=en ### Mailtrap.io @@ -73,30 +109,7 @@ That service will intercept emails and show them on their web-based interface in You can try and fine tune the emails there while testing. -### Google Email - -A popular option for sending email is to simply use your Google Accounts SMTP server. To set this up you will need to do 2 things first: - -1. Enable IMAP in your Gmail `Settings` -> `Forwarding and POP/IMAP` -> `IMAP Access` -2. Enable `Less secure apps` in your [user account settings](https://myaccount.google.com/lesssecureapps) -3. If you have 2-factor authentication, you will need to create a unique application password to use rather than your personal password - -Then configure the Email plugin: - -``` -mailer: - engine: smtp - smtp: - server: smtp.gmail.com - port: 587 - encryption: tls - user: 'YOUR_GOOGLE_EMAIL_ADDRESS' - password: 'YOUR_GOOGLE_PASSWORD' -``` - -> NOTE: Check your email sending limits: https://support.google.com/a/answer/166852?hl=en - -#### Sparkpost +### Sparkpost Generous email sending limits even in the free tier, and simple setup, make [Sparkpost](https://www.sparkpost.com) a great option for email sending. You just need to create an account, then setup a verified sending domain. Sparkpost does a nice job of making this process very easy and undertandable. Then just click on the SMTP Relay option to get your details for the configuration: @@ -106,14 +119,13 @@ mailer: smtp: server: smtp.sparkpostmail.com port: 587 - encryption: tls user: 'SMTP_Injection' password: 'SEND_EMAIL_API_KEY' ``` Then try sending a test email... -#### Sendgrid +### Sendgrid [Sendgrid](https://sendgrid.com) offers a very easy-to-setup serivce with 100 emails/day for free. The next level allows you to send 40k/email a day for just $10/month. Configuration is pretty simple, just create an account, then click SMTP integration and click the button to create an API key. The configuration is as follows: @@ -123,12 +135,11 @@ mailer: smtp: server: smtp.sendgrid.net port: 587 - encryption: tls user: 'apikey' password: 'YOUR_SENDGRID_API_KEY' ``` -#### Mailgun +### Mailgun [Mailgun is a great service](https://www.mailgun.com/) that offers 10k/emails per month for free. Setup does require SPIF domain verification so that means you need to add at least a TXT entry in your DNS. This is pretty standard for SMTP sending services and does provide verification for remote email servers and makes your email sending more reliable. The Mailgun site, walks you through this process however, and the verification process is simple and fast. @@ -138,14 +149,13 @@ mailer: smtp: server: smtp.mailgun.org port: 587 - encryption: tls user: 'MAILGUN_EMAIL_ADDRESS' password: 'MAILGUN_EMAIL_PASSWORD' ``` Adjust these configurations for your account. -#### MailJet +### MailJet Mailjet is another great service that is easy to quickly setup and get started sending email. The free account gives you 200 emails/day or 600 emails/month. Just signup and setup your SPF and DKIM entries for your domain. Then click on the SMTP settings and use those to configure the email plugin: @@ -155,18 +165,15 @@ mailer: smtp: server: in-v3.mailjet.com port: 587 - encryption: tls user: 'MAILJUST_USERNAME_API_KEY' password: 'MAILJUST_PASSWORD_SECRET_KEY' ``` -It's that easy! - -#### ZOHO +### ZOHO ZOHO is a popular solution for hosted email due to it's great 'FREE' tier. It's paid options are also very reasonable and combined with the latest UI updates and outstanding security features, it's a solid email option. -In order to get ZOHO working with Grav, you need to send email via a user account. You can either use your users' password or generate an **App Password** via your ZOHO account (clicking on your avatar once logged in), then navigating to `Two Factor Authentication -> App Passwords -> Generate`. Just enter a unique app name (i.e. `Grav Website`). +In order to get ZOHO working with Grav, you need to send email via a user account. You can either use your users' password or generate an **App Password** via your ZOHO account (clicking on your avatar once logged in), then navigating to `My Account -> Security -> App Passwords -> Generate`. Just enter a unique app name (i.e. `Grav Website`). NOTE: The SMTP host required can be found in `Settings -> Mail - > Mail Accounts -> POP/IMAP -> SMTP`. This will provide the SMTP server for this account (it may not be `imap.zoho.com` depending on what region you are in) @@ -176,12 +183,11 @@ mailer: smtp: server: smtp.zoho.com port: 587 - encryption: tls user: 'ZOHO_EMAIL_ADDRESS' password: 'ZOHO_EMAIL_PASSWORD' ``` -#### Sendmail +### Sendmail Although not as reliable as SMTP not providing as much debug information, sendmail is a simple option as long as your hosting provider is not blocking the default SMTP port `25`: @@ -194,7 +200,7 @@ mailer: Simply adjust your binary command line to suite your environment -### SMTP Email Services +## SMTP Email Services Solid SMTP options that even provide a FREE tier for low email volumes include: @@ -206,30 +212,18 @@ Solid SMTP options that even provide a FREE tier for low email volumes include: If you are still unsure why should be using one in the first place, check out this article: https://zapier.com/learn/email-marketing/best-transactional-email-sending-services/ -## Email Queue - -For performance reasons, it's often desirable to queue emails and send them in batches, rather than forcing Grav to wait while an email is sent. This is because email servers are sometimes slow and you might not want to wait for the whole email-sending process before continuing with Grav processing. - -To address this, you can enable the **Email Queue** and this will ensure all email's in Grav are actually sent to the queue, and not sent directly. In order for the emails to be actually sent, you need to flush the queue. By default this is handled by the **Grav Scheduler**, so you need to ensure you have that enabled and setup correctly or **your emails will not be sent!!!**. - -You can also manually flush the queue by using the provided CLI command: - -``` -$ bin/plugin email flush-queue -``` - ## Testing with CLI Command You can test your email configuration with the following CLI Command: ``` -$ bin/plugin email test-email -t steve@apple.com +$ bin/plugin email test-email -t test@email.com ``` You can also pass in a configuration environment: ``` -$ bin/plugin email test-email -t steve@apple.com -e mysite.com +$ bin/plugin email test-email -t test@email.com --env=mysite.com ``` This will use the email configuration you have located in `user/mysite.com/config/plugins/email.yaml`. Read the docs to find out more about environment-based configuration: https://learn.getgrav.org/advanced/environment-config @@ -271,11 +265,8 @@ form: email: subject: "[Custom form] {{ form.value.name|e }}" body: "{% include 'forms/data.txt.twig' %}" - from: sender@example.com - from_name: 'Custom sender name' - to: recipient@example.com - to_name: 'Custom recipient name' - content_type: 'text/plain' + from: Custom Sender + to: Custom Recipient process_markdown: true ``` @@ -298,14 +289,14 @@ form: - subject: "[Custom Email 1] {{ form.value.name|e }}" body: "{% include 'forms/data.txt.twig' %}" - from: {mail: "owner@mysite.com", name: "Site OWner"} - to: {mail: "recepient_1@example.com", name: "Recepient 1"} + from: Site Owner + to: Recipient 1 template: "email/base.html.twig" - subject: "[Custom Email 2] {{ form.value.name|e }}" body: "{% include 'forms/data.txt.twig' %}" - from: {mail: "owner@mysite.com", name: "Site OWner"} - to: {mail: "recepient_2@example.com", name: "Recepient 1"} + from: Site Owner + to: Recipient 2 template: "email/base.html.twig" ``` @@ -379,7 +370,6 @@ To have more control over your generated email, you may also use the following a * `reply_to`: Set one or more addresses that should be used to reply to the message. * `cc` _(Carbon copy)_: Add one or more addresses to the delivery list. Many email clients will mark email in one's inbox differently depending on whether they are in the `To:` or `Cc:` list. * `bcc` _(Blind carbon copy)_: Add one or more addresses to the delivery list that should (usually) not be listed in the message data, remaining invisible to other recipients. -* `charset`: Explicitly set a charset for the generated email body (only takes effect if `body` parameter is a string, defaults to `utf-8`) ### Specifying email addresses @@ -391,6 +381,12 @@ Email-related parameters (`from`, `to`, `reply_to`, `cc`and `bcc`) allow differe to: mail@example.com ``` +#### `name-addr` RFC822 Formatted string + +``` +to: Joe Bloggs +``` + #### Multiple email address strings ``` @@ -400,49 +396,64 @@ to: - mail+2@example.com ``` -#### Single email address with name +or in `name-addr` format: ``` to: - mail: mail@example.com - name: Human-readable name + - Joe Bloggs + - Jane Doe + - Jasper Jesperson +``` + +#### Simple array format with names + +``` +to: [mail@exmaple.com, Joe Bloggs] +``` + +#### Formatted email address with names + +``` +to: + email: mail@example.com + name: Joe Bloggs ``` or inline: ``` -to: {mail: 'mail@example.com', name: 'Human-readable name'} +to: {email: 'mail@example.com', name: 'Joe Bloggs'} ``` #### Multiple email addresses (with and without names) +``` +to: + - [mail@example.com, Joe Bloggs] + - [mail+2@example.com, Jane Doe] +``` + ``` to: - - mail: mail@example.com - name: Human-readable name + email: mail@example.com + name: Joe Bloggs - - mail: mail+2@example.com - name: Another human-readable name - - - mail+3@example.com - - - mail+4@example.com + email: mail+2@example.com + name: Jane Doe ``` or inline: ``` to: - - {mail: 'mail@example.com', name: 'Human-readable name'} - - {mail: 'mail+2@example.com', name: 'Another human-readable name'} - - mail+3@example.com - - mail+4@example.com + - {email: 'mail@example.com', name: 'Joe Bloggs'} + - {email: 'mail+2@example.com', name: 'Jane Doe'} ``` ## Multi-part MIME messages -Apart from a simple string, an email body may contain different MIME parts (e.g. HTML body with plain text fallback). You may even specify a different charset for each part (default to `utf-8`): +Apart from a simple string, an email body may contain different MIME parts (e.g. HTML body with plain text fallback): ``` body: @@ -452,7 +463,7 @@ body: - content_type: 'text/plain' body: "{% include 'forms/default/data.txt.twig' %}" - charset: 'iso-8859-1' + ``` # Troubleshooting diff --git a/plugins/email/blueprints.yaml b/plugins/email/blueprints.yaml index 2a5f50c..68c89de 100644 --- a/plugins/email/blueprints.yaml +++ b/plugins/email/blueprints.yaml @@ -1,7 +1,7 @@ name: Email slug: email type: plugin -version: 3.2.0 +version: 4.0.1 testing: false description: Enables the emailing system for Grav icon: envelope @@ -15,8 +15,8 @@ bugs: https://github.com/getgrav/grav-plugin-email/issues license: MIT dependencies: - - { name: grav, version: '>=1.7.32' } - - { name: form, version: '>=6.0.0' } + - { name: grav, version: '>=1.7.41' } + - { name: form, version: '>=7.0.0' } form: validation: loose @@ -37,106 +37,8 @@ form: type: select label: PLUGIN_EMAIL.MAIL_ENGINE size: medium - options: - none: PLUGIN_ADMIN.DISABLED - smtp: SMTP - sendmail: Sendmail - - content_type: - type: select - label: PLUGIN_EMAIL.CONTENT_TYPE - size: medium - default: 'text/html' - options: - 'text/plain': PLUGIN_EMAIL.CONTENT_TYPE_PLAIN_TEXT - 'text/html': HTML - - charset: - type: text - size: medium - label: PLUGIN_EMAIL.CHARSET - placeholder: PLUGIN_EMAIL.CHARSET_PLACEHOLDER - - email_Defaults: - type: section - title: PLUGIN_EMAIL.EMAIL_DEFAULTS - underline: true - - from: - type: email - size: medium - label: PLUGIN_EMAIL.EMAIL_FORM - placeholder: PLUGIN_EMAIL.EMAIL_FORM_PLACEHOLDER - validate: - required: true - type: email - - from_name: - type: text - size: medium - label: PLUGIN_EMAIL.EMAIL_FROM_NAME - placeholder: PLUGIN_EMAIL.EMAIL_FROM_NAME_PLACEHOLDER - - to: - type: email - size: medium - label: PLUGIN_EMAIL.EMAIL_TO - placeholder: PLUGIN_EMAIL.EMAIL_TO_PLACEHOLDER - multiple: true - validate: - required: true - type: email - - to_name: - type: text - size: medium - label: PLUGIN_EMAIL.EMAIL_TO_NAME - placeholder: PLUGIN_EMAIL.EMAIL_TO_NAME_PLACEHOLDER - - cc: - type: email - size: medium - label: PLUGIN_EMAIL.EMAIL_CC - placeholder: PLUGIN_EMAIL.EMAIL_CC_PLACEHOLDER - multiple: true - validate: - type: email - - cc_name: - type: text - size: medium - label: PLUGIN_EMAIL.EMAIL_CC_NAME - placeholder: PLUGIN_EMAIL.EMAIL_CC_NAME_PLACEHOLDER - - bcc: - type: email - size: medium - label: PLUGIN_EMAIL.EMAIL_BCC - placeholder: PLUGIN_EMAIL.EMAIL_BCC_PLACEHOLDER - multiple: true - validate: - type: email - - reply_to: - type: email - size: medium - label: PLUGIN_EMAIL.EMAIL_REPLY_TO - placeholder: PLUGIN_EMAIL.EMAIL_REPLY_TO_PLACEHOLDER - multiple: true - validate: - type: email - - reply_to_name: - type: text - size: medium - label: PLUGIN_EMAIL.EMAIL_REPLY_TO_NAME - placeholder: PLUGIN_EMAIL.EMAIL_REPLY_TO_NAME_PLACEHOLDER - - body: - type: textarea - size: medium - label: PLUGIN_EMAIL.EMAIL_BODY - placeholder: PLUGIN_EMAIL.EMAIL_BODY_PLACEHOLDER + description: PLUGIN_EMAIL.MAIL_ENGINE_DESC + data-options@: '\Grav\Plugin\EmailPlugin::getEngines' smtp_config: type: section @@ -180,11 +82,6 @@ form: autocomplete: 'new-password' label: PLUGIN_EMAIL.SMTP_PASSWORD - mailer.smtp.auth_mode: - type: text - size: medium - label: PLUGIN_EMAIL.SMTP_AUTH_MODE - sendmail_config: type: section title: PLUGIN_EMAIL.SENDMAIL_CONFIGURATION @@ -196,43 +93,67 @@ form: label: PLUGIN_EMAIL.PATH_TO_SENDMAIL placeholder: "/usr/sbin/sendmail" - queue_section: + + + email_Defaults: type: section - title: PLUGIN_EMAIL.QUEUE_TITLE - text: PLUGIN_EMAIL.QUEUE_DESC - markdown: true + title: PLUGIN_EMAIL.EMAIL_DEFAULTS underline: true - queue.enabled: - type: toggle - label: PLUGIN_EMAIL.QUEUE_ENABLED - highlight: 0 - default: 0 - options: - 1: PLUGIN_ADMIN.ENABLED - 0: PLUGIN_ADMIN.DISABLED - validate: - type: bool - - queue.flush_frequency: - type: cron - label: PLUGIN_EMAIL.QUEUE_FLUSH_FREQUENCY + content_type: + type: select + label: PLUGIN_EMAIL.CONTENT_TYPE size: medium - help: PLUGIN_EMAIL.QUEUE_FLUSH_FREQUENCY_HELP - default: '* * * * *' - placeholder: '* * * * *' + default: 'text/html' + options: + 'text/plain': PLUGIN_EMAIL.CONTENT_TYPE_PLAIN_TEXT + 'text/html': HTML - queue.flush_msg_limit: - type: number - label: PLUGIN_EMAIL.QUEUE_FLUSH_MSG_LIMIT - size: x-small - append: PLUGIN_EMAIL.QUEUE_FLUSH_MSG_LIMIT_APPEND + from: + type: text + size: large + label: PLUGIN_EMAIL.EMAIL_FORM + placeholder: PLUGIN_EMAIL.EMAIL_FORM_PLACEHOLDER + help: PLUGIN_EMAIL.EMAIL_FORMAT + validate: + required: true - queue.flush_time_limit: - type: number - label: PLUGIN_EMAIL.QUEUE_FLUSH_TIME_LIMIT - size: x-small - append: PLUGIN_EMAIL.QUEUE_FLUSH_TIME_LIMIT_APPEND + to: + type: text + size: large + label: PLUGIN_EMAIL.EMAIL_TO + placeholder: PLUGIN_EMAIL.EMAIL_TO_PLACEHOLDER + help: PLUGIN_EMAIL.EMAIL_FORMAT + validate: + required: true + + cc: + type: text + size: large + label: PLUGIN_EMAIL.EMAIL_CC + placeholder: PLUGIN_EMAIL.EMAIL_CC_PLACEHOLDER + help: PLUGIN_EMAIL.EMAIL_FORMAT + + bcc: + type: text + size: large + label: PLUGIN_EMAIL.EMAIL_BCC + placeholder: PLUGIN_EMAIL.EMAIL_BCC_PLACEHOLDER + help: PLUGIN_EMAIL.EMAIL_FORMAT + + reply_to: + type: text + size: large + label: PLUGIN_EMAIL.EMAIL_REPLY_TO + placeholder: PLUGIN_EMAIL.EMAIL_REPLY_TO_PLACEHOLDER + help: PLUGIN_EMAIL.EMAIL_FORMAT + + body: + type: textarea + size: large + rows: 10 + label: PLUGIN_EMAIL.EMAIL_BODY + placeholder: PLUGIN_EMAIL.EMAIL_BODY_PLACEHOLDER advanced_section: type: section diff --git a/plugins/email/classes/Email.php b/plugins/email/classes/Email.php index 7254e25..617bbee 100644 --- a/plugins/email/classes/Email.php +++ b/plugins/email/classes/Email.php @@ -3,33 +3,46 @@ namespace Grav\Plugin\Email; use Grav\Common\Config\Config; use Grav\Common\Grav; +use Grav\Common\Utils; use Grav\Common\Language\Language; use Grav\Common\Markdown\Parsedown; use Grav\Common\Twig\Twig; use Grav\Framework\Form\Interfaces\FormInterface; use \Monolog\Logger; use \Monolog\Handler\StreamHandler; +use RocketTheme\Toolbox\Event\Event; +use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; +use Symfony\Component\Mailer\Mailer; +use Symfony\Component\Mailer\Transport; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Component\Mime\Address; class Email { - /** - * @var \Swift_Transport - */ + /** @var Mailer */ protected $mailer; - /** - * @var \Swift_Plugins_LoggerPlugin - */ - protected $logger; + /** @var TransportInterface */ + protected $transport; - protected $queue_path; + protected $log; + + public function __construct() + { + $this->initMailer(); + $this->initLog(); + } /** * Returns true if emails have been enabled in the system. * * @return bool */ - public static function enabled() + public static function enabled(): bool { return Grav::instance()['config']->get('plugins.email.mailer.engine') !== 'none'; } @@ -39,7 +52,7 @@ class Email * * @return bool */ - public static function debug() + public static function debug(): bool { return Grav::instance()['config']->get('plugins.email.debug') == 'true'; } @@ -47,82 +60,57 @@ class Email /** * Creates an email message. * - * @param string $subject - * @param string $body - * @param string $contentType - * @param string $charset - * @return \Swift_Message + * @param string|null $subject + * @param string|null $body + * @param string|null $contentType + * @param string|null $charset @deprecated + * @return Message */ - public function message($subject = null, $body = null, $contentType = null, $charset = null) + public function message(string $subject = null, string $body = null, string $contentType = null, string $charset = null): Message { - return new \Swift_Message($subject, $body, $contentType, $charset); - } + $message = new Message(); + $message->subject($subject); + if ($contentType === 'text/html') { + $message->html($body); + } else { + $message->text($body); + } - /** - * Creates an attachment. - * - * @param string $data - * @param string $filename - * @param string $contentType - * @return \Swift_Attachment - */ - public function attachment($data = null, $filename = null, $contentType = null) - { - return new \Swift_Attachment($data, $filename, $contentType); - } - - /** - * Creates an embedded attachment. - * - * @param string $data - * @param string $filename - * @param string $contentType - * @return \Swift_EmbeddedFile - */ - public function embedded($data = null, $filename = null, $contentType = null) - { - return new \Swift_EmbeddedFile($data, $filename, $contentType); - } - - /** - * Creates an image attachment. - * - * @param string $data - * @param string $filename - * @param string $contentType - * @return \Swift_Image - */ - public function image($data = null, $filename = null, $contentType = null) - { - return new \Swift_Image($data, $filename, $contentType); + return $message; } /** * Send email. * - * @param \Swift_Message $message - * @param array|null $failedRecipients + * @param Message $message + * @param Envelope|null $envelope * @return int */ - public function send($message, &$failedRecipients = null) + public function send(Message $message, Envelope $envelope = null): int { - $mailer = $this->getMailer(); + $status = '🛑 '; + $sent_msg = null; + $debug = null; - $result = $mailer ? $mailer->send($message, $failedRecipients) : 0; - - // Check if emails and debugging are both enabled. - if ($mailer && $this->debug()) { - - $log = new Logger('email'); - $locator = Grav::instance()['locator']; - $log_file = $locator->findResource('log://email.log', true, true); - $log->pushHandler(new StreamHandler($log_file, Logger::DEBUG)); - - // Append the SwiftMailer log to the log. - $log->addDebug($this->getLogs()); + try { + $sent_msg = $this->transport->send($message->getEmail(), $envelope); + $return = 1; + $status = '✅'; + $debug = $sent_msg->getDebug(); + } catch (TransportExceptionInterface $e) { + $return = 0; + $status .= $e->getMessage(); + $debug = $e->getDebug(); } - return $result; + if ($this->debug()) { + $log_msg = "Email sent to %s at %s -> %s\n%s"; + $to = $this->jsonifyRecipients($message->getEmail()->getTo()); + $msg = sprintf($log_msg, $to, date('Y-m-d H:i:s'), $status, $debug); + $this->log->addInfo($msg); + } + + return $return; } /** @@ -130,9 +118,9 @@ class Email * * @param array $params * @param array $vars - * @return \Swift_Message + * @return Message */ - public function buildMessage(array $params, array $vars = []) + public function buildMessage(array $params, array $vars = []): Message { /** @var Twig $twig */ $twig = Grav::instance()['twig']; @@ -145,7 +133,9 @@ class Email $language = Grav::instance()['language']; // Create message object. - $message = $this->message(); + $message = new Message(); + $headers = $message->getEmail()->getHeaders(); + $email = $message->getEmail(); // Extend parameters with defaults. $params += [ @@ -174,61 +164,31 @@ class Email throw new \RuntimeException($language->translate('PLUGIN_EMAIL.PLEASE_CONFIGURE_A_FROM_ADDRESS')); } + // make email configuration available to templates $vars += [ 'email' => $params, ]; + $params = $this->processParams($params, $vars); + // Process parameters. foreach ($params as $key => $value) { switch ($key) { case 'body': if (is_string($value)) { - if (strpos($value, '{{') !== false || strpos($value, '{%') !== false) { - $body = $twig->processString($value, $vars); - } else { - $body = $value; - } - - if ($params['process_markdown'] && $params['content_type'] === 'text/html') { - $parsedown = new Parsedown(); - $body = $parsedown->text($body); - } - - if ($params['template']) { - $body = $twig->processTemplate($params['template'], ['content' => $body] + $vars); - } - - $content_type = !empty($params['content_type']) ? $twig->processString($params['content_type'], $vars) : null; - $charset = !empty($params['charset']) ? $twig->processString($params['charset'], $vars) : null; - - $message->setBody($body, $content_type, $charset); + $this->processBody($message, $params, $vars, $twig, $value); } elseif (is_array($value)) { foreach ($value as $body_part) { - $body_part += [ - 'charset' => $params['charset'], - 'content_type' => $params['content_type'], - ]; - - $body = !empty($body_part['body']) ? $twig->processString($body_part['body'], $vars) : null; - - if ($params['process_markdown'] && $body_part['content_type'] === 'text/html') { - $parsedown = new Parsedown(); - $body = $parsedown->text($body); + $params_part = $params; + if (isset($body_part['content_type'])) { + $params_part['content_type'] = $body_part['content_type']; } - if (isset($body_part['template'])) { - $body = $twig->processTemplate($body_part['template'], ['content' => $body] + $vars); + $params_part['template'] = $body_part['template']; } - - $content_type = !empty($body_part['content_type']) ? $twig->processString($body_part['content_type'], $vars) : null; - $charset = !empty($body_part['charset']) ? $twig->processString($body_part['charset'], $vars) : null; - - if (!$message->getBody()) { - $message->setBody($body, $content_type, $charset); - } - else { - $message->addPart($body, $content_type, $charset); + if (isset($body_part['body'])) { + $this->processBody($message, $params_part, $vars, $twig, $body_part['body']); } } } @@ -236,68 +196,34 @@ class Email case 'subject': if ($value) { - $message->setSubject($twig->processString($language->translate($value), $vars)); + $message->subject($language->translate($value)); } break; case 'to': - if (is_string($value) && !empty($params['to_name'])) { - $value = [ - 'mail' => $twig->processString($value, $vars), - 'name' => $twig->processString($params['to_name'], $vars), - ]; - } - - foreach ($this->parseAddressValue($value, $vars) as $address) { - $message->addTo($address->mail, $address->name); - } - break; - - case 'cc': - if (is_string($value) && !empty($params['cc_name'])) { - $value = [ - 'mail' => $twig->processString($value, $vars), - 'name' => $twig->processString($params['cc_name'], $vars), - ]; - } - - foreach ($this->parseAddressValue($value, $vars) as $address) { - $message->addCc($address->mail, $address->name); - } - break; - - case 'bcc': - foreach ($this->parseAddressValue($value, $vars) as $address) { - $message->addBcc($address->mail, $address->name); - } - break; - case 'from': - if (is_string($value) && !empty($params['from_name'])) { - $value = [ - 'mail' => $twig->processString($value, $vars), - 'name' => $twig->processString($params['from_name'], $vars), - ]; - } - - foreach ($this->parseAddressValue($value, $vars) as $address) { - $message->addFrom($address->mail, $address->name); - } - break; - + case 'cc': + case 'bcc': case 'reply_to': - if (is_string($value) && !empty($params['reply_to_name'])) { - $value = [ - 'mail' => $twig->processString($value, $vars), - 'name' => $twig->processString($params['reply_to_name'], $vars), - ]; - } - - foreach ($this->parseAddressValue($value, $vars) as $address) { - $message->addReplyTo($address->mail, $address->name); + if ($recipients = $this->processRecipients($key, $params)) { + $key = $key === 'reply_to' ? 'replyTo' : $key; + $email->$key(...$recipients); + } + break; + case 'tags': + foreach ((array) $value as $tag) { + if (is_string($tag)) { + $headers->add(new TagHeader($tag)); + } + } + break; + case 'metadata': + foreach ((array) $value as $k => $v) { + if (is_string($k) && is_string($v)) { + $headers->add(new MetadataHeader($k, $v)); + } } break; - } } @@ -305,260 +231,282 @@ class Email } /** - * Return parsed e-mail address value. - * - * @param string|string[] $value - * @param array $vars + * @param string $type + * @param array $params * @return array */ - public function parseAddressValue($value, array $vars = []) + protected function processRecipients(string $type, array $params): array { - $parsed = []; + $recipients = $params[$type] ?? Grav::instance()['config']->get('plugins.email.'.$type) ?? []; - /** @var Twig $twig */ - $twig = Grav::instance()['twig']; + $list = []; - // Single e-mail address string - if (is_string($value)) { - $parsed[] = (object) [ - 'mail' => $twig->processString($value, $vars), - 'name' => null, - ]; - } - - else { - // Cast value as array - $value = (array) $value; - - // Single e-mail address array - if (!empty($value['mail'])) { - $parsed[] = (object) [ - 'mail' => $twig->processString($value['mail'], $vars), - 'name' => !empty($value['name']) ? $twig->processString($value['name'], $vars) : NULL, - ]; - } - - // Multiple addresses (either as strings or arrays) - elseif (!(empty($value['mail']) && !empty($value['name']))) { - foreach ($value as $y => $itemx) { - $addresses = $this->parseAddressValue($itemx, $vars); - - if (($address = reset($addresses))) { - $parsed[] = $address; + if (!empty($recipients)) { + if (is_array($recipients) && Utils::isAssoc($recipients)) { + $list[] = $this->createAddress($recipients); + } else { + if (is_array($recipients)) { + if (count($recipients) ===2 && $this->isValidEmail($recipients[0]) && is_string($recipients[1])) { + $list[] = $this->createAddress($recipients); + } else { + foreach ($recipients as $recipient) { + $list[] = $this->createAddress($recipient); + } + } + } else { + if (is_string($recipients) && Utils::contains($recipients, ',')) { + $recipients = array_map('trim', explode(',', $recipients)); + foreach ($recipients as $recipient) { + $list[] = $this->createAddress($recipient); + } + } else { + if (!Utils::contains($recipients, ['<','>']) && ($params[$type."_name"])) { + $recipients = [$recipients, $params[$type."_name"]]; + } + $list[] = $this->createAddress($recipients); } } } } - return $parsed; + return $list; } /** - * Return debugging logs if enabled - * - * @return string + * @param $data + * @return Address */ - public function getLogs() + protected function createAddress($data): Address { - if ($this->debug()) { - return $this->logger->dump(); + if (is_string($data)) { + preg_match('/^(.*)\<(.*)\>$/', $data, $matches); + if (isset($matches[2])) { + $email = trim($matches[2]); + $name = trim($matches[1]); + } else { + $email = $data; + $name = ''; + } + } elseif (Utils::isAssoc($data)) { + $first_key = array_key_first($data); + if (filter_var($first_key, FILTER_VALIDATE_EMAIL)) { + $email = $first_key; + $name = $data[$first_key]; + } else { + $email = $data['email'] ?? $data['mail'] ?? $data['address'] ?? ''; + $name = $data['name'] ?? $data['fullname'] ?? ''; + } + } else { + $email = $data[0] ?? ''; + $name = $data[1] ?? ''; } - return ''; + return new Address($email, $name); } /** + * @return null|Mailer * @internal - * @return null|\Swift_Mailer */ - protected function getMailer() + protected function initMailer(): ?Mailer { if (!$this->enabled()) { return null; } - if (!$this->mailer) { - /** @var Config $config */ - $config = Grav::instance()['config']; - $queue_enabled = $config->get('plugins.email.queue.enabled'); - - $transport = $queue_enabled === true ? $this->getQueue() : $this->getTransport(); - + $this->transport = $this->getTransport(); // Create the Mailer using your created Transport - $this->mailer = new \Swift_Mailer($transport); - - // Register the logger if we're debugging. - if ($this->debug()) { - $this->logger = new \Swift_Plugins_Loggers_ArrayLogger(); - $this->mailer->registerPlugin(new \Swift_Plugins_LoggerPlugin($this->logger)); - } + $this->mailer = new Mailer($this->transport); } - return $this->mailer; } - protected static function getQueuePath() + /** + * @return void + * @throws \Exception + */ + protected function initLog() { - $queue_path = Grav::instance()['locator']->findResource('user://data', true) . '/email-queue'; - - if (!file_exists($queue_path)) { - mkdir($queue_path); - } - - return $queue_path; + $log_file = Grav::instance()['locator']->findResource('log://email.log', true, true); + $this->log = new Logger('email'); + /** @var UniformResourceLocator $locator */ + $this->log->pushHandler(new StreamHandler($log_file, Logger::DEBUG)); } - protected static function getQueue() + /** + * @param array $params + * @param array $vars + * @return array + */ + protected function processParams(array $params, array $vars = []): array { - $queue_path = static::getQueuePath(); - - $spool = new \Swift_FileSpool($queue_path); - $transport = new \Swift_SpoolTransport($spool); - - return $transport; - } - - public static function flushQueue() - { - $grav = Grav::instance(); - - $grav['debugger']->enabled(false); - - $config = $grav['config']->get('plugins.email.queue'); - - try { - $queue = static::getQueue(); - $spool = $queue->getSpool(); - $spool->setMessageLimit($config['flush_msg_limit']); - $spool->setTimeLimit($config['flush_time_limit']); - $failures = []; - $result = $spool->flushQueue(static::getTransport(), $failures); - return $result . ' messages flushed from queue...'; - } catch (\Exception $e) { - $grav['log']->error($e->getMessage()); - return $e->getMessage(); - } - - } - - public static function clearQueueFailures() - { - $grav = Grav::instance(); - $grav['debugger']->enabled(false); - - $preferences = \Swift_Preferences::getInstance(); - $preferences->setTempDir(sys_get_temp_dir()); - - /** @var \Swift_Transport $transport */ - $transport = static::getTransport(); - if (!$transport->isStarted()) { - $transport->start(); - } - - $queue_path = static::getQueuePath(); - - foreach (new \GlobIterator($queue_path . '/*.sending') as $file) { - $final_message = $file->getPathname(); - - /** @var \Swift_Message $message */ - $message = unserialize(file_get_contents($final_message)); - - echo(sprintf( - 'Retrying "%s" to "%s"', - $message->getSubject(), - implode(', ', array_keys($message->getTo())) - ) . "\n"); - - try { - $clean = static::cloneMessage($message); - $transport->send($clean); - echo("sent!\n"); - - // DOn't want to trip up any errors from sending too fast - sleep(1); - } catch (\Swift_TransportException $e) { - echo("ERROR: Send failed - deleting spooled message\n"); + $twig = Grav::instance()['twig']; + array_walk_recursive($params, function(&$value) use ($twig, $vars) { + if (is_string($value)) { + $value = $twig->processString($value, $vars); } + }); + return $params; + } - // Remove the file - unlink($final_message); + /** + * @param $message + * @param $params + * @param $vars + * @param $twig + * @param $body + * @return void + */ + protected function processBody($message, $params, $vars, $twig, $body) + { + if ($params['process_markdown'] && $params['content_type'] === 'text/html') { + $body = (new Parsedown())->text($body); + } + + if ($params['template']) { + $body = $twig->processTemplate($params['template'], ['content' => $body] + $vars); + } + + $content_type = !empty($params['content_type']) ? $twig->processString($params['content_type'], $vars) : null; + + if ($content_type === 'text/html') { + $message->html($body); + } else { + $message->text($body); } } /** - * Clean copy a message - * - * @param \Swift_Message $message + * @return TransportInterface */ - public static function cloneMessage($message) - { - $clean = new \Swift_Message(); - - $clean->setBoundary($message->getBoundary()); - $clean->setBcc($message->getBcc()); - $clean->setBody($message->getBody()); - $clean->setCharset($message->getCharset()); - $clean->setChildren($message->getChildren()); - $clean->setContentType($message->getContentType()); - $clean->setCc($message->getCc()); - $clean->setDate($message->getDate()); - $clean->setDescription($message->getDescription()); - $clean->setEncoder($message->getEncoder()); - $clean->setFormat($message->getFormat()); - $clean->setFrom($message->getFrom()); - $clean->setId($message->getId()); - $clean->setMaxLineLength($message->getMaxLineLength()); - $clean->setPriority($message->getPriority()); - $clean->setReplyTo($message->getReplyTo()); - $clean->setReturnPath($message->getReturnPath()); - $clean->setSender($message->getSender()); - $clean->setSubject($message->getSubject()); - $clean->setTo($message->getTo()); - $clean->setAuthMode($message->getAuthMode()); - - return $clean; - - } - - protected static function getTransport() + protected static function getTransport(): Transport\TransportInterface { /** @var Config $config */ $config = Grav::instance()['config']; - $engine = $config->get('plugins.email.mailer.engine'); + $dsn = 'null://default'; + // Create the Transport and initialize it. switch ($engine) { + case 'smtps': case 'smtp': - $transport = new \Swift_SmtpTransport(); - $options = $config->get('plugins.email.mailer.smtp'); - if (!empty($options['server'])) { - $transport->setHost($options['server']); + $dsn = $engine . '://'; + $auth = ''; + + if (isset($options['encryption']) && $options['encryption'] === 'none') { + $options['options']['verify_peer'] = 0; } - if (!empty($options['port'])) { - $transport->setPort($options['port']); + if (isset($options['user'])) { + $auth .= urlencode($options['user']); } - if (!empty($options['encryption']) && $options['encryption'] !== 'none') { - $transport->setEncryption($options['encryption']); + if (isset($options['password'])) { + $auth .= ':'. urlencode($options['password']); } - if (!empty($options['user'])) { - $transport->setUsername($options['user']); + if (!empty($auth)) { + $dsn .= "$auth@"; } - if (!empty($options['password'])) { - $transport->setPassword($options['password']); + if (isset($options['server'])) { + $dsn .= urlencode($options['server']); } - if (!empty($options['auth_mode'])) { - $transport->setAuthMode($options['auth_mode']); + if (isset($options['port'])) { + $dsn .= ":{$options['port']}"; } + if (isset($options['options'])) { + $dsn .= '?' . http_build_query($options['options']); + } + break; + case 'mail': + case 'native': + $dsn = 'native://default'; break; case 'sendmail': - default: - $options = $config->get('plugins.email.mailer.sendmail'); - $bin = !empty($options['bin']) ? $options['bin'] : '/usr/sbin/sendmail'; - $transport = new \Swift_SendmailTransport($bin); + $dsn = 'sendmail://default'; + $bin = $config->get('plugins.email.mailer.sendmail.bin'); + if (isset($bin)) { + $dsn .= '?command=' . urlencode($bin); + } break; + default: + $e = new Event(['engine' => $engine, ]); + Grav::instance()->fireEvent('onEmailTransportDsn', $e); + if (isset($e['dsn'])) { + $dsn = $e['dsn']; + } + break; + } + + if ($dsn instanceof TransportInterface) { + $transport = $dsn; + } else { + $transport = Transport::fromDsn($dsn) ; } return $transport; } + + /** + * @param array $recipients + * @return string + */ + protected function jsonifyRecipients(array $recipients): string + { + $json = []; + foreach ($recipients as $recipient) { + $json[] = str_replace('"', "", $recipient->toString()); + } + return json_encode($json); + } + + protected function isValidEmail($email): bool + { + return is_string($email) && filter_var($email, FILTER_VALIDATE_EMAIL) !== false; + } + + /** + * @return void + * @deprecated 4.0 Switched from Swiftmailer to Symfony/Mailer - No longer supported + */ + public static function flushQueue() {} + + /** + * @return void + * @deprecated 4.0 Switched from Swiftmailer to Symfony/Mailer - No longer supported + */ + public static function clearQueueFailures() {} + + /** + * Creates an attachment. + * + * @param string $data + * @param string $filename + * @param string $contentType + * @deprecated 4.0 Switched from Swiftmailer to Symfony/Mailer - No longer supported + * @return void + */ + public function attachment($data = null, $filename = null, $contentType = null) {} + + /** + * Creates an embedded attachment. + * + * @param string $data + * @param string $filename + * @param string $contentType + * @deprecated 4.0 Switched from Swiftmailer to Symfony/Mailer - No longer supported + * @return void + */ + public function embedded($data = null, $filename = null, $contentType = null) {} + + + /** + * Creates an image attachment. + * + * @param string $data + * @param string $filename + * @param string $contentType + * @deprecated 4.0 Switched from Swiftmailer to Symfony/Mailer - No longer supported + * @return void + */ + public function image($data = null, $filename = null, $contentType = null) {} + } diff --git a/plugins/email/classes/Message.php b/plugins/email/classes/Message.php new file mode 100644 index 0000000..fb691f8 --- /dev/null +++ b/plugins/email/classes/Message.php @@ -0,0 +1,97 @@ +email = new SymfonyEmail(); + } + + public function subject($subject): self + { + $this->email->subject($subject); + return $this; + } + + public function to($to): self + { + $this->email->to($to); + return $this; + } + + public function from($from): self + { + $this->email->from($from); + return $this; + } + + public function cc($cc): self + { + $this->email->cc($cc); + return $this; + } + + public function bcc($bcc): self + { + $this->email->bcc($bcc); + return $this; + } + + public function replyTo($reply_to): self + { + $this->email->replyTo($reply_to); + return $this; + } + + public function text($text): self + { + $this->email->text($text); + return $this; + } + + public function html($html): self + { + $this->email->html($html); + return $this; + } + + public function attachFromPath($path): self + { + $this->email->attachFromPath($path); + return $this; + } + + public function embedFromPath($path): self + { + $this->email->embedFromPath($path); + return $this; + } + + public function reply_to($reply_to): self + { + $this->replyTo($reply_to); + return $this; + } + + public function setFrom($from): self + { + $this->from($from); + return $this; + } + + public function setTo($to): self + { + $this->to($to); + return $this; + } + + public function getEmail(): SymfonyEmail + { + return $this->email; + } +} \ No newline at end of file diff --git a/plugins/email/cli/ClearQueueFailuresCommand.php b/plugins/email/cli/ClearQueueFailuresCommand.php index 705c825..42910c3 100644 --- a/plugins/email/cli/ClearQueueFailuresCommand.php +++ b/plugins/email/cli/ClearQueueFailuresCommand.php @@ -9,6 +9,7 @@ use Symfony\Component\Console\Input\InputOption; /** * Class FlushQueueCommand * @package Grav\Console\Cli\ + * @deprecated 4.0 Switched from Swiftmailer to Symfony/Mailer - No longer supported */ class ClearQueueFailuresCommand extends ConsoleCommand { @@ -23,40 +24,16 @@ class ClearQueueFailuresCommand extends ConsoleCommand $this ->setName('clear-queue-failures') ->setAliases(['clearqueue']) - ->addOption( - 'env', - 'e', - InputOption::VALUE_OPTIONAL, - 'The environment to trigger a specific configuration. For example: localhost, mysite.dev, www.mysite.com' - ) - ->setDescription('Clears any queue failures that have accumulated') + ->setDescription('DEPRECATED: Clears any queue failures that have accumulated') ->setHelp('The clear-queue-failures command clears any queue failures that have accumulated'); } /** * @return int + * @deprecated 4.0 Switched from Swiftmailer to Symfony/Mailer - No longer supported */ protected function serve() { - // TODO: remove when requiring Grav 1.7+ - if (method_exists($this, 'initializeGrav')) { - $this->initializeGrav(); - } - - - $this->output->writeln(''); - $this->output->writeln('Current Configuration:'); - $this->output->writeln(''); - - $grav = Grav::instance(); - dump($grav['config']->get('plugins.email')); - - $this->output->writeln(''); - - require_once __DIR__ . '/../vendor/autoload.php'; - - Email::clearQueueFailures(); - return 0; } } diff --git a/plugins/email/cli/FlushQueueCommand.php b/plugins/email/cli/FlushQueueCommand.php index 3a735a8..c9a5d99 100644 --- a/plugins/email/cli/FlushQueueCommand.php +++ b/plugins/email/cli/FlushQueueCommand.php @@ -9,6 +9,7 @@ use Symfony\Component\Console\Input\InputOption; /** * Class FlushQueueCommand * @package Grav\Console\Cli\ + * @deprecated 4.0 Switched from Swiftmailer to Symfony/Mailer - No longer supported */ class FlushQueueCommand extends ConsoleCommand { @@ -23,41 +24,16 @@ class FlushQueueCommand extends ConsoleCommand $this ->setName('flush-queue') ->setAliases(['flushqueue']) - ->addOption( - 'env', - 'e', - InputOption::VALUE_OPTIONAL, - 'The environment to trigger a specific configuration. For example: localhost, mysite.dev, www.mysite.com' - ) - ->setDescription('Flushes the email queue of any pending emails') + ->setDescription('DEPRECATED: Flushes the email queue of any pending emails') ->setHelp('The flush-queue command flushes the email queue of any pending emails'); } /** * @return int + * @deprecated 4.0 Switched from Swiftmailer to Symfony/Mailer - No longer supported */ protected function serve() { - // TODO: remove when requiring Grav 1.7+ - if (method_exists($this, 'initializeGrav')) { - $this->initializeGrav(); - } - - $this->output->writeln(''); - $this->output->writeln('Current Configuration:'); - $this->output->writeln(''); - - $grav = Grav::instance(); - dump($grav['config']->get('plugins.email')); - - $this->output->writeln(''); - - require_once __DIR__ . '/../vendor/autoload.php'; - - $output = Email::flushQueue(); - - $this->output->writeln('' . $output . ''); - return 0; } } diff --git a/plugins/email/cli/TestEmailCommand.php b/plugins/email/cli/TestEmailCommand.php index 0c07dd0..2f2f4e8 100644 --- a/plugins/email/cli/TestEmailCommand.php +++ b/plugins/email/cli/TestEmailCommand.php @@ -79,8 +79,6 @@ class TestEmailCommand extends ConsoleCommand $this->output->writeln(''); - $grav['Email'] = new Email(); - $to = $this->input->getOption('to') ?: $grav['config']->get('plugins.email.to'); $subject = $this->input->getOption('subject'); $body = $this->input->getOption('body'); diff --git a/plugins/email/composer.json b/plugins/email/composer.json index 89591ec..4928588 100644 --- a/plugins/email/composer.json +++ b/plugins/email/composer.json @@ -21,7 +21,8 @@ }, "require": { "php": ">=7.3.6", - "swiftmailer/swiftmailer": "~6.0" + "symfony/mailer": "^5.4", + "symfony/messenger": "^5.4" }, "replace": { "symfony/polyfill-iconv": "*", diff --git a/plugins/email/composer.lock b/plugins/email/composer.lock index 679d1c3..f9b9152 100644 --- a/plugins/email/composer.lock +++ b/plugins/email/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": "87a959e0f18deeaf7c499a59c3c059bf", + "content-hash": "af2cff88b1d472f0931ba2c86fcdddc9", "packages": [ { "name": "doctrine/lexer", @@ -84,16 +84,16 @@ }, { "name": "egulias/email-validator", - "version": "3.1.2", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "ee0db30118f661fb166bcffbf5d82032df484697" + "reference": "f88dcf4b14af14a98ad96b14b2b317969eab6715" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ee0db30118f661fb166bcffbf5d82032df484697", - "reference": "ee0db30118f661fb166bcffbf5d82032df484697", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/f88dcf4b14af14a98ad96b14b2b317969eab6715", + "reference": "f88dcf4b14af14a98ad96b14b2b317969eab6715", "shasum": "" }, "require": { @@ -140,7 +140,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/3.1.2" + "source": "https://github.com/egulias/EmailValidator/tree/3.2.1" }, "funding": [ { @@ -148,45 +148,188 @@ "type": "github" } ], - "time": "2021-10-11T09:18:27+00:00" + "time": "2022-06-18T20:57:19+00:00" }, { - "name": "swiftmailer/swiftmailer", - "version": "v6.3.0", + "name": "psr/container", + "version": "1.1.1", "source": { "type": "git", - "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c" + "url": "https://github.com/php-fig/container.git", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/8a5d5072dca8f48460fce2f4131fcc495eec654c", - "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", "shasum": "" }, "require": { - "egulias/email-validator": "^2.0|^3.1", - "php": ">=7.0.0", - "symfony/polyfill-iconv": "^1.0", - "symfony/polyfill-intl-idn": "^1.10", - "symfony/polyfill-mbstring": "^1.0" + "php": ">=7.2.0" }, - "require-dev": { - "mockery/mockery": "^1.0", - "symfony/phpunit-bridge": "^4.4|^5.4" + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } }, - "suggest": { - "ext-intl": "Needed to support internationalized email addresses" + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.1" + }, + "time": "2021-03-05T17:36:06+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "6.2-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { - "files": [ - "lib/swift_required.php" + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "symfony/amqp-messenger", + "version": "v5.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/amqp-messenger.git", + "reference": "def93f2a7841cfa1a4a1fa487b84054d0d53e521" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/amqp-messenger/zipball/def93f2a7841cfa1a4a1fa487b84054d0d53e521", + "reference": "def93f2a7841cfa1a4a1fa487b84054d0d53e521", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/messenger": "^5.3|^6.0" + }, + "require-dev": { + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/property-access": "^4.4|^5.0|^6.0", + "symfony/serializer": "^4.4|^5.0|^6.0" + }, + "type": "symfony-messenger-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Messenger\\Bridge\\Amqp\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -194,50 +337,601 @@ "MIT" ], "authors": [ - { - "name": "Chris Corbyn" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Swiftmailer, free feature-rich PHP mailer", - "homepage": "https://swiftmailer.symfony.com", - "keywords": [ - "email", - "mail", - "mailer" - ], + "description": "Symfony AMQP extension Messenger Bridge", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/swiftmailer/swiftmailer/issues", - "source": "https://github.com/swiftmailer/swiftmailer/tree/v6.3.0" + "source": "https://github.com/symfony/amqp-messenger/tree/v5.4.13" }, "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, { "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/swiftmailer/swiftmailer", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "abandoned": "symfony/mailer", - "time": "2021-10-18T15:26:12+00:00" + "time": "2022-09-11T09:11:59+00:00" }, { - "name": "symfony/polyfill-intl-idn", - "version": "v1.25.0", + "name": "symfony/deprecation-contracts", + "version": "v2.5.2", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "749045c69efb97c70d25d7463abba812e91f3a44" + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/749045c69efb97c70d25d7463abba812e91f3a44", - "reference": "749045c69efb97c70d25d7463abba812e91f3a44", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "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.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/doctrine-messenger", + "version": "v5.4.12", + "source": { + "type": "git", + "url": "https://github.com/symfony/doctrine-messenger.git", + "reference": "7649a80e917b47c5072480a2d763c2422da239d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/7649a80e917b47c5072480a2d763c2422da239d2", + "reference": "7649a80e917b47c5072480a2d763c2422da239d2", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/messenger": "^5.1|^6.0", + "symfony/service-contracts": "^1.1|^2|^3" + }, + "conflict": { + "doctrine/dbal": "<2.13", + "doctrine/persistence": "<1.3" + }, + "require-dev": { + "doctrine/dbal": "^2.13|^3.0", + "doctrine/persistence": "^1.3|^2|^3", + "symfony/property-access": "^4.4|^5.0|^6.0", + "symfony/serializer": "^4.4|^5.0|^6.0" + }, + "type": "symfony-messenger-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Messenger\\Bridge\\Doctrine\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Doctrine Messenger Bridge", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/doctrine-messenger/tree/v5.4.12" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-09T12:54:00+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v5.4.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", + "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/event-dispatcher-contracts": "^2|^3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<4.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^4.4|^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/stopwatch": "^4.4|^5.0|^6.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.9" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-05T16:45:39+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/event-dispatcher": "^1" + }, + "suggest": { + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/mailer", + "version": "v5.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "63bf36a5150ac0bfed1c4d0a4e0b114a57b77e11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/63bf36a5150ac0bfed1c4d0a4e0b114a57b77e11", + "reference": "63bf36a5150ac0bfed1c4d0a4e0b114a57b77e11", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.1.10|^3", + "php": ">=7.2.5", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/mime": "^5.2.6|^6.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2|^3" + }, + "conflict": { + "symfony/http-kernel": "<4.4" + }, + "require-dev": { + "symfony/http-client-contracts": "^1.1|^2|^3", + "symfony/messenger": "^4.4|^5.0|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mailer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps sending emails", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/mailer/tree/v5.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-29T06:47:07+00:00" + }, + { + "name": "symfony/messenger", + "version": "v5.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/messenger.git", + "reference": "8f8d3425991e627902f8288088609a8d8f6c6ea4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/messenger/zipball/8f8d3425991e627902f8288088609a8d8f6c6ea4", + "reference": "8f8d3425991e627902f8288088609a8d8f6c6ea4", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/log": "^1|^2|^3", + "symfony/amqp-messenger": "^5.1|^6.0", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/doctrine-messenger": "^5.1|^6.0", + "symfony/polyfill-php80": "^1.16", + "symfony/redis-messenger": "^5.1|^6.0" + }, + "conflict": { + "symfony/event-dispatcher": "<4.4", + "symfony/framework-bundle": "<4.4", + "symfony/http-kernel": "<4.4", + "symfony/serializer": "<5.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/console": "^5.4|^6.0", + "symfony/dependency-injection": "^5.3|^6.0", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/property-access": "^4.4|^5.0|^6.0", + "symfony/routing": "^4.4|^5.0|^6.0", + "symfony/serializer": "^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/stopwatch": "^4.4|^5.0|^6.0", + "symfony/validator": "^4.4|^5.0|^6.0" + }, + "suggest": { + "enqueue/messenger-adapter": "For using the php-enqueue library as a transport." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Messenger\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Samuel Roze", + "email": "samuel.roze@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps applications send and receive messages to/from other applications or via message queues", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/messenger/tree/v5.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-09-17T07:31:22+00:00" + }, + { + "name": "symfony/mime", + "version": "v5.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "bb2ccf759e2b967dcd11bdee5bdf30dddd2290bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/bb2ccf759e2b967dcd11bdee5bdf30dddd2290bd", + "reference": "bb2ccf759e2b967dcd11bdee5bdf30dddd2290bd", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/property-access": "^4.4|^5.1|^6.0", + "symfony/property-info": "^4.4|^5.1|^6.0", + "symfony/serializer": "^5.2|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v5.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-09-01T18:18:29+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8", + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8", "shasum": "" }, "require": { @@ -251,7 +945,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -295,7 +989,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.26.0" }, "funding": [ { @@ -311,20 +1005,20 @@ "type": "tidelift" } ], - "time": "2021-09-14T14:02:44+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "219aa369ceff116e673852dce47c3a41794c14bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd", "shasum": "" }, "require": { @@ -336,7 +1030,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -379,7 +1073,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" }, "funding": [ { @@ -395,7 +1089,240 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-05-24T11:49:31+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-10T07:21:04+00:00" + }, + { + "name": "symfony/redis-messenger", + "version": "v5.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/redis-messenger.git", + "reference": "d3028b772de91e9aa0342c92ff71c77b130ac9c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/redis-messenger/zipball/d3028b772de91e9aa0342c92ff71c77b130ac9c4", + "reference": "d3028b772de91e9aa0342c92ff71c77b130ac9c4", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/messenger": "^5.1|^6.0" + }, + "require-dev": { + "symfony/property-access": "^4.4|^5.0|^6.0", + "symfony/serializer": "^4.4|^5.0|^6.0" + }, + "type": "symfony-messenger-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Messenger\\Bridge\\Redis\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Redis extension Messenger Bridge", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/redis-messenger/tree/v5.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-09-11T09:11:59+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-30T19:17:29+00:00" } ], "packages-dev": [], @@ -411,5 +1338,5 @@ "platform-overrides": { "php": "7.3.6" }, - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.3.0" } diff --git a/plugins/email/email.php b/plugins/email/email.php index 8d95c73..b96ff36 100644 --- a/plugins/email/email.php +++ b/plugins/email/email.php @@ -3,7 +3,9 @@ namespace Grav\Plugin; use Composer\Autoload\ClassLoader; use Grav\Common\Data\Data; +use Grav\Common\Grav; use Grav\Common\Plugin; +use Grav\Common\Utils; use Grav\Plugin\Email\Email; use RocketTheme\Toolbox\Event\Event; @@ -67,8 +69,6 @@ class EmailPlugin extends Plugin /** @var Data $obj */ $obj = $event['object']; - - if ($obj instanceof Data && $obj->blueprints()->getFilename() === 'email/blueprints') { $current_pw = $this->grav['config']->get('plugins.email.mailer.smtp.password'); $new_pw = $obj->get('mailer.smtp.password'); @@ -109,7 +109,7 @@ class EmailPlugin extends Plugin $this->grav->fireEvent('onEmailSend', new Event(['params' => &$params, 'vars' => &$vars])); - if ($this->isAssocArray($params)) { + if (Utils::isAssoc($params)) { $this->sendFormEmail($form, $params, $vars); } else { foreach ($params as $email) { @@ -121,25 +121,6 @@ class EmailPlugin extends Plugin } } - /** - * Add index job to Grav Scheduler - * Requires Grav 1.6.0 - Scheduler - */ - public function onSchedulerInitialized(Event $e) - { - if ($this->config->get('plugins.email.queue.enabled')) { - - /** @var Scheduler $scheduler */ - $scheduler = $e['scheduler']; - $at = $this->config->get('plugins.email.queue.flush_frequency'); - $logs = 'logs/email-queue.out'; - $job = $scheduler->addFunction('Grav\Plugin\Email\Email::flushQueue', [], 'email-flushqueue'); - $job->at($at); - $job->output($logs); - $job->backlink('/plugins/email'); - } - } - protected function sendFormEmail($form, $params, $vars) { // Build message @@ -158,7 +139,7 @@ class EmailPlugin extends Plugin } try { - $message->attach(\Swift_Attachment::fromPath($filename)); + $message->attachFromPath($filename); } catch (\Exception $e) { // Log any issues $this->grav['log']->error($e->getMessage()); @@ -177,12 +158,30 @@ class EmailPlugin extends Plugin $this->grav->fireEvent('onEmailSent', new Event(['message' => $message, 'params' => $params, 'form' => $form])); } - protected function isAssocArray(array $arr) + /** + * Used for dynamic blueprint field + * + * @return array + */ + public static function getEngines(): array { - if (array() === $arr) return false; - $keys = array_keys($arr); - $index_keys = range(0, count($arr) - 1); - return $keys !== $index_keys; + $engines = (object) [ + 'sendmail' => 'Sendmail', + 'smtp' => 'SMTP', + 'smtps' => 'SMTPS', + 'native' => 'Native', + 'none' => 'PLUGIN_ADMIN.DISABLED', + ]; + Grav::instance()->fireEvent('onEmailEngines', new Event(['engines' => $engines])); + return (array) $engines; + } + + /** + * @deprecated 4.0 Switched from Swiftmailer to Symfony/Mailer - No longer supported + */ + public function onSchedulerInitialized(Event $e) + { + } } diff --git a/plugins/email/email.yaml b/plugins/email/email.yaml index 6ddf722..846ae77 100644 --- a/plugins/email/email.yaml +++ b/plugins/email/email.yaml @@ -1,22 +1,14 @@ enabled: true from: -from_name: to: -to_name: -queue: - enabled: false - flush_frequency: '* * * * *' - flush_msg_limit: 10 - flush_time_limit: 100 mailer: engine: sendmail smtp: server: localhost port: 25 encryption: none - user: '' - password: '' - auth_mode: '' + user: + password: sendmail: bin: '/usr/sbin/sendmail -bs' content_type: text/html diff --git a/plugins/email/languages.yaml b/plugins/email/languages.yaml index fa89ac4..4cb044c 100644 --- a/plugins/email/languages.yaml +++ b/plugins/email/languages.yaml @@ -2,6 +2,7 @@ en: PLUGIN_EMAIL: MAIL_ENGINE: "Mail Engine" MAIL_ENGINE_DISABLED: "Disabled" + MAIL_ENGINE_DESC: "NOTE: If you select an engine provided by another plugin, you should configure options in that plugin." CONTENT_TYPE: "Content type" CONTENT_TYPE_PLAIN_TEXT: "Plain text" CHARSET: "Charset" @@ -35,14 +36,14 @@ en: SMTP_LOGIN_NAME: "SMTP login name" SMTP_PASSWORD: "SMTP password" SMTP_AUTH_MODE: "SMTP auth mode" - PATH_TO_SENDMAIL: "Path to sendmail" + PATH_TO_SENDMAIL: "Path to sendmail binary" DEBUG: "Debug" EMAIL_NOT_CONFIGURED: "Email not configured" PLEASE_CONFIGURE_A_TO_ADDRESS: "Please configure a 'to' address in the Email Plugin settings, or in the form" PLEASE_CONFIGURE_A_FROM_ADDRESS: "Please configure a 'from' address in the Email Plugin settings, or in the form" TEST_EMAIL_BODY: "

Testing Email

This test email has been sent based on the following configuration:

%1$s

" EMAIL_DEFAULTS: "Email Defaults" - SMTP_CONFIGURATION: "SMTP Configuration" + SMTP_CONFIGURATION: "SMTP/S Configuration" SENDMAIL_CONFIGURATION: "Sendmail Configuration" ADVANCED: "Advanced" EMAIL_FOOTER: "GetGrav.org" @@ -55,8 +56,7 @@ en: QUEUE_FLUSH_MSG_LIMIT_APPEND: "Messages" QUEUE_FLUSH_TIME_LIMIT: "Flush time limit" QUEUE_FLUSH_TIME_LIMIT_APPEND: "Seconds" - - + EMAIL_FORMAT: "Use the `addr` format: `email@address.org` or `name-addr` format: `Your Name `. Comma separated for multiple addresses" da: PLUGIN_EMAIL: @@ -76,11 +76,61 @@ es: fr: PLUGIN_EMAIL: + MAIL_ENGINE: "Moteur de messagerie" + MAIL_ENGINE_DISABLED: "Désactivé" + CONTENT_TYPE: "Type de contenu" + CONTENT_TYPE_PLAIN_TEXT: "Texte brut" + CHARSET: "Jeu de caractères" + CHARSET_PLACEHOLDER: "Defaults to UTF-8" + EMAIL_FORM: "Adresse de l’expéditeur" + EMAIL_FORM_PLACEHOLDER: "Adresse e-mail par défaut de l’expéditeur" + EMAIL_FROM_NAME: "Nom de l’expéditeur" + EMAIL_FROM_NAME_PLACEHOLDER: "Nom par défaut de l’expéditeur" + EMAIL_TO: "Adresse du destinataire" + EMAIL_TO_PLACEHOLDER: "Adresse e-mail par défaut du destinataire" + EMAIL_TO_NAME: "Nom du destinataire" + EMAIL_TO_NAME_PLACEHOLDER: "Nom par défaut du destinataire" + EMAIL_CC: "Adresse en CC" + EMAIL_CC_PLACEHOLDER: "Adresse e-mail par défaut en CC" + EMAIL_CC_NAME: "Nom en CC" + EMAIL_CC_NAME_PLACEHOLDER: "Nom par défaut en CC" + EMAIL_BCC: "Adresse en BCC" + EMAIL_BCC_PLACEHOLDER: "Adresse e-mail par défaut en BCC" + EMAIL_REPLY_TO: "Adresse de réponse" + EMAIL_REPLY_TO_PLACEHOLDER: "Adresse e-mail par défaut pour la réponse" + EMAIL_REPLY_TO_NAME: "Nom pour la réponse" + EMAIL_REPLY_TO_NAME_PLACEHOLDER: "Nom par défaut pour la réponse" + EMAIL_BODY: "Corps" + EMAIL_BODY_PLACEHOLDER: "Table de tous les champs de formulaire par défaut" + SMTP_SERVER: "Serveur SMTP" + SMTP_SERVER_PLACEHOLDER: "ex. smtp.google.com" + SMTP_PORT: "Port SMTP" + SMTP_PORT_PLACEHOLDER: "25 (texte brut) / 587 (encrypté) par défaut" + SMTP_ENCRYPTION: "cryptage SMTP" + SMTP_ENCRYPTION_NONE: "Aucun" + SMTP_LOGIN_NAME: "Nom d'utilisateur SMTP" + SMTP_PASSWORD: "Mot de passe SMTP" + SMTP_AUTH_MODE: "Mode d'authentification SMTP" + PATH_TO_SENDMAIL: "Chemin vers sendmail" + DEBUG: "Débogage" EMAIL_NOT_CONFIGURED: "L’e-mail n’est pas configuré" - PLEASE_CONFIGURE_A_TO_ADDRESS: "Veuillez configurer une adresse de 'destinataire' dans les paramètres du Plugin ou dans le formulaire." - PLEASE_CONFIGURE_A_FROM_ADDRESS: "Veuillez configurer une adresse 'd'expéditeur' dans les paramètres du Plugin ou dans le formulaire." + PLEASE_CONFIGURE_A_TO_ADDRESS: "Veuillez configurer une adresse de 'destinataire' dans les paramètres du plugin d’e-mail ou dans le formulaire." + PLEASE_CONFIGURE_A_FROM_ADDRESS: "Veuillez configurer une adresse 'd’expéditeur' dans les paramètres du plugin d’e-mail ou dans le formulaire." TEST_EMAIL_BODY: "

E-mail de test

Cet e-mail de test est basé sur la configuration suivante :

%1$s

" + EMAIL_DEFAULTS: "E-mail par défaut" + SMTP_CONFIGURATION: "Configuration SMTP" + SENDMAIL_CONFIGURATION: "Configuration Sendmail" + ADVANCED: "Avancée" EMAIL_FOOTER: "GetGrav.org" + QUEUE_TITLE: "Fil d’attente d’e-mails" + QUEUE_DESC: "Lorsque vous activez la file d’attente des e-mails, ils ne sont pas envoyés immédiatement. Au contraire, ils sont envoyés dans la file d’attente, puis le planificateur Grav videra la file d’attente et enverra les e-mails en fonction de la fréquence configurée. Cela permet de s’assurer que Grav n’attend pas la fin des connexions pour les envoyer" + QUEUE_ENABLED: "Activé" + QUEUE_FLUSH_FREQUENCY: "Fréquence de Flush" + QUEUE_FLUSH_FREQUENCY_HELP: "Utiliser le format 'cron'" + QUEUE_FLUSH_MSG_LIMIT: "Messages par Flush" + QUEUE_FLUSH_MSG_LIMIT_APPEND: "Messages" + QUEUE_FLUSH_TIME_LIMIT: "Délai de Flush" + QUEUE_FLUSH_TIME_LIMIT_APPEND: "Seconds" hr: PLUGIN_EMAIL: @@ -142,7 +192,7 @@ ru: QUEUE_TITLE: "Очередь Email" QUEUE_DESC: "Когда вы включаете очередь email, электронная почта не отправляется немедленно, а отправляется в очередь, затем планировщик Grav обрабатывает очередь и на основе настроенной частоты фактически отправляет электронную почту. Это гарантирует, что Grav не ждет завершения подключения к электронной почте." QUEUE_ENABLED: "Включено" - QUEUE_FLUSH_FREQUENCY: "Частота обраблтки" + QUEUE_FLUSH_FREQUENCY: "Частота обработки" QUEUE_FLUSH_FREQUENCY_HELP: "Использовать формат 'cron'" QUEUE_FLUSH_MSG_LIMIT: "Количество сообщений на задачу" QUEUE_FLUSH_MSG_LIMIT_APPEND: "Сообщений" diff --git a/plugins/email/vendor/autoload.php b/plugins/email/vendor/autoload.php index 26a2db7..e3e38f1 100644 --- a/plugins/email/vendor/autoload.php +++ b/plugins/email/vendor/autoload.php @@ -2,6 +2,11 @@ // autoload.php @generated by Composer +if (PHP_VERSION_ID < 50600) { + echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; + exit(1); +} + require_once __DIR__ . '/composer/autoload_real.php'; return ComposerAutoloaderInit73924571ea6ee98bb12d10ff20aff2ab::getLoader(); diff --git a/plugins/email/vendor/composer/InstalledVersions.php b/plugins/email/vendor/composer/InstalledVersions.php index d50e0c9..c6b54af 100644 --- a/plugins/email/vendor/composer/InstalledVersions.php +++ b/plugins/email/vendor/composer/InstalledVersions.php @@ -21,12 +21,14 @@ use Composer\Semver\VersionParser; * See also https://getcomposer.org/doc/07-runtime.md#installed-versions * * To require its presence, you can require `composer-runtime-api ^2.0` + * + * @final */ class InstalledVersions { /** * @var mixed[]|null - * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array}|array{}|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null */ private static $installed; @@ -37,7 +39,7 @@ class InstalledVersions /** * @var array[] - * @psalm-var array}> + * @psalm-var array}> */ private static $installedByVendor = array(); @@ -241,7 +243,7 @@ class InstalledVersions /** * @return array - * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string} + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} */ public static function getRootPackage() { @@ -255,7 +257,7 @@ class InstalledVersions * * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. * @return array[] - * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} */ public static function getRawData() { @@ -278,7 +280,7 @@ class InstalledVersions * Returns the raw data of all installed.php which are currently loaded for custom implementations * * @return array[] - * @psalm-return list}> + * @psalm-return list}> */ public static function getAllRawData() { @@ -301,7 +303,7 @@ class InstalledVersions * @param array[] $data A vendor/composer/installed.php data set * @return void * - * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} $data + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data */ public static function reload($data) { @@ -311,7 +313,7 @@ class InstalledVersions /** * @return array[] - * @psalm-return list}> + * @psalm-return list}> */ private static function getInstalled() { diff --git a/plugins/email/vendor/composer/autoload_classmap.php b/plugins/email/vendor/composer/autoload_classmap.php index 17e18aa..ceabe59 100644 --- a/plugins/email/vendor/composer/autoload_classmap.php +++ b/plugins/email/vendor/composer/autoload_classmap.php @@ -2,11 +2,16 @@ // autoload_classmap.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname($vendorDir); return array( + 'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'Grav\\Plugin\\EmailPlugin' => $baseDir . '/email.php', 'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + 'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', + 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', ); diff --git a/plugins/email/vendor/composer/autoload_files.php b/plugins/email/vendor/composer/autoload_files.php index e652642..d010da8 100644 --- a/plugins/email/vendor/composer/autoload_files.php +++ b/plugins/email/vendor/composer/autoload_files.php @@ -2,11 +2,12 @@ // autoload_files.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname($vendorDir); return array( + '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', + 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', - '2c102faa651ef8ea5874edb585946bce' => $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php', ); diff --git a/plugins/email/vendor/composer/autoload_namespaces.php b/plugins/email/vendor/composer/autoload_namespaces.php index b7fc012..15a2ff3 100644 --- a/plugins/email/vendor/composer/autoload_namespaces.php +++ b/plugins/email/vendor/composer/autoload_namespaces.php @@ -2,7 +2,7 @@ // autoload_namespaces.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname($vendorDir); return array( diff --git a/plugins/email/vendor/composer/autoload_psr4.php b/plugins/email/vendor/composer/autoload_psr4.php index 4b1fe17..85ac5cd 100644 --- a/plugins/email/vendor/composer/autoload_psr4.php +++ b/plugins/email/vendor/composer/autoload_psr4.php @@ -2,12 +2,25 @@ // autoload_psr4.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname($vendorDir); return array( + 'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'), 'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'), 'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'), + 'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'), + 'Symfony\\Contracts\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher-contracts'), + 'Symfony\\Component\\Mime\\' => array($vendorDir . '/symfony/mime'), + 'Symfony\\Component\\Messenger\\Bridge\\Redis\\' => array($vendorDir . '/symfony/redis-messenger'), + 'Symfony\\Component\\Messenger\\Bridge\\Doctrine\\' => array($vendorDir . '/symfony/doctrine-messenger'), + 'Symfony\\Component\\Messenger\\Bridge\\Amqp\\' => array($vendorDir . '/symfony/amqp-messenger'), + 'Symfony\\Component\\Messenger\\' => array($vendorDir . '/symfony/messenger'), + 'Symfony\\Component\\Mailer\\' => array($vendorDir . '/symfony/mailer'), + 'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), + 'Psr\\EventDispatcher\\' => array($vendorDir . '/psr/event-dispatcher/src'), + 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), 'Grav\\Plugin\\Email\\' => array($baseDir . '/classes'), 'Grav\\Plugin\\Console\\' => array($baseDir . '/cli'), 'Egulias\\EmailValidator\\' => array($vendorDir . '/egulias/email-validator/src'), diff --git a/plugins/email/vendor/composer/autoload_real.php b/plugins/email/vendor/composer/autoload_real.php index cdba7ec..850a062 100644 --- a/plugins/email/vendor/composer/autoload_real.php +++ b/plugins/email/vendor/composer/autoload_real.php @@ -25,38 +25,15 @@ class ComposerAutoloaderInit73924571ea6ee98bb12d10ff20aff2ab require __DIR__ . '/platform_check.php'; spl_autoload_register(array('ComposerAutoloaderInit73924571ea6ee98bb12d10ff20aff2ab', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); spl_autoload_unregister(array('ComposerAutoloaderInit73924571ea6ee98bb12d10ff20aff2ab', 'loadClassLoader')); - $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); - if ($useStaticLoader) { - require __DIR__ . '/autoload_static.php'; - - call_user_func(\Composer\Autoload\ComposerStaticInit73924571ea6ee98bb12d10ff20aff2ab::getInitializer($loader)); - } else { - $map = require __DIR__ . '/autoload_namespaces.php'; - foreach ($map as $namespace => $path) { - $loader->set($namespace, $path); - } - - $map = require __DIR__ . '/autoload_psr4.php'; - foreach ($map as $namespace => $path) { - $loader->setPsr4($namespace, $path); - } - - $classMap = require __DIR__ . '/autoload_classmap.php'; - if ($classMap) { - $loader->addClassMap($classMap); - } - } + require __DIR__ . '/autoload_static.php'; + call_user_func(\Composer\Autoload\ComposerStaticInit73924571ea6ee98bb12d10ff20aff2ab::getInitializer($loader)); $loader->register(true); - if ($useStaticLoader) { - $includeFiles = Composer\Autoload\ComposerStaticInit73924571ea6ee98bb12d10ff20aff2ab::$files; - } else { - $includeFiles = require __DIR__ . '/autoload_files.php'; - } + $includeFiles = \Composer\Autoload\ComposerStaticInit73924571ea6ee98bb12d10ff20aff2ab::$files; foreach ($includeFiles as $fileIdentifier => $file) { composerRequire73924571ea6ee98bb12d10ff20aff2ab($fileIdentifier, $file); } diff --git a/plugins/email/vendor/composer/autoload_static.php b/plugins/email/vendor/composer/autoload_static.php index 3d6d8ce..0d0f4c2 100644 --- a/plugins/email/vendor/composer/autoload_static.php +++ b/plugins/email/vendor/composer/autoload_static.php @@ -7,16 +7,33 @@ namespace Composer\Autoload; class ComposerStaticInit73924571ea6ee98bb12d10ff20aff2ab { public static $files = array ( + '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', + 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', - '2c102faa651ef8ea5874edb585946bce' => __DIR__ . '/..' . '/swiftmailer/swiftmailer/lib/swift_required.php', ); public static $prefixLengthsPsr4 = array ( 'S' => array ( + 'Symfony\\Polyfill\\Php80\\' => 23, 'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33, 'Symfony\\Polyfill\\Intl\\Idn\\' => 26, + 'Symfony\\Contracts\\Service\\' => 26, + 'Symfony\\Contracts\\EventDispatcher\\' => 34, + 'Symfony\\Component\\Mime\\' => 23, + 'Symfony\\Component\\Messenger\\Bridge\\Redis\\' => 41, + 'Symfony\\Component\\Messenger\\Bridge\\Doctrine\\' => 44, + 'Symfony\\Component\\Messenger\\Bridge\\Amqp\\' => 40, + 'Symfony\\Component\\Messenger\\' => 28, + 'Symfony\\Component\\Mailer\\' => 25, + 'Symfony\\Component\\EventDispatcher\\' => 34, + ), + 'P' => + array ( + 'Psr\\Log\\' => 8, + 'Psr\\EventDispatcher\\' => 20, + 'Psr\\Container\\' => 14, ), 'G' => array ( @@ -34,6 +51,10 @@ class ComposerStaticInit73924571ea6ee98bb12d10ff20aff2ab ); public static $prefixDirsPsr4 = array ( + 'Symfony\\Polyfill\\Php80\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php80', + ), 'Symfony\\Polyfill\\Intl\\Normalizer\\' => array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer', @@ -42,6 +63,54 @@ class ComposerStaticInit73924571ea6ee98bb12d10ff20aff2ab array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn', ), + 'Symfony\\Contracts\\Service\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/service-contracts', + ), + 'Symfony\\Contracts\\EventDispatcher\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/event-dispatcher-contracts', + ), + 'Symfony\\Component\\Mime\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/mime', + ), + 'Symfony\\Component\\Messenger\\Bridge\\Redis\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/redis-messenger', + ), + 'Symfony\\Component\\Messenger\\Bridge\\Doctrine\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/doctrine-messenger', + ), + 'Symfony\\Component\\Messenger\\Bridge\\Amqp\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/amqp-messenger', + ), + 'Symfony\\Component\\Messenger\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/messenger', + ), + 'Symfony\\Component\\Mailer\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/mailer', + ), + 'Symfony\\Component\\EventDispatcher\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/event-dispatcher', + ), + 'Psr\\Log\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/log/Psr/Log', + ), + 'Psr\\EventDispatcher\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/event-dispatcher/src', + ), + 'Psr\\Container\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/container/src', + ), 'Grav\\Plugin\\Email\\' => array ( 0 => __DIR__ . '/../..' . '/classes', @@ -61,9 +130,14 @@ class ComposerStaticInit73924571ea6ee98bb12d10ff20aff2ab ); public static $classMap = array ( + 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'Grav\\Plugin\\EmailPlugin' => __DIR__ . '/../..' . '/email.php', 'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + 'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', + 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', ); public static function getInitializer(ClassLoader $loader) diff --git a/plugins/email/vendor/composer/installed.json b/plugins/email/vendor/composer/installed.json index 9bb23b4..b64a77e 100644 --- a/plugins/email/vendor/composer/installed.json +++ b/plugins/email/vendor/composer/installed.json @@ -81,17 +81,17 @@ }, { "name": "egulias/email-validator", - "version": "3.1.2", - "version_normalized": "3.1.2.0", + "version": "3.2.1", + "version_normalized": "3.2.1.0", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "ee0db30118f661fb166bcffbf5d82032df484697" + "reference": "f88dcf4b14af14a98ad96b14b2b317969eab6715" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ee0db30118f661fb166bcffbf5d82032df484697", - "reference": "ee0db30118f661fb166bcffbf5d82032df484697", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/f88dcf4b14af14a98ad96b14b2b317969eab6715", + "reference": "f88dcf4b14af14a98ad96b14b2b317969eab6715", "shasum": "" }, "require": { @@ -107,7 +107,7 @@ "suggest": { "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" }, - "time": "2021-10-11T09:18:27+00:00", + "time": "2022-06-18T20:57:19+00:00", "type": "library", "extra": { "branch-alias": { @@ -140,7 +140,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/3.1.2" + "source": "https://github.com/egulias/EmailValidator/tree/3.2.1" }, "funding": [ { @@ -151,45 +151,197 @@ "install-path": "../egulias/email-validator" }, { - "name": "swiftmailer/swiftmailer", - "version": "v6.3.0", - "version_normalized": "6.3.0.0", + "name": "psr/container", + "version": "1.1.1", + "version_normalized": "1.1.1.0", "source": { "type": "git", - "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c" + "url": "https://github.com/php-fig/container.git", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/8a5d5072dca8f48460fce2f4131fcc495eec654c", - "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", "shasum": "" }, "require": { - "egulias/email-validator": "^2.0|^3.1", - "php": ">=7.0.0", - "symfony/polyfill-iconv": "^1.0", - "symfony/polyfill-intl-idn": "^1.10", - "symfony/polyfill-mbstring": "^1.0" + "php": ">=7.2.0" }, - "require-dev": { - "mockery/mockery": "^1.0", - "symfony/phpunit-bridge": "^4.4|^5.4" + "time": "2021-03-05T17:36:06+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } }, - "suggest": { - "ext-intl": "Needed to support internationalized email addresses" + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.1" }, - "time": "2021-10-18T15:26:12+00:00", + "install-path": "../psr/container" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "time": "2019-01-08T18:20:26+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "6.2-dev" + "dev-master": "1.0.x-dev" } }, "installation-source": "dist", "autoload": { - "files": [ - "lib/swift_required.php" + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "install-path": "../psr/event-dispatcher" + }, + { + "name": "psr/log", + "version": "1.1.4", + "version_normalized": "1.1.4.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2021-05-03T11:20:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "install-path": "../psr/log" + }, + { + "name": "symfony/amqp-messenger", + "version": "v5.4.13", + "version_normalized": "5.4.13.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/amqp-messenger.git", + "reference": "def93f2a7841cfa1a4a1fa487b84054d0d53e521" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/amqp-messenger/zipball/def93f2a7841cfa1a4a1fa487b84054d0d53e521", + "reference": "def93f2a7841cfa1a4a1fa487b84054d0d53e521", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/messenger": "^5.3|^6.0" + }, + "require-dev": { + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/property-access": "^4.4|^5.0|^6.0", + "symfony/serializer": "^4.4|^5.0|^6.0" + }, + "time": "2022-09-11T09:11:59+00:00", + "type": "symfony-messenger-bridge", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Messenger\\Bridge\\Amqp\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -197,51 +349,623 @@ "MIT" ], "authors": [ - { - "name": "Chris Corbyn" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Swiftmailer, free feature-rich PHP mailer", - "homepage": "https://swiftmailer.symfony.com", - "keywords": [ - "email", - "mail", - "mailer" - ], + "description": "Symfony AMQP extension Messenger Bridge", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/swiftmailer/swiftmailer/issues", - "source": "https://github.com/swiftmailer/swiftmailer/tree/v6.3.0" + "source": "https://github.com/symfony/amqp-messenger/tree/v5.4.13" }, "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, { "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/swiftmailer/swiftmailer", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "abandoned": "symfony/mailer", - "install-path": "../swiftmailer/swiftmailer" + "install-path": "../symfony/amqp-messenger" }, { - "name": "symfony/polyfill-intl-idn", - "version": "v1.25.0", - "version_normalized": "1.25.0.0", + "name": "symfony/deprecation-contracts", + "version": "v2.5.2", + "version_normalized": "2.5.2.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "749045c69efb97c70d25d7463abba812e91f3a44" + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/749045c69efb97c70d25d7463abba812e91f3a44", - "reference": "749045c69efb97c70d25d7463abba812e91f3a44", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2022-01-02T09:53:40+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "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.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/deprecation-contracts" + }, + { + "name": "symfony/doctrine-messenger", + "version": "v5.4.12", + "version_normalized": "5.4.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/doctrine-messenger.git", + "reference": "7649a80e917b47c5072480a2d763c2422da239d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/7649a80e917b47c5072480a2d763c2422da239d2", + "reference": "7649a80e917b47c5072480a2d763c2422da239d2", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/messenger": "^5.1|^6.0", + "symfony/service-contracts": "^1.1|^2|^3" + }, + "conflict": { + "doctrine/dbal": "<2.13", + "doctrine/persistence": "<1.3" + }, + "require-dev": { + "doctrine/dbal": "^2.13|^3.0", + "doctrine/persistence": "^1.3|^2|^3", + "symfony/property-access": "^4.4|^5.0|^6.0", + "symfony/serializer": "^4.4|^5.0|^6.0" + }, + "time": "2022-08-09T12:54:00+00:00", + "type": "symfony-messenger-bridge", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Messenger\\Bridge\\Doctrine\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Doctrine Messenger Bridge", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/doctrine-messenger/tree/v5.4.12" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/doctrine-messenger" + }, + { + "name": "symfony/event-dispatcher", + "version": "v5.4.9", + "version_normalized": "5.4.9.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", + "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/event-dispatcher-contracts": "^2|^3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<4.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^4.4|^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/stopwatch": "^4.4|^5.0|^6.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "time": "2022-05-05T16:45:39+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.9" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/event-dispatcher" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v2.5.2", + "version_normalized": "2.5.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/event-dispatcher": "^1" + }, + "suggest": { + "symfony/event-dispatcher-implementation": "" + }, + "time": "2022-01-02T09:53:40+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/event-dispatcher-contracts" + }, + { + "name": "symfony/mailer", + "version": "v5.4.13", + "version_normalized": "5.4.13.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "63bf36a5150ac0bfed1c4d0a4e0b114a57b77e11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/63bf36a5150ac0bfed1c4d0a4e0b114a57b77e11", + "reference": "63bf36a5150ac0bfed1c4d0a4e0b114a57b77e11", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.1.10|^3", + "php": ">=7.2.5", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/mime": "^5.2.6|^6.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2|^3" + }, + "conflict": { + "symfony/http-kernel": "<4.4" + }, + "require-dev": { + "symfony/http-client-contracts": "^1.1|^2|^3", + "symfony/messenger": "^4.4|^5.0|^6.0" + }, + "time": "2022-08-29T06:47:07+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mailer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps sending emails", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/mailer/tree/v5.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/mailer" + }, + { + "name": "symfony/messenger", + "version": "v5.4.13", + "version_normalized": "5.4.13.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/messenger.git", + "reference": "8f8d3425991e627902f8288088609a8d8f6c6ea4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/messenger/zipball/8f8d3425991e627902f8288088609a8d8f6c6ea4", + "reference": "8f8d3425991e627902f8288088609a8d8f6c6ea4", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/log": "^1|^2|^3", + "symfony/amqp-messenger": "^5.1|^6.0", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/doctrine-messenger": "^5.1|^6.0", + "symfony/polyfill-php80": "^1.16", + "symfony/redis-messenger": "^5.1|^6.0" + }, + "conflict": { + "symfony/event-dispatcher": "<4.4", + "symfony/framework-bundle": "<4.4", + "symfony/http-kernel": "<4.4", + "symfony/serializer": "<5.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/console": "^5.4|^6.0", + "symfony/dependency-injection": "^5.3|^6.0", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/property-access": "^4.4|^5.0|^6.0", + "symfony/routing": "^4.4|^5.0|^6.0", + "symfony/serializer": "^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/stopwatch": "^4.4|^5.0|^6.0", + "symfony/validator": "^4.4|^5.0|^6.0" + }, + "suggest": { + "enqueue/messenger-adapter": "For using the php-enqueue library as a transport." + }, + "time": "2022-09-17T07:31:22+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Messenger\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Samuel Roze", + "email": "samuel.roze@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps applications send and receive messages to/from other applications or via message queues", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/messenger/tree/v5.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/messenger" + }, + { + "name": "symfony/mime", + "version": "v5.4.13", + "version_normalized": "5.4.13.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "bb2ccf759e2b967dcd11bdee5bdf30dddd2290bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/bb2ccf759e2b967dcd11bdee5bdf30dddd2290bd", + "reference": "bb2ccf759e2b967dcd11bdee5bdf30dddd2290bd", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/property-access": "^4.4|^5.1|^6.0", + "symfony/property-info": "^4.4|^5.1|^6.0", + "symfony/serializer": "^5.2|^6.0" + }, + "time": "2022-09-01T18:18:29+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v5.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/mime" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.26.0", + "version_normalized": "1.26.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8", + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8", "shasum": "" }, "require": { @@ -252,11 +976,11 @@ "suggest": { "ext-intl": "For best performance" }, - "time": "2021-09-14T14:02:44+00:00", + "time": "2022-05-24T11:49:31+00:00", "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -301,7 +1025,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.26.0" }, "funding": [ { @@ -321,17 +1045,17 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.25.0", - "version_normalized": "1.25.0.0", + "version": "v1.26.0", + "version_normalized": "1.26.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "219aa369ceff116e673852dce47c3a41794c14bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd", "shasum": "" }, "require": { @@ -340,11 +1064,11 @@ "suggest": { "ext-intl": "For best performance" }, - "time": "2021-02-19T12:13:01+00:00", + "time": "2022-05-24T11:49:31+00:00", "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -388,7 +1112,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" }, "funding": [ { @@ -405,8 +1129,250 @@ } ], "install-path": "../symfony/polyfill-intl-normalizer" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.26.0", + "version_normalized": "1.26.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2022-05-10T07:21:04+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-php80" + }, + { + "name": "symfony/redis-messenger", + "version": "v5.4.13", + "version_normalized": "5.4.13.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/redis-messenger.git", + "reference": "d3028b772de91e9aa0342c92ff71c77b130ac9c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/redis-messenger/zipball/d3028b772de91e9aa0342c92ff71c77b130ac9c4", + "reference": "d3028b772de91e9aa0342c92ff71c77b130ac9c4", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/messenger": "^5.1|^6.0" + }, + "require-dev": { + "symfony/property-access": "^4.4|^5.0|^6.0", + "symfony/serializer": "^4.4|^5.0|^6.0" + }, + "time": "2022-09-11T09:11:59+00:00", + "type": "symfony-messenger-bridge", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Messenger\\Bridge\\Redis\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Redis extension Messenger Bridge", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/redis-messenger/tree/v5.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/redis-messenger" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "version_normalized": "2.5.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "time": "2022-05-30T19:17:29+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/service-contracts" } ], - "dev": false, + "dev": true, "dev-package-names": [] } diff --git a/plugins/email/vendor/composer/installed.php b/plugins/email/vendor/composer/installed.php index 1b8f980..b2fbb84 100644 --- a/plugins/email/vendor/composer/installed.php +++ b/plugins/email/vendor/composer/installed.php @@ -1,49 +1,151 @@ array( + 'name' => 'getgrav/grav-plugin-email', 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', + 'reference' => 'f6eb15486887c489363e6bf79fa49ea4a3d833c6', 'type' => 'grav-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), - 'reference' => '6ab4ab743d351b196fa32aa7885651e6b7e2e6d4', - 'name' => 'getgrav/grav-plugin-email', - 'dev' => false, + 'dev' => true, ), 'versions' => array( 'doctrine/lexer' => array( 'pretty_version' => '1.2.3', 'version' => '1.2.3.0', + 'reference' => 'c268e882d4dbdd85e36e4ad69e02dc284f89d229', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/lexer', 'aliases' => array(), - 'reference' => 'c268e882d4dbdd85e36e4ad69e02dc284f89d229', 'dev_requirement' => false, ), 'egulias/email-validator' => array( - 'pretty_version' => '3.1.2', - 'version' => '3.1.2.0', + 'pretty_version' => '3.2.1', + 'version' => '3.2.1.0', + 'reference' => 'f88dcf4b14af14a98ad96b14b2b317969eab6715', 'type' => 'library', 'install_path' => __DIR__ . '/../egulias/email-validator', 'aliases' => array(), - 'reference' => 'ee0db30118f661fb166bcffbf5d82032df484697', 'dev_requirement' => false, ), 'getgrav/grav-plugin-email' => array( 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', + 'reference' => 'f6eb15486887c489363e6bf79fa49ea4a3d833c6', 'type' => 'grav-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), - 'reference' => '6ab4ab743d351b196fa32aa7885651e6b7e2e6d4', 'dev_requirement' => false, ), - 'swiftmailer/swiftmailer' => array( - 'pretty_version' => 'v6.3.0', - 'version' => '6.3.0.0', + 'psr/container' => array( + 'pretty_version' => '1.1.1', + 'version' => '1.1.1.0', + 'reference' => '8622567409010282b7aeebe4bb841fe98b58dcaf', 'type' => 'library', - 'install_path' => __DIR__ . '/../swiftmailer/swiftmailer', + 'install_path' => __DIR__ . '/../psr/container', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/event-dispatcher' => array( + 'pretty_version' => '1.0.0', + 'version' => '1.0.0.0', + 'reference' => 'dbefd12671e8a14ec7f180cab83036ed26714bb0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/event-dispatcher', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/event-dispatcher-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/log' => array( + 'pretty_version' => '1.1.4', + 'version' => '1.1.4.0', + 'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/log', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/amqp-messenger' => array( + 'pretty_version' => 'v5.4.13', + 'version' => '5.4.13.0', + 'reference' => 'def93f2a7841cfa1a4a1fa487b84054d0d53e521', + 'type' => 'symfony-messenger-bridge', + 'install_path' => __DIR__ . '/../symfony/amqp-messenger', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/deprecation-contracts' => array( + 'pretty_version' => 'v2.5.2', + 'version' => '2.5.2.0', + 'reference' => 'e8b495ea28c1d97b5e0c121748d6f9b53d075c66', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/doctrine-messenger' => array( + 'pretty_version' => 'v5.4.12', + 'version' => '5.4.12.0', + 'reference' => '7649a80e917b47c5072480a2d763c2422da239d2', + 'type' => 'symfony-messenger-bridge', + 'install_path' => __DIR__ . '/../symfony/doctrine-messenger', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/event-dispatcher' => array( + 'pretty_version' => 'v5.4.9', + 'version' => '5.4.9.0', + 'reference' => '8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/event-dispatcher', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/event-dispatcher-contracts' => array( + 'pretty_version' => 'v2.5.2', + 'version' => '2.5.2.0', + 'reference' => 'f98b54df6ad059855739db6fcbc2d36995283fe1', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/event-dispatcher-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/event-dispatcher-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '2.0', + ), + ), + 'symfony/mailer' => array( + 'pretty_version' => 'v5.4.13', + 'version' => '5.4.13.0', + 'reference' => '63bf36a5150ac0bfed1c4d0a4e0b114a57b77e11', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/mailer', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/messenger' => array( + 'pretty_version' => 'v5.4.13', + 'version' => '5.4.13.0', + 'reference' => '8f8d3425991e627902f8288088609a8d8f6c6ea4', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/messenger', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/mime' => array( + 'pretty_version' => 'v5.4.13', + 'version' => '5.4.13.0', + 'reference' => 'bb2ccf759e2b967dcd11bdee5bdf30dddd2290bd', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/mime', 'aliases' => array(), - 'reference' => '8a5d5072dca8f48460fce2f4131fcc495eec654c', 'dev_requirement' => false, ), 'symfony/polyfill-iconv' => array( @@ -53,21 +155,21 @@ ), ), 'symfony/polyfill-intl-idn' => array( - 'pretty_version' => 'v1.25.0', - 'version' => '1.25.0.0', + 'pretty_version' => 'v1.26.0', + 'version' => '1.26.0.0', + 'reference' => '59a8d271f00dd0e4c2e518104cc7963f655a1aa8', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn', 'aliases' => array(), - 'reference' => '749045c69efb97c70d25d7463abba812e91f3a44', 'dev_requirement' => false, ), 'symfony/polyfill-intl-normalizer' => array( - 'pretty_version' => 'v1.25.0', - 'version' => '1.25.0.0', + 'pretty_version' => 'v1.26.0', + 'version' => '1.26.0.0', + 'reference' => '219aa369ceff116e673852dce47c3a41794c14bd', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', 'aliases' => array(), - 'reference' => '8590a5f561694770bdcd3f9b5c69dde6945028e8', 'dev_requirement' => false, ), 'symfony/polyfill-mbstring' => array( @@ -82,5 +184,32 @@ 0 => '*', ), ), + 'symfony/polyfill-php80' => array( + 'pretty_version' => 'v1.26.0', + 'version' => '1.26.0.0', + 'reference' => 'cfa0ae98841b9e461207c13ab093d76b0fa7bace', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php80', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/redis-messenger' => array( + 'pretty_version' => 'v5.4.13', + 'version' => '5.4.13.0', + 'reference' => 'd3028b772de91e9aa0342c92ff71c77b130ac9c4', + 'type' => 'symfony-messenger-bridge', + 'install_path' => __DIR__ . '/../symfony/redis-messenger', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/service-contracts' => array( + 'pretty_version' => 'v2.5.2', + 'version' => '2.5.2.0', + 'reference' => '4b426aac47d6427cc1a1d0f7e2ac724627f5966c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/service-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), ), ); diff --git a/plugins/email/vendor/egulias/email-validator/CONTRIBUTING.md b/plugins/email/vendor/egulias/email-validator/CONTRIBUTING.md index 7b79e10..907bc2c 100644 --- a/plugins/email/vendor/egulias/email-validator/CONTRIBUTING.md +++ b/plugins/email/vendor/egulias/email-validator/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing -When contributing to this repository make sure to follow the Pull request process below. +When contributing to this repository make sure to follow the Pull request process below. Reduce to the minimum 3rd party dependencies. Please note we have a [code of conduct](#Code of Conduct), please follow it in all your interactions with the project. @@ -14,7 +14,7 @@ When doing a PR to v2 remember that you also have to do the PR port to v3, or te 3. Describe the changes you are proposing 1. If adding an extra validation state the benefits of adding it and the problem is solving 2. Document in the readme, by adding it to the list -4. Provide appropiate tests for the code you are submitting: aim to keep the existing coverage percentage. +4. Provide appropriate tests for the code you are submitting: aim to keep the existing coverage percentage. 5. Add your Twitter handle (if you have) so we can thank you there. ## License @@ -139,11 +139,11 @@ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at [https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0]. -Community Impact Guidelines were inspired by +Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. For answers to common questions about this code of conduct, see the FAQ at -[https://www.contributor-covenant.org/faq][FAQ]. Translations are available +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations]. [homepage]: https://www.contributor-covenant.org diff --git a/plugins/email/vendor/egulias/email-validator/composer.lock b/plugins/email/vendor/egulias/email-validator/composer.lock index c575e7f..4b918d1 100644 --- a/plugins/email/vendor/egulias/email-validator/composer.lock +++ b/plugins/email/vendor/egulias/email-validator/composer.lock @@ -8,32 +8,28 @@ "packages": [ { "name": "doctrine/lexer", - "version": "1.2.1", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "e864bbf5904cb8f5bb334f99209b48018522f042" + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042", - "reference": "e864bbf5904cb8f5bb334f99209b48018522f042", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpstan/phpstan": "^0.11.8", - "phpunit/phpunit": "^8.2" + "doctrine/coding-standard": "^9.0", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.11" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" @@ -68,7 +64,7 @@ ], "support": { "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/1.2.1" + "source": "https://github.com/doctrine/lexer/tree/1.2.3" }, "funding": [ { @@ -84,20 +80,20 @@ "type": "tidelift" } ], - "time": "2020-05-25T17:44:05+00:00" + "time": "2022-02-28T11:07:21+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.22.1", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "2d63434d922daf7da8dd863e7907e67ee3031483" + "reference": "749045c69efb97c70d25d7463abba812e91f3a44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/2d63434d922daf7da8dd863e7907e67ee3031483", - "reference": "2d63434d922daf7da8dd863e7907e67ee3031483", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/749045c69efb97c70d25d7463abba812e91f3a44", + "reference": "749045c69efb97c70d25d7463abba812e91f3a44", "shasum": "" }, "require": { @@ -111,7 +107,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -119,12 +115,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -155,7 +151,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.25.0" }, "funding": [ { @@ -171,20 +167,20 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-09-14T14:02:44+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.22.1", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248" + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248", - "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", "shasum": "" }, "require": { @@ -196,7 +192,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -204,12 +200,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -239,7 +235,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" }, "funding": [ { @@ -255,20 +251,20 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.22.1", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", "shasum": "" }, "require": { @@ -277,7 +273,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -285,12 +281,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -315,7 +311,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.25.0" }, "funding": [ { @@ -331,33 +327,33 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-05-27T09:17:38+00:00" } ], "packages-dev": [ { "name": "amphp/amp", - "version": "v2.5.2", + "version": "v2.6.2", "source": { "type": "git", "url": "https://github.com/amphp/amp.git", - "reference": "efca2b32a7580087adb8aabbff6be1dc1bb924a9" + "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/efca2b32a7580087adb8aabbff6be1dc1bb924a9", - "reference": "efca2b32a7580087adb8aabbff6be1dc1bb924a9", + "url": "https://api.github.com/repos/amphp/amp/zipball/9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", + "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", "shasum": "" }, "require": { - "php": ">=7" + "php": ">=7.1" }, "require-dev": { "amphp/php-cs-fixer-config": "dev-master", "amphp/phpunit-util": "^1", "ext-json": "*", "jetbrains/phpstorm-stubs": "^2019.3", - "phpunit/phpunit": "^6.0.9 | ^7", + "phpunit/phpunit": "^7 | ^8 | ^9", "psalm/phar": "^3.11@dev", "react/promise": "^2" }, @@ -368,13 +364,13 @@ } }, "autoload": { - "psr-4": { - "Amp\\": "lib" - }, "files": [ "lib/functions.php", "lib/Internal/functions.php" - ] + ], + "psr-4": { + "Amp\\": "lib" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -399,7 +395,7 @@ } ], "description": "A non-blocking concurrency framework for PHP applications.", - "homepage": "http://amphp.org/amp", + "homepage": "https://amphp.org/amp", "keywords": [ "async", "asynchronous", @@ -414,7 +410,7 @@ "support": { "irc": "irc://irc.freenode.org/amphp", "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v2.5.2" + "source": "https://github.com/amphp/amp/tree/v2.6.2" }, "funding": [ { @@ -422,20 +418,20 @@ "type": "github" } ], - "time": "2021-01-10T17:06:37+00:00" + "time": "2022-02-20T17:52:18+00:00" }, { "name": "amphp/byte-stream", - "version": "v1.8.0", + "version": "v1.8.1", "source": { "type": "git", "url": "https://github.com/amphp/byte-stream.git", - "reference": "f0c20cf598a958ba2aa8c6e5a71c697d652c7088" + "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/byte-stream/zipball/f0c20cf598a958ba2aa8c6e5a71c697d652c7088", - "reference": "f0c20cf598a958ba2aa8c6e5a71c697d652c7088", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/acbd8002b3536485c997c4e019206b3f10ca15bd", + "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd", "shasum": "" }, "require": { @@ -457,12 +453,12 @@ } }, "autoload": { - "psr-4": { - "Amp\\ByteStream\\": "lib" - }, "files": [ "lib/functions.php" - ] + ], + "psr-4": { + "Amp\\ByteStream\\": "lib" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -491,22 +487,28 @@ "support": { "irc": "irc://irc.freenode.org/amphp", "issues": "https://github.com/amphp/byte-stream/issues", - "source": "https://github.com/amphp/byte-stream/tree/master" + "source": "https://github.com/amphp/byte-stream/tree/v1.8.1" }, - "time": "2020-06-29T18:35:05+00:00" + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2021-03-30T17:13:30+00:00" }, { "name": "composer/package-versions-deprecated", - "version": "1.11.99.1", + "version": "1.11.99.5", "source": { "type": "git", "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "7413f0b55a051e89485c5cb9f765fe24bb02a7b6" + "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/7413f0b55a051e89485c5cb9f765fe24bb02a7b6", - "reference": "7413f0b55a051e89485c5cb9f765fe24bb02a7b6", + "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b4f54f74ef3453349c24a845d22392cd31e65f1d", + "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d", "shasum": "" }, "require": { @@ -550,7 +552,7 @@ "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", "support": { "issues": "https://github.com/composer/package-versions-deprecated/issues", - "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.1" + "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.5" }, "funding": [ { @@ -566,27 +568,98 @@ "type": "tidelift" } ], - "time": "2020-11-11T10:22:58+00:00" + "time": "2022-01-17T14:14:24+00:00" }, { - "name": "composer/semver", - "version": "3.2.4", + "name": "composer/pcre", + "version": "3.0.0", "source": { "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464" + "url": "https://github.com/composer/pcre.git", + "reference": "e300eb6c535192decd27a85bc72a9290f0d6b3bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", - "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", + "url": "https://api.github.com/repos/composer/pcre/zipball/e300eb6c535192decd27a85bc72a9290f0d6b3bd", + "reference": "e300eb6c535192decd27a85bc72a9290f0d6b3bd", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.3", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.0.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-02-25T20:21:48+00:00" + }, + { + "name": "composer/semver", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.54", + "phpstan/phpstan": "^1.4", "symfony/phpunit-bridge": "^4.2 || ^5" }, "type": "library", @@ -631,7 +704,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.2.4" + "source": "https://github.com/composer/semver/tree/3.3.2" }, "funding": [ { @@ -647,28 +720,31 @@ "type": "tidelift" } ], - "time": "2020-11-13T08:59:24+00:00" + "time": "2022-04-01T19:23:25+00:00" }, { "name": "composer/xdebug-handler", - "version": "1.4.5", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "f28d44c286812c714741478d968104c5e604a1d4" + "reference": "ced299686f41dce890debac69273b47ffe98a40c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f28d44c286812c714741478d968104c5e604a1d4", - "reference": "f28d44c286812c714741478d968104c5e604a1d4", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", + "reference": "ced299686f41dce890debac69273b47ffe98a40c", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0 || ^8.0", - "psr/log": "^1.0" + "composer/pcre": "^1 || ^2 || ^3", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1 || ^2 || ^3" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8" + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^6.0" }, "type": "library", "autoload": { @@ -694,7 +770,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/1.4.5" + "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" }, "funding": [ { @@ -710,7 +786,7 @@ "type": "tidelift" } ], - "time": "2020-11-13T08:04:11+00:00" + "time": "2022-02-25T21:32:43+00:00" }, { "name": "dnoegel/php-xdg-base-dir", @@ -751,29 +827,30 @@ }, { "name": "doctrine/instantiator", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc", + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^8.0", + "doctrine/coding-standard": "^9", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.22" }, "type": "library", "autoload": { @@ -800,7 +877,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.0" + "source": "https://github.com/doctrine/instantiator/tree/1.4.1" }, "funding": [ { @@ -816,24 +893,24 @@ "type": "tidelift" } ], - "time": "2020-11-10T18:47:58+00:00" + "time": "2022-03-03T08:28:38+00:00" }, { "name": "felixfbecker/advanced-json-rpc", - "version": "v3.2.0", + "version": "v3.2.1", "source": { "type": "git", "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", - "reference": "06f0b06043c7438959dbdeed8bb3f699a19be22e" + "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/06f0b06043c7438959dbdeed8bb3f699a19be22e", - "reference": "06f0b06043c7438959dbdeed8bb3f699a19be22e", + "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/b5f37dbff9a8ad360ca341f3240dc1c168b45447", + "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447", "shasum": "" }, "require": { - "netresearch/jsonmapper": "^1.0 || ^2.0", + "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", "php": "^7.1 || ^8.0", "phpdocumentor/reflection-docblock": "^4.3.4 || ^5.0.0" }, @@ -859,22 +936,22 @@ "description": "A more advanced JSONRPC implementation", "support": { "issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues", - "source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/v3.2.0" + "source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/v3.2.1" }, - "time": "2021-01-10T17:48:47+00:00" + "time": "2021-06-11T22:34:44+00:00" }, { "name": "felixfbecker/language-server-protocol", - "version": "1.5.1", + "version": "v1.5.2", "source": { "type": "git", "url": "https://github.com/felixfbecker/php-language-server-protocol.git", - "reference": "9d846d1f5cf101deee7a61c8ba7caa0a975cd730" + "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/9d846d1f5cf101deee7a61c8ba7caa0a975cd730", - "reference": "9d846d1f5cf101deee7a61c8ba7caa0a975cd730", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/6e82196ffd7c62f7794d778ca52b69feec9f2842", + "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842", "shasum": "" }, "require": { @@ -915,39 +992,41 @@ ], "support": { "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", - "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/1.5.1" + "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.2" }, - "time": "2021-02-22T14:02:09+00:00" + "time": "2022-03-02T22:36:06+00:00" }, { "name": "guzzlehttp/guzzle", - "version": "7.2.0", + "version": "7.4.3", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "0aa74dfb41ae110835923ef10a9d803a22d50e79" + "reference": "74a8602c6faec9ef74b7a9391ac82c5e65b1cdab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/0aa74dfb41ae110835923ef10a9d803a22d50e79", - "reference": "0aa74dfb41ae110835923ef10a9d803a22d50e79", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/74a8602c6faec9ef74b7a9391ac82c5e65b1cdab", + "reference": "74a8602c6faec9ef74b7a9391ac82c5e65b1cdab", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.4", - "guzzlehttp/psr7": "^1.7", + "guzzlehttp/promises": "^1.5", + "guzzlehttp/psr7": "^1.8.3 || ^2.1", "php": "^7.2.5 || ^8.0", - "psr/http-client": "^1.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.4.1", "ext-curl": "*", "php-http/client-integration-tests": "^3.0", "phpunit/phpunit": "^8.5.5 || ^9.3.5", - "psr/log": "^1.1" + "psr/log": "^1.1 || ^2.0 || ^3.0" }, "suggest": { "ext-curl": "Required for CURL handler support", @@ -957,35 +1036,59 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "7.1-dev" + "dev-master": "7.4-dev" } }, "autoload": { - "psr-4": { - "GuzzleHttp\\": "src/" - }, "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://sagikazarmark.hu" + "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", - "homepage": "http://guzzlephp.org/", "keywords": [ "client", "curl", @@ -999,7 +1102,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.2.0" + "source": "https://github.com/guzzle/guzzle/tree/7.4.3" }, "funding": [ { @@ -1011,28 +1114,24 @@ "type": "github" }, { - "url": "https://github.com/alexeyshockov", - "type": "github" - }, - { - "url": "https://github.com/gmponos", - "type": "github" + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" } ], - "time": "2020-10-10T11:47:56+00:00" + "time": "2022-05-25T13:24:33+00:00" }, { "name": "guzzlehttp/promises", - "version": "1.4.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "60d379c243457e073cff02bc323a2a86cb355631" + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631", - "reference": "60d379c243457e073cff02bc323a2a86cb355631", + "url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da", + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da", "shasum": "" }, "require": { @@ -1044,26 +1143,41 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "1.5-dev" } }, "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "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", @@ -1072,35 +1186,52 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.4.0" + "source": "https://github.com/guzzle/promises/tree/1.5.1" }, - "time": "2020-09-30T07:37:28+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/promises", + "type": "tidelift" + } + ], + "time": "2021-10-22T20:56:57+00:00" }, { "name": "guzzlehttp/psr7", - "version": "1.7.0", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3" + "reference": "c94a94f120803a18554c1805ef2e539f8285f9a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/53330f47520498c0ae1f61f7e2c90f55690c06a3", - "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/c94a94f120803a18554c1805ef2e539f8285f9a2", + "reference": "c94a94f120803a18554c1805ef2e539f8285f9a2", "shasum": "" }, "require": { - "php": ">=5.4.0", - "psr/http-message": "~1.0", - "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3.0" }, "provide": { + "psr/http-factory-implementation": "1.0", "psr/http-message-implementation": "1.0" }, "require-dev": { - "ext-zlib": "*", - "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + "bamarni/composer-bin-plugin": "^1.4.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.8 || ^9.3.10" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -1108,30 +1239,53 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "2.2-dev" } }, "autoload": { "psr-4": { "GuzzleHttp\\Psr7\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] + } }, "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": "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" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" } ], "description": "PSR-7 message implementation that also provides common utility methods", @@ -1147,43 +1301,58 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/1.7.0" + "source": "https://github.com/guzzle/psr7/tree/2.2.1" }, - "time": "2020-09-30T07:37:11+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/psr7", + "type": "tidelift" + } + ], + "time": "2022-03-20T21:55:58+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.10.2", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, - "replace": { - "myclabs/deep-copy": "self.version" + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" }, "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, "files": [ "src/DeepCopy/deep_copy.php" - ] + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1199,7 +1368,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" }, "funding": [ { @@ -1207,20 +1376,20 @@ "type": "tidelift" } ], - "time": "2020-11-13T09:40:50+00:00" + "time": "2022-03-03T13:19:32+00:00" }, { "name": "netresearch/jsonmapper", - "version": "v2.1.0", + "version": "v4.0.0", "source": { "type": "git", "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e" + "reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/e0f1e33a71587aca81be5cffbb9746510e1fe04e", - "reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d", + "reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d", "shasum": "" }, "require": { @@ -1228,10 +1397,10 @@ "ext-pcre": "*", "ext-reflection": "*", "ext-spl": "*", - "php": ">=5.6" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4 || ~7.0", + "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0", "squizlabs/php_codesniffer": "~3.5" }, "type": "library", @@ -1256,22 +1425,22 @@ "support": { "email": "cweiske@cweiske.de", "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/master" + "source": "https://github.com/cweiske/jsonmapper/tree/v4.0.0" }, - "time": "2020-04-16T18:48:43+00:00" + "time": "2020-12-01T19:48:11+00:00" }, { "name": "nikic/php-parser", - "version": "v4.10.4", + "version": "v4.13.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e" + "reference": "210577fe3cf7badcc5814d99455df46564f3c077" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c6d052fc58cb876152f89f532b95a8d7907e7f0e", - "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", + "reference": "210577fe3cf7badcc5814d99455df46564f3c077", "shasum": "" }, "require": { @@ -1312,9 +1481,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.4" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" }, - "time": "2020-12-20T10:01:03+00:00" + "time": "2021-11-30T19:35:32+00:00" }, { "name": "openlss/lib-array2xml", @@ -1371,16 +1540,16 @@ }, { "name": "phar-io/manifest", - "version": "2.0.1", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133" + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", "shasum": "" }, "require": { @@ -1425,22 +1594,22 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/master" + "source": "https://github.com/phar-io/manifest/tree/2.0.3" }, - "time": "2020-06-27T14:33:11+00:00" + "time": "2021-07-20T11:28:43+00:00" }, { "name": "phar-io/version", - "version": "3.1.0", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "bae7c545bef187884426f042434e561ab1ddb182" + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", - "reference": "bae7c545bef187884426f042434e561ab1ddb182", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", "shasum": "" }, "require": { @@ -1476,22 +1645,22 @@ "description": "Library for handling version information and constraints", "support": { "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.1.0" + "source": "https://github.com/phar-io/version/tree/3.2.1" }, - "time": "2021-02-23T14:00:09+00:00" + "time": "2022-02-21T01:04:05+00:00" }, { "name": "php-coveralls/php-coveralls", - "version": "v2.4.3", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/php-coveralls/php-coveralls.git", - "reference": "909381bd40a17ae6e9076051f0d73293c1c091af" + "reference": "007e13afdcdba2cd0efcc5f72c3b7efb356a8bd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-coveralls/php-coveralls/zipball/909381bd40a17ae6e9076051f0d73293c1c091af", - "reference": "909381bd40a17ae6e9076051f0d73293c1c091af", + "url": "https://api.github.com/repos/php-coveralls/php-coveralls/zipball/007e13afdcdba2cd0efcc5f72c3b7efb356a8bd4", + "reference": "007e13afdcdba2cd0efcc5f72c3b7efb356a8bd4", "shasum": "" }, "require": { @@ -1499,11 +1668,11 @@ "ext-simplexml": "*", "guzzlehttp/guzzle": "^6.0 || ^7.0", "php": "^5.5 || ^7.0 || ^8.0", - "psr/log": "^1.0", - "symfony/config": "^2.1 || ^3.0 || ^4.0 || ^5.0", - "symfony/console": "^2.1 || ^3.0 || ^4.0 || ^5.0", - "symfony/stopwatch": "^2.0 || ^3.0 || ^4.0 || ^5.0", - "symfony/yaml": "^2.0.5 || ^3.0 || ^4.0 || ^5.0" + "psr/log": "^1.0 || ^2.0", + "symfony/config": "^2.1 || ^3.0 || ^4.0 || ^5.0 || ^6.0", + "symfony/console": "^2.1 || ^3.0 || ^4.0 || ^5.0 || ^6.0", + "symfony/stopwatch": "^2.0 || ^3.0 || ^4.0 || ^5.0 || ^6.0", + "symfony/yaml": "^2.0.5 || ^3.0 || ^4.0 || ^5.0 || ^6.0" }, "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.4.3 || ^6.0 || ^7.0 || ^8.0 || ^9.0", @@ -1559,9 +1728,9 @@ ], "support": { "issues": "https://github.com/php-coveralls/php-coveralls/issues", - "source": "https://github.com/php-coveralls/php-coveralls/tree/v2.4.3" + "source": "https://github.com/php-coveralls/php-coveralls/tree/v2.5.2" }, - "time": "2020-12-24T09:17:03+00:00" + "time": "2021-12-06T17:05:08+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -1618,16 +1787,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.2.2", + "version": "5.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", "shasum": "" }, "require": { @@ -1638,7 +1807,8 @@ "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.2" + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" }, "type": "library", "extra": { @@ -1668,22 +1838,22 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" }, - "time": "2020-09-03T19:13:55+00:00" + "time": "2021-10-19T17:43:47+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.4.0", + "version": "1.6.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" + "reference": "77a32518733312af16a44300404e945338981de3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3", + "reference": "77a32518733312af16a44300404e945338981de3", "shasum": "" }, "require": { @@ -1691,7 +1861,8 @@ "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "*" + "ext-tokenizer": "*", + "psalm/phar": "^4.8" }, "type": "library", "extra": { @@ -1717,39 +1888,39 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1" }, - "time": "2020-09-17T18:55:26+00:00" + "time": "2022-03-15T21:29:03+00:00" }, { "name": "phpspec/prophecy", - "version": "1.12.2", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "245710e971a030f42e08f4912863805570f23d39" + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/245710e971a030f42e08f4912863805570f23d39", - "reference": "245710e971a030f42e08f4912863805570f23d39", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13", + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13", "shasum": "" }, "require": { "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.1", + "php": "^7.2 || ~8.0, <8.2", "phpdocumentor/reflection-docblock": "^5.2", "sebastian/comparator": "^3.0 || ^4.0", "sebastian/recursion-context": "^3.0 || ^4.0" }, "require-dev": { - "phpspec/phpspec": "^6.0", + "phpspec/phpspec": "^6.0 || ^7.0", "phpunit/phpunit": "^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { @@ -1784,46 +1955,50 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.12.2" + "source": "https://github.com/phpspec/prophecy/tree/v1.15.0" }, - "time": "2020-12-19T10:15:11+00:00" + "time": "2021-12-08T12:19:24+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "7.0.14", + "version": "9.2.15", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "bb7c9a210c72e4709cdde67f8b7362f672f2225c" + "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/bb7c9a210c72e4709cdde67f8b7362f672f2225c", - "reference": "bb7c9a210c72e4709cdde67f8b7362f672f2225c", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2e9da11878c4202f97915c1cb4bb1ca318a63f5f", + "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-xmlwriter": "*", - "php": ">=7.2", - "phpunit/php-file-iterator": "^2.0.2", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.1.1 || ^4.0", - "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^4.2.2", - "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1.3" + "nikic/php-parser": "^4.13.0", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" }, "require-dev": { - "phpunit/phpunit": "^8.2.2" + "phpunit/phpunit": "^9.3" }, "suggest": { - "ext-xdebug": "^2.7.2" + "ext-pcov": "*", + "ext-xdebug": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "7.0-dev" + "dev-master": "9.2-dev" } }, "autoload": { @@ -1851,7 +2026,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/7.0.14" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.15" }, "funding": [ { @@ -1859,32 +2034,32 @@ "type": "github" } ], - "time": "2020-12-02T13:39:03+00:00" + "time": "2022-03-07T09:28:20+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "2.0.3", + "version": "3.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "4b49fb70f067272b659ef0174ff9ca40fdaa6357" + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/4b49fb70f067272b659ef0174ff9ca40fdaa6357", - "reference": "4b49fb70f067272b659ef0174ff9ca40fdaa6357", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^8.5" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1911,7 +2086,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0.3" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" }, "funding": [ { @@ -1919,26 +2094,97 @@ "type": "github" } ], - "time": "2020-11-30T08:25:21+00:00" + "time": "2021-12-02T12:48:52+00:00" }, { - "name": "phpunit/php-text-template", - "version": "1.2.1", + "name": "phpunit/php-invoker", + "version": "3.1.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -1962,34 +2208,40 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" }, - "time": "2015-06-21T13:50:34+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" }, { "name": "phpunit/php-timer", - "version": "2.1.3", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662" + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2454ae1765516d20c4ffe103d85a58a9a3bd5662", - "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^8.5" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -2015,7 +2267,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/2.1.3" + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" }, "funding": [ { @@ -2023,80 +2275,20 @@ "type": "github" } ], - "time": "2020-11-30T08:20:02+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "3.1.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "472b687829041c24b25f475e14c2f38a09edf1c2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/472b687829041c24b25f475e14c2f38a09edf1c2", - "reference": "472b687829041c24b25f475e14c2f38a09edf1c2", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", - "source": "https://github.com/sebastianbergmann/php-token-stream/tree/3.1.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "abandoned": true, - "time": "2020-11-30T08:38:46+00:00" + "time": "2020-10-26T13:16:10+00:00" }, { "name": "phpunit/phpunit", - "version": "8.5.14", + "version": "9.5.20", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c25f79895d27b6ecd5abfa63de1606b786a461a3" + "reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c25f79895d27b6ecd5abfa63de1606b786a461a3", - "reference": "c25f79895d27b6ecd5abfa63de1606b786a461a3", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/12bc8879fb65aef2138b26fc633cb1e3620cffba", + "reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba", "shasum": "" }, "require": { @@ -2107,32 +2299,35 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.0", - "phar-io/manifest": "^2.0.1", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", - "php": ">=7.2", - "phpspec/prophecy": "^1.10.3", - "phpunit/php-code-coverage": "^7.0.12", - "phpunit/php-file-iterator": "^2.0.2", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^2.1.2", - "sebastian/comparator": "^3.0.2", - "sebastian/diff": "^3.0.2", - "sebastian/environment": "^4.2.3", - "sebastian/exporter": "^3.1.2", - "sebastian/global-state": "^3.0.0", - "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^2.0.1", - "sebastian/type": "^1.1.3", - "sebastian/version": "^2.0.1" + "php": ">=7.3", + "phpspec/prophecy": "^1.12.1", + "phpunit/php-code-coverage": "^9.2.13", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.5", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.3", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^3.0", + "sebastian/version": "^3.0.2" }, "require-dev": { - "ext-pdo": "*" + "ext-pdo": "*", + "phpspec/prophecy-phpunit": "^2.0.1" }, "suggest": { "ext-soap": "*", - "ext-xdebug": "*", - "phpunit/php-invoker": "^2.0.0" + "ext-xdebug": "*" }, "bin": [ "phpunit" @@ -2140,10 +2335,13 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "8.5-dev" + "dev-master": "9.5-dev" } }, "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], "classmap": [ "src/" ] @@ -2168,11 +2366,11 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/8.5.14" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.20" }, "funding": [ { - "url": "https://phpunit.de/donate.html", + "url": "https://phpunit.de/sponsors.html", "type": "custom" }, { @@ -2180,31 +2378,26 @@ "type": "github" } ], - "time": "2021-01-17T07:37:30+00:00" + "time": "2022-04-01T12:37:26+00:00" }, { "name": "psr/container", - "version": "1.0.0", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=7.4.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "autoload": { "psr-4": { "Psr\\Container\\": "src/" @@ -2217,7 +2410,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common Container Interface (PHP FIG PSR-11)", @@ -2231,9 +2424,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/master" + "source": "https://github.com/php-fig/container/tree/1.1.2" }, - "time": "2017-02-14T16:28:37+00:00" + "time": "2021-11-05T16:50:12+00:00" }, { "name": "psr/http-client", @@ -2287,6 +2480,61 @@ }, "time": "2020-06-29T06:28:15+00:00" }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2019-04-30T12:38:16+00:00" + }, { "name": "psr/http-message", "version": "1.0.1", @@ -2342,16 +2590,16 @@ }, { "name": "psr/log", - "version": "1.1.3", + "version": "1.1.4", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", "shasum": "" }, "require": { @@ -2375,7 +2623,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for logging libraries", @@ -2386,9 +2634,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/1.1.3" + "source": "https://github.com/php-fig/log/tree/1.1.4" }, - "time": "2020-03-23T09:12:05+00:00" + "time": "2021-05-03T11:20:27+00:00" }, { "name": "ralouphie/getallheaders", @@ -2435,29 +2683,141 @@ "time": "2019-03-08T08:55:37+00:00" }, { - "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.2", + "name": "sebastian/cli-parser", + "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619" + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619", - "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", "shasum": "" }, "require": { - "php": ">=5.6" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^8.5" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" } }, "autoload": { @@ -2479,7 +2839,7 @@ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "support": { "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2" + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" }, "funding": [ { @@ -2487,34 +2847,34 @@ "type": "github" } ], - "time": "2020-11-30T08:15:22+00:00" + "time": "2020-09-28T05:30:19+00:00" }, { "name": "sebastian/comparator", - "version": "3.0.3", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "1071dfcef776a57013124ff35e1fc41ccd294758" + "reference": "55f4261989e546dc112258c7a75935a81a7ce382" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1071dfcef776a57013124ff35e1fc41ccd294758", - "reference": "1071dfcef776a57013124ff35e1fc41ccd294758", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", + "reference": "55f4261989e546dc112258c7a75935a81a7ce382", "shasum": "" }, "require": { - "php": ">=7.1", - "sebastian/diff": "^3.0", - "sebastian/exporter": "^3.1" + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^8.5" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -2553,7 +2913,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" }, "funding": [ { @@ -2561,33 +2921,90 @@ "type": "github" } ], - "time": "2020-11-30T08:04:30+00:00" + "time": "2020-10-26T15:49:45+00:00" }, { - "name": "sebastian/diff", - "version": "3.0.3", + "name": "sebastian/complexity", + "version": "2.0.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211" + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/14f72dd46eaf2f2293cbe79c93cc0bc43161a211", - "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", "shasum": "" }, "require": { - "php": ">=7.1" + "nikic/php-parser": "^4.7", + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.0", - "symfony/process": "^2 || ^3.3 || ^4" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" } }, "autoload": { @@ -2619,7 +3036,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" }, "funding": [ { @@ -2627,27 +3044,27 @@ "type": "github" } ], - "time": "2020-11-30T07:59:04+00:00" + "time": "2020-10-26T13:10:38+00:00" }, { "name": "sebastian/environment", - "version": "4.2.4", + "version": "5.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0" + "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", - "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/1b5dff7bb151a4db11d49d90e5408e4e938270f7", + "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^7.5" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-posix": "*" @@ -2655,7 +3072,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "5.1-dev" } }, "autoload": { @@ -2682,7 +3099,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/4.2.4" + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.4" }, "funding": [ { @@ -2690,34 +3107,34 @@ "type": "github" } ], - "time": "2020-11-30T07:53:42+00:00" + "time": "2022-04-03T09:37:03+00:00" }, { "name": "sebastian/exporter", - "version": "3.1.3", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "6b853149eab67d4da22291d36f5b0631c0fd856e" + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/6b853149eab67d4da22291d36f5b0631c0fd856e", - "reference": "6b853149eab67d4da22291d36f5b0631c0fd856e", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9", + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9", "shasum": "" }, "require": { - "php": ">=7.0", - "sebastian/recursion-context": "^3.0" + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -2752,14 +3169,14 @@ } ], "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", + "homepage": "https://www.github.com/sebastianbergmann/exporter", "keywords": [ "export", "exporter" ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/3.1.3" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4" }, "funding": [ { @@ -2767,30 +3184,30 @@ "type": "github" } ], - "time": "2020-11-30T07:47:53+00:00" + "time": "2021-11-11T14:18:36+00:00" }, { "name": "sebastian/global-state", - "version": "3.0.1", + "version": "5.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "474fb9edb7ab891665d3bfc6317f42a0a150454b" + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/474fb9edb7ab891665d3bfc6317f42a0a150454b", - "reference": "474fb9edb7ab891665d3bfc6317f42a0a150454b", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", "shasum": "" }, "require": { - "php": ">=7.2", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^8.0" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-uopz": "*" @@ -2798,7 +3215,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -2823,7 +3240,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/3.0.1" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" }, "funding": [ { @@ -2831,34 +3248,91 @@ "type": "github" } ], - "time": "2020-11-30T07:43:24+00:00" + "time": "2022-02-14T08:28:10+00:00" }, { - "name": "sebastian/object-enumerator", - "version": "3.0.4", + "name": "sebastian/lines-of-code", + "version": "1.0.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2" + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", - "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", "shasum": "" }, "require": { - "php": ">=7.0", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" + "nikic/php-parser": "^4.6", + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" } }, "autoload": { @@ -2880,7 +3354,7 @@ "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4" + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" }, "funding": [ { @@ -2888,32 +3362,32 @@ "type": "github" } ], - "time": "2020-11-30T07:40:27+00:00" + "time": "2020-10-26T13:12:34+00:00" }, { "name": "sebastian/object-reflector", - "version": "1.1.2", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d" + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", - "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", "shasum": "" }, "require": { - "php": ">=7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -2935,7 +3409,7 @@ "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2" + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" }, "funding": [ { @@ -2943,32 +3417,32 @@ "type": "github" } ], - "time": "2020-11-30T07:37:18+00:00" + "time": "2020-10-26T13:14:26+00:00" }, { "name": "sebastian/recursion-context", - "version": "3.0.1", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb" + "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb", - "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", + "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", "shasum": "" }, "require": { - "php": ">=7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -2998,7 +3472,7 @@ "homepage": "http://www.github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" }, "funding": [ { @@ -3006,29 +3480,32 @@ "type": "github" } ], - "time": "2020-11-30T07:34:24+00:00" + "time": "2020-10-26T13:17:30+00:00" }, { "name": "sebastian/resource-operations", - "version": "2.0.2", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3" + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/31d35ca87926450c44eae7e2611d45a7a65ea8b3", - "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -3050,7 +3527,7 @@ "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/2.0.2" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" }, "funding": [ { @@ -3058,32 +3535,32 @@ "type": "github" } ], - "time": "2020-11-30T07:30:19+00:00" + "time": "2020-09-28T06:45:17+00:00" }, { "name": "sebastian/type", - "version": "1.1.4", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4" + "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/0150cfbc4495ed2df3872fb31b26781e4e077eb4", - "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b233b84bc4465aff7b57cf1c4bc75c86d00d6dad", + "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad", "shasum": "" }, "require": { - "php": ">=7.2" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^8.2" + "phpunit/phpunit": "^9.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -3106,7 +3583,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/1.1.4" + "source": "https://github.com/sebastianbergmann/type/tree/3.0.0" }, "funding": [ { @@ -3114,29 +3591,29 @@ "type": "github" } ], - "time": "2020-11-30T07:25:11+00:00" + "time": "2022-03-15T09:54:48+00:00" }, { "name": "sebastian/version", - "version": "2.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + "reference": "c6c1022351a901512170118436c764e473f6de8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", "shasum": "" }, "require": { - "php": ">=5.6" + "php": ">=7.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -3159,40 +3636,47 @@ "homepage": "https://github.com/sebastianbergmann/version", "support": { "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/master" + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" }, - "time": "2016-10-03T07:35:21+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" }, { "name": "symfony/config", - "version": "v5.2.3", + "version": "v5.4.9", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "50e0e1314a3b2609d32b6a5a0d0fb5342494c4ab" + "reference": "8f551fe22672ac7ab2c95fe46d899f960ed4d979" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/50e0e1314a3b2609d32b6a5a0d0fb5342494c4ab", - "reference": "50e0e1314a3b2609d32b6a5a0d0fb5342494c4ab", + "url": "https://api.github.com/repos/symfony/config/zipball/8f551fe22672ac7ab2c95fe46d899f960ed4d979", + "reference": "8f551fe22672ac7ab2c95fe46d899f960ed4d979", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/filesystem": "^4.4|^5.0", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/filesystem": "^4.4|^5.0|^6.0", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22" }, "conflict": { "symfony/finder": "<4.4" }, "require-dev": { - "symfony/event-dispatcher": "^4.4|^5.0", - "symfony/finder": "^4.4|^5.0", - "symfony/messenger": "^4.4|^5.0", - "symfony/service-contracts": "^1.1|^2", - "symfony/yaml": "^4.4|^5.0" + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/finder": "^4.4|^5.0|^6.0", + "symfony/messenger": "^4.4|^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/yaml": "^4.4|^5.0|^6.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -3223,7 +3707,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.2.3" + "source": "https://github.com/symfony/config/tree/v5.4.9" }, "funding": [ { @@ -3239,31 +3723,33 @@ "type": "tidelift" } ], - "time": "2021-01-27T10:15:41+00:00" + "time": "2022-05-17T10:39:36+00:00" }, { "name": "symfony/console", - "version": "v5.2.3", + "version": "v5.4.9", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "89d4b176d12a2946a1ae4e34906a025b7b6b135a" + "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/89d4b176d12a2946a1ae4e34906a025b7b6b135a", - "reference": "89d4b176d12a2946a1ae4e34906a025b7b6b135a", + "url": "https://api.github.com/repos/symfony/console/zipball/829d5d1bf60b2efeb0887b7436873becc71a45eb", + "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb", "shasum": "" }, "require": { "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.8", - "symfony/polyfill-php80": "^1.15", - "symfony/service-contracts": "^1.1|^2", - "symfony/string": "^5.1" + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/string": "^5.1|^6.0" }, "conflict": { + "psr/log": ">=3", "symfony/dependency-injection": "<4.4", "symfony/dotenv": "<5.1", "symfony/event-dispatcher": "<4.4", @@ -3271,16 +3757,16 @@ "symfony/process": "<4.4" }, "provide": { - "psr/log-implementation": "1.0" + "psr/log-implementation": "1.0|2.0" }, "require-dev": { - "psr/log": "~1.0", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/event-dispatcher": "^4.4|^5.0", - "symfony/lock": "^4.4|^5.0", - "symfony/process": "^4.4|^5.0", - "symfony/var-dumper": "^4.4|^5.0" + "psr/log": "^1|^2", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/lock": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/var-dumper": "^4.4|^5.0|^6.0" }, "suggest": { "psr/log": "For using the console logger", @@ -3320,7 +3806,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.2.3" + "source": "https://github.com/symfony/console/tree/v5.4.9" }, "funding": [ { @@ -3336,20 +3822,20 @@ "type": "tidelift" } ], - "time": "2021-01-28T22:06:19+00:00" + "time": "2022-05-18T06:17:34+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.2.0", + "version": "v2.5.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665" + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5fa56b4074d1ae755beb55617ddafe6f5d78f665", - "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", "shasum": "" }, "require": { @@ -3358,7 +3844,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -3387,7 +3873,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/master" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.1" }, "funding": [ { @@ -3403,25 +3889,27 @@ "type": "tidelift" } ], - "time": "2020-09-07T11:33:47+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/filesystem", - "version": "v5.2.3", + "version": "v5.4.9", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "262d033b57c73e8b59cd6e68a45c528318b15038" + "reference": "36a017fa4cce1eff1b8e8129ff53513abcef05ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/262d033b57c73e8b59cd6e68a45c528318b15038", - "reference": "262d033b57c73e8b59cd6e68a45c528318b15038", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/36a017fa4cce1eff1b8e8129ff53513abcef05ba", + "reference": "36a017fa4cce1eff1b8e8129ff53513abcef05ba", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/polyfill-ctype": "~1.8" + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -3449,7 +3937,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.2.3" + "source": "https://github.com/symfony/filesystem/tree/v5.4.9" }, "funding": [ { @@ -3465,32 +3953,35 @@ "type": "tidelift" } ], - "time": "2021-01-27T10:01:46+00:00" + "time": "2022-05-20T13:55:35+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.22.1", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" + "reference": "30885182c981ab175d4d034db0f6f469898070ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", - "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-ctype": "*" + }, "suggest": { "ext-ctype": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3498,12 +3989,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3528,7 +4019,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" }, "funding": [ { @@ -3544,20 +4035,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-10-20T20:35:02+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.22.1", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170" + "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/5601e09b69f26c1828b13b6bb87cb07cddba3170", - "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", + "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", "shasum": "" }, "require": { @@ -3569,7 +4060,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3577,12 +4068,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3609,7 +4100,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0" }, "funding": [ { @@ -3625,32 +4116,35 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-11-23T21:10:46+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.22.1", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "5232de97ee3b75b0360528dae24e73db49566ab1" + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1", - "reference": "5232de97ee3b75b0360528dae24e73db49566ab1", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-mbstring": "*" + }, "suggest": { "ext-mbstring": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3658,12 +4152,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3689,7 +4183,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0" }, "funding": [ { @@ -3705,20 +4199,20 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-11-30T18:21:41+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.22.1", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2" + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", - "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", "shasum": "" }, "require": { @@ -3727,7 +4221,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3735,12 +4229,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -3768,7 +4262,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.25.0" }, "funding": [ { @@ -3784,20 +4278,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-06-05T21:20:04+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.22.1", + "version": "v1.25.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" + "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", - "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c", + "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c", "shasum": "" }, "require": { @@ -3806,7 +4300,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3814,12 +4308,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -3851,7 +4345,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0" }, "funding": [ { @@ -3867,25 +4361,108 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2022-03-04T08:16:47+00:00" }, { - "name": "symfony/service-contracts", - "version": "v2.2.0", + "name": "symfony/polyfill-php81", + "version": "v1.25.0", "source": { "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1" + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1", - "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", + "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-09-13T13:58:11+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/24d9dc654b83e91aa59f9d167b131bc3b5bea24c", + "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c", "shasum": "" }, "require": { "php": ">=7.2.5", - "psr/container": "^1.0" + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" }, "suggest": { "symfony/service-implementation": "" @@ -3893,7 +4470,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -3930,7 +4507,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/master" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.1" }, "funding": [ { @@ -3946,25 +4523,25 @@ "type": "tidelift" } ], - "time": "2020-09-07T11:33:47+00:00" + "time": "2022-03-13T20:07:29+00:00" }, { "name": "symfony/stopwatch", - "version": "v5.2.3", + "version": "v5.4.5", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "b12274acfab9d9850c52583d136a24398cdf1a0c" + "reference": "4d04b5c24f3c9a1a168a131f6cbe297155bc0d30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/b12274acfab9d9850c52583d136a24398cdf1a0c", - "reference": "b12274acfab9d9850c52583d136a24398cdf1a0c", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/4d04b5c24f3c9a1a168a131f6cbe297155bc0d30", + "reference": "4d04b5c24f3c9a1a168a131f6cbe297155bc0d30", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/service-contracts": "^1.0|^2" + "symfony/service-contracts": "^1|^2|^3" }, "type": "library", "autoload": { @@ -3992,7 +4569,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.2.3" + "source": "https://github.com/symfony/stopwatch/tree/v5.4.5" }, "funding": [ { @@ -4008,20 +4585,20 @@ "type": "tidelift" } ], - "time": "2021-01-27T10:15:41+00:00" + "time": "2022-02-18T16:06:09+00:00" }, { "name": "symfony/string", - "version": "v5.2.3", + "version": "v5.4.9", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "c95468897f408dd0aca2ff582074423dd0455122" + "reference": "985e6a9703ef5ce32ba617c9c7d97873bb7b2a99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/c95468897f408dd0aca2ff582074423dd0455122", - "reference": "c95468897f408dd0aca2ff582074423dd0455122", + "url": "https://api.github.com/repos/symfony/string/zipball/985e6a9703ef5ce32ba617c9c7d97873bb7b2a99", + "reference": "985e6a9703ef5ce32ba617c9c7d97873bb7b2a99", "shasum": "" }, "require": { @@ -4032,20 +4609,23 @@ "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php80": "~1.15" }, + "conflict": { + "symfony/translation-contracts": ">=3.0" + }, "require-dev": { - "symfony/error-handler": "^4.4|^5.0", - "symfony/http-client": "^4.4|^5.0", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/http-client": "^4.4|^5.0|^6.0", "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0" + "symfony/var-exporter": "^4.4|^5.0|^6.0" }, "type": "library", "autoload": { - "psr-4": { - "Symfony\\Component\\String\\": "" - }, "files": [ "Resources/functions.php" ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, "exclude-from-classmap": [ "/Tests/" ] @@ -4075,7 +4655,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.2.3" + "source": "https://github.com/symfony/string/tree/v5.4.9" }, "funding": [ { @@ -4091,32 +4671,32 @@ "type": "tidelift" } ], - "time": "2021-01-25T15:14:59+00:00" + "time": "2022-04-19T10:40:37+00:00" }, { "name": "symfony/yaml", - "version": "v5.2.3", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "338cddc6d74929f6adf19ca5682ac4b8e109cdb0" + "reference": "e80f87d2c9495966768310fc531b487ce64237a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/338cddc6d74929f6adf19ca5682ac4b8e109cdb0", - "reference": "338cddc6d74929f6adf19ca5682ac4b8e109cdb0", + "url": "https://api.github.com/repos/symfony/yaml/zipball/e80f87d2c9495966768310fc531b487ce64237a2", + "reference": "e80f87d2c9495966768310fc531b487ce64237a2", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/polyfill-ctype": "~1.8" + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/console": "<4.4" + "symfony/console": "<5.3" }, "require-dev": { - "symfony/console": "^4.4|^5.0" + "symfony/console": "^5.3|^6.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" @@ -4150,7 +4730,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.2.3" + "source": "https://github.com/symfony/yaml/tree/v5.4.3" }, "funding": [ { @@ -4166,20 +4746,20 @@ "type": "tidelift" } ], - "time": "2021-02-03T04:42:09+00:00" + "time": "2022-01-26T16:32:32+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "75a63c33a8577608444246075ea0af0d052e452a" + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", - "reference": "75a63c33a8577608444246075ea0af0d052e452a", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", "shasum": "" }, "require": { @@ -4208,7 +4788,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/master" + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" }, "funding": [ { @@ -4216,29 +4796,30 @@ "type": "github" } ], - "time": "2020-07-12T23:59:07+00:00" + "time": "2021-07-28T10:34:58+00:00" }, { "name": "vimeo/psalm", - "version": "4.6.2", + "version": "4.23.0", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "bca09d74adc704c4eaee36a3c3e9d379e290fc3b" + "reference": "f1fe6ff483bf325c803df9f510d09a03fd796f88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/bca09d74adc704c4eaee36a3c3e9d379e290fc3b", - "reference": "bca09d74adc704c4eaee36a3c3e9d379e290fc3b", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/f1fe6ff483bf325c803df9f510d09a03fd796f88", + "reference": "f1fe6ff483bf325c803df9f510d09a03fd796f88", "shasum": "" }, "require": { - "amphp/amp": "^2.1", + "amphp/amp": "^2.4.2", "amphp/byte-stream": "^1.5", "composer/package-versions-deprecated": "^1.8.0", "composer/semver": "^1.4 || ^2.0 || ^3.0", - "composer/xdebug-handler": "^1.1", + "composer/xdebug-handler": "^1.1 || ^2.0 || ^3.0", "dnoegel/php-xdg-base-dir": "^0.1.1", + "ext-ctype": "*", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", @@ -4248,18 +4829,18 @@ "felixfbecker/advanced-json-rpc": "^3.0.3", "felixfbecker/language-server-protocol": "^1.5", "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", - "nikic/php-parser": "^4.10.1", + "nikic/php-parser": "^4.13", "openlss/lib-array2xml": "^1.0", "php": "^7.1|^8", "sebastian/diff": "^3.0 || ^4.0", - "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0", + "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0 || ^6.0", + "symfony/polyfill-php80": "^1.25", "webmozart/path-util": "^2.3" }, "provide": { "psalm/psalm": "self.version" }, "require-dev": { - "amphp/amp": "^2.4.2", "bamarni/composer-bin-plugin": "^1.2", "brianium/paratest": "^4.0||^6.0", "ext-curl": "*", @@ -4268,14 +4849,15 @@ "phpmyadmin/sql-parser": "5.1.0||dev-master", "phpspec/prophecy": ">=1.9.0", "phpunit/phpunit": "^9.0", - "psalm/plugin-phpunit": "^0.13", - "slevomat/coding-standard": "^6.3.11", + "psalm/plugin-phpunit": "^0.16", + "slevomat/coding-standard": "^7.0", "squizlabs/php_codesniffer": "^3.5", - "symfony/process": "^4.3", + "symfony/process": "^4.3 || ^5.0 || ^6.0", "weirdan/prophecy-shim": "^1.0 || ^2.0" }, "suggest": { - "ext-igbinary": "^2.0.5" + "ext-curl": "In order to send data to shepherd", + "ext-igbinary": "^2.0.5 is required, used to serialize caching data" }, "bin": [ "psalm", @@ -4294,13 +4876,13 @@ } }, "autoload": { - "psr-4": { - "Psalm\\": "src/Psalm/" - }, "files": [ "src/functions.php", "src/spl_object_id.php" - ] + ], + "psr-4": { + "Psalm\\": "src/Psalm/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4319,36 +4901,41 @@ ], "support": { "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm/tree/4.6.2" + "source": "https://github.com/vimeo/psalm/tree/4.23.0" }, - "time": "2021-02-26T02:24:18+00:00" + "time": "2022-04-28T17:35:49+00:00" }, { "name": "webmozart/assert", - "version": "1.9.1", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0 || ^8.0", + "php": "^7.2 || ^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<3.9.1" + "vimeo/psalm": "<4.6.1 || 4.6.2" }, "require-dev": { - "phpunit/phpunit": "^4.8.36 || ^7.5.13" + "phpunit/phpunit": "^8.5.13" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -4372,9 +4959,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.9.1" + "source": "https://github.com/webmozarts/assert/tree/1.10.0" }, - "time": "2020-07-08T17:02:28+00:00" + "time": "2021-03-09T10:59:23+00:00" }, { "name": "webmozart/path-util", @@ -4424,6 +5011,7 @@ "issues": "https://github.com/webmozart/path-util/issues", "source": "https://github.com/webmozart/path-util/tree/2.3.0" }, + "abandoned": "symfony/filesystem", "time": "2015-12-17T08:42:14+00:00" } ], diff --git a/plugins/email/vendor/egulias/email-validator/src/EmailLexer.php b/plugins/email/vendor/egulias/email-validator/src/EmailLexer.php index 41e9ea9..7e660b6 100644 --- a/plugins/email/vendor/egulias/email-validator/src/EmailLexer.php +++ b/plugins/email/vendor/egulias/email-validator/src/EmailLexer.php @@ -61,7 +61,7 @@ class EmailLexer extends AbstractLexer * * @var array */ - protected $charValue = array( + protected $charValue = [ '{' => self::S_OPENCURLYBRACES, '}' => self::S_CLOSECURLYBRACES, '(' => self::S_OPENPARENTHESIS, @@ -105,11 +105,29 @@ class EmailLexer extends AbstractLexer '?' => self::QUESTIONMARK, '#' => self::NUMBER_SIGN, '¡' => self::INVERT_EXCLAMATION, - ); + ]; - /** - * @var bool - */ + const INVALID_CHARS_REGEX = "/[^\p{S}\p{C}\p{Cc}]+/iu"; + + const VALID_UTF8_REGEX = '/\p{Cc}+/u'; + + const CATCHABLE_PATTERNS = [ + '[a-zA-Z]+[46]?', //ASCII and domain literal + '[^\x00-\x7F]', //UTF-8 + '[0-9]+', + '\r\n', + '::', + '\s+?', + '.', + ]; + + const NON_CATCHABLE_PATTERNS = [ + '[\xA0-\xff]+', + ]; + + const MODIFIERS = 'iu'; + + /** @var bool */ protected $hasInvalidTokens = false; /** @@ -133,27 +151,21 @@ class EmailLexer extends AbstractLexer /** * The next token in the input. * - * @var array|null + * @var array{position: int, type: int|null|string, value: int|string}|null */ public $lookahead; - /** - * @psalm-var array{value:'', type:null, position:0} - */ + /** @psalm-var array{value:'', type:null, position:0} */ private static $nullToken = [ 'value' => '', 'type' => null, 'position' => 0, ]; - /** - * @var string - */ + /** @var string */ private $accumulator = ''; - /** - * @var bool - */ + /** @var bool */ private $hasToRecord = false; public function __construct() @@ -162,24 +174,13 @@ class EmailLexer extends AbstractLexer $this->lookahead = null; } - /** - * @return void - */ - public function reset() + public function reset() : void { $this->hasInvalidTokens = false; parent::reset(); $this->previous = $this->token = self::$nullToken; } - /** - * @return bool - */ - public function hasInvalidTokens() - { - return $this->hasInvalidTokens; - } - /** * @param int $type * @throws \UnexpectedValueException @@ -187,7 +188,7 @@ class EmailLexer extends AbstractLexer * * @psalm-suppress InvalidScalarArgument */ - public function find($type) + public function find($type) : bool { $search = clone $this; $search->skipUntil($type); @@ -198,30 +199,24 @@ class EmailLexer extends AbstractLexer return true; } - /** - * getPrevious - * - * @return array - */ - public function getPrevious() - { - return $this->previous; - } - /** * moveNext * * @return boolean */ - public function moveNext() + public function moveNext() : bool { if ($this->hasToRecord && $this->previous === self::$nullToken) { $this->accumulator .= $this->token['value']; } $this->previous = $this->token; + + if($this->lookahead === null) { + $this->lookahead = self::$nullToken; + } + $hasNext = parent::moveNext(); - $this->token = $this->token ?: self::$nullToken; if ($this->hasToRecord) { $this->accumulator .= $this->token['value']; @@ -230,36 +225,6 @@ class EmailLexer extends AbstractLexer return $hasNext; } - /** - * Lexical catchable patterns. - * - * @return string[] - */ - protected function getCatchablePatterns() - { - return array( - '[a-zA-Z]+[46]?', //ASCII and domain literal - '[^\x00-\x7F]', //UTF-8 - '[0-9]+', - '\r\n', - '::', - '\s+?', - '.', - ); - } - - /** - * Lexical non-catchable patterns. - * - * @return string[] - */ - protected function getNonCatchablePatterns() - { - return [ - '[\xA0-\xff]+', - ]; - } - /** * Retrieve token type. Also processes the token value if necessary. * @@ -272,7 +237,7 @@ class EmailLexer extends AbstractLexer $encoded = $value; if (mb_detect_encoding($value, 'auto', true) !== 'UTF-8') { - $encoded = utf8_encode($value); + $encoded = mb_convert_encoding($value, 'UTF-8', 'Windows-1252'); } if ($this->isValid($encoded)) { @@ -292,51 +257,64 @@ class EmailLexer extends AbstractLexer return self::GENERIC; } - protected function isInvalidChar(string $value) : bool - { - if(preg_match("/[^\p{S}\p{C}\p{Cc}]+/iu", $value) ) { - return false; - } - return true; - } - protected function isValid(string $value) : bool { - if (isset($this->charValue[$value])) { - return true; - } - - return false; + return isset($this->charValue[$value]); } - /** - * @param string $value - * @return bool - */ - protected function isNullType($value) + protected function isNullType(string $value) : bool { - if ($value === "\0") { - return true; - } + return $value === "\0"; + } - return false; + protected function isInvalidChar(string $value) : bool + { + return !preg_match(self::INVALID_CHARS_REGEX, $value); } protected function isUTF8Invalid(string $value) : bool { - if (preg_match('/\p{Cc}+/u', $value)) { - return true; - } + return preg_match(self::VALID_UTF8_REGEX, $value) !== false; + } - return false; + public function hasInvalidTokens() : bool + { + return $this->hasInvalidTokens; } /** - * @return string + * getPrevious + * + * @return array */ - protected function getModifiers() + public function getPrevious() : array { - return 'iu'; + return $this->previous; + } + + /** + * Lexical catchable patterns. + * + * @return string[] + */ + protected function getCatchablePatterns() : array + { + return self::CATCHABLE_PATTERNS; + } + + /** + * Lexical non-catchable patterns. + * + * @return string[] + */ + protected function getNonCatchablePatterns() : array + { + return self::NON_CATCHABLE_PATTERNS; + } + + protected function getModifiers() : string + { + return self::MODIFIERS; } public function getAccumulatedValues() : string diff --git a/plugins/email/vendor/egulias/email-validator/src/MessageIDParser.php b/plugins/email/vendor/egulias/email-validator/src/MessageIDParser.php index 9b029e1..fe58b9f 100644 --- a/plugins/email/vendor/egulias/email-validator/src/MessageIDParser.php +++ b/plugins/email/vendor/egulias/email-validator/src/MessageIDParser.php @@ -3,7 +3,6 @@ namespace Egulias\EmailValidator; use Egulias\EmailValidator\Parser; -use Egulias\EmailValidator\EmailLexer; use Egulias\EmailValidator\Result\Result; use Egulias\EmailValidator\Parser\IDLeftPart; use Egulias\EmailValidator\Parser\IDRightPart; diff --git a/plugins/email/vendor/egulias/email-validator/src/Parser/DomainLiteral.php b/plugins/email/vendor/egulias/email-validator/src/Parser/DomainLiteral.php index 54a6fab..4e5b8bf 100644 --- a/plugins/email/vendor/egulias/email-validator/src/Parser/DomainLiteral.php +++ b/plugins/email/vendor/egulias/email-validator/src/Parser/DomainLiteral.php @@ -22,6 +22,15 @@ use Egulias\EmailValidator\Warning\DomainLiteral as WarningDomainLiteral; class DomainLiteral extends PartParser { + const IPV4_REGEX = '/\\b(?:(?: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]?)$/'; + + const OBSOLETE_WARNINGS = [ + EmailLexer::INVALID, + EmailLexer::C_DEL, + EmailLexer::S_LF, + EmailLexer::S_BACKSLASH + ]; + public function parse() : Result { $this->addTagWarnings(); @@ -41,7 +50,7 @@ class DomainLiteral extends PartParser } if ($this->lexer->isNextTokenAny( - array(EmailLexer::S_HTAB, EmailLexer::S_SP, $this->lexer->token['type'] === EmailLexer::CRLF) + array(EmailLexer::S_HTAB, EmailLexer::S_SP, EmailLexer::CRLF) )) { $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); $this->parseFWS(); @@ -138,11 +147,8 @@ class DomainLiteral extends PartParser public function convertIPv4ToIPv6(string $addressLiteralIPv4) : string { - $matchesIP = array(); - $IPv4Match = preg_match( - '/\\b(?:(?: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]?)$/', - $addressLiteralIPv4, - $matchesIP); + $matchesIP = []; + $IPv4Match = preg_match(self::IPV4_REGEX, $addressLiteralIPv4, $matchesIP); // Extract IPv4 part from the end of the address-literal (if there is one) if ($IPv4Match > 0) { @@ -164,11 +170,8 @@ class DomainLiteral extends PartParser */ protected function checkIPV4Tag($addressLiteral) : bool { - $matchesIP = array(); - $IPv4Match = preg_match( - '/\\b(?:(?: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]?)$/', - $addressLiteral, - $matchesIP); + $matchesIP = []; + $IPv4Match = preg_match(self::IPV4_REGEX, $addressLiteral, $matchesIP); // Extract IPv4 part from the end of the address-literal (if there is one) @@ -186,11 +189,7 @@ class DomainLiteral extends PartParser private function addObsoleteWarnings() : void { - if ($this->lexer->token['type'] === EmailLexer::INVALID || - $this->lexer->token['type'] === EmailLexer::C_DEL || - $this->lexer->token['type'] === EmailLexer::S_LF || - $this->lexer->token['type'] === EmailLexer::S_BACKSLASH - ) { + if(in_array($this->lexer->token['type'], self::OBSOLETE_WARNINGS)) { $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT(); } } diff --git a/plugins/email/vendor/egulias/email-validator/src/Parser/DomainPart.php b/plugins/email/vendor/egulias/email-validator/src/Parser/DomainPart.php index 4ca54f2..f171740 100644 --- a/plugins/email/vendor/egulias/email-validator/src/Parser/DomainPart.php +++ b/plugins/email/vendor/egulias/email-validator/src/Parser/DomainPart.php @@ -292,7 +292,7 @@ class DomainPart extends PartParser private function isLabelTooLong(string $label) : bool { if (preg_match('/[^\x00-\x7F]/', $label)) { - idn_to_ascii(utf8_decode($label), IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46, $idnaInfo); + idn_to_ascii($label, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46, $idnaInfo); return (bool) ($idnaInfo['errors'] & IDNA_ERROR_LABEL_TOO_LONG); } return strlen($label) > self::LABEL_MAX_LENGTH; @@ -309,4 +309,4 @@ class DomainPart extends PartParser { return $this->domainPart; } -} \ No newline at end of file +} diff --git a/plugins/email/vendor/egulias/email-validator/src/Parser/DoubleQuote.php b/plugins/email/vendor/egulias/email-validator/src/Parser/DoubleQuote.php index 19c098e..8b83273 100644 --- a/plugins/email/vendor/egulias/email-validator/src/Parser/DoubleQuote.php +++ b/plugins/email/vendor/egulias/email-validator/src/Parser/DoubleQuote.php @@ -19,18 +19,19 @@ class DoubleQuote extends PartParser $validQuotedString = $this->checkDQUOTE(); if($validQuotedString->isInvalid()) return $validQuotedString; - $special = array( + $special = [ EmailLexer::S_CR => true, EmailLexer::S_HTAB => true, EmailLexer::S_LF => true - ); + ]; - $invalid = array( + $invalid = [ EmailLexer::C_NUL => true, EmailLexer::S_HTAB => true, EmailLexer::S_CR => true, EmailLexer::S_LF => true - ); + ]; + $setSpecialsWarning = true; $this->lexer->moveNext(); diff --git a/plugins/email/vendor/egulias/email-validator/src/Parser/FoldingWhiteSpace.php b/plugins/email/vendor/egulias/email-validator/src/Parser/FoldingWhiteSpace.php index d32231e..da17d43 100644 --- a/plugins/email/vendor/egulias/email-validator/src/Parser/FoldingWhiteSpace.php +++ b/plugins/email/vendor/egulias/email-validator/src/Parser/FoldingWhiteSpace.php @@ -15,6 +15,14 @@ use Egulias\EmailValidator\Result\ValidEmail; class FoldingWhiteSpace extends PartParser { + const FWS_TYPES = [ + EmailLexer::S_SP, + EmailLexer::S_HTAB, + EmailLexer::S_CR, + EmailLexer::S_LF, + EmailLexer::CRLF + ]; + public function parse() : Result { if (!$this->isFWS()) { @@ -73,10 +81,6 @@ class FoldingWhiteSpace extends PartParser return false; } - return $this->lexer->token['type'] === EmailLexer::S_SP || - $this->lexer->token['type'] === EmailLexer::S_HTAB || - $this->lexer->token['type'] === EmailLexer::S_CR || - $this->lexer->token['type'] === EmailLexer::S_LF || - $this->lexer->token['type'] === EmailLexer::CRLF; + return in_array($this->lexer->token['type'], self::FWS_TYPES); } } \ No newline at end of file diff --git a/plugins/email/vendor/egulias/email-validator/src/Parser/IDRightPart.php b/plugins/email/vendor/egulias/email-validator/src/Parser/IDRightPart.php index bcf80dd..2432562 100644 --- a/plugins/email/vendor/egulias/email-validator/src/Parser/IDRightPart.php +++ b/plugins/email/vendor/egulias/email-validator/src/Parser/IDRightPart.php @@ -12,14 +12,14 @@ class IDRightPart extends DomainPart { protected function validateTokens(bool $hasComments) : Result { - $invalidDomainTokens = array( + $invalidDomainTokens = [ EmailLexer::S_DQUOTE => true, EmailLexer::S_SQUOTE => true, EmailLexer::S_BACKTICK => true, EmailLexer::S_SEMICOLON => true, EmailLexer::S_GREATERTHAN => true, EmailLexer::S_LOWERTHAN => true, - ); + ]; if (isset($invalidDomainTokens[$this->lexer->token['type']])) { return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . $this->lexer->token['value']), $this->lexer->token['value']); diff --git a/plugins/email/vendor/egulias/email-validator/src/Parser/LocalPart.php b/plugins/email/vendor/egulias/email-validator/src/Parser/LocalPart.php index d505c61..90f01a5 100644 --- a/plugins/email/vendor/egulias/email-validator/src/Parser/LocalPart.php +++ b/plugins/email/vendor/egulias/email-validator/src/Parser/LocalPart.php @@ -15,6 +15,17 @@ use Egulias\EmailValidator\Parser\CommentStrategy\LocalComment; class LocalPart extends PartParser { + const INVALID_TOKENS = [ + EmailLexer::S_COMMA => EmailLexer::S_COMMA, + EmailLexer::S_CLOSEBRACKET => EmailLexer::S_CLOSEBRACKET, + EmailLexer::S_OPENBRACKET => EmailLexer::S_OPENBRACKET, + EmailLexer::S_GREATERTHAN => EmailLexer::S_GREATERTHAN, + EmailLexer::S_LOWERTHAN => EmailLexer::S_LOWERTHAN, + EmailLexer::S_COLON => EmailLexer::S_COLON, + EmailLexer::S_SEMICOLON => EmailLexer::S_SEMICOLON, + EmailLexer::INVALID => EmailLexer::INVALID + ]; + /** * @var string */ @@ -88,17 +99,7 @@ class LocalPart extends PartParser protected function validateTokens(bool $hasComments) : Result { - $invalidTokens = array( - EmailLexer::S_COMMA => EmailLexer::S_COMMA, - EmailLexer::S_CLOSEBRACKET => EmailLexer::S_CLOSEBRACKET, - EmailLexer::S_OPENBRACKET => EmailLexer::S_OPENBRACKET, - EmailLexer::S_GREATERTHAN => EmailLexer::S_GREATERTHAN, - EmailLexer::S_LOWERTHAN => EmailLexer::S_LOWERTHAN, - EmailLexer::S_COLON => EmailLexer::S_COLON, - EmailLexer::S_SEMICOLON => EmailLexer::S_SEMICOLON, - EmailLexer::INVALID => EmailLexer::INVALID - ); - if (isset($invalidTokens[$this->lexer->token['type']])) { + if (isset(self::INVALID_TOKENS[$this->lexer->token['type']])) { return new InvalidEmail(new ExpectingATEXT('Invalid token found'), $this->lexer->token['value']); } return new ValidEmail(); diff --git a/plugins/email/vendor/egulias/email-validator/src/Result/Reason/UnOpenedComment.php b/plugins/email/vendor/egulias/email-validator/src/Result/Reason/UnOpenedComment.php index cc7915c..c76a584 100644 --- a/plugins/email/vendor/egulias/email-validator/src/Result/Reason/UnOpenedComment.php +++ b/plugins/email/vendor/egulias/email-validator/src/Result/Reason/UnOpenedComment.php @@ -11,6 +11,6 @@ class UnOpenedComment implements Reason public function description(): string { - return 'Missing openning comment parentheses - https://tools.ietf.org/html/rfc5322#section-3.2.2'; + return 'Missing opening comment parentheses - https://tools.ietf.org/html/rfc5322#section-3.2.2'; } } \ No newline at end of file diff --git a/plugins/email/vendor/egulias/email-validator/src/Validation/DNSCheckValidation.php b/plugins/email/vendor/egulias/email-validator/src/Validation/DNSCheckValidation.php index a935727..4e0041b 100644 --- a/plugins/email/vendor/egulias/email-validator/src/Validation/DNSCheckValidation.php +++ b/plugins/email/vendor/egulias/email-validator/src/Validation/DNSCheckValidation.php @@ -2,6 +2,7 @@ namespace Egulias\EmailValidator\Validation; +use Egulias\EmailValidator\Validation\DNSGetRecordWrapper; use Egulias\EmailValidator\EmailLexer; use Egulias\EmailValidator\Result\InvalidEmail; use Egulias\EmailValidator\Result\Reason\DomainAcceptsNoMail; @@ -17,6 +18,29 @@ class DNSCheckValidation implements EmailValidation */ protected const DNS_RECORD_TYPES_TO_CHECK = DNS_MX + DNS_A + DNS_AAAA; + /** + * Reserved Top Level DNS Names (https://tools.ietf.org/html/rfc2606#section-2), + * mDNS and private DNS Namespaces (https://tools.ietf.org/html/rfc6762#appendix-G) + */ + const RESERVED_DNS_TOP_LEVEL_NAMES = [ + // Reserved Top Level DNS Names + 'test', + 'example', + 'invalid', + 'localhost', + + // mDNS + 'local', + + // Private DNS Namespaces + 'intranet', + 'internal', + 'private', + 'corp', + 'home', + 'lan', + ]; + /** * @var array */ @@ -32,12 +56,22 @@ class DNSCheckValidation implements EmailValidation */ private $mxRecords = []; + /** + * @var DNSGetRecordWrapper + */ + private $dnsGetRecord; - public function __construct() + public function __construct(DNSGetRecordWrapper $dnsGetRecord = null) { if (!function_exists('idn_to_ascii')) { throw new \LogicException(sprintf('The %s class requires the Intl extension.', __CLASS__)); } + + if ($dnsGetRecord == null) { + $dnsGetRecord = new DNSGetRecordWrapper(); + } + + $this->dnsGetRecord = $dnsGetRecord; } public function isValid(string $email, EmailLexer $emailLexer) : bool @@ -53,29 +87,8 @@ class DNSCheckValidation implements EmailValidation // Get the domain parts $hostParts = explode('.', $host); - // Reserved Top Level DNS Names (https://tools.ietf.org/html/rfc2606#section-2), - // mDNS and private DNS Namespaces (https://tools.ietf.org/html/rfc6762#appendix-G) - $reservedTopLevelDnsNames = [ - // Reserved Top Level DNS Names - 'test', - 'example', - 'invalid', - 'localhost', - - // mDNS - 'local', - - // Private DNS Namespaces - 'intranet', - 'internal', - 'private', - 'corp', - 'home', - 'lan', - ]; - $isLocalDomain = count($hostParts) <= 1; - $isReservedTopLevel = in_array($hostParts[(count($hostParts) - 1)], $reservedTopLevelDnsNames, true); + $isReservedTopLevel = in_array($hostParts[(count($hostParts) - 1)], self::RESERVED_DNS_TOP_LEVEL_NAMES, true); // Exclude reserved top level DNS names if ($isLocalDomain || $isReservedTopLevel) { @@ -120,27 +133,17 @@ class DNSCheckValidation implements EmailValidation */ private function validateDnsRecords($host) : bool { - // A workaround to fix https://bugs.php.net/bug.php?id=73149 - /** @psalm-suppress InvalidArgument */ - set_error_handler( - static function (int $errorLevel, string $errorMessage): ?bool { - throw new \RuntimeException("Unable to get DNS record for the host: $errorMessage"); - } - ); + $dnsRecordsResult = $this->dnsGetRecord->getRecords($host, static::DNS_RECORD_TYPES_TO_CHECK); - try { - // Get all MX, A and AAAA DNS records for host - $dnsRecords = dns_get_record($host, static::DNS_RECORD_TYPES_TO_CHECK); - } catch (\RuntimeException $exception) { + if ($dnsRecordsResult->withError()) { $this->error = new InvalidEmail(new UnableToGetDNSRecord(), ''); - return false; - } finally { - restore_error_handler(); } + $dnsRecords = $dnsRecordsResult->getRecords(); + // No MX, A or AAAA DNS records - if ($dnsRecords === [] || $dnsRecords === false) { + if ($dnsRecords === []) { $this->error = new InvalidEmail(new ReasonNoDNSRecord(), ''); return false; } @@ -167,6 +170,11 @@ class DNSCheckValidation implements EmailValidation */ private function validateMxRecord($dnsRecord) : bool { + if (!isset($dnsRecord['type'])) { + $this->error = new InvalidEmail(new ReasonNoDNSRecord(), ''); + return false; + } + if ($dnsRecord['type'] !== 'MX') { return true; } diff --git a/plugins/email/vendor/egulias/email-validator/src/Validation/DNSGetRecordWrapper.php b/plugins/email/vendor/egulias/email-validator/src/Validation/DNSGetRecordWrapper.php new file mode 100644 index 0000000..ec6fe4b --- /dev/null +++ b/plugins/email/vendor/egulias/email-validator/src/Validation/DNSGetRecordWrapper.php @@ -0,0 +1,28 @@ +records = $records; + $this->error = $error; + } + + public function getRecords() : array + { + return $this->records; + } + + public function withError() : bool + { + return $this->error; + } + + +} \ No newline at end of file diff --git a/plugins/email/vendor/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php b/plugins/email/vendor/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php index 6debf22..90d4f0d 100644 --- a/plugins/email/vendor/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php +++ b/plugins/email/vendor/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php @@ -10,7 +10,7 @@ use Egulias\EmailValidator\Result\MultipleErrors; class MultipleValidationWithAnd implements EmailValidation { /** - * If one of validations fails, the remaining validations will be skept. + * If one of validations fails, the remaining validations will be skipped. * This means MultipleErrors will only contain a single error, the first found. */ const STOP_ON_ERROR = 0; diff --git a/plugins/email/vendor/egulias/email-validator/src/Warning/Warning.php b/plugins/email/vendor/egulias/email-validator/src/Warning/Warning.php index bce7e7a..a0158a2 100644 --- a/plugins/email/vendor/egulias/email-validator/src/Warning/Warning.php +++ b/plugins/email/vendor/egulias/email-validator/src/Warning/Warning.php @@ -42,6 +42,6 @@ abstract class Warning public function __toString() { - return $this->message() . " rfc: " . $this->rfcNumber . "interal code: " . static::CODE; + return $this->message() . " rfc: " . $this->rfcNumber . "internal code: " . static::CODE; } } diff --git a/plugins/email/vendor/psr/container/.gitignore b/plugins/email/vendor/psr/container/.gitignore new file mode 100644 index 0000000..b2395aa --- /dev/null +++ b/plugins/email/vendor/psr/container/.gitignore @@ -0,0 +1,3 @@ +composer.lock +composer.phar +/vendor/ diff --git a/plugins/email/vendor/psr/container/LICENSE b/plugins/email/vendor/psr/container/LICENSE new file mode 100644 index 0000000..2877a48 --- /dev/null +++ b/plugins/email/vendor/psr/container/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2016 container-interop +Copyright (c) 2016 PHP Framework Interoperability Group + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/email/vendor/psr/container/README.md b/plugins/email/vendor/psr/container/README.md new file mode 100644 index 0000000..1b9d9e5 --- /dev/null +++ b/plugins/email/vendor/psr/container/README.md @@ -0,0 +1,13 @@ +Container interface +============== + +This repository holds all interfaces related to [PSR-11 (Container Interface)][psr-url]. + +Note that this is not a Container implementation of its own. It is merely abstractions that describe the components of a Dependency Injection Container. + +The installable [package][package-url] and [implementations][implementation-url] are listed on Packagist. + +[psr-url]: https://www.php-fig.org/psr/psr-11/ +[package-url]: https://packagist.org/packages/psr/container +[implementation-url]: https://packagist.org/providers/psr/container-implementation + diff --git a/plugins/email/vendor/psr/container/composer.json b/plugins/email/vendor/psr/container/composer.json new file mode 100644 index 0000000..3797a25 --- /dev/null +++ b/plugins/email/vendor/psr/container/composer.json @@ -0,0 +1,22 @@ +{ + "name": "psr/container", + "type": "library", + "description": "Common Container Interface (PHP FIG PSR-11)", + "keywords": ["psr", "psr-11", "container", "container-interop", "container-interface"], + "homepage": "https://github.com/php-fig/container", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=7.2.0" + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + } +} diff --git a/plugins/email/vendor/psr/container/src/ContainerExceptionInterface.php b/plugins/email/vendor/psr/container/src/ContainerExceptionInterface.php new file mode 100644 index 0000000..cf10b8b --- /dev/null +++ b/plugins/email/vendor/psr/container/src/ContainerExceptionInterface.php @@ -0,0 +1,10 @@ +=7.2.0" + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/plugins/email/vendor/psr/event-dispatcher/src/EventDispatcherInterface.php b/plugins/email/vendor/psr/event-dispatcher/src/EventDispatcherInterface.php new file mode 100644 index 0000000..4306fa9 --- /dev/null +++ b/plugins/email/vendor/psr/event-dispatcher/src/EventDispatcherInterface.php @@ -0,0 +1,21 @@ + - -| Q | A -| ------------------- | ----- -| Bug report? | yes/no -| Feature request? | yes/no -| RFC? | yes/no -| How used? | Standalone/Symfony/3party -| Swiftmailer version | x.y.z -| PHP version | x.y.z - -### Observed behaviour - - -### Expected behaviour - - -### Example - diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/.github/PULL_REQUEST_TEMPLATE.md b/plugins/email/vendor/swiftmailer/swiftmailer/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 4b39510..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,14 +0,0 @@ - - -| Q | A -| ------------- | --- -| Bug fix? | yes/no -| New feature? | yes/no -| Doc update? | yes/no -| BC breaks? | yes/no -| Deprecations? | yes/no -| Fixed tickets | #... -| License | MIT - - - diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/.github/workflows/tests.yml b/plugins/email/vendor/swiftmailer/swiftmailer/.github/workflows/tests.yml deleted file mode 100644 index dc83ec6..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/.github/workflows/tests.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: tests - -on: - push: - pull_request: - -jobs: - linux_tests: - runs-on: ubuntu-20.04 - - services: - mailcatcher: - image: dockage/mailcatcher:0.7.1 - ports: - - 4456:1025 - - strategy: - fail-fast: true - matrix: - php: ['7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] - - name: PHP ${{ matrix.php }} - - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - extensions: dom, curl, libxml, mbstring, zip, intl - tools: composer:v2 - coverage: none - - - name: Prepare test config files - run: | - cp tests/acceptance.conf.php.default tests/acceptance.conf.php - cp tests/smoke.conf.php.default tests/smoke.conf.php - - - name: Require Symfony PHPUnit Bridge 5.4 for PHP 8.1 - if: ${{ matrix.php >= 8.1 }} - run: composer require symfony/phpunit-bridge:^5.4 --dev --prefer-dist --no-interaction --no-progress - - - name: Install dependencies - uses: nick-invision/retry@v1 - with: - timeout_minutes: 5 - max_attempts: 5 - command: composer update --prefer-stable --prefer-dist --no-interaction --no-progress - - - name: Execute tests - run: vendor/bin/simple-phpunit --verbose - env: - SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT: 1 diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/.gitignore b/plugins/email/vendor/swiftmailer/swiftmailer/.gitignore deleted file mode 100644 index a911ddf..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -/.php_cs.cache -/.phpunit -/.phpunit.result.cache -/build/* -/composer.lock -/phpunit.xml -/tests/acceptance.conf.php -/tests/smoke.conf.php -/vendor/ diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/.php_cs.dist b/plugins/email/vendor/swiftmailer/swiftmailer/.php_cs.dist deleted file mode 100644 index 563b48b..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/.php_cs.dist +++ /dev/null @@ -1,21 +0,0 @@ -setRules([ - '@Symfony' => true, - '@Symfony:risky' => true, - '@PHPUnit75Migration:risky' => true, - 'php_unit_dedicate_assert' => ['target' => '5.6'], - 'array_syntax' => ['syntax' => 'short'], - 'php_unit_fqcn_annotation' => true, - 'no_unreachable_default_argument_value' => false, - 'braces' => ['allow_single_line_closure' => true], - 'heredoc_to_nowdoc' => false, - 'ordered_imports' => true, - 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], - 'native_function_invocation' => ['include' => ['@compiler_optimized'], 'scope' => 'all'], - 'fopen_flags' => false, - ]) - ->setRiskyAllowed(true) - ->setFinder(PhpCsFixer\Finder::create()->in(__DIR__)) -; diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/CHANGES b/plugins/email/vendor/swiftmailer/swiftmailer/CHANGES deleted file mode 100644 index a7ffa00..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/CHANGES +++ /dev/null @@ -1,391 +0,0 @@ -Changelog -========= - -**Swiftmailer will stop being maintained at the end of November 2021.** - -Please, move to Symfony Mailer at your earliest convenience. -Symfony Mailer is the next evolution of Swiftmailer. -It provides the same features with support for modern PHP code and support for third-party providers. -See https://symfony.com/doc/current/mailer.html for more information. - -6.3.0 (2021-10-18) ------------------- - - * Fix support for PHP 8.1 - -6.2.7 (2021-03-09) ------------------- - - * Allow egulias/email-validator 3.1+ - -6.2.6 (2021-03-05) ------------------- - - * Fix Bcc support - -6.2.5 (2021-01-12) ------------------- - - * Don't trust properties at destruct time - * Remove invalid PHPDocs param in EventDispatcher interface - * Bump license year - * Removes PHP version from README - -6.2.4 (2020-12-08) ------------------- - - * Prevent flushing of the bubble queue when event handler raises another event - * Add support for PHP 8 - * Code cleanups - -6.2.3 (2019-11-12) ------------------- - - * no changes - -6.2.2 (2019-11-12) ------------------- - - * fixed compat with PHP 7.4 - * fixed error message when connecting to a stream raises an error before connect() - -6.2.1 (2019-04-21) ------------------- - - * reverted "deprecated Swift_CharacterStream_ArrayCharacterStream and Swift_CharacterStream_NgCharacterStream in favor of Swift_CharacterStream_CharacterStream" - -6.2.0 (2019-03-10) ------------------- - - * added support for symfony/polyfill-intl-dn - * deprecated Swift_CharacterStream_ArrayCharacterStream and Swift_CharacterStream_NgCharacterStream in favor of Swift_CharacterStream_CharacterStream - -6.1.3 (2018-09-11) ------------------- - - * added auto-start to the SMTP transport when sending a message - * tweaked error message when the response from an SMTP server is empty - * fixed missing property in Swift_Mime_IdGenerator - * exposed original body content type with Swift_Mime_SimpleMimeEntity::getBodyContentType() - * fixed typo in variable name in Swift_AddressEncoder_IdnAddressEncoder - * fixed return type in MessageLogger - * fixed missing property addressEncoder in SimpleHeaderFactory class - -6.1.2 (2018-07-13) ------------------- - - * handled recipient errors when pipelining - -6.1.1 (2018-07-04) ------------------- - - * removed hard dependency on an IDN encoder - -6.1.0 (2018-07-02) ------------------- - - * added address encoder exceptions during send - * added support for bubbling up authenticator error messages - * added support for non-ASCII email addresses - * introduced new dependencies: transport.smtphandlers and transport.authhandlers - * deprecated Swift_Signers_OpenDKIMSigner; use Swift_Signers_DKIMSigner instead - * added support for SMTP pipelining - * added Swift_Transport_Esmtp_EightBitMimeHandler - * fixed startTLS only allowed tls1.0, now allowed: tls1.0, tls1.1, tls1.2 - -6.0.2 (2017-09-30) ------------------- - - * fixed DecoratorPlugin - * removed usage of getmypid() - -6.0.1 (2017-05-20) ------------------- - - * fixed BC break that can be avoided easily - -6.0.0 (2017-05-19) ------------------- - - * added Swift_Transport::ping() - * removed Swift_Mime_HeaderFactory, Swift_Mime_HeaderSet, Swift_Mime_Message, Swift_Mime_MimeEntity, - and Swift_Mime_ParameterizedHeader interfaces - * removed Swift_MailTransport and Swift_Transport_MailTransport - * removed Swift_Encoding - * removed the Swift_Transport_MailInvoker interface and Swift_Transport_SimpleMailInvoker class - * removed the Swift_SignedMessage class - * removed newInstance() methods everywhere - * methods operating on Date header now use DateTimeImmutable object instead of Unix timestamp; - Swift_Mime_Headers_DateHeader::getTimestamp()/setTimestamp() renamed to getDateTime()/setDateTime() - * bumped minimum version to PHP 7.0 - * removed Swift_Validate and replaced by egulias/email-validator - -5.4.9 (2018-01-23) ------------------- - - * no changes, last version of the 5.x series - -5.4.8 (2017-05-01) ------------------- - - * fixed encoding inheritance in addPart() - * fixed sorting MIME children when their types are equal - -5.4.7 (2017-04-20) ------------------- - - * fixed NTLMAuthenticator clobbering bcmath scale - -5.4.6 (2017-02-13) ------------------- - - * removed exceptions thrown in destructors as they lead to fatal errors - * switched to use sha256 by default in DKIM as per the RFC - * fixed an 'Undefined variable: pipes' PHP notice - * fixed long To headers when using the mail transport - * fixed NTLMAuthenticator when no domain is passed with the username - * prevented fatal error during unserialization of a message - * fixed a PHP warning when sending a message that has a length of a multiple of 8192 - -5.4.5 (2016-12-29) ------------------- - - * SECURITY FIX: fixed CVE-2016-10074 by disallowing potentially unsafe shell characters - - Prior to 5.4.5, the mail transport (Swift_Transport_MailTransport) was vulnerable to passing - arbitrary shell arguments if the "From", "ReturnPath" or "Sender" header came - from a non-trusted source, potentially allowing Remote Code Execution - * deprecated the mail transport - -5.4.4 (2016-11-23) ------------------- - - * reverted escaping command-line args to mail (PHP mail() function already does it) - -5.4.3 (2016-07-08) ------------------- - - * fixed SimpleHeaderSet::has()/get() when the 0 index is removed - * removed the need to have mcrypt installed - * fixed broken MIME header encoding with quotes/colons and non-ascii chars - * allowed mail transport send for messages without To header - * fixed PHP 7 support - -5.4.2 (2016-05-01) ------------------- - - * fixed support for IPv6 sockets - * added auto-retry when sending messages from the memory spool - * fixed consecutive read calls in Swift_ByteStream_FileByteStream - * added support for iso-8859-15 encoding - * fixed PHP mail extra params on missing reversePath - * added methods to set custom stream context options - * fixed charset changes in QpContentEncoderProxy - * added return-path header to the ignoredHeaders list of DKIMSigner - * fixed crlf for subject using mail - * fixed add soft line break only when necessary - * fixed escaping command-line args to mail - -5.4.1 (2015-06-06) ------------------- - - * made Swiftmailer exceptions confirm to PHP base exception constructor signature - * fixed MAIL FROM & RCPT TO headers to be RFC compliant - -5.4.0 (2015-03-14) ------------------- - - * added the possibility to add extra certs to PKCS#7 signature - * fix base64 encoding with streams - * added a new RESULT_SPOOLED status for SpoolTransport - * fixed getBody() on attachments when called more than once - * removed dots from generated filenames in filespool - -5.3.1 (2014-12-05) ------------------- - - * fixed cloning of messages with attachments - -5.3.0 (2014-10-04) ------------------- - - * fixed cloning when using signers - * reverted removal of Swift_Encoding - * drop support for PHP 5.2.x - -5.2.2 (2014-09-20) ------------------- - - * fixed Japanese support - * fixed the memory spool when the message changes when in the pool - * added support for cloning messages - * fixed PHP warning in the redirect plugin - * changed the way to and cc-ed email are sent to only use one transaction - -5.2.1 (2014-06-13) ------------------- - - * SECURITY FIX: fixed CLI escaping when using sendmail as a transport - - Prior to 5.2.1, the sendmail transport (Swift_Transport_SendmailTransport) - was vulnerable to an arbitrary shell execution if the "From" header came - from a non-trusted source and no "Return-Path" is configured. - - * fixed parameter in DKIMSigner - * fixed compatibility with PHP < 5.4 - -5.2.0 (2014-05-08) ------------------- - - * fixed Swift_ByteStream_FileByteStream::read() to match to the specification - * fixed from-charset and to-charset arguments in mbstring_convert_encoding() usages - * fixed infinite loop in StreamBuffer - * fixed NullTransport to return the number of ignored emails instead of 0 - * Use phpunit and mockery for unit testing (realityking) - -5.1.0 (2014-03-18) ------------------- - - * fixed data writing to stream when sending large messages - * added support for libopendkim (https://github.com/xdecock/php-opendkim) - * merged SignedMessage and Message - * added Gmail XOAuth2 authentication - * updated the list of known mime types - * added NTLM authentication - -5.0.3 (2013-12-03) ------------------- - - * fixed double-dot bug - * fixed DKIM signer - -5.0.2 (2013-08-30) ------------------- - - * handled correct exception type while reading IoBuffer output - -5.0.1 (2013-06-17) ------------------- - - * changed the spool to only start the transport when a mail has to be sent - * fixed compatibility with PHP 5.2 - * fixed LICENSE file - -5.0.0 (2013-04-30) ------------------- - - * changed the license from LGPL to MIT - -4.3.1 (2013-04-11) ------------------- - - * removed usage of the native QP encoder when the charset is not UTF-8 - * fixed usage of uniqid to avoid collisions - * made a performance improvement when tokenizing large headers - * fixed usage of the PHP native QP encoder on PHP 5.4.7+ - -4.3.0 (2013-01-08) ------------------- - - * made the temporary directory configurable via the TMPDIR env variable - * added S/MIME signer and encryption support - -4.2.2 (2012-10-25) ------------------- - - * added the possibility to throttle messages per second in ThrottlerPlugin (mostly for Amazon SES) - * switched mime.qpcontentencoder to automatically use the PHP native encoder on PHP 5.4.7+ - * allowed specifying a whitelist with regular expressions in RedirectingPlugin - -4.2.1 (2012-07-13) ------------------- - - * changed the coding standards to PSR-1/2 - * fixed issue with autoloading - * added NativeQpContentEncoder to enhance performance (for PHP 5.3+) - -4.2.0 (2012-06-29) ------------------- - - * added documentation about how to use the Japanese support introduced in 4.1.8 - * added a way to override the default configuration in a lazy way - * changed the PEAR init script to lazy-load the initialization - * fixed a bug when calling Swift_Preferences before anything else (regression introduced in 4.1.8) - -4.1.8 (2012-06-17) ------------------- - - * added Japanese iso-2022-jp support - * changed the init script to lazy-load the initialization - * fixed docblocks (@id) which caused some problems with libraries parsing the dobclocks - * fixed Swift_Mime_Headers_IdentificationHeader::setId() when passed an array of ids - * fixed encoding of email addresses in headers - * added replacements setter to the Decorator plugin - -4.1.7 (2012-04-26) ------------------- - - * fixed QpEncoder safeMapShareId property - -4.1.6 (2012-03-23) ------------------- - - * reduced the size of serialized Messages - -4.1.5 (2012-01-04) ------------------- - - * enforced Swift_Spool::queueMessage() to return a Boolean - * made an optimization to the memory spool: start the transport only when required - * prevented stream_socket_client() from generating an error and throw a Swift_TransportException instead - * fixed a PHP warning when calling to mail() when safe_mode is off - * many doc tweaks - -4.1.4 (2011-12-16) ------------------- - - * added a memory spool (Swift_MemorySpool) - * fixed too many opened files when sending emails with attachments - -4.1.3 (2011-10-27) ------------------- - - * added STARTTLS support - * added missing @return tags on fluent methods - * added a MessageLogger plugin that logs all sent messages - * added composer.json - -4.1.2 (2011-09-13) ------------------- - - * fixed wrong detection of magic_quotes_runtime - * fixed fatal errors when no To or Subject header has been set - * fixed charset on parameter header continuations - * added documentation about how to install Swiftmailer from the PEAR channel - * fixed various typos and markup problem in the documentation - * fixed warning when cache directory does not exist - * fixed "slashes are escaped" bug - * changed require_once() to require() in autoload - -4.1.1 (2011-07-04) ------------------- - - * added missing file in PEAR package - -4.1.0 (2011-06-30) ------------------- - - * documentation has been converted to ReST - -4.1.0 RC1 (2011-06-17) ----------------------- - -New features: - - * changed the Decorator Plugin to allow replacements in all headers - * added Swift_Mime_Grammar and Swift_Validate to validate an email address - * modified the autoloader to lazy-initialize Swiftmailer - * removed Swift_Mailer::batchSend() - * added NullTransport - * added new plugins: RedirectingPlugin and ImpersonatePlugin - * added a way to send messages asynchronously (Spool) diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/README.md b/plugins/email/vendor/swiftmailer/swiftmailer/README.md deleted file mode 100644 index 788d722..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/README.md +++ /dev/null @@ -1,25 +0,0 @@ -Swift Mailer ------------- - -**Swiftmailer will stop being maintained at the end of November 2021.** - -Please, move to [Symfony Mailer](https://symfony.com/doc/current/mailer.html) at your earliest convenience. -[Symfony Mailer](https://symfony.com/doc/current/mailer.html) is the next evolution of Swiftmailer. -It provides the same features with support for modern PHP code and support for third-party providers. - -Swift Mailer is a component based mailing solution for PHP. -It is released under the MIT license. - -Swift Mailer is highly object-oriented by design and lends itself -to use in complex web application with a great deal of flexibility. - -For full details on usage, read the [documentation](https://swiftmailer.symfony.com/docs/introduction.html). - -Sponsors --------- - - diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/composer.json b/plugins/email/vendor/swiftmailer/swiftmailer/composer.json deleted file mode 100644 index 546b3a1..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/composer.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "swiftmailer/swiftmailer", - "type": "library", - "description": "Swiftmailer, free feature-rich PHP mailer", - "keywords": ["mail","mailer","email"], - "homepage": "https://swiftmailer.symfony.com", - "license": "MIT", - "authors": [ - { - "name": "Chris Corbyn" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "require": { - "php": ">=7.0.0", - "egulias/email-validator": "^2.0|^3.1", - "symfony/polyfill-iconv": "^1.0", - "symfony/polyfill-mbstring": "^1.0", - "symfony/polyfill-intl-idn": "^1.10" - }, - "require-dev": { - "mockery/mockery": "^1.0", - "symfony/phpunit-bridge": "^4.4|^5.4" - }, - "suggest": { - "ext-intl": "Needed to support internationalized email addresses" - }, - "autoload": { - "files": ["lib/swift_required.php"] - }, - "autoload-dev": { - "psr-0": { "Swift_": "tests/unit" } - }, - "extra": { - "branch-alias": { - "dev-master": "6.2-dev" - } - }, - "minimum-stability": "dev", - "prefer-stable": true -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/doc/headers.rst b/plugins/email/vendor/swiftmailer/swiftmailer/doc/headers.rst deleted file mode 100644 index 8b8bece..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/doc/headers.rst +++ /dev/null @@ -1,621 +0,0 @@ -Message Headers -=============== - -Sometimes you'll want to add your own headers to a message or modify/remove -headers that are already present. You work with the message's HeaderSet to do -this. - -Header Basics -------------- - -All MIME entities in Swift Mailer -- including the message itself -- store -their headers in a single object called a HeaderSet. This HeaderSet is -retrieved with the ``getHeaders()`` method. - -As mentioned in the previous chapter, everything that forms a part of a message -in Swift Mailer is a MIME entity that is represented by an instance of -``Swift_Mime_SimpleMimeEntity``. This includes -- most notably -- the message -object itself, attachments, MIME parts and embedded images. Each of these MIME -entities consists of a body and a set of headers that describe the body. - -For all of the "standard" headers in these MIME entities, such as the -``Content-Type``, there are named methods for working with them, such as -``setContentType()`` and ``getContentType()``. This is because headers are a -moderately complex area of the library. Each header has a slightly different -required structure that it must meet in order to comply with the standards that -govern email (and that are checked by spam blockers etc). - -You fetch the HeaderSet from a MIME entity like so:: - - $message = new Swift_Message(); - - // Fetch the HeaderSet from a Message object - $headers = $message->getHeaders(); - - $attachment = Swift_Attachment::fromPath('document.pdf'); - - // Fetch the HeaderSet from an attachment object - $headers = $attachment->getHeaders(); - -The job of the HeaderSet is to contain and manage instances of Header objects. -Depending upon the MIME entity the HeaderSet came from, the contents of the -HeaderSet will be different, since an attachment for example has a different -set of headers to those in a message. - -You can find out what the HeaderSet contains with a quick loop, dumping out the -names of the headers:: - - foreach ($headers->getAll() as $header) { - printf("%s
\n", $header->getFieldName()); - } - - /* - Content-Transfer-Encoding - Content-Type - MIME-Version - Date - Message-ID - From - Subject - To - */ - -You can also dump out the rendered HeaderSet by calling its ``toString()`` -method:: - - echo $headers->toString(); - - /* - Message-ID: <1234869991.499a9ee7f1d5e@swift.generated> - Date: Tue, 17 Feb 2009 22:26:31 +1100 - Subject: Awesome subject! - From: sender@example.org - To: recipient@example.org - MIME-Version: 1.0 - Content-Type: text/plain; charset=utf-8 - Content-Transfer-Encoding: quoted-printable - */ - -Where the complexity comes in is when you want to modify an existing header. -This complexity comes from the fact that each header can be of a slightly -different type (such as a Date header, or a header that contains email -addresses, or a header that has key-value parameters on it!). Each header in -the HeaderSet is an instance of ``Swift_Mime_Header``. They all have common -functionality, but knowing exactly what type of header you're working with will -allow you a little more control. - -You can determine the type of header by comparing the return value of its -``getFieldType()`` method with the constants ``TYPE_TEXT``, -``TYPE_PARAMETERIZED``, ``TYPE_DATE``, ``TYPE_MAILBOX``, ``TYPE_ID`` and -``TYPE_PATH`` which are defined in ``Swift_Mime_Header``:: - - foreach ($headers->getAll() as $header) { - switch ($header->getFieldType()) { - case Swift_Mime_Header::TYPE_TEXT: $type = 'text'; - break; - case Swift_Mime_Header::TYPE_PARAMETERIZED: $type = 'parameterized'; - break; - case Swift_Mime_Header::TYPE_MAILBOX: $type = 'mailbox'; - break; - case Swift_Mime_Header::TYPE_DATE: $type = 'date'; - break; - case Swift_Mime_Header::TYPE_ID: $type = 'ID'; - break; - case Swift_Mime_Header::TYPE_PATH: $type = 'path'; - break; - } - printf("%s: is a %s header
\n", $header->getFieldName(), $type); - } - - /* - Content-Transfer-Encoding: is a text header - Content-Type: is a parameterized header - MIME-Version: is a text header - Date: is a date header - Message-ID: is a ID header - From: is a mailbox header - Subject: is a text header - To: is a mailbox header - */ - -Headers can be removed from the set, modified within the set, or added to the -set. - -The following sections show you how to work with the HeaderSet and explain the -details of each implementation of ``Swift_Mime_Header`` that may exist within -the HeaderSet. - -Header Types ------------- - -Because all headers are modeled on different data (dates, addresses, text!) -there are different types of Header in Swift Mailer. Swift Mailer attempts to -categorize all possible MIME headers into more general groups, defined by a -small number of classes. - -Text Headers -~~~~~~~~~~~~ - -Text headers are the simplest type of Header. They contain textual information -with no special information included within it -- for example the Subject -header in a message. - -There's nothing particularly interesting about a text header, though it is -probably the one you'd opt to use if you need to add a custom header to a -message. It represents text just like you'd think it does. If the text contains -characters that are not permitted in a message header (such as new lines, or -non-ascii characters) then the header takes care of encoding the text so that -it can be used. - -No header -- including text headers -- in Swift Mailer is vulnerable to -header-injection attacks. Swift Mailer breaks any attempt at header injection -by encoding the dangerous data into a non-dangerous form. - -It's easy to add a new text header to a HeaderSet. You do this by calling the -HeaderSet's ``addTextHeader()`` method:: - - $message = new Swift_Message(); - $headers = $message->getHeaders(); - $headers->addTextHeader('Your-Header-Name', 'the header value'); - -Changing the value of an existing text header is done by calling it's -``setValue()`` method:: - - $subject = $message->getHeaders()->get('Subject'); - $subject->setValue('new subject'); - -When output via ``toString()``, a text header produces something like the -following:: - - $subject = $message->getHeaders()->get('Subject'); - $subject->setValue('amazing subject line'); - echo $subject->toString(); - - /* - - Subject: amazing subject line - - */ - -If the header contains any characters that are outside of the US-ASCII range -however, they will be encoded. This is nothing to be concerned about since mail -clients will decode them back:: - - $subject = $message->getHeaders()->get('Subject'); - $subject->setValue('contains – dash'); - echo $subject->toString(); - - /* - - Subject: contains =?utf-8?Q?=E2=80=93?= dash - - */ - -Parameterized Headers -~~~~~~~~~~~~~~~~~~~~~ - -Parameterized headers are text headers that contain key-value parameters -following the textual content. The Content-Type header of a message is a -parameterized header since it contains charset information after the content -type. - -The parameterized header type is a special type of text header. It extends the -text header by allowing additional information to follow it. All of the methods -from text headers are available in addition to the methods described here. - -Adding a parameterized header to a HeaderSet is done by using the -``addParameterizedHeader()`` method which takes a text value like -``addTextHeader()`` but it also accepts an associative array of key-value -parameters:: - - $message = new Swift_Message(); - $headers = $message->getHeaders(); - $headers->addParameterizedHeader( - 'Header-Name', 'header value', - ['foo' => 'bar'] - ); - -To change the text value of the header, call it's ``setValue()`` method just as -you do with text headers. - -To change the parameters in the header, call the header's ``setParameters()`` -method or the ``setParameter()`` method (note the pluralization):: - - $type = $message->getHeaders()->get('Content-Type'); - - // setParameters() takes an associative array - $type->setParameters([ - 'name' => 'file.txt', - 'charset' => 'iso-8859-1' - ]); - - // setParameter() takes two args for $key and $value - $type->setParameter('charset', 'iso-8859-1'); - -When output via ``toString()``, a parameterized header produces something like -the following:: - - $type = $message->getHeaders()->get('Content-Type'); - $type->setValue('text/html'); - $type->setParameter('charset', 'utf-8'); - - echo $type->toString(); - - /* - - Content-Type: text/html; charset=utf-8 - - */ - -If the header contains any characters that are outside of the US-ASCII range -however, they will be encoded, just like they are for text headers. This is -nothing to be concerned about since mail clients will decode them back. -Likewise, if the parameters contain any non-ascii characters they will be -encoded so that they can be transmitted safely:: - - $attachment = new Swift_Attachment(); - $disp = $attachment->getHeaders()->get('Content-Disposition'); - $disp->setValue('attachment'); - $disp->setParameter('filename', 'report–may.pdf'); - echo $disp->toString(); - - /* - - Content-Disposition: attachment; filename*=utf-8''report%E2%80%93may.pdf - - */ - -Date Headers -~~~~~~~~~~~~ - -Date headers contains an RFC 2822 formatted date (i.e. what PHP's ``date('r')`` -returns). They are used anywhere a date or time is needed to be presented as a -message header. - -The data on which a date header is modeled as a DateTimeImmutable object. The -object is used to create a correctly structured RFC 2822 formatted date with -timezone such as ``Tue, 17 Feb 2009 22:26:31 +1100``. - -The obvious place this header type is used is in the ``Date:`` header of the -message itself. - -It's easy to add a new date header to a HeaderSet. You do this by calling the -HeaderSet's ``addDateHeader()`` method:: - - $message = new Swift_Message(); - $headers = $message->getHeaders(); - $headers->addDateHeader('Your-Header', new DateTimeImmutable('3 days ago')); - -Changing the value of an existing date header is done by calling it's -``setDateTime()`` method:: - - $date = $message->getHeaders()->get('Date'); - $date->setDateTime(new DateTimeImmutable()); - -When output via ``toString()``, a date header produces something like the -following:: - - $date = $message->getHeaders()->get('Date'); - echo $date->toString(); - - /* - - Date: Wed, 18 Feb 2009 13:35:02 +1100 - - */ - -Mailbox (e-mail address) Headers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Mailbox headers contain one or more email addresses, possibly with personalized -names attached to them. The data on which they are modeled is represented by an -associative array of email addresses and names. - -Mailbox headers are probably the most complex header type to understand in -Swift Mailer because they accept their input as an array which can take various -forms, as described in the previous chapter. - -All of the headers that contain e-mail addresses in a message -- with the -exception of ``Return-Path:`` which has a stricter syntax -- use this header -type. That is, ``To:``, ``From:`` etc. - -You add a new mailbox header to a HeaderSet by calling the HeaderSet's -``addMailboxHeader()`` method:: - - $message = new Swift_Message(); - $headers = $message->getHeaders(); - $headers->addMailboxHeader('Your-Header-Name', [ - 'person1@example.org' => 'Person Name One', - 'person2@example.org', - 'person3@example.org', - 'person4@example.org' => 'Another named person' - ]); - -Changing the value of an existing mailbox header is done by calling it's -``setNameAddresses()`` method:: - - $to = $message->getHeaders()->get('To'); - $to->setNameAddresses([ - 'joe@example.org' => 'Joe Bloggs', - 'john@example.org' => 'John Doe', - 'no-name@example.org' - ]); - -If you don't wish to concern yourself with the complicated accepted input -formats accepted by ``setNameAddresses()`` as described in the previous chapter -and you only want to set one or more addresses (not names) then you can just -use the ``setAddresses()`` method instead:: - - $to = $message->getHeaders()->get('To'); - $to->setAddresses([ - 'joe@example.org', - 'john@example.org', - 'no-name@example.org' - ]); - -.. note:: - - Both methods will accept the above input format in practice. - -If all you want to do is set a single address in the header, you can use a -string as the input parameter to ``setAddresses()`` and/or -``setNameAddresses()``:: - - $to = $message->getHeaders()->get('To'); - $to->setAddresses('joe-bloggs@example.org'); - -When output via ``toString()``, a mailbox header produces something like the -following:: - - $to = $message->getHeaders()->get('To'); - $to->setNameAddresses([ - 'person1@example.org' => 'Name of Person', - 'person2@example.org', - 'person3@example.org' => 'Another Person' - ]); - - echo $to->toString(); - - /* - - To: Name of Person , person2@example.org, Another Person - - - */ - -Internationalized domains are automatically converted to IDN encoding:: - - $to = $message->getHeaders()->get('To'); - $to->setAddresses('joe@ëxämple.org'); - - echo $to->toString(); - - /* - - To: joe@xn--xmple-gra1c.org - - */ - -ID Headers -~~~~~~~~~~ - -ID headers contain identifiers for the entity (or the message). The most -notable ID header is the Message-ID header on the message itself. - -An ID that exists inside an ID header looks more-or-less less like an email -address. For example, ``<1234955437.499becad62ec2@example.org>``. The part to -the left of the @ sign is usually unique, based on the current time and some -random factor. The part on the right is usually a domain name. - -Any ID passed to the header's ``setId()`` method absolutely MUST conform to -this structure, otherwise you'll get an Exception thrown at you by Swift Mailer -(a ``Swift_RfcComplianceException``). This is to ensure that the generated -email complies with relevant RFC documents and therefore is less likely to be -blocked as spam. - -It's easy to add a new ID header to a HeaderSet. You do this by calling the -HeaderSet's ``addIdHeader()`` method:: - - $message = new Swift_Message(); - $headers = $message->getHeaders(); - $headers->addIdHeader('Your-Header-Name', '123456.unqiue@example.org'); - -Changing the value of an existing ID header is done by calling its ``setId()`` -method:: - - $msgId = $message->getHeaders()->get('Message-ID'); - $msgId->setId(time() . '.' . uniqid('thing') . '@example.org'); - -When output via ``toString()``, an ID header produces something like the -following:: - - $msgId = $message->getHeaders()->get('Message-ID'); - echo $msgId->toString(); - - /* - - Message-ID: <1234955437.499becad62ec2@example.org> - - */ - -Path Headers -~~~~~~~~~~~~ - -Path headers are like very-restricted mailbox headers. They contain a single -email address with no associated name. The Return-Path header of a message is a -path header. - -You add a new path header to a HeaderSet by calling the HeaderSet's -``addPathHeader()`` method:: - - $message = new Swift_Message(); - $headers = $message->getHeaders(); - $headers->addPathHeader('Your-Header-Name', 'person@example.org'); - -Changing the value of an existing path header is done by calling its -``setAddress()`` method:: - - $return = $message->getHeaders()->get('Return-Path'); - $return->setAddress('my-address@example.org'); - -When output via ``toString()``, a path header produces something like the -following:: - - $return = $message->getHeaders()->get('Return-Path'); - $return->setAddress('person@example.org'); - echo $return->toString(); - - /* - - Return-Path: - - */ - -Header Operations ------------------ - -Working with the headers in a message involves knowing how to use the methods -on the HeaderSet and on the individual Headers within the HeaderSet. - -Adding new Headers -~~~~~~~~~~~~~~~~~~ - -New headers can be added to the HeaderSet by using one of the provided -``add..Header()`` methods. - -The added header will appear in the message when it is sent:: - - // Adding a custom header to a message - $message = new Swift_Message(); - $headers = $message->getHeaders(); - $headers->addTextHeader('X-Mine', 'something here'); - - // Adding a custom header to an attachment - $attachment = Swift_Attachment::fromPath('/path/to/doc.pdf'); - $attachment->getHeaders()->addDateHeader('X-Created-Time', time()); - -Retrieving Headers -~~~~~~~~~~~~~~~~~~ - -Headers are retrieved through the HeaderSet's ``get()`` and ``getAll()`` -methods:: - - $headers = $message->getHeaders(); - - // Get the To: header - $toHeader = $headers->get('To'); - - // Get all headers named "X-Foo" - $fooHeaders = $headers->getAll('X-Foo'); - - // Get the second header named "X-Foo" - $foo = $headers->get('X-Foo', 1); - - // Get all headers that are present - $all = $headers->getAll(); - -When using ``get()`` a single header is returned that matches the name (case -insensitive) that is passed to it. When using ``getAll()`` with a header name, -an array of headers with that name are returned. Calling ``getAll()`` with no -arguments returns an array of all headers present in the entity. - -.. note:: - - It's valid for some headers to appear more than once in a message (e.g. - the Received header). For this reason ``getAll()`` exists to fetch all - headers with a specified name. In addition, ``get()`` accepts an optional - numerical index, starting from zero to specify which header you want more - specifically. - -.. note:: - - If you want to modify the contents of the header and you don't know for - sure what type of header it is then you may need to check the type by - calling its ``getFieldType()`` method. - -Check if a Header Exists -~~~~~~~~~~~~~~~~~~~~~~~~ - -You can check if a named header is present in a HeaderSet by calling its -``has()`` method:: - - $headers = $message->getHeaders(); - - // Check if the To: header exists - if ($headers->has('To')) { - echo 'To: exists'; - } - - // Check if an X-Foo header exists twice (i.e. check for the 2nd one) - if ($headers->has('X-Foo', 1)) { - echo 'Second X-Foo header exists'; - } - -If the header exists, ``true`` will be returned or ``false`` if not. - -.. note:: - - It's valid for some headers to appear more than once in a message (e.g. - the Received header). For this reason ``has()`` accepts an optional - numerical index, starting from zero to specify which header you want to - check more specifically. - -Removing Headers -~~~~~~~~~~~~~~~~ - -Removing a Header from the HeaderSet is done by calling the HeaderSet's -``remove()`` or ``removeAll()`` methods:: - - $headers = $message->getHeaders(); - - // Remove the Subject: header - $headers->remove('Subject'); - - // Remove all X-Foo headers - $headers->removeAll('X-Foo'); - - // Remove only the second X-Foo header - $headers->remove('X-Foo', 1); - -When calling ``remove()`` a single header will be removed. When calling -``removeAll()`` all headers with the given name will be removed. If no headers -exist with the given name, no errors will occur. - -.. note:: - - It's valid for some headers to appear more than once in a message (e.g. - the Received header). For this reason ``remove()`` accepts an optional - numerical index, starting from zero to specify which header you want to - check more specifically. For the same reason, ``removeAll()`` exists to - remove all headers that have the given name. - -Modifying a Header's Content -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To change a Header's content you should know what type of header it is and then -call it's appropriate setter method. All headers also have a -``setFieldBodyModel()`` method that accepts a mixed parameter and delegates to -the correct setter:: - -The header will be updated inside the HeaderSet and the changes will be seen -when the message is sent:: - - $headers = $message->getHeaders(); - - // Change the Subject: header - $subj = $headers->get('Subject'); - $subj->setValue('new subject here'); - - // Change the To: header - $to = $headers->get('To'); - $to->setNameAddresses([ - 'person@example.org' => 'Person', - 'thing@example.org' - ]); - - // Using the setFieldBodyModel() just delegates to the correct method - // So here to calls setNameAddresses() - $to->setFieldBodyModel([ - 'person@example.org' => 'Person', - 'thing@example.org' - ]); diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/doc/index.rst b/plugins/email/vendor/swiftmailer/swiftmailer/doc/index.rst deleted file mode 100644 index 5d92889..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/doc/index.rst +++ /dev/null @@ -1,12 +0,0 @@ -Swiftmailer -=========== - -.. toctree:: - :maxdepth: 2 - - introduction - messages - headers - sending - plugins - japanese diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/doc/introduction.rst b/plugins/email/vendor/swiftmailer/swiftmailer/doc/introduction.rst deleted file mode 100644 index 8a47ef1..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/doc/introduction.rst +++ /dev/null @@ -1,67 +0,0 @@ -Swiftmailer: A feature-rich PHP Mailer -====================================== - -Swift Mailer is a component based library for sending e-mails from PHP applications. - -**Swiftmailer will stop being maintained at the end of November 2021.** - -Please, move to `Symfony Mailer `_ at your earliest convenience. -`Symfony Mailer `_ is the next evolution of Swiftmailer. -It provides the same features with support for modern PHP code and support for third-party providers. - -System Requirements -------------------- - -Swift Mailer requires PHP 7.0 or higher (``proc_*`` functions must be -available). - -Swift Mailer does not work when used with function overloading as implemented -by ``mbstring`` when ``mbstring.func_overload`` is set to ``2``. - -Installation ------------- - -The recommended way to install Swiftmailer is via Composer: - -.. code-block:: bash - - $ composer require "swiftmailer/swiftmailer:^6.0" - -Basic Usage ------------ - -Here is the simplest way to send emails with Swift Mailer:: - - require_once '/path/to/vendor/autoload.php'; - - // Create the Transport - $transport = (new Swift_SmtpTransport('smtp.example.org', 25)) - ->setUsername('your username') - ->setPassword('your password') - ; - - // Create the Mailer using your created Transport - $mailer = new Swift_Mailer($transport); - - // Create a message - $message = (new Swift_Message('Wonderful Subject')) - ->setFrom(['john@doe.com' => 'John Doe']) - ->setTo(['receiver@domain.org', 'other@domain.org' => 'A name']) - ->setBody('Here is the message itself') - ; - - // Send the message - $result = $mailer->send($message); - -You can also use Sendmail as a transport:: - - // Sendmail - $transport = new Swift_SendmailTransport('/usr/sbin/sendmail -bs'); - -Getting Help ------------- - -For general support, use `Stack Overflow `_. - -For bug reports and feature requests, create a new ticket in `GitHub -`_. diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/doc/japanese.rst b/plugins/email/vendor/swiftmailer/swiftmailer/doc/japanese.rst deleted file mode 100644 index 5454821..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/doc/japanese.rst +++ /dev/null @@ -1,19 +0,0 @@ -Using Swift Mailer for Japanese Emails -====================================== - -To send emails in Japanese, you need to tweak the default configuration. - -Call the ``Swift::init()`` method with the following code as early as possible -in your code:: - - Swift::init(function () { - Swift_DependencyContainer::getInstance() - ->register('mime.qpheaderencoder') - ->asAliasOf('mime.base64headerencoder'); - - Swift_Preferences::getInstance()->setCharset('iso-2022-jp'); - }); - - /* rest of code goes here */ - -That's all! diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/doc/messages.rst b/plugins/email/vendor/swiftmailer/swiftmailer/doc/messages.rst deleted file mode 100644 index e03859d..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/doc/messages.rst +++ /dev/null @@ -1,949 +0,0 @@ -Creating Messages -================= - -Creating messages in Swift Mailer is done by making use of the various MIME -entities provided with the library. Complex messages can be quickly created -with very little effort. - -Quick Reference ---------------- - -You can think of creating a Message as being similar to the steps you perform -when you click the Compose button in your mail client. You give it a subject, -specify some recipients, add any attachments and write your message:: - - // Create the message - $message = (new Swift_Message()) - - // Give the message a subject - ->setSubject('Your subject') - - // Set the From address with an associative array - ->setFrom(['john@doe.com' => 'John Doe']) - - // Set the To addresses with an associative array (setTo/setCc/setBcc) - ->setTo(['receiver@domain.org', 'other@domain.org' => 'A name']) - - // Give it a body - ->setBody('Here is the message itself') - - // And optionally an alternative body - ->addPart('Here is the message itself', 'text/html') - - // Optionally add any attachments - ->attach(Swift_Attachment::fromPath('my-document.pdf')) - ; - -Message Basics --------------- - -A message is a container for anything you want to send to somebody else. There -are several basic aspects of a message that you should know. - -An e-mail message is made up of several relatively simple entities that are -combined in different ways to achieve different results. All of these entities -have the same fundamental outline but serve a different purpose. The Message -itself can be defined as a MIME entity, an Attachment is a MIME entity, all -MIME parts are MIME entities -- and so on! - -The basic units of each MIME entity -- be it the Message itself, or an -Attachment -- are its Headers and its body: - -.. code-block:: text - - Header-Name: A header value - Other-Header: Another value - - The body content itself - -The Headers of a MIME entity, and its body must conform to some strict -standards defined by various RFC documents. Swift Mailer ensures that these -specifications are followed by using various types of object, including -Encoders and different Header types to generate the entity. - -The Structure of a Message -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Of all of the MIME entities, a message -- ``Swift_Message`` is the largest and -most complex. It has many properties that can be updated and it can contain -other MIME entities -- attachments for example -- nested inside it. - -A Message has a lot of different Headers which are there to present information -about the message to the recipients' mail client. Most of these headers will be -familiar to the majority of users, but we'll list the basic ones. Although it's -possible to work directly with the Headers of a Message (or other MIME entity), -the standard Headers have accessor methods provided to abstract away the -complex details for you. For example, although the Date on a message is written -with a strict format, you only need to pass a DateTimeInterface instance to -``setDate()``. - -+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| Header | Description | Accessors | -+===============================+====================================================================================================================================+=============================================+ -| ``Message-ID`` | Identifies this message with a unique ID, usually containing the domain name and time generated | ``getId()`` / ``setId()`` | -+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| ``Return-Path`` | Specifies where bounces should go (Swift Mailer reads this for other uses) | ``getReturnPath()`` / ``setReturnPath()`` | -+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| ``From`` | Specifies the address of the person who the message is from. This can be multiple addresses if multiple people wrote the message. | ``getFrom()`` / ``setFrom()`` | -+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| ``Sender`` | Specifies the address of the person who physically sent the message (higher precedence than ``From:``) | ``getSender()`` / ``setSender()`` | -+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| ``To`` | Specifies the addresses of the intended recipients | ``getTo()`` / ``setTo()`` | -+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| ``Cc`` | Specifies the addresses of recipients who will be copied in on the message | ``getCc()`` / ``setCc()`` | -+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| ``Bcc`` | Specifies the addresses of recipients who the message will be blind-copied to. Other recipients will not be aware of these copies. | ``getBcc()`` / ``setBcc()`` | -+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| ``Reply-To`` | Specifies the address where replies are sent to | ``getReplyTo()`` / ``setReplyTo()`` | -+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| ``Subject`` | Specifies the subject line that is displayed in the recipients' mail client | ``getSubject()`` / ``setSubject()`` | -+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| ``Date`` | Specifies the date at which the message was sent | ``getDate()`` / ``setDate()`` | -+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| ``Content-Type`` | Specifies the format of the message (usually ``text/plain`` or ``text/html``) | ``getContentType()`` / ``setContentType()`` | -+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| ``Content-Transfer-Encoding`` | Specifies the encoding scheme in the message | ``getEncoder()`` / ``setEncoder()`` | -+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ - -Working with a Message Object -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Although there are a lot of available methods on a message object, you only -need to make use of a small subset of them. Usually you'll use -``setSubject()``, ``setTo()`` and ``setFrom()`` before setting the body of your -message with ``setBody()``:: - - $message = new Swift_Message(); - $message->setSubject('My subject'); - -All MIME entities (including a message) have a ``toString()`` method that you -can call if you want to take a look at what is going to be sent. For example, -if you ``echo $message->toString();`` you would see something like this: - -.. code-block:: text - - Message-ID: <1230173678.4952f5eeb1432@swift.generated> - Date: Thu, 25 Dec 2008 13:54:38 +1100 - Subject: Example subject - From: Chris Corbyn - To: Receiver Name - MIME-Version: 1.0 - Content-Type: text/plain; charset=utf-8 - Content-Transfer-Encoding: quoted-printable - - Here is the message - -We'll take a closer look at the methods you use to create your message in the -following sections. - -Adding Content to Your Message ------------------------------- - -Rich content can be added to messages in Swift Mailer with relative ease by -calling methods such as ``setSubject()``, ``setBody()``, ``addPart()`` and -``attach()``. - -Setting the Subject Line -~~~~~~~~~~~~~~~~~~~~~~~~ - -The subject line, displayed in the recipients' mail client can be set with the -``setSubject()`` method, or as a parameter to ``new Swift_Message()``:: - - // Pass it as a parameter when you create the message - $message = new Swift_Message('My amazing subject'); - - // Or set it after like this - $message->setSubject('My amazing subject'); - -Setting the Body Content -~~~~~~~~~~~~~~~~~~~~~~~~ - -The body of the message -- seen when the user opens the message -- is specified -by calling the ``setBody()`` method. If an alternative body is to be included, -``addPart()`` can be used. - -The body of a message is the main part that is read by the user. Often people -want to send a message in HTML format (``text/html``), other times people want -to send in plain text (``text/plain``), or sometimes people want to send both -versions and allow the recipient to choose how they view the message. - -As a rule of thumb, if you're going to send a HTML email, always include a -plain-text equivalent of the same content so that users who prefer to read -plain text can do so. - -If the recipient's mail client offers preferences for displaying text vs. HTML -then the mail client will present that part to the user where available. In -other cases the mail client will display the "best" part it can - usually HTML -if you've included HTML:: - - // Pass it as a parameter when you create the message - $message = new Swift_Message('Subject here', 'My amazing body'); - - // Or set it after like this - $message->setBody('My amazing body', 'text/html'); - - // Add alternative parts with addPart() - $message->addPart('My amazing body in plain text', 'text/plain'); - -Attaching Files ---------------- - -Attachments are downloadable parts of a message and can be added by calling the -``attach()`` method on the message. You can add attachments that exist on disk, -or you can create attachments on-the-fly. - -Although we refer to files sent over e-mails as "attachments" -- because -they're attached to the message -- lots of other parts of the message are -actually "attached" even if we don't refer to these parts as attachments. - -File attachments are created by the ``Swift_Attachment`` class and then -attached to the message via the ``attach()`` method on it. For all of the -"every day" MIME types such as all image formats, word documents, PDFs and -spreadsheets you don't need to explicitly set the content-type of the -attachment, though it would do no harm to do so. For less common formats you -should set the content-type -- which we'll cover in a moment. - -Attaching Existing Files -~~~~~~~~~~~~~~~~~~~~~~~~ - -Files that already exist, either on disk or at a URL can be attached to a -message with just one line of code, using ``Swift_Attachment::fromPath()``. - -You can attach files that exist locally, or if your PHP installation has -``allow_url_fopen`` turned on you can attach files from other -websites. - -The attachment will be presented to the recipient as a downloadable file with -the same filename as the one you attached:: - - // Create the attachment - // * Note that you can technically leave the content-type parameter out - $attachment = Swift_Attachment::fromPath('/path/to/image.jpg', 'image/jpeg'); - - // Attach it to the message - $message->attach($attachment); - - // The two statements above could be written in one line instead - $message->attach(Swift_Attachment::fromPath('/path/to/image.jpg')); - - // You can attach files from a URL if allow_url_fopen is on in php.ini - $message->attach(Swift_Attachment::fromPath('http://site.tld/logo.png')); - -Setting the Filename -~~~~~~~~~~~~~~~~~~~~ - -Usually you don't need to explicitly set the filename of an attachment because -the name of the attached file will be used by default, but if you want to set -the filename you use the ``setFilename()`` method of the Attachment. - -The attachment will be attached in the normal way, but meta-data sent inside -the email will rename the file to something else:: - - // Create the attachment and call its setFilename() method - $attachment = Swift_Attachment::fromPath('/path/to/image.jpg') - ->setFilename('cool.jpg'); - - // Because there's a fluid interface, you can do this in one statement - $message->attach( - Swift_Attachment::fromPath('/path/to/image.jpg')->setFilename('cool.jpg') - ); - -Attaching Dynamic Content -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Files that are generated at runtime, such as PDF documents or images created -via GD can be attached directly to a message without writing them out to disk. -Use ``Swift_Attachment`` directly. - -The attachment will be presented to the recipient as a downloadable file -with the filename and content-type you specify:: - - // Create your file contents in the normal way, but don't write them to disk - $data = create_my_pdf_data(); - - // Create the attachment with your data - $attachment = new Swift_Attachment($data, 'my-file.pdf', 'application/pdf'); - - // Attach it to the message - $message->attach($attachment); - - - // You can alternatively use method chaining to build the attachment - $attachment = (new Swift_Attachment()) - ->setFilename('my-file.pdf') - ->setContentType('application/pdf') - ->setBody($data) - ; - -.. note:: - - If you would usually write the file to disk anyway you should just attach - it with ``Swift_Attachment::fromPath()`` since this will use less memory. - -Changing the Disposition -~~~~~~~~~~~~~~~~~~~~~~~~ - -Attachments just appear as files that can be saved to the Desktop if desired. -You can make attachment appear inline where possible by using the -``setDisposition()`` method of an attachment. - -The attachment will be displayed within the email viewing window if the mail -client knows how to display it:: - - // Create the attachment and call its setDisposition() method - $attachment = Swift_Attachment::fromPath('/path/to/image.jpg') - ->setDisposition('inline'); - - - // Because there's a fluid interface, you can do this in one statement - $message->attach( - Swift_Attachment::fromPath('/path/to/image.jpg')->setDisposition('inline') - ); - -.. note:: - - If you try to create an inline attachment for a non-displayable file type - such as a ZIP file, the mail client should just present the attachment as - normal. - -Embedding Inline Media Files -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Often, people want to include an image or other content inline with a HTML -message. It's easy to do this with HTML linking to remote resources, but this -approach is usually blocked by mail clients. Swift Mailer allows you to embed -your media directly into the message. - -Mail clients usually block downloads from remote resources because this -technique was often abused as a mean of tracking who opened an email. If -you're sending a HTML email and you want to include an image in the message -another approach you can take is to embed the image directly. - -Swift Mailer makes embedding files into messages extremely streamlined. You -embed a file by calling the ``embed()`` method of the message, -which returns a value you can use in a ``src`` or -``href`` attribute in your HTML. - -Just like with attachments, it's possible to embed dynamically generated -content without having an existing file available. - -The embedded files are sent in the email as a special type of attachment that -has a unique ID used to reference them within your HTML attributes. On mail -clients that do not support embedded files they may appear as attachments. - -Although this is commonly done for images, in theory it will work for any -displayable (or playable) media type. Support for other media types (such as -video) is dependent on the mail client however. - -Embedding Existing Files -........................ - -Files that already exist, either on disk or at a URL can be embedded in a -message with just one line of code, using ``Swift_EmbeddedFile::fromPath()``. - -You can embed files that exist locally, or if your PHP installation has -``allow_url_fopen`` turned on you can embed files from other websites. - -The file will be displayed with the message inline with the HTML wherever its ID -is used as a ``src`` attribute:: - - // Create the message - $message = new Swift_Message('My subject'); - - // Set the body - $message->setBody( - '' . - ' ' . - ' Here is an image Image' . - ' Rest of message' . - ' ' . - '', - 'text/html' // Mark the content-type as HTML - ); - - // You can embed files from a URL if allow_url_fopen is on in php.ini - $message->setBody( - '' . - ' ' . - ' Here is an image Image' . - ' Rest of message' . - ' ' . - '', - 'text/html' - ); - -.. note:: - - ``Swift_Image`` and ``Swift_EmbeddedFile`` are just aliases of one another. - ``Swift_Image`` exists for semantic purposes. - -.. note:: - - You can embed files in two stages if you prefer. Just capture the return - value of ``embed()`` in a variable and use that as the ``src`` attribute:: - - // If placing the embed() code inline becomes cumbersome - // it's easy to do this in two steps - $cid = $message->embed(Swift_Image::fromPath('image.png')); - - $message->setBody( - '' . - ' ' . - ' Here is an image Image' . - ' Rest of message' . - ' ' . - '', - 'text/html' // Mark the content-type as HTML - ); - -Embedding Dynamic Content -......................... - -Images that are generated at runtime, such as images created via GD can be -embedded directly to a message without writing them out to disk. Use the -standard ``new Swift_Image()`` method. - -The file will be displayed with the message inline with the HTML wherever its ID -is used as a ``src`` attribute:: - - // Create your file contents in the normal way, but don't write them to disk - $img_data = create_my_image_data(); - - // Create the message - $message = new Swift_Message('My subject'); - - // Set the body - $message->setBody( - '' . - ' ' . - ' Here is an image Image' . - ' Rest of message' . - ' ' . - '', - 'text/html' // Mark the content-type as HTML - ); - -.. note:: - - ``Swift_Image`` and ``Swift_EmbeddedFile`` are just aliases of one another. - ``Swift_Image`` exists for semantic purposes. - -.. note:: - - You can embed files in two stages if you prefer. Just capture the return - value of ``embed()`` in a variable and use that as the ``src`` attribute:: - - // If placing the embed() code inline becomes cumbersome - // it's easy to do this in two steps - $cid = $message->embed(new Swift_Image($img_data, 'image.jpg', 'image/jpeg')); - - $message->setBody( - '' . - ' ' . - ' Here is an image Image' . - ' Rest of message' . - ' ' . - '', - 'text/html' // Mark the content-type as HTML - ); - -Adding Recipients to Your Message ---------------------------------- - -Recipients are specified within the message itself via ``setTo()``, ``setCc()`` -and ``setBcc()``. Swift Mailer reads these recipients from the message when it -gets sent so that it knows where to send the message to. - -Message recipients are one of three types: - -* ``To:`` recipients -- the primary recipients (required) - -* ``Cc:`` recipients -- receive a copy of the message (optional) - -* ``Bcc:`` recipients -- hidden from other recipients (optional) - -Each type can contain one, or several addresses. It's possible to list only the -addresses of the recipients, or you can personalize the address by providing -the real name of the recipient. - -Make sure to add only valid email addresses as recipients. If you try to add an -invalid email address with ``setTo()``, ``setCc()`` or ``setBcc()``, Swift -Mailer will throw a ``Swift_RfcComplianceException``. - -If you add recipients automatically based on a data source that may contain -invalid email addresses, you can prevent possible exceptions by validating the -addresses using:: - - use Egulias\EmailValidator\EmailValidator; - use Egulias\EmailValidator\Validation\RFCValidation; - - $validator = new EmailValidator(); - $validator->isValid("example@example.com", new RFCValidation()); //true - -and only adding addresses that validate. Another way would be to wrap your ``setTo()``, ``setCc()`` and -``setBcc()`` calls in a try-catch block and handle the -``Swift_RfcComplianceException`` in the catch block. - -.. sidebar:: Syntax for Addresses - - If you only wish to refer to a single email address (for example your - ``From:`` address) then you can just use a string:: - - $message->setFrom('some@address.tld'); - - If you want to include a name then you must use an associative array:: - - $message->setFrom(['some@address.tld' => 'The Name']); - - If you want to include multiple addresses then you must use an array:: - - $message->setTo(['some@address.tld', 'other@address.tld']); - - You can mix personalized (addresses with a name) and non-personalized - addresses in the same list by mixing the use of associative and - non-associative array syntax:: - - $message->setTo([ - 'recipient-with-name@example.org' => 'Recipient Name One', - 'no-name@example.org', // Note that this is not a key-value pair - 'named-recipient@example.org' => 'Recipient Name Two' - ]); - -Setting ``To:`` Recipients -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``To:`` recipients are required in a message and are set with the ``setTo()`` -or ``addTo()`` methods of the message. - -To set ``To:`` recipients, create the message object using either ``new -Swift_Message( ... )``, then call the ``setTo()`` method with a complete array -of addresses, or use the ``addTo()`` method to iteratively add recipients. - -The ``setTo()`` method accepts input in various formats as described earlier in -this chapter. The ``addTo()`` method takes either one or two parameters. The -first being the email address and the second optional parameter being the name -of the recipient. - -``To:`` recipients are visible in the message headers and will be seen by the -other recipients:: - - // Using setTo() to set all recipients in one go - $message->setTo([ - 'person1@example.org', - 'person2@otherdomain.org' => 'Person 2 Name', - 'person3@example.org', - 'person4@example.org', - 'person5@example.org' => 'Person 5 Name' - ]); - -.. note:: - - Multiple calls to ``setTo()`` will not add new recipients -- each - call overrides the previous calls. If you want to iteratively add - recipients, use the ``addTo()`` method:: - - // Using addTo() to add recipients iteratively - $message->addTo('person1@example.org'); - $message->addTo('person2@example.org', 'Person 2 Name'); - -Setting ``Cc:`` Recipients -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``Cc:`` recipients are set with the ``setCc()`` or ``addCc()`` methods of the -message. - -To set ``Cc:`` recipients, create the message object using either ``new -Swift_Message( ... )``, then call the ``setCc()`` method with a complete array -of addresses, or use the ``addCc()`` method to iteratively add recipients. - -The ``setCc()`` method accepts input in various formats as described earlier in -this chapter. The ``addCc()`` method takes either one or two parameters. The -first being the email address and the second optional parameter being the name -of the recipient. - -``Cc:`` recipients are visible in the message headers and will be seen by the -other recipients:: - - // Using setTo() to set all recipients in one go - $message->setTo([ - 'person1@example.org', - 'person2@otherdomain.org' => 'Person 2 Name', - 'person3@example.org', - 'person4@example.org', - 'person5@example.org' => 'Person 5 Name' - ]); - -.. note:: - - Multiple calls to ``setCc()`` will not add new recipients -- each call - overrides the previous calls. If you want to iteratively add Cc: - recipients, use the ``addCc()`` method:: - - // Using addCc() to add recipients iteratively - $message->addCc('person1@example.org'); - $message->addCc('person2@example.org', 'Person 2 Name'); - -Setting ``Bcc:`` Recipients -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``Bcc:`` recipients receive a copy of the message without anybody else knowing -it, and are set with the ``setBcc()`` or ``addBcc()`` methods of the message. - -To set ``Bcc:`` recipients, create the message object using either ``new -Swift_Message( ... )``, then call the ``setBcc()`` method with a complete array -of addresses, or use the ``addBcc()`` method to iteratively add recipients. - -The ``setBcc()`` method accepts input in various formats as described earlier -in this chapter. The ``addBcc()`` method takes either one or two parameters. -The first being the email address and the second optional parameter being the -name of the recipient. - -Only the individual ``Bcc:`` recipient will see their address in the message -headers. Other recipients (including other ``Bcc:`` recipients) will not see -the address:: - - // Using setBcc() to set all recipients in one go - $message->setBcc([ - 'person1@example.org', - 'person2@otherdomain.org' => 'Person 2 Name', - 'person3@example.org', - 'person4@example.org', - 'person5@example.org' => 'Person 5 Name' - ]); - -.. note:: - - Multiple calls to ``setBcc()`` will not add new recipients -- each call - overrides the previous calls. If you want to iteratively add Bcc: - recipients, use the ``addBcc()`` method:: - - // Using addBcc() to add recipients iteratively - $message->addBcc('person1@example.org'); - $message->addBcc('person2@example.org', 'Person 2 Name'); - -.. sidebar:: Internationalized Email Addresses - - Traditionally only ASCII characters have been allowed in email addresses. - With the introduction of internationalized domain names (IDNs), non-ASCII - characters may appear in the domain name. By default, Swiftmailer encodes - such domain names in Punycode (e.g. xn--xample-ova.invalid). This is - compatible with all mail servers. - - RFC 6531 introduced an SMTP extension, SMTPUTF8, that allows non-ASCII - characters in email addresses on both sides of the @ sign. To send to such - addresses, your outbound SMTP server must support the SMTPUTF8 extension. - You should use the ``Swift_AddressEncoder_Utf8AddressEncoder`` address - encoder and enable the ``Swift_Transport_Esmtp_SmtpUtf8Handler`` SMTP - extension handler:: - - $smtpUtf8 = new Swift_Transport_Esmtp_SmtpUtf8Handler(); - $transport->setExtensionHandlers([$smtpUtf8]); - $utf8Encoder = new Swift_AddressEncoder_Utf8AddressEncoder(); - $transport->setAddressEncoder($utf8Encoder); - -Specifying Sender Details -------------------------- - -An email must include information about who sent it. Usually this is managed by -the ``From:`` address, however there are other options. - -The sender information is contained in three possible places: - -* ``From:`` -- the address(es) of who wrote the message (required) - -* ``Sender:`` -- the address of the single person who sent the message - (optional) - -* ``Return-Path:`` -- the address where bounces should go to (optional) - -You must always include a ``From:`` address by using ``setFrom()`` on the -message. Swift Mailer will use this as the default ``Return-Path:`` unless -otherwise specified. - -The ``Sender:`` address exists because the person who actually sent the email -may not be the person who wrote the email. It has a higher precedence than the -``From:`` address and will be used as the ``Return-Path:`` unless otherwise -specified. - -Setting the ``From:`` Address -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A ``From:`` address is required and is set with the ``setFrom()`` method of the -message. ``From:`` addresses specify who actually wrote the email, and usually -who sent it. - -What most people probably don't realize is that you can have more than one -``From:`` address if more than one person wrote the email -- for example if an -email was put together by a committee. - -The ``From:`` address(es) are visible in the message headers and will be seen -by the recipients. - -.. note:: - - If you set multiple ``From:`` addresses then you absolutely must set a - ``Sender:`` address to indicate who physically sent the message. - -:: - - // Set a single From: address - $message->setFrom('your@address.tld'); - - // Set a From: address including a name - $message->setFrom(['your@address.tld' => 'Your Name']); - - // Set multiple From: addresses if multiple people wrote the email - $message->setFrom([ - 'person1@example.org' => 'Sender One', - 'person2@example.org' => 'Sender Two' - ]); - -Setting the ``Sender:`` Address -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A ``Sender:`` address specifies who sent the message and is set with the -``setSender()`` method of the message. - -The ``Sender:`` address is visible in the message headers and will be seen by -the recipients. - -This address will be used as the ``Return-Path:`` unless otherwise specified. - -.. note:: - - If you set multiple ``From:`` addresses then you absolutely must set a - ``Sender:`` address to indicate who physically sent the message. - -You must not set more than one sender address on a message because it's not -possible for more than one person to send a single message:: - - $message->setSender('your@address.tld'); - -Setting the ``Return-Path:`` (Bounce) Address -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The ``Return-Path:`` address specifies where bounce notifications should be -sent and is set with the ``setReturnPath()`` method of the message. - -You can only have one ``Return-Path:`` and it must not include a personal name. - -Bounce notifications will be sent to this address:: - - $message->setReturnPath('bounces@address.tld'); - -Signed/Encrypted Message ------------------------- - -To increase the integrity/security of a message it is possible to sign and/or -encrypt an message using one or multiple signers. - -S/MIME -~~~~~~ - -S/MIME can sign and/or encrypt a message using the OpenSSL extension. - -When signing a message, the signer creates a signature of the entire content of -the message (including attachments). - -The certificate and private key must be PEM encoded, and can be either created -using for example OpenSSL or obtained at an official Certificate Authority (CA). - -**The recipient must have the CA certificate in the list of trusted issuers in -order to verify the signature.** - -**Make sure the certificate supports emailProtection.** - -When using OpenSSL this can done by the including the *-addtrust -emailProtection* parameter when creating the certificate:: - - $message = new Swift_Message(); - - $smimeSigner = new Swift_Signers_SMimeSigner(); - $smimeSigner->setSignCertificate('/path/to/certificate.pem', '/path/to/private-key.pem'); - $message->attachSigner($smimeSigner); - -When the private key is secured using a passphrase use the following instead:: - - $message = new Swift_Message(); - - $smimeSigner = new Swift_Signers_SMimeSigner(); - $smimeSigner->setSignCertificate('/path/to/certificate.pem', ['/path/to/private-key.pem', 'passphrase']); - $message->attachSigner($smimeSigner); - -By default the signature is added as attachment, making the message still -readable for mailing agents not supporting signed messages. - -Storing the message as binary is also possible but not recommended:: - - $smimeSigner->setSignCertificate('/path/to/certificate.pem', '/path/to/private-key.pem', PKCS7_BINARY); - -When encrypting the message (also known as enveloping), the entire message -(including attachments) is encrypted using a certificate, and the recipient can -then decrypt the message using corresponding private key. - -Encrypting ensures nobody can read the contents of the message without the -private key. - -Normally the recipient provides a certificate for encrypting and keeping the -decryption key private. - -Using both signing and encrypting is also possible:: - - $message = new Swift_Message(); - - $smimeSigner = new Swift_Signers_SMimeSigner(); - $smimeSigner->setSignCertificate('/path/to/sign-certificate.pem', '/path/to/private-key.pem'); - $smimeSigner->setEncryptCertificate('/path/to/encrypt-certificate.pem'); - $message->attachSigner($smimeSigner); - -The used encryption cipher can be set as the second parameter of -setEncryptCertificate() - -See https://secure.php.net/manual/openssl.ciphers for a list of supported ciphers. - -By default the message is first signed and then encrypted, this can be changed -by adding:: - - $smimeSigner->setSignThenEncrypt(false); - -**Changing this is not recommended as most mail agents don't support this -none-standard way.** - -Only when having trouble with sign then encrypt method, this should be changed. - -Requesting a Read Receipt -------------------------- - -It is possible to request a read-receipt to be sent to an address when the -email is opened. To request a read receipt set the address with -``setReadReceiptTo()``:: - - $message->setReadReceiptTo('your@address.tld'); - -When the email is opened, if the mail client supports it a notification will be -sent to this address. - -.. note:: - - Read receipts won't work for the majority of recipients since many mail - clients auto-disable them. Those clients that will send a read receipt - will make the user aware that one has been requested. - -Setting the Character Set -------------------------- - -The character set of the message (and its MIME parts) is set with the -``setCharset()`` method. You can also change the global default of UTF-8 by -working with the ``Swift_Preferences`` class. - -Swift Mailer will default to the UTF-8 character set unless otherwise -overridden. UTF-8 will work in most instances since it includes all of the -standard US keyboard characters in addition to most international characters. - -It is absolutely vital however that you know what character set your message -(or it's MIME parts) are written in otherwise your message may be received -completely garbled. - -There are two places in Swift Mailer where you can change the character set: - -* In the ``Swift_Preferences`` class - -* On each individual message and/or MIME part - -To set the character set of your Message: - -* Change the global UTF-8 setting by calling - ``Swift_Preferences::setCharset()``; or - -* Call the ``setCharset()`` method on the message or the MIME part:: - - // Approach 1: Change the global setting (suggested) - Swift_Preferences::getInstance()->setCharset('iso-8859-2'); - - // Approach 2: Call the setCharset() method of the message - $message = (new Swift_Message()) - ->setCharset('iso-8859-2'); - - // Approach 3: Specify the charset when setting the body - $message->setBody('My body', 'text/html', 'iso-8859-2'); - - // Approach 4: Specify the charset for each part added - $message->addPart('My part', 'text/plain', 'iso-8859-2'); - -Setting the Encoding --------------------- - -The body of each MIME part needs to be encoded. Binary attachments are encoded -in base64 using the ``Swift_Mime_ContentEncoder_Base64ContentEncoder``. Text -parts are traditionally encoded in quoted-printable using -``Swift_Mime_ContentEncoder_QpContentEncoder`` or -``Swift_Mime_ContentEncoder_NativeQpContentEncoder``. - -The encoder of the message or MIME part is set with the ``setEncoder()`` method. - -Quoted-printable is the safe choice, because it converts 8-bit text as 7-bit. -Most modern SMTP servers support 8-bit text. This is advertised via the 8BITMIME -SMTP extension. If your outbound SMTP server supports this SMTP extension, and -it supports downgrading the message (e.g converting to quoted-printable on the -fly) when delivering to a downstream server that does not support the extension, -you may wish to use ``Swift_Mime_ContentEncoder_PlainContentEncoder`` in -``8bit`` mode instead. This has the advantage that the source data is slightly -more readable and compact, especially for non-Western languages. - - $eightBitMime = new Swift_Transport_Esmtp_EightBitMimeHandler(); - $transport->setExtensionHandlers([$eightBitMime]); - $plainEncoder = new Swift_Mime_ContentEncoder_PlainContentEncoder('8bit'); - $message->setEncoder($plainEncoder); - -Setting the Line Length ------------------------ - -The length of lines in a message can be changed by using the -``setMaxLineLength()`` method on the message:: - - $message->setMaxLineLength(1000); - -Swift Mailer defaults to using 78 characters per line in a message. This is -done for historical reasons and so that the message can be easily viewed in -plain-text terminals - -Lines that are longer than the line length specified will be wrapped between -words. - -.. note:: - - You should never set a maximum length longer than 1000 characters - according to RFC 2822. Doing so could have unspecified side-effects such - as truncating parts of your message when it is transported between SMTP - servers. - -Setting the Message Priority ----------------------------- - -You can change the priority of the message with ``setPriority()``. Setting the -priority will not change the way your email is sent -- it is purely an -indicative setting for the recipient:: - - // Indicate "High" priority - $message->setPriority(2); - -The priority of a message is an indication to the recipient what significance -it has. Swift Mailer allows you to set the priority by calling the -``setPriority`` method. This method takes an integer value between 1 and 5: - -* ``Swift_Mime_SimpleMessage::PRIORITY_HIGHEST``: 1 -* ``Swift_Mime_SimpleMessage::PRIORITY_HIGH``: 2 -* ``Swift_Mime_SimpleMessage::PRIORITY_NORMAL``: 3 -* ``Swift_Mime_SimpleMessage::PRIORITY_LOW``: 4 -* ``Swift_Mime_SimpleMessage::PRIORITY_LOWEST``: 5 - -:: - - // Or use the constant to be more explicit - $message->setPriority(Swift_Mime_SimpleMessage::PRIORITY_HIGH); diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/doc/plugins.rst b/plugins/email/vendor/swiftmailer/swiftmailer/doc/plugins.rst deleted file mode 100644 index 548b07f..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/doc/plugins.rst +++ /dev/null @@ -1,337 +0,0 @@ -Plugins -======= - -Plugins exist to extend, or modify the behaviour of Swift Mailer. They respond -to Events that are fired within the Transports during sending. - -There are a number of Plugins provided as part of the base Swift Mailer package -and they all follow a common interface to respond to Events fired within the -library. Interfaces are provided to "listen" to each type of Event fired and to -act as desired when a listened-to Event occurs. - -Although several plugins are provided with Swift Mailer out-of-the-box, the -Events system has been specifically designed to make it easy for experienced -object-oriented developers to write their own plugins in order to achieve -goals that may not be possible with the base library. - -AntiFlood Plugin ----------------- - -Many SMTP servers have limits on the number of messages that may be sent during -any single SMTP connection. The AntiFlood plugin provides a way to stay within -this limit while still managing a large number of emails. - -A typical limit for a single connection is 100 emails. If the server you -connect to imposes such a limit, it expects you to disconnect after that number -of emails has been sent. You could manage this manually within a loop, but the -AntiFlood plugin provides the necessary wrapper code so that you don't need to -worry about this logic. - -Regardless of limits imposed by the server, it's usually a good idea to be -conservative with the resources of the SMTP server. Sending will become -sluggish if the server is being over-used so using the AntiFlood plugin will -not be a bad idea even if no limits exist. - -The AntiFlood plugin's logic is basically to disconnect and the immediately -re-connect with the SMTP server every X number of emails sent, where X is a -number you specify to the plugin. - -You can also specify a time period in seconds that Swift Mailer should pause -for between the disconnect/re-connect process. It's a good idea to pause for a -short time (say 30 seconds every 100 emails) simply to give the SMTP server a -chance to process its queue and recover some resources. - -Using the AntiFlood Plugin -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The AntiFlood Plugin -- like all plugins -- is added with the Mailer class's -``registerPlugin()`` method. It takes two constructor parameters: the number of -emails to pause after, and optionally the number of seconds to pause for. - -When Swift Mailer sends messages it will count the number of messages that have -been sent since the last re-connect. Once the number hits your specified -threshold it will disconnect and re-connect, optionally pausing for a specified -amount of time:: - - // Create the Mailer using any Transport - $mailer = new Swift_Mailer( - new Swift_SmtpTransport('smtp.example.org', 25) - ); - - // Use AntiFlood to re-connect after 100 emails - $mailer->registerPlugin(new Swift_Plugins_AntiFloodPlugin(100)); - - // And specify a time in seconds to pause for (30 secs) - $mailer->registerPlugin(new Swift_Plugins_AntiFloodPlugin(100, 30)); - - // Continue sending as normal - for ($lotsOfRecipients as $recipient) { - ... - - $mailer->send( ... ); - } - -Throttler Plugin ----------------- - -If your SMTP server has restrictions in place to limit the rate at which you -send emails, then your code will need to be aware of this rate-limiting. The -Throttler plugin makes Swift Mailer run at a rate-limited speed. - -Many shared hosts don't open their SMTP servers as a free-for-all. Usually they -have policies in place (probably to discourage spammers) that only allow you to -send a fixed number of emails per-hour/day. - -The Throttler plugin supports two modes of rate-limiting and with each, you -will need to do that math to figure out the values you want. The plugin can -limit based on the number of emails per minute, or the number of -bytes-transferred per-minute. - -Using the Throttler Plugin -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The Throttler Plugin -- like all plugins -- is added with the Mailer class' -``registerPlugin()`` method. It has two required constructor parameters that -tell it how to do its rate-limiting. - -When Swift Mailer sends messages it will keep track of the rate at which -sending messages is occurring. If it realises that sending is happening too -fast, it will cause your program to ``sleep()`` for enough time to average out -the rate:: - - // Create the Mailer using any Transport - $mailer = new Swift_Mailer( - new Swift_SmtpTransport('smtp.example.org', 25) - ); - - // Rate limit to 100 emails per-minute - $mailer->registerPlugin(new Swift_Plugins_ThrottlerPlugin( - 100, Swift_Plugins_ThrottlerPlugin::MESSAGES_PER_MINUTE - )); - - // Rate limit to 10MB per-minute - $mailer->registerPlugin(new Swift_Plugins_ThrottlerPlugin( - 1024 * 1024 * 10, Swift_Plugins_ThrottlerPlugin::BYTES_PER_MINUTE - )); - - // Continue sending as normal - for ($lotsOfRecipients as $recipient) { - ... - - $mailer->send( ... ); - } - -Logger Plugin -------------- - -The Logger plugins helps with debugging during the process of sending. It can -help to identify why an SMTP server is rejecting addresses, or any other -hard-to-find problems that may arise. - -The Logger plugin comes in two parts. There's the plugin itself, along with one -of a number of possible Loggers that you may choose to use. For example, the -logger may output messages directly in realtime, or it may capture messages in -an array. - -One other notable feature is the way in which the Logger plugin changes -Exception messages. If Exceptions are being thrown but the error message does -not provide conclusive information as to the source of the problem (such as an -ambiguous SMTP error) the Logger plugin includes the entire SMTP transcript in -the error message so that debugging becomes a simpler task. - -There are a few available Loggers included with Swift Mailer, but writing your -own implementation is incredibly simple and is achieved by creating a short -class that implements the ``Swift_Plugins_Logger`` interface. - -* ``Swift_Plugins_Loggers_ArrayLogger``: Keeps a collection of log messages - inside an array. The array content can be cleared or dumped out to the screen. - -* ``Swift_Plugins_Loggers_EchoLogger``: Prints output to the screen in - realtime. Handy for very rudimentary debug output. - -Using the Logger Plugin -~~~~~~~~~~~~~~~~~~~~~~~ - -The Logger Plugin -- like all plugins -- is added with the Mailer class' -``registerPlugin()`` method. It accepts an instance of ``Swift_Plugins_Logger`` -in its constructor. - -When Swift Mailer sends messages it will keep a log of all the interactions -with the underlying Transport being used. Depending upon the Logger that has -been used the behaviour will differ, but all implementations offer a way to get -the contents of the log:: - - // Create the Mailer using any Transport - $mailer = new Swift_Mailer( - new Swift_SmtpTransport('smtp.example.org', 25) - ); - - // To use the ArrayLogger - $logger = new Swift_Plugins_Loggers_ArrayLogger(); - $mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($logger)); - - // Or to use the Echo Logger - $logger = new Swift_Plugins_Loggers_EchoLogger(); - $mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($logger)); - - // Continue sending as normal - for ($lotsOfRecipients as $recipient) { - ... - - $mailer->send( ... ); - } - - // Dump the log contents - // NOTE: The EchoLogger dumps in realtime so dump() does nothing for it - echo $logger->dump(); - -Decorator Plugin ----------------- - -Often there's a need to send the same message to multiple recipients, but with -tiny variations such as the recipient's name being used inside the message -body. The Decorator plugin aims to provide a solution for allowing these small -differences. - -The decorator plugin works by intercepting the sending process of Swift Mailer, -reading the email address in the To: field and then looking up a set of -replacements for a template. - -While the use of this plugin is simple, it is probably the most commonly -misunderstood plugin due to the way in which it works. The typical mistake -users make is to try registering the plugin multiple times (once for each -recipient) -- inside a loop for example. This is incorrect. - -The Decorator plugin should be registered just once, but containing the list of -all recipients prior to sending. It will use this list of recipients to find -the required replacements during sending. - -Using the Decorator Plugin -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To use the Decorator plugin, simply create an associative array of replacements -based on email addresses and then use the mailer's ``registerPlugin()`` method -to add the plugin. - -First create an associative array of replacements based on the email addresses -you'll be sending the message to. - -.. note:: - - The replacements array becomes a 2-dimensional array whose keys are the - email addresses and whose values are an associative array of replacements - for that email address. The curly braces used in this example can be any - type of syntax you choose, provided they match the placeholders in your - email template:: - - $replacements = []; - foreach ($users as $user) { - $replacements[$user['email']] = [ - '{username}'=>$user['username'], - '{resetcode}'=>$user['resetcode'] - ]; - } - -Now create an instance of the Decorator plugin using this array of replacements -and then register it with the Mailer. Do this only once! - -:: - - $decorator = new Swift_Plugins_DecoratorPlugin($replacements); - - $mailer->registerPlugin($decorator); - -When you create your message, replace elements in the body (and/or the subject -line) with your placeholders:: - - $message = (new Swift_Message()) - ->setSubject('Important notice for {username}') - ->setBody( - "Hello {username}, you requested to reset your password.\n" . - "Please visit https://example.com/pwreset and use the reset code {resetcode} to set a new password." - ) - ; - - foreach ($users as $user) { - $message->addTo($user['email']); - } - -When you send this message to each of your recipients listed in your -``$replacements`` array they will receive a message customized for just -themselves. For example, the message used above when received may appear like -this to one user: - -.. code-block:: text - - Subject: Important notice for smilingsunshine2009 - - Hello smilingsunshine2009, you requested to reset your password. - Please visit https://example.com/pwreset and use the reset code 183457 to set a new password. - -While another use may receive the message as: - -.. code-block:: text - - Subject: Important notice for billy-bo-bob - - Hello billy-bo-bob, you requested to reset your password. - Please visit https://example.com/pwreset and use the reset code 539127 to set a new password. - -While the decorator plugin provides a means to solve this problem, there are -various ways you could tackle this problem without the need for a plugin. We're -trying to come up with a better way ourselves and while we have several -(obvious) ideas we don't quite have the perfect solution to go ahead and -implement it. Watch this space. - -Providing Your Own Replacements Lookup for the Decorator -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Filling an array with replacements may not be the best solution for providing -replacement information to the decorator. If you have a more elegant algorithm -that performs replacement lookups on-the-fly you may provide your own -implementation. - -Providing your own replacements lookup implementation for the Decorator is -simply a matter of passing an instance of -``Swift_Plugins_Decorator_Replacements`` to the decorator plugin's constructor, -rather than passing in an array. - -The Replacements interface is very simple to implement since it has just one -method: ``getReplacementsFor($address)``. - -Imagine you want to look up replacements from a database on-the-fly, you might -provide an implementation that does this. You need to create a small class:: - - class DbReplacements implements Swift_Plugins_Decorator_Replacements { - public function getReplacementsFor($address) { - global $db; // Your PDO instance with a connection to your database - $query = $db->prepare( - "SELECT * FROM `users` WHERE `email` = ?" - ); - - $query->execute([$address]); - - if ($row = $query->fetch(PDO::FETCH_ASSOC)) { - return [ - '{username}'=>$row['username'], - '{resetcode}'=>$row['resetcode'] - ]; - } - } - } - -Now all you need to do is pass an instance of your class into the Decorator -plugin's constructor instead of passing an array:: - - $decorator = new Swift_Plugins_DecoratorPlugin(new DbReplacements()); - - $mailer->registerPlugin($decorator); - -For each message sent, the plugin will call your class' -``getReplacementsFor()`` method to find the array of replacements it needs. - -.. note:: - - If your lookup algorithm is case sensitive, you should transform the - ``$address`` argument as appropriate -- for example by passing it through - ``strtolower()``. diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/doc/sending.rst b/plugins/email/vendor/swiftmailer/swiftmailer/doc/sending.rst deleted file mode 100644 index d3a10ad..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/doc/sending.rst +++ /dev/null @@ -1,464 +0,0 @@ -Sending Messages -================ - -Quick Reference for Sending a Message -------------------------------------- - -Sending a message is very straightforward. You create a Transport, use it to -create the Mailer, then you use the Mailer to send the message. - -When using ``send()`` the message will be sent just like it would be sent if -you used your mail client. An integer is returned which includes the number of -successful recipients. If none of the recipients could be sent to then zero -will be returned, which equates to a boolean ``false``. If you set two ``To:`` -recipients and three ``Bcc:`` recipients in the message and all of the -recipients are delivered to successfully then the value 5 will be returned:: - - // Create the Transport - $transport = (new Swift_SmtpTransport('smtp.example.org', 25)) - ->setUsername('your username') - ->setPassword('your password') - ; - - /* - You could alternatively use a different transport such as Sendmail: - - // Sendmail - $transport = new Swift_SendmailTransport('/usr/sbin/sendmail -bs'); - */ - - // Create the Mailer using your created Transport - $mailer = new Swift_Mailer($transport); - - // Create a message - $message = (new Swift_Message('Wonderful Subject')) - ->setFrom(['john@doe.com' => 'John Doe']) - ->setTo(['receiver@domain.org', 'other@domain.org' => 'A name']) - ->setBody('Here is the message itself') - ; - - // Send the message - $result = $mailer->send($message); - -Transport Types -~~~~~~~~~~~~~~~ - -Transports are the classes in Swift Mailer that are responsible for -communicating with a service in order to deliver a Message. There are several -types of Transport in Swift Mailer, all of which implement the -``Swift_Transport`` interface:: - -* ``Swift_SmtpTransport``: Sends messages over SMTP; Supports Authentication; - Supports Encryption. Very portable; Pleasingly predictable results; Provides - good feedback; - -* ``Swift_SendmailTransport``: Communicates with a locally installed - ``sendmail`` executable (Linux/UNIX). Quick time-to-run; Provides - less-accurate feedback than SMTP; Requires ``sendmail`` installation; - -* ``Swift_LoadBalancedTransport``: Cycles through a collection of the other - Transports to manage load-reduction. Provides graceful fallback if one - Transport fails (e.g. an SMTP server is down); Keeps the load on remote - services down by spreading the work; - -* ``Swift_FailoverTransport``: Works in conjunction with a collection of the - other Transports to provide high-availability. Provides graceful fallback if - one Transport fails (e.g. an SMTP server is down). - -The SMTP Transport -.................. - -The SMTP Transport sends messages over the (standardized) Simple Message -Transfer Protocol. It can deal with encryption and authentication. - -The SMTP Transport, ``Swift_SmtpTransport`` is without doubt the most commonly -used Transport because it will work on 99% of web servers (I just made that -number up, but you get the idea). All the server needs is the ability to -connect to a remote (or even local) SMTP server on the correct port number -(usually 25). - -SMTP servers often require users to authenticate with a username and password -before any mail can be sent to other domains. This is easily achieved using -Swift Mailer with the SMTP Transport. - -SMTP is a protocol -- in other words it's a "way" of communicating a job to be -done (i.e. sending a message). The SMTP protocol is the fundamental basis on -which messages are delivered all over the internet 7 days a week, 365 days a -year. For this reason it's the most "direct" method of sending messages you can -use and it's the one that will give you the most power and feedback (such as -delivery failures) when using Swift Mailer. - -Because SMTP is generally run as a remote service (i.e. you connect to it over -the network/internet) it's extremely portable from server-to-server. You can -easily store the SMTP server address and port number in a configuration file -within your application and adjust the settings accordingly if the code is -moved or if the SMTP server is changed. - -Some SMTP servers -- Google for example -- use encryption for security reasons. -Swift Mailer supports using both ``ssl`` (SMTPS = SMTP over TLS) and ``tls`` -(SMTP with STARTTLS) encryption settings. - -Using the SMTP Transport -^^^^^^^^^^^^^^^^^^^^^^^^ - -The SMTP Transport is easy to use. Most configuration options can be set with -the constructor. - -To use the SMTP Transport you need to know which SMTP server your code needs to -connect to. Ask your web host if you're not sure. Lots of people ask me who to -connect to -- I really can't answer that since it's a setting that's extremely -specific to your hosting environment. - -A connection to the SMTP server will be established upon the first call to -``send()``:: - - // Create the Transport - $transport = new Swift_SmtpTransport('smtp.example.org', 25); - - // Create the Mailer using your created Transport - $mailer = new Swift_Mailer($transport); - - /* - It's also possible to use multiple method calls - - $transport = (new Swift_SmtpTransport()) - ->setHost('smtp.example.org') - ->setPort(25) - ; - */ - -Encrypted SMTP -^^^^^^^^^^^^^^ - -You can use ``ssl`` (SMTPS) or ``tls`` (STARTTLS) encryption with the SMTP Transport -by specifying it as a parameter or with a method call:: - - // Create the Transport - // Option #1: SMTPS = SMTP over TLS (always encrypted): - $transport = new Swift_SmtpTransport('smtp.example.org', 587, 'ssl'); - // Option #2: SMTP with STARTTLS (best effort encryption): - $transport = new Swift_SmtpTransport('smtp.example.org', 587, 'tls'); - - // Create the Mailer using your created Transport - $mailer = new Swift_Mailer($transport); - -A connection to the SMTP server will be established upon the first call to -``send()``. The connection will be initiated with the correct encryption -settings. - -.. note:: - For SMTPS or STARTTLS encryption to work your PHP installation must have - appropriate OpenSSL transports wrappers. You can check if "tls" and/or - "ssl" are present in your PHP installation by using the PHP function - ``stream_get_transports()``. - -.. note:: - If you are using Mailcatcher_, make sure you do not set the encryption - for the ``Swift_SmtpTransport``, since Mailcatcher does not support encryption. - -.. note:: - When in doubt, try ``ssl`` first for higher security, since the communication - is always encrypted. - -.. note:: - Usually, port 587 or 465 is used for encrypted SMTP. Check the documentation - of your mail provider. - -SMTP with a Username and Password -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Some servers require authentication. You can provide a username and password -with ``setUsername()`` and ``setPassword()`` methods:: - - // Create the Transport the call setUsername() and setPassword() - $transport = (new Swift_SmtpTransport('smtp.example.org', 25)) - ->setUsername('username') - ->setPassword('password') - ; - - // Create the Mailer using your created Transport - $mailer = new Swift_Mailer($transport); - -Your username and password will be used to authenticate upon first connect when -``send()`` are first used on the Mailer. - -If authentication fails, an Exception of type ``Swift_TransportException`` will -be thrown. - -.. note:: - - If you need to know early whether or not authentication has failed and an - Exception is going to be thrown, call the ``start()`` method on the - created Transport. - -The Sendmail Transport -...................... - -The Sendmail Transport sends messages by communicating with a locally installed -MTA -- such as ``sendmail``. - -The Sendmail Transport, ``Swift_SendmailTransport`` does not directly connect -to any remote services. It is designed for Linux servers that have ``sendmail`` -installed. The Transport starts a local ``sendmail`` process and sends messages -to it. Usually the ``sendmail`` process will respond quickly as it spools your -messages to disk before sending them. - -The Transport is named the Sendmail Transport for historical reasons -(``sendmail`` was the "standard" UNIX tool for sending e-mail for years). It -will send messages using other transfer agents such as Exim or Postfix despite -its name, provided they have the relevant sendmail wrappers so that they can be -started with the correct command-line flags. - -It's a common misconception that because the Sendmail Transport returns a -result very quickly it must therefore deliver messages to recipients quickly -- -this is not true. It's not slow by any means, but it's certainly not faster -than SMTP when it comes to getting messages to the intended recipients. This is -because sendmail itself sends the messages over SMTP once they have been -quickly spooled to disk. - -The Sendmail Transport has the potential to be just as smart of the SMTP -Transport when it comes to notifying Swift Mailer about which recipients were -rejected, but in reality the majority of locally installed ``sendmail`` -instances are not configured well enough to provide any useful feedback. As -such Swift Mailer may report successful deliveries where they did in fact fail -before they even left your server. - -You can run the Sendmail Transport in two different modes specified by command -line flags: - -* "``-bs``" runs in SMTP mode so theoretically it will act like the SMTP - Transport - -* "``-t``" runs in piped mode with no feedback, but theoretically faster, - though not advised - -You can think of the Sendmail Transport as a sort of asynchronous SMTP -Transport -- though if you have problems with delivery failures you should try -using the SMTP Transport instead. Swift Mailer isn't doing the work here, it's -simply passing the work to somebody else (i.e. ``sendmail``). - -Using the Sendmail Transport -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -To use the Sendmail Transport you simply need to call ``new -Swift_SendmailTransport()`` with the command as a parameter. - -To use the Sendmail Transport you need to know where ``sendmail`` or another -MTA exists on the server. Swift Mailer uses a default value of -``/usr/sbin/sendmail``, which should work on most systems. - -You specify the entire command as a parameter (i.e. including the command line -flags). Swift Mailer supports operational modes of "``-bs``" (default) and -"``-t``". - -.. note:: - - If you run sendmail in "``-t``" mode you will get no feedback as to whether - or not sending has succeeded. Use "``-bs``" unless you have a reason not to. - -A sendmail process will be started upon the first call to ``send()``. If the -process cannot be started successfully an Exception of type -``Swift_TransportException`` will be thrown:: - - // Create the Transport - $transport = new Swift_SendmailTransport('/usr/sbin/exim -bs'); - - // Create the Mailer using your created Transport - $mailer = new Swift_Mailer($transport); - -Available Methods for Sending Messages -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The Mailer class offers one method for sending Messages -- ``send()``. - -When a message is sent in Swift Mailer, the Mailer class communicates with -whichever Transport class you have chosen to use. - -Each recipient in the message should either be accepted or rejected by the -Transport. For example, if the domain name on the email address is not -reachable the SMTP Transport may reject the address because it cannot process -it. ``send()`` will return an integer indicating the number of accepted -recipients. - -.. note:: - - It's possible to find out which recipients were rejected -- we'll cover that - later in this chapter. - -Using the ``send()`` Method -........................... - -The ``send()`` method of the ``Swift_Mailer`` class sends a message using -exactly the same logic as your Desktop mail client would use. Just pass it a -Message and get a result. - -The message will be sent just like it would be sent if you used your mail -client. An integer is returned which includes the number of successful -recipients. If none of the recipients could be sent to then zero will be -returned, which equates to a boolean ``false``. If you set two -``To:`` recipients and three ``Bcc:`` recipients in the message and all of the -recipients are delivered to successfully then the value 5 will be returned:: - - // Create the Transport - $transport = new Swift_SmtpTransport('localhost', 25); - - // Create the Mailer using your created Transport - $mailer = new Swift_Mailer($transport); - - // Create a message - $message = (new Swift_Message('Wonderful Subject')) - ->setFrom(['john@doe.com' => 'John Doe']) - ->setTo(['receiver@domain.org', 'other@domain.org' => 'A name']) - ->setBody('Here is the message itself') - ; - - // Send the message - $numSent = $mailer->send($message); - - printf("Sent %d messages\n", $numSent); - - /* Note that often that only the boolean equivalent of the - return value is of concern (zero indicates FALSE) - - if ($mailer->send($message)) - { - echo "Sent\n"; - } - else - { - echo "Failed\n"; - } - - */ - -Sending Emails in Batch -....................... - -If you want to send a separate message to each recipient so that only their own -address shows up in the ``To:`` field, follow the following recipe: - -* Create a Transport from one of the provided Transports -- - ``Swift_SmtpTransport``, ``Swift_SendmailTransport``, - or one of the aggregate Transports. - -* Create an instance of the ``Swift_Mailer`` class, using the Transport as - it's constructor parameter. - -* Create a Message. - -* Iterate over the recipients and send message via the ``send()`` method on - the Mailer object. - -Each recipient of the messages receives a different copy with only their own -email address on the ``To:`` field. - -Make sure to add only valid email addresses as recipients. If you try to add an -invalid email address with ``setTo()``, ``setCc()`` or ``setBcc()``, Swift -Mailer will throw a ``Swift_RfcComplianceException``. - -If you add recipients automatically based on a data source that may contain -invalid email addresses, you can prevent possible exceptions by validating the -addresses using ``Egulias\EmailValidator\EmailValidator`` (a dependency that is -installed with Swift Mailer) and only adding addresses that validate. Another -way would be to wrap your ``setTo()``, ``setCc()`` and ``setBcc()`` calls in a -try-catch block and handle the ``Swift_RfcComplianceException`` in the catch -block. - -Handling invalid addresses properly is especially important when sending emails -in large batches since a single invalid address might cause an unhandled -exception and stop the execution or your script early. - -.. note:: - - In the following example, two emails are sent. One to each of - ``receiver@domain.org`` and ``other@domain.org``. These recipients will - not be aware of each other:: - - // Create the Transport - $transport = new Swift_SmtpTransport('localhost', 25); - - // Create the Mailer using your created Transport - $mailer = new Swift_Mailer($transport); - - // Create a message - $message = (new Swift_Message('Wonderful Subject')) - ->setFrom(['john@doe.com' => 'John Doe']) - ->setBody('Here is the message itself') - ; - - // Send the message - $failedRecipients = []; - $numSent = 0; - $to = ['receiver@domain.org', 'other@domain.org' => 'A name']; - - foreach ($to as $address => $name) - { - if (is_int($address)) { - $message->setTo($name); - } else { - $message->setTo([$address => $name]); - } - - $numSent += $mailer->send($message, $failedRecipients); - } - - printf("Sent %d messages\n", $numSent); - -Finding out Rejected Addresses -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -It's possible to get a list of addresses that were rejected by the Transport by -using a by-reference parameter to ``send()``. - -As Swift Mailer attempts to send the message to each address given to it, if a -recipient is rejected it will be added to the array. You can pass an existing -array, otherwise one will be created by-reference. - -Collecting the list of recipients that were rejected can be useful in -circumstances where you need to "prune" a mailing list for example when some -addresses cannot be delivered to. - -Getting Failures By-reference -............................. - -Collecting delivery failures by-reference with the ``send()`` method is as -simple as passing a variable name to the method call:: - - $mailer = new Swift_Mailer( ... ); - - $message = (new Swift_Message( ... )) - ->setFrom( ... ) - ->setTo([ - 'receiver@bad-domain.org' => 'Receiver Name', - 'other@domain.org' => 'A name', - 'other-receiver@bad-domain.org' => 'Other Name' - )) - ->setBody( ... ) - ; - - // Pass a variable name to the send() method - if (!$mailer->send($message, $failures)) - { - echo "Failures:"; - print_r($failures); - } - - /* - Failures: - Array ( - 0 => receiver@bad-domain.org, - 1 => other-receiver@bad-domain.org - ) - */ - -If the Transport rejects any of the recipients, the culprit addresses will be -added to the array provided by-reference. - -.. note:: - - If the variable name does not yet exist, it will be initialized as an - empty array and then failures will be added to that array. If the variable - already exists it will be type-cast to an array and failures will be added - to it. - -.. _Mailcatcher: https://mailcatcher.me/ diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php deleted file mode 100644 index 51b19c9..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php +++ /dev/null @@ -1,78 +0,0 @@ -address = $address; - } - - public function getAddress(): string - { - return $this->address; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Attachment.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Attachment.php deleted file mode 100644 index 7a1420f..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Attachment.php +++ /dev/null @@ -1,54 +0,0 @@ -createDependenciesFor('mime.attachment') - ); - - $this->setBody($data, $contentType); - $this->setFilename($filename); - } - - /** - * Create a new Attachment from a filesystem path. - * - * @param string $path - * @param string $contentType optional - * - * @return self - */ - public static function fromPath($path, $contentType = null) - { - return (new self())->setFile( - new Swift_ByteStream_FileByteStream($path), - $contentType - ); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php deleted file mode 100644 index 3a69c15..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php +++ /dev/null @@ -1,176 +0,0 @@ -filters[$key] = $filter; - } - - /** - * Remove an already present StreamFilter based on its $key. - * - * @param string $key - */ - public function removeFilter($key) - { - unset($this->filters[$key]); - } - - /** - * Writes $bytes to the end of the stream. - * - * @param string $bytes - * - * @throws Swift_IoException - * - * @return int - */ - public function write($bytes) - { - $this->writeBuffer .= $bytes; - foreach ($this->filters as $filter) { - if ($filter->shouldBuffer($this->writeBuffer)) { - return; - } - } - $this->doWrite($this->writeBuffer); - - return ++$this->sequence; - } - - /** - * For any bytes that are currently buffered inside the stream, force them - * off the buffer. - * - * @throws Swift_IoException - */ - public function commit() - { - $this->doWrite($this->writeBuffer); - } - - /** - * Attach $is to this stream. - * - * The stream acts as an observer, receiving all data that is written. - * All {@link write()} and {@link flushBuffers()} operations will be mirrored. - */ - public function bind(Swift_InputByteStream $is) - { - $this->mirrors[] = $is; - } - - /** - * Remove an already bound stream. - * - * If $is is not bound, no errors will be raised. - * If the stream currently has any buffered data it will be written to $is - * before unbinding occurs. - */ - public function unbind(Swift_InputByteStream $is) - { - foreach ($this->mirrors as $k => $stream) { - if ($is === $stream) { - if ('' !== $this->writeBuffer) { - $stream->write($this->writeBuffer); - } - unset($this->mirrors[$k]); - } - } - } - - /** - * Flush the contents of the stream (empty it) and set the internal pointer - * to the beginning. - * - * @throws Swift_IoException - */ - public function flushBuffers() - { - if ('' !== $this->writeBuffer) { - $this->doWrite($this->writeBuffer); - } - $this->flush(); - - foreach ($this->mirrors as $stream) { - $stream->flushBuffers(); - } - } - - /** Run $bytes through all filters */ - private function filter($bytes) - { - foreach ($this->filters as $filter) { - $bytes = $filter->filter($bytes); - } - - return $bytes; - } - - /** Just write the bytes to the stream */ - private function doWrite($bytes) - { - $this->doCommit($this->filter($bytes)); - - foreach ($this->mirrors as $stream) { - $stream->write($bytes); - } - - $this->writeBuffer = ''; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php deleted file mode 100644 index 4f3dcc3..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php +++ /dev/null @@ -1,178 +0,0 @@ -array = $stack; - $this->arraySize = \count($stack); - } elseif (\is_string($stack)) { - $this->write($stack); - } else { - $this->array = []; - } - } - - /** - * Reads $length bytes from the stream into a string and moves the pointer - * through the stream by $length. - * - * If less bytes exist than are requested the - * remaining bytes are given instead. If no bytes are remaining at all, boolean - * false is returned. - * - * @param int $length - * - * @return string - */ - public function read($length) - { - if ($this->offset == $this->arraySize) { - return false; - } - - // Don't use array slice - $end = $length + $this->offset; - $end = $this->arraySize < $end ? $this->arraySize : $end; - $ret = ''; - for (; $this->offset < $end; ++$this->offset) { - $ret .= $this->array[$this->offset]; - } - - return $ret; - } - - /** - * Writes $bytes to the end of the stream. - * - * @param string $bytes - */ - public function write($bytes) - { - $to_add = str_split($bytes); - foreach ($to_add as $value) { - $this->array[] = $value; - } - $this->arraySize = \count($this->array); - - foreach ($this->mirrors as $stream) { - $stream->write($bytes); - } - } - - /** - * Not used. - */ - public function commit() - { - } - - /** - * Attach $is to this stream. - * - * The stream acts as an observer, receiving all data that is written. - * All {@link write()} and {@link flushBuffers()} operations will be mirrored. - */ - public function bind(Swift_InputByteStream $is) - { - $this->mirrors[] = $is; - } - - /** - * Remove an already bound stream. - * - * If $is is not bound, no errors will be raised. - * If the stream currently has any buffered data it will be written to $is - * before unbinding occurs. - */ - public function unbind(Swift_InputByteStream $is) - { - foreach ($this->mirrors as $k => $stream) { - if ($is === $stream) { - unset($this->mirrors[$k]); - } - } - } - - /** - * Move the internal read pointer to $byteOffset in the stream. - * - * @param int $byteOffset - * - * @return bool - */ - public function setReadPointer($byteOffset) - { - if ($byteOffset > $this->arraySize) { - $byteOffset = $this->arraySize; - } elseif ($byteOffset < 0) { - $byteOffset = 0; - } - - $this->offset = $byteOffset; - } - - /** - * Flush the contents of the stream (empty it) and set the internal pointer - * to the beginning. - */ - public function flushBuffers() - { - $this->offset = 0; - $this->array = []; - $this->arraySize = 0; - - foreach ($this->mirrors as $stream) { - $stream->flushBuffers(); - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php deleted file mode 100644 index f639121..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php +++ /dev/null @@ -1,214 +0,0 @@ -path = $path; - $this->mode = $writable ? 'w+b' : 'rb'; - } - - /** - * Get the complete path to the file. - * - * @return string - */ - public function getPath() - { - return $this->path; - } - - /** - * Reads $length bytes from the stream into a string and moves the pointer - * through the stream by $length. - * - * If less bytes exist than are requested the - * remaining bytes are given instead. If no bytes are remaining at all, boolean - * false is returned. - * - * @param int $length - * - * @return string|bool - * - * @throws Swift_IoException - */ - public function read($length) - { - $fp = $this->getReadHandle(); - if (!feof($fp)) { - $bytes = fread($fp, $length); - $this->offset = ftell($fp); - - // If we read one byte after reaching the end of the file - // feof() will return false and an empty string is returned - if ((false === $bytes || '' === $bytes) && feof($fp)) { - $this->resetReadHandle(); - - return false; - } - - return $bytes; - } - - $this->resetReadHandle(); - - return false; - } - - /** - * Move the internal read pointer to $byteOffset in the stream. - * - * @param int $byteOffset - * - * @return bool - */ - public function setReadPointer($byteOffset) - { - if (isset($this->reader)) { - $this->seekReadStreamToPosition($byteOffset); - } - $this->offset = $byteOffset; - } - - /** Just write the bytes to the file */ - protected function doCommit($bytes) - { - fwrite($this->getWriteHandle(), $bytes); - $this->resetReadHandle(); - } - - /** Not used */ - protected function flush() - { - } - - /** Get the resource for reading */ - private function getReadHandle() - { - if (!isset($this->reader)) { - $pointer = @fopen($this->path, 'rb'); - if (!$pointer) { - throw new Swift_IoException('Unable to open file for reading ['.$this->path.']'); - } - $this->reader = $pointer; - if (0 != $this->offset) { - $this->getReadStreamSeekableStatus(); - $this->seekReadStreamToPosition($this->offset); - } - } - - return $this->reader; - } - - /** Get the resource for writing */ - private function getWriteHandle() - { - if (!isset($this->writer)) { - if (!$this->writer = fopen($this->path, $this->mode)) { - throw new Swift_IoException('Unable to open file for writing ['.$this->path.']'); - } - } - - return $this->writer; - } - - /** Force a reload of the resource for reading */ - private function resetReadHandle() - { - if (isset($this->reader)) { - fclose($this->reader); - $this->reader = null; - } - } - - /** Check if ReadOnly Stream is seekable */ - private function getReadStreamSeekableStatus() - { - $metas = stream_get_meta_data($this->reader); - $this->seekable = $metas['seekable']; - } - - /** Streams in a readOnly stream ensuring copy if needed */ - private function seekReadStreamToPosition($offset) - { - if (null === $this->seekable) { - $this->getReadStreamSeekableStatus(); - } - if (false === $this->seekable) { - $currentPos = ftell($this->reader); - if ($currentPos < $offset) { - $toDiscard = $offset - $currentPos; - fread($this->reader, $toDiscard); - - return; - } - $this->copyReadStream(); - } - fseek($this->reader, $offset, SEEK_SET); - } - - /** Copy a readOnly Stream to ensure seekability */ - private function copyReadStream() - { - if ($tmpFile = fopen('php://temp/maxmemory:4096', 'w+b')) { - /* We have opened a php:// Stream Should work without problem */ - } elseif (\function_exists('sys_get_temp_dir') && is_writable(sys_get_temp_dir()) && ($tmpFile = tmpfile())) { - /* We have opened a tmpfile */ - } else { - throw new Swift_IoException('Unable to copy the file to make it seekable, sys_temp_dir is not writable, php://memory not available'); - } - $currentPos = ftell($this->reader); - fclose($this->reader); - $source = fopen($this->path, 'rb'); - if (!$source) { - throw new Swift_IoException('Unable to open file for copying ['.$this->path.']'); - } - fseek($tmpFile, 0, SEEK_SET); - while (!feof($source)) { - fwrite($tmpFile, fread($source, 4096)); - } - fseek($tmpFile, $currentPos, SEEK_SET); - fclose($source); - $this->reader = $tmpFile; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php deleted file mode 100644 index 0dc6190..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php +++ /dev/null @@ -1,52 +0,0 @@ -getPath()))) { - throw new Swift_IoException('Failed to get temporary file content.'); - } - - return $content; - } - - public function __destruct() - { - if (file_exists($this->getPath())) { - @unlink($this->getPath()); - } - } - - public function __sleep() - { - throw new \BadMethodCallException('Cannot serialize '.__CLASS__); - } - - public function __wakeup() - { - throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader.php deleted file mode 100644 index 4267adb..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader.php +++ /dev/null @@ -1,67 +0,0 @@ - - */ -interface Swift_CharacterReader -{ - const MAP_TYPE_INVALID = 0x01; - const MAP_TYPE_FIXED_LEN = 0x02; - const MAP_TYPE_POSITIONS = 0x03; - - /** - * Returns the complete character map. - * - * @param string $string - * @param int $startOffset - * @param array $currentMap - * @param mixed $ignoredChars - * - * @return int - */ - public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars); - - /** - * Returns the mapType, see constants. - * - * @return int - */ - public function getMapType(); - - /** - * Returns an integer which specifies how many more bytes to read. - * - * A positive integer indicates the number of more bytes to fetch before invoking - * this method again. - * - * A value of zero means this is already a valid character. - * A value of -1 means this cannot possibly be a valid character. - * - * @param int[] $bytes - * @param int $size - * - * @return int - */ - public function validateByteSequence($bytes, $size); - - /** - * Returns the number of bytes which should be read to start each character. - * - * For fixed width character sets this should be the number of octets-per-character. - * For multibyte character sets this will probably be 1. - * - * @return int - */ - public function getInitialByteSize(); -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php deleted file mode 100644 index 3e055af..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php +++ /dev/null @@ -1,97 +0,0 @@ - - */ -class Swift_CharacterReader_GenericFixedWidthReader implements Swift_CharacterReader -{ - /** - * The number of bytes in a single character. - * - * @var int - */ - private $width; - - /** - * Creates a new GenericFixedWidthReader using $width bytes per character. - * - * @param int $width - */ - public function __construct($width) - { - $this->width = $width; - } - - /** - * Returns the complete character map. - * - * @param string $string - * @param int $startOffset - * @param array $currentMap - * @param mixed $ignoredChars - * - * @return int - */ - public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars) - { - $strlen = \strlen($string); - // % and / are CPU intensive, so, maybe find a better way - $ignored = $strlen % $this->width; - $ignoredChars = $ignored ? substr($string, -$ignored) : ''; - $currentMap = $this->width; - - return ($strlen - $ignored) / $this->width; - } - - /** - * Returns the mapType. - * - * @return int - */ - public function getMapType() - { - return self::MAP_TYPE_FIXED_LEN; - } - - /** - * Returns an integer which specifies how many more bytes to read. - * - * A positive integer indicates the number of more bytes to fetch before invoking - * this method again. - * - * A value of zero means this is already a valid character. - * A value of -1 means this cannot possibly be a valid character. - * - * @param string $bytes - * @param int $size - * - * @return int - */ - public function validateByteSequence($bytes, $size) - { - $needed = $this->width - $size; - - return $needed > -1 ? $needed : -1; - } - - /** - * Returns the number of bytes which should be read to start each character. - * - * @return int - */ - public function getInitialByteSize() - { - return $this->width; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php deleted file mode 100644 index ffc05f7..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php +++ /dev/null @@ -1,84 +0,0 @@ - "\x07F") { - // Invalid char - $currentMap[$i + $startOffset] = $string[$i]; - } - } - - return $strlen; - } - - /** - * Returns mapType. - * - * @return int mapType - */ - public function getMapType() - { - return self::MAP_TYPE_INVALID; - } - - /** - * Returns an integer which specifies how many more bytes to read. - * - * A positive integer indicates the number of more bytes to fetch before invoking - * this method again. - * A value of zero means this is already a valid character. - * A value of -1 means this cannot possibly be a valid character. - * - * @param string $bytes - * @param int $size - * - * @return int - */ - public function validateByteSequence($bytes, $size) - { - $byte = reset($bytes); - if (1 == \count($bytes) && $byte >= 0x00 && $byte <= 0x7F) { - return 0; - } - - return -1; - } - - /** - * Returns the number of bytes which should be read to start each character. - * - * @return int - */ - public function getInitialByteSize() - { - return 1; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php deleted file mode 100644 index da37e0d..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php +++ /dev/null @@ -1,176 +0,0 @@ - - */ -class Swift_CharacterReader_Utf8Reader implements Swift_CharacterReader -{ - /** Pre-computed for optimization */ - private static $length_map = [ - // N=0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x0N - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x1N - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x2N - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x3N - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x4N - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x5N - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x6N - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x7N - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x8N - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x9N - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xAN - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xBN - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xCN - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xDN - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEN - 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0, // 0xFN - ]; - - private static $s_length_map = [ - "\x00" => 1, "\x01" => 1, "\x02" => 1, "\x03" => 1, "\x04" => 1, "\x05" => 1, "\x06" => 1, "\x07" => 1, - "\x08" => 1, "\x09" => 1, "\x0a" => 1, "\x0b" => 1, "\x0c" => 1, "\x0d" => 1, "\x0e" => 1, "\x0f" => 1, - "\x10" => 1, "\x11" => 1, "\x12" => 1, "\x13" => 1, "\x14" => 1, "\x15" => 1, "\x16" => 1, "\x17" => 1, - "\x18" => 1, "\x19" => 1, "\x1a" => 1, "\x1b" => 1, "\x1c" => 1, "\x1d" => 1, "\x1e" => 1, "\x1f" => 1, - "\x20" => 1, "\x21" => 1, "\x22" => 1, "\x23" => 1, "\x24" => 1, "\x25" => 1, "\x26" => 1, "\x27" => 1, - "\x28" => 1, "\x29" => 1, "\x2a" => 1, "\x2b" => 1, "\x2c" => 1, "\x2d" => 1, "\x2e" => 1, "\x2f" => 1, - "\x30" => 1, "\x31" => 1, "\x32" => 1, "\x33" => 1, "\x34" => 1, "\x35" => 1, "\x36" => 1, "\x37" => 1, - "\x38" => 1, "\x39" => 1, "\x3a" => 1, "\x3b" => 1, "\x3c" => 1, "\x3d" => 1, "\x3e" => 1, "\x3f" => 1, - "\x40" => 1, "\x41" => 1, "\x42" => 1, "\x43" => 1, "\x44" => 1, "\x45" => 1, "\x46" => 1, "\x47" => 1, - "\x48" => 1, "\x49" => 1, "\x4a" => 1, "\x4b" => 1, "\x4c" => 1, "\x4d" => 1, "\x4e" => 1, "\x4f" => 1, - "\x50" => 1, "\x51" => 1, "\x52" => 1, "\x53" => 1, "\x54" => 1, "\x55" => 1, "\x56" => 1, "\x57" => 1, - "\x58" => 1, "\x59" => 1, "\x5a" => 1, "\x5b" => 1, "\x5c" => 1, "\x5d" => 1, "\x5e" => 1, "\x5f" => 1, - "\x60" => 1, "\x61" => 1, "\x62" => 1, "\x63" => 1, "\x64" => 1, "\x65" => 1, "\x66" => 1, "\x67" => 1, - "\x68" => 1, "\x69" => 1, "\x6a" => 1, "\x6b" => 1, "\x6c" => 1, "\x6d" => 1, "\x6e" => 1, "\x6f" => 1, - "\x70" => 1, "\x71" => 1, "\x72" => 1, "\x73" => 1, "\x74" => 1, "\x75" => 1, "\x76" => 1, "\x77" => 1, - "\x78" => 1, "\x79" => 1, "\x7a" => 1, "\x7b" => 1, "\x7c" => 1, "\x7d" => 1, "\x7e" => 1, "\x7f" => 1, - "\x80" => 0, "\x81" => 0, "\x82" => 0, "\x83" => 0, "\x84" => 0, "\x85" => 0, "\x86" => 0, "\x87" => 0, - "\x88" => 0, "\x89" => 0, "\x8a" => 0, "\x8b" => 0, "\x8c" => 0, "\x8d" => 0, "\x8e" => 0, "\x8f" => 0, - "\x90" => 0, "\x91" => 0, "\x92" => 0, "\x93" => 0, "\x94" => 0, "\x95" => 0, "\x96" => 0, "\x97" => 0, - "\x98" => 0, "\x99" => 0, "\x9a" => 0, "\x9b" => 0, "\x9c" => 0, "\x9d" => 0, "\x9e" => 0, "\x9f" => 0, - "\xa0" => 0, "\xa1" => 0, "\xa2" => 0, "\xa3" => 0, "\xa4" => 0, "\xa5" => 0, "\xa6" => 0, "\xa7" => 0, - "\xa8" => 0, "\xa9" => 0, "\xaa" => 0, "\xab" => 0, "\xac" => 0, "\xad" => 0, "\xae" => 0, "\xaf" => 0, - "\xb0" => 0, "\xb1" => 0, "\xb2" => 0, "\xb3" => 0, "\xb4" => 0, "\xb5" => 0, "\xb6" => 0, "\xb7" => 0, - "\xb8" => 0, "\xb9" => 0, "\xba" => 0, "\xbb" => 0, "\xbc" => 0, "\xbd" => 0, "\xbe" => 0, "\xbf" => 0, - "\xc0" => 2, "\xc1" => 2, "\xc2" => 2, "\xc3" => 2, "\xc4" => 2, "\xc5" => 2, "\xc6" => 2, "\xc7" => 2, - "\xc8" => 2, "\xc9" => 2, "\xca" => 2, "\xcb" => 2, "\xcc" => 2, "\xcd" => 2, "\xce" => 2, "\xcf" => 2, - "\xd0" => 2, "\xd1" => 2, "\xd2" => 2, "\xd3" => 2, "\xd4" => 2, "\xd5" => 2, "\xd6" => 2, "\xd7" => 2, - "\xd8" => 2, "\xd9" => 2, "\xda" => 2, "\xdb" => 2, "\xdc" => 2, "\xdd" => 2, "\xde" => 2, "\xdf" => 2, - "\xe0" => 3, "\xe1" => 3, "\xe2" => 3, "\xe3" => 3, "\xe4" => 3, "\xe5" => 3, "\xe6" => 3, "\xe7" => 3, - "\xe8" => 3, "\xe9" => 3, "\xea" => 3, "\xeb" => 3, "\xec" => 3, "\xed" => 3, "\xee" => 3, "\xef" => 3, - "\xf0" => 4, "\xf1" => 4, "\xf2" => 4, "\xf3" => 4, "\xf4" => 4, "\xf5" => 4, "\xf6" => 4, "\xf7" => 4, - "\xf8" => 5, "\xf9" => 5, "\xfa" => 5, "\xfb" => 5, "\xfc" => 6, "\xfd" => 6, "\xfe" => 0, "\xff" => 0, - ]; - - /** - * Returns the complete character map. - * - * @param string $string - * @param int $startOffset - * @param array $currentMap - * @param mixed $ignoredChars - * - * @return int - */ - public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars) - { - if (!isset($currentMap['i']) || !isset($currentMap['p'])) { - $currentMap['p'] = $currentMap['i'] = []; - } - - $strlen = \strlen($string); - $charPos = \count($currentMap['p']); - $foundChars = 0; - $invalid = false; - for ($i = 0; $i < $strlen; ++$i) { - $char = $string[$i]; - $size = self::$s_length_map[$char]; - if (0 == $size) { - /* char is invalid, we must wait for a resync */ - $invalid = true; - continue; - } else { - if (true === $invalid) { - /* We mark the chars as invalid and start a new char */ - $currentMap['p'][$charPos + $foundChars] = $startOffset + $i; - $currentMap['i'][$charPos + $foundChars] = true; - ++$foundChars; - $invalid = false; - } - if (($i + $size) > $strlen) { - $ignoredChars = substr($string, $i); - break; - } - for ($j = 1; $j < $size; ++$j) { - $char = $string[$i + $j]; - if ($char > "\x7F" && $char < "\xC0") { - // Valid - continue parsing - } else { - /* char is invalid, we must wait for a resync */ - $invalid = true; - continue 2; - } - } - /* Ok we got a complete char here */ - $currentMap['p'][$charPos + $foundChars] = $startOffset + $i + $size; - $i += $j - 1; - ++$foundChars; - } - } - - return $foundChars; - } - - /** - * Returns mapType. - * - * @return int mapType - */ - public function getMapType() - { - return self::MAP_TYPE_POSITIONS; - } - - /** - * Returns an integer which specifies how many more bytes to read. - * - * A positive integer indicates the number of more bytes to fetch before invoking - * this method again. - * A value of zero means this is already a valid character. - * A value of -1 means this cannot possibly be a valid character. - * - * @param string $bytes - * @param int $size - * - * @return int - */ - public function validateByteSequence($bytes, $size) - { - if ($size < 1) { - return -1; - } - $needed = self::$length_map[$bytes[0]] - $size; - - return $needed > -1 ? $needed : -1; - } - - /** - * Returns the number of bytes which should be read to start each character. - * - * @return int - */ - public function getInitialByteSize() - { - return 1; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php deleted file mode 100644 index 15b6c69..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php +++ /dev/null @@ -1,26 +0,0 @@ -init(); - } - - public function __wakeup() - { - $this->init(); - } - - public function init() - { - if (\count(self::$map) > 0) { - return; - } - - $prefix = 'Swift_CharacterReader_'; - - $singleByte = [ - 'class' => $prefix.'GenericFixedWidthReader', - 'constructor' => [1], - ]; - - $doubleByte = [ - 'class' => $prefix.'GenericFixedWidthReader', - 'constructor' => [2], - ]; - - $fourBytes = [ - 'class' => $prefix.'GenericFixedWidthReader', - 'constructor' => [4], - ]; - - // Utf-8 - self::$map['utf-?8'] = [ - 'class' => $prefix.'Utf8Reader', - 'constructor' => [], - ]; - - //7-8 bit charsets - self::$map['(us-)?ascii'] = $singleByte; - self::$map['(iso|iec)-?8859-?[0-9]+'] = $singleByte; - self::$map['windows-?125[0-9]'] = $singleByte; - self::$map['cp-?[0-9]+'] = $singleByte; - self::$map['ansi'] = $singleByte; - self::$map['macintosh'] = $singleByte; - self::$map['koi-?7'] = $singleByte; - self::$map['koi-?8-?.+'] = $singleByte; - self::$map['mik'] = $singleByte; - self::$map['(cork|t1)'] = $singleByte; - self::$map['v?iscii'] = $singleByte; - - //16 bits - self::$map['(ucs-?2|utf-?16)'] = $doubleByte; - - //32 bits - self::$map['(ucs-?4|utf-?32)'] = $fourBytes; - - // Fallback - self::$map['.*'] = $singleByte; - } - - /** - * Returns a CharacterReader suitable for the charset applied. - * - * @param string $charset - * - * @return Swift_CharacterReader - */ - public function getReaderFor($charset) - { - $charset = strtolower(trim($charset ?? '')); - foreach (self::$map as $pattern => $spec) { - $re = '/^'.$pattern.'$/D'; - if (preg_match($re, $charset)) { - if (!\array_key_exists($pattern, self::$loaded)) { - $reflector = new ReflectionClass($spec['class']); - if ($reflector->getConstructor()) { - $reader = $reflector->newInstanceArgs($spec['constructor']); - } else { - $reader = $reflector->newInstance(); - } - self::$loaded[$pattern] = $reader; - } - - return self::$loaded[$pattern]; - } - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream.php deleted file mode 100644 index c9d8a07..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream.php +++ /dev/null @@ -1,87 +0,0 @@ -setCharacterReaderFactory($factory); - $this->setCharacterSet($charset); - } - - /** - * Set the character set used in this CharacterStream. - * - * @param string $charset - */ - public function setCharacterSet($charset) - { - $this->charset = $charset; - $this->charReader = null; - } - - /** - * Set the CharacterReaderFactory for multi charset support. - */ - public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory) - { - $this->charReaderFactory = $factory; - } - - /** - * Overwrite this character stream using the byte sequence in the byte stream. - * - * @param Swift_OutputByteStream $os output stream to read from - */ - public function importByteStream(Swift_OutputByteStream $os) - { - if (!isset($this->charReader)) { - $this->charReader = $this->charReaderFactory - ->getReaderFor($this->charset); - } - - $startLength = $this->charReader->getInitialByteSize(); - while (false !== $bytes = $os->read($startLength)) { - $c = []; - for ($i = 0, $len = \strlen($bytes); $i < $len; ++$i) { - $c[] = self::$byteMap[$bytes[$i]]; - } - $size = \count($c); - $need = $this->charReader - ->validateByteSequence($c, $size); - if ($need > 0 && - false !== $bytes = $os->read($need)) { - for ($i = 0, $len = \strlen($bytes); $i < $len; ++$i) { - $c[] = self::$byteMap[$bytes[$i]]; - } - } - $this->array[] = $c; - ++$this->array_size; - } - } - - /** - * Import a string a bytes into this CharacterStream, overwriting any existing - * data in the stream. - * - * @param string $string - */ - public function importString($string) - { - $this->flushContents(); - $this->write($string); - } - - /** - * Read $length characters from the stream and move the internal pointer - * $length further into the stream. - * - * @param int $length - * - * @return string - */ - public function read($length) - { - if ($this->offset == $this->array_size) { - return false; - } - - // Don't use array slice - $arrays = []; - $end = $length + $this->offset; - for ($i = $this->offset; $i < $end; ++$i) { - if (!isset($this->array[$i])) { - break; - } - $arrays[] = $this->array[$i]; - } - $this->offset += $i - $this->offset; // Limit function calls - $chars = false; - foreach ($arrays as $array) { - $chars .= implode('', array_map('chr', $array)); - } - - return $chars; - } - - /** - * Read $length characters from the stream and return a 1-dimensional array - * containing there octet values. - * - * @param int $length - * - * @return int[] - */ - public function readBytes($length) - { - if ($this->offset == $this->array_size) { - return false; - } - $arrays = []; - $end = $length + $this->offset; - for ($i = $this->offset; $i < $end; ++$i) { - if (!isset($this->array[$i])) { - break; - } - $arrays[] = $this->array[$i]; - } - $this->offset += ($i - $this->offset); // Limit function calls - - return array_merge(...$arrays); - } - - /** - * Write $chars to the end of the stream. - * - * @param string $chars - */ - public function write($chars) - { - if (!isset($this->charReader)) { - $this->charReader = $this->charReaderFactory->getReaderFor( - $this->charset); - } - - $startLength = $this->charReader->getInitialByteSize(); - - $fp = fopen('php://memory', 'w+b'); - fwrite($fp, $chars); - unset($chars); - fseek($fp, 0, SEEK_SET); - - $buffer = [0]; - $buf_pos = 1; - $buf_len = 1; - $has_datas = true; - do { - $bytes = []; - // Buffer Filing - if ($buf_len - $buf_pos < $startLength) { - $buf = array_splice($buffer, $buf_pos); - $new = $this->reloadBuffer($fp, 100); - if ($new) { - $buffer = array_merge($buf, $new); - $buf_len = \count($buffer); - $buf_pos = 0; - } else { - $has_datas = false; - } - } - if ($buf_len - $buf_pos > 0) { - $size = 0; - for ($i = 0; $i < $startLength && isset($buffer[$buf_pos]); ++$i) { - ++$size; - $bytes[] = $buffer[$buf_pos++]; - } - $need = $this->charReader->validateByteSequence( - $bytes, $size); - if ($need > 0) { - if ($buf_len - $buf_pos < $need) { - $new = $this->reloadBuffer($fp, $need); - - if ($new) { - $buffer = array_merge($buffer, $new); - $buf_len = \count($buffer); - } - } - for ($i = 0; $i < $need && isset($buffer[$buf_pos]); ++$i) { - $bytes[] = $buffer[$buf_pos++]; - } - } - $this->array[] = $bytes; - ++$this->array_size; - } - } while ($has_datas); - - fclose($fp); - } - - /** - * Move the internal pointer to $charOffset in the stream. - * - * @param int $charOffset - */ - public function setPointer($charOffset) - { - if ($charOffset > $this->array_size) { - $charOffset = $this->array_size; - } elseif ($charOffset < 0) { - $charOffset = 0; - } - $this->offset = $charOffset; - } - - /** - * Empty the stream and reset the internal pointer. - */ - public function flushContents() - { - $this->offset = 0; - $this->array = []; - $this->array_size = 0; - } - - private function reloadBuffer($fp, $len) - { - if (!feof($fp) && false !== ($bytes = fread($fp, $len))) { - $buf = []; - for ($i = 0, $len = \strlen($bytes); $i < $len; ++$i) { - $buf[] = self::$byteMap[$bytes[$i]]; - } - - return $buf; - } - - return false; - } - - private static function initializeMaps() - { - if (!isset(self::$charMap)) { - self::$charMap = []; - for ($byte = 0; $byte < 256; ++$byte) { - self::$charMap[$byte] = \chr($byte); - } - self::$byteMap = array_flip(self::$charMap); - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php deleted file mode 100644 index 7578dda..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php +++ /dev/null @@ -1,262 +0,0 @@ - - */ -class Swift_CharacterStream_NgCharacterStream implements Swift_CharacterStream -{ - /** - * The char reader (lazy-loaded) for the current charset. - * - * @var Swift_CharacterReader - */ - private $charReader; - - /** - * A factory for creating CharacterReader instances. - * - * @var Swift_CharacterReaderFactory - */ - private $charReaderFactory; - - /** - * The character set this stream is using. - * - * @var string - */ - private $charset; - - /** - * The data's stored as-is. - * - * @var string - */ - private $datas = ''; - - /** - * Number of bytes in the stream. - * - * @var int - */ - private $datasSize = 0; - - /** - * Map. - * - * @var mixed - */ - private $map; - - /** - * Map Type. - * - * @var int - */ - private $mapType = 0; - - /** - * Number of characters in the stream. - * - * @var int - */ - private $charCount = 0; - - /** - * Position in the stream. - * - * @var int - */ - private $currentPos = 0; - - /** - * Constructor. - * - * @param string $charset - */ - public function __construct(Swift_CharacterReaderFactory $factory, $charset) - { - $this->setCharacterReaderFactory($factory); - $this->setCharacterSet($charset); - } - - /* -- Changing parameters of the stream -- */ - - /** - * Set the character set used in this CharacterStream. - * - * @param string $charset - */ - public function setCharacterSet($charset) - { - $this->charset = $charset; - $this->charReader = null; - $this->mapType = 0; - } - - /** - * Set the CharacterReaderFactory for multi charset support. - */ - public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory) - { - $this->charReaderFactory = $factory; - } - - /** - * @see Swift_CharacterStream::flushContents() - */ - public function flushContents() - { - $this->datas = null; - $this->map = null; - $this->charCount = 0; - $this->currentPos = 0; - $this->datasSize = 0; - } - - /** - * @see Swift_CharacterStream::importByteStream() - */ - public function importByteStream(Swift_OutputByteStream $os) - { - $this->flushContents(); - $blocks = 512; - $os->setReadPointer(0); - while (false !== ($read = $os->read($blocks))) { - $this->write($read); - } - } - - /** - * @see Swift_CharacterStream::importString() - * - * @param string $string - */ - public function importString($string) - { - $this->flushContents(); - $this->write($string); - } - - /** - * @see Swift_CharacterStream::read() - * - * @param int $length - * - * @return string - */ - public function read($length) - { - if ($this->currentPos >= $this->charCount) { - return false; - } - $ret = false; - $length = ($this->currentPos + $length > $this->charCount) ? $this->charCount - $this->currentPos : $length; - switch ($this->mapType) { - case Swift_CharacterReader::MAP_TYPE_FIXED_LEN: - $len = $length * $this->map; - $ret = substr($this->datas, - $this->currentPos * $this->map, - $len); - $this->currentPos += $length; - break; - - case Swift_CharacterReader::MAP_TYPE_INVALID: - $ret = ''; - for (; $this->currentPos < $length; ++$this->currentPos) { - if (isset($this->map[$this->currentPos])) { - $ret .= '?'; - } else { - $ret .= $this->datas[$this->currentPos]; - } - } - break; - - case Swift_CharacterReader::MAP_TYPE_POSITIONS: - $end = $this->currentPos + $length; - $end = $end > $this->charCount ? $this->charCount : $end; - $ret = ''; - $start = 0; - if ($this->currentPos > 0) { - $start = $this->map['p'][$this->currentPos - 1]; - } - $to = $start; - for (; $this->currentPos < $end; ++$this->currentPos) { - if (isset($this->map['i'][$this->currentPos])) { - $ret .= substr($this->datas, $start, $to - $start).'?'; - $start = $this->map['p'][$this->currentPos]; - } else { - $to = $this->map['p'][$this->currentPos]; - } - } - $ret .= substr($this->datas, $start, $to - $start); - break; - } - - return $ret; - } - - /** - * @see Swift_CharacterStream::readBytes() - * - * @param int $length - * - * @return int[] - */ - public function readBytes($length) - { - $read = $this->read($length); - if (false !== $read) { - $ret = array_map('ord', str_split($read, 1)); - - return $ret; - } - - return false; - } - - /** - * @see Swift_CharacterStream::setPointer() - * - * @param int $charOffset - */ - public function setPointer($charOffset) - { - if ($this->charCount < $charOffset) { - $charOffset = $this->charCount; - } - $this->currentPos = $charOffset; - } - - /** - * @see Swift_CharacterStream::write() - * - * @param string $chars - */ - public function write($chars) - { - if (!isset($this->charReader)) { - $this->charReader = $this->charReaderFactory->getReaderFor( - $this->charset); - $this->map = []; - $this->mapType = $this->charReader->getMapType(); - } - $ignored = ''; - $this->datas .= $chars; - $this->charCount += $this->charReader->getCharPositions(substr($this->datas, $this->datasSize), $this->datasSize, $this->map, $ignored); - if (false !== $ignored) { - $this->datasSize = \strlen($this->datas) - \strlen($ignored); - } else { - $this->datasSize = \strlen($this->datas); - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ConfigurableSpool.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ConfigurableSpool.php deleted file mode 100644 index a711bac..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ConfigurableSpool.php +++ /dev/null @@ -1,63 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Base class for Spools (implements time and message limits). - * - * @author Fabien Potencier - */ -abstract class Swift_ConfigurableSpool implements Swift_Spool -{ - /** The maximum number of messages to send per flush */ - private $message_limit; - - /** The time limit per flush */ - private $time_limit; - - /** - * Sets the maximum number of messages to send per flush. - * - * @param int $limit - */ - public function setMessageLimit($limit) - { - $this->message_limit = (int) $limit; - } - - /** - * Gets the maximum number of messages to send per flush. - * - * @return int The limit - */ - public function getMessageLimit() - { - return $this->message_limit; - } - - /** - * Sets the time limit (in seconds) per flush. - * - * @param int $limit The limit - */ - public function setTimeLimit($limit) - { - $this->time_limit = (int) $limit; - } - - /** - * Gets the time limit (in seconds) per flush. - * - * @return int The limit - */ - public function getTimeLimit() - { - return $this->time_limit; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php deleted file mode 100644 index 3cc885e..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php +++ /dev/null @@ -1,387 +0,0 @@ -store); - } - - /** - * Test if an item is registered in this container with the given name. - * - * @see register() - * - * @param string $itemName - * - * @return bool - */ - public function has($itemName) - { - return \array_key_exists($itemName, $this->store) - && isset($this->store[$itemName]['lookupType']); - } - - /** - * Lookup the item with the given $itemName. - * - * @see register() - * - * @param string $itemName - * - * @return mixed - * - * @throws Swift_DependencyException If the dependency is not found - */ - public function lookup($itemName) - { - if (!$this->has($itemName)) { - throw new Swift_DependencyException('Cannot lookup dependency "'.$itemName.'" since it is not registered.'); - } - - switch ($this->store[$itemName]['lookupType']) { - case self::TYPE_ALIAS: - return $this->createAlias($itemName); - case self::TYPE_VALUE: - return $this->getValue($itemName); - case self::TYPE_INSTANCE: - return $this->createNewInstance($itemName); - case self::TYPE_SHARED: - return $this->createSharedInstance($itemName); - case self::TYPE_ARRAY: - return $this->createDependenciesFor($itemName); - } - } - - /** - * Create an array of arguments passed to the constructor of $itemName. - * - * @param string $itemName - * - * @return array - */ - public function createDependenciesFor($itemName) - { - $args = []; - if (isset($this->store[$itemName]['args'])) { - $args = $this->resolveArgs($this->store[$itemName]['args']); - } - - return $args; - } - - /** - * Register a new dependency with $itemName. - * - * This method returns the current DependencyContainer instance because it - * requires the use of the fluid interface to set the specific details for the - * dependency. - * - * @see asNewInstanceOf(), asSharedInstanceOf(), asValue() - * - * @param string $itemName - * - * @return $this - */ - public function register($itemName) - { - $this->store[$itemName] = []; - $this->endPoint = &$this->store[$itemName]; - - return $this; - } - - /** - * Specify the previously registered item as a literal value. - * - * {@link register()} must be called before this will work. - * - * @param mixed $value - * - * @return $this - */ - public function asValue($value) - { - $endPoint = &$this->getEndPoint(); - $endPoint['lookupType'] = self::TYPE_VALUE; - $endPoint['value'] = $value; - - return $this; - } - - /** - * Specify the previously registered item as an alias of another item. - * - * @param string $lookup - * - * @return $this - */ - public function asAliasOf($lookup) - { - $endPoint = &$this->getEndPoint(); - $endPoint['lookupType'] = self::TYPE_ALIAS; - $endPoint['ref'] = $lookup; - - return $this; - } - - /** - * Specify the previously registered item as a new instance of $className. - * - * {@link register()} must be called before this will work. - * Any arguments can be set with {@link withDependencies()}, - * {@link addConstructorValue()} or {@link addConstructorLookup()}. - * - * @see withDependencies(), addConstructorValue(), addConstructorLookup() - * - * @param string $className - * - * @return $this - */ - public function asNewInstanceOf($className) - { - $endPoint = &$this->getEndPoint(); - $endPoint['lookupType'] = self::TYPE_INSTANCE; - $endPoint['className'] = $className; - - return $this; - } - - /** - * Specify the previously registered item as a shared instance of $className. - * - * {@link register()} must be called before this will work. - * - * @param string $className - * - * @return $this - */ - public function asSharedInstanceOf($className) - { - $endPoint = &$this->getEndPoint(); - $endPoint['lookupType'] = self::TYPE_SHARED; - $endPoint['className'] = $className; - - return $this; - } - - /** - * Specify the previously registered item as array of dependencies. - * - * {@link register()} must be called before this will work. - * - * @return $this - */ - public function asArray() - { - $endPoint = &$this->getEndPoint(); - $endPoint['lookupType'] = self::TYPE_ARRAY; - - return $this; - } - - /** - * Specify a list of injected dependencies for the previously registered item. - * - * This method takes an array of lookup names. - * - * @see addConstructorValue(), addConstructorLookup() - * - * @return $this - */ - public function withDependencies(array $lookups) - { - $endPoint = &$this->getEndPoint(); - $endPoint['args'] = []; - foreach ($lookups as $lookup) { - $this->addConstructorLookup($lookup); - } - - return $this; - } - - /** - * Specify a literal (non looked up) value for the constructor of the - * previously registered item. - * - * @see withDependencies(), addConstructorLookup() - * - * @param mixed $value - * - * @return $this - */ - public function addConstructorValue($value) - { - $endPoint = &$this->getEndPoint(); - if (!isset($endPoint['args'])) { - $endPoint['args'] = []; - } - $endPoint['args'][] = ['type' => 'value', 'item' => $value]; - - return $this; - } - - /** - * Specify a dependency lookup for the constructor of the previously - * registered item. - * - * @see withDependencies(), addConstructorValue() - * - * @param string $lookup - * - * @return $this - */ - public function addConstructorLookup($lookup) - { - $endPoint = &$this->getEndPoint(); - if (!isset($this->endPoint['args'])) { - $endPoint['args'] = []; - } - $endPoint['args'][] = ['type' => 'lookup', 'item' => $lookup]; - - return $this; - } - - /** Get the literal value with $itemName */ - private function getValue($itemName) - { - return $this->store[$itemName]['value']; - } - - /** Resolve an alias to another item */ - private function createAlias($itemName) - { - return $this->lookup($this->store[$itemName]['ref']); - } - - /** Create a fresh instance of $itemName */ - private function createNewInstance($itemName) - { - $reflector = new ReflectionClass($this->store[$itemName]['className']); - if ($reflector->getConstructor()) { - return $reflector->newInstanceArgs( - $this->createDependenciesFor($itemName) - ); - } - - return $reflector->newInstance(); - } - - /** Create and register a shared instance of $itemName */ - private function createSharedInstance($itemName) - { - if (!isset($this->store[$itemName]['instance'])) { - $this->store[$itemName]['instance'] = $this->createNewInstance($itemName); - } - - return $this->store[$itemName]['instance']; - } - - /** Get the current endpoint in the store */ - private function &getEndPoint() - { - if (!isset($this->endPoint)) { - throw new BadMethodCallException('Component must first be registered by calling register()'); - } - - return $this->endPoint; - } - - /** Get an argument list with dependencies resolved */ - private function resolveArgs(array $args) - { - $resolved = []; - foreach ($args as $argDefinition) { - switch ($argDefinition['type']) { - case 'lookup': - $resolved[] = $this->lookupRecursive($argDefinition['item']); - break; - case 'value': - $resolved[] = $argDefinition['item']; - break; - } - } - - return $resolved; - } - - /** Resolve a single dependency with an collections */ - private function lookupRecursive($item) - { - if (\is_array($item)) { - $collection = []; - foreach ($item as $k => $v) { - $collection[$k] = $this->lookupRecursive($v); - } - - return $collection; - } - - return $this->lookup($item); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyException.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyException.php deleted file mode 100644 index 799d38d..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyException.php +++ /dev/null @@ -1,27 +0,0 @@ -createDependenciesFor('mime.embeddedfile') - ); - - $this->setBody($data); - $this->setFilename($filename); - if ($contentType) { - $this->setContentType($contentType); - } - } - - /** - * Create a new EmbeddedFile from a filesystem path. - * - * @param string $path - * - * @return Swift_Mime_EmbeddedFile - */ - public static function fromPath($path) - { - return (new self())->setFile(new Swift_ByteStream_FileByteStream($path)); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder.php deleted file mode 100644 index 2073abc..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder.php +++ /dev/null @@ -1,28 +0,0 @@ -= $maxLineLength || 76 < $maxLineLength) { - $maxLineLength = 76; - } - - $encodedString = base64_encode($string ?? ''); - $firstLine = ''; - - if (0 != $firstLineOffset) { - $firstLine = substr( - $encodedString, 0, $maxLineLength - $firstLineOffset - )."\r\n"; - $encodedString = substr( - $encodedString, $maxLineLength - $firstLineOffset - ); - } - - return $firstLine.trim(chunk_split($encodedString, $maxLineLength, "\r\n")); - } - - /** - * Does nothing. - */ - public function charsetChanged($charset) - { - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php deleted file mode 100644 index 7eac368..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php +++ /dev/null @@ -1,90 +0,0 @@ -charStream = $charStream; - } - - /** - * Takes an unencoded string and produces a string encoded according to - * RFC 2231 from it. - * - * @param string $string - * @param int $firstLineOffset - * @param int $maxLineLength optional, 0 indicates the default of 75 bytes - * - * @return string - */ - public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) - { - $lines = []; - $lineCount = 0; - $lines[] = ''; - $currentLine = &$lines[$lineCount++]; - - if (0 >= $maxLineLength) { - $maxLineLength = 75; - } - - $this->charStream->flushContents(); - $this->charStream->importString($string); - - $thisLineLength = $maxLineLength - $firstLineOffset; - - while (false !== $char = $this->charStream->read(4)) { - $encodedChar = rawurlencode($char); - if (0 != \strlen($currentLine) - && \strlen($currentLine.$encodedChar) > $thisLineLength) { - $lines[] = ''; - $currentLine = &$lines[$lineCount++]; - $thisLineLength = $maxLineLength; - } - $currentLine .= $encodedChar; - } - - return implode("\r\n", $lines); - } - - /** - * Updates the charset used. - * - * @param string $charset - */ - public function charsetChanged($charset) - { - $this->charStream->setCharacterSet($charset); - } - - /** - * Make a deep copy of object. - */ - public function __clone() - { - $this->charStream = clone $this->charStream; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandEvent.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandEvent.php deleted file mode 100644 index 18994c1..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandEvent.php +++ /dev/null @@ -1,64 +0,0 @@ -command = $command; - $this->successCodes = $successCodes; - } - - /** - * Get the command which was sent to the server. - * - * @return string - */ - public function getCommand() - { - return $this->command; - } - - /** - * Get the numeric response codes which indicate success for this command. - * - * @return int[] - */ - public function getSuccessCodes() - { - return $this->successCodes; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandListener.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandListener.php deleted file mode 100644 index b158eab..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandListener.php +++ /dev/null @@ -1,22 +0,0 @@ -source = $source; - } - - /** - * Get the source object of this event. - * - * @return object - */ - public function getSource() - { - return $this->source; - } - - /** - * Prevent this Event from bubbling any further up the stack. - */ - public function cancelBubble($cancel = true) - { - $this->bubbleCancelled = $cancel; - } - - /** - * Returns true if this Event will not bubble any further up the stack. - * - * @return bool - */ - public function bubbleCancelled() - { - return $this->bubbleCancelled; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php deleted file mode 100644 index ff7c371..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php +++ /dev/null @@ -1,64 +0,0 @@ -response = $response; - $this->valid = $valid; - } - - /** - * Get the response which was received from the server. - * - * @return string - */ - public function getResponse() - { - return $this->response; - } - - /** - * Get the success status of this Event. - * - * @return bool - */ - public function isValid() - { - return $this->valid; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseListener.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseListener.php deleted file mode 100644 index 85115a3..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseListener.php +++ /dev/null @@ -1,22 +0,0 @@ -message = $message; - $this->result = self::RESULT_PENDING; - } - - /** - * Get the Transport used to send the Message. - * - * @return Swift_Transport - */ - public function getTransport() - { - return $this->getSource(); - } - - /** - * Get the Message being sent. - * - * @return Swift_Mime_SimpleMessage - */ - public function getMessage() - { - return $this->message; - } - - /** - * Set the array of addresses that failed in sending. - * - * @param array $recipients - */ - public function setFailedRecipients($recipients) - { - $this->failedRecipients = $recipients; - } - - /** - * Get an recipient addresses which were not accepted for delivery. - * - * @return string[] - */ - public function getFailedRecipients() - { - return $this->failedRecipients; - } - - /** - * Set the result of sending. - * - * @param int $result - */ - public function setResult($result) - { - $this->result = $result; - } - - /** - * Get the result of this Event. - * - * The return value is a bitmask from - * {@see RESULT_PENDING, RESULT_SUCCESS, RESULT_TENTATIVE, RESULT_FAILED} - * - * @return int - */ - public function getResult() - { - return $this->result; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendListener.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendListener.php deleted file mode 100644 index f7bf55e..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendListener.php +++ /dev/null @@ -1,27 +0,0 @@ -eventMap = [ - 'Swift_Events_CommandEvent' => 'Swift_Events_CommandListener', - 'Swift_Events_ResponseEvent' => 'Swift_Events_ResponseListener', - 'Swift_Events_SendEvent' => 'Swift_Events_SendListener', - 'Swift_Events_TransportChangeEvent' => 'Swift_Events_TransportChangeListener', - 'Swift_Events_TransportExceptionEvent' => 'Swift_Events_TransportExceptionListener', - ]; - } - - /** - * Create a new SendEvent for $source and $message. - * - * @return Swift_Events_SendEvent - */ - public function createSendEvent(Swift_Transport $source, Swift_Mime_SimpleMessage $message) - { - return new Swift_Events_SendEvent($source, $message); - } - - /** - * Create a new CommandEvent for $source and $command. - * - * @param string $command That will be executed - * @param array $successCodes That are needed - * - * @return Swift_Events_CommandEvent - */ - public function createCommandEvent(Swift_Transport $source, $command, $successCodes = []) - { - return new Swift_Events_CommandEvent($source, $command, $successCodes); - } - - /** - * Create a new ResponseEvent for $source and $response. - * - * @param string $response - * @param bool $valid If the response is valid - * - * @return Swift_Events_ResponseEvent - */ - public function createResponseEvent(Swift_Transport $source, $response, $valid) - { - return new Swift_Events_ResponseEvent($source, $response, $valid); - } - - /** - * Create a new TransportChangeEvent for $source. - * - * @return Swift_Events_TransportChangeEvent - */ - public function createTransportChangeEvent(Swift_Transport $source) - { - return new Swift_Events_TransportChangeEvent($source); - } - - /** - * Create a new TransportExceptionEvent for $source. - * - * @return Swift_Events_TransportExceptionEvent - */ - public function createTransportExceptionEvent(Swift_Transport $source, Swift_TransportException $ex) - { - return new Swift_Events_TransportExceptionEvent($source, $ex); - } - - /** - * Bind an event listener to this dispatcher. - */ - public function bindEventListener(Swift_Events_EventListener $listener) - { - foreach ($this->listeners as $l) { - // Already loaded - if ($l === $listener) { - return; - } - } - $this->listeners[] = $listener; - } - - /** - * Dispatch the given Event to all suitable listeners. - * - * @param string $target method - */ - public function dispatchEvent(Swift_Events_EventObject $evt, $target) - { - $bubbleQueue = $this->prepareBubbleQueue($evt); - $this->bubble($bubbleQueue, $evt, $target); - } - - /** Queue listeners on a stack ready for $evt to be bubbled up it */ - private function prepareBubbleQueue(Swift_Events_EventObject $evt) - { - $bubbleQueue = []; - $evtClass = \get_class($evt); - foreach ($this->listeners as $listener) { - if (\array_key_exists($evtClass, $this->eventMap) - && ($listener instanceof $this->eventMap[$evtClass])) { - $bubbleQueue[] = $listener; - } - } - - return $bubbleQueue; - } - - /** Bubble $evt up the stack calling $target() on each listener */ - private function bubble(array &$bubbleQueue, Swift_Events_EventObject $evt, $target) - { - if (!$evt->bubbleCancelled() && $listener = array_shift($bubbleQueue)) { - $listener->$target($evt); - $this->bubble($bubbleQueue, $evt, $target); - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php deleted file mode 100644 index a8972fd..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php +++ /dev/null @@ -1,27 +0,0 @@ -getSource(); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php deleted file mode 100644 index 4a7492b..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php +++ /dev/null @@ -1,37 +0,0 @@ -exception = $ex; - } - - /** - * Get the TransportException thrown. - * - * @return Swift_TransportException - */ - public function getException() - { - return $this->exception; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php deleted file mode 100644 index ad80eb0..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php +++ /dev/null @@ -1,22 +0,0 @@ -createDependenciesFor('transport.failover') - ); - - $this->setTransports($transports); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileSpool.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileSpool.php deleted file mode 100644 index 7af8471..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileSpool.php +++ /dev/null @@ -1,208 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Stores Messages on the filesystem. - * - * @author Fabien Potencier - * @author Xavier De Cock - */ -class Swift_FileSpool extends Swift_ConfigurableSpool -{ - /** The spool directory */ - private $path; - - /** - * File WriteRetry Limit. - * - * @var int - */ - private $retryLimit = 10; - - /** - * Create a new FileSpool. - * - * @param string $path - * - * @throws Swift_IoException - */ - public function __construct($path) - { - $this->path = $path; - - if (!file_exists($this->path)) { - if (!mkdir($this->path, 0777, true)) { - throw new Swift_IoException(sprintf('Unable to create path "%s".', $this->path)); - } - } - } - - /** - * Tests if this Spool mechanism has started. - * - * @return bool - */ - public function isStarted() - { - return true; - } - - /** - * Starts this Spool mechanism. - */ - public function start() - { - } - - /** - * Stops this Spool mechanism. - */ - public function stop() - { - } - - /** - * Allow to manage the enqueuing retry limit. - * - * Default, is ten and allows over 64^20 different fileNames - * - * @param int $limit - */ - public function setRetryLimit($limit) - { - $this->retryLimit = $limit; - } - - /** - * Queues a message. - * - * @param Swift_Mime_SimpleMessage $message The message to store - * - * @throws Swift_IoException - * - * @return bool - */ - public function queueMessage(Swift_Mime_SimpleMessage $message) - { - $ser = serialize($message); - $fileName = $this->path.'/'.$this->getRandomString(10); - for ($i = 0; $i < $this->retryLimit; ++$i) { - /* We try an exclusive creation of the file. This is an atomic operation, it avoid locking mechanism */ - $fp = @fopen($fileName.'.message', 'xb'); - if (false !== $fp) { - if (false === fwrite($fp, $ser)) { - return false; - } - - return fclose($fp); - } else { - /* The file already exists, we try a longer fileName */ - $fileName .= $this->getRandomString(1); - } - } - - throw new Swift_IoException(sprintf('Unable to create a file for enqueuing Message in "%s".', $this->path)); - } - - /** - * Execute a recovery if for any reason a process is sending for too long. - * - * @param int $timeout in second Defaults is for very slow smtp responses - */ - public function recover($timeout = 900) - { - foreach (new DirectoryIterator($this->path) as $file) { - $file = $file->getRealPath(); - - if ('.message.sending' == substr($file, -16)) { - $lockedtime = filectime($file); - if ((time() - $lockedtime) > $timeout) { - rename($file, substr($file, 0, -8)); - } - } - } - } - - /** - * Sends messages using the given transport instance. - * - * @param Swift_Transport $transport A transport instance - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int The number of sent e-mail's - */ - public function flushQueue(Swift_Transport $transport, &$failedRecipients = null) - { - $directoryIterator = new DirectoryIterator($this->path); - - /* Start the transport only if there are queued files to send */ - if (!$transport->isStarted()) { - foreach ($directoryIterator as $file) { - if ('.message' == substr($file->getRealPath(), -8)) { - $transport->start(); - break; - } - } - } - - $failedRecipients = (array) $failedRecipients; - $count = 0; - $time = time(); - foreach ($directoryIterator as $file) { - $file = $file->getRealPath(); - - if ('.message' != substr($file, -8)) { - continue; - } - - /* We try a rename, it's an atomic operation, and avoid locking the file */ - if (rename($file, $file.'.sending')) { - $message = unserialize(file_get_contents($file.'.sending')); - - $count += $transport->send($message, $failedRecipients); - - unlink($file.'.sending'); - } else { - /* This message has just been catched by another process */ - continue; - } - - if ($this->getMessageLimit() && $count >= $this->getMessageLimit()) { - break; - } - - if ($this->getTimeLimit() && (time() - $time) >= $this->getTimeLimit()) { - break; - } - } - - return $count; - } - - /** - * Returns a random string needed to generate a fileName for the queue. - * - * @param int $count - * - * @return string - */ - protected function getRandomString($count) - { - // This string MUST stay FS safe, avoid special chars - $base = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-'; - $ret = ''; - $strlen = \strlen($base); - for ($i = 0; $i < $count; ++$i) { - $ret .= $base[random_int(0, $strlen - 1)]; - } - - return $ret; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileStream.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileStream.php deleted file mode 100644 index 0b24db1..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileStream.php +++ /dev/null @@ -1,24 +0,0 @@ -setFile(new Swift_ByteStream_FileByteStream($path)); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/InputByteStream.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/InputByteStream.php deleted file mode 100644 index 379a5a1..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/InputByteStream.php +++ /dev/null @@ -1,75 +0,0 @@ -stream = $stream; - } - - /** - * Set a string into the cache under $itemKey for the namespace $nsKey. - * - * @see MODE_WRITE, MODE_APPEND - * - * @param string $nsKey - * @param string $itemKey - * @param string $string - * @param int $mode - */ - public function setString($nsKey, $itemKey, $string, $mode) - { - $this->prepareCache($nsKey); - switch ($mode) { - case self::MODE_WRITE: - $this->contents[$nsKey][$itemKey] = $string; - break; - case self::MODE_APPEND: - if (!$this->hasKey($nsKey, $itemKey)) { - $this->contents[$nsKey][$itemKey] = ''; - } - $this->contents[$nsKey][$itemKey] .= $string; - break; - default: - throw new Swift_SwiftException('Invalid mode ['.$mode.'] used to set nsKey='.$nsKey.', itemKey='.$itemKey); - } - } - - /** - * Set a ByteStream into the cache under $itemKey for the namespace $nsKey. - * - * @see MODE_WRITE, MODE_APPEND - * - * @param string $nsKey - * @param string $itemKey - * @param int $mode - */ - public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode) - { - $this->prepareCache($nsKey); - switch ($mode) { - case self::MODE_WRITE: - $this->clearKey($nsKey, $itemKey); - // no break - case self::MODE_APPEND: - if (!$this->hasKey($nsKey, $itemKey)) { - $this->contents[$nsKey][$itemKey] = ''; - } - while (false !== $bytes = $os->read(8192)) { - $this->contents[$nsKey][$itemKey] .= $bytes; - } - break; - default: - throw new Swift_SwiftException('Invalid mode ['.$mode.'] used to set nsKey='.$nsKey.', itemKey='.$itemKey); - } - } - - /** - * Provides a ByteStream which when written to, writes data to $itemKey. - * - * NOTE: The stream will always write in append mode. - * - * @param string $nsKey - * @param string $itemKey - * - * @return Swift_InputByteStream - */ - public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) - { - $is = clone $this->stream; - $is->setKeyCache($this); - $is->setNsKey($nsKey); - $is->setItemKey($itemKey); - if (isset($writeThrough)) { - $is->setWriteThroughStream($writeThrough); - } - - return $is; - } - - /** - * Get data back out of the cache as a string. - * - * @param string $nsKey - * @param string $itemKey - * - * @return string - */ - public function getString($nsKey, $itemKey) - { - $this->prepareCache($nsKey); - if ($this->hasKey($nsKey, $itemKey)) { - return $this->contents[$nsKey][$itemKey]; - } - } - - /** - * Get data back out of the cache as a ByteStream. - * - * @param string $nsKey - * @param string $itemKey - * @param Swift_InputByteStream $is to write the data to - */ - public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is) - { - $this->prepareCache($nsKey); - $is->write($this->getString($nsKey, $itemKey)); - } - - /** - * Check if the given $itemKey exists in the namespace $nsKey. - * - * @param string $nsKey - * @param string $itemKey - * - * @return bool - */ - public function hasKey($nsKey, $itemKey) - { - $this->prepareCache($nsKey); - - return \array_key_exists($itemKey, $this->contents[$nsKey]); - } - - /** - * Clear data for $itemKey in the namespace $nsKey if it exists. - * - * @param string $nsKey - * @param string $itemKey - */ - public function clearKey($nsKey, $itemKey) - { - unset($this->contents[$nsKey][$itemKey]); - } - - /** - * Clear all data in the namespace $nsKey if it exists. - * - * @param string $nsKey - */ - public function clearAll($nsKey) - { - unset($this->contents[$nsKey]); - } - - /** - * Initialize the namespace of $nsKey if needed. - * - * @param string $nsKey - */ - private function prepareCache($nsKey) - { - if (!\array_key_exists($nsKey, $this->contents)) { - $this->contents[$nsKey] = []; - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php deleted file mode 100644 index 33b6367..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php +++ /dev/null @@ -1,294 +0,0 @@ -stream = $stream; - $this->path = $path; - } - - /** - * Set a string into the cache under $itemKey for the namespace $nsKey. - * - * @see MODE_WRITE, MODE_APPEND - * - * @param string $nsKey - * @param string $itemKey - * @param string $string - * @param int $mode - * - * @throws Swift_IoException - */ - public function setString($nsKey, $itemKey, $string, $mode) - { - $this->prepareCache($nsKey); - switch ($mode) { - case self::MODE_WRITE: - $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_START); - break; - case self::MODE_APPEND: - $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_END); - break; - default: - throw new Swift_SwiftException('Invalid mode ['.$mode.'] used to set nsKey='.$nsKey.', itemKey='.$itemKey); - break; - } - fwrite($fp, $string); - $this->freeHandle($nsKey, $itemKey); - } - - /** - * Set a ByteStream into the cache under $itemKey for the namespace $nsKey. - * - * @see MODE_WRITE, MODE_APPEND - * - * @param string $nsKey - * @param string $itemKey - * @param int $mode - * - * @throws Swift_IoException - */ - public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode) - { - $this->prepareCache($nsKey); - switch ($mode) { - case self::MODE_WRITE: - $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_START); - break; - case self::MODE_APPEND: - $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_END); - break; - default: - throw new Swift_SwiftException('Invalid mode ['.$mode.'] used to set nsKey='.$nsKey.', itemKey='.$itemKey); - break; - } - while (false !== $bytes = $os->read(8192)) { - fwrite($fp, $bytes); - } - $this->freeHandle($nsKey, $itemKey); - } - - /** - * Provides a ByteStream which when written to, writes data to $itemKey. - * - * NOTE: The stream will always write in append mode. - * - * @param string $nsKey - * @param string $itemKey - * - * @return Swift_InputByteStream - */ - public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) - { - $is = clone $this->stream; - $is->setKeyCache($this); - $is->setNsKey($nsKey); - $is->setItemKey($itemKey); - if (isset($writeThrough)) { - $is->setWriteThroughStream($writeThrough); - } - - return $is; - } - - /** - * Get data back out of the cache as a string. - * - * @param string $nsKey - * @param string $itemKey - * - * @throws Swift_IoException - * - * @return string - */ - public function getString($nsKey, $itemKey) - { - $this->prepareCache($nsKey); - if ($this->hasKey($nsKey, $itemKey)) { - $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_START); - $str = ''; - while (!feof($fp) && false !== $bytes = fread($fp, 8192)) { - $str .= $bytes; - } - $this->freeHandle($nsKey, $itemKey); - - return $str; - } - } - - /** - * Get data back out of the cache as a ByteStream. - * - * @param string $nsKey - * @param string $itemKey - * @param Swift_InputByteStream $is to write the data to - */ - public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is) - { - if ($this->hasKey($nsKey, $itemKey)) { - $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_START); - while (!feof($fp) && false !== $bytes = fread($fp, 8192)) { - $is->write($bytes); - } - $this->freeHandle($nsKey, $itemKey); - } - } - - /** - * Check if the given $itemKey exists in the namespace $nsKey. - * - * @param string $nsKey - * @param string $itemKey - * - * @return bool - */ - public function hasKey($nsKey, $itemKey) - { - return is_file($this->path.'/'.$nsKey.'/'.$itemKey); - } - - /** - * Clear data for $itemKey in the namespace $nsKey if it exists. - * - * @param string $nsKey - * @param string $itemKey - */ - public function clearKey($nsKey, $itemKey) - { - if ($this->hasKey($nsKey, $itemKey)) { - $this->freeHandle($nsKey, $itemKey); - unlink($this->path.'/'.$nsKey.'/'.$itemKey); - } - } - - /** - * Clear all data in the namespace $nsKey if it exists. - * - * @param string $nsKey - */ - public function clearAll($nsKey) - { - if (\array_key_exists($nsKey, $this->keys)) { - foreach ($this->keys[$nsKey] as $itemKey => $null) { - $this->clearKey($nsKey, $itemKey); - } - if (is_dir($this->path.'/'.$nsKey)) { - rmdir($this->path.'/'.$nsKey); - } - unset($this->keys[$nsKey]); - } - } - - /** - * Initialize the namespace of $nsKey if needed. - * - * @param string $nsKey - */ - private function prepareCache($nsKey) - { - $cacheDir = $this->path.'/'.$nsKey; - if (!is_dir($cacheDir)) { - if (!mkdir($cacheDir)) { - throw new Swift_IoException('Failed to create cache directory '.$cacheDir); - } - $this->keys[$nsKey] = []; - } - } - - /** - * Get a file handle on the cache item. - * - * @param string $nsKey - * @param string $itemKey - * @param int $position - * - * @return resource - */ - private function getHandle($nsKey, $itemKey, $position) - { - if (!isset($this->keys[$nsKey][$itemKey])) { - $openMode = $this->hasKey($nsKey, $itemKey) ? 'r+b' : 'w+b'; - $fp = fopen($this->path.'/'.$nsKey.'/'.$itemKey, $openMode); - $this->keys[$nsKey][$itemKey] = $fp; - } - if (self::POSITION_START == $position) { - fseek($this->keys[$nsKey][$itemKey], 0, SEEK_SET); - } elseif (self::POSITION_END == $position) { - fseek($this->keys[$nsKey][$itemKey], 0, SEEK_END); - } - - return $this->keys[$nsKey][$itemKey]; - } - - private function freeHandle($nsKey, $itemKey) - { - $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_CURRENT); - fclose($fp); - $this->keys[$nsKey][$itemKey] = null; - } - - /** - * Destructor. - */ - public function __destruct() - { - foreach ($this->keys as $nsKey => $null) { - $this->clearAll($nsKey); - } - } - - public function __wakeup() - { - $this->keys = []; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php deleted file mode 100644 index be2dbba..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php +++ /dev/null @@ -1,47 +0,0 @@ -keyCache = $keyCache; - } - - /** - * Specify a stream to write through for each write(). - */ - public function setWriteThroughStream(Swift_InputByteStream $is) - { - $this->writeThrough = $is; - } - - /** - * Writes $bytes to the end of the stream. - * - * @param string $bytes - * @param Swift_InputByteStream $is optional - */ - public function write($bytes, Swift_InputByteStream $is = null) - { - $this->keyCache->setString( - $this->nsKey, $this->itemKey, $bytes, Swift_KeyCache::MODE_APPEND - ); - if (isset($is)) { - $is->write($bytes); - } - if (isset($this->writeThrough)) { - $this->writeThrough->write($bytes); - } - } - - /** - * Not used. - */ - public function commit() - { - } - - /** - * Not used. - */ - public function bind(Swift_InputByteStream $is) - { - } - - /** - * Not used. - */ - public function unbind(Swift_InputByteStream $is) - { - } - - /** - * Flush the contents of the stream (empty it) and set the internal pointer - * to the beginning. - */ - public function flushBuffers() - { - $this->keyCache->clearKey($this->nsKey, $this->itemKey); - } - - /** - * Set the nsKey which will be written to. - * - * @param string $nsKey - */ - public function setNsKey($nsKey) - { - $this->nsKey = $nsKey; - } - - /** - * Set the itemKey which will be written to. - * - * @param string $itemKey - */ - public function setItemKey($itemKey) - { - $this->itemKey = $itemKey; - } - - /** - * Any implementation should be cloneable, allowing the clone to access a - * separate $nsKey and $itemKey. - */ - public function __clone() - { - $this->writeThrough = null; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php deleted file mode 100644 index 244b5f6..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php +++ /dev/null @@ -1,33 +0,0 @@ -createDependenciesFor('transport.loadbalanced') - ); - - $this->setTransports($transports); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php deleted file mode 100644 index 5763007..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php +++ /dev/null @@ -1,98 +0,0 @@ -transport = $transport; - } - - /** - * Create a new class instance of one of the message services. - * - * For example 'mimepart' would create a 'message.mimepart' instance - * - * @param string $service - * - * @return object - */ - public function createMessage($service = 'message') - { - return Swift_DependencyContainer::getInstance() - ->lookup('message.'.$service); - } - - /** - * Send the given Message like it would be sent in a mail client. - * - * All recipients (with the exception of Bcc) will be able to see the other - * recipients this message was sent to. - * - * Recipient/sender data will be retrieved from the Message object. - * - * The return value is the number of recipients who were accepted for - * delivery. - * - * @param array $failedRecipients An array of failures by-reference - * - * @return int The number of successful recipients. Can be 0 which indicates failure - */ - public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) - { - $failedRecipients = (array) $failedRecipients; - - // FIXME: to be removed in 7.0 (as transport must now start itself on send) - if (!$this->transport->isStarted()) { - $this->transport->start(); - } - - $sent = 0; - - try { - $sent = $this->transport->send($message, $failedRecipients); - } catch (Swift_RfcComplianceException $e) { - foreach ($message->getTo() as $address => $name) { - $failedRecipients[] = $address; - } - } - - return $sent; - } - - /** - * Register a plugin using a known unique key (e.g. myPlugin). - */ - public function registerPlugin(Swift_Events_EventListener $plugin) - { - $this->transport->registerPlugin($plugin); - } - - /** - * The Transport used to send messages. - * - * @return Swift_Transport - */ - public function getTransport() - { - return $this->transport; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php deleted file mode 100644 index 19aa82a..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php +++ /dev/null @@ -1,53 +0,0 @@ -recipients = $recipients; - } - - /** - * Returns true only if there are more recipients to send to. - * - * @return bool - */ - public function hasNext() - { - return !empty($this->recipients); - } - - /** - * Returns an array where the keys are the addresses of recipients and the - * values are the names. e.g. ('foo@bar' => 'Foo') or ('foo@bar' => NULL). - * - * @return array - */ - public function nextRecipient() - { - return array_splice($this->recipients, 0, 1); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php deleted file mode 100644 index 650f3ec..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php +++ /dev/null @@ -1,32 +0,0 @@ - 'Foo') or ('foo@bar' => NULL). - * - * @return array - */ - public function nextRecipient(); -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php deleted file mode 100644 index e3b0894..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php +++ /dev/null @@ -1,110 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Stores Messages in memory. - * - * @author Fabien Potencier - */ -class Swift_MemorySpool implements Swift_Spool -{ - protected $messages = []; - private $flushRetries = 3; - - /** - * Tests if this Transport mechanism has started. - * - * @return bool - */ - public function isStarted() - { - return true; - } - - /** - * Starts this Transport mechanism. - */ - public function start() - { - } - - /** - * Stops this Transport mechanism. - */ - public function stop() - { - } - - /** - * @param int $retries - */ - public function setFlushRetries($retries) - { - $this->flushRetries = $retries; - } - - /** - * Stores a message in the queue. - * - * @param Swift_Mime_SimpleMessage $message The message to store - * - * @return bool Whether the operation has succeeded - */ - public function queueMessage(Swift_Mime_SimpleMessage $message) - { - //clone the message to make sure it is not changed while in the queue - $this->messages[] = clone $message; - - return true; - } - - /** - * Sends messages using the given transport instance. - * - * @param Swift_Transport $transport A transport instance - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int The number of sent emails - */ - public function flushQueue(Swift_Transport $transport, &$failedRecipients = null) - { - if (!$this->messages) { - return 0; - } - - if (!$transport->isStarted()) { - $transport->start(); - } - - $count = 0; - $retries = $this->flushRetries; - while ($retries--) { - try { - while ($message = array_pop($this->messages)) { - $count += $transport->send($message, $failedRecipients); - } - } catch (Swift_TransportException $exception) { - if ($retries) { - // re-queue the message at the end of the queue to give a chance - // to the other messages to be sent, in case the failure was due to - // this message and not just the transport failing - array_unshift($this->messages, $message); - - // wait half a second before we try again - usleep(500000); - } else { - throw $exception; - } - } - } - - return $count; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Message.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Message.php deleted file mode 100644 index 5c5834e..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Message.php +++ /dev/null @@ -1,279 +0,0 @@ -createDependenciesFor('mime.message') - ); - - if (!isset($charset)) { - $charset = Swift_DependencyContainer::getInstance() - ->lookup('properties.charset'); - } - $this->setSubject($subject); - $this->setBody($body); - $this->setCharset($charset); - if ($contentType) { - $this->setContentType($contentType); - } - } - - /** - * Add a MimePart to this Message. - * - * @param string|Swift_OutputByteStream $body - * @param string $contentType - * @param string $charset - * - * @return $this - */ - public function addPart($body, $contentType = null, $charset = null) - { - return $this->attach((new Swift_MimePart($body, $contentType, $charset))->setEncoder($this->getEncoder())); - } - - /** - * Attach a new signature handler to the message. - * - * @return $this - */ - public function attachSigner(Swift_Signer $signer) - { - if ($signer instanceof Swift_Signers_HeaderSigner) { - $this->headerSigners[] = $signer; - } elseif ($signer instanceof Swift_Signers_BodySigner) { - $this->bodySigners[] = $signer; - } - - return $this; - } - - /** - * Detach a signature handler from a message. - * - * @return $this - */ - public function detachSigner(Swift_Signer $signer) - { - if ($signer instanceof Swift_Signers_HeaderSigner) { - foreach ($this->headerSigners as $k => $headerSigner) { - if ($headerSigner === $signer) { - unset($this->headerSigners[$k]); - - return $this; - } - } - } elseif ($signer instanceof Swift_Signers_BodySigner) { - foreach ($this->bodySigners as $k => $bodySigner) { - if ($bodySigner === $signer) { - unset($this->bodySigners[$k]); - - return $this; - } - } - } - - return $this; - } - - /** - * Clear all signature handlers attached to the message. - * - * @return $this - */ - public function clearSigners() - { - $this->headerSigners = []; - $this->bodySigners = []; - - return $this; - } - - /** - * Get this message as a complete string. - * - * @return string - */ - public function toString() - { - if (empty($this->headerSigners) && empty($this->bodySigners)) { - return parent::toString(); - } - - $this->saveMessage(); - - $this->doSign(); - - $string = parent::toString(); - - $this->restoreMessage(); - - return $string; - } - - /** - * Write this message to a {@link Swift_InputByteStream}. - */ - public function toByteStream(Swift_InputByteStream $is) - { - if (empty($this->headerSigners) && empty($this->bodySigners)) { - parent::toByteStream($is); - - return; - } - - $this->saveMessage(); - - $this->doSign(); - - parent::toByteStream($is); - - $this->restoreMessage(); - } - - public function __wakeup() - { - Swift_DependencyContainer::getInstance()->createDependenciesFor('mime.message'); - } - - /** - * loops through signers and apply the signatures. - */ - protected function doSign() - { - foreach ($this->bodySigners as $signer) { - $altered = $signer->getAlteredHeaders(); - $this->saveHeaders($altered); - $signer->signMessage($this); - } - - foreach ($this->headerSigners as $signer) { - $altered = $signer->getAlteredHeaders(); - $this->saveHeaders($altered); - $signer->reset(); - - $signer->setHeaders($this->getHeaders()); - - $signer->startBody(); - $this->bodyToByteStream($signer); - $signer->endBody(); - - $signer->addSignature($this->getHeaders()); - } - } - - /** - * save the message before any signature is applied. - */ - protected function saveMessage() - { - $this->savedMessage = ['headers' => []]; - $this->savedMessage['body'] = $this->getBody(); - $this->savedMessage['children'] = $this->getChildren(); - if (\count($this->savedMessage['children']) > 0 && '' != $this->getBody()) { - $this->setChildren(array_merge([$this->becomeMimePart()], $this->savedMessage['children'])); - $this->setBody(''); - } - } - - /** - * save the original headers. - */ - protected function saveHeaders(array $altered) - { - foreach ($altered as $head) { - $lc = strtolower($head ?? ''); - - if (!isset($this->savedMessage['headers'][$lc])) { - $this->savedMessage['headers'][$lc] = $this->getHeaders()->getAll($head); - } - } - } - - /** - * Remove or restore altered headers. - */ - protected function restoreHeaders() - { - foreach ($this->savedMessage['headers'] as $name => $savedValue) { - $headers = $this->getHeaders()->getAll($name); - - foreach ($headers as $key => $value) { - if (!isset($savedValue[$key])) { - $this->getHeaders()->remove($name, $key); - } - } - } - } - - /** - * Restore message body. - */ - protected function restoreMessage() - { - $this->setBody($this->savedMessage['body']); - $this->setChildren($this->savedMessage['children']); - - $this->restoreHeaders(); - $this->savedMessage = []; - } - - /** - * Clone Message Signers. - * - * @see Swift_Mime_SimpleMimeEntity::__clone() - */ - public function __clone() - { - parent::__clone(); - foreach ($this->bodySigners as $key => $bodySigner) { - $this->bodySigners[$key] = clone $bodySigner; - } - - foreach ($this->headerSigners as $key => $headerSigner) { - $this->headerSigners[$key] = clone $headerSigner; - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Attachment.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Attachment.php deleted file mode 100644 index d994373..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Attachment.php +++ /dev/null @@ -1,144 +0,0 @@ -setDisposition('attachment'); - $this->setContentType('application/octet-stream'); - $this->mimeTypes = $mimeTypes; - } - - /** - * Get the nesting level used for this attachment. - * - * Always returns {@link LEVEL_MIXED}. - * - * @return int - */ - public function getNestingLevel() - { - return self::LEVEL_MIXED; - } - - /** - * Get the Content-Disposition of this attachment. - * - * By default attachments have a disposition of "attachment". - * - * @return string - */ - public function getDisposition() - { - return $this->getHeaderFieldModel('Content-Disposition'); - } - - /** - * Set the Content-Disposition of this attachment. - * - * @param string $disposition - * - * @return $this - */ - public function setDisposition($disposition) - { - if (!$this->setHeaderFieldModel('Content-Disposition', $disposition)) { - $this->getHeaders()->addParameterizedHeader('Content-Disposition', $disposition); - } - - return $this; - } - - /** - * Get the filename of this attachment when downloaded. - * - * @return string - */ - public function getFilename() - { - return $this->getHeaderParameter('Content-Disposition', 'filename'); - } - - /** - * Set the filename of this attachment. - * - * @param string $filename - * - * @return $this - */ - public function setFilename($filename) - { - $this->setHeaderParameter('Content-Disposition', 'filename', $filename); - $this->setHeaderParameter('Content-Type', 'name', $filename); - - return $this; - } - - /** - * Get the file size of this attachment. - * - * @return int - */ - public function getSize() - { - return $this->getHeaderParameter('Content-Disposition', 'size'); - } - - /** - * Set the file size of this attachment. - * - * @param int $size - * - * @return $this - */ - public function setSize($size) - { - $this->setHeaderParameter('Content-Disposition', 'size', $size); - - return $this; - } - - /** - * Set the file that this attachment is for. - * - * @param string $contentType optional - * - * @return $this - */ - public function setFile(Swift_FileStream $file, $contentType = null) - { - $this->setFilename(basename($file->getPath())); - $this->setBody($file, $contentType); - if (!isset($contentType)) { - $extension = strtolower(substr($file->getPath(), strrpos($file->getPath(), '.') + 1)); - - if (\array_key_exists($extension, $this->mimeTypes)) { - $this->setContentType($this->mimeTypes[$extension]); - } - } - - return $this; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php deleted file mode 100644 index b49c3a8..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php +++ /dev/null @@ -1,24 +0,0 @@ -= $maxLineLength || 76 < $maxLineLength) { - $maxLineLength = 76; - } - - $remainder = 0; - $base64ReadBufferRemainderBytes = ''; - - // To reduce memory usage, the output buffer is streamed to the input buffer like so: - // Output Stream => base64encode => wrap line length => Input Stream - // HOWEVER it's important to note that base64_encode() should only be passed whole triplets of data (except for the final chunk of data) - // otherwise it will assume the input data has *ended* and it will incorrectly pad/terminate the base64 data mid-stream. - // We use $base64ReadBufferRemainderBytes to carry over 1-2 "remainder" bytes from the each chunk from OutputStream and pre-pend those onto the - // chunk of bytes read in the next iteration. - // When the OutputStream is empty, we must flush any remainder bytes. - while (true) { - $readBytes = $os->read(8192); - $atEOF = (false === $readBytes); - - if ($atEOF) { - $streamTheseBytes = $base64ReadBufferRemainderBytes; - } else { - $streamTheseBytes = $base64ReadBufferRemainderBytes.$readBytes; - } - $base64ReadBufferRemainderBytes = ''; - $bytesLength = \strlen($streamTheseBytes); - - if (0 === $bytesLength) { // no data left to encode - break; - } - - // if we're not on the last block of the ouput stream, make sure $streamTheseBytes ends with a complete triplet of data - // and carry over remainder 1-2 bytes to the next loop iteration - if (!$atEOF) { - $excessBytes = $bytesLength % 3; - if (0 !== $excessBytes) { - $base64ReadBufferRemainderBytes = substr($streamTheseBytes, -$excessBytes); - $streamTheseBytes = substr($streamTheseBytes, 0, $bytesLength - $excessBytes); - } - } - - $encoded = base64_encode($streamTheseBytes); - $encodedTransformed = ''; - $thisMaxLineLength = $maxLineLength - $remainder - $firstLineOffset; - - while ($thisMaxLineLength < \strlen($encoded)) { - $encodedTransformed .= substr($encoded, 0, $thisMaxLineLength)."\r\n"; - $firstLineOffset = 0; - $encoded = substr($encoded, $thisMaxLineLength); - $thisMaxLineLength = $maxLineLength; - $remainder = 0; - } - - if (0 < $remainingLength = \strlen($encoded)) { - $remainder += $remainingLength; - $encodedTransformed .= $encoded; - $encoded = null; - } - - $is->write($encodedTransformed); - - if ($atEOF) { - break; - } - } - } - - /** - * Get the name of this encoding scheme. - * Returns the string 'base64'. - * - * @return string - */ - public function getName() - { - return 'base64'; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php deleted file mode 100644 index 8dfea60..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php +++ /dev/null @@ -1,121 +0,0 @@ -charset = $charset ?: 'utf-8'; - } - - /** - * Notify this observer that the entity's charset has changed. - * - * @param string $charset - */ - public function charsetChanged($charset) - { - $this->charset = $charset; - } - - /** - * Encode $in to $out. - * - * @param Swift_OutputByteStream $os to read from - * @param Swift_InputByteStream $is to write to - * @param int $firstLineOffset - * @param int $maxLineLength 0 indicates the default length for this encoding - * - * @throws RuntimeException - */ - public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) - { - if ('utf-8' !== $this->charset) { - throw new RuntimeException(sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset)); - } - - $string = ''; - - while (false !== $bytes = $os->read(8192)) { - $string .= $bytes; - } - - $is->write($this->encodeString($string)); - } - - /** - * Get the MIME name of this content encoding scheme. - * - * @return string - */ - public function getName() - { - return 'quoted-printable'; - } - - /** - * Encode a given string to produce an encoded string. - * - * @param string $string - * @param int $firstLineOffset if first line needs to be shorter - * @param int $maxLineLength 0 indicates the default length for this encoding - * - * @throws RuntimeException - * - * @return string - */ - public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) - { - if ('utf-8' !== $this->charset) { - throw new RuntimeException(sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset)); - } - - return $this->standardize(quoted_printable_encode($string)); - } - - /** - * Make sure CRLF is correct and HT/SPACE are in valid places. - * - * @param string $string - * - * @return string - */ - protected function standardize($string) - { - // transform CR or LF to CRLF - $string = preg_replace('~=0D(?!=0A)|(? - */ -class Swift_Mime_ContentEncoder_NullContentEncoder implements Swift_Mime_ContentEncoder -{ - /** - * The name of this encoding scheme (probably 7bit or 8bit). - * - * @var string - */ - private $name; - - /** - * Creates a new NullContentEncoder with $name (probably 7bit or 8bit). - * - * @param string $name - */ - public function __construct($name) - { - $this->name = $name; - } - - /** - * Encode a given string to produce an encoded string. - * - * @param string $string - * @param int $firstLineOffset ignored - * @param int $maxLineLength ignored - * - * @return string - */ - public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) - { - return $string; - } - - /** - * Encode stream $in to stream $out. - * - * @param int $firstLineOffset ignored - * @param int $maxLineLength ignored - */ - public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) - { - while (false !== ($bytes = $os->read(8192))) { - $is->write($bytes); - } - } - - /** - * Get the name of this encoding scheme. - * - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * Not used. - */ - public function charsetChanged($charset) - { - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php deleted file mode 100644 index 72592fc..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php +++ /dev/null @@ -1,164 +0,0 @@ -name = $name; - $this->canonical = $canonical; - } - - /** - * Encode a given string to produce an encoded string. - * - * @param string $string - * @param int $firstLineOffset ignored - * @param int $maxLineLength - 0 means no wrapping will occur - * - * @return string - */ - public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) - { - if ($this->canonical) { - $string = $this->canonicalize($string); - } - - return $this->safeWordwrap($string, $maxLineLength, "\r\n"); - } - - /** - * Encode stream $in to stream $out. - * - * @param int $firstLineOffset ignored - * @param int $maxLineLength optional, 0 means no wrapping will occur - */ - public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) - { - $leftOver = ''; - while (false !== $bytes = $os->read(8192)) { - $toencode = $leftOver.$bytes; - if ($this->canonical) { - $toencode = $this->canonicalize($toencode); - } - $wrapped = $this->safeWordwrap($toencode, $maxLineLength, "\r\n"); - $lastLinePos = strrpos($wrapped, "\r\n"); - $leftOver = substr($wrapped, $lastLinePos); - $wrapped = substr($wrapped, 0, $lastLinePos); - - $is->write($wrapped); - } - if (\strlen($leftOver)) { - $is->write($leftOver); - } - } - - /** - * Get the name of this encoding scheme. - * - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * Not used. - */ - public function charsetChanged($charset) - { - } - - /** - * A safer (but weaker) wordwrap for unicode. - * - * @param string $string - * @param int $length - * @param string $le - * - * @return string - */ - private function safeWordwrap($string, $length = 75, $le = "\r\n") - { - if (0 >= $length) { - return $string; - } - - $originalLines = explode($le, $string); - - $lines = []; - $lineCount = 0; - - foreach ($originalLines as $originalLine) { - $lines[] = ''; - $currentLine = &$lines[$lineCount++]; - - //$chunks = preg_split('/(?<=[\ \t,\.!\?\-&\+\/])/', $originalLine); - $chunks = preg_split('/(?<=\s)/', $originalLine); - - foreach ($chunks as $chunk) { - if (0 != \strlen($currentLine) - && \strlen($currentLine.$chunk) > $length) { - $lines[] = ''; - $currentLine = &$lines[$lineCount++]; - } - $currentLine .= $chunk; - } - } - - return implode("\r\n", $lines); - } - - /** - * Canonicalize string input (fix CRLF). - * - * @param string $string - * - * @return string - */ - private function canonicalize($string) - { - return str_replace( - ["\r\n", "\r", "\n"], - ["\n", "\n", "\r\n"], - $string - ); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php deleted file mode 100644 index 465ffd8..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php +++ /dev/null @@ -1,134 +0,0 @@ -dotEscape = $dotEscape; - parent::__construct($charStream, $filter); - } - - public function __sleep() - { - return ['charStream', 'filter', 'dotEscape']; - } - - protected function getSafeMapShareId() - { - return static::class.($this->dotEscape ? '.dotEscape' : ''); - } - - protected function initSafeMap() - { - parent::initSafeMap(); - if ($this->dotEscape) { - /* Encode . as =2e for buggy remote servers */ - unset($this->safeMap[0x2e]); - } - } - - /** - * Encode stream $in to stream $out. - * - * QP encoded strings have a maximum line length of 76 characters. - * If the first line needs to be shorter, indicate the difference with - * $firstLineOffset. - * - * @param Swift_OutputByteStream $os output stream - * @param Swift_InputByteStream $is input stream - * @param int $firstLineOffset - * @param int $maxLineLength - */ - public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) - { - if ($maxLineLength > 76 || $maxLineLength <= 0) { - $maxLineLength = 76; - } - - $thisLineLength = $maxLineLength - $firstLineOffset; - - $this->charStream->flushContents(); - $this->charStream->importByteStream($os); - - $currentLine = ''; - $prepend = ''; - $size = $lineLen = 0; - - while (false !== $bytes = $this->nextSequence()) { - // If we're filtering the input - if (isset($this->filter)) { - // If we can't filter because we need more bytes - while ($this->filter->shouldBuffer($bytes)) { - // Then collect bytes into the buffer - if (false === $moreBytes = $this->nextSequence(1)) { - break; - } - - foreach ($moreBytes as $b) { - $bytes[] = $b; - } - } - // And filter them - $bytes = $this->filter->filter($bytes); - } - - $enc = $this->encodeByteSequence($bytes, $size); - - $i = strpos($enc, '=0D=0A'); - $newLineLength = $lineLen + (false === $i ? $size : $i); - - if ($currentLine && $newLineLength >= $thisLineLength) { - $is->write($prepend.$this->standardize($currentLine)); - $currentLine = ''; - $prepend = "=\r\n"; - $thisLineLength = $maxLineLength; - $lineLen = 0; - } - - $currentLine .= $enc; - - if (false === $i) { - $lineLen += $size; - } else { - // 6 is the length of '=0D=0A'. - $lineLen = $size - strrpos($enc, '=0D=0A') - 6; - } - } - if (\strlen($currentLine)) { - $is->write($prepend.$this->standardize($currentLine)); - } - } - - /** - * Get the name of this encoding scheme. - * Returns the string 'quoted-printable'. - * - * @return string - */ - public function getName() - { - return 'quoted-printable'; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php deleted file mode 100644 index f3ece43..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php +++ /dev/null @@ -1,96 +0,0 @@ - - */ -class Swift_Mime_ContentEncoder_QpContentEncoderProxy implements Swift_Mime_ContentEncoder -{ - /** - * @var Swift_Mime_ContentEncoder_QpContentEncoder - */ - private $safeEncoder; - - /** - * @var Swift_Mime_ContentEncoder_NativeQpContentEncoder - */ - private $nativeEncoder; - - /** - * @var string|null - */ - private $charset; - - /** - * Constructor. - * - * @param string|null $charset - */ - public function __construct(Swift_Mime_ContentEncoder_QpContentEncoder $safeEncoder, Swift_Mime_ContentEncoder_NativeQpContentEncoder $nativeEncoder, $charset) - { - $this->safeEncoder = $safeEncoder; - $this->nativeEncoder = $nativeEncoder; - $this->charset = $charset; - } - - /** - * Make a deep copy of object. - */ - public function __clone() - { - $this->safeEncoder = clone $this->safeEncoder; - $this->nativeEncoder = clone $this->nativeEncoder; - } - - /** - * {@inheritdoc} - */ - public function charsetChanged($charset) - { - $this->charset = $charset; - $this->safeEncoder->charsetChanged($charset); - } - - /** - * {@inheritdoc} - */ - public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) - { - $this->getEncoder()->encodeByteStream($os, $is, $firstLineOffset, $maxLineLength); - } - - /** - * {@inheritdoc} - */ - public function getName() - { - return 'quoted-printable'; - } - - /** - * {@inheritdoc} - */ - public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) - { - return $this->getEncoder()->encodeString($string, $firstLineOffset, $maxLineLength); - } - - /** - * @return Swift_Mime_ContentEncoder - */ - private function getEncoder() - { - return 'utf-8' === $this->charset ? $this->nativeEncoder : $this->safeEncoder; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php deleted file mode 100644 index 870e7f4..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php +++ /dev/null @@ -1,65 +0,0 @@ - - */ -class Swift_Mime_ContentEncoder_RawContentEncoder implements Swift_Mime_ContentEncoder -{ - /** - * Encode a given string to produce an encoded string. - * - * @param string $string - * @param int $firstLineOffset ignored - * @param int $maxLineLength ignored - * - * @return string - */ - public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) - { - return $string; - } - - /** - * Encode stream $in to stream $out. - * - * @param int $firstLineOffset ignored - * @param int $maxLineLength ignored - */ - public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) - { - while (false !== ($bytes = $os->read(8192))) { - $is->write($bytes); - } - } - - /** - * Get the name of this encoding scheme. - * - * @return string - */ - public function getName() - { - return 'raw'; - } - - /** - * Not used. - */ - public function charsetChanged($charset) - { - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php deleted file mode 100644 index 42a5177..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php +++ /dev/null @@ -1,41 +0,0 @@ -setDisposition('inline'); - $this->setId($this->getId()); - } - - /** - * Get the nesting level of this EmbeddedFile. - * - * Returns {@see LEVEL_RELATED}. - * - * @return int - */ - public function getNestingLevel() - { - return self::LEVEL_RELATED; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php deleted file mode 100644 index 1a952ec..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php +++ /dev/null @@ -1,22 +0,0 @@ -getName(), "\r\n"); - mb_internal_encoding($old); - - return $newstring; - } - - return parent::encodeString($string, $firstLineOffset, $maxLineLength); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php deleted file mode 100644 index 378c480..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php +++ /dev/null @@ -1,65 +0,0 @@ -safeMap[$byte] = \chr($byte); - } - } - - /** - * Get the name of this encoding scheme. - * - * Returns the string 'Q'. - * - * @return string - */ - public function getName() - { - return 'Q'; - } - - /** - * Takes an unencoded string and produces a QP encoded string from it. - * - * @param string $string string to encode - * @param int $firstLineOffset optional - * @param int $maxLineLength optional, 0 indicates the default of 76 chars - * - * @return string - */ - public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) - { - return str_replace([' ', '=20', "=\r\n"], ['_', '_', "\r\n"], - parent::encodeString($string, $firstLineOffset, $maxLineLength) - ); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/AbstractHeader.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/AbstractHeader.php deleted file mode 100644 index 25740d1..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/AbstractHeader.php +++ /dev/null @@ -1,486 +0,0 @@ -clearCachedValueIf($charset != $this->charset); - $this->charset = $charset; - if (isset($this->encoder)) { - $this->encoder->charsetChanged($charset); - } - } - - /** - * Get the character set used in this Header. - * - * @return string - */ - public function getCharset() - { - return $this->charset; - } - - /** - * Set the language used in this Header. - * - * For example, for US English, 'en-us'. - * This can be unspecified. - * - * @param string $lang - */ - public function setLanguage($lang) - { - $this->clearCachedValueIf($this->lang != $lang); - $this->lang = $lang; - } - - /** - * Get the language used in this Header. - * - * @return string - */ - public function getLanguage() - { - return $this->lang; - } - - /** - * Set the encoder used for encoding the header. - */ - public function setEncoder(Swift_Mime_HeaderEncoder $encoder) - { - $this->encoder = $encoder; - $this->setCachedValue(null); - } - - /** - * Get the encoder used for encoding this Header. - * - * @return Swift_Mime_HeaderEncoder - */ - public function getEncoder() - { - return $this->encoder; - } - - /** - * Get the name of this header (e.g. charset). - * - * @return string - */ - public function getFieldName() - { - return $this->name; - } - - /** - * Set the maximum length of lines in the header (excluding EOL). - * - * @param int $lineLength - */ - public function setMaxLineLength($lineLength) - { - $this->clearCachedValueIf($this->lineLength != $lineLength); - $this->lineLength = $lineLength; - } - - /** - * Get the maximum permitted length of lines in this Header. - * - * @return int - */ - public function getMaxLineLength() - { - return $this->lineLength; - } - - /** - * Get this Header rendered as a RFC 2822 compliant string. - * - * @return string - * - * @throws Swift_RfcComplianceException - */ - public function toString() - { - return $this->tokensToString($this->toTokens()); - } - - /** - * Returns a string representation of this object. - * - * @return string - * - * @see toString() - */ - public function __toString() - { - return $this->toString(); - } - - /** - * Set the name of this Header field. - * - * @param string $name - */ - protected function setFieldName($name) - { - $this->name = $name; - } - - /** - * Produces a compliant, formatted RFC 2822 'phrase' based on the string given. - * - * @param string $string as displayed - * @param string $charset of the text - * @param bool $shorten the first line to make remove for header name - * - * @return string - */ - protected function createPhrase(Swift_Mime_Header $header, $string, $charset, Swift_Mime_HeaderEncoder $encoder = null, $shorten = false) - { - // Treat token as exactly what was given - $phraseStr = $string; - // If it's not valid - - if (!preg_match('/^'.self::PHRASE_PATTERN.'$/D', $phraseStr)) { - // .. but it is just ascii text, try escaping some characters - // and make it a quoted-string - if (preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $phraseStr)) { - $phraseStr = $this->escapeSpecials($phraseStr, ['"']); - $phraseStr = '"'.$phraseStr.'"'; - } else { - // ... otherwise it needs encoding - // Determine space remaining on line if first line - if ($shorten) { - $usedLength = \strlen($header->getFieldName().': '); - } else { - $usedLength = 0; - } - $phraseStr = $this->encodeWords($header, $string, $usedLength); - } - } - - return $phraseStr; - } - - /** - * Escape special characters in a string (convert to quoted-pairs). - * - * @param string $token - * @param string[] $include additional chars to escape - * - * @return string - */ - private function escapeSpecials($token, $include = []) - { - foreach (array_merge(['\\'], $include) as $char) { - $token = str_replace($char, '\\'.$char, $token); - } - - return $token; - } - - /** - * Encode needed word tokens within a string of input. - * - * @param string $input - * @param string $usedLength optional - * - * @return string - */ - protected function encodeWords(Swift_Mime_Header $header, $input, $usedLength = -1) - { - $value = ''; - - $tokens = $this->getEncodableWordTokens($input); - - foreach ($tokens as $token) { - // See RFC 2822, Sect 2.2 (really 2.2 ??) - if ($this->tokenNeedsEncoding($token)) { - // Don't encode starting WSP - $firstChar = substr($token, 0, 1); - switch ($firstChar) { - case ' ': - case "\t": - $value .= $firstChar; - $token = substr($token, 1); - } - - if (-1 == $usedLength) { - $usedLength = \strlen($header->getFieldName().': ') + \strlen($value); - } - $value .= $this->getTokenAsEncodedWord($token, $usedLength); - - $header->setMaxLineLength(76); // Forcefully override - } else { - $value .= $token; - } - } - - return $value; - } - - /** - * Test if a token needs to be encoded or not. - * - * @param string $token - * - * @return bool - */ - protected function tokenNeedsEncoding($token) - { - return preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token); - } - - /** - * Splits a string into tokens in blocks of words which can be encoded quickly. - * - * @param string $string - * - * @return string[] - */ - protected function getEncodableWordTokens($string) - { - $tokens = []; - - $encodedToken = ''; - // Split at all whitespace boundaries - foreach (preg_split('~(?=[\t ])~', $string ?? '') as $token) { - if ($this->tokenNeedsEncoding($token)) { - $encodedToken .= $token; - } else { - if (\strlen($encodedToken) > 0) { - $tokens[] = $encodedToken; - $encodedToken = ''; - } - $tokens[] = $token; - } - } - if (\strlen($encodedToken)) { - $tokens[] = $encodedToken; - } - - return $tokens; - } - - /** - * Get a token as an encoded word for safe insertion into headers. - * - * @param string $token token to encode - * @param int $firstLineOffset optional - * - * @return string - */ - protected function getTokenAsEncodedWord($token, $firstLineOffset = 0) - { - // Adjust $firstLineOffset to account for space needed for syntax - $charsetDecl = $this->charset; - if (isset($this->lang)) { - $charsetDecl .= '*'.$this->lang; - } - $encodingWrapperLength = \strlen( - '=?'.$charsetDecl.'?'.$this->encoder->getName().'??=' - ); - - if ($firstLineOffset >= 75) { - //Does this logic need to be here? - $firstLineOffset = 0; - } - - $encodedTextLines = explode("\r\n", - $this->encoder->encodeString( - $token, $firstLineOffset, 75 - $encodingWrapperLength, $this->charset - ) ?? '' - ); - - if ('iso-2022-jp' !== strtolower($this->charset ?? '')) { - // special encoding for iso-2022-jp using mb_encode_mimeheader - foreach ($encodedTextLines as $lineNum => $line) { - $encodedTextLines[$lineNum] = '=?'.$charsetDecl. - '?'.$this->encoder->getName(). - '?'.$line.'?='; - } - } - - return implode("\r\n ", $encodedTextLines); - } - - /** - * Generates tokens from the given string which include CRLF as individual tokens. - * - * @param string $token - * - * @return string[] - */ - protected function generateTokenLines($token) - { - return preg_split('~(\r\n)~', $token ?? '', -1, PREG_SPLIT_DELIM_CAPTURE); - } - - /** - * Set a value into the cache. - * - * @param string $value - */ - protected function setCachedValue($value) - { - $this->cachedValue = $value; - } - - /** - * Get the value in the cache. - * - * @return string - */ - protected function getCachedValue() - { - return $this->cachedValue; - } - - /** - * Clear the cached value if $condition is met. - * - * @param bool $condition - */ - protected function clearCachedValueIf($condition) - { - if ($condition) { - $this->setCachedValue(null); - } - } - - /** - * Generate a list of all tokens in the final header. - * - * @param string $string The string to tokenize - * - * @return array An array of tokens as strings - */ - protected function toTokens($string = null) - { - if (null === $string) { - $string = $this->getFieldBody(); - } - - $tokens = []; - - // Generate atoms; split at all invisible boundaries followed by WSP - foreach (preg_split('~(?=[ \t])~', $string ?? '') as $token) { - $newTokens = $this->generateTokenLines($token); - foreach ($newTokens as $newToken) { - $tokens[] = $newToken; - } - } - - return $tokens; - } - - /** - * Takes an array of tokens which appear in the header and turns them into - * an RFC 2822 compliant string, adding FWSP where needed. - * - * @param string[] $tokens - * - * @return string - */ - private function tokensToString(array $tokens) - { - $lineCount = 0; - $headerLines = []; - $headerLines[] = $this->name.': '; - $currentLine = &$headerLines[$lineCount++]; - - // Build all tokens back into compliant header - foreach ($tokens as $i => $token) { - // Line longer than specified maximum or token was just a new line - if (("\r\n" == $token) || - ($i > 0 && \strlen($currentLine.$token) > $this->lineLength) - && 0 < \strlen($currentLine)) { - $headerLines[] = ''; - $currentLine = &$headerLines[$lineCount++]; - } - - // Append token to the line - if ("\r\n" != $token) { - $currentLine .= $token; - } - } - - // Implode with FWS (RFC 2822, 2.2.3) - return implode("\r\n", $headerLines)."\r\n"; - } - - /** - * Make a deep copy of object. - */ - public function __clone() - { - if ($this->encoder) { - $this->encoder = clone $this->encoder; - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php deleted file mode 100644 index efe1dad..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php +++ /dev/null @@ -1,113 +0,0 @@ -setFieldName($name); - } - - /** - * Get the type of Header that this instance represents. - * - * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX - * @see TYPE_DATE, TYPE_ID, TYPE_PATH - * - * @return int - */ - public function getFieldType() - { - return self::TYPE_DATE; - } - - /** - * Set the model for the field body. - * - * @param DateTimeInterface $model - */ - public function setFieldBodyModel($model) - { - $this->setDateTime($model); - } - - /** - * Get the model for the field body. - * - * @return DateTimeImmutable - */ - public function getFieldBodyModel() - { - return $this->getDateTime(); - } - - /** - * Get the date-time representing the Date in this Header. - * - * @return DateTimeImmutable - */ - public function getDateTime() - { - return $this->dateTime; - } - - /** - * Set the date-time of the Date in this Header. - * - * If a DateTime instance is provided, it is converted to DateTimeImmutable. - */ - public function setDateTime(DateTimeInterface $dateTime) - { - $this->clearCachedValueIf($this->getCachedValue() != $dateTime->format(DateTime::RFC2822)); - if ($dateTime instanceof DateTime) { - $immutable = new DateTimeImmutable('@'.$dateTime->getTimestamp()); - $dateTime = $immutable->setTimezone($dateTime->getTimezone()); - } - $this->dateTime = $dateTime; - } - - /** - * Get the string value of the body in this Header. - * - * This is not necessarily RFC 2822 compliant since folding white space will - * not be added at this stage (see {@link toString()} for that). - * - * @see toString() - * - * @return string - */ - public function getFieldBody() - { - if (!$this->getCachedValue()) { - if (isset($this->dateTime)) { - $this->setCachedValue($this->dateTime->format(DateTime::RFC2822)); - } - } - - return $this->getCachedValue(); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php deleted file mode 100644 index 4fcdff4..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php +++ /dev/null @@ -1,189 +0,0 @@ -setFieldName($name); - $this->emailValidator = $emailValidator; - $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder(); - } - - /** - * Get the type of Header that this instance represents. - * - * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX - * @see TYPE_DATE, TYPE_ID, TYPE_PATH - * - * @return int - */ - public function getFieldType() - { - return self::TYPE_ID; - } - - /** - * Set the model for the field body. - * - * This method takes a string ID, or an array of IDs. - * - * @param mixed $model - * - * @throws Swift_RfcComplianceException - */ - public function setFieldBodyModel($model) - { - $this->setId($model); - } - - /** - * Get the model for the field body. - * - * This method returns an array of IDs - * - * @return array - */ - public function getFieldBodyModel() - { - return $this->getIds(); - } - - /** - * Set the ID used in the value of this header. - * - * @param string|array $id - * - * @throws Swift_RfcComplianceException - */ - public function setId($id) - { - $this->setIds(\is_array($id) ? $id : [$id]); - } - - /** - * Get the ID used in the value of this Header. - * - * If multiple IDs are set only the first is returned. - * - * @return string - */ - public function getId() - { - if (\count($this->ids) > 0) { - return $this->ids[0]; - } - } - - /** - * Set a collection of IDs to use in the value of this Header. - * - * @param string[] $ids - * - * @throws Swift_RfcComplianceException - */ - public function setIds(array $ids) - { - $actualIds = []; - - foreach ($ids as $id) { - $this->assertValidId($id); - $actualIds[] = $id; - } - - $this->clearCachedValueIf($this->ids != $actualIds); - $this->ids = $actualIds; - } - - /** - * Get the list of IDs used in this Header. - * - * @return string[] - */ - public function getIds() - { - return $this->ids; - } - - /** - * Get the string value of the body in this Header. - * - * This is not necessarily RFC 2822 compliant since folding white space will - * not be added at this stage (see {@see toString()} for that). - * - * @see toString() - * - * @throws Swift_RfcComplianceException - * - * @return string - */ - public function getFieldBody() - { - if (!$this->getCachedValue()) { - $angleAddrs = []; - - foreach ($this->ids as $id) { - $angleAddrs[] = '<'.$this->addressEncoder->encodeString($id).'>'; - } - - $this->setCachedValue(implode(' ', $angleAddrs)); - } - - return $this->getCachedValue(); - } - - /** - * Throws an Exception if the id passed does not comply with RFC 2822. - * - * @param string $id - * - * @throws Swift_RfcComplianceException - */ - private function assertValidId($id) - { - $emailValidation = class_exists(MessageIDValidation::class) ? new MessageIDValidation() : new RFCValidation(); - - if (!$this->emailValidator->isValid($id, $emailValidation)) { - throw new Swift_RfcComplianceException('Invalid ID given <'.$id.'>'); - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php deleted file mode 100644 index ddd5e8c..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php +++ /dev/null @@ -1,358 +0,0 @@ -setFieldName($name); - $this->setEncoder($encoder); - $this->emailValidator = $emailValidator; - $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder(); - } - - /** - * Get the type of Header that this instance represents. - * - * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX - * @see TYPE_DATE, TYPE_ID, TYPE_PATH - * - * @return int - */ - public function getFieldType() - { - return self::TYPE_MAILBOX; - } - - /** - * Set the model for the field body. - * - * This method takes a string, or an array of addresses. - * - * @param mixed $model - * - * @throws Swift_RfcComplianceException - */ - public function setFieldBodyModel($model) - { - $this->setNameAddresses($model); - } - - /** - * Get the model for the field body. - * - * This method returns an associative array like {@link getNameAddresses()} - * - * @throws Swift_RfcComplianceException - * - * @return array - */ - public function getFieldBodyModel() - { - return $this->getNameAddresses(); - } - - /** - * Set a list of mailboxes to be shown in this Header. - * - * The mailboxes can be a simple array of addresses, or an array of - * key=>value pairs where (email => personalName). - * Example: - * - * setNameAddresses(array( - * 'chris@swiftmailer.org' => 'Chris Corbyn', - * 'mark@swiftmailer.org' //No associated personal name - * )); - * ?> - * - * - * @see __construct() - * @see setAddresses() - * @see setValue() - * - * @param string|string[] $mailboxes - * - * @throws Swift_RfcComplianceException - */ - public function setNameAddresses($mailboxes) - { - $this->mailboxes = $this->normalizeMailboxes((array) $mailboxes); - $this->setCachedValue(null); //Clear any cached value - } - - /** - * Get the full mailbox list of this Header as an array of valid RFC 2822 strings. - * - * Example: - * - * 'Chris Corbyn', - * 'mark@swiftmailer.org' => 'Mark Corbyn') - * ); - * print_r($header->getNameAddressStrings()); - * // array ( - * // 0 => Chris Corbyn , - * // 1 => Mark Corbyn - * // ) - * ?> - * - * - * @see getNameAddresses() - * @see toString() - * - * @throws Swift_RfcComplianceException - * - * @return string[] - */ - public function getNameAddressStrings() - { - return $this->createNameAddressStrings($this->getNameAddresses()); - } - - /** - * Get all mailboxes in this Header as key=>value pairs. - * - * The key is the address and the value is the name (or null if none set). - * Example: - * - * 'Chris Corbyn', - * 'mark@swiftmailer.org' => 'Mark Corbyn') - * ); - * print_r($header->getNameAddresses()); - * // array ( - * // chris@swiftmailer.org => Chris Corbyn, - * // mark@swiftmailer.org => Mark Corbyn - * // ) - * ?> - * - * - * @see getAddresses() - * @see getNameAddressStrings() - * - * @return string[] - */ - public function getNameAddresses() - { - return $this->mailboxes; - } - - /** - * Makes this Header represent a list of plain email addresses with no names. - * - * Example: - * - * setAddresses( - * array('one@domain.tld', 'two@domain.tld', 'three@domain.tld') - * ); - * ?> - * - * - * @see setNameAddresses() - * @see setValue() - * - * @param string[] $addresses - * - * @throws Swift_RfcComplianceException - */ - public function setAddresses($addresses) - { - $this->setNameAddresses(array_values((array) $addresses)); - } - - /** - * Get all email addresses in this Header. - * - * @see getNameAddresses() - * - * @return string[] - */ - public function getAddresses() - { - return array_keys($this->mailboxes); - } - - /** - * Remove one or more addresses from this Header. - * - * @param string|string[] $addresses - */ - public function removeAddresses($addresses) - { - $this->setCachedValue(null); - foreach ((array) $addresses as $address) { - unset($this->mailboxes[$address]); - } - } - - /** - * Get the string value of the body in this Header. - * - * This is not necessarily RFC 2822 compliant since folding white space will - * not be added at this stage (see {@link toString()} for that). - * - * @see toString() - * - * @throws Swift_RfcComplianceException - * - * @return string - */ - public function getFieldBody() - { - // Compute the string value of the header only if needed - if (null === $this->getCachedValue()) { - $this->setCachedValue($this->createMailboxListString($this->mailboxes)); - } - - return $this->getCachedValue(); - } - - /** - * Normalizes a user-input list of mailboxes into consistent key=>value pairs. - * - * @param string[] $mailboxes - * - * @return string[] - */ - protected function normalizeMailboxes(array $mailboxes) - { - $actualMailboxes = []; - - foreach ($mailboxes as $key => $value) { - if (\is_string($key)) { - //key is email addr - $address = $key; - $name = $value; - } else { - $address = $value; - $name = null; - } - $this->assertValidAddress($address); - $actualMailboxes[$address] = $name; - } - - return $actualMailboxes; - } - - /** - * Produces a compliant, formatted display-name based on the string given. - * - * @param string $displayName as displayed - * @param bool $shorten the first line to make remove for header name - * - * @return string - */ - protected function createDisplayNameString($displayName, $shorten = false) - { - return $this->createPhrase($this, $displayName, $this->getCharset(), $this->getEncoder(), $shorten); - } - - /** - * Creates a string form of all the mailboxes in the passed array. - * - * @param string[] $mailboxes - * - * @throws Swift_RfcComplianceException - * - * @return string - */ - protected function createMailboxListString(array $mailboxes) - { - return implode(', ', $this->createNameAddressStrings($mailboxes)); - } - - /** - * Redefine the encoding requirements for mailboxes. - * - * All "specials" must be encoded as the full header value will not be quoted - * - * @see RFC 2822 3.2.1 - * - * @param string $token - * - * @return bool - */ - protected function tokenNeedsEncoding($token) - { - return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token); - } - - /** - * Return an array of strings conforming the the name-addr spec of RFC 2822. - * - * @param string[] $mailboxes - * - * @return string[] - */ - private function createNameAddressStrings(array $mailboxes) - { - $strings = []; - - foreach ($mailboxes as $email => $name) { - $mailboxStr = $this->addressEncoder->encodeString($email); - if (null !== $name) { - $nameStr = $this->createDisplayNameString($name, empty($strings)); - $mailboxStr = $nameStr.' <'.$mailboxStr.'>'; - } - $strings[] = $mailboxStr; - } - - return $strings; - } - - /** - * Throws an Exception if the address passed does not comply with RFC 2822. - * - * @param string $address - * - * @throws Swift_RfcComplianceException if invalid - */ - private function assertValidAddress($address) - { - if (!$this->emailValidator->isValid($address, new RFCValidation())) { - throw new Swift_RfcComplianceException('Address in mailbox given ['.$address.'] does not comply with RFC 2822, 3.6.2.'); - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php deleted file mode 100644 index fafb5ba..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php +++ /dev/null @@ -1,135 +0,0 @@ - - * - * @deprecated since SwiftMailer 6.1.0; use Swift_Signers_DKIMSigner instead. - */ -class Swift_Mime_Headers_OpenDKIMHeader implements Swift_Mime_Header -{ - /** - * The value of this Header. - * - * @var string - */ - private $value; - - /** - * The name of this Header. - * - * @var string - */ - private $fieldName; - - /** - * @param string $name - */ - public function __construct($name) - { - $this->fieldName = $name; - } - - /** - * Get the type of Header that this instance represents. - * - * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX - * @see TYPE_DATE, TYPE_ID, TYPE_PATH - * - * @return int - */ - public function getFieldType() - { - return self::TYPE_TEXT; - } - - /** - * Set the model for the field body. - * - * This method takes a string for the field value. - * - * @param string $model - */ - public function setFieldBodyModel($model) - { - $this->setValue($model); - } - - /** - * Get the model for the field body. - * - * This method returns a string. - * - * @return string - */ - public function getFieldBodyModel() - { - return $this->getValue(); - } - - /** - * Get the (unencoded) value of this header. - * - * @return string - */ - public function getValue() - { - return $this->value; - } - - /** - * Set the (unencoded) value of this header. - * - * @param string $value - */ - public function setValue($value) - { - $this->value = $value; - } - - /** - * Get the value of this header prepared for rendering. - * - * @return string - */ - public function getFieldBody() - { - return $this->value; - } - - /** - * Get this Header rendered as a RFC 2822 compliant string. - * - * @return string - */ - public function toString() - { - return $this->fieldName.': '.$this->value."\r\n"; - } - - /** - * Set the Header FieldName. - * - * @see Swift_Mime_Header::getFieldName() - */ - public function getFieldName() - { - return $this->fieldName; - } - - /** - * Ignored. - */ - public function setCharset($charset) - { - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php deleted file mode 100644 index 47c15e6..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php +++ /dev/null @@ -1,255 +0,0 @@ -paramEncoder = $paramEncoder; - } - - /** - * Get the type of Header that this instance represents. - * - * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX - * @see TYPE_DATE, TYPE_ID, TYPE_PATH - * - * @return int - */ - public function getFieldType() - { - return self::TYPE_PARAMETERIZED; - } - - /** - * Set the character set used in this Header. - * - * @param string $charset - */ - public function setCharset($charset) - { - parent::setCharset($charset); - if (isset($this->paramEncoder)) { - $this->paramEncoder->charsetChanged($charset); - } - } - - /** - * Set the value of $parameter. - * - * @param string $parameter - * @param string $value - */ - public function setParameter($parameter, $value) - { - $this->setParameters(array_merge($this->getParameters(), [$parameter => $value])); - } - - /** - * Get the value of $parameter. - * - * @param string $parameter - * - * @return string - */ - public function getParameter($parameter) - { - $params = $this->getParameters(); - - return $params[$parameter] ?? null; - } - - /** - * Set an associative array of parameter names mapped to values. - * - * @param string[] $parameters - */ - public function setParameters(array $parameters) - { - $this->clearCachedValueIf($this->params != $parameters); - $this->params = $parameters; - } - - /** - * Returns an associative array of parameter names mapped to values. - * - * @return string[] - */ - public function getParameters() - { - return $this->params; - } - - /** - * Get the value of this header prepared for rendering. - * - * @return string - */ - public function getFieldBody() //TODO: Check caching here - { - $body = parent::getFieldBody(); - foreach ($this->params as $name => $value) { - if (null !== $value) { - // Add the parameter - $body .= '; '.$this->createParameter($name, $value); - } - } - - return $body; - } - - /** - * Generate a list of all tokens in the final header. - * - * This doesn't need to be overridden in theory, but it is for implementation - * reasons to prevent potential breakage of attributes. - * - * @param string $string The string to tokenize - * - * @return array An array of tokens as strings - */ - protected function toTokens($string = null) - { - $tokens = parent::toTokens(parent::getFieldBody()); - - // Try creating any parameters - foreach ($this->params as $name => $value) { - if (null !== $value) { - // Add the semi-colon separator - $tokens[\count($tokens) - 1] .= ';'; - $tokens = array_merge($tokens, $this->generateTokenLines( - ' '.$this->createParameter($name, $value) - )); - } - } - - return $tokens; - } - - /** - * Render a RFC 2047 compliant header parameter from the $name and $value. - * - * @param string $name - * @param string $value - * - * @return string - */ - private function createParameter($name, $value) - { - $origValue = $value; - - $encoded = false; - // Allow room for parameter name, indices, "=" and DQUOTEs - $maxValueLength = $this->getMaxLineLength() - \strlen($name.'=*N"";') - 1; - $firstLineOffset = 0; - - // If it's not already a valid parameter value... - if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { - // TODO: text, or something else?? - // ... and it's not ascii - if (!preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $value)) { - $encoded = true; - // Allow space for the indices, charset and language - $maxValueLength = $this->getMaxLineLength() - \strlen($name.'*N*="";') - 1; - $firstLineOffset = \strlen( - $this->getCharset()."'".$this->getLanguage()."'" - ); - } - } - - // Encode if we need to - if ($encoded || \strlen($value) > $maxValueLength) { - if (isset($this->paramEncoder)) { - $value = $this->paramEncoder->encodeString( - $origValue, $firstLineOffset, $maxValueLength, $this->getCharset() - ); - } else { - // We have to go against RFC 2183/2231 in some areas for interoperability - $value = $this->getTokenAsEncodedWord($origValue); - $encoded = false; - } - } - - $valueLines = isset($this->paramEncoder) ? explode("\r\n", $value) : [$value]; - - // Need to add indices - if (\count($valueLines) > 1) { - $paramLines = []; - foreach ($valueLines as $i => $line) { - $paramLines[] = $name.'*'.$i. - $this->getEndOfParameterValue($line, true, 0 == $i); - } - - return implode(";\r\n ", $paramLines); - } else { - return $name.$this->getEndOfParameterValue( - $valueLines[0], $encoded, true - ); - } - } - - /** - * Returns the parameter value from the "=" and beyond. - * - * @param string $value to append - * @param bool $encoded - * @param bool $firstLine - * - * @return string - */ - private function getEndOfParameterValue($value, $encoded = false, $firstLine = false) - { - if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { - $value = '"'.$value.'"'; - } - $prepend = '='; - if ($encoded) { - $prepend = '*='; - if ($firstLine) { - $prepend = '*='.$this->getCharset()."'".$this->getLanguage(). - "'"; - } - } - - return $prepend.$value; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php deleted file mode 100644 index 81b421e..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php +++ /dev/null @@ -1,153 +0,0 @@ -setFieldName($name); - $this->emailValidator = $emailValidator; - $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder(); - } - - /** - * Get the type of Header that this instance represents. - * - * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX - * @see TYPE_DATE, TYPE_ID, TYPE_PATH - * - * @return int - */ - public function getFieldType() - { - return self::TYPE_PATH; - } - - /** - * Set the model for the field body. - * This method takes a string for an address. - * - * @param string $model - * - * @throws Swift_RfcComplianceException - */ - public function setFieldBodyModel($model) - { - $this->setAddress($model); - } - - /** - * Get the model for the field body. - * This method returns a string email address. - * - * @return mixed - */ - public function getFieldBodyModel() - { - return $this->getAddress(); - } - - /** - * Set the Address which should appear in this Header. - * - * @param string $address - * - * @throws Swift_RfcComplianceException - */ - public function setAddress($address) - { - if (null === $address) { - $this->address = null; - } elseif ('' == $address) { - $this->address = ''; - } else { - $this->assertValidAddress($address); - $this->address = $address; - } - $this->setCachedValue(null); - } - - /** - * Get the address which is used in this Header (if any). - * - * Null is returned if no address is set. - * - * @return string - */ - public function getAddress() - { - return $this->address; - } - - /** - * Get the string value of the body in this Header. - * - * This is not necessarily RFC 2822 compliant since folding white space will - * not be added at this stage (see {@link toString()} for that). - * - * @see toString() - * - * @return string - */ - public function getFieldBody() - { - if (!$this->getCachedValue()) { - if (isset($this->address)) { - $address = $this->addressEncoder->encodeString($this->address); - $this->setCachedValue('<'.$address.'>'); - } - } - - return $this->getCachedValue(); - } - - /** - * Throws an Exception if the address passed does not comply with RFC 2822. - * - * @param string $address - * - * @throws Swift_RfcComplianceException If address is invalid - */ - private function assertValidAddress($address) - { - if (!$this->emailValidator->isValid($address, new RFCValidation())) { - throw new Swift_RfcComplianceException('Address set in PathHeader does not comply with addr-spec of RFC 2822.'); - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php deleted file mode 100644 index 64f160d..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php +++ /dev/null @@ -1,109 +0,0 @@ -setFieldName($name); - $this->setEncoder($encoder); - } - - /** - * Get the type of Header that this instance represents. - * - * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX - * @see TYPE_DATE, TYPE_ID, TYPE_PATH - * - * @return int - */ - public function getFieldType() - { - return self::TYPE_TEXT; - } - - /** - * Set the model for the field body. - * - * This method takes a string for the field value. - * - * @param string $model - */ - public function setFieldBodyModel($model) - { - $this->setValue($model); - } - - /** - * Get the model for the field body. - * - * This method returns a string. - * - * @return string - */ - public function getFieldBodyModel() - { - return $this->getValue(); - } - - /** - * Get the (unencoded) value of this header. - * - * @return string - */ - public function getValue() - { - return $this->value; - } - - /** - * Set the (unencoded) value of this header. - * - * @param string $value - */ - public function setValue($value) - { - $this->clearCachedValueIf($this->value != $value); - $this->value = $value; - } - - /** - * Get the value of this header prepared for rendering. - * - * @return string - */ - public function getFieldBody() - { - if (!$this->getCachedValue()) { - $this->setCachedValue( - $this->encodeWords($this, $this->value) - ); - } - - return $this->getCachedValue(); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/IdGenerator.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/IdGenerator.php deleted file mode 100644 index 3ce35f2..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/IdGenerator.php +++ /dev/null @@ -1,54 +0,0 @@ -idRight = $idRight; - } - - /** - * Returns the right-hand side of the "@" used in all generated IDs. - * - * @return string - */ - public function getIdRight() - { - return $this->idRight; - } - - /** - * Sets the right-hand side of the "@" to use in all generated IDs. - * - * @param string $idRight - */ - public function setIdRight($idRight) - { - $this->idRight = $idRight; - } - - /** - * @return string - */ - public function generateId() - { - // 32 hex values for the left part - return bin2hex(random_bytes(16)).'@'.$this->idRight; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/MimePart.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/MimePart.php deleted file mode 100644 index d0b2e65..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/MimePart.php +++ /dev/null @@ -1,199 +0,0 @@ -setContentType('text/plain'); - if (null !== $charset) { - $this->setCharset($charset); - } - } - - /** - * Set the body of this entity, either as a string, or as an instance of - * {@link Swift_OutputByteStream}. - * - * @param mixed $body - * @param string $contentType optional - * @param string $charset optional - * - * @return $this - */ - public function setBody($body, $contentType = null, $charset = null) - { - if (isset($charset)) { - $this->setCharset($charset); - } - $body = $this->convertString($body); - - parent::setBody($body, $contentType); - - return $this; - } - - /** - * Get the character set of this entity. - * - * @return string - */ - public function getCharset() - { - return $this->getHeaderParameter('Content-Type', 'charset'); - } - - /** - * Set the character set of this entity. - * - * @param string $charset - * - * @return $this - */ - public function setCharset($charset) - { - $this->setHeaderParameter('Content-Type', 'charset', $charset); - if ($charset !== $this->userCharset) { - $this->clearCache(); - } - $this->userCharset = $charset; - parent::charsetChanged($charset); - - return $this; - } - - /** - * Get the format of this entity (i.e. flowed or fixed). - * - * @return string - */ - public function getFormat() - { - return $this->getHeaderParameter('Content-Type', 'format'); - } - - /** - * Set the format of this entity (flowed or fixed). - * - * @param string $format - * - * @return $this - */ - public function setFormat($format) - { - $this->setHeaderParameter('Content-Type', 'format', $format); - $this->userFormat = $format; - - return $this; - } - - /** - * Test if delsp is being used for this entity. - * - * @return bool - */ - public function getDelSp() - { - return 'yes' === $this->getHeaderParameter('Content-Type', 'delsp'); - } - - /** - * Turn delsp on or off for this entity. - * - * @param bool $delsp - * - * @return $this - */ - public function setDelSp($delsp = true) - { - $this->setHeaderParameter('Content-Type', 'delsp', $delsp ? 'yes' : null); - $this->userDelSp = $delsp; - - return $this; - } - - /** - * Get the nesting level of this entity. - * - * @see LEVEL_TOP, LEVEL_ALTERNATIVE, LEVEL_MIXED, LEVEL_RELATED - * - * @return int - */ - public function getNestingLevel() - { - return $this->nestingLevel; - } - - /** - * Receive notification that the charset has changed on this document, or a - * parent document. - * - * @param string $charset - */ - public function charsetChanged($charset) - { - $this->setCharset($charset); - } - - /** Fix the content-type and encoding of this entity */ - protected function fixHeaders() - { - parent::fixHeaders(); - if (\count($this->getChildren())) { - $this->setHeaderParameter('Content-Type', 'charset', null); - $this->setHeaderParameter('Content-Type', 'format', null); - $this->setHeaderParameter('Content-Type', 'delsp', null); - } else { - $this->setCharset($this->userCharset); - $this->setFormat($this->userFormat); - $this->setDelSp($this->userDelSp); - } - } - - /** Set the nesting level of this entity */ - protected function setNestingLevel($level) - { - $this->nestingLevel = $level; - } - - /** Encode charset when charset is not utf-8 */ - protected function convertString($string) - { - $charset = strtolower($this->getCharset() ?? ''); - if (!\in_array($charset, ['utf-8', 'iso-8859-1', 'iso-8859-15', ''])) { - return mb_convert_encoding($string, $charset, 'utf-8'); - } - - return $string; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderFactory.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderFactory.php deleted file mode 100644 index ab3ce6b..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderFactory.php +++ /dev/null @@ -1,195 +0,0 @@ -encoder = $encoder; - $this->paramEncoder = $paramEncoder; - $this->emailValidator = $emailValidator; - $this->charset = $charset; - $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder(); - } - - /** - * Create a new Mailbox Header with a list of $addresses. - * - * @param string $name - * @param array|string|null $addresses - * - * @return Swift_Mime_Header - */ - public function createMailboxHeader($name, $addresses = null) - { - $header = new Swift_Mime_Headers_MailboxHeader($name, $this->encoder, $this->emailValidator, $this->addressEncoder); - if (isset($addresses)) { - $header->setFieldBodyModel($addresses); - } - $this->setHeaderCharset($header); - - return $header; - } - - /** - * Create a new Date header using $dateTime. - * - * @param string $name - * - * @return Swift_Mime_Header - */ - public function createDateHeader($name, DateTimeInterface $dateTime = null) - { - $header = new Swift_Mime_Headers_DateHeader($name); - if (isset($dateTime)) { - $header->setFieldBodyModel($dateTime); - } - $this->setHeaderCharset($header); - - return $header; - } - - /** - * Create a new basic text header with $name and $value. - * - * @param string $name - * @param string $value - * - * @return Swift_Mime_Header - */ - public function createTextHeader($name, $value = null) - { - $header = new Swift_Mime_Headers_UnstructuredHeader($name, $this->encoder); - if (isset($value)) { - $header->setFieldBodyModel($value); - } - $this->setHeaderCharset($header); - - return $header; - } - - /** - * Create a new ParameterizedHeader with $name, $value and $params. - * - * @param string $name - * @param string $value - * @param array $params - * - * @return Swift_Mime_Headers_ParameterizedHeader - */ - public function createParameterizedHeader($name, $value = null, $params = []) - { - $header = new Swift_Mime_Headers_ParameterizedHeader($name, $this->encoder, ('content-disposition' == strtolower($name ?? '')) ? $this->paramEncoder : null); - if (isset($value)) { - $header->setFieldBodyModel($value); - } - foreach ($params as $k => $v) { - $header->setParameter($k, $v); - } - $this->setHeaderCharset($header); - - return $header; - } - - /** - * Create a new ID header for Message-ID or Content-ID. - * - * @param string $name - * @param string|array $ids - * - * @return Swift_Mime_Header - */ - public function createIdHeader($name, $ids = null) - { - $header = new Swift_Mime_Headers_IdentificationHeader($name, $this->emailValidator); - if (isset($ids)) { - $header->setFieldBodyModel($ids); - } - $this->setHeaderCharset($header); - - return $header; - } - - /** - * Create a new Path header with an address (path) in it. - * - * @param string $name - * @param string $path - * - * @return Swift_Mime_Header - */ - public function createPathHeader($name, $path = null) - { - $header = new Swift_Mime_Headers_PathHeader($name, $this->emailValidator); - if (isset($path)) { - $header->setFieldBodyModel($path); - } - $this->setHeaderCharset($header); - - return $header; - } - - /** - * Notify this observer that the entity's charset has changed. - * - * @param string $charset - */ - public function charsetChanged($charset) - { - $this->charset = $charset; - $this->encoder->charsetChanged($charset); - $this->paramEncoder->charsetChanged($charset); - } - - /** - * Make a deep copy of object. - */ - public function __clone() - { - $this->encoder = clone $this->encoder; - $this->paramEncoder = clone $this->paramEncoder; - $this->addressEncoder = clone $this->addressEncoder; - } - - /** Apply the charset to the Header */ - private function setHeaderCharset(Swift_Mime_Header $header) - { - if (isset($this->charset)) { - $header->setCharset($this->charset); - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php deleted file mode 100644 index 5195bcf..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php +++ /dev/null @@ -1,399 +0,0 @@ -factory = $factory; - if (isset($charset)) { - $this->setCharset($charset); - } - } - - public function newInstance() - { - return new self($this->factory); - } - - /** - * Set the charset used by these headers. - * - * @param string $charset - */ - public function setCharset($charset) - { - $this->charset = $charset; - $this->factory->charsetChanged($charset); - $this->notifyHeadersOfCharset($charset); - } - - /** - * Add a new Mailbox Header with a list of $addresses. - * - * @param string $name - * @param array|string $addresses - */ - public function addMailboxHeader($name, $addresses = null) - { - $this->storeHeader($name, $this->factory->createMailboxHeader($name, $addresses)); - } - - /** - * Add a new Date header using $dateTime. - * - * @param string $name - */ - public function addDateHeader($name, DateTimeInterface $dateTime = null) - { - $this->storeHeader($name, $this->factory->createDateHeader($name, $dateTime)); - } - - /** - * Add a new basic text header with $name and $value. - * - * @param string $name - * @param string $value - */ - public function addTextHeader($name, $value = null) - { - $this->storeHeader($name, $this->factory->createTextHeader($name, $value)); - } - - /** - * Add a new ParameterizedHeader with $name, $value and $params. - * - * @param string $name - * @param string $value - * @param array $params - */ - public function addParameterizedHeader($name, $value = null, $params = []) - { - $this->storeHeader($name, $this->factory->createParameterizedHeader($name, $value, $params)); - } - - /** - * Add a new ID header for Message-ID or Content-ID. - * - * @param string $name - * @param string|array $ids - */ - public function addIdHeader($name, $ids = null) - { - $this->storeHeader($name, $this->factory->createIdHeader($name, $ids)); - } - - /** - * Add a new Path header with an address (path) in it. - * - * @param string $name - * @param string $path - */ - public function addPathHeader($name, $path = null) - { - $this->storeHeader($name, $this->factory->createPathHeader($name, $path)); - } - - /** - * Returns true if at least one header with the given $name exists. - * - * If multiple headers match, the actual one may be specified by $index. - * - * @param string $name - * @param int $index - * - * @return bool - */ - public function has($name, $index = 0) - { - $lowerName = strtolower($name ?? ''); - - if (!\array_key_exists($lowerName, $this->headers)) { - return false; - } - - if (\func_num_args() < 2) { - // index was not specified, so we only need to check that there is at least one header value set - return (bool) \count($this->headers[$lowerName]); - } - - return \array_key_exists($index, $this->headers[$lowerName]); - } - - /** - * Set a header in the HeaderSet. - * - * The header may be a previously fetched header via {@link get()} or it may - * be one that has been created separately. - * - * If $index is specified, the header will be inserted into the set at this - * offset. - * - * @param int $index - */ - public function set(Swift_Mime_Header $header, $index = 0) - { - $this->storeHeader($header->getFieldName(), $header, $index); - } - - /** - * Get the header with the given $name. - * - * If multiple headers match, the actual one may be specified by $index. - * Returns NULL if none present. - * - * @param string $name - * @param int $index - * - * @return Swift_Mime_Header|null - */ - public function get($name, $index = 0) - { - $name = strtolower($name ?? ''); - - if (\func_num_args() < 2) { - if ($this->has($name)) { - $values = array_values($this->headers[$name]); - - return array_shift($values); - } - } else { - if ($this->has($name, $index)) { - return $this->headers[$name][$index]; - } - } - } - - /** - * Get all headers with the given $name. - * - * @param string $name - * - * @return array - */ - public function getAll($name = null) - { - if (!isset($name)) { - $headers = []; - foreach ($this->headers as $collection) { - $headers = array_merge($headers, $collection); - } - - return $headers; - } - - $lowerName = strtolower($name ?? ''); - if (!\array_key_exists($lowerName, $this->headers)) { - return []; - } - - return $this->headers[$lowerName]; - } - - /** - * Return the name of all Headers. - * - * @return array - */ - public function listAll() - { - $headers = $this->headers; - if ($this->canSort()) { - uksort($headers, [$this, 'sortHeaders']); - } - - return array_keys($headers); - } - - /** - * Remove the header with the given $name if it's set. - * - * If multiple headers match, the actual one may be specified by $index. - * - * @param string $name - * @param int $index - */ - public function remove($name, $index = 0) - { - $lowerName = strtolower($name ?? ''); - unset($this->headers[$lowerName][$index]); - } - - /** - * Remove all headers with the given $name. - * - * @param string $name - */ - public function removeAll($name) - { - $lowerName = strtolower($name ?? ''); - unset($this->headers[$lowerName]); - } - - /** - * Define a list of Header names as an array in the correct order. - * - * These Headers will be output in the given order where present. - */ - public function defineOrdering(array $sequence) - { - $this->order = array_flip(array_map('strtolower', $sequence)); - } - - /** - * Set a list of header names which must always be displayed when set. - * - * Usually headers without a field value won't be output unless set here. - */ - public function setAlwaysDisplayed(array $names) - { - $this->required = array_flip(array_map('strtolower', $names)); - } - - /** - * Notify this observer that the entity's charset has changed. - * - * @param string $charset - */ - public function charsetChanged($charset) - { - $this->setCharset($charset); - } - - /** - * Returns a string with a representation of all headers. - * - * @return string - */ - public function toString() - { - $string = ''; - $headers = $this->headers; - if ($this->canSort()) { - uksort($headers, [$this, 'sortHeaders']); - } - foreach ($headers as $collection) { - foreach ($collection as $header) { - if ($this->isDisplayed($header) || '' != $header->getFieldBody()) { - $string .= $header->toString(); - } - } - } - - return $string; - } - - /** - * Returns a string representation of this object. - * - * @return string - * - * @see toString() - */ - public function __toString() - { - return $this->toString(); - } - - /** Save a Header to the internal collection */ - private function storeHeader($name, Swift_Mime_Header $header, $offset = null) - { - if (!isset($this->headers[strtolower($name ?? '')])) { - $this->headers[strtolower($name ?? '')] = []; - } - if (!isset($offset)) { - $this->headers[strtolower($name ?? '')][] = $header; - } else { - $this->headers[strtolower($name ?? '')][$offset] = $header; - } - } - - /** Test if the headers can be sorted */ - private function canSort() - { - return \count($this->order) > 0; - } - - /** uksort() algorithm for Header ordering */ - private function sortHeaders($a, $b) - { - $lowerA = strtolower($a ?? ''); - $lowerB = strtolower($b ?? ''); - $aPos = \array_key_exists($lowerA, $this->order) ? $this->order[$lowerA] : -1; - $bPos = \array_key_exists($lowerB, $this->order) ? $this->order[$lowerB] : -1; - - if (-1 === $aPos && -1 === $bPos) { - // just be sure to be determinist here - return $a > $b ? -1 : 1; - } - - if (-1 == $aPos) { - return 1; - } elseif (-1 == $bPos) { - return -1; - } - - return $aPos < $bPos ? -1 : 1; - } - - /** Test if the given Header is always displayed */ - private function isDisplayed(Swift_Mime_Header $header) - { - return \array_key_exists(strtolower($header->getFieldName() ?? ''), $this->required); - } - - /** Notify all Headers of the new charset */ - private function notifyHeadersOfCharset($charset) - { - foreach ($this->headers as $headerGroup) { - foreach ($headerGroup as $header) { - $header->setCharset($charset); - } - } - } - - /** - * Make a deep copy of object. - */ - public function __clone() - { - $this->factory = clone $this->factory; - foreach ($this->headers as $groupKey => $headerGroup) { - foreach ($headerGroup as $key => $header) { - $this->headers[$groupKey][$key] = clone $header; - } - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php deleted file mode 100644 index 62da165..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php +++ /dev/null @@ -1,642 +0,0 @@ -getHeaders()->defineOrdering([ - 'Return-Path', - 'Received', - 'DKIM-Signature', - 'DomainKey-Signature', - 'Sender', - 'Message-ID', - 'Date', - 'Subject', - 'From', - 'Reply-To', - 'To', - 'Cc', - 'Bcc', - 'MIME-Version', - 'Content-Type', - 'Content-Transfer-Encoding', - ]); - $this->getHeaders()->setAlwaysDisplayed(['Date', 'Message-ID', 'From']); - $this->getHeaders()->addTextHeader('MIME-Version', '1.0'); - $this->setDate(new DateTimeImmutable()); - $this->setId($this->getId()); - $this->getHeaders()->addMailboxHeader('From'); - } - - /** - * Always returns {@link LEVEL_TOP} for a message instance. - * - * @return int - */ - public function getNestingLevel() - { - return self::LEVEL_TOP; - } - - /** - * Set the subject of this message. - * - * @param string $subject - * - * @return $this - */ - public function setSubject($subject) - { - if (!$this->setHeaderFieldModel('Subject', $subject)) { - $this->getHeaders()->addTextHeader('Subject', $subject); - } - - return $this; - } - - /** - * Get the subject of this message. - * - * @return string - */ - public function getSubject() - { - return $this->getHeaderFieldModel('Subject'); - } - - /** - * Set the date at which this message was created. - * - * @return $this - */ - public function setDate(DateTimeInterface $dateTime) - { - if (!$this->setHeaderFieldModel('Date', $dateTime)) { - $this->getHeaders()->addDateHeader('Date', $dateTime); - } - - return $this; - } - - /** - * Get the date at which this message was created. - * - * @return DateTimeInterface - */ - public function getDate() - { - return $this->getHeaderFieldModel('Date'); - } - - /** - * Set the return-path (the bounce address) of this message. - * - * @param string $address - * - * @return $this - */ - public function setReturnPath($address) - { - if (!$this->setHeaderFieldModel('Return-Path', $address)) { - $this->getHeaders()->addPathHeader('Return-Path', $address); - } - - return $this; - } - - /** - * Get the return-path (bounce address) of this message. - * - * @return string - */ - public function getReturnPath() - { - return $this->getHeaderFieldModel('Return-Path'); - } - - /** - * Set the sender of this message. - * - * This does not override the From field, but it has a higher significance. - * - * @param string $address - * @param string $name optional - * - * @return $this - */ - public function setSender($address, $name = null) - { - if (!\is_array($address) && isset($name)) { - $address = [$address => $name]; - } - - if (!$this->setHeaderFieldModel('Sender', (array) $address)) { - $this->getHeaders()->addMailboxHeader('Sender', (array) $address); - } - - return $this; - } - - /** - * Get the sender of this message. - * - * @return string - */ - public function getSender() - { - return $this->getHeaderFieldModel('Sender'); - } - - /** - * Add a From: address to this message. - * - * If $name is passed this name will be associated with the address. - * - * @param string $address - * @param string $name optional - * - * @return $this - */ - public function addFrom($address, $name = null) - { - $current = $this->getFrom(); - $current[$address] = $name; - - return $this->setFrom($current); - } - - /** - * Set the from address of this message. - * - * You may pass an array of addresses if this message is from multiple people. - * - * If $name is passed and the first parameter is a string, this name will be - * associated with the address. - * - * @param string|array $addresses - * @param string $name optional - * - * @return $this - */ - public function setFrom($addresses, $name = null) - { - if (!\is_array($addresses) && isset($name)) { - $addresses = [$addresses => $name]; - } - - if (!$this->setHeaderFieldModel('From', (array) $addresses)) { - $this->getHeaders()->addMailboxHeader('From', (array) $addresses); - } - - return $this; - } - - /** - * Get the from address of this message. - * - * @return mixed - */ - public function getFrom() - { - return $this->getHeaderFieldModel('From'); - } - - /** - * Add a Reply-To: address to this message. - * - * If $name is passed this name will be associated with the address. - * - * @param string $address - * @param string $name optional - * - * @return $this - */ - public function addReplyTo($address, $name = null) - { - $current = $this->getReplyTo(); - $current[$address] = $name; - - return $this->setReplyTo($current); - } - - /** - * Set the reply-to address of this message. - * - * You may pass an array of addresses if replies will go to multiple people. - * - * If $name is passed and the first parameter is a string, this name will be - * associated with the address. - * - * @param mixed $addresses - * @param string $name optional - * - * @return $this - */ - public function setReplyTo($addresses, $name = null) - { - if (!\is_array($addresses) && isset($name)) { - $addresses = [$addresses => $name]; - } - - if (!$this->setHeaderFieldModel('Reply-To', (array) $addresses)) { - $this->getHeaders()->addMailboxHeader('Reply-To', (array) $addresses); - } - - return $this; - } - - /** - * Get the reply-to address of this message. - * - * @return string - */ - public function getReplyTo() - { - return $this->getHeaderFieldModel('Reply-To'); - } - - /** - * Add a To: address to this message. - * - * If $name is passed this name will be associated with the address. - * - * @param string $address - * @param string $name optional - * - * @return $this - */ - public function addTo($address, $name = null) - { - $current = $this->getTo(); - $current[$address] = $name; - - return $this->setTo($current); - } - - /** - * Set the to addresses of this message. - * - * If multiple recipients will receive the message an array should be used. - * Example: array('receiver@domain.org', 'other@domain.org' => 'A name') - * - * If $name is passed and the first parameter is a string, this name will be - * associated with the address. - * - * @param mixed $addresses - * @param string $name optional - * - * @return $this - */ - public function setTo($addresses, $name = null) - { - if (!\is_array($addresses) && isset($name)) { - $addresses = [$addresses => $name]; - } - - if (!$this->setHeaderFieldModel('To', (array) $addresses)) { - $this->getHeaders()->addMailboxHeader('To', (array) $addresses); - } - - return $this; - } - - /** - * Get the To addresses of this message. - * - * @return array - */ - public function getTo() - { - return $this->getHeaderFieldModel('To'); - } - - /** - * Add a Cc: address to this message. - * - * If $name is passed this name will be associated with the address. - * - * @param string $address - * @param string $name optional - * - * @return $this - */ - public function addCc($address, $name = null) - { - $current = $this->getCc(); - $current[$address] = $name; - - return $this->setCc($current); - } - - /** - * Set the Cc addresses of this message. - * - * If $name is passed and the first parameter is a string, this name will be - * associated with the address. - * - * @param mixed $addresses - * @param string $name optional - * - * @return $this - */ - public function setCc($addresses, $name = null) - { - if (!\is_array($addresses) && isset($name)) { - $addresses = [$addresses => $name]; - } - - if (!$this->setHeaderFieldModel('Cc', (array) $addresses)) { - $this->getHeaders()->addMailboxHeader('Cc', (array) $addresses); - } - - return $this; - } - - /** - * Get the Cc address of this message. - * - * @return array - */ - public function getCc() - { - return $this->getHeaderFieldModel('Cc'); - } - - /** - * Add a Bcc: address to this message. - * - * If $name is passed this name will be associated with the address. - * - * @param string $address - * @param string $name optional - * - * @return $this - */ - public function addBcc($address, $name = null) - { - $current = $this->getBcc(); - $current[$address] = $name; - - return $this->setBcc($current); - } - - /** - * Set the Bcc addresses of this message. - * - * If $name is passed and the first parameter is a string, this name will be - * associated with the address. - * - * @param mixed $addresses - * @param string $name optional - * - * @return $this - */ - public function setBcc($addresses, $name = null) - { - if (!\is_array($addresses) && isset($name)) { - $addresses = [$addresses => $name]; - } - - if (!$this->setHeaderFieldModel('Bcc', (array) $addresses)) { - $this->getHeaders()->addMailboxHeader('Bcc', (array) $addresses); - } - - return $this; - } - - /** - * Get the Bcc addresses of this message. - * - * @return array - */ - public function getBcc() - { - return $this->getHeaderFieldModel('Bcc'); - } - - /** - * Set the priority of this message. - * - * The value is an integer where 1 is the highest priority and 5 is the lowest. - * - * @param int $priority - * - * @return $this - */ - public function setPriority($priority) - { - $priorityMap = [ - self::PRIORITY_HIGHEST => 'Highest', - self::PRIORITY_HIGH => 'High', - self::PRIORITY_NORMAL => 'Normal', - self::PRIORITY_LOW => 'Low', - self::PRIORITY_LOWEST => 'Lowest', - ]; - $pMapKeys = array_keys($priorityMap); - if ($priority > max($pMapKeys)) { - $priority = max($pMapKeys); - } elseif ($priority < min($pMapKeys)) { - $priority = min($pMapKeys); - } - if (!$this->setHeaderFieldModel('X-Priority', - sprintf('%d (%s)', $priority, $priorityMap[$priority]))) { - $this->getHeaders()->addTextHeader('X-Priority', - sprintf('%d (%s)', $priority, $priorityMap[$priority])); - } - - return $this; - } - - /** - * Get the priority of this message. - * - * The returned value is an integer where 1 is the highest priority and 5 - * is the lowest. - * - * @return int - */ - public function getPriority() - { - list($priority) = sscanf($this->getHeaderFieldModel('X-Priority'), - '%[1-5]' - ); - - return $priority ?? 3; - } - - /** - * Ask for a delivery receipt from the recipient to be sent to $addresses. - * - * @param array $addresses - * - * @return $this - */ - public function setReadReceiptTo($addresses) - { - if (!$this->setHeaderFieldModel('Disposition-Notification-To', $addresses)) { - $this->getHeaders() - ->addMailboxHeader('Disposition-Notification-To', $addresses); - } - - return $this; - } - - /** - * Get the addresses to which a read-receipt will be sent. - * - * @return string - */ - public function getReadReceiptTo() - { - return $this->getHeaderFieldModel('Disposition-Notification-To'); - } - - /** - * Attach a {@link Swift_Mime_SimpleMimeEntity} such as an Attachment or MimePart. - * - * @return $this - */ - public function attach(Swift_Mime_SimpleMimeEntity $entity) - { - $this->setChildren(array_merge($this->getChildren(), [$entity])); - - return $this; - } - - /** - * Remove an already attached entity. - * - * @return $this - */ - public function detach(Swift_Mime_SimpleMimeEntity $entity) - { - $newChildren = []; - foreach ($this->getChildren() as $child) { - if ($entity !== $child) { - $newChildren[] = $child; - } - } - $this->setChildren($newChildren); - - return $this; - } - - /** - * Attach a {@link Swift_Mime_SimpleMimeEntity} and return it's CID source. - * - * This method should be used when embedding images or other data in a message. - * - * @return string - */ - public function embed(Swift_Mime_SimpleMimeEntity $entity) - { - $this->attach($entity); - - return 'cid:'.$entity->getId(); - } - - /** - * Get this message as a complete string. - * - * @return string - */ - public function toString() - { - if (\count($children = $this->getChildren()) > 0 && '' != $this->getBody()) { - $this->setChildren(array_merge([$this->becomeMimePart()], $children)); - $string = parent::toString(); - $this->setChildren($children); - } else { - $string = parent::toString(); - } - - return $string; - } - - /** - * Returns a string representation of this object. - * - * @see toString() - * - * @return string - */ - public function __toString() - { - return $this->toString(); - } - - /** - * Write this message to a {@link Swift_InputByteStream}. - */ - public function toByteStream(Swift_InputByteStream $is) - { - if (\count($children = $this->getChildren()) > 0 && '' != $this->getBody()) { - $this->setChildren(array_merge([$this->becomeMimePart()], $children)); - parent::toByteStream($is); - $this->setChildren($children); - } else { - parent::toByteStream($is); - } - } - - /** @see Swift_Mime_SimpleMimeEntity::getIdField() */ - protected function getIdField() - { - return 'Message-ID'; - } - - /** Turn the body of this message into a child of itself if needed */ - protected function becomeMimePart() - { - $part = new parent($this->getHeaders()->newInstance(), $this->getEncoder(), - $this->getCache(), $this->getIdGenerator(), $this->userCharset - ); - $part->setContentType($this->userContentType); - $part->setBody($this->getBody()); - $part->setFormat($this->userFormat); - $part->setDelSp($this->userDelSp); - $part->setNestingLevel($this->getTopNestingLevel()); - - return $part; - } - - /** Get the highest nesting level nested inside this message */ - private function getTopNestingLevel() - { - $highestLevel = $this->getNestingLevel(); - foreach ($this->getChildren() as $child) { - $childLevel = $child->getNestingLevel(); - if ($highestLevel < $childLevel) { - $highestLevel = $childLevel; - } - } - - return $highestLevel; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php deleted file mode 100644 index 03eaf47..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php +++ /dev/null @@ -1,826 +0,0 @@ - [self::LEVEL_TOP, self::LEVEL_MIXED], - 'multipart/alternative' => [self::LEVEL_MIXED, self::LEVEL_ALTERNATIVE], - 'multipart/related' => [self::LEVEL_ALTERNATIVE, self::LEVEL_RELATED], - ]; - - /** A set of filter rules to define what level an entity should be nested at */ - private $compoundLevelFilters = []; - - /** The nesting level of this entity */ - private $nestingLevel = self::LEVEL_ALTERNATIVE; - - /** A KeyCache instance used during encoding and streaming */ - private $cache; - - /** Direct descendants of this entity */ - private $immediateChildren = []; - - /** All descendants of this entity */ - private $children = []; - - /** The maximum line length of the body of this entity */ - private $maxLineLength = 78; - - /** The order in which alternative mime types should appear */ - private $alternativePartOrder = [ - 'text/plain' => 1, - 'text/html' => 2, - 'multipart/related' => 3, - ]; - - /** The CID of this entity */ - private $id; - - /** The key used for accessing the cache */ - private $cacheKey; - - protected $userContentType; - - /** - * Create a new SimpleMimeEntity with $headers, $encoder and $cache. - */ - public function __construct(Swift_Mime_SimpleHeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_IdGenerator $idGenerator) - { - $this->cacheKey = bin2hex(random_bytes(16)); // set 32 hex values - $this->cache = $cache; - $this->headers = $headers; - $this->idGenerator = $idGenerator; - $this->setEncoder($encoder); - $this->headers->defineOrdering(['Content-Type', 'Content-Transfer-Encoding']); - - // This array specifies that, when the entire MIME document contains - // $compoundLevel, then for each child within $level, if its Content-Type - // is $contentType then it should be treated as if it's level is - // $neededLevel instead. I tried to write that unambiguously! :-\ - // Data Structure: - // array ( - // $compoundLevel => array( - // $level => array( - // $contentType => $neededLevel - // ) - // ) - // ) - - $this->compoundLevelFilters = [ - (self::LEVEL_ALTERNATIVE + self::LEVEL_RELATED) => [ - self::LEVEL_ALTERNATIVE => [ - 'text/plain' => self::LEVEL_ALTERNATIVE, - 'text/html' => self::LEVEL_RELATED, - ], - ], - ]; - - $this->id = $this->idGenerator->generateId(); - } - - /** - * Generate a new Content-ID or Message-ID for this MIME entity. - * - * @return string - */ - public function generateId() - { - $this->setId($this->idGenerator->generateId()); - - return $this->id; - } - - /** - * Get the {@link Swift_Mime_SimpleHeaderSet} for this entity. - * - * @return Swift_Mime_SimpleHeaderSet - */ - public function getHeaders() - { - return $this->headers; - } - - /** - * Get the nesting level of this entity. - * - * @see LEVEL_TOP, LEVEL_MIXED, LEVEL_RELATED, LEVEL_ALTERNATIVE - * - * @return int - */ - public function getNestingLevel() - { - return $this->nestingLevel; - } - - /** - * Get the Content-type of this entity. - * - * @return string - */ - public function getContentType() - { - return $this->getHeaderFieldModel('Content-Type'); - } - - /** - * Get the Body Content-type of this entity. - * - * @return string - */ - public function getBodyContentType() - { - return $this->userContentType; - } - - /** - * Set the Content-type of this entity. - * - * @param string $type - * - * @return $this - */ - public function setContentType($type) - { - $this->setContentTypeInHeaders($type); - // Keep track of the value so that if the content-type changes automatically - // due to added child entities, it can be restored if they are later removed - $this->userContentType = $type; - - return $this; - } - - /** - * Get the CID of this entity. - * - * The CID will only be present in headers if a Content-ID header is present. - * - * @return string - */ - public function getId() - { - $tmp = (array) $this->getHeaderFieldModel($this->getIdField()); - - return $this->headers->has($this->getIdField()) ? current($tmp) : $this->id; - } - - /** - * Set the CID of this entity. - * - * @param string $id - * - * @return $this - */ - public function setId($id) - { - if (!$this->setHeaderFieldModel($this->getIdField(), $id)) { - $this->headers->addIdHeader($this->getIdField(), $id); - } - $this->id = $id; - - return $this; - } - - /** - * Get the description of this entity. - * - * This value comes from the Content-Description header if set. - * - * @return string - */ - public function getDescription() - { - return $this->getHeaderFieldModel('Content-Description'); - } - - /** - * Set the description of this entity. - * - * This method sets a value in the Content-ID header. - * - * @param string $description - * - * @return $this - */ - public function setDescription($description) - { - if (!$this->setHeaderFieldModel('Content-Description', $description)) { - $this->headers->addTextHeader('Content-Description', $description); - } - - return $this; - } - - /** - * Get the maximum line length of the body of this entity. - * - * @return int - */ - public function getMaxLineLength() - { - return $this->maxLineLength; - } - - /** - * Set the maximum line length of lines in this body. - * - * Though not enforced by the library, lines should not exceed 1000 chars. - * - * @param int $length - * - * @return $this - */ - public function setMaxLineLength($length) - { - $this->maxLineLength = $length; - - return $this; - } - - /** - * Get all children added to this entity. - * - * @return Swift_Mime_SimpleMimeEntity[] - */ - public function getChildren() - { - return $this->children; - } - - /** - * Set all children of this entity. - * - * @param Swift_Mime_SimpleMimeEntity[] $children - * @param int $compoundLevel For internal use only - * - * @return $this - */ - public function setChildren(array $children, $compoundLevel = null) - { - // TODO: Try to refactor this logic - $compoundLevel = $compoundLevel ?? $this->getCompoundLevel($children); - $immediateChildren = []; - $grandchildren = []; - $newContentType = $this->userContentType; - - foreach ($children as $child) { - $level = $this->getNeededChildLevel($child, $compoundLevel); - if (empty($immediateChildren)) { - //first iteration - $immediateChildren = [$child]; - } else { - $nextLevel = $this->getNeededChildLevel($immediateChildren[0], $compoundLevel); - if ($nextLevel == $level) { - $immediateChildren[] = $child; - } elseif ($level < $nextLevel) { - // Re-assign immediateChildren to grandchildren - $grandchildren = array_merge($grandchildren, $immediateChildren); - // Set new children - $immediateChildren = [$child]; - } else { - $grandchildren[] = $child; - } - } - } - - if ($immediateChildren) { - $lowestLevel = $this->getNeededChildLevel($immediateChildren[0], $compoundLevel); - - // Determine which composite media type is needed to accommodate the - // immediate children - foreach ($this->compositeRanges as $mediaType => $range) { - if ($lowestLevel > $range[0] && $lowestLevel <= $range[1]) { - $newContentType = $mediaType; - - break; - } - } - - // Put any grandchildren in a subpart - if (!empty($grandchildren)) { - $subentity = $this->createChild(); - $subentity->setNestingLevel($lowestLevel); - $subentity->setChildren($grandchildren, $compoundLevel); - array_unshift($immediateChildren, $subentity); - } - } - - $this->immediateChildren = $immediateChildren; - $this->children = $children; - $this->setContentTypeInHeaders($newContentType); - $this->fixHeaders(); - $this->sortChildren(); - - return $this; - } - - /** - * Get the body of this entity as a string. - * - * @return string - */ - public function getBody() - { - return $this->body instanceof Swift_OutputByteStream ? $this->readStream($this->body) : $this->body; - } - - /** - * Set the body of this entity, either as a string, or as an instance of - * {@link Swift_OutputByteStream}. - * - * @param mixed $body - * @param string $contentType optional - * - * @return $this - */ - public function setBody($body, $contentType = null) - { - if ($body !== $this->body) { - $this->clearCache(); - } - - $this->body = $body; - if (null !== $contentType) { - $this->setContentType($contentType); - } - - return $this; - } - - /** - * Get the encoder used for the body of this entity. - * - * @return Swift_Mime_ContentEncoder - */ - public function getEncoder() - { - return $this->encoder; - } - - /** - * Set the encoder used for the body of this entity. - * - * @return $this - */ - public function setEncoder(Swift_Mime_ContentEncoder $encoder) - { - if ($encoder !== $this->encoder) { - $this->clearCache(); - } - - $this->encoder = $encoder; - $this->setEncoding($encoder->getName()); - $this->notifyEncoderChanged($encoder); - - return $this; - } - - /** - * Get the boundary used to separate children in this entity. - * - * @return string - */ - public function getBoundary() - { - if (!isset($this->boundary)) { - $this->boundary = '_=_swift_'.time().'_'.bin2hex(random_bytes(16)).'_=_'; - } - - return $this->boundary; - } - - /** - * Set the boundary used to separate children in this entity. - * - * @param string $boundary - * - * @throws Swift_RfcComplianceException - * - * @return $this - */ - public function setBoundary($boundary) - { - $this->assertValidBoundary($boundary); - $this->boundary = $boundary; - - return $this; - } - - /** - * Receive notification that the charset of this entity, or a parent entity - * has changed. - * - * @param string $charset - */ - public function charsetChanged($charset) - { - $this->notifyCharsetChanged($charset); - } - - /** - * Receive notification that the encoder of this entity or a parent entity - * has changed. - */ - public function encoderChanged(Swift_Mime_ContentEncoder $encoder) - { - $this->notifyEncoderChanged($encoder); - } - - /** - * Get this entire entity as a string. - * - * @return string - */ - public function toString() - { - $string = $this->headers->toString(); - $string .= $this->bodyToString(); - - return $string; - } - - /** - * Get this entire entity as a string. - * - * @return string - */ - protected function bodyToString() - { - $string = ''; - - if (isset($this->body) && empty($this->immediateChildren)) { - if ($this->cache->hasKey($this->cacheKey, 'body')) { - $body = $this->cache->getString($this->cacheKey, 'body'); - } else { - $body = "\r\n".$this->encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength()); - $this->cache->setString($this->cacheKey, 'body', $body, Swift_KeyCache::MODE_WRITE); - } - $string .= $body; - } - - if (!empty($this->immediateChildren)) { - foreach ($this->immediateChildren as $child) { - $string .= "\r\n\r\n--".$this->getBoundary()."\r\n"; - $string .= $child->toString(); - } - $string .= "\r\n\r\n--".$this->getBoundary()."--\r\n"; - } - - return $string; - } - - /** - * Returns a string representation of this object. - * - * @see toString() - * - * @return string - */ - public function __toString() - { - return $this->toString(); - } - - /** - * Write this entire entity to a {@see Swift_InputByteStream}. - */ - public function toByteStream(Swift_InputByteStream $is) - { - $is->write($this->headers->toString()); - $is->commit(); - - $this->bodyToByteStream($is); - } - - /** - * Write this entire entity to a {@link Swift_InputByteStream}. - */ - protected function bodyToByteStream(Swift_InputByteStream $is) - { - if (empty($this->immediateChildren)) { - if (isset($this->body)) { - if ($this->cache->hasKey($this->cacheKey, 'body')) { - $this->cache->exportToByteStream($this->cacheKey, 'body', $is); - } else { - $cacheIs = $this->cache->getInputByteStream($this->cacheKey, 'body'); - if ($cacheIs) { - $is->bind($cacheIs); - } - - $is->write("\r\n"); - - if ($this->body instanceof Swift_OutputByteStream) { - $this->body->setReadPointer(0); - - $this->encoder->encodeByteStream($this->body, $is, 0, $this->getMaxLineLength()); - } else { - $is->write($this->encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength())); - } - - if ($cacheIs) { - $is->unbind($cacheIs); - } - } - } - } - - if (!empty($this->immediateChildren)) { - foreach ($this->immediateChildren as $child) { - $is->write("\r\n\r\n--".$this->getBoundary()."\r\n"); - $child->toByteStream($is); - } - $is->write("\r\n\r\n--".$this->getBoundary()."--\r\n"); - } - } - - /** - * Get the name of the header that provides the ID of this entity. - */ - protected function getIdField() - { - return 'Content-ID'; - } - - /** - * Get the model data (usually an array or a string) for $field. - */ - protected function getHeaderFieldModel($field) - { - if ($this->headers->has($field)) { - return $this->headers->get($field)->getFieldBodyModel(); - } - } - - /** - * Set the model data for $field. - */ - protected function setHeaderFieldModel($field, $model) - { - if ($this->headers->has($field)) { - $this->headers->get($field)->setFieldBodyModel($model); - - return true; - } - - return false; - } - - /** - * Get the parameter value of $parameter on $field header. - */ - protected function getHeaderParameter($field, $parameter) - { - if ($this->headers->has($field)) { - return $this->headers->get($field)->getParameter($parameter); - } - } - - /** - * Set the parameter value of $parameter on $field header. - */ - protected function setHeaderParameter($field, $parameter, $value) - { - if ($this->headers->has($field)) { - $this->headers->get($field)->setParameter($parameter, $value); - - return true; - } - - return false; - } - - /** - * Re-evaluate what content type and encoding should be used on this entity. - */ - protected function fixHeaders() - { - if (\count($this->immediateChildren)) { - $this->setHeaderParameter('Content-Type', 'boundary', - $this->getBoundary() - ); - $this->headers->remove('Content-Transfer-Encoding'); - } else { - $this->setHeaderParameter('Content-Type', 'boundary', null); - $this->setEncoding($this->encoder->getName()); - } - } - - /** - * Get the KeyCache used in this entity. - * - * @return Swift_KeyCache - */ - protected function getCache() - { - return $this->cache; - } - - /** - * Get the ID generator. - * - * @return Swift_IdGenerator - */ - protected function getIdGenerator() - { - return $this->idGenerator; - } - - /** - * Empty the KeyCache for this entity. - */ - protected function clearCache() - { - $this->cache->clearKey($this->cacheKey, 'body'); - } - - private function readStream(Swift_OutputByteStream $os) - { - $string = ''; - while (false !== $bytes = $os->read(8192)) { - $string .= $bytes; - } - - $os->setReadPointer(0); - - return $string; - } - - private function setEncoding($encoding) - { - if (!$this->setHeaderFieldModel('Content-Transfer-Encoding', $encoding)) { - $this->headers->addTextHeader('Content-Transfer-Encoding', $encoding); - } - } - - private function assertValidBoundary($boundary) - { - if (!preg_match('/^[a-z0-9\'\(\)\+_\-,\.\/:=\?\ ]{0,69}[a-z0-9\'\(\)\+_\-,\.\/:=\?]$/Di', $boundary)) { - throw new Swift_RfcComplianceException('Mime boundary set is not RFC 2046 compliant.'); - } - } - - private function setContentTypeInHeaders($type) - { - if (!$this->setHeaderFieldModel('Content-Type', $type)) { - $this->headers->addParameterizedHeader('Content-Type', $type); - } - } - - private function setNestingLevel($level) - { - $this->nestingLevel = $level; - } - - private function getCompoundLevel($children) - { - $level = 0; - foreach ($children as $child) { - $level |= $child->getNestingLevel(); - } - - return $level; - } - - private function getNeededChildLevel($child, $compoundLevel) - { - $filter = []; - foreach ($this->compoundLevelFilters as $bitmask => $rules) { - if (($compoundLevel & $bitmask) === $bitmask) { - $filter = $rules + $filter; - } - } - - $realLevel = $child->getNestingLevel(); - $lowercaseType = strtolower($child->getContentType() ?? ''); - - if (isset($filter[$realLevel]) && isset($filter[$realLevel][$lowercaseType])) { - return $filter[$realLevel][$lowercaseType]; - } - - return $realLevel; - } - - private function createChild() - { - return new self($this->headers->newInstance(), $this->encoder, $this->cache, $this->idGenerator); - } - - private function notifyEncoderChanged(Swift_Mime_ContentEncoder $encoder) - { - foreach ($this->immediateChildren as $child) { - $child->encoderChanged($encoder); - } - } - - private function notifyCharsetChanged($charset) - { - $this->encoder->charsetChanged($charset); - $this->headers->charsetChanged($charset); - foreach ($this->immediateChildren as $child) { - $child->charsetChanged($charset); - } - } - - private function sortChildren() - { - $shouldSort = false; - foreach ($this->immediateChildren as $child) { - // NOTE: This include alternative parts moved into a related part - if (self::LEVEL_ALTERNATIVE == $child->getNestingLevel()) { - $shouldSort = true; - break; - } - } - - // Sort in order of preference, if there is one - if ($shouldSort) { - // Group the messages by order of preference - $sorted = []; - foreach ($this->immediateChildren as $child) { - $type = $child->getContentType(); - $level = \array_key_exists($type, $this->alternativePartOrder) ? $this->alternativePartOrder[$type] : max($this->alternativePartOrder) + 1; - - if (empty($sorted[$level])) { - $sorted[$level] = []; - } - - $sorted[$level][] = $child; - } - - ksort($sorted); - - $this->immediateChildren = array_reduce($sorted, 'array_merge', []); - } - } - - /** - * Empties it's own contents from the cache. - */ - public function __destruct() - { - if ($this->cache instanceof Swift_KeyCache) { - $this->cache->clearAll($this->cacheKey); - } - } - - /** - * Make a deep copy of object. - */ - public function __clone() - { - $this->headers = clone $this->headers; - $this->encoder = clone $this->encoder; - $this->cacheKey = bin2hex(random_bytes(16)); // set 32 hex values - $children = []; - foreach ($this->children as $pos => $child) { - $children[$pos] = clone $child; - } - $this->setChildren($children); - } - - public function __wakeup() - { - $this->cacheKey = bin2hex(random_bytes(16)); // set 32 hex values - $this->cache = new Swift_KeyCache_ArrayKeyCache(new Swift_KeyCache_SimpleKeyCacheInputStream()); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MimePart.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MimePart.php deleted file mode 100644 index ea97619..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MimePart.php +++ /dev/null @@ -1,45 +0,0 @@ -createDependenciesFor('mime.part') - ); - - if (!isset($charset)) { - $charset = Swift_DependencyContainer::getInstance() - ->lookup('properties.charset'); - } - $this->setBody($body); - $this->setCharset($charset); - if ($contentType) { - $this->setContentType($contentType); - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/NullTransport.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/NullTransport.php deleted file mode 100644 index e44b7af..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/NullTransport.php +++ /dev/null @@ -1,26 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Pretends messages have been sent, but just ignores them. - * - * @author Fabien Potencier - */ -class Swift_NullTransport extends Swift_Transport_NullTransport -{ - public function __construct() - { - \call_user_func_array( - [$this, 'Swift_Transport_NullTransport::__construct'], - Swift_DependencyContainer::getInstance() - ->createDependenciesFor('transport.null') - ); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/OutputByteStream.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/OutputByteStream.php deleted file mode 100644 index 1f26f9b..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/OutputByteStream.php +++ /dev/null @@ -1,46 +0,0 @@ -setThreshold($threshold); - $this->setSleepTime($sleep); - $this->sleeper = $sleeper; - } - - /** - * Set the number of emails to send before restarting. - * - * @param int $threshold - */ - public function setThreshold($threshold) - { - $this->threshold = $threshold; - } - - /** - * Get the number of emails to send before restarting. - * - * @return int - */ - public function getThreshold() - { - return $this->threshold; - } - - /** - * Set the number of seconds to sleep for during a restart. - * - * @param int $sleep time - */ - public function setSleepTime($sleep) - { - $this->sleep = $sleep; - } - - /** - * Get the number of seconds to sleep for during a restart. - * - * @return int - */ - public function getSleepTime() - { - return $this->sleep; - } - - /** - * Invoked immediately before the Message is sent. - */ - public function beforeSendPerformed(Swift_Events_SendEvent $evt) - { - } - - /** - * Invoked immediately after the Message is sent. - */ - public function sendPerformed(Swift_Events_SendEvent $evt) - { - ++$this->counter; - if ($this->counter >= $this->threshold) { - $transport = $evt->getTransport(); - $transport->stop(); - if ($this->sleep) { - $this->sleep($this->sleep); - } - $transport->start(); - $this->counter = 0; - } - } - - /** - * Sleep for $seconds. - * - * @param int $seconds - */ - public function sleep($seconds) - { - if (isset($this->sleeper)) { - $this->sleeper->sleep($seconds); - } else { - sleep($seconds); - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php deleted file mode 100644 index 36451f4..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php +++ /dev/null @@ -1,154 +0,0 @@ -getMessage(); - $message->toByteStream($this); - } - - /** - * Invoked immediately following a command being sent. - */ - public function commandSent(Swift_Events_CommandEvent $evt) - { - $command = $evt->getCommand(); - $this->out += \strlen($command); - } - - /** - * Invoked immediately following a response coming back. - */ - public function responseReceived(Swift_Events_ResponseEvent $evt) - { - $response = $evt->getResponse(); - $this->in += \strlen($response); - } - - /** - * Called when a message is sent so that the outgoing counter can be increased. - * - * @param string $bytes - */ - public function write($bytes) - { - $this->out += \strlen($bytes); - foreach ($this->mirrors as $stream) { - $stream->write($bytes); - } - } - - /** - * Not used. - */ - public function commit() - { - } - - /** - * Attach $is to this stream. - * - * The stream acts as an observer, receiving all data that is written. - * All {@link write()} and {@link flushBuffers()} operations will be mirrored. - */ - public function bind(Swift_InputByteStream $is) - { - $this->mirrors[] = $is; - } - - /** - * Remove an already bound stream. - * - * If $is is not bound, no errors will be raised. - * If the stream currently has any buffered data it will be written to $is - * before unbinding occurs. - */ - public function unbind(Swift_InputByteStream $is) - { - foreach ($this->mirrors as $k => $stream) { - if ($is === $stream) { - unset($this->mirrors[$k]); - } - } - } - - /** - * Not used. - */ - public function flushBuffers() - { - foreach ($this->mirrors as $stream) { - $stream->flushBuffers(); - } - } - - /** - * Get the total number of bytes sent to the server. - * - * @return int - */ - public function getBytesOut() - { - return $this->out; - } - - /** - * Get the total number of bytes received from the server. - * - * @return int - */ - public function getBytesIn() - { - return $this->in; - } - - /** - * Reset the internal counters to zero. - */ - public function reset() - { - $this->out = 0; - $this->in = 0; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php deleted file mode 100644 index 9f9f08b..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php +++ /dev/null @@ -1,31 +0,0 @@ - - * $replacements = array( - * "address1@domain.tld" => array("{a}" => "b", "{c}" => "d"), - * "address2@domain.tld" => array("{a}" => "x", "{c}" => "y") - * ) - * - * - * When using an instance of {@link Swift_Plugins_Decorator_Replacements}, - * the object should return just the array of replacements for the address - * given to {@link Swift_Plugins_Decorator_Replacements::getReplacementsFor()}. - * - * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements - */ - public function __construct($replacements) - { - $this->setReplacements($replacements); - } - - /** - * Sets replacements. - * - * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements - * - * @see __construct() - */ - public function setReplacements($replacements) - { - if (!($replacements instanceof Swift_Plugins_Decorator_Replacements)) { - $this->replacements = (array) $replacements; - } else { - $this->replacements = $replacements; - } - } - - /** - * Invoked immediately before the Message is sent. - */ - public function beforeSendPerformed(Swift_Events_SendEvent $evt) - { - $message = $evt->getMessage(); - $this->restoreMessage($message); - $to = array_keys($message->getTo()); - $address = array_shift($to); - if ($replacements = $this->getReplacementsFor($address)) { - $body = $message->getBody(); - $search = array_keys($replacements); - $replace = array_values($replacements); - $bodyReplaced = str_replace( - $search, $replace, $body - ); - if ($body != $bodyReplaced) { - $this->originalBody = $body; - $message->setBody($bodyReplaced); - } - - foreach ($message->getHeaders()->getAll() as $header) { - $body = $header->getFieldBodyModel(); - $count = 0; - if (\is_array($body)) { - $bodyReplaced = []; - foreach ($body as $key => $value) { - $count1 = 0; - $count2 = 0; - $key = \is_string($key) ? str_replace($search, $replace, $key, $count1) : $key; - $value = \is_string($value) ? str_replace($search, $replace, $value, $count2) : $value; - $bodyReplaced[$key] = $value; - - if (!$count && ($count1 || $count2)) { - $count = 1; - } - } - } elseif (\is_string($body)) { - $bodyReplaced = str_replace($search, $replace, $body, $count); - } - - if ($count) { - $this->originalHeaders[$header->getFieldName()] = $body; - $header->setFieldBodyModel($bodyReplaced); - } - } - - $children = (array) $message->getChildren(); - foreach ($children as $child) { - list($type) = sscanf($child->getContentType(), '%[^/]/%s'); - if ('text' == $type) { - $body = $child->getBody(); - $bodyReplaced = str_replace( - $search, $replace, $body - ); - if ($body != $bodyReplaced) { - $child->setBody($bodyReplaced); - $this->originalChildBodies[$child->getId()] = $body; - } - } - } - $this->lastMessage = $message; - } - } - - /** - * Find a map of replacements for the address. - * - * If this plugin was provided with a delegate instance of - * {@link Swift_Plugins_Decorator_Replacements} then the call will be - * delegated to it. Otherwise, it will attempt to find the replacements - * from the array provided in the constructor. - * - * If no replacements can be found, an empty value (NULL) is returned. - * - * @param string $address - * - * @return array - */ - public function getReplacementsFor($address) - { - if ($this->replacements instanceof Swift_Plugins_Decorator_Replacements) { - return $this->replacements->getReplacementsFor($address); - } - - return $this->replacements[$address] ?? null; - } - - /** - * Invoked immediately after the Message is sent. - */ - public function sendPerformed(Swift_Events_SendEvent $evt) - { - $this->restoreMessage($evt->getMessage()); - } - - /** Restore a changed message back to its original state */ - private function restoreMessage(Swift_Mime_SimpleMessage $message) - { - if ($this->lastMessage === $message) { - if (isset($this->originalBody)) { - $message->setBody($this->originalBody); - $this->originalBody = null; - } - if (!empty($this->originalHeaders)) { - foreach ($message->getHeaders()->getAll() as $header) { - if (\array_key_exists($header->getFieldName(), $this->originalHeaders)) { - $header->setFieldBodyModel($this->originalHeaders[$header->getFieldName()]); - } - } - $this->originalHeaders = []; - } - if (!empty($this->originalChildBodies)) { - $children = (array) $message->getChildren(); - foreach ($children as $child) { - $id = $child->getId(); - if (\array_key_exists($id, $this->originalChildBodies)) { - $child->setBody($this->originalChildBodies[$id]); - } - } - $this->originalChildBodies = []; - } - $this->lastMessage = null; - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php deleted file mode 100644 index 3f4dbbf..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php +++ /dev/null @@ -1,65 +0,0 @@ -sender = $sender; - } - - /** - * Invoked immediately before the Message is sent. - */ - public function beforeSendPerformed(Swift_Events_SendEvent $evt) - { - $message = $evt->getMessage(); - $headers = $message->getHeaders(); - - // save current recipients - $headers->addPathHeader('X-Swift-Return-Path', $message->getReturnPath()); - - // replace them with the one to send to - $message->setReturnPath($this->sender); - } - - /** - * Invoked immediately after the Message is sent. - */ - public function sendPerformed(Swift_Events_SendEvent $evt) - { - $message = $evt->getMessage(); - - // restore original headers - $headers = $message->getHeaders(); - - if ($headers->has('X-Swift-Return-Path')) { - $message->setReturnPath($headers->get('X-Swift-Return-Path')->getAddress()); - $headers->removeAll('X-Swift-Return-Path'); - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Logger.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Logger.php deleted file mode 100644 index d9bce89..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Logger.php +++ /dev/null @@ -1,36 +0,0 @@ -logger = $logger; - } - - /** - * Add a log entry. - * - * @param string $entry - */ - public function add($entry) - { - $this->logger->add($entry); - } - - /** - * Clear the log contents. - */ - public function clear() - { - $this->logger->clear(); - } - - /** - * Get this log as a string. - * - * @return string - */ - public function dump() - { - return $this->logger->dump(); - } - - /** - * Invoked immediately following a command being sent. - */ - public function commandSent(Swift_Events_CommandEvent $evt) - { - $command = $evt->getCommand(); - $this->logger->add(sprintf('>> %s', $command)); - } - - /** - * Invoked immediately following a response coming back. - */ - public function responseReceived(Swift_Events_ResponseEvent $evt) - { - $response = $evt->getResponse(); - $this->logger->add(sprintf('<< %s', $response)); - } - - /** - * Invoked just before a Transport is started. - */ - public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt) - { - $transportName = \get_class($evt->getSource()); - $this->logger->add(sprintf('++ Starting %s', $transportName)); - } - - /** - * Invoked immediately after the Transport is started. - */ - public function transportStarted(Swift_Events_TransportChangeEvent $evt) - { - $transportName = \get_class($evt->getSource()); - $this->logger->add(sprintf('++ %s started', $transportName)); - } - - /** - * Invoked just before a Transport is stopped. - */ - public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt) - { - $transportName = \get_class($evt->getSource()); - $this->logger->add(sprintf('++ Stopping %s', $transportName)); - } - - /** - * Invoked immediately after the Transport is stopped. - */ - public function transportStopped(Swift_Events_TransportChangeEvent $evt) - { - $transportName = \get_class($evt->getSource()); - $this->logger->add(sprintf('++ %s stopped', $transportName)); - } - - /** - * Invoked as a TransportException is thrown in the Transport system. - */ - public function exceptionThrown(Swift_Events_TransportExceptionEvent $evt) - { - $e = $evt->getException(); - $message = $e->getMessage(); - $code = $e->getCode(); - $this->logger->add(sprintf('!! %s (code: %s)', $message, $code)); - $message .= PHP_EOL; - $message .= 'Log data:'.PHP_EOL; - $message .= $this->logger->dump(); - $evt->cancelBubble(); - throw new Swift_TransportException($message, $code, $e->getPrevious()); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php deleted file mode 100644 index 6f595ad..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php +++ /dev/null @@ -1,72 +0,0 @@ -size = $size; - } - - /** - * Add a log entry. - * - * @param string $entry - */ - public function add($entry) - { - $this->log[] = $entry; - while (\count($this->log) > $this->size) { - array_shift($this->log); - } - } - - /** - * Clear the log contents. - */ - public function clear() - { - $this->log = []; - } - - /** - * Get this log as a string. - * - * @return string - */ - public function dump() - { - return implode(PHP_EOL, $this->log); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php deleted file mode 100644 index 40a53d2..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php +++ /dev/null @@ -1,58 +0,0 @@ -isHtml = $isHtml; - } - - /** - * Add a log entry. - * - * @param string $entry - */ - public function add($entry) - { - if ($this->isHtml) { - printf('%s%s%s', htmlspecialchars($entry, ENT_QUOTES), '
', PHP_EOL); - } else { - printf('%s%s', $entry, PHP_EOL); - } - } - - /** - * Not implemented. - */ - public function clear() - { - } - - /** - * Not implemented. - */ - public function dump() - { - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php deleted file mode 100644 index 39c48ed..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php +++ /dev/null @@ -1,70 +0,0 @@ -messages = []; - } - - /** - * Get the message list. - * - * @return Swift_Mime_SimpleMessage[] - */ - public function getMessages() - { - return $this->messages; - } - - /** - * Get the message count. - * - * @return int count - */ - public function countMessages() - { - return \count($this->messages); - } - - /** - * Empty the message list. - */ - public function clear() - { - $this->messages = []; - } - - /** - * Invoked immediately before the Message is sent. - */ - public function beforeSendPerformed(Swift_Events_SendEvent $evt) - { - $this->messages[] = clone $evt->getMessage(); - } - - /** - * Invoked immediately after the Message is sent. - */ - public function sendPerformed(Swift_Events_SendEvent $evt) - { - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php deleted file mode 100644 index fb99e4c..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php +++ /dev/null @@ -1,31 +0,0 @@ -host = $host; - $this->port = $port; - $this->crypto = $crypto; - } - - /** - * Set a Pop3Connection to delegate to instead of connecting directly. - * - * @return $this - */ - public function setConnection(Swift_Plugins_Pop_Pop3Connection $connection) - { - $this->connection = $connection; - - return $this; - } - - /** - * Bind this plugin to a specific SMTP transport instance. - */ - public function bindSmtp(Swift_Transport $smtp) - { - $this->transport = $smtp; - } - - /** - * Set the connection timeout in seconds (default 10). - * - * @param int $timeout - * - * @return $this - */ - public function setTimeout($timeout) - { - $this->timeout = (int) $timeout; - - return $this; - } - - /** - * Set the username to use when connecting (if needed). - * - * @param string $username - * - * @return $this - */ - public function setUsername($username) - { - $this->username = $username; - - return $this; - } - - /** - * Set the password to use when connecting (if needed). - * - * @param string $password - * - * @return $this - */ - public function setPassword($password) - { - $this->password = $password; - - return $this; - } - - /** - * Connect to the POP3 host and authenticate. - * - * @throws Swift_Plugins_Pop_Pop3Exception if connection fails - */ - public function connect() - { - if (isset($this->connection)) { - $this->connection->connect(); - } else { - if (!isset($this->socket)) { - if (!$socket = fsockopen( - $this->getHostString(), $this->port, $errno, $errstr, $this->timeout)) { - throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to connect to POP3 host [%s]: %s', $this->host, $errstr)); - } - $this->socket = $socket; - - if (false === $greeting = fgets($this->socket)) { - throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to connect to POP3 host [%s]', trim($greeting ?? ''))); - } - - $this->assertOk($greeting); - - if ($this->username) { - $this->command(sprintf("USER %s\r\n", $this->username)); - $this->command(sprintf("PASS %s\r\n", $this->password)); - } - } - } - } - - /** - * Disconnect from the POP3 host. - */ - public function disconnect() - { - if (isset($this->connection)) { - $this->connection->disconnect(); - } else { - $this->command("QUIT\r\n"); - if (!fclose($this->socket)) { - throw new Swift_Plugins_Pop_Pop3Exception(sprintf('POP3 host [%s] connection could not be stopped', $this->host)); - } - $this->socket = null; - } - } - - /** - * Invoked just before a Transport is started. - */ - public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt) - { - if (isset($this->transport)) { - if ($this->transport !== $evt->getTransport()) { - return; - } - } - - $this->connect(); - $this->disconnect(); - } - - /** - * Not used. - */ - public function transportStarted(Swift_Events_TransportChangeEvent $evt) - { - } - - /** - * Not used. - */ - public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt) - { - } - - /** - * Not used. - */ - public function transportStopped(Swift_Events_TransportChangeEvent $evt) - { - } - - private function command($command) - { - if (!fwrite($this->socket, $command)) { - throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to write command [%s] to POP3 host', trim($command ?? ''))); - } - - if (false === $response = fgets($this->socket)) { - throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to read from POP3 host after command [%s]', trim($command ?? ''))); - } - - $this->assertOk($response); - - return $response; - } - - private function assertOk($response) - { - if ('+OK' != substr($response, 0, 3)) { - throw new Swift_Plugins_Pop_Pop3Exception(sprintf('POP3 command failed [%s]', trim($response ?? ''))); - } - } - - private function getHostString() - { - $host = $this->host; - switch (strtolower($this->crypto ?? '')) { - case 'ssl': - $host = 'ssl://'.$host; - break; - - case 'tls': - $host = 'tls://'.$host; - break; - } - - return $host; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php deleted file mode 100644 index f7373b2..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php +++ /dev/null @@ -1,201 +0,0 @@ -recipient = $recipient; - $this->whitelist = $whitelist; - } - - /** - * Set the recipient of all messages. - * - * @param mixed $recipient - */ - public function setRecipient($recipient) - { - $this->recipient = $recipient; - } - - /** - * Get the recipient of all messages. - * - * @return mixed - */ - public function getRecipient() - { - return $this->recipient; - } - - /** - * Set a list of regular expressions to whitelist certain recipients. - */ - public function setWhitelist(array $whitelist) - { - $this->whitelist = $whitelist; - } - - /** - * Get the whitelist. - * - * @return array - */ - public function getWhitelist() - { - return $this->whitelist; - } - - /** - * Invoked immediately before the Message is sent. - */ - public function beforeSendPerformed(Swift_Events_SendEvent $evt) - { - $message = $evt->getMessage(); - $headers = $message->getHeaders(); - - // conditionally save current recipients - - if ($headers->has('to')) { - $headers->addMailboxHeader('X-Swift-To', $message->getTo()); - } - - if ($headers->has('cc')) { - $headers->addMailboxHeader('X-Swift-Cc', $message->getCc()); - } - - if ($headers->has('bcc')) { - $headers->addMailboxHeader('X-Swift-Bcc', $message->getBcc()); - } - - // Filter remaining headers against whitelist - $this->filterHeaderSet($headers, 'To'); - $this->filterHeaderSet($headers, 'Cc'); - $this->filterHeaderSet($headers, 'Bcc'); - - // Add each hard coded recipient - $to = $message->getTo(); - if (null === $to) { - $to = []; - } - - foreach ((array) $this->recipient as $recipient) { - if (!\array_key_exists($recipient, $to)) { - $message->addTo($recipient); - } - } - } - - /** - * Filter header set against a whitelist of regular expressions. - * - * @param string $type - */ - private function filterHeaderSet(Swift_Mime_SimpleHeaderSet $headerSet, $type) - { - foreach ($headerSet->getAll($type) as $headers) { - $headers->setNameAddresses($this->filterNameAddresses($headers->getNameAddresses())); - } - } - - /** - * Filtered list of addresses => name pairs. - * - * @return array - */ - private function filterNameAddresses(array $recipients) - { - $filtered = []; - - foreach ($recipients as $address => $name) { - if ($this->isWhitelisted($address)) { - $filtered[$address] = $name; - } - } - - return $filtered; - } - - /** - * Matches address against whitelist of regular expressions. - * - * @return bool - */ - protected function isWhitelisted($recipient) - { - if (\in_array($recipient, (array) $this->recipient)) { - return true; - } - - foreach ($this->whitelist as $pattern) { - if (preg_match($pattern, $recipient)) { - return true; - } - } - - return false; - } - - /** - * Invoked immediately after the Message is sent. - */ - public function sendPerformed(Swift_Events_SendEvent $evt) - { - $this->restoreMessage($evt->getMessage()); - } - - private function restoreMessage(Swift_Mime_SimpleMessage $message) - { - // restore original headers - $headers = $message->getHeaders(); - - if ($headers->has('X-Swift-To')) { - $message->setTo($headers->get('X-Swift-To')->getNameAddresses()); - $headers->removeAll('X-Swift-To'); - } else { - $message->setTo(null); - } - - if ($headers->has('X-Swift-Cc')) { - $message->setCc($headers->get('X-Swift-Cc')->getNameAddresses()); - $headers->removeAll('X-Swift-Cc'); - } - - if ($headers->has('X-Swift-Bcc')) { - $message->setBcc($headers->get('X-Swift-Bcc')->getNameAddresses()); - $headers->removeAll('X-Swift-Bcc'); - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporter.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporter.php deleted file mode 100644 index b881833..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporter.php +++ /dev/null @@ -1,31 +0,0 @@ -reporter = $reporter; - } - - /** - * Not used. - */ - public function beforeSendPerformed(Swift_Events_SendEvent $evt) - { - } - - /** - * Invoked immediately after the Message is sent. - */ - public function sendPerformed(Swift_Events_SendEvent $evt) - { - $message = $evt->getMessage(); - $failures = array_flip($evt->getFailedRecipients()); - foreach ((array) $message->getTo() as $address => $null) { - $this->reporter->notify($message, $address, (\array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS)); - } - foreach ((array) $message->getCc() as $address => $null) { - $this->reporter->notify($message, $address, (\array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS)); - } - foreach ((array) $message->getBcc() as $address => $null) { - $this->reporter->notify($message, $address, (\array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS)); - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php deleted file mode 100644 index 249cffb..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php +++ /dev/null @@ -1,58 +0,0 @@ -failures_cache[$address])) { - $this->failures[] = $address; - $this->failures_cache[$address] = true; - } - } - - /** - * Get an array of addresses for which delivery failed. - * - * @return array - */ - public function getFailedRecipients() - { - return $this->failures; - } - - /** - * Clear the buffer (empty the list). - */ - public function clear() - { - $this->failures = $this->failures_cache = []; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php deleted file mode 100644 index 1cfc3f9..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php +++ /dev/null @@ -1,38 +0,0 @@ -'.PHP_EOL; - echo 'PASS '.$address.PHP_EOL; - echo ''.PHP_EOL; - flush(); - } else { - echo '
'.PHP_EOL; - echo 'FAIL '.$address.PHP_EOL; - echo '
'.PHP_EOL; - flush(); - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php deleted file mode 100644 index 595c0f6..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php +++ /dev/null @@ -1,24 +0,0 @@ -rate = $rate; - $this->mode = $mode; - $this->sleeper = $sleeper; - $this->timer = $timer; - } - - /** - * Invoked immediately before the Message is sent. - */ - public function beforeSendPerformed(Swift_Events_SendEvent $evt) - { - $time = $this->getTimestamp(); - if (!isset($this->start)) { - $this->start = $time; - } - $duration = $time - $this->start; - - switch ($this->mode) { - case self::BYTES_PER_MINUTE: - $sleep = $this->throttleBytesPerMinute($duration); - break; - case self::MESSAGES_PER_SECOND: - $sleep = $this->throttleMessagesPerSecond($duration); - break; - case self::MESSAGES_PER_MINUTE: - $sleep = $this->throttleMessagesPerMinute($duration); - break; - default: - $sleep = 0; - break; - } - - if ($sleep > 0) { - $this->sleep($sleep); - } - } - - /** - * Invoked when a Message is sent. - */ - public function sendPerformed(Swift_Events_SendEvent $evt) - { - parent::sendPerformed($evt); - ++$this->messages; - } - - /** - * Sleep for $seconds. - * - * @param int $seconds - */ - public function sleep($seconds) - { - if (isset($this->sleeper)) { - $this->sleeper->sleep($seconds); - } else { - sleep($seconds); - } - } - - /** - * Get the current UNIX timestamp. - * - * @return int - */ - public function getTimestamp() - { - if (isset($this->timer)) { - return $this->timer->getTimestamp(); - } - - return time(); - } - - /** - * Get a number of seconds to sleep for. - * - * @param int $timePassed - * - * @return int - */ - private function throttleBytesPerMinute($timePassed) - { - $expectedDuration = $this->getBytesOut() / ($this->rate / 60); - - return (int) ceil($expectedDuration - $timePassed); - } - - /** - * Get a number of seconds to sleep for. - * - * @param int $timePassed - * - * @return int - */ - private function throttleMessagesPerSecond($timePassed) - { - $expectedDuration = $this->messages / $this->rate; - - return (int) ceil($expectedDuration - $timePassed); - } - - /** - * Get a number of seconds to sleep for. - * - * @param int $timePassed - * - * @return int - */ - private function throttleMessagesPerMinute($timePassed) - { - $expectedDuration = $this->messages / ($this->rate / 60); - - return (int) ceil($expectedDuration - $timePassed); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Timer.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Timer.php deleted file mode 100644 index 9c8deb3..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Timer.php +++ /dev/null @@ -1,24 +0,0 @@ -register('properties.charset')->asValue($charset); - - return $this; - } - - /** - * Set the directory where temporary files can be saved. - * - * @param string $dir - * - * @return $this - */ - public function setTempDir($dir) - { - Swift_DependencyContainer::getInstance()->register('tempdir')->asValue($dir); - - return $this; - } - - /** - * Set the type of cache to use (i.e. "disk" or "array"). - * - * @param string $type - * - * @return $this - */ - public function setCacheType($type) - { - Swift_DependencyContainer::getInstance()->register('cache')->asAliasOf(sprintf('cache.%s', $type)); - - return $this; - } - - /** - * Set the QuotedPrintable dot escaper preference. - * - * @param bool $dotEscape - * - * @return $this - */ - public function setQPDotEscape($dotEscape) - { - $dotEscape = !empty($dotEscape); - Swift_DependencyContainer::getInstance() - ->register('mime.qpcontentencoder') - ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder') - ->withDependencies(['mime.charstream', 'mime.bytecanonicalizer']) - ->addConstructorValue($dotEscape); - - return $this; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php deleted file mode 100644 index 2897474..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php +++ /dev/null @@ -1,27 +0,0 @@ -createDependenciesFor('transport.sendmail') - ); - - $this->setCommand($command); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signer.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signer.php deleted file mode 100644 index 26c5e28..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signer.php +++ /dev/null @@ -1,19 +0,0 @@ - - */ -interface Swift_Signer -{ - public function reset(); -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/BodySigner.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/BodySigner.php deleted file mode 100644 index b25c427..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/BodySigner.php +++ /dev/null @@ -1,31 +0,0 @@ - - */ -interface Swift_Signers_BodySigner extends Swift_Signer -{ - /** - * Change the Swift_Signed_Message to apply the singing. - * - * @return self - */ - public function signMessage(Swift_Message $message); - - /** - * Return the list of header a signer might tamper. - * - * @return array - */ - public function getAlteredHeaders(); -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php deleted file mode 100644 index ec82dc0..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php +++ /dev/null @@ -1,682 +0,0 @@ - - */ -class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner -{ - /** - * PrivateKey. - * - * @var string - */ - protected $privateKey; - - /** - * DomainName. - * - * @var string - */ - protected $domainName; - - /** - * Selector. - * - * @var string - */ - protected $selector; - - private $passphrase = ''; - - /** - * Hash algorithm used. - * - * @see RFC6376 3.3: Signers MUST implement and SHOULD sign using rsa-sha256. - * - * @var string - */ - protected $hashAlgorithm = 'rsa-sha256'; - - /** - * Body canon method. - * - * @var string - */ - protected $bodyCanon = 'simple'; - - /** - * Header canon method. - * - * @var string - */ - protected $headerCanon = 'simple'; - - /** - * Headers not being signed. - * - * @var array - */ - protected $ignoredHeaders = ['return-path' => true]; - - /** - * Signer identity. - * - * @var string - */ - protected $signerIdentity; - - /** - * BodyLength. - * - * @var int - */ - protected $bodyLen = 0; - - /** - * Maximum signedLen. - * - * @var int - */ - protected $maxLen = PHP_INT_MAX; - - /** - * Embbed bodyLen in signature. - * - * @var bool - */ - protected $showLen = false; - - /** - * When the signature has been applied (true means time()), false means not embedded. - * - * @var mixed - */ - protected $signatureTimestamp = true; - - /** - * When will the signature expires false means not embedded, if sigTimestamp is auto - * Expiration is relative, otherwise it's absolute. - * - * @var int - */ - protected $signatureExpiration = false; - - /** - * Must we embed signed headers? - * - * @var bool - */ - protected $debugHeaders = false; - - // work variables - /** - * Headers used to generate hash. - * - * @var array - */ - protected $signedHeaders = []; - - /** - * If debugHeaders is set store debugData here. - * - * @var string[] - */ - private $debugHeadersData = []; - - /** - * Stores the bodyHash. - * - * @var string - */ - private $bodyHash = ''; - - /** - * Stores the signature header. - * - * @var Swift_Mime_Headers_ParameterizedHeader - */ - protected $dkimHeader; - - private $bodyHashHandler; - - private $headerHash; - - private $headerCanonData = ''; - - private $bodyCanonEmptyCounter = 0; - - private $bodyCanonIgnoreStart = 2; - - private $bodyCanonSpace = false; - - private $bodyCanonLastChar = null; - - private $bodyCanonLine = ''; - - private $bound = []; - - /** - * Constructor. - * - * @param string $privateKey - * @param string $domainName - * @param string $selector - * @param string $passphrase - */ - public function __construct($privateKey, $domainName, $selector, $passphrase = '') - { - $this->privateKey = $privateKey; - $this->domainName = $domainName; - $this->signerIdentity = '@'.$domainName; - $this->selector = $selector; - $this->passphrase = $passphrase; - } - - /** - * Reset the Signer. - * - * @see Swift_Signer::reset() - */ - public function reset() - { - $this->headerHash = null; - $this->signedHeaders = []; - $this->bodyHash = null; - $this->bodyHashHandler = null; - $this->bodyCanonIgnoreStart = 2; - $this->bodyCanonEmptyCounter = 0; - $this->bodyCanonLastChar = null; - $this->bodyCanonSpace = false; - } - - /** - * Writes $bytes to the end of the stream. - * - * Writing may not happen immediately if the stream chooses to buffer. If - * you want to write these bytes with immediate effect, call {@link commit()} - * after calling write(). - * - * This method returns the sequence ID of the write (i.e. 1 for first, 2 for - * second, etc etc). - * - * @param string $bytes - * - * @return int - * - * @throws Swift_IoException - */ - // TODO fix return - public function write($bytes) - { - $this->canonicalizeBody($bytes); - foreach ($this->bound as $is) { - $is->write($bytes); - } - } - - /** - * For any bytes that are currently buffered inside the stream, force them - * off the buffer. - */ - public function commit() - { - // Nothing to do - return; - } - - /** - * Attach $is to this stream. - * - * The stream acts as an observer, receiving all data that is written. - * All {@link write()} and {@link flushBuffers()} operations will be mirrored. - */ - public function bind(Swift_InputByteStream $is) - { - // Don't have to mirror anything - $this->bound[] = $is; - - return; - } - - /** - * Remove an already bound stream. - * - * If $is is not bound, no errors will be raised. - * If the stream currently has any buffered data it will be written to $is - * before unbinding occurs. - */ - public function unbind(Swift_InputByteStream $is) - { - // Don't have to mirror anything - foreach ($this->bound as $k => $stream) { - if ($stream === $is) { - unset($this->bound[$k]); - - return; - } - } - } - - /** - * Flush the contents of the stream (empty it) and set the internal pointer - * to the beginning. - * - * @throws Swift_IoException - */ - public function flushBuffers() - { - $this->reset(); - } - - /** - * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1. - * - * @param string $hash 'rsa-sha1' or 'rsa-sha256' - * - * @throws Swift_SwiftException - * - * @return $this - */ - public function setHashAlgorithm($hash) - { - switch ($hash) { - case 'rsa-sha1': - $this->hashAlgorithm = 'rsa-sha1'; - break; - case 'rsa-sha256': - $this->hashAlgorithm = 'rsa-sha256'; - if (!\defined('OPENSSL_ALGO_SHA256')) { - throw new Swift_SwiftException('Unable to set sha256 as it is not supported by OpenSSL.'); - } - break; - default: - throw new Swift_SwiftException('Unable to set the hash algorithm, must be one of rsa-sha1 or rsa-sha256 (%s given).', $hash); - } - - return $this; - } - - /** - * Set the body canonicalization algorithm. - * - * @param string $canon - * - * @return $this - */ - public function setBodyCanon($canon) - { - if ('relaxed' == $canon) { - $this->bodyCanon = 'relaxed'; - } else { - $this->bodyCanon = 'simple'; - } - - return $this; - } - - /** - * Set the header canonicalization algorithm. - * - * @param string $canon - * - * @return $this - */ - public function setHeaderCanon($canon) - { - if ('relaxed' == $canon) { - $this->headerCanon = 'relaxed'; - } else { - $this->headerCanon = 'simple'; - } - - return $this; - } - - /** - * Set the signer identity. - * - * @param string $identity - * - * @return $this - */ - public function setSignerIdentity($identity) - { - $this->signerIdentity = $identity; - - return $this; - } - - /** - * Set the length of the body to sign. - * - * @param mixed $len (bool or int) - * - * @return $this - */ - public function setBodySignedLen($len) - { - if (true === $len) { - $this->showLen = true; - $this->maxLen = PHP_INT_MAX; - } elseif (false === $len) { - $this->showLen = false; - $this->maxLen = PHP_INT_MAX; - } else { - $this->showLen = true; - $this->maxLen = (int) $len; - } - - return $this; - } - - /** - * Set the signature timestamp. - * - * @param int $time A timestamp - * - * @return $this - */ - public function setSignatureTimestamp($time) - { - $this->signatureTimestamp = $time; - - return $this; - } - - /** - * Set the signature expiration timestamp. - * - * @param int $time A timestamp - * - * @return $this - */ - public function setSignatureExpiration($time) - { - $this->signatureExpiration = $time; - - return $this; - } - - /** - * Enable / disable the DebugHeaders. - * - * @param bool $debug - * - * @return Swift_Signers_DKIMSigner - */ - public function setDebugHeaders($debug) - { - $this->debugHeaders = (bool) $debug; - - return $this; - } - - /** - * Start Body. - */ - public function startBody() - { - // Init - switch ($this->hashAlgorithm) { - case 'rsa-sha256': - $this->bodyHashHandler = hash_init('sha256'); - break; - case 'rsa-sha1': - $this->bodyHashHandler = hash_init('sha1'); - break; - } - $this->bodyCanonLine = ''; - } - - /** - * End Body. - */ - public function endBody() - { - $this->endOfBody(); - } - - /** - * Returns the list of Headers Tampered by this plugin. - * - * @return array - */ - public function getAlteredHeaders() - { - if ($this->debugHeaders) { - return ['DKIM-Signature', 'X-DebugHash']; - } else { - return ['DKIM-Signature']; - } - } - - /** - * Adds an ignored Header. - * - * @param string $header_name - * - * @return Swift_Signers_DKIMSigner - */ - public function ignoreHeader($header_name) - { - $this->ignoredHeaders[strtolower($header_name ?? '')] = true; - - return $this; - } - - /** - * Set the headers to sign. - * - * @return Swift_Signers_DKIMSigner - */ - public function setHeaders(Swift_Mime_SimpleHeaderSet $headers) - { - $this->headerCanonData = ''; - // Loop through Headers - $listHeaders = $headers->listAll(); - foreach ($listHeaders as $hName) { - // Check if we need to ignore Header - if (!isset($this->ignoredHeaders[strtolower($hName ?? '')])) { - if ($headers->has($hName)) { - $tmp = $headers->getAll($hName); - foreach ($tmp as $header) { - if ('' != $header->getFieldBody()) { - $this->addHeader($header->toString()); - $this->signedHeaders[] = $header->getFieldName(); - } - } - } - } - } - - return $this; - } - - /** - * Add the signature to the given Headers. - * - * @return Swift_Signers_DKIMSigner - */ - public function addSignature(Swift_Mime_SimpleHeaderSet $headers) - { - // Prepare the DKIM-Signature - $params = ['v' => '1', 'a' => $this->hashAlgorithm, 'bh' => base64_encode($this->bodyHash ?? ''), 'd' => $this->domainName, 'h' => implode(': ', $this->signedHeaders), 'i' => $this->signerIdentity, 's' => $this->selector]; - if ('simple' != $this->bodyCanon) { - $params['c'] = $this->headerCanon.'/'.$this->bodyCanon; - } elseif ('simple' != $this->headerCanon) { - $params['c'] = $this->headerCanon; - } - if ($this->showLen) { - $params['l'] = $this->bodyLen; - } - if (true === $this->signatureTimestamp) { - $params['t'] = time(); - if (false !== $this->signatureExpiration) { - $params['x'] = $params['t'] + $this->signatureExpiration; - } - } else { - if (false !== $this->signatureTimestamp) { - $params['t'] = $this->signatureTimestamp; - } - if (false !== $this->signatureExpiration) { - $params['x'] = $this->signatureExpiration; - } - } - if ($this->debugHeaders) { - $params['z'] = implode('|', $this->debugHeadersData); - } - $string = ''; - foreach ($params as $k => $v) { - $string .= $k.'='.$v.'; '; - } - $string = trim($string); - $headers->addTextHeader('DKIM-Signature', $string); - // Add the last DKIM-Signature - $tmp = $headers->getAll('DKIM-Signature'); - $this->dkimHeader = end($tmp); - $this->addHeader(trim($this->dkimHeader->toString() ?? '')."\r\n b=", true); - if ($this->debugHeaders) { - $headers->addTextHeader('X-DebugHash', base64_encode($this->headerHash ?? '')); - } - $this->dkimHeader->setValue($string.' b='.trim(chunk_split(base64_encode($this->getEncryptedHash() ?? ''), 73, ' '))); - - return $this; - } - - /* Private helpers */ - - protected function addHeader($header, $is_sig = false) - { - switch ($this->headerCanon) { - case 'relaxed': - // Prepare Header and cascade - $exploded = explode(':', $header, 2); - $name = strtolower(trim($exploded[0])); - $value = str_replace("\r\n", '', $exploded[1]); - $value = preg_replace("/[ \t][ \t]+/", ' ', $value); - $header = $name.':'.trim($value).($is_sig ? '' : "\r\n"); - // no break - case 'simple': - // Nothing to do - } - $this->addToHeaderHash($header); - } - - protected function canonicalizeBody($string) - { - $len = \strlen($string); - $canon = ''; - $method = ('relaxed' == $this->bodyCanon); - for ($i = 0; $i < $len; ++$i) { - if ($this->bodyCanonIgnoreStart > 0) { - --$this->bodyCanonIgnoreStart; - continue; - } - switch ($string[$i]) { - case "\r": - $this->bodyCanonLastChar = "\r"; - break; - case "\n": - if ("\r" == $this->bodyCanonLastChar) { - if ($method) { - $this->bodyCanonSpace = false; - } - if ('' == $this->bodyCanonLine) { - ++$this->bodyCanonEmptyCounter; - } else { - $this->bodyCanonLine = ''; - $canon .= "\r\n"; - } - } else { - // Wooops Error - // todo handle it but should never happen - } - break; - case ' ': - case "\t": - if ($method) { - $this->bodyCanonSpace = true; - break; - } - // no break - default: - if ($this->bodyCanonEmptyCounter > 0) { - $canon .= str_repeat("\r\n", $this->bodyCanonEmptyCounter); - $this->bodyCanonEmptyCounter = 0; - } - if ($this->bodyCanonSpace) { - $this->bodyCanonLine .= ' '; - $canon .= ' '; - $this->bodyCanonSpace = false; - } - $this->bodyCanonLine .= $string[$i]; - $canon .= $string[$i]; - } - } - $this->addToBodyHash($canon); - } - - protected function endOfBody() - { - // Add trailing Line return if last line is non empty - if (\strlen($this->bodyCanonLine) > 0) { - $this->addToBodyHash("\r\n"); - } - $this->bodyHash = hash_final($this->bodyHashHandler, true); - } - - private function addToBodyHash($string) - { - $len = \strlen($string); - if ($len > ($new_len = ($this->maxLen - $this->bodyLen))) { - $string = substr($string, 0, $new_len); - $len = $new_len; - } - hash_update($this->bodyHashHandler, $string); - $this->bodyLen += $len; - } - - private function addToHeaderHash($header) - { - if ($this->debugHeaders) { - $this->debugHeadersData[] = trim($header ?? ''); - } - $this->headerCanonData .= $header; - } - - /** - * @throws Swift_SwiftException - * - * @return string - */ - private function getEncryptedHash() - { - $signature = ''; - switch ($this->hashAlgorithm) { - case 'rsa-sha1': - $algorithm = OPENSSL_ALGO_SHA1; - break; - case 'rsa-sha256': - $algorithm = OPENSSL_ALGO_SHA256; - break; - } - $pkeyId = openssl_get_privatekey($this->privateKey, $this->passphrase); - if (!$pkeyId) { - throw new Swift_SwiftException('Unable to load DKIM Private Key ['.openssl_error_string().']'); - } - if (openssl_sign($this->headerCanonData, $signature, $pkeyId, $algorithm)) { - return $signature; - } - throw new Swift_SwiftException('Unable to sign DKIM Hash ['.openssl_error_string().']'); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php deleted file mode 100644 index 5e2b67b..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php +++ /dev/null @@ -1,504 +0,0 @@ - - */ -class Swift_Signers_DomainKeySigner implements Swift_Signers_HeaderSigner -{ - /** - * PrivateKey. - * - * @var string - */ - protected $privateKey; - - /** - * DomainName. - * - * @var string - */ - protected $domainName; - - /** - * Selector. - * - * @var string - */ - protected $selector; - - /** - * Hash algorithm used. - * - * @var string - */ - protected $hashAlgorithm = 'rsa-sha1'; - - /** - * Canonisation method. - * - * @var string - */ - protected $canon = 'simple'; - - /** - * Headers not being signed. - * - * @var array - */ - protected $ignoredHeaders = []; - - /** - * Signer identity. - * - * @var string - */ - protected $signerIdentity; - - /** - * Must we embed signed headers? - * - * @var bool - */ - protected $debugHeaders = false; - - // work variables - /** - * Headers used to generate hash. - * - * @var array - */ - private $signedHeaders = []; - - /** - * Stores the signature header. - * - * @var Swift_Mime_Headers_ParameterizedHeader - */ - protected $domainKeyHeader; - - /** - * Hash Handler. - * - * @var resource|null - */ - private $hashHandler; - - private $canonData = ''; - - private $bodyCanonEmptyCounter = 0; - - private $bodyCanonIgnoreStart = 2; - - private $bodyCanonSpace = false; - - private $bodyCanonLastChar = null; - - private $bodyCanonLine = ''; - - private $bound = []; - - /** - * Constructor. - * - * @param string $privateKey - * @param string $domainName - * @param string $selector - */ - public function __construct($privateKey, $domainName, $selector) - { - $this->privateKey = $privateKey; - $this->domainName = $domainName; - $this->signerIdentity = '@'.$domainName; - $this->selector = $selector; - } - - /** - * Resets internal states. - * - * @return $this - */ - public function reset() - { - $this->hashHandler = null; - $this->bodyCanonIgnoreStart = 2; - $this->bodyCanonEmptyCounter = 0; - $this->bodyCanonLastChar = null; - $this->bodyCanonSpace = false; - - return $this; - } - - /** - * Writes $bytes to the end of the stream. - * - * Writing may not happen immediately if the stream chooses to buffer. If - * you want to write these bytes with immediate effect, call {@link commit()} - * after calling write(). - * - * This method returns the sequence ID of the write (i.e. 1 for first, 2 for - * second, etc etc). - * - * @param string $bytes - * - * @return int - * - * @throws Swift_IoException - * - * @return $this - */ - public function write($bytes) - { - $this->canonicalizeBody($bytes); - foreach ($this->bound as $is) { - $is->write($bytes); - } - - return $this; - } - - /** - * For any bytes that are currently buffered inside the stream, force them - * off the buffer. - * - * @throws Swift_IoException - * - * @return $this - */ - public function commit() - { - // Nothing to do - return $this; - } - - /** - * Attach $is to this stream. - * - * The stream acts as an observer, receiving all data that is written. - * All {@link write()} and {@link flushBuffers()} operations will be mirrored. - * - * @return $this - */ - public function bind(Swift_InputByteStream $is) - { - // Don't have to mirror anything - $this->bound[] = $is; - - return $this; - } - - /** - * Remove an already bound stream. - * - * If $is is not bound, no errors will be raised. - * If the stream currently has any buffered data it will be written to $is - * before unbinding occurs. - * - * @return $this - */ - public function unbind(Swift_InputByteStream $is) - { - // Don't have to mirror anything - foreach ($this->bound as $k => $stream) { - if ($stream === $is) { - unset($this->bound[$k]); - - break; - } - } - - return $this; - } - - /** - * Flush the contents of the stream (empty it) and set the internal pointer - * to the beginning. - * - * @throws Swift_IoException - * - * @return $this - */ - public function flushBuffers() - { - $this->reset(); - - return $this; - } - - /** - * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1 defaults to rsa-sha256. - * - * @param string $hash - * - * @return $this - */ - public function setHashAlgorithm($hash) - { - $this->hashAlgorithm = 'rsa-sha1'; - - return $this; - } - - /** - * Set the canonicalization algorithm. - * - * @param string $canon simple | nofws defaults to simple - * - * @return $this - */ - public function setCanon($canon) - { - if ('nofws' == $canon) { - $this->canon = 'nofws'; - } else { - $this->canon = 'simple'; - } - - return $this; - } - - /** - * Set the signer identity. - * - * @param string $identity - * - * @return $this - */ - public function setSignerIdentity($identity) - { - $this->signerIdentity = $identity; - - return $this; - } - - /** - * Enable / disable the DebugHeaders. - * - * @param bool $debug - * - * @return $this - */ - public function setDebugHeaders($debug) - { - $this->debugHeaders = (bool) $debug; - - return $this; - } - - /** - * Start Body. - */ - public function startBody() - { - } - - /** - * End Body. - */ - public function endBody() - { - $this->endOfBody(); - } - - /** - * Returns the list of Headers Tampered by this plugin. - * - * @return array - */ - public function getAlteredHeaders() - { - if ($this->debugHeaders) { - return ['DomainKey-Signature', 'X-DebugHash']; - } - - return ['DomainKey-Signature']; - } - - /** - * Adds an ignored Header. - * - * @param string $header_name - * - * @return $this - */ - public function ignoreHeader($header_name) - { - $this->ignoredHeaders[strtolower($header_name ?? '')] = true; - - return $this; - } - - /** - * Set the headers to sign. - * - * @return $this - */ - public function setHeaders(Swift_Mime_SimpleHeaderSet $headers) - { - $this->startHash(); - $this->canonData = ''; - // Loop through Headers - $listHeaders = $headers->listAll(); - foreach ($listHeaders as $hName) { - // Check if we need to ignore Header - if (!isset($this->ignoredHeaders[strtolower($hName ?? '')])) { - if ($headers->has($hName)) { - $tmp = $headers->getAll($hName); - foreach ($tmp as $header) { - if ('' != $header->getFieldBody()) { - $this->addHeader($header->toString()); - $this->signedHeaders[] = $header->getFieldName(); - } - } - } - } - } - $this->endOfHeaders(); - - return $this; - } - - /** - * Add the signature to the given Headers. - * - * @return $this - */ - public function addSignature(Swift_Mime_SimpleHeaderSet $headers) - { - // Prepare the DomainKey-Signature Header - $params = ['a' => $this->hashAlgorithm, 'b' => chunk_split(base64_encode($this->getEncryptedHash() ?? ''), 73, ' '), 'c' => $this->canon, 'd' => $this->domainName, 'h' => implode(': ', $this->signedHeaders), 'q' => 'dns', 's' => $this->selector]; - $string = ''; - foreach ($params as $k => $v) { - $string .= $k.'='.$v.'; '; - } - $string = trim($string); - $headers->addTextHeader('DomainKey-Signature', $string); - - return $this; - } - - /* Private helpers */ - - protected function addHeader($header) - { - switch ($this->canon) { - case 'nofws': - // Prepare Header and cascade - $exploded = explode(':', $header, 2); - $name = strtolower(trim($exploded[0])); - $value = str_replace("\r\n", '', $exploded[1]); - $value = preg_replace("/[ \t][ \t]+/", ' ', $value); - $header = $name.':'.trim($value)."\r\n"; - // no break - case 'simple': - // Nothing to do - } - $this->addToHash($header); - } - - protected function endOfHeaders() - { - $this->bodyCanonEmptyCounter = 1; - } - - protected function canonicalizeBody($string) - { - $len = \strlen($string); - $canon = ''; - $nofws = ('nofws' == $this->canon); - for ($i = 0; $i < $len; ++$i) { - if ($this->bodyCanonIgnoreStart > 0) { - --$this->bodyCanonIgnoreStart; - continue; - } - switch ($string[$i]) { - case "\r": - $this->bodyCanonLastChar = "\r"; - break; - case "\n": - if ("\r" == $this->bodyCanonLastChar) { - if ($nofws) { - $this->bodyCanonSpace = false; - } - if ('' == $this->bodyCanonLine) { - ++$this->bodyCanonEmptyCounter; - } else { - $this->bodyCanonLine = ''; - $canon .= "\r\n"; - } - } else { - // Wooops Error - throw new Swift_SwiftException('Invalid new line sequence in mail found \n without preceding \r'); - } - break; - case ' ': - case "\t": - case "\x09": //HTAB - if ($nofws) { - $this->bodyCanonSpace = true; - break; - } - // no break - default: - if ($this->bodyCanonEmptyCounter > 0) { - $canon .= str_repeat("\r\n", $this->bodyCanonEmptyCounter); - $this->bodyCanonEmptyCounter = 0; - } - $this->bodyCanonLine .= $string[$i]; - $canon .= $string[$i]; - } - } - $this->addToHash($canon); - } - - protected function endOfBody() - { - if (\strlen($this->bodyCanonLine) > 0) { - $this->addToHash("\r\n"); - } - } - - private function addToHash($string) - { - $this->canonData .= $string; - hash_update($this->hashHandler, $string); - } - - private function startHash() - { - // Init - switch ($this->hashAlgorithm) { - case 'rsa-sha1': - $this->hashHandler = hash_init('sha1'); - break; - } - $this->bodyCanonLine = ''; - } - - /** - * @throws Swift_SwiftException - * - * @return string - */ - private function getEncryptedHash() - { - $signature = ''; - $pkeyId = openssl_get_privatekey($this->privateKey); - if (!$pkeyId) { - throw new Swift_SwiftException('Unable to load DomainKey Private Key ['.openssl_error_string().']'); - } - if (openssl_sign($this->canonData, $signature, $pkeyId, OPENSSL_ALGO_SHA1)) { - return $signature; - } - throw new Swift_SwiftException('Unable to sign DomainKey Hash ['.openssl_error_string().']'); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php deleted file mode 100644 index 6f5c209..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php +++ /dev/null @@ -1,61 +0,0 @@ - - */ -interface Swift_Signers_HeaderSigner extends Swift_Signer, Swift_InputByteStream -{ - /** - * Exclude an header from the signed headers. - * - * @param string $header_name - * - * @return self - */ - public function ignoreHeader($header_name); - - /** - * Prepare the Signer to get a new Body. - * - * @return self - */ - public function startBody(); - - /** - * Give the signal that the body has finished streaming. - * - * @return self - */ - public function endBody(); - - /** - * Give the headers already given. - * - * @return self - */ - public function setHeaders(Swift_Mime_SimpleHeaderSet $headers); - - /** - * Add the header(s) to the headerSet. - * - * @return self - */ - public function addSignature(Swift_Mime_SimpleHeaderSet $headers); - - /** - * Return the list of header a signer might tamper. - * - * @return array - */ - public function getAlteredHeaders(); -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php deleted file mode 100644 index 520bcc1..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php +++ /dev/null @@ -1,183 +0,0 @@ - - * - * @deprecated since SwiftMailer 6.1.0; use Swift_Signers_DKIMSigner instead. - */ -class Swift_Signers_OpenDKIMSigner extends Swift_Signers_DKIMSigner -{ - private $peclLoaded = false; - - private $dkimHandler = null; - - private $dropFirstLF = true; - - const CANON_RELAXED = 1; - const CANON_SIMPLE = 2; - const SIG_RSA_SHA1 = 3; - const SIG_RSA_SHA256 = 4; - - public function __construct($privateKey, $domainName, $selector) - { - if (!\extension_loaded('opendkim')) { - throw new Swift_SwiftException('php-opendkim extension not found'); - } - - $this->peclLoaded = true; - - parent::__construct($privateKey, $domainName, $selector); - } - - public function addSignature(Swift_Mime_SimpleHeaderSet $headers) - { - $header = new Swift_Mime_Headers_OpenDKIMHeader('DKIM-Signature'); - $headerVal = $this->dkimHandler->getSignatureHeader(); - if (false === $headerVal || \is_int($headerVal)) { - throw new Swift_SwiftException('OpenDKIM Error: '.$this->dkimHandler->getError()); - } - $header->setValue($headerVal); - $headers->set($header); - - return $this; - } - - public function setHeaders(Swift_Mime_SimpleHeaderSet $headers) - { - $hash = 'rsa-sha1' == $this->hashAlgorithm ? OpenDKIMSign::ALG_RSASHA1 : OpenDKIMSign::ALG_RSASHA256; - $bodyCanon = 'simple' == $this->bodyCanon ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED; - $headerCanon = 'simple' == $this->headerCanon ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED; - $this->dkimHandler = new OpenDKIMSign($this->privateKey, $this->selector, $this->domainName, $headerCanon, $bodyCanon, $hash, -1); - // Hardcode signature Margin for now - $this->dkimHandler->setMargin(78); - - if (!is_numeric($this->signatureTimestamp)) { - OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, time()); - } else { - if (!OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, $this->signatureTimestamp)) { - throw new Swift_SwiftException('Unable to force signature timestamp ['.openssl_error_string().']'); - } - } - if (isset($this->signerIdentity)) { - $this->dkimHandler->setSigner($this->signerIdentity); - } - $listHeaders = $headers->listAll(); - foreach ($listHeaders as $hName) { - // Check if we need to ignore Header - if (!isset($this->ignoredHeaders[strtolower($hName ?? '')])) { - $tmp = $headers->getAll($hName); - if ($headers->has($hName)) { - foreach ($tmp as $header) { - if ('' != $header->getFieldBody()) { - $htosign = $header->toString(); - $this->dkimHandler->header($htosign); - $this->signedHeaders[] = $header->getFieldName(); - } - } - } - } - } - - return $this; - } - - public function startBody() - { - if (!$this->peclLoaded) { - return parent::startBody(); - } - $this->dropFirstLF = true; - $this->dkimHandler->eoh(); - - return $this; - } - - public function endBody() - { - if (!$this->peclLoaded) { - return parent::endBody(); - } - $this->dkimHandler->eom(); - - return $this; - } - - public function reset() - { - $this->dkimHandler = null; - parent::reset(); - - return $this; - } - - /** - * Set the signature timestamp. - * - * @param int $time - * - * @return $this - */ - public function setSignatureTimestamp($time) - { - $this->signatureTimestamp = $time; - - return $this; - } - - /** - * Set the signature expiration timestamp. - * - * @param int $time - * - * @return $this - */ - public function setSignatureExpiration($time) - { - $this->signatureExpiration = $time; - - return $this; - } - - /** - * Enable / disable the DebugHeaders. - * - * @param bool $debug - * - * @return $this - */ - public function setDebugHeaders($debug) - { - $this->debugHeaders = (bool) $debug; - - return $this; - } - - // Protected - - protected function canonicalizeBody($string) - { - if (!$this->peclLoaded) { - return parent::canonicalizeBody($string); - } - if (true === $this->dropFirstLF) { - if ("\r" == $string[0] && "\n" == $string[1]) { - $string = substr($string, 2); - } - } - $this->dropFirstLF = false; - if (\strlen($string)) { - $this->dkimHandler->body($string); - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php deleted file mode 100644 index 3dd3cd0..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php +++ /dev/null @@ -1,542 +0,0 @@ - - * @author Jan Flora - */ -class Swift_Signers_SMimeSigner implements Swift_Signers_BodySigner -{ - protected $signCertificate; - protected $signPrivateKey; - protected $encryptCert; - protected $signThenEncrypt = true; - protected $signLevel; - protected $encryptLevel; - protected $signOptions; - protected $encryptOptions; - protected $encryptCipher; - protected $extraCerts = null; - protected $wrapFullMessage = false; - - /** - * @var Swift_StreamFilters_StringReplacementFilterFactory - */ - protected $replacementFactory; - - /** - * @var Swift_Mime_SimpleHeaderFactory - */ - protected $headerFactory; - - /** - * Constructor. - * - * @param string|null $signCertificate - * @param string|null $signPrivateKey - * @param string|null $encryptCertificate - */ - public function __construct($signCertificate = null, $signPrivateKey = null, $encryptCertificate = null) - { - if (null !== $signPrivateKey) { - $this->setSignCertificate($signCertificate, $signPrivateKey); - } - - if (null !== $encryptCertificate) { - $this->setEncryptCertificate($encryptCertificate); - } - - $this->replacementFactory = Swift_DependencyContainer::getInstance() - ->lookup('transport.replacementfactory'); - - $this->signOptions = PKCS7_DETACHED; - $this->encryptCipher = OPENSSL_CIPHER_AES_128_CBC; - } - - /** - * Set the certificate location to use for signing. - * - * @see https://secure.php.net/manual/en/openssl.pkcs7.flags.php - * - * @param string $certificate - * @param string|array $privateKey If the key needs an passphrase use array('file-location', 'passphrase') instead - * @param int $signOptions Bitwise operator options for openssl_pkcs7_sign() - * @param string $extraCerts A file containing intermediate certificates needed by the signing certificate - * - * @return $this - */ - public function setSignCertificate($certificate, $privateKey = null, $signOptions = PKCS7_DETACHED, $extraCerts = null) - { - $this->signCertificate = 'file://'.str_replace('\\', '/', realpath($certificate)); - - if (null !== $privateKey) { - if (\is_array($privateKey)) { - $this->signPrivateKey = $privateKey; - $this->signPrivateKey[0] = 'file://'.str_replace('\\', '/', realpath($privateKey[0])); - } else { - $this->signPrivateKey = 'file://'.str_replace('\\', '/', realpath($privateKey)); - } - } - - $this->signOptions = $signOptions; - $this->extraCerts = $extraCerts ? realpath($extraCerts) : null; - - return $this; - } - - /** - * Set the certificate location to use for encryption. - * - * @see https://secure.php.net/manual/en/openssl.pkcs7.flags.php - * @see https://secure.php.net/manual/en/openssl.ciphers.php - * - * @param string|array $recipientCerts Either an single X.509 certificate, or an assoc array of X.509 certificates. - * @param int $cipher - * - * @return $this - */ - public function setEncryptCertificate($recipientCerts, $cipher = null) - { - if (\is_array($recipientCerts)) { - $this->encryptCert = []; - - foreach ($recipientCerts as $cert) { - $this->encryptCert[] = 'file://'.str_replace('\\', '/', realpath($cert)); - } - } else { - $this->encryptCert = 'file://'.str_replace('\\', '/', realpath($recipientCerts)); - } - - if (null !== $cipher) { - $this->encryptCipher = $cipher; - } - - return $this; - } - - /** - * @return string - */ - public function getSignCertificate() - { - return $this->signCertificate; - } - - /** - * @return string - */ - public function getSignPrivateKey() - { - return $this->signPrivateKey; - } - - /** - * Set perform signing before encryption. - * - * The default is to first sign the message and then encrypt. - * But some older mail clients, namely Microsoft Outlook 2000 will work when the message first encrypted. - * As this goes against the official specs, its recommended to only use 'encryption -> signing' when specifically targeting these 'broken' clients. - * - * @param bool $signThenEncrypt - * - * @return $this - */ - public function setSignThenEncrypt($signThenEncrypt = true) - { - $this->signThenEncrypt = $signThenEncrypt; - - return $this; - } - - /** - * @return bool - */ - public function isSignThenEncrypt() - { - return $this->signThenEncrypt; - } - - /** - * Resets internal states. - * - * @return $this - */ - public function reset() - { - return $this; - } - - /** - * Specify whether to wrap the entire MIME message in the S/MIME message. - * - * According to RFC5751 section 3.1: - * In order to protect outer, non-content-related message header fields - * (for instance, the "Subject", "To", "From", and "Cc" fields), the - * sending client MAY wrap a full MIME message in a message/rfc822 - * wrapper in order to apply S/MIME security services to these header - * fields. It is up to the receiving client to decide how to present - * this "inner" header along with the unprotected "outer" header. - * - * @param bool $wrap - * - * @return $this - */ - public function setWrapFullMessage($wrap) - { - $this->wrapFullMessage = $wrap; - } - - /** - * Change the Swift_Message to apply the signing. - * - * @return $this - */ - public function signMessage(Swift_Message $message) - { - if (null === $this->signCertificate && null === $this->encryptCert) { - return $this; - } - - if ($this->signThenEncrypt) { - $this->smimeSignMessage($message); - $this->smimeEncryptMessage($message); - } else { - $this->smimeEncryptMessage($message); - $this->smimeSignMessage($message); - } - } - - /** - * Return the list of header a signer might tamper. - * - * @return array - */ - public function getAlteredHeaders() - { - return ['Content-Type', 'Content-Transfer-Encoding', 'Content-Disposition']; - } - - /** - * Sign a Swift message. - */ - protected function smimeSignMessage(Swift_Message $message) - { - // If we don't have a certificate we can't sign the message - if (null === $this->signCertificate) { - return; - } - - // Work on a clone of the original message - $signMessage = clone $message; - $signMessage->clearSigners(); - - if ($this->wrapFullMessage) { - // The original message essentially becomes the body of the new - // wrapped message - $signMessage = $this->wrapMimeMessage($signMessage); - } else { - // Only keep header needed to parse the body correctly - $this->clearAllHeaders($signMessage); - $this->copyHeaders( - $message, - $signMessage, - [ - 'Content-Type', - 'Content-Transfer-Encoding', - 'Content-Disposition', - ] - ); - } - - // Copy the cloned message into a temporary file stream - $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); - $signMessage->toByteStream($messageStream); - $messageStream->commit(); - $signedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); - - // Sign the message using openssl - if (!openssl_pkcs7_sign( - $messageStream->getPath(), - $signedMessageStream->getPath(), - $this->signCertificate, - $this->signPrivateKey, - [], - $this->signOptions, - $this->extraCerts - ) - ) { - throw new Swift_IoException(sprintf('Failed to sign S/Mime message. Error: "%s".', openssl_error_string())); - } - - // Parse the resulting signed message content back into the Swift message - // preserving the original headers - $this->parseSSLOutput($signedMessageStream, $message); - } - - /** - * Encrypt a Swift message. - */ - protected function smimeEncryptMessage(Swift_Message $message) - { - // If we don't have a certificate we can't encrypt the message - if (null === $this->encryptCert) { - return; - } - - // Work on a clone of the original message - $encryptMessage = clone $message; - $encryptMessage->clearSigners(); - - if ($this->wrapFullMessage) { - // The original message essentially becomes the body of the new - // wrapped message - $encryptMessage = $this->wrapMimeMessage($encryptMessage); - } else { - // Only keep header needed to parse the body correctly - $this->clearAllHeaders($encryptMessage); - $this->copyHeaders( - $message, - $encryptMessage, - [ - 'Content-Type', - 'Content-Transfer-Encoding', - 'Content-Disposition', - ] - ); - } - - // Convert the message content (including headers) to a string - // and place it in a temporary file - $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); - $encryptMessage->toByteStream($messageStream); - $messageStream->commit(); - $encryptedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); - - // Encrypt the message - if (!openssl_pkcs7_encrypt( - $messageStream->getPath(), - $encryptedMessageStream->getPath(), - $this->encryptCert, - [], - 0, - $this->encryptCipher - ) - ) { - throw new Swift_IoException(sprintf('Failed to encrypt S/Mime message. Error: "%s".', openssl_error_string())); - } - - // Parse the resulting signed message content back into the Swift message - // preserving the original headers - $this->parseSSLOutput($encryptedMessageStream, $message); - } - - /** - * Copy named headers from one Swift message to another. - */ - protected function copyHeaders( - Swift_Message $fromMessage, - Swift_Message $toMessage, - array $headers = [] - ) { - foreach ($headers as $header) { - $this->copyHeader($fromMessage, $toMessage, $header); - } - } - - /** - * Copy a single header from one Swift message to another. - * - * @param string $headerName - */ - protected function copyHeader(Swift_Message $fromMessage, Swift_Message $toMessage, $headerName) - { - $header = $fromMessage->getHeaders()->get($headerName); - if (!$header) { - return; - } - $headers = $toMessage->getHeaders(); - switch ($header->getFieldType()) { - case Swift_Mime_Header::TYPE_TEXT: - $headers->addTextHeader($header->getFieldName(), $header->getValue()); - break; - case Swift_Mime_Header::TYPE_PARAMETERIZED: - $headers->addParameterizedHeader( - $header->getFieldName(), - $header->getValue(), - $header->getParameters() - ); - break; - } - } - - /** - * Remove all headers from a Swift message. - */ - protected function clearAllHeaders(Swift_Message $message) - { - $headers = $message->getHeaders(); - foreach ($headers->listAll() as $header) { - $headers->removeAll($header); - } - } - - /** - * Wraps a Swift_Message in a message/rfc822 MIME part. - * - * @return Swift_MimePart - */ - protected function wrapMimeMessage(Swift_Message $message) - { - // Start by copying the original message into a message stream - $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); - $message->toByteStream($messageStream); - $messageStream->commit(); - - // Create a new MIME part that wraps the original stream - $wrappedMessage = new Swift_MimePart($messageStream, 'message/rfc822'); - $wrappedMessage->setEncoder(new Swift_Mime_ContentEncoder_PlainContentEncoder('7bit')); - - return $wrappedMessage; - } - - protected function parseSSLOutput(Swift_InputByteStream $inputStream, Swift_Message $message) - { - $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); - $this->copyFromOpenSSLOutput($inputStream, $messageStream); - - $this->streamToMime($messageStream, $message); - } - - /** - * Merges an OutputByteStream from OpenSSL to a Swift_Message. - */ - protected function streamToMime(Swift_OutputByteStream $fromStream, Swift_Message $message) - { - // Parse the stream into headers and body - list($headers, $messageStream) = $this->parseStream($fromStream); - - // Get the original message headers - $messageHeaders = $message->getHeaders(); - - // Let the stream determine the headers describing the body content, - // since the body of the original message is overwritten by the body - // coming from the stream. - // These are all content-* headers. - - // Default transfer encoding is 7bit if not set - $encoding = ''; - // Remove all existing transfer encoding headers - $messageHeaders->removeAll('Content-Transfer-Encoding'); - // See whether the stream sets the transfer encoding - if (isset($headers['content-transfer-encoding'])) { - $encoding = $headers['content-transfer-encoding']; - } - - // We use the null content encoder, since the body is already encoded - // according to the transfer encoding specified in the stream - $message->setEncoder(new Swift_Mime_ContentEncoder_NullContentEncoder($encoding)); - - // Set the disposition, if present - if (isset($headers['content-disposition'])) { - $messageHeaders->addTextHeader('Content-Disposition', $headers['content-disposition']); - } - - // Copy over the body from the stream using the content type dictated - // by the stream content - $message->setChildren([]); - $message->setBody($messageStream, $headers['content-type']); - } - - /** - * This message will parse the headers of a MIME email byte stream - * and return an array that contains the headers as an associative - * array and the email body as a string. - * - * @return array - */ - protected function parseStream(Swift_OutputByteStream $emailStream) - { - $bufferLength = 78; - $headerData = ''; - $headerBodySeparator = "\r\n\r\n"; - - $emailStream->setReadPointer(0); - - // Read out the headers section from the stream to a string - while (false !== ($buffer = $emailStream->read($bufferLength))) { - $headerData .= $buffer; - - $headersPosEnd = strpos($headerData, $headerBodySeparator); - - // Stop reading if we found the end of the headers - if (false !== $headersPosEnd) { - break; - } - } - - // Split the header data into lines - $headerData = trim(substr($headerData, 0, $headersPosEnd)); - $headerLines = explode("\r\n", $headerData); - unset($headerData); - - $headers = []; - $currentHeaderName = ''; - - // Transform header lines into an associative array - foreach ($headerLines as $headerLine) { - // Handle headers that span multiple lines - if (false === strpos($headerLine, ':')) { - $headers[$currentHeaderName] .= ' '.trim($headerLine ?? ''); - continue; - } - - $header = explode(':', $headerLine, 2); - $currentHeaderName = strtolower($header[0] ?? ''); - $headers[$currentHeaderName] = trim($header[1] ?? ''); - } - - // Read the entire email body into a byte stream - $bodyStream = new Swift_ByteStream_TemporaryFileByteStream(); - - // Skip the header and separator and point to the body - $emailStream->setReadPointer($headersPosEnd + \strlen($headerBodySeparator)); - - while (false !== ($buffer = $emailStream->read($bufferLength))) { - $bodyStream->write($buffer); - } - - $bodyStream->commit(); - - return [$headers, $bodyStream]; - } - - protected function copyFromOpenSSLOutput(Swift_OutputByteStream $fromStream, Swift_InputByteStream $toStream) - { - $bufferLength = 4096; - $filteredStream = new Swift_ByteStream_TemporaryFileByteStream(); - $filteredStream->addFilter($this->replacementFactory->createFilter("\r\n", "\n"), 'CRLF to LF'); - $filteredStream->addFilter($this->replacementFactory->createFilter("\n", "\r\n"), 'LF to CRLF'); - - while (false !== ($buffer = $fromStream->read($bufferLength))) { - $filteredStream->write($buffer); - } - - $filteredStream->flushBuffers(); - - while (false !== ($buffer = $filteredStream->read($bufferLength))) { - $toStream->write($buffer); - } - - $toStream->commit(); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SmtpTransport.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SmtpTransport.php deleted file mode 100644 index 56b6232..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SmtpTransport.php +++ /dev/null @@ -1,45 +0,0 @@ -createDependenciesFor('transport.smtp') - ); - - $this->setHost($host); - $this->setPort($port); - $this->setEncryption($encryption); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Spool.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Spool.php deleted file mode 100644 index 9d0e8fe..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Spool.php +++ /dev/null @@ -1,53 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Interface for spools. - * - * @author Fabien Potencier - */ -interface Swift_Spool -{ - /** - * Starts this Spool mechanism. - */ - public function start(); - - /** - * Stops this Spool mechanism. - */ - public function stop(); - - /** - * Tests if this Spool mechanism has started. - * - * @return bool - */ - public function isStarted(); - - /** - * Queues a message. - * - * @param Swift_Mime_SimpleMessage $message The message to store - * - * @return bool Whether the operation has succeeded - */ - public function queueMessage(Swift_Mime_SimpleMessage $message); - - /** - * Sends messages using the given transport instance. - * - * @param Swift_Transport $transport A transport instance - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int The number of sent emails - */ - public function flushQueue(Swift_Transport $transport, &$failedRecipients = null); -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SpoolTransport.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SpoolTransport.php deleted file mode 100644 index c08e0fb..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SpoolTransport.php +++ /dev/null @@ -1,33 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Stores Messages in a queue. - * - * @author Fabien Potencier - */ -class Swift_SpoolTransport extends Swift_Transport_SpoolTransport -{ - /** - * Create a new SpoolTransport. - */ - public function __construct(Swift_Spool $spool) - { - $arguments = Swift_DependencyContainer::getInstance() - ->createDependenciesFor('transport.spool'); - - $arguments[] = $spool; - - \call_user_func_array( - [$this, 'Swift_Transport_SpoolTransport::__construct'], - $arguments - ); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilter.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilter.php deleted file mode 100644 index 362be2e..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilter.php +++ /dev/null @@ -1,35 +0,0 @@ -index = []; - $this->tree = []; - $this->replace = []; - $this->repSize = []; - - $tree = null; - $i = null; - $last_size = $size = 0; - foreach ($search as $i => $search_element) { - if (null !== $tree) { - $tree[-1] = min(\count($replace) - 1, $i - 1); - $tree[-2] = $last_size; - } - $tree = &$this->tree; - if (\is_array($search_element)) { - foreach ($search_element as $k => $char) { - $this->index[$char] = true; - if (!isset($tree[$char])) { - $tree[$char] = []; - } - $tree = &$tree[$char]; - } - $last_size = $k + 1; - $size = max($size, $last_size); - } else { - $last_size = 1; - if (!isset($tree[$search_element])) { - $tree[$search_element] = []; - } - $tree = &$tree[$search_element]; - $size = max($last_size, $size); - $this->index[$search_element] = true; - } - } - if (null !== $i) { - $tree[-1] = min(\count($replace) - 1, $i); - $tree[-2] = $last_size; - $this->treeMaxLen = $size; - } - foreach ($replace as $rep) { - if (!\is_array($rep)) { - $rep = [$rep]; - } - $this->replace[] = $rep; - } - for ($i = \count($this->replace) - 1; $i >= 0; --$i) { - $this->replace[$i] = $rep = $this->filter($this->replace[$i], $i); - $this->repSize[$i] = \count($rep); - } - } - - /** - * Returns true if based on the buffer passed more bytes should be buffered. - * - * @param array $buffer - * - * @return bool - */ - public function shouldBuffer($buffer) - { - $endOfBuffer = end($buffer); - - return isset($this->index[$endOfBuffer]); - } - - /** - * Perform the actual replacements on $buffer and return the result. - * - * @param array $buffer - * @param int $minReplaces - * - * @return array - */ - public function filter($buffer, $minReplaces = -1) - { - if (0 == $this->treeMaxLen) { - return $buffer; - } - - $newBuffer = []; - $buf_size = \count($buffer); - $last_size = 0; - for ($i = 0; $i < $buf_size; ++$i) { - $search_pos = $this->tree; - $last_found = PHP_INT_MAX; - // We try to find if the next byte is part of a search pattern - for ($j = 0; $j <= $this->treeMaxLen; ++$j) { - // We have a new byte for a search pattern - if (isset($buffer[$p = $i + $j]) && isset($search_pos[$buffer[$p]])) { - $search_pos = $search_pos[$buffer[$p]]; - // We have a complete pattern, save, in case we don't find a better match later - if (isset($search_pos[-1]) && $search_pos[-1] < $last_found - && $search_pos[-1] > $minReplaces) { - $last_found = $search_pos[-1]; - $last_size = $search_pos[-2]; - } - } - // We got a complete pattern - elseif (PHP_INT_MAX !== $last_found) { - // Adding replacement datas to output buffer - $rep_size = $this->repSize[$last_found]; - for ($j = 0; $j < $rep_size; ++$j) { - $newBuffer[] = $this->replace[$last_found][$j]; - } - // We Move cursor forward - $i += $last_size - 1; - // Edge Case, last position in buffer - if ($i >= $buf_size) { - $newBuffer[] = $buffer[$i]; - } - - // We start the next loop - continue 2; - } else { - // this byte is not in a pattern and we haven't found another pattern - break; - } - } - // Normal byte, move it to output buffer - $newBuffer[] = $buffer[$i]; - } - - return $newBuffer; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php deleted file mode 100644 index 50a63f1..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php +++ /dev/null @@ -1,70 +0,0 @@ -search = $search; - $this->replace = $replace; - } - - /** - * Returns true if based on the buffer passed more bytes should be buffered. - * - * @param string $buffer - * - * @return bool - */ - public function shouldBuffer($buffer) - { - if ('' === $buffer) { - return false; - } - - $endOfBuffer = substr($buffer, -1); - foreach ((array) $this->search as $needle) { - if (false !== strpos($needle, $endOfBuffer)) { - return true; - } - } - - return false; - } - - /** - * Perform the actual replacements on $buffer and return the result. - * - * @param string $buffer - * - * @return string - */ - public function filter($buffer) - { - return str_replace($this->search, $this->replace, $buffer); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php deleted file mode 100644 index 783b889..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php +++ /dev/null @@ -1,45 +0,0 @@ -filters[$search][$replace])) { - if (!isset($this->filters[$search])) { - $this->filters[$search] = []; - } - - if (!isset($this->filters[$search][$replace])) { - $this->filters[$search][$replace] = []; - } - - $this->filters[$search][$replace] = new Swift_StreamFilters_StringReplacementFilter($search, $replace); - } - - return $this->filters[$search][$replace]; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SwiftException.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SwiftException.php deleted file mode 100644 index 15e68b1..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SwiftException.php +++ /dev/null @@ -1,28 +0,0 @@ -ping()) { - * $transport->stop(); - * $transport->start(); - * } - * - * The Transport mechanism will be started, if it is not already. - * - * It is undefined if the Transport mechanism attempts to restart as long as - * the return value reflects whether the mechanism is now functional. - * - * @return bool TRUE if the transport is alive - */ - public function ping(); - - /** - * Send the given Message. - * - * Recipient/sender data will be retrieved from the Message API. - * The return value is the number of recipients who were accepted for delivery. - * - * This is the responsibility of the send method to start the transport if needed. - * - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int - */ - public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null); - - /** - * Register a plugin in the Transport. - */ - public function registerPlugin(Swift_Events_EventListener $plugin); -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php deleted file mode 100644 index d2dbd7a..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php +++ /dev/null @@ -1,541 +0,0 @@ -buffer = $buf; - $this->eventDispatcher = $dispatcher; - $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder(); - $this->setLocalDomain($localDomain); - } - - /** - * Set the name of the local domain which Swift will identify itself as. - * - * This should be a fully-qualified domain name and should be truly the domain - * you're using. - * - * If your server does not have a domain name, use the IP address. This will - * automatically be wrapped in square brackets as described in RFC 5321, - * section 4.1.3. - * - * @param string $domain - * - * @return $this - */ - public function setLocalDomain($domain) - { - if ('[' !== substr($domain, 0, 1)) { - if (filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { - $domain = '['.$domain.']'; - } elseif (filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { - $domain = '[IPv6:'.$domain.']'; - } - } - - $this->domain = $domain; - - return $this; - } - - /** - * Get the name of the domain Swift will identify as. - * - * If an IP address was specified, this will be returned wrapped in square - * brackets as described in RFC 5321, section 4.1.3. - * - * @return string - */ - public function getLocalDomain() - { - return $this->domain; - } - - /** - * Sets the source IP. - * - * @param string $source - */ - public function setSourceIp($source) - { - $this->sourceIp = $source; - } - - /** - * Returns the IP used to connect to the destination. - * - * @return string - */ - public function getSourceIp() - { - return $this->sourceIp; - } - - public function setAddressEncoder(Swift_AddressEncoder $addressEncoder) - { - $this->addressEncoder = $addressEncoder; - } - - public function getAddressEncoder() - { - return $this->addressEncoder; - } - - /** - * Start the SMTP connection. - */ - public function start() - { - if (!$this->started) { - if ($evt = $this->eventDispatcher->createTransportChangeEvent($this)) { - $this->eventDispatcher->dispatchEvent($evt, 'beforeTransportStarted'); - if ($evt->bubbleCancelled()) { - return; - } - } - - try { - $this->buffer->initialize($this->getBufferParams()); - } catch (Swift_TransportException $e) { - $this->throwException($e); - } - $this->readGreeting(); - $this->doHeloCommand(); - - if ($evt) { - $this->eventDispatcher->dispatchEvent($evt, 'transportStarted'); - } - - $this->started = true; - } - } - - /** - * Test if an SMTP connection has been established. - * - * @return bool - */ - public function isStarted() - { - return $this->started; - } - - /** - * Send the given Message. - * - * Recipient/sender data will be retrieved from the Message API. - * The return value is the number of recipients who were accepted for delivery. - * - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int - */ - public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) - { - if (!$this->isStarted()) { - $this->start(); - } - - $sent = 0; - $failedRecipients = (array) $failedRecipients; - - if ($evt = $this->eventDispatcher->createSendEvent($this, $message)) { - $this->eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); - if ($evt->bubbleCancelled()) { - return 0; - } - } - - if (!$reversePath = $this->getReversePath($message)) { - $this->throwException(new Swift_TransportException('Cannot send message without a sender address')); - } - - $to = (array) $message->getTo(); - $cc = (array) $message->getCc(); - $bcc = (array) $message->getBcc(); - $tos = array_merge($to, $cc, $bcc); - - $message->setBcc([]); - - try { - $sent += $this->sendTo($message, $reversePath, $tos, $failedRecipients); - } finally { - $message->setBcc($bcc); - } - - if ($evt) { - if ($sent == \count($to) + \count($cc) + \count($bcc)) { - $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); - } elseif ($sent > 0) { - $evt->setResult(Swift_Events_SendEvent::RESULT_TENTATIVE); - } else { - $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED); - } - $evt->setFailedRecipients($failedRecipients); - $this->eventDispatcher->dispatchEvent($evt, 'sendPerformed'); - } - - $message->generateId(); //Make sure a new Message ID is used - - return $sent; - } - - /** - * Stop the SMTP connection. - */ - public function stop() - { - if ($this->started) { - if ($evt = $this->eventDispatcher->createTransportChangeEvent($this)) { - $this->eventDispatcher->dispatchEvent($evt, 'beforeTransportStopped'); - if ($evt->bubbleCancelled()) { - return; - } - } - - try { - $this->executeCommand("QUIT\r\n", [221]); - } catch (Swift_TransportException $e) { - } - - try { - $this->buffer->terminate(); - - if ($evt) { - $this->eventDispatcher->dispatchEvent($evt, 'transportStopped'); - } - } catch (Swift_TransportException $e) { - $this->throwException($e); - } - } - $this->started = false; - } - - /** - * {@inheritdoc} - */ - public function ping() - { - try { - if (!$this->isStarted()) { - $this->start(); - } - - $this->executeCommand("NOOP\r\n", [250]); - } catch (Swift_TransportException $e) { - try { - $this->stop(); - } catch (Swift_TransportException $e) { - } - - return false; - } - - return true; - } - - /** - * Register a plugin. - */ - public function registerPlugin(Swift_Events_EventListener $plugin) - { - $this->eventDispatcher->bindEventListener($plugin); - } - - /** - * Reset the current mail transaction. - */ - public function reset() - { - $this->executeCommand("RSET\r\n", [250], $failures, true); - } - - /** - * Get the IoBuffer where read/writes are occurring. - * - * @return Swift_Transport_IoBuffer - */ - public function getBuffer() - { - return $this->buffer; - } - - /** - * Run a command against the buffer, expecting the given response codes. - * - * If no response codes are given, the response will not be validated. - * If codes are given, an exception will be thrown on an invalid response. - * If the command is RCPT TO, and the pipeline is non-empty, no exception - * will be thrown; instead the failing address is added to $failures. - * - * @param string $command - * @param int[] $codes - * @param string[] $failures An array of failures by-reference - * @param bool $pipeline Do not wait for response - * @param string $address the address, if command is RCPT TO - * - * @return string|null The server response, or null if pipelining is enabled - */ - public function executeCommand($command, $codes = [], &$failures = null, $pipeline = false, $address = null) - { - $failures = (array) $failures; - $seq = $this->buffer->write($command); - if ($evt = $this->eventDispatcher->createCommandEvent($this, $command, $codes)) { - $this->eventDispatcher->dispatchEvent($evt, 'commandSent'); - } - - $this->pipeline[] = [$command, $seq, $codes, $address]; - - if ($pipeline && $this->pipelining) { - return null; - } - - $response = null; - - while ($this->pipeline) { - list($command, $seq, $codes, $address) = array_shift($this->pipeline); - $response = $this->getFullResponse($seq); - try { - $this->assertResponseCode($response, $codes); - } catch (Swift_TransportException $e) { - if ($this->pipeline && $address) { - $failures[] = $address; - } else { - $this->throwException($e); - } - } - } - - return $response; - } - - /** Read the opening SMTP greeting */ - protected function readGreeting() - { - $this->assertResponseCode($this->getFullResponse(0), [220]); - } - - /** Send the HELO welcome */ - protected function doHeloCommand() - { - $this->executeCommand( - sprintf("HELO %s\r\n", $this->domain), [250] - ); - } - - /** Send the MAIL FROM command */ - protected function doMailFromCommand($address) - { - $address = $this->addressEncoder->encodeString($address); - $this->executeCommand( - sprintf("MAIL FROM:<%s>\r\n", $address), [250], $failures, true - ); - } - - /** Send the RCPT TO command */ - protected function doRcptToCommand($address) - { - $address = $this->addressEncoder->encodeString($address); - $this->executeCommand( - sprintf("RCPT TO:<%s>\r\n", $address), [250, 251, 252], $failures, true, $address - ); - } - - /** Send the DATA command */ - protected function doDataCommand(&$failedRecipients) - { - $this->executeCommand("DATA\r\n", [354], $failedRecipients); - } - - /** Stream the contents of the message over the buffer */ - protected function streamMessage(Swift_Mime_SimpleMessage $message) - { - $this->buffer->setWriteTranslations(["\r\n." => "\r\n.."]); - try { - $message->toByteStream($this->buffer); - $this->buffer->flushBuffers(); - } catch (Swift_TransportException $e) { - $this->throwException($e); - } - $this->buffer->setWriteTranslations([]); - $this->executeCommand("\r\n.\r\n", [250]); - } - - /** Determine the best-use reverse path for this message */ - protected function getReversePath(Swift_Mime_SimpleMessage $message) - { - $return = $message->getReturnPath(); - $sender = $message->getSender(); - $from = $message->getFrom(); - $path = null; - if (!empty($return)) { - $path = $return; - } elseif (!empty($sender)) { - // Don't use array_keys - reset($sender); // Reset Pointer to first pos - $path = key($sender); // Get key - } elseif (!empty($from)) { - reset($from); // Reset Pointer to first pos - $path = key($from); // Get key - } - - return $path; - } - - /** Throw a TransportException, first sending it to any listeners */ - protected function throwException(Swift_TransportException $e) - { - if ($evt = $this->eventDispatcher->createTransportExceptionEvent($this, $e)) { - $this->eventDispatcher->dispatchEvent($evt, 'exceptionThrown'); - if (!$evt->bubbleCancelled()) { - throw $e; - } - } else { - throw $e; - } - } - - /** Throws an Exception if a response code is incorrect */ - protected function assertResponseCode($response, $wanted) - { - if (!$response) { - $this->throwException(new Swift_TransportException('Expected response code '.implode('/', $wanted).' but got an empty response')); - } - - list($code) = sscanf($response, '%3d'); - $valid = (empty($wanted) || \in_array($code, $wanted)); - - if ($evt = $this->eventDispatcher->createResponseEvent($this, $response, - $valid)) { - $this->eventDispatcher->dispatchEvent($evt, 'responseReceived'); - } - - if (!$valid) { - $this->throwException(new Swift_TransportException('Expected response code '.implode('/', $wanted).' but got code "'.$code.'", with message "'.$response.'"', $code)); - } - } - - /** Get an entire multi-line response using its sequence number */ - protected function getFullResponse($seq) - { - $response = ''; - try { - do { - $line = $this->buffer->readLine($seq); - $response .= $line; - } while (null !== $line && false !== $line && ' ' != $line[3]); - } catch (Swift_TransportException $e) { - $this->throwException($e); - } catch (Swift_IoException $e) { - $this->throwException(new Swift_TransportException($e->getMessage(), 0, $e)); - } - - return $response; - } - - /** Send an email to the given recipients from the given reverse path */ - private function doMailTransaction($message, $reversePath, array $recipients, array &$failedRecipients) - { - $sent = 0; - $this->doMailFromCommand($reversePath); - foreach ($recipients as $forwardPath) { - try { - $this->doRcptToCommand($forwardPath); - ++$sent; - } catch (Swift_TransportException $e) { - $failedRecipients[] = $forwardPath; - } catch (Swift_AddressEncoderException $e) { - $failedRecipients[] = $forwardPath; - } - } - - if (0 != $sent) { - $sent += \count($failedRecipients); - $this->doDataCommand($failedRecipients); - $sent -= \count($failedRecipients); - - $this->streamMessage($message); - } else { - $this->reset(); - } - - return $sent; - } - - /** Send a message to the given To: recipients */ - private function sendTo(Swift_Mime_SimpleMessage $message, $reversePath, array $to, array &$failedRecipients) - { - if (empty($to)) { - return 0; - } - - return $this->doMailTransaction($message, $reversePath, array_keys($to), - $failedRecipients); - } - - /** - * Destructor. - */ - public function __destruct() - { - try { - $this->stop(); - } catch (Exception $e) { - } - } - - public function __sleep() - { - throw new \BadMethodCallException('Cannot serialize '.__CLASS__); - } - - public function __wakeup() - { - throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php deleted file mode 100644 index bb3a161..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php +++ /dev/null @@ -1,75 +0,0 @@ -executeCommand("AUTH CRAM-MD5\r\n", [334]); - $challenge = base64_decode(substr($challenge, 4)); - $message = base64_encode( - $username.' '.$this->getResponse($password, $challenge) - ); - $agent->executeCommand(sprintf("%s\r\n", $message), [235]); - - return true; - } catch (Swift_TransportException $e) { - $agent->executeCommand("RSET\r\n", [250]); - - throw $e; - } - } - - /** - * Generate a CRAM-MD5 response from a server challenge. - * - * @param string $secret - * @param string $challenge - * - * @return string - */ - private function getResponse($secret, $challenge) - { - if (\strlen($secret) > 64) { - $secret = pack('H32', md5($secret)); - } - - if (\strlen($secret) < 64) { - $secret = str_pad($secret, 64, \chr(0)); - } - - $k_ipad = substr($secret, 0, 64) ^ str_repeat(\chr(0x36), 64); - $k_opad = substr($secret, 0, 64) ^ str_repeat(\chr(0x5C), 64); - - $inner = pack('H32', md5($k_ipad.$challenge)); - $digest = md5($k_opad.$inner); - - return $digest; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php deleted file mode 100644 index 0b9d81b..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php +++ /dev/null @@ -1,45 +0,0 @@ -executeCommand("AUTH LOGIN\r\n", [334]); - $agent->executeCommand(sprintf("%s\r\n", base64_encode($username ?? '')), [334]); - $agent->executeCommand(sprintf("%s\r\n", base64_encode($password ?? '')), [235]); - - return true; - } catch (Swift_TransportException $e) { - $agent->executeCommand("RSET\r\n", [250]); - - throw $e; - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php deleted file mode 100644 index 41931fd..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php +++ /dev/null @@ -1,681 +0,0 @@ - - */ -class Swift_Transport_Esmtp_Auth_NTLMAuthenticator implements Swift_Transport_Esmtp_Authenticator -{ - const NTLMSIG = "NTLMSSP\x00"; - const DESCONST = 'KGS!@#$%'; - - /** - * Get the name of the AUTH mechanism this Authenticator handles. - * - * @return string - */ - public function getAuthKeyword() - { - return 'NTLM'; - } - - /** - * {@inheritdoc} - * - * @throws \LogicException - */ - public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password) - { - if (!\function_exists('openssl_encrypt')) { - throw new LogicException('The OpenSSL extension must be enabled to use the NTLM authenticator.'); - } - - if (!\function_exists('bcmul')) { - throw new LogicException('The BCMath functions must be enabled to use the NTLM authenticator.'); - } - - try { - // execute AUTH command and filter out the code at the beginning - // AUTH NTLM xxxx - $response = base64_decode(substr(trim($this->sendMessage1($agent) ?? ''), 4)); - - // extra parameters for our unit cases - $timestamp = \func_num_args() > 3 ? func_get_arg(3) : $this->getCorrectTimestamp(bcmul(microtime(true), '1000')); - $client = \func_num_args() > 4 ? func_get_arg(4) : random_bytes(8); - - // Message 3 response - $this->sendMessage3($response, $username, $password, $timestamp, $client, $agent); - - return true; - } catch (Swift_TransportException $e) { - $agent->executeCommand("RSET\r\n", [250]); - - throw $e; - } - } - - protected function si2bin($si, $bits = 32) - { - $bin = null; - if ($si >= -2 ** ($bits - 1) && ($si <= 2 ** ($bits - 1))) { - // positive or zero - if ($si >= 0) { - $bin = base_convert($si, 10, 2); - // pad to $bits bit - $bin_length = \strlen($bin); - if ($bin_length < $bits) { - $bin = str_repeat('0', $bits - $bin_length).$bin; - } - } else { - // negative - $si = -$si - 2 ** $bits; - $bin = base_convert($si, 10, 2); - $bin_length = \strlen($bin); - if ($bin_length > $bits) { - $bin = str_repeat('1', $bits - $bin_length).$bin; - } - } - } - - return $bin; - } - - /** - * Send our auth message and returns the response. - * - * @return string SMTP Response - */ - protected function sendMessage1(Swift_Transport_SmtpAgent $agent) - { - $message = $this->createMessage1(); - - return $agent->executeCommand(sprintf("AUTH %s %s\r\n", $this->getAuthKeyword(), base64_encode($message)), [334]); - } - - /** - * Fetch all details of our response (message 2). - * - * @param string $response - * - * @return array our response parsed - */ - protected function parseMessage2($response) - { - $responseHex = bin2hex($response); - $length = floor(hexdec(substr($responseHex, 28, 4)) / 256) * 2; - $offset = floor(hexdec(substr($responseHex, 32, 4)) / 256) * 2; - $challenge = hex2bin(substr($responseHex, 48, 16)); - $context = hex2bin(substr($responseHex, 64, 16)); - $targetInfoH = hex2bin(substr($responseHex, 80, 16)); - $targetName = hex2bin(substr($responseHex, $offset, $length)); - $offset = floor(hexdec(substr($responseHex, 88, 4)) / 256) * 2; - $targetInfoBlock = substr($responseHex, $offset); - list($domainName, $serverName, $DNSDomainName, $DNSServerName, $terminatorByte) = $this->readSubBlock($targetInfoBlock); - - return [ - $challenge, - $context, - $targetInfoH, - $targetName, - $domainName, - $serverName, - $DNSDomainName, - $DNSServerName, - hex2bin($targetInfoBlock), - $terminatorByte, - ]; - } - - /** - * Read the blob information in from message2. - * - * @return array - */ - protected function readSubBlock($block) - { - // remove terminatorByte cause it's always the same - $block = substr($block, 0, -8); - - $length = \strlen($block); - $offset = 0; - $data = []; - while ($offset < $length) { - $blockLength = hexdec(substr(substr($block, $offset, 8), -4)) / 256; - $offset += 8; - $data[] = hex2bin(substr($block, $offset, $blockLength * 2)); - $offset += $blockLength * 2; - } - - if (3 == \count($data)) { - $data[] = $data[2]; - $data[2] = ''; - } - - $data[] = $this->createByte('00'); - - return $data; - } - - /** - * Send our final message with all our data. - * - * @param string $response Message 1 response (message 2) - * @param string $username - * @param string $password - * @param string $timestamp - * @param string $client - * @param bool $v2 Use version2 of the protocol - * - * @return string - */ - protected function sendMessage3($response, $username, $password, $timestamp, $client, Swift_Transport_SmtpAgent $agent, $v2 = true) - { - list($domain, $username) = $this->getDomainAndUsername($username); - //$challenge, $context, $targetInfoH, $targetName, $domainName, $workstation, $DNSDomainName, $DNSServerName, $blob, $ter - list($challenge, , , , , $workstation, , , $blob) = $this->parseMessage2($response); - - if (!$v2) { - // LMv1 - $lmResponse = $this->createLMPassword($password, $challenge); - // NTLMv1 - $ntlmResponse = $this->createNTLMPassword($password, $challenge); - } else { - // LMv2 - $lmResponse = $this->createLMv2Password($password, $username, $domain, $challenge, $client); - // NTLMv2 - $ntlmResponse = $this->createNTLMv2Hash($password, $username, $domain, $challenge, $blob, $timestamp, $client); - } - - $message = $this->createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse); - - return $agent->executeCommand(sprintf("%s\r\n", base64_encode($message)), [235]); - } - - /** - * Create our message 1. - * - * @return string - */ - protected function createMessage1() - { - return self::NTLMSIG - .$this->createByte('01') // Message 1 -.$this->createByte('0702'); // Flags - } - - /** - * Create our message 3. - * - * @param string $domain - * @param string $username - * @param string $workstation - * @param string $lmResponse - * @param string $ntlmResponse - * - * @return string - */ - protected function createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse) - { - // Create security buffers - $domainSec = $this->createSecurityBuffer($domain, 64); - $domainInfo = $this->readSecurityBuffer(bin2hex($domainSec)); - $userSec = $this->createSecurityBuffer($username, ($domainInfo[0] + $domainInfo[1]) / 2); - $userInfo = $this->readSecurityBuffer(bin2hex($userSec)); - $workSec = $this->createSecurityBuffer($workstation, ($userInfo[0] + $userInfo[1]) / 2); - $workInfo = $this->readSecurityBuffer(bin2hex($workSec)); - $lmSec = $this->createSecurityBuffer($lmResponse, ($workInfo[0] + $workInfo[1]) / 2, true); - $lmInfo = $this->readSecurityBuffer(bin2hex($lmSec)); - $ntlmSec = $this->createSecurityBuffer($ntlmResponse, ($lmInfo[0] + $lmInfo[1]) / 2, true); - - return self::NTLMSIG - .$this->createByte('03') // TYPE 3 message -.$lmSec // LM response header -.$ntlmSec // NTLM response header -.$domainSec // Domain header -.$userSec // User header -.$workSec // Workstation header -.$this->createByte('000000009a', 8) // session key header (empty) -.$this->createByte('01020000') // FLAGS -.$this->convertTo16bit($domain) // domain name -.$this->convertTo16bit($username) // username -.$this->convertTo16bit($workstation) // workstation -.$lmResponse - .$ntlmResponse; - } - - /** - * @param string $timestamp Epoch timestamp in microseconds - * @param string $client Random bytes - * @param string $targetInfo - * - * @return string - */ - protected function createBlob($timestamp, $client, $targetInfo) - { - return $this->createByte('0101') - .$this->createByte('00') - .$timestamp - .$client - .$this->createByte('00') - .$targetInfo - .$this->createByte('00'); - } - - /** - * Get domain and username from our username. - * - * @example DOMAIN\username - * - * @param string $name - * - * @return array - */ - protected function getDomainAndUsername($name) - { - if (false !== strpos($name, '\\')) { - return explode('\\', $name); - } - - if (false !== strpos($name, '@')) { - list($user, $domain) = explode('@', $name); - - return [$domain, $user]; - } - - // no domain passed - return ['', $name]; - } - - /** - * Create LMv1 response. - * - * @param string $password - * @param string $challenge - * - * @return string - */ - protected function createLMPassword($password, $challenge) - { - // FIRST PART - $password = $this->createByte(strtoupper($password), 14, false); - list($key1, $key2) = str_split($password, 7); - - $desKey1 = $this->createDesKey($key1); - $desKey2 = $this->createDesKey($key2); - - $constantDecrypt = $this->createByte($this->desEncrypt(self::DESCONST, $desKey1).$this->desEncrypt(self::DESCONST, $desKey2), 21, false); - - // SECOND PART - list($key1, $key2, $key3) = str_split($constantDecrypt, 7); - - $desKey1 = $this->createDesKey($key1); - $desKey2 = $this->createDesKey($key2); - $desKey3 = $this->createDesKey($key3); - - return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3); - } - - /** - * Create NTLMv1 response. - * - * @param string $password - * @param string $challenge - * - * @return string - */ - protected function createNTLMPassword($password, $challenge) - { - // FIRST PART - $ntlmHash = $this->createByte($this->md4Encrypt($password), 21, false); - list($key1, $key2, $key3) = str_split($ntlmHash, 7); - - $desKey1 = $this->createDesKey($key1); - $desKey2 = $this->createDesKey($key2); - $desKey3 = $this->createDesKey($key3); - - return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3); - } - - /** - * Convert a normal timestamp to a tenth of a microtime epoch time. - * - * @param string $time - * - * @return string - */ - protected function getCorrectTimestamp($time) - { - // Get our timestamp (tricky!) - $time = number_format($time, 0, '.', ''); // save microtime to string - $time = bcadd($time, '11644473600000', 0); // add epoch time - $time = bcmul($time, 10000, 0); // tenths of a microsecond. - - $binary = $this->si2bin($time, 64); // create 64 bit binary string - $timestamp = ''; - for ($i = 0; $i < 8; ++$i) { - $timestamp .= \chr(bindec(substr($binary, -(($i + 1) * 8), 8))); - } - - return $timestamp; - } - - /** - * Create LMv2 response. - * - * @param string $password - * @param string $username - * @param string $domain - * @param string $challenge NTLM Challenge - * @param string $client Random string - * - * @return string - */ - protected function createLMv2Password($password, $username, $domain, $challenge, $client) - { - $lmPass = '00'; // by default 00 - // if $password > 15 than we can't use this method - if (\strlen($password) <= 15) { - $ntlmHash = $this->md4Encrypt($password); - $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain)); - - $lmPass = bin2hex($this->md5Encrypt($ntml2Hash, $challenge.$client).$client); - } - - return $this->createByte($lmPass, 24); - } - - /** - * Create NTLMv2 response. - * - * @param string $password - * @param string $username - * @param string $domain - * @param string $challenge Hex values - * @param string $targetInfo Hex values - * @param string $timestamp - * @param string $client Random bytes - * - * @return string - * - * @see http://davenport.sourceforge.net/ntlm.html#theNtlmResponse - */ - protected function createNTLMv2Hash($password, $username, $domain, $challenge, $targetInfo, $timestamp, $client) - { - $ntlmHash = $this->md4Encrypt($password); - $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain)); - - // create blob - $blob = $this->createBlob($timestamp, $client, $targetInfo); - - $ntlmv2Response = $this->md5Encrypt($ntml2Hash, $challenge.$blob); - - return $ntlmv2Response.$blob; - } - - protected function createDesKey($key) - { - $material = [bin2hex($key[0])]; - $len = \strlen($key); - for ($i = 1; $i < $len; ++$i) { - list($high, $low) = str_split(bin2hex($key[$i])); - $v = $this->castToByte(\ord($key[$i - 1]) << (7 + 1 - $i) | $this->uRShift(hexdec(dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xf)), $i)); - $material[] = str_pad(substr(dechex($v), -2), 2, '0', STR_PAD_LEFT); // cast to byte - } - $material[] = str_pad(substr(dechex($this->castToByte(\ord($key[6]) << 1)), -2), 2, '0'); - - // odd parity - foreach ($material as $k => $v) { - $b = $this->castToByte(hexdec($v)); - $needsParity = 0 == (($this->uRShift($b, 7) ^ $this->uRShift($b, 6) ^ $this->uRShift($b, 5) - ^ $this->uRShift($b, 4) ^ $this->uRShift($b, 3) ^ $this->uRShift($b, 2) - ^ $this->uRShift($b, 1)) & 0x01); - - list($high, $low) = str_split($v); - if ($needsParity) { - $material[$k] = dechex(hexdec($high) | 0x0).dechex(hexdec($low) | 0x1); - } else { - $material[$k] = dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xe); - } - } - - return hex2bin(implode('', $material)); - } - - /** HELPER FUNCTIONS */ - - /** - * Create our security buffer depending on length and offset. - * - * @param string $value Value we want to put in - * @param int $offset start of value - * @param bool $is16 Do we 16bit string or not? - * - * @return string - */ - protected function createSecurityBuffer($value, $offset, $is16 = false) - { - $length = \strlen(bin2hex($value)); - $length = $is16 ? $length / 2 : $length; - $length = $this->createByte(str_pad(dechex($length), 2, '0', STR_PAD_LEFT), 2); - - return $length.$length.$this->createByte(dechex($offset), 4); - } - - /** - * Read our security buffer to fetch length and offset of our value. - * - * @param string $value Securitybuffer in hex - * - * @return array array with length and offset - */ - protected function readSecurityBuffer($value) - { - $length = floor(hexdec(substr($value, 0, 4)) / 256) * 2; - $offset = floor(hexdec(substr($value, 8, 4)) / 256) * 2; - - return [$length, $offset]; - } - - /** - * Cast to byte java equivalent to (byte). - * - * @param int $v - * - * @return int - */ - protected function castToByte($v) - { - return (($v + 128) % 256) - 128; - } - - /** - * Java unsigned right bitwise - * $a >>> $b. - * - * @param int $a - * @param int $b - * - * @return int - */ - protected function uRShift($a, $b) - { - if (0 == $b) { - return $a; - } - - return ($a >> $b) & ~(1 << (8 * PHP_INT_SIZE - 1) >> ($b - 1)); - } - - /** - * Right padding with 0 to certain length. - * - * @param string $input - * @param int $bytes Length of bytes - * @param bool $isHex Did we provided hex value - * - * @return string - */ - protected function createByte($input, $bytes = 4, $isHex = true) - { - if ($isHex) { - $byte = hex2bin(str_pad($input, $bytes * 2, '00')); - } else { - $byte = str_pad($input, $bytes, "\x00"); - } - - return $byte; - } - - /** ENCRYPTION ALGORITHMS */ - - /** - * DES Encryption. - * - * @param string $value An 8-byte string - * @param string $key - * - * @return string - */ - protected function desEncrypt($value, $key) - { - return substr(openssl_encrypt($value, 'DES-ECB', $key, \OPENSSL_RAW_DATA), 0, 8); - } - - /** - * MD5 Encryption. - * - * @param string $key Encryption key - * @param string $msg Message to encrypt - * - * @return string - */ - protected function md5Encrypt($key, $msg) - { - $blocksize = 64; - if (\strlen($key) > $blocksize) { - $key = pack('H*', md5($key)); - } - - $key = str_pad($key, $blocksize, "\0"); - $ipadk = $key ^ str_repeat("\x36", $blocksize); - $opadk = $key ^ str_repeat("\x5c", $blocksize); - - return pack('H*', md5($opadk.pack('H*', md5($ipadk.$msg)))); - } - - /** - * MD4 Encryption. - * - * @param string $input - * - * @return string - * - * @see https://secure.php.net/manual/en/ref.hash.php - */ - protected function md4Encrypt($input) - { - $input = $this->convertTo16bit($input); - - return \function_exists('hash') ? hex2bin(hash('md4', $input)) : mhash(MHASH_MD4, $input); - } - - /** - * Convert UTF-8 to UTF-16. - * - * @param string $input - * - * @return string - */ - protected function convertTo16bit($input) - { - return iconv('UTF-8', 'UTF-16LE', $input); - } - - /** - * @param string $message - */ - protected function debug($message) - { - $message = bin2hex($message); - $messageId = substr($message, 16, 8); - echo substr($message, 0, 16)." NTLMSSP Signature
\n"; - echo $messageId." Type Indicator
\n"; - - if ('02000000' == $messageId) { - $map = [ - 'Challenge', - 'Context', - 'Target Information Security Buffer', - 'Target Name Data', - 'NetBIOS Domain Name', - 'NetBIOS Server Name', - 'DNS Domain Name', - 'DNS Server Name', - 'BLOB', - 'Target Information Terminator', - ]; - - $data = $this->parseMessage2(hex2bin($message)); - - foreach ($map as $key => $value) { - echo bin2hex($data[$key]).' - '.$data[$key].' ||| '.$value."
\n"; - } - } elseif ('03000000' == $messageId) { - $i = 0; - $data[$i++] = substr($message, 24, 16); - list($lmLength, $lmOffset) = $this->readSecurityBuffer($data[$i - 1]); - - $data[$i++] = substr($message, 40, 16); - list($ntmlLength, $ntmlOffset) = $this->readSecurityBuffer($data[$i - 1]); - - $data[$i++] = substr($message, 56, 16); - list($targetLength, $targetOffset) = $this->readSecurityBuffer($data[$i - 1]); - - $data[$i++] = substr($message, 72, 16); - list($userLength, $userOffset) = $this->readSecurityBuffer($data[$i - 1]); - - $data[$i++] = substr($message, 88, 16); - list($workLength, $workOffset) = $this->readSecurityBuffer($data[$i - 1]); - - $data[$i++] = substr($message, 104, 16); - $data[$i++] = substr($message, 120, 8); - $data[$i++] = substr($message, $targetOffset, $targetLength); - $data[$i++] = substr($message, $userOffset, $userLength); - $data[$i++] = substr($message, $workOffset, $workLength); - $data[$i++] = substr($message, $lmOffset, $lmLength); - $data[$i] = substr($message, $ntmlOffset, $ntmlLength); - - $map = [ - 'LM Response Security Buffer', - 'NTLM Response Security Buffer', - 'Target Name Security Buffer', - 'User Name Security Buffer', - 'Workstation Name Security Buffer', - 'Session Key Security Buffer', - 'Flags', - 'Target Name Data', - 'User Name Data', - 'Workstation Name Data', - 'LM Response Data', - 'NTLM Response Data', - ]; - - foreach ($map as $key => $value) { - echo $data[$key].' - '.hex2bin($data[$key]).' ||| '.$value."
\n"; - } - } - - echo '

'; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php deleted file mode 100644 index 41d0a50..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php +++ /dev/null @@ -1,44 +0,0 @@ -executeCommand(sprintf("AUTH PLAIN %s\r\n", $message), [235]); - - return true; - } catch (Swift_TransportException $e) { - $agent->executeCommand("RSET\r\n", [250]); - - throw $e; - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php deleted file mode 100644 index 859f22f..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php +++ /dev/null @@ -1,64 +0,0 @@ - - * $transport = (new Swift_SmtpTransport('smtp.gmail.com', 587, 'tls')) - * ->setAuthMode('XOAUTH2') - * ->setUsername('YOUR_EMAIL_ADDRESS') - * ->setPassword('YOUR_ACCESS_TOKEN'); - * - * - * @author xu.li - * - * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol - */ -class Swift_Transport_Esmtp_Auth_XOAuth2Authenticator implements Swift_Transport_Esmtp_Authenticator -{ - /** - * Get the name of the AUTH mechanism this Authenticator handles. - * - * @return string - */ - public function getAuthKeyword() - { - return 'XOAUTH2'; - } - - /** - * {@inheritdoc} - */ - public function authenticate(Swift_Transport_SmtpAgent $agent, $email, $token) - { - try { - $param = $this->constructXOAuth2Params($email, $token); - $agent->executeCommand('AUTH XOAUTH2 '.$param."\r\n", [235]); - - return true; - } catch (Swift_TransportException $e) { - $agent->executeCommand("RSET\r\n", [250]); - - throw $e; - } - } - - /** - * Construct the auth parameter. - * - * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol#the_sasl_xoauth2_mechanism - */ - protected function constructXOAuth2Params($email, $token) - { - return base64_encode("user=$email\1auth=Bearer $token\1\1"); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php deleted file mode 100644 index 53a90a8..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php +++ /dev/null @@ -1,268 +0,0 @@ -setAuthenticators($authenticators); - } - - /** - * Set the Authenticators which can process a login request. - * - * @param Swift_Transport_Esmtp_Authenticator[] $authenticators - */ - public function setAuthenticators(array $authenticators) - { - $this->authenticators = $authenticators; - } - - /** - * Get the Authenticators which can process a login request. - * - * @return Swift_Transport_Esmtp_Authenticator[] - */ - public function getAuthenticators() - { - return $this->authenticators; - } - - /** - * Set the username to authenticate with. - * - * @param string $username - */ - public function setUsername($username) - { - $this->username = $username; - } - - /** - * Get the username to authenticate with. - * - * @return string - */ - public function getUsername() - { - return $this->username; - } - - /** - * Set the password to authenticate with. - * - * @param string $password - */ - public function setPassword($password) - { - $this->password = $password; - } - - /** - * Get the password to authenticate with. - * - * @return string - */ - public function getPassword() - { - return $this->password; - } - - /** - * Set the auth mode to use to authenticate. - * - * @param string $mode - */ - public function setAuthMode($mode) - { - $this->auth_mode = $mode; - } - - /** - * Get the auth mode to use to authenticate. - * - * @return string - */ - public function getAuthMode() - { - return $this->auth_mode; - } - - /** - * Get the name of the ESMTP extension this handles. - * - * @return string - */ - public function getHandledKeyword() - { - return 'AUTH'; - } - - /** - * Set the parameters which the EHLO greeting indicated. - * - * @param string[] $parameters - */ - public function setKeywordParams(array $parameters) - { - $this->esmtpParams = $parameters; - } - - /** - * Runs immediately after a EHLO has been issued. - * - * @param Swift_Transport_SmtpAgent $agent to read/write - */ - public function afterEhlo(Swift_Transport_SmtpAgent $agent) - { - if ($this->username) { - $count = 0; - $errors = []; - foreach ($this->getAuthenticatorsForAgent() as $authenticator) { - if (\in_array(strtolower($authenticator->getAuthKeyword() ?? ''), array_map('strtolower', $this->esmtpParams))) { - ++$count; - try { - if ($authenticator->authenticate($agent, $this->username, $this->password)) { - return; - } - } catch (Swift_TransportException $e) { - // keep the error message, but tries the other authenticators - $errors[] = [$authenticator->getAuthKeyword(), $e->getMessage()]; - } - } - } - - $message = 'Failed to authenticate on SMTP server with username "'.$this->username.'" using '.$count.' possible authenticators.'; - foreach ($errors as $error) { - $message .= ' Authenticator '.$error[0].' returned '.$error[1].'.'; - } - throw new Swift_TransportException($message); - } - } - - /** - * Not used. - */ - public function getMailParams() - { - return []; - } - - /** - * Not used. - */ - public function getRcptParams() - { - return []; - } - - /** - * Not used. - */ - public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false) - { - } - - /** - * Returns +1, -1 or 0 according to the rules for usort(). - * - * This method is called to ensure extensions can be execute in an appropriate order. - * - * @param string $esmtpKeyword to compare with - * - * @return int - */ - public function getPriorityOver($esmtpKeyword) - { - return 0; - } - - /** - * Returns an array of method names which are exposed to the Esmtp class. - * - * @return string[] - */ - public function exposeMixinMethods() - { - return ['setUsername', 'getUsername', 'setPassword', 'getPassword', 'setAuthMode', 'getAuthMode']; - } - - /** - * Not used. - */ - public function resetState() - { - } - - /** - * Returns the authenticator list for the given agent. - * - * @return array - */ - protected function getAuthenticatorsForAgent() - { - if (!$mode = strtolower($this->auth_mode ?? '')) { - return $this->authenticators; - } - - foreach ($this->authenticators as $authenticator) { - if (strtolower($authenticator->getAuthKeyword() ?? '') == $mode) { - return [$authenticator]; - } - } - - throw new Swift_TransportException('Auth mode '.$mode.' is invalid'); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php deleted file mode 100644 index f692a6f..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php +++ /dev/null @@ -1,36 +0,0 @@ -encoding = $encoding; - } - - /** - * Get the name of the ESMTP extension this handles. - * - * @return string - */ - public function getHandledKeyword() - { - return '8BITMIME'; - } - - /** - * Not used. - */ - public function setKeywordParams(array $parameters) - { - } - - /** - * Not used. - */ - public function afterEhlo(Swift_Transport_SmtpAgent $agent) - { - } - - /** - * Get params which are appended to MAIL FROM:<>. - * - * @return string[] - */ - public function getMailParams() - { - return ['BODY='.$this->encoding]; - } - - /** - * Not used. - */ - public function getRcptParams() - { - return []; - } - - /** - * Not used. - */ - public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false) - { - } - - /** - * Returns +1, -1 or 0 according to the rules for usort(). - * - * This method is called to ensure extensions can be execute in an appropriate order. - * - * @param string $esmtpKeyword to compare with - * - * @return int - */ - public function getPriorityOver($esmtpKeyword) - { - return 0; - } - - /** - * Not used. - */ - public function exposeMixinMethods() - { - return []; - } - - /** - * Not used. - */ - public function resetState() - { - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/SmtpUtf8Handler.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/SmtpUtf8Handler.php deleted file mode 100644 index 7d0252a..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/SmtpUtf8Handler.php +++ /dev/null @@ -1,107 +0,0 @@ -. - * - * @return string[] - */ - public function getMailParams() - { - return ['SMTPUTF8']; - } - - /** - * Not used. - */ - public function getRcptParams() - { - return []; - } - - /** - * Not used. - */ - public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false) - { - } - - /** - * Returns +1, -1 or 0 according to the rules for usort(). - * - * This method is called to ensure extensions can be execute in an appropriate order. - * - * @param string $esmtpKeyword to compare with - * - * @return int - */ - public function getPriorityOver($esmtpKeyword) - { - return 0; - } - - /** - * Not used. - */ - public function exposeMixinMethods() - { - return []; - } - - /** - * Not used. - */ - public function resetState() - { - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpHandler.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpHandler.php deleted file mode 100644 index b8ea36e..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpHandler.php +++ /dev/null @@ -1,86 +0,0 @@ -. - * - * @return string[] - */ - public function getMailParams(); - - /** - * Get params which are appended to RCPT TO:<>. - * - * @return string[] - */ - public function getRcptParams(); - - /** - * Runs when a command is due to be sent. - * - * @param Swift_Transport_SmtpAgent $agent to read/write - * @param string $command to send - * @param int[] $codes expected in response - * @param string[] $failedRecipients to collect failures - * @param bool $stop to be set true by-reference if the command is now sent - */ - public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false); - - /** - * Returns +1, -1 or 0 according to the rules for usort(). - * - * This method is called to ensure extensions can be execute in an appropriate order. - * - * @param string $esmtpKeyword to compare with - * - * @return int - */ - public function getPriorityOver($esmtpKeyword); - - /** - * Returns an array of method names which are exposed to the Esmtp class. - * - * @return string[] - */ - public function exposeMixinMethods(); - - /** - * Tells this handler to clear any buffers and reset its state. - */ - public function resetState(); -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php deleted file mode 100644 index 36545f5..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php +++ /dev/null @@ -1,446 +0,0 @@ - 'tcp', - 'host' => 'localhost', - 'port' => 25, - 'timeout' => 30, - 'blocking' => 1, - 'tls' => false, - 'type' => Swift_Transport_IoBuffer::TYPE_SOCKET, - 'stream_context_options' => [], - ]; - - /** - * Creates a new EsmtpTransport using the given I/O buffer. - * - * @param Swift_Transport_EsmtpHandler[] $extensionHandlers - * @param string $localDomain - */ - public function __construct(Swift_Transport_IoBuffer $buf, array $extensionHandlers, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1', Swift_AddressEncoder $addressEncoder = null) - { - parent::__construct($buf, $dispatcher, $localDomain, $addressEncoder); - $this->setExtensionHandlers($extensionHandlers); - } - - /** - * Set the host to connect to. - * - * Literal IPv6 addresses should be wrapped in square brackets. - * - * @param string $host - * - * @return $this - */ - public function setHost($host) - { - $this->params['host'] = $host; - - return $this; - } - - /** - * Get the host to connect to. - * - * @return string - */ - public function getHost() - { - return $this->params['host']; - } - - /** - * Set the port to connect to. - * - * @param int $port - * - * @return $this - */ - public function setPort($port) - { - $this->params['port'] = (int) $port; - - return $this; - } - - /** - * Get the port to connect to. - * - * @return int - */ - public function getPort() - { - return $this->params['port']; - } - - /** - * Set the connection timeout. - * - * @param int $timeout seconds - * - * @return $this - */ - public function setTimeout($timeout) - { - $this->params['timeout'] = (int) $timeout; - $this->buffer->setParam('timeout', (int) $timeout); - - return $this; - } - - /** - * Get the connection timeout. - * - * @return int - */ - public function getTimeout() - { - return $this->params['timeout']; - } - - /** - * Set the encryption type (tls or ssl). - * - * @param string $encryption - * - * @return $this - */ - public function setEncryption($encryption) - { - $encryption = strtolower($encryption ?? ''); - if ('tls' == $encryption) { - $this->params['protocol'] = 'tcp'; - $this->params['tls'] = true; - } else { - $this->params['protocol'] = $encryption; - $this->params['tls'] = false; - } - - return $this; - } - - /** - * Get the encryption type. - * - * @return string - */ - public function getEncryption() - { - return $this->params['tls'] ? 'tls' : $this->params['protocol']; - } - - /** - * Sets the stream context options. - * - * @param array $options - * - * @return $this - */ - public function setStreamOptions($options) - { - $this->params['stream_context_options'] = $options; - - return $this; - } - - /** - * Returns the stream context options. - * - * @return array - */ - public function getStreamOptions() - { - return $this->params['stream_context_options']; - } - - /** - * Sets the source IP. - * - * IPv6 addresses should be wrapped in square brackets. - * - * @param string $source - * - * @return $this - */ - public function setSourceIp($source) - { - $this->params['sourceIp'] = $source; - - return $this; - } - - /** - * Returns the IP used to connect to the destination. - * - * @return string - */ - public function getSourceIp() - { - return $this->params['sourceIp'] ?? null; - } - - /** - * Sets whether SMTP pipelining is enabled. - * - * By default, support is auto-detected using the PIPELINING SMTP extension. - * Use this function to override that in the unlikely event of compatibility - * issues. - * - * @param bool $enabled - * - * @return $this - */ - public function setPipelining($enabled) - { - $this->pipelining = $enabled; - - return $this; - } - - /** - * Returns whether SMTP pipelining is enabled. - * - * @return bool|null a boolean if pipelining is explicitly enabled or disabled, - * or null if support is auto-detected - */ - public function getPipelining() - { - return $this->pipelining; - } - - /** - * Set ESMTP extension handlers. - * - * @param Swift_Transport_EsmtpHandler[] $handlers - * - * @return $this - */ - public function setExtensionHandlers(array $handlers) - { - $assoc = []; - foreach ($handlers as $handler) { - $assoc[$handler->getHandledKeyword()] = $handler; - } - uasort($assoc, function ($a, $b) { - return $a->getPriorityOver($b->getHandledKeyword()); - }); - $this->handlers = $assoc; - $this->setHandlerParams(); - - return $this; - } - - /** - * Get ESMTP extension handlers. - * - * @return Swift_Transport_EsmtpHandler[] - */ - public function getExtensionHandlers() - { - return array_values($this->handlers); - } - - /** - * Run a command against the buffer, expecting the given response codes. - * - * If no response codes are given, the response will not be validated. - * If codes are given, an exception will be thrown on an invalid response. - * - * @param string $command - * @param int[] $codes - * @param string[] $failures An array of failures by-reference - * @param bool $pipeline Do not wait for response - * @param string $address the address, if command is RCPT TO - * - * @return string|null The server response, or null if pipelining is enabled - */ - public function executeCommand($command, $codes = [], &$failures = null, $pipeline = false, $address = null) - { - $failures = (array) $failures; - $stopSignal = false; - $response = null; - foreach ($this->getActiveHandlers() as $handler) { - $response = $handler->onCommand( - $this, $command, $codes, $failures, $stopSignal - ); - if ($stopSignal) { - return $response; - } - } - - return parent::executeCommand($command, $codes, $failures, $pipeline, $address); - } - - /** Mixin handling method for ESMTP handlers */ - public function __call($method, $args) - { - foreach ($this->handlers as $handler) { - if (\in_array(strtolower($method), - array_map('strtolower', (array) $handler->exposeMixinMethods()) - )) { - $return = \call_user_func_array([$handler, $method], $args); - // Allow fluid method calls - if (null === $return && 'set' == substr($method, 0, 3)) { - return $this; - } else { - return $return; - } - } - } - trigger_error('Call to undefined method '.$method, E_USER_ERROR); - } - - /** Get the params to initialize the buffer */ - protected function getBufferParams() - { - return $this->params; - } - - /** Overridden to perform EHLO instead */ - protected function doHeloCommand() - { - try { - $response = $this->executeCommand( - sprintf("EHLO %s\r\n", $this->domain), [250] - ); - } catch (Swift_TransportException $e) { - return parent::doHeloCommand(); - } - - if ($this->params['tls']) { - try { - $this->executeCommand("STARTTLS\r\n", [220]); - - if (!$this->buffer->startTLS()) { - throw new Swift_TransportException('Unable to connect with TLS encryption'); - } - - try { - $response = $this->executeCommand( - sprintf("EHLO %s\r\n", $this->domain), [250] - ); - } catch (Swift_TransportException $e) { - return parent::doHeloCommand(); - } - } catch (Swift_TransportException $e) { - $this->throwException($e); - } - } - - $this->capabilities = $this->getCapabilities($response); - if (!isset($this->pipelining)) { - $this->pipelining = isset($this->capabilities['PIPELINING']); - } - - $this->setHandlerParams(); - foreach ($this->getActiveHandlers() as $handler) { - $handler->afterEhlo($this); - } - } - - /** Overridden to add Extension support */ - protected function doMailFromCommand($address) - { - $address = $this->addressEncoder->encodeString($address); - $handlers = $this->getActiveHandlers(); - $params = []; - foreach ($handlers as $handler) { - $params = array_merge($params, (array) $handler->getMailParams()); - } - $paramStr = !empty($params) ? ' '.implode(' ', $params) : ''; - $this->executeCommand( - sprintf("MAIL FROM:<%s>%s\r\n", $address, $paramStr), [250], $failures, true - ); - } - - /** Overridden to add Extension support */ - protected function doRcptToCommand($address) - { - $address = $this->addressEncoder->encodeString($address); - $handlers = $this->getActiveHandlers(); - $params = []; - foreach ($handlers as $handler) { - $params = array_merge($params, (array) $handler->getRcptParams()); - } - $paramStr = !empty($params) ? ' '.implode(' ', $params) : ''; - $this->executeCommand( - sprintf("RCPT TO:<%s>%s\r\n", $address, $paramStr), [250, 251, 252], $failures, true, $address - ); - } - - /** Determine ESMTP capabilities by function group */ - private function getCapabilities($ehloResponse) - { - $capabilities = []; - $ehloResponse = trim($ehloResponse ?? ''); - $lines = explode("\r\n", $ehloResponse); - array_shift($lines); - foreach ($lines as $line) { - if (preg_match('/^[0-9]{3}[ -]([A-Z0-9-]+)((?:[ =].*)?)$/Di', $line, $matches)) { - $keyword = strtoupper($matches[1]); - $paramStr = strtoupper(ltrim($matches[2], ' =')); - $params = !empty($paramStr) ? explode(' ', $paramStr) : []; - $capabilities[$keyword] = $params; - } - } - - return $capabilities; - } - - /** Set parameters which are used by each extension handler */ - private function setHandlerParams() - { - foreach ($this->handlers as $keyword => $handler) { - if (\array_key_exists($keyword, $this->capabilities)) { - $handler->setKeywordParams($this->capabilities[$keyword]); - } - } - } - - /** Get ESMTP handlers which are currently ok to use */ - private function getActiveHandlers() - { - $handlers = []; - foreach ($this->handlers as $keyword => $handler) { - if (\array_key_exists($keyword, $this->capabilities)) { - $handlers[] = $handler; - } - } - - return $handlers; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php deleted file mode 100644 index 1a4b475..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php +++ /dev/null @@ -1,103 +0,0 @@ -transports); - for ($i = 0; $i < $maxTransports - && $transport = $this->getNextTransport(); ++$i) { - if ($transport->ping()) { - return true; - } else { - $this->killCurrentTransport(); - } - } - - return \count($this->transports) > 0; - } - - /** - * Send the given Message. - * - * Recipient/sender data will be retrieved from the Message API. - * The return value is the number of recipients who were accepted for delivery. - * - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int - */ - public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) - { - $maxTransports = \count($this->transports); - $sent = 0; - $this->lastUsedTransport = null; - - for ($i = 0; $i < $maxTransports - && $transport = $this->getNextTransport(); ++$i) { - try { - if (!$transport->isStarted()) { - $transport->start(); - } - - if ($sent = $transport->send($message, $failedRecipients)) { - $this->lastUsedTransport = $transport; - - return $sent; - } - } catch (Swift_TransportException $e) { - $this->killCurrentTransport(); - } - } - - if (0 == \count($this->transports)) { - throw new Swift_TransportException('All Transports in FailoverTransport failed, or no Transports available'); - } - - return $sent; - } - - protected function getNextTransport() - { - if (!isset($this->currentTransport)) { - $this->currentTransport = parent::getNextTransport(); - } - - return $this->currentTransport; - } - - protected function killCurrentTransport() - { - $this->currentTransport = null; - parent::killCurrentTransport(); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php deleted file mode 100644 index 50f1e5e..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php +++ /dev/null @@ -1,65 +0,0 @@ -transports = $transports; - $this->deadTransports = []; - } - - /** - * Get $transports to delegate to. - * - * @return Swift_Transport[] - */ - public function getTransports() - { - return array_merge($this->transports, $this->deadTransports); - } - - /** - * Get the Transport used in the last successful send operation. - * - * @return Swift_Transport - */ - public function getLastUsedTransport() - { - return $this->lastUsedTransport; - } - - /** - * Test if this Transport mechanism has started. - * - * @return bool - */ - public function isStarted() - { - return \count($this->transports) > 0; - } - - /** - * Start this Transport mechanism. - */ - public function start() - { - $this->transports = array_merge($this->transports, $this->deadTransports); - } - - /** - * Stop this Transport mechanism. - */ - public function stop() - { - foreach ($this->transports as $transport) { - $transport->stop(); - } - } - - /** - * {@inheritdoc} - */ - public function ping() - { - foreach ($this->transports as $transport) { - if (!$transport->ping()) { - $this->killCurrentTransport(); - } - } - - return \count($this->transports) > 0; - } - - /** - * Send the given Message. - * - * Recipient/sender data will be retrieved from the Message API. - * The return value is the number of recipients who were accepted for delivery. - * - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int - */ - public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) - { - $maxTransports = \count($this->transports); - $sent = 0; - $this->lastUsedTransport = null; - - for ($i = 0; $i < $maxTransports - && $transport = $this->getNextTransport(); ++$i) { - try { - if (!$transport->isStarted()) { - $transport->start(); - } - if ($sent = $transport->send($message, $failedRecipients)) { - $this->lastUsedTransport = $transport; - break; - } - } catch (Swift_TransportException $e) { - $this->killCurrentTransport(); - } - } - - if (0 == \count($this->transports)) { - throw new Swift_TransportException('All Transports in LoadBalancedTransport failed, or no Transports available'); - } - - return $sent; - } - - /** - * Register a plugin. - */ - public function registerPlugin(Swift_Events_EventListener $plugin) - { - foreach ($this->transports as $transport) { - $transport->registerPlugin($plugin); - } - } - - /** - * Rotates the transport list around and returns the first instance. - * - * @return Swift_Transport - */ - protected function getNextTransport() - { - if ($next = array_shift($this->transports)) { - $this->transports[] = $next; - } - - return $next; - } - - /** - * Tag the currently used (top of stack) transport as dead/useless. - */ - protected function killCurrentTransport() - { - if ($transport = array_pop($this->transports)) { - try { - $transport->stop(); - } catch (Exception $e) { - } - $this->deadTransports[] = $transport; - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/NullTransport.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/NullTransport.php deleted file mode 100644 index 7d910db..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/NullTransport.php +++ /dev/null @@ -1,98 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Pretends messages have been sent, but just ignores them. - * - * @author Fabien Potencier - */ -class Swift_Transport_NullTransport implements Swift_Transport -{ - /** The event dispatcher from the plugin API */ - private $eventDispatcher; - - /** - * Constructor. - */ - public function __construct(Swift_Events_EventDispatcher $eventDispatcher) - { - $this->eventDispatcher = $eventDispatcher; - } - - /** - * Tests if this Transport mechanism has started. - * - * @return bool - */ - public function isStarted() - { - return true; - } - - /** - * Starts this Transport mechanism. - */ - public function start() - { - } - - /** - * Stops this Transport mechanism. - */ - public function stop() - { - } - - /** - * {@inheritdoc} - */ - public function ping() - { - return true; - } - - /** - * Sends the given message. - * - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int The number of sent emails - */ - public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) - { - if ($evt = $this->eventDispatcher->createSendEvent($this, $message)) { - $this->eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); - if ($evt->bubbleCancelled()) { - return 0; - } - } - - if ($evt) { - $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); - $this->eventDispatcher->dispatchEvent($evt, 'sendPerformed'); - } - - $count = ( - \count((array) $message->getTo()) - + \count((array) $message->getCc()) - + \count((array) $message->getBcc()) - ); - - return $count; - } - - /** - * Register a plugin. - */ - public function registerPlugin(Swift_Events_EventListener $plugin) - { - $this->eventDispatcher->bindEventListener($plugin); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php deleted file mode 100644 index 65a434d..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php +++ /dev/null @@ -1,158 +0,0 @@ - 30, - 'blocking' => 1, - 'command' => '/usr/sbin/sendmail -bs', - 'type' => Swift_Transport_IoBuffer::TYPE_PROCESS, - ]; - - /** - * Create a new SendmailTransport with $buf for I/O. - * - * @param string $localDomain - */ - public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1', Swift_AddressEncoder $addressEncoder = null) - { - parent::__construct($buf, $dispatcher, $localDomain, $addressEncoder); - } - - /** - * Start the standalone SMTP session if running in -bs mode. - */ - public function start() - { - if (false !== strpos($this->getCommand(), ' -bs')) { - parent::start(); - } - } - - /** - * Set the command to invoke. - * - * If using -t mode you are strongly advised to include -oi or -i in the flags. - * For example: /usr/sbin/sendmail -oi -t - * Swift will append a -f flag if one is not present. - * - * The recommended mode is "-bs" since it is interactive and failure notifications - * are hence possible. - * - * @param string $command - * - * @return $this - */ - public function setCommand($command) - { - $this->params['command'] = $command; - - return $this; - } - - /** - * Get the sendmail command which will be invoked. - * - * @return string - */ - public function getCommand() - { - return $this->params['command']; - } - - /** - * Send the given Message. - * - * Recipient/sender data will be retrieved from the Message API. - * - * The return value is the number of recipients who were accepted for delivery. - * NOTE: If using 'sendmail -t' you will not be aware of any failures until - * they bounce (i.e. send() will always return 100% success). - * - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int - */ - public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) - { - $failedRecipients = (array) $failedRecipients; - $command = $this->getCommand(); - $buffer = $this->getBuffer(); - $count = 0; - - if (false !== strpos($command, ' -t')) { - if ($evt = $this->eventDispatcher->createSendEvent($this, $message)) { - $this->eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); - if ($evt->bubbleCancelled()) { - return 0; - } - } - - if (false === strpos($command, ' -f')) { - $command .= ' -f'.escapeshellarg($this->getReversePath($message) ?? ''); - } - - $buffer->initialize(array_merge($this->params, ['command' => $command])); - - if (false === strpos($command, ' -i') && false === strpos($command, ' -oi')) { - $buffer->setWriteTranslations(["\r\n" => "\n", "\n." => "\n.."]); - } else { - $buffer->setWriteTranslations(["\r\n" => "\n"]); - } - - $count = \count((array) $message->getTo()) - + \count((array) $message->getCc()) - + \count((array) $message->getBcc()) - ; - $message->toByteStream($buffer); - $buffer->flushBuffers(); - $buffer->setWriteTranslations([]); - $buffer->terminate(); - - if ($evt) { - $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); - $evt->setFailedRecipients($failedRecipients); - $this->eventDispatcher->dispatchEvent($evt, 'sendPerformed'); - } - - $message->generateId(); - } elseif (false !== strpos($command, ' -bs')) { - $count = parent::send($message, $failedRecipients); - } else { - $this->throwException(new Swift_TransportException( - 'Unsupported sendmail command flags ['.$command.']. '. - 'Must be one of "-bs" or "-t" but can include additional flags.' - )); - } - - return $count; - } - - /** Get the params to initialize the buffer */ - protected function getBufferParams() - { - return $this->params; - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SmtpAgent.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SmtpAgent.php deleted file mode 100644 index e8ce65c..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SmtpAgent.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * Stores Messages in a queue. - * - * @author Fabien Potencier - */ -class Swift_Transport_SpoolTransport implements Swift_Transport -{ - /** The spool instance */ - private $spool; - - /** The event dispatcher from the plugin API */ - private $eventDispatcher; - - /** - * Constructor. - */ - public function __construct(Swift_Events_EventDispatcher $eventDispatcher, Swift_Spool $spool = null) - { - $this->eventDispatcher = $eventDispatcher; - $this->spool = $spool; - } - - /** - * Sets the spool object. - * - * @return $this - */ - public function setSpool(Swift_Spool $spool) - { - $this->spool = $spool; - - return $this; - } - - /** - * Get the spool object. - * - * @return Swift_Spool - */ - public function getSpool() - { - return $this->spool; - } - - /** - * Tests if this Transport mechanism has started. - * - * @return bool - */ - public function isStarted() - { - return true; - } - - /** - * Starts this Transport mechanism. - */ - public function start() - { - } - - /** - * Stops this Transport mechanism. - */ - public function stop() - { - } - - /** - * {@inheritdoc} - */ - public function ping() - { - return true; - } - - /** - * Sends the given message. - * - * @param string[] $failedRecipients An array of failures by-reference - * - * @return int The number of sent e-mail's - */ - public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) - { - if ($evt = $this->eventDispatcher->createSendEvent($this, $message)) { - $this->eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); - if ($evt->bubbleCancelled()) { - return 0; - } - } - - $success = $this->spool->queueMessage($message); - - if ($evt) { - $evt->setResult($success ? Swift_Events_SendEvent::RESULT_SPOOLED : Swift_Events_SendEvent::RESULT_FAILED); - $this->eventDispatcher->dispatchEvent($evt, 'sendPerformed'); - } - - return 1; - } - - /** - * Register a plugin. - */ - public function registerPlugin(Swift_Events_EventListener $plugin) - { - $this->eventDispatcher->bindEventListener($plugin); - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php deleted file mode 100644 index 70782ad..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php +++ /dev/null @@ -1,319 +0,0 @@ -replacementFactory = $replacementFactory; - } - - /** - * Perform any initialization needed, using the given $params. - * - * Parameters will vary depending upon the type of IoBuffer used. - */ - public function initialize(array $params) - { - $this->params = $params; - switch ($params['type']) { - case self::TYPE_PROCESS: - $this->establishProcessConnection(); - break; - case self::TYPE_SOCKET: - default: - $this->establishSocketConnection(); - break; - } - } - - /** - * Set an individual param on the buffer (e.g. switching to SSL). - * - * @param string $param - * @param mixed $value - */ - public function setParam($param, $value) - { - if (isset($this->stream)) { - switch ($param) { - case 'timeout': - if ($this->stream) { - stream_set_timeout($this->stream, $value); - } - break; - - case 'blocking': - if ($this->stream) { - stream_set_blocking($this->stream, 1); - } - } - } - $this->params[$param] = $value; - } - - public function startTLS() - { - // STREAM_CRYPTO_METHOD_TLS_CLIENT only allow tls1.0 connections (some php versions) - // To support modern tls we allow explicit tls1.0, tls1.1, tls1.2 - // Ssl3 and older are not allowed because they are vulnerable - // @TODO make tls arguments configurable - return stream_socket_enable_crypto($this->stream, true, STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT); - } - - /** - * Perform any shutdown logic needed. - */ - public function terminate() - { - if (isset($this->stream)) { - switch ($this->params['type']) { - case self::TYPE_PROCESS: - fclose($this->in); - fclose($this->out); - proc_close($this->stream); - break; - case self::TYPE_SOCKET: - default: - fclose($this->stream); - break; - } - } - $this->stream = null; - $this->out = null; - $this->in = null; - } - - /** - * Set an array of string replacements which should be made on data written - * to the buffer. - * - * This could replace LF with CRLF for example. - * - * @param string[] $replacements - */ - public function setWriteTranslations(array $replacements) - { - foreach ($this->translations as $search => $replace) { - if (!isset($replacements[$search])) { - $this->removeFilter($search); - unset($this->translations[$search]); - } - } - - foreach ($replacements as $search => $replace) { - if (!isset($this->translations[$search])) { - $this->addFilter( - $this->replacementFactory->createFilter($search, $replace), $search - ); - $this->translations[$search] = true; - } - } - } - - /** - * Get a line of output (including any CRLF). - * - * The $sequence number comes from any writes and may or may not be used - * depending upon the implementation. - * - * @param int $sequence of last write to scan from - * - * @return string - * - * @throws Swift_IoException - */ - public function readLine($sequence) - { - if (isset($this->out) && !feof($this->out)) { - $line = fgets($this->out); - if (0 == \strlen($line)) { - $metas = stream_get_meta_data($this->out); - if ($metas['timed_out']) { - throw new Swift_IoException('Connection to '.$this->getReadConnectionDescription().' Timed Out'); - } - } - - return $line; - } - } - - /** - * Reads $length bytes from the stream into a string and moves the pointer - * through the stream by $length. - * - * If less bytes exist than are requested the remaining bytes are given instead. - * If no bytes are remaining at all, boolean false is returned. - * - * @param int $length - * - * @return string|bool - * - * @throws Swift_IoException - */ - public function read($length) - { - if (isset($this->out) && !feof($this->out)) { - $ret = fread($this->out, $length); - if (0 == \strlen($ret)) { - $metas = stream_get_meta_data($this->out); - if ($metas['timed_out']) { - throw new Swift_IoException('Connection to '.$this->getReadConnectionDescription().' Timed Out'); - } - } - - return $ret; - } - } - - /** Not implemented */ - public function setReadPointer($byteOffset) - { - } - - /** Flush the stream contents */ - protected function flush() - { - if (isset($this->in)) { - fflush($this->in); - } - } - - /** Write this bytes to the stream */ - protected function doCommit($bytes) - { - if (isset($this->in)) { - $bytesToWrite = \strlen($bytes); - $totalBytesWritten = 0; - - while ($totalBytesWritten < $bytesToWrite) { - $bytesWritten = fwrite($this->in, substr($bytes, $totalBytesWritten)); - if (false === $bytesWritten || 0 === $bytesWritten) { - break; - } - - $totalBytesWritten += $bytesWritten; - } - - if ($totalBytesWritten > 0) { - return ++$this->sequence; - } - } - } - - /** - * Establishes a connection to a remote server. - */ - private function establishSocketConnection() - { - $host = $this->params['host']; - if (!empty($this->params['protocol'])) { - $host = $this->params['protocol'].'://'.$host; - } - $timeout = 15; - if (!empty($this->params['timeout'])) { - $timeout = $this->params['timeout']; - } - $options = []; - if (!empty($this->params['sourceIp'])) { - $options['socket']['bindto'] = $this->params['sourceIp'].':0'; - } - - if (isset($this->params['stream_context_options'])) { - $options = array_merge($options, $this->params['stream_context_options']); - } - $streamContext = stream_context_create($options); - - set_error_handler(function ($type, $msg) { - throw new Swift_TransportException('Connection could not be established with host '.$this->params['host'].' :'.$msg); - }); - try { - $this->stream = stream_socket_client($host.':'.$this->params['port'], $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $streamContext); - } finally { - restore_error_handler(); - } - - if (!empty($this->params['blocking'])) { - stream_set_blocking($this->stream, 1); - } else { - stream_set_blocking($this->stream, 0); - } - stream_set_timeout($this->stream, $timeout); - $this->in = &$this->stream; - $this->out = &$this->stream; - } - - /** - * Opens a process for input/output. - */ - private function establishProcessConnection() - { - $command = $this->params['command']; - $descriptorSpec = [ - 0 => ['pipe', 'r'], - 1 => ['pipe', 'w'], - 2 => ['pipe', 'w'], - ]; - $pipes = []; - $this->stream = proc_open($command, $descriptorSpec, $pipes); - stream_set_blocking($pipes[2], 0); - if ($err = stream_get_contents($pipes[2])) { - throw new Swift_TransportException('Process could not be started ['.$err.']'); - } - $this->in = &$pipes[0]; - $this->out = &$pipes[1]; - } - - private function getReadConnectionDescription() - { - switch ($this->params['type']) { - case self::TYPE_PROCESS: - return 'Process '.$this->params['command']; - break; - - case self::TYPE_SOCKET: - default: - $host = $this->params['host']; - if (!empty($this->params['protocol'])) { - $host = $this->params['protocol'].'://'.$host; - } - $host .= ':'.$this->params['port']; - - return $host; - break; - } - } -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/TransportException.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/TransportException.php deleted file mode 100644 index c741745..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/TransportException.php +++ /dev/null @@ -1,28 +0,0 @@ -register('cache') - ->asAliasOf('cache.array') - - ->register('tempdir') - ->asValue('/tmp') - - ->register('cache.null') - ->asSharedInstanceOf('Swift_KeyCache_NullKeyCache') - - ->register('cache.array') - ->asSharedInstanceOf('Swift_KeyCache_ArrayKeyCache') - ->withDependencies(['cache.inputstream']) - - ->register('cache.disk') - ->asSharedInstanceOf('Swift_KeyCache_DiskKeyCache') - ->withDependencies(['cache.inputstream', 'tempdir']) - - ->register('cache.inputstream') - ->asNewInstanceOf('Swift_KeyCache_SimpleKeyCacheInputStream') -; diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/message_deps.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/message_deps.php deleted file mode 100644 index 64d69d2..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/message_deps.php +++ /dev/null @@ -1,9 +0,0 @@ -register('message.message') - ->asNewInstanceOf('Swift_Message') - - ->register('message.mimepart') - ->asNewInstanceOf('Swift_MimePart') -; diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/mime_deps.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/mime_deps.php deleted file mode 100644 index 307756c..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/mime_deps.php +++ /dev/null @@ -1,134 +0,0 @@ -register('properties.charset') - ->asValue('utf-8') - - ->register('email.validator') - ->asSharedInstanceOf('Egulias\EmailValidator\EmailValidator') - - ->register('mime.idgenerator.idright') - // As SERVER_NAME can come from the user in certain configurations, check that - // it does not contain forbidden characters (see RFC 952 and RFC 2181). Use - // preg_replace() instead of preg_match() to prevent DoS attacks with long host names. - ->asValue(!empty($_SERVER['SERVER_NAME']) && '' === preg_replace('/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/', '', $_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'swift.generated') - - ->register('mime.idgenerator') - ->asSharedInstanceOf('Swift_Mime_IdGenerator') - ->withDependencies([ - 'mime.idgenerator.idright', - ]) - - ->register('mime.message') - ->asNewInstanceOf('Swift_Mime_SimpleMessage') - ->withDependencies([ - 'mime.headerset', - 'mime.textcontentencoder', - 'cache', - 'mime.idgenerator', - 'properties.charset', - ]) - - ->register('mime.part') - ->asNewInstanceOf('Swift_Mime_MimePart') - ->withDependencies([ - 'mime.headerset', - 'mime.textcontentencoder', - 'cache', - 'mime.idgenerator', - 'properties.charset', - ]) - - ->register('mime.attachment') - ->asNewInstanceOf('Swift_Mime_Attachment') - ->withDependencies([ - 'mime.headerset', - 'mime.base64contentencoder', - 'cache', - 'mime.idgenerator', - ]) - ->addConstructorValue($swift_mime_types) - - ->register('mime.embeddedfile') - ->asNewInstanceOf('Swift_Mime_EmbeddedFile') - ->withDependencies([ - 'mime.headerset', - 'mime.base64contentencoder', - 'cache', - 'mime.idgenerator', - ]) - ->addConstructorValue($swift_mime_types) - - ->register('mime.headerfactory') - ->asNewInstanceOf('Swift_Mime_SimpleHeaderFactory') - ->withDependencies([ - 'mime.qpheaderencoder', - 'mime.rfc2231encoder', - 'email.validator', - 'properties.charset', - 'address.idnaddressencoder', - ]) - - ->register('mime.headerset') - ->asNewInstanceOf('Swift_Mime_SimpleHeaderSet') - ->withDependencies(['mime.headerfactory', 'properties.charset']) - - ->register('mime.qpheaderencoder') - ->asNewInstanceOf('Swift_Mime_HeaderEncoder_QpHeaderEncoder') - ->withDependencies(['mime.charstream']) - - ->register('mime.base64headerencoder') - ->asNewInstanceOf('Swift_Mime_HeaderEncoder_Base64HeaderEncoder') - ->withDependencies(['mime.charstream']) - - ->register('mime.charstream') - ->asNewInstanceOf('Swift_CharacterStream_NgCharacterStream') - ->withDependencies(['mime.characterreaderfactory', 'properties.charset']) - - ->register('mime.bytecanonicalizer') - ->asSharedInstanceOf('Swift_StreamFilters_ByteArrayReplacementFilter') - ->addConstructorValue([[0x0D, 0x0A], [0x0D], [0x0A]]) - ->addConstructorValue([[0x0A], [0x0A], [0x0D, 0x0A]]) - - ->register('mime.characterreaderfactory') - ->asSharedInstanceOf('Swift_CharacterReaderFactory_SimpleCharacterReaderFactory') - - ->register('mime.textcontentencoder') - ->asAliasOf('mime.qpcontentencoder') - - ->register('mime.safeqpcontentencoder') - ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder') - ->withDependencies(['mime.charstream', 'mime.bytecanonicalizer']) - - ->register('mime.rawcontentencoder') - ->asNewInstanceOf('Swift_Mime_ContentEncoder_RawContentEncoder') - - ->register('mime.nativeqpcontentencoder') - ->withDependencies(['properties.charset']) - ->asNewInstanceOf('Swift_Mime_ContentEncoder_NativeQpContentEncoder') - - ->register('mime.qpcontentencoder') - ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoderProxy') - ->withDependencies(['mime.safeqpcontentencoder', 'mime.nativeqpcontentencoder', 'properties.charset']) - - ->register('mime.7bitcontentencoder') - ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder') - ->addConstructorValue('7bit') - ->addConstructorValue(true) - - ->register('mime.8bitcontentencoder') - ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder') - ->addConstructorValue('8bit') - ->addConstructorValue(true) - - ->register('mime.base64contentencoder') - ->asSharedInstanceOf('Swift_Mime_ContentEncoder_Base64ContentEncoder') - - ->register('mime.rfc2231encoder') - ->asNewInstanceOf('Swift_Encoder_Rfc2231Encoder') - ->withDependencies(['mime.charstream']) -; - -unset($swift_mime_types); diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/transport_deps.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/transport_deps.php deleted file mode 100644 index 34a63c7..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/transport_deps.php +++ /dev/null @@ -1,97 +0,0 @@ -register('transport.localdomain') - // As SERVER_NAME can come from the user in certain configurations, check that - // it does not contain forbidden characters (see RFC 952 and RFC 2181). Use - // preg_replace() instead of preg_match() to prevent DoS attacks with long host names. - ->asValue(!empty($_SERVER['SERVER_NAME']) && '' === preg_replace('/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/', '', $_SERVER['SERVER_NAME']) ? trim($_SERVER['SERVER_NAME'], '[]') : '127.0.0.1') - - ->register('transport.smtp') - ->asNewInstanceOf('Swift_Transport_EsmtpTransport') - ->withDependencies([ - 'transport.buffer', - 'transport.smtphandlers', - 'transport.eventdispatcher', - 'transport.localdomain', - 'address.idnaddressencoder', - ]) - - ->register('transport.sendmail') - ->asNewInstanceOf('Swift_Transport_SendmailTransport') - ->withDependencies([ - 'transport.buffer', - 'transport.eventdispatcher', - 'transport.localdomain', - ]) - - ->register('transport.loadbalanced') - ->asNewInstanceOf('Swift_Transport_LoadBalancedTransport') - - ->register('transport.failover') - ->asNewInstanceOf('Swift_Transport_FailoverTransport') - - ->register('transport.spool') - ->asNewInstanceOf('Swift_Transport_SpoolTransport') - ->withDependencies(['transport.eventdispatcher']) - - ->register('transport.null') - ->asNewInstanceOf('Swift_Transport_NullTransport') - ->withDependencies(['transport.eventdispatcher']) - - ->register('transport.buffer') - ->asNewInstanceOf('Swift_Transport_StreamBuffer') - ->withDependencies(['transport.replacementfactory']) - - ->register('transport.smtphandlers') - ->asArray() - ->withDependencies(['transport.authhandler']) - - ->register('transport.authhandler') - ->asNewInstanceOf('Swift_Transport_Esmtp_AuthHandler') - ->withDependencies(['transport.authhandlers']) - - ->register('transport.authhandlers') - ->asArray() - ->withDependencies([ - 'transport.crammd5auth', - 'transport.loginauth', - 'transport.plainauth', - 'transport.ntlmauth', - 'transport.xoauth2auth', - ]) - - ->register('transport.smtputf8handler') - ->asNewInstanceOf('Swift_Transport_Esmtp_SmtpUtf8Handler') - - ->register('transport.8bitmimehandler') - ->asNewInstanceOf('Swift_Transport_Esmtp_EightBitMimeHandler') - ->addConstructorValue('8BITMIME') - - ->register('transport.crammd5auth') - ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_CramMd5Authenticator') - - ->register('transport.loginauth') - ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_LoginAuthenticator') - - ->register('transport.plainauth') - ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_PlainAuthenticator') - - ->register('transport.xoauth2auth') - ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_XOAuth2Authenticator') - - ->register('transport.ntlmauth') - ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_NTLMAuthenticator') - - ->register('transport.eventdispatcher') - ->asNewInstanceOf('Swift_Events_SimpleEventDispatcher') - - ->register('transport.replacementfactory') - ->asSharedInstanceOf('Swift_StreamFilters_StringReplacementFilterFactory') - - ->register('address.idnaddressencoder') - ->asNewInstanceOf('Swift_AddressEncoder_IdnAddressEncoder') - - ->register('address.utf8addressencoder') - ->asNewInstanceOf('Swift_AddressEncoder_Utf8AddressEncoder') -; diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/mime_types.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/mime_types.php deleted file mode 100644 index 72c6fd2..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/mime_types.php +++ /dev/null @@ -1,1007 +0,0 @@ - 'text/vnd.in3d.3dml', - '3ds' => 'image/x-3ds', - '3g2' => 'video/3gpp2', - '3gp' => 'video/3gpp', - '7z' => 'application/x-7z-compressed', - 'aab' => 'application/x-authorware-bin', - 'aac' => 'audio/x-aac', - 'aam' => 'application/x-authorware-map', - 'aas' => 'application/x-authorware-seg', - 'abw' => 'application/x-abiword', - 'ac' => 'application/pkix-attr-cert', - 'acc' => 'application/vnd.americandynamics.acc', - 'ace' => 'application/x-ace-compressed', - 'acu' => 'application/vnd.acucobol', - 'acutc' => 'application/vnd.acucorp', - 'adp' => 'audio/adpcm', - 'aep' => 'application/vnd.audiograph', - 'afm' => 'application/x-font-type1', - 'afp' => 'application/vnd.ibm.modcap', - 'ahead' => 'application/vnd.ahead.space', - 'ai' => 'application/postscript', - 'aif' => 'audio/x-aiff', - 'aifc' => 'audio/x-aiff', - 'aiff' => 'audio/x-aiff', - 'air' => 'application/vnd.adobe.air-application-installer-package+zip', - 'ait' => 'application/vnd.dvb.ait', - 'ami' => 'application/vnd.amiga.ami', - 'apk' => 'application/vnd.android.package-archive', - 'appcache' => 'text/cache-manifest', - 'apr' => 'application/vnd.lotus-approach', - 'aps' => 'application/postscript', - 'arc' => 'application/x-freearc', - 'asc' => 'application/pgp-signature', - 'asf' => 'video/x-ms-asf', - 'asm' => 'text/x-asm', - 'aso' => 'application/vnd.accpac.simply.aso', - 'asx' => 'video/x-ms-asf', - 'atc' => 'application/vnd.acucorp', - 'atom' => 'application/atom+xml', - 'atomcat' => 'application/atomcat+xml', - 'atomsvc' => 'application/atomsvc+xml', - 'atx' => 'application/vnd.antix.game-component', - 'au' => 'audio/basic', - 'avi' => 'video/x-msvideo', - 'aw' => 'application/applixware', - 'azf' => 'application/vnd.airzip.filesecure.azf', - 'azs' => 'application/vnd.airzip.filesecure.azs', - 'azw' => 'application/vnd.amazon.ebook', - 'bat' => 'application/x-msdownload', - 'bcpio' => 'application/x-bcpio', - 'bdf' => 'application/x-font-bdf', - 'bdm' => 'application/vnd.syncml.dm+wbxml', - 'bed' => 'application/vnd.realvnc.bed', - 'bh2' => 'application/vnd.fujitsu.oasysprs', - 'bin' => 'application/octet-stream', - 'blb' => 'application/x-blorb', - 'blorb' => 'application/x-blorb', - 'bmi' => 'application/vnd.bmi', - 'bmp' => 'image/bmp', - 'book' => 'application/vnd.framemaker', - 'box' => 'application/vnd.previewsystems.box', - 'boz' => 'application/x-bzip2', - 'bpk' => 'application/octet-stream', - 'btif' => 'image/prs.btif', - 'bz' => 'application/x-bzip', - 'bz2' => 'application/x-bzip2', - 'c' => 'text/x-c', - 'c11amc' => 'application/vnd.cluetrust.cartomobile-config', - 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg', - 'c4d' => 'application/vnd.clonk.c4group', - 'c4f' => 'application/vnd.clonk.c4group', - 'c4g' => 'application/vnd.clonk.c4group', - 'c4p' => 'application/vnd.clonk.c4group', - 'c4u' => 'application/vnd.clonk.c4group', - 'cab' => 'application/vnd.ms-cab-compressed', - 'caf' => 'audio/x-caf', - 'cap' => 'application/vnd.tcpdump.pcap', - 'car' => 'application/vnd.curl.car', - 'cat' => 'application/vnd.ms-pki.seccat', - 'cb7' => 'application/x-cbr', - 'cba' => 'application/x-cbr', - 'cbr' => 'application/x-cbr', - 'cbt' => 'application/x-cbr', - 'cbz' => 'application/x-cbr', - 'cc' => 'text/x-c', - 'cct' => 'application/x-director', - 'ccxml' => 'application/ccxml+xml', - 'cdbcmsg' => 'application/vnd.contact.cmsg', - 'cdf' => 'application/x-netcdf', - 'cdkey' => 'application/vnd.mediastation.cdkey', - 'cdmia' => 'application/cdmi-capability', - 'cdmic' => 'application/cdmi-container', - 'cdmid' => 'application/cdmi-domain', - 'cdmio' => 'application/cdmi-object', - 'cdmiq' => 'application/cdmi-queue', - 'cdx' => 'chemical/x-cdx', - 'cdxml' => 'application/vnd.chemdraw+xml', - 'cdy' => 'application/vnd.cinderella', - 'cer' => 'application/pkix-cert', - 'cfs' => 'application/x-cfs-compressed', - 'cgm' => 'image/cgm', - 'chat' => 'application/x-chat', - 'chm' => 'application/vnd.ms-htmlhelp', - 'chrt' => 'application/vnd.kde.kchart', - 'cif' => 'chemical/x-cif', - 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', - 'cil' => 'application/vnd.ms-artgalry', - 'cla' => 'application/vnd.claymore', - 'class' => 'application/java-vm', - 'clkk' => 'application/vnd.crick.clicker.keyboard', - 'clkp' => 'application/vnd.crick.clicker.palette', - 'clkt' => 'application/vnd.crick.clicker.template', - 'clkw' => 'application/vnd.crick.clicker.wordbank', - 'clkx' => 'application/vnd.crick.clicker', - 'clp' => 'application/x-msclip', - 'cmc' => 'application/vnd.cosmocaller', - 'cmdf' => 'chemical/x-cmdf', - 'cml' => 'chemical/x-cml', - 'cmp' => 'application/vnd.yellowriver-custom-menu', - 'cmx' => 'image/x-cmx', - 'cod' => 'application/vnd.rim.cod', - 'com' => 'application/x-msdownload', - 'conf' => 'text/plain', - 'cpio' => 'application/x-cpio', - 'cpp' => 'text/x-c', - 'cpt' => 'application/mac-compactpro', - 'crd' => 'application/x-mscardfile', - 'crl' => 'application/pkix-crl', - 'crt' => 'application/x-x509-ca-cert', - 'csh' => 'application/x-csh', - 'csml' => 'chemical/x-csml', - 'csp' => 'application/vnd.commonspace', - 'css' => 'text/css', - 'cst' => 'application/x-director', - 'csv' => 'text/csv', - 'cu' => 'application/cu-seeme', - 'curl' => 'text/vnd.curl', - 'cww' => 'application/prs.cww', - 'cxt' => 'application/x-director', - 'cxx' => 'text/x-c', - 'dae' => 'model/vnd.collada+xml', - 'daf' => 'application/vnd.mobius.daf', - 'dart' => 'application/vnd.dart', - 'dataless' => 'application/vnd.fdsn.seed', - 'davmount' => 'application/davmount+xml', - 'dbk' => 'application/docbook+xml', - 'dcr' => 'application/x-director', - 'dcurl' => 'text/vnd.curl.dcurl', - 'dd2' => 'application/vnd.oma.dd2+xml', - 'ddd' => 'application/vnd.fujixerox.ddd', - 'deb' => 'application/x-debian-package', - 'def' => 'text/plain', - 'deploy' => 'application/octet-stream', - 'der' => 'application/x-x509-ca-cert', - 'dfac' => 'application/vnd.dreamfactory', - 'dgc' => 'application/x-dgc-compressed', - 'dic' => 'text/x-c', - 'dir' => 'application/x-director', - 'dis' => 'application/vnd.mobius.dis', - 'dist' => 'application/octet-stream', - 'distz' => 'application/octet-stream', - 'djv' => 'image/vnd.djvu', - 'djvu' => 'image/vnd.djvu', - 'dll' => 'application/x-msdownload', - 'dmg' => 'application/x-apple-diskimage', - 'dmp' => 'application/vnd.tcpdump.pcap', - 'dms' => 'application/octet-stream', - 'dna' => 'application/vnd.dna', - 'doc' => 'application/msword', - 'docm' => 'application/vnd.ms-word.document.macroenabled.12', - 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'dot' => 'application/msword', - 'dotm' => 'application/vnd.ms-word.template.macroenabled.12', - 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', - 'dp' => 'application/vnd.osgi.dp', - 'dpg' => 'application/vnd.dpgraph', - 'dra' => 'audio/vnd.dra', - 'dsc' => 'text/prs.lines.tag', - 'dssc' => 'application/dssc+der', - 'dtb' => 'application/x-dtbook+xml', - 'dtd' => 'application/xml-dtd', - 'dts' => 'audio/vnd.dts', - 'dtshd' => 'audio/vnd.dts.hd', - 'dump' => 'application/octet-stream', - 'dvb' => 'video/vnd.dvb.file', - 'dvi' => 'application/x-dvi', - 'dwf' => 'model/vnd.dwf', - 'dwg' => 'image/vnd.dwg', - 'dxf' => 'image/vnd.dxf', - 'dxp' => 'application/vnd.spotfire.dxp', - 'dxr' => 'application/x-director', - 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', - 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', - 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', - 'ecma' => 'application/ecmascript', - 'edm' => 'application/vnd.novadigm.edm', - 'edx' => 'application/vnd.novadigm.edx', - 'efif' => 'application/vnd.picsel', - 'ei6' => 'application/vnd.pg.osasli', - 'elc' => 'application/octet-stream', - 'emf' => 'application/x-msmetafile', - 'eml' => 'message/rfc822', - 'emma' => 'application/emma+xml', - 'emz' => 'application/x-msmetafile', - 'eol' => 'audio/vnd.digital-winds', - 'eot' => 'application/vnd.ms-fontobject', - 'eps' => 'application/postscript', - 'epub' => 'application/epub+zip', - 'es3' => 'application/vnd.eszigno3+xml', - 'esa' => 'application/vnd.osgi.subsystem', - 'esf' => 'application/vnd.epson.esf', - 'et3' => 'application/vnd.eszigno3+xml', - 'etx' => 'text/x-setext', - 'eva' => 'application/x-eva', - 'evy' => 'application/x-envoy', - 'exe' => 'application/x-msdownload', - 'exi' => 'application/exi', - 'ext' => 'application/vnd.novadigm.ext', - 'ez' => 'application/andrew-inset', - 'ez2' => 'application/vnd.ezpix-album', - 'ez3' => 'application/vnd.ezpix-package', - 'f' => 'text/x-fortran', - 'f4v' => 'video/x-f4v', - 'f77' => 'text/x-fortran', - 'f90' => 'text/x-fortran', - 'fbs' => 'image/vnd.fastbidsheet', - 'fcdt' => 'application/vnd.adobe.formscentral.fcdt', - 'fcs' => 'application/vnd.isac.fcs', - 'fdf' => 'application/vnd.fdf', - 'fe_launch' => 'application/vnd.denovo.fcselayout-link', - 'fg5' => 'application/vnd.fujitsu.oasysgp', - 'fgd' => 'application/x-director', - 'fh' => 'image/x-freehand', - 'fh4' => 'image/x-freehand', - 'fh5' => 'image/x-freehand', - 'fh7' => 'image/x-freehand', - 'fhc' => 'image/x-freehand', - 'fig' => 'application/x-xfig', - 'flac' => 'audio/x-flac', - 'fli' => 'video/x-fli', - 'flo' => 'application/vnd.micrografx.flo', - 'flv' => 'video/x-flv', - 'flw' => 'application/vnd.kde.kivio', - 'flx' => 'text/vnd.fmi.flexstor', - 'fly' => 'text/vnd.fly', - 'fm' => 'application/vnd.framemaker', - 'fnc' => 'application/vnd.frogans.fnc', - 'for' => 'text/x-fortran', - 'fpx' => 'image/vnd.fpx', - 'frame' => 'application/vnd.framemaker', - 'fsc' => 'application/vnd.fsc.weblaunch', - 'fst' => 'image/vnd.fst', - 'ftc' => 'application/vnd.fluxtime.clip', - 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', - 'fvt' => 'video/vnd.fvt', - 'fxp' => 'application/vnd.adobe.fxp', - 'fxpl' => 'application/vnd.adobe.fxp', - 'fzs' => 'application/vnd.fuzzysheet', - 'g2w' => 'application/vnd.geoplan', - 'g3' => 'image/g3fax', - 'g3w' => 'application/vnd.geospace', - 'gac' => 'application/vnd.groove-account', - 'gam' => 'application/x-tads', - 'gbr' => 'application/rpki-ghostbusters', - 'gca' => 'application/x-gca-compressed', - 'gdl' => 'model/vnd.gdl', - 'geo' => 'application/vnd.dynageo', - 'gex' => 'application/vnd.geometry-explorer', - 'ggb' => 'application/vnd.geogebra.file', - 'ggt' => 'application/vnd.geogebra.tool', - 'ghf' => 'application/vnd.groove-help', - 'gif' => 'image/gif', - 'gim' => 'application/vnd.groove-identity-message', - 'gml' => 'application/gml+xml', - 'gmx' => 'application/vnd.gmx', - 'gnumeric' => 'application/x-gnumeric', - 'gph' => 'application/vnd.flographit', - 'gpx' => 'application/gpx+xml', - 'gqf' => 'application/vnd.grafeq', - 'gqs' => 'application/vnd.grafeq', - 'gram' => 'application/srgs', - 'gramps' => 'application/x-gramps-xml', - 'gre' => 'application/vnd.geometry-explorer', - 'grv' => 'application/vnd.groove-injector', - 'grxml' => 'application/srgs+xml', - 'gsf' => 'application/x-font-ghostscript', - 'gtar' => 'application/x-gtar', - 'gtm' => 'application/vnd.groove-tool-message', - 'gtw' => 'model/vnd.gtw', - 'gv' => 'text/vnd.graphviz', - 'gxf' => 'application/gxf', - 'gxt' => 'application/vnd.geonext', - 'gz' => 'application/x-gzip', - 'h' => 'text/x-c', - 'h261' => 'video/h261', - 'h263' => 'video/h263', - 'h264' => 'video/h264', - 'hal' => 'application/vnd.hal+xml', - 'hbci' => 'application/vnd.hbci', - 'hdf' => 'application/x-hdf', - 'hh' => 'text/x-c', - 'hlp' => 'application/winhlp', - 'hpgl' => 'application/vnd.hp-hpgl', - 'hpid' => 'application/vnd.hp-hpid', - 'hps' => 'application/vnd.hp-hps', - 'hqx' => 'application/mac-binhex40', - 'htke' => 'application/vnd.kenameaapp', - 'htm' => 'text/html', - 'html' => 'text/html', - 'hvd' => 'application/vnd.yamaha.hv-dic', - 'hvp' => 'application/vnd.yamaha.hv-voice', - 'hvs' => 'application/vnd.yamaha.hv-script', - 'i2g' => 'application/vnd.intergeo', - 'icc' => 'application/vnd.iccprofile', - 'ice' => 'x-conference/x-cooltalk', - 'icm' => 'application/vnd.iccprofile', - 'ico' => 'image/x-icon', - 'ics' => 'text/calendar', - 'ief' => 'image/ief', - 'ifb' => 'text/calendar', - 'ifm' => 'application/vnd.shana.informed.formdata', - 'iges' => 'model/iges', - 'igl' => 'application/vnd.igloader', - 'igm' => 'application/vnd.insors.igm', - 'igs' => 'model/iges', - 'igx' => 'application/vnd.micrografx.igx', - 'iif' => 'application/vnd.shana.informed.interchange', - 'imp' => 'application/vnd.accpac.simply.imp', - 'ims' => 'application/vnd.ms-ims', - 'in' => 'text/plain', - 'ink' => 'application/inkml+xml', - 'inkml' => 'application/inkml+xml', - 'install' => 'application/x-install-instructions', - 'iota' => 'application/vnd.astraea-software.iota', - 'ipfix' => 'application/ipfix', - 'ipk' => 'application/vnd.shana.informed.package', - 'irm' => 'application/vnd.ibm.rights-management', - 'irp' => 'application/vnd.irepository.package+xml', - 'iso' => 'application/x-iso9660-image', - 'itp' => 'application/vnd.shana.informed.formtemplate', - 'ivp' => 'application/vnd.immervision-ivp', - 'ivu' => 'application/vnd.immervision-ivu', - 'jad' => 'text/vnd.sun.j2me.app-descriptor', - 'jam' => 'application/vnd.jam', - 'jar' => 'application/java-archive', - 'java' => 'text/x-java-source', - 'jisp' => 'application/vnd.jisp', - 'jlt' => 'application/vnd.hp-jlyt', - 'jnlp' => 'application/x-java-jnlp-file', - 'joda' => 'application/vnd.joost.joda-archive', - 'jpe' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'jpgm' => 'video/jpm', - 'jpgv' => 'video/jpeg', - 'jpm' => 'video/jpm', - 'js' => 'application/javascript', - 'json' => 'application/json', - 'jsonml' => 'application/jsonml+json', - 'kar' => 'audio/midi', - 'karbon' => 'application/vnd.kde.karbon', - 'kfo' => 'application/vnd.kde.kformula', - 'kia' => 'application/vnd.kidspiration', - 'kml' => 'application/vnd.google-earth.kml+xml', - 'kmz' => 'application/vnd.google-earth.kmz', - 'kne' => 'application/vnd.kinar', - 'knp' => 'application/vnd.kinar', - 'kon' => 'application/vnd.kde.kontour', - 'kpr' => 'application/vnd.kde.kpresenter', - 'kpt' => 'application/vnd.kde.kpresenter', - 'kpxx' => 'application/vnd.ds-keypoint', - 'ksp' => 'application/vnd.kde.kspread', - 'ktr' => 'application/vnd.kahootz', - 'ktx' => 'image/ktx', - 'ktz' => 'application/vnd.kahootz', - 'kwd' => 'application/vnd.kde.kword', - 'kwt' => 'application/vnd.kde.kword', - 'lasxml' => 'application/vnd.las.las+xml', - 'latex' => 'application/x-latex', - 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', - 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', - 'les' => 'application/vnd.hhe.lesson-player', - 'lha' => 'application/x-lzh-compressed', - 'link66' => 'application/vnd.route66.link66+xml', - 'list' => 'text/plain', - 'list3820' => 'application/vnd.ibm.modcap', - 'listafp' => 'application/vnd.ibm.modcap', - 'lnk' => 'application/x-ms-shortcut', - 'log' => 'text/plain', - 'lostxml' => 'application/lost+xml', - 'lrf' => 'application/octet-stream', - 'lrm' => 'application/vnd.ms-lrm', - 'ltf' => 'application/vnd.frogans.ltf', - 'lvp' => 'audio/vnd.lucent.voice', - 'lwp' => 'application/vnd.lotus-wordpro', - 'lzh' => 'application/x-lzh-compressed', - 'm13' => 'application/x-msmediaview', - 'm14' => 'application/x-msmediaview', - 'm1v' => 'video/mpeg', - 'm21' => 'application/mp21', - 'm2a' => 'audio/mpeg', - 'm2v' => 'video/mpeg', - 'm3a' => 'audio/mpeg', - 'm3u' => 'audio/x-mpegurl', - 'm3u8' => 'application/vnd.apple.mpegurl', - 'm4a' => 'audio/mp4', - 'm4u' => 'video/vnd.mpegurl', - 'm4v' => 'video/x-m4v', - 'ma' => 'application/mathematica', - 'mads' => 'application/mads+xml', - 'mag' => 'application/vnd.ecowin.chart', - 'maker' => 'application/vnd.framemaker', - 'man' => 'text/troff', - 'mar' => 'application/octet-stream', - 'mathml' => 'application/mathml+xml', - 'mb' => 'application/mathematica', - 'mbk' => 'application/vnd.mobius.mbk', - 'mbox' => 'application/mbox', - 'mc1' => 'application/vnd.medcalcdata', - 'mcd' => 'application/vnd.mcd', - 'mcurl' => 'text/vnd.curl.mcurl', - 'mdb' => 'application/x-msaccess', - 'mdi' => 'image/vnd.ms-modi', - 'me' => 'text/troff', - 'mesh' => 'model/mesh', - 'meta4' => 'application/metalink4+xml', - 'metalink' => 'application/metalink+xml', - 'mets' => 'application/mets+xml', - 'mfm' => 'application/vnd.mfmp', - 'mft' => 'application/rpki-manifest', - 'mgp' => 'application/vnd.osgeo.mapguide.package', - 'mgz' => 'application/vnd.proteus.magazine', - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', - 'mie' => 'application/x-mie', - 'mif' => 'application/vnd.mif', - 'mime' => 'message/rfc822', - 'mj2' => 'video/mj2', - 'mjp2' => 'video/mj2', - 'mk3d' => 'video/x-matroska', - 'mka' => 'audio/x-matroska', - 'mks' => 'video/x-matroska', - 'mkv' => 'video/x-matroska', - 'mlp' => 'application/vnd.dolby.mlp', - 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', - 'mmf' => 'application/vnd.smaf', - 'mmr' => 'image/vnd.fujixerox.edmics-mmr', - 'mng' => 'video/x-mng', - 'mny' => 'application/x-msmoney', - 'mobi' => 'application/x-mobipocket-ebook', - 'mods' => 'application/mods+xml', - 'mov' => 'video/quicktime', - 'movie' => 'video/x-sgi-movie', - 'mp2' => 'audio/mpeg', - 'mp21' => 'application/mp21', - 'mp2a' => 'audio/mpeg', - 'mp3' => 'audio/mpeg', - 'mp4' => 'video/mp4', - 'mp4a' => 'audio/mp4', - 'mp4s' => 'application/mp4', - 'mp4v' => 'video/mp4', - 'mpc' => 'application/vnd.mophun.certificate', - 'mpe' => 'video/mpeg', - 'mpeg' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'mpg4' => 'video/mp4', - 'mpga' => 'audio/mpeg', - 'mpkg' => 'application/vnd.apple.installer+xml', - 'mpm' => 'application/vnd.blueice.multipass', - 'mpn' => 'application/vnd.mophun.application', - 'mpp' => 'application/vnd.ms-project', - 'mpt' => 'application/vnd.ms-project', - 'mpy' => 'application/vnd.ibm.minipay', - 'mqy' => 'application/vnd.mobius.mqy', - 'mrc' => 'application/marc', - 'mrcx' => 'application/marcxml+xml', - 'ms' => 'text/troff', - 'mscml' => 'application/mediaservercontrol+xml', - 'mseed' => 'application/vnd.fdsn.mseed', - 'mseq' => 'application/vnd.mseq', - 'msf' => 'application/vnd.epson.msf', - 'msh' => 'model/mesh', - 'msi' => 'application/x-msdownload', - 'msl' => 'application/vnd.mobius.msl', - 'msty' => 'application/vnd.muvee.style', - 'mts' => 'model/vnd.mts', - 'mus' => 'application/vnd.musician', - 'musicxml' => 'application/vnd.recordare.musicxml+xml', - 'mvb' => 'application/x-msmediaview', - 'mwf' => 'application/vnd.mfer', - 'mxf' => 'application/mxf', - 'mxl' => 'application/vnd.recordare.musicxml', - 'mxml' => 'application/xv+xml', - 'mxs' => 'application/vnd.triscape.mxs', - 'mxu' => 'video/vnd.mpegurl', - 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', - 'n3' => 'text/n3', - 'nb' => 'application/mathematica', - 'nbp' => 'application/vnd.wolfram.player', - 'nc' => 'application/x-netcdf', - 'ncx' => 'application/x-dtbncx+xml', - 'nfo' => 'text/x-nfo', - 'ngdat' => 'application/vnd.nokia.n-gage.data', - 'nitf' => 'application/vnd.nitf', - 'nlu' => 'application/vnd.neurolanguage.nlu', - 'nml' => 'application/vnd.enliven', - 'nnd' => 'application/vnd.noblenet-directory', - 'nns' => 'application/vnd.noblenet-sealer', - 'nnw' => 'application/vnd.noblenet-web', - 'npx' => 'image/vnd.net-fpx', - 'nsc' => 'application/x-conference', - 'nsf' => 'application/vnd.lotus-notes', - 'ntf' => 'application/vnd.nitf', - 'nzb' => 'application/x-nzb', - 'oa2' => 'application/vnd.fujitsu.oasys2', - 'oa3' => 'application/vnd.fujitsu.oasys3', - 'oas' => 'application/vnd.fujitsu.oasys', - 'obd' => 'application/x-msbinder', - 'obj' => 'application/x-tgif', - 'oda' => 'application/oda', - 'odb' => 'application/vnd.oasis.opendocument.database', - 'odc' => 'application/vnd.oasis.opendocument.chart', - 'odf' => 'application/vnd.oasis.opendocument.formula', - 'odft' => 'application/vnd.oasis.opendocument.formula-template', - 'odg' => 'application/vnd.oasis.opendocument.graphics', - 'odi' => 'application/vnd.oasis.opendocument.image', - 'odm' => 'application/vnd.oasis.opendocument.text-master', - 'odp' => 'application/vnd.oasis.opendocument.presentation', - 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', - 'odt' => 'application/vnd.oasis.opendocument.text', - 'oga' => 'audio/ogg', - 'ogg' => 'audio/ogg', - 'ogv' => 'video/ogg', - 'ogx' => 'application/ogg', - 'omdoc' => 'application/omdoc+xml', - 'onepkg' => 'application/onenote', - 'onetmp' => 'application/onenote', - 'onetoc' => 'application/onenote', - 'onetoc2' => 'application/onenote', - 'opf' => 'application/oebps-package+xml', - 'opml' => 'text/x-opml', - 'oprc' => 'application/vnd.palm', - 'org' => 'application/vnd.lotus-organizer', - 'osf' => 'application/vnd.yamaha.openscoreformat', - 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml', - 'otc' => 'application/vnd.oasis.opendocument.chart-template', - 'otf' => 'application/x-font-otf', - 'otg' => 'application/vnd.oasis.opendocument.graphics-template', - 'oth' => 'application/vnd.oasis.opendocument.text-web', - 'oti' => 'application/vnd.oasis.opendocument.image-template', - 'otp' => 'application/vnd.oasis.opendocument.presentation-template', - 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', - 'ott' => 'application/vnd.oasis.opendocument.text-template', - 'oxps' => 'application/oxps', - 'oxt' => 'application/vnd.openofficeorg.extension', - 'p' => 'text/x-pascal', - 'p10' => 'application/pkcs10', - 'p12' => 'application/x-pkcs12', - 'p7b' => 'application/x-pkcs7-certificates', - 'p7c' => 'application/pkcs7-mime', - 'p7m' => 'application/pkcs7-mime', - 'p7r' => 'application/x-pkcs7-certreqresp', - 'p7s' => 'application/pkcs7-signature', - 'p8' => 'application/pkcs8', - 'pas' => 'text/x-pascal', - 'paw' => 'application/vnd.pawaafile', - 'pbd' => 'application/vnd.powerbuilder6', - 'pbm' => 'image/x-portable-bitmap', - 'pcap' => 'application/vnd.tcpdump.pcap', - 'pcf' => 'application/x-font-pcf', - 'pcl' => 'application/vnd.hp-pcl', - 'pclxl' => 'application/vnd.hp-pclxl', - 'pct' => 'image/x-pict', - 'pcurl' => 'application/vnd.curl.pcurl', - 'pcx' => 'image/x-pcx', - 'pdb' => 'application/vnd.palm', - 'pdf' => 'application/pdf', - 'pfa' => 'application/x-font-type1', - 'pfb' => 'application/x-font-type1', - 'pfm' => 'application/x-font-type1', - 'pfr' => 'application/font-tdpfr', - 'pfx' => 'application/x-pkcs12', - 'pgm' => 'image/x-portable-graymap', - 'pgn' => 'application/x-chess-pgn', - 'pgp' => 'application/pgp-encrypted', - 'php' => 'application/x-php', - 'php3' => 'application/x-php', - 'php4' => 'application/x-php', - 'php5' => 'application/x-php', - 'pic' => 'image/x-pict', - 'pkg' => 'application/octet-stream', - 'pki' => 'application/pkixcmp', - 'pkipath' => 'application/pkix-pkipath', - 'plb' => 'application/vnd.3gpp.pic-bw-large', - 'plc' => 'application/vnd.mobius.plc', - 'plf' => 'application/vnd.pocketlearn', - 'pls' => 'application/pls+xml', - 'pml' => 'application/vnd.ctc-posml', - 'png' => 'image/png', - 'pnm' => 'image/x-portable-anymap', - 'portpkg' => 'application/vnd.macports.portpkg', - 'pot' => 'application/vnd.ms-powerpoint', - 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12', - 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', - 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12', - 'ppd' => 'application/vnd.cups-ppd', - 'ppm' => 'image/x-portable-pixmap', - 'pps' => 'application/vnd.ms-powerpoint', - 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12', - 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', - 'ppt' => 'application/vnd.ms-powerpoint', - 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12', - 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'pqa' => 'application/vnd.palm', - 'prc' => 'application/x-mobipocket-ebook', - 'pre' => 'application/vnd.lotus-freelance', - 'prf' => 'application/pics-rules', - 'ps' => 'application/postscript', - 'psb' => 'application/vnd.3gpp.pic-bw-small', - 'psd' => 'image/vnd.adobe.photoshop', - 'psf' => 'application/x-font-linux-psf', - 'pskcxml' => 'application/pskc+xml', - 'ptid' => 'application/vnd.pvi.ptid1', - 'pub' => 'application/x-mspublisher', - 'pvb' => 'application/vnd.3gpp.pic-bw-var', - 'pwn' => 'application/vnd.3m.post-it-notes', - 'pya' => 'audio/vnd.ms-playready.media.pya', - 'pyv' => 'video/vnd.ms-playready.media.pyv', - 'qam' => 'application/vnd.epson.quickanime', - 'qbo' => 'application/vnd.intu.qbo', - 'qfx' => 'application/vnd.intu.qfx', - 'qps' => 'application/vnd.publishare-delta-tree', - 'qt' => 'video/quicktime', - 'qwd' => 'application/vnd.quark.quarkxpress', - 'qwt' => 'application/vnd.quark.quarkxpress', - 'qxb' => 'application/vnd.quark.quarkxpress', - 'qxd' => 'application/vnd.quark.quarkxpress', - 'qxl' => 'application/vnd.quark.quarkxpress', - 'qxt' => 'application/vnd.quark.quarkxpress', - 'ra' => 'audio/x-pn-realaudio', - 'ram' => 'audio/x-pn-realaudio', - 'rar' => 'application/x-rar-compressed', - 'ras' => 'image/x-cmu-raster', - 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', - 'rdf' => 'application/rdf+xml', - 'rdz' => 'application/vnd.data-vision.rdz', - 'rep' => 'application/vnd.businessobjects', - 'res' => 'application/x-dtbresource+xml', - 'rgb' => 'image/x-rgb', - 'rif' => 'application/reginfo+xml', - 'rip' => 'audio/vnd.rip', - 'ris' => 'application/x-research-info-systems', - 'rl' => 'application/resource-lists+xml', - 'rlc' => 'image/vnd.fujixerox.edmics-rlc', - 'rld' => 'application/resource-lists-diff+xml', - 'rm' => 'application/vnd.rn-realmedia', - 'rmi' => 'audio/midi', - 'rmp' => 'audio/x-pn-realaudio-plugin', - 'rms' => 'application/vnd.jcp.javame.midlet-rms', - 'rmvb' => 'application/vnd.rn-realmedia-vbr', - 'rnc' => 'application/relax-ng-compact-syntax', - 'roa' => 'application/rpki-roa', - 'roff' => 'text/troff', - 'rp9' => 'application/vnd.cloanto.rp9', - 'rpss' => 'application/vnd.nokia.radio-presets', - 'rpst' => 'application/vnd.nokia.radio-preset', - 'rq' => 'application/sparql-query', - 'rs' => 'application/rls-services+xml', - 'rsd' => 'application/rsd+xml', - 'rss' => 'application/rss+xml', - 'rtf' => 'application/rtf', - 'rtx' => 'text/richtext', - 's' => 'text/x-asm', - 's3m' => 'audio/s3m', - 'saf' => 'application/vnd.yamaha.smaf-audio', - 'sbml' => 'application/sbml+xml', - 'sc' => 'application/vnd.ibm.secure-container', - 'scd' => 'application/x-msschedule', - 'scm' => 'application/vnd.lotus-screencam', - 'scq' => 'application/scvp-cv-request', - 'scs' => 'application/scvp-cv-response', - 'scurl' => 'text/vnd.curl.scurl', - 'sda' => 'application/vnd.stardivision.draw', - 'sdc' => 'application/vnd.stardivision.calc', - 'sdd' => 'application/vnd.stardivision.impress', - 'sdkd' => 'application/vnd.solent.sdkm+xml', - 'sdkm' => 'application/vnd.solent.sdkm+xml', - 'sdp' => 'application/sdp', - 'sdw' => 'application/vnd.stardivision.writer', - 'see' => 'application/vnd.seemail', - 'seed' => 'application/vnd.fdsn.seed', - 'sema' => 'application/vnd.sema', - 'semd' => 'application/vnd.semd', - 'semf' => 'application/vnd.semf', - 'ser' => 'application/java-serialized-object', - 'setpay' => 'application/set-payment-initiation', - 'setreg' => 'application/set-registration-initiation', - 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data', - 'sfs' => 'application/vnd.spotfire.sfs', - 'sfv' => 'text/x-sfv', - 'sgi' => 'image/sgi', - 'sgl' => 'application/vnd.stardivision.writer-global', - 'sgm' => 'text/sgml', - 'sgml' => 'text/sgml', - 'sh' => 'application/x-sh', - 'shar' => 'application/x-shar', - 'shf' => 'application/shf+xml', - 'sid' => 'image/x-mrsid-image', - 'sig' => 'application/pgp-signature', - 'sil' => 'audio/silk', - 'silo' => 'model/mesh', - 'sis' => 'application/vnd.symbian.install', - 'sisx' => 'application/vnd.symbian.install', - 'sit' => 'application/x-stuffit', - 'sitx' => 'application/x-stuffitx', - 'skd' => 'application/vnd.koan', - 'skm' => 'application/vnd.koan', - 'skp' => 'application/vnd.koan', - 'skt' => 'application/vnd.koan', - 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12', - 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', - 'slt' => 'application/vnd.epson.salt', - 'sm' => 'application/vnd.stepmania.stepchart', - 'smf' => 'application/vnd.stardivision.math', - 'smi' => 'application/smil+xml', - 'smil' => 'application/smil+xml', - 'smv' => 'video/x-smv', - 'smzip' => 'application/vnd.stepmania.package', - 'snd' => 'audio/basic', - 'snf' => 'application/x-font-snf', - 'so' => 'application/octet-stream', - 'spc' => 'application/x-pkcs7-certificates', - 'spf' => 'application/vnd.yamaha.smaf-phrase', - 'spl' => 'application/x-futuresplash', - 'spot' => 'text/vnd.in3d.spot', - 'spp' => 'application/scvp-vp-response', - 'spq' => 'application/scvp-vp-request', - 'spx' => 'audio/ogg', - 'sql' => 'application/x-sql', - 'src' => 'application/x-wais-source', - 'srt' => 'application/x-subrip', - 'sru' => 'application/sru+xml', - 'srx' => 'application/sparql-results+xml', - 'ssdl' => 'application/ssdl+xml', - 'sse' => 'application/vnd.kodak-descriptor', - 'ssf' => 'application/vnd.epson.ssf', - 'ssml' => 'application/ssml+xml', - 'st' => 'application/vnd.sailingtracker.track', - 'stc' => 'application/vnd.sun.xml.calc.template', - 'std' => 'application/vnd.sun.xml.draw.template', - 'stf' => 'application/vnd.wt.stf', - 'sti' => 'application/vnd.sun.xml.impress.template', - 'stk' => 'application/hyperstudio', - 'stl' => 'application/vnd.ms-pki.stl', - 'str' => 'application/vnd.pg.format', - 'stw' => 'application/vnd.sun.xml.writer.template', - 'sub' => 'text/vnd.dvb.subtitle', - 'sus' => 'application/vnd.sus-calendar', - 'susp' => 'application/vnd.sus-calendar', - 'sv4cpio' => 'application/x-sv4cpio', - 'sv4crc' => 'application/x-sv4crc', - 'svc' => 'application/vnd.dvb.service', - 'svd' => 'application/vnd.svd', - 'svg' => 'image/svg+xml', - 'svgz' => 'image/svg+xml', - 'swa' => 'application/x-director', - 'swf' => 'application/x-shockwave-flash', - 'swi' => 'application/vnd.aristanetworks.swi', - 'sxc' => 'application/vnd.sun.xml.calc', - 'sxd' => 'application/vnd.sun.xml.draw', - 'sxg' => 'application/vnd.sun.xml.writer.global', - 'sxi' => 'application/vnd.sun.xml.impress', - 'sxm' => 'application/vnd.sun.xml.math', - 'sxw' => 'application/vnd.sun.xml.writer', - 't' => 'text/troff', - 't3' => 'application/x-t3vm-image', - 'taglet' => 'application/vnd.mynfc', - 'tao' => 'application/vnd.tao.intent-module-archive', - 'tar' => 'application/x-tar', - 'tcap' => 'application/vnd.3gpp2.tcap', - 'tcl' => 'application/x-tcl', - 'teacher' => 'application/vnd.smart.teacher', - 'tei' => 'application/tei+xml', - 'teicorpus' => 'application/tei+xml', - 'tex' => 'application/x-tex', - 'texi' => 'application/x-texinfo', - 'texinfo' => 'application/x-texinfo', - 'text' => 'text/plain', - 'tfi' => 'application/thraud+xml', - 'tfm' => 'application/x-tex-tfm', - 'tga' => 'image/x-tga', - 'thmx' => 'application/vnd.ms-officetheme', - 'tif' => 'image/tiff', - 'tiff' => 'image/tiff', - 'tmo' => 'application/vnd.tmobile-livetv', - 'torrent' => 'application/x-bittorrent', - 'tpl' => 'application/vnd.groove-tool-template', - 'tpt' => 'application/vnd.trid.tpt', - 'tr' => 'text/troff', - 'tra' => 'application/vnd.trueapp', - 'trm' => 'application/x-msterminal', - 'tsd' => 'application/timestamped-data', - 'tsv' => 'text/tab-separated-values', - 'ttc' => 'application/x-font-ttf', - 'ttf' => 'application/x-font-ttf', - 'ttl' => 'text/turtle', - 'twd' => 'application/vnd.simtech-mindmapper', - 'twds' => 'application/vnd.simtech-mindmapper', - 'txd' => 'application/vnd.genomatix.tuxedo', - 'txf' => 'application/vnd.mobius.txf', - 'txt' => 'text/plain', - 'u32' => 'application/x-authorware-bin', - 'udeb' => 'application/x-debian-package', - 'ufd' => 'application/vnd.ufdl', - 'ufdl' => 'application/vnd.ufdl', - 'ulx' => 'application/x-glulx', - 'umj' => 'application/vnd.umajin', - 'unityweb' => 'application/vnd.unity', - 'uoml' => 'application/vnd.uoml+xml', - 'uri' => 'text/uri-list', - 'uris' => 'text/uri-list', - 'urls' => 'text/uri-list', - 'ustar' => 'application/x-ustar', - 'utz' => 'application/vnd.uiq.theme', - 'uu' => 'text/x-uuencode', - 'uva' => 'audio/vnd.dece.audio', - 'uvd' => 'application/vnd.dece.data', - 'uvf' => 'application/vnd.dece.data', - 'uvg' => 'image/vnd.dece.graphic', - 'uvh' => 'video/vnd.dece.hd', - 'uvi' => 'image/vnd.dece.graphic', - 'uvm' => 'video/vnd.dece.mobile', - 'uvp' => 'video/vnd.dece.pd', - 'uvs' => 'video/vnd.dece.sd', - 'uvt' => 'application/vnd.dece.ttml+xml', - 'uvu' => 'video/vnd.uvvu.mp4', - 'uvv' => 'video/vnd.dece.video', - 'uvva' => 'audio/vnd.dece.audio', - 'uvvd' => 'application/vnd.dece.data', - 'uvvf' => 'application/vnd.dece.data', - 'uvvg' => 'image/vnd.dece.graphic', - 'uvvh' => 'video/vnd.dece.hd', - 'uvvi' => 'image/vnd.dece.graphic', - 'uvvm' => 'video/vnd.dece.mobile', - 'uvvp' => 'video/vnd.dece.pd', - 'uvvs' => 'video/vnd.dece.sd', - 'uvvt' => 'application/vnd.dece.ttml+xml', - 'uvvu' => 'video/vnd.uvvu.mp4', - 'uvvv' => 'video/vnd.dece.video', - 'uvvx' => 'application/vnd.dece.unspecified', - 'uvvz' => 'application/vnd.dece.zip', - 'uvx' => 'application/vnd.dece.unspecified', - 'uvz' => 'application/vnd.dece.zip', - 'vcard' => 'text/vcard', - 'vcd' => 'application/x-cdlink', - 'vcf' => 'text/x-vcard', - 'vcg' => 'application/vnd.groove-vcard', - 'vcs' => 'text/x-vcalendar', - 'vcx' => 'application/vnd.vcx', - 'vis' => 'application/vnd.visionary', - 'viv' => 'video/vnd.vivo', - 'vob' => 'video/x-ms-vob', - 'vor' => 'application/vnd.stardivision.writer', - 'vox' => 'application/x-authorware-bin', - 'vrml' => 'model/vrml', - 'vsd' => 'application/vnd.visio', - 'vsf' => 'application/vnd.vsf', - 'vss' => 'application/vnd.visio', - 'vst' => 'application/vnd.visio', - 'vsw' => 'application/vnd.visio', - 'vtu' => 'model/vnd.vtu', - 'vxml' => 'application/voicexml+xml', - 'w3d' => 'application/x-director', - 'wad' => 'application/x-doom', - 'wav' => 'audio/x-wav', - 'wax' => 'audio/x-ms-wax', - 'wbmp' => 'image/vnd.wap.wbmp', - 'wbs' => 'application/vnd.criticaltools.wbs+xml', - 'wbxml' => 'application/vnd.wap.wbxml', - 'wcm' => 'application/vnd.ms-works', - 'wdb' => 'application/vnd.ms-works', - 'wdp' => 'image/vnd.ms-photo', - 'weba' => 'audio/webm', - 'webm' => 'video/webm', - 'webp' => 'image/webp', - 'wg' => 'application/vnd.pmi.widget', - 'wgt' => 'application/widget', - 'wks' => 'application/vnd.ms-works', - 'wm' => 'video/x-ms-wm', - 'wma' => 'audio/x-ms-wma', - 'wmd' => 'application/x-ms-wmd', - 'wmf' => 'application/x-msmetafile', - 'wml' => 'text/vnd.wap.wml', - 'wmlc' => 'application/vnd.wap.wmlc', - 'wmls' => 'text/vnd.wap.wmlscript', - 'wmlsc' => 'application/vnd.wap.wmlscriptc', - 'wmv' => 'video/x-ms-wmv', - 'wmx' => 'video/x-ms-wmx', - 'wmz' => 'application/x-msmetafile', - 'woff' => 'application/font-woff', - 'wpd' => 'application/vnd.wordperfect', - 'wpl' => 'application/vnd.ms-wpl', - 'wps' => 'application/vnd.ms-works', - 'wqd' => 'application/vnd.wqd', - 'wri' => 'application/x-mswrite', - 'wrl' => 'model/vrml', - 'wsdl' => 'application/wsdl+xml', - 'wspolicy' => 'application/wspolicy+xml', - 'wtb' => 'application/vnd.webturbo', - 'wvx' => 'video/x-ms-wvx', - 'x32' => 'application/x-authorware-bin', - 'x3d' => 'model/x3d+xml', - 'x3db' => 'model/x3d+binary', - 'x3dbz' => 'model/x3d+binary', - 'x3dv' => 'model/x3d+vrml', - 'x3dvz' => 'model/x3d+vrml', - 'x3dz' => 'model/x3d+xml', - 'xaml' => 'application/xaml+xml', - 'xap' => 'application/x-silverlight-app', - 'xar' => 'application/vnd.xara', - 'xbap' => 'application/x-ms-xbap', - 'xbd' => 'application/vnd.fujixerox.docuworks.binder', - 'xbm' => 'image/x-xbitmap', - 'xdf' => 'application/xcap-diff+xml', - 'xdm' => 'application/vnd.syncml.dm+xml', - 'xdp' => 'application/vnd.adobe.xdp+xml', - 'xdssc' => 'application/dssc+xml', - 'xdw' => 'application/vnd.fujixerox.docuworks', - 'xenc' => 'application/xenc+xml', - 'xer' => 'application/patch-ops-error+xml', - 'xfdf' => 'application/vnd.adobe.xfdf', - 'xfdl' => 'application/vnd.xfdl', - 'xht' => 'application/xhtml+xml', - 'xhtml' => 'application/xhtml+xml', - 'xhvml' => 'application/xv+xml', - 'xif' => 'image/vnd.xiff', - 'xla' => 'application/vnd.ms-excel', - 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12', - 'xlc' => 'application/vnd.ms-excel', - 'xlf' => 'application/x-xliff+xml', - 'xlm' => 'application/vnd.ms-excel', - 'xls' => 'application/vnd.ms-excel', - 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12', - 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12', - 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'xlt' => 'application/vnd.ms-excel', - 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12', - 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', - 'xlw' => 'application/vnd.ms-excel', - 'xm' => 'audio/xm', - 'xml' => 'application/xml', - 'xo' => 'application/vnd.olpc-sugar', - 'xop' => 'application/xop+xml', - 'xpi' => 'application/x-xpinstall', - 'xpl' => 'application/xproc+xml', - 'xpm' => 'image/x-xpixmap', - 'xpr' => 'application/vnd.is-xpr', - 'xps' => 'application/vnd.ms-xpsdocument', - 'xpw' => 'application/vnd.intercon.formnet', - 'xpx' => 'application/vnd.intercon.formnet', - 'xsl' => 'application/xml', - 'xslt' => 'application/xslt+xml', - 'xsm' => 'application/vnd.syncml+xml', - 'xspf' => 'application/xspf+xml', - 'xul' => 'application/vnd.mozilla.xul+xml', - 'xvm' => 'application/xv+xml', - 'xvml' => 'application/xv+xml', - 'xwd' => 'image/x-xwindowdump', - 'xyz' => 'chemical/x-xyz', - 'xz' => 'application/x-xz', - 'yang' => 'application/yang', - 'yin' => 'application/yin+xml', - 'z1' => 'application/x-zmachine', - 'z2' => 'application/x-zmachine', - 'z3' => 'application/x-zmachine', - 'z4' => 'application/x-zmachine', - 'z5' => 'application/x-zmachine', - 'z6' => 'application/x-zmachine', - 'z7' => 'application/x-zmachine', - 'z8' => 'application/x-zmachine', - 'zaz' => 'application/vnd.zzazz.deck+xml', - 'zip' => 'application/zip', - 'zir' => 'application/vnd.zul', - 'zirz' => 'application/vnd.zul', - 'zmm' => 'application/vnd.handheld-entertainment+xml', - '123' => 'application/vnd.lotus-1-2-3', -]; diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/preferences.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/preferences.php deleted file mode 100644 index 27b7065..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/preferences.php +++ /dev/null @@ -1,19 +0,0 @@ -setCharset('utf-8'); - -// Without these lines the default caching mechanism is "array" but this uses a lot of memory. -// If possible, use a disk cache to enable attaching large attachments etc. -// You can override the default temporary directory by setting the TMPDIR environment variable. -if (@is_writable($tmpDir = sys_get_temp_dir())) { - $preferences->setTempDir($tmpDir)->setCacheType('disk'); -} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/swift_required.php b/plugins/email/vendor/swiftmailer/swiftmailer/lib/swift_required.php deleted file mode 100644 index d696056..0000000 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/swift_required.php +++ /dev/null @@ -1,22 +0,0 @@ - 'application/x-php', - 'php3' => 'application/x-php', - 'php4' => 'application/x-php', - 'php5' => 'application/x-php', - 'zip' => 'application/zip', - 'gif' => 'image/gif', - 'png' => 'image/png', - 'css' => 'text/css', - 'js' => 'text/javascript', - 'txt' => 'text/plain', - 'aif' => 'audio/x-aiff', - 'aiff' => 'audio/x-aiff', - 'avi' => 'video/avi', - 'bmp' => 'image/bmp', - 'bz2' => 'application/x-bz2', - 'csv' => 'text/csv', - 'dmg' => 'application/x-apple-diskimage', - 'doc' => 'application/msword', - 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'eml' => 'message/rfc822', - 'aps' => 'application/postscript', - 'exe' => 'application/x-ms-dos-executable', - 'flv' => 'video/x-flv', - 'gz' => 'application/x-gzip', - 'hqx' => 'application/stuffit', - 'htm' => 'text/html', - 'html' => 'text/html', - 'jar' => 'application/x-java-archive', - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'm3u' => 'audio/x-mpegurl', - 'm4a' => 'audio/mp4', - 'mdb' => 'application/x-msaccess', - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', - 'mov' => 'video/quicktime', - 'mp3' => 'audio/mpeg', - 'mp4' => 'video/mp4', - 'mpeg' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'odg' => 'vnd.oasis.opendocument.graphics', - 'odp' => 'vnd.oasis.opendocument.presentation', - 'odt' => 'vnd.oasis.opendocument.text', - 'ods' => 'vnd.oasis.opendocument.spreadsheet', - 'ogg' => 'audio/ogg', - 'pdf' => 'application/pdf', - 'ppt' => 'application/vnd.ms-powerpoint', - 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'ps' => 'application/postscript', - 'rar' => 'application/x-rar-compressed', - 'rtf' => 'application/rtf', - 'tar' => 'application/x-tar', - 'sit' => 'application/x-stuffit', - 'svg' => 'image/svg+xml', - 'tif' => 'image/tiff', - 'tiff' => 'image/tiff', - 'ttf' => 'application/x-font-truetype', - 'vcf' => 'text/x-vcard', - 'wav' => 'audio/wav', - 'wma' => 'audio/x-ms-wma', - 'wmv' => 'audio/x-ms-wmv', - 'xls' => 'application/vnd.ms-excel', - 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'xml' => 'application/xml', - ]; - - // wrap array for generating file - foreach ($valid_mime_types_preset as $extension => $mime_type) { - // generate array for mimetype to extension resolver (only first match) - $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; - } - - // all extensions from second match - foreach ($matches[2] as $i => $extensions) { - // explode multiple extensions from string - $extensions = explode(' ', strtolower($extensions ?? '')); - - // force array for foreach - if (!\is_array($extensions)) { - $extensions = [$extensions]; - } - - foreach ($extensions as $extension) { - // get mime type - $mime_type = $matches[1][$i]; - - // check if string length lower than 10 - if (\strlen($extension) < 10) { - if (!isset($valid_mime_types[$mime_type])) { - // generate array for mimetype to extension resolver (only first match) - $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; - } - } - } - } - } - - $xml = simplexml_load_string($mime_xml); - - foreach ($xml as $node) { - // check if there is no pattern - if (!isset($node->glob['pattern'])) { - continue; - } - - // get all matching extensions from match - foreach ((array) $node->glob['pattern'] as $extension) { - // skip none glob extensions - if (false === strpos($extension ?? '', '.')) { - continue; - } - - // remove get only last part - $extension = explode('.', strtolower($extension ?? '')); - $extension = end($extension); - } - - if (isset($node->glob['pattern'][0])) { - // mime type - $mime_type = strtolower((string) $node['type'] ?? ''); - - // get first extension - $extension = strtolower(trim($node->glob['ddpattern'][0] ?? '', '*.')); - - // skip none glob extensions and check if string length between 1 and 10 - if (false !== strpos($extension, '.') || \strlen($extension) < 1 || \strlen($extension) > 9) { - continue; - } - - // check if string length lower than 10 - if (!isset($valid_mime_types[$mime_type])) { - // generate array for mimetype to extension resolver (only first match) - $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; - } - } - } - - // full list of valid extensions only - $valid_mime_types = array_unique($valid_mime_types); - ksort($valid_mime_types); - - // combine mime types and extensions array - $output = "$preamble\$swift_mime_types = array(\n ".implode(",\n ", $valid_mime_types)."\n);"; - - // write mime_types.php config file - @file_put_contents('./mime_types.php', $output); -} - -generateUpToDateMimeArray(); diff --git a/plugins/email/vendor/symfony/amqp-messenger/CHANGELOG.md b/plugins/email/vendor/symfony/amqp-messenger/CHANGELOG.md new file mode 100644 index 0000000..1e5bcf3 --- /dev/null +++ b/plugins/email/vendor/symfony/amqp-messenger/CHANGELOG.md @@ -0,0 +1,21 @@ +CHANGELOG +========= + +5.3 +--- + + * Deprecated the `prefetch_count` parameter, it has no effect and will be removed in Symfony 6.0. + * `AmqpReceiver` implements `QueueReceiverInterface` to fetch messages from a specific set of queues. + * Add ability to distinguish retry and delay actions + +5.2.0 +----- + + * Add option to confirm message delivery + * DSN now support AMQPS out-of-the-box. + +5.1.0 +----- + + * Introduced the AMQP bridge. + * Deprecated use of invalid options diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/LICENSE b/plugins/email/vendor/symfony/amqp-messenger/LICENSE similarity index 96% rename from plugins/email/vendor/swiftmailer/swiftmailer/LICENSE rename to plugins/email/vendor/symfony/amqp-messenger/LICENSE index ab72077..74cdc2d 100644 --- a/plugins/email/vendor/swiftmailer/swiftmailer/LICENSE +++ b/plugins/email/vendor/symfony/amqp-messenger/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013-2021 Fabien Potencier +Copyright (c) 2018-2022 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/plugins/email/vendor/symfony/amqp-messenger/README.md b/plugins/email/vendor/symfony/amqp-messenger/README.md new file mode 100644 index 0000000..c53ebce --- /dev/null +++ b/plugins/email/vendor/symfony/amqp-messenger/README.md @@ -0,0 +1,12 @@ +AMQP Messenger +============== + +Provides AMQP integration for Symfony Messenger. + +Resources +--------- + + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpFactory.php b/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpFactory.php new file mode 100644 index 0000000..47d8487 --- /dev/null +++ b/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpFactory.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Amqp\Transport; + +class AmqpFactory +{ + public function createConnection(array $credentials): \AMQPConnection + { + return new \AMQPConnection($credentials); + } + + public function createChannel(\AMQPConnection $connection): \AMQPChannel + { + return new \AMQPChannel($connection); + } + + public function createQueue(\AMQPChannel $channel): \AMQPQueue + { + return new \AMQPQueue($channel); + } + + public function createExchange(\AMQPChannel $channel): \AMQPExchange + { + return new \AMQPExchange($channel); + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\AmqpExt\AmqpFactory::class, false)) { + class_alias(AmqpFactory::class, \Symfony\Component\Messenger\Transport\AmqpExt\AmqpFactory::class); +} diff --git a/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpReceivedStamp.php b/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpReceivedStamp.php new file mode 100644 index 0000000..b661cd8 --- /dev/null +++ b/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpReceivedStamp.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Amqp\Transport; + +use Symfony\Component\Messenger\Stamp\NonSendableStampInterface; + +/** + * Stamp applied when a message is received from Amqp. + */ +class AmqpReceivedStamp implements NonSendableStampInterface +{ + private $amqpEnvelope; + private $queueName; + + public function __construct(\AMQPEnvelope $amqpEnvelope, string $queueName) + { + $this->amqpEnvelope = $amqpEnvelope; + $this->queueName = $queueName; + } + + public function getAmqpEnvelope(): \AMQPEnvelope + { + return $this->amqpEnvelope; + } + + public function getQueueName(): string + { + return $this->queueName; + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceivedStamp::class, false)) { + class_alias(AmqpReceivedStamp::class, \Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceivedStamp::class); +} diff --git a/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpReceiver.php b/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpReceiver.php new file mode 100644 index 0000000..141ab8c --- /dev/null +++ b/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpReceiver.php @@ -0,0 +1,150 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Amqp\Transport; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\LogicException; +use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; +use Symfony\Component\Messenger\Exception\TransportException; +use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface; +use Symfony\Component\Messenger\Transport\Receiver\QueueReceiverInterface; +use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; + +/** + * Symfony Messenger receiver to get messages from AMQP brokers using PHP's AMQP extension. + * + * @author Samuel Roze + */ +class AmqpReceiver implements QueueReceiverInterface, MessageCountAwareInterface +{ + private $serializer; + private $connection; + + public function __construct(Connection $connection, SerializerInterface $serializer = null) + { + $this->connection = $connection; + $this->serializer = $serializer ?? new PhpSerializer(); + } + + /** + * {@inheritdoc} + */ + public function get(): iterable + { + yield from $this->getFromQueues($this->connection->getQueueNames()); + } + + /** + * {@inheritdoc} + */ + public function getFromQueues(array $queueNames): iterable + { + foreach ($queueNames as $queueName) { + yield from $this->getEnvelope($queueName); + } + } + + private function getEnvelope(string $queueName): iterable + { + try { + $amqpEnvelope = $this->connection->get($queueName); + } catch (\AMQPException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + + if (null === $amqpEnvelope) { + return; + } + + $body = $amqpEnvelope->getBody(); + + try { + $envelope = $this->serializer->decode([ + 'body' => false === $body ? '' : $body, // workaround https://github.com/pdezwart/php-amqp/issues/351 + 'headers' => $amqpEnvelope->getHeaders(), + ]); + } catch (MessageDecodingFailedException $exception) { + // invalid message of some type + $this->rejectAmqpEnvelope($amqpEnvelope, $queueName); + + throw $exception; + } + + yield $envelope->with(new AmqpReceivedStamp($amqpEnvelope, $queueName)); + } + + /** + * {@inheritdoc} + */ + public function ack(Envelope $envelope): void + { + try { + $stamp = $this->findAmqpStamp($envelope); + + $this->connection->ack( + $stamp->getAmqpEnvelope(), + $stamp->getQueueName() + ); + } catch (\AMQPException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + } + + /** + * {@inheritdoc} + */ + public function reject(Envelope $envelope): void + { + $stamp = $this->findAmqpStamp($envelope); + + $this->rejectAmqpEnvelope( + $stamp->getAmqpEnvelope(), + $stamp->getQueueName() + ); + } + + /** + * {@inheritdoc} + */ + public function getMessageCount(): int + { + try { + return $this->connection->countMessagesInQueues(); + } catch (\AMQPException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + } + + private function rejectAmqpEnvelope(\AMQPEnvelope $amqpEnvelope, string $queueName): void + { + try { + $this->connection->nack($amqpEnvelope, $queueName, \AMQP_NOPARAM); + } catch (\AMQPException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + } + + private function findAmqpStamp(Envelope $envelope): AmqpReceivedStamp + { + $amqpReceivedStamp = $envelope->last(AmqpReceivedStamp::class); + if (null === $amqpReceivedStamp) { + throw new LogicException('No "AmqpReceivedStamp" stamp found on the Envelope.'); + } + + return $amqpReceivedStamp; + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceiver::class, false)) { + class_alias(AmqpReceiver::class, \Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceiver::class); +} diff --git a/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpSender.php b/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpSender.php new file mode 100644 index 0000000..5fdfdff --- /dev/null +++ b/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpSender.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Amqp\Transport; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\TransportException; +use Symfony\Component\Messenger\Stamp\DelayStamp; +use Symfony\Component\Messenger\Stamp\RedeliveryStamp; +use Symfony\Component\Messenger\Transport\Sender\SenderInterface; +use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; + +/** + * Symfony Messenger sender to send messages to AMQP brokers using PHP's AMQP extension. + * + * @author Samuel Roze + */ +class AmqpSender implements SenderInterface +{ + private $serializer; + private $connection; + + public function __construct(Connection $connection, SerializerInterface $serializer = null) + { + $this->connection = $connection; + $this->serializer = $serializer ?? new PhpSerializer(); + } + + /** + * {@inheritdoc} + */ + public function send(Envelope $envelope): Envelope + { + $encodedMessage = $this->serializer->encode($envelope); + + /** @var DelayStamp|null $delayStamp */ + $delayStamp = $envelope->last(DelayStamp::class); + $delay = $delayStamp ? $delayStamp->getDelay() : 0; + + /** @var AmqpStamp|null $amqpStamp */ + $amqpStamp = $envelope->last(AmqpStamp::class); + if (isset($encodedMessage['headers']['Content-Type'])) { + $contentType = $encodedMessage['headers']['Content-Type']; + unset($encodedMessage['headers']['Content-Type']); + + if (!$amqpStamp || !isset($amqpStamp->getAttributes()['content_type'])) { + $amqpStamp = AmqpStamp::createWithAttributes(['content_type' => $contentType], $amqpStamp); + } + } + + $amqpReceivedStamp = $envelope->last(AmqpReceivedStamp::class); + if ($amqpReceivedStamp instanceof AmqpReceivedStamp) { + $amqpStamp = AmqpStamp::createFromAmqpEnvelope( + $amqpReceivedStamp->getAmqpEnvelope(), + $amqpStamp, + $envelope->last(RedeliveryStamp::class) ? $amqpReceivedStamp->getQueueName() : null + ); + } + + try { + $this->connection->publish( + $encodedMessage['body'], + $encodedMessage['headers'] ?? [], + $delay, + $amqpStamp + ); + } catch (\AMQPException $e) { + throw new TransportException($e->getMessage(), 0, $e); + } + + return $envelope; + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\AmqpExt\AmqpSender::class, false)) { + class_alias(AmqpSender::class, \Symfony\Component\Messenger\Transport\AmqpExt\AmqpSender::class); +} diff --git a/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpStamp.php b/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpStamp.php new file mode 100644 index 0000000..5835bdc --- /dev/null +++ b/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpStamp.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Amqp\Transport; + +use Symfony\Component\Messenger\Stamp\NonSendableStampInterface; + +/** + * @author Guillaume Gammelin + * @author Samuel Roze + */ +final class AmqpStamp implements NonSendableStampInterface +{ + private $routingKey; + private $flags; + private $attributes; + private $isRetryAttempt = false; + + public function __construct(string $routingKey = null, int $flags = \AMQP_NOPARAM, array $attributes = []) + { + $this->routingKey = $routingKey; + $this->flags = $flags; + $this->attributes = $attributes; + } + + public function getRoutingKey(): ?string + { + return $this->routingKey; + } + + public function getFlags(): int + { + return $this->flags; + } + + public function getAttributes(): array + { + return $this->attributes; + } + + public static function createFromAmqpEnvelope(\AMQPEnvelope $amqpEnvelope, self $previousStamp = null, string $retryRoutingKey = null): self + { + $attr = $previousStamp->attributes ?? []; + + $attr['headers'] = $attr['headers'] ?? $amqpEnvelope->getHeaders(); + $attr['content_type'] = $attr['content_type'] ?? $amqpEnvelope->getContentType(); + $attr['content_encoding'] = $attr['content_encoding'] ?? $amqpEnvelope->getContentEncoding(); + $attr['delivery_mode'] = $attr['delivery_mode'] ?? $amqpEnvelope->getDeliveryMode(); + $attr['priority'] = $attr['priority'] ?? $amqpEnvelope->getPriority(); + $attr['timestamp'] = $attr['timestamp'] ?? $amqpEnvelope->getTimestamp(); + $attr['app_id'] = $attr['app_id'] ?? $amqpEnvelope->getAppId(); + $attr['message_id'] = $attr['message_id'] ?? $amqpEnvelope->getMessageId(); + $attr['user_id'] = $attr['user_id'] ?? $amqpEnvelope->getUserId(); + $attr['expiration'] = $attr['expiration'] ?? $amqpEnvelope->getExpiration(); + $attr['type'] = $attr['type'] ?? $amqpEnvelope->getType(); + $attr['reply_to'] = $attr['reply_to'] ?? $amqpEnvelope->getReplyTo(); + $attr['correlation_id'] = $attr['correlation_id'] ?? $amqpEnvelope->getCorrelationId(); + + if (null === $retryRoutingKey) { + $stamp = new self($previousStamp->routingKey ?? $amqpEnvelope->getRoutingKey(), $previousStamp->flags ?? \AMQP_NOPARAM, $attr); + } else { + $stamp = new self($retryRoutingKey, $previousStamp->flags ?? \AMQP_NOPARAM, $attr); + $stamp->isRetryAttempt = true; + } + + return $stamp; + } + + public function isRetryAttempt(): bool + { + return $this->isRetryAttempt; + } + + public static function createWithAttributes(array $attributes, self $previousStamp = null): self + { + return new self( + $previousStamp->routingKey ?? null, + $previousStamp->flags ?? \AMQP_NOPARAM, + array_merge($previousStamp->attributes ?? [], $attributes) + ); + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\AmqpExt\AmqpStamp::class, false)) { + class_alias(AmqpStamp::class, \Symfony\Component\Messenger\Transport\AmqpExt\AmqpStamp::class); +} diff --git a/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpTransport.php b/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpTransport.php new file mode 100644 index 0000000..9ffda47 --- /dev/null +++ b/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpTransport.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Amqp\Transport; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface; +use Symfony\Component\Messenger\Transport\Receiver\QueueReceiverInterface; +use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Component\Messenger\Transport\SetupableTransportInterface; +use Symfony\Component\Messenger\Transport\TransportInterface; + +/** + * @author Nicolas Grekas + */ +class AmqpTransport implements QueueReceiverInterface, TransportInterface, SetupableTransportInterface, MessageCountAwareInterface +{ + private $serializer; + private $connection; + private $receiver; + private $sender; + + public function __construct(Connection $connection, SerializerInterface $serializer = null) + { + $this->connection = $connection; + $this->serializer = $serializer ?? new PhpSerializer(); + } + + /** + * {@inheritdoc} + */ + public function get(): iterable + { + return ($this->receiver ?? $this->getReceiver())->get(); + } + + /** + * {@inheritdoc} + */ + public function getFromQueues(array $queueNames): iterable + { + return ($this->receiver ?? $this->getReceiver())->getFromQueues($queueNames); + } + + /** + * {@inheritdoc} + */ + public function ack(Envelope $envelope): void + { + ($this->receiver ?? $this->getReceiver())->ack($envelope); + } + + /** + * {@inheritdoc} + */ + public function reject(Envelope $envelope): void + { + ($this->receiver ?? $this->getReceiver())->reject($envelope); + } + + /** + * {@inheritdoc} + */ + public function send(Envelope $envelope): Envelope + { + return ($this->sender ?? $this->getSender())->send($envelope); + } + + /** + * {@inheritdoc} + */ + public function setup(): void + { + $this->connection->setup(); + } + + /** + * {@inheritdoc} + */ + public function getMessageCount(): int + { + return ($this->receiver ?? $this->getReceiver())->getMessageCount(); + } + + private function getReceiver(): AmqpReceiver + { + return $this->receiver = new AmqpReceiver($this->connection, $this->serializer); + } + + private function getSender(): AmqpSender + { + return $this->sender = new AmqpSender($this->connection, $this->serializer); + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\AmqpExt\AmqpTransport::class, false)) { + class_alias(AmqpTransport::class, \Symfony\Component\Messenger\Transport\AmqpExt\AmqpTransport::class); +} diff --git a/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpTransportFactory.php b/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpTransportFactory.php new file mode 100644 index 0000000..420cf7a --- /dev/null +++ b/plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpTransportFactory.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Amqp\Transport; + +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Component\Messenger\Transport\TransportFactoryInterface; +use Symfony\Component\Messenger\Transport\TransportInterface; + +/** + * @author Samuel Roze + */ +class AmqpTransportFactory implements TransportFactoryInterface +{ + public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface + { + unset($options['transport_name']); + + return new AmqpTransport(Connection::fromDsn($dsn, $options), $serializer); + } + + public function supports(string $dsn, array $options): bool + { + return 0 === strpos($dsn, 'amqp://') || 0 === strpos($dsn, 'amqps://'); + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\AmqpExt\AmqpTransportFactory::class, false)) { + class_alias(AmqpTransportFactory::class, \Symfony\Component\Messenger\Transport\AmqpExt\AmqpTransportFactory::class); +} diff --git a/plugins/email/vendor/symfony/amqp-messenger/Transport/Connection.php b/plugins/email/vendor/symfony/amqp-messenger/Transport/Connection.php new file mode 100644 index 0000000..e5a9d59 --- /dev/null +++ b/plugins/email/vendor/symfony/amqp-messenger/Transport/Connection.php @@ -0,0 +1,583 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Amqp\Transport; + +use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\Exception\LogicException; + +/** + * An AMQP connection. + * + * @author Samuel Roze + * + * @final + */ +class Connection +{ + private const ARGUMENTS_AS_INTEGER = [ + 'x-delay', + 'x-expires', + 'x-max-length', + 'x-max-length-bytes', + 'x-max-priority', + 'x-message-ttl', + ]; + + private const AVAILABLE_OPTIONS = [ + 'host', + 'port', + 'vhost', + 'user', + 'login', + 'password', + 'queues', + 'exchange', + 'delay', + 'auto_setup', + 'prefetch_count', + 'retry', + 'persistent', + 'frame_max', + 'channel_max', + 'heartbeat', + 'read_timeout', + 'write_timeout', + 'confirm_timeout', + 'connect_timeout', + 'cacert', + 'cert', + 'key', + 'verify', + 'sasl_method', + ]; + + private const AVAILABLE_QUEUE_OPTIONS = [ + 'binding_keys', + 'binding_arguments', + 'flags', + 'arguments', + ]; + + private const AVAILABLE_EXCHANGE_OPTIONS = [ + 'name', + 'type', + 'default_publish_routing_key', + 'flags', + 'arguments', + ]; + + private $connectionOptions; + private $exchangeOptions; + private $queuesOptions; + private $amqpFactory; + private $autoSetupExchange; + private $autoSetupDelayExchange; + + /** + * @var \AMQPChannel|null + */ + private $amqpChannel; + + /** + * @var \AMQPExchange|null + */ + private $amqpExchange; + + /** + * @var \AMQPQueue[]|null + */ + private $amqpQueues = []; + + /** + * @var \AMQPExchange|null + */ + private $amqpDelayExchange; + + public function __construct(array $connectionOptions, array $exchangeOptions, array $queuesOptions, AmqpFactory $amqpFactory = null) + { + if (!\extension_loaded('amqp')) { + throw new LogicException(sprintf('You cannot use the "%s" as the "amqp" extension is not installed.', __CLASS__)); + } + + $this->connectionOptions = array_replace_recursive([ + 'delay' => [ + 'exchange_name' => 'delays', + 'queue_name_pattern' => 'delay_%exchange_name%_%routing_key%_%delay%', + ], + ], $connectionOptions); + $this->autoSetupExchange = $this->autoSetupDelayExchange = $connectionOptions['auto_setup'] ?? true; + $this->exchangeOptions = $exchangeOptions; + $this->queuesOptions = $queuesOptions; + $this->amqpFactory = $amqpFactory ?? new AmqpFactory(); + } + + /** + * Creates a connection based on the DSN and options. + * + * Available options: + * + * * host: Hostname of the AMQP service + * * port: Port of the AMQP service + * * vhost: Virtual Host to use with the AMQP service + * * user|login: Username to use to connect the AMQP service + * * password: Password to use to connect to the AMQP service + * * read_timeout: Timeout in for income activity. Note: 0 or greater seconds. May be fractional. + * * write_timeout: Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional. + * * connect_timeout: Connection timeout. Note: 0 or greater seconds. May be fractional. + * * confirm_timeout: Timeout in seconds for confirmation, if none specified transport will not wait for message confirmation. Note: 0 or greater seconds. May be fractional. + * * queues[name]: An array of queues, keyed by the name + * * binding_keys: The binding keys (if any) to bind to this queue + * * binding_arguments: Arguments to be used while binding the queue. + * * flags: Queue flags (Default: AMQP_DURABLE) + * * arguments: Extra arguments + * * exchange: + * * name: Name of the exchange + * * type: Type of exchange (Default: fanout) + * * default_publish_routing_key: Routing key to use when publishing, if none is specified on the message + * * flags: Exchange flags (Default: AMQP_DURABLE) + * * arguments: Extra arguments + * * delay: + * * queue_name_pattern: Pattern to use to create the queues (Default: "delay_%exchange_name%_%routing_key%_%delay%") + * * exchange_name: Name of the exchange to be used for the delayed/retried messages (Default: "delays") + * * auto_setup: Enable or not the auto-setup of queues and exchanges (Default: true) + * + * * Connection tuning options (see http://www.rabbitmq.com/amqp-0-9-1-reference.html#connection.tune for details): + * * channel_max: Specifies highest channel number that the server permits. 0 means standard extension limit + * (see PHP_AMQP_MAX_CHANNELS constant) + * * frame_max: The largest frame size that the server proposes for the connection, including frame header + * and end-byte. 0 means standard extension limit (depends on librabbimq default frame size limit) + * * heartbeat: The delay, in seconds, of the connection heartbeat that the server wants. + * 0 means the server does not want a heartbeat. Note, librabbitmq has limited heartbeat support, + * which means heartbeats checked only during blocking calls. + * + * TLS support (see https://www.rabbitmq.com/ssl.html for details): + * * cacert: Path to the CA cert file in PEM format. + * * cert: Path to the client certificate in PEM format. + * * key: Path to the client key in PEM format. + * * verify: Enable or disable peer verification. If peer verification is enabled then the common name in the + * server certificate must match the server name. Peer verification is enabled by default. + */ + public static function fromDsn(string $dsn, array $options = [], AmqpFactory $amqpFactory = null): self + { + if (false === $parsedUrl = parse_url($dsn)) { + // this is a valid URI that parse_url cannot handle when you want to pass all parameters as options + if (!\in_array($dsn, ['amqp://', 'amqps://'])) { + throw new InvalidArgumentException(sprintf('The given AMQP DSN "%s" is invalid.', $dsn)); + } + + $parsedUrl = []; + } + + $useAmqps = 0 === strpos($dsn, 'amqps://'); + $pathParts = isset($parsedUrl['path']) ? explode('/', trim($parsedUrl['path'], '/')) : []; + $exchangeName = $pathParts[1] ?? 'messages'; + parse_str($parsedUrl['query'] ?? '', $parsedQuery); + $port = $useAmqps ? 5671 : 5672; + + $amqpOptions = array_replace_recursive([ + 'host' => $parsedUrl['host'] ?? 'localhost', + 'port' => $parsedUrl['port'] ?? $port, + 'vhost' => isset($pathParts[0]) ? urldecode($pathParts[0]) : '/', + 'exchange' => [ + 'name' => $exchangeName, + ], + ], $options, $parsedQuery); + + self::validateOptions($amqpOptions); + + if (isset($parsedUrl['user'])) { + $amqpOptions['login'] = urldecode($parsedUrl['user']); + } + + if (isset($parsedUrl['pass'])) { + $amqpOptions['password'] = urldecode($parsedUrl['pass']); + } + + if (!isset($amqpOptions['queues'])) { + $amqpOptions['queues'][$exchangeName] = []; + } + + $exchangeOptions = $amqpOptions['exchange']; + $queuesOptions = $amqpOptions['queues']; + unset($amqpOptions['queues'], $amqpOptions['exchange']); + if (isset($amqpOptions['auto_setup'])) { + $amqpOptions['auto_setup'] = filter_var($amqpOptions['auto_setup'], \FILTER_VALIDATE_BOOLEAN); + } + + $queuesOptions = array_map(function ($queueOptions) { + if (!\is_array($queueOptions)) { + $queueOptions = []; + } + if (\is_array($queueOptions['arguments'] ?? false)) { + $queueOptions['arguments'] = self::normalizeQueueArguments($queueOptions['arguments']); + } + + return $queueOptions; + }, $queuesOptions); + + if (!$useAmqps) { + unset($amqpOptions['cacert'], $amqpOptions['cert'], $amqpOptions['key'], $amqpOptions['verify']); + } + + if ($useAmqps && !self::hasCaCertConfigured($amqpOptions)) { + throw new InvalidArgumentException('No CA certificate has been provided. Set "amqp.cacert" in your php.ini or pass the "cacert" parameter in the DSN to use SSL. Alternatively, you can use amqp:// to use without SSL.'); + } + + return new self($amqpOptions, $exchangeOptions, $queuesOptions, $amqpFactory); + } + + private static function validateOptions(array $options): void + { + if (0 < \count($invalidOptions = array_diff(array_keys($options), self::AVAILABLE_OPTIONS))) { + trigger_deprecation('symfony/messenger', '5.1', 'Invalid option(s) "%s" passed to the AMQP Messenger transport. Passing invalid options is deprecated.', implode('", "', $invalidOptions)); + } + + if (isset($options['prefetch_count'])) { + trigger_deprecation('symfony/messenger', '5.3', 'The "prefetch_count" option passed to the AMQP Messenger transport has no effect and should not be used.'); + } + + if (\is_array($options['queues'] ?? false)) { + foreach ($options['queues'] as $queue) { + if (!\is_array($queue)) { + continue; + } + + if (0 < \count($invalidQueueOptions = array_diff(array_keys($queue), self::AVAILABLE_QUEUE_OPTIONS))) { + trigger_deprecation('symfony/messenger', '5.1', 'Invalid queue option(s) "%s" passed to the AMQP Messenger transport. Passing invalid queue options is deprecated.', implode('", "', $invalidQueueOptions)); + } + } + } + + if (\is_array($options['exchange'] ?? false) + && 0 < \count($invalidExchangeOptions = array_diff(array_keys($options['exchange']), self::AVAILABLE_EXCHANGE_OPTIONS))) { + trigger_deprecation('symfony/messenger', '5.1', 'Invalid exchange option(s) "%s" passed to the AMQP Messenger transport. Passing invalid exchange options is deprecated.', implode('", "', $invalidExchangeOptions)); + } + } + + private static function normalizeQueueArguments(array $arguments): array + { + foreach (self::ARGUMENTS_AS_INTEGER as $key) { + if (!\array_key_exists($key, $arguments)) { + continue; + } + + if (!is_numeric($arguments[$key])) { + throw new InvalidArgumentException(sprintf('Integer expected for queue argument "%s", "%s" given.', $key, get_debug_type($arguments[$key]))); + } + + $arguments[$key] = (int) $arguments[$key]; + } + + return $arguments; + } + + private static function hasCaCertConfigured(array $amqpOptions): bool + { + return (isset($amqpOptions['cacert']) && '' !== $amqpOptions['cacert']) || '' !== \ini_get('amqp.cacert'); + } + + /** + * @throws \AMQPException + */ + public function publish(string $body, array $headers = [], int $delayInMs = 0, AmqpStamp $amqpStamp = null): void + { + $this->clearWhenDisconnected(); + + if ($this->autoSetupExchange) { + $this->setupExchangeAndQueues(); // also setup normal exchange for delayed messages so delay queue can DLX messages to it + } + + if (0 !== $delayInMs) { + $this->publishWithDelay($body, $headers, $delayInMs, $amqpStamp); + + return; + } + + $this->publishOnExchange( + $this->exchange(), + $body, + $this->getRoutingKeyForMessage($amqpStamp), + $headers, + $amqpStamp + ); + } + + /** + * Returns an approximate count of the messages in defined queues. + */ + public function countMessagesInQueues(): int + { + return array_sum(array_map(function ($queueName) { + return $this->queue($queueName)->declareQueue(); + }, $this->getQueueNames())); + } + + /** + * @throws \AMQPException + */ + private function publishWithDelay(string $body, array $headers, int $delay, AmqpStamp $amqpStamp = null) + { + $routingKey = $this->getRoutingKeyForMessage($amqpStamp); + $isRetryAttempt = $amqpStamp ? $amqpStamp->isRetryAttempt() : false; + + $this->setupDelay($delay, $routingKey, $isRetryAttempt); + + $this->publishOnExchange( + $this->getDelayExchange(), + $body, + $this->getRoutingKeyForDelay($delay, $routingKey, $isRetryAttempt), + $headers, + $amqpStamp + ); + } + + private function publishOnExchange(\AMQPExchange $exchange, string $body, string $routingKey = null, array $headers = [], AmqpStamp $amqpStamp = null) + { + $attributes = $amqpStamp ? $amqpStamp->getAttributes() : []; + $attributes['headers'] = array_merge($attributes['headers'] ?? [], $headers); + $attributes['delivery_mode'] = $attributes['delivery_mode'] ?? 2; + $attributes['timestamp'] = $attributes['timestamp'] ?? time(); + + $exchange->publish( + $body, + $routingKey, + $amqpStamp ? $amqpStamp->getFlags() : \AMQP_NOPARAM, + $attributes + ); + + if ('' !== ($this->connectionOptions['confirm_timeout'] ?? '')) { + $this->channel()->waitForConfirm((float) $this->connectionOptions['confirm_timeout']); + } + } + + private function setupDelay(int $delay, ?string $routingKey, bool $isRetryAttempt) + { + if ($this->autoSetupDelayExchange) { + $this->setupDelayExchange(); + } + + $queue = $this->createDelayQueue($delay, $routingKey, $isRetryAttempt); + $queue->declareQueue(); // the delay queue always need to be declared because the name is dynamic and cannot be declared in advance + $queue->bind($this->connectionOptions['delay']['exchange_name'], $this->getRoutingKeyForDelay($delay, $routingKey, $isRetryAttempt)); + } + + private function getDelayExchange(): \AMQPExchange + { + if (null === $this->amqpDelayExchange) { + $this->amqpDelayExchange = $this->amqpFactory->createExchange($this->channel()); + $this->amqpDelayExchange->setName($this->connectionOptions['delay']['exchange_name']); + $this->amqpDelayExchange->setType(\AMQP_EX_TYPE_DIRECT); + $this->amqpDelayExchange->setFlags(\AMQP_DURABLE); + } + + return $this->amqpDelayExchange; + } + + /** + * Creates a delay queue that will delay for a certain amount of time. + * + * This works by setting message TTL for the delay and pointing + * the dead letter exchange to the original exchange. The result + * is that after the TTL, the message is sent to the dead-letter-exchange, + * which is the original exchange, resulting on it being put back into + * the original queue. + */ + private function createDelayQueue(int $delay, ?string $routingKey, bool $isRetryAttempt): \AMQPQueue + { + $queue = $this->amqpFactory->createQueue($this->channel()); + $queue->setName($this->getRoutingKeyForDelay($delay, $routingKey, $isRetryAttempt)); + $queue->setFlags(\AMQP_DURABLE); + $queue->setArguments([ + 'x-message-ttl' => $delay, + // delete the delay queue 10 seconds after the message expires + // publishing another message redeclares the queue which renews the lease + 'x-expires' => $delay + 10000, + // message should be broadcasted to all consumers during delay, but to only one queue during retry + // empty name is default direct exchange + 'x-dead-letter-exchange' => $isRetryAttempt ? '' : $this->exchangeOptions['name'], + // after being released from to DLX, make sure the original routing key will be used + // we must use an empty string instead of null for the argument to be picked up + 'x-dead-letter-routing-key' => $routingKey ?? '', + ]); + + return $queue; + } + + private function getRoutingKeyForDelay(int $delay, ?string $finalRoutingKey, bool $isRetryAttempt): string + { + $action = $isRetryAttempt ? '_retry' : '_delay'; + + return str_replace( + ['%delay%', '%exchange_name%', '%routing_key%'], + [$delay, $this->exchangeOptions['name'], $finalRoutingKey ?? ''], + $this->connectionOptions['delay']['queue_name_pattern'] + ).$action; + } + + /** + * Gets a message from the specified queue. + * + * @throws \AMQPException + */ + public function get(string $queueName): ?\AMQPEnvelope + { + $this->clearWhenDisconnected(); + + if ($this->autoSetupExchange) { + $this->setupExchangeAndQueues(); + } + + if (false !== $message = $this->queue($queueName)->get()) { + return $message; + } + + return null; + } + + public function ack(\AMQPEnvelope $message, string $queueName): bool + { + return $this->queue($queueName)->ack($message->getDeliveryTag()); + } + + public function nack(\AMQPEnvelope $message, string $queueName, int $flags = \AMQP_NOPARAM): bool + { + return $this->queue($queueName)->nack($message->getDeliveryTag(), $flags); + } + + public function setup(): void + { + $this->setupExchangeAndQueues(); + $this->setupDelayExchange(); + } + + private function setupExchangeAndQueues(): void + { + $this->exchange()->declareExchange(); + + foreach ($this->queuesOptions as $queueName => $queueConfig) { + $this->queue($queueName)->declareQueue(); + foreach ($queueConfig['binding_keys'] ?? [null] as $bindingKey) { + $this->queue($queueName)->bind($this->exchangeOptions['name'], $bindingKey, $queueConfig['binding_arguments'] ?? []); + } + } + $this->autoSetupExchange = false; + } + + private function setupDelayExchange(): void + { + $this->getDelayExchange()->declareExchange(); + $this->autoSetupDelayExchange = false; + } + + /** + * @return string[] + */ + public function getQueueNames(): array + { + return array_keys($this->queuesOptions); + } + + public function channel(): \AMQPChannel + { + if (null === $this->amqpChannel) { + $connection = $this->amqpFactory->createConnection($this->connectionOptions); + $connectMethod = 'true' === ($this->connectionOptions['persistent'] ?? 'false') ? 'pconnect' : 'connect'; + + try { + $connection->{$connectMethod}(); + } catch (\AMQPConnectionException $e) { + throw new \AMQPException('Could not connect to the AMQP server. Please verify the provided DSN.', 0, $e); + } + $this->amqpChannel = $this->amqpFactory->createChannel($connection); + + if ('' !== ($this->connectionOptions['confirm_timeout'] ?? '')) { + $this->amqpChannel->confirmSelect(); + $this->amqpChannel->setConfirmCallback( + static function (): bool { + return false; + }, + static function (): bool { + return false; + } + ); + } + } + + return $this->amqpChannel; + } + + public function queue(string $queueName): \AMQPQueue + { + if (!isset($this->amqpQueues[$queueName])) { + $queueConfig = $this->queuesOptions[$queueName]; + + $amqpQueue = $this->amqpFactory->createQueue($this->channel()); + $amqpQueue->setName($queueName); + $amqpQueue->setFlags($queueConfig['flags'] ?? \AMQP_DURABLE); + + if (isset($queueConfig['arguments'])) { + $amqpQueue->setArguments($queueConfig['arguments']); + } + + $this->amqpQueues[$queueName] = $amqpQueue; + } + + return $this->amqpQueues[$queueName]; + } + + public function exchange(): \AMQPExchange + { + if (null === $this->amqpExchange) { + $this->amqpExchange = $this->amqpFactory->createExchange($this->channel()); + $this->amqpExchange->setName($this->exchangeOptions['name']); + $this->amqpExchange->setType($this->exchangeOptions['type'] ?? \AMQP_EX_TYPE_FANOUT); + $this->amqpExchange->setFlags($this->exchangeOptions['flags'] ?? \AMQP_DURABLE); + + if (isset($this->exchangeOptions['arguments'])) { + $this->amqpExchange->setArguments($this->exchangeOptions['arguments']); + } + } + + return $this->amqpExchange; + } + + private function clearWhenDisconnected(): void + { + if (!$this->channel()->isConnected()) { + $this->amqpChannel = null; + $this->amqpQueues = []; + $this->amqpExchange = null; + $this->amqpDelayExchange = null; + } + } + + private function getDefaultPublishRoutingKey(): ?string + { + return $this->exchangeOptions['default_publish_routing_key'] ?? null; + } + + public function purgeQueues() + { + foreach ($this->getQueueNames() as $queueName) { + $this->queue($queueName)->purge(); + } + } + + private function getRoutingKeyForMessage(?AmqpStamp $amqpStamp): ?string + { + return (null !== $amqpStamp ? $amqpStamp->getRoutingKey() : null) ?? $this->getDefaultPublishRoutingKey(); + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\AmqpExt\Connection::class, false)) { + class_alias(Connection::class, \Symfony\Component\Messenger\Transport\AmqpExt\Connection::class); +} diff --git a/plugins/email/vendor/symfony/amqp-messenger/composer.json b/plugins/email/vendor/symfony/amqp-messenger/composer.json new file mode 100644 index 0000000..dd0ecf9 --- /dev/null +++ b/plugins/email/vendor/symfony/amqp-messenger/composer.json @@ -0,0 +1,36 @@ +{ + "name": "symfony/amqp-messenger", + "type": "symfony-messenger-bridge", + "description": "Symfony AMQP extension Messenger Bridge", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/messenger": "^5.3|^6.0" + }, + "require-dev": { + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/property-access": "^4.4|^5.0|^6.0", + "symfony/serializer": "^4.4|^5.0|^6.0" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Messenger\\Bridge\\Amqp\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/plugins/email/vendor/symfony/deprecation-contracts/.gitignore b/plugins/email/vendor/symfony/deprecation-contracts/.gitignore new file mode 100644 index 0000000..c49a5d8 --- /dev/null +++ b/plugins/email/vendor/symfony/deprecation-contracts/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/plugins/email/vendor/symfony/deprecation-contracts/CHANGELOG.md b/plugins/email/vendor/symfony/deprecation-contracts/CHANGELOG.md new file mode 100644 index 0000000..7932e26 --- /dev/null +++ b/plugins/email/vendor/symfony/deprecation-contracts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG +========= + +The changelog is maintained for all Symfony contracts at the following URL: +https://github.com/symfony/contracts/blob/main/CHANGELOG.md diff --git a/plugins/email/vendor/symfony/deprecation-contracts/LICENSE b/plugins/email/vendor/symfony/deprecation-contracts/LICENSE new file mode 100644 index 0000000..406242f --- /dev/null +++ b/plugins/email/vendor/symfony/deprecation-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2020-2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/plugins/email/vendor/symfony/deprecation-contracts/README.md b/plugins/email/vendor/symfony/deprecation-contracts/README.md new file mode 100644 index 0000000..4957933 --- /dev/null +++ b/plugins/email/vendor/symfony/deprecation-contracts/README.md @@ -0,0 +1,26 @@ +Symfony Deprecation Contracts +============================= + +A generic function and convention to trigger deprecation notices. + +This package provides a single global function named `trigger_deprecation()` that triggers silenced deprecation notices. + +By using a custom PHP error handler such as the one provided by the Symfony ErrorHandler component, +the triggered deprecations can be caught and logged for later discovery, both on dev and prod environments. + +The function requires at least 3 arguments: + - the name of the Composer package that is triggering the deprecation + - the version of the package that introduced the deprecation + - the message of the deprecation + - more arguments can be provided: they will be inserted in the message using `printf()` formatting + +Example: +```php +trigger_deprecation('symfony/blockchain', '8.9', 'Using "%s" is deprecated, use "%s" instead.', 'bitcoin', 'fabcoin'); +``` + +This will generate the following message: +`Since symfony/blockchain 8.9: Using "bitcoin" is deprecated, use "fabcoin" instead.` + +While not necessarily recommended, the deprecation notices can be completely ignored by declaring an empty +`function trigger_deprecation() {}` in your application. diff --git a/plugins/email/vendor/symfony/deprecation-contracts/composer.json b/plugins/email/vendor/symfony/deprecation-contracts/composer.json new file mode 100644 index 0000000..cc7cc12 --- /dev/null +++ b/plugins/email/vendor/symfony/deprecation-contracts/composer.json @@ -0,0 +1,35 @@ +{ + "name": "symfony/deprecation-contracts", + "type": "library", + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1" + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + } +} diff --git a/plugins/email/vendor/symfony/deprecation-contracts/function.php b/plugins/email/vendor/symfony/deprecation-contracts/function.php new file mode 100644 index 0000000..d437150 --- /dev/null +++ b/plugins/email/vendor/symfony/deprecation-contracts/function.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (!function_exists('trigger_deprecation')) { + /** + * Triggers a silenced deprecation notice. + * + * @param string $package The name of the Composer package that is triggering the deprecation + * @param string $version The version of the package that introduced the deprecation + * @param string $message The message of the deprecation + * @param mixed ...$args Values to insert in the message using printf() formatting + * + * @author Nicolas Grekas + */ + function trigger_deprecation(string $package, string $version, string $message, ...$args): void + { + @trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), \E_USER_DEPRECATED); + } +} diff --git a/plugins/email/vendor/symfony/doctrine-messenger/CHANGELOG.md b/plugins/email/vendor/symfony/doctrine-messenger/CHANGELOG.md new file mode 100644 index 0000000..aaed248 --- /dev/null +++ b/plugins/email/vendor/symfony/doctrine-messenger/CHANGELOG.md @@ -0,0 +1,8 @@ +CHANGELOG +========= + +5.1.0 +----- + + * Introduced the Doctrine bridge. + * Added support for PostgreSQL `LISTEN`/`NOTIFY`. diff --git a/plugins/email/vendor/symfony/doctrine-messenger/LICENSE b/plugins/email/vendor/symfony/doctrine-messenger/LICENSE new file mode 100644 index 0000000..74cdc2d --- /dev/null +++ b/plugins/email/vendor/symfony/doctrine-messenger/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/plugins/email/vendor/symfony/doctrine-messenger/README.md b/plugins/email/vendor/symfony/doctrine-messenger/README.md new file mode 100644 index 0000000..d29c9c3 --- /dev/null +++ b/plugins/email/vendor/symfony/doctrine-messenger/README.md @@ -0,0 +1,12 @@ +Doctrine Messenger +================== + +Provides Doctrine integration for Symfony Messenger. + +Resources +--------- + + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/plugins/email/vendor/symfony/doctrine-messenger/Transport/Connection.php b/plugins/email/vendor/symfony/doctrine-messenger/Transport/Connection.php new file mode 100644 index 0000000..b760df6 --- /dev/null +++ b/plugins/email/vendor/symfony/doctrine-messenger/Transport/Connection.php @@ -0,0 +1,508 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Doctrine\Transport; + +use Doctrine\DBAL\Connection as DBALConnection; +use Doctrine\DBAL\Driver\Exception as DriverException; +use Doctrine\DBAL\Driver\Result as DriverResult; +use Doctrine\DBAL\Exception as DBALException; +use Doctrine\DBAL\Exception\TableNotFoundException; +use Doctrine\DBAL\LockMode; +use Doctrine\DBAL\Platforms\MySQLPlatform; +use Doctrine\DBAL\Platforms\OraclePlatform; +use Doctrine\DBAL\Query\QueryBuilder; +use Doctrine\DBAL\Result; +use Doctrine\DBAL\Schema\AbstractSchemaManager; +use Doctrine\DBAL\Schema\Comparator; +use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\Schema\SchemaDiff; +use Doctrine\DBAL\Schema\Synchronizer\SchemaSynchronizer; +use Doctrine\DBAL\Schema\Table; +use Doctrine\DBAL\Types\Types; +use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\Exception\TransportException; +use Symfony\Contracts\Service\ResetInterface; + +/** + * @internal since Symfony 5.1 + * + * @author Vincent Touzet + * @author Kévin Dunglas + */ +class Connection implements ResetInterface +{ + protected const TABLE_OPTION_NAME = '_symfony_messenger_table_name'; + + protected const DEFAULT_OPTIONS = [ + 'table_name' => 'messenger_messages', + 'queue_name' => 'default', + 'redeliver_timeout' => 3600, + 'auto_setup' => true, + ]; + + /** + * Configuration of the connection. + * + * Available options: + * + * * table_name: name of the table + * * connection: name of the Doctrine's entity manager + * * queue_name: name of the queue + * * redeliver_timeout: Timeout before redeliver messages still in handling state (i.e: delivered_at is not null and message is still in table). Default: 3600 + * * auto_setup: Whether the table should be created automatically during send / get. Default: true + */ + protected $configuration = []; + protected $driverConnection; + protected $queueEmptiedAt; + private $schemaSynchronizer; + private $autoSetup; + + public function __construct(array $configuration, DBALConnection $driverConnection, SchemaSynchronizer $schemaSynchronizer = null) + { + $this->configuration = array_replace_recursive(static::DEFAULT_OPTIONS, $configuration); + $this->driverConnection = $driverConnection; + $this->schemaSynchronizer = $schemaSynchronizer; + $this->autoSetup = $this->configuration['auto_setup']; + } + + public function reset() + { + $this->queueEmptiedAt = null; + } + + public function getConfiguration(): array + { + return $this->configuration; + } + + public static function buildConfiguration(string $dsn, array $options = []): array + { + if (false === $components = parse_url($dsn)) { + throw new InvalidArgumentException(sprintf('The given Doctrine Messenger DSN "%s" is invalid.', $dsn)); + } + + $query = []; + if (isset($components['query'])) { + parse_str($components['query'], $query); + } + + $configuration = ['connection' => $components['host']]; + $configuration += $query + $options + static::DEFAULT_OPTIONS; + + $configuration['auto_setup'] = filter_var($configuration['auto_setup'], \FILTER_VALIDATE_BOOLEAN); + + // check for extra keys in options + $optionsExtraKeys = array_diff(array_keys($options), array_keys(static::DEFAULT_OPTIONS)); + if (0 < \count($optionsExtraKeys)) { + throw new InvalidArgumentException(sprintf('Unknown option found: [%s]. Allowed options are [%s].', implode(', ', $optionsExtraKeys), implode(', ', array_keys(static::DEFAULT_OPTIONS)))); + } + + // check for extra keys in options + $queryExtraKeys = array_diff(array_keys($query), array_keys(static::DEFAULT_OPTIONS)); + if (0 < \count($queryExtraKeys)) { + throw new InvalidArgumentException(sprintf('Unknown option found in DSN: [%s]. Allowed options are [%s].', implode(', ', $queryExtraKeys), implode(', ', array_keys(static::DEFAULT_OPTIONS)))); + } + + return $configuration; + } + + /** + * @param int $delay The delay in milliseconds + * + * @return string The inserted id + * + * @throws DBALException + */ + public function send(string $body, array $headers, int $delay = 0): string + { + $now = new \DateTime(); + $availableAt = (clone $now)->modify(sprintf('+%d seconds', $delay / 1000)); + + $queryBuilder = $this->driverConnection->createQueryBuilder() + ->insert($this->configuration['table_name']) + ->values([ + 'body' => '?', + 'headers' => '?', + 'queue_name' => '?', + 'created_at' => '?', + 'available_at' => '?', + ]); + + $this->executeStatement($queryBuilder->getSQL(), [ + $body, + json_encode($headers), + $this->configuration['queue_name'], + $now, + $availableAt, + ], [ + null, + null, + null, + Types::DATETIME_MUTABLE, + Types::DATETIME_MUTABLE, + ]); + + return $this->driverConnection->lastInsertId(); + } + + public function get(): ?array + { + if ($this->driverConnection->getDatabasePlatform() instanceof MySQLPlatform) { + try { + $this->driverConnection->delete($this->configuration['table_name'], ['delivered_at' => '9999-12-31 23:59:59']); + } catch (DriverException $e) { + // Ignore the exception + } + } + + get: + $this->driverConnection->beginTransaction(); + try { + $query = $this->createAvailableMessagesQueryBuilder() + ->orderBy('available_at', 'ASC') + ->setMaxResults(1); + + // Append pessimistic write lock to FROM clause if db platform supports it + $sql = $query->getSQL(); + if (($fromPart = $query->getQueryPart('from')) && + ($table = $fromPart[0]['table'] ?? null) && + ($alias = $fromPart[0]['alias'] ?? null) + ) { + $fromClause = sprintf('%s %s', $table, $alias); + $sql = str_replace( + sprintf('FROM %s WHERE', $fromClause), + sprintf('FROM %s WHERE', $this->driverConnection->getDatabasePlatform()->appendLockHint($fromClause, LockMode::PESSIMISTIC_WRITE)), + $sql + ); + } + + // Wrap the rownum query in a sub-query to allow writelocks without ORA-02014 error + if ($this->driverConnection->getDatabasePlatform() instanceof OraclePlatform) { + $sql = str_replace('SELECT a.* FROM', 'SELECT a.id FROM', $sql); + + $wrappedQuery = $this->driverConnection->createQueryBuilder() + ->select( + 'w.id AS "id", w.body AS "body", w.headers AS "headers", w.queue_name AS "queue_name", '. + 'w.created_at AS "created_at", w.available_at AS "available_at", '. + 'w.delivered_at AS "delivered_at"' + ) + ->from($this->configuration['table_name'], 'w') + ->where('w.id IN('.$sql.')'); + + $sql = $wrappedQuery->getSQL(); + } + + // use SELECT ... FOR UPDATE to lock table + $stmt = $this->executeQuery( + $sql.' '.$this->driverConnection->getDatabasePlatform()->getWriteLockSQL(), + $query->getParameters(), + $query->getParameterTypes() + ); + $doctrineEnvelope = $stmt instanceof Result || $stmt instanceof DriverResult ? $stmt->fetchAssociative() : $stmt->fetch(); + + if (false === $doctrineEnvelope) { + $this->driverConnection->commit(); + $this->queueEmptiedAt = microtime(true) * 1000; + + return null; + } + // Postgres can "group" notifications having the same channel and payload + // We need to be sure to empty the queue before blocking again + $this->queueEmptiedAt = null; + + $doctrineEnvelope = $this->decodeEnvelopeHeaders($doctrineEnvelope); + + $queryBuilder = $this->driverConnection->createQueryBuilder() + ->update($this->configuration['table_name']) + ->set('delivered_at', '?') + ->where('id = ?'); + $now = new \DateTime(); + $this->executeStatement($queryBuilder->getSQL(), [ + $now, + $doctrineEnvelope['id'], + ], [ + Types::DATETIME_MUTABLE, + ]); + + $this->driverConnection->commit(); + + return $doctrineEnvelope; + } catch (\Throwable $e) { + $this->driverConnection->rollBack(); + + if ($this->autoSetup && $e instanceof TableNotFoundException) { + $this->setup(); + goto get; + } + + throw $e; + } + } + + public function ack(string $id): bool + { + try { + if ($this->driverConnection->getDatabasePlatform() instanceof MySQLPlatform) { + return $this->driverConnection->update($this->configuration['table_name'], ['delivered_at' => '9999-12-31 23:59:59'], ['id' => $id]) > 0; + } + + return $this->driverConnection->delete($this->configuration['table_name'], ['id' => $id]) > 0; + } catch (DBALException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + } + + public function reject(string $id): bool + { + try { + if ($this->driverConnection->getDatabasePlatform() instanceof MySQLPlatform) { + return $this->driverConnection->update($this->configuration['table_name'], ['delivered_at' => '9999-12-31 23:59:59'], ['id' => $id]) > 0; + } + + return $this->driverConnection->delete($this->configuration['table_name'], ['id' => $id]) > 0; + } catch (DBALException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + } + + public function setup(): void + { + $configuration = $this->driverConnection->getConfiguration(); + $assetFilter = $configuration->getSchemaAssetsFilter(); + $configuration->setSchemaAssetsFilter(null); + $this->updateSchema(); + $configuration->setSchemaAssetsFilter($assetFilter); + $this->autoSetup = false; + } + + public function getMessageCount(): int + { + $queryBuilder = $this->createAvailableMessagesQueryBuilder() + ->select('COUNT(m.id) as message_count') + ->setMaxResults(1); + + $stmt = $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters(), $queryBuilder->getParameterTypes()); + + return $stmt instanceof Result || $stmt instanceof DriverResult ? $stmt->fetchOne() : $stmt->fetchColumn(); + } + + public function findAll(int $limit = null): array + { + $queryBuilder = $this->createAvailableMessagesQueryBuilder(); + if (null !== $limit) { + $queryBuilder->setMaxResults($limit); + } + + $stmt = $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters(), $queryBuilder->getParameterTypes()); + $data = $stmt instanceof Result || $stmt instanceof DriverResult ? $stmt->fetchAllAssociative() : $stmt->fetchAll(); + + return array_map(function ($doctrineEnvelope) { + return $this->decodeEnvelopeHeaders($doctrineEnvelope); + }, $data); + } + + public function find($id): ?array + { + $queryBuilder = $this->createQueryBuilder() + ->where('m.id = ? and m.queue_name = ?'); + + $stmt = $this->executeQuery($queryBuilder->getSQL(), [$id, $this->configuration['queue_name']]); + $data = $stmt instanceof Result || $stmt instanceof DriverResult ? $stmt->fetchAssociative() : $stmt->fetch(); + + return false === $data ? null : $this->decodeEnvelopeHeaders($data); + } + + /** + * @internal + */ + public function configureSchema(Schema $schema, DBALConnection $forConnection): void + { + // only update the schema for this connection + if ($forConnection !== $this->driverConnection) { + return; + } + + if ($schema->hasTable($this->configuration['table_name'])) { + return; + } + + $this->addTableToSchema($schema); + } + + /** + * @internal + */ + public function getExtraSetupSqlForTable(Table $createdTable): array + { + return []; + } + + private function createAvailableMessagesQueryBuilder(): QueryBuilder + { + $now = new \DateTime(); + $redeliverLimit = (clone $now)->modify(sprintf('-%d seconds', $this->configuration['redeliver_timeout'])); + + return $this->createQueryBuilder() + ->where('m.delivered_at is null OR m.delivered_at < ?') + ->andWhere('m.available_at <= ?') + ->andWhere('m.queue_name = ?') + ->setParameters([ + $redeliverLimit, + $now, + $this->configuration['queue_name'], + ], [ + Types::DATETIME_MUTABLE, + Types::DATETIME_MUTABLE, + ]); + } + + private function createQueryBuilder(): QueryBuilder + { + return $this->driverConnection->createQueryBuilder() + ->select('m.*') + ->from($this->configuration['table_name'], 'm'); + } + + private function executeQuery(string $sql, array $parameters = [], array $types = []) + { + try { + $stmt = $this->driverConnection->executeQuery($sql, $parameters, $types); + } catch (TableNotFoundException $e) { + if ($this->driverConnection->isTransactionActive()) { + throw $e; + } + + // create table + if ($this->autoSetup) { + $this->setup(); + } + $stmt = $this->driverConnection->executeQuery($sql, $parameters, $types); + } + + return $stmt; + } + + protected function executeStatement(string $sql, array $parameters = [], array $types = []) + { + try { + if (method_exists($this->driverConnection, 'executeStatement')) { + $stmt = $this->driverConnection->executeStatement($sql, $parameters, $types); + } else { + $stmt = $this->driverConnection->executeUpdate($sql, $parameters, $types); + } + } catch (TableNotFoundException $e) { + if ($this->driverConnection->isTransactionActive()) { + throw $e; + } + + // create table + if ($this->autoSetup) { + $this->setup(); + } + if (method_exists($this->driverConnection, 'executeStatement')) { + $stmt = $this->driverConnection->executeStatement($sql, $parameters, $types); + } else { + $stmt = $this->driverConnection->executeUpdate($sql, $parameters, $types); + } + } + + return $stmt; + } + + private function getSchema(): Schema + { + $schema = new Schema([], [], $this->createSchemaManager()->createSchemaConfig()); + $this->addTableToSchema($schema); + + return $schema; + } + + private function addTableToSchema(Schema $schema): void + { + $table = $schema->createTable($this->configuration['table_name']); + // add an internal option to mark that we created this & the non-namespaced table name + $table->addOption(self::TABLE_OPTION_NAME, $this->configuration['table_name']); + $table->addColumn('id', Types::BIGINT) + ->setAutoincrement(true) + ->setNotnull(true); + $table->addColumn('body', Types::TEXT) + ->setNotnull(true); + $table->addColumn('headers', Types::TEXT) + ->setNotnull(true); + $table->addColumn('queue_name', Types::STRING) + ->setLength(190) // MySQL 5.6 only supports 191 characters on an indexed column in utf8mb4 mode + ->setNotnull(true); + $table->addColumn('created_at', Types::DATETIME_MUTABLE) + ->setNotnull(true); + $table->addColumn('available_at', Types::DATETIME_MUTABLE) + ->setNotnull(true); + $table->addColumn('delivered_at', Types::DATETIME_MUTABLE) + ->setNotnull(false); + $table->setPrimaryKey(['id']); + $table->addIndex(['queue_name']); + $table->addIndex(['available_at']); + $table->addIndex(['delivered_at']); + } + + private function decodeEnvelopeHeaders(array $doctrineEnvelope): array + { + $doctrineEnvelope['headers'] = json_decode($doctrineEnvelope['headers'], true); + + return $doctrineEnvelope; + } + + private function updateSchema(): void + { + if (null !== $this->schemaSynchronizer) { + $this->schemaSynchronizer->updateSchema($this->getSchema(), true); + + return; + } + + $schemaManager = $this->createSchemaManager(); + $comparator = $this->createComparator($schemaManager); + $schemaDiff = $this->compareSchemas($comparator, $schemaManager->createSchema(), $this->getSchema()); + + foreach ($schemaDiff->toSaveSql($this->driverConnection->getDatabasePlatform()) as $sql) { + if (method_exists($this->driverConnection, 'executeStatement')) { + $this->driverConnection->executeStatement($sql); + } else { + $this->driverConnection->exec($sql); + } + } + } + + private function createSchemaManager(): AbstractSchemaManager + { + return method_exists($this->driverConnection, 'createSchemaManager') + ? $this->driverConnection->createSchemaManager() + : $this->driverConnection->getSchemaManager(); + } + + private function createComparator(AbstractSchemaManager $schemaManager): Comparator + { + return method_exists($schemaManager, 'createComparator') + ? $schemaManager->createComparator() + : new Comparator(); + } + + private function compareSchemas(Comparator $comparator, Schema $from, Schema $to): SchemaDiff + { + return method_exists($comparator, 'compareSchemas') + ? $comparator->compareSchemas($from, $to) + : $comparator->compare($from, $to); + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\Doctrine\Connection::class, false)) { + class_alias(Connection::class, \Symfony\Component\Messenger\Transport\Doctrine\Connection::class); +} diff --git a/plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineReceivedStamp.php b/plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineReceivedStamp.php new file mode 100644 index 0000000..7f0dee1 --- /dev/null +++ b/plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineReceivedStamp.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Doctrine\Transport; + +use Symfony\Component\Messenger\Stamp\NonSendableStampInterface; + +/** + * @author Vincent Touzet + */ +class DoctrineReceivedStamp implements NonSendableStampInterface +{ + private $id; + + public function __construct(string $id) + { + $this->id = $id; + } + + public function getId(): string + { + return $this->id; + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\Doctrine\DoctrineReceivedStamp::class, false)) { + class_alias(DoctrineReceivedStamp::class, \Symfony\Component\Messenger\Transport\Doctrine\DoctrineReceivedStamp::class); +} diff --git a/plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineReceiver.php b/plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineReceiver.php new file mode 100644 index 0000000..69cf0ed --- /dev/null +++ b/plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineReceiver.php @@ -0,0 +1,175 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Doctrine\Transport; + +use Doctrine\DBAL\Exception as DBALException; +use Doctrine\DBAL\Exception\RetryableException; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\LogicException; +use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; +use Symfony\Component\Messenger\Exception\TransportException; +use Symfony\Component\Messenger\Stamp\TransportMessageIdStamp; +use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface; +use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface; +use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; + +/** + * @author Vincent Touzet + */ +class DoctrineReceiver implements ListableReceiverInterface, MessageCountAwareInterface +{ + private const MAX_RETRIES = 3; + private $retryingSafetyCounter = 0; + private $connection; + private $serializer; + + public function __construct(Connection $connection, SerializerInterface $serializer = null) + { + $this->connection = $connection; + $this->serializer = $serializer ?? new PhpSerializer(); + } + + /** + * {@inheritdoc} + */ + public function get(): iterable + { + try { + $doctrineEnvelope = $this->connection->get(); + $this->retryingSafetyCounter = 0; // reset counter + } catch (RetryableException $exception) { + // Do nothing when RetryableException occurs less than "MAX_RETRIES" + // as it will likely be resolved on the next call to get() + // Problem with concurrent consumers and database deadlocks + if (++$this->retryingSafetyCounter >= self::MAX_RETRIES) { + $this->retryingSafetyCounter = 0; // reset counter + throw new TransportException($exception->getMessage(), 0, $exception); + } + + return []; + } catch (DBALException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + + if (null === $doctrineEnvelope) { + return []; + } + + return [$this->createEnvelopeFromData($doctrineEnvelope)]; + } + + /** + * {@inheritdoc} + */ + public function ack(Envelope $envelope): void + { + try { + $this->connection->ack($this->findDoctrineReceivedStamp($envelope)->getId()); + } catch (DBALException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + } + + /** + * {@inheritdoc} + */ + public function reject(Envelope $envelope): void + { + try { + $this->connection->reject($this->findDoctrineReceivedStamp($envelope)->getId()); + } catch (DBALException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + } + + /** + * {@inheritdoc} + */ + public function getMessageCount(): int + { + try { + return $this->connection->getMessageCount(); + } catch (DBALException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + } + + /** + * {@inheritdoc} + */ + public function all(int $limit = null): iterable + { + try { + $doctrineEnvelopes = $this->connection->findAll($limit); + } catch (DBALException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + + foreach ($doctrineEnvelopes as $doctrineEnvelope) { + yield $this->createEnvelopeFromData($doctrineEnvelope); + } + } + + /** + * {@inheritdoc} + */ + public function find($id): ?Envelope + { + try { + $doctrineEnvelope = $this->connection->find($id); + } catch (DBALException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + + if (null === $doctrineEnvelope) { + return null; + } + + return $this->createEnvelopeFromData($doctrineEnvelope); + } + + private function findDoctrineReceivedStamp(Envelope $envelope): DoctrineReceivedStamp + { + /** @var DoctrineReceivedStamp|null $doctrineReceivedStamp */ + $doctrineReceivedStamp = $envelope->last(DoctrineReceivedStamp::class); + + if (null === $doctrineReceivedStamp) { + throw new LogicException('No DoctrineReceivedStamp found on the Envelope.'); + } + + return $doctrineReceivedStamp; + } + + private function createEnvelopeFromData(array $data): Envelope + { + try { + $envelope = $this->serializer->decode([ + 'body' => $data['body'], + 'headers' => $data['headers'], + ]); + } catch (MessageDecodingFailedException $exception) { + $this->connection->reject($data['id']); + + throw $exception; + } + + return $envelope->with( + new DoctrineReceivedStamp($data['id']), + new TransportMessageIdStamp($data['id']) + ); + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\Doctrine\DoctrineReceiver::class, false)) { + class_alias(DoctrineReceiver::class, \Symfony\Component\Messenger\Transport\Doctrine\DoctrineReceiver::class); +} diff --git a/plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineSender.php b/plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineSender.php new file mode 100644 index 0000000..6e5aa60 --- /dev/null +++ b/plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineSender.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Doctrine\Transport; + +use Doctrine\DBAL\Exception as DBALException; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\TransportException; +use Symfony\Component\Messenger\Stamp\DelayStamp; +use Symfony\Component\Messenger\Stamp\TransportMessageIdStamp; +use Symfony\Component\Messenger\Transport\Sender\SenderInterface; +use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; + +/** + * @author Vincent Touzet + */ +class DoctrineSender implements SenderInterface +{ + private $connection; + private $serializer; + + public function __construct(Connection $connection, SerializerInterface $serializer = null) + { + $this->connection = $connection; + $this->serializer = $serializer ?? new PhpSerializer(); + } + + /** + * {@inheritdoc} + */ + public function send(Envelope $envelope): Envelope + { + $encodedMessage = $this->serializer->encode($envelope); + + /** @var DelayStamp|null $delayStamp */ + $delayStamp = $envelope->last(DelayStamp::class); + $delay = null !== $delayStamp ? $delayStamp->getDelay() : 0; + + try { + $id = $this->connection->send($encodedMessage['body'], $encodedMessage['headers'] ?? [], $delay); + } catch (DBALException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + + return $envelope->with(new TransportMessageIdStamp($id)); + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\Doctrine\DoctrineSender::class, false)) { + class_alias(DoctrineSender::class, \Symfony\Component\Messenger\Transport\Doctrine\DoctrineSender::class); +} diff --git a/plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineTransport.php b/plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineTransport.php new file mode 100644 index 0000000..97bc6fa --- /dev/null +++ b/plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineTransport.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Doctrine\Transport; + +use Doctrine\DBAL\Connection as DbalConnection; +use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\Schema\Table; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface; +use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Component\Messenger\Transport\SetupableTransportInterface; +use Symfony\Component\Messenger\Transport\TransportInterface; + +/** + * @author Vincent Touzet + */ +class DoctrineTransport implements TransportInterface, SetupableTransportInterface, MessageCountAwareInterface, ListableReceiverInterface +{ + private $connection; + private $serializer; + private $receiver; + private $sender; + + public function __construct(Connection $connection, SerializerInterface $serializer) + { + $this->connection = $connection; + $this->serializer = $serializer; + } + + /** + * {@inheritdoc} + */ + public function get(): iterable + { + return ($this->receiver ?? $this->getReceiver())->get(); + } + + /** + * {@inheritdoc} + */ + public function ack(Envelope $envelope): void + { + ($this->receiver ?? $this->getReceiver())->ack($envelope); + } + + /** + * {@inheritdoc} + */ + public function reject(Envelope $envelope): void + { + ($this->receiver ?? $this->getReceiver())->reject($envelope); + } + + /** + * {@inheritdoc} + */ + public function getMessageCount(): int + { + return ($this->receiver ?? $this->getReceiver())->getMessageCount(); + } + + /** + * {@inheritdoc} + */ + public function all(int $limit = null): iterable + { + return ($this->receiver ?? $this->getReceiver())->all($limit); + } + + /** + * {@inheritdoc} + */ + public function find($id): ?Envelope + { + return ($this->receiver ?? $this->getReceiver())->find($id); + } + + /** + * {@inheritdoc} + */ + public function send(Envelope $envelope): Envelope + { + return ($this->sender ?? $this->getSender())->send($envelope); + } + + /** + * {@inheritdoc} + */ + public function setup(): void + { + $this->connection->setup(); + } + + /** + * Adds the Table to the Schema if this transport uses this connection. + */ + public function configureSchema(Schema $schema, DbalConnection $forConnection): void + { + $this->connection->configureSchema($schema, $forConnection); + } + + /** + * Adds extra SQL if the given table was created by the Connection. + * + * @return string[] + */ + public function getExtraSetupSqlForTable(Table $createdTable): array + { + return $this->connection->getExtraSetupSqlForTable($createdTable); + } + + private function getReceiver(): DoctrineReceiver + { + return $this->receiver = new DoctrineReceiver($this->connection, $this->serializer); + } + + private function getSender(): DoctrineSender + { + return $this->sender = new DoctrineSender($this->connection, $this->serializer); + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\Doctrine\DoctrineTransport::class, false)) { + class_alias(DoctrineTransport::class, \Symfony\Component\Messenger\Transport\Doctrine\DoctrineTransport::class); +} diff --git a/plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineTransportFactory.php b/plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineTransportFactory.php new file mode 100644 index 0000000..f634e55 --- /dev/null +++ b/plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineTransportFactory.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Doctrine\Transport; + +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; +use Doctrine\Persistence\ConnectionRegistry; +use Symfony\Bridge\Doctrine\RegistryInterface; +use Symfony\Component\Messenger\Exception\TransportException; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Component\Messenger\Transport\TransportFactoryInterface; +use Symfony\Component\Messenger\Transport\TransportInterface; + +/** + * @author Vincent Touzet + */ +class DoctrineTransportFactory implements TransportFactoryInterface +{ + private $registry; + + public function __construct($registry) + { + if (!$registry instanceof RegistryInterface && !$registry instanceof ConnectionRegistry) { + throw new \TypeError(sprintf('Expected an instance of "%s" or "%s", but got "%s".', RegistryInterface::class, ConnectionRegistry::class, get_debug_type($registry))); + } + + $this->registry = $registry; + } + + public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface + { + $useNotify = ($options['use_notify'] ?? true); + unset($options['transport_name'], $options['use_notify']); + // Always allow PostgreSQL-specific keys, to be able to transparently fallback to the native driver when LISTEN/NOTIFY isn't available + $configuration = PostgreSqlConnection::buildConfiguration($dsn, $options); + + try { + $driverConnection = $this->registry->getConnection($configuration['connection']); + } catch (\InvalidArgumentException $e) { + throw new TransportException(sprintf('Could not find Doctrine connection from Messenger DSN "%s".', $dsn), 0, $e); + } + + if ($useNotify && $driverConnection->getDatabasePlatform() instanceof PostgreSQLPlatform) { + $connection = new PostgreSqlConnection($configuration, $driverConnection); + } else { + $connection = new Connection($configuration, $driverConnection); + } + + return new DoctrineTransport($connection, $serializer); + } + + public function supports(string $dsn, array $options): bool + { + return 0 === strpos($dsn, 'doctrine://'); + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\Doctrine\DoctrineTransportFactory::class, false)) { + class_alias(DoctrineTransportFactory::class, \Symfony\Component\Messenger\Transport\Doctrine\DoctrineTransportFactory::class); +} diff --git a/plugins/email/vendor/symfony/doctrine-messenger/Transport/PostgreSqlConnection.php b/plugins/email/vendor/symfony/doctrine-messenger/Transport/PostgreSqlConnection.php new file mode 100644 index 0000000..3691a93 --- /dev/null +++ b/plugins/email/vendor/symfony/doctrine-messenger/Transport/PostgreSqlConnection.php @@ -0,0 +1,150 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Doctrine\Transport; + +use Doctrine\DBAL\Schema\Table; + +/** + * Uses PostgreSQL LISTEN/NOTIFY to push messages to workers. + * + * @internal + * + * @author Kévin Dunglas + */ +final class PostgreSqlConnection extends Connection +{ + /** + * * use_notify: Set to false to disable the use of LISTEN/NOTIFY. Default: true + * * check_delayed_interval: The interval to check for delayed messages, in milliseconds. Set to 0 to disable checks. Default: 60000 (1 minute) + * * get_notify_timeout: The length of time to wait for a response when calling PDO::pgsqlGetNotify, in milliseconds. Default: 0. + */ + protected const DEFAULT_OPTIONS = parent::DEFAULT_OPTIONS + [ + 'use_notify' => true, + 'check_delayed_interval' => 60000, + 'get_notify_timeout' => 0, + ]; + + public function __sleep(): array + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + public function __destruct() + { + $this->unlisten(); + } + + public function reset() + { + parent::reset(); + $this->unlisten(); + } + + public function get(): ?array + { + if (null === $this->queueEmptiedAt) { + return parent::get(); + } + + // This is secure because the table name must be a valid identifier: + // https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS + $this->executeStatement(sprintf('LISTEN "%s"', $this->configuration['table_name'])); + + if (method_exists($this->driverConnection, 'getNativeConnection')) { + $wrappedConnection = $this->driverConnection->getNativeConnection(); + } else { + $wrappedConnection = $this->driverConnection; + while (method_exists($wrappedConnection, 'getWrappedConnection')) { + $wrappedConnection = $wrappedConnection->getWrappedConnection(); + } + } + + $notification = $wrappedConnection->pgsqlGetNotify(\PDO::FETCH_ASSOC, $this->configuration['get_notify_timeout']); + if ( + // no notifications, or for another table or queue + (false === $notification || $notification['message'] !== $this->configuration['table_name'] || $notification['payload'] !== $this->configuration['queue_name']) && + // delayed messages + (microtime(true) * 1000 - $this->queueEmptiedAt < $this->configuration['check_delayed_interval']) + ) { + usleep(1000); + + return null; + } + + return parent::get(); + } + + public function setup(): void + { + parent::setup(); + + $this->executeStatement(implode("\n", $this->getTriggerSql())); + } + + /** + * @return string[] + */ + public function getExtraSetupSqlForTable(Table $createdTable): array + { + if (!$createdTable->hasOption(self::TABLE_OPTION_NAME)) { + return []; + } + + if ($createdTable->getOption(self::TABLE_OPTION_NAME) !== $this->configuration['table_name']) { + return []; + } + + return $this->getTriggerSql(); + } + + private function getTriggerSql(): array + { + $functionName = $this->createTriggerFunctionName(); + + return [ + // create trigger function + sprintf(<<<'SQL' +CREATE OR REPLACE FUNCTION %1$s() RETURNS TRIGGER AS $$ + BEGIN + PERFORM pg_notify('%2$s', NEW.queue_name::text); + RETURN NEW; + END; +$$ LANGUAGE plpgsql; +SQL + , $functionName, $this->configuration['table_name']), + // register trigger + sprintf('DROP TRIGGER IF EXISTS notify_trigger ON %s;', $this->configuration['table_name']), + sprintf('CREATE TRIGGER notify_trigger AFTER INSERT OR UPDATE ON %1$s FOR EACH ROW EXECUTE PROCEDURE %2$s();', $this->configuration['table_name'], $functionName), + ]; + } + + private function createTriggerFunctionName(): string + { + $tableConfig = explode('.', $this->configuration['table_name']); + + if (1 === \count($tableConfig)) { + return sprintf('notify_%1$s', $tableConfig[0]); + } + + return sprintf('%1$s.notify_%2$s', $tableConfig[0], $tableConfig[1]); + } + + private function unlisten() + { + $this->executeStatement(sprintf('UNLISTEN "%s"', $this->configuration['table_name'])); + } +} diff --git a/plugins/email/vendor/symfony/doctrine-messenger/composer.json b/plugins/email/vendor/symfony/doctrine-messenger/composer.json new file mode 100644 index 0000000..3a9494a --- /dev/null +++ b/plugins/email/vendor/symfony/doctrine-messenger/composer.json @@ -0,0 +1,40 @@ +{ + "name": "symfony/doctrine-messenger", + "type": "symfony-messenger-bridge", + "description": "Symfony Doctrine Messenger Bridge", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "symfony/messenger": "^5.1|^6.0", + "symfony/service-contracts": "^1.1|^2|^3" + }, + "require-dev": { + "doctrine/dbal": "^2.13|^3.0", + "doctrine/persistence": "^1.3|^2|^3", + "symfony/property-access": "^4.4|^5.0|^6.0", + "symfony/serializer": "^4.4|^5.0|^6.0" + }, + "conflict": { + "doctrine/dbal": "<2.13", + "doctrine/persistence": "<1.3" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Messenger\\Bridge\\Doctrine\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/plugins/email/vendor/symfony/event-dispatcher-contracts/.gitignore b/plugins/email/vendor/symfony/event-dispatcher-contracts/.gitignore new file mode 100644 index 0000000..c49a5d8 --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher-contracts/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/plugins/email/vendor/symfony/event-dispatcher-contracts/CHANGELOG.md b/plugins/email/vendor/symfony/event-dispatcher-contracts/CHANGELOG.md new file mode 100644 index 0000000..7932e26 --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher-contracts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG +========= + +The changelog is maintained for all Symfony contracts at the following URL: +https://github.com/symfony/contracts/blob/main/CHANGELOG.md diff --git a/plugins/email/vendor/symfony/event-dispatcher-contracts/Event.php b/plugins/email/vendor/symfony/event-dispatcher-contracts/Event.php new file mode 100644 index 0000000..46dcb2b --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher-contracts/Event.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\EventDispatcher; + +use Psr\EventDispatcher\StoppableEventInterface; + +/** + * Event is the base class for classes containing event data. + * + * This class contains no event data. It is used by events that do not pass + * state information to an event handler when an event is raised. + * + * You can call the method stopPropagation() to abort the execution of + * further listeners in your event listener. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + * @author Nicolas Grekas + */ +class Event implements StoppableEventInterface +{ + private $propagationStopped = false; + + /** + * {@inheritdoc} + */ + public function isPropagationStopped(): bool + { + return $this->propagationStopped; + } + + /** + * Stops the propagation of the event to further event listeners. + * + * If multiple event listeners are connected to the same event, no + * further event listener will be triggered once any trigger calls + * stopPropagation(). + */ + public function stopPropagation(): void + { + $this->propagationStopped = true; + } +} diff --git a/plugins/email/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php b/plugins/email/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php new file mode 100644 index 0000000..351dc51 --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\EventDispatcher; + +use Psr\EventDispatcher\EventDispatcherInterface as PsrEventDispatcherInterface; + +/** + * Allows providing hooks on domain-specific lifecycles by dispatching events. + */ +interface EventDispatcherInterface extends PsrEventDispatcherInterface +{ + /** + * Dispatches an event to all registered listeners. + * + * @param object $event The event to pass to the event handlers/listeners + * @param string|null $eventName The name of the event to dispatch. If not supplied, + * the class of $event should be used instead. + * + * @return object The passed $event MUST be returned + */ + public function dispatch(object $event, string $eventName = null): object; +} diff --git a/plugins/email/vendor/symfony/event-dispatcher-contracts/LICENSE b/plugins/email/vendor/symfony/event-dispatcher-contracts/LICENSE new file mode 100644 index 0000000..74cdc2d --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/plugins/email/vendor/symfony/event-dispatcher-contracts/README.md b/plugins/email/vendor/symfony/event-dispatcher-contracts/README.md new file mode 100644 index 0000000..b1ab4c0 --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher-contracts/README.md @@ -0,0 +1,9 @@ +Symfony EventDispatcher Contracts +================================= + +A set of abstractions extracted out of the Symfony components. + +Can be used to build on semantics that the Symfony components proved useful - and +that already have battle tested implementations. + +See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/plugins/email/vendor/symfony/event-dispatcher-contracts/composer.json b/plugins/email/vendor/symfony/event-dispatcher-contracts/composer.json new file mode 100644 index 0000000..660df81 --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher-contracts/composer.json @@ -0,0 +1,38 @@ +{ + "name": "symfony/event-dispatcher-contracts", + "type": "library", + "description": "Generic abstractions related to dispatching event", + "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "psr/event-dispatcher": "^1" + }, + "suggest": { + "symfony/event-dispatcher-implementation": "" + }, + "autoload": { + "psr-4": { "Symfony\\Contracts\\EventDispatcher\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + } +} diff --git a/plugins/email/vendor/symfony/event-dispatcher/Attribute/AsEventListener.php b/plugins/email/vendor/symfony/event-dispatcher/Attribute/AsEventListener.php new file mode 100644 index 0000000..bb931b8 --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher/Attribute/AsEventListener.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Attribute; + +/** + * Service tag to autoconfigure event listeners. + * + * @author Alexander M. Turek + */ +#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] +class AsEventListener +{ + public function __construct( + public ?string $event = null, + public ?string $method = null, + public int $priority = 0, + public ?string $dispatcher = null, + ) { + } +} diff --git a/plugins/email/vendor/symfony/event-dispatcher/CHANGELOG.md b/plugins/email/vendor/symfony/event-dispatcher/CHANGELOG.md new file mode 100644 index 0000000..0f98598 --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher/CHANGELOG.md @@ -0,0 +1,91 @@ +CHANGELOG +========= + +5.4 +--- + + * Allow `#[AsEventListener]` attribute on methods + +5.3 +--- + + * Add `#[AsEventListener]` attribute for declaring listeners on PHP 8 + +5.1.0 +----- + + * The `LegacyEventDispatcherProxy` class has been deprecated. + * Added an optional `dispatcher` attribute to the listener and subscriber tags in `RegisterListenerPass`. + +5.0.0 +----- + + * The signature of the `EventDispatcherInterface::dispatch()` method has been changed to `dispatch($event, string $eventName = null): object`. + * The `Event` class has been removed in favor of `Symfony\Contracts\EventDispatcher\Event`. + * The `TraceableEventDispatcherInterface` has been removed. + * The `WrappedListener` class is now final. + +4.4.0 +----- + + * `AddEventAliasesPass` has been added, allowing applications and bundles to extend the event alias mapping used by `RegisterListenersPass`. + * Made the `event` attribute of the `kernel.event_listener` tag optional for FQCN events. + +4.3.0 +----- + + * The signature of the `EventDispatcherInterface::dispatch()` method should be updated to `dispatch($event, string $eventName = null)`, not doing so is deprecated + * deprecated the `Event` class, use `Symfony\Contracts\EventDispatcher\Event` instead + +4.1.0 +----- + + * added support for invokable event listeners tagged with `kernel.event_listener` by default + * The `TraceableEventDispatcher::getOrphanedEvents()` method has been added. + * The `TraceableEventDispatcherInterface` has been deprecated. + +4.0.0 +----- + + * removed the `ContainerAwareEventDispatcher` class + * added the `reset()` method to the `TraceableEventDispatcherInterface` + +3.4.0 +----- + + * Implementing `TraceableEventDispatcherInterface` without the `reset()` method has been deprecated. + +3.3.0 +----- + + * The ContainerAwareEventDispatcher class has been deprecated. Use EventDispatcher with closure factories instead. + +3.0.0 +----- + + * The method `getListenerPriority($eventName, $listener)` has been added to the + `EventDispatcherInterface`. + * The methods `Event::setDispatcher()`, `Event::getDispatcher()`, `Event::setName()` + and `Event::getName()` have been removed. + The event dispatcher and the event name are passed to the listener call. + +2.5.0 +----- + + * added Debug\TraceableEventDispatcher (originally in HttpKernel) + * changed Debug\TraceableEventDispatcherInterface to extend EventDispatcherInterface + * added RegisterListenersPass (originally in HttpKernel) + +2.1.0 +----- + + * added TraceableEventDispatcherInterface + * added ContainerAwareEventDispatcher + * added a reference to the EventDispatcher on the Event + * added a reference to the Event name on the event + * added fluid interface to the dispatch() method which now returns the Event + object + * added GenericEvent event class + * added the possibility for subscribers to subscribe several times for the + same event + * added ImmutableEventDispatcher diff --git a/plugins/email/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php b/plugins/email/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php new file mode 100644 index 0000000..acfbf61 --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php @@ -0,0 +1,366 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Debug; + +use Psr\EventDispatcher\StoppableEventInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Stopwatch\Stopwatch; +use Symfony\Contracts\Service\ResetInterface; + +/** + * Collects some data about event listeners. + * + * This event dispatcher delegates the dispatching to another one. + * + * @author Fabien Potencier + */ +class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterface +{ + protected $logger; + protected $stopwatch; + + /** + * @var \SplObjectStorage + */ + private $callStack; + private $dispatcher; + private $wrappedListeners; + private $orphanedEvents; + private $requestStack; + private $currentRequestHash = ''; + + public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null, RequestStack $requestStack = null) + { + $this->dispatcher = $dispatcher; + $this->stopwatch = $stopwatch; + $this->logger = $logger; + $this->wrappedListeners = []; + $this->orphanedEvents = []; + $this->requestStack = $requestStack; + } + + /** + * {@inheritdoc} + */ + public function addListener(string $eventName, $listener, int $priority = 0) + { + $this->dispatcher->addListener($eventName, $listener, $priority); + } + + /** + * {@inheritdoc} + */ + public function addSubscriber(EventSubscriberInterface $subscriber) + { + $this->dispatcher->addSubscriber($subscriber); + } + + /** + * {@inheritdoc} + */ + public function removeListener(string $eventName, $listener) + { + if (isset($this->wrappedListeners[$eventName])) { + foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) { + if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) { + $listener = $wrappedListener; + unset($this->wrappedListeners[$eventName][$index]); + break; + } + } + } + + return $this->dispatcher->removeListener($eventName, $listener); + } + + /** + * {@inheritdoc} + */ + public function removeSubscriber(EventSubscriberInterface $subscriber) + { + return $this->dispatcher->removeSubscriber($subscriber); + } + + /** + * {@inheritdoc} + */ + public function getListeners(string $eventName = null) + { + return $this->dispatcher->getListeners($eventName); + } + + /** + * {@inheritdoc} + */ + public function getListenerPriority(string $eventName, $listener) + { + // we might have wrapped listeners for the event (if called while dispatching) + // in that case get the priority by wrapper + if (isset($this->wrappedListeners[$eventName])) { + foreach ($this->wrappedListeners[$eventName] as $wrappedListener) { + if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) { + return $this->dispatcher->getListenerPriority($eventName, $wrappedListener); + } + } + } + + return $this->dispatcher->getListenerPriority($eventName, $listener); + } + + /** + * {@inheritdoc} + */ + public function hasListeners(string $eventName = null) + { + return $this->dispatcher->hasListeners($eventName); + } + + /** + * {@inheritdoc} + */ + public function dispatch(object $event, string $eventName = null): object + { + $eventName = $eventName ?? \get_class($event); + + if (null === $this->callStack) { + $this->callStack = new \SplObjectStorage(); + } + + $currentRequestHash = $this->currentRequestHash = $this->requestStack && ($request = $this->requestStack->getCurrentRequest()) ? spl_object_hash($request) : ''; + + if (null !== $this->logger && $event instanceof StoppableEventInterface && $event->isPropagationStopped()) { + $this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName)); + } + + $this->preProcess($eventName); + try { + $this->beforeDispatch($eventName, $event); + try { + $e = $this->stopwatch->start($eventName, 'section'); + try { + $this->dispatcher->dispatch($event, $eventName); + } finally { + if ($e->isStarted()) { + $e->stop(); + } + } + } finally { + $this->afterDispatch($eventName, $event); + } + } finally { + $this->currentRequestHash = $currentRequestHash; + $this->postProcess($eventName); + } + + return $event; + } + + /** + * @return array + */ + public function getCalledListeners(Request $request = null) + { + if (null === $this->callStack) { + return []; + } + + $hash = $request ? spl_object_hash($request) : null; + $called = []; + foreach ($this->callStack as $listener) { + [$eventName, $requestHash] = $this->callStack->getInfo(); + if (null === $hash || $hash === $requestHash) { + $called[] = $listener->getInfo($eventName); + } + } + + return $called; + } + + /** + * @return array + */ + public function getNotCalledListeners(Request $request = null) + { + try { + $allListeners = $this->getListeners(); + } catch (\Exception $e) { + if (null !== $this->logger) { + $this->logger->info('An exception was thrown while getting the uncalled listeners.', ['exception' => $e]); + } + + // unable to retrieve the uncalled listeners + return []; + } + + $hash = $request ? spl_object_hash($request) : null; + $calledListeners = []; + + if (null !== $this->callStack) { + foreach ($this->callStack as $calledListener) { + [, $requestHash] = $this->callStack->getInfo(); + + if (null === $hash || $hash === $requestHash) { + $calledListeners[] = $calledListener->getWrappedListener(); + } + } + } + + $notCalled = []; + foreach ($allListeners as $eventName => $listeners) { + foreach ($listeners as $listener) { + if (!\in_array($listener, $calledListeners, true)) { + if (!$listener instanceof WrappedListener) { + $listener = new WrappedListener($listener, null, $this->stopwatch, $this); + } + $notCalled[] = $listener->getInfo($eventName); + } + } + } + + uasort($notCalled, [$this, 'sortNotCalledListeners']); + + return $notCalled; + } + + public function getOrphanedEvents(Request $request = null): array + { + if ($request) { + return $this->orphanedEvents[spl_object_hash($request)] ?? []; + } + + if (!$this->orphanedEvents) { + return []; + } + + return array_merge(...array_values($this->orphanedEvents)); + } + + public function reset() + { + $this->callStack = null; + $this->orphanedEvents = []; + $this->currentRequestHash = ''; + } + + /** + * Proxies all method calls to the original event dispatcher. + * + * @param string $method The method name + * @param array $arguments The method arguments + * + * @return mixed + */ + public function __call(string $method, array $arguments) + { + return $this->dispatcher->{$method}(...$arguments); + } + + /** + * Called before dispatching the event. + */ + protected function beforeDispatch(string $eventName, object $event) + { + } + + /** + * Called after dispatching the event. + */ + protected function afterDispatch(string $eventName, object $event) + { + } + + private function preProcess(string $eventName): void + { + if (!$this->dispatcher->hasListeners($eventName)) { + $this->orphanedEvents[$this->currentRequestHash][] = $eventName; + + return; + } + + foreach ($this->dispatcher->getListeners($eventName) as $listener) { + $priority = $this->getListenerPriority($eventName, $listener); + $wrappedListener = new WrappedListener($listener instanceof WrappedListener ? $listener->getWrappedListener() : $listener, null, $this->stopwatch, $this); + $this->wrappedListeners[$eventName][] = $wrappedListener; + $this->dispatcher->removeListener($eventName, $listener); + $this->dispatcher->addListener($eventName, $wrappedListener, $priority); + $this->callStack->attach($wrappedListener, [$eventName, $this->currentRequestHash]); + } + } + + private function postProcess(string $eventName): void + { + unset($this->wrappedListeners[$eventName]); + $skipped = false; + foreach ($this->dispatcher->getListeners($eventName) as $listener) { + if (!$listener instanceof WrappedListener) { // #12845: a new listener was added during dispatch. + continue; + } + // Unwrap listener + $priority = $this->getListenerPriority($eventName, $listener); + $this->dispatcher->removeListener($eventName, $listener); + $this->dispatcher->addListener($eventName, $listener->getWrappedListener(), $priority); + + if (null !== $this->logger) { + $context = ['event' => $eventName, 'listener' => $listener->getPretty()]; + } + + if ($listener->wasCalled()) { + if (null !== $this->logger) { + $this->logger->debug('Notified event "{event}" to listener "{listener}".', $context); + } + } else { + $this->callStack->detach($listener); + } + + if (null !== $this->logger && $skipped) { + $this->logger->debug('Listener "{listener}" was not called for event "{event}".', $context); + } + + if ($listener->stoppedPropagation()) { + if (null !== $this->logger) { + $this->logger->debug('Listener "{listener}" stopped propagation of the event "{event}".', $context); + } + + $skipped = true; + } + } + } + + private function sortNotCalledListeners(array $a, array $b) + { + if (0 !== $cmp = strcmp($a['event'], $b['event'])) { + return $cmp; + } + + if (\is_int($a['priority']) && !\is_int($b['priority'])) { + return 1; + } + + if (!\is_int($a['priority']) && \is_int($b['priority'])) { + return -1; + } + + if ($a['priority'] === $b['priority']) { + return 0; + } + + if ($a['priority'] > $b['priority']) { + return -1; + } + + return 1; + } +} diff --git a/plugins/email/vendor/symfony/event-dispatcher/Debug/WrappedListener.php b/plugins/email/vendor/symfony/event-dispatcher/Debug/WrappedListener.php new file mode 100644 index 0000000..3916716 --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher/Debug/WrappedListener.php @@ -0,0 +1,127 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Debug; + +use Psr\EventDispatcher\StoppableEventInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Stopwatch\Stopwatch; +use Symfony\Component\VarDumper\Caster\ClassStub; + +/** + * @author Fabien Potencier + */ +final class WrappedListener +{ + private $listener; + private $optimizedListener; + private $name; + private $called; + private $stoppedPropagation; + private $stopwatch; + private $dispatcher; + private $pretty; + private $stub; + private $priority; + private static $hasClassStub; + + public function __construct($listener, ?string $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null) + { + $this->listener = $listener; + $this->optimizedListener = $listener instanceof \Closure ? $listener : (\is_callable($listener) ? \Closure::fromCallable($listener) : null); + $this->stopwatch = $stopwatch; + $this->dispatcher = $dispatcher; + $this->called = false; + $this->stoppedPropagation = false; + + if (\is_array($listener)) { + $this->name = \is_object($listener[0]) ? get_debug_type($listener[0]) : $listener[0]; + $this->pretty = $this->name.'::'.$listener[1]; + } elseif ($listener instanceof \Closure) { + $r = new \ReflectionFunction($listener); + if (str_contains($r->name, '{closure}')) { + $this->pretty = $this->name = 'closure'; + } elseif ($class = $r->getClosureScopeClass()) { + $this->name = $class->name; + $this->pretty = $this->name.'::'.$r->name; + } else { + $this->pretty = $this->name = $r->name; + } + } elseif (\is_string($listener)) { + $this->pretty = $this->name = $listener; + } else { + $this->name = get_debug_type($listener); + $this->pretty = $this->name.'::__invoke'; + } + + if (null !== $name) { + $this->name = $name; + } + + if (null === self::$hasClassStub) { + self::$hasClassStub = class_exists(ClassStub::class); + } + } + + public function getWrappedListener() + { + return $this->listener; + } + + public function wasCalled(): bool + { + return $this->called; + } + + public function stoppedPropagation(): bool + { + return $this->stoppedPropagation; + } + + public function getPretty(): string + { + return $this->pretty; + } + + public function getInfo(string $eventName): array + { + if (null === $this->stub) { + $this->stub = self::$hasClassStub ? new ClassStub($this->pretty.'()', $this->listener) : $this->pretty.'()'; + } + + return [ + 'event' => $eventName, + 'priority' => null !== $this->priority ? $this->priority : (null !== $this->dispatcher ? $this->dispatcher->getListenerPriority($eventName, $this->listener) : null), + 'pretty' => $this->pretty, + 'stub' => $this->stub, + ]; + } + + public function __invoke(object $event, string $eventName, EventDispatcherInterface $dispatcher): void + { + $dispatcher = $this->dispatcher ?: $dispatcher; + + $this->called = true; + $this->priority = $dispatcher->getListenerPriority($eventName, $this->listener); + + $e = $this->stopwatch->start($this->name, 'event_listener'); + + ($this->optimizedListener ?? $this->listener)($event, $eventName, $dispatcher); + + if ($e->isStarted()) { + $e->stop(); + } + + if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) { + $this->stoppedPropagation = true; + } + } +} diff --git a/plugins/email/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php b/plugins/email/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php new file mode 100644 index 0000000..6e7292b --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\DependencyInjection; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * This pass allows bundles to extend the list of event aliases. + * + * @author Alexander M. Turek + */ +class AddEventAliasesPass implements CompilerPassInterface +{ + private $eventAliases; + private $eventAliasesParameter; + + public function __construct(array $eventAliases, string $eventAliasesParameter = 'event_dispatcher.event_aliases') + { + if (1 < \func_num_args()) { + trigger_deprecation('symfony/event-dispatcher', '5.3', 'Configuring "%s" is deprecated.', __CLASS__); + } + + $this->eventAliases = $eventAliases; + $this->eventAliasesParameter = $eventAliasesParameter; + } + + public function process(ContainerBuilder $container): void + { + $eventAliases = $container->hasParameter($this->eventAliasesParameter) ? $container->getParameter($this->eventAliasesParameter) : []; + + $container->setParameter( + $this->eventAliasesParameter, + array_merge($eventAliases, $this->eventAliases) + ); + } +} diff --git a/plugins/email/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php b/plugins/email/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php new file mode 100644 index 0000000..8eabe7d --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php @@ -0,0 +1,238 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\DependencyInjection; + +use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Contracts\EventDispatcher\Event; + +/** + * Compiler pass to register tagged services for an event dispatcher. + */ +class RegisterListenersPass implements CompilerPassInterface +{ + protected $dispatcherService; + protected $listenerTag; + protected $subscriberTag; + protected $eventAliasesParameter; + + private $hotPathEvents = []; + private $hotPathTagName = 'container.hot_path'; + private $noPreloadEvents = []; + private $noPreloadTagName = 'container.no_preload'; + + public function __construct(string $dispatcherService = 'event_dispatcher', string $listenerTag = 'kernel.event_listener', string $subscriberTag = 'kernel.event_subscriber', string $eventAliasesParameter = 'event_dispatcher.event_aliases') + { + if (0 < \func_num_args()) { + trigger_deprecation('symfony/event-dispatcher', '5.3', 'Configuring "%s" is deprecated.', __CLASS__); + } + + $this->dispatcherService = $dispatcherService; + $this->listenerTag = $listenerTag; + $this->subscriberTag = $subscriberTag; + $this->eventAliasesParameter = $eventAliasesParameter; + } + + /** + * @return $this + */ + public function setHotPathEvents(array $hotPathEvents) + { + $this->hotPathEvents = array_flip($hotPathEvents); + + if (1 < \func_num_args()) { + trigger_deprecation('symfony/event-dispatcher', '5.4', 'Configuring "$tagName" in "%s" is deprecated.', __METHOD__); + $this->hotPathTagName = func_get_arg(1); + } + + return $this; + } + + /** + * @return $this + */ + public function setNoPreloadEvents(array $noPreloadEvents): self + { + $this->noPreloadEvents = array_flip($noPreloadEvents); + + if (1 < \func_num_args()) { + trigger_deprecation('symfony/event-dispatcher', '5.4', 'Configuring "$tagName" in "%s" is deprecated.', __METHOD__); + $this->noPreloadTagName = func_get_arg(1); + } + + return $this; + } + + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition($this->dispatcherService) && !$container->hasAlias($this->dispatcherService)) { + return; + } + + $aliases = []; + + if ($container->hasParameter($this->eventAliasesParameter)) { + $aliases = $container->getParameter($this->eventAliasesParameter); + } + + $globalDispatcherDefinition = $container->findDefinition($this->dispatcherService); + + foreach ($container->findTaggedServiceIds($this->listenerTag, true) as $id => $events) { + $noPreload = 0; + + foreach ($events as $event) { + $priority = $event['priority'] ?? 0; + + if (!isset($event['event'])) { + if ($container->getDefinition($id)->hasTag($this->subscriberTag)) { + continue; + } + + $event['method'] = $event['method'] ?? '__invoke'; + $event['event'] = $this->getEventFromTypeDeclaration($container, $id, $event['method']); + } + + $event['event'] = $aliases[$event['event']] ?? $event['event']; + + if (!isset($event['method'])) { + $event['method'] = 'on'.preg_replace_callback([ + '/(?<=\b|_)[a-z]/i', + '/[^a-z0-9]/i', + ], function ($matches) { return strtoupper($matches[0]); }, $event['event']); + $event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']); + + if (null !== ($class = $container->getDefinition($id)->getClass()) && ($r = $container->getReflectionClass($class, false)) && !$r->hasMethod($event['method']) && $r->hasMethod('__invoke')) { + $event['method'] = '__invoke'; + } + } + + $dispatcherDefinition = $globalDispatcherDefinition; + if (isset($event['dispatcher'])) { + $dispatcherDefinition = $container->getDefinition($event['dispatcher']); + } + + $dispatcherDefinition->addMethodCall('addListener', [$event['event'], [new ServiceClosureArgument(new Reference($id)), $event['method']], $priority]); + + if (isset($this->hotPathEvents[$event['event']])) { + $container->getDefinition($id)->addTag($this->hotPathTagName); + } elseif (isset($this->noPreloadEvents[$event['event']])) { + ++$noPreload; + } + } + + if ($noPreload && \count($events) === $noPreload) { + $container->getDefinition($id)->addTag($this->noPreloadTagName); + } + } + + $extractingDispatcher = new ExtractingEventDispatcher(); + + foreach ($container->findTaggedServiceIds($this->subscriberTag, true) as $id => $tags) { + $def = $container->getDefinition($id); + + // We must assume that the class value has been correctly filled, even if the service is created by a factory + $class = $def->getClass(); + + if (!$r = $container->getReflectionClass($class)) { + throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + } + if (!$r->isSubclassOf(EventSubscriberInterface::class)) { + throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, EventSubscriberInterface::class)); + } + $class = $r->name; + + $dispatcherDefinitions = []; + foreach ($tags as $attributes) { + if (!isset($attributes['dispatcher']) || isset($dispatcherDefinitions[$attributes['dispatcher']])) { + continue; + } + + $dispatcherDefinitions[$attributes['dispatcher']] = $container->getDefinition($attributes['dispatcher']); + } + + if (!$dispatcherDefinitions) { + $dispatcherDefinitions = [$globalDispatcherDefinition]; + } + + $noPreload = 0; + ExtractingEventDispatcher::$aliases = $aliases; + ExtractingEventDispatcher::$subscriber = $class; + $extractingDispatcher->addSubscriber($extractingDispatcher); + foreach ($extractingDispatcher->listeners as $args) { + $args[1] = [new ServiceClosureArgument(new Reference($id)), $args[1]]; + foreach ($dispatcherDefinitions as $dispatcherDefinition) { + $dispatcherDefinition->addMethodCall('addListener', $args); + } + + if (isset($this->hotPathEvents[$args[0]])) { + $container->getDefinition($id)->addTag($this->hotPathTagName); + } elseif (isset($this->noPreloadEvents[$args[0]])) { + ++$noPreload; + } + } + if ($noPreload && \count($extractingDispatcher->listeners) === $noPreload) { + $container->getDefinition($id)->addTag($this->noPreloadTagName); + } + $extractingDispatcher->listeners = []; + ExtractingEventDispatcher::$aliases = []; + } + } + + private function getEventFromTypeDeclaration(ContainerBuilder $container, string $id, string $method): string + { + if ( + null === ($class = $container->getDefinition($id)->getClass()) + || !($r = $container->getReflectionClass($class, false)) + || !$r->hasMethod($method) + || 1 > ($m = $r->getMethod($method))->getNumberOfParameters() + || !($type = $m->getParameters()[0]->getType()) instanceof \ReflectionNamedType + || $type->isBuiltin() + || Event::class === ($name = $type->getName()) + ) { + throw new InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag)); + } + + return $name; + } +} + +/** + * @internal + */ +class ExtractingEventDispatcher extends EventDispatcher implements EventSubscriberInterface +{ + public $listeners = []; + + public static $aliases = []; + public static $subscriber; + + public function addListener(string $eventName, $listener, int $priority = 0) + { + $this->listeners[] = [$eventName, $listener[1], $priority]; + } + + public static function getSubscribedEvents(): array + { + $events = []; + + foreach ([self::$subscriber, 'getSubscribedEvents']() as $eventName => $params) { + $events[self::$aliases[$eventName] ?? $eventName] = $params; + } + + return $events; + } +} diff --git a/plugins/email/vendor/symfony/event-dispatcher/EventDispatcher.php b/plugins/email/vendor/symfony/event-dispatcher/EventDispatcher.php new file mode 100644 index 0000000..8fe8fb5 --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher/EventDispatcher.php @@ -0,0 +1,280 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +use Psr\EventDispatcher\StoppableEventInterface; +use Symfony\Component\EventDispatcher\Debug\WrappedListener; + +/** + * The EventDispatcherInterface is the central point of Symfony's event listener system. + * + * Listeners are registered on the manager and events are dispatched through the + * manager. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + * @author Fabien Potencier + * @author Jordi Boggiano + * @author Jordan Alliot + * @author Nicolas Grekas + */ +class EventDispatcher implements EventDispatcherInterface +{ + private $listeners = []; + private $sorted = []; + private $optimized; + + public function __construct() + { + if (__CLASS__ === static::class) { + $this->optimized = []; + } + } + + /** + * {@inheritdoc} + */ + public function dispatch(object $event, string $eventName = null): object + { + $eventName = $eventName ?? \get_class($event); + + if (null !== $this->optimized) { + $listeners = $this->optimized[$eventName] ?? (empty($this->listeners[$eventName]) ? [] : $this->optimizeListeners($eventName)); + } else { + $listeners = $this->getListeners($eventName); + } + + if ($listeners) { + $this->callListeners($listeners, $eventName, $event); + } + + return $event; + } + + /** + * {@inheritdoc} + */ + public function getListeners(string $eventName = null) + { + if (null !== $eventName) { + if (empty($this->listeners[$eventName])) { + return []; + } + + if (!isset($this->sorted[$eventName])) { + $this->sortListeners($eventName); + } + + return $this->sorted[$eventName]; + } + + foreach ($this->listeners as $eventName => $eventListeners) { + if (!isset($this->sorted[$eventName])) { + $this->sortListeners($eventName); + } + } + + return array_filter($this->sorted); + } + + /** + * {@inheritdoc} + */ + public function getListenerPriority(string $eventName, $listener) + { + if (empty($this->listeners[$eventName])) { + return null; + } + + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { + $listener[0] = $listener[0](); + $listener[1] = $listener[1] ?? '__invoke'; + } + + foreach ($this->listeners[$eventName] as $priority => &$listeners) { + foreach ($listeners as &$v) { + if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) { + $v[0] = $v[0](); + $v[1] = $v[1] ?? '__invoke'; + } + if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) { + return $priority; + } + } + } + + return null; + } + + /** + * {@inheritdoc} + */ + public function hasListeners(string $eventName = null) + { + if (null !== $eventName) { + return !empty($this->listeners[$eventName]); + } + + foreach ($this->listeners as $eventListeners) { + if ($eventListeners) { + return true; + } + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function addListener(string $eventName, $listener, int $priority = 0) + { + $this->listeners[$eventName][$priority][] = $listener; + unset($this->sorted[$eventName], $this->optimized[$eventName]); + } + + /** + * {@inheritdoc} + */ + public function removeListener(string $eventName, $listener) + { + if (empty($this->listeners[$eventName])) { + return; + } + + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { + $listener[0] = $listener[0](); + $listener[1] = $listener[1] ?? '__invoke'; + } + + foreach ($this->listeners[$eventName] as $priority => &$listeners) { + foreach ($listeners as $k => &$v) { + if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) { + $v[0] = $v[0](); + $v[1] = $v[1] ?? '__invoke'; + } + if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) { + unset($listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]); + } + } + + if (!$listeners) { + unset($this->listeners[$eventName][$priority]); + } + } + } + + /** + * {@inheritdoc} + */ + public function addSubscriber(EventSubscriberInterface $subscriber) + { + foreach ($subscriber->getSubscribedEvents() as $eventName => $params) { + if (\is_string($params)) { + $this->addListener($eventName, [$subscriber, $params]); + } elseif (\is_string($params[0])) { + $this->addListener($eventName, [$subscriber, $params[0]], $params[1] ?? 0); + } else { + foreach ($params as $listener) { + $this->addListener($eventName, [$subscriber, $listener[0]], $listener[1] ?? 0); + } + } + } + } + + /** + * {@inheritdoc} + */ + public function removeSubscriber(EventSubscriberInterface $subscriber) + { + foreach ($subscriber->getSubscribedEvents() as $eventName => $params) { + if (\is_array($params) && \is_array($params[0])) { + foreach ($params as $listener) { + $this->removeListener($eventName, [$subscriber, $listener[0]]); + } + } else { + $this->removeListener($eventName, [$subscriber, \is_string($params) ? $params : $params[0]]); + } + } + } + + /** + * Triggers the listeners of an event. + * + * This method can be overridden to add functionality that is executed + * for each listener. + * + * @param callable[] $listeners The event listeners + * @param string $eventName The name of the event to dispatch + * @param object $event The event object to pass to the event handlers/listeners + */ + protected function callListeners(iterable $listeners, string $eventName, object $event) + { + $stoppable = $event instanceof StoppableEventInterface; + + foreach ($listeners as $listener) { + if ($stoppable && $event->isPropagationStopped()) { + break; + } + $listener($event, $eventName, $this); + } + } + + /** + * Sorts the internal list of listeners for the given event by priority. + */ + private function sortListeners(string $eventName) + { + krsort($this->listeners[$eventName]); + $this->sorted[$eventName] = []; + + foreach ($this->listeners[$eventName] as &$listeners) { + foreach ($listeners as $k => &$listener) { + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { + $listener[0] = $listener[0](); + $listener[1] = $listener[1] ?? '__invoke'; + } + $this->sorted[$eventName][] = $listener; + } + } + } + + /** + * Optimizes the internal list of listeners for the given event by priority. + */ + private function optimizeListeners(string $eventName): array + { + krsort($this->listeners[$eventName]); + $this->optimized[$eventName] = []; + + foreach ($this->listeners[$eventName] as &$listeners) { + foreach ($listeners as &$listener) { + $closure = &$this->optimized[$eventName][]; + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { + $closure = static function (...$args) use (&$listener, &$closure) { + if ($listener[0] instanceof \Closure) { + $listener[0] = $listener[0](); + $listener[1] = $listener[1] ?? '__invoke'; + } + ($closure = \Closure::fromCallable($listener))(...$args); + }; + } else { + $closure = $listener instanceof \Closure || $listener instanceof WrappedListener ? $listener : \Closure::fromCallable($listener); + } + } + } + + return $this->optimized[$eventName]; + } +} diff --git a/plugins/email/vendor/symfony/event-dispatcher/EventDispatcherInterface.php b/plugins/email/vendor/symfony/event-dispatcher/EventDispatcherInterface.php new file mode 100644 index 0000000..cc324e1 --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher/EventDispatcherInterface.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface; + +/** + * The EventDispatcherInterface is the central point of Symfony's event listener system. + * Listeners are registered on the manager and events are dispatched through the + * manager. + * + * @author Bernhard Schussek + */ +interface EventDispatcherInterface extends ContractsEventDispatcherInterface +{ + /** + * Adds an event listener that listens on the specified events. + * + * @param int $priority The higher this value, the earlier an event + * listener will be triggered in the chain (defaults to 0) + */ + public function addListener(string $eventName, callable $listener, int $priority = 0); + + /** + * Adds an event subscriber. + * + * The subscriber is asked for all the events it is + * interested in and added as a listener for these events. + */ + public function addSubscriber(EventSubscriberInterface $subscriber); + + /** + * Removes an event listener from the specified events. + */ + public function removeListener(string $eventName, callable $listener); + + public function removeSubscriber(EventSubscriberInterface $subscriber); + + /** + * Gets the listeners of a specific event or all listeners sorted by descending priority. + * + * @return array + */ + public function getListeners(string $eventName = null); + + /** + * Gets the listener priority for a specific event. + * + * Returns null if the event or the listener does not exist. + * + * @return int|null + */ + public function getListenerPriority(string $eventName, callable $listener); + + /** + * Checks whether an event has any registered listeners. + * + * @return bool + */ + public function hasListeners(string $eventName = null); +} diff --git a/plugins/email/vendor/symfony/event-dispatcher/EventSubscriberInterface.php b/plugins/email/vendor/symfony/event-dispatcher/EventSubscriberInterface.php new file mode 100644 index 0000000..2085e42 --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher/EventSubscriberInterface.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * An EventSubscriber knows itself what events it is interested in. + * If an EventSubscriber is added to an EventDispatcherInterface, the manager invokes + * {@link getSubscribedEvents} and registers the subscriber as a listener for all + * returned events. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + */ +interface EventSubscriberInterface +{ + /** + * Returns an array of event names this subscriber wants to listen to. + * + * The array keys are event names and the value can be: + * + * * The method name to call (priority defaults to 0) + * * An array composed of the method name to call and the priority + * * An array of arrays composed of the method names to call and respective + * priorities, or 0 if unset + * + * For instance: + * + * * ['eventName' => 'methodName'] + * * ['eventName' => ['methodName', $priority]] + * * ['eventName' => [['methodName1', $priority], ['methodName2']]] + * + * The code must not depend on runtime state as it will only be called at compile time. + * All logic depending on runtime state must be put into the individual methods handling the events. + * + * @return array> + */ + public static function getSubscribedEvents(); +} diff --git a/plugins/email/vendor/symfony/event-dispatcher/GenericEvent.php b/plugins/email/vendor/symfony/event-dispatcher/GenericEvent.php new file mode 100644 index 0000000..b32a301 --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher/GenericEvent.php @@ -0,0 +1,182 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +use Symfony\Contracts\EventDispatcher\Event; + +/** + * Event encapsulation class. + * + * Encapsulates events thus decoupling the observer from the subject they encapsulate. + * + * @author Drak + * + * @implements \ArrayAccess + * @implements \IteratorAggregate + */ +class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate +{ + protected $subject; + protected $arguments; + + /** + * Encapsulate an event with $subject and $args. + * + * @param mixed $subject The subject of the event, usually an object or a callable + * @param array $arguments Arguments to store in the event + */ + public function __construct($subject = null, array $arguments = []) + { + $this->subject = $subject; + $this->arguments = $arguments; + } + + /** + * Getter for subject property. + * + * @return mixed + */ + public function getSubject() + { + return $this->subject; + } + + /** + * Get argument by key. + * + * @return mixed + * + * @throws \InvalidArgumentException if key is not found + */ + public function getArgument(string $key) + { + if ($this->hasArgument($key)) { + return $this->arguments[$key]; + } + + throw new \InvalidArgumentException(sprintf('Argument "%s" not found.', $key)); + } + + /** + * Add argument to event. + * + * @param mixed $value Value + * + * @return $this + */ + public function setArgument(string $key, $value) + { + $this->arguments[$key] = $value; + + return $this; + } + + /** + * Getter for all arguments. + * + * @return array + */ + public function getArguments() + { + return $this->arguments; + } + + /** + * Set args property. + * + * @return $this + */ + public function setArguments(array $args = []) + { + $this->arguments = $args; + + return $this; + } + + /** + * Has argument. + * + * @return bool + */ + public function hasArgument(string $key) + { + return \array_key_exists($key, $this->arguments); + } + + /** + * ArrayAccess for argument getter. + * + * @param string $key Array key + * + * @return mixed + * + * @throws \InvalidArgumentException if key does not exist in $this->args + */ + #[\ReturnTypeWillChange] + public function offsetGet($key) + { + return $this->getArgument($key); + } + + /** + * ArrayAccess for argument setter. + * + * @param string $key Array key to set + * @param mixed $value Value + * + * @return void + */ + #[\ReturnTypeWillChange] + public function offsetSet($key, $value) + { + $this->setArgument($key, $value); + } + + /** + * ArrayAccess for unset argument. + * + * @param string $key Array key + * + * @return void + */ + #[\ReturnTypeWillChange] + public function offsetUnset($key) + { + if ($this->hasArgument($key)) { + unset($this->arguments[$key]); + } + } + + /** + * ArrayAccess has argument. + * + * @param string $key Array key + * + * @return bool + */ + #[\ReturnTypeWillChange] + public function offsetExists($key) + { + return $this->hasArgument($key); + } + + /** + * IteratorAggregate for iterating over the object like an array. + * + * @return \ArrayIterator + */ + #[\ReturnTypeWillChange] + public function getIterator() + { + return new \ArrayIterator($this->arguments); + } +} diff --git a/plugins/email/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php b/plugins/email/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php new file mode 100644 index 0000000..568d79c --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php @@ -0,0 +1,91 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * A read-only proxy for an event dispatcher. + * + * @author Bernhard Schussek + */ +class ImmutableEventDispatcher implements EventDispatcherInterface +{ + private $dispatcher; + + public function __construct(EventDispatcherInterface $dispatcher) + { + $this->dispatcher = $dispatcher; + } + + /** + * {@inheritdoc} + */ + public function dispatch(object $event, string $eventName = null): object + { + return $this->dispatcher->dispatch($event, $eventName); + } + + /** + * {@inheritdoc} + */ + public function addListener(string $eventName, $listener, int $priority = 0) + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + /** + * {@inheritdoc} + */ + public function addSubscriber(EventSubscriberInterface $subscriber) + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + /** + * {@inheritdoc} + */ + public function removeListener(string $eventName, $listener) + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + /** + * {@inheritdoc} + */ + public function removeSubscriber(EventSubscriberInterface $subscriber) + { + throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); + } + + /** + * {@inheritdoc} + */ + public function getListeners(string $eventName = null) + { + return $this->dispatcher->getListeners($eventName); + } + + /** + * {@inheritdoc} + */ + public function getListenerPriority(string $eventName, $listener) + { + return $this->dispatcher->getListenerPriority($eventName, $listener); + } + + /** + * {@inheritdoc} + */ + public function hasListeners(string $eventName = null) + { + return $this->dispatcher->hasListeners($eventName); + } +} diff --git a/plugins/email/vendor/symfony/event-dispatcher/LICENSE b/plugins/email/vendor/symfony/event-dispatcher/LICENSE new file mode 100644 index 0000000..88bf75b --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/plugins/email/vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.php b/plugins/email/vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.php new file mode 100644 index 0000000..6e17c8f --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; + +trigger_deprecation('symfony/event-dispatcher', '5.1', '%s is deprecated, use the event dispatcher without the proxy.', LegacyEventDispatcherProxy::class); + +/** + * A helper class to provide BC/FC with the legacy signature of EventDispatcherInterface::dispatch(). + * + * @author Nicolas Grekas + * + * @deprecated since Symfony 5.1 + */ +final class LegacyEventDispatcherProxy +{ + public static function decorate(?EventDispatcherInterface $dispatcher): ?EventDispatcherInterface + { + return $dispatcher; + } +} diff --git a/plugins/email/vendor/symfony/event-dispatcher/README.md b/plugins/email/vendor/symfony/event-dispatcher/README.md new file mode 100644 index 0000000..dcdb68d --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher/README.md @@ -0,0 +1,15 @@ +EventDispatcher Component +========================= + +The EventDispatcher component provides tools that allow your application +components to communicate with each other by dispatching events and listening to +them. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/event_dispatcher.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/plugins/email/vendor/symfony/event-dispatcher/composer.json b/plugins/email/vendor/symfony/event-dispatcher/composer.json new file mode 100644 index 0000000..32b42e4 --- /dev/null +++ b/plugins/email/vendor/symfony/event-dispatcher/composer.json @@ -0,0 +1,52 @@ +{ + "name": "symfony/event-dispatcher", + "type": "library", + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/event-dispatcher-contracts": "^2|^3", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^4.4|^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/stopwatch": "^4.4|^5.0|^6.0", + "psr/log": "^1|^2|^3" + }, + "conflict": { + "symfony/dependency-injection": "<4.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\EventDispatcher\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/plugins/email/vendor/symfony/mailer/CHANGELOG.md b/plugins/email/vendor/symfony/mailer/CHANGELOG.md new file mode 100644 index 0000000..cc6cd6f --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/CHANGELOG.md @@ -0,0 +1,61 @@ +CHANGELOG +========= + +5.4 +--- + + * Enable the mailer to operate on any PSR-14-compatible event dispatcher + +5.3 +--- + + * added the `mailer` monolog channel and set it on all transport definitions + +5.2.0 +----- + + * added `NativeTransportFactory` to configure a transport based on php.ini settings + * added `local_domain`, `restart_threshold`, `restart_threshold_sleep` and `ping_threshold` options for `smtp` + * added `command` option for `sendmail` + +4.4.0 +----- + + * [BC BREAK] changed the `NullTransport` DSN from `smtp://null` to `null://null` + * [BC BREAK] renamed `SmtpEnvelope` to `Envelope`, renamed `DelayedSmtpEnvelope` to + `DelayedEnvelope` + * [BC BREAK] changed the syntax for failover and roundrobin DSNs + + Before: + + dummy://a || dummy://b (for failover) + dummy://a && dummy://b (for roundrobin) + + After: + + failover(dummy://a dummy://b) + roundrobin(dummy://a dummy://b) + + * added support for multiple transports on a `Mailer` instance + * [BC BREAK] removed the `auth_mode` DSN option (it is now always determined automatically) + * STARTTLS cannot be enabled anymore (it is used automatically if TLS is disabled and the server supports STARTTLS) + * [BC BREAK] Removed the `encryption` DSN option (use `smtps` instead) + * Added support for the `smtps` protocol (does the same as using `smtp` and port `465`) + * Added PHPUnit constraints + * Added `MessageDataCollector` + * Added `MessageEvents` and `MessageLoggerListener` to allow collecting sent emails + * [BC BREAK] `TransportInterface` has a new `__toString()` method + * [BC BREAK] Classes `AbstractApiTransport` and `AbstractHttpTransport` moved under `Transport` sub-namespace. + * [BC BREAK] Transports depend on `Symfony\Contracts\EventDispatcher\EventDispatcherInterface` + instead of `Symfony\Component\EventDispatcher\EventDispatcherInterface`. + * Added possibility to register custom transport for dsn by implementing + `Symfony\Component\Mailer\Transport\TransportFactoryInterface` and tagging with `mailer.transport_factory` tag in DI. + * Added `Symfony\Component\Mailer\Test\TransportFactoryTestCase` to ease testing custom transport factories. + * Added `SentMessage::getDebug()` and `TransportExceptionInterface::getDebug` to help debugging + * Made `MessageEvent` final + * add DSN parameter `verify_peer` to disable TLS peer verification for SMTP transport + +4.3.0 +----- + + * Added the component. diff --git a/plugins/email/vendor/symfony/mailer/DataCollector/MessageDataCollector.php b/plugins/email/vendor/symfony/mailer/DataCollector/MessageDataCollector.php new file mode 100644 index 0000000..07f77b2 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/DataCollector/MessageDataCollector.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\DataCollector; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\DataCollector\DataCollector; +use Symfony\Component\Mailer\Event\MessageEvents; +use Symfony\Component\Mailer\EventListener\MessageLoggerListener; + +/** + * @author Fabien Potencier + */ +final class MessageDataCollector extends DataCollector +{ + private $events; + + public function __construct(MessageLoggerListener $logger) + { + $this->events = $logger->getEvents(); + } + + /** + * {@inheritdoc} + */ + public function collect(Request $request, Response $response, \Throwable $exception = null) + { + $this->data['events'] = $this->events; + } + + public function getEvents(): MessageEvents + { + return $this->data['events']; + } + + /** + * @internal + */ + public function base64Encode(string $data): string + { + return base64_encode($data); + } + + /** + * {@inheritdoc} + */ + public function reset() + { + $this->data = []; + } + + /** + * {@inheritdoc} + */ + public function getName(): string + { + return 'mailer'; + } +} diff --git a/plugins/email/vendor/symfony/mailer/DelayedEnvelope.php b/plugins/email/vendor/symfony/mailer/DelayedEnvelope.php new file mode 100644 index 0000000..b78b6f2 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/DelayedEnvelope.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Symfony\Component\Mailer\Exception\LogicException; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Message; + +/** + * @author Fabien Potencier + * + * @internal + */ +final class DelayedEnvelope extends Envelope +{ + private $senderSet = false; + private $recipientsSet = false; + private $message; + + public function __construct(Message $message) + { + $this->message = $message; + } + + public function setSender(Address $sender): void + { + parent::setSender($sender); + + $this->senderSet = true; + } + + public function getSender(): Address + { + if (!$this->senderSet) { + parent::setSender(self::getSenderFromHeaders($this->message->getHeaders())); + } + + return parent::getSender(); + } + + public function setRecipients(array $recipients): void + { + parent::setRecipients($recipients); + + $this->recipientsSet = parent::getRecipients(); + } + + /** + * @return Address[] + */ + public function getRecipients(): array + { + if ($this->recipientsSet) { + return parent::getRecipients(); + } + + return self::getRecipientsFromHeaders($this->message->getHeaders()); + } + + private static function getRecipientsFromHeaders(Headers $headers): array + { + $recipients = []; + foreach (['to', 'cc', 'bcc'] as $name) { + foreach ($headers->all($name) as $header) { + foreach ($header->getAddresses() as $address) { + $recipients[] = $address; + } + } + } + + return $recipients; + } + + private static function getSenderFromHeaders(Headers $headers): Address + { + if ($sender = $headers->get('Sender')) { + return $sender->getAddress(); + } + if ($return = $headers->get('Return-Path')) { + return $return->getAddress(); + } + if ($from = $headers->get('From')) { + return $from->getAddresses()[0]; + } + + throw new LogicException('Unable to determine the sender of the message.'); + } +} diff --git a/plugins/email/vendor/symfony/mailer/Envelope.php b/plugins/email/vendor/symfony/mailer/Envelope.php new file mode 100644 index 0000000..97c8d85 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Envelope.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Symfony\Component\Mailer\Exception\InvalidArgumentException; +use Symfony\Component\Mailer\Exception\LogicException; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + */ +class Envelope +{ + private $sender; + private $recipients = []; + + /** + * @param Address[] $recipients + */ + public function __construct(Address $sender, array $recipients) + { + $this->setSender($sender); + $this->setRecipients($recipients); + } + + public static function create(RawMessage $message): self + { + if (RawMessage::class === \get_class($message)) { + throw new LogicException('Cannot send a RawMessage instance without an explicit Envelope.'); + } + + return new DelayedEnvelope($message); + } + + public function setSender(Address $sender): void + { + // to ensure deliverability of bounce emails independent of UTF-8 capabilities of SMTP servers + if (!preg_match('/^[^@\x80-\xFF]++@/', $sender->getAddress())) { + throw new InvalidArgumentException(sprintf('Invalid sender "%s": non-ASCII characters not supported in local-part of email.', $sender->getAddress())); + } + $this->sender = $sender; + } + + /** + * @return Address Returns a "mailbox" as specified by RFC 2822 + * Must be converted to an "addr-spec" when used as a "MAIL FROM" value in SMTP (use getAddress()) + */ + public function getSender(): Address + { + return $this->sender; + } + + /** + * @param Address[] $recipients + */ + public function setRecipients(array $recipients): void + { + if (!$recipients) { + throw new InvalidArgumentException('An envelope must have at least one recipient.'); + } + + $this->recipients = []; + foreach ($recipients as $recipient) { + if (!$recipient instanceof Address) { + throw new InvalidArgumentException(sprintf('A recipient must be an instance of "%s" (got "%s").', Address::class, get_debug_type($recipient))); + } + $this->recipients[] = new Address($recipient->getAddress()); + } + } + + /** + * @return Address[] + */ + public function getRecipients(): array + { + return $this->recipients; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Event/MessageEvent.php b/plugins/email/vendor/symfony/mailer/Event/MessageEvent.php new file mode 100644 index 0000000..d6b7894 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Event/MessageEvent.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Event; + +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mime\RawMessage; +use Symfony\Contracts\EventDispatcher\Event; + +/** + * Allows the transformation of a Message and the Envelope before the email is sent. + * + * @author Fabien Potencier + */ +final class MessageEvent extends Event +{ + private $message; + private $envelope; + private $transport; + private $queued; + + public function __construct(RawMessage $message, Envelope $envelope, string $transport, bool $queued = false) + { + $this->message = $message; + $this->envelope = $envelope; + $this->transport = $transport; + $this->queued = $queued; + } + + public function getMessage(): RawMessage + { + return $this->message; + } + + public function setMessage(RawMessage $message): void + { + $this->message = $message; + } + + public function getEnvelope(): Envelope + { + return $this->envelope; + } + + public function setEnvelope(Envelope $envelope): void + { + $this->envelope = $envelope; + } + + public function getTransport(): string + { + return $this->transport; + } + + public function isQueued(): bool + { + return $this->queued; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Event/MessageEvents.php b/plugins/email/vendor/symfony/mailer/Event/MessageEvents.php new file mode 100644 index 0000000..b526649 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Event/MessageEvents.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Event; + +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + */ +class MessageEvents +{ + private $events = []; + private $transports = []; + + public function add(MessageEvent $event): void + { + $this->events[] = $event; + $this->transports[$event->getTransport()] = true; + } + + public function getTransports(): array + { + return array_keys($this->transports); + } + + /** + * @return MessageEvent[] + */ + public function getEvents(string $name = null): array + { + if (null === $name) { + return $this->events; + } + + $events = []; + foreach ($this->events as $event) { + if ($name === $event->getTransport()) { + $events[] = $event; + } + } + + return $events; + } + + /** + * @return RawMessage[] + */ + public function getMessages(string $name = null): array + { + $events = $this->getEvents($name); + $messages = []; + foreach ($events as $event) { + $messages[] = $event->getMessage(); + } + + return $messages; + } +} diff --git a/plugins/email/vendor/symfony/mailer/EventListener/EnvelopeListener.php b/plugins/email/vendor/symfony/mailer/EventListener/EnvelopeListener.php new file mode 100644 index 0000000..b2980bc --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/EventListener/EnvelopeListener.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Mailer\Event\MessageEvent; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Message; + +/** + * Manipulates the Envelope of a Message. + * + * @author Fabien Potencier + */ +class EnvelopeListener implements EventSubscriberInterface +{ + private $sender; + private $recipients; + + /** + * @param Address|string $sender + * @param array $recipients + */ + public function __construct($sender = null, array $recipients = null) + { + if (null !== $sender) { + $this->sender = Address::create($sender); + } + if (null !== $recipients) { + $this->recipients = Address::createArray($recipients); + } + } + + public function onMessage(MessageEvent $event): void + { + if ($this->sender) { + $event->getEnvelope()->setSender($this->sender); + + $message = $event->getMessage(); + if ($message instanceof Message) { + if (!$message->getHeaders()->has('Sender') && !$message->getHeaders()->has('From')) { + $message->getHeaders()->addMailboxHeader('Sender', $this->sender); + } + } + } + + if ($this->recipients) { + $event->getEnvelope()->setRecipients($this->recipients); + } + } + + public static function getSubscribedEvents() + { + return [ + // should be the last one to allow header changes by other listeners first + MessageEvent::class => ['onMessage', -255], + ]; + } +} diff --git a/plugins/email/vendor/symfony/mailer/EventListener/MessageListener.php b/plugins/email/vendor/symfony/mailer/EventListener/MessageListener.php new file mode 100644 index 0000000..f23c69d --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/EventListener/MessageListener.php @@ -0,0 +1,134 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Mailer\Event\MessageEvent; +use Symfony\Component\Mailer\Exception\InvalidArgumentException; +use Symfony\Component\Mailer\Exception\RuntimeException; +use Symfony\Component\Mime\BodyRendererInterface; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Header\MailboxListHeader; +use Symfony\Component\Mime\Message; + +/** + * Manipulates the headers and the body of a Message. + * + * @author Fabien Potencier + */ +class MessageListener implements EventSubscriberInterface +{ + public const HEADER_SET_IF_EMPTY = 1; + public const HEADER_ADD = 2; + public const HEADER_REPLACE = 3; + public const DEFAULT_RULES = [ + 'from' => self::HEADER_SET_IF_EMPTY, + 'return-path' => self::HEADER_SET_IF_EMPTY, + 'reply-to' => self::HEADER_ADD, + 'to' => self::HEADER_SET_IF_EMPTY, + 'cc' => self::HEADER_ADD, + 'bcc' => self::HEADER_ADD, + ]; + + private $headers; + private $headerRules = []; + private $renderer; + + public function __construct(Headers $headers = null, BodyRendererInterface $renderer = null, array $headerRules = self::DEFAULT_RULES) + { + $this->headers = $headers; + $this->renderer = $renderer; + foreach ($headerRules as $headerName => $rule) { + $this->addHeaderRule($headerName, $rule); + } + } + + public function addHeaderRule(string $headerName, int $rule): void + { + if ($rule < 1 || $rule > 3) { + throw new InvalidArgumentException(sprintf('The "%d" rule is not supported.', $rule)); + } + + $this->headerRules[strtolower($headerName)] = $rule; + } + + public function onMessage(MessageEvent $event): void + { + $message = $event->getMessage(); + if (!$message instanceof Message) { + return; + } + + $this->setHeaders($message); + $this->renderMessage($message); + } + + private function setHeaders(Message $message): void + { + if (!$this->headers) { + return; + } + + $headers = $message->getHeaders(); + foreach ($this->headers->all() as $name => $header) { + if (!$headers->has($name)) { + $headers->add($header); + + continue; + } + + switch ($this->headerRules[$name] ?? self::HEADER_SET_IF_EMPTY) { + case self::HEADER_SET_IF_EMPTY: + break; + + case self::HEADER_REPLACE: + $headers->remove($name); + $headers->add($header); + + break; + + case self::HEADER_ADD: + if (!Headers::isUniqueHeader($name)) { + $headers->add($header); + + break; + } + + $h = $headers->get($name); + if (!$h instanceof MailboxListHeader) { + throw new RuntimeException(sprintf('Unable to set header "%s".', $name)); + } + + Headers::checkHeaderClass($header); + foreach ($header->getAddresses() as $address) { + $h->addAddress($address); + } + } + } + } + + private function renderMessage(Message $message): void + { + if (!$this->renderer) { + return; + } + + $this->renderer->render($message); + } + + public static function getSubscribedEvents() + { + return [ + MessageEvent::class => 'onMessage', + ]; + } +} diff --git a/plugins/email/vendor/symfony/mailer/EventListener/MessageLoggerListener.php b/plugins/email/vendor/symfony/mailer/EventListener/MessageLoggerListener.php new file mode 100644 index 0000000..093bf2b --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/EventListener/MessageLoggerListener.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Mailer\Event\MessageEvent; +use Symfony\Component\Mailer\Event\MessageEvents; +use Symfony\Contracts\Service\ResetInterface; + +/** + * Logs Messages. + * + * @author Fabien Potencier + */ +class MessageLoggerListener implements EventSubscriberInterface, ResetInterface +{ + private $events; + + public function __construct() + { + $this->events = new MessageEvents(); + } + + /** + * {@inheritdoc} + */ + public function reset() + { + $this->events = new MessageEvents(); + } + + public function onMessage(MessageEvent $event): void + { + $this->events->add($event); + } + + public function getEvents(): MessageEvents + { + return $this->events; + } + + public static function getSubscribedEvents() + { + return [ + MessageEvent::class => ['onMessage', -255], + ]; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Exception/ExceptionInterface.php b/plugins/email/vendor/symfony/mailer/Exception/ExceptionInterface.php new file mode 100644 index 0000000..2f0f3a6 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * Exception interface for all exceptions thrown by the component. + * + * @author Fabien Potencier + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/plugins/email/vendor/symfony/mailer/Exception/HttpTransportException.php b/plugins/email/vendor/symfony/mailer/Exception/HttpTransportException.php new file mode 100644 index 0000000..c72eb6c --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Exception/HttpTransportException.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Fabien Potencier + */ +class HttpTransportException extends TransportException +{ + private $response; + + public function __construct(?string $message, ResponseInterface $response, int $code = 0, \Throwable $previous = null) + { + if (null === $message) { + trigger_deprecation('symfony/mailer', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); + + $message = ''; + } + + parent::__construct($message, $code, $previous); + + $this->response = $response; + } + + public function getResponse(): ResponseInterface + { + return $this->response; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Exception/IncompleteDsnException.php b/plugins/email/vendor/symfony/mailer/Exception/IncompleteDsnException.php new file mode 100644 index 0000000..f2618b6 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Exception/IncompleteDsnException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Konstantin Myakshin + */ +class IncompleteDsnException extends InvalidArgumentException +{ +} diff --git a/plugins/email/vendor/symfony/mailer/Exception/InvalidArgumentException.php b/plugins/email/vendor/symfony/mailer/Exception/InvalidArgumentException.php new file mode 100644 index 0000000..ba53334 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Exception/InvalidArgumentException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/plugins/email/vendor/symfony/mailer/Exception/LogicException.php b/plugins/email/vendor/symfony/mailer/Exception/LogicException.php new file mode 100644 index 0000000..487c0a3 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Exception/LogicException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/plugins/email/vendor/symfony/mailer/Exception/RuntimeException.php b/plugins/email/vendor/symfony/mailer/Exception/RuntimeException.php new file mode 100644 index 0000000..44b79cc --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Exception/RuntimeException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/plugins/email/vendor/symfony/mailer/Exception/TransportException.php b/plugins/email/vendor/symfony/mailer/Exception/TransportException.php new file mode 100644 index 0000000..dfad0c4 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Exception/TransportException.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + */ +class TransportException extends RuntimeException implements TransportExceptionInterface +{ + private $debug = ''; + + public function getDebug(): string + { + return $this->debug; + } + + public function appendDebug(string $debug): void + { + $this->debug .= $debug; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Exception/TransportExceptionInterface.php b/plugins/email/vendor/symfony/mailer/Exception/TransportExceptionInterface.php new file mode 100644 index 0000000..4318f5c --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Exception/TransportExceptionInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + */ +interface TransportExceptionInterface extends ExceptionInterface +{ + public function getDebug(): string; + + public function appendDebug(string $debug): void; +} diff --git a/plugins/email/vendor/symfony/mailer/Exception/UnsupportedSchemeException.php b/plugins/email/vendor/symfony/mailer/Exception/UnsupportedSchemeException.php new file mode 100644 index 0000000..e47a129 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Exception/UnsupportedSchemeException.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +use Symfony\Component\Mailer\Bridge; +use Symfony\Component\Mailer\Transport\Dsn; + +/** + * @author Konstantin Myakshin + */ +class UnsupportedSchemeException extends LogicException +{ + private const SCHEME_TO_PACKAGE_MAP = [ + 'gmail' => [ + 'class' => Bridge\Google\Transport\GmailTransportFactory::class, + 'package' => 'symfony/google-mailer', + ], + 'mailgun' => [ + 'class' => Bridge\Mailgun\Transport\MailgunTransportFactory::class, + 'package' => 'symfony/mailgun-mailer', + ], + 'mailjet' => [ + 'class' => Bridge\Mailjet\Transport\MailjetTransportFactory::class, + 'package' => 'symfony/mailjet-mailer', + ], + 'mandrill' => [ + 'class' => Bridge\Mailchimp\Transport\MandrillTransportFactory::class, + 'package' => 'symfony/mailchimp-mailer', + ], + 'ohmysmtp' => [ + 'class' => Bridge\OhMySmtp\Transport\OhMySmtpTransportFactory::class, + 'package' => 'symfony/oh-my-smtp-mailer', + ], + 'postmark' => [ + 'class' => Bridge\Postmark\Transport\PostmarkTransportFactory::class, + 'package' => 'symfony/postmark-mailer', + ], + 'sendgrid' => [ + 'class' => Bridge\Sendgrid\Transport\SendgridTransportFactory::class, + 'package' => 'symfony/sendgrid-mailer', + ], + 'sendinblue' => [ + 'class' => Bridge\Sendinblue\Transport\SendinblueTransportFactory::class, + 'package' => 'symfony/sendinblue-mailer', + ], + 'ses' => [ + 'class' => Bridge\Amazon\Transport\SesTransportFactory::class, + 'package' => 'symfony/amazon-mailer', + ], + ]; + + public function __construct(Dsn $dsn, string $name = null, array $supported = []) + { + $provider = $dsn->getScheme(); + if (false !== $pos = strpos($provider, '+')) { + $provider = substr($provider, 0, $pos); + } + $package = self::SCHEME_TO_PACKAGE_MAP[$provider] ?? null; + if ($package && !class_exists($package['class'])) { + parent::__construct(sprintf('Unable to send emails via "%s" as the bridge is not installed; try running "composer require %s".', $provider, $package['package'])); + + return; + } + + $message = sprintf('The "%s" scheme is not supported', $dsn->getScheme()); + if ($name && $supported) { + $message .= sprintf('; supported schemes for mailer "%s" are: "%s"', $name, implode('", "', $supported)); + } + + parent::__construct($message.'.'); + } +} diff --git a/plugins/email/vendor/symfony/mailer/Header/MetadataHeader.php b/plugins/email/vendor/symfony/mailer/Header/MetadataHeader.php new file mode 100644 index 0000000..d56acb1 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Header/MetadataHeader.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Header; + +use Symfony\Component\Mime\Header\UnstructuredHeader; + +/** + * @author Kevin Bond + */ +final class MetadataHeader extends UnstructuredHeader +{ + private $key; + + public function __construct(string $key, string $value) + { + $this->key = $key; + + parent::__construct('X-Metadata-'.$key, $value); + } + + public function getKey(): string + { + return $this->key; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Header/TagHeader.php b/plugins/email/vendor/symfony/mailer/Header/TagHeader.php new file mode 100644 index 0000000..7115cae --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Header/TagHeader.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Header; + +use Symfony\Component\Mime\Header\UnstructuredHeader; + +/** + * @author Kevin Bond + */ +final class TagHeader extends UnstructuredHeader +{ + public function __construct(string $value) + { + parent::__construct('X-Tag', $value); + } +} diff --git a/plugins/email/vendor/symfony/mailer/LICENSE b/plugins/email/vendor/symfony/mailer/LICENSE new file mode 100644 index 0000000..9c907a4 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019-2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/plugins/email/vendor/symfony/mailer/Mailer.php b/plugins/email/vendor/symfony/mailer/Mailer.php new file mode 100644 index 0000000..cbdcdf2 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Mailer.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; +use Symfony\Component\Mailer\Event\MessageEvent; +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\Messenger\SendEmailMessage; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Component\Messenger\Exception\HandlerFailedException; +use Symfony\Component\Messenger\MessageBusInterface; +use Symfony\Component\Mime\RawMessage; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as SymfonyEventDispatcherInterface; + +/** + * @author Fabien Potencier + */ +final class Mailer implements MailerInterface +{ + private $transport; + private $bus; + private $dispatcher; + + public function __construct(TransportInterface $transport, MessageBusInterface $bus = null, EventDispatcherInterface $dispatcher = null) + { + $this->transport = $transport; + $this->bus = $bus; + $this->dispatcher = class_exists(Event::class) && $dispatcher instanceof SymfonyEventDispatcherInterface ? LegacyEventDispatcherProxy::decorate($dispatcher) : $dispatcher; + } + + public function send(RawMessage $message, Envelope $envelope = null): void + { + if (null === $this->bus) { + $this->transport->send($message, $envelope); + + return; + } + + if (null !== $this->dispatcher) { + // The dispatched event here has `queued` set to `true`; the goal is NOT to render the message, but to let + // listeners do something before a message is sent to the queue. + // We are using a cloned message as we still want to dispatch the **original** message, not the one modified by listeners. + // That's because the listeners will run again when the email is sent via Messenger by the transport (see `AbstractTransport`). + // Listeners should act depending on the `$queued` argument of the `MessageEvent` instance. + $clonedMessage = clone $message; + $clonedEnvelope = null !== $envelope ? clone $envelope : Envelope::create($clonedMessage); + $event = new MessageEvent($clonedMessage, $clonedEnvelope, (string) $this->transport, true); + $this->dispatcher->dispatch($event); + } + + try { + $this->bus->dispatch(new SendEmailMessage($message, $envelope)); + } catch (HandlerFailedException $e) { + foreach ($e->getNestedExceptions() as $nested) { + if ($nested instanceof TransportExceptionInterface) { + throw $nested; + } + } + throw $e; + } + } +} diff --git a/plugins/email/vendor/symfony/mailer/MailerInterface.php b/plugins/email/vendor/symfony/mailer/MailerInterface.php new file mode 100644 index 0000000..eb44cf6 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/MailerInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mime\RawMessage; + +/** + * Interface for mailers able to send emails synchronous and/or asynchronous. + * + * Implementations must support synchronous and asynchronous sending. + * + * @author Fabien Potencier + */ +interface MailerInterface +{ + /** + * @throws TransportExceptionInterface + */ + public function send(RawMessage $message, Envelope $envelope = null): void; +} diff --git a/plugins/email/vendor/symfony/mailer/Messenger/MessageHandler.php b/plugins/email/vendor/symfony/mailer/Messenger/MessageHandler.php new file mode 100644 index 0000000..fefae9d --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Messenger/MessageHandler.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Messenger; + +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\Transport\TransportInterface; + +/** + * @author Fabien Potencier + */ +class MessageHandler +{ + private $transport; + + public function __construct(TransportInterface $transport) + { + $this->transport = $transport; + } + + public function __invoke(SendEmailMessage $message): ?SentMessage + { + return $this->transport->send($message->getMessage(), $message->getEnvelope()); + } +} diff --git a/plugins/email/vendor/symfony/mailer/Messenger/SendEmailMessage.php b/plugins/email/vendor/symfony/mailer/Messenger/SendEmailMessage.php new file mode 100644 index 0000000..b06ac83 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Messenger/SendEmailMessage.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Messenger; + +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + */ +class SendEmailMessage +{ + private $message; + private $envelope; + + public function __construct(RawMessage $message, Envelope $envelope = null) + { + $this->message = $message; + $this->envelope = $envelope; + } + + public function getMessage(): RawMessage + { + return $this->message; + } + + public function getEnvelope(): ?Envelope + { + return $this->envelope; + } +} diff --git a/plugins/email/vendor/symfony/mailer/README.md b/plugins/email/vendor/symfony/mailer/README.md new file mode 100644 index 0000000..93a9585 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/README.md @@ -0,0 +1,74 @@ +Mailer Component +================ + +The Mailer component helps sending emails. + +Getting Started +--------------- + +``` +$ composer require symfony/mailer +``` + +```php +use Symfony\Component\Mailer\Transport; +use Symfony\Component\Mailer\Mailer; +use Symfony\Component\Mime\Email; + +$transport = Transport::fromDsn('smtp://localhost'); +$mailer = new Mailer($transport); + +$email = (new Email()) + ->from('hello@example.com') + ->to('you@example.com') + //->cc('cc@example.com') + //->bcc('bcc@example.com') + //->replyTo('fabien@example.com') + //->priority(Email::PRIORITY_HIGH) + ->subject('Time for Symfony Mailer!') + ->text('Sending emails is fun again!') + ->html('

See Twig integration for better HTML integration!

'); + +$mailer->send($email); +``` + +To enable the Twig integration of the Mailer, require `symfony/twig-bridge` and +set up the `BodyRenderer`: + +```php +use Symfony\Bridge\Twig\Mime\BodyRenderer; +use Symfony\Bridge\Twig\Mime\TemplatedEmail; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\Mailer\EventListener\MessageListener; +use Symfony\Component\Mailer\Mailer; +use Symfony\Component\Mailer\Transport; +use Twig\Environment as TwigEnvironment; + +$twig = new TwigEnvironment(...); +$messageListener = new MessageListener(null, new BodyRenderer($twig)); + +$eventDispatcher = new EventDispatcher(); +$eventDispatcher->addSubscriber($messageListener); + +$transport = Transport::fromDsn('smtp://localhost', $eventDispatcher); +$mailer = new Mailer($transport, null, $eventDispatcher); + +$email = (new TemplatedEmail()) + // ... + ->htmlTemplate('emails/signup.html.twig') + ->context([ + 'expiration_date' => new \DateTime('+7 days'), + 'username' => 'foo', + ]) +; +$mailer->send($email); +``` + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/mailer.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/plugins/email/vendor/symfony/mailer/SentMessage.php b/plugins/email/vendor/symfony/mailer/SentMessage.php new file mode 100644 index 0000000..1a12d07 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/SentMessage.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + */ +class SentMessage +{ + private $original; + private $raw; + private $envelope; + private $messageId; + private $debug = ''; + + /** + * @internal + */ + public function __construct(RawMessage $message, Envelope $envelope) + { + $message->ensureValidity(); + + $this->original = $message; + $this->envelope = $envelope; + + if ($message instanceof Message) { + $message = clone $message; + $headers = $message->getHeaders(); + if (!$headers->has('Message-ID')) { + $headers->addIdHeader('Message-ID', $message->generateMessageId()); + } + $this->messageId = $headers->get('Message-ID')->getId(); + $this->raw = new RawMessage($message->toIterable()); + } else { + $this->raw = $message; + } + } + + public function getMessage(): RawMessage + { + return $this->raw; + } + + public function getOriginalMessage(): RawMessage + { + return $this->original; + } + + public function getEnvelope(): Envelope + { + return $this->envelope; + } + + public function setMessageId(string $id): void + { + $this->messageId = $id; + } + + public function getMessageId(): string + { + return $this->messageId; + } + + public function getDebug(): string + { + return $this->debug; + } + + public function appendDebug(string $debug): void + { + $this->debug .= $debug; + } + + public function toString(): string + { + return $this->raw->toString(); + } + + public function toIterable(): iterable + { + return $this->raw->toIterable(); + } +} diff --git a/plugins/email/vendor/symfony/mailer/Test/Constraint/EmailCount.php b/plugins/email/vendor/symfony/mailer/Test/Constraint/EmailCount.php new file mode 100644 index 0000000..59a7812 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Test/Constraint/EmailCount.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mailer\Event\MessageEvents; + +final class EmailCount extends Constraint +{ + private $expectedValue; + private $transport; + private $queued; + + public function __construct(int $expectedValue, string $transport = null, bool $queued = false) + { + $this->expectedValue = $expectedValue; + $this->transport = $transport; + $this->queued = $queued; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('%shas %s "%d" emails', $this->transport ? $this->transport.' ' : '', $this->queued ? 'queued' : 'sent', $this->expectedValue); + } + + /** + * @param MessageEvents $events + * + * {@inheritdoc} + */ + protected function matches($events): bool + { + return $this->expectedValue === $this->countEmails($events); + } + + /** + * @param MessageEvents $events + * + * {@inheritdoc} + */ + protected function failureDescription($events): string + { + return sprintf('the Transport %s (%d %s)', $this->toString(), $this->countEmails($events), $this->queued ? 'queued' : 'sent'); + } + + private function countEmails(MessageEvents $events): int + { + $count = 0; + foreach ($events->getEvents($this->transport) as $event) { + if ( + ($this->queued && $event->isQueued()) + || + (!$this->queued && !$event->isQueued()) + ) { + ++$count; + } + } + + return $count; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Test/Constraint/EmailIsQueued.php b/plugins/email/vendor/symfony/mailer/Test/Constraint/EmailIsQueued.php new file mode 100644 index 0000000..be9dac8 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Test/Constraint/EmailIsQueued.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mailer\Event\MessageEvent; + +final class EmailIsQueued extends Constraint +{ + /** + * {@inheritdoc} + */ + public function toString(): string + { + return 'is queued'; + } + + /** + * @param MessageEvent $event + * + * {@inheritdoc} + */ + protected function matches($event): bool + { + return $event->isQueued(); + } + + /** + * @param MessageEvent $event + * + * {@inheritdoc} + */ + protected function failureDescription($event): string + { + return 'the Email '.$this->toString(); + } +} diff --git a/plugins/email/vendor/symfony/mailer/Test/TransportFactoryTestCase.php b/plugins/email/vendor/symfony/mailer/Test/TransportFactoryTestCase.php new file mode 100644 index 0000000..c2426a0 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Test/TransportFactoryTestCase.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Test; + +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Symfony\Component\Mailer\Exception\IncompleteDsnException; +use Symfony\Component\Mailer\Exception\UnsupportedSchemeException; +use Symfony\Component\Mailer\Transport\Dsn; +use Symfony\Component\Mailer\Transport\TransportFactoryInterface; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * A test case to ease testing Transport Factory. + * + * @author Konstantin Myakshin + */ +abstract class TransportFactoryTestCase extends TestCase +{ + protected const USER = 'u$er'; + protected const PASSWORD = 'pa$s'; + + protected $dispatcher; + protected $client; + protected $logger; + + abstract public function getFactory(): TransportFactoryInterface; + + abstract public function supportsProvider(): iterable; + + abstract public function createProvider(): iterable; + + public function unsupportedSchemeProvider(): iterable + { + return []; + } + + public function incompleteDsnProvider(): iterable + { + return []; + } + + /** + * @dataProvider supportsProvider + */ + public function testSupports(Dsn $dsn, bool $supports) + { + $factory = $this->getFactory(); + + $this->assertSame($supports, $factory->supports($dsn)); + } + + /** + * @dataProvider createProvider + */ + public function testCreate(Dsn $dsn, TransportInterface $transport) + { + $factory = $this->getFactory(); + + $this->assertEquals($transport, $factory->create($dsn)); + if (str_contains('smtp', $dsn->getScheme())) { + $this->assertStringMatchesFormat($dsn->getScheme().'://%S'.$dsn->getHost().'%S', (string) $transport); + } + } + + /** + * @dataProvider unsupportedSchemeProvider + */ + public function testUnsupportedSchemeException(Dsn $dsn, string $message = null) + { + $factory = $this->getFactory(); + + $this->expectException(UnsupportedSchemeException::class); + if (null !== $message) { + $this->expectExceptionMessage($message); + } + + $factory->create($dsn); + } + + /** + * @dataProvider incompleteDsnProvider + */ + public function testIncompleteDsnException(Dsn $dsn) + { + $factory = $this->getFactory(); + + $this->expectException(IncompleteDsnException::class); + $factory->create($dsn); + } + + protected function getDispatcher(): EventDispatcherInterface + { + return $this->dispatcher ?? $this->dispatcher = $this->createMock(EventDispatcherInterface::class); + } + + protected function getClient(): HttpClientInterface + { + return $this->client ?? $this->client = $this->createMock(HttpClientInterface::class); + } + + protected function getLogger(): LoggerInterface + { + return $this->logger ?? $this->logger = $this->createMock(LoggerInterface::class); + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport.php b/plugins/email/vendor/symfony/mailer/Transport.php new file mode 100644 index 0000000..c2b813f --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport.php @@ -0,0 +1,206 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesTransportFactory; +use Symfony\Component\Mailer\Bridge\Google\Transport\GmailTransportFactory; +use Symfony\Component\Mailer\Bridge\Mailchimp\Transport\MandrillTransportFactory; +use Symfony\Component\Mailer\Bridge\Mailgun\Transport\MailgunTransportFactory; +use Symfony\Component\Mailer\Bridge\Mailjet\Transport\MailjetTransportFactory; +use Symfony\Component\Mailer\Bridge\OhMySmtp\Transport\OhMySmtpTransportFactory; +use Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkTransportFactory; +use Symfony\Component\Mailer\Bridge\Sendgrid\Transport\SendgridTransportFactory; +use Symfony\Component\Mailer\Bridge\Sendinblue\Transport\SendinblueTransportFactory; +use Symfony\Component\Mailer\Exception\InvalidArgumentException; +use Symfony\Component\Mailer\Exception\UnsupportedSchemeException; +use Symfony\Component\Mailer\Transport\Dsn; +use Symfony\Component\Mailer\Transport\FailoverTransport; +use Symfony\Component\Mailer\Transport\NativeTransportFactory; +use Symfony\Component\Mailer\Transport\NullTransportFactory; +use Symfony\Component\Mailer\Transport\RoundRobinTransport; +use Symfony\Component\Mailer\Transport\SendmailTransportFactory; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransportFactory; +use Symfony\Component\Mailer\Transport\TransportFactoryInterface; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Component\Mailer\Transport\Transports; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Fabien Potencier + * @author Konstantin Myakshin + * + * @final since Symfony 5.4 + */ +class Transport +{ + private const FACTORY_CLASSES = [ + GmailTransportFactory::class, + MailgunTransportFactory::class, + MailjetTransportFactory::class, + MandrillTransportFactory::class, + OhMySmtpTransportFactory::class, + PostmarkTransportFactory::class, + SendgridTransportFactory::class, + SendinblueTransportFactory::class, + SesTransportFactory::class, + ]; + + private $factories; + + /** + * @param EventDispatcherInterface|null $dispatcher + * @param HttpClientInterface|null $client + * @param LoggerInterface|null $logger + */ + public static function fromDsn(string $dsn/* , EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null */): TransportInterface + { + $dispatcher = 2 <= \func_num_args() ? func_get_arg(1) : null; + $client = 3 <= \func_num_args() ? func_get_arg(2) : null; + $logger = 4 <= \func_num_args() ? func_get_arg(3) : null; + + $factory = new self(iterator_to_array(self::getDefaultFactories($dispatcher, $client, $logger))); + + return $factory->fromString($dsn); + } + + /** + * @param EventDispatcherInterface|null $dispatcher + * @param HttpClientInterface|null $client + * @param LoggerInterface|null $logger + */ + public static function fromDsns(array $dsns/* , EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null */): TransportInterface + { + $dispatcher = 2 <= \func_num_args() ? func_get_arg(1) : null; + $client = 3 <= \func_num_args() ? func_get_arg(2) : null; + $logger = 4 <= \func_num_args() ? func_get_arg(3) : null; + + $factory = new self(iterator_to_array(self::getDefaultFactories($dispatcher, $client, $logger))); + + return $factory->fromStrings($dsns); + } + + /** + * @param TransportFactoryInterface[] $factories + */ + public function __construct(iterable $factories) + { + $this->factories = $factories; + } + + public function fromStrings(array $dsns): Transports + { + $transports = []; + foreach ($dsns as $name => $dsn) { + $transports[$name] = $this->fromString($dsn); + } + + return new Transports($transports); + } + + public function fromString(string $dsn): TransportInterface + { + [$transport, $offset] = $this->parseDsn($dsn); + if ($offset !== \strlen($dsn)) { + throw new InvalidArgumentException(sprintf('The DSN has some garbage at the end: "%s".', substr($dsn, $offset))); + } + + return $transport; + } + + private function parseDsn(string $dsn, int $offset = 0): array + { + static $keywords = [ + 'failover' => FailoverTransport::class, + 'roundrobin' => RoundRobinTransport::class, + ]; + + while (true) { + foreach ($keywords as $name => $class) { + $name .= '('; + if ($name === substr($dsn, $offset, \strlen($name))) { + $offset += \strlen($name) - 1; + preg_match('{\(([^()]|(?R))*\)}A', $dsn, $matches, 0, $offset); + if (!isset($matches[0])) { + continue; + } + + ++$offset; + $args = []; + while (true) { + [$arg, $offset] = $this->parseDsn($dsn, $offset); + $args[] = $arg; + if (\strlen($dsn) === $offset) { + break; + } + ++$offset; + if (')' === $dsn[$offset - 1]) { + break; + } + } + + return [new $class($args), $offset]; + } + } + + if (preg_match('{(\w+)\(}A', $dsn, $matches, 0, $offset)) { + throw new InvalidArgumentException(sprintf('The "%s" keyword is not valid (valid ones are "%s"), ', $matches[1], implode('", "', array_keys($keywords)))); + } + + if ($pos = strcspn($dsn, ' )', $offset)) { + return [$this->fromDsnObject(Dsn::fromString(substr($dsn, $offset, $pos))), $offset + $pos]; + } + + return [$this->fromDsnObject(Dsn::fromString(substr($dsn, $offset))), \strlen($dsn)]; + } + } + + public function fromDsnObject(Dsn $dsn): TransportInterface + { + foreach ($this->factories as $factory) { + if ($factory->supports($dsn)) { + return $factory->create($dsn); + } + } + + throw new UnsupportedSchemeException($dsn); + } + + /** + * @param EventDispatcherInterface|null $dispatcher + * @param HttpClientInterface|null $client + * @param LoggerInterface|null $logger + * + * @return \Traversable + */ + public static function getDefaultFactories(/* EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null */): iterable + { + $dispatcher = 1 <= \func_num_args() ? func_get_arg(0) : null; + $client = 2 <= \func_num_args() ? func_get_arg(1) : null; + $logger = 3 <= \func_num_args() ? func_get_arg(2) : null; + + foreach (self::FACTORY_CLASSES as $factoryClass) { + if (class_exists($factoryClass)) { + yield new $factoryClass($dispatcher, $client, $logger); + } + } + + yield new NullTransportFactory($dispatcher, $client, $logger); + + yield new SendmailTransportFactory($dispatcher, $client, $logger); + + yield new EsmtpTransportFactory($dispatcher, $client, $logger); + + yield new NativeTransportFactory($dispatcher, $client, $logger); + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/AbstractApiTransport.php b/plugins/email/vendor/symfony/mailer/Transport/AbstractApiTransport.php new file mode 100644 index 0000000..392484d --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/AbstractApiTransport.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Exception\RuntimeException; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email; +use Symfony\Component\Mime\MessageConverter; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Fabien Potencier + */ +abstract class AbstractApiTransport extends AbstractHttpTransport +{ + abstract protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $envelope): ResponseInterface; + + protected function doSendHttp(SentMessage $message): ResponseInterface + { + try { + $email = MessageConverter::toEmail($message->getOriginalMessage()); + } catch (\Exception $e) { + throw new RuntimeException(sprintf('Unable to send message with the "%s" transport: ', __CLASS__).$e->getMessage(), 0, $e); + } + + return $this->doSendApi($message, $email, $message->getEnvelope()); + } + + protected function getRecipients(Email $email, Envelope $envelope): array + { + return array_filter($envelope->getRecipients(), function (Address $address) use ($email) { + return false === \in_array($address, array_merge($email->getCc(), $email->getBcc()), true); + }); + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/AbstractHttpTransport.php b/plugins/email/vendor/symfony/mailer/Transport/AbstractHttpTransport.php new file mode 100644 index 0000000..2317a0d --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/AbstractHttpTransport.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\Mailer\Exception\HttpTransportException; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Victor Bocharsky + */ +abstract class AbstractHttpTransport extends AbstractTransport +{ + protected $host; + protected $port; + protected $client; + + public function __construct(HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + $this->client = $client; + if (null === $client) { + if (!class_exists(HttpClient::class)) { + throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__)); + } + + $this->client = HttpClient::create(); + } + + parent::__construct($dispatcher, $logger); + } + + /** + * @return $this + */ + public function setHost(?string $host) + { + $this->host = $host; + + return $this; + } + + /** + * @return $this + */ + public function setPort(?int $port) + { + $this->port = $port; + + return $this; + } + + abstract protected function doSendHttp(SentMessage $message): ResponseInterface; + + protected function doSend(SentMessage $message): void + { + $response = null; + try { + $response = $this->doSendHttp($message); + $message->appendDebug($response->getInfo('debug') ?? ''); + } catch (HttpTransportException $e) { + $e->appendDebug($e->getResponse()->getInfo('debug') ?? ''); + + throw $e; + } + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/AbstractTransport.php b/plugins/email/vendor/symfony/mailer/Transport/AbstractTransport.php new file mode 100644 index 0000000..77d810b --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/AbstractTransport.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Event\MessageEvent; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\RawMessage; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as SymfonyEventDispatcherInterface; + +/** + * @author Fabien Potencier + */ +abstract class AbstractTransport implements TransportInterface +{ + private $dispatcher; + private $logger; + private $rate = 0; + private $lastSent = 0; + + public function __construct(EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + $this->dispatcher = class_exists(Event::class) && $dispatcher instanceof SymfonyEventDispatcherInterface ? LegacyEventDispatcherProxy::decorate($dispatcher) : $dispatcher; + $this->logger = $logger ?? new NullLogger(); + } + + /** + * Sets the maximum number of messages to send per second (0 to disable). + * + * @return $this + */ + public function setMaxPerSecond(float $rate): self + { + if (0 >= $rate) { + $rate = 0; + } + + $this->rate = $rate; + $this->lastSent = 0; + + return $this; + } + + public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage + { + $message = clone $message; + $envelope = null !== $envelope ? clone $envelope : Envelope::create($message); + + if (null !== $this->dispatcher) { + $event = new MessageEvent($message, $envelope, (string) $this); + $this->dispatcher->dispatch($event); + $envelope = $event->getEnvelope(); + } + + $message = new SentMessage($message, $envelope); + $this->doSend($message); + + $this->checkThrottling(); + + return $message; + } + + abstract protected function doSend(SentMessage $message): void; + + /** + * @param Address[] $addresses + * + * @return string[] + */ + protected function stringifyAddresses(array $addresses): array + { + return array_map(function (Address $a) { + return $a->toString(); + }, $addresses); + } + + protected function getLogger(): LoggerInterface + { + return $this->logger; + } + + private function checkThrottling() + { + if (0 == $this->rate) { + return; + } + + $sleep = (1 / $this->rate) - (microtime(true) - $this->lastSent); + if (0 < $sleep) { + $this->logger->debug(sprintf('Email transport "%s" sleeps for %.2f seconds', __CLASS__, $sleep)); + usleep($sleep * 1000000); + } + $this->lastSent = microtime(true); + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/AbstractTransportFactory.php b/plugins/email/vendor/symfony/mailer/Transport/AbstractTransportFactory.php new file mode 100644 index 0000000..e1617d2 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/AbstractTransportFactory.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Mailer\Exception\IncompleteDsnException; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Konstantin Myakshin + */ +abstract class AbstractTransportFactory implements TransportFactoryInterface +{ + protected $dispatcher; + protected $client; + protected $logger; + + public function __construct(EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null) + { + $this->dispatcher = $dispatcher; + $this->client = $client; + $this->logger = $logger; + } + + public function supports(Dsn $dsn): bool + { + return \in_array($dsn->getScheme(), $this->getSupportedSchemes()); + } + + abstract protected function getSupportedSchemes(): array; + + protected function getUser(Dsn $dsn): string + { + $user = $dsn->getUser(); + if (null === $user) { + throw new IncompleteDsnException('User is not set.'); + } + + return $user; + } + + protected function getPassword(Dsn $dsn): string + { + $password = $dsn->getPassword(); + if (null === $password) { + throw new IncompleteDsnException('Password is not set.'); + } + + return $password; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/Dsn.php b/plugins/email/vendor/symfony/mailer/Transport/Dsn.php new file mode 100644 index 0000000..04d3540 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/Dsn.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Exception\InvalidArgumentException; + +/** + * @author Konstantin Myakshin + */ +final class Dsn +{ + private $scheme; + private $host; + private $user; + private $password; + private $port; + private $options; + + public function __construct(string $scheme, string $host, string $user = null, string $password = null, int $port = null, array $options = []) + { + $this->scheme = $scheme; + $this->host = $host; + $this->user = $user; + $this->password = $password; + $this->port = $port; + $this->options = $options; + } + + public static function fromString(string $dsn): self + { + if (false === $parsedDsn = parse_url($dsn)) { + throw new InvalidArgumentException(sprintf('The "%s" mailer DSN is invalid.', $dsn)); + } + + if (!isset($parsedDsn['scheme'])) { + throw new InvalidArgumentException(sprintf('The "%s" mailer DSN must contain a scheme.', $dsn)); + } + + if (!isset($parsedDsn['host'])) { + throw new InvalidArgumentException(sprintf('The "%s" mailer DSN must contain a host (use "default" by default).', $dsn)); + } + + $user = '' !== ($parsedDsn['user'] ?? '') ? urldecode($parsedDsn['user']) : null; + $password = '' !== ($parsedDsn['pass'] ?? '') ? urldecode($parsedDsn['pass']) : null; + $port = $parsedDsn['port'] ?? null; + parse_str($parsedDsn['query'] ?? '', $query); + + return new self($parsedDsn['scheme'], $parsedDsn['host'], $user, $password, $port, $query); + } + + public function getScheme(): string + { + return $this->scheme; + } + + public function getHost(): string + { + return $this->host; + } + + public function getUser(): ?string + { + return $this->user; + } + + public function getPassword(): ?string + { + return $this->password; + } + + public function getPort(int $default = null): ?int + { + return $this->port ?? $default; + } + + public function getOption(string $key, $default = null) + { + return $this->options[$key] ?? $default; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/FailoverTransport.php b/plugins/email/vendor/symfony/mailer/Transport/FailoverTransport.php new file mode 100644 index 0000000..4913901 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/FailoverTransport.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +/** + * Uses several Transports using a failover algorithm. + * + * @author Fabien Potencier + */ +class FailoverTransport extends RoundRobinTransport +{ + private $currentTransport; + + protected function getNextTransport(): ?TransportInterface + { + if (null === $this->currentTransport || $this->isTransportDead($this->currentTransport)) { + $this->currentTransport = parent::getNextTransport(); + } + + return $this->currentTransport; + } + + protected function getInitialCursor(): int + { + return 0; + } + + protected function getNameSymbol(): string + { + return 'failover'; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/NativeTransportFactory.php b/plugins/email/vendor/symfony/mailer/Transport/NativeTransportFactory.php new file mode 100644 index 0000000..8afa53c --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/NativeTransportFactory.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\Exception\UnsupportedSchemeException; +use Symfony\Component\Mailer\Transport\Smtp\SmtpTransport; +use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream; + +/** + * Factory that configures a transport (sendmail or SMTP) based on php.ini settings. + * + * @author Laurent VOULLEMIER + */ +final class NativeTransportFactory extends AbstractTransportFactory +{ + public function create(Dsn $dsn): TransportInterface + { + if (!\in_array($dsn->getScheme(), $this->getSupportedSchemes(), true)) { + throw new UnsupportedSchemeException($dsn, 'native', $this->getSupportedSchemes()); + } + + if ($sendMailPath = ini_get('sendmail_path')) { + return new SendmailTransport($sendMailPath, $this->dispatcher, $this->logger); + } + + if ('\\' !== \DIRECTORY_SEPARATOR) { + throw new TransportException('sendmail_path is not configured in php.ini.'); + } + + // Only for windows hosts; at this point non-windows + // host have already thrown an exception or returned a transport + $host = ini_get('SMTP'); + $port = (int) ini_get('smtp_port'); + + if (!$host || !$port) { + throw new TransportException('smtp or smtp_port is not configured in php.ini.'); + } + + $socketStream = new SocketStream(); + $socketStream->setHost($host); + $socketStream->setPort($port); + if (465 !== $port) { + $socketStream->disableTls(); + } + + return new SmtpTransport($socketStream, $this->dispatcher, $this->logger); + } + + protected function getSupportedSchemes(): array + { + return ['native']; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/NullTransport.php b/plugins/email/vendor/symfony/mailer/Transport/NullTransport.php new file mode 100644 index 0000000..92fb82a --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/NullTransport.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\SentMessage; + +/** + * Pretends messages have been sent, but just ignores them. + * + * @author Fabien Potencier + */ +final class NullTransport extends AbstractTransport +{ + protected function doSend(SentMessage $message): void + { + } + + public function __toString(): string + { + return 'null://'; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/NullTransportFactory.php b/plugins/email/vendor/symfony/mailer/Transport/NullTransportFactory.php new file mode 100644 index 0000000..4c45f39 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/NullTransportFactory.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Exception\UnsupportedSchemeException; + +/** + * @author Konstantin Myakshin + */ +final class NullTransportFactory extends AbstractTransportFactory +{ + public function create(Dsn $dsn): TransportInterface + { + if ('null' === $dsn->getScheme()) { + return new NullTransport($this->dispatcher, $this->logger); + } + + throw new UnsupportedSchemeException($dsn, 'null', $this->getSupportedSchemes()); + } + + protected function getSupportedSchemes(): array + { + return ['null']; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/RoundRobinTransport.php b/plugins/email/vendor/symfony/mailer/Transport/RoundRobinTransport.php new file mode 100644 index 0000000..2f35138 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/RoundRobinTransport.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mime\RawMessage; + +/** + * Uses several Transports using a round robin algorithm. + * + * @author Fabien Potencier + */ +class RoundRobinTransport implements TransportInterface +{ + /** + * @var \SplObjectStorage + */ + private $deadTransports; + private $transports = []; + private $retryPeriod; + private $cursor = -1; + + /** + * @param TransportInterface[] $transports + */ + public function __construct(array $transports, int $retryPeriod = 60) + { + if (!$transports) { + throw new TransportException(sprintf('"%s" must have at least one transport configured.', static::class)); + } + + $this->transports = $transports; + $this->deadTransports = new \SplObjectStorage(); + $this->retryPeriod = $retryPeriod; + } + + public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage + { + while ($transport = $this->getNextTransport()) { + try { + return $transport->send($message, $envelope); + } catch (TransportExceptionInterface $e) { + $this->deadTransports[$transport] = microtime(true); + } + } + + throw new TransportException('All transports failed.'); + } + + public function __toString(): string + { + return $this->getNameSymbol().'('.implode(' ', array_map('strval', $this->transports)).')'; + } + + /** + * Rotates the transport list around and returns the first instance. + */ + protected function getNextTransport(): ?TransportInterface + { + if (-1 === $this->cursor) { + $this->cursor = $this->getInitialCursor(); + } + + $cursor = $this->cursor; + while (true) { + $transport = $this->transports[$cursor]; + + if (!$this->isTransportDead($transport)) { + break; + } + + if ((microtime(true) - $this->deadTransports[$transport]) > $this->retryPeriod) { + $this->deadTransports->detach($transport); + + break; + } + + if ($this->cursor === $cursor = $this->moveCursor($cursor)) { + return null; + } + } + + $this->cursor = $this->moveCursor($cursor); + + return $transport; + } + + protected function isTransportDead(TransportInterface $transport): bool + { + return $this->deadTransports->contains($transport); + } + + protected function getInitialCursor(): int + { + // the cursor initial value is randomized so that + // when are not in a daemon, we are still rotating the transports + return mt_rand(0, \count($this->transports) - 1); + } + + protected function getNameSymbol(): string + { + return 'roundrobin'; + } + + private function moveCursor(int $cursor): int + { + return ++$cursor >= \count($this->transports) ? 0 : $cursor; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/SendmailTransport.php b/plugins/email/vendor/symfony/mailer/Transport/SendmailTransport.php new file mode 100644 index 0000000..43d0920 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/SendmailTransport.php @@ -0,0 +1,123 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\Transport\Smtp\SmtpTransport; +use Symfony\Component\Mailer\Transport\Smtp\Stream\AbstractStream; +use Symfony\Component\Mailer\Transport\Smtp\Stream\ProcessStream; +use Symfony\Component\Mime\RawMessage; + +/** + * SendmailTransport for sending mail through a Sendmail/Postfix (etc..) binary. + * + * Transport can be instanciated through SendmailTransportFactory or NativeTransportFactory: + * + * - SendmailTransportFactory to use most common sendmail path and recommanded options + * - NativeTransportFactory when configuration is set via php.ini + * + * @author Fabien Potencier + * @author Chris Corbyn + */ +class SendmailTransport extends AbstractTransport +{ + private $command = '/usr/sbin/sendmail -bs'; + private $stream; + private $transport; + + /** + * Constructor. + * + * Supported modes are -bs and -t, with any additional flags desired. + * + * The recommended mode is "-bs" since it is interactive and failure notifications are hence possible. + * Note that the -t mode does not support error reporting and does not support Bcc properly (the Bcc headers are not removed). + * + * If using -t mode, you are strongly advised to include -oi or -i in the flags (like /usr/sbin/sendmail -oi -t) + * + * -f flag will be appended automatically if one is not present. + */ + public function __construct(string $command = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + parent::__construct($dispatcher, $logger); + + if (null !== $command) { + if (!str_contains($command, ' -bs') && !str_contains($command, ' -t')) { + throw new \InvalidArgumentException(sprintf('Unsupported sendmail command flags "%s"; must be one of "-bs" or "-t" but can include additional flags.', $command)); + } + + $this->command = $command; + } + + $this->stream = new ProcessStream(); + if (str_contains($this->command, ' -bs')) { + $this->stream->setCommand($this->command); + $this->transport = new SmtpTransport($this->stream, $dispatcher, $logger); + } + } + + public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage + { + if ($this->transport) { + return $this->transport->send($message, $envelope); + } + + return parent::send($message, $envelope); + } + + public function __toString(): string + { + if ($this->transport) { + return (string) $this->transport; + } + + return 'smtp://sendmail'; + } + + protected function doSend(SentMessage $message): void + { + $this->getLogger()->debug(sprintf('Email transport "%s" starting', __CLASS__)); + + $command = $this->command; + + if ($recipients = $message->getEnvelope()->getRecipients()) { + $command = str_replace(' -t', '', $command); + } + + if (!str_contains($command, ' -f')) { + $command .= ' -f'.escapeshellarg($message->getEnvelope()->getSender()->getEncodedAddress()); + } + + $chunks = AbstractStream::replace("\r\n", "\n", $message->toIterable()); + + if (!str_contains($command, ' -i') && !str_contains($command, ' -oi')) { + $chunks = AbstractStream::replace("\n.", "\n..", $chunks); + } + + foreach ($recipients as $recipient) { + $command .= ' '.escapeshellarg($recipient->getEncodedAddress()); + } + + $this->stream->setCommand($command); + $this->stream->initialize(); + foreach ($chunks as $chunk) { + $this->stream->write($chunk); + } + $this->stream->flush(); + $this->stream->terminate(); + + $this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__)); + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/SendmailTransportFactory.php b/plugins/email/vendor/symfony/mailer/Transport/SendmailTransportFactory.php new file mode 100644 index 0000000..6d977e7 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/SendmailTransportFactory.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Exception\UnsupportedSchemeException; + +/** + * @author Konstantin Myakshin + */ +final class SendmailTransportFactory extends AbstractTransportFactory +{ + public function create(Dsn $dsn): TransportInterface + { + if ('sendmail+smtp' === $dsn->getScheme() || 'sendmail' === $dsn->getScheme()) { + return new SendmailTransport($dsn->getOption('command'), $this->dispatcher, $this->logger); + } + + throw new UnsupportedSchemeException($dsn, 'sendmail', $this->getSupportedSchemes()); + } + + protected function getSupportedSchemes(): array + { + return ['sendmail', 'sendmail+smtp']; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/AuthenticatorInterface.php b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/AuthenticatorInterface.php new file mode 100644 index 0000000..98ea2d4 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/AuthenticatorInterface.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Auth; + +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * An Authentication mechanism. + * + * @author Chris Corbyn + */ +interface AuthenticatorInterface +{ + /** + * Tries to authenticate the user. + * + * @throws TransportExceptionInterface + */ + public function authenticate(EsmtpTransport $client): void; + + /** + * Gets the name of the AUTH mechanism this Authenticator handles. + */ + public function getAuthKeyword(): string; +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/CramMd5Authenticator.php b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/CramMd5Authenticator.php new file mode 100644 index 0000000..b2ec7b0 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/CramMd5Authenticator.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Auth; + +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * Handles CRAM-MD5 authentication. + * + * @author Chris Corbyn + */ +class CramMd5Authenticator implements AuthenticatorInterface +{ + public function getAuthKeyword(): string + { + return 'CRAM-MD5'; + } + + /** + * {@inheritdoc} + * + * @see https://www.ietf.org/rfc/rfc4954.txt + */ + public function authenticate(EsmtpTransport $client): void + { + $challenge = $client->executeCommand("AUTH CRAM-MD5\r\n", [334]); + $challenge = base64_decode(substr($challenge, 4)); + $message = base64_encode($client->getUsername().' '.$this->getResponse($client->getPassword(), $challenge)); + $client->executeCommand(sprintf("%s\r\n", $message), [235]); + } + + /** + * Generates a CRAM-MD5 response from a server challenge. + */ + private function getResponse(string $secret, string $challenge): string + { + if (\strlen($secret) > 64) { + $secret = pack('H32', md5($secret)); + } + + if (\strlen($secret) < 64) { + $secret = str_pad($secret, 64, \chr(0)); + } + + $kipad = substr($secret, 0, 64) ^ str_repeat(\chr(0x36), 64); + $kopad = substr($secret, 0, 64) ^ str_repeat(\chr(0x5C), 64); + + $inner = pack('H32', md5($kipad.$challenge)); + $digest = md5($kopad.$inner); + + return $digest; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/LoginAuthenticator.php b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/LoginAuthenticator.php new file mode 100644 index 0000000..1ce321d --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/LoginAuthenticator.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Auth; + +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * Handles LOGIN authentication. + * + * @author Chris Corbyn + */ +class LoginAuthenticator implements AuthenticatorInterface +{ + public function getAuthKeyword(): string + { + return 'LOGIN'; + } + + /** + * {@inheritdoc} + * + * @see https://www.ietf.org/rfc/rfc4954.txt + */ + public function authenticate(EsmtpTransport $client): void + { + $client->executeCommand("AUTH LOGIN\r\n", [334]); + $client->executeCommand(sprintf("%s\r\n", base64_encode($client->getUsername())), [334]); + $client->executeCommand(sprintf("%s\r\n", base64_encode($client->getPassword())), [235]); + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/PlainAuthenticator.php b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/PlainAuthenticator.php new file mode 100644 index 0000000..8d60690 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/PlainAuthenticator.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Auth; + +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * Handles PLAIN authentication. + * + * @author Chris Corbyn + */ +class PlainAuthenticator implements AuthenticatorInterface +{ + public function getAuthKeyword(): string + { + return 'PLAIN'; + } + + /** + * {@inheritdoc} + * + * @see https://www.ietf.org/rfc/rfc4954.txt + */ + public function authenticate(EsmtpTransport $client): void + { + $client->executeCommand(sprintf("AUTH PLAIN %s\r\n", base64_encode($client->getUsername().\chr(0).$client->getUsername().\chr(0).$client->getPassword())), [235]); + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php new file mode 100644 index 0000000..7941776 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Auth; + +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * Handles XOAUTH2 authentication. + * + * @author xu.li + * + * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol + */ +class XOAuth2Authenticator implements AuthenticatorInterface +{ + public function getAuthKeyword(): string + { + return 'XOAUTH2'; + } + + /** + * {@inheritdoc} + * + * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol#the_sasl_xoauth2_mechanism + */ + public function authenticate(EsmtpTransport $client): void + { + $client->executeCommand('AUTH XOAUTH2 '.base64_encode('user='.$client->getUsername()."\1auth=Bearer ".$client->getPassword()."\1\1")."\r\n", [235]); + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/Smtp/EsmtpTransport.php b/plugins/email/vendor/symfony/mailer/Transport/Smtp/EsmtpTransport.php new file mode 100644 index 0000000..1dcb53f --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/Smtp/EsmtpTransport.php @@ -0,0 +1,200 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\Transport\Smtp\Auth\AuthenticatorInterface; +use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream; + +/** + * Sends Emails over SMTP with ESMTP support. + * + * @author Fabien Potencier + * @author Chris Corbyn + */ +class EsmtpTransport extends SmtpTransport +{ + private $authenticators = []; + private $username = ''; + private $password = ''; + + public function __construct(string $host = 'localhost', int $port = 0, bool $tls = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + parent::__construct(null, $dispatcher, $logger); + + // order is important here (roughly most secure and popular first) + $this->authenticators = [ + new Auth\CramMd5Authenticator(), + new Auth\LoginAuthenticator(), + new Auth\PlainAuthenticator(), + new Auth\XOAuth2Authenticator(), + ]; + + /** @var SocketStream $stream */ + $stream = $this->getStream(); + + if (null === $tls) { + if (465 === $port) { + $tls = true; + } else { + $tls = \defined('OPENSSL_VERSION_NUMBER') && 0 === $port && 'localhost' !== $host; + } + } + if (!$tls) { + $stream->disableTls(); + } + if (0 === $port) { + $port = $tls ? 465 : 25; + } + + $stream->setHost($host); + $stream->setPort($port); + } + + /** + * @return $this + */ + public function setUsername(string $username): self + { + $this->username = $username; + + return $this; + } + + public function getUsername(): string + { + return $this->username; + } + + /** + * @return $this + */ + public function setPassword(string $password): self + { + $this->password = $password; + + return $this; + } + + public function getPassword(): string + { + return $this->password; + } + + public function addAuthenticator(AuthenticatorInterface $authenticator): void + { + $this->authenticators[] = $authenticator; + } + + protected function doHeloCommand(): void + { + if (!$capabilities = $this->callHeloCommand()) { + return; + } + + /** @var SocketStream $stream */ + $stream = $this->getStream(); + // WARNING: !$stream->isTLS() is right, 100% sure :) + // if you think that the ! should be removed, read the code again + // if doing so "fixes" your issue then it probably means your SMTP server behaves incorrectly or is wrongly configured + if (!$stream->isTLS() && \defined('OPENSSL_VERSION_NUMBER') && \array_key_exists('STARTTLS', $capabilities)) { + $this->executeCommand("STARTTLS\r\n", [220]); + + if (!$stream->startTLS()) { + throw new TransportException('Unable to connect with STARTTLS.'); + } + + $capabilities = $this->callHeloCommand(); + } + + if (\array_key_exists('AUTH', $capabilities)) { + $this->handleAuth($capabilities['AUTH']); + } + } + + private function callHeloCommand(): array + { + try { + $response = $this->executeCommand(sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]); + } catch (TransportExceptionInterface $e) { + try { + parent::doHeloCommand(); + + return []; + } catch (TransportExceptionInterface $ex) { + if (!$ex->getCode()) { + throw $e; + } + + throw $ex; + } + } + + $capabilities = []; + $lines = explode("\r\n", trim($response)); + array_shift($lines); + foreach ($lines as $line) { + if (preg_match('/^[0-9]{3}[ -]([A-Z0-9-]+)((?:[ =].*)?)$/Di', $line, $matches)) { + $value = strtoupper(ltrim($matches[2], ' =')); + $capabilities[strtoupper($matches[1])] = $value ? explode(' ', $value) : []; + } + } + + return $capabilities; + } + + private function handleAuth(array $modes): void + { + if (!$this->username) { + return; + } + + $authNames = []; + $errors = []; + $modes = array_map('strtolower', $modes); + foreach ($this->authenticators as $authenticator) { + if (!\in_array(strtolower($authenticator->getAuthKeyword()), $modes, true)) { + continue; + } + + $authNames[] = $authenticator->getAuthKeyword(); + try { + $authenticator->authenticate($this); + + return; + } catch (TransportExceptionInterface $e) { + try { + $this->executeCommand("RSET\r\n", [250]); + } catch (TransportExceptionInterface $_) { + // ignore this exception as it probably means that the server error was final + } + + // keep the error message, but tries the other authenticators + $errors[$authenticator->getAuthKeyword()] = $e->getMessage(); + } + } + + if (!$authNames) { + throw new TransportException(sprintf('Failed to find an authenticator supported by the SMTP server, which currently supports: "%s".', implode('", "', $modes))); + } + + $message = sprintf('Failed to authenticate on SMTP server with username "%s" using the following authenticators: "%s".', $this->username, implode('", "', $authNames)); + foreach ($errors as $name => $error) { + $message .= sprintf(' Authenticator "%s" returned "%s".', $name, $error); + } + + throw new TransportException($message); + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/Smtp/EsmtpTransportFactory.php b/plugins/email/vendor/symfony/mailer/Transport/Smtp/EsmtpTransportFactory.php new file mode 100644 index 0000000..e2a280e --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/Smtp/EsmtpTransportFactory.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp; + +use Symfony\Component\Mailer\Transport\AbstractTransportFactory; +use Symfony\Component\Mailer\Transport\Dsn; +use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream; +use Symfony\Component\Mailer\Transport\TransportInterface; + +/** + * @author Konstantin Myakshin + */ +final class EsmtpTransportFactory extends AbstractTransportFactory +{ + public function create(Dsn $dsn): TransportInterface + { + $tls = 'smtps' === $dsn->getScheme() ? true : null; + $port = $dsn->getPort(0); + $host = $dsn->getHost(); + + $transport = new EsmtpTransport($host, $port, $tls, $this->dispatcher, $this->logger); + + if ('' !== $dsn->getOption('verify_peer') && !filter_var($dsn->getOption('verify_peer', true), \FILTER_VALIDATE_BOOLEAN)) { + /** @var SocketStream $stream */ + $stream = $transport->getStream(); + $streamOptions = $stream->getStreamOptions(); + + $streamOptions['ssl']['verify_peer'] = false; + $streamOptions['ssl']['verify_peer_name'] = false; + + $stream->setStreamOptions($streamOptions); + } + + if ($user = $dsn->getUser()) { + $transport->setUsername($user); + } + + if ($password = $dsn->getPassword()) { + $transport->setPassword($password); + } + + if (null !== ($localDomain = $dsn->getOption('local_domain'))) { + $transport->setLocalDomain($localDomain); + } + + if (null !== ($restartThreshold = $dsn->getOption('restart_threshold'))) { + $transport->setRestartThreshold((int) $restartThreshold, (int) $dsn->getOption('restart_threshold_sleep', 0)); + } + + if (null !== ($pingThreshold = $dsn->getOption('ping_threshold'))) { + $transport->setPingThreshold((int) $pingThreshold); + } + + return $transport; + } + + protected function getSupportedSchemes(): array + { + return ['smtp', 'smtps']; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/Smtp/SmtpTransport.php b/plugins/email/vendor/symfony/mailer/Transport/Smtp/SmtpTransport.php new file mode 100644 index 0000000..92af6aa --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/Smtp/SmtpTransport.php @@ -0,0 +1,361 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp; + +use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Exception\LogicException; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\Transport\AbstractTransport; +use Symfony\Component\Mailer\Transport\Smtp\Stream\AbstractStream; +use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream; +use Symfony\Component\Mime\RawMessage; + +/** + * Sends emails over SMTP. + * + * @author Fabien Potencier + * @author Chris Corbyn + */ +class SmtpTransport extends AbstractTransport +{ + private $started = false; + private $restartThreshold = 100; + private $restartThresholdSleep = 0; + private $restartCounter; + private $pingThreshold = 100; + private $lastMessageTime = 0; + private $stream; + private $domain = '[127.0.0.1]'; + + public function __construct(AbstractStream $stream = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + parent::__construct($dispatcher, $logger); + + $this->stream = $stream ?? new SocketStream(); + } + + public function getStream(): AbstractStream + { + return $this->stream; + } + + /** + * Sets the maximum number of messages to send before re-starting the transport. + * + * By default, the threshold is set to 100 (and no sleep at restart). + * + * @param int $threshold The maximum number of messages (0 to disable) + * @param int $sleep The number of seconds to sleep between stopping and re-starting the transport + * + * @return $this + */ + public function setRestartThreshold(int $threshold, int $sleep = 0): self + { + $this->restartThreshold = $threshold; + $this->restartThresholdSleep = $sleep; + + return $this; + } + + /** + * Sets the minimum number of seconds required between two messages, before the server is pinged. + * If the transport wants to send a message and the time since the last message exceeds the specified threshold, + * the transport will ping the server first (NOOP command) to check if the connection is still alive. + * Otherwise the message will be sent without pinging the server first. + * + * Do not set the threshold too low, as the SMTP server may drop the connection if there are too many + * non-mail commands (like pinging the server with NOOP). + * + * By default, the threshold is set to 100 seconds. + * + * @param int $seconds The minimum number of seconds between two messages required to ping the server + * + * @return $this + */ + public function setPingThreshold(int $seconds): self + { + $this->pingThreshold = $seconds; + + return $this; + } + + /** + * Sets the name of the local domain that will be used in HELO. + * + * This should be a fully-qualified domain name and should be truly the domain + * you're using. + * + * If your server does not have a domain name, use the IP address. This will + * automatically be wrapped in square brackets as described in RFC 5321, + * section 4.1.3. + * + * @return $this + */ + public function setLocalDomain(string $domain): self + { + if ('' !== $domain && '[' !== $domain[0]) { + if (filter_var($domain, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) { + $domain = '['.$domain.']'; + } elseif (filter_var($domain, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) { + $domain = '[IPv6:'.$domain.']'; + } + } + + $this->domain = $domain; + + return $this; + } + + /** + * Gets the name of the domain that will be used in HELO. + * + * If an IP address was specified, this will be returned wrapped in square + * brackets as described in RFC 5321, section 4.1.3. + */ + public function getLocalDomain(): string + { + return $this->domain; + } + + public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage + { + try { + $message = parent::send($message, $envelope); + } catch (TransportExceptionInterface $e) { + if ($this->started) { + try { + $this->executeCommand("RSET\r\n", [250]); + } catch (TransportExceptionInterface $_) { + // ignore this exception as it probably means that the server error was final + } + } + + throw $e; + } + + $this->checkRestartThreshold(); + + return $message; + } + + public function __toString(): string + { + if ($this->stream instanceof SocketStream) { + $name = sprintf('smtp%s://%s', ($tls = $this->stream->isTLS()) ? 's' : '', $this->stream->getHost()); + $port = $this->stream->getPort(); + if (!(25 === $port || ($tls && 465 === $port))) { + $name .= ':'.$port; + } + + return $name; + } + + return 'smtp://sendmail'; + } + + /** + * Runs a command against the stream, expecting the given response codes. + * + * @param int[] $codes + * + * @throws TransportException when an invalid response if received + * + * @internal + */ + public function executeCommand(string $command, array $codes): string + { + $this->stream->write($command); + $response = $this->getFullResponse(); + $this->assertResponseCode($response, $codes); + + return $response; + } + + protected function doSend(SentMessage $message): void + { + if (microtime(true) - $this->lastMessageTime > $this->pingThreshold) { + $this->ping(); + } + + if (!$this->started) { + $this->start(); + } + + try { + $envelope = $message->getEnvelope(); + $this->doMailFromCommand($envelope->getSender()->getEncodedAddress()); + foreach ($envelope->getRecipients() as $recipient) { + $this->doRcptToCommand($recipient->getEncodedAddress()); + } + + $this->executeCommand("DATA\r\n", [354]); + try { + foreach (AbstractStream::replace("\r\n.", "\r\n..", $message->toIterable()) as $chunk) { + $this->stream->write($chunk, false); + } + $this->stream->flush(); + } catch (TransportExceptionInterface $e) { + throw $e; + } catch (\Exception $e) { + $this->stream->terminate(); + $this->started = false; + $this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__)); + throw $e; + } + $this->executeCommand("\r\n.\r\n", [250]); + $message->appendDebug($this->stream->getDebug()); + $this->lastMessageTime = microtime(true); + } catch (TransportExceptionInterface $e) { + $e->appendDebug($this->stream->getDebug()); + $this->lastMessageTime = 0; + throw $e; + } + } + + protected function doHeloCommand(): void + { + $this->executeCommand(sprintf("HELO %s\r\n", $this->domain), [250]); + } + + private function doMailFromCommand(string $address): void + { + $this->executeCommand(sprintf("MAIL FROM:<%s>\r\n", $address), [250]); + } + + private function doRcptToCommand(string $address): void + { + $this->executeCommand(sprintf("RCPT TO:<%s>\r\n", $address), [250, 251, 252]); + } + + private function start(): void + { + if ($this->started) { + return; + } + + $this->getLogger()->debug(sprintf('Email transport "%s" starting', __CLASS__)); + + $this->stream->initialize(); + $this->assertResponseCode($this->getFullResponse(), [220]); + $this->doHeloCommand(); + $this->started = true; + $this->lastMessageTime = 0; + + $this->getLogger()->debug(sprintf('Email transport "%s" started', __CLASS__)); + } + + private function stop(): void + { + if (!$this->started) { + return; + } + + $this->getLogger()->debug(sprintf('Email transport "%s" stopping', __CLASS__)); + + try { + $this->executeCommand("QUIT\r\n", [221]); + } catch (TransportExceptionInterface $e) { + } finally { + $this->stream->terminate(); + $this->started = false; + $this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__)); + } + } + + private function ping(): void + { + if (!$this->started) { + return; + } + + try { + $this->executeCommand("NOOP\r\n", [250]); + } catch (TransportExceptionInterface $e) { + $this->stop(); + } + } + + /** + * @throws TransportException if a response code is incorrect + */ + private function assertResponseCode(string $response, array $codes): void + { + if (!$codes) { + throw new LogicException('You must set the expected response code.'); + } + + [$code] = sscanf($response, '%3d'); + $valid = \in_array($code, $codes); + + if (!$valid || !$response) { + $codeStr = $code ? sprintf('code "%s"', $code) : 'empty code'; + $responseStr = $response ? sprintf(', with message "%s"', trim($response)) : ''; + + throw new TransportException(sprintf('Expected response code "%s" but got ', implode('/', $codes)).$codeStr.$responseStr.'.', $code ?: 0); + } + } + + private function getFullResponse(): string + { + $response = ''; + do { + $line = $this->stream->readLine(); + $response .= $line; + } while ($line && isset($line[3]) && ' ' !== $line[3]); + + return $response; + } + + private function checkRestartThreshold(): void + { + // when using sendmail via non-interactive mode, the transport is never "started" + if (!$this->started) { + return; + } + + ++$this->restartCounter; + if ($this->restartCounter < $this->restartThreshold) { + return; + } + + $this->stop(); + if (0 < $sleep = $this->restartThresholdSleep) { + $this->getLogger()->debug(sprintf('Email transport "%s" sleeps for %d seconds after stopping', __CLASS__, $sleep)); + + sleep($sleep); + } + $this->start(); + $this->restartCounter = 0; + } + + /** + * @return array + */ + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + public function __destruct() + { + $this->stop(); + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/Smtp/Stream/AbstractStream.php b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Stream/AbstractStream.php new file mode 100644 index 0000000..28cb616 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Stream/AbstractStream.php @@ -0,0 +1,138 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Stream; + +use Symfony\Component\Mailer\Exception\TransportException; + +/** + * A stream supporting remote sockets and local processes. + * + * @author Fabien Potencier + * @author Nicolas Grekas + * @author Chris Corbyn + * + * @internal + */ +abstract class AbstractStream +{ + protected $stream; + protected $in; + protected $out; + + private $debug = ''; + + public function write(string $bytes, bool $debug = true): void + { + if ($debug) { + foreach (explode("\n", trim($bytes)) as $line) { + $this->debug .= sprintf("> %s\n", $line); + } + } + + $bytesToWrite = \strlen($bytes); + $totalBytesWritten = 0; + while ($totalBytesWritten < $bytesToWrite) { + $bytesWritten = @fwrite($this->in, substr($bytes, $totalBytesWritten)); + if (false === $bytesWritten || 0 === $bytesWritten) { + throw new TransportException('Unable to write bytes on the wire.'); + } + + $totalBytesWritten += $bytesWritten; + } + } + + /** + * Flushes the contents of the stream (empty it) and set the internal pointer to the beginning. + */ + public function flush(): void + { + fflush($this->in); + } + + /** + * Performs any initialization needed. + */ + abstract public function initialize(): void; + + public function terminate(): void + { + $this->stream = $this->out = $this->in = null; + } + + public function readLine(): string + { + if (feof($this->out)) { + return ''; + } + + $line = fgets($this->out); + if ('' === $line) { + $metas = stream_get_meta_data($this->out); + if ($metas['timed_out']) { + throw new TransportException(sprintf('Connection to "%s" timed out.', $this->getReadConnectionDescription())); + } + if ($metas['eof']) { + throw new TransportException(sprintf('Connection to "%s" has been closed unexpectedly.', $this->getReadConnectionDescription())); + } + } + + $this->debug .= sprintf('< %s', $line); + + return $line; + } + + public function getDebug(): string + { + $debug = $this->debug; + $this->debug = ''; + + return $debug; + } + + public static function replace(string $from, string $to, iterable $chunks): \Generator + { + if ('' === $from) { + yield from $chunks; + + return; + } + + $carry = ''; + $fromLen = \strlen($from); + + foreach ($chunks as $chunk) { + if ('' === $chunk = $carry.$chunk) { + continue; + } + + if (str_contains($chunk, $from)) { + $chunk = explode($from, $chunk); + $carry = array_pop($chunk); + + yield implode($to, $chunk).$to; + } else { + $carry = $chunk; + } + + if (\strlen($carry) > $fromLen) { + yield substr($carry, 0, -$fromLen); + $carry = substr($carry, -$fromLen); + } + } + + if ('' !== $carry) { + yield $carry; + } + } + + abstract protected function getReadConnectionDescription(): string; +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/Smtp/Stream/ProcessStream.php b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Stream/ProcessStream.php new file mode 100644 index 0000000..a8a8603 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Stream/ProcessStream.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Stream; + +use Symfony\Component\Mailer\Exception\TransportException; + +/** + * A stream supporting local processes. + * + * @author Fabien Potencier + * @author Chris Corbyn + * + * @internal + */ +final class ProcessStream extends AbstractStream +{ + private $command; + + public function setCommand(string $command) + { + $this->command = $command; + } + + public function initialize(): void + { + $descriptorSpec = [ + 0 => ['pipe', 'r'], + 1 => ['pipe', 'w'], + 2 => ['pipe', 'w'], + ]; + $pipes = []; + $this->stream = proc_open($this->command, $descriptorSpec, $pipes); + stream_set_blocking($pipes[2], false); + if ($err = stream_get_contents($pipes[2])) { + throw new TransportException('Process could not be started: '.$err); + } + $this->in = &$pipes[0]; + $this->out = &$pipes[1]; + } + + public function terminate(): void + { + if (null !== $this->stream) { + fclose($this->in); + fclose($this->out); + proc_close($this->stream); + } + + parent::terminate(); + } + + protected function getReadConnectionDescription(): string + { + return 'process '.$this->command; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/Smtp/Stream/SocketStream.php b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Stream/SocketStream.php new file mode 100644 index 0000000..144ab7f --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/Smtp/Stream/SocketStream.php @@ -0,0 +1,193 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Stream; + +use Symfony\Component\Mailer\Exception\TransportException; + +/** + * A stream supporting remote sockets. + * + * @author Fabien Potencier + * @author Chris Corbyn + * + * @internal + */ +final class SocketStream extends AbstractStream +{ + private $url; + private $host = 'localhost'; + private $port = 465; + private $timeout; + private $tls = true; + private $sourceIp; + private $streamContextOptions = []; + + /** + * @return $this + */ + public function setTimeout(float $timeout): self + { + $this->timeout = $timeout; + + return $this; + } + + public function getTimeout(): float + { + return $this->timeout ?? (float) \ini_get('default_socket_timeout'); + } + + /** + * Literal IPv6 addresses should be wrapped in square brackets. + * + * @return $this + */ + public function setHost(string $host): self + { + $this->host = $host; + + return $this; + } + + public function getHost(): string + { + return $this->host; + } + + /** + * @return $this + */ + public function setPort(int $port): self + { + $this->port = $port; + + return $this; + } + + public function getPort(): int + { + return $this->port; + } + + /** + * Sets the TLS/SSL on the socket (disables STARTTLS). + * + * @return $this + */ + public function disableTls(): self + { + $this->tls = false; + + return $this; + } + + public function isTLS(): bool + { + return $this->tls; + } + + /** + * @return $this + */ + public function setStreamOptions(array $options): self + { + $this->streamContextOptions = $options; + + return $this; + } + + public function getStreamOptions(): array + { + return $this->streamContextOptions; + } + + /** + * Sets the source IP. + * + * IPv6 addresses should be wrapped in square brackets. + * + * @return $this + */ + public function setSourceIp(string $ip): self + { + $this->sourceIp = $ip; + + return $this; + } + + /** + * Returns the IP used to connect to the destination. + */ + public function getSourceIp(): ?string + { + return $this->sourceIp; + } + + public function initialize(): void + { + $this->url = $this->host.':'.$this->port; + if ($this->tls) { + $this->url = 'ssl://'.$this->url; + } + $options = []; + if ($this->sourceIp) { + $options['socket']['bindto'] = $this->sourceIp.':0'; + } + if ($this->streamContextOptions) { + $options = array_merge($options, $this->streamContextOptions); + } + // do it unconditionnally as it will be used by STARTTLS as well if supported + $options['ssl']['crypto_method'] = $options['ssl']['crypto_method'] ?? \STREAM_CRYPTO_METHOD_TLS_CLIENT | \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT | \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; + $streamContext = stream_context_create($options); + + $timeout = $this->getTimeout(); + set_error_handler(function ($type, $msg) { + throw new TransportException(sprintf('Connection could not be established with host "%s": ', $this->url).$msg); + }); + try { + $this->stream = stream_socket_client($this->url, $errno, $errstr, $timeout, \STREAM_CLIENT_CONNECT, $streamContext); + } finally { + restore_error_handler(); + } + + stream_set_blocking($this->stream, true); + stream_set_timeout($this->stream, $timeout); + $this->in = &$this->stream; + $this->out = &$this->stream; + } + + public function startTLS(): bool + { + set_error_handler(function ($type, $msg) { + throw new TransportException('Unable to connect with STARTTLS: '.$msg); + }); + try { + return stream_socket_enable_crypto($this->stream, true); + } finally { + restore_error_handler(); + } + } + + public function terminate(): void + { + if (null !== $this->stream) { + fclose($this->stream); + } + + parent::terminate(); + } + + protected function getReadConnectionDescription(): string + { + return $this->url; + } +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/TransportFactoryInterface.php b/plugins/email/vendor/symfony/mailer/Transport/TransportFactoryInterface.php new file mode 100644 index 0000000..9785ae8 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/TransportFactoryInterface.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Exception\IncompleteDsnException; +use Symfony\Component\Mailer\Exception\UnsupportedSchemeException; + +/** + * @author Konstantin Myakshin + */ +interface TransportFactoryInterface +{ + /** + * @throws UnsupportedSchemeException + * @throws IncompleteDsnException + */ + public function create(Dsn $dsn): TransportInterface; + + public function supports(Dsn $dsn): bool; +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/TransportInterface.php b/plugins/email/vendor/symfony/mailer/Transport/TransportInterface.php new file mode 100644 index 0000000..ed562cf --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/TransportInterface.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mime\RawMessage; + +/** + * Interface for all mailer transports. + * + * When sending emails, you should prefer MailerInterface implementations + * as they allow asynchronous sending. + * + * @author Fabien Potencier + */ +interface TransportInterface +{ + /** + * @throws TransportExceptionInterface + */ + public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage; + + public function __toString(): string; +} diff --git a/plugins/email/vendor/symfony/mailer/Transport/Transports.php b/plugins/email/vendor/symfony/mailer/Transport/Transports.php new file mode 100644 index 0000000..702fc5c --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/Transport/Transports.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Exception\InvalidArgumentException; +use Symfony\Component\Mailer\Exception\LogicException; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + */ +final class Transports implements TransportInterface +{ + private $transports; + private $default; + + /** + * @param TransportInterface[] $transports + */ + public function __construct(iterable $transports) + { + $this->transports = []; + foreach ($transports as $name => $transport) { + if (null === $this->default) { + $this->default = $transport; + } + $this->transports[$name] = $transport; + } + + if (!$this->transports) { + throw new LogicException(sprintf('"%s" must have at least one transport configured.', __CLASS__)); + } + } + + public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage + { + /** @var Message $message */ + if (RawMessage::class === \get_class($message) || !$message->getHeaders()->has('X-Transport')) { + return $this->default->send($message, $envelope); + } + + $headers = $message->getHeaders(); + $transport = $headers->get('X-Transport')->getBody(); + $headers->remove('X-Transport'); + + if (!isset($this->transports[$transport])) { + throw new InvalidArgumentException(sprintf('The "%s" transport does not exist (available transports: "%s").', $transport, implode('", "', array_keys($this->transports)))); + } + + try { + return $this->transports[$transport]->send($message, $envelope); + } catch (\Throwable $e) { + $headers->addTextHeader('X-Transport', $transport); + + throw $e; + } + } + + public function __toString(): string + { + return '['.implode(',', array_keys($this->transports)).']'; + } +} diff --git a/plugins/email/vendor/symfony/mailer/composer.json b/plugins/email/vendor/symfony/mailer/composer.json new file mode 100644 index 0000000..53cf0f5 --- /dev/null +++ b/plugins/email/vendor/symfony/mailer/composer.json @@ -0,0 +1,43 @@ +{ + "name": "symfony/mailer", + "type": "library", + "description": "Helps sending emails", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "egulias/email-validator": "^2.1.10|^3", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/mime": "^5.2.6|^6.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2|^3" + }, + "require-dev": { + "symfony/http-client-contracts": "^1.1|^2|^3", + "symfony/messenger": "^4.4|^5.0|^6.0" + }, + "conflict": { + "symfony/http-kernel": "<4.4" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Mailer\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/plugins/email/vendor/symfony/messenger/Attribute/AsMessageHandler.php b/plugins/email/vendor/symfony/messenger/Attribute/AsMessageHandler.php new file mode 100644 index 0000000..8c12a80 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Attribute/AsMessageHandler.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Attribute; + +/** + * Service tag to autoconfigure message handlers. + * + * @author Alireza Mirsepassi + */ +#[\Attribute(\Attribute::TARGET_CLASS)] +class AsMessageHandler +{ + public function __construct( + public ?string $bus = null, + public ?string $fromTransport = null, + public ?string $handles = null, + public ?string $method = null, + public int $priority = 0, + ) { + } +} diff --git a/plugins/email/vendor/symfony/messenger/CHANGELOG.md b/plugins/email/vendor/symfony/messenger/CHANGELOG.md new file mode 100644 index 0000000..ede59fe --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/CHANGELOG.md @@ -0,0 +1,212 @@ +CHANGELOG +========= + +5.4 +--- + + * Add `AsMessageHandler` attribute for declaring message handlers on PHP 8. + * Add support for handling messages in batches with `BatchHandlerInterface` and corresponding trait + * Add `StopWorkerExceptionInterface` and its implementation `StopWorkerException` to stop the worker. + * Add support for resetting container services after each messenger message. + * Added `WorkerMetadata` class which allows you to access the configuration details of a worker, like `queueNames` and `transportNames` it consumes from. + * New method `getMetadata()` was added to `Worker` class which returns the `WorkerMetadata` object. + * Deprecate not setting the `reset_on_message` config option, its default value will change to `true` in 6.0 + * Add log when worker should stop. + * Add log when `SIGTERM` is received. + +5.3 +--- + + * Add the `RouterContextMiddleware` to restore the original router context when handling a message + * `InMemoryTransport` can perform message serialization through dsn `in-memory://?serialize=true`. + * Added `queues` option to `Worker` to only fetch messages from a specific queue from a receiver implementing `QueueReceiverInterface`. + +5.2.0 +----- + + * The `RedeliveryStamp` will no longer be populated with error data. This information is now stored in the `ErrorDetailsStamp` instead. + * Added `FlattenExceptionNormalizer` to give more information about the exception on Messenger background processes. The `FlattenExceptionNormalizer` has a higher priority than `ProblemNormalizer` and it is only used when the Messenger serialization context is set. + * Added factory methods `DelayStamp::delayFor(\DateInterval)` and `DelayStamp::delayUntil(\DateTimeInterface)`. + * Removed the exception when dispatching a message with a `DispatchAfterCurrentBusStamp` and not in a context of another dispatch call + * Added `WorkerMessageRetriedEvent` + * Added `WorkerMessageReceivedEvent::setEnvelope()` and made event mutable + +5.1.0 +----- + + * Moved AmqpExt transport to package `symfony/amqp-messenger`. All classes in `Symfony\Component\Messenger\Transport\AmqpExt` have been moved to `Symfony\Component\Messenger\Bridge\Amqp\Transport` + * Moved Doctrine transport to package `symfony/doctrine-messenger`. All classes in `Symfony\Component\Messenger\Transport\Doctrine` have been moved to `Symfony\Component\Messenger\Bridge\Doctrine\Transport` + * Moved RedisExt transport to package `symfony/redis-messenger`. All classes in `Symfony\Component\Messenger\Transport\RedisExt` have been moved to `Symfony\Component\Messenger\Bridge\Redis\Transport` + * Added support for passing a `\Throwable` argument to `RetryStrategyInterface` methods. This allows to define strategies based on the reason of the handling failure. + * Added `StopWorkerOnFailureLimitListener` to stop the worker after a specified amount of failed messages is reached. + * Added `RecoverableExceptionInterface` interface to force retry. + +5.0.0 +----- + + * The `LoggingMiddleware` class has been removed, pass a logger to `SendMessageMiddleware` instead. + * made `SendersLocator` require a `ContainerInterface` as 2nd argument + +4.4.0 +----- + + * Added support for auto trimming of Redis streams. + * `InMemoryTransport` handle acknowledged and rejected messages. + * Made all dispatched worker event classes final. + * Added support for `from_transport` attribute on `messenger.message_handler` tag. + * Added support for passing `dbindex` as a query parameter to the redis transport DSN. + * Added `WorkerStartedEvent` and `WorkerRunningEvent` + * [BC BREAK] Removed `SendersLocatorInterface::getSenderByAlias` added in 4.3. + * [BC BREAK] Removed `$retryStrategies` argument from `Worker::__construct`. + * [BC BREAK] Changed arguments of `ConsumeMessagesCommand::__construct`. + * [BC BREAK] Removed `$senderClassOrAlias` argument from `RedeliveryStamp::__construct`. + * [BC BREAK] Removed `UnknownSenderException`. + * [BC BREAK] Removed `WorkerInterface`. + * [BC BREAK] Removed `$onHandledCallback` of `Worker::run(array $options = [], callable $onHandledCallback = null)`. + * [BC BREAK] Removed `StopWhenMemoryUsageIsExceededWorker` in favor of `StopWorkerOnMemoryLimitListener`. + * [BC BREAK] Removed `StopWhenMessageCountIsExceededWorker` in favor of `StopWorkerOnMessageLimitListener`. + * [BC BREAK] Removed `StopWhenTimeLimitIsReachedWorker` in favor of `StopWorkerOnTimeLimitListener`. + * [BC BREAK] Removed `StopWhenRestartSignalIsReceived` in favor of `StopWorkerOnRestartSignalListener`. + * The component is not marked as `@experimental` anymore. + * Marked the `MessengerDataCollector` class as `@final`. + * Added support for `DelayStamp` to the `redis` transport. + +4.3.0 +----- + + * Added `NonSendableStampInterface` that a stamp can implement if + it should not be sent to a transport. Transport serializers + must now check for these stamps and not encode them. + * [BC BREAK] `SendersLocatorInterface` has an additional method: + `getSenderByAlias()`. + * Removed argument `?bool &$handle = false` from `SendersLocatorInterface::getSenders` + * A new `ListableReceiverInterface` was added, which a receiver + can implement (when applicable) to enable listing and fetching + individual messages by id (used in the new "Failed Messages" commands). + * Both `SenderInterface::send()` and `ReceiverInterface::get()` + should now (when applicable) add a `TransportMessageIdStamp`. + * Added `WorkerStoppedEvent` dispatched when a worker is stopped. + * Added optional `MessageCountAwareInterface` that receivers can implement + to give information about how many messages are waiting to be processed. + * [BC BREAK] The `Envelope::__construct()` signature changed: + you can no longer pass an unlimited number of stamps as the second, + third, fourth, arguments etc: stamps are now an array passed to the + second argument. + * [BC BREAK] The `MessageBusInterface::dispatch()` signature changed: + a second argument `array $stamps = []` was added. + * Added new `messenger:stop-workers` command that sends a signal + to stop all `messenger:consume` workers. + * [BC BREAK] The `TransportFactoryInterface::createTransport()` signature + changed: a required 3rd `SerializerInterface` argument was added. + * Added a new `SyncTransport` to explicitly handle messages synchronously. + * Added `AmqpStamp` allowing to provide a routing key, flags and attributes on message publishing. + * [BC BREAK] Removed publishing with a `routing_key` option from queue configuration, for + AMQP. Use exchange `default_publish_routing_key` or `AmqpStamp` instead. + * [BC BREAK] Changed the `queue` option in the AMQP transport DSN to be `queues[name]`. You can + therefore name the queue but also configure `binding_keys`, `flags` and `arguments`. + * [BC BREAK] The methods `get`, `ack`, `nack` and `queue` of the AMQP `Connection` + have a new argument: the queue name. + * Added optional parameter `prefetch_count` in connection configuration, + to setup channel prefetch count. + * New classes: `RoutableMessageBus`, `AddBusNameStampMiddleware` + and `BusNameStamp` were added, which allow you to add a bus identifier + to the `Envelope` then find the correct bus when receiving from + the transport. See `ConsumeMessagesCommand`. + * The optional `$busNames` constructor argument of the class `ConsumeMessagesCommand` was removed. + * [BC BREAK] 3 new methods were added to `ReceiverInterface`: + `ack()`, `reject()` and `get()`. The methods `receive()` + and `stop()` were removed. + * [BC BREAK] Error handling was moved from the receivers into + `Worker`. Implementations of `ReceiverInterface::handle()` + should now allow all exceptions to be thrown, except for transport + exceptions. They should also not retry (e.g. if there's a queue, + remove from the queue) if there is a problem decoding the message. + * [BC BREAK] `RejectMessageExceptionInterface` was removed and replaced + by `Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException`, + which has the same behavior: a message will not be retried + * The default command name for `ConsumeMessagesCommand` was + changed from `messenger:consume-messages` to `messenger:consume` + * `ConsumeMessagesCommand` has two new optional constructor arguments + * [BC BREAK] The first argument to Worker changed from a single + `ReceiverInterface` to an array of `ReceiverInterface`. + * `Worker` has 3 new optional constructor arguments. + * The `Worker` class now handles calling `pcntl_signal_dispatch()` the + receiver no longer needs to call this. + * The `AmqpSender` will now retry messages using a dead-letter exchange + and delayed queues, instead of retrying via `nack()` + * Senders now receive the `Envelope` with the `SentStamp` on it. Previously, + the `Envelope` was passed to the sender and *then* the `SentStamp` + was added. + * `SerializerInterface` implementations should now throw a + `Symfony\Component\Messenger\Exception\MessageDecodingFailedException` + if `decode()` fails for any reason. + * [BC BREAK] The default `Serializer` will now throw a + `MessageDecodingFailedException` if `decode()` fails, instead + of the underlying exceptions from the Serializer component. + * Added `PhpSerializer` which uses PHP's native `serialize()` and + `unserialize()` to serialize messages to a transport + * [BC BREAK] If no serializer were passed, the default serializer + changed from `Serializer` to `PhpSerializer` inside `AmqpReceiver`, + `AmqpSender`, `AmqpTransport` and `AmqpTransportFactory`. + * Added `TransportException` to mark an exception transport-related + * [BC BREAK] If listening to exceptions while using `AmqpSender` or `AmqpReceiver`, `\AMQPException` is + no longer thrown in favor of `TransportException`. + * Deprecated `LoggingMiddleware`, pass a logger to `SendMessageMiddleware` instead. + * [BC BREAK] `Connection::__construct()` and `Connection::fromDsn()` + both no longer have `$isDebug` arguments. + * [BC BREAK] The Amqp Transport now automatically sets up the exchanges + and queues by default. Previously, this was done when in "debug" mode + only. Pass the `auto_setup` connection option to control this. + * Added a `SetupTransportsCommand` command to setup the transports + * Added a Doctrine transport. For example, use the `doctrine://default` DSN (this uses the `default` Doctrine entity manager) + * [BC BREAK] The `getConnectionConfiguration` method on Amqp's `Connection` has been removed. + * [BC BREAK] A `HandlerFailedException` exception will be thrown if one or more handler fails. + * [BC BREAK] The `HandlersLocationInterface::getHandlers` method needs to return `HandlerDescriptor` + instances instead of callables. + * [BC BREAK] The `HandledStamp` stamp has changed: `handlerAlias` has been renamed to `handlerName`, + `getCallableName` has been removed and its constructor only has 2 arguments now. + * [BC BREAK] The `ReceivedStamp` needs to exposes the name of the transport from which the message + has been received. + +4.2.0 +----- + + * Added `HandleTrait` leveraging a message bus instance to return a single + synchronous message handling result + * Added `HandledStamp` & `SentStamp` stamps + * All the changes below are BC BREAKS + * Senders and handlers subscribing to parent interfaces now receive *all* matching messages, wildcard included + * `MessageBusInterface::dispatch()`, `MiddlewareInterface::handle()` and `SenderInterface::send()` return `Envelope` + * `MiddlewareInterface::handle()` now require an `Envelope` as first argument and a `StackInterface` as second + * `EnvelopeAwareInterface` has been removed + * The signature of `Amqp*` classes changed to take a `Connection` as a first argument and an optional + `Serializer` as a second argument. + * `MessageSubscriberInterface::getHandledMessages()` return value has changed. The value of an array item + needs to be an associative array or the method name. + * `StampInterface` replaces `EnvelopeItemInterface` and doesn't extend `Serializable` anymore + * The `ConsumeMessagesCommand` class now takes an instance of `Psr\Container\ContainerInterface` + as first constructor argument + * The `EncoderInterface` and `DecoderInterface` have been replaced by a unified `Symfony\Component\Messenger\Transport\Serialization\SerializerInterface`. + * Renamed `EnvelopeItemInterface` to `StampInterface` + * `Envelope`'s constructor and `with()` method now accept `StampInterface` objects as variadic parameters + * Renamed and moved `ReceivedMessage`, `ValidationConfiguration` and `SerializerConfiguration` in the `Stamp` namespace + * Removed the `WrapIntoReceivedMessage` class + * `MessengerDataCollector::getMessages()` returns an iterable, not just an array anymore + * `HandlerLocatorInterface::resolve()` has been removed, use `HandlersLocator::getHandlers()` instead + * `SenderLocatorInterface::getSenderForMessage()` has been removed, use `SendersLocator::getSenders()` instead + * Classes in the `Middleware\Enhancers` sub-namespace have been moved to the `Middleware` one + * Classes in the `Asynchronous\Routing` sub-namespace have been moved to the `Transport\Sender\Locator` sub-namespace + * The `Asynchronous/Middleware/SendMessageMiddleware` class has been moved to the `Middleware` namespace + * `SenderInterface` has been moved to the `Transport\Sender` sub-namespace + * The `ChainHandler` and `ChainSender` classes have been removed + * `ReceiverInterface` and its implementations have been moved to the `Transport\Receiver` sub-namespace + * `ActivationMiddlewareDecorator` has been renamed `ActivationMiddleware` + * `AllowNoHandlerMiddleware` has been removed in favor of a new constructor argument on `HandleMessageMiddleware` + * The `ContainerHandlerLocator`, `AbstractHandlerLocator`, `SenderLocator` and `AbstractSenderLocator` classes have been removed + * `Envelope::all()` takes a new optional `$stampFqcn` argument and returns the stamps for the specified FQCN, or all stamps by their class name + * `Envelope::get()` has been renamed `Envelope::last()` + +4.1.0 +----- + + * Introduced the component as experimental diff --git a/plugins/email/vendor/symfony/messenger/Command/AbstractFailedMessagesCommand.php b/plugins/email/vendor/symfony/messenger/Command/AbstractFailedMessagesCommand.php new file mode 100644 index 0000000..7a6fc21 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Command/AbstractFailedMessagesCommand.php @@ -0,0 +1,298 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Command; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Helper\Dumper; +use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\DependencyInjection\ServiceLocator; +use Symfony\Component\ErrorHandler\Exception\FlattenException; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\Stamp\ErrorDetailsStamp; +use Symfony\Component\Messenger\Stamp\RedeliveryStamp; +use Symfony\Component\Messenger\Stamp\SentToFailureTransportStamp; +use Symfony\Component\Messenger\Stamp\TransportMessageIdStamp; +use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface; +use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface; +use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; +use Symfony\Component\VarDumper\Caster\Caster; +use Symfony\Component\VarDumper\Caster\TraceStub; +use Symfony\Component\VarDumper\Cloner\ClonerInterface; +use Symfony\Component\VarDumper\Cloner\Stub; +use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Contracts\Service\ServiceProviderInterface; + +/** + * @author Ryan Weaver + * + * @internal + */ +abstract class AbstractFailedMessagesCommand extends Command +{ + protected const DEFAULT_TRANSPORT_OPTION = 'choose'; + + protected $failureTransports; + + private $globalFailureReceiverName; + + /** + * @param ServiceProviderInterface $failureTransports + */ + public function __construct(?string $globalFailureReceiverName, $failureTransports) + { + $this->failureTransports = $failureTransports; + if (!$failureTransports instanceof ServiceProviderInterface) { + trigger_deprecation('symfony/messenger', '5.3', 'Passing a receiver as 2nd argument to "%s()" is deprecated, pass a service locator instead.', __METHOD__); + + if (null === $globalFailureReceiverName) { + throw new InvalidArgumentException(sprintf('The argument "globalFailureReceiver" from method "%s()" must be not null if 2nd argument is not a ServiceLocator.', __METHOD__)); + } + + $this->failureTransports = new ServiceLocator([$globalFailureReceiverName => static function () use ($failureTransports) { return $failureTransports; }]); + } + $this->globalFailureReceiverName = $globalFailureReceiverName; + + parent::__construct(); + } + + protected function getReceiverName(): string + { + trigger_deprecation('symfony/messenger', '5.3', 'The method "%s()" is deprecated, use getGlobalFailureReceiverName() instead.', __METHOD__); + + return $this->globalFailureReceiverName; + } + + protected function getGlobalFailureReceiverName(): ?string + { + return $this->globalFailureReceiverName; + } + + /** + * @return mixed + */ + protected function getMessageId(Envelope $envelope) + { + /** @var TransportMessageIdStamp $stamp */ + $stamp = $envelope->last(TransportMessageIdStamp::class); + + return null !== $stamp ? $stamp->getId() : null; + } + + protected function displaySingleMessage(Envelope $envelope, SymfonyStyle $io) + { + $io->title('Failed Message Details'); + + /** @var SentToFailureTransportStamp|null $sentToFailureTransportStamp */ + $sentToFailureTransportStamp = $envelope->last(SentToFailureTransportStamp::class); + /** @var RedeliveryStamp|null $lastRedeliveryStamp */ + $lastRedeliveryStamp = $envelope->last(RedeliveryStamp::class); + /** @var ErrorDetailsStamp|null $lastErrorDetailsStamp */ + $lastErrorDetailsStamp = $envelope->last(ErrorDetailsStamp::class); + $lastRedeliveryStampWithException = $this->getLastRedeliveryStampWithException($envelope, true); + + $rows = [ + ['Class', \get_class($envelope->getMessage())], + ]; + + if (null !== $id = $this->getMessageId($envelope)) { + $rows[] = ['Message Id', $id]; + } + + if (null === $sentToFailureTransportStamp) { + $io->warning('Message does not appear to have been sent to this transport after failing'); + } else { + $failedAt = ''; + $errorMessage = ''; + $errorCode = ''; + $errorClass = '(unknown)'; + + if (null !== $lastRedeliveryStamp) { + $failedAt = $lastRedeliveryStamp->getRedeliveredAt()->format('Y-m-d H:i:s'); + } + + if (null !== $lastErrorDetailsStamp) { + $errorMessage = $lastErrorDetailsStamp->getExceptionMessage(); + $errorCode = $lastErrorDetailsStamp->getExceptionCode(); + $errorClass = $lastErrorDetailsStamp->getExceptionClass(); + } elseif (null !== $lastRedeliveryStampWithException) { + // Try reading the errorMessage for messages that are still in the queue without the new ErrorDetailStamps. + $errorMessage = $lastRedeliveryStampWithException->getExceptionMessage(); + if (null !== $lastRedeliveryStampWithException->getFlattenException()) { + $errorClass = $lastRedeliveryStampWithException->getFlattenException()->getClass(); + } + } + + $rows = array_merge($rows, [ + ['Failed at', $failedAt], + ['Error', $errorMessage], + ['Error Code', $errorCode], + ['Error Class', $errorClass], + ['Transport', $sentToFailureTransportStamp->getOriginalReceiverName()], + ]); + } + + $io->table([], $rows); + + /** @var RedeliveryStamp[] $redeliveryStamps */ + $redeliveryStamps = $envelope->all(RedeliveryStamp::class); + $io->writeln(' Message history:'); + foreach ($redeliveryStamps as $redeliveryStamp) { + $io->writeln(sprintf(' * Message failed at %s and was redelivered', $redeliveryStamp->getRedeliveredAt()->format('Y-m-d H:i:s'))); + } + $io->newLine(); + + if ($io->isVeryVerbose()) { + $io->title('Message:'); + $dump = new Dumper($io, null, $this->createCloner()); + $io->writeln($dump($envelope->getMessage())); + $io->title('Exception:'); + $flattenException = null; + if (null !== $lastErrorDetailsStamp) { + $flattenException = $lastErrorDetailsStamp->getFlattenException(); + } elseif (null !== $lastRedeliveryStampWithException) { + $flattenException = $lastRedeliveryStampWithException->getFlattenException(); + } + $io->writeln(null === $flattenException ? '(no data)' : $dump($flattenException)); + } else { + $io->writeln(' Re-run command with -vv to see more message & error details.'); + } + } + + protected function printPendingMessagesMessage(ReceiverInterface $receiver, SymfonyStyle $io) + { + if ($receiver instanceof MessageCountAwareInterface) { + if (1 === $receiver->getMessageCount()) { + $io->writeln('There is 1 message pending in the failure transport.'); + } else { + $io->writeln(sprintf('There are %d messages pending in the failure transport.', $receiver->getMessageCount())); + } + } + } + + /** + * @param string|null $name + */ + protected function getReceiver(/* string $name = null */): ReceiverInterface + { + if (1 > \func_num_args() && __CLASS__ !== static::class && __CLASS__ !== (new \ReflectionMethod($this, __FUNCTION__))->getDeclaringClass()->getName() && !$this instanceof \PHPUnit\Framework\MockObject\MockObject && !$this instanceof \Prophecy\Prophecy\ProphecySubjectInterface && !$this instanceof \Mockery\MockInterface) { + trigger_deprecation('symfony/messenger', '5.3', 'The "%s()" method will have a new "string $name" argument in version 6.0, not defining it is deprecated.', __METHOD__); + } + $name = \func_num_args() > 0 ? func_get_arg(0) : null; + + if (null === $name = $name ?? $this->globalFailureReceiverName) { + throw new InvalidArgumentException(sprintf('No default failure transport is defined. Available transports are: "%s".', implode('", "', array_keys($this->failureTransports->getProvidedServices())))); + } + + if (!$this->failureTransports->has($name)) { + throw new InvalidArgumentException(sprintf('The "%s" failure transport was not found. Available transports are: "%s".', $name, implode('", "', array_keys($this->failureTransports->getProvidedServices())))); + } + + return $this->failureTransports->get($name); + } + + protected function getLastRedeliveryStampWithException(Envelope $envelope): ?RedeliveryStamp + { + if (null === \func_get_args()[1]) { + trigger_deprecation('symfony/messenger', '5.2', sprintf('Using the "getLastRedeliveryStampWithException" method in the "%s" class is deprecated, use the "Envelope::last(%s)" instead.', self::class, ErrorDetailsStamp::class)); + } + + // Use ErrorDetailsStamp instead if it is available + if (null !== $envelope->last(ErrorDetailsStamp::class)) { + return null; + } + + /** @var RedeliveryStamp $stamp */ + foreach (array_reverse($envelope->all(RedeliveryStamp::class)) as $stamp) { + if (null !== $stamp->getExceptionMessage()) { + return $stamp; + } + } + + return null; + } + + private function createCloner(): ?ClonerInterface + { + if (!class_exists(VarCloner::class)) { + return null; + } + + $cloner = new VarCloner(); + $cloner->addCasters([FlattenException::class => function (FlattenException $flattenException, array $a, Stub $stub): array { + $stub->class = $flattenException->getClass(); + + return [ + Caster::PREFIX_VIRTUAL.'message' => $flattenException->getMessage(), + Caster::PREFIX_VIRTUAL.'code' => $flattenException->getCode(), + Caster::PREFIX_VIRTUAL.'file' => $flattenException->getFile(), + Caster::PREFIX_VIRTUAL.'line' => $flattenException->getLine(), + Caster::PREFIX_VIRTUAL.'trace' => new TraceStub($flattenException->getTrace()), + ]; + }]); + + return $cloner; + } + + protected function printWarningAvailableFailureTransports(SymfonyStyle $io, ?string $failureTransportName): void + { + $failureTransports = array_keys($this->failureTransports->getProvidedServices()); + $failureTransportsCount = \count($failureTransports); + if ($failureTransportsCount > 1) { + $io->writeln([ + sprintf('> Loading messages from the global failure transport %s.', $failureTransportName), + '> To use a different failure transport, pass --transport=.', + sprintf('> Available failure transports are: %s', implode(', ', $failureTransports)), + "\n", + ]); + } + } + + protected function interactiveChooseFailureTransport(SymfonyStyle $io) + { + $failedTransports = array_keys($this->failureTransports->getProvidedServices()); + $question = new ChoiceQuestion('Select failed transport:', $failedTransports, 0); + $question->setMultiselect(false); + + return $io->askQuestion($question); + } + + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + if ($input->mustSuggestOptionValuesFor('transport')) { + $suggestions->suggestValues(array_keys($this->failureTransports->getProvidedServices())); + + return; + } + + if ($input->mustSuggestArgumentValuesFor('id')) { + $transport = $input->getOption('transport'); + $transport = self::DEFAULT_TRANSPORT_OPTION === $transport ? $this->getGlobalFailureReceiverName() : $transport; + $receiver = $this->getReceiver($transport); + + if (!$receiver instanceof ListableReceiverInterface) { + return; + } + + $ids = []; + foreach ($receiver->all(50) as $envelope) { + $ids[] = $this->getMessageId($envelope); + } + $suggestions->suggestValues($ids); + + return; + } + } +} diff --git a/plugins/email/vendor/symfony/messenger/Command/ConsumeMessagesCommand.php b/plugins/email/vendor/symfony/messenger/Command/ConsumeMessagesCommand.php new file mode 100644 index 0000000..6e9a02b --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Command/ConsumeMessagesCommand.php @@ -0,0 +1,267 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Command; + +use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Messenger\EventListener\ResetServicesListener; +use Symfony\Component\Messenger\EventListener\StopWorkerOnFailureLimitListener; +use Symfony\Component\Messenger\EventListener\StopWorkerOnMemoryLimitListener; +use Symfony\Component\Messenger\EventListener\StopWorkerOnMessageLimitListener; +use Symfony\Component\Messenger\EventListener\StopWorkerOnTimeLimitListener; +use Symfony\Component\Messenger\RoutableMessageBus; +use Symfony\Component\Messenger\Worker; + +/** + * @author Samuel Roze + */ +class ConsumeMessagesCommand extends Command +{ + protected static $defaultName = 'messenger:consume'; + protected static $defaultDescription = 'Consume messages'; + + private $routableBus; + private $receiverLocator; + private $eventDispatcher; + private $logger; + private $receiverNames; + private $resetServicesListener; + private $busIds; + + public function __construct(RoutableMessageBus $routableBus, ContainerInterface $receiverLocator, EventDispatcherInterface $eventDispatcher, LoggerInterface $logger = null, array $receiverNames = [], ResetServicesListener $resetServicesListener = null, array $busIds = []) + { + $this->routableBus = $routableBus; + $this->receiverLocator = $receiverLocator; + $this->eventDispatcher = $eventDispatcher; + $this->logger = $logger; + $this->receiverNames = $receiverNames; + $this->resetServicesListener = $resetServicesListener; + $this->busIds = $busIds; + + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + protected function configure(): void + { + $defaultReceiverName = 1 === \count($this->receiverNames) ? current($this->receiverNames) : null; + + $this + ->setDefinition([ + new InputArgument('receivers', InputArgument::IS_ARRAY, 'Names of the receivers/transports to consume in order of priority', $defaultReceiverName ? [$defaultReceiverName] : []), + new InputOption('limit', 'l', InputOption::VALUE_REQUIRED, 'Limit the number of received messages'), + new InputOption('failure-limit', 'f', InputOption::VALUE_REQUIRED, 'The number of failed messages the worker can consume'), + new InputOption('memory-limit', 'm', InputOption::VALUE_REQUIRED, 'The memory limit the worker can consume'), + new InputOption('time-limit', 't', InputOption::VALUE_REQUIRED, 'The time limit in seconds the worker can handle new messages'), + new InputOption('sleep', null, InputOption::VALUE_REQUIRED, 'Seconds to sleep before asking for new messages after no messages were found', 1), + new InputOption('bus', 'b', InputOption::VALUE_REQUIRED, 'Name of the bus to which received messages should be dispatched (if not passed, bus is determined automatically)'), + new InputOption('queues', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Limit receivers to only consume from the specified queues'), + new InputOption('no-reset', null, InputOption::VALUE_NONE, 'Do not reset container services after each message'), + ]) + ->setDescription(self::$defaultDescription) + ->setHelp(<<<'EOF' +The %command.name% command consumes messages and dispatches them to the message bus. + + php %command.full_name% + +To receive from multiple transports, pass each name: + + php %command.full_name% receiver1 receiver2 + +Use the --limit option to limit the number of messages received: + + php %command.full_name% --limit=10 + +Use the --failure-limit option to stop the worker when the given number of failed messages is reached: + + php %command.full_name% --failure-limit=2 + +Use the --memory-limit option to stop the worker if it exceeds a given memory usage limit. You can use shorthand byte values [K, M or G]: + + php %command.full_name% --memory-limit=128M + +Use the --time-limit option to stop the worker when the given time limit (in seconds) is reached. +If a message is being handled, the worker will stop after the processing is finished: + + php %command.full_name% --time-limit=3600 + +Use the --bus option to specify the message bus to dispatch received messages +to instead of trying to determine it automatically. This is required if the +messages didn't originate from Messenger: + + php %command.full_name% --bus=event_bus + +Use the --queues option to limit a receiver to only certain queues (only supported by some receivers): + + php %command.full_name% --queues=fasttrack + +Use the --no-reset option to prevent services resetting after each message (may lead to leaking services' state between messages): + + php %command.full_name% --no-reset +EOF + ) + ; + } + + /** + * {@inheritdoc} + */ + protected function interact(InputInterface $input, OutputInterface $output) + { + $io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output); + + if ($this->receiverNames && 0 === \count($input->getArgument('receivers'))) { + $io->block('Which transports/receivers do you want to consume?', null, 'fg=white;bg=blue', ' ', true); + + $io->writeln('Choose which receivers you want to consume messages from in order of priority.'); + if (\count($this->receiverNames) > 1) { + $io->writeln(sprintf('Hint: to consume from multiple, use a list of their names, e.g. %s', implode(', ', $this->receiverNames))); + } + + $question = new ChoiceQuestion('Select receivers to consume:', $this->receiverNames, 0); + $question->setMultiselect(true); + + $input->setArgument('receivers', $io->askQuestion($question)); + } + + if (0 === \count($input->getArgument('receivers'))) { + throw new RuntimeException('Please pass at least one receiver.'); + } + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $receivers = []; + foreach ($receiverNames = $input->getArgument('receivers') as $receiverName) { + if (!$this->receiverLocator->has($receiverName)) { + $message = sprintf('The receiver "%s" does not exist.', $receiverName); + if ($this->receiverNames) { + $message .= sprintf(' Valid receivers are: %s.', implode(', ', $this->receiverNames)); + } + + throw new RuntimeException($message); + } + + $receivers[$receiverName] = $this->receiverLocator->get($receiverName); + } + + if (null !== $this->resetServicesListener && !$input->getOption('no-reset')) { + $this->eventDispatcher->addSubscriber($this->resetServicesListener); + } + + $stopsWhen = []; + if ($limit = $input->getOption('limit')) { + $stopsWhen[] = "processed {$limit} messages"; + $this->eventDispatcher->addSubscriber(new StopWorkerOnMessageLimitListener($limit, $this->logger)); + } + + if ($failureLimit = $input->getOption('failure-limit')) { + $stopsWhen[] = "reached {$failureLimit} failed messages"; + $this->eventDispatcher->addSubscriber(new StopWorkerOnFailureLimitListener($failureLimit, $this->logger)); + } + + if ($memoryLimit = $input->getOption('memory-limit')) { + $stopsWhen[] = "exceeded {$memoryLimit} of memory"; + $this->eventDispatcher->addSubscriber(new StopWorkerOnMemoryLimitListener($this->convertToBytes($memoryLimit), $this->logger)); + } + + if (null !== ($timeLimit = $input->getOption('time-limit'))) { + $stopsWhen[] = "been running for {$timeLimit}s"; + $this->eventDispatcher->addSubscriber(new StopWorkerOnTimeLimitListener($timeLimit, $this->logger)); + } + + $stopsWhen[] = 'received a stop signal via the messenger:stop-workers command'; + + $io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output); + $io->success(sprintf('Consuming messages from transport%s "%s".', \count($receivers) > 0 ? 's' : '', implode(', ', $receiverNames))); + + if ($stopsWhen) { + $last = array_pop($stopsWhen); + $stopsWhen = ($stopsWhen ? implode(', ', $stopsWhen).' or ' : '').$last; + $io->comment("The worker will automatically exit once it has {$stopsWhen}."); + } + + $io->comment('Quit the worker with CONTROL-C.'); + + if (OutputInterface::VERBOSITY_VERBOSE > $output->getVerbosity()) { + $io->comment('Re-run the command with a -vv option to see logs about consumed messages.'); + } + + $bus = $input->getOption('bus') ? $this->routableBus->getMessageBus($input->getOption('bus')) : $this->routableBus; + + $worker = new Worker($receivers, $bus, $this->eventDispatcher, $this->logger); + $options = [ + 'sleep' => $input->getOption('sleep') * 1000000, + ]; + if ($queues = $input->getOption('queues')) { + $options['queues'] = $queues; + } + $worker->run($options); + + return 0; + } + + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + if ($input->mustSuggestArgumentValuesFor('receivers')) { + $suggestions->suggestValues(array_diff($this->receiverNames, array_diff($input->getArgument('receivers'), [$input->getCompletionValue()]))); + + return; + } + + if ($input->mustSuggestOptionValuesFor('bus')) { + $suggestions->suggestValues($this->busIds); + } + } + + private function convertToBytes(string $memoryLimit): int + { + $memoryLimit = strtolower($memoryLimit); + $max = ltrim($memoryLimit, '+'); + if (str_starts_with($max, '0x')) { + $max = \intval($max, 16); + } elseif (str_starts_with($max, '0')) { + $max = \intval($max, 8); + } else { + $max = (int) $max; + } + + switch (substr(rtrim($memoryLimit, 'b'), -1)) { + case 't': $max *= 1024; + // no break + case 'g': $max *= 1024; + // no break + case 'm': $max *= 1024; + // no break + case 'k': $max *= 1024; + } + + return $max; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Command/DebugCommand.php b/plugins/email/vendor/symfony/messenger/Command/DebugCommand.php new file mode 100644 index 0000000..4320ad7 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Command/DebugCommand.php @@ -0,0 +1,150 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Command; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +/** + * A console command to debug Messenger information. + * + * @author Roland Franssen + */ +class DebugCommand extends Command +{ + protected static $defaultName = 'debug:messenger'; + protected static $defaultDescription = 'List messages you can dispatch using the message buses'; + + private $mapping; + + public function __construct(array $mapping) + { + $this->mapping = $mapping; + + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->addArgument('bus', InputArgument::OPTIONAL, sprintf('The bus id (one of "%s")', implode('", "', array_keys($this->mapping)))) + ->setDescription(self::$defaultDescription) + ->setHelp(<<<'EOF' +The %command.name% command displays all messages that can be +dispatched using the message buses: + + php %command.full_name% + +Or for a specific bus only: + + php %command.full_name% command_bus + +EOF + ) + ; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $io = new SymfonyStyle($input, $output); + $io->title('Messenger'); + + $mapping = $this->mapping; + if ($bus = $input->getArgument('bus')) { + if (!isset($mapping[$bus])) { + throw new RuntimeException(sprintf('Bus "%s" does not exist. Known buses are "%s".', $bus, implode('", "', array_keys($this->mapping)))); + } + $mapping = [$bus => $mapping[$bus]]; + } + + foreach ($mapping as $bus => $handlersByMessage) { + $io->section($bus); + + $tableRows = []; + foreach ($handlersByMessage as $message => $handlers) { + if ($description = self::getClassDescription($message)) { + $tableRows[] = [sprintf('%s', $description)]; + } + + $tableRows[] = [sprintf('%s', $message)]; + foreach ($handlers as $handler) { + $tableRows[] = [ + sprintf(' handled by %s', $handler[0]).$this->formatConditions($handler[1]), + ]; + if ($handlerDescription = self::getClassDescription($handler[0])) { + $tableRows[] = [sprintf(' %s', $handlerDescription)]; + } + } + $tableRows[] = ['']; + } + + if ($tableRows) { + $io->text('The following messages can be dispatched:'); + $io->newLine(); + $io->table([], $tableRows); + } else { + $io->warning(sprintf('No handled message found in bus "%s".', $bus)); + } + } + + return 0; + } + + private function formatConditions(array $options): string + { + if (!$options) { + return ''; + } + + $optionsMapping = []; + foreach ($options as $key => $value) { + $optionsMapping[] = $key.'='.$value; + } + + return ' (when '.implode(', ', $optionsMapping).')'; + } + + private static function getClassDescription(string $class): string + { + try { + $r = new \ReflectionClass($class); + + if ($docComment = $r->getDocComment()) { + $docComment = preg_split('#\n\s*\*\s*[\n@]#', substr($docComment, 3, -2), 2)[0]; + + return trim(preg_replace('#\s*\n\s*\*\s*#', ' ', $docComment)); + } + } catch (\ReflectionException $e) { + } + + return ''; + } + + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + if ($input->mustSuggestArgumentValuesFor('bus')) { + $suggestions->suggestValues(array_keys($this->mapping)); + } + } +} diff --git a/plugins/email/vendor/symfony/messenger/Command/FailedMessagesRemoveCommand.php b/plugins/email/vendor/symfony/messenger/Command/FailedMessagesRemoveCommand.php new file mode 100644 index 0000000..cfdcba5 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Command/FailedMessagesRemoveCommand.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Command; + +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface; +use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; + +/** + * @author Ryan Weaver + */ +class FailedMessagesRemoveCommand extends AbstractFailedMessagesCommand +{ + protected static $defaultName = 'messenger:failed:remove'; + protected static $defaultDescription = 'Remove given messages from the failure transport'; + + /** + * {@inheritdoc} + */ + protected function configure(): void + { + $this + ->setDefinition([ + new InputArgument('id', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'Specific message id(s) to remove'), + new InputOption('force', null, InputOption::VALUE_NONE, 'Force the operation without confirmation'), + new InputOption('transport', null, InputOption::VALUE_OPTIONAL, 'Use a specific failure transport', self::DEFAULT_TRANSPORT_OPTION), + new InputOption('show-messages', null, InputOption::VALUE_NONE, 'Display messages before removing it (if multiple ids are given)'), + ]) + ->setDescription(self::$defaultDescription) + ->setHelp(<<<'EOF' +The %command.name% removes given messages that are pending in the failure transport. + + php %command.full_name% {id1} [{id2} ...] + +The specific ids can be found via the messenger:failed:show command. +EOF + ) + ; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output); + + $failureTransportName = $input->getOption('transport'); + if (self::DEFAULT_TRANSPORT_OPTION === $failureTransportName) { + $failureTransportName = $this->getGlobalFailureReceiverName(); + } + + $receiver = $this->getReceiver($failureTransportName); + + $shouldForce = $input->getOption('force'); + $ids = (array) $input->getArgument('id'); + $shouldDisplayMessages = $input->getOption('show-messages') || 1 === \count($ids); + $this->removeMessages($failureTransportName, $ids, $receiver, $io, $shouldForce, $shouldDisplayMessages); + + return 0; + } + + private function removeMessages(string $failureTransportName, array $ids, ReceiverInterface $receiver, SymfonyStyle $io, bool $shouldForce, bool $shouldDisplayMessages): void + { + if (!$receiver instanceof ListableReceiverInterface) { + throw new RuntimeException(sprintf('The "%s" receiver does not support removing specific messages.', $failureTransportName)); + } + + foreach ($ids as $id) { + $envelope = $receiver->find($id); + if (null === $envelope) { + $io->error(sprintf('The message with id "%s" was not found.', $id)); + continue; + } + + if ($shouldDisplayMessages) { + $this->displaySingleMessage($envelope, $io); + } + + if ($shouldForce || $io->confirm('Do you want to permanently remove this message?', false)) { + $receiver->reject($envelope); + + $io->success(sprintf('Message with id %s removed.', $id)); + } else { + $io->note(sprintf('Message with id %s not removed.', $id)); + } + } + } +} diff --git a/plugins/email/vendor/symfony/messenger/Command/FailedMessagesRetryCommand.php b/plugins/email/vendor/symfony/messenger/Command/FailedMessagesRetryCommand.php new file mode 100644 index 0000000..0ef9984 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Command/FailedMessagesRetryCommand.php @@ -0,0 +1,226 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Command; + +use Psr\Log\LoggerInterface; +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent; +use Symfony\Component\Messenger\EventListener\StopWorkerOnMessageLimitListener; +use Symfony\Component\Messenger\Exception\LogicException; +use Symfony\Component\Messenger\MessageBusInterface; +use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface; +use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; +use Symfony\Component\Messenger\Transport\Receiver\SingleMessageReceiver; +use Symfony\Component\Messenger\Worker; + +/** + * @author Ryan Weaver + */ +class FailedMessagesRetryCommand extends AbstractFailedMessagesCommand +{ + protected static $defaultName = 'messenger:failed:retry'; + protected static $defaultDescription = 'Retry one or more messages from the failure transport'; + + private $eventDispatcher; + private $messageBus; + private $logger; + + public function __construct(?string $globalReceiverName, $failureTransports, MessageBusInterface $messageBus, EventDispatcherInterface $eventDispatcher, LoggerInterface $logger = null) + { + $this->eventDispatcher = $eventDispatcher; + $this->messageBus = $messageBus; + $this->logger = $logger; + + parent::__construct($globalReceiverName, $failureTransports); + } + + /** + * {@inheritdoc} + */ + protected function configure(): void + { + $this + ->setDefinition([ + new InputArgument('id', InputArgument::IS_ARRAY, 'Specific message id(s) to retry'), + new InputOption('force', null, InputOption::VALUE_NONE, 'Force action without confirmation'), + new InputOption('transport', null, InputOption::VALUE_OPTIONAL, 'Use a specific failure transport', self::DEFAULT_TRANSPORT_OPTION), + ]) + ->setDescription(self::$defaultDescription) + ->setHelp(<<<'EOF' +The %command.name% retries message in the failure transport. + + php %command.full_name% + +The command will interactively ask if each message should be retried +or discarded. + +Some transports support retrying a specific message id, which comes +from the messenger:failed:show command. + + php %command.full_name% {id} + +Or pass multiple ids at once to process multiple messages: + +php %command.full_name% {id1} {id2} {id3} + +EOF + ) + ; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->eventDispatcher->addSubscriber(new StopWorkerOnMessageLimitListener(1)); + + $io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output); + $io->comment('Quit this command with CONTROL-C.'); + if (!$output->isVeryVerbose()) { + $io->comment('Re-run the command with a -vv option to see logs about consumed messages.'); + } + + $failureTransportName = $input->getOption('transport'); + if (self::DEFAULT_TRANSPORT_OPTION === $failureTransportName) { + $this->printWarningAvailableFailureTransports($io, $this->getGlobalFailureReceiverName()); + } + if ('' === $failureTransportName || null === $failureTransportName) { + $failureTransportName = $this->interactiveChooseFailureTransport($io); + } + $failureTransportName = self::DEFAULT_TRANSPORT_OPTION === $failureTransportName ? $this->getGlobalFailureReceiverName() : $failureTransportName; + + $receiver = $this->getReceiver($failureTransportName); + $this->printPendingMessagesMessage($receiver, $io); + + $io->writeln(sprintf('To retry all the messages, run messenger:consume %s', $failureTransportName)); + + $shouldForce = $input->getOption('force'); + $ids = $input->getArgument('id'); + if (0 === \count($ids)) { + if (!$input->isInteractive()) { + throw new RuntimeException('Message id must be passed when in non-interactive mode.'); + } + + $this->runInteractive($failureTransportName, $io, $shouldForce); + + return 0; + } + + $this->retrySpecificIds($failureTransportName, $ids, $io, $shouldForce); + $io->success('All done!'); + + return 0; + } + + private function runInteractive(string $failureTransportName, SymfonyStyle $io, bool $shouldForce) + { + $receiver = $this->failureTransports->get($failureTransportName); + $count = 0; + if ($receiver instanceof ListableReceiverInterface) { + // for listable receivers, find the messages one-by-one + // this avoids using get(), which for some less-robust + // transports (like Doctrine), will cause the message + // to be temporarily "acked", even if the user aborts + // handling the message + while (true) { + $ids = []; + foreach ($receiver->all(1) as $envelope) { + ++$count; + + $id = $this->getMessageId($envelope); + if (null === $id) { + throw new LogicException(sprintf('The "%s" receiver is able to list messages by id but the envelope is missing the TransportMessageIdStamp stamp.', $failureTransportName)); + } + $ids[] = $id; + } + + // break the loop if all messages are consumed + if (0 === \count($ids)) { + break; + } + + $this->retrySpecificIds($failureTransportName, $ids, $io, $shouldForce); + } + } else { + // get() and ask messages one-by-one + $count = $this->runWorker($failureTransportName, $receiver, $io, $shouldForce); + } + + // avoid success message if nothing was processed + if (1 <= $count) { + $io->success('All failed messages have been handled or removed!'); + } + } + + private function runWorker(string $failureTransportName, ReceiverInterface $receiver, SymfonyStyle $io, bool $shouldForce): int + { + $count = 0; + $listener = function (WorkerMessageReceivedEvent $messageReceivedEvent) use ($io, $receiver, $shouldForce, &$count) { + ++$count; + $envelope = $messageReceivedEvent->getEnvelope(); + + $this->displaySingleMessage($envelope, $io); + + $shouldHandle = $shouldForce || $io->confirm('Do you want to retry (yes) or delete this message (no)?'); + + if ($shouldHandle) { + return; + } + + $messageReceivedEvent->shouldHandle(false); + $receiver->reject($envelope); + }; + $this->eventDispatcher->addListener(WorkerMessageReceivedEvent::class, $listener); + + $worker = new Worker( + [$failureTransportName => $receiver], + $this->messageBus, + $this->eventDispatcher, + $this->logger + ); + + try { + $worker->run(); + } finally { + $this->eventDispatcher->removeListener(WorkerMessageReceivedEvent::class, $listener); + } + + return $count; + } + + private function retrySpecificIds(string $failureTransportName, array $ids, SymfonyStyle $io, bool $shouldForce) + { + $receiver = $this->getReceiver($failureTransportName); + + if (!$receiver instanceof ListableReceiverInterface) { + throw new RuntimeException(sprintf('The "%s" receiver does not support retrying messages by id.', $failureTransportName)); + } + + foreach ($ids as $id) { + $envelope = $receiver->find($id); + if (null === $envelope) { + throw new RuntimeException(sprintf('The message "%s" was not found.', $id)); + } + + $singleReceiver = new SingleMessageReceiver($receiver, $envelope); + $this->runWorker($failureTransportName, $singleReceiver, $io, $shouldForce); + } + } +} diff --git a/plugins/email/vendor/symfony/messenger/Command/FailedMessagesShowCommand.php b/plugins/email/vendor/symfony/messenger/Command/FailedMessagesShowCommand.php new file mode 100644 index 0000000..6b78c8e --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Command/FailedMessagesShowCommand.php @@ -0,0 +1,153 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Command; + +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Messenger\Stamp\ErrorDetailsStamp; +use Symfony\Component\Messenger\Stamp\RedeliveryStamp; +use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface; + +/** + * @author Ryan Weaver + */ +class FailedMessagesShowCommand extends AbstractFailedMessagesCommand +{ + protected static $defaultName = 'messenger:failed:show'; + protected static $defaultDescription = 'Show one or more messages from the failure transport'; + + /** + * {@inheritdoc} + */ + protected function configure(): void + { + $this + ->setDefinition([ + new InputArgument('id', InputArgument::OPTIONAL, 'Specific message id to show'), + new InputOption('max', null, InputOption::VALUE_REQUIRED, 'Maximum number of messages to list', 50), + new InputOption('transport', null, InputOption::VALUE_OPTIONAL, 'Use a specific failure transport', self::DEFAULT_TRANSPORT_OPTION), + ]) + ->setDescription(self::$defaultDescription) + ->setHelp(<<<'EOF' +The %command.name% shows message that are pending in the failure transport. + + php %command.full_name% + +Or look at a specific message by its id: + + php %command.full_name% {id} +EOF + ) + ; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output); + + $failureTransportName = $input->getOption('transport'); + if (self::DEFAULT_TRANSPORT_OPTION === $failureTransportName) { + $this->printWarningAvailableFailureTransports($io, $this->getGlobalFailureReceiverName()); + } + if ('' === $failureTransportName || null === $failureTransportName) { + $failureTransportName = $this->interactiveChooseFailureTransport($io); + } + $failureTransportName = self::DEFAULT_TRANSPORT_OPTION === $failureTransportName ? $this->getGlobalFailureReceiverName() : $failureTransportName; + + $receiver = $this->getReceiver($failureTransportName); + + $this->printPendingMessagesMessage($receiver, $io); + + if (!$receiver instanceof ListableReceiverInterface) { + throw new RuntimeException(sprintf('The "%s" receiver does not support listing or showing specific messages.', $failureTransportName)); + } + + if (null === $id = $input->getArgument('id')) { + $this->listMessages($failureTransportName, $io, $input->getOption('max')); + } else { + $this->showMessage($failureTransportName, $id, $io); + } + + return 0; + } + + private function listMessages(?string $failedTransportName, SymfonyStyle $io, int $max) + { + /** @var ListableReceiverInterface $receiver */ + $receiver = $this->getReceiver($failedTransportName); + $envelopes = $receiver->all($max); + + $rows = []; + foreach ($envelopes as $envelope) { + /** @var RedeliveryStamp|null $lastRedeliveryStamp */ + $lastRedeliveryStamp = $envelope->last(RedeliveryStamp::class); + /** @var ErrorDetailsStamp|null $lastErrorDetailsStamp */ + $lastErrorDetailsStamp = $envelope->last(ErrorDetailsStamp::class); + $lastRedeliveryStampWithException = $this->getLastRedeliveryStampWithException($envelope, true); + + $errorMessage = ''; + if (null !== $lastErrorDetailsStamp) { + $errorMessage = $lastErrorDetailsStamp->getExceptionMessage(); + } elseif (null !== $lastRedeliveryStampWithException) { + // Try reading the errorMessage for messages that are still in the queue without the new ErrorDetailStamps. + $errorMessage = $lastRedeliveryStampWithException->getExceptionMessage(); + } + + $rows[] = [ + $this->getMessageId($envelope), + \get_class($envelope->getMessage()), + null === $lastRedeliveryStamp ? '' : $lastRedeliveryStamp->getRedeliveredAt()->format('Y-m-d H:i:s'), + $errorMessage, + ]; + } + + if (0 === \count($rows)) { + $io->success('No failed messages were found.'); + + return; + } + + $io->table(['Id', 'Class', 'Failed at', 'Error'], $rows); + + if (\count($rows) === $max) { + $io->comment(sprintf('Showing first %d messages.', $max)); + } + + $io->comment(sprintf('Run messenger:failed:show {id} --transport=%s -vv to see message details.', $failedTransportName)); + } + + private function showMessage(?string $failedTransportName, string $id, SymfonyStyle $io) + { + /** @var ListableReceiverInterface $receiver */ + $receiver = $this->getReceiver($failedTransportName); + $envelope = $receiver->find($id); + if (null === $envelope) { + throw new RuntimeException(sprintf('The message "%s" was not found.', $id)); + } + + $this->displaySingleMessage($envelope, $io); + + $io->writeln([ + '', + sprintf(' Run messenger:failed:retry %s --transport=%s to retry this message.', $id, $failedTransportName), + sprintf(' Run messenger:failed:remove %s --transport=%s to delete it.', $id, $failedTransportName), + ]); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Command/SetupTransportsCommand.php b/plugins/email/vendor/symfony/messenger/Command/SetupTransportsCommand.php new file mode 100644 index 0000000..a5feae3 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Command/SetupTransportsCommand.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Command; + +use Psr\Container\ContainerInterface; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Messenger\Transport\SetupableTransportInterface; + +/** + * @author Vincent Touzet + */ +class SetupTransportsCommand extends Command +{ + protected static $defaultName = 'messenger:setup-transports'; + protected static $defaultDescription = 'Prepare the required infrastructure for the transport'; + + private $transportLocator; + private $transportNames; + + public function __construct(ContainerInterface $transportLocator, array $transportNames = []) + { + $this->transportLocator = $transportLocator; + $this->transportNames = $transportNames; + + parent::__construct(); + } + + protected function configure() + { + $this + ->addArgument('transport', InputArgument::OPTIONAL, 'Name of the transport to setup', null) + ->setDescription(self::$defaultDescription) + ->setHelp(<<%command.name% command setups the transports: + + php %command.full_name% + +Or a specific transport only: + + php %command.full_name% +EOF + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $io = new SymfonyStyle($input, $output); + + $transportNames = $this->transportNames; + // do we want to set up only one transport? + if ($transport = $input->getArgument('transport')) { + if (!$this->transportLocator->has($transport)) { + throw new \RuntimeException(sprintf('The "%s" transport does not exist.', $transport)); + } + $transportNames = [$transport]; + } + + foreach ($transportNames as $id => $transportName) { + $transport = $this->transportLocator->get($transportName); + if ($transport instanceof SetupableTransportInterface) { + $transport->setup(); + $io->success(sprintf('The "%s" transport was set up successfully.', $transportName)); + } else { + $io->note(sprintf('The "%s" transport does not support setup.', $transportName)); + } + } + + return 0; + } + + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + if ($input->mustSuggestArgumentValuesFor('transport')) { + $suggestions->suggestValues($this->transportNames); + + return; + } + } +} diff --git a/plugins/email/vendor/symfony/messenger/Command/StopWorkersCommand.php b/plugins/email/vendor/symfony/messenger/Command/StopWorkersCommand.php new file mode 100644 index 0000000..16fb1a4 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Command/StopWorkersCommand.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Command; + +use Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Messenger\EventListener\StopWorkerOnRestartSignalListener; + +/** + * @author Ryan Weaver + */ +class StopWorkersCommand extends Command +{ + protected static $defaultName = 'messenger:stop-workers'; + protected static $defaultDescription = 'Stop workers after their current message'; + + private $restartSignalCachePool; + + public function __construct(CacheItemPoolInterface $restartSignalCachePool) + { + $this->restartSignalCachePool = $restartSignalCachePool; + + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + protected function configure(): void + { + $this + ->setDefinition([]) + ->setDescription(self::$defaultDescription) + ->setHelp(<<<'EOF' +The %command.name% command sends a signal to stop any messenger:consume processes that are running. + + php %command.full_name% + +Each worker command will finish the message they are currently processing +and then exit. Worker commands are *not* automatically restarted: that +should be handled by a process control system. +EOF + ) + ; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output); + + $cacheItem = $this->restartSignalCachePool->getItem(StopWorkerOnRestartSignalListener::RESTART_REQUESTED_TIMESTAMP_KEY); + $cacheItem->set(microtime(true)); + $this->restartSignalCachePool->save($cacheItem); + + $io->success('Signal successfully sent to stop any running workers.'); + + return 0; + } +} diff --git a/plugins/email/vendor/symfony/messenger/DataCollector/MessengerDataCollector.php b/plugins/email/vendor/symfony/messenger/DataCollector/MessengerDataCollector.php new file mode 100644 index 0000000..ef1ec4e --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/DataCollector/MessengerDataCollector.php @@ -0,0 +1,149 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\DataCollector; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\DataCollector\DataCollector; +use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface; +use Symfony\Component\Messenger\TraceableMessageBus; +use Symfony\Component\VarDumper\Caster\ClassStub; + +/** + * @author Samuel Roze + * + * @final + */ +class MessengerDataCollector extends DataCollector implements LateDataCollectorInterface +{ + private $traceableBuses = []; + + public function registerBus(string $name, TraceableMessageBus $bus) + { + $this->traceableBuses[$name] = $bus; + } + + /** + * {@inheritdoc} + */ + public function collect(Request $request, Response $response, \Throwable $exception = null) + { + // Noop. Everything is collected live by the traceable buses & cloned as late as possible. + } + + /** + * {@inheritdoc} + */ + public function lateCollect() + { + $this->data = ['messages' => [], 'buses' => array_keys($this->traceableBuses)]; + + $messages = []; + foreach ($this->traceableBuses as $busName => $bus) { + foreach ($bus->getDispatchedMessages() as $message) { + $debugRepresentation = $this->cloneVar($this->collectMessage($busName, $message)); + $messages[] = [$debugRepresentation, $message['callTime']]; + } + } + + // Order by call time + usort($messages, function ($a, $b) { return $a[1] <=> $b[1]; }); + + // Keep the messages clones only + $this->data['messages'] = array_column($messages, 0); + } + + /** + * {@inheritdoc} + */ + public function getName(): string + { + return 'messenger'; + } + + /** + * {@inheritdoc} + */ + public function reset() + { + $this->data = []; + foreach ($this->traceableBuses as $traceableBus) { + $traceableBus->reset(); + } + } + + /** + * {@inheritdoc} + */ + protected function getCasters(): array + { + $casters = parent::getCasters(); + + // Unset the default caster truncating collectors data. + unset($casters['*']); + + return $casters; + } + + private function collectMessage(string $busName, array $tracedMessage) + { + $message = $tracedMessage['message']; + + $debugRepresentation = [ + 'bus' => $busName, + 'stamps' => $tracedMessage['stamps'] ?? null, + 'stamps_after_dispatch' => $tracedMessage['stamps_after_dispatch'] ?? null, + 'message' => [ + 'type' => new ClassStub(\get_class($message)), + 'value' => $message, + ], + 'caller' => $tracedMessage['caller'], + ]; + + if (isset($tracedMessage['exception'])) { + $exception = $tracedMessage['exception']; + + $debugRepresentation['exception'] = [ + 'type' => \get_class($exception), + 'value' => $exception, + ]; + } + + return $debugRepresentation; + } + + public function getExceptionsCount(string $bus = null): int + { + $count = 0; + foreach ($this->getMessages($bus) as $message) { + $count += (int) isset($message['exception']); + } + + return $count; + } + + public function getMessages(string $bus = null): array + { + if (null === $bus) { + return $this->data['messages']; + } + + return array_filter($this->data['messages'], function ($message) use ($bus) { + return $bus === $message['bus']; + }); + } + + public function getBuses(): array + { + return $this->data['buses']; + } +} diff --git a/plugins/email/vendor/symfony/messenger/DependencyInjection/MessengerPass.php b/plugins/email/vendor/symfony/messenger/DependencyInjection/MessengerPass.php new file mode 100644 index 0000000..f423889 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/DependencyInjection/MessengerPass.php @@ -0,0 +1,402 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\DependencyInjection; + +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\ChildDefinition; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\OutOfBoundsException; +use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\Messenger\Handler\HandlerDescriptor; +use Symfony\Component\Messenger\Handler\HandlersLocator; +use Symfony\Component\Messenger\Handler\MessageSubscriberInterface; +use Symfony\Component\Messenger\TraceableMessageBus; +use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; + +/** + * @author Samuel Roze + */ +class MessengerPass implements CompilerPassInterface +{ + private $handlerTag; + private $busTag; + private $receiverTag; + + public function __construct(string $handlerTag = 'messenger.message_handler', string $busTag = 'messenger.bus', string $receiverTag = 'messenger.receiver') + { + if (0 < \func_num_args()) { + trigger_deprecation('symfony/messenger', '5.3', 'Configuring "%s" is deprecated.', __CLASS__); + } + + $this->handlerTag = $handlerTag; + $this->busTag = $busTag; + $this->receiverTag = $receiverTag; + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + $busIds = []; + foreach ($container->findTaggedServiceIds($this->busTag) as $busId => $tags) { + $busIds[] = $busId; + if ($container->hasParameter($busMiddlewareParameter = $busId.'.middleware')) { + $this->registerBusMiddleware($container, $busId, $container->getParameter($busMiddlewareParameter)); + + $container->getParameterBag()->remove($busMiddlewareParameter); + } + + if ($container->hasDefinition('data_collector.messenger')) { + $this->registerBusToCollector($container, $busId); + } + } + + if ($container->hasDefinition('messenger.receiver_locator')) { + $this->registerReceivers($container, $busIds); + } + $this->registerHandlers($container, $busIds); + } + + private function registerHandlers(ContainerBuilder $container, array $busIds) + { + $definitions = []; + $handlersByBusAndMessage = []; + $handlerToOriginalServiceIdMapping = []; + + foreach ($container->findTaggedServiceIds($this->handlerTag, true) as $serviceId => $tags) { + foreach ($tags as $tag) { + if (isset($tag['bus']) && !\in_array($tag['bus'], $busIds, true)) { + throw new RuntimeException(sprintf('Invalid handler service "%s": bus "%s" specified on the tag "%s" does not exist (known ones are: "%s").', $serviceId, $tag['bus'], $this->handlerTag, implode('", "', $busIds))); + } + + $className = $this->getServiceClass($container, $serviceId); + $r = $container->getReflectionClass($className); + + if (null === $r) { + throw new RuntimeException(sprintf('Invalid service "%s": class "%s" does not exist.', $serviceId, $className)); + } + + if (isset($tag['handles'])) { + $handles = isset($tag['method']) ? [$tag['handles'] => $tag['method']] : [$tag['handles']]; + } else { + $handles = $this->guessHandledClasses($r, $serviceId); + } + + $message = null; + $handlerBuses = (array) ($tag['bus'] ?? $busIds); + + foreach ($handles as $message => $options) { + $buses = $handlerBuses; + + if (\is_int($message)) { + if (\is_string($options)) { + $message = $options; + $options = []; + } else { + throw new RuntimeException(sprintf('The handler configuration needs to return an array of messages or an associated array of message and configuration. Found value of type "%s" at position "%d" for service "%s".', get_debug_type($options), $message, $serviceId)); + } + } + + if (\is_string($options)) { + $options = ['method' => $options]; + } + + if (!isset($options['from_transport']) && isset($tag['from_transport'])) { + $options['from_transport'] = $tag['from_transport']; + } + + $priority = $tag['priority'] ?? $options['priority'] ?? 0; + $method = $options['method'] ?? '__invoke'; + + if (isset($options['bus'])) { + if (!\in_array($options['bus'], $busIds)) { + $messageLocation = isset($tag['handles']) ? 'declared in your tag attribute "handles"' : ($r->implementsInterface(MessageSubscriberInterface::class) ? sprintf('returned by method "%s::getHandledMessages()"', $r->getName()) : sprintf('used as argument type in method "%s::%s()"', $r->getName(), $method)); + + throw new RuntimeException(sprintf('Invalid configuration "%s" for message "%s": bus "%s" does not exist.', $messageLocation, $message, $options['bus'])); + } + + $buses = [$options['bus']]; + } + + if ('*' !== $message && !class_exists($message) && !interface_exists($message, false)) { + $messageLocation = isset($tag['handles']) ? 'declared in your tag attribute "handles"' : ($r->implementsInterface(MessageSubscriberInterface::class) ? sprintf('returned by method "%s::getHandledMessages()"', $r->getName()) : sprintf('used as argument type in method "%s::%s()"', $r->getName(), $method)); + + throw new RuntimeException(sprintf('Invalid handler service "%s": class or interface "%s" "%s" not found.', $serviceId, $message, $messageLocation)); + } + + if (!$r->hasMethod($method)) { + throw new RuntimeException(sprintf('Invalid handler service "%s": method "%s::%s()" does not exist.', $serviceId, $r->getName(), $method)); + } + + if ('__invoke' !== $method) { + $wrapperDefinition = (new Definition('callable'))->addArgument([new Reference($serviceId), $method])->setFactory('Closure::fromCallable'); + + $definitions[$definitionId = '.messenger.method_on_object_wrapper.'.ContainerBuilder::hash($message.':'.$priority.':'.$serviceId.':'.$method)] = $wrapperDefinition; + } else { + $definitionId = $serviceId; + } + + $handlerToOriginalServiceIdMapping[$definitionId] = $serviceId; + + foreach ($buses as $handlerBus) { + $handlersByBusAndMessage[$handlerBus][$message][$priority][] = [$definitionId, $options]; + } + } + + if (null === $message) { + throw new RuntimeException(sprintf('Invalid handler service "%s": method "%s::getHandledMessages()" must return one or more messages.', $serviceId, $r->getName())); + } + } + } + + foreach ($handlersByBusAndMessage as $bus => $handlersByMessage) { + foreach ($handlersByMessage as $message => $handlersByPriority) { + krsort($handlersByPriority); + $handlersByBusAndMessage[$bus][$message] = array_merge(...$handlersByPriority); + } + } + + $handlersLocatorMappingByBus = []; + foreach ($handlersByBusAndMessage as $bus => $handlersByMessage) { + foreach ($handlersByMessage as $message => $handlers) { + $handlerDescriptors = []; + foreach ($handlers as $handler) { + $definitions[$definitionId = '.messenger.handler_descriptor.'.ContainerBuilder::hash($bus.':'.$message.':'.$handler[0])] = (new Definition(HandlerDescriptor::class))->setArguments([new Reference($handler[0]), $handler[1]]); + $handlerDescriptors[] = new Reference($definitionId); + } + + $handlersLocatorMappingByBus[$bus][$message] = new IteratorArgument($handlerDescriptors); + } + } + $container->addDefinitions($definitions); + + foreach ($busIds as $bus) { + $container->register($locatorId = $bus.'.messenger.handlers_locator', HandlersLocator::class) + ->setArgument(0, $handlersLocatorMappingByBus[$bus] ?? []) + ; + if ($container->has($handleMessageId = $bus.'.middleware.handle_message')) { + $container->getDefinition($handleMessageId) + ->replaceArgument(0, new Reference($locatorId)) + ; + } + } + + if ($container->hasDefinition('console.command.messenger_debug')) { + $debugCommandMapping = $handlersByBusAndMessage; + foreach ($busIds as $bus) { + if (!isset($debugCommandMapping[$bus])) { + $debugCommandMapping[$bus] = []; + } + + foreach ($debugCommandMapping[$bus] as $message => $handlers) { + foreach ($handlers as $key => $handler) { + $debugCommandMapping[$bus][$message][$key][0] = $handlerToOriginalServiceIdMapping[$handler[0]]; + } + } + } + $container->getDefinition('console.command.messenger_debug')->replaceArgument(0, $debugCommandMapping); + } + } + + private function guessHandledClasses(\ReflectionClass $handlerClass, string $serviceId): iterable + { + if ($handlerClass->implementsInterface(MessageSubscriberInterface::class)) { + return $handlerClass->getName()::getHandledMessages(); + } + + try { + $method = $handlerClass->getMethod('__invoke'); + } catch (\ReflectionException $e) { + throw new RuntimeException(sprintf('Invalid handler service "%s": class "%s" must have an "__invoke()" method.', $serviceId, $handlerClass->getName())); + } + + if (0 === $method->getNumberOfRequiredParameters()) { + throw new RuntimeException(sprintf('Invalid handler service "%s": method "%s::__invoke()" requires at least one argument, first one being the message it handles.', $serviceId, $handlerClass->getName())); + } + + $parameters = $method->getParameters(); + if (!$type = $parameters[0]->getType()) { + throw new RuntimeException(sprintf('Invalid handler service "%s": argument "$%s" of method "%s::__invoke()" must have a type-hint corresponding to the message class it handles.', $serviceId, $parameters[0]->getName(), $handlerClass->getName())); + } + + if ($type instanceof \ReflectionUnionType) { + $types = []; + $invalidTypes = []; + foreach ($type->getTypes() as $type) { + if (!$type->isBuiltin()) { + $types[] = (string) $type; + } else { + $invalidTypes[] = (string) $type; + } + } + + if ($types) { + return $types; + } + + throw new RuntimeException(sprintf('Invalid handler service "%s": type-hint of argument "$%s" in method "%s::__invoke()" must be a class , "%s" given.', $serviceId, $parameters[0]->getName(), $handlerClass->getName(), implode('|', $invalidTypes))); + } + + if ($type->isBuiltin()) { + throw new RuntimeException(sprintf('Invalid handler service "%s": type-hint of argument "$%s" in method "%s::__invoke()" must be a class , "%s" given.', $serviceId, $parameters[0]->getName(), $handlerClass->getName(), $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type)); + } + + return [$type->getName()]; + } + + private function registerReceivers(ContainerBuilder $container, array $busIds) + { + $receiverMapping = []; + $failureTransportsMap = []; + if ($container->hasDefinition('console.command.messenger_failed_messages_retry')) { + $commandDefinition = $container->getDefinition('console.command.messenger_failed_messages_retry'); + $globalReceiverName = $commandDefinition->getArgument(0); + if (null !== $globalReceiverName) { + if ($container->hasAlias('messenger.failure_transports.default')) { + $failureTransportsMap[$globalReceiverName] = new Reference('messenger.failure_transports.default'); + } else { + $failureTransportsMap[$globalReceiverName] = new Reference('messenger.transport.'.$globalReceiverName); + } + } + } + + foreach ($container->findTaggedServiceIds($this->receiverTag) as $id => $tags) { + $receiverClass = $this->getServiceClass($container, $id); + if (!is_subclass_of($receiverClass, ReceiverInterface::class)) { + throw new RuntimeException(sprintf('Invalid receiver "%s": class "%s" must implement interface "%s".', $id, $receiverClass, ReceiverInterface::class)); + } + + $receiverMapping[$id] = new Reference($id); + + foreach ($tags as $tag) { + if (isset($tag['alias'])) { + $receiverMapping[$tag['alias']] = $receiverMapping[$id]; + if ($tag['is_failure_transport'] ?? false) { + $failureTransportsMap[$tag['alias']] = $receiverMapping[$id]; + } + } + } + } + + $receiverNames = []; + foreach ($receiverMapping as $name => $reference) { + $receiverNames[(string) $reference] = $name; + } + + $buses = []; + foreach ($busIds as $busId) { + $buses[$busId] = new Reference($busId); + } + + if ($hasRoutableMessageBus = $container->hasDefinition('messenger.routable_message_bus')) { + $container->getDefinition('messenger.routable_message_bus') + ->replaceArgument(0, ServiceLocatorTagPass::register($container, $buses)); + } + + if ($container->hasDefinition('console.command.messenger_consume_messages')) { + $consumeCommandDefinition = $container->getDefinition('console.command.messenger_consume_messages'); + + if ($hasRoutableMessageBus) { + $consumeCommandDefinition->replaceArgument(0, new Reference('messenger.routable_message_bus')); + } + + $consumeCommandDefinition->replaceArgument(4, array_values($receiverNames)); + try { + $consumeCommandDefinition->replaceArgument(6, $busIds); + } catch (OutOfBoundsException $e) { + // ignore to preserve compatibility with symfony/framework-bundle < 5.4 + } + } + + if ($container->hasDefinition('console.command.messenger_setup_transports')) { + $container->getDefinition('console.command.messenger_setup_transports') + ->replaceArgument(1, array_values($receiverNames)); + } + + $container->getDefinition('messenger.receiver_locator')->replaceArgument(0, $receiverMapping); + + $failureTransportsLocator = ServiceLocatorTagPass::register($container, $failureTransportsMap); + + $failedCommandIds = [ + 'console.command.messenger_failed_messages_retry', + 'console.command.messenger_failed_messages_show', + 'console.command.messenger_failed_messages_remove', + ]; + foreach ($failedCommandIds as $failedCommandId) { + if ($container->hasDefinition($failedCommandId)) { + $definition = $container->getDefinition($failedCommandId); + $definition->replaceArgument(1, $failureTransportsLocator); + } + } + } + + private function registerBusToCollector(ContainerBuilder $container, string $busId) + { + $container->setDefinition( + $tracedBusId = 'debug.traced.'.$busId, + (new Definition(TraceableMessageBus::class, [new Reference($tracedBusId.'.inner')]))->setDecoratedService($busId) + ); + + $container->getDefinition('data_collector.messenger')->addMethodCall('registerBus', [$busId, new Reference($tracedBusId)]); + } + + private function registerBusMiddleware(ContainerBuilder $container, string $busId, array $middlewareCollection) + { + $middlewareReferences = []; + foreach ($middlewareCollection as $middlewareItem) { + $id = $middlewareItem['id']; + $arguments = $middlewareItem['arguments'] ?? []; + if (!$container->has($messengerMiddlewareId = 'messenger.middleware.'.$id)) { + $messengerMiddlewareId = $id; + } + + if (!$container->has($messengerMiddlewareId)) { + throw new RuntimeException(sprintf('Invalid middleware: service "%s" not found.', $id)); + } + + if ($container->findDefinition($messengerMiddlewareId)->isAbstract()) { + $childDefinition = new ChildDefinition($messengerMiddlewareId); + $childDefinition->setArguments($arguments); + if (isset($middlewareReferences[$messengerMiddlewareId = $busId.'.middleware.'.$id])) { + $messengerMiddlewareId .= '.'.ContainerBuilder::hash($arguments); + } + $container->setDefinition($messengerMiddlewareId, $childDefinition); + } elseif ($arguments) { + throw new RuntimeException(sprintf('Invalid middleware factory "%s": a middleware factory must be an abstract definition.', $id)); + } + + $middlewareReferences[$messengerMiddlewareId] = new Reference($messengerMiddlewareId); + } + + $container->getDefinition($busId)->replaceArgument(0, new IteratorArgument(array_values($middlewareReferences))); + } + + private function getServiceClass(ContainerBuilder $container, string $serviceId): string + { + while (true) { + $definition = $container->findDefinition($serviceId); + + if (!$definition->getClass() && $definition instanceof ChildDefinition) { + $serviceId = $definition->getParent(); + + continue; + } + + return $definition->getClass(); + } + } +} diff --git a/plugins/email/vendor/symfony/messenger/Envelope.php b/plugins/email/vendor/symfony/messenger/Envelope.php new file mode 100644 index 0000000..49476fe --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Envelope.php @@ -0,0 +1,131 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger; + +use Symfony\Component\Messenger\Stamp\StampInterface; + +/** + * A message wrapped in an envelope with stamps (configurations, markers, ...). + * + * @author Maxime Steinhausser + */ +final class Envelope +{ + /** + * @var array> + */ + private $stamps = []; + private $message; + + /** + * @param StampInterface[] $stamps + */ + public function __construct(object $message, array $stamps = []) + { + $this->message = $message; + + foreach ($stamps as $stamp) { + $this->stamps[\get_class($stamp)][] = $stamp; + } + } + + /** + * Makes sure the message is in an Envelope and adds the given stamps. + * + * @param object|Envelope $message + * @param StampInterface[] $stamps + */ + public static function wrap(object $message, array $stamps = []): self + { + $envelope = $message instanceof self ? $message : new self($message); + + return $envelope->with(...$stamps); + } + + /** + * @return static A new Envelope instance with additional stamp + */ + public function with(StampInterface ...$stamps): self + { + $cloned = clone $this; + + foreach ($stamps as $stamp) { + $cloned->stamps[\get_class($stamp)][] = $stamp; + } + + return $cloned; + } + + /** + * @return static A new Envelope instance without any stamps of the given class + */ + public function withoutAll(string $stampFqcn): self + { + $cloned = clone $this; + + unset($cloned->stamps[$this->resolveAlias($stampFqcn)]); + + return $cloned; + } + + /** + * Removes all stamps that implement the given type. + */ + public function withoutStampsOfType(string $type): self + { + $cloned = clone $this; + $type = $this->resolveAlias($type); + + foreach ($cloned->stamps as $class => $stamps) { + if ($class === $type || is_subclass_of($class, $type)) { + unset($cloned->stamps[$class]); + } + } + + return $cloned; + } + + public function last(string $stampFqcn): ?StampInterface + { + return isset($this->stamps[$stampFqcn = $this->resolveAlias($stampFqcn)]) ? end($this->stamps[$stampFqcn]) : null; + } + + /** + * @return StampInterface[]|StampInterface[][] The stamps for the specified FQCN, or all stamps by their class name + */ + public function all(string $stampFqcn = null): array + { + if (null !== $stampFqcn) { + return $this->stamps[$this->resolveAlias($stampFqcn)] ?? []; + } + + return $this->stamps; + } + + /** + * @return object The original message contained in the envelope + */ + public function getMessage(): object + { + return $this->message; + } + + /** + * BC to be removed in 6.0. + */ + private function resolveAlias(string $fqcn): string + { + static $resolved; + + return $resolved[$fqcn] ?? ($resolved[$fqcn] = class_exists($fqcn) ? (new \ReflectionClass($fqcn))->getName() : $fqcn); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Event/AbstractWorkerMessageEvent.php b/plugins/email/vendor/symfony/messenger/Event/AbstractWorkerMessageEvent.php new file mode 100644 index 0000000..e3ece81 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Event/AbstractWorkerMessageEvent.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Event; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Stamp\StampInterface; + +abstract class AbstractWorkerMessageEvent +{ + private $envelope; + private $receiverName; + + public function __construct(Envelope $envelope, string $receiverName) + { + $this->envelope = $envelope; + $this->receiverName = $receiverName; + } + + public function getEnvelope(): Envelope + { + return $this->envelope; + } + + /** + * Returns a unique identifier for transport receiver this message was received from. + */ + public function getReceiverName(): string + { + return $this->receiverName; + } + + public function addStamps(StampInterface ...$stamps): void + { + $this->envelope = $this->envelope->with(...$stamps); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Event/SendMessageToTransportsEvent.php b/plugins/email/vendor/symfony/messenger/Event/SendMessageToTransportsEvent.php new file mode 100644 index 0000000..5fd5fd8 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Event/SendMessageToTransportsEvent.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Event; + +use Symfony\Component\Messenger\Envelope; + +/** + * Event is dispatched before a message is sent to the transport. + * + * The event is *only* dispatched if the message will actually + * be sent to at least one transport. If the message is sent + * to multiple transports, the message is dispatched only one time. + * This message is only dispatched the first time a message + * is sent to a transport, not also if it is retried. + * + * @author Ryan Weaver + */ +final class SendMessageToTransportsEvent +{ + private $envelope; + + public function __construct(Envelope $envelope) + { + $this->envelope = $envelope; + } + + public function getEnvelope(): Envelope + { + return $this->envelope; + } + + public function setEnvelope(Envelope $envelope) + { + $this->envelope = $envelope; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Event/WorkerMessageFailedEvent.php b/plugins/email/vendor/symfony/messenger/Event/WorkerMessageFailedEvent.php new file mode 100644 index 0000000..7fb858c --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Event/WorkerMessageFailedEvent.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Event; + +use Symfony\Component\Messenger\Envelope; + +/** + * Dispatched when a message was received from a transport and handling failed. + * + * The event name is the class name. + */ +final class WorkerMessageFailedEvent extends AbstractWorkerMessageEvent +{ + private $throwable; + private $willRetry = false; + + public function __construct(Envelope $envelope, string $receiverName, \Throwable $error) + { + $this->throwable = $error; + + parent::__construct($envelope, $receiverName); + } + + public function getThrowable(): \Throwable + { + return $this->throwable; + } + + public function willRetry(): bool + { + return $this->willRetry; + } + + public function setForRetry(): void + { + $this->willRetry = true; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Event/WorkerMessageHandledEvent.php b/plugins/email/vendor/symfony/messenger/Event/WorkerMessageHandledEvent.php new file mode 100644 index 0000000..3c4a030 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Event/WorkerMessageHandledEvent.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Event; + +/** + * Dispatched after a message was received from a transport and successfully handled. + * + * The event name is the class name. + */ +final class WorkerMessageHandledEvent extends AbstractWorkerMessageEvent +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Event/WorkerMessageReceivedEvent.php b/plugins/email/vendor/symfony/messenger/Event/WorkerMessageReceivedEvent.php new file mode 100644 index 0000000..5b99edc --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Event/WorkerMessageReceivedEvent.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Event; + +/** + * Dispatched when a message was received from a transport but before sent to the bus. + * + * The event name is the class name. + */ +final class WorkerMessageReceivedEvent extends AbstractWorkerMessageEvent +{ + private $shouldHandle = true; + + public function shouldHandle(bool $shouldHandle = null): bool + { + if (null !== $shouldHandle) { + $this->shouldHandle = $shouldHandle; + } + + return $this->shouldHandle; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Event/WorkerMessageRetriedEvent.php b/plugins/email/vendor/symfony/messenger/Event/WorkerMessageRetriedEvent.php new file mode 100644 index 0000000..d348b44 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Event/WorkerMessageRetriedEvent.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Event; + +/** + * Dispatched after a message has been sent for retry. + * + * The event name is the class name. + */ +final class WorkerMessageRetriedEvent extends AbstractWorkerMessageEvent +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Event/WorkerRunningEvent.php b/plugins/email/vendor/symfony/messenger/Event/WorkerRunningEvent.php new file mode 100644 index 0000000..ca32cb4 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Event/WorkerRunningEvent.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Event; + +use Symfony\Component\Messenger\Worker; + +/** + * Dispatched after the worker processed a message or didn't receive a message at all. + * + * @author Tobias Schultze + */ +final class WorkerRunningEvent +{ + private $worker; + private $isWorkerIdle; + + public function __construct(Worker $worker, bool $isWorkerIdle) + { + $this->worker = $worker; + $this->isWorkerIdle = $isWorkerIdle; + } + + public function getWorker(): Worker + { + return $this->worker; + } + + /** + * Returns true when no message has been received by the worker. + */ + public function isWorkerIdle(): bool + { + return $this->isWorkerIdle; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Event/WorkerStartedEvent.php b/plugins/email/vendor/symfony/messenger/Event/WorkerStartedEvent.php new file mode 100644 index 0000000..9d37d8d --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Event/WorkerStartedEvent.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Event; + +use Symfony\Component\Messenger\Worker; + +/** + * Dispatched when a worker has been started. + * + * @author Tobias Schultze + */ +final class WorkerStartedEvent +{ + private $worker; + + public function __construct(Worker $worker) + { + $this->worker = $worker; + } + + public function getWorker(): Worker + { + return $this->worker; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Event/WorkerStoppedEvent.php b/plugins/email/vendor/symfony/messenger/Event/WorkerStoppedEvent.php new file mode 100644 index 0000000..e0d4610 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Event/WorkerStoppedEvent.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Event; + +use Symfony\Component\Messenger\Worker; + +/** + * Dispatched when a worker has been stopped. + * + * @author Robin Chalas + */ +final class WorkerStoppedEvent +{ + private $worker; + + public function __construct(Worker $worker) + { + $this->worker = $worker; + } + + public function getWorker(): Worker + { + return $this->worker; + } +} diff --git a/plugins/email/vendor/symfony/messenger/EventListener/AddErrorDetailsStampListener.php b/plugins/email/vendor/symfony/messenger/EventListener/AddErrorDetailsStampListener.php new file mode 100644 index 0000000..fd5c9d6 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/EventListener/AddErrorDetailsStampListener.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; +use Symfony\Component\Messenger\Stamp\ErrorDetailsStamp; + +final class AddErrorDetailsStampListener implements EventSubscriberInterface +{ + public function onMessageFailed(WorkerMessageFailedEvent $event): void + { + $stamp = ErrorDetailsStamp::create($event->getThrowable()); + $previousStamp = $event->getEnvelope()->last(ErrorDetailsStamp::class); + + // Do not append duplicate information + if (null === $previousStamp || !$previousStamp->equals($stamp)) { + $event->addStamps($stamp); + } + } + + public static function getSubscribedEvents(): array + { + return [ + // must have higher priority than SendFailedMessageForRetryListener + WorkerMessageFailedEvent::class => ['onMessageFailed', 200], + ]; + } +} diff --git a/plugins/email/vendor/symfony/messenger/EventListener/DispatchPcntlSignalListener.php b/plugins/email/vendor/symfony/messenger/EventListener/DispatchPcntlSignalListener.php new file mode 100644 index 0000000..27182bd --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/EventListener/DispatchPcntlSignalListener.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Event\WorkerRunningEvent; + +/** + * @author Tobias Schultze + */ +class DispatchPcntlSignalListener implements EventSubscriberInterface +{ + public function onWorkerRunning(): void + { + pcntl_signal_dispatch(); + } + + public static function getSubscribedEvents() + { + if (!\function_exists('pcntl_signal_dispatch')) { + return []; + } + + return [ + WorkerRunningEvent::class => ['onWorkerRunning', 100], + ]; + } +} diff --git a/plugins/email/vendor/symfony/messenger/EventListener/ResetServicesListener.php b/plugins/email/vendor/symfony/messenger/EventListener/ResetServicesListener.php new file mode 100644 index 0000000..d5266f3 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/EventListener/ResetServicesListener.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter; +use Symfony\Component\Messenger\Event\WorkerRunningEvent; +use Symfony\Component\Messenger\Event\WorkerStoppedEvent; + +/** + * @author Grégoire Pineau + */ +class ResetServicesListener implements EventSubscriberInterface +{ + private $servicesResetter; + + public function __construct(ServicesResetter $servicesResetter) + { + $this->servicesResetter = $servicesResetter; + } + + public function resetServices(WorkerRunningEvent $event): void + { + if (!$event->isWorkerIdle()) { + $this->servicesResetter->reset(); + } + } + + public function resetServicesAtStop(WorkerStoppedEvent $event): void + { + $this->servicesResetter->reset(); + } + + public static function getSubscribedEvents(): array + { + return [ + WorkerRunningEvent::class => ['resetServices', -1024], + WorkerStoppedEvent::class => ['resetServicesAtStop', -1024], + ]; + } +} diff --git a/plugins/email/vendor/symfony/messenger/EventListener/SendFailedMessageForRetryListener.php b/plugins/email/vendor/symfony/messenger/EventListener/SendFailedMessageForRetryListener.php new file mode 100644 index 0000000..dab74b2 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/EventListener/SendFailedMessageForRetryListener.php @@ -0,0 +1,173 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\EventListener; + +use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; +use Symfony\Component\Messenger\Event\WorkerMessageRetriedEvent; +use Symfony\Component\Messenger\Exception\HandlerFailedException; +use Symfony\Component\Messenger\Exception\RecoverableExceptionInterface; +use Symfony\Component\Messenger\Exception\RuntimeException; +use Symfony\Component\Messenger\Exception\UnrecoverableExceptionInterface; +use Symfony\Component\Messenger\Retry\RetryStrategyInterface; +use Symfony\Component\Messenger\Stamp\DelayStamp; +use Symfony\Component\Messenger\Stamp\RedeliveryStamp; +use Symfony\Component\Messenger\Stamp\StampInterface; +use Symfony\Component\Messenger\Transport\Sender\SenderInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; + +/** + * @author Tobias Schultze + */ +class SendFailedMessageForRetryListener implements EventSubscriberInterface +{ + private $sendersLocator; + private $retryStrategyLocator; + private $logger; + private $eventDispatcher; + private $historySize; + + public function __construct(ContainerInterface $sendersLocator, ContainerInterface $retryStrategyLocator, LoggerInterface $logger = null, EventDispatcherInterface $eventDispatcher = null, int $historySize = 10) + { + $this->sendersLocator = $sendersLocator; + $this->retryStrategyLocator = $retryStrategyLocator; + $this->logger = $logger; + $this->eventDispatcher = $eventDispatcher; + $this->historySize = $historySize; + } + + public function onMessageFailed(WorkerMessageFailedEvent $event) + { + $retryStrategy = $this->getRetryStrategyForTransport($event->getReceiverName()); + $envelope = $event->getEnvelope(); + $throwable = $event->getThrowable(); + + $message = $envelope->getMessage(); + $context = [ + 'class' => \get_class($message), + ]; + + $shouldRetry = $retryStrategy && $this->shouldRetry($throwable, $envelope, $retryStrategy); + + $retryCount = RedeliveryStamp::getRetryCountFromEnvelope($envelope); + if ($shouldRetry) { + $event->setForRetry(); + + ++$retryCount; + + $delay = $retryStrategy->getWaitingTime($envelope, $throwable); + + if (null !== $this->logger) { + $this->logger->warning('Error thrown while handling message {class}. Sending for retry #{retryCount} using {delay} ms delay. Error: "{error}"', $context + ['retryCount' => $retryCount, 'delay' => $delay, 'error' => $throwable->getMessage(), 'exception' => $throwable]); + } + + // add the delay and retry stamp info + $retryEnvelope = $this->withLimitedHistory($envelope, new DelayStamp($delay), new RedeliveryStamp($retryCount)); + + // re-send the message for retry + $this->getSenderForTransport($event->getReceiverName())->send($retryEnvelope); + + if (null !== $this->eventDispatcher) { + $this->eventDispatcher->dispatch(new WorkerMessageRetriedEvent($retryEnvelope, $event->getReceiverName())); + } + } else { + if (null !== $this->logger) { + $this->logger->critical('Error thrown while handling message {class}. Removing from transport after {retryCount} retries. Error: "{error}"', $context + ['retryCount' => $retryCount, 'error' => $throwable->getMessage(), 'exception' => $throwable]); + } + } + } + + /** + * Adds stamps to the envelope by keeping only the First + Last N stamps. + */ + private function withLimitedHistory(Envelope $envelope, StampInterface ...$stamps): Envelope + { + foreach ($stamps as $stamp) { + $history = $envelope->all(\get_class($stamp)); + if (\count($history) < $this->historySize) { + $envelope = $envelope->with($stamp); + continue; + } + + $history = array_merge( + [$history[0]], + \array_slice($history, -$this->historySize + 2), + [$stamp] + ); + + $envelope = $envelope->withoutAll(\get_class($stamp))->with(...$history); + } + + return $envelope; + } + + public static function getSubscribedEvents() + { + return [ + // must have higher priority than SendFailedMessageToFailureTransportListener + WorkerMessageFailedEvent::class => ['onMessageFailed', 100], + ]; + } + + private function shouldRetry(\Throwable $e, Envelope $envelope, RetryStrategyInterface $retryStrategy): bool + { + if ($e instanceof RecoverableExceptionInterface) { + return true; + } + + // if one or more nested Exceptions is an instance of RecoverableExceptionInterface we should retry + // if ALL nested Exceptions are an instance of UnrecoverableExceptionInterface we should not retry + if ($e instanceof HandlerFailedException) { + $shouldNotRetry = true; + foreach ($e->getNestedExceptions() as $nestedException) { + if ($nestedException instanceof RecoverableExceptionInterface) { + return true; + } + + if (!$nestedException instanceof UnrecoverableExceptionInterface) { + $shouldNotRetry = false; + break; + } + } + if ($shouldNotRetry) { + return false; + } + } + + if ($e instanceof UnrecoverableExceptionInterface) { + return false; + } + + return $retryStrategy->isRetryable($envelope, $e); + } + + private function getRetryStrategyForTransport(string $alias): ?RetryStrategyInterface + { + if ($this->retryStrategyLocator->has($alias)) { + return $this->retryStrategyLocator->get($alias); + } + + return null; + } + + private function getSenderForTransport(string $alias): SenderInterface + { + if ($this->sendersLocator->has($alias)) { + return $this->sendersLocator->get($alias); + } + + throw new RuntimeException(sprintf('Could not find sender "%s" based on the same receiver to send the failed message to for retry.', $alias)); + } +} diff --git a/plugins/email/vendor/symfony/messenger/EventListener/SendFailedMessageToFailureTransportListener.php b/plugins/email/vendor/symfony/messenger/EventListener/SendFailedMessageToFailureTransportListener.php new file mode 100644 index 0000000..644f5a6 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/EventListener/SendFailedMessageToFailureTransportListener.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\EventListener; + +use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; +use Symfony\Component\Messenger\Stamp\DelayStamp; +use Symfony\Component\Messenger\Stamp\RedeliveryStamp; +use Symfony\Component\Messenger\Stamp\SentToFailureTransportStamp; +use Symfony\Component\Messenger\Transport\Sender\SenderInterface; + +/** + * Sends a rejected message to a "failure transport". + * + * @author Ryan Weaver + */ +class SendFailedMessageToFailureTransportListener implements EventSubscriberInterface +{ + private $failureSenders; + private $logger; + + /** + * @param ContainerInterface $failureSenders + */ + public function __construct($failureSenders, LoggerInterface $logger = null) + { + if (!$failureSenders instanceof ContainerInterface) { + trigger_deprecation('symfony/messenger', '5.3', 'Passing a SenderInterface value as 1st argument to "%s()" is deprecated, pass a ServiceLocator instead.', __METHOD__); + } + + $this->failureSenders = $failureSenders; + $this->logger = $logger; + } + + public function onMessageFailed(WorkerMessageFailedEvent $event) + { + if ($event->willRetry()) { + return; + } + + if (!$this->hasFailureTransports($event)) { + return; + } + + $failureSender = $this->getFailureSender($event->getReceiverName()); + if (null === $failureSender) { + return; + } + + $envelope = $event->getEnvelope(); + + // avoid re-sending to the failed sender + if (null !== $envelope->last(SentToFailureTransportStamp::class)) { + return; + } + + $envelope = $envelope->with( + new SentToFailureTransportStamp($event->getReceiverName()), + new DelayStamp(0), + new RedeliveryStamp(0) + ); + + if (null !== $this->logger) { + $this->logger->info('Rejected message {class} will be sent to the failure transport {transport}.', [ + 'class' => \get_class($envelope->getMessage()), + 'transport' => \get_class($failureSender), + ]); + } + + $failureSender->send($envelope); + } + + public static function getSubscribedEvents() + { + return [ + WorkerMessageFailedEvent::class => ['onMessageFailed', -100], + ]; + } + + private function getFailureSender(string $receiverName): SenderInterface + { + if ($this->failureSenders instanceof SenderInterface) { + return $this->failureSenders; + } + + return $this->failureSenders->get($receiverName); + } + + private function hasFailureTransports(WorkerMessageFailedEvent $event): bool + { + return ($this->failureSenders instanceof ContainerInterface && $this->failureSenders->has($event->getReceiverName())) || $this->failureSenders instanceof SenderInterface; + } +} diff --git a/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnCustomStopExceptionListener.php b/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnCustomStopExceptionListener.php new file mode 100644 index 0000000..ee8daec --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnCustomStopExceptionListener.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; +use Symfony\Component\Messenger\Event\WorkerRunningEvent; +use Symfony\Component\Messenger\Exception\HandlerFailedException; +use Symfony\Component\Messenger\Exception\StopWorkerExceptionInterface; + +/** + * @author Grégoire Pineau + */ +class StopWorkerOnCustomStopExceptionListener implements EventSubscriberInterface +{ + private $stop = false; + + public function onMessageFailed(WorkerMessageFailedEvent $event): void + { + $th = $event->getThrowable(); + if ($th instanceof StopWorkerExceptionInterface) { + $this->stop = true; + } + if ($th instanceof HandlerFailedException) { + foreach ($th->getNestedExceptions() as $e) { + if ($e instanceof StopWorkerExceptionInterface) { + $this->stop = true; + break; + } + } + } + } + + public function onWorkerRunning(WorkerRunningEvent $event): void + { + if ($this->stop) { + $event->getWorker()->stop(); + } + } + + public static function getSubscribedEvents(): array + { + return [ + WorkerMessageFailedEvent::class => 'onMessageFailed', + WorkerRunningEvent::class => 'onWorkerRunning', + ]; + } +} diff --git a/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnFailureLimitListener.php b/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnFailureLimitListener.php new file mode 100644 index 0000000..29dc6aa --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnFailureLimitListener.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\EventListener; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; +use Symfony\Component\Messenger\Event\WorkerRunningEvent; +use Symfony\Component\Messenger\Exception\InvalidArgumentException; + +/** + * @author Michel Hunziker + */ +class StopWorkerOnFailureLimitListener implements EventSubscriberInterface +{ + private $maximumNumberOfFailures; + private $logger; + private $failedMessages = 0; + + public function __construct(int $maximumNumberOfFailures, LoggerInterface $logger = null) + { + $this->maximumNumberOfFailures = $maximumNumberOfFailures; + $this->logger = $logger; + + if ($maximumNumberOfFailures <= 0) { + throw new InvalidArgumentException('Failure limit must be greater than zero.'); + } + } + + public function onMessageFailed(WorkerMessageFailedEvent $event): void + { + ++$this->failedMessages; + } + + public function onWorkerRunning(WorkerRunningEvent $event): void + { + if (!$event->isWorkerIdle() && $this->failedMessages >= $this->maximumNumberOfFailures) { + $this->failedMessages = 0; + $event->getWorker()->stop(); + + if (null !== $this->logger) { + $this->logger->info('Worker stopped due to limit of {count} failed message(s) is reached', ['count' => $this->maximumNumberOfFailures]); + } + } + } + + public static function getSubscribedEvents(): array + { + return [ + WorkerMessageFailedEvent::class => 'onMessageFailed', + WorkerRunningEvent::class => 'onWorkerRunning', + ]; + } +} diff --git a/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnMemoryLimitListener.php b/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnMemoryLimitListener.php new file mode 100644 index 0000000..73350fd --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnMemoryLimitListener.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\EventListener; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Event\WorkerRunningEvent; + +/** + * @author Simon Delicata + * @author Tobias Schultze + */ +class StopWorkerOnMemoryLimitListener implements EventSubscriberInterface +{ + private $memoryLimit; + private $logger; + private $memoryResolver; + + public function __construct(int $memoryLimit, LoggerInterface $logger = null, callable $memoryResolver = null) + { + $this->memoryLimit = $memoryLimit; + $this->logger = $logger; + $this->memoryResolver = $memoryResolver ?: static function () { + return memory_get_usage(true); + }; + } + + public function onWorkerRunning(WorkerRunningEvent $event): void + { + $memoryResolver = $this->memoryResolver; + $usedMemory = $memoryResolver(); + if ($usedMemory > $this->memoryLimit) { + $event->getWorker()->stop(); + if (null !== $this->logger) { + $this->logger->info('Worker stopped due to memory limit of {limit} bytes exceeded ({memory} bytes used)', ['limit' => $this->memoryLimit, 'memory' => $usedMemory]); + } + } + } + + public static function getSubscribedEvents() + { + return [ + WorkerRunningEvent::class => 'onWorkerRunning', + ]; + } +} diff --git a/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnMessageLimitListener.php b/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnMessageLimitListener.php new file mode 100644 index 0000000..ca71ff1 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnMessageLimitListener.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\EventListener; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Event\WorkerRunningEvent; +use Symfony\Component\Messenger\Exception\InvalidArgumentException; + +/** + * @author Samuel Roze + * @author Tobias Schultze + */ +class StopWorkerOnMessageLimitListener implements EventSubscriberInterface +{ + private $maximumNumberOfMessages; + private $logger; + private $receivedMessages = 0; + + public function __construct(int $maximumNumberOfMessages, LoggerInterface $logger = null) + { + $this->maximumNumberOfMessages = $maximumNumberOfMessages; + $this->logger = $logger; + + if ($maximumNumberOfMessages <= 0) { + throw new InvalidArgumentException('Message limit must be greater than zero.'); + } + } + + public function onWorkerRunning(WorkerRunningEvent $event): void + { + if (!$event->isWorkerIdle() && ++$this->receivedMessages >= $this->maximumNumberOfMessages) { + $this->receivedMessages = 0; + $event->getWorker()->stop(); + + if (null !== $this->logger) { + $this->logger->info('Worker stopped due to maximum count of {count} messages processed', ['count' => $this->maximumNumberOfMessages]); + } + } + } + + public static function getSubscribedEvents() + { + return [ + WorkerRunningEvent::class => 'onWorkerRunning', + ]; + } +} diff --git a/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnRestartSignalListener.php b/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnRestartSignalListener.php new file mode 100644 index 0000000..0fb3d40 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnRestartSignalListener.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\EventListener; + +use Psr\Cache\CacheItemPoolInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Event\WorkerRunningEvent; +use Symfony\Component\Messenger\Event\WorkerStartedEvent; + +/** + * @author Ryan Weaver + */ +class StopWorkerOnRestartSignalListener implements EventSubscriberInterface +{ + public const RESTART_REQUESTED_TIMESTAMP_KEY = 'workers.restart_requested_timestamp'; + + private $cachePool; + private $logger; + private $workerStartedAt; + + public function __construct(CacheItemPoolInterface $cachePool, LoggerInterface $logger = null) + { + $this->cachePool = $cachePool; + $this->logger = $logger; + } + + public function onWorkerStarted(): void + { + $this->workerStartedAt = microtime(true); + } + + public function onWorkerRunning(WorkerRunningEvent $event): void + { + if ($this->shouldRestart()) { + $event->getWorker()->stop(); + if (null !== $this->logger) { + $this->logger->info('Worker stopped because a restart was requested.'); + } + } + } + + public static function getSubscribedEvents() + { + return [ + WorkerStartedEvent::class => 'onWorkerStarted', + WorkerRunningEvent::class => 'onWorkerRunning', + ]; + } + + private function shouldRestart(): bool + { + $cacheItem = $this->cachePool->getItem(self::RESTART_REQUESTED_TIMESTAMP_KEY); + + if (!$cacheItem->isHit()) { + // no restart has ever been scheduled + return false; + } + + return $this->workerStartedAt < $cacheItem->get(); + } +} diff --git a/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnSigtermSignalListener.php b/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnSigtermSignalListener.php new file mode 100644 index 0000000..c865546 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnSigtermSignalListener.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\EventListener; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Event\WorkerStartedEvent; + +/** + * @author Tobias Schultze + */ +class StopWorkerOnSigtermSignalListener implements EventSubscriberInterface +{ + private $logger; + + public function __construct(LoggerInterface $logger = null) + { + $this->logger = $logger; + } + + public function onWorkerStarted(WorkerStartedEvent $event): void + { + pcntl_signal(\SIGTERM, function () use ($event) { + if (null !== $this->logger) { + $this->logger->info('Received SIGTERM signal.', ['transport_names' => $event->getWorker()->getMetadata()->getTransportNames()]); + } + + $event->getWorker()->stop(); + }); + } + + public static function getSubscribedEvents() + { + if (!\function_exists('pcntl_signal')) { + return []; + } + + return [ + WorkerStartedEvent::class => ['onWorkerStarted', 100], + ]; + } +} diff --git a/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnTimeLimitListener.php b/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnTimeLimitListener.php new file mode 100644 index 0000000..a3f982d --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnTimeLimitListener.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\EventListener; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Event\WorkerRunningEvent; +use Symfony\Component\Messenger\Event\WorkerStartedEvent; + +/** + * @author Simon Delicata + * @author Tobias Schultze + */ +class StopWorkerOnTimeLimitListener implements EventSubscriberInterface +{ + private $timeLimitInSeconds; + private $logger; + private $endTime; + + public function __construct(int $timeLimitInSeconds, LoggerInterface $logger = null) + { + $this->timeLimitInSeconds = $timeLimitInSeconds; + $this->logger = $logger; + } + + public function onWorkerStarted(): void + { + $startTime = microtime(true); + $this->endTime = $startTime + $this->timeLimitInSeconds; + } + + public function onWorkerRunning(WorkerRunningEvent $event): void + { + if ($this->endTime < microtime(true)) { + $event->getWorker()->stop(); + if (null !== $this->logger) { + $this->logger->info('Worker stopped due to time limit of {timeLimit}s exceeded', ['timeLimit' => $this->timeLimitInSeconds]); + } + } + } + + public static function getSubscribedEvents() + { + return [ + WorkerStartedEvent::class => 'onWorkerStarted', + WorkerRunningEvent::class => 'onWorkerRunning', + ]; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/DelayedMessageHandlingException.php b/plugins/email/vendor/symfony/messenger/Exception/DelayedMessageHandlingException.php new file mode 100644 index 0000000..4314a4f --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/DelayedMessageHandlingException.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * When handling queued messages from {@link DispatchAfterCurrentBusMiddleware}, + * some handlers caused an exception. This exception contains all those handler exceptions. + * + * @author Tobias Nyholm + */ +class DelayedMessageHandlingException extends RuntimeException +{ + private $exceptions; + + public function __construct(array $exceptions) + { + $exceptionMessages = implode(", \n", array_map( + function (\Throwable $e) { + return \get_class($e).': '.$e->getMessage(); + }, + $exceptions + )); + + if (1 === \count($exceptions)) { + $message = sprintf("A delayed message handler threw an exception: \n\n%s", $exceptionMessages); + } else { + $message = sprintf("Some delayed message handlers threw an exception: \n\n%s", $exceptionMessages); + } + + $this->exceptions = $exceptions; + + parent::__construct($message, 0, $exceptions[0]); + } + + public function getExceptions(): array + { + return $this->exceptions; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/ExceptionInterface.php b/plugins/email/vendor/symfony/messenger/Exception/ExceptionInterface.php new file mode 100644 index 0000000..02a72de --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * Base Messenger component's exception. + * + * @author Samuel Roze + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/HandlerFailedException.php b/plugins/email/vendor/symfony/messenger/Exception/HandlerFailedException.php new file mode 100644 index 0000000..6ac3169 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/HandlerFailedException.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +use Symfony\Component\Messenger\Envelope; + +class HandlerFailedException extends RuntimeException +{ + private $exceptions; + private $envelope; + + /** + * @param \Throwable[] $exceptions + */ + public function __construct(Envelope $envelope, array $exceptions) + { + $firstFailure = current($exceptions); + + $message = sprintf('Handling "%s" failed: ', \get_class($envelope->getMessage())); + + parent::__construct( + $message.(1 === \count($exceptions) + ? $firstFailure->getMessage() + : sprintf('%d handlers failed. First failure is: %s', \count($exceptions), $firstFailure->getMessage()) + ), + (int) $firstFailure->getCode(), + $firstFailure + ); + + $this->envelope = $envelope; + $this->exceptions = $exceptions; + } + + public function getEnvelope(): Envelope + { + return $this->envelope; + } + + /** + * @return \Throwable[] + */ + public function getNestedExceptions(): array + { + return $this->exceptions; + } + + public function getNestedExceptionOfClass(string $exceptionClassName): array + { + return array_values( + array_filter( + $this->exceptions, + function ($exception) use ($exceptionClassName) { + return is_a($exception, $exceptionClassName); + } + ) + ); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/InvalidArgumentException.php b/plugins/email/vendor/symfony/messenger/Exception/InvalidArgumentException.php new file mode 100644 index 0000000..a75c722 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/InvalidArgumentException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * @author Yonel Ceruto + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/LogicException.php b/plugins/email/vendor/symfony/messenger/Exception/LogicException.php new file mode 100644 index 0000000..75f97d2 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/LogicException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * @author Roland Franssen + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/MessageDecodingFailedException.php b/plugins/email/vendor/symfony/messenger/Exception/MessageDecodingFailedException.php new file mode 100644 index 0000000..bea4ac5 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/MessageDecodingFailedException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * Thrown when a message cannot be decoded in a serializer. + */ +class MessageDecodingFailedException extends InvalidArgumentException +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/NoHandlerForMessageException.php b/plugins/email/vendor/symfony/messenger/Exception/NoHandlerForMessageException.php new file mode 100644 index 0000000..d5efb45 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/NoHandlerForMessageException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * @author Samuel Roze + */ +class NoHandlerForMessageException extends LogicException +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/RecoverableExceptionInterface.php b/plugins/email/vendor/symfony/messenger/Exception/RecoverableExceptionInterface.php new file mode 100644 index 0000000..b49ddbf --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/RecoverableExceptionInterface.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * Marker interface for exceptions to indicate that handling a message should have worked. + * + * If something goes wrong while handling a message that's received from a transport + * and the message should be retried, a handler can throw such an exception. + * + * @author Jérémy Derussé + */ +interface RecoverableExceptionInterface extends \Throwable +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/RecoverableMessageHandlingException.php b/plugins/email/vendor/symfony/messenger/Exception/RecoverableMessageHandlingException.php new file mode 100644 index 0000000..6514573 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/RecoverableMessageHandlingException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * A concrete implementation of RecoverableExceptionInterface that can be used directly. + * + * @author Frederic Bouchery + */ +class RecoverableMessageHandlingException extends RuntimeException implements RecoverableExceptionInterface +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/RejectRedeliveredMessageException.php b/plugins/email/vendor/symfony/messenger/Exception/RejectRedeliveredMessageException.php new file mode 100644 index 0000000..0befccf --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/RejectRedeliveredMessageException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * @author Tobias Schultze + */ +class RejectRedeliveredMessageException extends RuntimeException +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/RuntimeException.php b/plugins/email/vendor/symfony/messenger/Exception/RuntimeException.php new file mode 100644 index 0000000..2d6c7b3 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/RuntimeException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * @author Fabien Potencier + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/StopWorkerException.php b/plugins/email/vendor/symfony/messenger/Exception/StopWorkerException.php new file mode 100644 index 0000000..e53bd32 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/StopWorkerException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * @author Grégoire Pineau + */ +class StopWorkerException extends RuntimeException implements StopWorkerExceptionInterface +{ + public function __construct(string $message = 'Worker should stop.', \Throwable $previous = null) + { + parent::__construct($message, 0, $previous); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/StopWorkerExceptionInterface.php b/plugins/email/vendor/symfony/messenger/Exception/StopWorkerExceptionInterface.php new file mode 100644 index 0000000..16019e8 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/StopWorkerExceptionInterface.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * @author Grégoire Pineau + */ +interface StopWorkerExceptionInterface extends \Throwable +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/TransportException.php b/plugins/email/vendor/symfony/messenger/Exception/TransportException.php new file mode 100644 index 0000000..79952b8 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/TransportException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * @author Eric Masoero + */ +class TransportException extends RuntimeException +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/UnrecoverableExceptionInterface.php b/plugins/email/vendor/symfony/messenger/Exception/UnrecoverableExceptionInterface.php new file mode 100644 index 0000000..ba5addf --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/UnrecoverableExceptionInterface.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * Marker interface for exceptions to indicate that handling a message will continue to fail. + * + * If something goes wrong while handling a message that's received from a transport + * and the message should not be retried, a handler can throw such an exception. + * + * @author Tobias Schultze + */ +interface UnrecoverableExceptionInterface extends \Throwable +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/UnrecoverableMessageHandlingException.php b/plugins/email/vendor/symfony/messenger/Exception/UnrecoverableMessageHandlingException.php new file mode 100644 index 0000000..31616fb --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/UnrecoverableMessageHandlingException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * A concrete implementation of UnrecoverableExceptionInterface that can be used directly. + * + * @author Frederic Bouchery + */ +class UnrecoverableMessageHandlingException extends RuntimeException implements UnrecoverableExceptionInterface +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Exception/ValidationFailedException.php b/plugins/email/vendor/symfony/messenger/Exception/ValidationFailedException.php new file mode 100644 index 0000000..fe129cd --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Exception/ValidationFailedException.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +use Symfony\Component\Validator\ConstraintViolationListInterface; + +/** + * @author Tobias Nyholm + */ +class ValidationFailedException extends RuntimeException +{ + private $violations; + private $violatingMessage; + + public function __construct(object $violatingMessage, ConstraintViolationListInterface $violations) + { + $this->violatingMessage = $violatingMessage; + $this->violations = $violations; + + parent::__construct(sprintf('Message of type "%s" failed validation.', \get_class($this->violatingMessage))); + } + + public function getViolatingMessage() + { + return $this->violatingMessage; + } + + public function getViolations(): ConstraintViolationListInterface + { + return $this->violations; + } +} diff --git a/plugins/email/vendor/symfony/messenger/HandleTrait.php b/plugins/email/vendor/symfony/messenger/HandleTrait.php new file mode 100644 index 0000000..4f77a93 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/HandleTrait.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger; + +use Symfony\Component\Messenger\Exception\LogicException; +use Symfony\Component\Messenger\Stamp\HandledStamp; + +/** + * Leverages a message bus to expect a single, synchronous message handling and return its result. + * + * @author Maxime Steinhausser + */ +trait HandleTrait +{ + /** @var MessageBusInterface */ + private $messageBus; + + /** + * Dispatches the given message, expecting to be handled by a single handler + * and returns the result from the handler returned value. + * This behavior is useful for both synchronous command & query buses, + * the last one usually returning the handler result. + * + * @param object|Envelope $message The message or the message pre-wrapped in an envelope + * + * @return mixed + */ + private function handle(object $message) + { + if (!$this->messageBus instanceof MessageBusInterface) { + throw new LogicException(sprintf('You must provide a "%s" instance in the "%s::$messageBus" property, "%s" given.', MessageBusInterface::class, static::class, get_debug_type($this->messageBus))); + } + + $envelope = $this->messageBus->dispatch($message); + /** @var HandledStamp[] $handledStamps */ + $handledStamps = $envelope->all(HandledStamp::class); + + if (!$handledStamps) { + throw new LogicException(sprintf('Message of type "%s" was handled zero times. Exactly one handler is expected when using "%s::%s()".', get_debug_type($envelope->getMessage()), static::class, __FUNCTION__)); + } + + if (\count($handledStamps) > 1) { + $handlers = implode(', ', array_map(function (HandledStamp $stamp): string { + return sprintf('"%s"', $stamp->getHandlerName()); + }, $handledStamps)); + + throw new LogicException(sprintf('Message of type "%s" was handled multiple times. Only one handler is expected when using "%s::%s()", got %d: %s.', get_debug_type($envelope->getMessage()), static::class, __FUNCTION__, \count($handledStamps), $handlers)); + } + + return $handledStamps[0]->getResult(); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Handler/Acknowledger.php b/plugins/email/vendor/symfony/messenger/Handler/Acknowledger.php new file mode 100644 index 0000000..a2317b7 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Handler/Acknowledger.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Handler; + +use Symfony\Component\Messenger\Exception\LogicException; + +/** + * @author Nicolas Grekas + */ +class Acknowledger +{ + private $handlerClass; + private $ack; + private $error = null; + private $result = null; + + /** + * @param null|\Closure(\Throwable|null, mixed):void $ack + */ + public function __construct(string $handlerClass, \Closure $ack = null) + { + $this->handlerClass = $handlerClass; + $this->ack = $ack ?? static function () {}; + } + + /** + * @param mixed $result + */ + public function ack($result = null): void + { + $this->doAck(null, $result); + } + + public function nack(\Throwable $error): void + { + $this->doAck($error); + } + + public function getError(): ?\Throwable + { + return $this->error; + } + + /** + * @return mixed + */ + public function getResult() + { + return $this->result; + } + + public function isAcknowledged(): bool + { + return null === $this->ack; + } + + public function __destruct() + { + if ($this->ack instanceof \Closure) { + throw new LogicException(sprintf('The acknowledger was not called by the "%s" batch handler.', $this->handlerClass)); + } + } + + private function doAck(\Throwable $e = null, $result = null): void + { + if (!$ack = $this->ack) { + throw new LogicException(sprintf('The acknowledger cannot be called twice by the "%s" batch handler.', $this->handlerClass)); + } + $this->ack = null; + $this->error = $e; + $this->result = $result; + $ack($e, $result); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Handler/BatchHandlerInterface.php b/plugins/email/vendor/symfony/messenger/Handler/BatchHandlerInterface.php new file mode 100644 index 0000000..a2fce4e --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Handler/BatchHandlerInterface.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Handler; + +/** + * @author Nicolas Grekas + */ +interface BatchHandlerInterface +{ + /** + * @param Acknowledger|null $ack The function to call to ack/nack the $message. + * The message should be handled synchronously when null. + * + * @return mixed The number of pending messages in the batch if $ack is not null, + * the result from handling the message otherwise + */ + // public function __invoke(object $message, Acknowledger $ack = null): mixed; + + /** + * Flushes any pending buffers. + * + * @param bool $force Whether flushing is required; it can be skipped if not + */ + public function flush(bool $force): void; +} diff --git a/plugins/email/vendor/symfony/messenger/Handler/BatchHandlerTrait.php b/plugins/email/vendor/symfony/messenger/Handler/BatchHandlerTrait.php new file mode 100644 index 0000000..be7124d --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Handler/BatchHandlerTrait.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Handler; + +use Symfony\Component\Messenger\Exception\LogicException; + +/** + * @author Nicolas Grekas + */ +trait BatchHandlerTrait +{ + private $jobs = []; + + /** + * {@inheritdoc} + */ + public function flush(bool $force): void + { + if ($jobs = $this->jobs) { + $this->jobs = []; + $this->process($jobs); + } + } + + /** + * @param Acknowledger|null $ack The function to call to ack/nack the $message. + * The message should be handled synchronously when null. + * + * @return mixed The number of pending messages in the batch if $ack is not null, + * the result from handling the message otherwise + */ + private function handle(object $message, ?Acknowledger $ack) + { + if (null === $ack) { + $ack = new Acknowledger(get_debug_type($this)); + $this->jobs[] = [$message, $ack]; + $this->flush(true); + + return $ack->getResult(); + } + + $this->jobs[] = [$message, $ack]; + if (!$this->shouldFlush()) { + return \count($this->jobs); + } + + $this->flush(true); + + return 0; + } + + private function shouldFlush(): bool + { + return 10 <= \count($this->jobs); + } + + /** + * Completes the jobs in the list. + * + * @list $jobs A list of pairs of messages and their corresponding acknowledgers + */ + private function process(array $jobs): void + { + throw new LogicException(sprintf('"%s" should implement abstract method "process()".', get_debug_type($this))); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Handler/HandlerDescriptor.php b/plugins/email/vendor/symfony/messenger/Handler/HandlerDescriptor.php new file mode 100644 index 0000000..6acb2c2 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Handler/HandlerDescriptor.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Handler; + +/** + * Describes a handler and the possible associated options, such as `from_transport`, `bus`, etc. + * + * @author Samuel Roze + */ +final class HandlerDescriptor +{ + private $handler; + private $name; + private $batchHandler; + private $options; + + public function __construct(callable $handler, array $options = []) + { + if (!$handler instanceof \Closure) { + $handler = \Closure::fromCallable($handler); + } + + $this->handler = $handler; + $this->options = $options; + + $r = new \ReflectionFunction($handler); + + if (str_contains($r->name, '{closure}')) { + $this->name = 'Closure'; + } elseif (!$handler = $r->getClosureThis()) { + $class = $r->getClosureScopeClass(); + + $this->name = ($class ? $class->name.'::' : '').$r->name; + } else { + if ($handler instanceof BatchHandlerInterface) { + $this->batchHandler = $handler; + } + + $this->name = \get_class($handler).'::'.$r->name; + } + } + + public function getHandler(): callable + { + return $this->handler; + } + + public function getName(): string + { + $name = $this->name; + $alias = $this->options['alias'] ?? null; + + if (null !== $alias) { + $name .= '@'.$alias; + } + + return $name; + } + + public function getBatchHandler(): ?BatchHandlerInterface + { + return $this->batchHandler; + } + + public function getOption(string $option) + { + return $this->options[$option] ?? null; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Handler/HandlersLocator.php b/plugins/email/vendor/symfony/messenger/Handler/HandlersLocator.php new file mode 100644 index 0000000..6252bcc --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Handler/HandlersLocator.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Handler; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Stamp\ReceivedStamp; + +/** + * Maps a message to a list of handlers. + * + * @author Nicolas Grekas + * @author Samuel Roze + */ +class HandlersLocator implements HandlersLocatorInterface +{ + private $handlers; + + /** + * @param HandlerDescriptor[][]|callable[][] $handlers + */ + public function __construct(array $handlers) + { + $this->handlers = $handlers; + } + + /** + * {@inheritdoc} + */ + public function getHandlers(Envelope $envelope): iterable + { + $seen = []; + + foreach (self::listTypes($envelope) as $type) { + foreach ($this->handlers[$type] ?? [] as $handlerDescriptor) { + if (\is_callable($handlerDescriptor)) { + $handlerDescriptor = new HandlerDescriptor($handlerDescriptor); + } + + if (!$this->shouldHandle($envelope, $handlerDescriptor)) { + continue; + } + + $name = $handlerDescriptor->getName(); + if (\in_array($name, $seen)) { + continue; + } + + $seen[] = $name; + + yield $handlerDescriptor; + } + } + } + + /** + * @internal + */ + public static function listTypes(Envelope $envelope): array + { + $class = \get_class($envelope->getMessage()); + + return [$class => $class] + + class_parents($class) + + class_implements($class) + + ['*' => '*']; + } + + private function shouldHandle(Envelope $envelope, HandlerDescriptor $handlerDescriptor): bool + { + if (null === $received = $envelope->last(ReceivedStamp::class)) { + return true; + } + + if (null === $expectedTransport = $handlerDescriptor->getOption('from_transport')) { + return true; + } + + return $received->getTransportName() === $expectedTransport; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Handler/HandlersLocatorInterface.php b/plugins/email/vendor/symfony/messenger/Handler/HandlersLocatorInterface.php new file mode 100644 index 0000000..c0ac07f --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Handler/HandlersLocatorInterface.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Handler; + +use Symfony\Component\Messenger\Envelope; + +/** + * Maps a message to a list of handlers. + * + * @author Nicolas Grekas + */ +interface HandlersLocatorInterface +{ + /** + * Returns the handlers for the given message name. + * + * @return iterable + */ + public function getHandlers(Envelope $envelope): iterable; +} diff --git a/plugins/email/vendor/symfony/messenger/Handler/MessageHandlerInterface.php b/plugins/email/vendor/symfony/messenger/Handler/MessageHandlerInterface.php new file mode 100644 index 0000000..7b219a3 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Handler/MessageHandlerInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Handler; + +/** + * Marker interface for message handlers. + * + * @author Samuel Roze + */ +interface MessageHandlerInterface +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Handler/MessageSubscriberInterface.php b/plugins/email/vendor/symfony/messenger/Handler/MessageSubscriberInterface.php new file mode 100644 index 0000000..2eca1a9 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Handler/MessageSubscriberInterface.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Handler; + +/** + * Handlers can implement this interface to handle multiple messages. + * + * @author Samuel Roze + */ +interface MessageSubscriberInterface extends MessageHandlerInterface +{ + /** + * Returns a list of messages to be handled. + * + * It returns a list of messages like in the following example: + * + * yield MyMessage::class; + * + * It can also change the priority per classes. + * + * yield FirstMessage::class => ['priority' => 0]; + * yield SecondMessage::class => ['priority' => -10]; + * + * It can also specify a method, a priority, a bus and/or a transport per message: + * + * yield FirstMessage::class => ['method' => 'firstMessageMethod']; + * yield SecondMessage::class => [ + * 'method' => 'secondMessageMethod', + * 'priority' => 20, + * 'bus' => 'my_bus_name', + * 'from_transport' => 'your_transport_name', + * ]; + * + * The benefit of using `yield` instead of returning an array is that you can `yield` multiple times the + * same key and therefore subscribe to the same message multiple times with different options. + * + * The `__invoke` method of the handler will be called as usual with the message to handle. + */ + public static function getHandledMessages(): iterable; +} diff --git a/plugins/email/vendor/symfony/messenger/LICENSE b/plugins/email/vendor/symfony/messenger/LICENSE new file mode 100644 index 0000000..74cdc2d --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/plugins/email/vendor/symfony/messenger/MessageBus.php b/plugins/email/vendor/symfony/messenger/MessageBus.php new file mode 100644 index 0000000..3db9fab --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/MessageBus.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger; + +use Symfony\Component\Messenger\Middleware\MiddlewareInterface; +use Symfony\Component\Messenger\Middleware\StackMiddleware; + +/** + * @author Samuel Roze + * @author Matthias Noback + * @author Nicolas Grekas + */ +class MessageBus implements MessageBusInterface +{ + private $middlewareAggregate; + + /** + * @param iterable $middlewareHandlers + */ + public function __construct(iterable $middlewareHandlers = []) + { + if ($middlewareHandlers instanceof \IteratorAggregate) { + $this->middlewareAggregate = $middlewareHandlers; + } elseif (\is_array($middlewareHandlers)) { + $this->middlewareAggregate = new \ArrayObject($middlewareHandlers); + } else { + // $this->middlewareAggregate should be an instance of IteratorAggregate. + // When $middlewareHandlers is an Iterator, we wrap it to ensure it is lazy-loaded and can be rewound. + $this->middlewareAggregate = new class($middlewareHandlers) implements \IteratorAggregate { + private $middlewareHandlers; + private $cachedIterator; + + public function __construct(\Traversable $middlewareHandlers) + { + $this->middlewareHandlers = $middlewareHandlers; + } + + public function getIterator(): \Traversable + { + if (null === $this->cachedIterator) { + $this->cachedIterator = new \ArrayObject(iterator_to_array($this->middlewareHandlers, false)); + } + + return $this->cachedIterator; + } + }; + } + } + + /** + * {@inheritdoc} + */ + public function dispatch(object $message, array $stamps = []): Envelope + { + $envelope = Envelope::wrap($message, $stamps); + $middlewareIterator = $this->middlewareAggregate->getIterator(); + + while ($middlewareIterator instanceof \IteratorAggregate) { + $middlewareIterator = $middlewareIterator->getIterator(); + } + $middlewareIterator->rewind(); + + if (!$middlewareIterator->valid()) { + return $envelope; + } + $stack = new StackMiddleware($middlewareIterator); + + return $middlewareIterator->current()->handle($envelope, $stack); + } +} diff --git a/plugins/email/vendor/symfony/messenger/MessageBusInterface.php b/plugins/email/vendor/symfony/messenger/MessageBusInterface.php new file mode 100644 index 0000000..f1dbe0a --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/MessageBusInterface.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger; + +use Symfony\Component\Messenger\Stamp\StampInterface; + +/** + * @author Samuel Roze + */ +interface MessageBusInterface +{ + /** + * Dispatches the given message. + * + * @param object|Envelope $message The message or the message pre-wrapped in an envelope + * @param StampInterface[] $stamps + */ + public function dispatch(object $message, array $stamps = []): Envelope; +} diff --git a/plugins/email/vendor/symfony/messenger/Middleware/ActivationMiddleware.php b/plugins/email/vendor/symfony/messenger/Middleware/ActivationMiddleware.php new file mode 100644 index 0000000..8d101e4 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Middleware/ActivationMiddleware.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +use Symfony\Component\Messenger\Envelope; + +/** + * Execute the inner middleware according to an activation strategy. + * + * @author Maxime Steinhausser + */ +class ActivationMiddleware implements MiddlewareInterface +{ + private $inner; + private $activated; + + /** + * @param bool|callable $activated + */ + public function __construct(MiddlewareInterface $inner, $activated) + { + $this->inner = $inner; + $this->activated = $activated; + } + + /** + * {@inheritdoc} + */ + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + if (\is_callable($this->activated) ? ($this->activated)($envelope) : $this->activated) { + return $this->inner->handle($envelope, $stack); + } + + return $stack->next()->handle($envelope, $stack); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Middleware/AddBusNameStampMiddleware.php b/plugins/email/vendor/symfony/messenger/Middleware/AddBusNameStampMiddleware.php new file mode 100644 index 0000000..925fd5f --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Middleware/AddBusNameStampMiddleware.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Stamp\BusNameStamp; + +/** + * Adds the BusNameStamp to the bus. + * + * @author Ryan Weaver + */ +class AddBusNameStampMiddleware implements MiddlewareInterface +{ + private $busName; + + public function __construct(string $busName) + { + $this->busName = $busName; + } + + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + if (null === $envelope->last(BusNameStamp::class)) { + $envelope = $envelope->with(new BusNameStamp($this->busName)); + } + + return $stack->next()->handle($envelope, $stack); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Middleware/DispatchAfterCurrentBusMiddleware.php b/plugins/email/vendor/symfony/messenger/Middleware/DispatchAfterCurrentBusMiddleware.php new file mode 100644 index 0000000..a088140 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Middleware/DispatchAfterCurrentBusMiddleware.php @@ -0,0 +1,133 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\DelayedMessageHandlingException; +use Symfony\Component\Messenger\Stamp\DispatchAfterCurrentBusStamp; + +/** + * Allow to configure messages to be handled after the current bus is finished. + * + * I.e, messages dispatched from a handler with a DispatchAfterCurrentBus stamp + * will actually be handled once the current message being dispatched is fully + * handled. + * + * For instance, using this middleware before the DoctrineTransactionMiddleware + * means sub-dispatched messages with a DispatchAfterCurrentBus stamp would be + * handled after the Doctrine transaction has been committed. + * + * @author Tobias Nyholm + */ +class DispatchAfterCurrentBusMiddleware implements MiddlewareInterface +{ + /** + * @var QueuedEnvelope[] A queue of messages and next middleware + */ + private $queue = []; + + /** + * @var bool this property is used to signal if we are inside a the first/root call to + * MessageBusInterface::dispatch() or if dispatch has been called inside a message handler + */ + private $isRootDispatchCallRunning = false; + + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + if (null !== $envelope->last(DispatchAfterCurrentBusStamp::class)) { + if ($this->isRootDispatchCallRunning) { + $this->queue[] = new QueuedEnvelope($envelope, $stack); + + return $envelope; + } + + $envelope = $envelope->withoutAll(DispatchAfterCurrentBusStamp::class); + } + + if ($this->isRootDispatchCallRunning) { + /* + * A call to MessageBusInterface::dispatch() was made from inside the main bus handling, + * but the message does not have the stamp. So, process it like normal. + */ + return $stack->next()->handle($envelope, $stack); + } + + // First time we get here, mark as inside a "root dispatch" call: + $this->isRootDispatchCallRunning = true; + try { + // Execute the whole middleware stack & message handling for main dispatch: + $returnedEnvelope = $stack->next()->handle($envelope, $stack); + } catch (\Throwable $exception) { + /* + * Whenever an exception occurs while handling a message that has + * queued other messages, we drop the queued ones. + * This is intentional since the queued commands were likely dependent + * on the preceding command. + */ + $this->queue = []; + $this->isRootDispatchCallRunning = false; + + throw $exception; + } + + // "Root dispatch" call is finished, dispatch stored messages. + $exceptions = []; + while (null !== $queueItem = array_shift($this->queue)) { + // Save how many messages are left in queue before handling the message + $queueLengthBefore = \count($this->queue); + try { + // Execute the stored messages + $queueItem->getStack()->next()->handle($queueItem->getEnvelope(), $queueItem->getStack()); + } catch (\Exception $exception) { + // Gather all exceptions + $exceptions[] = $exception; + // Restore queue to previous state + $this->queue = \array_slice($this->queue, 0, $queueLengthBefore); + } + } + + $this->isRootDispatchCallRunning = false; + if (\count($exceptions) > 0) { + throw new DelayedMessageHandlingException($exceptions); + } + + return $returnedEnvelope; + } +} + +/** + * @internal + */ +final class QueuedEnvelope +{ + /** @var Envelope */ + private $envelope; + + /** @var StackInterface */ + private $stack; + + public function __construct(Envelope $envelope, StackInterface $stack) + { + $this->envelope = $envelope->withoutAll(DispatchAfterCurrentBusStamp::class); + $this->stack = $stack; + } + + public function getEnvelope(): Envelope + { + return $this->envelope; + } + + public function getStack(): StackInterface + { + return $this->stack; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Middleware/FailedMessageProcessingMiddleware.php b/plugins/email/vendor/symfony/messenger/Middleware/FailedMessageProcessingMiddleware.php new file mode 100644 index 0000000..6e40d11 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Middleware/FailedMessageProcessingMiddleware.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Stamp\ReceivedStamp; +use Symfony\Component\Messenger\Stamp\SentToFailureTransportStamp; + +/** + * @author Ryan Weaver + */ +class FailedMessageProcessingMiddleware implements MiddlewareInterface +{ + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + // look for "received" messages decorated with the SentToFailureTransportStamp + /** @var SentToFailureTransportStamp|null $sentToFailureStamp */ + $sentToFailureStamp = $envelope->last(SentToFailureTransportStamp::class); + if (null !== $sentToFailureStamp && null !== $envelope->last(ReceivedStamp::class)) { + // mark the message as "received" from the original transport + // this guarantees the same behavior as when originally received + $envelope = $envelope->with(new ReceivedStamp($sentToFailureStamp->getOriginalReceiverName())); + } + + return $stack->next()->handle($envelope, $stack); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Middleware/HandleMessageMiddleware.php b/plugins/email/vendor/symfony/messenger/Middleware/HandleMessageMiddleware.php new file mode 100644 index 0000000..149f304 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Middleware/HandleMessageMiddleware.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +use Psr\Log\LoggerAwareTrait; +use Psr\Log\NullLogger; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\HandlerFailedException; +use Symfony\Component\Messenger\Exception\LogicException; +use Symfony\Component\Messenger\Exception\NoHandlerForMessageException; +use Symfony\Component\Messenger\Handler\Acknowledger; +use Symfony\Component\Messenger\Handler\HandlerDescriptor; +use Symfony\Component\Messenger\Handler\HandlersLocatorInterface; +use Symfony\Component\Messenger\Stamp\AckStamp; +use Symfony\Component\Messenger\Stamp\FlushBatchHandlersStamp; +use Symfony\Component\Messenger\Stamp\HandledStamp; +use Symfony\Component\Messenger\Stamp\NoAutoAckStamp; + +/** + * @author Samuel Roze + */ +class HandleMessageMiddleware implements MiddlewareInterface +{ + use LoggerAwareTrait; + + private $handlersLocator; + private $allowNoHandlers; + + public function __construct(HandlersLocatorInterface $handlersLocator, bool $allowNoHandlers = false) + { + $this->handlersLocator = $handlersLocator; + $this->allowNoHandlers = $allowNoHandlers; + $this->logger = new NullLogger(); + } + + /** + * {@inheritdoc} + * + * @throws NoHandlerForMessageException When no handler is found and $allowNoHandlers is false + */ + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + $handler = null; + $message = $envelope->getMessage(); + + $context = [ + 'class' => \get_class($message), + ]; + + $exceptions = []; + foreach ($this->handlersLocator->getHandlers($envelope) as $handlerDescriptor) { + if ($this->messageHasAlreadyBeenHandled($envelope, $handlerDescriptor)) { + continue; + } + + try { + $handler = $handlerDescriptor->getHandler(); + $batchHandler = $handlerDescriptor->getBatchHandler(); + + /** @var AckStamp $ackStamp */ + if ($batchHandler && $ackStamp = $envelope->last(AckStamp::class)) { + $ack = new Acknowledger(get_debug_type($batchHandler), static function (\Throwable $e = null, $result = null) use ($envelope, $ackStamp, $handlerDescriptor) { + if (null !== $e) { + $e = new HandlerFailedException($envelope, [$e]); + } else { + $envelope = $envelope->with(HandledStamp::fromDescriptor($handlerDescriptor, $result)); + } + + $ackStamp->ack($envelope, $e); + }); + + $result = $handler($message, $ack); + + if (!\is_int($result) || 0 > $result) { + throw new LogicException(sprintf('A handler implementing BatchHandlerInterface must return the size of the current batch as a positive integer, "%s" returned from "%s".', \is_int($result) ? $result : get_debug_type($result), get_debug_type($batchHandler))); + } + + if (!$ack->isAcknowledged()) { + $envelope = $envelope->with(new NoAutoAckStamp($handlerDescriptor)); + } elseif ($ack->getError()) { + throw $ack->getError(); + } else { + $result = $ack->getResult(); + } + } else { + $result = $handler($message); + } + + $handledStamp = HandledStamp::fromDescriptor($handlerDescriptor, $result); + $envelope = $envelope->with($handledStamp); + $this->logger->info('Message {class} handled by {handler}', $context + ['handler' => $handledStamp->getHandlerName()]); + } catch (\Throwable $e) { + $exceptions[] = $e; + } + } + + /** @var FlushBatchHandlersStamp $flushStamp */ + if ($flushStamp = $envelope->last(FlushBatchHandlersStamp::class)) { + /** @var NoAutoAckStamp $stamp */ + foreach ($envelope->all(NoAutoAckStamp::class) as $stamp) { + try { + $handler = $stamp->getHandlerDescriptor()->getBatchHandler(); + $handler->flush($flushStamp->force()); + } catch (\Throwable $e) { + $exceptions[] = $e; + } + } + } + + if (null === $handler) { + if (!$this->allowNoHandlers) { + throw new NoHandlerForMessageException(sprintf('No handler for message "%s".', $context['class'])); + } + + $this->logger->info('No handler for message {class}', $context); + } + + if (\count($exceptions)) { + throw new HandlerFailedException($envelope, $exceptions); + } + + return $stack->next()->handle($envelope, $stack); + } + + private function messageHasAlreadyBeenHandled(Envelope $envelope, HandlerDescriptor $handlerDescriptor): bool + { + /** @var HandledStamp $stamp */ + foreach ($envelope->all(HandledStamp::class) as $stamp) { + if ($stamp->getHandlerName() === $handlerDescriptor->getName()) { + return true; + } + } + + return false; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Middleware/MiddlewareInterface.php b/plugins/email/vendor/symfony/messenger/Middleware/MiddlewareInterface.php new file mode 100644 index 0000000..9826611 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Middleware/MiddlewareInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +use Symfony\Component\Messenger\Envelope; + +/** + * @author Samuel Roze + */ +interface MiddlewareInterface +{ + public function handle(Envelope $envelope, StackInterface $stack): Envelope; +} diff --git a/plugins/email/vendor/symfony/messenger/Middleware/RejectRedeliveredMessageMiddleware.php b/plugins/email/vendor/symfony/messenger/Middleware/RejectRedeliveredMessageMiddleware.php new file mode 100644 index 0000000..9e994dd --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Middleware/RejectRedeliveredMessageMiddleware.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpReceivedStamp; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\RejectRedeliveredMessageException; +use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceivedStamp as LegacyAmqpReceivedStamp; + +/** + * Middleware that throws a RejectRedeliveredMessageException when a message is detected that has been redelivered by AMQP. + * + * The middleware runs before the HandleMessageMiddleware and prevents redelivered messages from being handled directly. + * The thrown exception is caught by the worker and will trigger the retry logic according to the retry strategy. + * + * AMQP redelivers messages when they do not get acknowledged or rejected. This can happen when the connection times out + * or an exception is thrown before acknowledging or rejecting. When such errors happen again while handling the + * redelivered message, the message would get redelivered again and again. The purpose of this middleware is to prevent + * infinite redelivery loops and to unblock the queue by republishing the redelivered messages as retries with a retry + * limit and potential delay. + * + * @author Tobias Schultze + */ +class RejectRedeliveredMessageMiddleware implements MiddlewareInterface +{ + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + $amqpReceivedStamp = $envelope->last(AmqpReceivedStamp::class); + if ($amqpReceivedStamp instanceof AmqpReceivedStamp && $amqpReceivedStamp->getAmqpEnvelope()->isRedelivery()) { + throw new RejectRedeliveredMessageException('Redelivered message from AMQP detected that will be rejected and trigger the retry logic.'); + } + + // Legacy code to support symfony/messenger < 5.1 + $amqpReceivedStamp = $envelope->last(LegacyAmqpReceivedStamp::class); + if ($amqpReceivedStamp instanceof LegacyAmqpReceivedStamp && $amqpReceivedStamp->getAmqpEnvelope()->isRedelivery()) { + throw new RejectRedeliveredMessageException('Redelivered message from AMQP detected that will be rejected and trigger the retry logic.'); + } + + return $stack->next()->handle($envelope, $stack); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Middleware/RouterContextMiddleware.php b/plugins/email/vendor/symfony/messenger/Middleware/RouterContextMiddleware.php new file mode 100644 index 0000000..62bd1d7 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Middleware/RouterContextMiddleware.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp; +use Symfony\Component\Messenger\Stamp\RouterContextStamp; +use Symfony\Component\Routing\RequestContextAwareInterface; + +/** + * Restore the Router context when processing the message. + * + * @author Jérémy Derussé + */ +class RouterContextMiddleware implements MiddlewareInterface +{ + private $router; + + public function __construct(RequestContextAwareInterface $router) + { + $this->router = $router; + } + + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + if (!$envelope->last(ConsumedByWorkerStamp::class) || !$contextStamp = $envelope->last(RouterContextStamp::class)) { + $context = $this->router->getContext(); + $envelope = $envelope->with(new RouterContextStamp( + $context->getBaseUrl(), + $context->getMethod(), + $context->getHost(), + $context->getScheme(), + $context->getHttpPort(), + $context->getHttpsPort(), + $context->getPathInfo(), + $context->getQueryString() + )); + + return $stack->next()->handle($envelope, $stack); + } + + $context = $this->router->getContext(); + $currentBaseUrl = $context->getBaseUrl(); + $currentMethod = $context->getMethod(); + $currentHost = $context->getHost(); + $currentScheme = $context->getScheme(); + $currentHttpPort = $context->getHttpPort(); + $currentHttpsPort = $context->getHttpsPort(); + $currentPathInfo = $context->getPathInfo(); + $currentQueryString = $context->getQueryString(); + + /* @var RouterContextStamp $contextStamp */ + $context + ->setBaseUrl($contextStamp->getBaseUrl()) + ->setMethod($contextStamp->getMethod()) + ->setHost($contextStamp->getHost()) + ->setScheme($contextStamp->getScheme()) + ->setHttpPort($contextStamp->getHttpPort()) + ->setHttpsPort($contextStamp->getHttpsPort()) + ->setPathInfo($contextStamp->getPathInfo()) + ->setQueryString($contextStamp->getQueryString()) + ; + + try { + return $stack->next()->handle($envelope, $stack); + } finally { + $context + ->setBaseUrl($currentBaseUrl) + ->setMethod($currentMethod) + ->setHost($currentHost) + ->setScheme($currentScheme) + ->setHttpPort($currentHttpPort) + ->setHttpsPort($currentHttpsPort) + ->setPathInfo($currentPathInfo) + ->setQueryString($currentQueryString) + ; + } + } +} diff --git a/plugins/email/vendor/symfony/messenger/Middleware/SendMessageMiddleware.php b/plugins/email/vendor/symfony/messenger/Middleware/SendMessageMiddleware.php new file mode 100644 index 0000000..669fe76 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Middleware/SendMessageMiddleware.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +use Psr\Log\LoggerAwareTrait; +use Psr\Log\NullLogger; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Event\SendMessageToTransportsEvent; +use Symfony\Component\Messenger\Stamp\ReceivedStamp; +use Symfony\Component\Messenger\Stamp\SentStamp; +use Symfony\Component\Messenger\Transport\Sender\SendersLocatorInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; + +/** + * @author Samuel Roze + * @author Tobias Schultze + */ +class SendMessageMiddleware implements MiddlewareInterface +{ + use LoggerAwareTrait; + + private $sendersLocator; + private $eventDispatcher; + + public function __construct(SendersLocatorInterface $sendersLocator, EventDispatcherInterface $eventDispatcher = null) + { + $this->sendersLocator = $sendersLocator; + $this->eventDispatcher = class_exists(Event::class) ? LegacyEventDispatcherProxy::decorate($eventDispatcher) : $eventDispatcher; + $this->logger = new NullLogger(); + } + + /** + * {@inheritdoc} + */ + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + $context = [ + 'class' => \get_class($envelope->getMessage()), + ]; + + $sender = null; + + if ($envelope->all(ReceivedStamp::class)) { + // it's a received message, do not send it back + $this->logger->info('Received message {class}', $context); + } else { + $shouldDispatchEvent = true; + foreach ($this->sendersLocator->getSenders($envelope) as $alias => $sender) { + if (null !== $this->eventDispatcher && $shouldDispatchEvent) { + $event = new SendMessageToTransportsEvent($envelope); + $this->eventDispatcher->dispatch($event); + $envelope = $event->getEnvelope(); + $shouldDispatchEvent = false; + } + + $this->logger->info('Sending message {class} with {alias} sender using {sender}', $context + ['alias' => $alias, 'sender' => \get_class($sender)]); + $envelope = $sender->send($envelope->with(new SentStamp(\get_class($sender), \is_string($alias) ? $alias : null))); + } + } + + if (null === $sender) { + return $stack->next()->handle($envelope, $stack); + } + + // message should only be sent and not be handled by the next middleware + return $envelope; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Middleware/StackInterface.php b/plugins/email/vendor/symfony/messenger/Middleware/StackInterface.php new file mode 100644 index 0000000..6e922c5 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Middleware/StackInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +/** + * @author Nicolas Grekas + * + * Implementations must be cloneable, and each clone must unstack the stack independently. + */ +interface StackInterface +{ + /** + * Returns the next middleware to process a message. + */ + public function next(): MiddlewareInterface; +} diff --git a/plugins/email/vendor/symfony/messenger/Middleware/StackMiddleware.php b/plugins/email/vendor/symfony/messenger/Middleware/StackMiddleware.php new file mode 100644 index 0000000..30c181f --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Middleware/StackMiddleware.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +use Symfony\Component\Messenger\Envelope; + +/** + * @author Nicolas Grekas + */ +class StackMiddleware implements MiddlewareInterface, StackInterface +{ + private $stack; + private $offset = 0; + + /** + * @param iterable|MiddlewareInterface|null $middlewareIterator + */ + public function __construct($middlewareIterator = null) + { + $this->stack = new MiddlewareStack(); + + if (null === $middlewareIterator) { + return; + } + + if ($middlewareIterator instanceof \Iterator) { + $this->stack->iterator = $middlewareIterator; + } elseif ($middlewareIterator instanceof MiddlewareInterface) { + $this->stack->stack[] = $middlewareIterator; + } elseif (!is_iterable($middlewareIterator)) { + throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be iterable of "%s", "%s" given.', __METHOD__, MiddlewareInterface::class, get_debug_type($middlewareIterator))); + } else { + $this->stack->iterator = (function () use ($middlewareIterator) { + yield from $middlewareIterator; + })(); + } + } + + public function next(): MiddlewareInterface + { + if (null === $next = $this->stack->next($this->offset)) { + return $this; + } + + ++$this->offset; + + return $next; + } + + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + return $envelope; + } +} + +/** + * @internal + */ +class MiddlewareStack +{ + /** @var \Iterator */ + public $iterator; + public $stack = []; + + public function next(int $offset): ?MiddlewareInterface + { + if (isset($this->stack[$offset])) { + return $this->stack[$offset]; + } + + if (null === $this->iterator) { + return null; + } + + $this->iterator->next(); + + if (!$this->iterator->valid()) { + return $this->iterator = null; + } + + return $this->stack[] = $this->iterator->current(); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Middleware/TraceableMiddleware.php b/plugins/email/vendor/symfony/messenger/Middleware/TraceableMiddleware.php new file mode 100644 index 0000000..f391cfe --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Middleware/TraceableMiddleware.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Stopwatch\Stopwatch; + +/** + * Collects some data about a middleware. + * + * @author Maxime Steinhausser + */ +class TraceableMiddleware implements MiddlewareInterface +{ + private $stopwatch; + private $busName; + private $eventCategory; + + public function __construct(Stopwatch $stopwatch, string $busName, string $eventCategory = 'messenger.middleware') + { + $this->stopwatch = $stopwatch; + $this->busName = $busName; + $this->eventCategory = $eventCategory; + } + + /** + * {@inheritdoc} + */ + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + $stack = new TraceableStack($stack, $this->stopwatch, $this->busName, $this->eventCategory); + + try { + return $stack->next()->handle($envelope, $stack); + } finally { + $stack->stop(); + } + } +} + +/** + * @internal + */ +class TraceableStack implements StackInterface +{ + private $stack; + private $stopwatch; + private $busName; + private $eventCategory; + private $currentEvent; + + public function __construct(StackInterface $stack, Stopwatch $stopwatch, string $busName, string $eventCategory) + { + $this->stack = $stack; + $this->stopwatch = $stopwatch; + $this->busName = $busName; + $this->eventCategory = $eventCategory; + } + + /** + * {@inheritdoc} + */ + public function next(): MiddlewareInterface + { + if (null !== $this->currentEvent && $this->stopwatch->isStarted($this->currentEvent)) { + $this->stopwatch->stop($this->currentEvent); + } + + if ($this->stack === $nextMiddleware = $this->stack->next()) { + $this->currentEvent = 'Tail'; + } else { + $this->currentEvent = sprintf('"%s"', get_debug_type($nextMiddleware)); + } + $this->currentEvent .= sprintf(' on "%s"', $this->busName); + + $this->stopwatch->start($this->currentEvent, $this->eventCategory); + + return $nextMiddleware; + } + + public function stop(): void + { + if (null !== $this->currentEvent && $this->stopwatch->isStarted($this->currentEvent)) { + $this->stopwatch->stop($this->currentEvent); + } + $this->currentEvent = null; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Middleware/ValidationMiddleware.php b/plugins/email/vendor/symfony/messenger/Middleware/ValidationMiddleware.php new file mode 100644 index 0000000..fb199dd --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Middleware/ValidationMiddleware.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\ValidationFailedException; +use Symfony\Component\Messenger\Stamp\ValidationStamp; +use Symfony\Component\Validator\Validator\ValidatorInterface; + +/** + * @author Tobias Nyholm + */ +class ValidationMiddleware implements MiddlewareInterface +{ + private $validator; + + public function __construct(ValidatorInterface $validator) + { + $this->validator = $validator; + } + + /** + * {@inheritdoc} + */ + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + $message = $envelope->getMessage(); + $groups = null; + /** @var ValidationStamp|null $validationStamp */ + if ($validationStamp = $envelope->last(ValidationStamp::class)) { + $groups = $validationStamp->getGroups(); + } + + $violations = $this->validator->validate($message, null, $groups); + if (\count($violations)) { + throw new ValidationFailedException($message, $violations); + } + + return $stack->next()->handle($envelope, $stack); + } +} diff --git a/plugins/email/vendor/symfony/messenger/README.md b/plugins/email/vendor/symfony/messenger/README.md new file mode 100644 index 0000000..644269c --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/README.md @@ -0,0 +1,29 @@ +Messenger Component +=================== + +The Messenger component helps applications send and receive messages to/from +other applications or via message queues. + +Sponsor +------- + +The Messenger component for Symfony 5.4/6.0 is [backed][1] by [SensioLabs][2]. + +As the creator of Symfony, SensioLabs supports companies using Symfony, with an +offering encompassing consultancy, expertise, services, training, and technical +assistance to ensure the success of web application development projects. + +Help Symfony by [sponsoring][3] its development! + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/messenger.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://sensiolabs.com +[3]: https://symfony.com/sponsor diff --git a/plugins/email/vendor/symfony/messenger/Retry/MultiplierRetryStrategy.php b/plugins/email/vendor/symfony/messenger/Retry/MultiplierRetryStrategy.php new file mode 100644 index 0000000..c081830 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Retry/MultiplierRetryStrategy.php @@ -0,0 +1,91 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Retry; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\Stamp\RedeliveryStamp; + +/** + * A retry strategy with a constant or exponential retry delay. + * + * For example, if $delayMilliseconds=10000 & $multiplier=1 (default), + * each retry will wait exactly 10 seconds. + * + * But if $delayMilliseconds=10000 & $multiplier=2: + * * Retry 1: 10 second delay + * * Retry 2: 20 second delay (10000 * 2 = 20000) + * * Retry 3: 40 second delay (20000 * 2 = 40000) + * + * @author Ryan Weaver + * + * @final + */ +class MultiplierRetryStrategy implements RetryStrategyInterface +{ + private $maxRetries; + private $delayMilliseconds; + private $multiplier; + private $maxDelayMilliseconds; + + /** + * @param int $maxRetries The maximum number of times to retry + * @param int $delayMilliseconds Amount of time to delay (or the initial value when multiplier is used) + * @param float $multiplier Multiplier to apply to the delay each time a retry occurs + * @param int $maxDelayMilliseconds Maximum delay to allow (0 means no maximum) + */ + public function __construct(int $maxRetries = 3, int $delayMilliseconds = 1000, float $multiplier = 1, int $maxDelayMilliseconds = 0) + { + $this->maxRetries = $maxRetries; + + if ($delayMilliseconds < 0) { + throw new InvalidArgumentException(sprintf('Delay must be greater than or equal to zero: "%s" given.', $delayMilliseconds)); + } + $this->delayMilliseconds = $delayMilliseconds; + + if ($multiplier < 1) { + throw new InvalidArgumentException(sprintf('Multiplier must be greater than zero: "%s" given.', $multiplier)); + } + $this->multiplier = $multiplier; + + if ($maxDelayMilliseconds < 0) { + throw new InvalidArgumentException(sprintf('Max delay must be greater than or equal to zero: "%s" given.', $maxDelayMilliseconds)); + } + $this->maxDelayMilliseconds = $maxDelayMilliseconds; + } + + /** + * @param \Throwable|null $throwable The cause of the failed handling + */ + public function isRetryable(Envelope $message, \Throwable $throwable = null): bool + { + $retries = RedeliveryStamp::getRetryCountFromEnvelope($message); + + return $retries < $this->maxRetries; + } + + /** + * @param \Throwable|null $throwable The cause of the failed handling + */ + public function getWaitingTime(Envelope $message, \Throwable $throwable = null): int + { + $retries = RedeliveryStamp::getRetryCountFromEnvelope($message); + + $delay = $this->delayMilliseconds * $this->multiplier ** $retries; + + if ($delay > $this->maxDelayMilliseconds && 0 !== $this->maxDelayMilliseconds) { + return $this->maxDelayMilliseconds; + } + + return (int) ceil($delay); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Retry/RetryStrategyInterface.php b/plugins/email/vendor/symfony/messenger/Retry/RetryStrategyInterface.php new file mode 100644 index 0000000..52c294b --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Retry/RetryStrategyInterface.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Retry; + +use Symfony\Component\Messenger\Envelope; + +/** + * @author Fabien Potencier + * @author Grégoire Pineau + * @author Ryan Weaver + */ +interface RetryStrategyInterface +{ + /** + * @param \Throwable|null $throwable The cause of the failed handling + */ + public function isRetryable(Envelope $message/* , \Throwable $throwable = null */): bool; + + /** + * @param \Throwable|null $throwable The cause of the failed handling + * + * @return int The time to delay/wait in milliseconds + */ + public function getWaitingTime(Envelope $message/* , \Throwable $throwable = null */): int; +} diff --git a/plugins/email/vendor/symfony/messenger/RoutableMessageBus.php b/plugins/email/vendor/symfony/messenger/RoutableMessageBus.php new file mode 100644 index 0000000..ece1478 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/RoutableMessageBus.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger; + +use Psr\Container\ContainerInterface; +use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\Stamp\BusNameStamp; + +/** + * Bus of buses that is routable using a BusNameStamp. + * + * This is useful when passed to Worker: messages received + * from the transport can be sent to the correct bus. + * + * @author Ryan Weaver + */ +class RoutableMessageBus implements MessageBusInterface +{ + private $busLocator; + private $fallbackBus; + + public function __construct(ContainerInterface $busLocator, MessageBusInterface $fallbackBus = null) + { + $this->busLocator = $busLocator; + $this->fallbackBus = $fallbackBus; + } + + public function dispatch(object $envelope, array $stamps = []): Envelope + { + if (!$envelope instanceof Envelope) { + throw new InvalidArgumentException('Messages passed to RoutableMessageBus::dispatch() must be inside an Envelope.'); + } + + /** @var BusNameStamp|null $busNameStamp */ + $busNameStamp = $envelope->last(BusNameStamp::class); + + if (null === $busNameStamp) { + if (null === $this->fallbackBus) { + throw new InvalidArgumentException('Envelope is missing a BusNameStamp and no fallback message bus is configured on RoutableMessageBus.'); + } + + return $this->fallbackBus->dispatch($envelope, $stamps); + } + + return $this->getMessageBus($busNameStamp->getBusName())->dispatch($envelope, $stamps); + } + + /** + * @internal + */ + public function getMessageBus(string $busName): MessageBusInterface + { + if (!$this->busLocator->has($busName)) { + throw new InvalidArgumentException(sprintf('Bus named "%s" does not exist.', $busName)); + } + + return $this->busLocator->get($busName); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/AckStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/AckStamp.php new file mode 100644 index 0000000..b94c2c9 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/AckStamp.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +use Symfony\Component\Messenger\Envelope; + +/** + * Marker stamp for messages that can be ack/nack'ed. + */ +final class AckStamp implements NonSendableStampInterface +{ + private $ack; + + /** + * @param \Closure(Envelope, \Throwable|null) $ack + */ + public function __construct(\Closure $ack) + { + $this->ack = $ack; + } + + public function ack(Envelope $envelope, \Throwable $e = null): void + { + ($this->ack)($envelope, $e); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/BusNameStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/BusNameStamp.php new file mode 100644 index 0000000..e9765c0 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/BusNameStamp.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * Stamp used to identify which bus it was passed to. + * + * @author Ryan Weaver + */ +final class BusNameStamp implements StampInterface +{ + private $busName; + + public function __construct(string $busName) + { + $this->busName = $busName; + } + + public function getBusName(): string + { + return $this->busName; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/ConsumedByWorkerStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/ConsumedByWorkerStamp.php new file mode 100644 index 0000000..3ae37ba --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/ConsumedByWorkerStamp.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * A marker that this message was consumed by a worker process. + */ +class ConsumedByWorkerStamp implements NonSendableStampInterface +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/DelayStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/DelayStamp.php new file mode 100644 index 0000000..92859e3 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/DelayStamp.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * Apply this stamp to delay delivery of your message on a transport. + */ +final class DelayStamp implements StampInterface +{ + private $delay; + + /** + * @param int $delay The delay in milliseconds + */ + public function __construct(int $delay) + { + $this->delay = $delay; + } + + public function getDelay(): int + { + return $this->delay; + } + + public static function delayFor(\DateInterval $interval): self + { + $now = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); + $end = $now->add($interval); + + return new self(($end->getTimestamp() - $now->getTimestamp()) * 1000); + } + + public static function delayUntil(\DateTimeInterface $dateTime): self + { + return new self(($dateTime->getTimestamp() - time()) * 1000); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/DispatchAfterCurrentBusStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/DispatchAfterCurrentBusStamp.php new file mode 100644 index 0000000..0ee31f0 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/DispatchAfterCurrentBusStamp.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * Marker item to tell this message should be handled in after the current bus has finished. + * + * @see \Symfony\Component\Messenger\Middleware\DispatchAfterCurrentBusMiddleware + * + * @author Tobias Nyholm + */ +final class DispatchAfterCurrentBusStamp implements NonSendableStampInterface +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/ErrorDetailsStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/ErrorDetailsStamp.php new file mode 100644 index 0000000..62abf23 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/ErrorDetailsStamp.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +use Symfony\Component\ErrorHandler\Exception\FlattenException; +use Symfony\Component\Messenger\Exception\HandlerFailedException; +use Throwable; + +/** + * Stamp applied when a messages fails due to an exception in the handler. + */ +final class ErrorDetailsStamp implements StampInterface +{ + /** @var string */ + private $exceptionClass; + + /** @var int|string */ + private $exceptionCode; + + /** @var string */ + private $exceptionMessage; + + /** @var FlattenException|null */ + private $flattenException; + + /** + * @param int|string $exceptionCode + */ + public function __construct(string $exceptionClass, $exceptionCode, string $exceptionMessage, FlattenException $flattenException = null) + { + $this->exceptionClass = $exceptionClass; + $this->exceptionCode = $exceptionCode; + $this->exceptionMessage = $exceptionMessage; + $this->flattenException = $flattenException; + } + + public static function create(Throwable $throwable): self + { + if ($throwable instanceof HandlerFailedException) { + $throwable = $throwable->getPrevious(); + } + + $flattenException = null; + if (class_exists(FlattenException::class)) { + $flattenException = FlattenException::createFromThrowable($throwable); + } + + return new self(\get_class($throwable), $throwable->getCode(), $throwable->getMessage(), $flattenException); + } + + public function getExceptionClass(): string + { + return $this->exceptionClass; + } + + public function getExceptionCode() + { + return $this->exceptionCode; + } + + public function getExceptionMessage(): string + { + return $this->exceptionMessage; + } + + public function getFlattenException(): ?FlattenException + { + return $this->flattenException; + } + + public function equals(?self $that): bool + { + if (null === $that) { + return false; + } + + if ($this->flattenException && $that->flattenException) { + return $this->flattenException->getClass() === $that->flattenException->getClass() + && $this->flattenException->getCode() === $that->flattenException->getCode() + && $this->flattenException->getMessage() === $that->flattenException->getMessage(); + } + + return $this->exceptionClass === $that->exceptionClass + && $this->exceptionCode === $that->exceptionCode + && $this->exceptionMessage === $that->exceptionMessage; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/FlushBatchHandlersStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/FlushBatchHandlersStamp.php new file mode 100644 index 0000000..5dfbe22 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/FlushBatchHandlersStamp.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * Marker telling that any batch handlers bound to the envelope should be flushed. + */ +final class FlushBatchHandlersStamp implements NonSendableStampInterface +{ + private $force; + + public function __construct(bool $force) + { + $this->force = $force; + } + + public function force(): bool + { + return $this->force; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/HandledStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/HandledStamp.php new file mode 100644 index 0000000..9d5a2c1 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/HandledStamp.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +use Symfony\Component\Messenger\Handler\HandlerDescriptor; + +/** + * Stamp identifying a message handled by the `HandleMessageMiddleware` middleware + * and storing the handler returned value. + * + * This is used by synchronous command buses expecting a return value and the retry logic + * to only execute handlers that didn't succeed. + * + * @see \Symfony\Component\Messenger\Middleware\HandleMessageMiddleware + * @see \Symfony\Component\Messenger\HandleTrait + * + * @author Maxime Steinhausser + */ +final class HandledStamp implements StampInterface +{ + private $result; + private $handlerName; + + /** + * @param mixed $result The returned value of the message handler + */ + public function __construct($result, string $handlerName) + { + $this->result = $result; + $this->handlerName = $handlerName; + } + + /** + * @param mixed $result The returned value of the message handler + */ + public static function fromDescriptor(HandlerDescriptor $handler, $result): self + { + return new self($result, $handler->getName()); + } + + /** + * @return mixed + */ + public function getResult() + { + return $this->result; + } + + public function getHandlerName(): string + { + return $this->handlerName; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/NoAutoAckStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/NoAutoAckStamp.php new file mode 100644 index 0000000..15ba383 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/NoAutoAckStamp.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +use Symfony\Component\Messenger\Handler\HandlerDescriptor; + +/** + * Marker telling that ack should not be done automatically for this message. + */ +final class NoAutoAckStamp implements NonSendableStampInterface +{ + private $handlerDescriptor; + + public function __construct(HandlerDescriptor $handlerDescriptor) + { + $this->handlerDescriptor = $handlerDescriptor; + } + + public function getHandlerDescriptor(): HandlerDescriptor + { + return $this->handlerDescriptor; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/NonSendableStampInterface.php b/plugins/email/vendor/symfony/messenger/Stamp/NonSendableStampInterface.php new file mode 100644 index 0000000..9ebd534 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/NonSendableStampInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * A stamp that should not be included with the Envelope if sent to a transport. + * + * @author Ryan Weaver + */ +interface NonSendableStampInterface extends StampInterface +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/ReceivedStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/ReceivedStamp.php new file mode 100644 index 0000000..7297b17 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/ReceivedStamp.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +use Symfony\Component\Messenger\Middleware\SendMessageMiddleware; + +/** + * Marker stamp for a received message. + * + * This is mainly used by the `SendMessageMiddleware` middleware to identify + * a message should not be sent if it was just received. + * + * @see SendMessageMiddleware + * + * @author Samuel Roze + */ +final class ReceivedStamp implements NonSendableStampInterface +{ + private $transportName; + + public function __construct(string $transportName) + { + $this->transportName = $transportName; + } + + public function getTransportName(): string + { + return $this->transportName; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/RedeliveryStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/RedeliveryStamp.php new file mode 100644 index 0000000..fef9b06 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/RedeliveryStamp.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +use Symfony\Component\ErrorHandler\Exception\FlattenException; +use Symfony\Component\Messenger\Envelope; + +/** + * Stamp applied when a messages needs to be redelivered. + */ +final class RedeliveryStamp implements StampInterface +{ + private $retryCount; + private $redeliveredAt; + private $exceptionMessage; + private $flattenException; + + /** + * @param \DateTimeInterface|null $exceptionMessage + */ + public function __construct(int $retryCount, $exceptionMessage = null, FlattenException $flattenException = null, \DateTimeInterface $redeliveredAt = null) + { + $this->retryCount = $retryCount; + $this->redeliveredAt = $redeliveredAt ?? new \DateTimeImmutable(); + if (null !== $redeliveredAt) { + trigger_deprecation('symfony/messenger', '5.2', sprintf('Using the "$redeliveredAt" as 4th argument of the "%s::__construct()" is deprecated, pass "$redeliveredAt" as second argument instead.', self::class)); + } + + if ($exceptionMessage instanceof \DateTimeInterface) { + // In Symfony 6.0, the second argument will be $redeliveredAt + $this->redeliveredAt = $exceptionMessage; + if (null !== $redeliveredAt) { + throw new \LogicException('It is deprecated to specify a redeliveredAt as 4th argument. The correct way is to specify redeliveredAt as the second argument. Using both is not allowed.'); + } + } elseif (null !== $exceptionMessage) { + trigger_deprecation('symfony/messenger', '5.2', sprintf('Using the "$exceptionMessage" parameter in the "%s" class is deprecated, use the "%s" class instead.', self::class, ErrorDetailsStamp::class)); + $this->exceptionMessage = $exceptionMessage; + } + + if (null !== $flattenException) { + trigger_deprecation('symfony/messenger', '5.2', sprintf('Using the "$flattenException" parameter in the "%s" class is deprecated, use the "%s" class instead.', self::class, ErrorDetailsStamp::class)); + } + $this->flattenException = $flattenException; + } + + public static function getRetryCountFromEnvelope(Envelope $envelope): int + { + /** @var self|null $retryMessageStamp */ + $retryMessageStamp = $envelope->last(self::class); + + return $retryMessageStamp ? $retryMessageStamp->getRetryCount() : 0; + } + + public function getRetryCount(): int + { + return $this->retryCount; + } + + /** + * @deprecated since Symfony 5.2, use ErrorDetailsStamp instead. + */ + public function getExceptionMessage(): ?string + { + trigger_deprecation('symfony/messenger', '5.2', sprintf('Using the "getExceptionMessage()" method of the "%s" class is deprecated, use the "%s" class instead.', self::class, ErrorDetailsStamp::class)); + + return $this->exceptionMessage; + } + + /** + * @deprecated since Symfony 5.2, use ErrorDetailsStamp instead. + */ + public function getFlattenException(): ?FlattenException + { + trigger_deprecation('symfony/messenger', '5.2', sprintf('Using the "getFlattenException()" method of the "%s" class is deprecated, use the "%s" class instead.', self::class, ErrorDetailsStamp::class)); + + return $this->flattenException; + } + + public function getRedeliveredAt(): \DateTimeInterface + { + return $this->redeliveredAt; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/RouterContextStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/RouterContextStamp.php new file mode 100644 index 0000000..4906f50 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/RouterContextStamp.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * @author Jérémy Derussé + */ +class RouterContextStamp implements StampInterface +{ + private $baseUrl; + private $method; + private $host; + private $scheme; + private $httpPort; + private $httpsPort; + private $pathInfo; + private $queryString; + + public function __construct(string $baseUrl, string $method, string $host, string $scheme, int $httpPort, int $httpsPort, string $pathInfo, string $queryString) + { + $this->baseUrl = $baseUrl; + $this->method = $method; + $this->host = $host; + $this->scheme = $scheme; + $this->httpPort = $httpPort; + $this->httpsPort = $httpsPort; + $this->pathInfo = $pathInfo; + $this->queryString = $queryString; + } + + public function getBaseUrl(): string + { + return $this->baseUrl; + } + + public function getMethod(): string + { + return $this->method; + } + + public function getHost(): string + { + return $this->host; + } + + public function getScheme(): string + { + return $this->scheme; + } + + public function getHttpPort(): int + { + return $this->httpPort; + } + + public function getHttpsPort(): int + { + return $this->httpsPort; + } + + public function getPathInfo(): string + { + return $this->pathInfo; + } + + public function getQueryString(): string + { + return $this->queryString; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/SentStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/SentStamp.php new file mode 100644 index 0000000..eebbfc3 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/SentStamp.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * Marker stamp identifying a message sent by the `SendMessageMiddleware`. + * + * @see \Symfony\Component\Messenger\Middleware\SendMessageMiddleware + * + * @author Maxime Steinhausser + */ +final class SentStamp implements NonSendableStampInterface +{ + private $senderClass; + private $senderAlias; + + public function __construct(string $senderClass, string $senderAlias = null) + { + $this->senderAlias = $senderAlias; + $this->senderClass = $senderClass; + } + + public function getSenderClass(): string + { + return $this->senderClass; + } + + public function getSenderAlias(): ?string + { + return $this->senderAlias; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/SentToFailureTransportStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/SentToFailureTransportStamp.php new file mode 100644 index 0000000..60810cf --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/SentToFailureTransportStamp.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * Stamp applied when a message is sent to the failure transport. + * + * @author Ryan Weaver + */ +final class SentToFailureTransportStamp implements StampInterface +{ + private $originalReceiverName; + + public function __construct(string $originalReceiverName) + { + $this->originalReceiverName = $originalReceiverName; + } + + public function getOriginalReceiverName(): string + { + return $this->originalReceiverName; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/SerializerStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/SerializerStamp.php new file mode 100644 index 0000000..3df15ca --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/SerializerStamp.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * @author Maxime Steinhausser + */ +final class SerializerStamp implements StampInterface +{ + private $context; + + public function __construct(array $context) + { + $this->context = $context; + } + + public function getContext(): array + { + return $this->context; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/StampInterface.php b/plugins/email/vendor/symfony/messenger/Stamp/StampInterface.php new file mode 100644 index 0000000..dc1fc0a --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/StampInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * An envelope stamp related to a message. + * + * Stamps must be serializable value objects for transport. + * + * @author Maxime Steinhausser + */ +interface StampInterface +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/TransportMessageIdStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/TransportMessageIdStamp.php new file mode 100644 index 0000000..2128b46 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/TransportMessageIdStamp.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * Added by a sender or receiver to indicate the id of this message in that transport. + * + * @author Ryan Weaver + */ +final class TransportMessageIdStamp implements StampInterface +{ + private $id; + + /** + * @param mixed $id some "identifier" of the message in a transport + */ + public function __construct($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Stamp/ValidationStamp.php b/plugins/email/vendor/symfony/messenger/Stamp/ValidationStamp.php new file mode 100644 index 0000000..2127187 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Stamp/ValidationStamp.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +use Symfony\Component\Validator\Constraints\GroupSequence; + +/** + * @author Maxime Steinhausser + */ +final class ValidationStamp implements StampInterface +{ + private $groups; + + /** + * @param string[]|GroupSequence $groups + */ + public function __construct($groups) + { + $this->groups = $groups; + } + + public function getGroups() + { + return $this->groups; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Test/Middleware/MiddlewareTestCase.php b/plugins/email/vendor/symfony/messenger/Test/Middleware/MiddlewareTestCase.php new file mode 100644 index 0000000..08c3d6a --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Test/Middleware/MiddlewareTestCase.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Test\Middleware; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Middleware\MiddlewareInterface; +use Symfony\Component\Messenger\Middleware\StackInterface; +use Symfony\Component\Messenger\Middleware\StackMiddleware; + +/** + * @author Nicolas Grekas + */ +abstract class MiddlewareTestCase extends TestCase +{ + protected function getStackMock(bool $nextIsCalled = true) + { + if (!$nextIsCalled) { + $stack = $this->createMock(StackInterface::class); + $stack + ->expects($this->never()) + ->method('next') + ; + + return $stack; + } + + $nextMiddleware = $this->createMock(MiddlewareInterface::class); + $nextMiddleware + ->expects($this->once()) + ->method('handle') + ->willReturnCallback(function (Envelope $envelope, StackInterface $stack): Envelope { + return $envelope; + }) + ; + + return new StackMiddleware($nextMiddleware); + } + + protected function getThrowingStackMock(\Throwable $throwable = null) + { + $nextMiddleware = $this->createMock(MiddlewareInterface::class); + $nextMiddleware + ->expects($this->once()) + ->method('handle') + ->willThrowException($throwable ?? new \RuntimeException('Thrown from next middleware.')) + ; + + return new StackMiddleware($nextMiddleware); + } +} diff --git a/plugins/email/vendor/symfony/messenger/TraceableMessageBus.php b/plugins/email/vendor/symfony/messenger/TraceableMessageBus.php new file mode 100644 index 0000000..df595b0 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/TraceableMessageBus.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger; + +/** + * @author Samuel Roze + */ +class TraceableMessageBus implements MessageBusInterface +{ + private $decoratedBus; + private $dispatchedMessages = []; + + public function __construct(MessageBusInterface $decoratedBus) + { + $this->decoratedBus = $decoratedBus; + } + + /** + * {@inheritdoc} + */ + public function dispatch(object $message, array $stamps = []): Envelope + { + $envelope = Envelope::wrap($message, $stamps); + $context = [ + 'stamps' => array_merge([], ...array_values($envelope->all())), + 'message' => $envelope->getMessage(), + 'caller' => $this->getCaller(), + 'callTime' => microtime(true), + ]; + + try { + return $envelope = $this->decoratedBus->dispatch($message, $stamps); + } catch (\Throwable $e) { + $context['exception'] = $e; + + throw $e; + } finally { + $this->dispatchedMessages[] = $context + ['stamps_after_dispatch' => array_merge([], ...array_values($envelope->all()))]; + } + } + + public function getDispatchedMessages(): array + { + return $this->dispatchedMessages; + } + + public function reset() + { + $this->dispatchedMessages = []; + } + + private function getCaller(): array + { + $trace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 8); + + $file = $trace[1]['file'] ?? null; + $line = $trace[1]['line'] ?? null; + + $handleTraitFile = (new \ReflectionClass(HandleTrait::class))->getFileName(); + $found = false; + for ($i = 1; $i < 8; ++$i) { + if (isset($trace[$i]['file'], $trace[$i + 1]['file'], $trace[$i + 1]['line']) && $trace[$i]['file'] === $handleTraitFile) { + $file = $trace[$i + 1]['file']; + $line = $trace[$i + 1]['line']; + $found = true; + + break; + } + } + + for ($i = 2; $i < 8 && !$found; ++$i) { + if (isset($trace[$i]['class'], $trace[$i]['function']) + && 'dispatch' === $trace[$i]['function'] + && is_a($trace[$i]['class'], MessageBusInterface::class, true) + ) { + $file = $trace[$i]['file']; + $line = $trace[$i]['line']; + + while (++$i < 8) { + if (isset($trace[$i]['function'], $trace[$i]['file']) && empty($trace[$i]['class']) && !str_starts_with($trace[$i]['function'], 'call_user_func')) { + $file = $trace[$i]['file']; + $line = $trace[$i]['line']; + + break; + } + } + break; + } + } + + $name = str_replace('\\', '/', (string) $file); + + return [ + 'name' => substr($name, strrpos($name, '/') + 1), + 'file' => $file, + 'line' => $line, + ]; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpFactory.php b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpFactory.php new file mode 100644 index 0000000..27775b7 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpFactory.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\AmqpExt; + +use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpFactory as BridgeAmqpFactory; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The AmqpExt transport has been moved to package "symfony/amqp-messenger" and will not be included by default in 6.0. Run "composer require symfony/amqp-messenger".', AmqpFactory::class, BridgeAmqpFactory::class); + +class_exists(BridgeAmqpFactory::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/amqp-messenger instead. + */ + class AmqpFactory + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpReceivedStamp.php b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpReceivedStamp.php new file mode 100644 index 0000000..3ce9a1d --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpReceivedStamp.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\AmqpExt; + +use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpReceivedStamp as BridgeAmqpReceivedStamp; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated,use "%s" instead. The AmqpExt transport has been moved to package "symfony/amqp-messenger" and will not be included by default in 6.0. Run "composer require symfony/amqp-messenger".', AmqpReceivedStamp::class, BridgeAmqpReceivedStamp::class); + +class_exists(BridgeAmqpReceivedStamp::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/amqp-messenger instead. + */ + class AmqpReceivedStamp + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpReceiver.php b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpReceiver.php new file mode 100644 index 0000000..3b4b8f9 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpReceiver.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\AmqpExt; + +use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpReceiver as BridgeAmqpReceiver; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The AmqpExt transport has been moved to package "symfony/amqp-messenger" and will not be included by default in 6.0. Run "composer require symfony/amqp-messenger".', AmqpReceiver::class, BridgeAmqpReceiver::class); + +class_exists(BridgeAmqpReceiver::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/amqp-messenger instead. + */ + class AmqpReceiver + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpSender.php b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpSender.php new file mode 100644 index 0000000..f6e195d --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpSender.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\AmqpExt; + +use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpSender as BridgeAmqpSender; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The AmqpExt transport has been moved to package "symfony/amqp-messenger" and will not be included by default in 6.0. Run "composer require symfony/amqp-messenger".', AmqpSender::class, BridgeAmqpSender::class); + +class_exists(BridgeAmqpSender::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/amqp-messenger instead. + */ + class AmqpSender + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpStamp.php b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpStamp.php new file mode 100644 index 0000000..5c6f696 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpStamp.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\AmqpExt; + +use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpStamp as BridgeAmqpStamp; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The AmqpExt transport has been moved to package "symfony/amqp-messenger" and will not be included by default in 6.0. Run "composer require symfony/amqp-messenger".', AmqpStamp::class, BridgeAmqpStamp::class); + +class_exists(BridgeAmqpStamp::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/amqp-messenger instead. + */ + class AmqpStamp + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpTransport.php b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpTransport.php new file mode 100644 index 0000000..e14dbfc --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpTransport.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\AmqpExt; + +use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpTransport as BridgeAmqpTransport; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The AmqpExt transport has been moved to package "symfony/amqp-messenger" and will not be included by default in 6.0. Run "composer require symfony/amqp-messenger".', AmqpTransport::class, BridgeAmqpTransport::class); + +class_exists(BridgeAmqpTransport::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/amqp-messenger instead. + */ + class AmqpTransport + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpTransportFactory.php b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpTransportFactory.php new file mode 100644 index 0000000..2b48968 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpTransportFactory.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\AmqpExt; + +use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpTransportFactory as BridgeAmqpTransportFactory; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The AmqpExt transport has been moved to package "symfony/amqp-messenger" and will not be included by default in 6.0. Run "composer require symfony/amqp-messenger".', AmqpTransportFactory::class, BridgeAmqpTransportFactory::class); + +class_exists(BridgeAmqpTransportFactory::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/amqp-messenger instead. + */ + class AmqpTransportFactory + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/Connection.php b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/Connection.php new file mode 100644 index 0000000..1301ca9 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/AmqpExt/Connection.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\AmqpExt; + +use Symfony\Component\Messenger\Bridge\Amqp\Transport\Connection as BridgeConnection; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The AmqpExt transport has been moved to package "symfony/amqp-messenger" and will not be included by default in 6.0. Run "composer require symfony/amqp-messenger".', Connection::class, BridgeConnection::class); + +class_exists(BridgeConnection::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/amqp-messenger instead. + */ + class Connection + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Doctrine/Connection.php b/plugins/email/vendor/symfony/messenger/Transport/Doctrine/Connection.php new file mode 100644 index 0000000..6f02bcc --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Doctrine/Connection.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Doctrine; + +use Symfony\Component\Messenger\Bridge\Doctrine\Transport\Connection as BridgeConnection; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The Doctrine transport has been moved to package "symfony/doctrine-messenger" and will not be included by default in 6.0. Run "composer require symfony/doctrine-messenger".', Connection::class, BridgeConnection::class); + +class_exists(BridgeConnection::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/doctrine-messenger instead. + */ + class Connection + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineReceivedStamp.php b/plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineReceivedStamp.php new file mode 100644 index 0000000..6adb60a --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineReceivedStamp.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Doctrine; + +use Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineReceivedStamp as BridgeDoctrineReceivedStamp; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The Doctrine transport has been moved to package "symfony/doctrine-messenger" and will not be included by default in 6.0. Run "composer require symfony/doctrine-messenger".', DoctrineReceivedStamp::class, BridgeDoctrineReceivedStamp::class); + +class_exists(BridgeDoctrineReceivedStamp::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/doctrine-messenger instead. + */ + class DoctrineReceivedStamp + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineReceiver.php b/plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineReceiver.php new file mode 100644 index 0000000..ffe0d44 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineReceiver.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Doctrine; + +use Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineReceiver as BridgeDoctrineReceiver; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The Doctrine transport has been moved to package "symfony/doctrine-messenger" and will not be included by default in 6.0. Run "composer require symfony/doctrine-messenger".', DoctrineReceiver::class, BridgeDoctrineReceiver::class); + +class_exists(BridgeDoctrineReceiver::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/doctrine-messenger instead. + */ + class DoctrineReceiver + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineSender.php b/plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineSender.php new file mode 100644 index 0000000..17aa795 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineSender.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Doctrine; + +use Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineSender as BridgeDoctrineSender; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The Doctrine transport has been moved to package "symfony/doctrine-messenger" and will not be included by default in 6.0. Run "composer require symfony/doctrine-messenger".', DoctrineSender::class, BridgeDoctrineSender::class); + +class_exists(BridgeDoctrineSender::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/doctrine-messenger instead. + */ + class DoctrineSender + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineTransport.php b/plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineTransport.php new file mode 100644 index 0000000..6aa96ba --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineTransport.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Doctrine; + +use Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineTransport as BridgeDoctrineTransport; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The Doctrine transport has been moved to package "symfony/doctrine-messenger" and will not be included by default in 6.0. Run "composer require symfony/doctrine-messenger".', DoctrineTransport::class, BridgeDoctrineTransport::class); + +class_exists(BridgeDoctrineTransport::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/doctrine-messenger instead. + */ + class DoctrineTransport + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineTransportFactory.php b/plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineTransportFactory.php new file mode 100644 index 0000000..fe277d6 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineTransportFactory.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Doctrine; + +use Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineTransportFactory as BridgeDoctrineTransportFactory; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The Doctrine transport has been moved to package "symfony/doctrine-messenger" and will not be included by default in 6.0. Run "composer require symfony/doctrine-messenger".', DoctrineTransportFactory::class, BridgeDoctrineTransportFactory::class); + +class_exists(BridgeDoctrineTransportFactory::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/doctrine-messenger instead. + */ + class DoctrineTransportFactory + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/InMemoryTransport.php b/plugins/email/vendor/symfony/messenger/Transport/InMemoryTransport.php new file mode 100644 index 0000000..eedbb9c --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/InMemoryTransport.php @@ -0,0 +1,166 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\LogicException; +use Symfony\Component\Messenger\Stamp\TransportMessageIdStamp; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * Transport that stays in memory. Useful for testing purpose. + * + * @author Gary PEGEOT + */ +class InMemoryTransport implements TransportInterface, ResetInterface +{ + /** + * @var Envelope[] + */ + private $sent = []; + + /** + * @var Envelope[] + */ + private $acknowledged = []; + + /** + * @var Envelope[] + */ + private $rejected = []; + + /** + * @var Envelope[] + */ + private $queue = []; + + private $nextId = 1; + + /** + * @var SerializerInterface|null + */ + private $serializer; + + public function __construct(SerializerInterface $serializer = null) + { + $this->serializer = $serializer; + } + + /** + * {@inheritdoc} + */ + public function get(): iterable + { + return array_values($this->decode($this->queue)); + } + + /** + * {@inheritdoc} + */ + public function ack(Envelope $envelope): void + { + $this->acknowledged[] = $this->encode($envelope); + + if (!$transportMessageIdStamp = $envelope->last(TransportMessageIdStamp::class)) { + throw new LogicException('No TransportMessageIdStamp found on the Envelope.'); + } + + unset($this->queue[$transportMessageIdStamp->getId()]); + } + + /** + * {@inheritdoc} + */ + public function reject(Envelope $envelope): void + { + $this->rejected[] = $this->encode($envelope); + + if (!$transportMessageIdStamp = $envelope->last(TransportMessageIdStamp::class)) { + throw new LogicException('No TransportMessageIdStamp found on the Envelope.'); + } + + unset($this->queue[$transportMessageIdStamp->getId()]); + } + + /** + * {@inheritdoc} + */ + public function send(Envelope $envelope): Envelope + { + $id = $this->nextId++; + $envelope = $envelope->with(new TransportMessageIdStamp($id)); + $encodedEnvelope = $this->encode($envelope); + $this->sent[] = $encodedEnvelope; + $this->queue[$id] = $encodedEnvelope; + + return $envelope; + } + + public function reset() + { + $this->sent = $this->queue = $this->rejected = $this->acknowledged = []; + } + + /** + * @return Envelope[] + */ + public function getAcknowledged(): array + { + return $this->decode($this->acknowledged); + } + + /** + * @return Envelope[] + */ + public function getRejected(): array + { + return $this->decode($this->rejected); + } + + /** + * @return Envelope[] + */ + public function getSent(): array + { + return $this->decode($this->sent); + } + + /** + * @return Envelope|array + */ + private function encode(Envelope $envelope) + { + if (null === $this->serializer) { + return $envelope; + } + + return $this->serializer->encode($envelope); + } + + /** + * @param array $messagesEncoded + * + * @return Envelope[] + */ + private function decode(array $messagesEncoded): array + { + if (null === $this->serializer) { + return $messagesEncoded; + } + + return array_map( + [$this->serializer, 'decode'], + $messagesEncoded + ); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/InMemoryTransportFactory.php b/plugins/email/vendor/symfony/messenger/Transport/InMemoryTransportFactory.php new file mode 100644 index 0000000..ee7d028 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/InMemoryTransportFactory.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport; + +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * @author Gary PEGEOT + */ +class InMemoryTransportFactory implements TransportFactoryInterface, ResetInterface +{ + /** + * @var InMemoryTransport[] + */ + private $createdTransports = []; + + public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface + { + ['serialize' => $serialize] = $this->parseDsn($dsn); + + return $this->createdTransports[] = new InMemoryTransport($serialize ? $serializer : null); + } + + public function supports(string $dsn, array $options): bool + { + return str_starts_with($dsn, 'in-memory://'); + } + + public function reset() + { + foreach ($this->createdTransports as $transport) { + $transport->reset(); + } + } + + private function parseDsn(string $dsn): array + { + $query = []; + if ($queryAsString = strstr($dsn, '?')) { + parse_str(ltrim($queryAsString, '?'), $query); + } + + return [ + 'serialize' => filter_var($query['serialize'] ?? false, \FILTER_VALIDATE_BOOLEAN), + ]; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Receiver/ListableReceiverInterface.php b/plugins/email/vendor/symfony/messenger/Transport/Receiver/ListableReceiverInterface.php new file mode 100644 index 0000000..897c7a5 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Receiver/ListableReceiverInterface.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Receiver; + +use Symfony\Component\Messenger\Envelope; + +/** + * Used when a receiver has the ability to list messages and find specific messages. + * A receiver that implements this should add the TransportMessageIdStamp + * to the Envelopes that it returns. + * + * @author Ryan Weaver + */ +interface ListableReceiverInterface extends ReceiverInterface +{ + /** + * Returns all the messages (up to the limit) in this receiver. + * + * Messages should be given the same stamps as when using ReceiverInterface::get(). + * + * @return Envelope[]|iterable + */ + public function all(int $limit = null): iterable; + + /** + * Returns the Envelope by id or none. + * + * Message should be given the same stamps as when using ReceiverInterface::get(). + */ + public function find($id): ?Envelope; +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Receiver/MessageCountAwareInterface.php b/plugins/email/vendor/symfony/messenger/Transport/Receiver/MessageCountAwareInterface.php new file mode 100644 index 0000000..b680d8a --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Receiver/MessageCountAwareInterface.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Receiver; + +/** + * @author Samuel Roze + * @author Ryan Weaver + */ +interface MessageCountAwareInterface +{ + /** + * Returns the number of messages waiting to be handled. + * + * In some systems, this may be an approximate number. + */ + public function getMessageCount(): int; +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Receiver/QueueReceiverInterface.php b/plugins/email/vendor/symfony/messenger/Transport/Receiver/QueueReceiverInterface.php new file mode 100644 index 0000000..1886afe --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Receiver/QueueReceiverInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Receiver; + +use Symfony\Component\Messenger\Envelope; + +/** + * Some transports may have multiple queues. This interface is used to read from only some queues. + * + * @author David Buchmann + */ +interface QueueReceiverInterface extends ReceiverInterface +{ + /** + * Get messages from the specified queue names instead of consuming from all queues. + * + * @param string[] $queueNames + * + * @return Envelope[] + */ + public function getFromQueues(array $queueNames): iterable; +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Receiver/ReceiverInterface.php b/plugins/email/vendor/symfony/messenger/Transport/Receiver/ReceiverInterface.php new file mode 100644 index 0000000..68f72c5 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Receiver/ReceiverInterface.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Receiver; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\TransportException; + +/** + * @author Samuel Roze + * @author Ryan Weaver + */ +interface ReceiverInterface +{ + /** + * Receives some messages. + * + * While this method could return an unlimited number of messages, + * the intention is that it returns only one, or a "small number" + * of messages each time. This gives the user more flexibility: + * they can finish processing the one (or "small number") of messages + * from this receiver and move on to check other receivers for messages. + * If this method returns too many messages, it could cause a + * blocking effect where handling the messages received from one + * call to get() takes a long time, blocking other receivers from + * being called. + * + * If applicable, the Envelope should contain a TransportMessageIdStamp. + * + * If a received message cannot be decoded, the message should not + * be retried again (e.g. if there's a queue, it should be removed) + * and a MessageDecodingFailedException should be thrown. + * + * @throws TransportException If there is an issue communicating with the transport + * + * @return Envelope[] + */ + public function get(): iterable; + + /** + * Acknowledges that the passed message was handled. + * + * @throws TransportException If there is an issue communicating with the transport + */ + public function ack(Envelope $envelope): void; + + /** + * Called when handling the message failed and it should not be retried. + * + * @throws TransportException If there is an issue communicating with the transport + */ + public function reject(Envelope $envelope): void; +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Receiver/SingleMessageReceiver.php b/plugins/email/vendor/symfony/messenger/Transport/Receiver/SingleMessageReceiver.php new file mode 100644 index 0000000..1ad5f22 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Receiver/SingleMessageReceiver.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Receiver; + +use Symfony\Component\Messenger\Envelope; + +/** + * Receiver that decorates another, but receives only 1 specific message. + * + * @author Ryan Weaver + * + * @internal + */ +class SingleMessageReceiver implements ReceiverInterface +{ + private $receiver; + private $envelope; + private $hasReceived = false; + + public function __construct(ReceiverInterface $receiver, Envelope $envelope) + { + $this->receiver = $receiver; + $this->envelope = $envelope; + } + + public function get(): iterable + { + if ($this->hasReceived) { + return []; + } + + $this->hasReceived = true; + + return [$this->envelope]; + } + + public function ack(Envelope $envelope): void + { + $this->receiver->ack($envelope); + } + + public function reject(Envelope $envelope): void + { + $this->receiver->reject($envelope); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/RedisExt/Connection.php b/plugins/email/vendor/symfony/messenger/Transport/RedisExt/Connection.php new file mode 100644 index 0000000..39679ab --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/RedisExt/Connection.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\RedisExt; + +use Symfony\Component\Messenger\Bridge\Redis\Transport\Connection as BridgeConnection; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The RedisExt transport has been moved to package "symfony/redis-messenger" and will not be included by default in 6.0. Run "composer require symfony/redis-messenger".', Connection::class, BridgeConnection::class); + +class_exists(BridgeConnection::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/redis-messenger instead. + */ + class Connection + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisReceivedStamp.php b/plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisReceivedStamp.php new file mode 100644 index 0000000..0a5866c --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisReceivedStamp.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\RedisExt; + +use Symfony\Component\Messenger\Bridge\Redis\Transport\RedisReceivedStamp as BridgeRedisReceivedStamp; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated,use "%s" instead. The RedisExt transport has been moved to package "symfony/redis-messenger" and will not be included by default in 6.0. Run "composer require symfony/redis-messenger".', RedisReceivedStamp::class, BridgeRedisReceivedStamp::class); + +class_exists(BridgeRedisReceivedStamp::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/redis-messenger instead. + */ + class RedisReceivedStamp + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisReceiver.php b/plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisReceiver.php new file mode 100644 index 0000000..6aafbb1 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisReceiver.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\RedisExt; + +use Symfony\Component\Messenger\Bridge\Redis\Transport\RedisReceiver as BridgeRedisReceiver; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The RedisExt transport has been moved to package "symfony/redis-messenger" and will not be included by default in 6.0. Run "composer require symfony/redis-messenger".', RedisReceiver::class, BridgeRedisReceiver::class); + +class_exists(BridgeRedisReceiver::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/redis-messenger instead. + */ + class RedisReceiver + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisSender.php b/plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisSender.php new file mode 100644 index 0000000..8928236 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisSender.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\RedisExt; + +use Symfony\Component\Messenger\Bridge\Redis\Transport\RedisSender as BridgeRedisSender; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The RedisExt transport has been moved to package "symfony/redis-messenger" and will not be included by default in 6.0. Run "composer require symfony/redis-messenger".', RedisSender::class, BridgeRedisSender::class); + +class_exists(BridgeRedisSender::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/redis-messenger instead. + */ + class RedisSender + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisTransport.php b/plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisTransport.php new file mode 100644 index 0000000..939b748 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisTransport.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\RedisExt; + +use Symfony\Component\Messenger\Bridge\Redis\Transport\RedisTransport as BridgeRedisTransport; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The RedisExt transport has been moved to package "symfony/redis-messenger" and will not be included by default in 6.0. Run "composer require symfony/redis-messenger".', RedisTransport::class, BridgeRedisTransport::class); + +class_exists(BridgeRedisTransport::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/redis-messenger instead. + */ + class RedisTransport + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisTransportFactory.php b/plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisTransportFactory.php new file mode 100644 index 0000000..a93822b --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisTransportFactory.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\RedisExt; + +use Symfony\Component\Messenger\Bridge\Redis\Transport\RedisTransportFactory as BridgeRedisTransportFactory; + +trigger_deprecation('symfony/messenger', '5.1', 'The "%s" class is deprecated, use "%s" instead. The RedisExt transport has been moved to package "symfony/redis-messenger" and will not be included by default in 6.0. Run "composer require symfony/redis-messenger".', RedisTransportFactory::class, BridgeRedisTransportFactory::class); + +class_exists(BridgeRedisTransportFactory::class); + +if (false) { + /** + * @deprecated since Symfony 5.1, to be removed in 6.0. Use symfony/redis-messenger instead. + */ + class RedisTransportFactory + { + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Sender/SenderInterface.php b/plugins/email/vendor/symfony/messenger/Transport/Sender/SenderInterface.php new file mode 100644 index 0000000..3414a40 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Sender/SenderInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Sender; + +use Symfony\Component\Messenger\Envelope; + +/** + * @author Samuel Roze + */ +interface SenderInterface +{ + /** + * Sends the given envelope. + * + * The sender can read different stamps for transport configuration, + * like delivery delay. + * + * If applicable, the returned Envelope should contain a TransportMessageIdStamp. + */ + public function send(Envelope $envelope): Envelope; +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Sender/SendersLocator.php b/plugins/email/vendor/symfony/messenger/Transport/Sender/SendersLocator.php new file mode 100644 index 0000000..9d0a1e3 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Sender/SendersLocator.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Sender; + +use Psr\Container\ContainerInterface; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\RuntimeException; +use Symfony\Component\Messenger\Handler\HandlersLocator; + +/** + * Maps a message to a list of senders. + * + * @author Fabien Potencier + */ +class SendersLocator implements SendersLocatorInterface +{ + private $sendersMap; + private $sendersLocator; + + /** + * @param array> $sendersMap An array, keyed by "type", set to an array of sender aliases + * @param ContainerInterface $sendersLocator Locator of senders, keyed by sender alias + */ + public function __construct(array $sendersMap, ContainerInterface $sendersLocator) + { + $this->sendersMap = $sendersMap; + $this->sendersLocator = $sendersLocator; + } + + /** + * {@inheritdoc} + */ + public function getSenders(Envelope $envelope): iterable + { + $seen = []; + + foreach (HandlersLocator::listTypes($envelope) as $type) { + foreach ($this->sendersMap[$type] ?? [] as $senderAlias) { + if (!\in_array($senderAlias, $seen, true)) { + if (!$this->sendersLocator->has($senderAlias)) { + throw new RuntimeException(sprintf('Invalid senders configuration: sender "%s" is not in the senders locator.', $senderAlias)); + } + + $seen[] = $senderAlias; + $sender = $this->sendersLocator->get($senderAlias); + yield $senderAlias => $sender; + } + } + } + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Sender/SendersLocatorInterface.php b/plugins/email/vendor/symfony/messenger/Transport/Sender/SendersLocatorInterface.php new file mode 100644 index 0000000..feab1f4 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Sender/SendersLocatorInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Sender; + +use Symfony\Component\Messenger\Envelope; + +/** + * Maps a message to a list of senders. + * + * @author Samuel Roze + * @author Tobias Schultze + */ +interface SendersLocatorInterface +{ + /** + * Gets the senders for the given message name. + * + * @return iterable Indexed by sender alias if available + */ + public function getSenders(Envelope $envelope): iterable; +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Serialization/Normalizer/FlattenExceptionNormalizer.php b/plugins/email/vendor/symfony/messenger/Transport/Serialization/Normalizer/FlattenExceptionNormalizer.php new file mode 100644 index 0000000..5f335d0 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Serialization/Normalizer/FlattenExceptionNormalizer.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Serialization\Normalizer; + +use Symfony\Component\ErrorHandler\Exception\FlattenException; +use Symfony\Component\Messenger\Transport\Serialization\Serializer; +use Symfony\Component\Serializer\Exception\InvalidArgumentException; +use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; + +/** + * This normalizer is only used in Debug/Dev/Messenger contexts. + * + * @author Pascal Luna + */ +final class FlattenExceptionNormalizer implements DenormalizerInterface, ContextAwareNormalizerInterface +{ + use NormalizerAwareTrait; + + /** + * {@inheritdoc} + * + * @throws InvalidArgumentException + */ + public function normalize($object, string $format = null, array $context = []): array + { + $normalized = [ + 'message' => $object->getMessage(), + 'code' => $object->getCode(), + 'headers' => $object->getHeaders(), + 'class' => $object->getClass(), + 'file' => $object->getFile(), + 'line' => $object->getLine(), + 'previous' => null === $object->getPrevious() ? null : $this->normalize($object->getPrevious(), $format, $context), + 'status' => $object->getStatusCode(), + 'status_text' => $object->getStatusText(), + 'trace' => $object->getTrace(), + 'trace_as_string' => $object->getTraceAsString(), + ]; + + return $normalized; + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, string $format = null, array $context = []): bool + { + return $data instanceof FlattenException && ($context[Serializer::MESSENGER_SERIALIZATION_CONTEXT] ?? false); + } + + /** + * {@inheritdoc} + */ + public function denormalize($data, string $type, string $format = null, array $context = []): FlattenException + { + $object = new FlattenException(); + + $object->setMessage($data['message']); + $object->setCode($data['code']); + $object->setStatusCode($data['status'] ?? 500); + $object->setClass($data['class']); + $object->setFile($data['file']); + $object->setLine($data['line']); + $object->setStatusText($data['status_text']); + $object->setHeaders((array) $data['headers']); + + if (isset($data['previous'])) { + $object->setPrevious($this->denormalize($data['previous'], $type, $format, $context)); + } + + $property = new \ReflectionProperty(FlattenException::class, 'trace'); + $property->setAccessible(true); + $property->setValue($object, (array) $data['trace']); + + $property = new \ReflectionProperty(FlattenException::class, 'traceAsString'); + $property->setAccessible(true); + $property->setValue($object, $data['trace_as_string']); + + return $object; + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, string $type, string $format = null, array $context = []): bool + { + return FlattenException::class === $type && ($context[Serializer::MESSENGER_SERIALIZATION_CONTEXT] ?? false); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Serialization/PhpSerializer.php b/plugins/email/vendor/symfony/messenger/Transport/Serialization/PhpSerializer.php new file mode 100644 index 0000000..e6332b3 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Serialization/PhpSerializer.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Serialization; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; +use Symfony\Component\Messenger\Stamp\NonSendableStampInterface; + +/** + * @author Ryan Weaver + */ +class PhpSerializer implements SerializerInterface +{ + /** + * {@inheritdoc} + */ + public function decode(array $encodedEnvelope): Envelope + { + if (empty($encodedEnvelope['body'])) { + throw new MessageDecodingFailedException('Encoded envelope should have at least a "body", or maybe you should implement your own serializer.'); + } + + if (!str_ends_with($encodedEnvelope['body'], '}')) { + $encodedEnvelope['body'] = base64_decode($encodedEnvelope['body']); + } + + $serializeEnvelope = stripslashes($encodedEnvelope['body']); + + return $this->safelyUnserialize($serializeEnvelope); + } + + /** + * {@inheritdoc} + */ + public function encode(Envelope $envelope): array + { + $envelope = $envelope->withoutStampsOfType(NonSendableStampInterface::class); + + $body = addslashes(serialize($envelope)); + + if (!preg_match('//u', $body)) { + $body = base64_encode($body); + } + + return [ + 'body' => $body, + ]; + } + + private function safelyUnserialize(string $contents) + { + if ('' === $contents) { + throw new MessageDecodingFailedException('Could not decode an empty message using PHP serialization.'); + } + + $signalingException = new MessageDecodingFailedException(sprintf('Could not decode message using PHP serialization: %s.', $contents)); + $prevUnserializeHandler = ini_set('unserialize_callback_func', self::class.'::handleUnserializeCallback'); + $prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler, $signalingException) { + if (__FILE__ === $file) { + throw $signalingException; + } + + return $prevErrorHandler ? $prevErrorHandler($type, $msg, $file, $line, $context) : false; + }); + + try { + $meta = unserialize($contents); + } finally { + restore_error_handler(); + ini_set('unserialize_callback_func', $prevUnserializeHandler); + } + + return $meta; + } + + /** + * @internal + */ + public static function handleUnserializeCallback(string $class) + { + throw new MessageDecodingFailedException(sprintf('Message class "%s" not found during decoding.', $class)); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Serialization/Serializer.php b/plugins/email/vendor/symfony/messenger/Transport/Serialization/Serializer.php new file mode 100644 index 0000000..6142266 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Serialization/Serializer.php @@ -0,0 +1,183 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Serialization; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\LogicException; +use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; +use Symfony\Component\Messenger\Stamp\NonSendableStampInterface; +use Symfony\Component\Messenger\Stamp\SerializerStamp; +use Symfony\Component\Messenger\Stamp\StampInterface; +use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\Encoder\XmlEncoder; +use Symfony\Component\Serializer\Exception\ExceptionInterface; +use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; +use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; +use Symfony\Component\Serializer\Serializer as SymfonySerializer; +use Symfony\Component\Serializer\SerializerInterface as SymfonySerializerInterface; + +/** + * @author Samuel Roze + */ +class Serializer implements SerializerInterface +{ + public const MESSENGER_SERIALIZATION_CONTEXT = 'messenger_serialization'; + private const STAMP_HEADER_PREFIX = 'X-Message-Stamp-'; + + private $serializer; + private $format; + private $context; + + public function __construct(SymfonySerializerInterface $serializer = null, string $format = 'json', array $context = []) + { + $this->serializer = $serializer ?? self::create()->serializer; + $this->format = $format; + $this->context = $context + [self::MESSENGER_SERIALIZATION_CONTEXT => true]; + } + + public static function create(): self + { + if (!class_exists(SymfonySerializer::class)) { + throw new LogicException(sprintf('The "%s" class requires Symfony\'s Serializer component. Try running "composer require symfony/serializer" or use "%s" instead.', __CLASS__, PhpSerializer::class)); + } + + $encoders = [new XmlEncoder(), new JsonEncoder()]; + $normalizers = [new ArrayDenormalizer(), new ObjectNormalizer()]; + $serializer = new SymfonySerializer($normalizers, $encoders); + + return new self($serializer); + } + + /** + * {@inheritdoc} + */ + public function decode(array $encodedEnvelope): Envelope + { + if (empty($encodedEnvelope['body']) || empty($encodedEnvelope['headers'])) { + throw new MessageDecodingFailedException('Encoded envelope should have at least a "body" and some "headers", or maybe you should implement your own serializer.'); + } + + if (empty($encodedEnvelope['headers']['type'])) { + throw new MessageDecodingFailedException('Encoded envelope does not have a "type" header.'); + } + + $stamps = $this->decodeStamps($encodedEnvelope); + $serializerStamp = $this->findFirstSerializerStamp($stamps); + + $context = $this->context; + if (null !== $serializerStamp) { + $context = $serializerStamp->getContext() + $context; + } + + try { + $message = $this->serializer->deserialize($encodedEnvelope['body'], $encodedEnvelope['headers']['type'], $this->format, $context); + } catch (ExceptionInterface $e) { + throw new MessageDecodingFailedException('Could not decode message: '.$e->getMessage(), $e->getCode(), $e); + } + + return new Envelope($message, $stamps); + } + + /** + * {@inheritdoc} + */ + public function encode(Envelope $envelope): array + { + $context = $this->context; + /** @var SerializerStamp|null $serializerStamp */ + if ($serializerStamp = $envelope->last(SerializerStamp::class)) { + $context = $serializerStamp->getContext() + $context; + } + + $envelope = $envelope->withoutStampsOfType(NonSendableStampInterface::class); + + $headers = ['type' => \get_class($envelope->getMessage())] + $this->encodeStamps($envelope) + $this->getContentTypeHeader(); + + return [ + 'body' => $this->serializer->serialize($envelope->getMessage(), $this->format, $context), + 'headers' => $headers, + ]; + } + + private function decodeStamps(array $encodedEnvelope): array + { + $stamps = []; + foreach ($encodedEnvelope['headers'] as $name => $value) { + if (!str_starts_with($name, self::STAMP_HEADER_PREFIX)) { + continue; + } + + try { + $stamps[] = $this->serializer->deserialize($value, substr($name, \strlen(self::STAMP_HEADER_PREFIX)).'[]', $this->format, $this->context); + } catch (ExceptionInterface $e) { + throw new MessageDecodingFailedException('Could not decode stamp: '.$e->getMessage(), $e->getCode(), $e); + } + } + if ($stamps) { + $stamps = array_merge(...$stamps); + } + + return $stamps; + } + + private function encodeStamps(Envelope $envelope): array + { + if (!$allStamps = $envelope->all()) { + return []; + } + + $headers = []; + foreach ($allStamps as $class => $stamps) { + $headers[self::STAMP_HEADER_PREFIX.$class] = $this->serializer->serialize($stamps, $this->format, $this->context); + } + + return $headers; + } + + /** + * @param StampInterface[] $stamps + */ + private function findFirstSerializerStamp(array $stamps): ?SerializerStamp + { + foreach ($stamps as $stamp) { + if ($stamp instanceof SerializerStamp) { + return $stamp; + } + } + + return null; + } + + private function getContentTypeHeader(): array + { + $mimeType = $this->getMimeTypeForFormat(); + + return null === $mimeType ? [] : ['Content-Type' => $mimeType]; + } + + private function getMimeTypeForFormat(): ?string + { + switch ($this->format) { + case 'json': + return 'application/json'; + case 'xml': + return 'application/xml'; + case 'yml': + case 'yaml': + return 'application/x-yaml'; + case 'csv': + return 'text/csv'; + } + + return null; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Serialization/SerializerInterface.php b/plugins/email/vendor/symfony/messenger/Transport/Serialization/SerializerInterface.php new file mode 100644 index 0000000..fc133f7 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Serialization/SerializerInterface.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Serialization; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; + +/** + * @author Samuel Roze + */ +interface SerializerInterface +{ + /** + * Decodes an envelope and its message from an encoded-form. + * + * The `$encodedEnvelope` parameter is a key-value array that + * describes the envelope and its content, that will be used by the different transports. + * + * The most common keys are: + * - `body` (string) - the message body + * - `headers` (string) - a key/value pair of headers + * + * @throws MessageDecodingFailedException + */ + public function decode(array $encodedEnvelope): Envelope; + + /** + * Encodes an envelope content (message & stamps) to a common format understandable by transports. + * The encoded array should only contain scalars and arrays. + * + * Stamps that implement NonSendableStampInterface should + * not be encoded. + * + * The most common keys of the encoded array are: + * - `body` (string) - the message body + * - `headers` (string) - a key/value pair of headers + */ + public function encode(Envelope $envelope): array; +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/SetupableTransportInterface.php b/plugins/email/vendor/symfony/messenger/Transport/SetupableTransportInterface.php new file mode 100644 index 0000000..8b6a857 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/SetupableTransportInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport; + +/** + * @author Vincent Touzet + */ +interface SetupableTransportInterface +{ + /** + * Setup the transport. + */ + public function setup(): void; +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Sync/SyncTransport.php b/plugins/email/vendor/symfony/messenger/Transport/Sync/SyncTransport.php new file mode 100644 index 0000000..67af903 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Sync/SyncTransport.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Sync; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\MessageBusInterface; +use Symfony\Component\Messenger\Stamp\ReceivedStamp; +use Symfony\Component\Messenger\Stamp\SentStamp; +use Symfony\Component\Messenger\Transport\TransportInterface; + +/** + * Transport that immediately marks messages as received and dispatches for handling. + * + * @author Ryan Weaver + */ +class SyncTransport implements TransportInterface +{ + private $messageBus; + + public function __construct(MessageBusInterface $messageBus) + { + $this->messageBus = $messageBus; + } + + public function get(): iterable + { + throw new InvalidArgumentException('You cannot receive messages from the Messenger SyncTransport.'); + } + + public function stop(): void + { + throw new InvalidArgumentException('You cannot call stop() on the Messenger SyncTransport.'); + } + + public function ack(Envelope $envelope): void + { + throw new InvalidArgumentException('You cannot call ack() on the Messenger SyncTransport.'); + } + + public function reject(Envelope $envelope): void + { + throw new InvalidArgumentException('You cannot call reject() on the Messenger SyncTransport.'); + } + + public function send(Envelope $envelope): Envelope + { + /** @var SentStamp|null $sentStamp */ + $sentStamp = $envelope->last(SentStamp::class); + $alias = null === $sentStamp ? 'sync' : ($sentStamp->getSenderAlias() ?: $sentStamp->getSenderClass()); + + $envelope = $envelope->with(new ReceivedStamp($alias)); + + return $this->messageBus->dispatch($envelope); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/Sync/SyncTransportFactory.php b/plugins/email/vendor/symfony/messenger/Transport/Sync/SyncTransportFactory.php new file mode 100644 index 0000000..d30c49c --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/Sync/SyncTransportFactory.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Sync; + +use Symfony\Component\Messenger\MessageBusInterface; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Component\Messenger\Transport\TransportFactoryInterface; +use Symfony\Component\Messenger\Transport\TransportInterface; + +/** + * @author Ryan Weaver + */ +class SyncTransportFactory implements TransportFactoryInterface +{ + private $messageBus; + + public function __construct(MessageBusInterface $messageBus) + { + $this->messageBus = $messageBus; + } + + public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface + { + return new SyncTransport($this->messageBus); + } + + public function supports(string $dsn, array $options): bool + { + return str_starts_with($dsn, 'sync://'); + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/TransportFactory.php b/plugins/email/vendor/symfony/messenger/Transport/TransportFactory.php new file mode 100644 index 0000000..474dd6f --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/TransportFactory.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport; + +use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; + +/** + * @author Samuel Roze + */ +class TransportFactory implements TransportFactoryInterface +{ + private $factories; + + /** + * @param iterable $factories + */ + public function __construct(iterable $factories) + { + $this->factories = $factories; + } + + public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface + { + foreach ($this->factories as $factory) { + if ($factory->supports($dsn, $options)) { + return $factory->createTransport($dsn, $options, $serializer); + } + } + + // Help the user to select Symfony packages based on protocol. + $packageSuggestion = ''; + if (0 === strpos($dsn, 'amqp://')) { + $packageSuggestion = ' Run "composer require symfony/amqp-messenger" to install AMQP transport.'; + } elseif (0 === strpos($dsn, 'doctrine://')) { + $packageSuggestion = ' Run "composer require symfony/doctrine-messenger" to install Doctrine transport.'; + } elseif (0 === strpos($dsn, 'redis://') || 0 === strpos($dsn, 'rediss://')) { + $packageSuggestion = ' Run "composer require symfony/redis-messenger" to install Redis transport.'; + } elseif (0 === strpos($dsn, 'sqs://') || preg_match('#^https://sqs\.[\w\-]+\.amazonaws\.com/.+#', $dsn)) { + $packageSuggestion = ' Run "composer require symfony/amazon-sqs-messenger" to install Amazon SQS transport.'; + } elseif (0 === strpos($dsn, 'beanstalkd://')) { + $packageSuggestion = ' Run "composer require symfony/beanstalkd-messenger" to install Beanstalkd transport.'; + } + + throw new InvalidArgumentException(sprintf('No transport supports the given Messenger DSN "%s".%s.', $dsn, $packageSuggestion)); + } + + public function supports(string $dsn, array $options): bool + { + foreach ($this->factories as $factory) { + if ($factory->supports($dsn, $options)) { + return true; + } + } + + return false; + } +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/TransportFactoryInterface.php b/plugins/email/vendor/symfony/messenger/Transport/TransportFactoryInterface.php new file mode 100644 index 0000000..5741c30 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/TransportFactoryInterface.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport; + +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; + +/** + * Creates a Messenger transport. + * + * @author Samuel Roze + */ +interface TransportFactoryInterface +{ + public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface; + + public function supports(string $dsn, array $options): bool; +} diff --git a/plugins/email/vendor/symfony/messenger/Transport/TransportInterface.php b/plugins/email/vendor/symfony/messenger/Transport/TransportInterface.php new file mode 100644 index 0000000..18c1bb8 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Transport/TransportInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport; + +use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; +use Symfony\Component\Messenger\Transport\Sender\SenderInterface; + +/** + * @author Nicolas Grekas + */ +interface TransportInterface extends ReceiverInterface, SenderInterface +{ +} diff --git a/plugins/email/vendor/symfony/messenger/Worker.php b/plugins/email/vendor/symfony/messenger/Worker.php new file mode 100644 index 0000000..33358d3 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/Worker.php @@ -0,0 +1,268 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; +use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; +use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent; +use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent; +use Symfony\Component\Messenger\Event\WorkerRunningEvent; +use Symfony\Component\Messenger\Event\WorkerStartedEvent; +use Symfony\Component\Messenger\Event\WorkerStoppedEvent; +use Symfony\Component\Messenger\Exception\HandlerFailedException; +use Symfony\Component\Messenger\Exception\RejectRedeliveredMessageException; +use Symfony\Component\Messenger\Exception\RuntimeException; +use Symfony\Component\Messenger\Stamp\AckStamp; +use Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp; +use Symfony\Component\Messenger\Stamp\FlushBatchHandlersStamp; +use Symfony\Component\Messenger\Stamp\NoAutoAckStamp; +use Symfony\Component\Messenger\Stamp\ReceivedStamp; +use Symfony\Component\Messenger\Transport\Receiver\QueueReceiverInterface; +use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; + +/** + * @author Samuel Roze + * @author Tobias Schultze + * + * @final + */ +class Worker +{ + private $receivers; + private $bus; + private $eventDispatcher; + private $logger; + private $shouldStop = false; + private $metadata; + private $acks = []; + private $unacks; + + /** + * @param ReceiverInterface[] $receivers Where the key is the transport name + */ + public function __construct(array $receivers, MessageBusInterface $bus, EventDispatcherInterface $eventDispatcher = null, LoggerInterface $logger = null) + { + $this->receivers = $receivers; + $this->bus = $bus; + $this->logger = $logger; + $this->eventDispatcher = class_exists(Event::class) ? LegacyEventDispatcherProxy::decorate($eventDispatcher) : $eventDispatcher; + $this->metadata = new WorkerMetadata([ + 'transportNames' => array_keys($receivers), + ]); + $this->unacks = new \SplObjectStorage(); + } + + /** + * Receive the messages and dispatch them to the bus. + * + * Valid options are: + * * sleep (default: 1000000): Time in microseconds to sleep after no messages are found + * * queues: The queue names to consume from, instead of consuming from all queues. When this is used, all receivers must implement the QueueReceiverInterface + */ + public function run(array $options = []): void + { + $options = array_merge([ + 'sleep' => 1000000, + ], $options); + $queueNames = $options['queues'] ?? null; + + $this->metadata->set(['queueNames' => $queueNames]); + + $this->dispatchEvent(new WorkerStartedEvent($this)); + + if ($queueNames) { + // if queue names are specified, all receivers must implement the QueueReceiverInterface + foreach ($this->receivers as $transportName => $receiver) { + if (!$receiver instanceof QueueReceiverInterface) { + throw new RuntimeException(sprintf('Receiver for "%s" does not implement "%s".', $transportName, QueueReceiverInterface::class)); + } + } + } + + while (!$this->shouldStop) { + $envelopeHandled = false; + $envelopeHandledStart = microtime(true); + foreach ($this->receivers as $transportName => $receiver) { + if ($queueNames) { + $envelopes = $receiver->getFromQueues($queueNames); + } else { + $envelopes = $receiver->get(); + } + + foreach ($envelopes as $envelope) { + $envelopeHandled = true; + + $this->handleMessage($envelope, $transportName); + $this->dispatchEvent(new WorkerRunningEvent($this, false)); + + if ($this->shouldStop) { + break 2; + } + } + + // after handling a single receiver, quit and start the loop again + // this should prevent multiple lower priority receivers from + // blocking too long before the higher priority are checked + if ($envelopeHandled) { + break; + } + } + + if (!$envelopeHandled && $this->flush(false)) { + continue; + } + + if (!$envelopeHandled) { + $this->dispatchEvent(new WorkerRunningEvent($this, true)); + + if (0 < $sleep = (int) ($options['sleep'] - 1e6 * (microtime(true) - $envelopeHandledStart))) { + usleep($sleep); + } + } + } + + $this->flush(true); + $this->dispatchEvent(new WorkerStoppedEvent($this)); + } + + private function handleMessage(Envelope $envelope, string $transportName): void + { + $event = new WorkerMessageReceivedEvent($envelope, $transportName); + $this->dispatchEvent($event); + $envelope = $event->getEnvelope(); + + if (!$event->shouldHandle()) { + return; + } + + $acked = false; + $ack = function (Envelope $envelope, \Throwable $e = null) use ($transportName, &$acked) { + $acked = true; + $this->acks[] = [$transportName, $envelope, $e]; + }; + + try { + $e = null; + $envelope = $this->bus->dispatch($envelope->with(new ReceivedStamp($transportName), new ConsumedByWorkerStamp(), new AckStamp($ack))); + } catch (\Throwable $e) { + } + + $noAutoAckStamp = $envelope->last(NoAutoAckStamp::class); + + if (!$acked && !$noAutoAckStamp) { + $this->acks[] = [$transportName, $envelope, $e]; + } elseif ($noAutoAckStamp) { + $this->unacks[$noAutoAckStamp->getHandlerDescriptor()->getBatchHandler()] = [$envelope->withoutAll(AckStamp::class), $transportName]; + } + + $this->ack(); + } + + private function ack(): bool + { + $acks = $this->acks; + $this->acks = []; + + foreach ($acks as [$transportName, $envelope, $e]) { + $receiver = $this->receivers[$transportName]; + + if (null !== $e) { + if ($rejectFirst = $e instanceof RejectRedeliveredMessageException) { + // redelivered messages are rejected first so that continuous failures in an event listener or while + // publishing for retry does not cause infinite redelivery loops + $receiver->reject($envelope); + } + + if ($e instanceof HandlerFailedException) { + $envelope = $e->getEnvelope(); + } + + $failedEvent = new WorkerMessageFailedEvent($envelope, $transportName, $e); + + $this->dispatchEvent($failedEvent); + $envelope = $failedEvent->getEnvelope(); + + if (!$rejectFirst) { + $receiver->reject($envelope); + } + + continue; + } + + $handledEvent = new WorkerMessageHandledEvent($envelope, $transportName); + $this->dispatchEvent($handledEvent); + $envelope = $handledEvent->getEnvelope(); + + if (null !== $this->logger) { + $message = $envelope->getMessage(); + $context = [ + 'class' => \get_class($message), + ]; + $this->logger->info('{class} was handled successfully (acknowledging to transport).', $context); + } + + $receiver->ack($envelope); + } + + return (bool) $acks; + } + + private function flush(bool $force): bool + { + $unacks = $this->unacks; + + if (!$unacks->count()) { + return false; + } + + $this->unacks = new \SplObjectStorage(); + + foreach ($unacks as $batchHandler) { + [$envelope, $transportName] = $unacks[$batchHandler]; + try { + $this->bus->dispatch($envelope->with(new FlushBatchHandlersStamp($force))); + $envelope = $envelope->withoutAll(NoAutoAckStamp::class); + unset($unacks[$batchHandler], $batchHandler); + } catch (\Throwable $e) { + $this->acks[] = [$transportName, $envelope, $e]; + } + } + + return $this->ack(); + } + + public function stop(): void + { + if (null !== $this->logger) { + $this->logger->info('Stopping worker.', ['transport_names' => $this->metadata->getTransportNames()]); + } + + $this->shouldStop = true; + } + + public function getMetadata(): WorkerMetadata + { + return $this->metadata; + } + + private function dispatchEvent(object $event): void + { + if (null === $this->eventDispatcher) { + return; + } + + $this->eventDispatcher->dispatch($event); + } +} diff --git a/plugins/email/vendor/symfony/messenger/WorkerMetadata.php b/plugins/email/vendor/symfony/messenger/WorkerMetadata.php new file mode 100644 index 0000000..0eaab06 --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/WorkerMetadata.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger; + +/** + * @author Oleg Krasavin + */ +final class WorkerMetadata +{ + private $metadata; + + public function __construct(array $metadata) + { + $this->metadata = $metadata; + } + + public function set(array $newMetadata): void + { + $this->metadata = array_merge($this->metadata, $newMetadata); + } + + /** + * Returns the queue names the worker consumes from, if "--queues" option was used. + * Returns null otherwise. + */ + public function getQueueNames(): ?array + { + return $this->metadata['queueNames'] ?? null; + } + + /** + * Returns an array of unique identifiers for transport receivers the worker consumes from. + */ + public function getTransportNames(): array + { + return $this->metadata['transportNames'] ?? []; + } +} diff --git a/plugins/email/vendor/symfony/messenger/composer.json b/plugins/email/vendor/symfony/messenger/composer.json new file mode 100644 index 0000000..a62537c --- /dev/null +++ b/plugins/email/vendor/symfony/messenger/composer.json @@ -0,0 +1,57 @@ +{ + "name": "symfony/messenger", + "type": "library", + "description": "Helps applications send and receive messages to/from other applications or via message queues", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Samuel Roze", + "email": "samuel.roze@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "psr/log": "^1|^2|^3", + "symfony/amqp-messenger": "^5.1|^6.0", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/doctrine-messenger": "^5.1|^6.0", + "symfony/polyfill-php80": "^1.16", + "symfony/redis-messenger": "^5.1|^6.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/console": "^5.4|^6.0", + "symfony/dependency-injection": "^5.3|^6.0", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/property-access": "^4.4|^5.0|^6.0", + "symfony/routing": "^4.4|^5.0|^6.0", + "symfony/serializer": "^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/stopwatch": "^4.4|^5.0|^6.0", + "symfony/validator": "^4.4|^5.0|^6.0" + }, + "conflict": { + "symfony/event-dispatcher": "<4.4", + "symfony/framework-bundle": "<4.4", + "symfony/http-kernel": "<4.4", + "symfony/serializer": "<5.0" + }, + "suggest": { + "enqueue/messenger-adapter": "For using the php-enqueue library as a transport." + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Messenger\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/plugins/email/vendor/symfony/mime/Address.php b/plugins/email/vendor/symfony/mime/Address.php new file mode 100644 index 0000000..ae83efd --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Address.php @@ -0,0 +1,149 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Egulias\EmailValidator\EmailValidator; +use Egulias\EmailValidator\Validation\MessageIDValidation; +use Egulias\EmailValidator\Validation\RFCValidation; +use Symfony\Component\Mime\Encoder\IdnAddressEncoder; +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Exception\LogicException; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * @author Fabien Potencier + */ +final class Address +{ + /** + * A regex that matches a structure like 'Name '. + * It matches anything between the first < and last > as email address. + * This allows to use a single string to construct an Address, which can be convenient to use in + * config, and allows to have more readable config. + * This does not try to cover all edge cases for address. + */ + private const FROM_STRING_PATTERN = '~(?[^<]*)<(?.*)>[^>]*~'; + + private static $validator; + private static $encoder; + + private $address; + private $name; + + public function __construct(string $address, string $name = '') + { + if (!class_exists(EmailValidator::class)) { + throw new LogicException(sprintf('The "%s" class cannot be used as it needs "%s"; try running "composer require egulias/email-validator".', __CLASS__, EmailValidator::class)); + } + + if (null === self::$validator) { + self::$validator = new EmailValidator(); + } + + $this->address = trim($address); + $this->name = trim(str_replace(["\n", "\r"], '', $name)); + + if (!self::$validator->isValid($this->address, class_exists(MessageIDValidation::class) ? new MessageIDValidation() : new RFCValidation())) { + throw new RfcComplianceException(sprintf('Email "%s" does not comply with addr-spec of RFC 2822.', $address)); + } + } + + public function getAddress(): string + { + return $this->address; + } + + public function getName(): string + { + return $this->name; + } + + public function getEncodedAddress(): string + { + if (null === self::$encoder) { + self::$encoder = new IdnAddressEncoder(); + } + + return self::$encoder->encodeString($this->address); + } + + public function toString(): string + { + return ($n = $this->getEncodedName()) ? $n.' <'.$this->getEncodedAddress().'>' : $this->getEncodedAddress(); + } + + public function getEncodedName(): string + { + if ('' === $this->getName()) { + return ''; + } + + return sprintf('"%s"', preg_replace('/"/u', '\"', $this->getName())); + } + + /** + * @param Address|string $address + */ + public static function create($address): self + { + if ($address instanceof self) { + return $address; + } + + if (!\is_string($address)) { + throw new InvalidArgumentException(sprintf('An address can be an instance of Address or a string ("%s" given).', get_debug_type($address))); + } + + if (false === strpos($address, '<')) { + return new self($address); + } + + if (!preg_match(self::FROM_STRING_PATTERN, $address, $matches)) { + throw new InvalidArgumentException(sprintf('Could not parse "%s" to a "%s" instance.', $address, self::class)); + } + + return new self($matches['addrSpec'], trim($matches['displayName'], ' \'"')); + } + + /** + * @param array $addresses + * + * @return Address[] + */ + public static function createArray(array $addresses): array + { + $addrs = []; + foreach ($addresses as $address) { + $addrs[] = self::create($address); + } + + return $addrs; + } + + /** + * @deprecated since Symfony 5.2, use "create()" instead. + */ + public static function fromString(string $string): self + { + trigger_deprecation('symfony/mime', '5.2', '"%s()" is deprecated, use "%s::create()" instead.', __METHOD__, __CLASS__); + + if (!str_contains($string, '<')) { + return new self($string, ''); + } + + if (!preg_match(self::FROM_STRING_PATTERN, $string, $matches)) { + throw new InvalidArgumentException(sprintf('Could not parse "%s" to a "%s" instance.', $string, self::class)); + } + + return new self($matches['addrSpec'], trim($matches['displayName'], ' \'"')); + } +} diff --git a/plugins/email/vendor/symfony/mime/BodyRendererInterface.php b/plugins/email/vendor/symfony/mime/BodyRendererInterface.php new file mode 100644 index 0000000..d692172 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/BodyRendererInterface.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * @author Fabien Potencier + */ +interface BodyRendererInterface +{ + public function render(Message $message): void; +} diff --git a/plugins/email/vendor/symfony/mime/CHANGELOG.md b/plugins/email/vendor/symfony/mime/CHANGELOG.md new file mode 100644 index 0000000..f272346 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/CHANGELOG.md @@ -0,0 +1,26 @@ +CHANGELOG +========= + +5.2.0 +----- + + * Add support for DKIM + * Deprecated `Address::fromString()`, use `Address::create()` instead + +4.4.0 +----- + + * [BC BREAK] Removed `NamedAddress` (`Address` now supports a name) + * Added PHPUnit constraints + * Added `AbstractPart::asDebugString()` + * Added `Address::fromString()` + +4.3.3 +----- + + * [BC BREAK] Renamed method `Headers::getAll()` to `Headers::all()`. + +4.3.0 +----- + + * Introduced the component as experimental diff --git a/plugins/email/vendor/symfony/mime/CharacterStream.php b/plugins/email/vendor/symfony/mime/CharacterStream.php new file mode 100644 index 0000000..238debd --- /dev/null +++ b/plugins/email/vendor/symfony/mime/CharacterStream.php @@ -0,0 +1,218 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * @author Fabien Potencier + * @author Xavier De Cock + * + * @internal + */ +final class CharacterStream +{ + /** Pre-computed for optimization */ + private const UTF8_LENGTH_MAP = [ + "\x00" => 1, "\x01" => 1, "\x02" => 1, "\x03" => 1, "\x04" => 1, "\x05" => 1, "\x06" => 1, "\x07" => 1, + "\x08" => 1, "\x09" => 1, "\x0a" => 1, "\x0b" => 1, "\x0c" => 1, "\x0d" => 1, "\x0e" => 1, "\x0f" => 1, + "\x10" => 1, "\x11" => 1, "\x12" => 1, "\x13" => 1, "\x14" => 1, "\x15" => 1, "\x16" => 1, "\x17" => 1, + "\x18" => 1, "\x19" => 1, "\x1a" => 1, "\x1b" => 1, "\x1c" => 1, "\x1d" => 1, "\x1e" => 1, "\x1f" => 1, + "\x20" => 1, "\x21" => 1, "\x22" => 1, "\x23" => 1, "\x24" => 1, "\x25" => 1, "\x26" => 1, "\x27" => 1, + "\x28" => 1, "\x29" => 1, "\x2a" => 1, "\x2b" => 1, "\x2c" => 1, "\x2d" => 1, "\x2e" => 1, "\x2f" => 1, + "\x30" => 1, "\x31" => 1, "\x32" => 1, "\x33" => 1, "\x34" => 1, "\x35" => 1, "\x36" => 1, "\x37" => 1, + "\x38" => 1, "\x39" => 1, "\x3a" => 1, "\x3b" => 1, "\x3c" => 1, "\x3d" => 1, "\x3e" => 1, "\x3f" => 1, + "\x40" => 1, "\x41" => 1, "\x42" => 1, "\x43" => 1, "\x44" => 1, "\x45" => 1, "\x46" => 1, "\x47" => 1, + "\x48" => 1, "\x49" => 1, "\x4a" => 1, "\x4b" => 1, "\x4c" => 1, "\x4d" => 1, "\x4e" => 1, "\x4f" => 1, + "\x50" => 1, "\x51" => 1, "\x52" => 1, "\x53" => 1, "\x54" => 1, "\x55" => 1, "\x56" => 1, "\x57" => 1, + "\x58" => 1, "\x59" => 1, "\x5a" => 1, "\x5b" => 1, "\x5c" => 1, "\x5d" => 1, "\x5e" => 1, "\x5f" => 1, + "\x60" => 1, "\x61" => 1, "\x62" => 1, "\x63" => 1, "\x64" => 1, "\x65" => 1, "\x66" => 1, "\x67" => 1, + "\x68" => 1, "\x69" => 1, "\x6a" => 1, "\x6b" => 1, "\x6c" => 1, "\x6d" => 1, "\x6e" => 1, "\x6f" => 1, + "\x70" => 1, "\x71" => 1, "\x72" => 1, "\x73" => 1, "\x74" => 1, "\x75" => 1, "\x76" => 1, "\x77" => 1, + "\x78" => 1, "\x79" => 1, "\x7a" => 1, "\x7b" => 1, "\x7c" => 1, "\x7d" => 1, "\x7e" => 1, "\x7f" => 1, + "\x80" => 0, "\x81" => 0, "\x82" => 0, "\x83" => 0, "\x84" => 0, "\x85" => 0, "\x86" => 0, "\x87" => 0, + "\x88" => 0, "\x89" => 0, "\x8a" => 0, "\x8b" => 0, "\x8c" => 0, "\x8d" => 0, "\x8e" => 0, "\x8f" => 0, + "\x90" => 0, "\x91" => 0, "\x92" => 0, "\x93" => 0, "\x94" => 0, "\x95" => 0, "\x96" => 0, "\x97" => 0, + "\x98" => 0, "\x99" => 0, "\x9a" => 0, "\x9b" => 0, "\x9c" => 0, "\x9d" => 0, "\x9e" => 0, "\x9f" => 0, + "\xa0" => 0, "\xa1" => 0, "\xa2" => 0, "\xa3" => 0, "\xa4" => 0, "\xa5" => 0, "\xa6" => 0, "\xa7" => 0, + "\xa8" => 0, "\xa9" => 0, "\xaa" => 0, "\xab" => 0, "\xac" => 0, "\xad" => 0, "\xae" => 0, "\xaf" => 0, + "\xb0" => 0, "\xb1" => 0, "\xb2" => 0, "\xb3" => 0, "\xb4" => 0, "\xb5" => 0, "\xb6" => 0, "\xb7" => 0, + "\xb8" => 0, "\xb9" => 0, "\xba" => 0, "\xbb" => 0, "\xbc" => 0, "\xbd" => 0, "\xbe" => 0, "\xbf" => 0, + "\xc0" => 2, "\xc1" => 2, "\xc2" => 2, "\xc3" => 2, "\xc4" => 2, "\xc5" => 2, "\xc6" => 2, "\xc7" => 2, + "\xc8" => 2, "\xc9" => 2, "\xca" => 2, "\xcb" => 2, "\xcc" => 2, "\xcd" => 2, "\xce" => 2, "\xcf" => 2, + "\xd0" => 2, "\xd1" => 2, "\xd2" => 2, "\xd3" => 2, "\xd4" => 2, "\xd5" => 2, "\xd6" => 2, "\xd7" => 2, + "\xd8" => 2, "\xd9" => 2, "\xda" => 2, "\xdb" => 2, "\xdc" => 2, "\xdd" => 2, "\xde" => 2, "\xdf" => 2, + "\xe0" => 3, "\xe1" => 3, "\xe2" => 3, "\xe3" => 3, "\xe4" => 3, "\xe5" => 3, "\xe6" => 3, "\xe7" => 3, + "\xe8" => 3, "\xe9" => 3, "\xea" => 3, "\xeb" => 3, "\xec" => 3, "\xed" => 3, "\xee" => 3, "\xef" => 3, + "\xf0" => 4, "\xf1" => 4, "\xf2" => 4, "\xf3" => 4, "\xf4" => 4, "\xf5" => 4, "\xf6" => 4, "\xf7" => 4, + "\xf8" => 5, "\xf9" => 5, "\xfa" => 5, "\xfb" => 5, "\xfc" => 6, "\xfd" => 6, "\xfe" => 0, "\xff" => 0, + ]; + + private $data = ''; + private $dataSize = 0; + private $map = []; + private $charCount = 0; + private $currentPos = 0; + private $fixedWidth = 0; + + /** + * @param resource|string $input + */ + public function __construct($input, ?string $charset = 'utf-8') + { + $charset = strtolower(trim($charset)) ?: 'utf-8'; + if ('utf-8' === $charset || 'utf8' === $charset) { + $this->fixedWidth = 0; + $this->map = ['p' => [], 'i' => []]; + } else { + switch ($charset) { + // 16 bits + case 'ucs2': + case 'ucs-2': + case 'utf16': + case 'utf-16': + $this->fixedWidth = 2; + break; + + // 32 bits + case 'ucs4': + case 'ucs-4': + case 'utf32': + case 'utf-32': + $this->fixedWidth = 4; + break; + + // 7-8 bit charsets: (us-)?ascii, (iso|iec)-?8859-?[0-9]+, windows-?125[0-9], cp-?[0-9]+, ansi, macintosh, + // koi-?7, koi-?8-?.+, mik, (cork|t1), v?iscii + // and fallback + default: + $this->fixedWidth = 1; + } + } + if (\is_resource($input)) { + $blocks = 16372; + while (false !== $read = fread($input, $blocks)) { + $this->write($read); + } + } else { + $this->write($input); + } + } + + public function read(int $length): ?string + { + if ($this->currentPos >= $this->charCount) { + return null; + } + $length = ($this->currentPos + $length > $this->charCount) ? $this->charCount - $this->currentPos : $length; + if ($this->fixedWidth > 0) { + $len = $length * $this->fixedWidth; + $ret = substr($this->data, $this->currentPos * $this->fixedWidth, $len); + $this->currentPos += $length; + } else { + $end = $this->currentPos + $length; + $end = $end > $this->charCount ? $this->charCount : $end; + $ret = ''; + $start = 0; + if ($this->currentPos > 0) { + $start = $this->map['p'][$this->currentPos - 1]; + } + $to = $start; + for (; $this->currentPos < $end; ++$this->currentPos) { + if (isset($this->map['i'][$this->currentPos])) { + $ret .= substr($this->data, $start, $to - $start).'?'; + $start = $this->map['p'][$this->currentPos]; + } else { + $to = $this->map['p'][$this->currentPos]; + } + } + $ret .= substr($this->data, $start, $to - $start); + } + + return $ret; + } + + public function readBytes(int $length): ?array + { + if (null !== $read = $this->read($length)) { + return array_map('ord', str_split($read, 1)); + } + + return null; + } + + public function setPointer(int $charOffset): void + { + if ($this->charCount < $charOffset) { + $charOffset = $this->charCount; + } + $this->currentPos = $charOffset; + } + + public function write(string $chars): void + { + $ignored = ''; + $this->data .= $chars; + if ($this->fixedWidth > 0) { + $strlen = \strlen($chars); + $ignoredL = $strlen % $this->fixedWidth; + $ignored = $ignoredL ? substr($chars, -$ignoredL) : ''; + $this->charCount += ($strlen - $ignoredL) / $this->fixedWidth; + } else { + $this->charCount += $this->getUtf8CharPositions($chars, $this->dataSize, $ignored); + } + $this->dataSize = \strlen($this->data) - \strlen($ignored); + } + + private function getUtf8CharPositions(string $string, int $startOffset, string &$ignoredChars): int + { + $strlen = \strlen($string); + $charPos = \count($this->map['p']); + $foundChars = 0; + $invalid = false; + for ($i = 0; $i < $strlen; ++$i) { + $char = $string[$i]; + $size = self::UTF8_LENGTH_MAP[$char]; + if (0 == $size) { + /* char is invalid, we must wait for a resync */ + $invalid = true; + continue; + } + + if ($invalid) { + /* We mark the chars as invalid and start a new char */ + $this->map['p'][$charPos + $foundChars] = $startOffset + $i; + $this->map['i'][$charPos + $foundChars] = true; + ++$foundChars; + $invalid = false; + } + if (($i + $size) > $strlen) { + $ignoredChars = substr($string, $i); + break; + } + for ($j = 1; $j < $size; ++$j) { + $char = $string[$i + $j]; + if ($char > "\x7F" && $char < "\xC0") { + // Valid - continue parsing + } else { + /* char is invalid, we must wait for a resync */ + $invalid = true; + continue 2; + } + } + /* Ok we got a complete char here */ + $this->map['p'][$charPos + $foundChars] = $startOffset + $i + $size; + $i += $j - 1; + ++$foundChars; + } + + return $foundChars; + } +} diff --git a/plugins/email/vendor/symfony/mime/Crypto/DkimOptions.php b/plugins/email/vendor/symfony/mime/Crypto/DkimOptions.php new file mode 100644 index 0000000..171bb25 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Crypto/DkimOptions.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Crypto; + +/** + * A helper providing autocompletion for available DkimSigner options. + * + * @author Fabien Potencier + */ +final class DkimOptions +{ + private $options = []; + + public function toArray(): array + { + return $this->options; + } + + /** + * @return $this + */ + public function algorithm(string $algo): self + { + $this->options['algorithm'] = $algo; + + return $this; + } + + /** + * @return $this + */ + public function signatureExpirationDelay(int $show): self + { + $this->options['signature_expiration_delay'] = $show; + + return $this; + } + + /** + * @return $this + */ + public function bodyMaxLength(int $max): self + { + $this->options['body_max_length'] = $max; + + return $this; + } + + /** + * @return $this + */ + public function bodyShowLength(bool $show): self + { + $this->options['body_show_length'] = $show; + + return $this; + } + + /** + * @return $this + */ + public function headerCanon(string $canon): self + { + $this->options['header_canon'] = $canon; + + return $this; + } + + /** + * @return $this + */ + public function bodyCanon(string $canon): self + { + $this->options['body_canon'] = $canon; + + return $this; + } + + /** + * @return $this + */ + public function headersToIgnore(array $headers): self + { + $this->options['headers_to_ignore'] = $headers; + + return $this; + } +} diff --git a/plugins/email/vendor/symfony/mime/Crypto/DkimSigner.php b/plugins/email/vendor/symfony/mime/Crypto/DkimSigner.php new file mode 100644 index 0000000..f0f7091 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Crypto/DkimSigner.php @@ -0,0 +1,220 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Crypto; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Exception\RuntimeException; +use Symfony\Component\Mime\Header\UnstructuredHeader; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\Part\AbstractPart; + +/** + * @author Fabien Potencier + * + * RFC 6376 and 8301 + */ +final class DkimSigner +{ + public const CANON_SIMPLE = 'simple'; + public const CANON_RELAXED = 'relaxed'; + + public const ALGO_SHA256 = 'rsa-sha256'; + public const ALGO_ED25519 = 'ed25519-sha256'; // RFC 8463 + + private $key; + private $domainName; + private $selector; + private $defaultOptions; + + /** + * @param string $pk The private key as a string or the path to the file containing the private key, should be prefixed with file:// (in PEM format) + * @param string $passphrase A passphrase of the private key (if any) + */ + public function __construct(string $pk, string $domainName, string $selector, array $defaultOptions = [], string $passphrase = '') + { + if (!\extension_loaded('openssl')) { + throw new \LogicException('PHP extension "openssl" is required to use DKIM.'); + } + if (!$this->key = openssl_pkey_get_private($pk, $passphrase)) { + throw new InvalidArgumentException('Unable to load DKIM private key: '.openssl_error_string()); + } + + $this->domainName = $domainName; + $this->selector = $selector; + $this->defaultOptions = $defaultOptions + [ + 'algorithm' => self::ALGO_SHA256, + 'signature_expiration_delay' => 0, + 'body_max_length' => \PHP_INT_MAX, + 'body_show_length' => false, + 'header_canon' => self::CANON_RELAXED, + 'body_canon' => self::CANON_RELAXED, + 'headers_to_ignore' => [], + ]; + } + + public function sign(Message $message, array $options = []): Message + { + $options += $this->defaultOptions; + if (!\in_array($options['algorithm'], [self::ALGO_SHA256, self::ALGO_ED25519], true)) { + throw new InvalidArgumentException(sprintf('Invalid DKIM signing algorithm "%s".', $options['algorithm'])); + } + $headersToIgnore['return-path'] = true; + $headersToIgnore['x-transport'] = true; + foreach ($options['headers_to_ignore'] as $name) { + $headersToIgnore[strtolower($name)] = true; + } + unset($headersToIgnore['from']); + $signedHeaderNames = []; + $headerCanonData = ''; + $headers = $message->getPreparedHeaders(); + foreach ($headers->getNames() as $name) { + foreach ($headers->all($name) as $header) { + if (isset($headersToIgnore[strtolower($header->getName())])) { + continue; + } + + if ('' !== $header->getBodyAsString()) { + $headerCanonData .= $this->canonicalizeHeader($header->toString(), $options['header_canon']); + $signedHeaderNames[] = $header->getName(); + } + } + } + + [$bodyHash, $bodyLength] = $this->hashBody($message->getBody(), $options['body_canon'], $options['body_max_length']); + + $params = [ + 'v' => '1', + 'q' => 'dns/txt', + 'a' => $options['algorithm'], + 'bh' => base64_encode($bodyHash), + 'd' => $this->domainName, + 'h' => implode(': ', $signedHeaderNames), + 'i' => '@'.$this->domainName, + 's' => $this->selector, + 't' => time(), + 'c' => $options['header_canon'].'/'.$options['body_canon'], + ]; + + if ($options['body_show_length']) { + $params['l'] = $bodyLength; + } + if ($options['signature_expiration_delay']) { + $params['x'] = $params['t'] + $options['signature_expiration_delay']; + } + $value = ''; + foreach ($params as $k => $v) { + $value .= $k.'='.$v.'; '; + } + $value = trim($value); + $header = new UnstructuredHeader('DKIM-Signature', $value); + $headerCanonData .= rtrim($this->canonicalizeHeader($header->toString()."\r\n b=", $options['header_canon'])); + if (self::ALGO_SHA256 === $options['algorithm']) { + if (!openssl_sign($headerCanonData, $signature, $this->key, \OPENSSL_ALGO_SHA256)) { + throw new RuntimeException('Unable to sign DKIM hash: '.openssl_error_string()); + } + } else { + throw new \RuntimeException(sprintf('The "%s" DKIM signing algorithm is not supported yet.', self::ALGO_ED25519)); + } + $header->setValue($value.' b='.trim(chunk_split(base64_encode($signature), 73, ' '))); + $headers->add($header); + + return new Message($headers, $message->getBody()); + } + + private function canonicalizeHeader(string $header, string $headerCanon): string + { + if (self::CANON_RELAXED !== $headerCanon) { + return $header."\r\n"; + } + + $exploded = explode(':', $header, 2); + $name = strtolower(trim($exploded[0])); + $value = str_replace("\r\n", '', $exploded[1]); + $value = trim(preg_replace("/[ \t][ \t]+/", ' ', $value)); + + return $name.':'.$value."\r\n"; + } + + private function hashBody(AbstractPart $body, string $bodyCanon, int $maxLength): array + { + $hash = hash_init('sha256'); + $relaxed = self::CANON_RELAXED === $bodyCanon; + $currentLine = ''; + $emptyCounter = 0; + $isSpaceSequence = false; + $length = 0; + foreach ($body->bodyToIterable() as $chunk) { + $canon = ''; + for ($i = 0, $len = \strlen($chunk); $i < $len; ++$i) { + switch ($chunk[$i]) { + case "\r": + break; + case "\n": + // previous char is always \r + if ($relaxed) { + $isSpaceSequence = false; + } + if ('' === $currentLine) { + ++$emptyCounter; + } else { + $currentLine = ''; + $canon .= "\r\n"; + } + break; + case ' ': + case "\t": + if ($relaxed) { + $isSpaceSequence = true; + break; + } + // no break + default: + if ($emptyCounter > 0) { + $canon .= str_repeat("\r\n", $emptyCounter); + $emptyCounter = 0; + } + if ($isSpaceSequence) { + $currentLine .= ' '; + $canon .= ' '; + $isSpaceSequence = false; + } + $currentLine .= $chunk[$i]; + $canon .= $chunk[$i]; + } + } + + if ($length + \strlen($canon) >= $maxLength) { + $canon = substr($canon, 0, $maxLength - $length); + $length += \strlen($canon); + hash_update($hash, $canon); + + break; + } + + $length += \strlen($canon); + hash_update($hash, $canon); + } + + // Add trailing Line return if last line is non empty + if ('' !== $currentLine) { + hash_update($hash, "\r\n"); + $length += \strlen("\r\n"); + } + + if (!$relaxed && 0 === $length) { + hash_update($hash, "\r\n"); + $length = 2; + } + + return [hash_final($hash, true), $length]; + } +} diff --git a/plugins/email/vendor/symfony/mime/Crypto/SMime.php b/plugins/email/vendor/symfony/mime/Crypto/SMime.php new file mode 100644 index 0000000..cba95f2 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Crypto/SMime.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Crypto; + +use Symfony\Component\Mime\Exception\RuntimeException; +use Symfony\Component\Mime\Part\SMimePart; + +/** + * @author Sebastiaan Stok + * + * @internal + */ +abstract class SMime +{ + protected function normalizeFilePath(string $path): string + { + if (!file_exists($path)) { + throw new RuntimeException(sprintf('File does not exist: "%s".', $path)); + } + + return 'file://'.str_replace('\\', '/', realpath($path)); + } + + protected function iteratorToFile(iterable $iterator, $stream): void + { + foreach ($iterator as $chunk) { + fwrite($stream, $chunk); + } + } + + protected function convertMessageToSMimePart($stream, string $type, string $subtype): SMimePart + { + rewind($stream); + + $headers = ''; + + while (!feof($stream)) { + $buffer = fread($stream, 78); + $headers .= $buffer; + + // Detect ending of header list + if (preg_match('/(\r\n\r\n|\n\n)/', $headers, $match)) { + $headersPosEnd = strpos($headers, $headerBodySeparator = $match[0]); + + break; + } + } + + $headers = $this->getMessageHeaders(trim(substr($headers, 0, $headersPosEnd))); + + fseek($stream, $headersPosEnd + \strlen($headerBodySeparator)); + + return new SMimePart($this->getStreamIterator($stream), $type, $subtype, $this->getParametersFromHeader($headers['content-type'])); + } + + protected function getStreamIterator($stream): iterable + { + while (!feof($stream)) { + yield str_replace("\n", "\r\n", str_replace("\r\n", "\n", fread($stream, 16372))); + } + } + + private function getMessageHeaders(string $headerData): array + { + $headers = []; + $headerLines = explode("\r\n", str_replace("\n", "\r\n", str_replace("\r\n", "\n", $headerData))); + $currentHeaderName = ''; + + // Transform header lines into an associative array + foreach ($headerLines as $headerLine) { + // Empty lines between headers indicate a new mime-entity + if ('' === $headerLine) { + break; + } + + // Handle headers that span multiple lines + if (!str_contains($headerLine, ':')) { + $headers[$currentHeaderName] .= ' '.trim($headerLine); + continue; + } + + $header = explode(':', $headerLine, 2); + $currentHeaderName = strtolower($header[0]); + $headers[$currentHeaderName] = trim($header[1]); + } + + return $headers; + } + + private function getParametersFromHeader(string $header): array + { + $params = []; + + preg_match_all('/(?P[a-z-0-9]+)=(?P"[^"]+"|(?:[^\s;]+|$))(?:\s+;)?/i', $header, $matches); + + foreach ($matches['value'] as $pos => $paramValue) { + $params[$matches['name'][$pos]] = trim($paramValue, '"'); + } + + return $params; + } +} diff --git a/plugins/email/vendor/symfony/mime/Crypto/SMimeEncrypter.php b/plugins/email/vendor/symfony/mime/Crypto/SMimeEncrypter.php new file mode 100644 index 0000000..9081860 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Crypto/SMimeEncrypter.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Crypto; + +use Symfony\Component\Mime\Exception\RuntimeException; +use Symfony\Component\Mime\Message; + +/** + * @author Sebastiaan Stok + */ +final class SMimeEncrypter extends SMime +{ + private $certs; + private $cipher; + + /** + * @param string|string[] $certificate The path (or array of paths) of the file(s) containing the X.509 certificate(s) + * @param int|null $cipher A set of algorithms used to encrypt the message. Must be one of these PHP constants: https://www.php.net/manual/en/openssl.ciphers.php + */ + public function __construct($certificate, int $cipher = null) + { + if (!\extension_loaded('openssl')) { + throw new \LogicException('PHP extension "openssl" is required to use SMime.'); + } + + if (\is_array($certificate)) { + $this->certs = array_map([$this, 'normalizeFilePath'], $certificate); + } else { + $this->certs = $this->normalizeFilePath($certificate); + } + + $this->cipher = $cipher ?? \OPENSSL_CIPHER_AES_256_CBC; + } + + public function encrypt(Message $message): Message + { + $bufferFile = tmpfile(); + $outputFile = tmpfile(); + + $this->iteratorToFile($message->toIterable(), $bufferFile); + + if (!@openssl_pkcs7_encrypt(stream_get_meta_data($bufferFile)['uri'], stream_get_meta_data($outputFile)['uri'], $this->certs, [], 0, $this->cipher)) { + throw new RuntimeException(sprintf('Failed to encrypt S/Mime message. Error: "%s".', openssl_error_string())); + } + + $mimePart = $this->convertMessageToSMimePart($outputFile, 'application', 'pkcs7-mime'); + $mimePart->getHeaders() + ->addTextHeader('Content-Transfer-Encoding', 'base64') + ->addParameterizedHeader('Content-Disposition', 'attachment', ['name' => 'smime.p7m']) + ; + + return new Message($message->getHeaders(), $mimePart); + } +} diff --git a/plugins/email/vendor/symfony/mime/Crypto/SMimeSigner.php b/plugins/email/vendor/symfony/mime/Crypto/SMimeSigner.php new file mode 100644 index 0000000..5b94a45 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Crypto/SMimeSigner.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Crypto; + +use Symfony\Component\Mime\Exception\RuntimeException; +use Symfony\Component\Mime\Message; + +/** + * @author Sebastiaan Stok + */ +final class SMimeSigner extends SMime +{ + private $signCertificate; + private $signPrivateKey; + private $signOptions; + private $extraCerts; + + /** + * @param string $certificate The path of the file containing the signing certificate (in PEM format) + * @param string $privateKey The path of the file containing the private key (in PEM format) + * @param string|null $privateKeyPassphrase A passphrase of the private key (if any) + * @param string|null $extraCerts The path of the file containing intermediate certificates (in PEM format) needed by the signing certificate + * @param int|null $signOptions Bitwise operator options for openssl_pkcs7_sign() (@see https://secure.php.net/manual/en/openssl.pkcs7.flags.php) + */ + public function __construct(string $certificate, string $privateKey, string $privateKeyPassphrase = null, string $extraCerts = null, int $signOptions = null) + { + if (!\extension_loaded('openssl')) { + throw new \LogicException('PHP extension "openssl" is required to use SMime.'); + } + + $this->signCertificate = $this->normalizeFilePath($certificate); + + if (null !== $privateKeyPassphrase) { + $this->signPrivateKey = [$this->normalizeFilePath($privateKey), $privateKeyPassphrase]; + } else { + $this->signPrivateKey = $this->normalizeFilePath($privateKey); + } + + $this->signOptions = $signOptions ?? \PKCS7_DETACHED; + $this->extraCerts = $extraCerts ? realpath($extraCerts) : null; + } + + public function sign(Message $message): Message + { + $bufferFile = tmpfile(); + $outputFile = tmpfile(); + + $this->iteratorToFile($message->getBody()->toIterable(), $bufferFile); + + if (!@openssl_pkcs7_sign(stream_get_meta_data($bufferFile)['uri'], stream_get_meta_data($outputFile)['uri'], $this->signCertificate, $this->signPrivateKey, [], $this->signOptions, $this->extraCerts)) { + throw new RuntimeException(sprintf('Failed to sign S/Mime message. Error: "%s".', openssl_error_string())); + } + + return new Message($message->getHeaders(), $this->convertMessageToSMimePart($outputFile, 'multipart', 'signed')); + } +} diff --git a/plugins/email/vendor/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php b/plugins/email/vendor/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php new file mode 100644 index 0000000..00eef94 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\DependencyInjection; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Registers custom mime types guessers. + * + * @author Fabien Potencier + */ +class AddMimeTypeGuesserPass implements CompilerPassInterface +{ + private $mimeTypesService; + private $mimeTypeGuesserTag; + + public function __construct(string $mimeTypesService = 'mime_types', string $mimeTypeGuesserTag = 'mime.mime_type_guesser') + { + if (0 < \func_num_args()) { + trigger_deprecation('symfony/mime', '5.3', 'Configuring "%s" is deprecated.', __CLASS__); + } + + $this->mimeTypesService = $mimeTypesService; + $this->mimeTypeGuesserTag = $mimeTypeGuesserTag; + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + if ($container->has($this->mimeTypesService)) { + $definition = $container->findDefinition($this->mimeTypesService); + foreach ($container->findTaggedServiceIds($this->mimeTypeGuesserTag, true) as $id => $attributes) { + $definition->addMethodCall('registerGuesser', [new Reference($id)]); + } + } + } +} diff --git a/plugins/email/vendor/symfony/mime/Email.php b/plugins/email/vendor/symfony/mime/Email.php new file mode 100644 index 0000000..bd0a476 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Email.php @@ -0,0 +1,630 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\LogicException; +use Symfony\Component\Mime\Part\AbstractPart; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\Multipart\AlternativePart; +use Symfony\Component\Mime\Part\Multipart\MixedPart; +use Symfony\Component\Mime\Part\Multipart\RelatedPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * @author Fabien Potencier + */ +class Email extends Message +{ + public const PRIORITY_HIGHEST = 1; + public const PRIORITY_HIGH = 2; + public const PRIORITY_NORMAL = 3; + public const PRIORITY_LOW = 4; + public const PRIORITY_LOWEST = 5; + + private const PRIORITY_MAP = [ + self::PRIORITY_HIGHEST => 'Highest', + self::PRIORITY_HIGH => 'High', + self::PRIORITY_NORMAL => 'Normal', + self::PRIORITY_LOW => 'Low', + self::PRIORITY_LOWEST => 'Lowest', + ]; + + private $text; + private $textCharset; + private $html; + private $htmlCharset; + private $attachments = []; + /** + * @var AbstractPart|null + */ + private $cachedBody; // Used to avoid wrong body hash in DKIM signatures with multiple parts (e.g. HTML + TEXT) due to multiple boundaries. + + /** + * @return $this + */ + public function subject(string $subject) + { + return $this->setHeaderBody('Text', 'Subject', $subject); + } + + public function getSubject(): ?string + { + return $this->getHeaders()->getHeaderBody('Subject'); + } + + /** + * @return $this + */ + public function date(\DateTimeInterface $dateTime) + { + return $this->setHeaderBody('Date', 'Date', $dateTime); + } + + public function getDate(): ?\DateTimeImmutable + { + return $this->getHeaders()->getHeaderBody('Date'); + } + + /** + * @param Address|string $address + * + * @return $this + */ + public function returnPath($address) + { + return $this->setHeaderBody('Path', 'Return-Path', Address::create($address)); + } + + public function getReturnPath(): ?Address + { + return $this->getHeaders()->getHeaderBody('Return-Path'); + } + + /** + * @param Address|string $address + * + * @return $this + */ + public function sender($address) + { + return $this->setHeaderBody('Mailbox', 'Sender', Address::create($address)); + } + + public function getSender(): ?Address + { + return $this->getHeaders()->getHeaderBody('Sender'); + } + + /** + * @param Address|string ...$addresses + * + * @return $this + */ + public function addFrom(...$addresses) + { + return $this->addListAddressHeaderBody('From', $addresses); + } + + /** + * @param Address|string ...$addresses + * + * @return $this + */ + public function from(...$addresses) + { + return $this->setListAddressHeaderBody('From', $addresses); + } + + /** + * @return Address[] + */ + public function getFrom(): array + { + return $this->getHeaders()->getHeaderBody('From') ?: []; + } + + /** + * @param Address|string ...$addresses + * + * @return $this + */ + public function addReplyTo(...$addresses) + { + return $this->addListAddressHeaderBody('Reply-To', $addresses); + } + + /** + * @param Address|string ...$addresses + * + * @return $this + */ + public function replyTo(...$addresses) + { + return $this->setListAddressHeaderBody('Reply-To', $addresses); + } + + /** + * @return Address[] + */ + public function getReplyTo(): array + { + return $this->getHeaders()->getHeaderBody('Reply-To') ?: []; + } + + /** + * @param Address|string ...$addresses + * + * @return $this + */ + public function addTo(...$addresses) + { + return $this->addListAddressHeaderBody('To', $addresses); + } + + /** + * @param Address|string ...$addresses + * + * @return $this + */ + public function to(...$addresses) + { + return $this->setListAddressHeaderBody('To', $addresses); + } + + /** + * @return Address[] + */ + public function getTo(): array + { + return $this->getHeaders()->getHeaderBody('To') ?: []; + } + + /** + * @param Address|string ...$addresses + * + * @return $this + */ + public function addCc(...$addresses) + { + return $this->addListAddressHeaderBody('Cc', $addresses); + } + + /** + * @param Address|string ...$addresses + * + * @return $this + */ + public function cc(...$addresses) + { + return $this->setListAddressHeaderBody('Cc', $addresses); + } + + /** + * @return Address[] + */ + public function getCc(): array + { + return $this->getHeaders()->getHeaderBody('Cc') ?: []; + } + + /** + * @param Address|string ...$addresses + * + * @return $this + */ + public function addBcc(...$addresses) + { + return $this->addListAddressHeaderBody('Bcc', $addresses); + } + + /** + * @param Address|string ...$addresses + * + * @return $this + */ + public function bcc(...$addresses) + { + return $this->setListAddressHeaderBody('Bcc', $addresses); + } + + /** + * @return Address[] + */ + public function getBcc(): array + { + return $this->getHeaders()->getHeaderBody('Bcc') ?: []; + } + + /** + * Sets the priority of this message. + * + * The value is an integer where 1 is the highest priority and 5 is the lowest. + * + * @return $this + */ + public function priority(int $priority) + { + if ($priority > 5) { + $priority = 5; + } elseif ($priority < 1) { + $priority = 1; + } + + return $this->setHeaderBody('Text', 'X-Priority', sprintf('%d (%s)', $priority, self::PRIORITY_MAP[$priority])); + } + + /** + * Get the priority of this message. + * + * The returned value is an integer where 1 is the highest priority and 5 + * is the lowest. + */ + public function getPriority(): int + { + [$priority] = sscanf($this->getHeaders()->getHeaderBody('X-Priority') ?? '', '%[1-5]'); + + return $priority ?? 3; + } + + /** + * @param resource|string|null $body + * + * @return $this + */ + public function text($body, string $charset = 'utf-8') + { + if (null !== $body && !\is_string($body) && !\is_resource($body)) { + throw new \TypeError(sprintf('The body must be a string, a resource or null (got "%s").', get_debug_type($body))); + } + + $this->cachedBody = null; + $this->text = $body; + $this->textCharset = $charset; + + return $this; + } + + /** + * @return resource|string|null + */ + public function getTextBody() + { + return $this->text; + } + + public function getTextCharset(): ?string + { + return $this->textCharset; + } + + /** + * @param resource|string|null $body + * + * @return $this + */ + public function html($body, string $charset = 'utf-8') + { + if (null !== $body && !\is_string($body) && !\is_resource($body)) { + throw new \TypeError(sprintf('The body must be a string, a resource or null (got "%s").', get_debug_type($body))); + } + + $this->cachedBody = null; + $this->html = $body; + $this->htmlCharset = $charset; + + return $this; + } + + /** + * @return resource|string|null + */ + public function getHtmlBody() + { + return $this->html; + } + + public function getHtmlCharset(): ?string + { + return $this->htmlCharset; + } + + /** + * @param resource|string $body + * + * @return $this + */ + public function attach($body, string $name = null, string $contentType = null) + { + if (!\is_string($body) && !\is_resource($body)) { + throw new \TypeError(sprintf('The body must be a string or a resource (got "%s").', get_debug_type($body))); + } + + $this->cachedBody = null; + $this->attachments[] = ['body' => $body, 'name' => $name, 'content-type' => $contentType, 'inline' => false]; + + return $this; + } + + /** + * @return $this + */ + public function attachFromPath(string $path, string $name = null, string $contentType = null) + { + $this->cachedBody = null; + $this->attachments[] = ['path' => $path, 'name' => $name, 'content-type' => $contentType, 'inline' => false]; + + return $this; + } + + /** + * @param resource|string $body + * + * @return $this + */ + public function embed($body, string $name = null, string $contentType = null) + { + if (!\is_string($body) && !\is_resource($body)) { + throw new \TypeError(sprintf('The body must be a string or a resource (got "%s").', get_debug_type($body))); + } + + $this->cachedBody = null; + $this->attachments[] = ['body' => $body, 'name' => $name, 'content-type' => $contentType, 'inline' => true]; + + return $this; + } + + /** + * @return $this + */ + public function embedFromPath(string $path, string $name = null, string $contentType = null) + { + $this->cachedBody = null; + $this->attachments[] = ['path' => $path, 'name' => $name, 'content-type' => $contentType, 'inline' => true]; + + return $this; + } + + /** + * @return $this + */ + public function attachPart(DataPart $part) + { + $this->cachedBody = null; + $this->attachments[] = ['part' => $part]; + + return $this; + } + + /** + * @return array|DataPart[] + */ + public function getAttachments(): array + { + $parts = []; + foreach ($this->attachments as $attachment) { + $parts[] = $this->createDataPart($attachment); + } + + return $parts; + } + + public function getBody(): AbstractPart + { + if (null !== $body = parent::getBody()) { + return $body; + } + + return $this->generateBody(); + } + + public function ensureValidity() + { + if (null === $this->text && null === $this->html && !$this->attachments) { + throw new LogicException('A message must have a text or an HTML part or attachments.'); + } + + parent::ensureValidity(); + } + + /** + * Generates an AbstractPart based on the raw body of a message. + * + * The most "complex" part generated by this method is when there is text and HTML bodies + * with related images for the HTML part and some attachments: + * + * multipart/mixed + * | + * |------------> multipart/related + * | | + * | |------------> multipart/alternative + * | | | + * | | ------------> text/plain (with content) + * | | | + * | | ------------> text/html (with content) + * | | + * | ------------> image/png (with content) + * | + * ------------> application/pdf (with content) + */ + private function generateBody(): AbstractPart + { + if (null !== $this->cachedBody) { + return $this->cachedBody; + } + + $this->ensureValidity(); + + [$htmlPart, $otherParts, $relatedParts] = $this->prepareParts(); + + $part = null === $this->text ? null : new TextPart($this->text, $this->textCharset); + if (null !== $htmlPart) { + if (null !== $part) { + $part = new AlternativePart($part, $htmlPart); + } else { + $part = $htmlPart; + } + } + + if ($relatedParts) { + $part = new RelatedPart($part, ...$relatedParts); + } + + if ($otherParts) { + if ($part) { + $part = new MixedPart($part, ...$otherParts); + } else { + $part = new MixedPart(...$otherParts); + } + } + + return $this->cachedBody = $part; + } + + private function prepareParts(): ?array + { + $names = []; + $htmlPart = null; + $html = $this->html; + if (null !== $html) { + $htmlPart = new TextPart($html, $this->htmlCharset, 'html'); + $html = $htmlPart->getBody(); + preg_match_all('(]*src\s*=\s*(?:([\'"])cid:(.+?)\\1|cid:([^>\s]+)))i', $html, $names); + $names = array_filter(array_unique(array_merge($names[2], $names[3]))); + } + + // usage of reflection is a temporary workaround for missing getters that will be added in 6.2 + $nameRef = new \ReflectionProperty(TextPart::class, 'name'); + $nameRef->setAccessible(true); + $otherParts = $relatedParts = []; + foreach ($this->attachments as $attachment) { + $part = $this->createDataPart($attachment); + if (isset($attachment['part'])) { + $attachment['name'] = $nameRef->getValue($part); + } + + $related = false; + foreach ($names as $name) { + if ($name !== $attachment['name']) { + continue; + } + if (isset($relatedParts[$name])) { + continue 2; + } + $part->setDisposition('inline'); + $html = str_replace('cid:'.$name, 'cid:'.$part->getContentId(), $html, $count); + if ($count) { + $related = true; + } + $part->setName($part->getContentId()); + + break; + } + + if ($related) { + $relatedParts[$attachment['name']] = $part; + } else { + $otherParts[] = $part; + } + } + if (null !== $htmlPart) { + $htmlPart = new TextPart($html, $this->htmlCharset, 'html'); + } + + return [$htmlPart, $otherParts, array_values($relatedParts)]; + } + + private function createDataPart(array $attachment): DataPart + { + if (isset($attachment['part'])) { + return $attachment['part']; + } + + if (isset($attachment['body'])) { + $part = new DataPart($attachment['body'], $attachment['name'] ?? null, $attachment['content-type'] ?? null); + } else { + $part = DataPart::fromPath($attachment['path'] ?? '', $attachment['name'] ?? null, $attachment['content-type'] ?? null); + } + if ($attachment['inline']) { + $part->asInline(); + } + + return $part; + } + + /** + * @return $this + */ + private function setHeaderBody(string $type, string $name, $body): object + { + $this->getHeaders()->setHeaderBody($type, $name, $body); + + return $this; + } + + private function addListAddressHeaderBody(string $name, array $addresses) + { + if (!$header = $this->getHeaders()->get($name)) { + return $this->setListAddressHeaderBody($name, $addresses); + } + $header->addAddresses(Address::createArray($addresses)); + + return $this; + } + + /** + * @return $this + */ + private function setListAddressHeaderBody(string $name, array $addresses) + { + $addresses = Address::createArray($addresses); + $headers = $this->getHeaders(); + if ($header = $headers->get($name)) { + $header->setAddresses($addresses); + } else { + $headers->addMailboxListHeader($name, $addresses); + } + + return $this; + } + + /** + * @internal + */ + public function __serialize(): array + { + if (\is_resource($this->text)) { + $this->text = (new TextPart($this->text))->getBody(); + } + + if (\is_resource($this->html)) { + $this->html = (new TextPart($this->html))->getBody(); + } + + foreach ($this->attachments as $i => $attachment) { + if (isset($attachment['body']) && \is_resource($attachment['body'])) { + $this->attachments[$i]['body'] = (new TextPart($attachment['body']))->getBody(); + } + } + + return [$this->text, $this->textCharset, $this->html, $this->htmlCharset, $this->attachments, parent::__serialize()]; + } + + /** + * @internal + */ + public function __unserialize(array $data): void + { + [$this->text, $this->textCharset, $this->html, $this->htmlCharset, $this->attachments, $parentData] = $data; + + parent::__unserialize($parentData); + } +} diff --git a/plugins/email/vendor/symfony/mime/Encoder/AddressEncoderInterface.php b/plugins/email/vendor/symfony/mime/Encoder/AddressEncoderInterface.php new file mode 100644 index 0000000..de477d8 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Encoder/AddressEncoderInterface.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\Exception\AddressEncoderException; + +/** + * @author Christian Schmidt + */ +interface AddressEncoderInterface +{ + /** + * Encodes an email address. + * + * @throws AddressEncoderException if the email cannot be represented in + * the encoding implemented by this class + */ + public function encodeString(string $address): string; +} diff --git a/plugins/email/vendor/symfony/mime/Encoder/Base64ContentEncoder.php b/plugins/email/vendor/symfony/mime/Encoder/Base64ContentEncoder.php new file mode 100644 index 0000000..440868a --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Encoder/Base64ContentEncoder.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\Exception\RuntimeException; + +/** + * @author Fabien Potencier + */ +final class Base64ContentEncoder extends Base64Encoder implements ContentEncoderInterface +{ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable + { + if (!\is_resource($stream)) { + throw new \TypeError(sprintf('Method "%s" takes a stream as a first argument.', __METHOD__)); + } + + $filter = stream_filter_append($stream, 'convert.base64-encode', \STREAM_FILTER_READ, [ + 'line-length' => 0 >= $maxLineLength || 76 < $maxLineLength ? 76 : $maxLineLength, + 'line-break-chars' => "\r\n", + ]); + if (!\is_resource($filter)) { + throw new RuntimeException('Unable to set the base64 content encoder to the filter.'); + } + + while (!feof($stream)) { + yield fread($stream, 16372); + } + stream_filter_remove($filter); + } + + public function getName(): string + { + return 'base64'; + } +} diff --git a/plugins/email/vendor/symfony/mime/Encoder/Base64Encoder.php b/plugins/email/vendor/symfony/mime/Encoder/Base64Encoder.php new file mode 100644 index 0000000..7106478 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Encoder/Base64Encoder.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + */ +class Base64Encoder implements EncoderInterface +{ + /** + * Takes an unencoded string and produces a Base64 encoded string from it. + * + * Base64 encoded strings have a maximum line length of 76 characters. + * If the first line needs to be shorter, indicate the difference with + * $firstLineOffset. + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + if (0 >= $maxLineLength || 76 < $maxLineLength) { + $maxLineLength = 76; + } + + $encodedString = base64_encode($string); + $firstLine = ''; + if (0 !== $firstLineOffset) { + $firstLine = substr($encodedString, 0, $maxLineLength - $firstLineOffset)."\r\n"; + $encodedString = substr($encodedString, $maxLineLength - $firstLineOffset); + } + + return $firstLine.trim(chunk_split($encodedString, $maxLineLength, "\r\n")); + } +} diff --git a/plugins/email/vendor/symfony/mime/Encoder/Base64MimeHeaderEncoder.php b/plugins/email/vendor/symfony/mime/Encoder/Base64MimeHeaderEncoder.php new file mode 100644 index 0000000..5c06f6d --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Encoder/Base64MimeHeaderEncoder.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + */ +final class Base64MimeHeaderEncoder extends Base64Encoder implements MimeHeaderEncoderInterface +{ + public function getName(): string + { + return 'B'; + } + + /** + * Takes an unencoded string and produces a Base64 encoded string from it. + * + * If the charset is iso-2022-jp, it uses mb_encode_mimeheader instead of + * default encodeString, otherwise pass to the parent method. + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + if ('iso-2022-jp' === strtolower($charset)) { + $old = mb_internal_encoding(); + mb_internal_encoding('utf-8'); + $newstring = mb_encode_mimeheader($string, 'iso-2022-jp', $this->getName(), "\r\n"); + mb_internal_encoding($old); + + return $newstring; + } + + return parent::encodeString($string, $charset, $firstLineOffset, $maxLineLength); + } +} diff --git a/plugins/email/vendor/symfony/mime/Encoder/ContentEncoderInterface.php b/plugins/email/vendor/symfony/mime/Encoder/ContentEncoderInterface.php new file mode 100644 index 0000000..a45ad04 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Encoder/ContentEncoderInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + */ +interface ContentEncoderInterface extends EncoderInterface +{ + /** + * Encodes the stream to a Generator. + * + * @param resource $stream + */ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable; + + /** + * Gets the MIME name of this content encoding scheme. + */ + public function getName(): string; +} diff --git a/plugins/email/vendor/symfony/mime/Encoder/EightBitContentEncoder.php b/plugins/email/vendor/symfony/mime/Encoder/EightBitContentEncoder.php new file mode 100644 index 0000000..8283120 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Encoder/EightBitContentEncoder.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Fabien Potencier + */ +final class EightBitContentEncoder implements ContentEncoderInterface +{ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable + { + while (!feof($stream)) { + yield fread($stream, 16372); + } + } + + public function getName(): string + { + return '8bit'; + } + + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + return $string; + } +} diff --git a/plugins/email/vendor/symfony/mime/Encoder/EncoderInterface.php b/plugins/email/vendor/symfony/mime/Encoder/EncoderInterface.php new file mode 100644 index 0000000..bbf6d48 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Encoder/EncoderInterface.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + */ +interface EncoderInterface +{ + /** + * Encode a given string to produce an encoded string. + * + * @param int $firstLineOffset if first line needs to be shorter + * @param int $maxLineLength - 0 indicates the default length for this encoding + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string; +} diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoder/IdnAddressEncoder.php b/plugins/email/vendor/symfony/mime/Encoder/IdnAddressEncoder.php similarity index 50% rename from plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoder/IdnAddressEncoder.php rename to plugins/email/vendor/symfony/mime/Encoder/IdnAddressEncoder.php index a373ef9..b56e7e3 100644 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoder/IdnAddressEncoder.php +++ b/plugins/email/vendor/symfony/mime/Encoder/IdnAddressEncoder.php @@ -1,33 +1,31 @@ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +namespace Symfony\Component\Mime\Encoder; + /** * An IDN email address encoder. * * Encodes the domain part of an address using IDN. This is compatible will all * SMTP servers. * - * This encoder does not support email addresses with non-ASCII characters in - * local-part (the substring before @). To send to such addresses, use - * Swift_AddressEncoder_Utf8AddressEncoder together with - * Swift_Transport_Esmtp_SmtpUtf8Handler. Your outbound SMTP server must support - * the SMTPUTF8 extension. + * Note: It leaves the local part as is. In case there are non-ASCII characters + * in the local part then it depends on the SMTP Server if this is supported. * * @author Christian Schmidt */ -class Swift_AddressEncoder_IdnAddressEncoder implements Swift_AddressEncoder +final class IdnAddressEncoder implements AddressEncoderInterface { /** * Encodes the domain part of an address using IDN. - * - * @throws Swift_AddressEncoderException If local-part contains non-ASCII characters */ public function encodeString(string $address): string { @@ -36,12 +34,8 @@ class Swift_AddressEncoder_IdnAddressEncoder implements Swift_AddressEncoder $local = substr($address, 0, $i); $domain = substr($address, $i + 1); - if (preg_match('/[^\x00-\x7F]/', $local)) { - throw new Swift_AddressEncoderException('Non-ASCII characters not supported in local-part', $address); - } - if (preg_match('/[^\x00-\x7F]/', $domain)) { - $address = sprintf('%s@%s', $local, idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46)); + $address = sprintf('%s@%s', $local, idn_to_ascii($domain, \IDNA_DEFAULT | \IDNA_USE_STD3_RULES | \IDNA_CHECK_BIDI | \IDNA_CHECK_CONTEXTJ | \IDNA_NONTRANSITIONAL_TO_ASCII, \INTL_IDNA_VARIANT_UTS46)); } } diff --git a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder.php b/plugins/email/vendor/symfony/mime/Encoder/MimeHeaderEncoderInterface.php similarity index 52% rename from plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder.php rename to plugins/email/vendor/symfony/mime/Encoder/MimeHeaderEncoderInterface.php index 08fd453..fff2c78 100644 --- a/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder.php +++ b/plugins/email/vendor/symfony/mime/Encoder/MimeHeaderEncoderInterface.php @@ -1,24 +1,23 @@ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +namespace Symfony\Component\Mime\Encoder; + /** - * Interface for all Header Encoding schemes. - * * @author Chris Corbyn */ -interface Swift_Mime_HeaderEncoder extends Swift_Encoder +interface MimeHeaderEncoderInterface { /** * Get the MIME name of this content encoding scheme. - * - * @return string */ - public function getName(); + public function getName(): string; } diff --git a/plugins/email/vendor/symfony/mime/Encoder/QpContentEncoder.php b/plugins/email/vendor/symfony/mime/Encoder/QpContentEncoder.php new file mode 100644 index 0000000..4703cc2 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Encoder/QpContentEncoder.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Lars Strojny + */ +final class QpContentEncoder implements ContentEncoderInterface +{ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable + { + if (!\is_resource($stream)) { + throw new \TypeError(sprintf('Method "%s" takes a stream as a first argument.', __METHOD__)); + } + + // we don't use PHP stream filters here as the content should be small enough + yield $this->encodeString(stream_get_contents($stream), 'utf-8', 0, $maxLineLength); + } + + public function getName(): string + { + return 'quoted-printable'; + } + + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + return $this->standardize(quoted_printable_encode($string)); + } + + /** + * Make sure CRLF is correct and HT/SPACE are in valid places. + */ + private function standardize(string $string): string + { + // transform CR or LF to CRLF + $string = preg_replace('~=0D(?!=0A)|(? * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\CharacterStream; + /** - * Handles Quoted Printable (QP) Encoding in Swift Mailer. - * - * Possibly the most accurate RFC 2045 QP implementation found in PHP. - * - * @author Chris Corbyn + * @author Chris Corbyn */ -class Swift_Encoder_QpEncoder implements Swift_Encoder +class QpEncoder implements EncoderInterface { - /** - * The CharacterStream used for reading characters (as opposed to bytes). - * - * @var Swift_CharacterStream - */ - protected $charStream; - - /** - * A filter used if input should be canonicalized. - * - * @var Swift_StreamFilter - */ - protected $filter; - /** * Pre-computed QP for HUGE optimization. - * - * @var string[] */ - protected static $qpMap = [ + private const QP_MAP = [ 0 => '=00', 1 => '=01', 2 => '=02', 3 => '=03', 4 => '=04', 5 => '=05', 6 => '=06', 7 => '=07', 8 => '=08', 9 => '=09', 10 => '=0A', 11 => '=0B', 12 => '=0C', 13 => '=0D', 14 => '=0E', @@ -89,77 +74,47 @@ class Swift_Encoder_QpEncoder implements Swift_Encoder 245 => '=F5', 246 => '=F6', 247 => '=F7', 248 => '=F8', 249 => '=F9', 250 => '=FA', 251 => '=FB', 252 => '=FC', 253 => '=FD', 254 => '=FE', 255 => '=FF', - ]; + ]; - protected static $safeMapShare = []; + private static $safeMapShare = []; /** * A map of non-encoded ascii characters. * * @var string[] + * + * @internal */ protected $safeMap = []; - /** - * Creates a new QpEncoder for the given CharacterStream. - * - * @param Swift_CharacterStream $charStream to use for reading characters - * @param Swift_StreamFilter $filter if input should be canonicalized - */ - public function __construct(Swift_CharacterStream $charStream, Swift_StreamFilter $filter = null) + public function __construct() { - $this->charStream = $charStream; - if (!isset(self::$safeMapShare[$this->getSafeMapShareId()])) { + $id = static::class; + if (!isset(self::$safeMapShare[$id])) { $this->initSafeMap(); - self::$safeMapShare[$this->getSafeMapShareId()] = $this->safeMap; + self::$safeMapShare[$id] = $this->safeMap; } else { - $this->safeMap = self::$safeMapShare[$this->getSafeMapShareId()]; - } - $this->filter = $filter; - } - - public function __sleep() - { - return ['charStream', 'filter']; - } - - public function __wakeup() - { - if (!isset(self::$safeMapShare[$this->getSafeMapShareId()])) { - $this->initSafeMap(); - self::$safeMapShare[$this->getSafeMapShareId()] = $this->safeMap; - } else { - $this->safeMap = self::$safeMapShare[$this->getSafeMapShareId()]; + $this->safeMap = self::$safeMapShare[$id]; } } - protected function getSafeMapShareId() + protected function initSafeMap(): void { - return static::class; - } - - protected function initSafeMap() - { - foreach (array_merge( - [0x09, 0x20], range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte) { + foreach (array_merge([0x09, 0x20], range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte) { $this->safeMap[$byte] = \chr($byte); } } /** + * {@inheritdoc} + * * Takes an unencoded string and produces a QP encoded string from it. * * QP encoded strings have a maximum line length of 76 characters. * If the first line needs to be shorter, indicate the difference with * $firstLineOffset. - * - * @param string $string to encode - * @param int $firstLineOffset optional - * @param int $maxLineLength optional 0 indicates the default of 76 chars - * - * @return string */ - public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string { if ($maxLineLength > 76 || $maxLineLength <= 0) { $maxLineLength = 76; @@ -172,31 +127,12 @@ class Swift_Encoder_QpEncoder implements Swift_Encoder $lines[$lNo] = ''; $currentLine = &$lines[$lNo++]; $size = $lineLen = 0; - - $this->charStream->flushContents(); - $this->charStream->importString($string); + $charStream = new CharacterStream($string, $charset); // Fetching more than 4 chars at one is slower, as is fetching fewer bytes // Conveniently 4 chars is the UTF-8 safe number since UTF-8 has up to 6 // bytes per char and (6 * 4 * 3 = 72 chars per line) * =NN is 3 bytes - while (false !== $bytes = $this->nextSequence()) { - // If we're filtering the input - if (isset($this->filter)) { - // If we can't filter because we need more bytes - while ($this->filter->shouldBuffer($bytes)) { - // Then collect bytes into the buffer - if (false === $moreBytes = $this->nextSequence(1)) { - break; - } - - foreach ($moreBytes as $b) { - $bytes[] = $b; - } - } - // And filter them - $bytes = $this->filter->filter($bytes); - } - + while (null !== $bytes = $charStream->readBytes(4)) { $enc = $this->encodeByteSequence($bytes, $size); $i = strpos($enc, '=0D=0A'); @@ -222,25 +158,10 @@ class Swift_Encoder_QpEncoder implements Swift_Encoder return $this->standardize(implode("=\r\n", $lines)); } - /** - * Updates the charset used. - * - * @param string $charset - */ - public function charsetChanged($charset) - { - $this->charStream->setCharacterSet($charset); - } - /** * Encode the given byte array into a verbatim QP form. - * - * @param int[] $bytes - * @param int $size - * - * @return string */ - protected function encodeByteSequence(array $bytes, &$size) + private function encodeByteSequence(array $bytes, int &$size): string { $ret = ''; $size = 0; @@ -249,7 +170,7 @@ class Swift_Encoder_QpEncoder implements Swift_Encoder $ret .= $this->safeMap[$b]; ++$size; } else { - $ret .= self::$qpMap[$b]; + $ret .= self::QP_MAP[$b]; $size += 3; } } @@ -257,44 +178,18 @@ class Swift_Encoder_QpEncoder implements Swift_Encoder return $ret; } - /** - * Get the next sequence of bytes to read from the char stream. - * - * @param int $size number of bytes to read - * - * @return int[] - */ - protected function nextSequence($size = 4) - { - return $this->charStream->readBytes($size); - } - /** * Make sure CRLF is correct and HT/SPACE are in valid places. - * - * @param string $string - * - * @return string */ - protected function standardize($string) + private function standardize(string $string): string { - $string = str_replace(["\t=0D=0A", ' =0D=0A', '=0D=0A'], - ["=09\r\n", "=20\r\n", "\r\n"], $string - ); + $string = str_replace(["\t=0D=0A", ' =0D=0A', '=0D=0A'], ["=09\r\n", "=20\r\n", "\r\n"], $string); switch ($end = \ord(substr($string, -1))) { case 0x09: case 0x20: - $string = substr_replace($string, self::$qpMap[$end], -1); + $string = substr_replace($string, self::QP_MAP[$end], -1); } return $string; } - - /** - * Make a deep copy of object. - */ - public function __clone() - { - $this->charStream = clone $this->charStream; - } } diff --git a/plugins/email/vendor/symfony/mime/Encoder/QpMimeHeaderEncoder.php b/plugins/email/vendor/symfony/mime/Encoder/QpMimeHeaderEncoder.php new file mode 100644 index 0000000..d1d3837 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Encoder/QpMimeHeaderEncoder.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + */ +final class QpMimeHeaderEncoder extends QpEncoder implements MimeHeaderEncoderInterface +{ + protected function initSafeMap(): void + { + foreach (array_merge( + range(0x61, 0x7A), range(0x41, 0x5A), + range(0x30, 0x39), [0x20, 0x21, 0x2A, 0x2B, 0x2D, 0x2F] + ) as $byte) { + $this->safeMap[$byte] = \chr($byte); + } + } + + public function getName(): string + { + return 'Q'; + } + + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + return str_replace([' ', '=20', "=\r\n"], ['_', '_', "\r\n"], + parent::encodeString($string, $charset, $firstLineOffset, $maxLineLength) + ); + } +} diff --git a/plugins/email/vendor/symfony/mime/Encoder/Rfc2231Encoder.php b/plugins/email/vendor/symfony/mime/Encoder/Rfc2231Encoder.php new file mode 100644 index 0000000..4d93dc6 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Encoder/Rfc2231Encoder.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\CharacterStream; + +/** + * @author Chris Corbyn + */ +final class Rfc2231Encoder implements EncoderInterface +{ + /** + * Takes an unencoded string and produces a string encoded according to RFC 2231 from it. + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + $lines = []; + $lineCount = 0; + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + + if (0 >= $maxLineLength) { + $maxLineLength = 75; + } + + $charStream = new CharacterStream($string, $charset); + $thisLineLength = $maxLineLength - $firstLineOffset; + + while (null !== $char = $charStream->read(4)) { + $encodedChar = rawurlencode($char); + if ('' !== $currentLine && \strlen($currentLine.$encodedChar) > $thisLineLength) { + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + $thisLineLength = $maxLineLength; + } + $currentLine .= $encodedChar; + } + + return implode("\r\n", $lines); + } +} diff --git a/plugins/email/vendor/symfony/mime/Exception/AddressEncoderException.php b/plugins/email/vendor/symfony/mime/Exception/AddressEncoderException.php new file mode 100644 index 0000000..51ee2e0 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Exception/AddressEncoderException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + */ +class AddressEncoderException extends RfcComplianceException +{ +} diff --git a/plugins/email/vendor/symfony/mime/Exception/ExceptionInterface.php b/plugins/email/vendor/symfony/mime/Exception/ExceptionInterface.php new file mode 100644 index 0000000..1193390 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Exception/ExceptionInterface.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/plugins/email/vendor/symfony/mime/Exception/InvalidArgumentException.php b/plugins/email/vendor/symfony/mime/Exception/InvalidArgumentException.php new file mode 100644 index 0000000..e89ebae --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Exception/InvalidArgumentException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/plugins/email/vendor/symfony/mime/Exception/LogicException.php b/plugins/email/vendor/symfony/mime/Exception/LogicException.php new file mode 100644 index 0000000..0508ee7 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Exception/LogicException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/plugins/email/vendor/symfony/mime/Exception/RfcComplianceException.php b/plugins/email/vendor/symfony/mime/Exception/RfcComplianceException.php new file mode 100644 index 0000000..26e4a50 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Exception/RfcComplianceException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + */ +class RfcComplianceException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/plugins/email/vendor/symfony/mime/Exception/RuntimeException.php b/plugins/email/vendor/symfony/mime/Exception/RuntimeException.php new file mode 100644 index 0000000..fb018b0 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Exception/RuntimeException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/plugins/email/vendor/symfony/mime/FileBinaryMimeTypeGuesser.php b/plugins/email/vendor/symfony/mime/FileBinaryMimeTypeGuesser.php new file mode 100644 index 0000000..3acf4d4 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/FileBinaryMimeTypeGuesser.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Exception\LogicException; + +/** + * Guesses the MIME type with the binary "file" (only available on *nix). + * + * @author Bernhard Schussek + */ +class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface +{ + private $cmd; + + /** + * The $cmd pattern must contain a "%s" string that will be replaced + * with the file name to guess. + * + * The command output must start with the MIME type of the file. + * + * @param string $cmd The command to run to get the MIME type of a file + */ + public function __construct(string $cmd = 'file -b --mime -- %s 2>/dev/null') + { + $this->cmd = $cmd; + } + + /** + * {@inheritdoc} + */ + public function isGuesserSupported(): bool + { + static $supported = null; + + if (null !== $supported) { + return $supported; + } + + if ('\\' === \DIRECTORY_SEPARATOR || !\function_exists('passthru') || !\function_exists('escapeshellarg')) { + return $supported = false; + } + + ob_start(); + passthru('command -v file', $exitStatus); + $binPath = trim(ob_get_clean()); + + return $supported = 0 === $exitStatus && '' !== $binPath; + } + + /** + * {@inheritdoc} + */ + public function guessMimeType(string $path): ?string + { + if (!is_file($path) || !is_readable($path)) { + throw new InvalidArgumentException(sprintf('The "%s" file does not exist or is not readable.', $path)); + } + + if (!$this->isGuesserSupported()) { + throw new LogicException(sprintf('The "%s" guesser is not supported.', __CLASS__)); + } + + ob_start(); + + // need to use --mime instead of -i. see #6641 + passthru(sprintf($this->cmd, escapeshellarg((str_starts_with($path, '-') ? './' : '').$path)), $return); + if ($return > 0) { + ob_end_clean(); + + return null; + } + + $type = trim(ob_get_clean()); + + if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-\+\.]+)#i', $type, $match)) { + // it's not a type, but an error message + return null; + } + + return $match[1]; + } +} diff --git a/plugins/email/vendor/symfony/mime/FileinfoMimeTypeGuesser.php b/plugins/email/vendor/symfony/mime/FileinfoMimeTypeGuesser.php new file mode 100644 index 0000000..c6c7559 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/FileinfoMimeTypeGuesser.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Exception\LogicException; + +/** + * Guesses the MIME type using the PECL extension FileInfo. + * + * @author Bernhard Schussek + */ +class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface +{ + private $magicFile; + + /** + * @param string $magicFile A magic file to use with the finfo instance + * + * @see http://www.php.net/manual/en/function.finfo-open.php + */ + public function __construct(string $magicFile = null) + { + $this->magicFile = $magicFile; + } + + /** + * {@inheritdoc} + */ + public function isGuesserSupported(): bool + { + return \function_exists('finfo_open'); + } + + /** + * {@inheritdoc} + */ + public function guessMimeType(string $path): ?string + { + if (!is_file($path) || !is_readable($path)) { + throw new InvalidArgumentException(sprintf('The "%s" file does not exist or is not readable.', $path)); + } + + if (!$this->isGuesserSupported()) { + throw new LogicException(sprintf('The "%s" guesser is not supported.', __CLASS__)); + } + + if (false === $finfo = new \finfo(\FILEINFO_MIME_TYPE, $this->magicFile)) { + return null; + } + $mimeType = $finfo->file($path); + + if ($mimeType && 0 === (\strlen($mimeType) % 2)) { + $mimeStart = substr($mimeType, 0, \strlen($mimeType) >> 1); + $mimeType = $mimeStart.$mimeStart === $mimeType ? $mimeStart : $mimeType; + } + + return $mimeType; + } +} diff --git a/plugins/email/vendor/symfony/mime/Header/AbstractHeader.php b/plugins/email/vendor/symfony/mime/Header/AbstractHeader.php new file mode 100644 index 0000000..5de9066 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Header/AbstractHeader.php @@ -0,0 +1,284 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Encoder\QpMimeHeaderEncoder; + +/** + * An abstract base MIME Header. + * + * @author Chris Corbyn + */ +abstract class AbstractHeader implements HeaderInterface +{ + public const PHRASE_PATTERN = '(?:(?:(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]+(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?)|(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?"((?:(?:[ \t]*(?:\r\n))?[ \t])?(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21\x23-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])))*(?:(?:[ \t]*(?:\r\n))?[ \t])?"(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?))+?)'; + + private static $encoder; + + private $name; + private $lineLength = 76; + private $lang; + private $charset = 'utf-8'; + + public function __construct(string $name) + { + $this->name = $name; + } + + public function setCharset(string $charset) + { + $this->charset = $charset; + } + + public function getCharset(): ?string + { + return $this->charset; + } + + /** + * Set the language used in this Header. + * + * For example, for US English, 'en-us'. + */ + public function setLanguage(string $lang) + { + $this->lang = $lang; + } + + public function getLanguage(): ?string + { + return $this->lang; + } + + public function getName(): string + { + return $this->name; + } + + public function setMaxLineLength(int $lineLength) + { + $this->lineLength = $lineLength; + } + + public function getMaxLineLength(): int + { + return $this->lineLength; + } + + public function toString(): string + { + return $this->tokensToString($this->toTokens()); + } + + /** + * Produces a compliant, formatted RFC 2822 'phrase' based on the string given. + * + * @param string $string as displayed + * @param bool $shorten the first line to make remove for header name + */ + protected function createPhrase(HeaderInterface $header, string $string, string $charset, bool $shorten = false): string + { + // Treat token as exactly what was given + $phraseStr = $string; + + // If it's not valid + if (!preg_match('/^'.self::PHRASE_PATTERN.'$/D', $phraseStr)) { + // .. but it is just ascii text, try escaping some characters + // and make it a quoted-string + if (preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $phraseStr)) { + foreach (['\\', '"'] as $char) { + $phraseStr = str_replace($char, '\\'.$char, $phraseStr); + } + $phraseStr = '"'.$phraseStr.'"'; + } else { + // ... otherwise it needs encoding + // Determine space remaining on line if first line + if ($shorten) { + $usedLength = \strlen($header->getName().': '); + } else { + $usedLength = 0; + } + $phraseStr = $this->encodeWords($header, $string, $usedLength); + } + } elseif (str_contains($phraseStr, '(')) { + foreach (['\\', '"'] as $char) { + $phraseStr = str_replace($char, '\\'.$char, $phraseStr); + } + $phraseStr = '"'.$phraseStr.'"'; + } + + return $phraseStr; + } + + /** + * Encode needed word tokens within a string of input. + */ + protected function encodeWords(HeaderInterface $header, string $input, int $usedLength = -1): string + { + $value = ''; + $tokens = $this->getEncodableWordTokens($input); + foreach ($tokens as $token) { + // See RFC 2822, Sect 2.2 (really 2.2 ??) + if ($this->tokenNeedsEncoding($token)) { + // Don't encode starting WSP + $firstChar = substr($token, 0, 1); + switch ($firstChar) { + case ' ': + case "\t": + $value .= $firstChar; + $token = substr($token, 1); + } + + if (-1 == $usedLength) { + $usedLength = \strlen($header->getName().': ') + \strlen($value); + } + $value .= $this->getTokenAsEncodedWord($token, $usedLength); + } else { + $value .= $token; + } + } + + return $value; + } + + protected function tokenNeedsEncoding(string $token): bool + { + return (bool) preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token); + } + + /** + * Splits a string into tokens in blocks of words which can be encoded quickly. + * + * @return string[] + */ + protected function getEncodableWordTokens(string $string): array + { + $tokens = []; + $encodedToken = ''; + // Split at all whitespace boundaries + foreach (preg_split('~(?=[\t ])~', $string) as $token) { + if ($this->tokenNeedsEncoding($token)) { + $encodedToken .= $token; + } else { + if ('' !== $encodedToken) { + $tokens[] = $encodedToken; + $encodedToken = ''; + } + $tokens[] = $token; + } + } + if ('' !== $encodedToken) { + $tokens[] = $encodedToken; + } + + return $tokens; + } + + /** + * Get a token as an encoded word for safe insertion into headers. + */ + protected function getTokenAsEncodedWord(string $token, int $firstLineOffset = 0): string + { + if (null === self::$encoder) { + self::$encoder = new QpMimeHeaderEncoder(); + } + + // Adjust $firstLineOffset to account for space needed for syntax + $charsetDecl = $this->charset; + if (null !== $this->lang) { + $charsetDecl .= '*'.$this->lang; + } + $encodingWrapperLength = \strlen('=?'.$charsetDecl.'?'.self::$encoder->getName().'??='); + + if ($firstLineOffset >= 75) { + // Does this logic need to be here? + $firstLineOffset = 0; + } + + $encodedTextLines = explode("\r\n", + self::$encoder->encodeString($token, $this->charset, $firstLineOffset, 75 - $encodingWrapperLength) + ); + + if ('iso-2022-jp' !== strtolower($this->charset)) { + // special encoding for iso-2022-jp using mb_encode_mimeheader + foreach ($encodedTextLines as $lineNum => $line) { + $encodedTextLines[$lineNum] = '=?'.$charsetDecl.'?'.self::$encoder->getName().'?'.$line.'?='; + } + } + + return implode("\r\n ", $encodedTextLines); + } + + /** + * Generates tokens from the given string which include CRLF as individual tokens. + * + * @return string[] + */ + protected function generateTokenLines(string $token): array + { + return preg_split('~(\r\n)~', $token, -1, \PREG_SPLIT_DELIM_CAPTURE); + } + + /** + * Generate a list of all tokens in the final header. + */ + protected function toTokens(string $string = null): array + { + if (null === $string) { + $string = $this->getBodyAsString(); + } + + $tokens = []; + // Generate atoms; split at all invisible boundaries followed by WSP + foreach (preg_split('~(?=[ \t])~', $string) as $token) { + $newTokens = $this->generateTokenLines($token); + foreach ($newTokens as $newToken) { + $tokens[] = $newToken; + } + } + + return $tokens; + } + + /** + * Takes an array of tokens which appear in the header and turns them into + * an RFC 2822 compliant string, adding FWSP where needed. + * + * @param string[] $tokens + */ + private function tokensToString(array $tokens): string + { + $lineCount = 0; + $headerLines = []; + $headerLines[] = $this->name.': '; + $currentLine = &$headerLines[$lineCount++]; + + // Build all tokens back into compliant header + foreach ($tokens as $i => $token) { + // Line longer than specified maximum or token was just a new line + if (("\r\n" === $token) || + ($i > 0 && \strlen($currentLine.$token) > $this->lineLength) + && '' !== $currentLine) { + $headerLines[] = ''; + $currentLine = &$headerLines[$lineCount++]; + } + + // Append token to the line + if ("\r\n" !== $token) { + $currentLine .= $token; + } + } + + // Implode with FWS (RFC 2822, 2.2.3) + return implode("\r\n", $headerLines); + } +} diff --git a/plugins/email/vendor/symfony/mime/Header/DateHeader.php b/plugins/email/vendor/symfony/mime/Header/DateHeader.php new file mode 100644 index 0000000..a7385d4 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Header/DateHeader.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +/** + * A Date MIME Header. + * + * @author Chris Corbyn + */ +final class DateHeader extends AbstractHeader +{ + private $dateTime; + + public function __construct(string $name, \DateTimeInterface $date) + { + parent::__construct($name); + + $this->setDateTime($date); + } + + /** + * @param \DateTimeInterface $body + */ + public function setBody($body) + { + $this->setDateTime($body); + } + + public function getBody(): \DateTimeImmutable + { + return $this->getDateTime(); + } + + public function getDateTime(): \DateTimeImmutable + { + return $this->dateTime; + } + + /** + * Set the date-time of the Date in this Header. + * + * If a DateTime instance is provided, it is converted to DateTimeImmutable. + */ + public function setDateTime(\DateTimeInterface $dateTime) + { + if ($dateTime instanceof \DateTime) { + $immutable = new \DateTimeImmutable('@'.$dateTime->getTimestamp()); + $dateTime = $immutable->setTimezone($dateTime->getTimezone()); + } + $this->dateTime = $dateTime; + } + + public function getBodyAsString(): string + { + return $this->dateTime->format(\DateTime::RFC2822); + } +} diff --git a/plugins/email/vendor/symfony/mime/Header/HeaderInterface.php b/plugins/email/vendor/symfony/mime/Header/HeaderInterface.php new file mode 100644 index 0000000..4546947 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Header/HeaderInterface.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +/** + * A MIME Header. + * + * @author Chris Corbyn + */ +interface HeaderInterface +{ + /** + * Sets the body. + * + * The type depends on the Header concrete class. + * + * @param mixed $body + */ + public function setBody($body); + + /** + * Gets the body. + * + * The return type depends on the Header concrete class. + * + * @return mixed + */ + public function getBody(); + + public function setCharset(string $charset); + + public function getCharset(): ?string; + + public function setLanguage(string $lang); + + public function getLanguage(): ?string; + + public function getName(): string; + + public function setMaxLineLength(int $lineLength); + + public function getMaxLineLength(): int; + + /** + * Gets this Header rendered as a compliant string. + */ + public function toString(): string; + + /** + * Gets the header's body, prepared for folding into a final header value. + * + * This is not necessarily RFC 2822 compliant since folding white space is + * not added at this stage (see {@link toString()} for that). + */ + public function getBodyAsString(): string; +} diff --git a/plugins/email/vendor/symfony/mime/Header/Headers.php b/plugins/email/vendor/symfony/mime/Header/Headers.php new file mode 100644 index 0000000..8db9125 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Header/Headers.php @@ -0,0 +1,307 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\LogicException; + +/** + * A collection of headers. + * + * @author Fabien Potencier + */ +final class Headers +{ + private const UNIQUE_HEADERS = [ + 'date', 'from', 'sender', 'reply-to', 'to', 'cc', 'bcc', + 'message-id', 'in-reply-to', 'references', 'subject', + ]; + private const HEADER_CLASS_MAP = [ + 'date' => DateHeader::class, + 'from' => MailboxListHeader::class, + 'sender' => MailboxHeader::class, + 'reply-to' => MailboxListHeader::class, + 'to' => MailboxListHeader::class, + 'cc' => MailboxListHeader::class, + 'bcc' => MailboxListHeader::class, + 'message-id' => IdentificationHeader::class, + 'in-reply-to' => UnstructuredHeader::class, // `In-Reply-To` and `References` are less strict than RFC 2822 (3.6.4) to allow users entering the original email's ... + 'references' => UnstructuredHeader::class, // ... `Message-ID`, even if that is no valid `msg-id` + 'return-path' => PathHeader::class, + ]; + + /** + * @var HeaderInterface[][] + */ + private $headers = []; + private $lineLength = 76; + + public function __construct(HeaderInterface ...$headers) + { + foreach ($headers as $header) { + $this->add($header); + } + } + + public function __clone() + { + foreach ($this->headers as $name => $collection) { + foreach ($collection as $i => $header) { + $this->headers[$name][$i] = clone $header; + } + } + } + + public function setMaxLineLength(int $lineLength) + { + $this->lineLength = $lineLength; + foreach ($this->all() as $header) { + $header->setMaxLineLength($lineLength); + } + } + + public function getMaxLineLength(): int + { + return $this->lineLength; + } + + /** + * @param array $addresses + * + * @return $this + */ + public function addMailboxListHeader(string $name, array $addresses): self + { + return $this->add(new MailboxListHeader($name, Address::createArray($addresses))); + } + + /** + * @param Address|string $address + * + * @return $this + */ + public function addMailboxHeader(string $name, $address): self + { + return $this->add(new MailboxHeader($name, Address::create($address))); + } + + /** + * @param string|array $ids + * + * @return $this + */ + public function addIdHeader(string $name, $ids): self + { + return $this->add(new IdentificationHeader($name, $ids)); + } + + /** + * @param Address|string $path + * + * @return $this + */ + public function addPathHeader(string $name, $path): self + { + return $this->add(new PathHeader($name, $path instanceof Address ? $path : new Address($path))); + } + + /** + * @return $this + */ + public function addDateHeader(string $name, \DateTimeInterface $dateTime): self + { + return $this->add(new DateHeader($name, $dateTime)); + } + + /** + * @return $this + */ + public function addTextHeader(string $name, string $value): self + { + return $this->add(new UnstructuredHeader($name, $value)); + } + + /** + * @return $this + */ + public function addParameterizedHeader(string $name, string $value, array $params = []): self + { + return $this->add(new ParameterizedHeader($name, $value, $params)); + } + + /** + * @return $this + */ + public function addHeader(string $name, $argument, array $more = []): self + { + $parts = explode('\\', self::HEADER_CLASS_MAP[strtolower($name)] ?? UnstructuredHeader::class); + $method = 'add'.ucfirst(array_pop($parts)); + if ('addUnstructuredHeader' === $method) { + $method = 'addTextHeader'; + } elseif ('addIdentificationHeader' === $method) { + $method = 'addIdHeader'; + } + + return $this->$method($name, $argument, $more); + } + + public function has(string $name): bool + { + return isset($this->headers[strtolower($name)]); + } + + /** + * @return $this + */ + public function add(HeaderInterface $header): self + { + self::checkHeaderClass($header); + + $header->setMaxLineLength($this->lineLength); + $name = strtolower($header->getName()); + + if (\in_array($name, self::UNIQUE_HEADERS, true) && isset($this->headers[$name]) && \count($this->headers[$name]) > 0) { + throw new LogicException(sprintf('Impossible to set header "%s" as it\'s already defined and must be unique.', $header->getName())); + } + + $this->headers[$name][] = $header; + + return $this; + } + + public function get(string $name): ?HeaderInterface + { + $name = strtolower($name); + if (!isset($this->headers[$name])) { + return null; + } + + $values = array_values($this->headers[$name]); + + return array_shift($values); + } + + public function all(string $name = null): iterable + { + if (null === $name) { + foreach ($this->headers as $name => $collection) { + foreach ($collection as $header) { + yield $name => $header; + } + } + } elseif (isset($this->headers[strtolower($name)])) { + foreach ($this->headers[strtolower($name)] as $header) { + yield $header; + } + } + } + + public function getNames(): array + { + return array_keys($this->headers); + } + + public function remove(string $name): void + { + unset($this->headers[strtolower($name)]); + } + + public static function isUniqueHeader(string $name): bool + { + return \in_array(strtolower($name), self::UNIQUE_HEADERS, true); + } + + /** + * @throws LogicException if the header name and class are not compatible + */ + public static function checkHeaderClass(HeaderInterface $header): void + { + $name = strtolower($header->getName()); + + if (($c = self::HEADER_CLASS_MAP[$name] ?? null) && !$header instanceof $c) { + throw new LogicException(sprintf('The "%s" header must be an instance of "%s" (got "%s").', $header->getName(), $c, get_debug_type($header))); + } + } + + public function toString(): string + { + $string = ''; + foreach ($this->toArray() as $str) { + $string .= $str."\r\n"; + } + + return $string; + } + + public function toArray(): array + { + $arr = []; + foreach ($this->all() as $header) { + if ('' !== $header->getBodyAsString()) { + $arr[] = $header->toString(); + } + } + + return $arr; + } + + /** + * @internal + */ + public function getHeaderBody(string $name) + { + return $this->has($name) ? $this->get($name)->getBody() : null; + } + + /** + * @internal + */ + public function setHeaderBody(string $type, string $name, $body): void + { + if ($this->has($name)) { + $this->get($name)->setBody($body); + } else { + $this->{'add'.$type.'Header'}($name, $body); + } + } + + public function getHeaderParameter(string $name, string $parameter): ?string + { + if (!$this->has($name)) { + return null; + } + + $header = $this->get($name); + if (!$header instanceof ParameterizedHeader) { + throw new LogicException(sprintf('Unable to get parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class)); + } + + return $header->getParameter($parameter); + } + + /** + * @internal + */ + public function setHeaderParameter(string $name, string $parameter, ?string $value): void + { + if (!$this->has($name)) { + throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not defined.', $parameter, $name)); + } + + $header = $this->get($name); + if (!$header instanceof ParameterizedHeader) { + throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class)); + } + + $header->setParameter($parameter, $value); + } +} diff --git a/plugins/email/vendor/symfony/mime/Header/IdentificationHeader.php b/plugins/email/vendor/symfony/mime/Header/IdentificationHeader.php new file mode 100644 index 0000000..8a94574 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Header/IdentificationHeader.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * An ID MIME Header for something like Message-ID or Content-ID (one or more addresses). + * + * @author Chris Corbyn + */ +final class IdentificationHeader extends AbstractHeader +{ + private $ids = []; + private $idsAsAddresses = []; + + /** + * @param string|array $ids + */ + public function __construct(string $name, $ids) + { + parent::__construct($name); + + $this->setId($ids); + } + + /** + * @param string|array $body a string ID or an array of IDs + * + * @throws RfcComplianceException + */ + public function setBody($body) + { + $this->setId($body); + } + + public function getBody(): array + { + return $this->getIds(); + } + + /** + * Set the ID used in the value of this header. + * + * @param string|array $id + * + * @throws RfcComplianceException + */ + public function setId($id) + { + $this->setIds(\is_array($id) ? $id : [$id]); + } + + /** + * Get the ID used in the value of this Header. + * + * If multiple IDs are set only the first is returned. + */ + public function getId(): ?string + { + return $this->ids[0] ?? null; + } + + /** + * Set a collection of IDs to use in the value of this Header. + * + * @param string[] $ids + * + * @throws RfcComplianceException + */ + public function setIds(array $ids) + { + $this->ids = []; + $this->idsAsAddresses = []; + foreach ($ids as $id) { + $this->idsAsAddresses[] = new Address($id); + $this->ids[] = $id; + } + } + + /** + * Get the list of IDs used in this Header. + * + * @return string[] + */ + public function getIds(): array + { + return $this->ids; + } + + public function getBodyAsString(): string + { + $addrs = []; + foreach ($this->idsAsAddresses as $address) { + $addrs[] = '<'.$address->toString().'>'; + } + + return implode(' ', $addrs); + } +} diff --git a/plugins/email/vendor/symfony/mime/Header/MailboxHeader.php b/plugins/email/vendor/symfony/mime/Header/MailboxHeader.php new file mode 100644 index 0000000..b58c825 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Header/MailboxHeader.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * A Mailbox MIME Header for something like Sender (one named address). + * + * @author Fabien Potencier + */ +final class MailboxHeader extends AbstractHeader +{ + private $address; + + public function __construct(string $name, Address $address) + { + parent::__construct($name); + + $this->setAddress($address); + } + + /** + * @param Address $body + * + * @throws RfcComplianceException + */ + public function setBody($body) + { + $this->setAddress($body); + } + + /** + * @throws RfcComplianceException + */ + public function getBody(): Address + { + return $this->getAddress(); + } + + /** + * @throws RfcComplianceException + */ + public function setAddress(Address $address) + { + $this->address = $address; + } + + public function getAddress(): Address + { + return $this->address; + } + + public function getBodyAsString(): string + { + $str = $this->address->getEncodedAddress(); + if ($name = $this->address->getName()) { + $str = $this->createPhrase($this, $name, $this->getCharset(), true).' <'.$str.'>'; + } + + return $str; + } + + /** + * Redefine the encoding requirements for an address. + * + * All "specials" must be encoded as the full header value will not be quoted + * + * @see RFC 2822 3.2.1 + */ + protected function tokenNeedsEncoding(string $token): bool + { + return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token); + } +} diff --git a/plugins/email/vendor/symfony/mime/Header/MailboxListHeader.php b/plugins/email/vendor/symfony/mime/Header/MailboxListHeader.php new file mode 100644 index 0000000..1d00fdb --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Header/MailboxListHeader.php @@ -0,0 +1,136 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * A Mailbox list MIME Header for something like From, To, Cc, and Bcc (one or more named addresses). + * + * @author Chris Corbyn + */ +final class MailboxListHeader extends AbstractHeader +{ + private $addresses = []; + + /** + * @param Address[] $addresses + */ + public function __construct(string $name, array $addresses) + { + parent::__construct($name); + + $this->setAddresses($addresses); + } + + /** + * @param Address[] $body + * + * @throws RfcComplianceException + */ + public function setBody($body) + { + $this->setAddresses($body); + } + + /** + * @throws RfcComplianceException + * + * @return Address[] + */ + public function getBody(): array + { + return $this->getAddresses(); + } + + /** + * Sets a list of addresses to be shown in this Header. + * + * @param Address[] $addresses + * + * @throws RfcComplianceException + */ + public function setAddresses(array $addresses) + { + $this->addresses = []; + $this->addAddresses($addresses); + } + + /** + * Sets a list of addresses to be shown in this Header. + * + * @param Address[] $addresses + * + * @throws RfcComplianceException + */ + public function addAddresses(array $addresses) + { + foreach ($addresses as $address) { + $this->addAddress($address); + } + } + + /** + * @throws RfcComplianceException + */ + public function addAddress(Address $address) + { + $this->addresses[] = $address; + } + + /** + * @return Address[] + */ + public function getAddresses(): array + { + return $this->addresses; + } + + /** + * Gets the full mailbox list of this Header as an array of valid RFC 2822 strings. + * + * @throws RfcComplianceException + * + * @return string[] + */ + public function getAddressStrings(): array + { + $strings = []; + foreach ($this->addresses as $address) { + $str = $address->getEncodedAddress(); + if ($name = $address->getName()) { + $str = $this->createPhrase($this, $name, $this->getCharset(), !$strings).' <'.$str.'>'; + } + $strings[] = $str; + } + + return $strings; + } + + public function getBodyAsString(): string + { + return implode(', ', $this->getAddressStrings()); + } + + /** + * Redefine the encoding requirements for addresses. + * + * All "specials" must be encoded as the full header value will not be quoted + * + * @see RFC 2822 3.2.1 + */ + protected function tokenNeedsEncoding(string $token): bool + { + return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token); + } +} diff --git a/plugins/email/vendor/symfony/mime/Header/ParameterizedHeader.php b/plugins/email/vendor/symfony/mime/Header/ParameterizedHeader.php new file mode 100644 index 0000000..e5d4238 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Header/ParameterizedHeader.php @@ -0,0 +1,191 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Encoder\Rfc2231Encoder; + +/** + * @author Chris Corbyn + */ +final class ParameterizedHeader extends UnstructuredHeader +{ + /** + * RFC 2231's definition of a token. + * + * @var string + */ + public const TOKEN_REGEX = '(?:[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E]+)'; + + private $encoder; + private $parameters = []; + + public function __construct(string $name, string $value, array $parameters = []) + { + parent::__construct($name, $value); + + foreach ($parameters as $k => $v) { + $this->setParameter($k, $v); + } + + if ('content-type' !== strtolower($name)) { + $this->encoder = new Rfc2231Encoder(); + } + } + + public function setParameter(string $parameter, ?string $value) + { + $this->setParameters(array_merge($this->getParameters(), [$parameter => $value])); + } + + public function getParameter(string $parameter): string + { + return $this->getParameters()[$parameter] ?? ''; + } + + /** + * @param string[] $parameters + */ + public function setParameters(array $parameters) + { + $this->parameters = $parameters; + } + + /** + * @return string[] + */ + public function getParameters(): array + { + return $this->parameters; + } + + public function getBodyAsString(): string + { + $body = parent::getBodyAsString(); + foreach ($this->parameters as $name => $value) { + if (null !== $value) { + $body .= '; '.$this->createParameter($name, $value); + } + } + + return $body; + } + + /** + * Generate a list of all tokens in the final header. + * + * This doesn't need to be overridden in theory, but it is for implementation + * reasons to prevent potential breakage of attributes. + */ + protected function toTokens(string $string = null): array + { + $tokens = parent::toTokens(parent::getBodyAsString()); + + // Try creating any parameters + foreach ($this->parameters as $name => $value) { + if (null !== $value) { + // Add the semi-colon separator + $tokens[\count($tokens) - 1] .= ';'; + $tokens = array_merge($tokens, $this->generateTokenLines(' '.$this->createParameter($name, $value))); + } + } + + return $tokens; + } + + /** + * Render an RFC 2047 compliant header parameter from the $name and $value. + */ + private function createParameter(string $name, string $value): string + { + $origValue = $value; + + $encoded = false; + // Allow room for parameter name, indices, "=" and DQUOTEs + $maxValueLength = $this->getMaxLineLength() - \strlen($name.'=*N"";') - 1; + $firstLineOffset = 0; + + // If it's not already a valid parameter value... + if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { + // TODO: text, or something else?? + // ... and it's not ascii + if (!preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $value)) { + $encoded = true; + // Allow space for the indices, charset and language + $maxValueLength = $this->getMaxLineLength() - \strlen($name.'*N*="";') - 1; + $firstLineOffset = \strlen($this->getCharset()."'".$this->getLanguage()."'"); + } + + if (\in_array($name, ['name', 'filename'], true) && 'form-data' === $this->getValue() && 'content-disposition' === strtolower($this->getName()) && preg_match('//u', $value)) { + // WHATWG HTML living standard 4.10.21.8 2 specifies: + // For field names and filenames for file fields, the result of the + // encoding in the previous bullet point must be escaped by replacing + // any 0x0A (LF) bytes with the byte sequence `%0A`, 0x0D (CR) with `%0D` + // and 0x22 (") with `%22`. + // The user agent must not perform any other escapes. + $value = str_replace(['"', "\r", "\n"], ['%22', '%0D', '%0A'], $value); + + if (\strlen($value) <= $maxValueLength) { + return $name.'="'.$value.'"'; + } + + $value = $origValue; + } + } + + // Encode if we need to + if ($encoded || \strlen($value) > $maxValueLength) { + if (null !== $this->encoder) { + $value = $this->encoder->encodeString($origValue, $this->getCharset(), $firstLineOffset, $maxValueLength); + } else { + // We have to go against RFC 2183/2231 in some areas for interoperability + $value = $this->getTokenAsEncodedWord($origValue); + $encoded = false; + } + } + + $valueLines = $this->encoder ? explode("\r\n", $value) : [$value]; + + // Need to add indices + if (\count($valueLines) > 1) { + $paramLines = []; + foreach ($valueLines as $i => $line) { + $paramLines[] = $name.'*'.$i.$this->getEndOfParameterValue($line, true, 0 === $i); + } + + return implode(";\r\n ", $paramLines); + } else { + return $name.$this->getEndOfParameterValue($valueLines[0], $encoded, true); + } + } + + /** + * Returns the parameter value from the "=" and beyond. + * + * @param string $value to append + */ + private function getEndOfParameterValue(string $value, bool $encoded = false, bool $firstLine = false): string + { + $forceHttpQuoting = 'form-data' === $this->getValue() && 'content-disposition' === strtolower($this->getName()); + if ($forceHttpQuoting || !preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { + $value = '"'.$value.'"'; + } + $prepend = '='; + if ($encoded) { + $prepend = '*='; + if ($firstLine) { + $prepend = '*='.$this->getCharset()."'".$this->getLanguage()."'"; + } + } + + return $prepend.$value; + } +} diff --git a/plugins/email/vendor/symfony/mime/Header/PathHeader.php b/plugins/email/vendor/symfony/mime/Header/PathHeader.php new file mode 100644 index 0000000..5101ad0 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Header/PathHeader.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * A Path Header, such a Return-Path (one address). + * + * @author Chris Corbyn + */ +final class PathHeader extends AbstractHeader +{ + private $address; + + public function __construct(string $name, Address $address) + { + parent::__construct($name); + + $this->setAddress($address); + } + + /** + * @param Address $body + * + * @throws RfcComplianceException + */ + public function setBody($body) + { + $this->setAddress($body); + } + + public function getBody(): Address + { + return $this->getAddress(); + } + + public function setAddress(Address $address) + { + $this->address = $address; + } + + public function getAddress(): Address + { + return $this->address; + } + + public function getBodyAsString(): string + { + return '<'.$this->address->toString().'>'; + } +} diff --git a/plugins/email/vendor/symfony/mime/Header/UnstructuredHeader.php b/plugins/email/vendor/symfony/mime/Header/UnstructuredHeader.php new file mode 100644 index 0000000..2085ddf --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Header/UnstructuredHeader.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +/** + * A Simple MIME Header. + * + * @author Chris Corbyn + */ +class UnstructuredHeader extends AbstractHeader +{ + private $value; + + public function __construct(string $name, string $value) + { + parent::__construct($name); + + $this->setValue($value); + } + + /** + * @param string $body + */ + public function setBody($body) + { + $this->setValue($body); + } + + /** + * @return string + */ + public function getBody() + { + return $this->getValue(); + } + + /** + * Get the (unencoded) value of this header. + */ + public function getValue(): string + { + return $this->value; + } + + /** + * Set the (unencoded) value of this header. + */ + public function setValue(string $value) + { + $this->value = $value; + } + + /** + * Get the value of this header prepared for rendering. + */ + public function getBodyAsString(): string + { + return $this->encodeWords($this, $this->value); + } +} diff --git a/plugins/email/vendor/symfony/mime/LICENSE b/plugins/email/vendor/symfony/mime/LICENSE new file mode 100644 index 0000000..298be14 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010-2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/plugins/email/vendor/symfony/mime/Message.php b/plugins/email/vendor/symfony/mime/Message.php new file mode 100644 index 0000000..651ffd4 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Message.php @@ -0,0 +1,160 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\LogicException; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Part\AbstractPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * @author Fabien Potencier + */ +class Message extends RawMessage +{ + private $headers; + private $body; + + public function __construct(Headers $headers = null, AbstractPart $body = null) + { + $this->headers = $headers ? clone $headers : new Headers(); + $this->body = $body; + } + + public function __clone() + { + $this->headers = clone $this->headers; + + if (null !== $this->body) { + $this->body = clone $this->body; + } + } + + /** + * @return $this + */ + public function setBody(AbstractPart $body = null) + { + $this->body = $body; + + return $this; + } + + public function getBody(): ?AbstractPart + { + return $this->body; + } + + /** + * @return $this + */ + public function setHeaders(Headers $headers) + { + $this->headers = $headers; + + return $this; + } + + public function getHeaders(): Headers + { + return $this->headers; + } + + public function getPreparedHeaders(): Headers + { + $headers = clone $this->headers; + + if (!$headers->has('From')) { + if (!$headers->has('Sender')) { + throw new LogicException('An email must have a "From" or a "Sender" header.'); + } + $headers->addMailboxListHeader('From', [$headers->get('Sender')->getAddress()]); + } + + if (!$headers->has('MIME-Version')) { + $headers->addTextHeader('MIME-Version', '1.0'); + } + + if (!$headers->has('Date')) { + $headers->addDateHeader('Date', new \DateTimeImmutable()); + } + + // determine the "real" sender + if (!$headers->has('Sender') && \count($froms = $headers->get('From')->getAddresses()) > 1) { + $headers->addMailboxHeader('Sender', $froms[0]); + } + + if (!$headers->has('Message-ID')) { + $headers->addIdHeader('Message-ID', $this->generateMessageId()); + } + + // remove the Bcc field which should NOT be part of the sent message + $headers->remove('Bcc'); + + return $headers; + } + + public function toString(): string + { + if (null === $body = $this->getBody()) { + $body = new TextPart(''); + } + + return $this->getPreparedHeaders()->toString().$body->toString(); + } + + public function toIterable(): iterable + { + if (null === $body = $this->getBody()) { + $body = new TextPart(''); + } + + yield $this->getPreparedHeaders()->toString(); + yield from $body->toIterable(); + } + + public function ensureValidity() + { + if (!$this->headers->has('To') && !$this->headers->has('Cc') && !$this->headers->has('Bcc')) { + throw new LogicException('An email must have a "To", "Cc", or "Bcc" header.'); + } + + if (!$this->headers->has('From') && !$this->headers->has('Sender')) { + throw new LogicException('An email must have a "From" or a "Sender" header.'); + } + + parent::ensureValidity(); + } + + public function generateMessageId(): string + { + if ($this->headers->has('Sender')) { + $sender = $this->headers->get('Sender')->getAddress(); + } elseif ($this->headers->has('From')) { + $sender = $this->headers->get('From')->getAddresses()[0]; + } else { + throw new LogicException('An email must have a "From" or a "Sender" header.'); + } + + return bin2hex(random_bytes(16)).strstr($sender->getAddress(), '@'); + } + + public function __serialize(): array + { + return [$this->headers, $this->body]; + } + + public function __unserialize(array $data): void + { + [$this->headers, $this->body] = $data; + } +} diff --git a/plugins/email/vendor/symfony/mime/MessageConverter.php b/plugins/email/vendor/symfony/mime/MessageConverter.php new file mode 100644 index 0000000..0539eac --- /dev/null +++ b/plugins/email/vendor/symfony/mime/MessageConverter.php @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\RuntimeException; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\Multipart\AlternativePart; +use Symfony\Component\Mime\Part\Multipart\MixedPart; +use Symfony\Component\Mime\Part\Multipart\RelatedPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * @author Fabien Potencier + */ +final class MessageConverter +{ + /** + * @throws RuntimeException when unable to convert the message to an email + */ + public static function toEmail(Message $message): Email + { + if ($message instanceof Email) { + return $message; + } + + // try to convert to a "simple" Email instance + $body = $message->getBody(); + if ($body instanceof TextPart) { + return self::createEmailFromTextPart($message, $body); + } + + if ($body instanceof AlternativePart) { + return self::createEmailFromAlternativePart($message, $body); + } + + if ($body instanceof RelatedPart) { + return self::createEmailFromRelatedPart($message, $body); + } + + if ($body instanceof MixedPart) { + $parts = $body->getParts(); + if ($parts[0] instanceof RelatedPart) { + $email = self::createEmailFromRelatedPart($message, $parts[0]); + } elseif ($parts[0] instanceof AlternativePart) { + $email = self::createEmailFromAlternativePart($message, $parts[0]); + } elseif ($parts[0] instanceof TextPart) { + $email = self::createEmailFromTextPart($message, $parts[0]); + } else { + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); + } + + return self::attachParts($email, \array_slice($parts, 1)); + } + + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); + } + + private static function createEmailFromTextPart(Message $message, TextPart $part): Email + { + if ('text' === $part->getMediaType() && 'plain' === $part->getMediaSubtype()) { + return (new Email(clone $message->getHeaders()))->text($part->getBody(), $part->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8'); + } + if ('text' === $part->getMediaType() && 'html' === $part->getMediaSubtype()) { + return (new Email(clone $message->getHeaders()))->html($part->getBody(), $part->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8'); + } + + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); + } + + private static function createEmailFromAlternativePart(Message $message, AlternativePart $part): Email + { + $parts = $part->getParts(); + if ( + 2 === \count($parts) && + $parts[0] instanceof TextPart && 'text' === $parts[0]->getMediaType() && 'plain' === $parts[0]->getMediaSubtype() && + $parts[1] instanceof TextPart && 'text' === $parts[1]->getMediaType() && 'html' === $parts[1]->getMediaSubtype() + ) { + return (new Email(clone $message->getHeaders())) + ->text($parts[0]->getBody(), $parts[0]->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8') + ->html($parts[1]->getBody(), $parts[1]->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8') + ; + } + + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); + } + + private static function createEmailFromRelatedPart(Message $message, RelatedPart $part): Email + { + $parts = $part->getParts(); + if ($parts[0] instanceof AlternativePart) { + $email = self::createEmailFromAlternativePart($message, $parts[0]); + } elseif ($parts[0] instanceof TextPart) { + $email = self::createEmailFromTextPart($message, $parts[0]); + } else { + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); + } + + return self::attachParts($email, \array_slice($parts, 1)); + } + + private static function attachParts(Email $email, array $parts): Email + { + foreach ($parts as $part) { + if (!$part instanceof DataPart) { + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($email))); + } + + $headers = $part->getPreparedHeaders(); + $method = 'inline' === $headers->getHeaderBody('Content-Disposition') ? 'embed' : 'attach'; + $name = $headers->getHeaderParameter('Content-Disposition', 'filename'); + $email->$method($part->getBody(), $name, $part->getMediaType().'/'.$part->getMediaSubtype()); + } + + return $email; + } +} diff --git a/plugins/email/vendor/symfony/mime/MimeTypeGuesserInterface.php b/plugins/email/vendor/symfony/mime/MimeTypeGuesserInterface.php new file mode 100644 index 0000000..30ee3b6 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/MimeTypeGuesserInterface.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * Guesses the MIME type of a file. + * + * @author Fabien Potencier + */ +interface MimeTypeGuesserInterface +{ + /** + * Returns true if this guesser is supported. + */ + public function isGuesserSupported(): bool; + + /** + * Guesses the MIME type of the file with the given path. + * + * @throws \LogicException If the guesser is not supported + * @throws \InvalidArgumentException If the file does not exist or is not readable + */ + public function guessMimeType(string $path): ?string; +} diff --git a/plugins/email/vendor/symfony/mime/MimeTypes.php b/plugins/email/vendor/symfony/mime/MimeTypes.php new file mode 100644 index 0000000..bdea994 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/MimeTypes.php @@ -0,0 +1,3537 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\LogicException; + +/** + * Manages MIME types and file extensions. + * + * For MIME type guessing, you can register custom guessers + * by calling the registerGuesser() method. + * Custom guessers are always called before any default ones: + * + * $guesser = new MimeTypes(); + * $guesser->registerGuesser(new MyCustomMimeTypeGuesser()); + * + * If you want to change the order of the default guessers, just re-register your + * preferred one as a custom one. The last registered guesser is preferred over + * previously registered ones. + * + * Re-registering a built-in guesser also allows you to configure it: + * + * $guesser = new MimeTypes(); + * $guesser->registerGuesser(new FileinfoMimeTypeGuesser('/path/to/magic/file')); + * + * @author Fabien Potencier + */ +final class MimeTypes implements MimeTypesInterface +{ + private $extensions = []; + private $mimeTypes = []; + + /** + * @var MimeTypeGuesserInterface[] + */ + private $guessers = []; + private static $default; + + public function __construct(array $map = []) + { + foreach ($map as $mimeType => $extensions) { + $this->extensions[$mimeType] = $extensions; + + foreach ($extensions as $extension) { + $this->mimeTypes[$extension][] = $mimeType; + } + } + $this->registerGuesser(new FileBinaryMimeTypeGuesser()); + $this->registerGuesser(new FileinfoMimeTypeGuesser()); + } + + public static function setDefault(self $default) + { + self::$default = $default; + } + + public static function getDefault(): self + { + return self::$default ?? self::$default = new self(); + } + + /** + * Registers a MIME type guesser. + * + * The last registered guesser has precedence over the other ones. + */ + public function registerGuesser(MimeTypeGuesserInterface $guesser) + { + array_unshift($this->guessers, $guesser); + } + + /** + * {@inheritdoc} + */ + public function getExtensions(string $mimeType): array + { + if ($this->extensions) { + $extensions = $this->extensions[$mimeType] ?? $this->extensions[$lcMimeType = strtolower($mimeType)] ?? null; + } + + return $extensions ?? self::MAP[$mimeType] ?? self::MAP[$lcMimeType ?? strtolower($mimeType)] ?? []; + } + + /** + * {@inheritdoc} + */ + public function getMimeTypes(string $ext): array + { + if ($this->mimeTypes) { + $mimeTypes = $this->mimeTypes[$ext] ?? $this->mimeTypes[$lcExt = strtolower($ext)] ?? null; + } + + return $mimeTypes ?? self::REVERSE_MAP[$ext] ?? self::REVERSE_MAP[$lcExt ?? strtolower($ext)] ?? []; + } + + /** + * {@inheritdoc} + */ + public function isGuesserSupported(): bool + { + foreach ($this->guessers as $guesser) { + if ($guesser->isGuesserSupported()) { + return true; + } + } + + return false; + } + + /** + * {@inheritdoc} + * + * The file is passed to each registered MIME type guesser in reverse order + * of their registration (last registered is queried first). Once a guesser + * returns a value that is not null, this method terminates and returns the + * value. + */ + public function guessMimeType(string $path): ?string + { + foreach ($this->guessers as $guesser) { + if (!$guesser->isGuesserSupported()) { + continue; + } + + if (null !== $mimeType = $guesser->guessMimeType($path)) { + return $mimeType; + } + } + + if (!$this->isGuesserSupported()) { + throw new LogicException('Unable to guess the MIME type as no guessers are available (have you enabled the php_fileinfo extension?).'); + } + + return null; + } + + /** + * A map of MIME types and their default extensions. + * + * Updated from upstream on 2021-09-03 + * + * @see Resources/bin/update_mime_types.php + */ + private const MAP = [ + 'application/acrobat' => ['pdf'], + 'application/andrew-inset' => ['ez'], + 'application/annodex' => ['anx'], + 'application/applixware' => ['aw'], + 'application/atom+xml' => ['atom'], + 'application/atomcat+xml' => ['atomcat'], + 'application/atomdeleted+xml' => ['atomdeleted'], + 'application/atomsvc+xml' => ['atomsvc'], + 'application/atsc-dwd+xml' => ['dwd'], + 'application/atsc-held+xml' => ['held'], + 'application/atsc-rsat+xml' => ['rsat'], + 'application/bdoc' => ['bdoc'], + 'application/bzip2' => ['bz2', 'bz'], + 'application/calendar+xml' => ['xcs'], + 'application/ccxml+xml' => ['ccxml'], + 'application/cdfx+xml' => ['cdfx'], + 'application/cdmi-capability' => ['cdmia'], + 'application/cdmi-container' => ['cdmic'], + 'application/cdmi-domain' => ['cdmid'], + 'application/cdmi-object' => ['cdmio'], + 'application/cdmi-queue' => ['cdmiq'], + 'application/cdr' => ['cdr'], + 'application/coreldraw' => ['cdr'], + 'application/csv' => ['csv'], + 'application/cu-seeme' => ['cu'], + 'application/dash+xml' => ['mpd'], + 'application/davmount+xml' => ['davmount'], + 'application/dbase' => ['dbf'], + 'application/dbf' => ['dbf'], + 'application/dicom' => ['dcm'], + 'application/docbook+xml' => ['dbk', 'docbook'], + 'application/dssc+der' => ['dssc'], + 'application/dssc+xml' => ['xdssc'], + 'application/ecmascript' => ['ecma', 'es'], + 'application/emf' => ['emf'], + 'application/emma+xml' => ['emma'], + 'application/emotionml+xml' => ['emotionml'], + 'application/epub+zip' => ['epub'], + 'application/exi' => ['exi'], + 'application/fdt+xml' => ['fdt'], + 'application/font-tdpfr' => ['pfr'], + 'application/font-woff' => ['woff'], + 'application/futuresplash' => ['swf', 'spl'], + 'application/geo+json' => ['geojson', 'geo.json'], + 'application/gml+xml' => ['gml'], + 'application/gnunet-directory' => ['gnd'], + 'application/gpx' => ['gpx'], + 'application/gpx+xml' => ['gpx'], + 'application/gxf' => ['gxf'], + 'application/gzip' => ['gz'], + 'application/hjson' => ['hjson'], + 'application/hyperstudio' => ['stk'], + 'application/ico' => ['ico'], + 'application/ics' => ['vcs', 'ics'], + 'application/illustrator' => ['ai'], + 'application/inkml+xml' => ['ink', 'inkml'], + 'application/ipfix' => ['ipfix'], + 'application/its+xml' => ['its'], + 'application/java' => ['class'], + 'application/java-archive' => ['jar', 'war', 'ear'], + 'application/java-byte-code' => ['class'], + 'application/java-serialized-object' => ['ser'], + 'application/java-vm' => ['class'], + 'application/javascript' => ['js', 'mjs', 'jsm'], + 'application/jrd+json' => ['jrd'], + 'application/json' => ['json', 'map'], + 'application/json-patch+json' => ['json-patch'], + 'application/json5' => ['json5'], + 'application/jsonml+json' => ['jsonml'], + 'application/ld+json' => ['jsonld'], + 'application/lgr+xml' => ['lgr'], + 'application/lost+xml' => ['lostxml'], + 'application/lotus123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'application/m3u' => ['m3u', 'm3u8', 'vlc'], + 'application/mac-binhex40' => ['hqx'], + 'application/mac-compactpro' => ['cpt'], + 'application/mads+xml' => ['mads'], + 'application/manifest+json' => ['webmanifest'], + 'application/marc' => ['mrc'], + 'application/marcxml+xml' => ['mrcx'], + 'application/mathematica' => ['ma', 'nb', 'mb'], + 'application/mathml+xml' => ['mathml', 'mml'], + 'application/mbox' => ['mbox'], + 'application/mdb' => ['mdb'], + 'application/mediaservercontrol+xml' => ['mscml'], + 'application/metalink+xml' => ['metalink'], + 'application/metalink4+xml' => ['meta4'], + 'application/mets+xml' => ['mets'], + 'application/mmt-aei+xml' => ['maei'], + 'application/mmt-usd+xml' => ['musd'], + 'application/mods+xml' => ['mods'], + 'application/mp21' => ['m21', 'mp21'], + 'application/mp4' => ['mp4s', 'm4p'], + 'application/mrb-consumer+xml' => ['xdf'], + 'application/mrb-publish+xml' => ['xdf'], + 'application/ms-tnef' => ['tnef', 'tnf'], + 'application/msaccess' => ['mdb'], + 'application/msexcel' => ['xls', 'xlc', 'xll', 'xlm', 'xlw', 'xla', 'xlt', 'xld'], + 'application/mspowerpoint' => ['ppz', 'ppt', 'pps', 'pot'], + 'application/msword' => ['doc', 'dot'], + 'application/msword-template' => ['dot'], + 'application/mxf' => ['mxf'], + 'application/n-quads' => ['nq'], + 'application/n-triples' => ['nt'], + 'application/nappdf' => ['pdf'], + 'application/node' => ['cjs'], + 'application/octet-stream' => ['bin', 'dms', 'lrf', 'mar', 'so', 'dist', 'distz', 'pkg', 'bpk', 'dump', 'elc', 'deploy', 'exe', 'dll', 'deb', 'dmg', 'iso', 'img', 'msi', 'msp', 'msm', 'buffer'], + 'application/oda' => ['oda'], + 'application/oebps-package+xml' => ['opf'], + 'application/ogg' => ['ogx'], + 'application/omdoc+xml' => ['omdoc'], + 'application/onenote' => ['onetoc', 'onetoc2', 'onetmp', 'onepkg'], + 'application/ovf' => ['ova'], + 'application/owl+xml' => ['owx'], + 'application/oxps' => ['oxps'], + 'application/p2p-overlay+xml' => ['relo'], + 'application/patch-ops-error+xml' => ['xer'], + 'application/pcap' => ['pcap', 'cap', 'dmp'], + 'application/pdf' => ['pdf'], + 'application/pgp' => ['pgp', 'gpg', 'asc'], + 'application/pgp-encrypted' => ['pgp', 'gpg', 'asc'], + 'application/pgp-keys' => ['skr', 'pkr', 'asc', 'pgp', 'gpg', 'key'], + 'application/pgp-signature' => ['asc', 'sig', 'pgp', 'gpg'], + 'application/photoshop' => ['psd'], + 'application/pics-rules' => ['prf'], + 'application/pkcs10' => ['p10'], + 'application/pkcs12' => ['p12', 'pfx'], + 'application/pkcs7-mime' => ['p7m', 'p7c'], + 'application/pkcs7-signature' => ['p7s'], + 'application/pkcs8' => ['p8'], + 'application/pkcs8-encrypted' => ['p8e'], + 'application/pkix-attr-cert' => ['ac'], + 'application/pkix-cert' => ['cer'], + 'application/pkix-crl' => ['crl'], + 'application/pkix-pkipath' => ['pkipath'], + 'application/pkixcmp' => ['pki'], + 'application/pls' => ['pls'], + 'application/pls+xml' => ['pls'], + 'application/postscript' => ['ai', 'eps', 'ps'], + 'application/powerpoint' => ['ppz', 'ppt', 'pps', 'pot'], + 'application/provenance+xml' => ['provx'], + 'application/prs.cww' => ['cww'], + 'application/pskc+xml' => ['pskcxml'], + 'application/ram' => ['ram'], + 'application/raml+yaml' => ['raml'], + 'application/rdf+xml' => ['rdf', 'owl', 'rdfs'], + 'application/reginfo+xml' => ['rif'], + 'application/relax-ng-compact-syntax' => ['rnc'], + 'application/resource-lists+xml' => ['rl'], + 'application/resource-lists-diff+xml' => ['rld'], + 'application/rls-services+xml' => ['rs'], + 'application/route-apd+xml' => ['rapd'], + 'application/route-s-tsid+xml' => ['sls'], + 'application/route-usd+xml' => ['rusd'], + 'application/rpki-ghostbusters' => ['gbr'], + 'application/rpki-manifest' => ['mft'], + 'application/rpki-roa' => ['roa'], + 'application/rsd+xml' => ['rsd'], + 'application/rss+xml' => ['rss'], + 'application/rtf' => ['rtf'], + 'application/sbml+xml' => ['sbml'], + 'application/schema+json' => ['json'], + 'application/scvp-cv-request' => ['scq'], + 'application/scvp-cv-response' => ['scs'], + 'application/scvp-vp-request' => ['spq'], + 'application/scvp-vp-response' => ['spp'], + 'application/sdp' => ['sdp'], + 'application/senml+xml' => ['senmlx'], + 'application/sensml+xml' => ['sensmlx'], + 'application/set-payment-initiation' => ['setpay'], + 'application/set-registration-initiation' => ['setreg'], + 'application/shf+xml' => ['shf'], + 'application/sieve' => ['siv', 'sieve'], + 'application/smil' => ['smil', 'smi', 'sml', 'kino'], + 'application/smil+xml' => ['smi', 'smil', 'sml', 'kino'], + 'application/sparql-query' => ['rq'], + 'application/sparql-results+xml' => ['srx'], + 'application/sql' => ['sql'], + 'application/srgs' => ['gram'], + 'application/srgs+xml' => ['grxml'], + 'application/sru+xml' => ['sru'], + 'application/ssdl+xml' => ['ssdl'], + 'application/ssml+xml' => ['ssml'], + 'application/stuffit' => ['sit', 'hqx'], + 'application/swid+xml' => ['swidtag'], + 'application/tei+xml' => ['tei', 'teicorpus'], + 'application/tga' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'application/thraud+xml' => ['tfi'], + 'application/timestamped-data' => ['tsd'], + 'application/toml' => ['toml'], + 'application/trig' => ['trig'], + 'application/ttml+xml' => ['ttml'], + 'application/ubjson' => ['ubj'], + 'application/urc-ressheet+xml' => ['rsheet'], + 'application/urc-targetdesc+xml' => ['td'], + 'application/vnd.1000minds.decision-model+xml' => ['1km'], + 'application/vnd.3gpp.pic-bw-large' => ['plb'], + 'application/vnd.3gpp.pic-bw-small' => ['psb'], + 'application/vnd.3gpp.pic-bw-var' => ['pvb'], + 'application/vnd.3gpp2.tcap' => ['tcap'], + 'application/vnd.3m.post-it-notes' => ['pwn'], + 'application/vnd.accpac.simply.aso' => ['aso'], + 'application/vnd.accpac.simply.imp' => ['imp'], + 'application/vnd.acucobol' => ['acu'], + 'application/vnd.acucorp' => ['atc', 'acutc'], + 'application/vnd.adobe.air-application-installer-package+zip' => ['air'], + 'application/vnd.adobe.flash.movie' => ['swf', 'spl'], + 'application/vnd.adobe.formscentral.fcdt' => ['fcdt'], + 'application/vnd.adobe.fxp' => ['fxp', 'fxpl'], + 'application/vnd.adobe.illustrator' => ['ai'], + 'application/vnd.adobe.xdp+xml' => ['xdp'], + 'application/vnd.adobe.xfdf' => ['xfdf'], + 'application/vnd.ahead.space' => ['ahead'], + 'application/vnd.airzip.filesecure.azf' => ['azf'], + 'application/vnd.airzip.filesecure.azs' => ['azs'], + 'application/vnd.amazon.ebook' => ['azw'], + 'application/vnd.amazon.mobi8-ebook' => ['azw3', 'kfx'], + 'application/vnd.americandynamics.acc' => ['acc'], + 'application/vnd.amiga.ami' => ['ami'], + 'application/vnd.android.package-archive' => ['apk'], + 'application/vnd.anser-web-certificate-issue-initiation' => ['cii'], + 'application/vnd.anser-web-funds-transfer-initiation' => ['fti'], + 'application/vnd.antix.game-component' => ['atx'], + 'application/vnd.appimage' => ['appimage'], + 'application/vnd.apple.installer+xml' => ['mpkg'], + 'application/vnd.apple.keynote' => ['key', 'keynote'], + 'application/vnd.apple.mpegurl' => ['m3u8', 'm3u'], + 'application/vnd.apple.numbers' => ['numbers'], + 'application/vnd.apple.pages' => ['pages'], + 'application/vnd.apple.pkpass' => ['pkpass'], + 'application/vnd.aristanetworks.swi' => ['swi'], + 'application/vnd.astraea-software.iota' => ['iota'], + 'application/vnd.audiograph' => ['aep'], + 'application/vnd.balsamiq.bmml+xml' => ['bmml'], + 'application/vnd.blueice.multipass' => ['mpm'], + 'application/vnd.bmi' => ['bmi'], + 'application/vnd.businessobjects' => ['rep'], + 'application/vnd.chemdraw+xml' => ['cdxml'], + 'application/vnd.chess-pgn' => ['pgn'], + 'application/vnd.chipnuts.karaoke-mmd' => ['mmd'], + 'application/vnd.cinderella' => ['cdy'], + 'application/vnd.citationstyles.style+xml' => ['csl'], + 'application/vnd.claymore' => ['cla'], + 'application/vnd.cloanto.rp9' => ['rp9'], + 'application/vnd.clonk.c4group' => ['c4g', 'c4d', 'c4f', 'c4p', 'c4u'], + 'application/vnd.cluetrust.cartomobile-config' => ['c11amc'], + 'application/vnd.cluetrust.cartomobile-config-pkg' => ['c11amz'], + 'application/vnd.coffeescript' => ['coffee'], + 'application/vnd.comicbook+zip' => ['cbz'], + 'application/vnd.comicbook-rar' => ['cbr'], + 'application/vnd.commonspace' => ['csp'], + 'application/vnd.contact.cmsg' => ['cdbcmsg'], + 'application/vnd.corel-draw' => ['cdr'], + 'application/vnd.cosmocaller' => ['cmc'], + 'application/vnd.crick.clicker' => ['clkx'], + 'application/vnd.crick.clicker.keyboard' => ['clkk'], + 'application/vnd.crick.clicker.palette' => ['clkp'], + 'application/vnd.crick.clicker.template' => ['clkt'], + 'application/vnd.crick.clicker.wordbank' => ['clkw'], + 'application/vnd.criticaltools.wbs+xml' => ['wbs'], + 'application/vnd.ctc-posml' => ['pml'], + 'application/vnd.cups-ppd' => ['ppd'], + 'application/vnd.curl.car' => ['car'], + 'application/vnd.curl.pcurl' => ['pcurl'], + 'application/vnd.dart' => ['dart'], + 'application/vnd.data-vision.rdz' => ['rdz'], + 'application/vnd.dbf' => ['dbf'], + 'application/vnd.debian.binary-package' => ['deb', 'udeb'], + 'application/vnd.dece.data' => ['uvf', 'uvvf', 'uvd', 'uvvd'], + 'application/vnd.dece.ttml+xml' => ['uvt', 'uvvt'], + 'application/vnd.dece.unspecified' => ['uvx', 'uvvx'], + 'application/vnd.dece.zip' => ['uvz', 'uvvz'], + 'application/vnd.denovo.fcselayout-link' => ['fe_launch'], + 'application/vnd.dna' => ['dna'], + 'application/vnd.dolby.mlp' => ['mlp'], + 'application/vnd.dpgraph' => ['dpg'], + 'application/vnd.dreamfactory' => ['dfac'], + 'application/vnd.ds-keypoint' => ['kpxx'], + 'application/vnd.dvb.ait' => ['ait'], + 'application/vnd.dvb.service' => ['svc'], + 'application/vnd.dynageo' => ['geo'], + 'application/vnd.ecowin.chart' => ['mag'], + 'application/vnd.emusic-emusic_package' => ['emp'], + 'application/vnd.enliven' => ['nml'], + 'application/vnd.epson.esf' => ['esf'], + 'application/vnd.epson.msf' => ['msf'], + 'application/vnd.epson.quickanime' => ['qam'], + 'application/vnd.epson.salt' => ['slt'], + 'application/vnd.epson.ssf' => ['ssf'], + 'application/vnd.eszigno3+xml' => ['es3', 'et3'], + 'application/vnd.etsi.asic-e+zip' => ['asice'], + 'application/vnd.ezpix-album' => ['ez2'], + 'application/vnd.ezpix-package' => ['ez3'], + 'application/vnd.fdf' => ['fdf'], + 'application/vnd.fdsn.mseed' => ['mseed'], + 'application/vnd.fdsn.seed' => ['seed', 'dataless'], + 'application/vnd.flatpak' => ['flatpak', 'xdgapp'], + 'application/vnd.flatpak.ref' => ['flatpakref'], + 'application/vnd.flatpak.repo' => ['flatpakrepo'], + 'application/vnd.flographit' => ['gph'], + 'application/vnd.fluxtime.clip' => ['ftc'], + 'application/vnd.framemaker' => ['fm', 'frame', 'maker', 'book'], + 'application/vnd.frogans.fnc' => ['fnc'], + 'application/vnd.frogans.ltf' => ['ltf'], + 'application/vnd.fsc.weblaunch' => ['fsc'], + 'application/vnd.fujitsu.oasys' => ['oas'], + 'application/vnd.fujitsu.oasys2' => ['oa2'], + 'application/vnd.fujitsu.oasys3' => ['oa3'], + 'application/vnd.fujitsu.oasysgp' => ['fg5'], + 'application/vnd.fujitsu.oasysprs' => ['bh2'], + 'application/vnd.fujixerox.ddd' => ['ddd'], + 'application/vnd.fujixerox.docuworks' => ['xdw'], + 'application/vnd.fujixerox.docuworks.binder' => ['xbd'], + 'application/vnd.fuzzysheet' => ['fzs'], + 'application/vnd.genomatix.tuxedo' => ['txd'], + 'application/vnd.geo+json' => ['geojson', 'geo.json'], + 'application/vnd.geogebra.file' => ['ggb'], + 'application/vnd.geogebra.tool' => ['ggt'], + 'application/vnd.geometry-explorer' => ['gex', 'gre'], + 'application/vnd.geonext' => ['gxt'], + 'application/vnd.geoplan' => ['g2w'], + 'application/vnd.geospace' => ['g3w'], + 'application/vnd.gmx' => ['gmx'], + 'application/vnd.google-apps.document' => ['gdoc'], + 'application/vnd.google-apps.presentation' => ['gslides'], + 'application/vnd.google-apps.spreadsheet' => ['gsheet'], + 'application/vnd.google-earth.kml+xml' => ['kml'], + 'application/vnd.google-earth.kmz' => ['kmz'], + 'application/vnd.grafeq' => ['gqf', 'gqs'], + 'application/vnd.groove-account' => ['gac'], + 'application/vnd.groove-help' => ['ghf'], + 'application/vnd.groove-identity-message' => ['gim'], + 'application/vnd.groove-injector' => ['grv'], + 'application/vnd.groove-tool-message' => ['gtm'], + 'application/vnd.groove-tool-template' => ['tpl'], + 'application/vnd.groove-vcard' => ['vcg'], + 'application/vnd.haansoft-hwp' => ['hwp'], + 'application/vnd.haansoft-hwt' => ['hwt'], + 'application/vnd.hal+xml' => ['hal'], + 'application/vnd.handheld-entertainment+xml' => ['zmm'], + 'application/vnd.hbci' => ['hbci'], + 'application/vnd.hhe.lesson-player' => ['les'], + 'application/vnd.hp-hpgl' => ['hpgl'], + 'application/vnd.hp-hpid' => ['hpid'], + 'application/vnd.hp-hps' => ['hps'], + 'application/vnd.hp-jlyt' => ['jlt'], + 'application/vnd.hp-pcl' => ['pcl'], + 'application/vnd.hp-pclxl' => ['pclxl'], + 'application/vnd.hydrostatix.sof-data' => ['sfd-hdstx'], + 'application/vnd.ibm.minipay' => ['mpy'], + 'application/vnd.ibm.modcap' => ['afp', 'listafp', 'list3820'], + 'application/vnd.ibm.rights-management' => ['irm'], + 'application/vnd.ibm.secure-container' => ['sc'], + 'application/vnd.iccprofile' => ['icc', 'icm'], + 'application/vnd.igloader' => ['igl'], + 'application/vnd.immervision-ivp' => ['ivp'], + 'application/vnd.immervision-ivu' => ['ivu'], + 'application/vnd.insors.igm' => ['igm'], + 'application/vnd.intercon.formnet' => ['xpw', 'xpx'], + 'application/vnd.intergeo' => ['i2g'], + 'application/vnd.intu.qbo' => ['qbo'], + 'application/vnd.intu.qfx' => ['qfx'], + 'application/vnd.ipunplugged.rcprofile' => ['rcprofile'], + 'application/vnd.irepository.package+xml' => ['irp'], + 'application/vnd.is-xpr' => ['xpr'], + 'application/vnd.isac.fcs' => ['fcs'], + 'application/vnd.jam' => ['jam'], + 'application/vnd.jcp.javame.midlet-rms' => ['rms'], + 'application/vnd.jisp' => ['jisp'], + 'application/vnd.joost.joda-archive' => ['joda'], + 'application/vnd.kahootz' => ['ktz', 'ktr'], + 'application/vnd.kde.karbon' => ['karbon'], + 'application/vnd.kde.kchart' => ['chrt'], + 'application/vnd.kde.kformula' => ['kfo'], + 'application/vnd.kde.kivio' => ['flw'], + 'application/vnd.kde.kontour' => ['kon'], + 'application/vnd.kde.kpresenter' => ['kpr', 'kpt'], + 'application/vnd.kde.kspread' => ['ksp'], + 'application/vnd.kde.kword' => ['kwd', 'kwt'], + 'application/vnd.kenameaapp' => ['htke'], + 'application/vnd.kidspiration' => ['kia'], + 'application/vnd.kinar' => ['kne', 'knp'], + 'application/vnd.koan' => ['skp', 'skd', 'skt', 'skm'], + 'application/vnd.kodak-descriptor' => ['sse'], + 'application/vnd.las.las+xml' => ['lasxml'], + 'application/vnd.llamagraphics.life-balance.desktop' => ['lbd'], + 'application/vnd.llamagraphics.life-balance.exchange+xml' => ['lbe'], + 'application/vnd.lotus-1-2-3' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'application/vnd.lotus-approach' => ['apr'], + 'application/vnd.lotus-freelance' => ['pre'], + 'application/vnd.lotus-notes' => ['nsf'], + 'application/vnd.lotus-organizer' => ['org'], + 'application/vnd.lotus-screencam' => ['scm'], + 'application/vnd.lotus-wordpro' => ['lwp'], + 'application/vnd.macports.portpkg' => ['portpkg'], + 'application/vnd.mapbox-vector-tile' => ['mvt'], + 'application/vnd.mcd' => ['mcd'], + 'application/vnd.medcalcdata' => ['mc1'], + 'application/vnd.mediastation.cdkey' => ['cdkey'], + 'application/vnd.mfer' => ['mwf'], + 'application/vnd.mfmp' => ['mfm'], + 'application/vnd.micrografx.flo' => ['flo'], + 'application/vnd.micrografx.igx' => ['igx'], + 'application/vnd.mif' => ['mif'], + 'application/vnd.mobius.daf' => ['daf'], + 'application/vnd.mobius.dis' => ['dis'], + 'application/vnd.mobius.mbk' => ['mbk'], + 'application/vnd.mobius.mqy' => ['mqy'], + 'application/vnd.mobius.msl' => ['msl'], + 'application/vnd.mobius.plc' => ['plc'], + 'application/vnd.mobius.txf' => ['txf'], + 'application/vnd.mophun.application' => ['mpn'], + 'application/vnd.mophun.certificate' => ['mpc'], + 'application/vnd.mozilla.xul+xml' => ['xul'], + 'application/vnd.ms-access' => ['mdb'], + 'application/vnd.ms-artgalry' => ['cil'], + 'application/vnd.ms-asf' => ['asf'], + 'application/vnd.ms-cab-compressed' => ['cab'], + 'application/vnd.ms-excel' => ['xls', 'xlm', 'xla', 'xlc', 'xlt', 'xlw', 'xll', 'xld'], + 'application/vnd.ms-excel.addin.macroenabled.12' => ['xlam'], + 'application/vnd.ms-excel.sheet.binary.macroenabled.12' => ['xlsb'], + 'application/vnd.ms-excel.sheet.macroenabled.12' => ['xlsm'], + 'application/vnd.ms-excel.template.macroenabled.12' => ['xltm'], + 'application/vnd.ms-fontobject' => ['eot'], + 'application/vnd.ms-htmlhelp' => ['chm'], + 'application/vnd.ms-ims' => ['ims'], + 'application/vnd.ms-lrm' => ['lrm'], + 'application/vnd.ms-officetheme' => ['thmx'], + 'application/vnd.ms-outlook' => ['msg'], + 'application/vnd.ms-pki.seccat' => ['cat'], + 'application/vnd.ms-pki.stl' => ['stl'], + 'application/vnd.ms-powerpoint' => ['ppt', 'pps', 'pot', 'ppz'], + 'application/vnd.ms-powerpoint.addin.macroenabled.12' => ['ppam'], + 'application/vnd.ms-powerpoint.presentation.macroenabled.12' => ['pptm'], + 'application/vnd.ms-powerpoint.slide.macroenabled.12' => ['sldm'], + 'application/vnd.ms-powerpoint.slideshow.macroenabled.12' => ['ppsm'], + 'application/vnd.ms-powerpoint.template.macroenabled.12' => ['potm'], + 'application/vnd.ms-project' => ['mpp', 'mpt'], + 'application/vnd.ms-publisher' => ['pub'], + 'application/vnd.ms-tnef' => ['tnef', 'tnf'], + 'application/vnd.ms-visio.drawing.macroenabled.main+xml' => ['vsdm'], + 'application/vnd.ms-visio.drawing.main+xml' => ['vsdx'], + 'application/vnd.ms-visio.stencil.macroenabled.main+xml' => ['vssm'], + 'application/vnd.ms-visio.stencil.main+xml' => ['vssx'], + 'application/vnd.ms-visio.template.macroenabled.main+xml' => ['vstm'], + 'application/vnd.ms-visio.template.main+xml' => ['vstx'], + 'application/vnd.ms-word' => ['doc'], + 'application/vnd.ms-word.document.macroenabled.12' => ['docm'], + 'application/vnd.ms-word.template.macroenabled.12' => ['dotm'], + 'application/vnd.ms-works' => ['wps', 'wks', 'wcm', 'wdb', 'xlr'], + 'application/vnd.ms-wpl' => ['wpl'], + 'application/vnd.ms-xpsdocument' => ['xps'], + 'application/vnd.msaccess' => ['mdb'], + 'application/vnd.mseq' => ['mseq'], + 'application/vnd.musician' => ['mus'], + 'application/vnd.muvee.style' => ['msty'], + 'application/vnd.mynfc' => ['taglet'], + 'application/vnd.neurolanguage.nlu' => ['nlu'], + 'application/vnd.nintendo.snes.rom' => ['sfc', 'smc'], + 'application/vnd.nitf' => ['ntf', 'nitf'], + 'application/vnd.noblenet-directory' => ['nnd'], + 'application/vnd.noblenet-sealer' => ['nns'], + 'application/vnd.noblenet-web' => ['nnw'], + 'application/vnd.nokia.n-gage.ac+xml' => ['ac'], + 'application/vnd.nokia.n-gage.data' => ['ngdat'], + 'application/vnd.nokia.n-gage.symbian.install' => ['n-gage'], + 'application/vnd.nokia.radio-preset' => ['rpst'], + 'application/vnd.nokia.radio-presets' => ['rpss'], + 'application/vnd.novadigm.edm' => ['edm'], + 'application/vnd.novadigm.edx' => ['edx'], + 'application/vnd.novadigm.ext' => ['ext'], + 'application/vnd.oasis.docbook+xml' => ['dbk', 'docbook'], + 'application/vnd.oasis.opendocument.chart' => ['odc'], + 'application/vnd.oasis.opendocument.chart-template' => ['otc'], + 'application/vnd.oasis.opendocument.database' => ['odb'], + 'application/vnd.oasis.opendocument.formula' => ['odf'], + 'application/vnd.oasis.opendocument.formula-template' => ['odft', 'otf'], + 'application/vnd.oasis.opendocument.graphics' => ['odg'], + 'application/vnd.oasis.opendocument.graphics-flat-xml' => ['fodg'], + 'application/vnd.oasis.opendocument.graphics-template' => ['otg'], + 'application/vnd.oasis.opendocument.image' => ['odi'], + 'application/vnd.oasis.opendocument.image-template' => ['oti'], + 'application/vnd.oasis.opendocument.presentation' => ['odp'], + 'application/vnd.oasis.opendocument.presentation-flat-xml' => ['fodp'], + 'application/vnd.oasis.opendocument.presentation-template' => ['otp'], + 'application/vnd.oasis.opendocument.spreadsheet' => ['ods'], + 'application/vnd.oasis.opendocument.spreadsheet-flat-xml' => ['fods'], + 'application/vnd.oasis.opendocument.spreadsheet-template' => ['ots'], + 'application/vnd.oasis.opendocument.text' => ['odt'], + 'application/vnd.oasis.opendocument.text-flat-xml' => ['fodt'], + 'application/vnd.oasis.opendocument.text-master' => ['odm'], + 'application/vnd.oasis.opendocument.text-template' => ['ott'], + 'application/vnd.oasis.opendocument.text-web' => ['oth'], + 'application/vnd.olpc-sugar' => ['xo'], + 'application/vnd.oma.dd2+xml' => ['dd2'], + 'application/vnd.openblox.game+xml' => ['obgx'], + 'application/vnd.openofficeorg.extension' => ['oxt'], + 'application/vnd.openstreetmap.data+xml' => ['osm'], + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => ['pptx'], + 'application/vnd.openxmlformats-officedocument.presentationml.slide' => ['sldx'], + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => ['ppsx'], + 'application/vnd.openxmlformats-officedocument.presentationml.template' => ['potx'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => ['xlsx'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => ['xltx'], + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => ['docx'], + 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => ['dotx'], + 'application/vnd.osgeo.mapguide.package' => ['mgp'], + 'application/vnd.osgi.dp' => ['dp'], + 'application/vnd.osgi.subsystem' => ['esa'], + 'application/vnd.palm' => ['pdb', 'pqa', 'oprc', 'prc'], + 'application/vnd.pawaafile' => ['paw'], + 'application/vnd.pg.format' => ['str'], + 'application/vnd.pg.osasli' => ['ei6'], + 'application/vnd.picsel' => ['efif'], + 'application/vnd.pmi.widget' => ['wg'], + 'application/vnd.pocketlearn' => ['plf'], + 'application/vnd.powerbuilder6' => ['pbd'], + 'application/vnd.previewsystems.box' => ['box'], + 'application/vnd.proteus.magazine' => ['mgz'], + 'application/vnd.publishare-delta-tree' => ['qps'], + 'application/vnd.pvi.ptid1' => ['ptid'], + 'application/vnd.quark.quarkxpress' => ['qxd', 'qxt', 'qwd', 'qwt', 'qxl', 'qxb'], + 'application/vnd.rar' => ['rar'], + 'application/vnd.realvnc.bed' => ['bed'], + 'application/vnd.recordare.musicxml' => ['mxl'], + 'application/vnd.recordare.musicxml+xml' => ['musicxml'], + 'application/vnd.rig.cryptonote' => ['cryptonote'], + 'application/vnd.rim.cod' => ['cod'], + 'application/vnd.rn-realmedia' => ['rm', 'rmj', 'rmm', 'rms', 'rmx', 'rmvb'], + 'application/vnd.rn-realmedia-vbr' => ['rmvb', 'rm', 'rmj', 'rmm', 'rms', 'rmx'], + 'application/vnd.route66.link66+xml' => ['link66'], + 'application/vnd.sailingtracker.track' => ['st'], + 'application/vnd.sdp' => ['sdp'], + 'application/vnd.seemail' => ['see'], + 'application/vnd.sema' => ['sema'], + 'application/vnd.semd' => ['semd'], + 'application/vnd.semf' => ['semf'], + 'application/vnd.shana.informed.formdata' => ['ifm'], + 'application/vnd.shana.informed.formtemplate' => ['itp'], + 'application/vnd.shana.informed.interchange' => ['iif'], + 'application/vnd.shana.informed.package' => ['ipk'], + 'application/vnd.simtech-mindmapper' => ['twd', 'twds'], + 'application/vnd.smaf' => ['mmf', 'smaf'], + 'application/vnd.smart.teacher' => ['teacher'], + 'application/vnd.snap' => ['snap'], + 'application/vnd.software602.filler.form+xml' => ['fo'], + 'application/vnd.solent.sdkm+xml' => ['sdkm', 'sdkd'], + 'application/vnd.spotfire.dxp' => ['dxp'], + 'application/vnd.spotfire.sfs' => ['sfs'], + 'application/vnd.sqlite3' => ['sqlite3'], + 'application/vnd.squashfs' => ['sqsh'], + 'application/vnd.stardivision.calc' => ['sdc'], + 'application/vnd.stardivision.chart' => ['sds'], + 'application/vnd.stardivision.draw' => ['sda'], + 'application/vnd.stardivision.impress' => ['sdd', 'sdp'], + 'application/vnd.stardivision.mail' => ['smd'], + 'application/vnd.stardivision.math' => ['smf'], + 'application/vnd.stardivision.writer' => ['sdw', 'vor', 'sgl'], + 'application/vnd.stardivision.writer-global' => ['sgl', 'sdw', 'vor'], + 'application/vnd.stepmania.package' => ['smzip'], + 'application/vnd.stepmania.stepchart' => ['sm'], + 'application/vnd.sun.wadl+xml' => ['wadl'], + 'application/vnd.sun.xml.base' => ['odb'], + 'application/vnd.sun.xml.calc' => ['sxc'], + 'application/vnd.sun.xml.calc.template' => ['stc'], + 'application/vnd.sun.xml.draw' => ['sxd'], + 'application/vnd.sun.xml.draw.template' => ['std'], + 'application/vnd.sun.xml.impress' => ['sxi'], + 'application/vnd.sun.xml.impress.template' => ['sti'], + 'application/vnd.sun.xml.math' => ['sxm'], + 'application/vnd.sun.xml.writer' => ['sxw'], + 'application/vnd.sun.xml.writer.global' => ['sxg'], + 'application/vnd.sun.xml.writer.template' => ['stw'], + 'application/vnd.sus-calendar' => ['sus', 'susp'], + 'application/vnd.svd' => ['svd'], + 'application/vnd.symbian.install' => ['sis', 'sisx'], + 'application/vnd.syncml+xml' => ['xsm'], + 'application/vnd.syncml.dm+wbxml' => ['bdm'], + 'application/vnd.syncml.dm+xml' => ['xdm'], + 'application/vnd.syncml.dmddf+xml' => ['ddf'], + 'application/vnd.tao.intent-module-archive' => ['tao'], + 'application/vnd.tcpdump.pcap' => ['pcap', 'cap', 'dmp'], + 'application/vnd.tmobile-livetv' => ['tmo'], + 'application/vnd.trid.tpt' => ['tpt'], + 'application/vnd.triscape.mxs' => ['mxs'], + 'application/vnd.trueapp' => ['tra'], + 'application/vnd.ufdl' => ['ufd', 'ufdl'], + 'application/vnd.uiq.theme' => ['utz'], + 'application/vnd.umajin' => ['umj'], + 'application/vnd.unity' => ['unityweb'], + 'application/vnd.uoml+xml' => ['uoml'], + 'application/vnd.vcx' => ['vcx'], + 'application/vnd.visio' => ['vsd', 'vst', 'vss', 'vsw'], + 'application/vnd.visionary' => ['vis'], + 'application/vnd.vsf' => ['vsf'], + 'application/vnd.wap.wbxml' => ['wbxml'], + 'application/vnd.wap.wmlc' => ['wmlc'], + 'application/vnd.wap.wmlscriptc' => ['wmlsc'], + 'application/vnd.webturbo' => ['wtb'], + 'application/vnd.wolfram.player' => ['nbp'], + 'application/vnd.wordperfect' => ['wpd', 'wp', 'wp4', 'wp5', 'wp6', 'wpp'], + 'application/vnd.wqd' => ['wqd'], + 'application/vnd.wt.stf' => ['stf'], + 'application/vnd.xara' => ['xar'], + 'application/vnd.xdgapp' => ['flatpak', 'xdgapp'], + 'application/vnd.xfdl' => ['xfdl'], + 'application/vnd.yamaha.hv-dic' => ['hvd'], + 'application/vnd.yamaha.hv-script' => ['hvs'], + 'application/vnd.yamaha.hv-voice' => ['hvp'], + 'application/vnd.yamaha.openscoreformat' => ['osf'], + 'application/vnd.yamaha.openscoreformat.osfpvg+xml' => ['osfpvg'], + 'application/vnd.yamaha.smaf-audio' => ['saf'], + 'application/vnd.yamaha.smaf-phrase' => ['spf'], + 'application/vnd.yellowriver-custom-menu' => ['cmp'], + 'application/vnd.youtube.yt' => ['yt'], + 'application/vnd.zul' => ['zir', 'zirz'], + 'application/vnd.zzazz.deck+xml' => ['zaz'], + 'application/voicexml+xml' => ['vxml'], + 'application/wasm' => ['wasm'], + 'application/widget' => ['wgt'], + 'application/winhlp' => ['hlp'], + 'application/wk1' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'application/wmf' => ['wmf'], + 'application/wordperfect' => ['wp', 'wp4', 'wp5', 'wp6', 'wpd', 'wpp'], + 'application/wsdl+xml' => ['wsdl'], + 'application/wspolicy+xml' => ['wspolicy'], + 'application/wwf' => ['wwf'], + 'application/x-123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'application/x-7z-compressed' => ['7z', '7z.001'], + 'application/x-abiword' => ['abw', 'abw.CRASHED', 'abw.gz', 'zabw'], + 'application/x-ace' => ['ace'], + 'application/x-ace-compressed' => ['ace'], + 'application/x-alz' => ['alz'], + 'application/x-amiga-disk-format' => ['adf'], + 'application/x-amipro' => ['sam'], + 'application/x-annodex' => ['anx'], + 'application/x-aportisdoc' => ['pdb', 'pdc'], + 'application/x-apple-diskimage' => ['dmg'], + 'application/x-apple-systemprofiler+xml' => ['spx'], + 'application/x-appleworks-document' => ['cwk'], + 'application/x-applix-spreadsheet' => ['as'], + 'application/x-applix-word' => ['aw'], + 'application/x-archive' => ['a', 'ar'], + 'application/x-arj' => ['arj'], + 'application/x-asp' => ['asp'], + 'application/x-atari-2600-rom' => ['a26'], + 'application/x-atari-7800-rom' => ['a78'], + 'application/x-atari-lynx-rom' => ['lnx'], + 'application/x-authorware-bin' => ['aab', 'x32', 'u32', 'vox'], + 'application/x-authorware-map' => ['aam'], + 'application/x-authorware-seg' => ['aas'], + 'application/x-awk' => ['awk'], + 'application/x-bcpio' => ['bcpio'], + 'application/x-bdoc' => ['bdoc'], + 'application/x-bittorrent' => ['torrent'], + 'application/x-blender' => ['blender', 'blend', 'BLEND'], + 'application/x-blorb' => ['blb', 'blorb'], + 'application/x-bps-patch' => ['bps'], + 'application/x-bsdiff' => ['bsdiff'], + 'application/x-bz2' => ['bz2'], + 'application/x-bzdvi' => ['dvi.bz2'], + 'application/x-bzip' => ['bz', 'bz2'], + 'application/x-bzip-compressed-tar' => ['tar.bz2', 'tar.bz', 'tbz2', 'tbz', 'tb2'], + 'application/x-bzip2' => ['bz2', 'boz', 'bz'], + 'application/x-bzpdf' => ['pdf.bz2'], + 'application/x-bzpostscript' => ['ps.bz2'], + 'application/x-cb7' => ['cb7'], + 'application/x-cbr' => ['cbr', 'cba', 'cbt', 'cbz', 'cb7'], + 'application/x-cbt' => ['cbt'], + 'application/x-cbz' => ['cbz'], + 'application/x-ccmx' => ['ccmx'], + 'application/x-cd-image' => ['iso', 'iso9660'], + 'application/x-cdlink' => ['vcd'], + 'application/x-cdr' => ['cdr'], + 'application/x-cdrdao-toc' => ['toc'], + 'application/x-cfs-compressed' => ['cfs'], + 'application/x-chat' => ['chat'], + 'application/x-chess-pgn' => ['pgn'], + 'application/x-chm' => ['chm'], + 'application/x-chrome-extension' => ['crx'], + 'application/x-cisco-vpn-settings' => ['pcf'], + 'application/x-cocoa' => ['cco'], + 'application/x-compress' => ['Z'], + 'application/x-compressed-iso' => ['cso'], + 'application/x-compressed-tar' => ['tar.gz', 'tgz'], + 'application/x-conference' => ['nsc'], + 'application/x-coreldraw' => ['cdr'], + 'application/x-cpio' => ['cpio'], + 'application/x-cpio-compressed' => ['cpio.gz'], + 'application/x-csh' => ['csh'], + 'application/x-cue' => ['cue'], + 'application/x-dar' => ['dar'], + 'application/x-dbase' => ['dbf'], + 'application/x-dbf' => ['dbf'], + 'application/x-dc-rom' => ['dc'], + 'application/x-deb' => ['deb', 'udeb'], + 'application/x-debian-package' => ['deb', 'udeb'], + 'application/x-designer' => ['ui'], + 'application/x-desktop' => ['desktop', 'kdelnk'], + 'application/x-dgc-compressed' => ['dgc'], + 'application/x-dia-diagram' => ['dia'], + 'application/x-dia-shape' => ['shape'], + 'application/x-director' => ['dir', 'dcr', 'dxr', 'cst', 'cct', 'cxt', 'w3d', 'fgd', 'swa'], + 'application/x-discjuggler-cd-image' => ['cdi'], + 'application/x-docbook+xml' => ['dbk', 'docbook'], + 'application/x-doom' => ['wad'], + 'application/x-doom-wad' => ['wad'], + 'application/x-dreamcast-rom' => ['iso'], + 'application/x-dtbncx+xml' => ['ncx'], + 'application/x-dtbook+xml' => ['dtb'], + 'application/x-dtbresource+xml' => ['res'], + 'application/x-dvi' => ['dvi'], + 'application/x-e-theme' => ['etheme'], + 'application/x-egon' => ['egon'], + 'application/x-emf' => ['emf'], + 'application/x-envoy' => ['evy'], + 'application/x-eva' => ['eva'], + 'application/x-fd-file' => ['fd', 'qd'], + 'application/x-fds-disk' => ['fds'], + 'application/x-fictionbook' => ['fb2'], + 'application/x-fictionbook+xml' => ['fb2'], + 'application/x-flash-video' => ['flv'], + 'application/x-fluid' => ['fl'], + 'application/x-font-afm' => ['afm'], + 'application/x-font-bdf' => ['bdf'], + 'application/x-font-ghostscript' => ['gsf'], + 'application/x-font-linux-psf' => ['psf'], + 'application/x-font-otf' => ['otf'], + 'application/x-font-pcf' => ['pcf', 'pcf.Z', 'pcf.gz'], + 'application/x-font-snf' => ['snf'], + 'application/x-font-speedo' => ['spd'], + 'application/x-font-truetype' => ['ttf'], + 'application/x-font-ttf' => ['ttf'], + 'application/x-font-ttx' => ['ttx'], + 'application/x-font-type1' => ['pfa', 'pfb', 'pfm', 'afm', 'gsf'], + 'application/x-font-woff' => ['woff'], + 'application/x-frame' => ['fm'], + 'application/x-freearc' => ['arc'], + 'application/x-futuresplash' => ['spl'], + 'application/x-gameboy-color-rom' => ['gbc', 'cgb'], + 'application/x-gameboy-rom' => ['gb', 'sgb'], + 'application/x-gamecube-iso-image' => ['iso'], + 'application/x-gamecube-rom' => ['iso'], + 'application/x-gamegear-rom' => ['gg'], + 'application/x-gba-rom' => ['gba', 'agb'], + 'application/x-gca-compressed' => ['gca'], + 'application/x-gd-rom-cue' => ['gdi'], + 'application/x-gedcom' => ['ged', 'gedcom'], + 'application/x-genesis-32x-rom' => ['32x', 'mdx'], + 'application/x-genesis-rom' => ['gen', 'smd', 'sgd'], + 'application/x-gettext' => ['po'], + 'application/x-gettext-translation' => ['gmo', 'mo'], + 'application/x-glade' => ['glade'], + 'application/x-glulx' => ['ulx'], + 'application/x-gnome-app-info' => ['desktop', 'kdelnk'], + 'application/x-gnucash' => ['gnucash', 'gnc', 'xac'], + 'application/x-gnumeric' => ['gnumeric'], + 'application/x-gnuplot' => ['gp', 'gplt', 'gnuplot'], + 'application/x-go-sgf' => ['sgf'], + 'application/x-gpx' => ['gpx'], + 'application/x-gpx+xml' => ['gpx'], + 'application/x-gramps-xml' => ['gramps'], + 'application/x-graphite' => ['gra'], + 'application/x-gtar' => ['gtar', 'tar', 'gem'], + 'application/x-gtk-builder' => ['ui'], + 'application/x-gz-font-linux-psf' => ['psf.gz'], + 'application/x-gzdvi' => ['dvi.gz'], + 'application/x-gzip' => ['gz'], + 'application/x-gzpdf' => ['pdf.gz'], + 'application/x-gzpostscript' => ['ps.gz'], + 'application/x-hdf' => ['hdf', 'hdf4', 'h4', 'hdf5', 'h5'], + 'application/x-hfe-file' => ['hfe'], + 'application/x-hfe-floppy-image' => ['hfe'], + 'application/x-httpd-php' => ['php'], + 'application/x-hwp' => ['hwp'], + 'application/x-hwt' => ['hwt'], + 'application/x-ica' => ['ica'], + 'application/x-install-instructions' => ['install'], + 'application/x-ips-patch' => ['ips'], + 'application/x-ipynb+json' => ['ipynb'], + 'application/x-iso9660-appimage' => ['appimage'], + 'application/x-iso9660-image' => ['iso', 'iso9660'], + 'application/x-it87' => ['it87'], + 'application/x-iwork-keynote-sffkey' => ['key'], + 'application/x-iwork-numbers-sffnumbers' => ['numbers'], + 'application/x-iwork-pages-sffpages' => ['pages'], + 'application/x-jar' => ['jar'], + 'application/x-java' => ['class'], + 'application/x-java-archive' => ['jar'], + 'application/x-java-archive-diff' => ['jardiff'], + 'application/x-java-class' => ['class'], + 'application/x-java-jce-keystore' => ['jceks'], + 'application/x-java-jnlp-file' => ['jnlp'], + 'application/x-java-keystore' => ['jks', 'ks'], + 'application/x-java-pack200' => ['pack'], + 'application/x-java-vm' => ['class'], + 'application/x-javascript' => ['js', 'jsm', 'mjs'], + 'application/x-jbuilder-project' => ['jpr', 'jpx'], + 'application/x-karbon' => ['karbon'], + 'application/x-kchart' => ['chrt'], + 'application/x-keepass2' => ['kdbx'], + 'application/x-kexi-connectiondata' => ['kexic'], + 'application/x-kexiproject-shortcut' => ['kexis'], + 'application/x-kexiproject-sqlite' => ['kexi'], + 'application/x-kexiproject-sqlite2' => ['kexi'], + 'application/x-kexiproject-sqlite3' => ['kexi'], + 'application/x-kformula' => ['kfo'], + 'application/x-killustrator' => ['kil'], + 'application/x-kivio' => ['flw'], + 'application/x-kontour' => ['kon'], + 'application/x-kpovmodeler' => ['kpm'], + 'application/x-kpresenter' => ['kpr', 'kpt'], + 'application/x-krita' => ['kra', 'krz'], + 'application/x-kspread' => ['ksp'], + 'application/x-kugar' => ['kud'], + 'application/x-kword' => ['kwd', 'kwt'], + 'application/x-latex' => ['latex'], + 'application/x-lha' => ['lha', 'lzh'], + 'application/x-lhz' => ['lhz'], + 'application/x-linguist' => ['ts'], + 'application/x-lotus123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'application/x-lrzip' => ['lrz'], + 'application/x-lrzip-compressed-tar' => ['tar.lrz', 'tlrz'], + 'application/x-lua-bytecode' => ['luac'], + 'application/x-lyx' => ['lyx'], + 'application/x-lz4' => ['lz4'], + 'application/x-lz4-compressed-tar' => ['tar.lz4'], + 'application/x-lzh-compressed' => ['lzh', 'lha'], + 'application/x-lzip' => ['lz'], + 'application/x-lzip-compressed-tar' => ['tar.lz'], + 'application/x-lzma' => ['lzma'], + 'application/x-lzma-compressed-tar' => ['tar.lzma', 'tlz'], + 'application/x-lzop' => ['lzo'], + 'application/x-lzpdf' => ['pdf.lz'], + 'application/x-m4' => ['m4'], + 'application/x-magicpoint' => ['mgp'], + 'application/x-makeself' => ['run'], + 'application/x-mame-chd' => ['chd'], + 'application/x-markaby' => ['mab'], + 'application/x-mathematica' => ['nb'], + 'application/x-mdb' => ['mdb'], + 'application/x-mie' => ['mie'], + 'application/x-mif' => ['mif'], + 'application/x-mimearchive' => ['mhtml', 'mht'], + 'application/x-mobi8-ebook' => ['azw3', 'kfx'], + 'application/x-mobipocket-ebook' => ['prc', 'mobi'], + 'application/x-ms-application' => ['application'], + 'application/x-ms-asx' => ['asx', 'wax', 'wvx', 'wmx'], + 'application/x-ms-dos-executable' => ['exe'], + 'application/x-ms-shortcut' => ['lnk'], + 'application/x-ms-wim' => ['wim', 'swm'], + 'application/x-ms-wmd' => ['wmd'], + 'application/x-ms-wmz' => ['wmz'], + 'application/x-ms-xbap' => ['xbap'], + 'application/x-msaccess' => ['mdb'], + 'application/x-msbinder' => ['obd'], + 'application/x-mscardfile' => ['crd'], + 'application/x-msclip' => ['clp'], + 'application/x-msdos-program' => ['exe'], + 'application/x-msdownload' => ['exe', 'dll', 'com', 'bat', 'msi'], + 'application/x-msexcel' => ['xls', 'xlc', 'xll', 'xlm', 'xlw', 'xla', 'xlt', 'xld'], + 'application/x-msi' => ['msi'], + 'application/x-msmediaview' => ['mvb', 'm13', 'm14'], + 'application/x-msmetafile' => ['wmf', 'wmz', 'emf', 'emz'], + 'application/x-msmoney' => ['mny'], + 'application/x-mspowerpoint' => ['ppz', 'ppt', 'pps', 'pot'], + 'application/x-mspublisher' => ['pub'], + 'application/x-msschedule' => ['scd'], + 'application/x-msterminal' => ['trm'], + 'application/x-mswinurl' => ['url'], + 'application/x-msword' => ['doc'], + 'application/x-mswrite' => ['wri'], + 'application/x-msx-rom' => ['msx'], + 'application/x-n64-rom' => ['n64', 'z64', 'v64'], + 'application/x-navi-animation' => ['ani'], + 'application/x-neo-geo-pocket-color-rom' => ['ngc'], + 'application/x-neo-geo-pocket-rom' => ['ngp'], + 'application/x-nes-rom' => ['nes', 'nez', 'unf', 'unif'], + 'application/x-netcdf' => ['nc', 'cdf'], + 'application/x-netshow-channel' => ['nsc'], + 'application/x-nintendo-3ds-executable' => ['3dsx'], + 'application/x-nintendo-3ds-rom' => ['3ds', 'cci'], + 'application/x-nintendo-ds-rom' => ['nds'], + 'application/x-ns-proxy-autoconfig' => ['pac'], + 'application/x-nzb' => ['nzb'], + 'application/x-object' => ['o', 'mod'], + 'application/x-ogg' => ['ogx'], + 'application/x-oleo' => ['oleo'], + 'application/x-pagemaker' => ['p65', 'pm', 'pm6', 'pmd'], + 'application/x-pak' => ['pak'], + 'application/x-palm-database' => ['prc', 'pdb', 'pqa', 'oprc'], + 'application/x-par2' => ['PAR2', 'par2'], + 'application/x-partial-download' => ['wkdownload', 'crdownload', 'part'], + 'application/x-pc-engine-rom' => ['pce'], + 'application/x-pcap' => ['pcap', 'cap', 'dmp'], + 'application/x-pdf' => ['pdf'], + 'application/x-perl' => ['pl', 'pm', 'PL', 'al', 'perl', 'pod', 't'], + 'application/x-photoshop' => ['psd'], + 'application/x-php' => ['php', 'php3', 'php4', 'php5', 'phps'], + 'application/x-pilot' => ['prc', 'pdb'], + 'application/x-pkcs12' => ['p12', 'pfx'], + 'application/x-pkcs7-certificates' => ['p7b', 'spc'], + 'application/x-pkcs7-certreqresp' => ['p7r'], + 'application/x-planperfect' => ['pln'], + 'application/x-pocket-word' => ['psw'], + 'application/x-pw' => ['pw'], + 'application/x-pyspread-bz-spreadsheet' => ['pys'], + 'application/x-pyspread-spreadsheet' => ['pysu'], + 'application/x-python-bytecode' => ['pyc', 'pyo'], + 'application/x-qed-disk' => ['qed'], + 'application/x-qemu-disk' => ['qcow2', 'qcow'], + 'application/x-qpress' => ['qp'], + 'application/x-qtiplot' => ['qti', 'qti.gz'], + 'application/x-quattropro' => ['wb1', 'wb2', 'wb3'], + 'application/x-quicktime-media-link' => ['qtl'], + 'application/x-quicktimeplayer' => ['qtl'], + 'application/x-qw' => ['qif'], + 'application/x-rar' => ['rar'], + 'application/x-rar-compressed' => ['rar'], + 'application/x-raw-disk-image' => ['raw-disk-image', 'img'], + 'application/x-raw-disk-image-xz-compressed' => ['raw-disk-image.xz', 'img.xz'], + 'application/x-raw-floppy-disk-image' => ['fd', 'qd'], + 'application/x-redhat-package-manager' => ['rpm'], + 'application/x-reject' => ['rej'], + 'application/x-research-info-systems' => ['ris'], + 'application/x-rnc' => ['rnc'], + 'application/x-rpm' => ['rpm'], + 'application/x-ruby' => ['rb'], + 'application/x-sami' => ['smi', 'sami'], + 'application/x-sap-file' => ['sap'], + 'application/x-saturn-rom' => ['iso'], + 'application/x-sdp' => ['sdp'], + 'application/x-sea' => ['sea'], + 'application/x-sega-cd-rom' => ['iso'], + 'application/x-sega-pico-rom' => ['iso'], + 'application/x-sg1000-rom' => ['sg'], + 'application/x-sh' => ['sh'], + 'application/x-shar' => ['shar'], + 'application/x-shared-library-la' => ['la'], + 'application/x-sharedlib' => ['so'], + 'application/x-shellscript' => ['sh'], + 'application/x-shockwave-flash' => ['swf', 'spl'], + 'application/x-shorten' => ['shn'], + 'application/x-siag' => ['siag'], + 'application/x-silverlight-app' => ['xap'], + 'application/x-sit' => ['sit'], + 'application/x-smaf' => ['mmf', 'smaf'], + 'application/x-sms-rom' => ['sms'], + 'application/x-snes-rom' => ['sfc', 'smc'], + 'application/x-source-rpm' => ['src.rpm', 'spm'], + 'application/x-spss-por' => ['por'], + 'application/x-spss-sav' => ['sav', 'zsav'], + 'application/x-spss-savefile' => ['sav', 'zsav'], + 'application/x-sql' => ['sql'], + 'application/x-sqlite2' => ['sqlite2'], + 'application/x-sqlite3' => ['sqlite3'], + 'application/x-srt' => ['srt'], + 'application/x-stuffit' => ['sit'], + 'application/x-stuffitx' => ['sitx'], + 'application/x-subrip' => ['srt'], + 'application/x-sv4cpio' => ['sv4cpio'], + 'application/x-sv4crc' => ['sv4crc'], + 'application/x-t3vm-image' => ['t3'], + 'application/x-t602' => ['602'], + 'application/x-tads' => ['gam'], + 'application/x-tar' => ['tar', 'gtar', 'gem'], + 'application/x-targa' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'application/x-tarz' => ['tar.Z', 'taz'], + 'application/x-tcl' => ['tcl', 'tk'], + 'application/x-tex' => ['tex', 'ltx', 'sty', 'cls', 'dtx', 'ins', 'latex'], + 'application/x-tex-gf' => ['gf'], + 'application/x-tex-pk' => ['pk'], + 'application/x-tex-tfm' => ['tfm'], + 'application/x-texinfo' => ['texinfo', 'texi'], + 'application/x-tga' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'application/x-tgif' => ['obj'], + 'application/x-theme' => ['theme'], + 'application/x-thomson-cartridge-memo7' => ['m7'], + 'application/x-thomson-cassette' => ['k7'], + 'application/x-thomson-sap-image' => ['sap'], + 'application/x-trash' => ['bak', 'old', 'sik'], + 'application/x-trig' => ['trig'], + 'application/x-troff' => ['tr', 'roff', 't'], + 'application/x-troff-man' => ['man'], + 'application/x-tzo' => ['tar.lzo', 'tzo'], + 'application/x-ufraw' => ['ufraw'], + 'application/x-ustar' => ['ustar'], + 'application/x-vdi-disk' => ['vdi'], + 'application/x-vhd-disk' => ['vhd', 'vpc'], + 'application/x-vhdx-disk' => ['vhdx'], + 'application/x-virtual-boy-rom' => ['vb'], + 'application/x-virtualbox-hdd' => ['hdd'], + 'application/x-virtualbox-ova' => ['ova'], + 'application/x-virtualbox-ovf' => ['ovf'], + 'application/x-virtualbox-vbox' => ['vbox'], + 'application/x-virtualbox-vbox-extpack' => ['vbox-extpack'], + 'application/x-virtualbox-vdi' => ['vdi'], + 'application/x-virtualbox-vhd' => ['vhd', 'vpc'], + 'application/x-virtualbox-vhdx' => ['vhdx'], + 'application/x-virtualbox-vmdk' => ['vmdk'], + 'application/x-vmdk-disk' => ['vmdk'], + 'application/x-vnd.kde.kexi' => ['kexi'], + 'application/x-wais-source' => ['src'], + 'application/x-wbfs' => ['iso'], + 'application/x-web-app-manifest+json' => ['webapp'], + 'application/x-wia' => ['iso'], + 'application/x-wii-iso-image' => ['iso'], + 'application/x-wii-rom' => ['iso'], + 'application/x-wii-wad' => ['wad'], + 'application/x-windows-themepack' => ['themepack'], + 'application/x-wmf' => ['wmf'], + 'application/x-wonderswan-color-rom' => ['wsc'], + 'application/x-wonderswan-rom' => ['ws'], + 'application/x-wordperfect' => ['wp', 'wp4', 'wp5', 'wp6', 'wpd', 'wpp'], + 'application/x-wpg' => ['wpg'], + 'application/x-wwf' => ['wwf'], + 'application/x-x509-ca-cert' => ['der', 'crt', 'pem', 'cert'], + 'application/x-xar' => ['xar', 'pkg'], + 'application/x-xbel' => ['xbel'], + 'application/x-xfig' => ['fig'], + 'application/x-xliff' => ['xlf', 'xliff'], + 'application/x-xliff+xml' => ['xlf'], + 'application/x-xpinstall' => ['xpi'], + 'application/x-xspf+xml' => ['xspf'], + 'application/x-xz' => ['xz'], + 'application/x-xz-compressed-tar' => ['tar.xz', 'txz'], + 'application/x-xzpdf' => ['pdf.xz'], + 'application/x-yaml' => ['yaml', 'yml'], + 'application/x-zip' => ['zip'], + 'application/x-zip-compressed' => ['zip'], + 'application/x-zip-compressed-fb2' => ['fb2.zip'], + 'application/x-zmachine' => ['z1', 'z2', 'z3', 'z4', 'z5', 'z6', 'z7', 'z8'], + 'application/x-zoo' => ['zoo'], + 'application/x-zstd-compressed-tar' => ['tar.zst', 'tzst'], + 'application/xaml+xml' => ['xaml'], + 'application/xcap-att+xml' => ['xav'], + 'application/xcap-caps+xml' => ['xca'], + 'application/xcap-diff+xml' => ['xdf'], + 'application/xcap-el+xml' => ['xel'], + 'application/xcap-error+xml' => ['xer'], + 'application/xcap-ns+xml' => ['xns'], + 'application/xenc+xml' => ['xenc'], + 'application/xhtml+xml' => ['xhtml', 'xht', 'html', 'htm'], + 'application/xliff+xml' => ['xlf', 'xliff'], + 'application/xml' => ['xml', 'xsl', 'xsd', 'rng', 'xbl'], + 'application/xml-dtd' => ['dtd'], + 'application/xml-external-parsed-entity' => ['ent'], + 'application/xop+xml' => ['xop'], + 'application/xproc+xml' => ['xpl'], + 'application/xps' => ['xps'], + 'application/xslt+xml' => ['xsl', 'xslt'], + 'application/xspf+xml' => ['xspf'], + 'application/xv+xml' => ['mxml', 'xhvml', 'xvml', 'xvm'], + 'application/yang' => ['yang'], + 'application/yin+xml' => ['yin'], + 'application/zip' => ['zip'], + 'application/zlib' => ['zz'], + 'application/zstd' => ['zst'], + 'audio/3gpp' => ['3gpp', '3gp', '3ga'], + 'audio/3gpp-encrypted' => ['3gp', '3gpp', '3ga'], + 'audio/3gpp2' => ['3g2', '3gp2', '3gpp2'], + 'audio/aac' => ['aac', 'adts', 'ass'], + 'audio/ac3' => ['ac3'], + 'audio/adpcm' => ['adp'], + 'audio/amr' => ['amr'], + 'audio/amr-encrypted' => ['amr'], + 'audio/amr-wb' => ['awb'], + 'audio/amr-wb-encrypted' => ['awb'], + 'audio/annodex' => ['axa'], + 'audio/basic' => ['au', 'snd'], + 'audio/flac' => ['flac'], + 'audio/imelody' => ['imy', 'ime'], + 'audio/m3u' => ['m3u', 'm3u8', 'vlc'], + 'audio/m4a' => ['m4a', 'f4a'], + 'audio/midi' => ['mid', 'midi', 'kar', 'rmi'], + 'audio/mobile-xmf' => ['mxmf', 'xmf'], + 'audio/mp2' => ['mp2'], + 'audio/mp3' => ['mp3', 'mpga'], + 'audio/mp4' => ['m4a', 'mp4a', 'f4a'], + 'audio/mpeg' => ['mp3', 'mpga', 'mp2', 'mp2a', 'm2a', 'm3a'], + 'audio/mpegurl' => ['m3u', 'm3u8', 'vlc'], + 'audio/ogg' => ['ogg', 'oga', 'spx', 'opus'], + 'audio/prs.sid' => ['sid', 'psid'], + 'audio/s3m' => ['s3m'], + 'audio/scpls' => ['pls'], + 'audio/silk' => ['sil'], + 'audio/tta' => ['tta'], + 'audio/usac' => ['loas', 'xhe'], + 'audio/vnd.audible' => ['aa', 'aax'], + 'audio/vnd.audible.aax' => ['aax'], + 'audio/vnd.dece.audio' => ['uva', 'uvva'], + 'audio/vnd.digital-winds' => ['eol'], + 'audio/vnd.dra' => ['dra'], + 'audio/vnd.dts' => ['dts'], + 'audio/vnd.dts.hd' => ['dtshd'], + 'audio/vnd.lucent.voice' => ['lvp'], + 'audio/vnd.m-realaudio' => ['ra', 'rax'], + 'audio/vnd.ms-playready.media.pya' => ['pya'], + 'audio/vnd.nuera.ecelp4800' => ['ecelp4800'], + 'audio/vnd.nuera.ecelp7470' => ['ecelp7470'], + 'audio/vnd.nuera.ecelp9600' => ['ecelp9600'], + 'audio/vnd.rip' => ['rip'], + 'audio/vnd.rn-realaudio' => ['ra', 'rax'], + 'audio/vnd.wave' => ['wav'], + 'audio/vorbis' => ['oga', 'ogg'], + 'audio/wav' => ['wav'], + 'audio/wave' => ['wav'], + 'audio/webm' => ['weba'], + 'audio/wma' => ['wma'], + 'audio/x-aac' => ['aac', 'adts', 'ass'], + 'audio/x-aifc' => ['aifc', 'aiffc'], + 'audio/x-aiff' => ['aif', 'aiff', 'aifc'], + 'audio/x-aiffc' => ['aifc', 'aiffc'], + 'audio/x-amzxml' => ['amz'], + 'audio/x-annodex' => ['axa'], + 'audio/x-ape' => ['ape'], + 'audio/x-caf' => ['caf'], + 'audio/x-dts' => ['dts'], + 'audio/x-dtshd' => ['dtshd'], + 'audio/x-flac' => ['flac'], + 'audio/x-flac+ogg' => ['oga', 'ogg'], + 'audio/x-gsm' => ['gsm'], + 'audio/x-hx-aac-adts' => ['aac', 'adts', 'ass'], + 'audio/x-imelody' => ['imy', 'ime'], + 'audio/x-iriver-pla' => ['pla'], + 'audio/x-it' => ['it'], + 'audio/x-m3u' => ['m3u', 'm3u8', 'vlc'], + 'audio/x-m4a' => ['m4a', 'f4a'], + 'audio/x-m4b' => ['m4b', 'f4b'], + 'audio/x-m4r' => ['m4r'], + 'audio/x-matroska' => ['mka'], + 'audio/x-midi' => ['mid', 'midi', 'kar'], + 'audio/x-minipsf' => ['minipsf'], + 'audio/x-mo3' => ['mo3'], + 'audio/x-mod' => ['mod', 'ult', 'uni', 'm15', 'mtm', '669', 'med'], + 'audio/x-mp2' => ['mp2'], + 'audio/x-mp3' => ['mp3', 'mpga'], + 'audio/x-mp3-playlist' => ['m3u', 'm3u8', 'vlc'], + 'audio/x-mpeg' => ['mp3', 'mpga'], + 'audio/x-mpegurl' => ['m3u', 'm3u8', 'vlc'], + 'audio/x-mpg' => ['mp3', 'mpga'], + 'audio/x-ms-asx' => ['asx', 'wax', 'wvx', 'wmx'], + 'audio/x-ms-wax' => ['wax'], + 'audio/x-ms-wma' => ['wma'], + 'audio/x-ms-wmv' => ['wmv'], + 'audio/x-musepack' => ['mpc', 'mpp', 'mp+'], + 'audio/x-ogg' => ['oga', 'ogg', 'opus'], + 'audio/x-oggflac' => ['oga', 'ogg'], + 'audio/x-opus+ogg' => ['opus'], + 'audio/x-pn-audibleaudio' => ['aa', 'aax'], + 'audio/x-pn-realaudio' => ['ram', 'ra', 'rax'], + 'audio/x-pn-realaudio-plugin' => ['rmp'], + 'audio/x-psf' => ['psf'], + 'audio/x-psflib' => ['psflib'], + 'audio/x-realaudio' => ['ra'], + 'audio/x-rn-3gpp-amr' => ['3gp', '3gpp', '3ga'], + 'audio/x-rn-3gpp-amr-encrypted' => ['3gp', '3gpp', '3ga'], + 'audio/x-rn-3gpp-amr-wb' => ['3gp', '3gpp', '3ga'], + 'audio/x-rn-3gpp-amr-wb-encrypted' => ['3gp', '3gpp', '3ga'], + 'audio/x-s3m' => ['s3m'], + 'audio/x-scpls' => ['pls'], + 'audio/x-shorten' => ['shn'], + 'audio/x-speex' => ['spx'], + 'audio/x-speex+ogg' => ['oga', 'ogg', 'spx'], + 'audio/x-stm' => ['stm'], + 'audio/x-tta' => ['tta'], + 'audio/x-voc' => ['voc'], + 'audio/x-vorbis' => ['oga', 'ogg'], + 'audio/x-vorbis+ogg' => ['oga', 'ogg'], + 'audio/x-wav' => ['wav'], + 'audio/x-wavpack' => ['wv', 'wvp'], + 'audio/x-wavpack-correction' => ['wvc'], + 'audio/x-xi' => ['xi'], + 'audio/x-xm' => ['xm'], + 'audio/x-xmf' => ['xmf'], + 'audio/xm' => ['xm'], + 'audio/xmf' => ['xmf'], + 'chemical/x-cdx' => ['cdx'], + 'chemical/x-cif' => ['cif'], + 'chemical/x-cmdf' => ['cmdf'], + 'chemical/x-cml' => ['cml'], + 'chemical/x-csml' => ['csml'], + 'chemical/x-xyz' => ['xyz'], + 'flv-application/octet-stream' => ['flv'], + 'font/collection' => ['ttc'], + 'font/otf' => ['otf'], + 'font/ttf' => ['ttf'], + 'font/woff' => ['woff'], + 'font/woff2' => ['woff2'], + 'image/aces' => ['exr'], + 'image/apng' => ['apng'], + 'image/astc' => ['astc'], + 'image/avif' => ['avif', 'avifs'], + 'image/avif-sequence' => ['avif', 'avifs'], + 'image/bmp' => ['bmp', 'dib'], + 'image/cdr' => ['cdr'], + 'image/cgm' => ['cgm'], + 'image/dicom-rle' => ['drle'], + 'image/emf' => ['emf'], + 'image/fax-g3' => ['g3'], + 'image/fits' => ['fits'], + 'image/g3fax' => ['g3'], + 'image/gif' => ['gif'], + 'image/heic' => ['heic', 'heif'], + 'image/heic-sequence' => ['heics', 'heic', 'heif'], + 'image/heif' => ['heif', 'heic'], + 'image/heif-sequence' => ['heifs', 'heic', 'heif'], + 'image/hej2k' => ['hej2'], + 'image/hsj2' => ['hsj2'], + 'image/ico' => ['ico'], + 'image/icon' => ['ico'], + 'image/ief' => ['ief'], + 'image/jls' => ['jls'], + 'image/jp2' => ['jp2', 'jpg2'], + 'image/jpeg' => ['jpg', 'jpeg', 'jpe'], + 'image/jpeg2000' => ['jp2', 'jpg2'], + 'image/jpeg2000-image' => ['jp2', 'jpg2'], + 'image/jph' => ['jph'], + 'image/jphc' => ['jhc'], + 'image/jpm' => ['jpm', 'jpgm'], + 'image/jpx' => ['jpx', 'jpf'], + 'image/jxl' => ['jxl'], + 'image/jxr' => ['jxr'], + 'image/jxra' => ['jxra'], + 'image/jxrs' => ['jxrs'], + 'image/jxs' => ['jxs'], + 'image/jxsc' => ['jxsc'], + 'image/jxsi' => ['jxsi'], + 'image/jxss' => ['jxss'], + 'image/ktx' => ['ktx'], + 'image/ktx2' => ['ktx2'], + 'image/openraster' => ['ora'], + 'image/pdf' => ['pdf'], + 'image/photoshop' => ['psd'], + 'image/pjpeg' => ['jpg', 'jpeg', 'jpe'], + 'image/png' => ['png'], + 'image/prs.btif' => ['btif'], + 'image/prs.pti' => ['pti'], + 'image/psd' => ['psd'], + 'image/rle' => ['rle'], + 'image/sgi' => ['sgi'], + 'image/svg' => ['svg'], + 'image/svg+xml' => ['svg', 'svgz'], + 'image/svg+xml-compressed' => ['svgz'], + 'image/t38' => ['t38'], + 'image/targa' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'image/tga' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'image/tiff' => ['tif', 'tiff'], + 'image/tiff-fx' => ['tfx'], + 'image/vnd.adobe.photoshop' => ['psd'], + 'image/vnd.airzip.accelerator.azv' => ['azv'], + 'image/vnd.dece.graphic' => ['uvi', 'uvvi', 'uvg', 'uvvg'], + 'image/vnd.djvu' => ['djvu', 'djv'], + 'image/vnd.djvu+multipage' => ['djvu', 'djv'], + 'image/vnd.dvb.subtitle' => ['sub'], + 'image/vnd.dwg' => ['dwg'], + 'image/vnd.dxf' => ['dxf'], + 'image/vnd.fastbidsheet' => ['fbs'], + 'image/vnd.fpx' => ['fpx'], + 'image/vnd.fst' => ['fst'], + 'image/vnd.fujixerox.edmics-mmr' => ['mmr'], + 'image/vnd.fujixerox.edmics-rlc' => ['rlc'], + 'image/vnd.microsoft.icon' => ['ico'], + 'image/vnd.ms-dds' => ['dds'], + 'image/vnd.ms-modi' => ['mdi'], + 'image/vnd.ms-photo' => ['wdp'], + 'image/vnd.net-fpx' => ['npx'], + 'image/vnd.pco.b16' => ['b16'], + 'image/vnd.rn-realpix' => ['rp'], + 'image/vnd.tencent.tap' => ['tap'], + 'image/vnd.valve.source.texture' => ['vtf'], + 'image/vnd.wap.wbmp' => ['wbmp'], + 'image/vnd.xiff' => ['xif'], + 'image/vnd.zbrush.pcx' => ['pcx'], + 'image/webp' => ['webp'], + 'image/wmf' => ['wmf'], + 'image/x-3ds' => ['3ds'], + 'image/x-adobe-dng' => ['dng'], + 'image/x-applix-graphics' => ['ag'], + 'image/x-bmp' => ['bmp', 'dib'], + 'image/x-bzeps' => ['eps.bz2', 'epsi.bz2', 'epsf.bz2'], + 'image/x-canon-cr2' => ['cr2'], + 'image/x-canon-cr3' => ['cr3'], + 'image/x-canon-crw' => ['crw'], + 'image/x-cdr' => ['cdr'], + 'image/x-cmu-raster' => ['ras'], + 'image/x-cmx' => ['cmx'], + 'image/x-compressed-xcf' => ['xcf.gz', 'xcf.bz2'], + 'image/x-dds' => ['dds'], + 'image/x-djvu' => ['djvu', 'djv'], + 'image/x-emf' => ['emf'], + 'image/x-eps' => ['eps', 'epsi', 'epsf'], + 'image/x-exr' => ['exr'], + 'image/x-fits' => ['fits'], + 'image/x-freehand' => ['fh', 'fhc', 'fh4', 'fh5', 'fh7'], + 'image/x-fuji-raf' => ['raf'], + 'image/x-gimp-gbr' => ['gbr'], + 'image/x-gimp-gih' => ['gih'], + 'image/x-gimp-pat' => ['pat'], + 'image/x-gzeps' => ['eps.gz', 'epsi.gz', 'epsf.gz'], + 'image/x-icb' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'image/x-icns' => ['icns'], + 'image/x-ico' => ['ico'], + 'image/x-icon' => ['ico'], + 'image/x-iff' => ['iff', 'ilbm', 'lbm'], + 'image/x-ilbm' => ['iff', 'ilbm', 'lbm'], + 'image/x-jng' => ['jng'], + 'image/x-jp2-codestream' => ['j2c', 'j2k', 'jpc'], + 'image/x-jpeg2000-image' => ['jp2', 'jpg2'], + 'image/x-kodak-dcr' => ['dcr'], + 'image/x-kodak-k25' => ['k25'], + 'image/x-kodak-kdc' => ['kdc'], + 'image/x-lwo' => ['lwo', 'lwob'], + 'image/x-lws' => ['lws'], + 'image/x-macpaint' => ['pntg'], + 'image/x-minolta-mrw' => ['mrw'], + 'image/x-mrsid-image' => ['sid'], + 'image/x-ms-bmp' => ['bmp', 'dib'], + 'image/x-msod' => ['msod'], + 'image/x-nikon-nef' => ['nef'], + 'image/x-nikon-nrw' => ['nrw'], + 'image/x-olympus-orf' => ['orf'], + 'image/x-panasonic-raw' => ['raw'], + 'image/x-panasonic-raw2' => ['rw2'], + 'image/x-panasonic-rw' => ['raw'], + 'image/x-panasonic-rw2' => ['rw2'], + 'image/x-pcx' => ['pcx'], + 'image/x-pentax-pef' => ['pef'], + 'image/x-photo-cd' => ['pcd'], + 'image/x-photoshop' => ['psd'], + 'image/x-pict' => ['pic', 'pct', 'pict', 'pict1', 'pict2'], + 'image/x-portable-anymap' => ['pnm'], + 'image/x-portable-bitmap' => ['pbm'], + 'image/x-portable-graymap' => ['pgm'], + 'image/x-portable-pixmap' => ['ppm'], + 'image/x-psd' => ['psd'], + 'image/x-quicktime' => ['qtif', 'qif'], + 'image/x-rgb' => ['rgb'], + 'image/x-sgi' => ['sgi'], + 'image/x-sigma-x3f' => ['x3f'], + 'image/x-skencil' => ['sk', 'sk1'], + 'image/x-sony-arw' => ['arw'], + 'image/x-sony-sr2' => ['sr2'], + 'image/x-sony-srf' => ['srf'], + 'image/x-sun-raster' => ['sun'], + 'image/x-targa' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'image/x-tga' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'image/x-win-bitmap' => ['cur'], + 'image/x-win-metafile' => ['wmf'], + 'image/x-wmf' => ['wmf'], + 'image/x-xbitmap' => ['xbm'], + 'image/x-xcf' => ['xcf'], + 'image/x-xfig' => ['fig'], + 'image/x-xpixmap' => ['xpm'], + 'image/x-xpm' => ['xpm'], + 'image/x-xwindowdump' => ['xwd'], + 'image/x.djvu' => ['djvu', 'djv'], + 'message/disposition-notification' => ['disposition-notification'], + 'message/global' => ['u8msg'], + 'message/global-delivery-status' => ['u8dsn'], + 'message/global-disposition-notification' => ['u8mdn'], + 'message/global-headers' => ['u8hdr'], + 'message/rfc822' => ['eml', 'mime'], + 'message/vnd.wfa.wsc' => ['wsc'], + 'model/3mf' => ['3mf'], + 'model/gltf+json' => ['gltf'], + 'model/gltf-binary' => ['glb'], + 'model/iges' => ['igs', 'iges'], + 'model/mesh' => ['msh', 'mesh', 'silo'], + 'model/mtl' => ['mtl'], + 'model/obj' => ['obj'], + 'model/step+zip' => ['stpz'], + 'model/step-xml+zip' => ['stpxz'], + 'model/stl' => ['stl'], + 'model/vnd.collada+xml' => ['dae'], + 'model/vnd.dwf' => ['dwf'], + 'model/vnd.gdl' => ['gdl'], + 'model/vnd.gtw' => ['gtw'], + 'model/vnd.mts' => ['mts'], + 'model/vnd.opengex' => ['ogex'], + 'model/vnd.parasolid.transmit.binary' => ['x_b'], + 'model/vnd.parasolid.transmit.text' => ['x_t'], + 'model/vnd.sap.vds' => ['vds'], + 'model/vnd.usdz+zip' => ['usdz'], + 'model/vnd.valve.source.compiled-map' => ['bsp'], + 'model/vnd.vtu' => ['vtu'], + 'model/vrml' => ['wrl', 'vrml', 'vrm'], + 'model/x.stl-ascii' => ['stl'], + 'model/x.stl-binary' => ['stl'], + 'model/x3d+binary' => ['x3db', 'x3dbz'], + 'model/x3d+fastinfoset' => ['x3db'], + 'model/x3d+vrml' => ['x3dv', 'x3dvz'], + 'model/x3d+xml' => ['x3d', 'x3dz'], + 'model/x3d-vrml' => ['x3dv'], + 'text/cache-manifest' => ['appcache', 'manifest'], + 'text/calendar' => ['ics', 'ifb', 'vcs'], + 'text/coffeescript' => ['coffee', 'litcoffee'], + 'text/crystal' => ['cr'], + 'text/css' => ['css'], + 'text/csv' => ['csv'], + 'text/csv-schema' => ['csvs'], + 'text/directory' => ['vcard', 'vcf', 'vct', 'gcrd'], + 'text/ecmascript' => ['es'], + 'text/gedcom' => ['ged', 'gedcom'], + 'text/google-video-pointer' => ['gvp'], + 'text/html' => ['html', 'htm', 'shtml'], + 'text/ico' => ['ico'], + 'text/jade' => ['jade'], + 'text/javascript' => ['js', 'jsm', 'mjs'], + 'text/jsx' => ['jsx'], + 'text/less' => ['less'], + 'text/markdown' => ['md', 'markdown', 'mkd'], + 'text/mathml' => ['mml'], + 'text/mdx' => ['mdx'], + 'text/n3' => ['n3'], + 'text/org' => ['org'], + 'text/plain' => ['txt', 'text', 'conf', 'def', 'list', 'log', 'in', 'ini', 'asc'], + 'text/prs.lines.tag' => ['dsc'], + 'text/rdf' => ['rdf', 'rdfs', 'owl'], + 'text/richtext' => ['rtx'], + 'text/rss' => ['rss'], + 'text/rtf' => ['rtf'], + 'text/rust' => ['rs'], + 'text/sgml' => ['sgml', 'sgm'], + 'text/shex' => ['shex'], + 'text/slim' => ['slim', 'slm'], + 'text/spdx' => ['spdx'], + 'text/spreadsheet' => ['sylk', 'slk'], + 'text/stylus' => ['stylus', 'styl'], + 'text/tab-separated-values' => ['tsv'], + 'text/tcl' => ['tcl', 'tk'], + 'text/troff' => ['t', 'tr', 'roff', 'man', 'me', 'ms'], + 'text/turtle' => ['ttl'], + 'text/uri-list' => ['uri', 'uris', 'urls'], + 'text/vbs' => ['vbs'], + 'text/vbscript' => ['vbs'], + 'text/vcard' => ['vcard', 'vcf', 'vct', 'gcrd'], + 'text/vnd.curl' => ['curl'], + 'text/vnd.curl.dcurl' => ['dcurl'], + 'text/vnd.curl.mcurl' => ['mcurl'], + 'text/vnd.curl.scurl' => ['scurl'], + 'text/vnd.dvb.subtitle' => ['sub'], + 'text/vnd.fly' => ['fly'], + 'text/vnd.fmi.flexstor' => ['flx'], + 'text/vnd.graphviz' => ['gv', 'dot'], + 'text/vnd.in3d.3dml' => ['3dml'], + 'text/vnd.in3d.spot' => ['spot'], + 'text/vnd.qt.linguist' => ['ts'], + 'text/vnd.rn-realtext' => ['rt'], + 'text/vnd.senx.warpscript' => ['mc2'], + 'text/vnd.sun.j2me.app-descriptor' => ['jad'], + 'text/vnd.trolltech.linguist' => ['ts'], + 'text/vnd.wap.wml' => ['wml'], + 'text/vnd.wap.wmlscript' => ['wmls'], + 'text/vtt' => ['vtt'], + 'text/x-adasrc' => ['adb', 'ads'], + 'text/x-asm' => ['s', 'asm'], + 'text/x-bibtex' => ['bib'], + 'text/x-c' => ['c', 'cc', 'cxx', 'cpp', 'h', 'hh', 'dic'], + 'text/x-c++hdr' => ['hh', 'hp', 'hpp', 'h++', 'hxx'], + 'text/x-c++src' => ['cpp', 'cxx', 'cc', 'C', 'c++'], + 'text/x-chdr' => ['h'], + 'text/x-cmake' => ['cmake'], + 'text/x-cobol' => ['cbl', 'cob'], + 'text/x-comma-separated-values' => ['csv'], + 'text/x-common-lisp' => ['asd', 'fasl', 'lisp', 'ros'], + 'text/x-component' => ['htc'], + 'text/x-crystal' => ['cr'], + 'text/x-csharp' => ['cs'], + 'text/x-csrc' => ['c'], + 'text/x-csv' => ['csv'], + 'text/x-dart' => ['dart'], + 'text/x-dbus-service' => ['service'], + 'text/x-dcl' => ['dcl'], + 'text/x-diff' => ['diff', 'patch'], + 'text/x-dsl' => ['dsl'], + 'text/x-dsrc' => ['d', 'di'], + 'text/x-dtd' => ['dtd'], + 'text/x-eiffel' => ['e', 'eif'], + 'text/x-elixir' => ['ex', 'exs'], + 'text/x-emacs-lisp' => ['el'], + 'text/x-erlang' => ['erl'], + 'text/x-fortran' => ['f', 'for', 'f77', 'f90', 'f95'], + 'text/x-genie' => ['gs'], + 'text/x-gettext-translation' => ['po'], + 'text/x-gettext-translation-template' => ['pot'], + 'text/x-gherkin' => ['feature'], + 'text/x-go' => ['go'], + 'text/x-google-video-pointer' => ['gvp'], + 'text/x-gradle' => ['gradle'], + 'text/x-groovy' => ['groovy', 'gvy', 'gy', 'gsh'], + 'text/x-handlebars-template' => ['hbs'], + 'text/x-haskell' => ['hs'], + 'text/x-idl' => ['idl'], + 'text/x-imelody' => ['imy', 'ime'], + 'text/x-iptables' => ['iptables'], + 'text/x-java' => ['java'], + 'text/x-java-source' => ['java'], + 'text/x-kaitai-struct' => ['ksy'], + 'text/x-kotlin' => ['kt'], + 'text/x-ldif' => ['ldif'], + 'text/x-lilypond' => ['ly'], + 'text/x-literate-haskell' => ['lhs'], + 'text/x-log' => ['log'], + 'text/x-lua' => ['lua'], + 'text/x-lyx' => ['lyx'], + 'text/x-makefile' => ['mk', 'mak'], + 'text/x-markdown' => ['md', 'mkd', 'markdown'], + 'text/x-matlab' => ['m'], + 'text/x-microdvd' => ['sub'], + 'text/x-moc' => ['moc'], + 'text/x-modelica' => ['mo'], + 'text/x-mof' => ['mof'], + 'text/x-mpsub' => ['sub'], + 'text/x-mrml' => ['mrml', 'mrl'], + 'text/x-ms-regedit' => ['reg'], + 'text/x-mup' => ['mup', 'not'], + 'text/x-nfo' => ['nfo'], + 'text/x-objcsrc' => ['m'], + 'text/x-ocaml' => ['ml', 'mli'], + 'text/x-ocl' => ['ocl'], + 'text/x-octave' => ['m'], + 'text/x-ooc' => ['ooc'], + 'text/x-opencl-src' => ['cl'], + 'text/x-opml' => ['opml'], + 'text/x-opml+xml' => ['opml'], + 'text/x-org' => ['org'], + 'text/x-pascal' => ['p', 'pas'], + 'text/x-patch' => ['diff', 'patch'], + 'text/x-perl' => ['pl', 'PL', 'pm', 'al', 'perl', 'pod', 't'], + 'text/x-po' => ['po'], + 'text/x-pot' => ['pot'], + 'text/x-processing' => ['pde'], + 'text/x-python' => ['py', 'pyx', 'wsgi'], + 'text/x-python3' => ['py', 'py3', 'py3x', 'pyi'], + 'text/x-qml' => ['qml', 'qmltypes', 'qmlproject'], + 'text/x-reject' => ['rej'], + 'text/x-rpm-spec' => ['spec'], + 'text/x-rst' => ['rst'], + 'text/x-sagemath' => ['sage'], + 'text/x-sass' => ['sass'], + 'text/x-scala' => ['scala', 'sc'], + 'text/x-scheme' => ['scm', 'ss'], + 'text/x-scss' => ['scss'], + 'text/x-setext' => ['etx'], + 'text/x-sfv' => ['sfv'], + 'text/x-sh' => ['sh'], + 'text/x-sql' => ['sql'], + 'text/x-ssa' => ['ssa', 'ass'], + 'text/x-subviewer' => ['sub'], + 'text/x-suse-ymp' => ['ymp'], + 'text/x-svhdr' => ['svh'], + 'text/x-svsrc' => ['sv'], + 'text/x-systemd-unit' => ['automount', 'device', 'mount', 'path', 'scope', 'service', 'slice', 'socket', 'swap', 'target', 'timer'], + 'text/x-tcl' => ['tcl', 'tk'], + 'text/x-tex' => ['tex', 'ltx', 'sty', 'cls', 'dtx', 'ins', 'latex'], + 'text/x-texinfo' => ['texi', 'texinfo'], + 'text/x-troff' => ['tr', 'roff', 't'], + 'text/x-troff-me' => ['me'], + 'text/x-troff-mm' => ['mm'], + 'text/x-troff-ms' => ['ms'], + 'text/x-twig' => ['twig'], + 'text/x-txt2tags' => ['t2t'], + 'text/x-uil' => ['uil'], + 'text/x-uuencode' => ['uu', 'uue'], + 'text/x-vala' => ['vala', 'vapi'], + 'text/x-vcalendar' => ['vcs', 'ics'], + 'text/x-vcard' => ['vcf', 'vcard', 'vct', 'gcrd'], + 'text/x-verilog' => ['v'], + 'text/x-vhdl' => ['vhd', 'vhdl'], + 'text/x-xmi' => ['xmi'], + 'text/x-xslfo' => ['fo', 'xslfo'], + 'text/x-yaml' => ['yaml', 'yml'], + 'text/x.gcode' => ['gcode'], + 'text/xml' => ['xml', 'xbl', 'xsd', 'rng'], + 'text/xml-external-parsed-entity' => ['ent'], + 'text/yaml' => ['yaml', 'yml'], + 'video/3gp' => ['3gp', '3gpp', '3ga'], + 'video/3gpp' => ['3gp', '3gpp', '3ga'], + 'video/3gpp-encrypted' => ['3gp', '3gpp', '3ga'], + 'video/3gpp2' => ['3g2', '3gp2', '3gpp2'], + 'video/annodex' => ['axv'], + 'video/avi' => ['avi', 'avf', 'divx'], + 'video/divx' => ['avi', 'avf', 'divx'], + 'video/dv' => ['dv'], + 'video/fli' => ['fli', 'flc'], + 'video/flv' => ['flv'], + 'video/h261' => ['h261'], + 'video/h263' => ['h263'], + 'video/h264' => ['h264'], + 'video/iso.segment' => ['m4s'], + 'video/jpeg' => ['jpgv'], + 'video/jpm' => ['jpm', 'jpgm'], + 'video/mj2' => ['mj2', 'mjp2'], + 'video/mp2t' => ['ts', 'm2t', 'm2ts', 'mts', 'cpi', 'clpi', 'mpl', 'mpls', 'bdm', 'bdmv'], + 'video/mp4' => ['mp4', 'mp4v', 'mpg4', 'm4v', 'f4v', 'lrv'], + 'video/mp4v-es' => ['mp4', 'm4v', 'f4v', 'lrv'], + 'video/mpeg' => ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v', 'mp2', 'vob'], + 'video/mpeg-system' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], + 'video/msvideo' => ['avi', 'avf', 'divx'], + 'video/ogg' => ['ogv', 'ogg'], + 'video/quicktime' => ['mov', 'qt', 'moov', 'qtvr'], + 'video/vivo' => ['viv', 'vivo'], + 'video/vnd.dece.hd' => ['uvh', 'uvvh'], + 'video/vnd.dece.mobile' => ['uvm', 'uvvm'], + 'video/vnd.dece.pd' => ['uvp', 'uvvp'], + 'video/vnd.dece.sd' => ['uvs', 'uvvs'], + 'video/vnd.dece.video' => ['uvv', 'uvvv'], + 'video/vnd.divx' => ['avi', 'avf', 'divx'], + 'video/vnd.dvb.file' => ['dvb'], + 'video/vnd.fvt' => ['fvt'], + 'video/vnd.mpegurl' => ['mxu', 'm4u', 'm1u'], + 'video/vnd.ms-playready.media.pyv' => ['pyv'], + 'video/vnd.radgamettools.bink' => ['bik', 'bk2'], + 'video/vnd.radgamettools.smacker' => ['smk'], + 'video/vnd.rn-realvideo' => ['rv', 'rvx'], + 'video/vnd.uvvu.mp4' => ['uvu', 'uvvu'], + 'video/vnd.vivo' => ['viv', 'vivo'], + 'video/webm' => ['webm'], + 'video/x-anim' => ['anim[1-9j]'], + 'video/x-annodex' => ['axv'], + 'video/x-avi' => ['avi', 'avf', 'divx'], + 'video/x-f4v' => ['f4v'], + 'video/x-fli' => ['fli', 'flc'], + 'video/x-flic' => ['fli', 'flc'], + 'video/x-flv' => ['flv'], + 'video/x-javafx' => ['fxm'], + 'video/x-m4v' => ['m4v', 'mp4', 'f4v', 'lrv'], + 'video/x-matroska' => ['mkv', 'mk3d', 'mks'], + 'video/x-matroska-3d' => ['mk3d'], + 'video/x-mjpeg' => ['mjpeg', 'mjpg'], + 'video/x-mng' => ['mng'], + 'video/x-mpeg' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], + 'video/x-mpeg-system' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], + 'video/x-mpeg2' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], + 'video/x-mpegurl' => ['m1u', 'm4u', 'mxu'], + 'video/x-ms-asf' => ['asf', 'asx'], + 'video/x-ms-asf-plugin' => ['asf'], + 'video/x-ms-vob' => ['vob'], + 'video/x-ms-wax' => ['asx', 'wax', 'wvx', 'wmx'], + 'video/x-ms-wm' => ['wm', 'asf'], + 'video/x-ms-wmv' => ['wmv'], + 'video/x-ms-wmx' => ['wmx', 'asx', 'wax', 'wvx'], + 'video/x-ms-wvx' => ['wvx', 'asx', 'wax', 'wmx'], + 'video/x-msvideo' => ['avi', 'avf', 'divx'], + 'video/x-nsv' => ['nsv'], + 'video/x-ogg' => ['ogv', 'ogg'], + 'video/x-ogm' => ['ogm'], + 'video/x-ogm+ogg' => ['ogm'], + 'video/x-real-video' => ['rv', 'rvx'], + 'video/x-sgi-movie' => ['movie'], + 'video/x-smv' => ['smv'], + 'video/x-theora' => ['ogg'], + 'video/x-theora+ogg' => ['ogg'], + 'x-conference/x-cooltalk' => ['ice'], + 'x-epoc/x-sisx-app' => ['sisx'], + 'zz-application/zz-winassoc-123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'zz-application/zz-winassoc-cab' => ['cab'], + 'zz-application/zz-winassoc-cdr' => ['cdr'], + 'zz-application/zz-winassoc-doc' => ['doc'], + 'zz-application/zz-winassoc-hlp' => ['hlp'], + 'zz-application/zz-winassoc-mdb' => ['mdb'], + 'zz-application/zz-winassoc-uu' => ['uue'], + 'zz-application/zz-winassoc-xls' => ['xls', 'xlc', 'xll', 'xlm', 'xlw', 'xla', 'xlt', 'xld'], + ]; + + private const REVERSE_MAP = [ + '1km' => ['application/vnd.1000minds.decision-model+xml'], + '32x' => ['application/x-genesis-32x-rom'], + '3dml' => ['text/vnd.in3d.3dml'], + '3ds' => ['application/x-nintendo-3ds-rom', 'image/x-3ds'], + '3dsx' => ['application/x-nintendo-3ds-executable'], + '3g2' => ['audio/3gpp2', 'video/3gpp2'], + '3ga' => ['audio/3gpp', 'audio/3gpp-encrypted', 'audio/x-rn-3gpp-amr', 'audio/x-rn-3gpp-amr-encrypted', 'audio/x-rn-3gpp-amr-wb', 'audio/x-rn-3gpp-amr-wb-encrypted', 'video/3gp', 'video/3gpp', 'video/3gpp-encrypted'], + '3gp' => ['audio/3gpp', 'audio/3gpp-encrypted', 'audio/x-rn-3gpp-amr', 'audio/x-rn-3gpp-amr-encrypted', 'audio/x-rn-3gpp-amr-wb', 'audio/x-rn-3gpp-amr-wb-encrypted', 'video/3gp', 'video/3gpp', 'video/3gpp-encrypted'], + '3gp2' => ['audio/3gpp2', 'video/3gpp2'], + '3gpp' => ['audio/3gpp', 'audio/3gpp-encrypted', 'audio/x-rn-3gpp-amr', 'audio/x-rn-3gpp-amr-encrypted', 'audio/x-rn-3gpp-amr-wb', 'audio/x-rn-3gpp-amr-wb-encrypted', 'video/3gp', 'video/3gpp', 'video/3gpp-encrypted'], + '3gpp2' => ['audio/3gpp2', 'video/3gpp2'], + '3mf' => ['model/3mf'], + '7z' => ['application/x-7z-compressed'], + '7z.001' => ['application/x-7z-compressed'], + 'BLEND' => ['application/x-blender'], + 'C' => ['text/x-c++src'], + 'PAR2' => ['application/x-par2'], + 'PL' => ['application/x-perl', 'text/x-perl'], + 'Z' => ['application/x-compress'], + 'a' => ['application/x-archive'], + 'a26' => ['application/x-atari-2600-rom'], + 'a78' => ['application/x-atari-7800-rom'], + 'aa' => ['audio/vnd.audible', 'audio/x-pn-audibleaudio'], + 'aab' => ['application/x-authorware-bin'], + 'aac' => ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts'], + 'aam' => ['application/x-authorware-map'], + 'aas' => ['application/x-authorware-seg'], + 'aax' => ['audio/vnd.audible', 'audio/vnd.audible.aax', 'audio/x-pn-audibleaudio'], + 'abw' => ['application/x-abiword'], + 'abw.CRASHED' => ['application/x-abiword'], + 'abw.gz' => ['application/x-abiword'], + 'ac' => ['application/pkix-attr-cert', 'application/vnd.nokia.n-gage.ac+xml'], + 'ac3' => ['audio/ac3'], + 'acc' => ['application/vnd.americandynamics.acc'], + 'ace' => ['application/x-ace', 'application/x-ace-compressed'], + 'acu' => ['application/vnd.acucobol'], + 'acutc' => ['application/vnd.acucorp'], + 'adb' => ['text/x-adasrc'], + 'adf' => ['application/x-amiga-disk-format'], + 'adp' => ['audio/adpcm'], + 'ads' => ['text/x-adasrc'], + 'adts' => ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts'], + 'aep' => ['application/vnd.audiograph'], + 'afm' => ['application/x-font-afm', 'application/x-font-type1'], + 'afp' => ['application/vnd.ibm.modcap'], + 'ag' => ['image/x-applix-graphics'], + 'agb' => ['application/x-gba-rom'], + 'ahead' => ['application/vnd.ahead.space'], + 'ai' => ['application/illustrator', 'application/postscript', 'application/vnd.adobe.illustrator'], + 'aif' => ['audio/x-aiff'], + 'aifc' => ['audio/x-aifc', 'audio/x-aiff', 'audio/x-aiffc'], + 'aiff' => ['audio/x-aiff'], + 'aiffc' => ['audio/x-aifc', 'audio/x-aiffc'], + 'air' => ['application/vnd.adobe.air-application-installer-package+zip'], + 'ait' => ['application/vnd.dvb.ait'], + 'al' => ['application/x-perl', 'text/x-perl'], + 'alz' => ['application/x-alz'], + 'ami' => ['application/vnd.amiga.ami'], + 'amr' => ['audio/amr', 'audio/amr-encrypted'], + 'amz' => ['audio/x-amzxml'], + 'ani' => ['application/x-navi-animation'], + 'anim[1-9j]' => ['video/x-anim'], + 'anx' => ['application/annodex', 'application/x-annodex'], + 'ape' => ['audio/x-ape'], + 'apk' => ['application/vnd.android.package-archive'], + 'apng' => ['image/apng'], + 'appcache' => ['text/cache-manifest'], + 'appimage' => ['application/vnd.appimage', 'application/x-iso9660-appimage'], + 'application' => ['application/x-ms-application'], + 'apr' => ['application/vnd.lotus-approach'], + 'ar' => ['application/x-archive'], + 'arc' => ['application/x-freearc'], + 'arj' => ['application/x-arj'], + 'arw' => ['image/x-sony-arw'], + 'as' => ['application/x-applix-spreadsheet'], + 'asc' => ['application/pgp', 'application/pgp-encrypted', 'application/pgp-keys', 'application/pgp-signature', 'text/plain'], + 'asd' => ['text/x-common-lisp'], + 'asf' => ['application/vnd.ms-asf', 'video/x-ms-asf', 'video/x-ms-asf-plugin', 'video/x-ms-wm'], + 'asice' => ['application/vnd.etsi.asic-e+zip'], + 'asm' => ['text/x-asm'], + 'aso' => ['application/vnd.accpac.simply.aso'], + 'asp' => ['application/x-asp'], + 'ass' => ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts', 'text/x-ssa'], + 'astc' => ['image/astc'], + 'asx' => ['application/x-ms-asx', 'audio/x-ms-asx', 'video/x-ms-asf', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], + 'atc' => ['application/vnd.acucorp'], + 'atom' => ['application/atom+xml'], + 'atomcat' => ['application/atomcat+xml'], + 'atomdeleted' => ['application/atomdeleted+xml'], + 'atomsvc' => ['application/atomsvc+xml'], + 'atx' => ['application/vnd.antix.game-component'], + 'au' => ['audio/basic'], + 'automount' => ['text/x-systemd-unit'], + 'avf' => ['video/avi', 'video/divx', 'video/msvideo', 'video/vnd.divx', 'video/x-avi', 'video/x-msvideo'], + 'avi' => ['video/avi', 'video/divx', 'video/msvideo', 'video/vnd.divx', 'video/x-avi', 'video/x-msvideo'], + 'avif' => ['image/avif', 'image/avif-sequence'], + 'avifs' => ['image/avif', 'image/avif-sequence'], + 'aw' => ['application/applixware', 'application/x-applix-word'], + 'awb' => ['audio/amr-wb', 'audio/amr-wb-encrypted'], + 'awk' => ['application/x-awk'], + 'axa' => ['audio/annodex', 'audio/x-annodex'], + 'axv' => ['video/annodex', 'video/x-annodex'], + 'azf' => ['application/vnd.airzip.filesecure.azf'], + 'azs' => ['application/vnd.airzip.filesecure.azs'], + 'azv' => ['image/vnd.airzip.accelerator.azv'], + 'azw' => ['application/vnd.amazon.ebook'], + 'azw3' => ['application/vnd.amazon.mobi8-ebook', 'application/x-mobi8-ebook'], + 'b16' => ['image/vnd.pco.b16'], + 'bak' => ['application/x-trash'], + 'bat' => ['application/x-msdownload'], + 'bcpio' => ['application/x-bcpio'], + 'bdf' => ['application/x-font-bdf'], + 'bdm' => ['application/vnd.syncml.dm+wbxml', 'video/mp2t'], + 'bdmv' => ['video/mp2t'], + 'bdoc' => ['application/bdoc', 'application/x-bdoc'], + 'bed' => ['application/vnd.realvnc.bed'], + 'bh2' => ['application/vnd.fujitsu.oasysprs'], + 'bib' => ['text/x-bibtex'], + 'bik' => ['video/vnd.radgamettools.bink'], + 'bin' => ['application/octet-stream'], + 'bk2' => ['video/vnd.radgamettools.bink'], + 'blb' => ['application/x-blorb'], + 'blend' => ['application/x-blender'], + 'blender' => ['application/x-blender'], + 'blorb' => ['application/x-blorb'], + 'bmi' => ['application/vnd.bmi'], + 'bmml' => ['application/vnd.balsamiq.bmml+xml'], + 'bmp' => ['image/bmp', 'image/x-bmp', 'image/x-ms-bmp'], + 'book' => ['application/vnd.framemaker'], + 'box' => ['application/vnd.previewsystems.box'], + 'boz' => ['application/x-bzip2'], + 'bps' => ['application/x-bps-patch'], + 'bsdiff' => ['application/x-bsdiff'], + 'bsp' => ['model/vnd.valve.source.compiled-map'], + 'btif' => ['image/prs.btif'], + 'bz' => ['application/bzip2', 'application/x-bzip', 'application/x-bzip2'], + 'bz2' => ['application/x-bz2', 'application/bzip2', 'application/x-bzip', 'application/x-bzip2'], + 'c' => ['text/x-c', 'text/x-csrc'], + 'c++' => ['text/x-c++src'], + 'c11amc' => ['application/vnd.cluetrust.cartomobile-config'], + 'c11amz' => ['application/vnd.cluetrust.cartomobile-config-pkg'], + 'c4d' => ['application/vnd.clonk.c4group'], + 'c4f' => ['application/vnd.clonk.c4group'], + 'c4g' => ['application/vnd.clonk.c4group'], + 'c4p' => ['application/vnd.clonk.c4group'], + 'c4u' => ['application/vnd.clonk.c4group'], + 'cab' => ['application/vnd.ms-cab-compressed', 'zz-application/zz-winassoc-cab'], + 'caf' => ['audio/x-caf'], + 'cap' => ['application/pcap', 'application/vnd.tcpdump.pcap', 'application/x-pcap'], + 'car' => ['application/vnd.curl.car'], + 'cat' => ['application/vnd.ms-pki.seccat'], + 'cb7' => ['application/x-cb7', 'application/x-cbr'], + 'cba' => ['application/x-cbr'], + 'cbl' => ['text/x-cobol'], + 'cbr' => ['application/vnd.comicbook-rar', 'application/x-cbr'], + 'cbt' => ['application/x-cbr', 'application/x-cbt'], + 'cbz' => ['application/vnd.comicbook+zip', 'application/x-cbr', 'application/x-cbz'], + 'cc' => ['text/x-c', 'text/x-c++src'], + 'cci' => ['application/x-nintendo-3ds-rom'], + 'ccmx' => ['application/x-ccmx'], + 'cco' => ['application/x-cocoa'], + 'cct' => ['application/x-director'], + 'ccxml' => ['application/ccxml+xml'], + 'cdbcmsg' => ['application/vnd.contact.cmsg'], + 'cdf' => ['application/x-netcdf'], + 'cdfx' => ['application/cdfx+xml'], + 'cdi' => ['application/x-discjuggler-cd-image'], + 'cdkey' => ['application/vnd.mediastation.cdkey'], + 'cdmia' => ['application/cdmi-capability'], + 'cdmic' => ['application/cdmi-container'], + 'cdmid' => ['application/cdmi-domain'], + 'cdmio' => ['application/cdmi-object'], + 'cdmiq' => ['application/cdmi-queue'], + 'cdr' => ['application/cdr', 'application/coreldraw', 'application/vnd.corel-draw', 'application/x-cdr', 'application/x-coreldraw', 'image/cdr', 'image/x-cdr', 'zz-application/zz-winassoc-cdr'], + 'cdx' => ['chemical/x-cdx'], + 'cdxml' => ['application/vnd.chemdraw+xml'], + 'cdy' => ['application/vnd.cinderella'], + 'cer' => ['application/pkix-cert'], + 'cert' => ['application/x-x509-ca-cert'], + 'cfs' => ['application/x-cfs-compressed'], + 'cgb' => ['application/x-gameboy-color-rom'], + 'cgm' => ['image/cgm'], + 'chat' => ['application/x-chat'], + 'chd' => ['application/x-mame-chd'], + 'chm' => ['application/vnd.ms-htmlhelp', 'application/x-chm'], + 'chrt' => ['application/vnd.kde.kchart', 'application/x-kchart'], + 'cif' => ['chemical/x-cif'], + 'cii' => ['application/vnd.anser-web-certificate-issue-initiation'], + 'cil' => ['application/vnd.ms-artgalry'], + 'cjs' => ['application/node'], + 'cl' => ['text/x-opencl-src'], + 'cla' => ['application/vnd.claymore'], + 'class' => ['application/java', 'application/java-byte-code', 'application/java-vm', 'application/x-java', 'application/x-java-class', 'application/x-java-vm'], + 'clkk' => ['application/vnd.crick.clicker.keyboard'], + 'clkp' => ['application/vnd.crick.clicker.palette'], + 'clkt' => ['application/vnd.crick.clicker.template'], + 'clkw' => ['application/vnd.crick.clicker.wordbank'], + 'clkx' => ['application/vnd.crick.clicker'], + 'clp' => ['application/x-msclip'], + 'clpi' => ['video/mp2t'], + 'cls' => ['application/x-tex', 'text/x-tex'], + 'cmake' => ['text/x-cmake'], + 'cmc' => ['application/vnd.cosmocaller'], + 'cmdf' => ['chemical/x-cmdf'], + 'cml' => ['chemical/x-cml'], + 'cmp' => ['application/vnd.yellowriver-custom-menu'], + 'cmx' => ['image/x-cmx'], + 'cob' => ['text/x-cobol'], + 'cod' => ['application/vnd.rim.cod'], + 'coffee' => ['application/vnd.coffeescript', 'text/coffeescript'], + 'com' => ['application/x-msdownload'], + 'conf' => ['text/plain'], + 'cpi' => ['video/mp2t'], + 'cpio' => ['application/x-cpio'], + 'cpio.gz' => ['application/x-cpio-compressed'], + 'cpp' => ['text/x-c', 'text/x-c++src'], + 'cpt' => ['application/mac-compactpro'], + 'cr' => ['text/crystal', 'text/x-crystal'], + 'cr2' => ['image/x-canon-cr2'], + 'cr3' => ['image/x-canon-cr3'], + 'crd' => ['application/x-mscardfile'], + 'crdownload' => ['application/x-partial-download'], + 'crl' => ['application/pkix-crl'], + 'crt' => ['application/x-x509-ca-cert'], + 'crw' => ['image/x-canon-crw'], + 'crx' => ['application/x-chrome-extension'], + 'cryptonote' => ['application/vnd.rig.cryptonote'], + 'cs' => ['text/x-csharp'], + 'csh' => ['application/x-csh'], + 'csl' => ['application/vnd.citationstyles.style+xml'], + 'csml' => ['chemical/x-csml'], + 'cso' => ['application/x-compressed-iso'], + 'csp' => ['application/vnd.commonspace'], + 'css' => ['text/css'], + 'cst' => ['application/x-director'], + 'csv' => ['text/csv', 'application/csv', 'text/x-comma-separated-values', 'text/x-csv'], + 'csvs' => ['text/csv-schema'], + 'cu' => ['application/cu-seeme'], + 'cue' => ['application/x-cue'], + 'cur' => ['image/x-win-bitmap'], + 'curl' => ['text/vnd.curl'], + 'cwk' => ['application/x-appleworks-document'], + 'cww' => ['application/prs.cww'], + 'cxt' => ['application/x-director'], + 'cxx' => ['text/x-c', 'text/x-c++src'], + 'd' => ['text/x-dsrc'], + 'dae' => ['model/vnd.collada+xml'], + 'daf' => ['application/vnd.mobius.daf'], + 'dar' => ['application/x-dar'], + 'dart' => ['application/vnd.dart', 'text/x-dart'], + 'dataless' => ['application/vnd.fdsn.seed'], + 'davmount' => ['application/davmount+xml'], + 'dbf' => ['application/dbase', 'application/dbf', 'application/vnd.dbf', 'application/x-dbase', 'application/x-dbf'], + 'dbk' => ['application/docbook+xml', 'application/vnd.oasis.docbook+xml', 'application/x-docbook+xml'], + 'dc' => ['application/x-dc-rom'], + 'dcl' => ['text/x-dcl'], + 'dcm' => ['application/dicom'], + 'dcr' => ['application/x-director', 'image/x-kodak-dcr'], + 'dcurl' => ['text/vnd.curl.dcurl'], + 'dd2' => ['application/vnd.oma.dd2+xml'], + 'ddd' => ['application/vnd.fujixerox.ddd'], + 'ddf' => ['application/vnd.syncml.dmddf+xml'], + 'dds' => ['image/vnd.ms-dds', 'image/x-dds'], + 'deb' => ['application/vnd.debian.binary-package', 'application/x-deb', 'application/x-debian-package'], + 'def' => ['text/plain'], + 'der' => ['application/x-x509-ca-cert'], + 'desktop' => ['application/x-desktop', 'application/x-gnome-app-info'], + 'device' => ['text/x-systemd-unit'], + 'dfac' => ['application/vnd.dreamfactory'], + 'dgc' => ['application/x-dgc-compressed'], + 'di' => ['text/x-dsrc'], + 'dia' => ['application/x-dia-diagram'], + 'dib' => ['image/bmp', 'image/x-bmp', 'image/x-ms-bmp'], + 'dic' => ['text/x-c'], + 'diff' => ['text/x-diff', 'text/x-patch'], + 'dir' => ['application/x-director'], + 'dis' => ['application/vnd.mobius.dis'], + 'disposition-notification' => ['message/disposition-notification'], + 'divx' => ['video/avi', 'video/divx', 'video/msvideo', 'video/vnd.divx', 'video/x-avi', 'video/x-msvideo'], + 'djv' => ['image/vnd.djvu', 'image/vnd.djvu+multipage', 'image/x-djvu', 'image/x.djvu'], + 'djvu' => ['image/vnd.djvu', 'image/vnd.djvu+multipage', 'image/x-djvu', 'image/x.djvu'], + 'dll' => ['application/x-msdownload'], + 'dmg' => ['application/x-apple-diskimage'], + 'dmp' => ['application/pcap', 'application/vnd.tcpdump.pcap', 'application/x-pcap'], + 'dna' => ['application/vnd.dna'], + 'dng' => ['image/x-adobe-dng'], + 'doc' => ['application/msword', 'application/vnd.ms-word', 'application/x-msword', 'zz-application/zz-winassoc-doc'], + 'docbook' => ['application/docbook+xml', 'application/vnd.oasis.docbook+xml', 'application/x-docbook+xml'], + 'docm' => ['application/vnd.ms-word.document.macroenabled.12'], + 'docx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'], + 'dot' => ['application/msword', 'application/msword-template', 'text/vnd.graphviz'], + 'dotm' => ['application/vnd.ms-word.template.macroenabled.12'], + 'dotx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.template'], + 'dp' => ['application/vnd.osgi.dp'], + 'dpg' => ['application/vnd.dpgraph'], + 'dra' => ['audio/vnd.dra'], + 'drle' => ['image/dicom-rle'], + 'dsc' => ['text/prs.lines.tag'], + 'dsl' => ['text/x-dsl'], + 'dssc' => ['application/dssc+der'], + 'dtb' => ['application/x-dtbook+xml'], + 'dtd' => ['application/xml-dtd', 'text/x-dtd'], + 'dts' => ['audio/vnd.dts', 'audio/x-dts'], + 'dtshd' => ['audio/vnd.dts.hd', 'audio/x-dtshd'], + 'dtx' => ['application/x-tex', 'text/x-tex'], + 'dv' => ['video/dv'], + 'dvb' => ['video/vnd.dvb.file'], + 'dvi' => ['application/x-dvi'], + 'dvi.bz2' => ['application/x-bzdvi'], + 'dvi.gz' => ['application/x-gzdvi'], + 'dwd' => ['application/atsc-dwd+xml'], + 'dwf' => ['model/vnd.dwf'], + 'dwg' => ['image/vnd.dwg'], + 'dxf' => ['image/vnd.dxf'], + 'dxp' => ['application/vnd.spotfire.dxp'], + 'dxr' => ['application/x-director'], + 'e' => ['text/x-eiffel'], + 'ear' => ['application/java-archive'], + 'ecelp4800' => ['audio/vnd.nuera.ecelp4800'], + 'ecelp7470' => ['audio/vnd.nuera.ecelp7470'], + 'ecelp9600' => ['audio/vnd.nuera.ecelp9600'], + 'ecma' => ['application/ecmascript'], + 'edm' => ['application/vnd.novadigm.edm'], + 'edx' => ['application/vnd.novadigm.edx'], + 'efif' => ['application/vnd.picsel'], + 'egon' => ['application/x-egon'], + 'ei6' => ['application/vnd.pg.osasli'], + 'eif' => ['text/x-eiffel'], + 'el' => ['text/x-emacs-lisp'], + 'emf' => ['application/emf', 'application/x-emf', 'application/x-msmetafile', 'image/emf', 'image/x-emf'], + 'eml' => ['message/rfc822'], + 'emma' => ['application/emma+xml'], + 'emotionml' => ['application/emotionml+xml'], + 'emp' => ['application/vnd.emusic-emusic_package'], + 'emz' => ['application/x-msmetafile'], + 'ent' => ['application/xml-external-parsed-entity', 'text/xml-external-parsed-entity'], + 'eol' => ['audio/vnd.digital-winds'], + 'eot' => ['application/vnd.ms-fontobject'], + 'eps' => ['application/postscript', 'image/x-eps'], + 'eps.bz2' => ['image/x-bzeps'], + 'eps.gz' => ['image/x-gzeps'], + 'epsf' => ['image/x-eps'], + 'epsf.bz2' => ['image/x-bzeps'], + 'epsf.gz' => ['image/x-gzeps'], + 'epsi' => ['image/x-eps'], + 'epsi.bz2' => ['image/x-bzeps'], + 'epsi.gz' => ['image/x-gzeps'], + 'epub' => ['application/epub+zip'], + 'erl' => ['text/x-erlang'], + 'es' => ['application/ecmascript', 'text/ecmascript'], + 'es3' => ['application/vnd.eszigno3+xml'], + 'esa' => ['application/vnd.osgi.subsystem'], + 'esf' => ['application/vnd.epson.esf'], + 'et3' => ['application/vnd.eszigno3+xml'], + 'etheme' => ['application/x-e-theme'], + 'etx' => ['text/x-setext'], + 'eva' => ['application/x-eva'], + 'evy' => ['application/x-envoy'], + 'ex' => ['text/x-elixir'], + 'exe' => ['application/x-ms-dos-executable', 'application/x-msdos-program', 'application/x-msdownload'], + 'exi' => ['application/exi'], + 'exr' => ['image/aces', 'image/x-exr'], + 'exs' => ['text/x-elixir'], + 'ext' => ['application/vnd.novadigm.ext'], + 'ez' => ['application/andrew-inset'], + 'ez2' => ['application/vnd.ezpix-album'], + 'ez3' => ['application/vnd.ezpix-package'], + 'f' => ['text/x-fortran'], + 'f4a' => ['audio/m4a', 'audio/mp4', 'audio/x-m4a'], + 'f4b' => ['audio/x-m4b'], + 'f4v' => ['video/mp4', 'video/mp4v-es', 'video/x-f4v', 'video/x-m4v'], + 'f77' => ['text/x-fortran'], + 'f90' => ['text/x-fortran'], + 'f95' => ['text/x-fortran'], + 'fasl' => ['text/x-common-lisp'], + 'fb2' => ['application/x-fictionbook', 'application/x-fictionbook+xml'], + 'fb2.zip' => ['application/x-zip-compressed-fb2'], + 'fbs' => ['image/vnd.fastbidsheet'], + 'fcdt' => ['application/vnd.adobe.formscentral.fcdt'], + 'fcs' => ['application/vnd.isac.fcs'], + 'fd' => ['application/x-fd-file', 'application/x-raw-floppy-disk-image'], + 'fdf' => ['application/vnd.fdf'], + 'fds' => ['application/x-fds-disk'], + 'fdt' => ['application/fdt+xml'], + 'fe_launch' => ['application/vnd.denovo.fcselayout-link'], + 'feature' => ['text/x-gherkin'], + 'fg5' => ['application/vnd.fujitsu.oasysgp'], + 'fgd' => ['application/x-director'], + 'fh' => ['image/x-freehand'], + 'fh4' => ['image/x-freehand'], + 'fh5' => ['image/x-freehand'], + 'fh7' => ['image/x-freehand'], + 'fhc' => ['image/x-freehand'], + 'fig' => ['application/x-xfig', 'image/x-xfig'], + 'fits' => ['image/fits', 'image/x-fits'], + 'fl' => ['application/x-fluid'], + 'flac' => ['audio/flac', 'audio/x-flac'], + 'flatpak' => ['application/vnd.flatpak', 'application/vnd.xdgapp'], + 'flatpakref' => ['application/vnd.flatpak.ref'], + 'flatpakrepo' => ['application/vnd.flatpak.repo'], + 'flc' => ['video/fli', 'video/x-fli', 'video/x-flic'], + 'fli' => ['video/fli', 'video/x-fli', 'video/x-flic'], + 'flo' => ['application/vnd.micrografx.flo'], + 'flv' => ['video/x-flv', 'application/x-flash-video', 'flv-application/octet-stream', 'video/flv'], + 'flw' => ['application/vnd.kde.kivio', 'application/x-kivio'], + 'flx' => ['text/vnd.fmi.flexstor'], + 'fly' => ['text/vnd.fly'], + 'fm' => ['application/vnd.framemaker', 'application/x-frame'], + 'fnc' => ['application/vnd.frogans.fnc'], + 'fo' => ['application/vnd.software602.filler.form+xml', 'text/x-xslfo'], + 'fodg' => ['application/vnd.oasis.opendocument.graphics-flat-xml'], + 'fodp' => ['application/vnd.oasis.opendocument.presentation-flat-xml'], + 'fods' => ['application/vnd.oasis.opendocument.spreadsheet-flat-xml'], + 'fodt' => ['application/vnd.oasis.opendocument.text-flat-xml'], + 'for' => ['text/x-fortran'], + 'fpx' => ['image/vnd.fpx'], + 'frame' => ['application/vnd.framemaker'], + 'fsc' => ['application/vnd.fsc.weblaunch'], + 'fst' => ['image/vnd.fst'], + 'ftc' => ['application/vnd.fluxtime.clip'], + 'fti' => ['application/vnd.anser-web-funds-transfer-initiation'], + 'fvt' => ['video/vnd.fvt'], + 'fxm' => ['video/x-javafx'], + 'fxp' => ['application/vnd.adobe.fxp'], + 'fxpl' => ['application/vnd.adobe.fxp'], + 'fzs' => ['application/vnd.fuzzysheet'], + 'g2w' => ['application/vnd.geoplan'], + 'g3' => ['image/fax-g3', 'image/g3fax'], + 'g3w' => ['application/vnd.geospace'], + 'gac' => ['application/vnd.groove-account'], + 'gam' => ['application/x-tads'], + 'gb' => ['application/x-gameboy-rom'], + 'gba' => ['application/x-gba-rom'], + 'gbc' => ['application/x-gameboy-color-rom'], + 'gbr' => ['application/rpki-ghostbusters', 'image/x-gimp-gbr'], + 'gca' => ['application/x-gca-compressed'], + 'gcode' => ['text/x.gcode'], + 'gcrd' => ['text/directory', 'text/vcard', 'text/x-vcard'], + 'gdi' => ['application/x-gd-rom-cue'], + 'gdl' => ['model/vnd.gdl'], + 'gdoc' => ['application/vnd.google-apps.document'], + 'ged' => ['application/x-gedcom', 'text/gedcom'], + 'gedcom' => ['application/x-gedcom', 'text/gedcom'], + 'gem' => ['application/x-gtar', 'application/x-tar'], + 'gen' => ['application/x-genesis-rom'], + 'geo' => ['application/vnd.dynageo'], + 'geo.json' => ['application/geo+json', 'application/vnd.geo+json'], + 'geojson' => ['application/geo+json', 'application/vnd.geo+json'], + 'gex' => ['application/vnd.geometry-explorer'], + 'gf' => ['application/x-tex-gf'], + 'gg' => ['application/x-gamegear-rom'], + 'ggb' => ['application/vnd.geogebra.file'], + 'ggt' => ['application/vnd.geogebra.tool'], + 'ghf' => ['application/vnd.groove-help'], + 'gif' => ['image/gif'], + 'gih' => ['image/x-gimp-gih'], + 'gim' => ['application/vnd.groove-identity-message'], + 'glade' => ['application/x-glade'], + 'glb' => ['model/gltf-binary'], + 'gltf' => ['model/gltf+json'], + 'gml' => ['application/gml+xml'], + 'gmo' => ['application/x-gettext-translation'], + 'gmx' => ['application/vnd.gmx'], + 'gnc' => ['application/x-gnucash'], + 'gnd' => ['application/gnunet-directory'], + 'gnucash' => ['application/x-gnucash'], + 'gnumeric' => ['application/x-gnumeric'], + 'gnuplot' => ['application/x-gnuplot'], + 'go' => ['text/x-go'], + 'gp' => ['application/x-gnuplot'], + 'gpg' => ['application/pgp', 'application/pgp-encrypted', 'application/pgp-keys', 'application/pgp-signature'], + 'gph' => ['application/vnd.flographit'], + 'gplt' => ['application/x-gnuplot'], + 'gpx' => ['application/gpx', 'application/gpx+xml', 'application/x-gpx', 'application/x-gpx+xml'], + 'gqf' => ['application/vnd.grafeq'], + 'gqs' => ['application/vnd.grafeq'], + 'gra' => ['application/x-graphite'], + 'gradle' => ['text/x-gradle'], + 'gram' => ['application/srgs'], + 'gramps' => ['application/x-gramps-xml'], + 'gre' => ['application/vnd.geometry-explorer'], + 'groovy' => ['text/x-groovy'], + 'grv' => ['application/vnd.groove-injector'], + 'grxml' => ['application/srgs+xml'], + 'gs' => ['text/x-genie'], + 'gsf' => ['application/x-font-ghostscript', 'application/x-font-type1'], + 'gsh' => ['text/x-groovy'], + 'gsheet' => ['application/vnd.google-apps.spreadsheet'], + 'gslides' => ['application/vnd.google-apps.presentation'], + 'gsm' => ['audio/x-gsm'], + 'gtar' => ['application/x-gtar', 'application/x-tar'], + 'gtm' => ['application/vnd.groove-tool-message'], + 'gtw' => ['model/vnd.gtw'], + 'gv' => ['text/vnd.graphviz'], + 'gvp' => ['text/google-video-pointer', 'text/x-google-video-pointer'], + 'gvy' => ['text/x-groovy'], + 'gxf' => ['application/gxf'], + 'gxt' => ['application/vnd.geonext'], + 'gy' => ['text/x-groovy'], + 'gz' => ['application/x-gzip', 'application/gzip'], + 'h' => ['text/x-c', 'text/x-chdr'], + 'h++' => ['text/x-c++hdr'], + 'h261' => ['video/h261'], + 'h263' => ['video/h263'], + 'h264' => ['video/h264'], + 'h4' => ['application/x-hdf'], + 'h5' => ['application/x-hdf'], + 'hal' => ['application/vnd.hal+xml'], + 'hbci' => ['application/vnd.hbci'], + 'hbs' => ['text/x-handlebars-template'], + 'hdd' => ['application/x-virtualbox-hdd'], + 'hdf' => ['application/x-hdf'], + 'hdf4' => ['application/x-hdf'], + 'hdf5' => ['application/x-hdf'], + 'heic' => ['image/heic', 'image/heic-sequence', 'image/heif', 'image/heif-sequence'], + 'heics' => ['image/heic-sequence'], + 'heif' => ['image/heic', 'image/heic-sequence', 'image/heif', 'image/heif-sequence'], + 'heifs' => ['image/heif-sequence'], + 'hej2' => ['image/hej2k'], + 'held' => ['application/atsc-held+xml'], + 'hfe' => ['application/x-hfe-file', 'application/x-hfe-floppy-image'], + 'hh' => ['text/x-c', 'text/x-c++hdr'], + 'hjson' => ['application/hjson'], + 'hlp' => ['application/winhlp', 'zz-application/zz-winassoc-hlp'], + 'hp' => ['text/x-c++hdr'], + 'hpgl' => ['application/vnd.hp-hpgl'], + 'hpid' => ['application/vnd.hp-hpid'], + 'hpp' => ['text/x-c++hdr'], + 'hps' => ['application/vnd.hp-hps'], + 'hqx' => ['application/stuffit', 'application/mac-binhex40'], + 'hs' => ['text/x-haskell'], + 'hsj2' => ['image/hsj2'], + 'htc' => ['text/x-component'], + 'htke' => ['application/vnd.kenameaapp'], + 'htm' => ['text/html', 'application/xhtml+xml'], + 'html' => ['text/html', 'application/xhtml+xml'], + 'hvd' => ['application/vnd.yamaha.hv-dic'], + 'hvp' => ['application/vnd.yamaha.hv-voice'], + 'hvs' => ['application/vnd.yamaha.hv-script'], + 'hwp' => ['application/vnd.haansoft-hwp', 'application/x-hwp'], + 'hwt' => ['application/vnd.haansoft-hwt', 'application/x-hwt'], + 'hxx' => ['text/x-c++hdr'], + 'i2g' => ['application/vnd.intergeo'], + 'ica' => ['application/x-ica'], + 'icb' => ['application/tga', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], + 'icc' => ['application/vnd.iccprofile'], + 'ice' => ['x-conference/x-cooltalk'], + 'icm' => ['application/vnd.iccprofile'], + 'icns' => ['image/x-icns'], + 'ico' => ['application/ico', 'image/ico', 'image/icon', 'image/vnd.microsoft.icon', 'image/x-ico', 'image/x-icon', 'text/ico'], + 'ics' => ['application/ics', 'text/calendar', 'text/x-vcalendar'], + 'idl' => ['text/x-idl'], + 'ief' => ['image/ief'], + 'ifb' => ['text/calendar'], + 'iff' => ['image/x-iff', 'image/x-ilbm'], + 'ifm' => ['application/vnd.shana.informed.formdata'], + 'iges' => ['model/iges'], + 'igl' => ['application/vnd.igloader'], + 'igm' => ['application/vnd.insors.igm'], + 'igs' => ['model/iges'], + 'igx' => ['application/vnd.micrografx.igx'], + 'iif' => ['application/vnd.shana.informed.interchange'], + 'ilbm' => ['image/x-iff', 'image/x-ilbm'], + 'ime' => ['audio/imelody', 'audio/x-imelody', 'text/x-imelody'], + 'img' => ['application/x-raw-disk-image'], + 'img.xz' => ['application/x-raw-disk-image-xz-compressed'], + 'imp' => ['application/vnd.accpac.simply.imp'], + 'ims' => ['application/vnd.ms-ims'], + 'imy' => ['audio/imelody', 'audio/x-imelody', 'text/x-imelody'], + 'in' => ['text/plain'], + 'ini' => ['text/plain'], + 'ink' => ['application/inkml+xml'], + 'inkml' => ['application/inkml+xml'], + 'ins' => ['application/x-tex', 'text/x-tex'], + 'install' => ['application/x-install-instructions'], + 'iota' => ['application/vnd.astraea-software.iota'], + 'ipfix' => ['application/ipfix'], + 'ipk' => ['application/vnd.shana.informed.package'], + 'ips' => ['application/x-ips-patch'], + 'iptables' => ['text/x-iptables'], + 'ipynb' => ['application/x-ipynb+json'], + 'irm' => ['application/vnd.ibm.rights-management'], + 'irp' => ['application/vnd.irepository.package+xml'], + 'iso' => ['application/x-cd-image', 'application/x-dreamcast-rom', 'application/x-gamecube-iso-image', 'application/x-gamecube-rom', 'application/x-iso9660-image', 'application/x-saturn-rom', 'application/x-sega-cd-rom', 'application/x-sega-pico-rom', 'application/x-wbfs', 'application/x-wia', 'application/x-wii-iso-image', 'application/x-wii-rom'], + 'iso9660' => ['application/x-cd-image', 'application/x-iso9660-image'], + 'it' => ['audio/x-it'], + 'it87' => ['application/x-it87'], + 'itp' => ['application/vnd.shana.informed.formtemplate'], + 'its' => ['application/its+xml'], + 'ivp' => ['application/vnd.immervision-ivp'], + 'ivu' => ['application/vnd.immervision-ivu'], + 'j2c' => ['image/x-jp2-codestream'], + 'j2k' => ['image/x-jp2-codestream'], + 'jad' => ['text/vnd.sun.j2me.app-descriptor'], + 'jade' => ['text/jade'], + 'jam' => ['application/vnd.jam'], + 'jar' => ['application/x-java-archive', 'application/java-archive', 'application/x-jar'], + 'jardiff' => ['application/x-java-archive-diff'], + 'java' => ['text/x-java', 'text/x-java-source'], + 'jceks' => ['application/x-java-jce-keystore'], + 'jhc' => ['image/jphc'], + 'jisp' => ['application/vnd.jisp'], + 'jks' => ['application/x-java-keystore'], + 'jls' => ['image/jls'], + 'jlt' => ['application/vnd.hp-jlyt'], + 'jng' => ['image/x-jng'], + 'jnlp' => ['application/x-java-jnlp-file'], + 'joda' => ['application/vnd.joost.joda-archive'], + 'jp2' => ['image/jp2', 'image/jpeg2000', 'image/jpeg2000-image', 'image/x-jpeg2000-image'], + 'jpc' => ['image/x-jp2-codestream'], + 'jpe' => ['image/jpeg', 'image/pjpeg'], + 'jpeg' => ['image/jpeg', 'image/pjpeg'], + 'jpf' => ['image/jpx'], + 'jpg' => ['image/jpeg', 'image/pjpeg'], + 'jpg2' => ['image/jp2', 'image/jpeg2000', 'image/jpeg2000-image', 'image/x-jpeg2000-image'], + 'jpgm' => ['image/jpm', 'video/jpm'], + 'jpgv' => ['video/jpeg'], + 'jph' => ['image/jph'], + 'jpm' => ['image/jpm', 'video/jpm'], + 'jpr' => ['application/x-jbuilder-project'], + 'jpx' => ['application/x-jbuilder-project', 'image/jpx'], + 'jrd' => ['application/jrd+json'], + 'js' => ['text/javascript', 'application/javascript', 'application/x-javascript'], + 'jsm' => ['application/javascript', 'application/x-javascript', 'text/javascript'], + 'json' => ['application/json', 'application/schema+json'], + 'json-patch' => ['application/json-patch+json'], + 'json5' => ['application/json5'], + 'jsonld' => ['application/ld+json'], + 'jsonml' => ['application/jsonml+json'], + 'jsx' => ['text/jsx'], + 'jxl' => ['image/jxl'], + 'jxr' => ['image/jxr'], + 'jxra' => ['image/jxra'], + 'jxrs' => ['image/jxrs'], + 'jxs' => ['image/jxs'], + 'jxsc' => ['image/jxsc'], + 'jxsi' => ['image/jxsi'], + 'jxss' => ['image/jxss'], + 'k25' => ['image/x-kodak-k25'], + 'k7' => ['application/x-thomson-cassette'], + 'kar' => ['audio/midi', 'audio/x-midi'], + 'karbon' => ['application/vnd.kde.karbon', 'application/x-karbon'], + 'kdbx' => ['application/x-keepass2'], + 'kdc' => ['image/x-kodak-kdc'], + 'kdelnk' => ['application/x-desktop', 'application/x-gnome-app-info'], + 'kexi' => ['application/x-kexiproject-sqlite', 'application/x-kexiproject-sqlite2', 'application/x-kexiproject-sqlite3', 'application/x-vnd.kde.kexi'], + 'kexic' => ['application/x-kexi-connectiondata'], + 'kexis' => ['application/x-kexiproject-shortcut'], + 'key' => ['application/vnd.apple.keynote', 'application/pgp-keys', 'application/x-iwork-keynote-sffkey'], + 'keynote' => ['application/vnd.apple.keynote'], + 'kfo' => ['application/vnd.kde.kformula', 'application/x-kformula'], + 'kfx' => ['application/vnd.amazon.mobi8-ebook', 'application/x-mobi8-ebook'], + 'kia' => ['application/vnd.kidspiration'], + 'kil' => ['application/x-killustrator'], + 'kino' => ['application/smil', 'application/smil+xml'], + 'kml' => ['application/vnd.google-earth.kml+xml'], + 'kmz' => ['application/vnd.google-earth.kmz'], + 'kne' => ['application/vnd.kinar'], + 'knp' => ['application/vnd.kinar'], + 'kon' => ['application/vnd.kde.kontour', 'application/x-kontour'], + 'kpm' => ['application/x-kpovmodeler'], + 'kpr' => ['application/vnd.kde.kpresenter', 'application/x-kpresenter'], + 'kpt' => ['application/vnd.kde.kpresenter', 'application/x-kpresenter'], + 'kpxx' => ['application/vnd.ds-keypoint'], + 'kra' => ['application/x-krita'], + 'krz' => ['application/x-krita'], + 'ks' => ['application/x-java-keystore'], + 'ksp' => ['application/vnd.kde.kspread', 'application/x-kspread'], + 'ksy' => ['text/x-kaitai-struct'], + 'kt' => ['text/x-kotlin'], + 'ktr' => ['application/vnd.kahootz'], + 'ktx' => ['image/ktx'], + 'ktx2' => ['image/ktx2'], + 'ktz' => ['application/vnd.kahootz'], + 'kud' => ['application/x-kugar'], + 'kwd' => ['application/vnd.kde.kword', 'application/x-kword'], + 'kwt' => ['application/vnd.kde.kword', 'application/x-kword'], + 'la' => ['application/x-shared-library-la'], + 'lasxml' => ['application/vnd.las.las+xml'], + 'latex' => ['application/x-latex', 'application/x-tex', 'text/x-tex'], + 'lbd' => ['application/vnd.llamagraphics.life-balance.desktop'], + 'lbe' => ['application/vnd.llamagraphics.life-balance.exchange+xml'], + 'lbm' => ['image/x-iff', 'image/x-ilbm'], + 'ldif' => ['text/x-ldif'], + 'les' => ['application/vnd.hhe.lesson-player'], + 'less' => ['text/less'], + 'lgr' => ['application/lgr+xml'], + 'lha' => ['application/x-lha', 'application/x-lzh-compressed'], + 'lhs' => ['text/x-literate-haskell'], + 'lhz' => ['application/x-lhz'], + 'link66' => ['application/vnd.route66.link66+xml'], + 'lisp' => ['text/x-common-lisp'], + 'list' => ['text/plain'], + 'list3820' => ['application/vnd.ibm.modcap'], + 'listafp' => ['application/vnd.ibm.modcap'], + 'litcoffee' => ['text/coffeescript'], + 'lnk' => ['application/x-ms-shortcut'], + 'lnx' => ['application/x-atari-lynx-rom'], + 'loas' => ['audio/usac'], + 'log' => ['text/plain', 'text/x-log'], + 'lostxml' => ['application/lost+xml'], + 'lrm' => ['application/vnd.ms-lrm'], + 'lrv' => ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], + 'lrz' => ['application/x-lrzip'], + 'ltf' => ['application/vnd.frogans.ltf'], + 'ltx' => ['application/x-tex', 'text/x-tex'], + 'lua' => ['text/x-lua'], + 'luac' => ['application/x-lua-bytecode'], + 'lvp' => ['audio/vnd.lucent.voice'], + 'lwo' => ['image/x-lwo'], + 'lwob' => ['image/x-lwo'], + 'lwp' => ['application/vnd.lotus-wordpro'], + 'lws' => ['image/x-lws'], + 'ly' => ['text/x-lilypond'], + 'lyx' => ['application/x-lyx', 'text/x-lyx'], + 'lz' => ['application/x-lzip'], + 'lz4' => ['application/x-lz4'], + 'lzh' => ['application/x-lha', 'application/x-lzh-compressed'], + 'lzma' => ['application/x-lzma'], + 'lzo' => ['application/x-lzop'], + 'm' => ['text/x-matlab', 'text/x-objcsrc', 'text/x-octave'], + 'm13' => ['application/x-msmediaview'], + 'm14' => ['application/x-msmediaview'], + 'm15' => ['audio/x-mod'], + 'm1u' => ['video/vnd.mpegurl', 'video/x-mpegurl'], + 'm1v' => ['video/mpeg'], + 'm21' => ['application/mp21'], + 'm2a' => ['audio/mpeg'], + 'm2t' => ['video/mp2t'], + 'm2ts' => ['video/mp2t'], + 'm2v' => ['video/mpeg'], + 'm3a' => ['audio/mpeg'], + 'm3u' => ['audio/x-mpegurl', 'application/m3u', 'application/vnd.apple.mpegurl', 'audio/m3u', 'audio/mpegurl', 'audio/x-m3u', 'audio/x-mp3-playlist'], + 'm3u8' => ['application/m3u', 'application/vnd.apple.mpegurl', 'audio/m3u', 'audio/mpegurl', 'audio/x-m3u', 'audio/x-mp3-playlist', 'audio/x-mpegurl'], + 'm4' => ['application/x-m4'], + 'm4a' => ['audio/mp4', 'audio/m4a', 'audio/x-m4a'], + 'm4b' => ['audio/x-m4b'], + 'm4p' => ['application/mp4'], + 'm4r' => ['audio/x-m4r'], + 'm4s' => ['video/iso.segment'], + 'm4u' => ['video/vnd.mpegurl', 'video/x-mpegurl'], + 'm4v' => ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], + 'm7' => ['application/x-thomson-cartridge-memo7'], + 'ma' => ['application/mathematica'], + 'mab' => ['application/x-markaby'], + 'mads' => ['application/mads+xml'], + 'maei' => ['application/mmt-aei+xml'], + 'mag' => ['application/vnd.ecowin.chart'], + 'mak' => ['text/x-makefile'], + 'maker' => ['application/vnd.framemaker'], + 'man' => ['application/x-troff-man', 'text/troff'], + 'manifest' => ['text/cache-manifest'], + 'map' => ['application/json'], + 'markdown' => ['text/markdown', 'text/x-markdown'], + 'mathml' => ['application/mathml+xml'], + 'mb' => ['application/mathematica'], + 'mbk' => ['application/vnd.mobius.mbk'], + 'mbox' => ['application/mbox'], + 'mc1' => ['application/vnd.medcalcdata'], + 'mc2' => ['text/vnd.senx.warpscript'], + 'mcd' => ['application/vnd.mcd'], + 'mcurl' => ['text/vnd.curl.mcurl'], + 'md' => ['text/markdown', 'text/x-markdown'], + 'mdb' => ['application/x-msaccess', 'application/mdb', 'application/msaccess', 'application/vnd.ms-access', 'application/vnd.msaccess', 'application/x-mdb', 'zz-application/zz-winassoc-mdb'], + 'mdi' => ['image/vnd.ms-modi'], + 'mdx' => ['application/x-genesis-32x-rom', 'text/mdx'], + 'me' => ['text/troff', 'text/x-troff-me'], + 'med' => ['audio/x-mod'], + 'mesh' => ['model/mesh'], + 'meta4' => ['application/metalink4+xml'], + 'metalink' => ['application/metalink+xml'], + 'mets' => ['application/mets+xml'], + 'mfm' => ['application/vnd.mfmp'], + 'mft' => ['application/rpki-manifest'], + 'mgp' => ['application/vnd.osgeo.mapguide.package', 'application/x-magicpoint'], + 'mgz' => ['application/vnd.proteus.magazine'], + 'mht' => ['application/x-mimearchive'], + 'mhtml' => ['application/x-mimearchive'], + 'mid' => ['audio/midi', 'audio/x-midi'], + 'midi' => ['audio/midi', 'audio/x-midi'], + 'mie' => ['application/x-mie'], + 'mif' => ['application/vnd.mif', 'application/x-mif'], + 'mime' => ['message/rfc822'], + 'minipsf' => ['audio/x-minipsf'], + 'mj2' => ['video/mj2'], + 'mjp2' => ['video/mj2'], + 'mjpeg' => ['video/x-mjpeg'], + 'mjpg' => ['video/x-mjpeg'], + 'mjs' => ['application/javascript', 'application/x-javascript', 'text/javascript'], + 'mk' => ['text/x-makefile'], + 'mk3d' => ['video/x-matroska', 'video/x-matroska-3d'], + 'mka' => ['audio/x-matroska'], + 'mkd' => ['text/markdown', 'text/x-markdown'], + 'mks' => ['video/x-matroska'], + 'mkv' => ['video/x-matroska'], + 'ml' => ['text/x-ocaml'], + 'mli' => ['text/x-ocaml'], + 'mlp' => ['application/vnd.dolby.mlp'], + 'mm' => ['text/x-troff-mm'], + 'mmd' => ['application/vnd.chipnuts.karaoke-mmd'], + 'mmf' => ['application/vnd.smaf', 'application/x-smaf'], + 'mml' => ['application/mathml+xml', 'text/mathml'], + 'mmr' => ['image/vnd.fujixerox.edmics-mmr'], + 'mng' => ['video/x-mng'], + 'mny' => ['application/x-msmoney'], + 'mo' => ['application/x-gettext-translation', 'text/x-modelica'], + 'mo3' => ['audio/x-mo3'], + 'mobi' => ['application/x-mobipocket-ebook'], + 'moc' => ['text/x-moc'], + 'mod' => ['application/x-object', 'audio/x-mod'], + 'mods' => ['application/mods+xml'], + 'mof' => ['text/x-mof'], + 'moov' => ['video/quicktime'], + 'mount' => ['text/x-systemd-unit'], + 'mov' => ['video/quicktime'], + 'movie' => ['video/x-sgi-movie'], + 'mp+' => ['audio/x-musepack'], + 'mp2' => ['audio/mp2', 'audio/mpeg', 'audio/x-mp2', 'video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], + 'mp21' => ['application/mp21'], + 'mp2a' => ['audio/mpeg'], + 'mp3' => ['audio/mpeg', 'audio/mp3', 'audio/x-mp3', 'audio/x-mpeg', 'audio/x-mpg'], + 'mp4' => ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], + 'mp4a' => ['audio/mp4'], + 'mp4s' => ['application/mp4'], + 'mp4v' => ['video/mp4'], + 'mpc' => ['application/vnd.mophun.certificate', 'audio/x-musepack'], + 'mpd' => ['application/dash+xml'], + 'mpe' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], + 'mpeg' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], + 'mpg' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], + 'mpg4' => ['video/mp4'], + 'mpga' => ['audio/mp3', 'audio/mpeg', 'audio/x-mp3', 'audio/x-mpeg', 'audio/x-mpg'], + 'mpkg' => ['application/vnd.apple.installer+xml'], + 'mpl' => ['video/mp2t'], + 'mpls' => ['video/mp2t'], + 'mpm' => ['application/vnd.blueice.multipass'], + 'mpn' => ['application/vnd.mophun.application'], + 'mpp' => ['application/vnd.ms-project', 'audio/x-musepack'], + 'mpt' => ['application/vnd.ms-project'], + 'mpy' => ['application/vnd.ibm.minipay'], + 'mqy' => ['application/vnd.mobius.mqy'], + 'mrc' => ['application/marc'], + 'mrcx' => ['application/marcxml+xml'], + 'mrl' => ['text/x-mrml'], + 'mrml' => ['text/x-mrml'], + 'mrw' => ['image/x-minolta-mrw'], + 'ms' => ['text/troff', 'text/x-troff-ms'], + 'mscml' => ['application/mediaservercontrol+xml'], + 'mseed' => ['application/vnd.fdsn.mseed'], + 'mseq' => ['application/vnd.mseq'], + 'msf' => ['application/vnd.epson.msf'], + 'msg' => ['application/vnd.ms-outlook'], + 'msh' => ['model/mesh'], + 'msi' => ['application/x-msdownload', 'application/x-msi'], + 'msl' => ['application/vnd.mobius.msl'], + 'msod' => ['image/x-msod'], + 'msty' => ['application/vnd.muvee.style'], + 'msx' => ['application/x-msx-rom'], + 'mtl' => ['model/mtl'], + 'mtm' => ['audio/x-mod'], + 'mts' => ['model/vnd.mts', 'video/mp2t'], + 'mup' => ['text/x-mup'], + 'mus' => ['application/vnd.musician'], + 'musd' => ['application/mmt-usd+xml'], + 'musicxml' => ['application/vnd.recordare.musicxml+xml'], + 'mvb' => ['application/x-msmediaview'], + 'mvt' => ['application/vnd.mapbox-vector-tile'], + 'mwf' => ['application/vnd.mfer'], + 'mxf' => ['application/mxf'], + 'mxl' => ['application/vnd.recordare.musicxml'], + 'mxmf' => ['audio/mobile-xmf'], + 'mxml' => ['application/xv+xml'], + 'mxs' => ['application/vnd.triscape.mxs'], + 'mxu' => ['video/vnd.mpegurl', 'video/x-mpegurl'], + 'n-gage' => ['application/vnd.nokia.n-gage.symbian.install'], + 'n3' => ['text/n3'], + 'n64' => ['application/x-n64-rom'], + 'nb' => ['application/mathematica', 'application/x-mathematica'], + 'nbp' => ['application/vnd.wolfram.player'], + 'nc' => ['application/x-netcdf'], + 'ncx' => ['application/x-dtbncx+xml'], + 'nds' => ['application/x-nintendo-ds-rom'], + 'nef' => ['image/x-nikon-nef'], + 'nes' => ['application/x-nes-rom'], + 'nez' => ['application/x-nes-rom'], + 'nfo' => ['text/x-nfo'], + 'ngc' => ['application/x-neo-geo-pocket-color-rom'], + 'ngdat' => ['application/vnd.nokia.n-gage.data'], + 'ngp' => ['application/x-neo-geo-pocket-rom'], + 'nitf' => ['application/vnd.nitf'], + 'nlu' => ['application/vnd.neurolanguage.nlu'], + 'nml' => ['application/vnd.enliven'], + 'nnd' => ['application/vnd.noblenet-directory'], + 'nns' => ['application/vnd.noblenet-sealer'], + 'nnw' => ['application/vnd.noblenet-web'], + 'not' => ['text/x-mup'], + 'npx' => ['image/vnd.net-fpx'], + 'nq' => ['application/n-quads'], + 'nrw' => ['image/x-nikon-nrw'], + 'nsc' => ['application/x-conference', 'application/x-netshow-channel'], + 'nsf' => ['application/vnd.lotus-notes'], + 'nsv' => ['video/x-nsv'], + 'nt' => ['application/n-triples'], + 'ntf' => ['application/vnd.nitf'], + 'numbers' => ['application/vnd.apple.numbers', 'application/x-iwork-numbers-sffnumbers'], + 'nzb' => ['application/x-nzb'], + 'o' => ['application/x-object'], + 'oa2' => ['application/vnd.fujitsu.oasys2'], + 'oa3' => ['application/vnd.fujitsu.oasys3'], + 'oas' => ['application/vnd.fujitsu.oasys'], + 'obd' => ['application/x-msbinder'], + 'obgx' => ['application/vnd.openblox.game+xml'], + 'obj' => ['application/x-tgif', 'model/obj'], + 'ocl' => ['text/x-ocl'], + 'oda' => ['application/oda'], + 'odb' => ['application/vnd.oasis.opendocument.database', 'application/vnd.sun.xml.base'], + 'odc' => ['application/vnd.oasis.opendocument.chart'], + 'odf' => ['application/vnd.oasis.opendocument.formula'], + 'odft' => ['application/vnd.oasis.opendocument.formula-template'], + 'odg' => ['application/vnd.oasis.opendocument.graphics'], + 'odi' => ['application/vnd.oasis.opendocument.image'], + 'odm' => ['application/vnd.oasis.opendocument.text-master'], + 'odp' => ['application/vnd.oasis.opendocument.presentation'], + 'ods' => ['application/vnd.oasis.opendocument.spreadsheet'], + 'odt' => ['application/vnd.oasis.opendocument.text'], + 'oga' => ['audio/ogg', 'audio/vorbis', 'audio/x-flac+ogg', 'audio/x-ogg', 'audio/x-oggflac', 'audio/x-speex+ogg', 'audio/x-vorbis', 'audio/x-vorbis+ogg'], + 'ogex' => ['model/vnd.opengex'], + 'ogg' => ['audio/ogg', 'audio/vorbis', 'audio/x-flac+ogg', 'audio/x-ogg', 'audio/x-oggflac', 'audio/x-speex+ogg', 'audio/x-vorbis', 'audio/x-vorbis+ogg', 'video/ogg', 'video/x-ogg', 'video/x-theora', 'video/x-theora+ogg'], + 'ogm' => ['video/x-ogm', 'video/x-ogm+ogg'], + 'ogv' => ['video/ogg', 'video/x-ogg'], + 'ogx' => ['application/ogg', 'application/x-ogg'], + 'old' => ['application/x-trash'], + 'oleo' => ['application/x-oleo'], + 'omdoc' => ['application/omdoc+xml'], + 'onepkg' => ['application/onenote'], + 'onetmp' => ['application/onenote'], + 'onetoc' => ['application/onenote'], + 'onetoc2' => ['application/onenote'], + 'ooc' => ['text/x-ooc'], + 'opf' => ['application/oebps-package+xml'], + 'opml' => ['text/x-opml', 'text/x-opml+xml'], + 'oprc' => ['application/vnd.palm', 'application/x-palm-database'], + 'opus' => ['audio/ogg', 'audio/x-ogg', 'audio/x-opus+ogg'], + 'ora' => ['image/openraster'], + 'orf' => ['image/x-olympus-orf'], + 'org' => ['application/vnd.lotus-organizer', 'text/org', 'text/x-org'], + 'osf' => ['application/vnd.yamaha.openscoreformat'], + 'osfpvg' => ['application/vnd.yamaha.openscoreformat.osfpvg+xml'], + 'osm' => ['application/vnd.openstreetmap.data+xml'], + 'otc' => ['application/vnd.oasis.opendocument.chart-template'], + 'otf' => ['application/vnd.oasis.opendocument.formula-template', 'application/x-font-otf', 'font/otf'], + 'otg' => ['application/vnd.oasis.opendocument.graphics-template'], + 'oth' => ['application/vnd.oasis.opendocument.text-web'], + 'oti' => ['application/vnd.oasis.opendocument.image-template'], + 'otp' => ['application/vnd.oasis.opendocument.presentation-template'], + 'ots' => ['application/vnd.oasis.opendocument.spreadsheet-template'], + 'ott' => ['application/vnd.oasis.opendocument.text-template'], + 'ova' => ['application/ovf', 'application/x-virtualbox-ova'], + 'ovf' => ['application/x-virtualbox-ovf'], + 'owl' => ['application/rdf+xml', 'text/rdf'], + 'owx' => ['application/owl+xml'], + 'oxps' => ['application/oxps'], + 'oxt' => ['application/vnd.openofficeorg.extension'], + 'p' => ['text/x-pascal'], + 'p10' => ['application/pkcs10'], + 'p12' => ['application/pkcs12', 'application/x-pkcs12'], + 'p65' => ['application/x-pagemaker'], + 'p7b' => ['application/x-pkcs7-certificates'], + 'p7c' => ['application/pkcs7-mime'], + 'p7m' => ['application/pkcs7-mime'], + 'p7r' => ['application/x-pkcs7-certreqresp'], + 'p7s' => ['application/pkcs7-signature'], + 'p8' => ['application/pkcs8'], + 'p8e' => ['application/pkcs8-encrypted'], + 'pac' => ['application/x-ns-proxy-autoconfig'], + 'pack' => ['application/x-java-pack200'], + 'pages' => ['application/vnd.apple.pages', 'application/x-iwork-pages-sffpages'], + 'pak' => ['application/x-pak'], + 'par2' => ['application/x-par2'], + 'part' => ['application/x-partial-download'], + 'pas' => ['text/x-pascal'], + 'pat' => ['image/x-gimp-pat'], + 'patch' => ['text/x-diff', 'text/x-patch'], + 'path' => ['text/x-systemd-unit'], + 'paw' => ['application/vnd.pawaafile'], + 'pbd' => ['application/vnd.powerbuilder6'], + 'pbm' => ['image/x-portable-bitmap'], + 'pcap' => ['application/pcap', 'application/vnd.tcpdump.pcap', 'application/x-pcap'], + 'pcd' => ['image/x-photo-cd'], + 'pce' => ['application/x-pc-engine-rom'], + 'pcf' => ['application/x-cisco-vpn-settings', 'application/x-font-pcf'], + 'pcf.Z' => ['application/x-font-pcf'], + 'pcf.gz' => ['application/x-font-pcf'], + 'pcl' => ['application/vnd.hp-pcl'], + 'pclxl' => ['application/vnd.hp-pclxl'], + 'pct' => ['image/x-pict'], + 'pcurl' => ['application/vnd.curl.pcurl'], + 'pcx' => ['image/vnd.zbrush.pcx', 'image/x-pcx'], + 'pdb' => ['application/vnd.palm', 'application/x-aportisdoc', 'application/x-palm-database', 'application/x-pilot'], + 'pdc' => ['application/x-aportisdoc'], + 'pde' => ['text/x-processing'], + 'pdf' => ['application/pdf', 'application/acrobat', 'application/nappdf', 'application/x-pdf', 'image/pdf'], + 'pdf.bz2' => ['application/x-bzpdf'], + 'pdf.gz' => ['application/x-gzpdf'], + 'pdf.lz' => ['application/x-lzpdf'], + 'pdf.xz' => ['application/x-xzpdf'], + 'pef' => ['image/x-pentax-pef'], + 'pem' => ['application/x-x509-ca-cert'], + 'perl' => ['application/x-perl', 'text/x-perl'], + 'pfa' => ['application/x-font-type1'], + 'pfb' => ['application/x-font-type1'], + 'pfm' => ['application/x-font-type1'], + 'pfr' => ['application/font-tdpfr'], + 'pfx' => ['application/pkcs12', 'application/x-pkcs12'], + 'pgm' => ['image/x-portable-graymap'], + 'pgn' => ['application/vnd.chess-pgn', 'application/x-chess-pgn'], + 'pgp' => ['application/pgp', 'application/pgp-encrypted', 'application/pgp-keys', 'application/pgp-signature'], + 'php' => ['application/x-php', 'application/x-httpd-php'], + 'php3' => ['application/x-php'], + 'php4' => ['application/x-php'], + 'php5' => ['application/x-php'], + 'phps' => ['application/x-php'], + 'pic' => ['image/x-pict'], + 'pict' => ['image/x-pict'], + 'pict1' => ['image/x-pict'], + 'pict2' => ['image/x-pict'], + 'pk' => ['application/x-tex-pk'], + 'pkg' => ['application/x-xar'], + 'pki' => ['application/pkixcmp'], + 'pkipath' => ['application/pkix-pkipath'], + 'pkpass' => ['application/vnd.apple.pkpass'], + 'pkr' => ['application/pgp-keys'], + 'pl' => ['application/x-perl', 'text/x-perl'], + 'pla' => ['audio/x-iriver-pla'], + 'plb' => ['application/vnd.3gpp.pic-bw-large'], + 'plc' => ['application/vnd.mobius.plc'], + 'plf' => ['application/vnd.pocketlearn'], + 'pln' => ['application/x-planperfect'], + 'pls' => ['application/pls', 'application/pls+xml', 'audio/scpls', 'audio/x-scpls'], + 'pm' => ['application/x-pagemaker', 'application/x-perl', 'text/x-perl'], + 'pm6' => ['application/x-pagemaker'], + 'pmd' => ['application/x-pagemaker'], + 'pml' => ['application/vnd.ctc-posml'], + 'png' => ['image/png'], + 'pnm' => ['image/x-portable-anymap'], + 'pntg' => ['image/x-macpaint'], + 'po' => ['application/x-gettext', 'text/x-gettext-translation', 'text/x-po'], + 'pod' => ['application/x-perl', 'text/x-perl'], + 'por' => ['application/x-spss-por'], + 'portpkg' => ['application/vnd.macports.portpkg'], + 'pot' => ['application/mspowerpoint', 'application/powerpoint', 'application/vnd.ms-powerpoint', 'application/x-mspowerpoint', 'text/x-gettext-translation-template', 'text/x-pot'], + 'potm' => ['application/vnd.ms-powerpoint.template.macroenabled.12'], + 'potx' => ['application/vnd.openxmlformats-officedocument.presentationml.template'], + 'ppam' => ['application/vnd.ms-powerpoint.addin.macroenabled.12'], + 'ppd' => ['application/vnd.cups-ppd'], + 'ppm' => ['image/x-portable-pixmap'], + 'pps' => ['application/mspowerpoint', 'application/powerpoint', 'application/vnd.ms-powerpoint', 'application/x-mspowerpoint'], + 'ppsm' => ['application/vnd.ms-powerpoint.slideshow.macroenabled.12'], + 'ppsx' => ['application/vnd.openxmlformats-officedocument.presentationml.slideshow'], + 'ppt' => ['application/vnd.ms-powerpoint', 'application/mspowerpoint', 'application/powerpoint', 'application/x-mspowerpoint'], + 'pptm' => ['application/vnd.ms-powerpoint.presentation.macroenabled.12'], + 'pptx' => ['application/vnd.openxmlformats-officedocument.presentationml.presentation'], + 'ppz' => ['application/mspowerpoint', 'application/powerpoint', 'application/vnd.ms-powerpoint', 'application/x-mspowerpoint'], + 'pqa' => ['application/vnd.palm', 'application/x-palm-database'], + 'prc' => ['application/vnd.palm', 'application/x-mobipocket-ebook', 'application/x-palm-database', 'application/x-pilot'], + 'pre' => ['application/vnd.lotus-freelance'], + 'prf' => ['application/pics-rules'], + 'provx' => ['application/provenance+xml'], + 'ps' => ['application/postscript'], + 'ps.bz2' => ['application/x-bzpostscript'], + 'ps.gz' => ['application/x-gzpostscript'], + 'psb' => ['application/vnd.3gpp.pic-bw-small'], + 'psd' => ['application/photoshop', 'application/x-photoshop', 'image/photoshop', 'image/psd', 'image/vnd.adobe.photoshop', 'image/x-photoshop', 'image/x-psd'], + 'psf' => ['application/x-font-linux-psf', 'audio/x-psf'], + 'psf.gz' => ['application/x-gz-font-linux-psf'], + 'psflib' => ['audio/x-psflib'], + 'psid' => ['audio/prs.sid'], + 'pskcxml' => ['application/pskc+xml'], + 'psw' => ['application/x-pocket-word'], + 'pti' => ['image/prs.pti'], + 'ptid' => ['application/vnd.pvi.ptid1'], + 'pub' => ['application/vnd.ms-publisher', 'application/x-mspublisher'], + 'pvb' => ['application/vnd.3gpp.pic-bw-var'], + 'pw' => ['application/x-pw'], + 'pwn' => ['application/vnd.3m.post-it-notes'], + 'py' => ['text/x-python', 'text/x-python3'], + 'py3' => ['text/x-python3'], + 'py3x' => ['text/x-python3'], + 'pya' => ['audio/vnd.ms-playready.media.pya'], + 'pyc' => ['application/x-python-bytecode'], + 'pyi' => ['text/x-python3'], + 'pyo' => ['application/x-python-bytecode'], + 'pys' => ['application/x-pyspread-bz-spreadsheet'], + 'pysu' => ['application/x-pyspread-spreadsheet'], + 'pyv' => ['video/vnd.ms-playready.media.pyv'], + 'pyx' => ['text/x-python'], + 'qam' => ['application/vnd.epson.quickanime'], + 'qbo' => ['application/vnd.intu.qbo'], + 'qcow' => ['application/x-qemu-disk'], + 'qcow2' => ['application/x-qemu-disk'], + 'qd' => ['application/x-fd-file', 'application/x-raw-floppy-disk-image'], + 'qed' => ['application/x-qed-disk'], + 'qfx' => ['application/vnd.intu.qfx'], + 'qif' => ['application/x-qw', 'image/x-quicktime'], + 'qml' => ['text/x-qml'], + 'qmlproject' => ['text/x-qml'], + 'qmltypes' => ['text/x-qml'], + 'qp' => ['application/x-qpress'], + 'qps' => ['application/vnd.publishare-delta-tree'], + 'qt' => ['video/quicktime'], + 'qti' => ['application/x-qtiplot'], + 'qti.gz' => ['application/x-qtiplot'], + 'qtif' => ['image/x-quicktime'], + 'qtl' => ['application/x-quicktime-media-link', 'application/x-quicktimeplayer'], + 'qtvr' => ['video/quicktime'], + 'qwd' => ['application/vnd.quark.quarkxpress'], + 'qwt' => ['application/vnd.quark.quarkxpress'], + 'qxb' => ['application/vnd.quark.quarkxpress'], + 'qxd' => ['application/vnd.quark.quarkxpress'], + 'qxl' => ['application/vnd.quark.quarkxpress'], + 'qxt' => ['application/vnd.quark.quarkxpress'], + 'ra' => ['audio/vnd.m-realaudio', 'audio/vnd.rn-realaudio', 'audio/x-pn-realaudio', 'audio/x-realaudio'], + 'raf' => ['image/x-fuji-raf'], + 'ram' => ['application/ram', 'audio/x-pn-realaudio'], + 'raml' => ['application/raml+yaml'], + 'rapd' => ['application/route-apd+xml'], + 'rar' => ['application/x-rar-compressed', 'application/vnd.rar', 'application/x-rar'], + 'ras' => ['image/x-cmu-raster'], + 'raw' => ['image/x-panasonic-raw', 'image/x-panasonic-rw'], + 'raw-disk-image' => ['application/x-raw-disk-image'], + 'raw-disk-image.xz' => ['application/x-raw-disk-image-xz-compressed'], + 'rax' => ['audio/vnd.m-realaudio', 'audio/vnd.rn-realaudio', 'audio/x-pn-realaudio'], + 'rb' => ['application/x-ruby'], + 'rcprofile' => ['application/vnd.ipunplugged.rcprofile'], + 'rdf' => ['application/rdf+xml', 'text/rdf'], + 'rdfs' => ['application/rdf+xml', 'text/rdf'], + 'rdz' => ['application/vnd.data-vision.rdz'], + 'reg' => ['text/x-ms-regedit'], + 'rej' => ['application/x-reject', 'text/x-reject'], + 'relo' => ['application/p2p-overlay+xml'], + 'rep' => ['application/vnd.businessobjects'], + 'res' => ['application/x-dtbresource+xml'], + 'rgb' => ['image/x-rgb'], + 'rif' => ['application/reginfo+xml'], + 'rip' => ['audio/vnd.rip'], + 'ris' => ['application/x-research-info-systems'], + 'rl' => ['application/resource-lists+xml'], + 'rlc' => ['image/vnd.fujixerox.edmics-rlc'], + 'rld' => ['application/resource-lists-diff+xml'], + 'rle' => ['image/rle'], + 'rm' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rmi' => ['audio/midi'], + 'rmj' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rmm' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rmp' => ['audio/x-pn-realaudio-plugin'], + 'rms' => ['application/vnd.jcp.javame.midlet-rms', 'application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rmvb' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rmx' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rnc' => ['application/relax-ng-compact-syntax', 'application/x-rnc'], + 'rng' => ['application/xml', 'text/xml'], + 'roa' => ['application/rpki-roa'], + 'roff' => ['application/x-troff', 'text/troff', 'text/x-troff'], + 'ros' => ['text/x-common-lisp'], + 'rp' => ['image/vnd.rn-realpix'], + 'rp9' => ['application/vnd.cloanto.rp9'], + 'rpm' => ['application/x-redhat-package-manager', 'application/x-rpm'], + 'rpss' => ['application/vnd.nokia.radio-presets'], + 'rpst' => ['application/vnd.nokia.radio-preset'], + 'rq' => ['application/sparql-query'], + 'rs' => ['application/rls-services+xml', 'text/rust'], + 'rsat' => ['application/atsc-rsat+xml'], + 'rsd' => ['application/rsd+xml'], + 'rsheet' => ['application/urc-ressheet+xml'], + 'rss' => ['application/rss+xml', 'text/rss'], + 'rst' => ['text/x-rst'], + 'rt' => ['text/vnd.rn-realtext'], + 'rtf' => ['application/rtf', 'text/rtf'], + 'rtx' => ['text/richtext'], + 'run' => ['application/x-makeself'], + 'rusd' => ['application/route-usd+xml'], + 'rv' => ['video/vnd.rn-realvideo', 'video/x-real-video'], + 'rvx' => ['video/vnd.rn-realvideo', 'video/x-real-video'], + 'rw2' => ['image/x-panasonic-raw2', 'image/x-panasonic-rw2'], + 's' => ['text/x-asm'], + 's3m' => ['audio/s3m', 'audio/x-s3m'], + 'saf' => ['application/vnd.yamaha.smaf-audio'], + 'sage' => ['text/x-sagemath'], + 'sam' => ['application/x-amipro'], + 'sami' => ['application/x-sami'], + 'sap' => ['application/x-sap-file', 'application/x-thomson-sap-image'], + 'sass' => ['text/x-sass'], + 'sav' => ['application/x-spss-sav', 'application/x-spss-savefile'], + 'sbml' => ['application/sbml+xml'], + 'sc' => ['application/vnd.ibm.secure-container', 'text/x-scala'], + 'scala' => ['text/x-scala'], + 'scd' => ['application/x-msschedule'], + 'scm' => ['application/vnd.lotus-screencam', 'text/x-scheme'], + 'scope' => ['text/x-systemd-unit'], + 'scq' => ['application/scvp-cv-request'], + 'scs' => ['application/scvp-cv-response'], + 'scss' => ['text/x-scss'], + 'scurl' => ['text/vnd.curl.scurl'], + 'sda' => ['application/vnd.stardivision.draw'], + 'sdc' => ['application/vnd.stardivision.calc'], + 'sdd' => ['application/vnd.stardivision.impress'], + 'sdkd' => ['application/vnd.solent.sdkm+xml'], + 'sdkm' => ['application/vnd.solent.sdkm+xml'], + 'sdp' => ['application/sdp', 'application/vnd.sdp', 'application/vnd.stardivision.impress', 'application/x-sdp'], + 'sds' => ['application/vnd.stardivision.chart'], + 'sdw' => ['application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global'], + 'sea' => ['application/x-sea'], + 'see' => ['application/vnd.seemail'], + 'seed' => ['application/vnd.fdsn.seed'], + 'sema' => ['application/vnd.sema'], + 'semd' => ['application/vnd.semd'], + 'semf' => ['application/vnd.semf'], + 'senmlx' => ['application/senml+xml'], + 'sensmlx' => ['application/sensml+xml'], + 'ser' => ['application/java-serialized-object'], + 'service' => ['text/x-dbus-service', 'text/x-systemd-unit'], + 'setpay' => ['application/set-payment-initiation'], + 'setreg' => ['application/set-registration-initiation'], + 'sfc' => ['application/vnd.nintendo.snes.rom', 'application/x-snes-rom'], + 'sfd-hdstx' => ['application/vnd.hydrostatix.sof-data'], + 'sfs' => ['application/vnd.spotfire.sfs'], + 'sfv' => ['text/x-sfv'], + 'sg' => ['application/x-sg1000-rom'], + 'sgb' => ['application/x-gameboy-rom'], + 'sgd' => ['application/x-genesis-rom'], + 'sgf' => ['application/x-go-sgf'], + 'sgi' => ['image/sgi', 'image/x-sgi'], + 'sgl' => ['application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global'], + 'sgm' => ['text/sgml'], + 'sgml' => ['text/sgml'], + 'sh' => ['application/x-sh', 'application/x-shellscript', 'text/x-sh'], + 'shape' => ['application/x-dia-shape'], + 'shar' => ['application/x-shar'], + 'shex' => ['text/shex'], + 'shf' => ['application/shf+xml'], + 'shn' => ['application/x-shorten', 'audio/x-shorten'], + 'shtml' => ['text/html'], + 'siag' => ['application/x-siag'], + 'sid' => ['audio/prs.sid', 'image/x-mrsid-image'], + 'sieve' => ['application/sieve'], + 'sig' => ['application/pgp-signature'], + 'sik' => ['application/x-trash'], + 'sil' => ['audio/silk'], + 'silo' => ['model/mesh'], + 'sis' => ['application/vnd.symbian.install'], + 'sisx' => ['application/vnd.symbian.install', 'x-epoc/x-sisx-app'], + 'sit' => ['application/x-stuffit', 'application/stuffit', 'application/x-sit'], + 'sitx' => ['application/x-stuffitx'], + 'siv' => ['application/sieve'], + 'sk' => ['image/x-skencil'], + 'sk1' => ['image/x-skencil'], + 'skd' => ['application/vnd.koan'], + 'skm' => ['application/vnd.koan'], + 'skp' => ['application/vnd.koan'], + 'skr' => ['application/pgp-keys'], + 'skt' => ['application/vnd.koan'], + 'sldm' => ['application/vnd.ms-powerpoint.slide.macroenabled.12'], + 'sldx' => ['application/vnd.openxmlformats-officedocument.presentationml.slide'], + 'slice' => ['text/x-systemd-unit'], + 'slim' => ['text/slim'], + 'slk' => ['text/spreadsheet'], + 'slm' => ['text/slim'], + 'sls' => ['application/route-s-tsid+xml'], + 'slt' => ['application/vnd.epson.salt'], + 'sm' => ['application/vnd.stepmania.stepchart'], + 'smaf' => ['application/vnd.smaf', 'application/x-smaf'], + 'smc' => ['application/vnd.nintendo.snes.rom', 'application/x-snes-rom'], + 'smd' => ['application/vnd.stardivision.mail', 'application/x-genesis-rom'], + 'smf' => ['application/vnd.stardivision.math'], + 'smi' => ['application/smil', 'application/smil+xml', 'application/x-sami'], + 'smil' => ['application/smil', 'application/smil+xml'], + 'smk' => ['video/vnd.radgamettools.smacker'], + 'sml' => ['application/smil', 'application/smil+xml'], + 'sms' => ['application/x-sms-rom'], + 'smv' => ['video/x-smv'], + 'smzip' => ['application/vnd.stepmania.package'], + 'snap' => ['application/vnd.snap'], + 'snd' => ['audio/basic'], + 'snf' => ['application/x-font-snf'], + 'so' => ['application/x-sharedlib'], + 'socket' => ['text/x-systemd-unit'], + 'spc' => ['application/x-pkcs7-certificates'], + 'spd' => ['application/x-font-speedo'], + 'spdx' => ['text/spdx'], + 'spec' => ['text/x-rpm-spec'], + 'spf' => ['application/vnd.yamaha.smaf-phrase'], + 'spl' => ['application/futuresplash', 'application/vnd.adobe.flash.movie', 'application/x-futuresplash', 'application/x-shockwave-flash'], + 'spm' => ['application/x-source-rpm'], + 'spot' => ['text/vnd.in3d.spot'], + 'spp' => ['application/scvp-vp-response'], + 'spq' => ['application/scvp-vp-request'], + 'spx' => ['application/x-apple-systemprofiler+xml', 'audio/ogg', 'audio/x-speex', 'audio/x-speex+ogg'], + 'sql' => ['application/sql', 'application/x-sql', 'text/x-sql'], + 'sqlite2' => ['application/x-sqlite2'], + 'sqlite3' => ['application/vnd.sqlite3', 'application/x-sqlite3'], + 'sqsh' => ['application/vnd.squashfs'], + 'sr2' => ['image/x-sony-sr2'], + 'src' => ['application/x-wais-source'], + 'src.rpm' => ['application/x-source-rpm'], + 'srf' => ['image/x-sony-srf'], + 'srt' => ['application/x-srt', 'application/x-subrip'], + 'sru' => ['application/sru+xml'], + 'srx' => ['application/sparql-results+xml'], + 'ss' => ['text/x-scheme'], + 'ssa' => ['text/x-ssa'], + 'ssdl' => ['application/ssdl+xml'], + 'sse' => ['application/vnd.kodak-descriptor'], + 'ssf' => ['application/vnd.epson.ssf'], + 'ssml' => ['application/ssml+xml'], + 'st' => ['application/vnd.sailingtracker.track'], + 'stc' => ['application/vnd.sun.xml.calc.template'], + 'std' => ['application/vnd.sun.xml.draw.template'], + 'stf' => ['application/vnd.wt.stf'], + 'sti' => ['application/vnd.sun.xml.impress.template'], + 'stk' => ['application/hyperstudio'], + 'stl' => ['application/vnd.ms-pki.stl', 'model/stl', 'model/x.stl-ascii', 'model/x.stl-binary'], + 'stm' => ['audio/x-stm'], + 'stpxz' => ['model/step-xml+zip'], + 'stpz' => ['model/step+zip'], + 'str' => ['application/vnd.pg.format'], + 'stw' => ['application/vnd.sun.xml.writer.template'], + 'sty' => ['application/x-tex', 'text/x-tex'], + 'styl' => ['text/stylus'], + 'stylus' => ['text/stylus'], + 'sub' => ['image/vnd.dvb.subtitle', 'text/vnd.dvb.subtitle', 'text/x-microdvd', 'text/x-mpsub', 'text/x-subviewer'], + 'sun' => ['image/x-sun-raster'], + 'sus' => ['application/vnd.sus-calendar'], + 'susp' => ['application/vnd.sus-calendar'], + 'sv' => ['text/x-svsrc'], + 'sv4cpio' => ['application/x-sv4cpio'], + 'sv4crc' => ['application/x-sv4crc'], + 'svc' => ['application/vnd.dvb.service'], + 'svd' => ['application/vnd.svd'], + 'svg' => ['image/svg+xml', 'image/svg'], + 'svgz' => ['image/svg+xml', 'image/svg+xml-compressed'], + 'svh' => ['text/x-svhdr'], + 'swa' => ['application/x-director'], + 'swap' => ['text/x-systemd-unit'], + 'swf' => ['application/futuresplash', 'application/vnd.adobe.flash.movie', 'application/x-shockwave-flash'], + 'swi' => ['application/vnd.aristanetworks.swi'], + 'swidtag' => ['application/swid+xml'], + 'swm' => ['application/x-ms-wim'], + 'sxc' => ['application/vnd.sun.xml.calc'], + 'sxd' => ['application/vnd.sun.xml.draw'], + 'sxg' => ['application/vnd.sun.xml.writer.global'], + 'sxi' => ['application/vnd.sun.xml.impress'], + 'sxm' => ['application/vnd.sun.xml.math'], + 'sxw' => ['application/vnd.sun.xml.writer'], + 'sylk' => ['text/spreadsheet'], + 't' => ['application/x-perl', 'application/x-troff', 'text/troff', 'text/x-perl', 'text/x-troff'], + 't2t' => ['text/x-txt2tags'], + 't3' => ['application/x-t3vm-image'], + 't38' => ['image/t38'], + 'taglet' => ['application/vnd.mynfc'], + 'tao' => ['application/vnd.tao.intent-module-archive'], + 'tap' => ['image/vnd.tencent.tap'], + 'tar' => ['application/x-tar', 'application/x-gtar'], + 'tar.Z' => ['application/x-tarz'], + 'tar.bz' => ['application/x-bzip-compressed-tar'], + 'tar.bz2' => ['application/x-bzip-compressed-tar'], + 'tar.gz' => ['application/x-compressed-tar'], + 'tar.lrz' => ['application/x-lrzip-compressed-tar'], + 'tar.lz' => ['application/x-lzip-compressed-tar'], + 'tar.lz4' => ['application/x-lz4-compressed-tar'], + 'tar.lzma' => ['application/x-lzma-compressed-tar'], + 'tar.lzo' => ['application/x-tzo'], + 'tar.xz' => ['application/x-xz-compressed-tar'], + 'tar.zst' => ['application/x-zstd-compressed-tar'], + 'target' => ['text/x-systemd-unit'], + 'taz' => ['application/x-tarz'], + 'tb2' => ['application/x-bzip-compressed-tar'], + 'tbz' => ['application/x-bzip-compressed-tar'], + 'tbz2' => ['application/x-bzip-compressed-tar'], + 'tcap' => ['application/vnd.3gpp2.tcap'], + 'tcl' => ['application/x-tcl', 'text/tcl', 'text/x-tcl'], + 'td' => ['application/urc-targetdesc+xml'], + 'teacher' => ['application/vnd.smart.teacher'], + 'tei' => ['application/tei+xml'], + 'teicorpus' => ['application/tei+xml'], + 'tex' => ['application/x-tex', 'text/x-tex'], + 'texi' => ['application/x-texinfo', 'text/x-texinfo'], + 'texinfo' => ['application/x-texinfo', 'text/x-texinfo'], + 'text' => ['text/plain'], + 'tfi' => ['application/thraud+xml'], + 'tfm' => ['application/x-tex-tfm'], + 'tfx' => ['image/tiff-fx'], + 'tga' => ['application/tga', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], + 'tgz' => ['application/x-compressed-tar'], + 'theme' => ['application/x-theme'], + 'themepack' => ['application/x-windows-themepack'], + 'thmx' => ['application/vnd.ms-officetheme'], + 'tif' => ['image/tiff'], + 'tiff' => ['image/tiff'], + 'timer' => ['text/x-systemd-unit'], + 'tk' => ['application/x-tcl', 'text/tcl', 'text/x-tcl'], + 'tlrz' => ['application/x-lrzip-compressed-tar'], + 'tlz' => ['application/x-lzma-compressed-tar'], + 'tmo' => ['application/vnd.tmobile-livetv'], + 'tnef' => ['application/ms-tnef', 'application/vnd.ms-tnef'], + 'tnf' => ['application/ms-tnef', 'application/vnd.ms-tnef'], + 'toc' => ['application/x-cdrdao-toc'], + 'toml' => ['application/toml'], + 'torrent' => ['application/x-bittorrent'], + 'tpic' => ['application/tga', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], + 'tpl' => ['application/vnd.groove-tool-template'], + 'tpt' => ['application/vnd.trid.tpt'], + 'tr' => ['application/x-troff', 'text/troff', 'text/x-troff'], + 'tra' => ['application/vnd.trueapp'], + 'trig' => ['application/trig', 'application/x-trig'], + 'trm' => ['application/x-msterminal'], + 'ts' => ['application/x-linguist', 'text/vnd.qt.linguist', 'text/vnd.trolltech.linguist', 'video/mp2t'], + 'tsd' => ['application/timestamped-data'], + 'tsv' => ['text/tab-separated-values'], + 'tta' => ['audio/tta', 'audio/x-tta'], + 'ttc' => ['font/collection'], + 'ttf' => ['application/x-font-truetype', 'application/x-font-ttf', 'font/ttf'], + 'ttl' => ['text/turtle'], + 'ttml' => ['application/ttml+xml'], + 'ttx' => ['application/x-font-ttx'], + 'twd' => ['application/vnd.simtech-mindmapper'], + 'twds' => ['application/vnd.simtech-mindmapper'], + 'twig' => ['text/x-twig'], + 'txd' => ['application/vnd.genomatix.tuxedo'], + 'txf' => ['application/vnd.mobius.txf'], + 'txt' => ['text/plain'], + 'txz' => ['application/x-xz-compressed-tar'], + 'tzo' => ['application/x-tzo'], + 'tzst' => ['application/x-zstd-compressed-tar'], + 'u32' => ['application/x-authorware-bin'], + 'u8dsn' => ['message/global-delivery-status'], + 'u8hdr' => ['message/global-headers'], + 'u8mdn' => ['message/global-disposition-notification'], + 'u8msg' => ['message/global'], + 'ubj' => ['application/ubjson'], + 'udeb' => ['application/vnd.debian.binary-package', 'application/x-deb', 'application/x-debian-package'], + 'ufd' => ['application/vnd.ufdl'], + 'ufdl' => ['application/vnd.ufdl'], + 'ufraw' => ['application/x-ufraw'], + 'ui' => ['application/x-designer', 'application/x-gtk-builder'], + 'uil' => ['text/x-uil'], + 'ult' => ['audio/x-mod'], + 'ulx' => ['application/x-glulx'], + 'umj' => ['application/vnd.umajin'], + 'unf' => ['application/x-nes-rom'], + 'uni' => ['audio/x-mod'], + 'unif' => ['application/x-nes-rom'], + 'unityweb' => ['application/vnd.unity'], + 'uoml' => ['application/vnd.uoml+xml'], + 'uri' => ['text/uri-list'], + 'uris' => ['text/uri-list'], + 'url' => ['application/x-mswinurl'], + 'urls' => ['text/uri-list'], + 'usdz' => ['model/vnd.usdz+zip'], + 'ustar' => ['application/x-ustar'], + 'utz' => ['application/vnd.uiq.theme'], + 'uu' => ['text/x-uuencode'], + 'uue' => ['text/x-uuencode', 'zz-application/zz-winassoc-uu'], + 'uva' => ['audio/vnd.dece.audio'], + 'uvd' => ['application/vnd.dece.data'], + 'uvf' => ['application/vnd.dece.data'], + 'uvg' => ['image/vnd.dece.graphic'], + 'uvh' => ['video/vnd.dece.hd'], + 'uvi' => ['image/vnd.dece.graphic'], + 'uvm' => ['video/vnd.dece.mobile'], + 'uvp' => ['video/vnd.dece.pd'], + 'uvs' => ['video/vnd.dece.sd'], + 'uvt' => ['application/vnd.dece.ttml+xml'], + 'uvu' => ['video/vnd.uvvu.mp4'], + 'uvv' => ['video/vnd.dece.video'], + 'uvva' => ['audio/vnd.dece.audio'], + 'uvvd' => ['application/vnd.dece.data'], + 'uvvf' => ['application/vnd.dece.data'], + 'uvvg' => ['image/vnd.dece.graphic'], + 'uvvh' => ['video/vnd.dece.hd'], + 'uvvi' => ['image/vnd.dece.graphic'], + 'uvvm' => ['video/vnd.dece.mobile'], + 'uvvp' => ['video/vnd.dece.pd'], + 'uvvs' => ['video/vnd.dece.sd'], + 'uvvt' => ['application/vnd.dece.ttml+xml'], + 'uvvu' => ['video/vnd.uvvu.mp4'], + 'uvvv' => ['video/vnd.dece.video'], + 'uvvx' => ['application/vnd.dece.unspecified'], + 'uvvz' => ['application/vnd.dece.zip'], + 'uvx' => ['application/vnd.dece.unspecified'], + 'uvz' => ['application/vnd.dece.zip'], + 'v' => ['text/x-verilog'], + 'v64' => ['application/x-n64-rom'], + 'vala' => ['text/x-vala'], + 'vapi' => ['text/x-vala'], + 'vb' => ['application/x-virtual-boy-rom'], + 'vbox' => ['application/x-virtualbox-vbox'], + 'vbox-extpack' => ['application/x-virtualbox-vbox-extpack'], + 'vbs' => ['text/vbs', 'text/vbscript'], + 'vcard' => ['text/directory', 'text/vcard', 'text/x-vcard'], + 'vcd' => ['application/x-cdlink'], + 'vcf' => ['text/x-vcard', 'text/directory', 'text/vcard'], + 'vcg' => ['application/vnd.groove-vcard'], + 'vcs' => ['application/ics', 'text/calendar', 'text/x-vcalendar'], + 'vct' => ['text/directory', 'text/vcard', 'text/x-vcard'], + 'vcx' => ['application/vnd.vcx'], + 'vda' => ['application/tga', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], + 'vdi' => ['application/x-vdi-disk', 'application/x-virtualbox-vdi'], + 'vds' => ['model/vnd.sap.vds'], + 'vhd' => ['application/x-vhd-disk', 'application/x-virtualbox-vhd', 'text/x-vhdl'], + 'vhdl' => ['text/x-vhdl'], + 'vhdx' => ['application/x-vhdx-disk', 'application/x-virtualbox-vhdx'], + 'vis' => ['application/vnd.visionary'], + 'viv' => ['video/vivo', 'video/vnd.vivo'], + 'vivo' => ['video/vivo', 'video/vnd.vivo'], + 'vlc' => ['application/m3u', 'audio/m3u', 'audio/mpegurl', 'audio/x-m3u', 'audio/x-mp3-playlist', 'audio/x-mpegurl'], + 'vmdk' => ['application/x-virtualbox-vmdk', 'application/x-vmdk-disk'], + 'vob' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2', 'video/x-ms-vob'], + 'voc' => ['audio/x-voc'], + 'vor' => ['application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global'], + 'vox' => ['application/x-authorware-bin'], + 'vpc' => ['application/x-vhd-disk', 'application/x-virtualbox-vhd'], + 'vrm' => ['model/vrml'], + 'vrml' => ['model/vrml'], + 'vsd' => ['application/vnd.visio'], + 'vsdm' => ['application/vnd.ms-visio.drawing.macroenabled.main+xml'], + 'vsdx' => ['application/vnd.ms-visio.drawing.main+xml'], + 'vsf' => ['application/vnd.vsf'], + 'vss' => ['application/vnd.visio'], + 'vssm' => ['application/vnd.ms-visio.stencil.macroenabled.main+xml'], + 'vssx' => ['application/vnd.ms-visio.stencil.main+xml'], + 'vst' => ['application/tga', 'application/vnd.visio', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], + 'vstm' => ['application/vnd.ms-visio.template.macroenabled.main+xml'], + 'vstx' => ['application/vnd.ms-visio.template.main+xml'], + 'vsw' => ['application/vnd.visio'], + 'vtf' => ['image/vnd.valve.source.texture'], + 'vtt' => ['text/vtt'], + 'vtu' => ['model/vnd.vtu'], + 'vxml' => ['application/voicexml+xml'], + 'w3d' => ['application/x-director'], + 'wad' => ['application/x-doom', 'application/x-doom-wad', 'application/x-wii-wad'], + 'wadl' => ['application/vnd.sun.wadl+xml'], + 'war' => ['application/java-archive'], + 'wasm' => ['application/wasm'], + 'wav' => ['audio/wav', 'audio/vnd.wave', 'audio/wave', 'audio/x-wav'], + 'wax' => ['application/x-ms-asx', 'audio/x-ms-asx', 'audio/x-ms-wax', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], + 'wb1' => ['application/x-quattropro'], + 'wb2' => ['application/x-quattropro'], + 'wb3' => ['application/x-quattropro'], + 'wbmp' => ['image/vnd.wap.wbmp'], + 'wbs' => ['application/vnd.criticaltools.wbs+xml'], + 'wbxml' => ['application/vnd.wap.wbxml'], + 'wcm' => ['application/vnd.ms-works'], + 'wdb' => ['application/vnd.ms-works'], + 'wdp' => ['image/vnd.ms-photo'], + 'weba' => ['audio/webm'], + 'webapp' => ['application/x-web-app-manifest+json'], + 'webm' => ['video/webm'], + 'webmanifest' => ['application/manifest+json'], + 'webp' => ['image/webp'], + 'wg' => ['application/vnd.pmi.widget'], + 'wgt' => ['application/widget'], + 'wim' => ['application/x-ms-wim'], + 'wk1' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], + 'wk3' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], + 'wk4' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], + 'wkdownload' => ['application/x-partial-download'], + 'wks' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/vnd.ms-works', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], + 'wm' => ['video/x-ms-wm'], + 'wma' => ['audio/x-ms-wma', 'audio/wma'], + 'wmd' => ['application/x-ms-wmd'], + 'wmf' => ['application/wmf', 'application/x-msmetafile', 'application/x-wmf', 'image/wmf', 'image/x-win-metafile', 'image/x-wmf'], + 'wml' => ['text/vnd.wap.wml'], + 'wmlc' => ['application/vnd.wap.wmlc'], + 'wmls' => ['text/vnd.wap.wmlscript'], + 'wmlsc' => ['application/vnd.wap.wmlscriptc'], + 'wmv' => ['audio/x-ms-wmv', 'video/x-ms-wmv'], + 'wmx' => ['application/x-ms-asx', 'audio/x-ms-asx', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], + 'wmz' => ['application/x-ms-wmz', 'application/x-msmetafile'], + 'woff' => ['application/font-woff', 'application/x-font-woff', 'font/woff'], + 'woff2' => ['font/woff2'], + 'wp' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wp4' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wp5' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wp6' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wpd' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wpg' => ['application/x-wpg'], + 'wpl' => ['application/vnd.ms-wpl'], + 'wpp' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wps' => ['application/vnd.ms-works'], + 'wqd' => ['application/vnd.wqd'], + 'wri' => ['application/x-mswrite'], + 'wrl' => ['model/vrml'], + 'ws' => ['application/x-wonderswan-rom'], + 'wsc' => ['application/x-wonderswan-color-rom', 'message/vnd.wfa.wsc'], + 'wsdl' => ['application/wsdl+xml'], + 'wsgi' => ['text/x-python'], + 'wspolicy' => ['application/wspolicy+xml'], + 'wtb' => ['application/vnd.webturbo'], + 'wv' => ['audio/x-wavpack'], + 'wvc' => ['audio/x-wavpack-correction'], + 'wvp' => ['audio/x-wavpack'], + 'wvx' => ['application/x-ms-asx', 'audio/x-ms-asx', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], + 'wwf' => ['application/wwf', 'application/x-wwf'], + 'x32' => ['application/x-authorware-bin'], + 'x3d' => ['model/x3d+xml'], + 'x3db' => ['model/x3d+binary', 'model/x3d+fastinfoset'], + 'x3dbz' => ['model/x3d+binary'], + 'x3dv' => ['model/x3d+vrml', 'model/x3d-vrml'], + 'x3dvz' => ['model/x3d+vrml'], + 'x3dz' => ['model/x3d+xml'], + 'x3f' => ['image/x-sigma-x3f'], + 'x_b' => ['model/vnd.parasolid.transmit.binary'], + 'x_t' => ['model/vnd.parasolid.transmit.text'], + 'xac' => ['application/x-gnucash'], + 'xaml' => ['application/xaml+xml'], + 'xap' => ['application/x-silverlight-app'], + 'xar' => ['application/vnd.xara', 'application/x-xar'], + 'xav' => ['application/xcap-att+xml'], + 'xbap' => ['application/x-ms-xbap'], + 'xbd' => ['application/vnd.fujixerox.docuworks.binder'], + 'xbel' => ['application/x-xbel'], + 'xbl' => ['application/xml', 'text/xml'], + 'xbm' => ['image/x-xbitmap'], + 'xca' => ['application/xcap-caps+xml'], + 'xcf' => ['image/x-xcf'], + 'xcf.bz2' => ['image/x-compressed-xcf'], + 'xcf.gz' => ['image/x-compressed-xcf'], + 'xcs' => ['application/calendar+xml'], + 'xdf' => ['application/mrb-consumer+xml', 'application/mrb-publish+xml', 'application/xcap-diff+xml'], + 'xdgapp' => ['application/vnd.flatpak', 'application/vnd.xdgapp'], + 'xdm' => ['application/vnd.syncml.dm+xml'], + 'xdp' => ['application/vnd.adobe.xdp+xml'], + 'xdssc' => ['application/dssc+xml'], + 'xdw' => ['application/vnd.fujixerox.docuworks'], + 'xel' => ['application/xcap-el+xml'], + 'xenc' => ['application/xenc+xml'], + 'xer' => ['application/patch-ops-error+xml', 'application/xcap-error+xml'], + 'xfdf' => ['application/vnd.adobe.xfdf'], + 'xfdl' => ['application/vnd.xfdl'], + 'xhe' => ['audio/usac'], + 'xht' => ['application/xhtml+xml'], + 'xhtml' => ['application/xhtml+xml'], + 'xhvml' => ['application/xv+xml'], + 'xi' => ['audio/x-xi'], + 'xif' => ['image/vnd.xiff'], + 'xla' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xlam' => ['application/vnd.ms-excel.addin.macroenabled.12'], + 'xlc' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xld' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xlf' => ['application/x-xliff', 'application/x-xliff+xml', 'application/xliff+xml'], + 'xliff' => ['application/x-xliff', 'application/xliff+xml'], + 'xll' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xlm' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xlr' => ['application/vnd.ms-works'], + 'xls' => ['application/vnd.ms-excel', 'application/msexcel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xlsb' => ['application/vnd.ms-excel.sheet.binary.macroenabled.12'], + 'xlsm' => ['application/vnd.ms-excel.sheet.macroenabled.12'], + 'xlsx' => ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'], + 'xlt' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xltm' => ['application/vnd.ms-excel.template.macroenabled.12'], + 'xltx' => ['application/vnd.openxmlformats-officedocument.spreadsheetml.template'], + 'xlw' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xm' => ['audio/x-xm', 'audio/xm'], + 'xmf' => ['audio/mobile-xmf', 'audio/x-xmf', 'audio/xmf'], + 'xmi' => ['text/x-xmi'], + 'xml' => ['application/xml', 'text/xml'], + 'xns' => ['application/xcap-ns+xml'], + 'xo' => ['application/vnd.olpc-sugar'], + 'xop' => ['application/xop+xml'], + 'xpi' => ['application/x-xpinstall'], + 'xpl' => ['application/xproc+xml'], + 'xpm' => ['image/x-xpixmap', 'image/x-xpm'], + 'xpr' => ['application/vnd.is-xpr'], + 'xps' => ['application/vnd.ms-xpsdocument', 'application/xps'], + 'xpw' => ['application/vnd.intercon.formnet'], + 'xpx' => ['application/vnd.intercon.formnet'], + 'xsd' => ['application/xml', 'text/xml'], + 'xsl' => ['application/xml', 'application/xslt+xml'], + 'xslfo' => ['text/x-xslfo'], + 'xslt' => ['application/xslt+xml'], + 'xsm' => ['application/vnd.syncml+xml'], + 'xspf' => ['application/x-xspf+xml', 'application/xspf+xml'], + 'xul' => ['application/vnd.mozilla.xul+xml'], + 'xvm' => ['application/xv+xml'], + 'xvml' => ['application/xv+xml'], + 'xwd' => ['image/x-xwindowdump'], + 'xyz' => ['chemical/x-xyz'], + 'xz' => ['application/x-xz'], + 'yaml' => ['application/x-yaml', 'text/x-yaml', 'text/yaml'], + 'yang' => ['application/yang'], + 'yin' => ['application/yin+xml'], + 'yml' => ['application/x-yaml', 'text/x-yaml', 'text/yaml'], + 'ymp' => ['text/x-suse-ymp'], + 'yt' => ['application/vnd.youtube.yt'], + 'z1' => ['application/x-zmachine'], + 'z2' => ['application/x-zmachine'], + 'z3' => ['application/x-zmachine'], + 'z4' => ['application/x-zmachine'], + 'z5' => ['application/x-zmachine'], + 'z6' => ['application/x-zmachine'], + 'z64' => ['application/x-n64-rom'], + 'z7' => ['application/x-zmachine'], + 'z8' => ['application/x-zmachine'], + 'zabw' => ['application/x-abiword'], + 'zaz' => ['application/vnd.zzazz.deck+xml'], + 'zip' => ['application/zip', 'application/x-zip', 'application/x-zip-compressed'], + 'zir' => ['application/vnd.zul'], + 'zirz' => ['application/vnd.zul'], + 'zmm' => ['application/vnd.handheld-entertainment+xml'], + 'zoo' => ['application/x-zoo'], + 'zsav' => ['application/x-spss-sav', 'application/x-spss-savefile'], + 'zst' => ['application/zstd'], + 'zz' => ['application/zlib'], + '123' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], + '602' => ['application/x-t602'], + '669' => ['audio/x-mod'], + ]; +} diff --git a/plugins/email/vendor/symfony/mime/MimeTypesInterface.php b/plugins/email/vendor/symfony/mime/MimeTypesInterface.php new file mode 100644 index 0000000..17d45ad --- /dev/null +++ b/plugins/email/vendor/symfony/mime/MimeTypesInterface.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * @author Fabien Potencier + */ +interface MimeTypesInterface extends MimeTypeGuesserInterface +{ + /** + * Gets the extensions for the given MIME type in decreasing order of preference. + * + * @return string[] + */ + public function getExtensions(string $mimeType): array; + + /** + * Gets the MIME types for the given extension in decreasing order of preference. + * + * @return string[] + */ + public function getMimeTypes(string $ext): array; +} diff --git a/plugins/email/vendor/symfony/mime/Part/AbstractMultipartPart.php b/plugins/email/vendor/symfony/mime/Part/AbstractMultipartPart.php new file mode 100644 index 0000000..685d250 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Part/AbstractMultipartPart.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Header\Headers; + +/** + * @author Fabien Potencier + */ +abstract class AbstractMultipartPart extends AbstractPart +{ + private $boundary; + private $parts = []; + + public function __construct(AbstractPart ...$parts) + { + parent::__construct(); + + foreach ($parts as $part) { + $this->parts[] = $part; + } + } + + /** + * @return AbstractPart[] + */ + public function getParts(): array + { + return $this->parts; + } + + public function getMediaType(): string + { + return 'multipart'; + } + + public function getPreparedHeaders(): Headers + { + $headers = parent::getPreparedHeaders(); + $headers->setHeaderParameter('Content-Type', 'boundary', $this->getBoundary()); + + return $headers; + } + + public function bodyToString(): string + { + $parts = $this->getParts(); + $string = ''; + foreach ($parts as $part) { + $string .= '--'.$this->getBoundary()."\r\n".$part->toString()."\r\n"; + } + $string .= '--'.$this->getBoundary()."--\r\n"; + + return $string; + } + + public function bodyToIterable(): iterable + { + $parts = $this->getParts(); + foreach ($parts as $part) { + yield '--'.$this->getBoundary()."\r\n"; + yield from $part->toIterable(); + yield "\r\n"; + } + yield '--'.$this->getBoundary()."--\r\n"; + } + + public function asDebugString(): string + { + $str = parent::asDebugString(); + foreach ($this->getParts() as $part) { + $lines = explode("\n", $part->asDebugString()); + $str .= "\n └ ".array_shift($lines); + foreach ($lines as $line) { + $str .= "\n |".$line; + } + } + + return $str; + } + + private function getBoundary(): string + { + if (null === $this->boundary) { + $this->boundary = strtr(base64_encode(random_bytes(6)), '+/', '-_'); + } + + return $this->boundary; + } +} diff --git a/plugins/email/vendor/symfony/mime/Part/AbstractPart.php b/plugins/email/vendor/symfony/mime/Part/AbstractPart.php new file mode 100644 index 0000000..93892d9 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Part/AbstractPart.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Header\Headers; + +/** + * @author Fabien Potencier + */ +abstract class AbstractPart +{ + private $headers; + + public function __construct() + { + $this->headers = new Headers(); + } + + public function getHeaders(): Headers + { + return $this->headers; + } + + public function getPreparedHeaders(): Headers + { + $headers = clone $this->headers; + $headers->setHeaderBody('Parameterized', 'Content-Type', $this->getMediaType().'/'.$this->getMediaSubtype()); + + return $headers; + } + + public function toString(): string + { + return $this->getPreparedHeaders()->toString()."\r\n".$this->bodyToString(); + } + + public function toIterable(): iterable + { + yield $this->getPreparedHeaders()->toString(); + yield "\r\n"; + yield from $this->bodyToIterable(); + } + + public function asDebugString(): string + { + return $this->getMediaType().'/'.$this->getMediaSubtype(); + } + + abstract public function bodyToString(): string; + + abstract public function bodyToIterable(): iterable; + + abstract public function getMediaType(): string; + + abstract public function getMediaSubtype(): string; +} diff --git a/plugins/email/vendor/symfony/mime/Part/DataPart.php b/plugins/email/vendor/symfony/mime/Part/DataPart.php new file mode 100644 index 0000000..4247ce7 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Part/DataPart.php @@ -0,0 +1,183 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\MimeTypes; + +/** + * @author Fabien Potencier + */ +class DataPart extends TextPart +{ + /** @internal */ + protected $_parent; + + private static $mimeTypes; + + private $filename; + private $mediaType; + private $cid; + private $handle; + + /** + * @param resource|string $body + */ + public function __construct($body, string $filename = null, string $contentType = null, string $encoding = null) + { + unset($this->_parent); + + if (null === $contentType) { + $contentType = 'application/octet-stream'; + } + [$this->mediaType, $subtype] = explode('/', $contentType); + + parent::__construct($body, null, $subtype, $encoding); + + if (null !== $filename) { + $this->filename = $filename; + $this->setName($filename); + } + $this->setDisposition('attachment'); + } + + public static function fromPath(string $path, string $name = null, string $contentType = null): self + { + if (null === $contentType) { + $ext = strtolower(substr($path, strrpos($path, '.') + 1)); + if (null === self::$mimeTypes) { + self::$mimeTypes = new MimeTypes(); + } + $contentType = self::$mimeTypes->getMimeTypes($ext)[0] ?? 'application/octet-stream'; + } + + if ((is_file($path) && !is_readable($path)) || is_dir($path)) { + throw new InvalidArgumentException(sprintf('Path "%s" is not readable.', $path)); + } + + if (false === $handle = @fopen($path, 'r', false)) { + throw new InvalidArgumentException(sprintf('Unable to open path "%s".', $path)); + } + + if (!is_file($path)) { + $cache = fopen('php://temp', 'r+'); + stream_copy_to_stream($handle, $cache); + $handle = $cache; + } + + $p = new self($handle, $name ?: basename($path), $contentType); + $p->handle = $handle; + + return $p; + } + + /** + * @return $this + */ + public function asInline() + { + return $this->setDisposition('inline'); + } + + public function getContentId(): string + { + return $this->cid ?: $this->cid = $this->generateContentId(); + } + + public function hasContentId(): bool + { + return null !== $this->cid; + } + + public function getMediaType(): string + { + return $this->mediaType; + } + + public function getPreparedHeaders(): Headers + { + $headers = parent::getPreparedHeaders(); + + if (null !== $this->cid) { + $headers->setHeaderBody('Id', 'Content-ID', $this->cid); + } + + if (null !== $this->filename) { + $headers->setHeaderParameter('Content-Disposition', 'filename', $this->filename); + } + + return $headers; + } + + public function asDebugString(): string + { + $str = parent::asDebugString(); + if (null !== $this->filename) { + $str .= ' filename: '.$this->filename; + } + + return $str; + } + + private function generateContentId(): string + { + return bin2hex(random_bytes(16)).'@symfony'; + } + + public function __destruct() + { + if (null !== $this->handle && \is_resource($this->handle)) { + fclose($this->handle); + } + } + + /** + * @return array + */ + public function __sleep() + { + // converts the body to a string + parent::__sleep(); + + $this->_parent = []; + foreach (['body', 'charset', 'subtype', 'disposition', 'name', 'encoding'] as $name) { + $r = new \ReflectionProperty(TextPart::class, $name); + $r->setAccessible(true); + $this->_parent[$name] = $r->getValue($this); + } + $this->_headers = $this->getHeaders(); + + return ['_headers', '_parent', 'filename', 'mediaType']; + } + + public function __wakeup() + { + $r = new \ReflectionProperty(AbstractPart::class, 'headers'); + $r->setAccessible(true); + $r->setValue($this, $this->_headers); + unset($this->_headers); + + if (!\is_array($this->_parent)) { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + foreach (['body', 'charset', 'subtype', 'disposition', 'name', 'encoding'] as $name) { + if (null !== $this->_parent[$name] && !\is_string($this->_parent[$name])) { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + $r = new \ReflectionProperty(TextPart::class, $name); + $r->setAccessible(true); + $r->setValue($this, $this->_parent[$name]); + } + unset($this->_parent); + } +} diff --git a/plugins/email/vendor/symfony/mime/Part/MessagePart.php b/plugins/email/vendor/symfony/mime/Part/MessagePart.php new file mode 100644 index 0000000..1b5c23e --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Part/MessagePart.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +/** + * @final + * + * @author Fabien Potencier + */ +class MessagePart extends DataPart +{ + private $message; + + public function __construct(RawMessage $message) + { + if ($message instanceof Message) { + $name = $message->getHeaders()->getHeaderBody('Subject').'.eml'; + } else { + $name = 'email.eml'; + } + parent::__construct('', $name); + + $this->message = $message; + } + + public function getMediaType(): string + { + return 'message'; + } + + public function getMediaSubtype(): string + { + return 'rfc822'; + } + + public function getBody(): string + { + return $this->message->toString(); + } + + public function bodyToString(): string + { + return $this->getBody(); + } + + public function bodyToIterable(): iterable + { + return $this->message->toIterable(); + } +} diff --git a/plugins/email/vendor/symfony/mime/Part/Multipart/AlternativePart.php b/plugins/email/vendor/symfony/mime/Part/Multipart/AlternativePart.php new file mode 100644 index 0000000..fd75423 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Part/Multipart/AlternativePart.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; + +/** + * @author Fabien Potencier + */ +final class AlternativePart extends AbstractMultipartPart +{ + public function getMediaSubtype(): string + { + return 'alternative'; + } +} diff --git a/plugins/email/vendor/symfony/mime/Part/Multipart/DigestPart.php b/plugins/email/vendor/symfony/mime/Part/Multipart/DigestPart.php new file mode 100644 index 0000000..27537f1 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Part/Multipart/DigestPart.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; +use Symfony\Component\Mime\Part\MessagePart; + +/** + * @author Fabien Potencier + */ +final class DigestPart extends AbstractMultipartPart +{ + public function __construct(MessagePart ...$parts) + { + parent::__construct(...$parts); + } + + public function getMediaSubtype(): string + { + return 'digest'; + } +} diff --git a/plugins/email/vendor/symfony/mime/Part/Multipart/FormDataPart.php b/plugins/email/vendor/symfony/mime/Part/Multipart/FormDataPart.php new file mode 100644 index 0000000..ff6df81 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Part/Multipart/FormDataPart.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Part\AbstractMultipartPart; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * Implements RFC 7578. + * + * @author Fabien Potencier + */ +final class FormDataPart extends AbstractMultipartPart +{ + private $fields = []; + + /** + * @param array $fields + */ + public function __construct(array $fields = []) + { + parent::__construct(); + + foreach ($fields as $name => $value) { + if (!\is_string($value) && !\is_array($value) && !$value instanceof TextPart) { + throw new InvalidArgumentException(sprintf('A form field value can only be a string, an array, or an instance of TextPart ("%s" given).', get_debug_type($value))); + } + + $this->fields[$name] = $value; + } + // HTTP does not support \r\n in header values + $this->getHeaders()->setMaxLineLength(\PHP_INT_MAX); + } + + public function getMediaSubtype(): string + { + return 'form-data'; + } + + public function getParts(): array + { + return $this->prepareFields($this->fields); + } + + private function prepareFields(array $fields): array + { + $values = []; + + $prepare = function ($item, $key, $root = null) use (&$values, &$prepare) { + if (\is_int($key) && \is_array($item)) { + if (1 !== \count($item)) { + throw new InvalidArgumentException(sprintf('Form field values with integer keys can only have one array element, the key being the field name and the value being the field value, %d provided.', \count($item))); + } + + $key = key($item); + $item = $item[$key]; + } + + $fieldName = null !== $root ? sprintf('%s[%s]', $root, $key) : $key; + + if (\is_array($item)) { + array_walk($item, $prepare, $fieldName); + + return; + } + + $values[] = $this->preparePart($fieldName, $item); + }; + + array_walk($fields, $prepare); + + return $values; + } + + private function preparePart(string $name, $value): TextPart + { + if (\is_string($value)) { + return $this->configurePart($name, new TextPart($value, 'utf-8', 'plain', '8bit')); + } + + return $this->configurePart($name, $value); + } + + private function configurePart(string $name, TextPart $part): TextPart + { + static $r; + + if (null === $r) { + $r = new \ReflectionProperty(TextPart::class, 'encoding'); + $r->setAccessible(true); + } + + $part->setDisposition('form-data'); + $part->setName($name); + // HTTP does not support \r\n in header values + $part->getHeaders()->setMaxLineLength(\PHP_INT_MAX); + $r->setValue($part, '8bit'); + + return $part; + } +} diff --git a/plugins/email/vendor/symfony/mime/Part/Multipart/MixedPart.php b/plugins/email/vendor/symfony/mime/Part/Multipart/MixedPart.php new file mode 100644 index 0000000..c8d7028 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Part/Multipart/MixedPart.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; + +/** + * @author Fabien Potencier + */ +final class MixedPart extends AbstractMultipartPart +{ + public function getMediaSubtype(): string + { + return 'mixed'; + } +} diff --git a/plugins/email/vendor/symfony/mime/Part/Multipart/RelatedPart.php b/plugins/email/vendor/symfony/mime/Part/Multipart/RelatedPart.php new file mode 100644 index 0000000..08fdd5f --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Part/Multipart/RelatedPart.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; +use Symfony\Component\Mime\Part\AbstractPart; + +/** + * @author Fabien Potencier + */ +final class RelatedPart extends AbstractMultipartPart +{ + private $mainPart; + + public function __construct(AbstractPart $mainPart, AbstractPart $part, AbstractPart ...$parts) + { + $this->mainPart = $mainPart; + $this->prepareParts($part, ...$parts); + + parent::__construct($part, ...$parts); + } + + public function getParts(): array + { + return array_merge([$this->mainPart], parent::getParts()); + } + + public function getMediaSubtype(): string + { + return 'related'; + } + + private function generateContentId(): string + { + return bin2hex(random_bytes(16)).'@symfony'; + } + + private function prepareParts(AbstractPart ...$parts): void + { + foreach ($parts as $part) { + if (!$part->getHeaders()->has('Content-ID')) { + $part->getHeaders()->setHeaderBody('Id', 'Content-ID', $this->generateContentId()); + } + } + } +} diff --git a/plugins/email/vendor/symfony/mime/Part/SMimePart.php b/plugins/email/vendor/symfony/mime/Part/SMimePart.php new file mode 100644 index 0000000..cb619c2 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Part/SMimePart.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Header\Headers; + +/** + * @author Sebastiaan Stok + */ +class SMimePart extends AbstractPart +{ + /** @internal */ + protected $_headers; + + private $body; + private $type; + private $subtype; + private $parameters; + + /** + * @param iterable|string $body + */ + public function __construct($body, string $type, string $subtype, array $parameters) + { + unset($this->_headers); + + parent::__construct(); + + if (!\is_string($body) && !is_iterable($body)) { + throw new \TypeError(sprintf('The body of "%s" must be a string or a iterable (got "%s").', self::class, get_debug_type($body))); + } + + $this->body = $body; + $this->type = $type; + $this->subtype = $subtype; + $this->parameters = $parameters; + } + + public function getMediaType(): string + { + return $this->type; + } + + public function getMediaSubtype(): string + { + return $this->subtype; + } + + public function bodyToString(): string + { + if (\is_string($this->body)) { + return $this->body; + } + + $body = ''; + foreach ($this->body as $chunk) { + $body .= $chunk; + } + $this->body = $body; + + return $body; + } + + public function bodyToIterable(): iterable + { + if (\is_string($this->body)) { + yield $this->body; + + return; + } + + $body = ''; + foreach ($this->body as $chunk) { + $body .= $chunk; + yield $chunk; + } + $this->body = $body; + } + + public function getPreparedHeaders(): Headers + { + $headers = clone parent::getHeaders(); + + $headers->setHeaderBody('Parameterized', 'Content-Type', $this->getMediaType().'/'.$this->getMediaSubtype()); + + foreach ($this->parameters as $name => $value) { + $headers->setHeaderParameter('Content-Type', $name, $value); + } + + return $headers; + } + + public function __sleep(): array + { + // convert iterables to strings for serialization + if (is_iterable($this->body)) { + $this->body = $this->bodyToString(); + } + + $this->_headers = $this->getHeaders(); + + return ['_headers', 'body', 'type', 'subtype', 'parameters']; + } + + public function __wakeup(): void + { + $r = new \ReflectionProperty(AbstractPart::class, 'headers'); + $r->setAccessible(true); + $r->setValue($this, $this->_headers); + unset($this->_headers); + } +} diff --git a/plugins/email/vendor/symfony/mime/Part/TextPart.php b/plugins/email/vendor/symfony/mime/Part/TextPart.php new file mode 100644 index 0000000..bfe41c0 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Part/TextPart.php @@ -0,0 +1,215 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Encoder\Base64ContentEncoder; +use Symfony\Component\Mime\Encoder\ContentEncoderInterface; +use Symfony\Component\Mime\Encoder\EightBitContentEncoder; +use Symfony\Component\Mime\Encoder\QpContentEncoder; +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Header\Headers; + +/** + * @author Fabien Potencier + */ +class TextPart extends AbstractPart +{ + /** @internal */ + protected $_headers; + + private static $encoders = []; + + private $body; + private $charset; + private $subtype; + /** + * @var ?string + */ + private $disposition; + private $name; + private $encoding; + private $seekable; + + /** + * @param resource|string $body + */ + public function __construct($body, ?string $charset = 'utf-8', string $subtype = 'plain', string $encoding = null) + { + unset($this->_headers); + + parent::__construct(); + + if (!\is_string($body) && !\is_resource($body)) { + throw new \TypeError(sprintf('The body of "%s" must be a string or a resource (got "%s").', self::class, get_debug_type($body))); + } + + $this->body = $body; + $this->charset = $charset; + $this->subtype = $subtype; + $this->seekable = \is_resource($body) ? stream_get_meta_data($body)['seekable'] && 0 === fseek($body, 0, \SEEK_CUR) : null; + + if (null === $encoding) { + $this->encoding = $this->chooseEncoding(); + } else { + if ('quoted-printable' !== $encoding && 'base64' !== $encoding && '8bit' !== $encoding) { + throw new InvalidArgumentException(sprintf('The encoding must be one of "quoted-printable", "base64", or "8bit" ("%s" given).', $encoding)); + } + $this->encoding = $encoding; + } + } + + public function getMediaType(): string + { + return 'text'; + } + + public function getMediaSubtype(): string + { + return $this->subtype; + } + + /** + * @param string $disposition one of attachment, inline, or form-data + * + * @return $this + */ + public function setDisposition(string $disposition) + { + $this->disposition = $disposition; + + return $this; + } + + /** + * Sets the name of the file (used by FormDataPart). + * + * @return $this + */ + public function setName(string $name) + { + $this->name = $name; + + return $this; + } + + public function getBody(): string + { + if (null === $this->seekable) { + return $this->body; + } + + if ($this->seekable) { + rewind($this->body); + } + + return stream_get_contents($this->body) ?: ''; + } + + public function bodyToString(): string + { + return $this->getEncoder()->encodeString($this->getBody(), $this->charset); + } + + public function bodyToIterable(): iterable + { + if (null !== $this->seekable) { + if ($this->seekable) { + rewind($this->body); + } + yield from $this->getEncoder()->encodeByteStream($this->body); + } else { + yield $this->getEncoder()->encodeString($this->body); + } + } + + public function getPreparedHeaders(): Headers + { + $headers = parent::getPreparedHeaders(); + + $headers->setHeaderBody('Parameterized', 'Content-Type', $this->getMediaType().'/'.$this->getMediaSubtype()); + if ($this->charset) { + $headers->setHeaderParameter('Content-Type', 'charset', $this->charset); + } + if ($this->name && 'form-data' !== $this->disposition) { + $headers->setHeaderParameter('Content-Type', 'name', $this->name); + } + $headers->setHeaderBody('Text', 'Content-Transfer-Encoding', $this->encoding); + + if (!$headers->has('Content-Disposition') && null !== $this->disposition) { + $headers->setHeaderBody('Parameterized', 'Content-Disposition', $this->disposition); + if ($this->name) { + $headers->setHeaderParameter('Content-Disposition', 'name', $this->name); + } + } + + return $headers; + } + + public function asDebugString(): string + { + $str = parent::asDebugString(); + if (null !== $this->charset) { + $str .= ' charset: '.$this->charset; + } + if (null !== $this->disposition) { + $str .= ' disposition: '.$this->disposition; + } + + return $str; + } + + private function getEncoder(): ContentEncoderInterface + { + if ('8bit' === $this->encoding) { + return self::$encoders[$this->encoding] ?? (self::$encoders[$this->encoding] = new EightBitContentEncoder()); + } + + if ('quoted-printable' === $this->encoding) { + return self::$encoders[$this->encoding] ?? (self::$encoders[$this->encoding] = new QpContentEncoder()); + } + + return self::$encoders[$this->encoding] ?? (self::$encoders[$this->encoding] = new Base64ContentEncoder()); + } + + private function chooseEncoding(): string + { + if (null === $this->charset) { + return 'base64'; + } + + return 'quoted-printable'; + } + + /** + * @return array + */ + public function __sleep() + { + // convert resources to strings for serialization + if (null !== $this->seekable) { + $this->body = $this->getBody(); + $this->seekable = null; + } + + $this->_headers = $this->getHeaders(); + + return ['_headers', 'body', 'charset', 'subtype', 'disposition', 'name', 'encoding']; + } + + public function __wakeup() + { + $r = new \ReflectionProperty(AbstractPart::class, 'headers'); + $r->setAccessible(true); + $r->setValue($this, $this->_headers); + unset($this->_headers); + } +} diff --git a/plugins/email/vendor/symfony/mime/README.md b/plugins/email/vendor/symfony/mime/README.md new file mode 100644 index 0000000..8e4d5c7 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/README.md @@ -0,0 +1,13 @@ +MIME Component +============== + +The MIME component allows manipulating MIME messages. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/mime.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/plugins/email/vendor/symfony/mime/RawMessage.php b/plugins/email/vendor/symfony/mime/RawMessage.php new file mode 100644 index 0000000..d2a311d --- /dev/null +++ b/plugins/email/vendor/symfony/mime/RawMessage.php @@ -0,0 +1,91 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\LogicException; + +/** + * @author Fabien Potencier + */ +class RawMessage implements \Serializable +{ + private $message; + + /** + * @param iterable|string $message + */ + public function __construct($message) + { + $this->message = $message; + } + + public function toString(): string + { + if (\is_string($this->message)) { + return $this->message; + } + if ($this->message instanceof \Traversable) { + $this->message = iterator_to_array($this->message, false); + } + + return $this->message = implode('', $this->message); + } + + public function toIterable(): iterable + { + if (\is_string($this->message)) { + yield $this->message; + + return; + } + + $message = ''; + foreach ($this->message as $chunk) { + $message .= $chunk; + yield $chunk; + } + $this->message = $message; + } + + /** + * @throws LogicException if the message is not valid + */ + public function ensureValidity() + { + } + + /** + * @internal + */ + final public function serialize(): string + { + return serialize($this->__serialize()); + } + + /** + * @internal + */ + final public function unserialize($serialized) + { + $this->__unserialize(unserialize($serialized)); + } + + public function __serialize(): array + { + return [$this->toString()]; + } + + public function __unserialize(array $data): void + { + [$this->message] = $data; + } +} diff --git a/plugins/email/vendor/symfony/mime/Resources/bin/update_mime_types.php b/plugins/email/vendor/symfony/mime/Resources/bin/update_mime_types.php new file mode 100644 index 0000000..9f13bf3 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Resources/bin/update_mime_types.php @@ -0,0 +1,161 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +// load new map +$data = json_decode(file_get_contents('https://cdn.jsdelivr.net/gh/jshttp/mime-db@v1.49.0/db.json'), true); +$new = []; +foreach ($data as $mimeType => $mimeTypeInformation) { + if (!array_key_exists('extensions', $mimeTypeInformation)) { + continue; + } + $new[$mimeType] = $mimeTypeInformation['extensions']; +} + +$xml = simplexml_load_string(file_get_contents('https://gitlab.freedesktop.org/xdg/shared-mime-info/-/raw/master/data/freedesktop.org.xml.in')); +foreach ($xml as $node) { + $exts = []; + foreach ($node->glob as $glob) { + $pattern = (string) $glob['pattern']; + if ('*' != $pattern[0] || '.' != $pattern[1]) { + continue; + } + + $exts[] = substr($pattern, 2); + } + + if (!$exts) { + continue; + } + + $mt = strtolower((string) $node['type']); + $new[$mt] = array_merge($new[$mt] ?? [], $exts); + foreach ($node->alias as $alias) { + $mt = strtolower((string) $alias['type']); + $new[$mt] = array_merge($new[$mt] ?? [], $exts); + } +} + +// load current map +$data = file_get_contents($output = __DIR__.'/../../MimeTypes.php'); +$current = []; +$pre = ''; +$post = ''; +foreach (explode("\n", $data) as $line) { + if (!preg_match("{^ '([^']+/[^']+)' => \['(.+)'\],$}", $line, $matches)) { + if (!$current) { + $pre .= $line."\n"; + } else { + $post .= $line."\n"; + } + continue; + } + $current[$matches[1]] = explode("', '", $matches[2]); +} + +$data = $pre; + +// reverse map +// we prefill the extensions with some preferences for content-types +$exts = [ + 'asice' => ['application/vnd.etsi.asic-e+zip'], + 'bz2' => ['application/x-bz2'], + 'csv' => ['text/csv'], + 'ecma' => ['application/ecmascript'], + 'flv' => ['video/x-flv'], + 'gif' => ['image/gif'], + 'gz' => ['application/x-gzip'], + 'htm' => ['text/html'], + 'html' => ['text/html'], + 'jar' => ['application/x-java-archive'], + 'jpg' => ['image/jpeg'], + 'js' => ['text/javascript'], + 'keynote' => ['application/vnd.apple.keynote'], + 'key' => ['application/vnd.apple.keynote'], + 'm3u' => ['audio/x-mpegurl'], + 'm4a' => ['audio/mp4'], + 'md' => ['text/markdown', 'text/x-markdown'], + 'mdb' => ['application/x-msaccess'], + 'mid' => ['audio/midi'], + 'mov' => ['video/quicktime'], + 'mp3' => ['audio/mpeg'], + 'ogg' => ['audio/ogg'], + 'pdf' => ['application/pdf'], + 'php' => ['application/x-php'], + 'ppt' => ['application/vnd.ms-powerpoint'], + 'rar' => ['application/x-rar-compressed'], + 'hqx' => ['application/stuffit'], + 'sit' => ['application/x-stuffit', 'application/stuffit'], + 'svg' => ['image/svg+xml'], + 'tar' => ['application/x-tar'], + 'tif' => ['image/tiff'], + 'ttf' => ['application/x-font-truetype'], + 'vcf' => ['text/x-vcard'], + 'wav' => ['audio/wav'], + 'wma' => ['audio/x-ms-wma'], + 'wmv' => ['audio/x-ms-wmv'], + 'xls' => ['application/vnd.ms-excel'], + 'zip' => ['application/zip'], +]; + +// we merge the 2 maps (we never remove old mime types) +$map = array_replace_recursive($current, $new); + +foreach ($exts as $ext => $types) { + foreach ($types as $mt) { + if (!isset($map[$mt])) { + $map += [$mt => [$ext]]; + } + } +} +ksort($map); + +foreach ($map as $mimeType => $extensions) { + foreach ($exts as $ext => $types) { + if (in_array($mimeType, $types, true)) { + array_unshift($extensions, $ext); + } + } + $data .= sprintf(" '%s' => ['%s'],\n", $mimeType, implode("', '", array_unique($extensions))); +} +$data .= $post; + +foreach ($map as $mimeType => $extensions) { + foreach ($extensions as $extension) { + if ('application/octet-stream' === $mimeType && 'bin' !== $extension) { + continue; + } + + $exts[$extension][] = $mimeType; + } +} +ksort($exts); + +$updated = ''; +$state = 0; +foreach (explode("\n", $data) as $line) { + if (!preg_match("{^ '([^'/]+)' => \['(.+)'\],$}", $line, $matches)) { + if (1 === $state) { + $state = 2; + foreach ($exts as $ext => $mimeTypes) { + $updated .= sprintf(" '%s' => ['%s'],\n", $ext, implode("', '", array_unique($mimeTypes))); + } + } + $updated .= $line."\n"; + continue; + } + $state = 1; +} + +$updated = preg_replace('{Updated from upstream on .+?\.}', 'Updated from upstream on '.date('Y-m-d'), $updated, -1); + +file_put_contents($output, rtrim($updated, "\n")."\n"); + +echo "Done.\n"; diff --git a/plugins/email/vendor/symfony/mime/Test/Constraint/EmailAddressContains.php b/plugins/email/vendor/symfony/mime/Test/Constraint/EmailAddressContains.php new file mode 100644 index 0000000..827e141 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Test/Constraint/EmailAddressContains.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mime\Header\MailboxHeader; +use Symfony\Component\Mime\Header\MailboxListHeader; +use Symfony\Component\Mime\RawMessage; + +final class EmailAddressContains extends Constraint +{ + private $headerName; + private $expectedValue; + + public function __construct(string $headerName, string $expectedValue) + { + $this->headerName = $headerName; + $this->expectedValue = $expectedValue; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('contains address "%s" with value "%s"', $this->headerName, $this->expectedValue); + } + + /** + * @param RawMessage $message + * + * {@inheritdoc} + */ + protected function matches($message): bool + { + if (RawMessage::class === \get_class($message)) { + throw new \LogicException('Unable to test a message address on a RawMessage instance.'); + } + + $header = $message->getHeaders()->get($this->headerName); + if ($header instanceof MailboxHeader) { + return $this->expectedValue === $header->getAddress()->getAddress(); + } elseif ($header instanceof MailboxListHeader) { + foreach ($header->getAddresses() as $address) { + if ($this->expectedValue === $address->getAddress()) { + return true; + } + } + + return false; + } + + throw new \LogicException('Unable to test a message address on a non-address header.'); + } + + /** + * @param RawMessage $message + * + * {@inheritdoc} + */ + protected function failureDescription($message): string + { + return sprintf('the Email %s (value is %s)', $this->toString(), $message->getHeaders()->get($this->headerName)->getBodyAsString()); + } +} diff --git a/plugins/email/vendor/symfony/mime/Test/Constraint/EmailAttachmentCount.php b/plugins/email/vendor/symfony/mime/Test/Constraint/EmailAttachmentCount.php new file mode 100644 index 0000000..c0adbe3 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Test/Constraint/EmailAttachmentCount.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +final class EmailAttachmentCount extends Constraint +{ + private $expectedValue; + private $transport; + + public function __construct(int $expectedValue, string $transport = null) + { + $this->expectedValue = $expectedValue; + $this->transport = $transport; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has sent "%d" attachment(s)', $this->expectedValue); + } + + /** + * @param RawMessage $message + * + * {@inheritdoc} + */ + protected function matches($message): bool + { + if (RawMessage::class === \get_class($message) || Message::class === \get_class($message)) { + throw new \LogicException('Unable to test a message attachment on a RawMessage or Message instance.'); + } + + return $this->expectedValue === \count($message->getAttachments()); + } + + /** + * @param RawMessage $message + * + * {@inheritdoc} + */ + protected function failureDescription($message): string + { + return 'the Email '.$this->toString(); + } +} diff --git a/plugins/email/vendor/symfony/mime/Test/Constraint/EmailHasHeader.php b/plugins/email/vendor/symfony/mime/Test/Constraint/EmailHasHeader.php new file mode 100644 index 0000000..a29f835 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Test/Constraint/EmailHasHeader.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mime\RawMessage; + +final class EmailHasHeader extends Constraint +{ + private $headerName; + + public function __construct(string $headerName) + { + $this->headerName = $headerName; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has header "%s"', $this->headerName); + } + + /** + * @param RawMessage $message + * + * {@inheritdoc} + */ + protected function matches($message): bool + { + if (RawMessage::class === \get_class($message)) { + throw new \LogicException('Unable to test a message header on a RawMessage instance.'); + } + + return $message->getHeaders()->has($this->headerName); + } + + /** + * @param RawMessage $message + * + * {@inheritdoc} + */ + protected function failureDescription($message): string + { + return 'the Email '.$this->toString(); + } +} diff --git a/plugins/email/vendor/symfony/mime/Test/Constraint/EmailHeaderSame.php b/plugins/email/vendor/symfony/mime/Test/Constraint/EmailHeaderSame.php new file mode 100644 index 0000000..74b4121 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Test/Constraint/EmailHeaderSame.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mime\Header\UnstructuredHeader; +use Symfony\Component\Mime\RawMessage; + +final class EmailHeaderSame extends Constraint +{ + private $headerName; + private $expectedValue; + + public function __construct(string $headerName, string $expectedValue) + { + $this->headerName = $headerName; + $this->expectedValue = $expectedValue; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has header "%s" with value "%s"', $this->headerName, $this->expectedValue); + } + + /** + * @param RawMessage $message + * + * {@inheritdoc} + */ + protected function matches($message): bool + { + if (RawMessage::class === \get_class($message)) { + throw new \LogicException('Unable to test a message header on a RawMessage instance.'); + } + + return $this->expectedValue === $this->getHeaderValue($message); + } + + /** + * @param RawMessage $message + * + * {@inheritdoc} + */ + protected function failureDescription($message): string + { + return sprintf('the Email %s (value is %s)', $this->toString(), $this->getHeaderValue($message) ?? 'null'); + } + + private function getHeaderValue($message): ?string + { + if (null === $header = $message->getHeaders()->get($this->headerName)) { + return null; + } + + return $header instanceof UnstructuredHeader ? $header->getValue() : $header->getBodyAsString(); + } +} diff --git a/plugins/email/vendor/symfony/mime/Test/Constraint/EmailHtmlBodyContains.php b/plugins/email/vendor/symfony/mime/Test/Constraint/EmailHtmlBodyContains.php new file mode 100644 index 0000000..3c61376 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Test/Constraint/EmailHtmlBodyContains.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +final class EmailHtmlBodyContains extends Constraint +{ + private $expectedText; + + public function __construct(string $expectedText) + { + $this->expectedText = $expectedText; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('contains "%s"', $this->expectedText); + } + + /** + * {@inheritdoc} + * + * @param RawMessage $message + */ + protected function matches($message): bool + { + if (RawMessage::class === \get_class($message) || Message::class === \get_class($message)) { + throw new \LogicException('Unable to test a message HTML body on a RawMessage or Message instance.'); + } + + return false !== mb_strpos($message->getHtmlBody(), $this->expectedText); + } + + /** + * {@inheritdoc} + * + * @param RawMessage $message + */ + protected function failureDescription($message): string + { + return 'the Email HTML body '.$this->toString(); + } +} diff --git a/plugins/email/vendor/symfony/mime/Test/Constraint/EmailTextBodyContains.php b/plugins/email/vendor/symfony/mime/Test/Constraint/EmailTextBodyContains.php new file mode 100644 index 0000000..063d963 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/Test/Constraint/EmailTextBodyContains.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +final class EmailTextBodyContains extends Constraint +{ + private $expectedText; + + public function __construct(string $expectedText) + { + $this->expectedText = $expectedText; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('contains "%s"', $this->expectedText); + } + + /** + * {@inheritdoc} + * + * @param RawMessage $message + */ + protected function matches($message): bool + { + if (RawMessage::class === \get_class($message) || Message::class === \get_class($message)) { + throw new \LogicException('Unable to test a message text body on a RawMessage or Message instance.'); + } + + return false !== mb_strpos($message->getTextBody(), $this->expectedText); + } + + /** + * {@inheritdoc} + * + * @param RawMessage $message + */ + protected function failureDescription($message): string + { + return 'the Email text body '.$this->toString(); + } +} diff --git a/plugins/email/vendor/symfony/mime/composer.json b/plugins/email/vendor/symfony/mime/composer.json new file mode 100644 index 0000000..cd04969 --- /dev/null +++ b/plugins/email/vendor/symfony/mime/composer.json @@ -0,0 +1,46 @@ +{ + "name": "symfony/mime", + "type": "library", + "description": "Allows manipulating MIME messages", + "keywords": ["mime", "mime-type"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/property-access": "^4.4|^5.1|^6.0", + "symfony/property-info": "^4.4|^5.1|^6.0", + "symfony/serializer": "^5.2|^6.0" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<4.4" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Mime\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/plugins/email/vendor/symfony/polyfill-intl-idn/README.md b/plugins/email/vendor/symfony/polyfill-intl-idn/README.md index 2e75f2e..cae5517 100644 --- a/plugins/email/vendor/symfony/polyfill-intl-idn/README.md +++ b/plugins/email/vendor/symfony/polyfill-intl-idn/README.md @@ -4,7 +4,7 @@ Symfony Polyfill / Intl: Idn This component provides [`idn_to_ascii`](https://php.net/idn-to-ascii) and [`idn_to_utf8`](https://php.net/idn-to-utf8) functions to users who run php versions without the [Intl](https://php.net/intl) extension. More information can be found in the -[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). License ======= diff --git a/plugins/email/vendor/symfony/polyfill-intl-idn/composer.json b/plugins/email/vendor/symfony/polyfill-intl-idn/composer.json index c5a2a46..71030a2 100644 --- a/plugins/email/vendor/symfony/polyfill-intl-idn/composer.json +++ b/plugins/email/vendor/symfony/polyfill-intl-idn/composer.json @@ -34,7 +34,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", diff --git a/plugins/email/vendor/symfony/polyfill-intl-normalizer/README.md b/plugins/email/vendor/symfony/polyfill-intl-normalizer/README.md index 15060c5..b9b762e 100644 --- a/plugins/email/vendor/symfony/polyfill-intl-normalizer/README.md +++ b/plugins/email/vendor/symfony/polyfill-intl-normalizer/README.md @@ -6,7 +6,7 @@ This component provides a fallback implementation for the by the [Intl](https://php.net/intl) extension. More information can be found in the -[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). License ======= diff --git a/plugins/email/vendor/symfony/polyfill-intl-normalizer/composer.json b/plugins/email/vendor/symfony/polyfill-intl-normalizer/composer.json index 393edf7..eb452bf 100644 --- a/plugins/email/vendor/symfony/polyfill-intl-normalizer/composer.json +++ b/plugins/email/vendor/symfony/polyfill-intl-normalizer/composer.json @@ -29,7 +29,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", diff --git a/plugins/email/vendor/symfony/polyfill-php80/LICENSE b/plugins/email/vendor/symfony/polyfill-php80/LICENSE new file mode 100644 index 0000000..5593b1d --- /dev/null +++ b/plugins/email/vendor/symfony/polyfill-php80/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2020 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/plugins/email/vendor/symfony/polyfill-php80/Php80.php b/plugins/email/vendor/symfony/polyfill-php80/Php80.php new file mode 100644 index 0000000..362dd1a --- /dev/null +++ b/plugins/email/vendor/symfony/polyfill-php80/Php80.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php80; + +/** + * @author Ion Bazan + * @author Nico Oelgart + * @author Nicolas Grekas + * + * @internal + */ +final class Php80 +{ + public static function fdiv(float $dividend, float $divisor): float + { + return @($dividend / $divisor); + } + + public static function get_debug_type($value): string + { + switch (true) { + case null === $value: return 'null'; + case \is_bool($value): return 'bool'; + case \is_string($value): return 'string'; + case \is_array($value): return 'array'; + case \is_int($value): return 'int'; + case \is_float($value): return 'float'; + case \is_object($value): break; + case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class'; + default: + if (null === $type = @get_resource_type($value)) { + return 'unknown'; + } + + if ('Unknown' === $type) { + $type = 'closed'; + } + + return "resource ($type)"; + } + + $class = \get_class($value); + + if (false === strpos($class, '@')) { + return $class; + } + + return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous'; + } + + public static function get_resource_id($res): int + { + if (!\is_resource($res) && null === @get_resource_type($res)) { + throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res))); + } + + return (int) $res; + } + + public static function preg_last_error_msg(): string + { + switch (preg_last_error()) { + case \PREG_INTERNAL_ERROR: + return 'Internal error'; + case \PREG_BAD_UTF8_ERROR: + return 'Malformed UTF-8 characters, possibly incorrectly encoded'; + case \PREG_BAD_UTF8_OFFSET_ERROR: + return 'The offset did not correspond to the beginning of a valid UTF-8 code point'; + case \PREG_BACKTRACK_LIMIT_ERROR: + return 'Backtrack limit exhausted'; + case \PREG_RECURSION_LIMIT_ERROR: + return 'Recursion limit exhausted'; + case \PREG_JIT_STACKLIMIT_ERROR: + return 'JIT stack limit exhausted'; + case \PREG_NO_ERROR: + return 'No error'; + default: + return 'Unknown error'; + } + } + + public static function str_contains(string $haystack, string $needle): bool + { + return '' === $needle || false !== strpos($haystack, $needle); + } + + public static function str_starts_with(string $haystack, string $needle): bool + { + return 0 === strncmp($haystack, $needle, \strlen($needle)); + } + + public static function str_ends_with(string $haystack, string $needle): bool + { + if ('' === $needle || $needle === $haystack) { + return true; + } + + if ('' === $haystack) { + return false; + } + + $needleLength = \strlen($needle); + + return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength); + } +} diff --git a/plugins/email/vendor/symfony/polyfill-php80/PhpToken.php b/plugins/email/vendor/symfony/polyfill-php80/PhpToken.php new file mode 100644 index 0000000..fe6e691 --- /dev/null +++ b/plugins/email/vendor/symfony/polyfill-php80/PhpToken.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php80; + +/** + * @author Fedonyuk Anton + * + * @internal + */ +class PhpToken implements \Stringable +{ + /** + * @var int + */ + public $id; + + /** + * @var string + */ + public $text; + + /** + * @var int + */ + public $line; + + /** + * @var int + */ + public $pos; + + public function __construct(int $id, string $text, int $line = -1, int $position = -1) + { + $this->id = $id; + $this->text = $text; + $this->line = $line; + $this->pos = $position; + } + + public function getTokenName(): ?string + { + if ('UNKNOWN' === $name = token_name($this->id)) { + $name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text; + } + + return $name; + } + + /** + * @param int|string|array $kind + */ + public function is($kind): bool + { + foreach ((array) $kind as $value) { + if (\in_array($value, [$this->id, $this->text], true)) { + return true; + } + } + + return false; + } + + public function isIgnorable(): bool + { + return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true); + } + + public function __toString(): string + { + return (string) $this->text; + } + + /** + * @return static[] + */ + public static function tokenize(string $code, int $flags = 0): array + { + $line = 1; + $position = 0; + $tokens = token_get_all($code, $flags); + foreach ($tokens as $index => $token) { + if (\is_string($token)) { + $id = \ord($token); + $text = $token; + } else { + [$id, $text, $line] = $token; + } + $tokens[$index] = new static($id, $text, $line, $position); + $position += \strlen($text); + } + + return $tokens; + } +} diff --git a/plugins/email/vendor/symfony/polyfill-php80/README.md b/plugins/email/vendor/symfony/polyfill-php80/README.md new file mode 100644 index 0000000..3816c55 --- /dev/null +++ b/plugins/email/vendor/symfony/polyfill-php80/README.md @@ -0,0 +1,25 @@ +Symfony Polyfill / Php80 +======================== + +This component provides features added to PHP 8.0 core: + +- [`Stringable`](https://php.net/stringable) interface +- [`fdiv`](https://php.net/fdiv) +- [`ValueError`](https://php.net/valueerror) class +- [`UnhandledMatchError`](https://php.net/unhandledmatcherror) class +- `FILTER_VALIDATE_BOOL` constant +- [`get_debug_type`](https://php.net/get_debug_type) +- [`PhpToken`](https://php.net/phptoken) class +- [`preg_last_error_msg`](https://php.net/preg_last_error_msg) +- [`str_contains`](https://php.net/str_contains) +- [`str_starts_with`](https://php.net/str_starts_with) +- [`str_ends_with`](https://php.net/str_ends_with) +- [`get_resource_id`](https://php.net/get_resource_id) + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php b/plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php new file mode 100644 index 0000000..7ea6d27 --- /dev/null +++ b/plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php @@ -0,0 +1,22 @@ +flags = $flags; + } +} diff --git a/plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php b/plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php new file mode 100644 index 0000000..72f1081 --- /dev/null +++ b/plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php @@ -0,0 +1,7 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Php80 as p; + +if (\PHP_VERSION_ID >= 80000) { + return; +} + +if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) { + define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN); +} + +if (!function_exists('fdiv')) { + function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); } +} +if (!function_exists('preg_last_error_msg')) { + function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); } +} +if (!function_exists('str_contains')) { + function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); } +} +if (!function_exists('str_starts_with')) { + function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); } +} +if (!function_exists('str_ends_with')) { + function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); } +} +if (!function_exists('get_debug_type')) { + function get_debug_type($value): string { return p\Php80::get_debug_type($value); } +} +if (!function_exists('get_resource_id')) { + function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); } +} diff --git a/plugins/email/vendor/symfony/polyfill-php80/composer.json b/plugins/email/vendor/symfony/polyfill-php80/composer.json new file mode 100644 index 0000000..cd3e9b6 --- /dev/null +++ b/plugins/email/vendor/symfony/polyfill-php80/composer.json @@ -0,0 +1,40 @@ +{ + "name": "symfony/polyfill-php80", + "type": "library", + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "keywords": ["polyfill", "shim", "compatibility", "portable"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Php80\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/plugins/email/vendor/symfony/redis-messenger/CHANGELOG.md b/plugins/email/vendor/symfony/redis-messenger/CHANGELOG.md new file mode 100644 index 0000000..700abd7 --- /dev/null +++ b/plugins/email/vendor/symfony/redis-messenger/CHANGELOG.md @@ -0,0 +1,34 @@ +CHANGELOG +========= + +5.4 +--- + + * Deprecate not setting the `delete_after_ack` config option (or DSN parameter), + its default value will change to `true` in 6.0 + +5.3 +--- + + * Add `rediss://` DSN scheme support for TLS protocol + * Deprecate TLS option, use `rediss://127.0.0.1` instead of `redis://127.0.0.1?tls=1` + * Add support for `\RedisCluster` instance in `Connection` constructor + * Add support for Redis Cluster in DSN + +5.2.0 +----- + + * Added a `delete_after_reject` option to the DSN to allow control over message + deletion, similar to `delete_after_ack`. + * Added option `lazy` to delay connecting to Redis server until we first use it. + +5.1.0 +----- + + * Introduced the Redis bridge. + * Added TLS option in the DSN. Example: `redis://127.0.0.1?tls=1` + * Deprecated use of invalid options + * Added ability to receive of old pending messages with new `redeliver_timeout` + and `claim_interval` options. + * Added a `delete_after_ack` option to the DSN as an alternative to + `stream_max_entries` to avoid leaking memory. diff --git a/plugins/email/vendor/symfony/redis-messenger/LICENSE b/plugins/email/vendor/symfony/redis-messenger/LICENSE new file mode 100644 index 0000000..74cdc2d --- /dev/null +++ b/plugins/email/vendor/symfony/redis-messenger/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/plugins/email/vendor/symfony/redis-messenger/README.md b/plugins/email/vendor/symfony/redis-messenger/README.md new file mode 100644 index 0000000..2a56984 --- /dev/null +++ b/plugins/email/vendor/symfony/redis-messenger/README.md @@ -0,0 +1,12 @@ +Redis Messenger +=============== + +Provides Redis integration for Symfony Messenger. + +Resources +--------- + + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/plugins/email/vendor/symfony/redis-messenger/Transport/Connection.php b/plugins/email/vendor/symfony/redis-messenger/Transport/Connection.php new file mode 100644 index 0000000..ffcac3e --- /dev/null +++ b/plugins/email/vendor/symfony/redis-messenger/Transport/Connection.php @@ -0,0 +1,596 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Redis\Transport; + +use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\Exception\LogicException; +use Symfony\Component\Messenger\Exception\TransportException; + +/** + * A Redis connection. + * + * @author Alexander Schranz + * @author Antoine Bluchet + * @author Robin Chalas + * + * @internal + * @final + */ +class Connection +{ + private const DEFAULT_OPTIONS = [ + 'stream' => 'messages', + 'group' => 'symfony', + 'consumer' => 'consumer', + 'auto_setup' => true, + 'delete_after_ack' => false, + 'delete_after_reject' => true, + 'stream_max_entries' => 0, // any value higher than 0 defines an approximate maximum number of stream entries + 'dbindex' => 0, + 'tls' => false, + 'redeliver_timeout' => 3600, // Timeout before redeliver messages still in pending state (seconds) + 'claim_interval' => 60000, // Interval by which pending/abandoned messages should be checked + 'lazy' => false, + 'auth' => null, + 'serializer' => \Redis::SERIALIZER_PHP, + ]; + + private $connection; + private $stream; + private $queue; + private $group; + private $consumer; + private $autoSetup; + private $maxEntries; + private $redeliverTimeout; + private $nextClaim = 0.0; + private $claimInterval; + private $deleteAfterAck; + private $deleteAfterReject; + private $couldHavePendingMessages = true; + + /** + * @param \Redis|\RedisCluster|null $redis + */ + public function __construct(array $configuration, array $connectionCredentials = [], array $redisOptions = [], $redis = null) + { + if (version_compare(phpversion('redis'), '4.3.0', '<')) { + throw new LogicException('The redis transport requires php-redis 4.3.0 or higher.'); + } + + $host = $connectionCredentials['host'] ?? '127.0.0.1'; + $port = $connectionCredentials['port'] ?? 6379; + $serializer = $redisOptions['serializer'] ?? \Redis::SERIALIZER_PHP; + $dbIndex = $configuration['dbindex'] ?? self::DEFAULT_OPTIONS['dbindex']; + $auth = $connectionCredentials['auth'] ?? null; + if ('' === $auth) { + $auth = null; + } + + $lazy = $configuration['lazy'] ?? self::DEFAULT_OPTIONS['lazy']; + if (\is_array($host) || $redis instanceof \RedisCluster) { + $hosts = \is_string($host) ? [$host.':'.$port] : $host; // Always ensure we have an array + $initializer = static function ($redis) use ($hosts, $auth, $serializer) { + return self::initializeRedisCluster($redis, $hosts, $auth, $serializer); + }; + $redis = $lazy ? new RedisClusterProxy($redis, $initializer) : $initializer($redis); + } else { + $redis = $redis ?? new \Redis(); + $initializer = static function ($redis) use ($host, $port, $auth, $serializer, $dbIndex) { + return self::initializeRedis($redis, $host, $port, $auth, $serializer, $dbIndex); + }; + $redis = $lazy ? new RedisProxy($redis, $initializer) : $initializer($redis); + } + + $this->connection = $redis; + + foreach (['stream', 'group', 'consumer'] as $key) { + if (isset($configuration[$key]) && '' === $configuration[$key]) { + throw new InvalidArgumentException(sprintf('"%s" should be configured, got an empty string.', $key)); + } + } + + $this->stream = $configuration['stream'] ?? self::DEFAULT_OPTIONS['stream']; + $this->group = $configuration['group'] ?? self::DEFAULT_OPTIONS['group']; + $this->consumer = $configuration['consumer'] ?? self::DEFAULT_OPTIONS['consumer']; + $this->queue = $this->stream.'__queue'; + $this->autoSetup = $configuration['auto_setup'] ?? self::DEFAULT_OPTIONS['auto_setup']; + $this->maxEntries = $configuration['stream_max_entries'] ?? self::DEFAULT_OPTIONS['stream_max_entries']; + $this->deleteAfterAck = $configuration['delete_after_ack'] ?? self::DEFAULT_OPTIONS['delete_after_ack']; + $this->deleteAfterReject = $configuration['delete_after_reject'] ?? self::DEFAULT_OPTIONS['delete_after_reject']; + $this->redeliverTimeout = ($configuration['redeliver_timeout'] ?? self::DEFAULT_OPTIONS['redeliver_timeout']) * 1000; + $this->claimInterval = ($configuration['claim_interval'] ?? self::DEFAULT_OPTIONS['claim_interval']) / 1000; + } + + /** + * @param string|string[]|null $auth + */ + private static function initializeRedis(\Redis $redis, string $host, int $port, $auth, int $serializer, int $dbIndex): \Redis + { + $redis->connect($host, $port); + $redis->setOption(\Redis::OPT_SERIALIZER, $serializer); + + if (null !== $auth && !$redis->auth($auth)) { + throw new InvalidArgumentException('Redis connection failed: '.$redis->getLastError()); + } + + if ($dbIndex && !$redis->select($dbIndex)) { + throw new InvalidArgumentException('Redis connection failed: '.$redis->getLastError()); + } + + return $redis; + } + + /** + * @param string|string[]|null $auth + */ + private static function initializeRedisCluster(?\RedisCluster $redis, array $hosts, $auth, int $serializer): \RedisCluster + { + if (null === $redis) { + $redis = new \RedisCluster(null, $hosts, 0.0, 0.0, false, $auth); + } + + $redis->setOption(\Redis::OPT_SERIALIZER, $serializer); + + return $redis; + } + + /** + * @param \Redis|\RedisCluster|null $redis + */ + public static function fromDsn(string $dsn, array $redisOptions = [], $redis = null): self + { + if (false === strpos($dsn, ',')) { + $parsedUrl = self::parseDsn($dsn, $redisOptions); + } else { + $dsns = explode(',', $dsn); + $parsedUrls = array_map(function ($dsn) use (&$redisOptions) { + return self::parseDsn($dsn, $redisOptions); + }, $dsns); + + // Merge all the URLs, the last one overrides the previous ones + $parsedUrl = array_merge(...$parsedUrls); + + // Regroup all the hosts in an array interpretable by RedisCluster + $parsedUrl['host'] = array_map(function ($parsedUrl, $dsn) { + if (!isset($parsedUrl['host'])) { + throw new InvalidArgumentException(sprintf('Missing host in DSN part "%s", it must be defined when using Redis Cluster.', $dsn)); + } + + return $parsedUrl['host'].':'.($parsedUrl['port'] ?? 6379); + }, $parsedUrls, $dsns); + } + + self::validateOptions($redisOptions); + + $autoSetup = null; + if (\array_key_exists('auto_setup', $redisOptions)) { + $autoSetup = filter_var($redisOptions['auto_setup'], \FILTER_VALIDATE_BOOLEAN); + unset($redisOptions['auto_setup']); + } + + $maxEntries = null; + if (\array_key_exists('stream_max_entries', $redisOptions)) { + $maxEntries = filter_var($redisOptions['stream_max_entries'], \FILTER_VALIDATE_INT); + unset($redisOptions['stream_max_entries']); + } + + $deleteAfterAck = null; + if (\array_key_exists('delete_after_ack', $redisOptions)) { + $deleteAfterAck = filter_var($redisOptions['delete_after_ack'], \FILTER_VALIDATE_BOOLEAN); + unset($redisOptions['delete_after_ack']); + } else { + trigger_deprecation('symfony/redis-messenger', '5.4', 'Not setting the "delete_after_ack" boolean option explicitly is deprecated, its default value will change to true in 6.0.'); + } + + $deleteAfterReject = null; + if (\array_key_exists('delete_after_reject', $redisOptions)) { + $deleteAfterReject = filter_var($redisOptions['delete_after_reject'], \FILTER_VALIDATE_BOOLEAN); + unset($redisOptions['delete_after_reject']); + } + + $dbIndex = null; + if (\array_key_exists('dbindex', $redisOptions)) { + $dbIndex = filter_var($redisOptions['dbindex'], \FILTER_VALIDATE_INT); + unset($redisOptions['dbindex']); + } + + $tls = 'rediss' === $parsedUrl['scheme']; + if (\array_key_exists('tls', $redisOptions)) { + trigger_deprecation('symfony/redis-messenger', '5.3', 'Providing "tls" parameter is deprecated, use "rediss://" DSN scheme instead'); + $tls = filter_var($redisOptions['tls'], \FILTER_VALIDATE_BOOLEAN); + unset($redisOptions['tls']); + } + + $redeliverTimeout = null; + if (\array_key_exists('redeliver_timeout', $redisOptions)) { + $redeliverTimeout = filter_var($redisOptions['redeliver_timeout'], \FILTER_VALIDATE_INT); + unset($redisOptions['redeliver_timeout']); + } + + $claimInterval = null; + if (\array_key_exists('claim_interval', $redisOptions)) { + $claimInterval = filter_var($redisOptions['claim_interval'], \FILTER_VALIDATE_INT); + unset($redisOptions['claim_interval']); + } + + $configuration = [ + 'stream' => $redisOptions['stream'] ?? null, + 'group' => $redisOptions['group'] ?? null, + 'consumer' => $redisOptions['consumer'] ?? null, + 'lazy' => $redisOptions['lazy'] ?? self::DEFAULT_OPTIONS['lazy'], + 'auto_setup' => $autoSetup, + 'stream_max_entries' => $maxEntries, + 'delete_after_ack' => $deleteAfterAck, + 'delete_after_reject' => $deleteAfterReject, + 'dbindex' => $dbIndex, + 'redeliver_timeout' => $redeliverTimeout, + 'claim_interval' => $claimInterval, + ]; + + if (isset($parsedUrl['host'])) { + $pass = '' !== ($parsedUrl['pass'] ?? '') ? urldecode($parsedUrl['pass']) : null; + $user = '' !== ($parsedUrl['user'] ?? '') ? urldecode($parsedUrl['user']) : null; + $connectionCredentials = [ + 'host' => $parsedUrl['host'] ?? '127.0.0.1', + 'port' => $parsedUrl['port'] ?? 6379, + // See: https://github.com/phpredis/phpredis/#auth + 'auth' => $redisOptions['auth'] ?? (null !== $pass && null !== $user ? [$user, $pass] : ($pass ?? $user)), + ]; + + $pathParts = explode('/', rtrim($parsedUrl['path'] ?? '', '/')); + + $configuration['stream'] = $pathParts[1] ?? $configuration['stream']; + $configuration['group'] = $pathParts[2] ?? $configuration['group']; + $configuration['consumer'] = $pathParts[3] ?? $configuration['consumer']; + if ($tls) { + $connectionCredentials['host'] = 'tls://'.$connectionCredentials['host']; + } + } else { + $connectionCredentials = [ + 'host' => $parsedUrl['path'], + 'port' => 0, + ]; + } + + return new self($configuration, $connectionCredentials, $redisOptions, $redis); + } + + private static function parseDsn(string $dsn, array &$redisOptions): array + { + $url = $dsn; + $scheme = 0 === strpos($dsn, 'rediss:') ? 'rediss' : 'redis'; + + if (preg_match('#^'.$scheme.':///([^:@])+$#', $dsn)) { + $url = str_replace($scheme.':', 'file:', $dsn); + } + + if (false === $parsedUrl = parse_url($url)) { + throw new InvalidArgumentException(sprintf('The given Redis DSN "%s" is invalid.', $dsn)); + } + if (isset($parsedUrl['query'])) { + parse_str($parsedUrl['query'], $dsnOptions); + $redisOptions = array_merge($redisOptions, $dsnOptions); + } + + return $parsedUrl; + } + + private static function validateOptions(array $options): void + { + $availableOptions = array_keys(self::DEFAULT_OPTIONS); + + if (0 < \count($invalidOptions = array_diff(array_keys($options), $availableOptions))) { + trigger_deprecation('symfony/messenger', '5.1', 'Invalid option(s) "%s" passed to the Redis Messenger transport. Passing invalid options is deprecated.', implode('", "', $invalidOptions)); + } + } + + private function claimOldPendingMessages() + { + try { + // This could soon be optimized with https://github.com/antirez/redis/issues/5212 or + // https://github.com/antirez/redis/issues/6256 + $pendingMessages = $this->connection->xpending($this->stream, $this->group, '-', '+', 1); + } catch (\RedisException $e) { + throw new TransportException($e->getMessage(), 0, $e); + } + + $claimableIds = []; + foreach ($pendingMessages as $pendingMessage) { + if ($pendingMessage[1] === $this->consumer) { + $this->couldHavePendingMessages = true; + + return; + } + + if ($pendingMessage[2] >= $this->redeliverTimeout) { + $claimableIds[] = $pendingMessage[0]; + } + } + + if (\count($claimableIds) > 0) { + try { + $this->connection->xclaim( + $this->stream, + $this->group, + $this->consumer, + $this->redeliverTimeout, + $claimableIds, + ['JUSTID'] + ); + + $this->couldHavePendingMessages = true; + } catch (\RedisException $e) { + throw new TransportException($e->getMessage(), 0, $e); + } + } + + $this->nextClaim = microtime(true) + $this->claimInterval; + } + + public function get(): ?array + { + if ($this->autoSetup) { + $this->setup(); + } + $now = microtime(); + $now = substr($now, 11).substr($now, 2, 3); + + $queuedMessageCount = $this->rawCommand('ZCOUNT', 0, $now); + + while ($queuedMessageCount--) { + if (!$message = $this->rawCommand('ZPOPMIN', 1)) { + break; + } + + [$queuedMessage, $expiry] = $message; + + if (\strlen($expiry) === \strlen($now) ? $expiry > $now : \strlen($expiry) < \strlen($now)) { + // if a future-placed message is popped because of a race condition with + // another running consumer, the message is readded to the queue + + if (!$this->rawCommand('ZADD', 'NX', $expiry, $queuedMessage)) { + throw new TransportException('Could not add a message to the redis stream.'); + } + + break; + } + + $decodedQueuedMessage = json_decode($queuedMessage, true); + $this->add(\array_key_exists('body', $decodedQueuedMessage) ? $decodedQueuedMessage['body'] : $queuedMessage, $decodedQueuedMessage['headers'] ?? [], 0); + } + + if (!$this->couldHavePendingMessages && $this->nextClaim <= microtime(true)) { + $this->claimOldPendingMessages(); + } + + $messageId = '>'; // will receive new messages + + if ($this->couldHavePendingMessages) { + $messageId = '0'; // will receive consumers pending messages + } + + try { + $messages = $this->connection->xreadgroup( + $this->group, + $this->consumer, + [$this->stream => $messageId], + 1 + ); + } catch (\RedisException $e) { + throw new TransportException($e->getMessage(), 0, $e); + } + + if (false === $messages) { + if ($error = $this->connection->getLastError() ?: null) { + $this->connection->clearLastError(); + } + + throw new TransportException($error ?? 'Could not read messages from the redis stream.'); + } + + if ($this->couldHavePendingMessages && empty($messages[$this->stream])) { + $this->couldHavePendingMessages = false; + + // No pending messages so get a new one + return $this->get(); + } + + foreach ($messages[$this->stream] ?? [] as $key => $message) { + return [ + 'id' => $key, + 'data' => $message, + ]; + } + + return null; + } + + public function ack(string $id): void + { + try { + $acknowledged = $this->connection->xack($this->stream, $this->group, [$id]); + if ($this->deleteAfterAck) { + $acknowledged = $this->connection->xdel($this->stream, [$id]); + } + } catch (\RedisException $e) { + throw new TransportException($e->getMessage(), 0, $e); + } + + if (!$acknowledged) { + if ($error = $this->connection->getLastError() ?: null) { + $this->connection->clearLastError(); + } + throw new TransportException($error ?? sprintf('Could not acknowledge redis message "%s".', $id)); + } + } + + public function reject(string $id): void + { + try { + $deleted = $this->connection->xack($this->stream, $this->group, [$id]); + if ($this->deleteAfterReject) { + $deleted = $this->connection->xdel($this->stream, [$id]) && $deleted; + } + } catch (\RedisException $e) { + throw new TransportException($e->getMessage(), 0, $e); + } + + if (!$deleted) { + if ($error = $this->connection->getLastError() ?: null) { + $this->connection->clearLastError(); + } + throw new TransportException($error ?? sprintf('Could not delete message "%s" from the redis stream.', $id)); + } + } + + public function add(string $body, array $headers, int $delayInMs = 0): void + { + if ($this->autoSetup) { + $this->setup(); + } + + try { + if ($delayInMs > 0) { // the delay is <= 0 for queued messages + $message = json_encode([ + 'body' => $body, + 'headers' => $headers, + // Entry need to be unique in the sorted set else it would only be added once to the delayed messages queue + 'uniqid' => uniqid('', true), + ]); + + if (false === $message) { + throw new TransportException(json_last_error_msg()); + } + + $now = explode(' ', microtime(), 2); + $now[0] = str_pad($delayInMs + substr($now[0], 2, 3), 3, '0', \STR_PAD_LEFT); + if (3 < \strlen($now[0])) { + $now[1] += substr($now[0], 0, -3); + $now[0] = substr($now[0], -3); + + if (\is_float($now[1])) { + throw new TransportException("Message delay is too big: {$delayInMs}ms."); + } + } + + $added = $this->rawCommand('ZADD', 'NX', $now[1].$now[0], $message); + } else { + $message = json_encode([ + 'body' => $body, + 'headers' => $headers, + ]); + + if (false === $message) { + throw new TransportException(json_last_error_msg()); + } + + if ($this->maxEntries) { + $added = $this->connection->xadd($this->stream, '*', ['message' => $message], $this->maxEntries, true); + } else { + $added = $this->connection->xadd($this->stream, '*', ['message' => $message]); + } + } + } catch (\RedisException $e) { + if ($error = $this->connection->getLastError() ?: null) { + $this->connection->clearLastError(); + } + throw new TransportException($error ?? $e->getMessage(), 0, $e); + } + + if (!$added) { + if ($error = $this->connection->getLastError() ?: null) { + $this->connection->clearLastError(); + } + throw new TransportException($error ?? 'Could not add a message to the redis stream.'); + } + } + + public function setup(): void + { + try { + $this->connection->xgroup('CREATE', $this->stream, $this->group, 0, true); + } catch (\RedisException $e) { + throw new TransportException($e->getMessage(), 0, $e); + } + + // group might already exist, ignore + if ($this->connection->getLastError()) { + $this->connection->clearLastError(); + } + + if ($this->deleteAfterAck || $this->deleteAfterReject) { + $groups = $this->connection->xinfo('GROUPS', $this->stream); + if ( + // support for Redis extension version 5+ + (\is_array($groups) && 1 < \count($groups)) + // support for Redis extension version 4.x + || (\is_string($groups) && substr_count($groups, '"name"')) + ) { + throw new LogicException(sprintf('More than one group exists for stream "%s", delete_after_ack and delete_after_reject cannot be enabled as it risks deleting messages before all groups could consume them.', $this->stream)); + } + } + + $this->autoSetup = false; + } + + private function getCurrentTimeInMilliseconds(): int + { + return (int) (microtime(true) * 1000); + } + + public function cleanup(): void + { + static $unlink = true; + + if ($unlink) { + try { + $unlink = false !== $this->connection->unlink($this->stream, $this->queue); + } catch (\Throwable $e) { + $unlink = false; + } + } + + if (!$unlink) { + $this->connection->del($this->stream, $this->queue); + } + } + + /** + * @return mixed + */ + private function rawCommand(string $command, ...$arguments) + { + try { + if ($this->connection instanceof \RedisCluster || $this->connection instanceof RedisClusterProxy) { + $result = $this->connection->rawCommand($this->queue, $command, $this->queue, ...$arguments); + } else { + $result = $this->connection->rawCommand($command, $this->queue, ...$arguments); + } + } catch (\RedisException $e) { + throw new TransportException($e->getMessage(), 0, $e); + } + + if (false === $result) { + if ($error = $this->connection->getLastError() ?: null) { + $this->connection->clearLastError(); + } + throw new TransportException($error ?? sprintf('Could not run "%s" on Redis queue.', $command)); + } + + return $result; + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\RedisExt\Connection::class, false)) { + class_alias(Connection::class, \Symfony\Component\Messenger\Transport\RedisExt\Connection::class); +} diff --git a/plugins/email/vendor/symfony/redis-messenger/Transport/RedisClusterProxy.php b/plugins/email/vendor/symfony/redis-messenger/Transport/RedisClusterProxy.php new file mode 100644 index 0000000..ccbdf77 --- /dev/null +++ b/plugins/email/vendor/symfony/redis-messenger/Transport/RedisClusterProxy.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Redis\Transport; + +/** + * Allow to delay connection to Redis Cluster. + * + * @author Johann Pardanaud + * + * @internal + */ +class RedisClusterProxy +{ + private $redis; + private $initializer; + private $ready = false; + + public function __construct(?\RedisCluster $redis, \Closure $initializer) + { + $this->redis = $redis; + $this->initializer = $initializer; + } + + public function __call(string $method, array $args) + { + if (!$this->ready) { + $this->redis = $this->initializer->__invoke($this->redis); + $this->ready = true; + } + + return $this->redis->{$method}(...$args); + } +} diff --git a/plugins/email/vendor/symfony/redis-messenger/Transport/RedisProxy.php b/plugins/email/vendor/symfony/redis-messenger/Transport/RedisProxy.php new file mode 100644 index 0000000..6ad5ecb --- /dev/null +++ b/plugins/email/vendor/symfony/redis-messenger/Transport/RedisProxy.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Redis\Transport; + +/** + * Allow to delay connection to Redis. + * + * @author Tobias Nyholm + * @author Nicolas Grekas + * + * @internal + */ +class RedisProxy +{ + private $redis; + private $initializer; + private $ready = false; + + public function __construct(\Redis $redis, \Closure $initializer) + { + $this->redis = $redis; + $this->initializer = $initializer; + } + + public function __call(string $method, array $args) + { + if (!$this->ready) { + $this->redis = $this->initializer->__invoke($this->redis); + $this->ready = true; + } + + return $this->redis->{$method}(...$args); + } +} diff --git a/plugins/email/vendor/symfony/redis-messenger/Transport/RedisReceivedStamp.php b/plugins/email/vendor/symfony/redis-messenger/Transport/RedisReceivedStamp.php new file mode 100644 index 0000000..3469f69 --- /dev/null +++ b/plugins/email/vendor/symfony/redis-messenger/Transport/RedisReceivedStamp.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Redis\Transport; + +use Symfony\Component\Messenger\Stamp\NonSendableStampInterface; + +/** + * @author Alexander Schranz + */ +class RedisReceivedStamp implements NonSendableStampInterface +{ + private $id; + + public function __construct(string $id) + { + $this->id = $id; + } + + public function getId(): string + { + return $this->id; + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\RedisExt\RedisReceivedStamp::class, false)) { + class_alias(RedisReceivedStamp::class, \Symfony\Component\Messenger\Transport\RedisExt\RedisReceivedStamp::class); +} diff --git a/plugins/email/vendor/symfony/redis-messenger/Transport/RedisReceiver.php b/plugins/email/vendor/symfony/redis-messenger/Transport/RedisReceiver.php new file mode 100644 index 0000000..1a63d33 --- /dev/null +++ b/plugins/email/vendor/symfony/redis-messenger/Transport/RedisReceiver.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Redis\Transport; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\LogicException; +use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; +use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; +use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; + +/** + * @author Alexander Schranz + * @author Antoine Bluchet + */ +class RedisReceiver implements ReceiverInterface +{ + private $connection; + private $serializer; + + public function __construct(Connection $connection, SerializerInterface $serializer = null) + { + $this->connection = $connection; + $this->serializer = $serializer ?? new PhpSerializer(); + } + + /** + * {@inheritdoc} + */ + public function get(): iterable + { + $message = $this->connection->get(); + + if (null === $message) { + return []; + } + + $redisEnvelope = json_decode($message['data']['message'] ?? '', true); + + if (null === $redisEnvelope) { + return []; + } + + try { + if (\array_key_exists('body', $redisEnvelope) && \array_key_exists('headers', $redisEnvelope)) { + $envelope = $this->serializer->decode([ + 'body' => $redisEnvelope['body'], + 'headers' => $redisEnvelope['headers'], + ]); + } else { + $envelope = $this->serializer->decode($redisEnvelope); + } + } catch (MessageDecodingFailedException $exception) { + $this->connection->reject($message['id']); + + throw $exception; + } + + return [$envelope->with(new RedisReceivedStamp($message['id']))]; + } + + /** + * {@inheritdoc} + */ + public function ack(Envelope $envelope): void + { + $this->connection->ack($this->findRedisReceivedStamp($envelope)->getId()); + } + + /** + * {@inheritdoc} + */ + public function reject(Envelope $envelope): void + { + $this->connection->reject($this->findRedisReceivedStamp($envelope)->getId()); + } + + private function findRedisReceivedStamp(Envelope $envelope): RedisReceivedStamp + { + /** @var RedisReceivedStamp|null $redisReceivedStamp */ + $redisReceivedStamp = $envelope->last(RedisReceivedStamp::class); + + if (null === $redisReceivedStamp) { + throw new LogicException('No RedisReceivedStamp found on the Envelope.'); + } + + return $redisReceivedStamp; + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\RedisExt\RedisReceiver::class, false)) { + class_alias(RedisReceiver::class, \Symfony\Component\Messenger\Transport\RedisExt\RedisReceiver::class); +} diff --git a/plugins/email/vendor/symfony/redis-messenger/Transport/RedisSender.php b/plugins/email/vendor/symfony/redis-messenger/Transport/RedisSender.php new file mode 100644 index 0000000..433cfe9 --- /dev/null +++ b/plugins/email/vendor/symfony/redis-messenger/Transport/RedisSender.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Redis\Transport; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Stamp\DelayStamp; +use Symfony\Component\Messenger\Transport\Sender\SenderInterface; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; + +/** + * @author Alexander Schranz + * @author Antoine Bluchet + */ +class RedisSender implements SenderInterface +{ + private $connection; + private $serializer; + + public function __construct(Connection $connection, SerializerInterface $serializer) + { + $this->connection = $connection; + $this->serializer = $serializer; + } + + /** + * {@inheritdoc} + */ + public function send(Envelope $envelope): Envelope + { + $encodedMessage = $this->serializer->encode($envelope); + + /** @var DelayStamp|null $delayStamp */ + $delayStamp = $envelope->last(DelayStamp::class); + $delayInMs = null !== $delayStamp ? $delayStamp->getDelay() : 0; + + $this->connection->add($encodedMessage['body'], $encodedMessage['headers'] ?? [], $delayInMs); + + return $envelope; + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\RedisExt\RedisSender::class, false)) { + class_alias(RedisSender::class, \Symfony\Component\Messenger\Transport\RedisExt\RedisSender::class); +} diff --git a/plugins/email/vendor/symfony/redis-messenger/Transport/RedisTransport.php b/plugins/email/vendor/symfony/redis-messenger/Transport/RedisTransport.php new file mode 100644 index 0000000..88daa22 --- /dev/null +++ b/plugins/email/vendor/symfony/redis-messenger/Transport/RedisTransport.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Redis\Transport; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Component\Messenger\Transport\SetupableTransportInterface; +use Symfony\Component\Messenger\Transport\TransportInterface; + +/** + * @author Alexander Schranz + * @author Antoine Bluchet + */ +class RedisTransport implements TransportInterface, SetupableTransportInterface +{ + private $serializer; + private $connection; + private $receiver; + private $sender; + + public function __construct(Connection $connection, SerializerInterface $serializer = null) + { + $this->connection = $connection; + $this->serializer = $serializer ?? new PhpSerializer(); + } + + /** + * {@inheritdoc} + */ + public function get(): iterable + { + return ($this->receiver ?? $this->getReceiver())->get(); + } + + /** + * {@inheritdoc} + */ + public function ack(Envelope $envelope): void + { + ($this->receiver ?? $this->getReceiver())->ack($envelope); + } + + /** + * {@inheritdoc} + */ + public function reject(Envelope $envelope): void + { + ($this->receiver ?? $this->getReceiver())->reject($envelope); + } + + /** + * {@inheritdoc} + */ + public function send(Envelope $envelope): Envelope + { + return ($this->sender ?? $this->getSender())->send($envelope); + } + + /** + * {@inheritdoc} + */ + public function setup(): void + { + $this->connection->setup(); + } + + private function getReceiver(): RedisReceiver + { + return $this->receiver = new RedisReceiver($this->connection, $this->serializer); + } + + private function getSender(): RedisSender + { + return $this->sender = new RedisSender($this->connection, $this->serializer); + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\RedisExt\RedisTransport::class, false)) { + class_alias(RedisTransport::class, \Symfony\Component\Messenger\Transport\RedisExt\RedisTransport::class); +} diff --git a/plugins/email/vendor/symfony/redis-messenger/Transport/RedisTransportFactory.php b/plugins/email/vendor/symfony/redis-messenger/Transport/RedisTransportFactory.php new file mode 100644 index 0000000..88cead8 --- /dev/null +++ b/plugins/email/vendor/symfony/redis-messenger/Transport/RedisTransportFactory.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Bridge\Redis\Transport; + +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Component\Messenger\Transport\TransportFactoryInterface; +use Symfony\Component\Messenger\Transport\TransportInterface; + +/** + * @author Alexander Schranz + * @author Antoine Bluchet + */ +class RedisTransportFactory implements TransportFactoryInterface +{ + public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface + { + unset($options['transport_name']); + + return new RedisTransport(Connection::fromDsn($dsn, $options), $serializer); + } + + public function supports(string $dsn, array $options): bool + { + return 0 === strpos($dsn, 'redis://') || 0 === strpos($dsn, 'rediss://'); + } +} + +if (!class_exists(\Symfony\Component\Messenger\Transport\RedisExt\RedisTransportFactory::class, false)) { + class_alias(RedisTransportFactory::class, \Symfony\Component\Messenger\Transport\RedisExt\RedisTransportFactory::class); +} diff --git a/plugins/email/vendor/symfony/redis-messenger/composer.json b/plugins/email/vendor/symfony/redis-messenger/composer.json new file mode 100644 index 0000000..c663be4 --- /dev/null +++ b/plugins/email/vendor/symfony/redis-messenger/composer.json @@ -0,0 +1,34 @@ +{ + "name": "symfony/redis-messenger", + "type": "symfony-messenger-bridge", + "description": "Symfony Redis extension Messenger Bridge", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/messenger": "^5.1|^6.0" + }, + "require-dev": { + "symfony/property-access": "^4.4|^5.0|^6.0", + "symfony/serializer": "^4.4|^5.0|^6.0" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Messenger\\Bridge\\Redis\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/plugins/email/vendor/symfony/service-contracts/.gitignore b/plugins/email/vendor/symfony/service-contracts/.gitignore new file mode 100644 index 0000000..c49a5d8 --- /dev/null +++ b/plugins/email/vendor/symfony/service-contracts/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/plugins/email/vendor/symfony/service-contracts/Attribute/Required.php b/plugins/email/vendor/symfony/service-contracts/Attribute/Required.php new file mode 100644 index 0000000..9df8511 --- /dev/null +++ b/plugins/email/vendor/symfony/service-contracts/Attribute/Required.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Attribute; + +/** + * A required dependency. + * + * This attribute indicates that a property holds a required dependency. The annotated property or method should be + * considered during the instantiation process of the containing class. + * + * @author Alexander M. Turek + */ +#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] +final class Required +{ +} diff --git a/plugins/email/vendor/symfony/service-contracts/Attribute/SubscribedService.php b/plugins/email/vendor/symfony/service-contracts/Attribute/SubscribedService.php new file mode 100644 index 0000000..10d1bc3 --- /dev/null +++ b/plugins/email/vendor/symfony/service-contracts/Attribute/SubscribedService.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Attribute; + +use Symfony\Contracts\Service\ServiceSubscriberTrait; + +/** + * Use with {@see ServiceSubscriberTrait} to mark a method's return type + * as a subscribed service. + * + * @author Kevin Bond + */ +#[\Attribute(\Attribute::TARGET_METHOD)] +final class SubscribedService +{ + /** + * @param string|null $key The key to use for the service + * If null, use "ClassName::methodName" + */ + public function __construct( + public ?string $key = null + ) { + } +} diff --git a/plugins/email/vendor/symfony/service-contracts/CHANGELOG.md b/plugins/email/vendor/symfony/service-contracts/CHANGELOG.md new file mode 100644 index 0000000..7932e26 --- /dev/null +++ b/plugins/email/vendor/symfony/service-contracts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG +========= + +The changelog is maintained for all Symfony contracts at the following URL: +https://github.com/symfony/contracts/blob/main/CHANGELOG.md diff --git a/plugins/email/vendor/symfony/service-contracts/LICENSE b/plugins/email/vendor/symfony/service-contracts/LICENSE new file mode 100644 index 0000000..74cdc2d --- /dev/null +++ b/plugins/email/vendor/symfony/service-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/plugins/email/vendor/symfony/service-contracts/README.md b/plugins/email/vendor/symfony/service-contracts/README.md new file mode 100644 index 0000000..41e054a --- /dev/null +++ b/plugins/email/vendor/symfony/service-contracts/README.md @@ -0,0 +1,9 @@ +Symfony Service Contracts +========================= + +A set of abstractions extracted out of the Symfony components. + +Can be used to build on semantics that the Symfony components proved useful - and +that already have battle tested implementations. + +See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/plugins/email/vendor/symfony/service-contracts/ResetInterface.php b/plugins/email/vendor/symfony/service-contracts/ResetInterface.php new file mode 100644 index 0000000..1af1075 --- /dev/null +++ b/plugins/email/vendor/symfony/service-contracts/ResetInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +/** + * Provides a way to reset an object to its initial state. + * + * When calling the "reset()" method on an object, it should be put back to its + * initial state. This usually means clearing any internal buffers and forwarding + * the call to internal dependencies. All properties of the object should be put + * back to the same state it had when it was first ready to use. + * + * This method could be called, for example, to recycle objects that are used as + * services, so that they can be used to handle several requests in the same + * process loop (note that we advise making your services stateless instead of + * implementing this interface when possible.) + */ +interface ResetInterface +{ + public function reset(); +} diff --git a/plugins/email/vendor/symfony/service-contracts/ServiceLocatorTrait.php b/plugins/email/vendor/symfony/service-contracts/ServiceLocatorTrait.php new file mode 100644 index 0000000..74dfa43 --- /dev/null +++ b/plugins/email/vendor/symfony/service-contracts/ServiceLocatorTrait.php @@ -0,0 +1,128 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; + +// Help opcache.preload discover always-needed symbols +class_exists(ContainerExceptionInterface::class); +class_exists(NotFoundExceptionInterface::class); + +/** + * A trait to help implement ServiceProviderInterface. + * + * @author Robin Chalas + * @author Nicolas Grekas + */ +trait ServiceLocatorTrait +{ + private $factories; + private $loading = []; + private $providedTypes; + + /** + * @param callable[] $factories + */ + public function __construct(array $factories) + { + $this->factories = $factories; + } + + /** + * {@inheritdoc} + * + * @return bool + */ + public function has(string $id) + { + return isset($this->factories[$id]); + } + + /** + * {@inheritdoc} + * + * @return mixed + */ + public function get(string $id) + { + if (!isset($this->factories[$id])) { + throw $this->createNotFoundException($id); + } + + if (isset($this->loading[$id])) { + $ids = array_values($this->loading); + $ids = \array_slice($this->loading, array_search($id, $ids)); + $ids[] = $id; + + throw $this->createCircularReferenceException($id, $ids); + } + + $this->loading[$id] = $id; + try { + return $this->factories[$id]($this); + } finally { + unset($this->loading[$id]); + } + } + + /** + * {@inheritdoc} + */ + public function getProvidedServices(): array + { + if (null === $this->providedTypes) { + $this->providedTypes = []; + + foreach ($this->factories as $name => $factory) { + if (!\is_callable($factory)) { + $this->providedTypes[$name] = '?'; + } else { + $type = (new \ReflectionFunction($factory))->getReturnType(); + + $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?'; + } + } + } + + return $this->providedTypes; + } + + private function createNotFoundException(string $id): NotFoundExceptionInterface + { + if (!$alternatives = array_keys($this->factories)) { + $message = 'is empty...'; + } else { + $last = array_pop($alternatives); + if ($alternatives) { + $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); + } else { + $message = sprintf('only knows about the "%s" service.', $last); + } + } + + if ($this->loading) { + $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); + } else { + $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message); + } + + return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { + }; + } + + private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface + { + return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { + }; + } +} diff --git a/plugins/email/vendor/symfony/service-contracts/ServiceProviderInterface.php b/plugins/email/vendor/symfony/service-contracts/ServiceProviderInterface.php new file mode 100644 index 0000000..c60ad0b --- /dev/null +++ b/plugins/email/vendor/symfony/service-contracts/ServiceProviderInterface.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerInterface; + +/** + * A ServiceProviderInterface exposes the identifiers and the types of services provided by a container. + * + * @author Nicolas Grekas + * @author Mateusz Sip + */ +interface ServiceProviderInterface extends ContainerInterface +{ + /** + * Returns an associative array of service types keyed by the identifiers provided by the current container. + * + * Examples: + * + * * ['logger' => 'Psr\Log\LoggerInterface'] means the object provides a service named "logger" that implements Psr\Log\LoggerInterface + * * ['foo' => '?'] means the container provides service name "foo" of unspecified type + * * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null + * + * @return string[] The provided service types, keyed by service names + */ + public function getProvidedServices(): array; +} diff --git a/plugins/email/vendor/symfony/service-contracts/ServiceSubscriberInterface.php b/plugins/email/vendor/symfony/service-contracts/ServiceSubscriberInterface.php new file mode 100644 index 0000000..098ab90 --- /dev/null +++ b/plugins/email/vendor/symfony/service-contracts/ServiceSubscriberInterface.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +/** + * A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method. + * + * The getSubscribedServices method returns an array of service types required by such instances, + * optionally keyed by the service names used internally. Service types that start with an interrogation + * mark "?" are optional, while the other ones are mandatory service dependencies. + * + * The injected service locators SHOULD NOT allow access to any other services not specified by the method. + * + * It is expected that ServiceSubscriber instances consume PSR-11-based service locators internally. + * This interface does not dictate any injection method for these service locators, although constructor + * injection is recommended. + * + * @author Nicolas Grekas + */ +interface ServiceSubscriberInterface +{ + /** + * Returns an array of service types required by such instances, optionally keyed by the service names used internally. + * + * For mandatory dependencies: + * + * * ['logger' => 'Psr\Log\LoggerInterface'] means the objects use the "logger" name + * internally to fetch a service which must implement Psr\Log\LoggerInterface. + * * ['loggers' => 'Psr\Log\LoggerInterface[]'] means the objects use the "loggers" name + * internally to fetch an iterable of Psr\Log\LoggerInterface instances. + * * ['Psr\Log\LoggerInterface'] is a shortcut for + * * ['Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface'] + * + * otherwise: + * + * * ['logger' => '?Psr\Log\LoggerInterface'] denotes an optional dependency + * * ['loggers' => '?Psr\Log\LoggerInterface[]'] denotes an optional iterable dependency + * * ['?Psr\Log\LoggerInterface'] is a shortcut for + * * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface'] + * + * @return string[] The required service types, optionally keyed by service names + */ + public static function getSubscribedServices(); +} diff --git a/plugins/email/vendor/symfony/service-contracts/ServiceSubscriberTrait.php b/plugins/email/vendor/symfony/service-contracts/ServiceSubscriberTrait.php new file mode 100644 index 0000000..16e3eb2 --- /dev/null +++ b/plugins/email/vendor/symfony/service-contracts/ServiceSubscriberTrait.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\Attribute\SubscribedService; + +/** + * Implementation of ServiceSubscriberInterface that determines subscribed services from + * method return types. Service ids are available as "ClassName::methodName". + * + * @author Kevin Bond + */ +trait ServiceSubscriberTrait +{ + /** @var ContainerInterface */ + protected $container; + + /** + * {@inheritdoc} + */ + public static function getSubscribedServices(): array + { + $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; + $attributeOptIn = false; + + if (\PHP_VERSION_ID >= 80000) { + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if (self::class !== $method->getDeclaringClass()->name) { + continue; + } + + if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) { + continue; + } + + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + } + + if (!$returnType = $method->getReturnType()) { + throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + } + + $serviceId = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; + + if ($returnType->allowsNull()) { + $serviceId = '?'.$serviceId; + } + + $services[$attribute->newInstance()->key ?? self::class.'::'.$method->name] = $serviceId; + $attributeOptIn = true; + } + } + + if (!$attributeOptIn) { + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + continue; + } + + if (self::class !== $method->getDeclaringClass()->name) { + continue; + } + + if (!($returnType = $method->getReturnType()) instanceof \ReflectionNamedType) { + continue; + } + + if ($returnType->isBuiltin()) { + continue; + } + + if (\PHP_VERSION_ID >= 80000) { + trigger_deprecation('symfony/service-contracts', '2.5', 'Using "%s" in "%s" without using the "%s" attribute on any method is deprecated.', ServiceSubscriberTrait::class, self::class, SubscribedService::class); + } + + $services[self::class.'::'.$method->name] = '?'.($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType); + } + } + + return $services; + } + + /** + * @required + * + * @return ContainerInterface|null + */ + public function setContainer(ContainerInterface $container) + { + $this->container = $container; + + if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) { + return parent::setContainer($container); + } + + return null; + } +} diff --git a/plugins/email/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php b/plugins/email/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php new file mode 100644 index 0000000..2a1b565 --- /dev/null +++ b/plugins/email/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Test; + +use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\ServiceLocatorTrait; + +abstract class ServiceLocatorTest extends TestCase +{ + /** + * @return ContainerInterface + */ + protected function getServiceLocator(array $factories) + { + return new class($factories) implements ContainerInterface { + use ServiceLocatorTrait; + }; + } + + public function testHas() + { + $locator = $this->getServiceLocator([ + 'foo' => function () { return 'bar'; }, + 'bar' => function () { return 'baz'; }, + function () { return 'dummy'; }, + ]); + + $this->assertTrue($locator->has('foo')); + $this->assertTrue($locator->has('bar')); + $this->assertFalse($locator->has('dummy')); + } + + public function testGet() + { + $locator = $this->getServiceLocator([ + 'foo' => function () { return 'bar'; }, + 'bar' => function () { return 'baz'; }, + ]); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('baz', $locator->get('bar')); + } + + public function testGetDoesNotMemoize() + { + $i = 0; + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$i) { + ++$i; + + return 'bar'; + }, + ]); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame(2, $i); + } + + public function testThrowsOnUndefinedInternalService() + { + if (!$this->getExpectedException()) { + $this->expectException(\Psr\Container\NotFoundExceptionInterface::class); + $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); + } + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, + ]); + + $locator->get('foo'); + } + + public function testThrowsOnCircularReference() + { + $this->expectException(\Psr\Container\ContainerExceptionInterface::class); + $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, + 'bar' => function () use (&$locator) { return $locator->get('baz'); }, + 'baz' => function () use (&$locator) { return $locator->get('bar'); }, + ]); + + $locator->get('foo'); + } +} diff --git a/plugins/email/vendor/symfony/service-contracts/composer.json b/plugins/email/vendor/symfony/service-contracts/composer.json new file mode 100644 index 0000000..f058637 --- /dev/null +++ b/plugins/email/vendor/symfony/service-contracts/composer.json @@ -0,0 +1,42 @@ +{ + "name": "symfony/service-contracts", + "type": "library", + "description": "Generic abstractions related to writing services", + "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "autoload": { + "psr-4": { "Symfony\\Contracts\\Service\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + } +} diff --git a/plugins/flex-objects/CHANGELOG.md b/plugins/flex-objects/CHANGELOG.md index 3661e3e..f18cefa 100644 --- a/plugins/flex-objects/CHANGELOG.md +++ b/plugins/flex-objects/CHANGELOG.md @@ -1,3 +1,9 @@ +# v1.3.5 +## 05/09/2023 + +1. [](#improved) + * Various deprecation fixes for PHP 8.2+ + # v1.3.4 ## 02/19/2023 diff --git a/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/add.html.twig b/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/add.html.twig index 076f293..cb91524 100644 --- a/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/add.html.twig +++ b/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/add.html.twig @@ -1,3 +1,3 @@ - + {{ 'PLUGIN_ADMIN.ADD'|tu }} diff --git a/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/export-csv.html.twig b/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/export-csv.html.twig index 8c53c1b..6a8fadc 100644 --- a/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/export-csv.html.twig +++ b/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/export-csv.html.twig @@ -1,3 +1,3 @@ - + {{ 'PLUGIN_FLEX_OBJECTS.CSV'|tu }} diff --git a/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/export.html.twig b/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/export.html.twig index 0f8382b..99a36e1 100644 --- a/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/export.html.twig +++ b/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/export.html.twig @@ -6,7 +6,7 @@