diff --git a/build/psalm_bootstrap.php b/build/psalm_bootstrap.php index 03afd6da3d..92099c77f5 100644 --- a/build/psalm_bootstrap.php +++ b/build/psalm_bootstrap.php @@ -33,7 +33,6 @@ require_once $phpbb_root_path . 'includes/functions_compress.' . $phpEx; require_once $phpbb_root_path . 'includes/functions_content.' . $phpEx; require_once $phpbb_root_path . 'includes/functions_display.' . $phpEx; require_once $phpbb_root_path . 'includes/functions_mcp.' . $phpEx; -require_once $phpbb_root_path . 'includes/functions_messenger.' . $phpEx; require_once $phpbb_root_path . 'includes/functions_module.' . $phpEx; require_once $phpbb_root_path . 'includes/functions_posting.' . $phpEx; require_once $phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx; diff --git a/phpBB/composer.json b/phpBB/composer.json index 1d43e78ad9..c77ab77819 100644 --- a/phpBB/composer.json +++ b/phpBB/composer.json @@ -51,6 +51,7 @@ "symfony/http-foundation": "^6.3", "symfony/http-kernel": "^6.3", "symfony/polyfill-mbstring": "^1.23", + "symfony/mailer": "^6.3", "symfony/mime": "^6.3", "symfony/process": "^6.3", "symfony/proxy-manager-bridge": "^6.3", diff --git a/phpBB/composer.lock b/phpBB/composer.lock index 47607417ab..bf9ac175e9 100644 --- a/phpBB/composer.lock +++ b/phpBB/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": "f6e182dafa1a6e6a60136e35d5379532", + "content-hash": "2ce7bc4e8f61d065ff471afa38f12394", "packages": [ { "name": "bantu/ini-get-wrapper", @@ -1417,6 +1417,150 @@ ], "time": "2022-10-12T20:51:15+00:00" }, + { + "name": "doctrine/lexer", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "84a527db05647743d50373e0ec53a152f2cde568" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/84a527db05647743d50373e0ec53a152f2cde568", + "reference": "84a527db05647743d50373e0ec53a152f2cde568", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^10", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^9.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/3.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2022-12-15T16:57:16+00:00" + }, + { + "name": "egulias/email-validator", + "version": "4.0.2", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ebaaf5be6c0286928352e054f2d5125608e5405e", + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2.0 || ^3.0", + "php": ">=8.1", + "symfony/polyfill-intl-idn": "^1.26" + }, + "require-dev": { + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/egulias/EmailValidator/issues", + "source": "https://github.com/egulias/EmailValidator/tree/4.0.2" + }, + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "time": "2023-10-06T06:47:41+00:00" + }, { "name": "friendsofphp/proxy-manager-lts", "version": "v1.0.18", @@ -4342,6 +4486,86 @@ ], "time": "2024-11-27T12:49:36+00:00" }, + { + "name": "symfony/mailer", + "version": "v6.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "c2f7e0d8d7ac8fe25faccf5d8cac462805db2663" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/c2f7e0d8d7ac8fe25faccf5d8cac462805db2663", + "reference": "c2f7e0d8d7ac8fe25faccf5d8cac462805db2663", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.1.10|^3|^4", + "php": ">=8.1", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/mime": "^6.2|^7.0", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<5.4", + "symfony/messenger": "<6.2", + "symfony/mime": "<6.2", + "symfony/twig-bridge": "<6.2.1" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/messenger": "^6.2|^7.0", + "symfony/twig-bridge": "^6.2|^7.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/v6.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": "2024-09-25T14:18:03+00:00" + }, { "name": "symfony/mime", "version": "v6.4.13", diff --git a/phpBB/config/default/container/services.yml b/phpBB/config/default/container/services.yml index 8a4336e832..c09f21b5c6 100644 --- a/phpBB/config/default/container/services.yml +++ b/phpBB/config/default/container/services.yml @@ -19,6 +19,7 @@ imports: - { resource: services_http.yml } - { resource: services_language.yml } - { resource: services_mention.yml } + - { resource: services_messenger.yml } - { resource: services_migrator.yml } - { resource: services_mimetype_guesser.yml } - { resource: services_module.yml } diff --git a/phpBB/config/default/container/services_console.yml b/phpBB/config/default/container/services_console.yml index 6c85e22f9a..81bc0f51b6 100644 --- a/phpBB/config/default/container/services_console.yml +++ b/phpBB/config/default/container/services_console.yml @@ -327,6 +327,7 @@ services: - '@config' - '@language' - '@log' + - '@messenger.method.email' - '@notification_manager' - '@user_loader' - '%core.root_path%' @@ -341,6 +342,7 @@ services: - '@dbal.conn' - '@config' - '@language' + - '@messenger.method.email' - '@passwords.manager' - '%core.root_path%' - '%core.php_ext%' diff --git a/phpBB/config/default/container/services_cron.yml b/phpBB/config/default/container/services_cron.yml index a19ed9900d..85d5c1631f 100644 --- a/phpBB/config/default/container/services_cron.yml +++ b/phpBB/config/default/container/services_cron.yml @@ -86,10 +86,9 @@ services: cron.task.core.queue: class: phpbb\cron\task\core\queue arguments: - - '%core.root_path%' - - '%core.php_ext%' - '@config' - - '%core.cache_dir%' + - '@messenger.queue' + - '%core.messenger_queue_file%' calls: - [set_name, [cron.task.core.queue]] tags: diff --git a/phpBB/config/default/container/services_messenger.yml b/phpBB/config/default/container/services_messenger.yml new file mode 100644 index 0000000000..8645d2f17c --- /dev/null +++ b/phpBB/config/default/container/services_messenger.yml @@ -0,0 +1,57 @@ +parameters: + core.messenger_queue_file: '%core.cache_dir%queue.%core.php_ext%' + +services: + messenger.method_collection: + class: phpbb\di\service_collection + arguments: + - '@service_container' + tags: + - { name: service_collection, tag: messenger.method, class_name_aware: true } + + messenger.method.base: + class: phpbb\messenger\method\base + shared: false + arguments: + - '@assets.bag' + - '@config' + - '@dispatcher' + - '@language' + - '@messenger.queue' + - '@path_helper' + - '@request' + - '@template.twig.extensions.collection' + - '@template.twig.lexer' + - '@user' + - '%core.root_path%' + - '%core.template.cache_path%' + - '@?ext.manager' + - '@?log' + + messenger.method.email: + class: phpbb\messenger\method\email + shared: false + parent: messenger.method.base + calls: + - [init, []] + - [set_transport, []] + tags: + - { name: messenger.method } + + messenger.method.jabber: + class: phpbb\messenger\method\jabber + shared: false + parent: messenger.method.base + calls: + - [init, []] + tags: + - { name: messenger.method } + + messenger.queue: + class: phpbb\messenger\queue + shared: false + arguments: + - '@config' + - '@dispatcher' + - '@messenger.method_collection' + - '%core.messenger_queue_file%' diff --git a/phpBB/config/default/container/services_notification.yml b/phpBB/config/default/container/services_notification.yml index 92592850f9..0ac9dc6a88 100644 --- a/phpBB/config/default/container/services_notification.yml +++ b/phpBB/config/default/container/services_notification.yml @@ -229,6 +229,7 @@ services: - '%core.root_path%' - '%core.php_ext%' - '%tables.notification_emails%' + - '@messenger.method_collection' tags: - { name: notification.method } @@ -241,6 +242,7 @@ services: - '@config' - '%core.root_path%' - '%core.php_ext%' + - '@messenger.method_collection' tags: - { name: notification.method } diff --git a/phpBB/config/default/container/services_ucp.yml b/phpBB/config/default/container/services_ucp.yml index acd78f8440..bbe5d35f2b 100644 --- a/phpBB/config/default/container/services_ucp.yml +++ b/phpBB/config/default/container/services_ucp.yml @@ -19,6 +19,7 @@ services: - '@controller.helper' - '@language' - '@log' + - '@messenger.method.email' - '@passwords.manager' - '@request' - '@template' diff --git a/phpBB/config/installer/container/services.yml b/phpBB/config/installer/container/services.yml index 70fb0ee308..7ef423afb1 100644 --- a/phpBB/config/installer/container/services.yml +++ b/phpBB/config/installer/container/services.yml @@ -5,6 +5,7 @@ imports: - { resource: ../../default/container/services_filesystem.yml } - { resource: ../../default/container/services_http.yml } - { resource: ../../default/container/services_language.yml } + - { resource: ../../default/container/services_messenger.yml } - { resource: ../../default/container/services_php.yml } - { resource: ../../default/container/services_routing.yml } - { resource: ../../default/container/services_twig.yml } diff --git a/phpBB/config/installer/container/services_install_finish.yml b/phpBB/config/installer/container/services_install_finish.yml index b200118e11..9eb05b8a44 100644 --- a/phpBB/config/installer/container/services_install_finish.yml +++ b/phpBB/config/installer/container/services_install_finish.yml @@ -24,7 +24,6 @@ services: - '@installer.helper.config' - '@installer.helper.iohandler' - '%core.root_path%' - - '%core.php_ext%' tags: - { name: install_finish, order: 3 } diff --git a/phpBB/docs/install-config.sample.yml b/phpBB/docs/install-config.sample.yml index a354e52e2f..5ef6c643be 100644 --- a/phpBB/docs/install-config.sample.yml +++ b/phpBB/docs/install-config.sample.yml @@ -23,7 +23,6 @@ installer: smtp_delivery : ~ smtp_host: ~ smtp_port: ~ - smtp_auth: ~ smtp_user: ~ smtp_pass: ~ diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index bda5661278..b20d0d9753 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -473,7 +473,6 @@ class acp_board 'smtp_delivery' => array('lang' => 'USE_SMTP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'smtp_host' => array('lang' => 'SMTP_SERVER', 'validate' => 'string', 'type' => 'text:25:50', 'explain' => true), 'smtp_port' => array('lang' => 'SMTP_PORT', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true), - 'smtp_auth_method' => array('lang' => 'SMTP_AUTH_METHOD', 'validate' => 'string', 'type' => 'select', 'method' => 'mail_auth_select', 'explain' => true), 'smtp_username' => array('lang' => 'SMTP_USERNAME', 'validate' => 'string', 'type' => 'text:25:255', 'explain' => true), 'smtp_password' => array('lang' => 'SMTP_PASSWORD', 'validate' => 'string', 'type' => 'password:25:255', 'explain' => true), 'smtp_verify_peer' => array('lang' => 'SMTP_VERIFY_PEER', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), @@ -721,17 +720,16 @@ class acp_board { if ($config['email_enable']) { - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - - $messenger = new messenger(false); - $messenger->template('test'); - $messenger->set_addresses($user->data); - $messenger->anti_abuse_headers($config, $user); - $messenger->assign_vars(array( + $email_method = $phpbb_container->get('messenger.method.email'); + $email_method->set_use_queue(false); + $email_method->template('test'); + $email_method->set_addresses($user->data); + $email_method->anti_abuse_headers($config, $user); + $email_method->assign_vars([ 'USERNAME' => html_entity_decode($user->data['username'], ENT_COMPAT), 'MESSAGE' => html_entity_decode($request->variable('send_test_email_text', '', true), ENT_COMPAT), - )); - $messenger->send(NOTIFY_EMAIL); + ]); + $email_method->send(); trigger_error($user->lang('TEST_EMAIL_SENT') . adm_back_link($this->u_action)); } @@ -884,30 +882,6 @@ class acp_board ]; } - /** - * Select mail authentication method - */ - function mail_auth_select($selected_method, $key = '') - { - global $user; - - $auth_methods = ['PLAIN', 'LOGIN', 'CRAM-MD5', 'DIGEST-MD5', 'POP-BEFORE-SMTP']; - $s_smtp_auth_options = []; - - foreach ($auth_methods as $method) - { - $s_smtp_auth_options[] = [ - 'value' => $method, - 'selected' => $selected_method == $method, - 'label' => $user->lang('SMTP_' . str_replace('-', '_', $method)), - ]; - } - - return [ - 'options' => $s_smtp_auth_options, - ]; - } - /** * Select full folder action */ diff --git a/phpBB/includes/acp/acp_email.php b/phpBB/includes/acp/acp_email.php index cddf7b3324..00ce89317c 100644 --- a/phpBB/includes/acp/acp_email.php +++ b/phpBB/includes/acp/acp_email.php @@ -11,6 +11,8 @@ * */ +use phpbb\messenger\method\messenger_interface; + /** * @ignore */ @@ -156,9 +158,9 @@ class acp_email foreach ($rows as $row) { - if (($row['user_notify_type'] == NOTIFY_EMAIL && $row['user_email']) || - ($row['user_notify_type'] == NOTIFY_IM && $row['user_jabber']) || - ($row['user_notify_type'] == NOTIFY_BOTH && ($row['user_email'] || $row['user_jabber']))) + if (($row['user_notify_type'] == messenger_interface::NOTIFY_EMAIL && $row['user_email']) || + ($row['user_notify_type'] == messenger_interface::NOTIFY_IM && $row['user_jabber']) || + ($row['user_notify_type'] == messenger_interface::NOTIFY_BOTH && ($row['user_email'] || $row['user_jabber']))) { if ($i == $max_chunk_size || $row['user_lang'] != $old_lang || $row['user_notify_type'] != $old_notify_type) { @@ -182,25 +184,13 @@ class acp_email } } - // Send the messages - if (!class_exists('messenger')) - { - include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - } - - if (!function_exists('get_group_name')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - $messenger = new messenger($use_queue); - $errored = false; $email_template = 'admin_send_email'; - $template_data = array( + $template_data = [ 'CONTACT_EMAIL' => phpbb_get_board_contact($config, $phpEx), 'MESSAGE' => html_entity_decode($message, ENT_COMPAT), - ); + ]; $generate_log_entry = true; /** @@ -229,36 +219,64 @@ class acp_email ); extract($phpbb_dispatcher->trigger_event('core.acp_email_send_before', compact($vars))); + /** @var \phpbb\di\service_collection */ + $messenger = $phpbb_container->get('messenger.method_collection'); + $messenger_collection_iterator = $messenger->getIterator(); for ($i = 0, $size = count($email_list); $i < $size; $i++) { $used_lang = $email_list[$i][0]['lang']; $used_method = $email_list[$i][0]['method']; - for ($j = 0, $list_size = count($email_list[$i]); $j < $list_size; $j++) + foreach ($messenger_collection_iterator as $messenger_method) { - $email_row = $email_list[$i][$j]; + $notify_method = $messenger_method->get_id(); + if ($notify_method == $used_method || $used_method == messenger_interface::NOTIFY_BOTH) + { + $messenger_method->set_use_queue($use_queue); + $messenger_method->template($email_template, $used_lang); + $messenger_method->subject(html_entity_decode($subject, ENT_COMPAT)); + $messenger_method->assign_vars($template_data); - $messenger->{((count($email_list[$i]) == 1) ? 'to' : 'bcc')}($email_row['email'], $email_row['name']); - $messenger->im($email_row['jabber'], $email_row['name']); - } + if ($notify_method == messenger_interface::NOTIFY_EMAIL) + { + for ($j = 0, $list_size = count($email_list[$i]); $j < $list_size; $j++) + { + $email_row = $email_list[$i][$j]; + if (count($email_list[$i]) == 1) + { + $messenger_method->to($email_row['email'], $email_row['name']); + } + else + { + $messenger_method->bcc($email_row['email'], $email_row['name']); + } + } - $messenger->template($email_template, $used_lang); + $messenger_method->anti_abuse_headers($config, $user); + $messenger_method->set_mail_priority($priority); + } + else if ($notify_method == messenger_interface::NOTIFY_IM) + { + for ($j = 0, $list_size = count($email_list[$i]); $j < $list_size; $j++) + { + $email_row = $email_list[$i][$j]; + $messenger_method->to($email_row['jabber'], $email_row['name']); + } + } - $messenger->anti_abuse_headers($config, $user); - - $messenger->subject(html_entity_decode($subject, ENT_COMPAT)); - $messenger->set_mail_priority($priority); - - $messenger->assign_vars($template_data); - - if (!($messenger->send($used_method))) - { - $errored = true; + $errored = !$messenger_method->send() || $errored; + } } } unset($email_list); - $messenger->save_queue(); + if ($use_queue) + { + foreach ($messenger_collection_iterator as $messenger_method) + { + $messenger_method->save_queue(); + } + } if ($generate_log_entry) { diff --git a/phpBB/includes/acp/acp_inactive.php b/phpBB/includes/acp/acp_inactive.php index 0301a53c2b..2436277e15 100644 --- a/phpBB/includes/acp/acp_inactive.php +++ b/phpBB/includes/acp/acp_inactive.php @@ -114,29 +114,19 @@ class acp_inactive if ($config['require_activation'] == USER_ACTIVATION_ADMIN && !empty($inactive_users)) { - if (!class_exists('messenger')) - { - include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - } - - $messenger = new messenger(false); + $email_method = $phpbb_container->get('messenger.method.email'); + $email_method->set_use_queue(false); foreach ($inactive_users as $row) { - $messenger->template('admin_welcome_activated', $row['user_lang']); - - $messenger->set_addresses($row); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'USERNAME' => html_entity_decode($row['username'], ENT_COMPAT)) - ); - - $messenger->send(NOTIFY_EMAIL); + $email_method->template('admin_welcome_activated', $row['user_lang']); + $email_method->set_addresses($row); + $email_method->anti_abuse_headers($config, $user); + $email_method->assign_vars([ + 'USERNAME' => html_entity_decode($row['username'], ENT_COMPAT), + ]); + $email_method->send(); } - - $messenger->save_queue(); } if (!empty($inactive_users)) @@ -204,39 +194,43 @@ class acp_inactive $result = $db->sql_query($sql); + /** @var \phpbb\di\service_collection */ + $messenger = $phpbb_container->get('messenger.method_collection'); + $messenger_collection_iterator = $messenger->getIterator(); + if ($row = $db->sql_fetchrow($result)) { // Send the messages - if (!class_exists('messenger')) - { - include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - } - - $messenger = new messenger(); $usernames = $user_ids = array(); do { - $messenger->template('user_remind_inactive', $row['user_lang']); + foreach ($messenger_collection_iterator as $messenger_method) + { + if ($messenger_method->get_id() == $user_row['user_notify_type'] || $user_row['user_notify_type'] == $messenger_method::NOTIFY_BOTH) + { + $messenger_method->template('user_remind_inactive', $row['user_lang']); + $messenger_method->set_addresses($row); + $messenger_method->anti_abuse_headers($config, $user); + $messenger_method->assign_vars([ + 'USERNAME' => html_entity_decode($row['username'], ENT_COMPAT), + 'REGISTER_DATE' => $user->format_date($row['user_regdate'], false, true), + 'U_ACTIVATE' => generate_board_url() . "/ucp.$phpEx?mode=activate&u=" . $row['user_id'] . '&k=' . $row['user_actkey'], + ]); - $messenger->set_addresses($row); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'USERNAME' => html_entity_decode($row['username'], ENT_COMPAT), - 'REGISTER_DATE' => $user->format_date($row['user_regdate'], false, true), - 'U_ACTIVATE' => generate_board_url() . "/ucp.$phpEx?mode=activate&u=" . $row['user_id'] . '&k=' . $row['user_actkey']) - ); - - $messenger->send($row['user_notify_type']); + $messenger_method->send(); + } + } $usernames[] = $row['username']; $user_ids[] = (int) $row['user_id']; } while ($row = $db->sql_fetchrow($result)); - $messenger->save_queue(); + foreach ($messenger_collection_iterator as $messenger_method) + { + $messenger_method->save_queue(); + } // Add the remind state to the database and increase activation expiration by one day $sql = 'UPDATE ' . USERS_TABLE . ' diff --git a/phpBB/includes/acp/acp_jabber.php b/phpBB/includes/acp/acp_jabber.php index 07f5dadbff..fce1dee1df 100644 --- a/phpBB/includes/acp/acp_jabber.php +++ b/phpBB/includes/acp/acp_jabber.php @@ -30,15 +30,12 @@ class acp_jabber function main($id, $mode) { global $db, $user, $template, $phpbb_log, $request; - global $config, $phpbb_root_path, $phpEx; + global $config, $phpbb_container, $phpbb_root_path, $phpEx; + + $jabber = $phpbb_container->get('messenger.method.jabber'); $user->add_lang('acp/board'); - if (!class_exists('jabber')) - { - include($phpbb_root_path . 'includes/functions_jabber.' . $phpEx); - } - $submit = (isset($_POST['submit'])) ? true : false; if ($mode != 'settings') @@ -74,10 +71,8 @@ class acp_jabber $log = 'JAB_SETTINGS_CHANGED'; // Is this feature enabled? Then try to establish a connection - if ($jab_enable) + if ($jabber->is_enabled()) { - $jabber = new jabber($jab_host, $jab_port, $jab_username, $jab_password, $jab_use_ssl, $jab_verify_peer, $jab_verify_peer_name, $jab_allow_self_signed); - if (!$jabber->connect()) { trigger_error($user->lang['ERR_JAB_CONNECT'] . '

' . $jabber->get_log() . adm_back_link($this->u_action), E_USER_WARNING); @@ -97,12 +92,12 @@ class acp_jabber // We update the user table to be sure all users that have IM as notify type are set to both as notify type // We set this to both because users still have their jabber address entered and may want to receive jabber notifications again once it is re-enabled. $sql_ary = array( - 'user_notify_type' => NOTIFY_BOTH, + 'user_notify_type' => $jabber::NOTIFY_BOTH, ); $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE user_notify_type = ' . NOTIFY_IM; + WHERE user_notify_type = ' . $jabber::NOTIFY_IM; $db->sql_query($sql); } @@ -137,7 +132,7 @@ class acp_jabber 'JAB_VERIFY_PEER' => $jab_verify_peer, 'JAB_VERIFY_PEER_NAME' => $jab_verify_peer_name, 'JAB_ALLOW_SELF_SIGNED' => $jab_allow_self_signed, - 'S_CAN_USE_SSL' => jabber::can_use_ssl(), + 'S_CAN_USE_SSL' => $jabber::can_use_ssl(), 'S_GTALK_NOTE' => (!@function_exists('dns_get_record')) ? true : false, )); } diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php index 75b1cde0d8..a954ec09f0 100644 --- a/phpBB/includes/acp/acp_users.php +++ b/phpBB/includes/acp/acp_users.php @@ -16,6 +16,7 @@ */ use phpbb\controller\helper; +use phpbb\messenger\method\messenger_interface; if (!defined('IN_PHPBB')) { @@ -364,11 +365,6 @@ class acp_users if ($config['email_enable']) { - if (!class_exists('messenger')) - { - include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - } - $server_url = generate_board_url(); $user_actkey = gen_rand_string(mt_rand(6, 10)); @@ -403,21 +399,17 @@ class acp_users $db->sql_query($sql); // Start sending email - $messenger = new messenger(false); - - $messenger->template($email_template, $user_row['user_lang']); - - $messenger->set_addresses($user_row); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( + $email_method = $phpbb_container->get('messenger.method.email'); + $email_method->set_use_queue(false); + $email_method->template($email_template, $user_row['user_lang']); + $email_method->set_addresses($user_row); + $email_method->anti_abuse_headers($config, $user); + $email_method->assign_vars([ 'WELCOME_MSG' => html_entity_decode(sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename']), ENT_COMPAT), 'USERNAME' => html_entity_decode($user_row['username'], ENT_COMPAT), - 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k=$user_actkey") - ); - - $messenger->send(NOTIFY_EMAIL); + 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k=$user_actkey", + ]); + $email_method->send(); $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_REACTIVATE', false, array($user_row['username'])); $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_REACTIVATE_USER', false, array( @@ -462,24 +454,15 @@ class acp_users $phpbb_notifications = $phpbb_container->get('notification_manager'); $phpbb_notifications->delete_notifications('notification.type.admin_activate_user', $user_row['user_id']); - if (!class_exists('messenger')) - { - include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - } - - $messenger = new messenger(false); - - $messenger->template('admin_welcome_activated', $user_row['user_lang']); - - $messenger->set_addresses($user_row); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'USERNAME' => html_entity_decode($user_row['username'], ENT_COMPAT)) - ); - - $messenger->send(NOTIFY_EMAIL); + $email_method = $phpbb_container->get('messenger.method.email'); + $email_method->set_use_queue(false); + $email_method->template('admin_welcome_activated', $user_row['user_lang']); + $email_method->set_addresses($user_row); + $email_method->anti_abuse_headers($config, $user); + $email_method->assign_vars([ + 'USERNAME' => html_entity_decode($user_row['username'], ENT_COMPAT), + ]); + $email_method->send(); } } @@ -1810,9 +1793,9 @@ class acp_users 'MASS_EMAIL' => $data['massemail'], 'ALLOW_PM' => $data['allowpm'], 'HIDE_ONLINE' => $data['hideonline'], - 'NOTIFY_EMAIL' => ($data['notifymethod'] == NOTIFY_EMAIL) ? true : false, - 'NOTIFY_IM' => ($data['notifymethod'] == NOTIFY_IM) ? true : false, - 'NOTIFY_BOTH' => ($data['notifymethod'] == NOTIFY_BOTH) ? true : false, + 'NOTIFY_EMAIL' => ($data['notifymethod'] == messenger_interface::NOTIFY_EMAIL) ? true : false, + 'NOTIFY_IM' => ($data['notifymethod'] == messenger_interface::NOTIFY_IM) ? true : false, + 'NOTIFY_BOTH' => ($data['notifymethod'] == messenger_interface::NOTIFY_BOTH) ? true : false, 'NOTIFY_PM' => $data['notifypm'], 'BBCODE' => $data['bbcode'], 'SMILIES' => $data['smilies'], diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index 825a328d39..e9890d27e1 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -120,8 +120,11 @@ define('POST_ANNOUNCE', 2); define('POST_GLOBAL', 3); // Notify methods +/** @deprecated 4.0.0-a1 Replaced by \phpbb\messenger\method\messenger_interface::NOTIFY_EMAIL, to be removed in 5.0.0-a1 */ define('NOTIFY_EMAIL', 0); +/** @deprecated 4.0.0-a1 Replaced by \phpbb\messenger\method\messenger_interface::NOTIFY_IM, to be removed in 5.0.0-a1 */ define('NOTIFY_IM', 1); +/** @deprecated 4.0.0-a1 Replaced by \phpbb\messenger\method\messenger_interface::NOTIFY_BOTH, to be removed in 5.0.0-a1 */ define('NOTIFY_BOTH', 2); // Notify status diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php deleted file mode 100644 index c94a2a5c42..0000000000 --- a/phpBB/includes/functions_messenger.php +++ /dev/null @@ -1,2016 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Messenger -*/ -class messenger -{ - var $msg, $replyto, $from, $subject; - var $addresses = array(); - var $extra_headers = array(); - - var $mail_priority = MAIL_NORMAL_PRIORITY; - var $use_queue = true; - - /** @var \phpbb\template\template */ - protected $template; - - /** - * Constructor - */ - function __construct($use_queue = true) - { - global $config; - - $this->use_queue = (!$config['email_package_size']) ? false : $use_queue; - $this->subject = ''; - } - - /** - * Resets all the data (address, template file, etc etc) to default - */ - function reset() - { - $this->addresses = $this->extra_headers = array(); - $this->msg = $this->replyto = $this->from = ''; - $this->mail_priority = MAIL_NORMAL_PRIORITY; - } - - /** - * Set addresses for to/im as available - * - * @param array $user User row - */ - function set_addresses($user) - { - if (isset($user['user_email']) && $user['user_email']) - { - $this->to($user['user_email'], (isset($user['username']) ? $user['username'] : '')); - } - - if (isset($user['user_jabber']) && $user['user_jabber']) - { - $this->im($user['user_jabber'], (isset($user['username']) ? $user['username'] : '')); - } - } - - /** - * Sets an email address to send to - */ - function to($address, $realname = '') - { - global $config; - - if (!trim($address)) - { - return; - } - - $pos = isset($this->addresses['to']) ? count($this->addresses['to']) : 0; - - $this->addresses['to'][$pos]['email'] = trim($address); - - // If empty sendmail_path on windows, PHP changes the to line - if (!$config['smtp_delivery'] && DIRECTORY_SEPARATOR == '\\') - { - $this->addresses['to'][$pos]['name'] = ''; - } - else - { - $this->addresses['to'][$pos]['name'] = trim($realname); - } - } - - /** - * Sets an cc address to send to - */ - function cc($address, $realname = '') - { - if (!trim($address)) - { - return; - } - - $pos = isset($this->addresses['cc']) ? count($this->addresses['cc']) : 0; - $this->addresses['cc'][$pos]['email'] = trim($address); - $this->addresses['cc'][$pos]['name'] = trim($realname); - } - - /** - * Sets an bcc address to send to - */ - function bcc($address, $realname = '') - { - if (!trim($address)) - { - return; - } - - $pos = isset($this->addresses['bcc']) ? count($this->addresses['bcc']) : 0; - $this->addresses['bcc'][$pos]['email'] = trim($address); - $this->addresses['bcc'][$pos]['name'] = trim($realname); - } - - /** - * Sets a im contact to send to - */ - function im($address, $realname = '') - { - // IM-Addresses could be empty - if (!trim($address)) - { - return; - } - - $pos = isset($this->addresses['im']) ? count($this->addresses['im']) : 0; - $this->addresses['im'][$pos]['uid'] = trim($address); - $this->addresses['im'][$pos]['name'] = trim($realname); - } - - /** - * Set the reply to address - */ - function replyto($address) - { - $this->replyto = trim($address); - } - - /** - * Set the from address - */ - function from($address) - { - $this->from = trim($address); - } - - /** - * set up subject for mail - */ - function subject($subject = '') - { - $this->subject = trim($subject); - } - - /** - * set up extra mail headers - */ - function headers($headers) - { - $this->extra_headers[] = trim($headers); - } - - /** - * Adds X-AntiAbuse headers - * - * @param \phpbb\config\config $config Config object - * @param \phpbb\user $user User object - * @return void - */ - function anti_abuse_headers($config, $user) - { - $this->headers('X-AntiAbuse: Board servername - ' . mail_encode($config['server_name'])); - $this->headers('X-AntiAbuse: User_id - ' . $user->data['user_id']); - $this->headers('X-AntiAbuse: Username - ' . mail_encode($user->data['username'])); - $this->headers('X-AntiAbuse: User IP - ' . $user->ip); - } - - /** - * Set the email priority - */ - function set_mail_priority($priority = MAIL_NORMAL_PRIORITY) - { - $this->mail_priority = $priority; - } - - /** - * Set email template to use - */ - function template($template_file, $template_lang = '', $template_path = '', $template_dir_prefix = '') - { - global $config, $phpbb_root_path, $user; - - $template_dir_prefix = (!$template_dir_prefix || $template_dir_prefix[0] === '/') ? $template_dir_prefix : '/' . $template_dir_prefix; - - $this->setup_template(); - - if (!trim($template_file)) - { - trigger_error('No template file for emailing set.', E_USER_ERROR); - } - - if (!trim($template_lang)) - { - // fall back to board default language if the user's language is - // missing $template_file. If this does not exist either, - // $this->template->set_filenames will do a trigger_error - $template_lang = basename($config['default_lang']); - } - - $ext_template_paths = array( - array( - 'name' => $template_lang . '_email', - 'ext_path' => 'language/' . $template_lang . '/email' . $template_dir_prefix, - ), - ); - - if ($template_path) - { - $template_paths = array( - $template_path . $template_dir_prefix, - ); - } - else - { - $template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; - $template_path .= $template_lang . '/email'; - - $template_paths = array( - $template_path . $template_dir_prefix, - ); - - $board_language = basename($config['default_lang']); - - // we can only specify default language fallback when the path is not a custom one for which we - // do not know the default language alternative - if ($template_lang !== $board_language) - { - $fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; - $fallback_template_path .= $board_language . '/email'; - - $template_paths[] = $fallback_template_path . $template_dir_prefix; - - $ext_template_paths[] = array( - 'name' => $board_language . '_email', - 'ext_path' => 'language/' . $board_language . '/email' . $template_dir_prefix, - ); - } - // If everything fails just fall back to en template - if ($template_lang !== 'en' && $board_language !== 'en') - { - $fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; - $fallback_template_path .= 'en/email'; - - $template_paths[] = $fallback_template_path . $template_dir_prefix; - - $ext_template_paths[] = array( - 'name' => 'en_email', - 'ext_path' => 'language/en/email' . $template_dir_prefix, - ); - } - } - - $this->set_template_paths($ext_template_paths, $template_paths); - - $this->template->set_filenames(array( - 'body' => $template_file . '.txt', - )); - - return true; - } - - /** - * assign variables to email template - */ - function assign_vars($vars) - { - $this->setup_template(); - - $this->template->assign_vars($vars); - } - - function assign_block_vars($blockname, $vars) - { - $this->setup_template(); - - $this->template->assign_block_vars($blockname, $vars); - } - - /** - * Send the mail out to the recipients set previously in var $this->addresses - * - * @param int $method User notification method NOTIFY_EMAIL|NOTIFY_IM|NOTIFY_BOTH - * @param bool $break Flag indicating if the function only formats the subject - * and the message without sending it - * - * @return bool - */ - function send($method = NOTIFY_EMAIL, $break = false) - { - global $config, $user, $phpbb_dispatcher; - - // We add some standard variables we always use, no need to specify them always - $this->assign_vars(array( - 'U_BOARD' => generate_board_url(), - 'EMAIL_SIG' => str_replace('
', "\n", "-- \n" . html_entity_decode($config['board_email_sig'], ENT_COMPAT)), - 'SITENAME' => html_entity_decode($config['sitename'], ENT_COMPAT), - )); - - $subject = $this->subject; - $template = $this->template; - /** - * Event to modify the template before parsing - * - * @event core.modify_notification_template - * @var int method User notification method NOTIFY_EMAIL|NOTIFY_IM|NOTIFY_BOTH - * @var bool break Flag indicating if the function only formats the subject - * and the message without sending it - * @var string subject The message subject - * @var \phpbb\template\template template The (readonly) template object - * @since 3.2.4-RC1 - */ - $vars = array('method', 'break', 'subject', 'template'); - extract($phpbb_dispatcher->trigger_event('core.modify_notification_template', compact($vars))); - - // Parse message through template - $message = trim($this->template->assign_display('body')); - - /** - * Event to modify notification message text after parsing - * - * @event core.modify_notification_message - * @var int method User notification method NOTIFY_EMAIL|NOTIFY_IM|NOTIFY_BOTH - * @var bool break Flag indicating if the function only formats the subject - * and the message without sending it - * @var string subject The message subject - * @var string message The message text - * @since 3.1.11-RC1 - */ - $vars = array('method', 'break', 'subject', 'message'); - extract($phpbb_dispatcher->trigger_event('core.modify_notification_message', compact($vars))); - - $this->subject = $subject; - $this->msg = $message; - unset($subject, $message, $template); - - // Because we use \n for newlines in the body message we need to fix line encoding errors for those admins who uploaded email template files in the wrong encoding - $this->msg = str_replace("\r\n", "\n", $this->msg); - - // We now try and pull a subject from the email body ... if it exists, - // do this here because the subject may contain a variable - $drop_header = ''; - $match = array(); - if (preg_match('#^(Subject:(.*?))$#m', $this->msg, $match)) - { - $this->subject = (trim($match[2]) != '') ? trim($match[2]) : (($this->subject != '') ? $this->subject : $user->lang['NO_EMAIL_SUBJECT']); - $drop_header .= '[\r\n]*?' . preg_quote($match[1], '#'); - } - else - { - $this->subject = (($this->subject != '') ? $this->subject : $user->lang['NO_EMAIL_SUBJECT']); - } - - if (preg_match('#^(List-Unsubscribe:(.*?))$#m', $this->msg, $match)) - { - $this->extra_headers[] = $match[1]; - $drop_header .= '[\r\n]*?' . preg_quote($match[1], '#'); - } - - if ($drop_header) - { - $this->msg = trim(preg_replace('#' . $drop_header . '#s', '', $this->msg)); - } - - if ($break) - { - return true; - } - - switch ($method) - { - case NOTIFY_EMAIL: - $result = $this->msg_email(); - break; - - case NOTIFY_IM: - $result = $this->msg_jabber(); - break; - - case NOTIFY_BOTH: - $result = $this->msg_email(); - $this->msg_jabber(); - break; - } - - $this->reset(); - return $result; - } - - /** - * Add error message to log - */ - function error($type, $msg) - { - global $user, $config, $request, $phpbb_log; - - // Session doesn't exist, create it - if (!isset($user->session_id) || $user->session_id === '') - { - $user->session_begin(); - } - - $calling_page = html_entity_decode($request->server('REQUEST_URI'), ENT_COMPAT); - - switch ($type) - { - case 'EMAIL': - $message = 'EMAIL/' . (($config['smtp_delivery']) ? 'SMTP' : 'PHP/mail()') . ''; - break; - - default: - $message = "$type"; - break; - } - - $message .= '
' . htmlspecialchars($calling_page, ENT_COMPAT) . '

' . $msg . '
'; - $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_ERROR_' . $type, false, array($message)); - } - - /** - * Save to queue - */ - function save_queue() - { - global $config; - - if ($config['email_package_size'] && $this->use_queue && !empty($this->queue)) - { - $this->queue->save(); - return; - } - } - - /** - * Generates a valid message id to be used in emails - * - * @return string message id - */ - function generate_message_id() - { - global $config, $request; - - $domain = ($config['server_name']) ?: $request->server('SERVER_NAME', 'phpbb.generated'); - - return md5(unique_id()) . '@' . $domain; - } - - /** - * Return email header - */ - function build_header($to, $cc, $bcc) - { - global $config, $phpbb_dispatcher; - - // We could use keys here, but we won't do this for 3.0.x to retain backwards compatibility - $headers = array(); - - $headers[] = 'From: ' . $this->from; - - if ($cc) - { - $headers[] = 'Cc: ' . $cc; - } - - if ($bcc) - { - $headers[] = 'Bcc: ' . $bcc; - } - - $headers[] = 'Reply-To: ' . $this->replyto; - $headers[] = 'Return-Path: <' . $config['board_email'] . '>'; - $headers[] = 'Sender: <' . $config['board_email'] . '>'; - $headers[] = 'MIME-Version: 1.0'; - $headers[] = 'Message-ID: <' . $this->generate_message_id() . '>'; - $headers[] = 'Date: ' . date('r', time()); - $headers[] = 'Content-Type: text/plain; charset=UTF-8'; // format=flowed - $headers[] = 'Content-Transfer-Encoding: 8bit'; // 7bit - - $headers[] = 'X-Priority: ' . $this->mail_priority; - $headers[] = 'X-MSMail-Priority: ' . (($this->mail_priority == MAIL_LOW_PRIORITY) ? 'Low' : (($this->mail_priority == MAIL_NORMAL_PRIORITY) ? 'Normal' : 'High')); - $headers[] = 'X-Mailer: phpBB3'; - $headers[] = 'X-MimeOLE: phpBB3'; - $headers[] = 'X-phpBB-Origin: phpbb://' . str_replace(array('http://', 'https://'), array('', ''), generate_board_url()); - - /** - * Event to modify email header entries - * - * @event core.modify_email_headers - * @var array headers Array containing email header entries - * @since 3.1.11-RC1 - */ - $vars = array('headers'); - extract($phpbb_dispatcher->trigger_event('core.modify_email_headers', compact($vars))); - - if (count($this->extra_headers)) - { - $headers = array_merge($headers, $this->extra_headers); - } - - return $headers; - } - - /** - * Send out emails - */ - function msg_email() - { - global $config, $phpbb_dispatcher; - - if (empty($config['email_enable'])) - { - return false; - } - - // Addresses to send to? - if (empty($this->addresses) || (empty($this->addresses['to']) && empty($this->addresses['cc']) && empty($this->addresses['bcc']))) - { - // Send was successful. ;) - return true; - } - - $use_queue = false; - if ($config['email_package_size'] && $this->use_queue) - { - if (empty($this->queue)) - { - $this->queue = new queue(); - $this->queue->init('email', $config['email_package_size']); - } - $use_queue = true; - } - - $contact_name = html_entity_decode($config['board_contact_name'], ENT_COMPAT); - $board_contact = (($contact_name !== '') ? '"' . mail_encode($contact_name) . '" ' : '') . '<' . $config['board_contact'] . '>'; - - $break = false; - $addresses = $this->addresses; - $subject = $this->subject; - $msg = $this->msg; - /** - * Event to send message via external transport - * - * @event core.notification_message_email - * @var bool break Flag indicating if the function return after hook - * @var array addresses The message recipients - * @var string subject The message subject - * @var string msg The message text - * @since 3.2.4-RC1 - */ - $vars = array( - 'break', - 'addresses', - 'subject', - 'msg', - ); - extract($phpbb_dispatcher->trigger_event('core.notification_message_email', compact($vars))); - - $this->addresses = $addresses; - $this->subject = $subject; - $this->msg = $msg; - unset($addresses, $subject, $msg); - - if ($break) - { - return true; - } - - if (empty($this->replyto)) - { - $this->replyto = $board_contact; - } - - if (empty($this->from)) - { - $this->from = $board_contact; - } - - $encode_eol = $config['smtp_delivery'] || PHP_VERSION_ID >= 80000 ? "\r\n" : PHP_EOL; - - // Build to, cc and bcc strings - $to = $cc = $bcc = ''; - foreach ($this->addresses as $type => $address_ary) - { - if ($type == 'im') - { - continue; - } - - foreach ($address_ary as $which_ary) - { - ${$type} .= ((${$type} != '') ? ', ' : '') . (($which_ary['name'] != '') ? mail_encode($which_ary['name'], $encode_eol) . ' <' . $which_ary['email'] . '>' : $which_ary['email']); - } - } - - // Build header - $headers = $this->build_header($to, $cc, $bcc); - - // Send message ... - if (!$use_queue) - { - $mail_to = ($to == '') ? 'undisclosed-recipients:;' : $to; - $err_msg = ''; - - if ($config['smtp_delivery']) - { - $result = smtpmail($this->addresses, mail_encode($this->subject), wordwrap(utf8_wordwrap($this->msg), 997, "\n", true), $err_msg, $headers); - } - else - { - $result = phpbb_mail($mail_to, $this->subject, $this->msg, $headers, $encode_eol, $err_msg); - } - - if (!$result) - { - $this->error('EMAIL', $err_msg); - return false; - } - } - else - { - $this->queue->put('email', array( - 'to' => $to, - 'addresses' => $this->addresses, - 'subject' => $this->subject, - 'msg' => $this->msg, - 'headers' => $headers) - ); - } - - return true; - } - - /** - * Send jabber message out - */ - function msg_jabber() - { - global $config, $user, $phpbb_root_path, $phpEx; - - if (empty($config['jab_enable']) || empty($config['jab_host']) || empty($config['jab_username']) || empty($config['jab_password'])) - { - return false; - } - - if (empty($this->addresses['im'])) - { - // Send was successful. ;) - return true; - } - - $use_queue = false; - if ($config['jab_package_size'] && $this->use_queue) - { - if (empty($this->queue)) - { - $this->queue = new queue(); - $this->queue->init('jabber', $config['jab_package_size']); - } - $use_queue = true; - } - - $addresses = array(); - foreach ($this->addresses['im'] as $type => $uid_ary) - { - $addresses[] = $uid_ary['uid']; - } - $addresses = array_unique($addresses); - - if (!$use_queue) - { - include_once($phpbb_root_path . 'includes/functions_jabber.' . $phpEx); - $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], html_entity_decode($config['jab_password'], ENT_COMPAT), $config['jab_use_ssl'], $config['jab_verify_peer'], $config['jab_verify_peer_name'], $config['jab_allow_self_signed']); - - if (!$this->jabber->connect()) - { - $this->error('JABBER', $user->lang['ERR_JAB_CONNECT'] . '
' . $this->jabber->get_log()); - return false; - } - - if (!$this->jabber->login()) - { - $this->error('JABBER', $user->lang['ERR_JAB_AUTH'] . '
' . $this->jabber->get_log()); - return false; - } - - foreach ($addresses as $address) - { - $this->jabber->send_message($address, $this->msg, $this->subject); - } - - $this->jabber->disconnect(); - } - else - { - $this->queue->put('jabber', array( - 'addresses' => $addresses, - 'subject' => $this->subject, - 'msg' => $this->msg) - ); - } - unset($addresses); - return true; - } - - /** - * Setup template engine - */ - protected function setup_template() - { - global $phpbb_container, $phpbb_dispatcher; - - if ($this->template instanceof \phpbb\template\template) - { - return; - } - - $template_environment = new \phpbb\template\twig\environment( - $phpbb_container->get('assets.bag'), - $phpbb_container->get('config'), - $phpbb_container->get('filesystem'), - $phpbb_container->get('path_helper'), - $phpbb_container->getParameter('core.template.cache_path'), - $phpbb_container->get('ext.manager'), - new \phpbb\template\twig\loader(), - $phpbb_dispatcher, - array() - ); - $template_environment->setLexer($phpbb_container->get('template.twig.lexer')); - - $this->template = new \phpbb\template\twig\twig( - $phpbb_container->get('path_helper'), - $phpbb_container->get('config'), - new \phpbb\template\context(), - $template_environment, - $phpbb_container->getParameter('core.template.cache_path'), - $phpbb_container->get('user'), - $phpbb_container->get('template.twig.extensions.collection'), - $phpbb_container->get('ext.manager') - ); - } - - /** - * Set template paths to load - */ - protected function set_template_paths($path_name, $paths) - { - $this->setup_template(); - - $this->template->set_custom_style($path_name, $paths); - } -} - -/** -* handling email and jabber queue -*/ -class queue -{ - var $data = array(); - var $queue_data = array(); - var $package_size = 0; - var $cache_file = ''; - var $eol = "\n"; - - /** - * @var \phpbb\filesystem\filesystem_interface - */ - protected $filesystem; - - /** - * constructor - */ - function __construct() - { - global $phpEx, $phpbb_root_path, $phpbb_filesystem, $phpbb_container; - - $this->data = array(); - $this->cache_file = $phpbb_container->getParameter('core.cache_dir') . "queue.$phpEx"; - $this->filesystem = $phpbb_filesystem; - } - - /** - * Init a queue object - */ - function init($object, $package_size) - { - $this->data[$object] = array(); - $this->data[$object]['package_size'] = $package_size; - $this->data[$object]['data'] = array(); - } - - /** - * Put object in queue - */ - function put($object, $scope) - { - $this->data[$object]['data'][] = $scope; - } - - /** - * Process queue - * Using lock file - */ - function process() - { - global $config, $phpEx, $phpbb_root_path, $user, $phpbb_dispatcher; - - $lock = new \phpbb\lock\flock($this->cache_file); - $lock->acquire(); - - // avoid races, check file existence once - $have_cache_file = file_exists($this->cache_file); - if (!$have_cache_file || $config['last_queue_run'] > time() - $config['queue_interval']) - { - if (!$have_cache_file) - { - $config->set('last_queue_run', time(), false); - } - - $lock->release(); - return; - } - - $config->set('last_queue_run', time(), false); - - include($this->cache_file); - - foreach ($this->queue_data as $object => $data_ary) - { - @set_time_limit(0); - - if (!isset($data_ary['package_size'])) - { - $data_ary['package_size'] = 0; - } - - $package_size = $data_ary['package_size']; - $num_items = (!$package_size || count($data_ary['data']) < $package_size) ? count($data_ary['data']) : $package_size; - - /* - * This code is commented out because it causes problems on some web hosts. - * The core problem is rather restrictive email sending limits. - * This code is nly useful if you have no such restrictions from the - * web host and the package size setting is wrong. - - // If the amount of emails to be sent is way more than package_size than we need to increase it to prevent backlogs... - if (count($data_ary['data']) > $package_size * 2.5) - { - $num_items = count($data_ary['data']); - } - */ - - switch ($object) - { - case 'email': - // Delete the email queued objects if mailing is disabled - if (!$config['email_enable']) - { - unset($this->queue_data['email']); - continue 2; - } - break; - - case 'jabber': - if (!$config['jab_enable']) - { - unset($this->queue_data['jabber']); - continue 2; - } - - include_once($phpbb_root_path . 'includes/functions_jabber.' . $phpEx); - $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], html_entity_decode($config['jab_password'], ENT_COMPAT), $config['jab_use_ssl'], $config['jab_verify_peer'], $config['jab_verify_peer_name'], $config['jab_allow_self_signed']); - - if (!$this->jabber->connect()) - { - $messenger = new messenger(); - $messenger->error('JABBER', $user->lang['ERR_JAB_CONNECT']); - continue 2; - } - - if (!$this->jabber->login()) - { - $messenger = new messenger(); - $messenger->error('JABBER', $user->lang['ERR_JAB_AUTH']); - continue 2; - } - - break; - - default: - $lock->release(); - return; - } - - for ($i = 0; $i < $num_items; $i++) - { - // Make variables available... - extract(array_shift($this->queue_data[$object]['data'])); - - switch ($object) - { - case 'email': - $break = false; - /** - * Event to send message via external transport - * - * @event core.notification_message_process - * @var bool break Flag indicating if the function return after hook - * @var array addresses The message recipients - * @var string subject The message subject - * @var string msg The message text - * @since 3.2.4-RC1 - */ - $vars = array( - 'break', - 'addresses', - 'subject', - 'msg', - ); - extract($phpbb_dispatcher->trigger_event('core.notification_message_process', compact($vars))); - - if (!$break) - { - $err_msg = ''; - $to = (!$to) ? 'undisclosed-recipients:;' : $to; - - if ($config['smtp_delivery']) - { - $result = smtpmail($addresses, mail_encode($subject), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $err_msg, $headers); - } - else - { - $encode_eol = $config['smtp_delivery'] || PHP_VERSION_ID >= 80000 ? "\r\n" : PHP_EOL; - $result = phpbb_mail($to, $subject, $msg, $headers, $encode_eol, $err_msg); - } - - if (!$result) - { - $messenger = new messenger(); - $messenger->error('EMAIL', $err_msg); - continue 2; - } - } - break; - - case 'jabber': - foreach ($addresses as $address) - { - if ($this->jabber->send_message($address, $msg, $subject) === false) - { - $messenger = new messenger(); - $messenger->error('JABBER', $this->jabber->get_log()); - continue 3; - } - } - break; - } - } - - // No more data for this object? Unset it - if (!count($this->queue_data[$object]['data'])) - { - unset($this->queue_data[$object]); - } - - // Post-object processing - switch ($object) - { - case 'jabber': - // Hang about a couple of secs to ensure the messages are - // handled, then disconnect - $this->jabber->disconnect(); - break; - } - } - - if (!count($this->queue_data)) - { - @unlink($this->cache_file); - } - else - { - if ($fp = @fopen($this->cache_file, 'wb')) - { - fwrite($fp, "queue_data = unserialize(" . var_export(serialize($this->queue_data), true) . ");\n\n?>"); - fclose($fp); - - if (function_exists('opcache_invalidate')) - { - @opcache_invalidate($this->cache_file); - } - - try - { - $this->filesystem->phpbb_chmod($this->cache_file, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - } - } - - $lock->release(); - } - - /** - * Save queue - */ - function save() - { - if (!count($this->data)) - { - return; - } - - $lock = new \phpbb\lock\flock($this->cache_file); - $lock->acquire(); - - if (file_exists($this->cache_file)) - { - include($this->cache_file); - - foreach ($this->queue_data as $object => $data_ary) - { - if (isset($this->data[$object]) && count($this->data[$object])) - { - $this->data[$object]['data'] = array_merge($data_ary['data'], $this->data[$object]['data']); - } - else - { - $this->data[$object]['data'] = $data_ary['data']; - } - } - } - - if ($fp = @fopen($this->cache_file, 'w')) - { - fwrite($fp, "queue_data = unserialize(" . var_export(serialize($this->data), true) . ");\n\n?>"); - fclose($fp); - - if (function_exists('opcache_invalidate')) - { - @opcache_invalidate($this->cache_file); - } - - try - { - $this->filesystem->phpbb_chmod($this->cache_file, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE); - } - catch (\phpbb\filesystem\exception\filesystem_exception $e) - { - // Do nothing - } - - $this->data = array(); - } - - $lock->release(); - } -} - -/** -* Replacement or substitute for PHP's mail command -*/ -function smtpmail($addresses, $subject, $message, &$err_msg, $headers = false) -{ - global $config, $user; - - // Fix any bare linefeeds in the message to make it RFC821 Compliant. - $message = preg_replace("#(?lang['NO_EMAIL_SUBJECT'])) ? $user->lang['NO_EMAIL_SUBJECT'] : 'No email subject specified'; - return false; - } - - if (trim($message) == '') - { - $err_msg = (isset($user->lang['NO_EMAIL_MESSAGE'])) ? $user->lang['NO_EMAIL_MESSAGE'] : 'Email message was blank'; - return false; - } - - $mail_rcpt = $mail_to = $mail_cc = array(); - - // Build correct addresses for RCPT TO command and the client side display (TO, CC) - if (isset($addresses['to']) && count($addresses['to'])) - { - foreach ($addresses['to'] as $which_ary) - { - $mail_to[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>'; - $mail_rcpt['to'][] = '<' . trim($which_ary['email']) . '>'; - } - } - - if (isset($addresses['bcc']) && count($addresses['bcc'])) - { - foreach ($addresses['bcc'] as $which_ary) - { - $mail_rcpt['bcc'][] = '<' . trim($which_ary['email']) . '>'; - } - } - - if (isset($addresses['cc']) && count($addresses['cc'])) - { - foreach ($addresses['cc'] as $which_ary) - { - $mail_cc[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>'; - $mail_rcpt['cc'][] = '<' . trim($which_ary['email']) . '>'; - } - } - - $smtp = new smtp_class(); - - $errno = 0; - $errstr = ''; - - $smtp->add_backtrace('Connecting to ' . $config['smtp_host'] . ':' . $config['smtp_port']); - - // Ok we have error checked as much as we can to this point let's get on it already. - if (!class_exists('\phpbb\error_collector')) - { - global $phpbb_root_path, $phpEx; - include($phpbb_root_path . 'includes/error_collector.' . $phpEx); - } - $collector = new \phpbb\error_collector; - $collector->install(); - - $options = array(); - $verify_peer = (bool) $config['smtp_verify_peer']; - $verify_peer_name = (bool) $config['smtp_verify_peer_name']; - $allow_self_signed = (bool) $config['smtp_allow_self_signed']; - $remote_socket = $config['smtp_host'] . ':' . $config['smtp_port']; - - // Set ssl context options, see http://php.net/manual/en/context.ssl.php - $options['ssl'] = array('verify_peer' => $verify_peer, 'verify_peer_name' => $verify_peer_name, 'allow_self_signed' => $allow_self_signed); - $socket_context = stream_context_create($options); - - $smtp->socket = @stream_socket_client($remote_socket, $errno, $errstr, 20, STREAM_CLIENT_CONNECT, $socket_context); - $collector->uninstall(); - $error_contents = $collector->format_errors(); - - if (!$smtp->socket) - { - if ($errstr) - { - $errstr = utf8_convert_message($errstr); - } - - $err_msg = (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr"; - $err_msg .= ($error_contents) ? '

' . htmlspecialchars($error_contents, ENT_COMPAT) : ''; - return false; - } - - // Wait for reply - if ($err_msg = $smtp->server_parse('220', __LINE__)) - { - $smtp->close_session($err_msg); - return false; - } - - // Let me in. This function handles the complete authentication process - if ($err_msg = $smtp->log_into_server($config['smtp_host'], $config['smtp_username'], html_entity_decode($config['smtp_password'], ENT_COMPAT), $config['smtp_auth_method'])) - { - $smtp->close_session($err_msg); - return false; - } - - // From this point onward most server response codes should be 250 - // Specify who the mail is from.... - $smtp->server_send('MAIL FROM:<' . $config['board_email'] . '>'); - if ($err_msg = $smtp->server_parse('250', __LINE__)) - { - $smtp->close_session($err_msg); - return false; - } - - // Specify each user to send to and build to header. - $to_header = implode(', ', $mail_to); - $cc_header = implode(', ', $mail_cc); - - // Now tell the MTA to send the Message to the following people... [TO, BCC, CC] - $rcpt = false; - foreach ($mail_rcpt as $type => $mail_to_addresses) - { - foreach ($mail_to_addresses as $mail_to_address) - { - // Add an additional bit of error checking to the To field. - if (preg_match('#[^ ]+\@[^ ]+#', $mail_to_address)) - { - $smtp->server_send("RCPT TO:$mail_to_address"); - if ($err_msg = $smtp->server_parse('250', __LINE__)) - { - // We continue... if users are not resolved we do not care - if ($smtp->numeric_response_code != 550) - { - $smtp->close_session($err_msg); - return false; - } - } - else - { - $rcpt = true; - } - } - } - } - - // We try to send messages even if a few people do not seem to have valid email addresses, but if no one has, we have to exit here. - if (!$rcpt) - { - $user->session_begin(); - $err_msg .= '

'; - $err_msg .= (isset($user->lang['INVALID_EMAIL_LOG'])) ? sprintf($user->lang['INVALID_EMAIL_LOG'], htmlspecialchars($mail_to_address, ENT_COMPAT)) : '' . htmlspecialchars($mail_to_address, ENT_COMPAT) . ' possibly an invalid email address?'; - $smtp->close_session($err_msg); - return false; - } - - // Ok now we tell the server we are ready to start sending data - $smtp->server_send('DATA'); - - // This is the last response code we look for until the end of the message. - if ($err_msg = $smtp->server_parse('354', __LINE__)) - { - $smtp->close_session($err_msg); - return false; - } - - // Send the Subject Line... - $smtp->server_send("Subject: $subject"); - - // Now the To Header. - $to_header = ($to_header == '') ? 'undisclosed-recipients:;' : $to_header; - $smtp->server_send("To: $to_header"); - - // Now the CC Header. - if ($cc_header != '') - { - $smtp->server_send("CC: $cc_header"); - } - - // Now any custom headers.... - if ($headers !== false) - { - $smtp->server_send("$headers\r\n"); - } - - // Ok now we are ready for the message... - $smtp->server_send($message); - - // Ok the all the ingredients are mixed in let's cook this puppy... - $smtp->server_send('.'); - if ($err_msg = $smtp->server_parse('250', __LINE__)) - { - $smtp->close_session($err_msg); - return false; - } - - // Now tell the server we are done and close the socket... - $smtp->server_send('QUIT'); - $smtp->close_session($err_msg); - - return true; -} - -/** -* SMTP Class -* Auth Mechanisms originally taken from the AUTH Modules found within the PHP Extension and Application Repository (PEAR) -* See docs/AUTHORS for more details -*/ -class smtp_class -{ - var $server_response = ''; - var $socket = 0; - protected $socket_tls = false; - var $responses = array(); - var $commands = array(); - var $numeric_response_code = 0; - - var $backtrace = false; - var $backtrace_log = array(); - - function __construct() - { - // Always create a backtrace for admins to identify SMTP problems - $this->backtrace = true; - $this->backtrace_log = array(); - } - - /** - * Add backtrace message for debugging - */ - function add_backtrace($message) - { - if ($this->backtrace) - { - $this->backtrace_log[] = utf8_htmlspecialchars($message, ENT_COMPAT); - } - } - - /** - * Send command to smtp server - */ - function server_send($command, $private_info = false) - { - fputs($this->socket, $command . "\r\n"); - - (!$private_info) ? $this->add_backtrace("# $command") : $this->add_backtrace('# Omitting sensitive information'); - - // We could put additional code here - } - - /** - * We use the line to give the support people an indication at which command the error occurred - */ - function server_parse($response, $line) - { - global $user; - - $this->server_response = ''; - $this->responses = array(); - $this->numeric_response_code = 0; - - while (substr($this->server_response, 3, 1) != ' ') - { - if (!($this->server_response = fgets($this->socket, 256))) - { - return (isset($user->lang['NO_EMAIL_RESPONSE_CODE'])) ? $user->lang['NO_EMAIL_RESPONSE_CODE'] : 'Could not get mail server response codes'; - } - $this->responses[] = substr(rtrim($this->server_response), 4); - $this->numeric_response_code = (int) substr($this->server_response, 0, 3); - - $this->add_backtrace("LINE: $line <- {$this->server_response}"); - } - - if (!(substr($this->server_response, 0, 3) == $response)) - { - $this->numeric_response_code = (int) substr($this->server_response, 0, 3); - return (isset($user->lang['EMAIL_SMTP_ERROR_RESPONSE'])) ? sprintf($user->lang['EMAIL_SMTP_ERROR_RESPONSE'], $line, $this->server_response) : "Ran into problems sending Mail at Line $line. Response: $this->server_response"; - } - - return 0; - } - - /** - * Close session - */ - function close_session(&$err_msg) - { - fclose($this->socket); - - if ($this->backtrace) - { - $message = '

Backtrace

' . implode('
', $this->backtrace_log) . '

'; - $err_msg .= $message; - } - } - - /** - * Log into server and get possible auth codes if neccessary - */ - function log_into_server($hostname, $username, $password, $default_auth_method) - { - global $user; - - // Here we try to determine the *real* hostname (reverse DNS entry preferrably) - if (function_exists('php_uname') && !empty($local_host = php_uname('n'))) - { - // Able to resolve name to IP - if (($addr = @gethostbyname($local_host)) !== $local_host) - { - // Able to resolve IP back to name - if (!empty($name = @gethostbyaddr($addr)) && $name !== $addr) - { - $local_host = $name; - } - } - } - else - { - $local_host = $user->host; - } - - // If we are authenticating through pop-before-smtp, we - // have to login ones before we get authenticated - // NOTE: on some configurations the time between an update of the auth database takes so - // long that the first email send does not work. This is not a biggie on a live board (only - // the install mail will most likely fail) - but on a dynamic ip connection this might produce - // severe problems and is not fixable! - if ($default_auth_method == 'POP-BEFORE-SMTP' && $username && $password) - { - global $config; - - $errno = 0; - $errstr = ''; - - $this->server_send("QUIT"); - fclose($this->socket); - - $this->pop_before_smtp($hostname, $username, $password); - $username = $password = $default_auth_method = ''; - - // We need to close the previous session, else the server is not - // able to get our ip for matching... - if (!$this->socket = @fsockopen($config['smtp_host'], $config['smtp_port'], $errno, $errstr, 10)) - { - if ($errstr) - { - $errstr = utf8_convert_message($errstr); - } - - $err_msg = (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr"; - return $err_msg; - } - - // Wait for reply - if ($err_msg = $this->server_parse('220', __LINE__)) - { - $this->close_session($err_msg); - return $err_msg; - } - } - - $hello_result = $this->hello($local_host); - if (!is_null($hello_result)) - { - return $hello_result; - } - - // SMTP STARTTLS (RFC 3207) - if (!$this->socket_tls) - { - $this->socket_tls = $this->starttls(); - - if ($this->socket_tls) - { - // Switched to TLS - // RFC 3207: "The client MUST discard any knowledge obtained from the server, [...]" - // So say hello again - $hello_result = $this->hello($local_host); - - if (!is_null($hello_result)) - { - return $hello_result; - } - } - } - - // If we are not authenticated yet, something might be wrong if no username and passwd passed - if (!$username || !$password) - { - return false; - } - - if (!isset($this->commands['AUTH'])) - { - return (isset($user->lang['SMTP_NO_AUTH_SUPPORT'])) ? $user->lang['SMTP_NO_AUTH_SUPPORT'] : 'SMTP server does not support authentication'; - } - - // Get best authentication method - $available_methods = explode(' ', $this->commands['AUTH']); - - // Define the auth ordering if the default auth method was not found - $auth_methods = array('PLAIN', 'LOGIN', 'CRAM-MD5', 'DIGEST-MD5'); - $method = ''; - - if (in_array($default_auth_method, $available_methods)) - { - $method = $default_auth_method; - } - else - { - foreach ($auth_methods as $_method) - { - if (in_array($_method, $available_methods)) - { - $method = $_method; - break; - } - } - } - - if (!$method) - { - return (isset($user->lang['NO_SUPPORTED_AUTH_METHODS'])) ? $user->lang['NO_SUPPORTED_AUTH_METHODS'] : 'No supported authentication methods'; - } - - $method = strtolower(str_replace('-', '_', $method)); - return $this->$method($username, $password); - } - - /** - * SMTP EHLO/HELO - * - * @return mixed Null if the authentication process is supposed to continue - * False if already authenticated - * Error message (string) otherwise - */ - protected function hello($hostname) - { - // Try EHLO first - $this->server_send("EHLO $hostname"); - if ($err_msg = $this->server_parse('250', __LINE__)) - { - // a 503 response code means that we're already authenticated - if ($this->numeric_response_code == 503) - { - return false; - } - - // If EHLO fails, we try HELO - $this->server_send("HELO $hostname"); - if ($err_msg = $this->server_parse('250', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } - } - - foreach ($this->responses as $response) - { - $response = explode(' ', $response); - $response_code = $response[0]; - unset($response[0]); - $this->commands[$response_code] = implode(' ', $response); - } - - return null; - } - - /** - * SMTP STARTTLS (RFC 3207) - * - * @return bool Returns true if TLS was started - * Otherwise false - */ - protected function starttls() - { - global $config; - - // allow SMTPS (what was used by phpBB 3.0) if hostname is prefixed with tls:// or ssl:// - if (strpos($config['smtp_host'], 'tls://') === 0 || strpos($config['smtp_host'], 'ssl://') === 0) - { - return true; - } - - if (!function_exists('stream_socket_enable_crypto')) - { - return false; - } - - if (!isset($this->commands['STARTTLS'])) - { - return false; - } - - $this->server_send('STARTTLS'); - - if ($err_msg = $this->server_parse('220', __LINE__)) - { - return false; - } - - $result = false; - $stream_meta = stream_get_meta_data($this->socket); - - if (socket_set_blocking($this->socket, 1)) - { - // https://secure.php.net/manual/en/function.stream-socket-enable-crypto.php#119122 - $crypto = (phpbb_version_compare(PHP_VERSION, '5.6.7', '<')) ? STREAM_CRYPTO_METHOD_TLS_CLIENT : STREAM_CRYPTO_METHOD_SSLv23_CLIENT; - $result = stream_socket_enable_crypto($this->socket, true, $crypto); - socket_set_blocking($this->socket, (int) $stream_meta['blocked']); - } - - return $result; - } - - /** - * Pop before smtp authentication - */ - function pop_before_smtp($hostname, $username, $password) - { - global $user; - - if (!$this->socket = @fsockopen($hostname, 110, $errno, $errstr, 10)) - { - if ($errstr) - { - $errstr = utf8_convert_message($errstr); - } - - return (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr"; - } - - $this->server_send("USER $username", true); - if ($err_msg = $this->server_parse('+OK', __LINE__)) - { - return $err_msg; - } - - $this->server_send("PASS $password", true); - if ($err_msg = $this->server_parse('+OK', __LINE__)) - { - return $err_msg; - } - - $this->server_send('QUIT'); - fclose($this->socket); - - return false; - } - - /** - * Plain authentication method - */ - function plain($username, $password) - { - $this->server_send('AUTH PLAIN'); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } - - $base64_method_plain = base64_encode("\0" . $username . "\0" . $password); - $this->server_send($base64_method_plain, true); - if ($err_msg = $this->server_parse('235', __LINE__)) - { - return $err_msg; - } - - return false; - } - - /** - * Login authentication method - */ - function login($username, $password) - { - $this->server_send('AUTH LOGIN'); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } - - $this->server_send(base64_encode($username), true); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return $err_msg; - } - - $this->server_send(base64_encode($password), true); - if ($err_msg = $this->server_parse('235', __LINE__)) - { - return $err_msg; - } - - return false; - } - - /** - * cram_md5 authentication method - */ - function cram_md5($username, $password) - { - $this->server_send('AUTH CRAM-MD5'); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } - - $md5_challenge = base64_decode($this->responses[0]); - $password = (strlen($password) > 64) ? pack('H32', md5($password)) : ((strlen($password) < 64) ? str_pad($password, 64, chr(0)) : $password); - $md5_digest = md5((substr($password, 0, 64) ^ str_repeat(chr(0x5C), 64)) . (pack('H32', md5((substr($password, 0, 64) ^ str_repeat(chr(0x36), 64)) . $md5_challenge)))); - - $base64_method_cram_md5 = base64_encode($username . ' ' . $md5_digest); - - $this->server_send($base64_method_cram_md5, true); - if ($err_msg = $this->server_parse('235', __LINE__)) - { - return $err_msg; - } - - return false; - } - - /** - * digest_md5 authentication method - * A real pain in the *** - */ - function digest_md5($username, $password) - { - global $config, $user; - - $this->server_send('AUTH DIGEST-MD5'); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } - - $md5_challenge = base64_decode($this->responses[0]); - - // Parse the md5 challenge - from AUTH_SASL (PEAR) - $tokens = array(); - while (preg_match('/^([a-z-]+)=("[^"]+(?host; - } - - // Maxbuf - if (empty($tokens['maxbuf'])) - { - $tokens['maxbuf'] = 65536; - } - - // Required: nonce, algorithm - if (empty($tokens['nonce']) || empty($tokens['algorithm'])) - { - $tokens = array(); - } - $md5_challenge = $tokens; - - if (!empty($md5_challenge)) - { - $str = ''; - for ($i = 0; $i < 32; $i++) - { - $str .= chr(mt_rand(0, 255)); - } - $cnonce = base64_encode($str); - - $digest_uri = 'smtp/' . $config['smtp_host']; - - $auth_1 = sprintf('%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $username, $md5_challenge['realm'], $password))), $md5_challenge['nonce'], $cnonce); - $auth_2 = 'AUTHENTICATE:' . $digest_uri; - $response_value = md5(sprintf('%s:%s:00000001:%s:auth:%s', md5($auth_1), $md5_challenge['nonce'], $cnonce, md5($auth_2))); - - $input_string = sprintf('username="%s",realm="%s",nonce="%s",cnonce="%s",nc="00000001",qop=auth,digest-uri="%s",response=%s,%d', $username, $md5_challenge['realm'], $md5_challenge['nonce'], $cnonce, $digest_uri, $response_value, $md5_challenge['maxbuf']); - } - else - { - return (isset($user->lang['INVALID_DIGEST_CHALLENGE'])) ? $user->lang['INVALID_DIGEST_CHALLENGE'] : 'Invalid digest challenge'; - } - - $base64_method_digest_md5 = base64_encode($input_string); - $this->server_send($base64_method_digest_md5, true); - if ($err_msg = $this->server_parse('334', __LINE__)) - { - return $err_msg; - } - - $this->server_send(' '); - if ($err_msg = $this->server_parse('235', __LINE__)) - { - return $err_msg; - } - - return false; - } -} - -/** - * Encodes the given string for proper display in UTF-8 or US-ASCII. - * - * This version is based on iconv_mime_encode() implementation - * from symfomy/polyfill-iconv - * https://github.com/symfony/polyfill-iconv/blob/fd324208ec59a39ebe776e6e9ec5540ad4f40aaa/Iconv.php#L355 - * - * @param string $str - * @param string $eol Lines delimiter (optional to be backwards compatible) - * - * @return string - */ -function mail_encode($str, $eol = "\r\n") -{ - // Check if string contains ASCII only characters - $is_ascii = strlen($str) === utf8_strlen($str); - - $scheme = $is_ascii ? 'Q' : 'B'; - - // Define start delimiter, end delimiter - // Use the Quoted-Printable encoding for ASCII strings to avoid unnecessary encoding in Base64 - $start = '=?' . ($is_ascii ? 'US-ASCII' : 'UTF-8') . '?' . $scheme . '?'; - $end = '?='; - - // Maximum encoded-word length is 75 as per RFC 2047 section 2. - // $split_length *must* be a multiple of 4, but <= 75 - strlen($start . $eol . $end)!!! - $split_length = 75 - strlen($start . $eol . $end); - $split_length = $split_length - $split_length % 4; - - $line_length = strlen($start) + strlen($end); - $line_offset = strlen($start) + 1; - $line_data = ''; - - $is_quoted_printable = 'Q' === $scheme; - - preg_match_all('/./us', $str, $chars); - $chars = $chars[0] ?? []; - - $str = []; - foreach ($chars as $char) - { - $encoded_char = $is_quoted_printable - ? $char = preg_replace_callback( - '/[()<>@,;:\\\\".\[\]=_?\x20\x00-\x1F\x80-\xFF]/', - function ($matches) - { - $hex = dechex(ord($matches[0])); - $hex = strlen($hex) == 1 ? "0$hex" : $hex; - return '=' . strtoupper($hex); - }, - $char - ) - : base64_encode($line_data . $char); - - if (isset($encoded_char[$split_length - $line_length])) - { - if (!$is_quoted_printable) - { - $line_data = base64_encode($line_data); - } - $str[] = $start . $line_data . $end; - $line_length = $line_offset; - $line_data = ''; - } - - $line_data .= $char; - $is_quoted_printable && $line_length += strlen($char); - } - - if ($line_data !== '') - { - if (!$is_quoted_printable) - { - $line_data = base64_encode($line_data); - } - $str[] = $start . $line_data . $end; - } - - return implode($eol . ' ', $str); -} - -/** - * Wrapper for sending out emails with the PHP's mail function - */ -function phpbb_mail($to, $subject, $msg, $headers, $eol, &$err_msg) -{ - global $config, $phpbb_root_path, $phpEx, $phpbb_dispatcher; - - // Convert Numeric Character References to UTF-8 chars (ie. Emojis) - $subject = utf8_decode_ncr($subject); - $msg = utf8_decode_ncr($msg); - - /** - * We use the EOL character for the OS here because the PHP mail function does not correctly transform line endings. - * On Windows SMTP is used (SMTP is \r\n), on UNIX a command is used... - * Reference: http://bugs.php.net/bug.php?id=15841 - */ - $headers = implode($eol, $headers); - - if (!class_exists('\phpbb\error_collector')) - { - include($phpbb_root_path . 'includes/error_collector.' . $phpEx); - } - - $collector = new \phpbb\error_collector; - $collector->install(); - - /** - * On some PHP Versions mail() *may* fail if there are newlines within the subject. - * Newlines are used as a delimiter for lines in mail_encode() according to RFC 2045 section 6.8. - * Because PHP can't decide what is wanted we revert back to the non-RFC-compliant way of separating by one space - * (Use '' as parameter to mail_encode() results in SPACE used) - */ - $additional_parameters = $config['email_force_sender'] ? '-f' . $config['board_email'] : ''; - - /** - * Modify data before sending out emails with PHP's mail function - * - * @event core.phpbb_mail_before - * @var string to The message recipient - * @var string subject The message subject - * @var string msg The message text - * @var string headers The email headers - * @var string eol The endline character - * @var string additional_parameters The additional parameters - * @since 3.3.6-RC1 - */ - $vars = [ - 'to', - 'subject', - 'msg', - 'headers', - 'eol', - 'additional_parameters', - ]; - extract($phpbb_dispatcher->trigger_event('core.phpbb_mail_before', compact($vars))); - - $result = mail($to, mail_encode($subject, ''), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $headers, $additional_parameters); - - /** - * Execute code after sending out emails with PHP's mail function - * - * @event core.phpbb_mail_after - * @var string to The message recipient - * @var string subject The message subject - * @var string msg The message text - * @var string headers The email headers - * @var string eol The endline character - * @var string additional_parameters The additional parameters - * @var bool result True if the email was sent, false otherwise - * @since 3.3.6-RC1 - */ - $vars = [ - 'to', - 'subject', - 'msg', - 'headers', - 'eol', - 'additional_parameters', - 'result', - ]; - extract($phpbb_dispatcher->trigger_event('core.phpbb_mail_after', compact($vars))); - - $collector->uninstall(); - $err_msg = $collector->format_errors(); - - return $result; -} diff --git a/phpBB/includes/functions_user.php b/phpBB/includes/functions_user.php index bb1b63f177..7441b74413 100644 --- a/phpBB/includes/functions_user.php +++ b/phpBB/includes/functions_user.php @@ -11,6 +11,8 @@ * */ +use phpbb\messenger\method\messenger_interface; + /** * @ignore */ @@ -244,7 +246,7 @@ function user_add($user_row, $cp_data = false, $notifications_data = null) 'user_notify' => 0, 'user_notify_pm' => 1, - 'user_notify_type' => NOTIFY_EMAIL, + 'user_notify_type' => messenger_interface::NOTIFY_EMAIL, 'user_allow_pm' => 1, 'user_allow_viewonline' => 1, 'user_allow_viewemail' => 1, diff --git a/phpBB/includes/mcp/mcp_pm_reports.php b/phpBB/includes/mcp/mcp_pm_reports.php index 63fabb35db..afb3cb102d 100644 --- a/phpBB/includes/mcp/mcp_pm_reports.php +++ b/phpBB/includes/mcp/mcp_pm_reports.php @@ -51,8 +51,6 @@ class mcp_pm_reports { case 'close': case 'delete': - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - $report_id_list = $request->variable('report_id_list', array(0)); if (!count($report_id_list)) diff --git a/phpBB/includes/mcp/mcp_queue.php b/phpBB/includes/mcp/mcp_queue.php index fbde670bd0..57f6d4c94b 100644 --- a/phpBB/includes/mcp/mcp_queue.php +++ b/phpBB/includes/mcp/mcp_queue.php @@ -50,8 +50,6 @@ class mcp_queue { case 'approve': case 'restore': - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - $post_id_list = $request->variable('post_id_list', array(0)); $topic_id_list = $request->variable('topic_id_list', array(0)); @@ -113,11 +111,6 @@ class mcp_queue return; } - if (!class_exists('messenger')) - { - include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - } - if (!empty($topic_id_list)) { $post_visibility = ($mode == 'deleted_topics') ? ITEM_DELETED : array(ITEM_UNAPPROVED, ITEM_REAPPROVE); diff --git a/phpBB/includes/mcp/mcp_reports.php b/phpBB/includes/mcp/mcp_reports.php index 97d1dbbfda..7843bc1efe 100644 --- a/phpBB/includes/mcp/mcp_reports.php +++ b/phpBB/includes/mcp/mcp_reports.php @@ -49,8 +49,6 @@ class mcp_reports { case 'close': case 'delete': - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - $report_id_list = $request->variable('report_id_list', array(0)); if (!count($report_id_list)) diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index cad43866fc..d19d1ad9d7 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -107,7 +107,6 @@ function mcp_topic_view($id, $mode, $action) } include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx); - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); if (!count($post_id_list)) { diff --git a/phpBB/includes/questionnaire/questionnaire.php b/phpBB/includes/questionnaire/questionnaire.php index 74675e0e03..319537f3e3 100644 --- a/phpBB/includes/questionnaire/questionnaire.php +++ b/phpBB/includes/questionnaire/questionnaire.php @@ -435,7 +435,6 @@ class phpbb_questionnaire_phpbb_data_provider 'secure_downloads' => true, 'session_gc' => true, 'session_length' => true, - 'smtp_auth_method' => true, 'smtp_delivery' => true, 'topics_per_page' => true, 'version' => true, diff --git a/phpBB/includes/ucp/ucp_activate.php b/phpBB/includes/ucp/ucp_activate.php index da25425e3a..c9dd3e553e 100644 --- a/phpBB/includes/ucp/ucp_activate.php +++ b/phpBB/includes/ucp/ucp_activate.php @@ -131,21 +131,23 @@ class ucp_activate $phpbb_notifications = $phpbb_container->get('notification_manager'); $phpbb_notifications->delete_notifications('notification.type.admin_activate_user', $user_row['user_id']); - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); + $messenger = $phpbb_container->get('messenger.method_collection'); + $messenger_collection_iterator = $messenger->getIterator(); + foreach ($messenger_collection_iterator as $messenger_method) + { + if ($messenger_method->get_id() == $user_row['user_notify_type'] || $user_row['user_notify_type'] == $messenger_method::NOTIFY_BOTH) + { + $messenger_method->set_use_queue(false); + $messenger_method->template('admin_welcome_activated', $user_row['user_lang']); + $messenger_method->set_addresses($user_row); + $messenger_method->anti_abuse_headers($config, $user); + $messenger_method->assign_vars([ + 'USERNAME' => html_entity_decode($user_row['username'], ENT_COMPAT), + ]); - $messenger = new messenger(false); - - $messenger->template('admin_welcome_activated', $user_row['user_lang']); - - $messenger->set_addresses($user_row); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'USERNAME' => html_entity_decode($user_row['username'], ENT_COMPAT)) - ); - - $messenger->send($user_row['user_notify_type']); + $messenger_method->send(); + } + } $message = 'ACCOUNT_ACTIVE_ADMIN'; } diff --git a/phpBB/includes/ucp/ucp_prefs.php b/phpBB/includes/ucp/ucp_prefs.php index 8c682cebc0..d08a81b854 100644 --- a/phpBB/includes/ucp/ucp_prefs.php +++ b/phpBB/includes/ucp/ucp_prefs.php @@ -11,6 +11,8 @@ * */ +use phpbb\messenger\method\messenger_interface; + /** * @ignore */ @@ -52,10 +54,10 @@ class ucp_prefs 'allowpm' => $request->variable('allowpm', (bool) $user->data['user_allow_pm']), ); - if ($data['notifymethod'] == NOTIFY_IM && (!$config['jab_enable'] || !$user->data['user_jabber'] || !@extension_loaded('xml'))) + if ($data['notifymethod'] == messenger_interface::NOTIFY_IM && (!$config['jab_enable'] || !$user->data['user_jabber'] || !@extension_loaded('xml'))) { // Jabber isnt enabled, or no jabber field filled in. Update the users table to be sure its correct. - $data['notifymethod'] = NOTIFY_BOTH; + $data['notifymethod'] = messenger_interface::NOTIFY_BOTH; } /** @@ -182,9 +184,9 @@ class ucp_prefs $template->assign_vars([ 'ERROR' => (count($error)) ? implode('
', $error) : '', - 'S_NOTIFY_EMAIL' => ($data['notifymethod'] == NOTIFY_EMAIL) ? true : false, - 'S_NOTIFY_IM' => ($data['notifymethod'] == NOTIFY_IM) ? true : false, - 'S_NOTIFY_BOTH' => ($data['notifymethod'] == NOTIFY_BOTH) ? true : false, + 'S_NOTIFY_EMAIL' => ($data['notifymethod'] == messenger_interface::NOTIFY_EMAIL) ? true : false, + 'S_NOTIFY_IM' => ($data['notifymethod'] == messenger_interface::NOTIFY_IM) ? true : false, + 'S_NOTIFY_BOTH' => ($data['notifymethod'] == messenger_interface::NOTIFY_BOTH) ? true : false, 'S_VIEW_EMAIL' => $data['viewemail'], 'S_MASS_EMAIL' => $data['massemail'], 'S_ALLOW_PM' => $data['allowpm'], diff --git a/phpBB/includes/ucp/ucp_profile.php b/phpBB/includes/ucp/ucp_profile.php index 36ccd76156..52b007a1fe 100644 --- a/phpBB/includes/ucp/ucp_profile.php +++ b/phpBB/includes/ucp/ucp_profile.php @@ -11,6 +11,8 @@ * */ +use phpbb\messenger\method\messenger_interface; + /** * @ignore */ @@ -170,27 +172,20 @@ class ucp_profile { $message = ($config['require_activation'] == USER_ACTIVATION_SELF) ? 'ACCOUNT_EMAIL_CHANGED' : 'ACCOUNT_EMAIL_CHANGED_ADMIN'; - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - $server_url = generate_board_url(); $user_actkey = gen_rand_string(mt_rand(6, 10)); - $messenger = new messenger(false); - + $email_method = $phpbb_container->get('messenger.method.email'); $template_file = ($config['require_activation'] == USER_ACTIVATION_ADMIN) ? 'user_activate_inactive' : 'user_activate'; - $messenger->template($template_file, $user->data['user_lang']); - - $messenger->to($data['email'], $data['username']); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( + $email_method->template($template_file, $user->data['user_lang']); + $email_method->to($data['email'], $data['username']); + $email_method->anti_abuse_headers($config, $user); + $email_method->assign_vars([ 'USERNAME' => html_entity_decode($data['username'], ENT_COMPAT), - 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user->data['user_id']}&k=$user_actkey") - ); - - $messenger->send(NOTIFY_EMAIL); + 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user->data['user_id']}&k=$user_actkey", + ]); + $email_method->send(); if ($config['require_activation'] == USER_ACTIVATION_ADMIN) { @@ -370,11 +365,11 @@ class ucp_profile { $data['notify'] = $user->data['user_notify_type']; - if ($data['notify'] == NOTIFY_IM && (!$config['jab_enable'] || !$data['jabber'] || !@extension_loaded('xml'))) + if ($data['notify'] == messenger_interface::NOTIFY_IM && (!$config['jab_enable'] || !$data['jabber'] || !@extension_loaded('xml'))) { // User has not filled in a jabber address (Or one of the modules is disabled or jabber is disabled) // Disable notify by Jabber now for this user. - $data['notify'] = NOTIFY_EMAIL; + $data['notify'] = messenger_interface::NOTIFY_EMAIL; } $sql_ary = array( diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php index b8d0d78b40..e5319f1dbb 100644 --- a/phpBB/includes/ucp/ucp_register.php +++ b/phpBB/includes/ucp/ucp_register.php @@ -458,30 +458,26 @@ class ucp_register if ($config['email_enable']) { - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - - $messenger = new messenger(false); - - $messenger->template($email_template, $data['lang']); - - $messenger->to($data['email'], $data['username']); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( + /** var \phpbb\messenger\method\email */ + $email_method = $phpbb_container->get('messenger.method.email'); + $email_method->set_use_queue(false); + $email_method->template($email_template, $data['lang']); + $email_method->to($data['email'], $data['username']); + $email_method->anti_abuse_headers($config, $user); + $email_method->assign_vars([ 'WELCOME_MSG' => html_entity_decode(sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename']), ENT_COMPAT), 'USERNAME' => html_entity_decode($data['username'], ENT_COMPAT), 'PASSWORD' => html_entity_decode($data['new_password'], ENT_COMPAT), - 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u=$user_id&k=$user_actkey") - ); + 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u=$user_id&k=$user_actkey", + ]); if ($coppa) { - $messenger->assign_vars(array( + $email_method->assign_vars([ 'FAX_INFO' => $config['coppa_fax'], 'MAIL_INFO' => $config['coppa_mail'], - 'EMAIL_ADDRESS' => $data['email']) - ); + 'EMAIL_ADDRESS' => $data['email'], + ]); } /** @@ -495,8 +491,9 @@ class ucp_register * @var string server_url Server URL * @var int user_id New user ID * @var string user_actkey User activation key - * @var messenger messenger phpBB Messenger + * @var \phpbb\messenger\method\email email_method phpBB email notification method * @since 3.2.4-RC1 + * @changed 4.0.0-a1 Added vars: email_method. Removed vars: messenger. */ $vars = array( 'user_row', @@ -506,11 +503,11 @@ class ucp_register 'server_url', 'user_id', 'user_actkey', - 'messenger', + 'email_method', ); extract($phpbb_dispatcher->trigger_event('core.ucp_register_welcome_email_before', compact($vars))); - $messenger->send(NOTIFY_EMAIL); + $email_method->send(); } if ($config['require_activation'] == USER_ACTIVATION_ADMIN) diff --git a/phpBB/includes/ucp/ucp_resend.php b/phpBB/includes/ucp/ucp_resend.php index 31e0878663..76e748e85d 100644 --- a/phpBB/includes/ucp/ucp_resend.php +++ b/phpBB/includes/ucp/ucp_resend.php @@ -30,7 +30,7 @@ class ucp_resend function main($id, $mode) { global $config, $phpbb_root_path, $phpEx; - global $db, $user, $auth, $template, $request; + global $db, $user, $auth, $template, $request, $phpbb_container; $username = $request->variable('username', '', true); $email = strtolower($request->variable('email', '')); @@ -92,34 +92,35 @@ class ucp_resend trigger_error('NO_GROUP'); } + $board_url = generate_board_url(); $coppa = ($row['group_name'] == 'REGISTERED_COPPA' && $row['group_type'] == GROUP_SPECIAL) ? true : false; - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - $messenger = new messenger(false); + $email_method = $phpbb_container->get('messenger.method.email'); + $email_method->set_use_queue(false); if ($config['require_activation'] == USER_ACTIVATION_SELF || $coppa) { - $messenger->template(($coppa) ? 'coppa_resend_inactive' : 'user_resend_inactive', $user_row['user_lang']); - $messenger->set_addresses($user_row); + $email_method->template(($coppa) ? 'coppa_resend_inactive' : 'user_resend_inactive', $user_row['user_lang']); + $email_method->set_addresses($user_row); - $messenger->anti_abuse_headers($config, $user); + $email_method->anti_abuse_headers($config, $user); - $messenger->assign_vars(array( + $email_method->assign_vars([ 'WELCOME_MSG' => html_entity_decode(sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename']), ENT_COMPAT), 'USERNAME' => html_entity_decode($user_row['username'], ENT_COMPAT), - 'U_ACTIVATE' => generate_board_url() . "/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k={$user_row['user_actkey']}") - ); + 'U_ACTIVATE' => $board_url . "/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k={$user_row['user_actkey']}", + ]); if ($coppa) { - $messenger->assign_vars(array( + $email_method->assign_vars([ 'FAX_INFO' => $config['coppa_fax'], 'MAIL_INFO' => $config['coppa_mail'], - 'EMAIL_ADDRESS' => $user_row['user_email']) - ); + 'EMAIL_ADDRESS' => $user_row['user_email'], + ]); } - $messenger->send(NOTIFY_EMAIL); + $email_method->send(); } if ($config['require_activation'] == USER_ACTIVATION_ADMIN) @@ -132,22 +133,36 @@ class ucp_resend WHERE ' . $db->sql_in_set('user_id', $admin_ary[0]['a_user']); $result = $db->sql_query($sql); + /** @var \phpbb\di\service_collection */ + $messenger = $phpbb_container->get('messenger.method_collection'); + $messenger_collection_iterator = $messenger->getIterator(); while ($row = $db->sql_fetchrow($result)) { - $messenger->template('admin_activate', $row['user_lang']); - $messenger->set_addresses($row); + foreach ($messenger_collection_iterator as $messenger_method) + { + $messenger_method->set_use_queue(false); + if ($messenger_method->get_id() == $row['user_notify_type'] || $row['user_notify_type'] == $messenger_method::NOTIFY_BOTH) + { + $messenger_method->template('admin_activate', $row['user_lang']); + $messenger_method->set_addresses($row); + $messenger_method->anti_abuse_headers($config, $user); + $messenger_method->assign_vars([ + 'USERNAME' => html_entity_decode($user_row['username'], ENT_COMPAT), + 'U_USER_DETAILS' => $board_url . "/memberlist.$phpEx?mode=viewprofile&u={$user_row['user_id']}", + 'U_ACTIVATE' => $board_url . "/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k={$user_row['user_actkey']}", + ]); - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'USERNAME' => html_entity_decode($user_row['username'], ENT_COMPAT), - 'U_USER_DETAILS' => generate_board_url() . "/memberlist.$phpEx?mode=viewprofile&u={$user_row['user_id']}", - 'U_ACTIVATE' => generate_board_url() . "/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k={$user_row['user_actkey']}") - ); - - $messenger->send($row['user_notify_type']); + $messenger_method->send(); + } + } } $db->sql_freeresult($result); + + // Save the queue in the messenger method class (has to be called or these messages could be lost) + foreach ($messenger_collection_iterator as $messenger_method) + { + $messenger_method->save_queue(); + } } $this->update_activation_expiration(); diff --git a/phpBB/install/convertors/convert_phpbb20.php b/phpBB/install/convertors/convert_phpbb20.php index 864e6f3b6e..8750c24dcc 100644 --- a/phpBB/install/convertors/convert_phpbb20.php +++ b/phpBB/install/convertors/convert_phpbb20.php @@ -11,6 +11,8 @@ * */ +use phpbb\messenger\method\messenger_interface; + /** * NOTE to potential convertor authors. Please use this file to get * familiar with the structure since we added some bare explanations here. @@ -936,7 +938,7 @@ if (!$get_info) array('user_emailtime', 'users.user_emailtime', 'null_to_zero'), array('user_notify', 'users.user_notify', 'intval'), array('user_notify_pm', 'users.user_notify_pm', 'intval'), - array('user_notify_type', NOTIFY_EMAIL, ''), + array('user_notify_type', $messenger_method::NOTIFY_EMAIL, ''), array('user_allow_pm', 'users.user_allow_pm', 'intval'), array('user_allow_viewonline', 'users.user_allow_viewonline', 'intval'), array('user_allow_viewemail', 'users.user_viewemail', 'intval'), diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql index 21b26ee9c8..43b8f95fc8 100644 --- a/phpBB/install/schemas/schema_data.sql +++ b/phpBB/install/schemas/schema_data.sql @@ -287,7 +287,6 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('sitename_short', ' INSERT INTO phpbb_config (config_name, config_value) VALUES ('smilies_path', 'images/smilies'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('smilies_per_page', '50'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('smtp_allow_self_signed', '0'); -INSERT INTO phpbb_config (config_name, config_value) VALUES ('smtp_auth_method', 'PLAIN'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('smtp_delivery', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('smtp_host', ''); INSERT INTO phpbb_config (config_name, config_value) VALUES ('smtp_port', '25'); diff --git a/phpBB/language/en/acp/board.php b/phpBB/language/en/acp/board.php index 633df91138..e46091c954 100644 --- a/phpBB/language/en/acp/board.php +++ b/phpBB/language/en/acp/board.php @@ -553,15 +553,8 @@ $lang = array_merge($lang, array( 'SEND_TEST_EMAIL_EXPLAIN' => 'This will send a test email to the address defined in your account.', 'SMTP_ALLOW_SELF_SIGNED' => 'Allow self-signed SSL certificates', 'SMTP_ALLOW_SELF_SIGNED_EXPLAIN'=> 'Allow connections to SMTP server with self-signed SSL certificate.
Warning: Allowing self-signed SSL certificates may cause security implications.', - 'SMTP_AUTH_METHOD' => 'Authentication method for SMTP', - 'SMTP_AUTH_METHOD_EXPLAIN' => 'Only used if a username/password is set, ask your provider if you are unsure which method to use.', - 'SMTP_CRAM_MD5' => 'CRAM-MD5', - 'SMTP_DIGEST_MD5' => 'DIGEST-MD5', - 'SMTP_LOGIN' => 'LOGIN', 'SMTP_PASSWORD' => 'SMTP password', 'SMTP_PASSWORD_EXPLAIN' => 'Only enter a password if your SMTP server requires it.
Warning: This password will be stored as plain text in the database, visible to everybody who can access your database or who can view this configuration page.', - 'SMTP_PLAIN' => 'PLAIN', - 'SMTP_POP_BEFORE_SMTP' => 'POP-BEFORE-SMTP', 'SMTP_PORT' => 'SMTP server port', 'SMTP_PORT_EXPLAIN' => 'Only change this if you know your SMTP server is on a different port.', 'SMTP_SERVER' => 'SMTP server address', diff --git a/phpBB/memberlist.php b/phpBB/memberlist.php index 28b1adbdee..aa15cdd6be 100644 --- a/phpBB/memberlist.php +++ b/phpBB/memberlist.php @@ -428,8 +428,6 @@ switch ($mode) if (check_form_key('memberlist_messaging')) { - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - $subject = sprintf($user->lang['IM_JABBER_SUBJECT'], $user->data['username'], $config['server_name']); $message = $request->variable('message', '', true); @@ -438,22 +436,21 @@ switch ($mode) trigger_error('EMPTY_MESSAGE_IM'); } - $messenger = new messenger(false); + $jabber = $phpbb_container->get('messenger.method.jabber'); + $jabber->set_use_queue(false); - $messenger->template('profile_send_im', $row['user_lang']); - $messenger->subject(html_entity_decode($subject, ENT_COMPAT)); + $jabber->template('profile_send_im', $row['user_lang']); + $jabber->subject(html_entity_decode($subject, ENT_COMPAT)); + $jabber->set_addresses($row); - $messenger->replyto($user->data['user_email']); - $messenger->set_addresses($row); - - $messenger->assign_vars(array( + $jabber->assign_vars([ 'BOARD_CONTACT' => phpbb_get_board_contact($config, $phpEx), 'FROM_USERNAME' => html_entity_decode($user->data['username'], ENT_COMPAT), 'TO_USERNAME' => html_entity_decode($row['username'], ENT_COMPAT), - 'MESSAGE' => html_entity_decode($message, ENT_COMPAT)) - ); + 'MESSAGE' => html_entity_decode($message, ENT_COMPAT), + ]); - $messenger->send(NOTIFY_IM); + $jabber->send(); $s_select = 'S_SENT_JABBER'; } @@ -903,10 +900,7 @@ switch ($mode) case 'contactadmin': case 'email': - if (!class_exists('messenger')) - { - include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - } + $messenger = $phpbb_container->get('messenger.method_collection'); $user_id = $request->variable('u', 0); $topic_id = $request->variable('t', 0); @@ -940,7 +934,6 @@ switch ($mode) if ($request->is_set_post('submit')) { - $messenger = new messenger(false); $form->submit($messenger); } diff --git a/phpBB/phpbb/console/command/user/activate.php b/phpBB/phpbb/console/command/user/activate.php index 1d635b46dc..9fa0f4182b 100644 --- a/phpBB/phpbb/console/command/user/activate.php +++ b/phpBB/phpbb/console/command/user/activate.php @@ -17,6 +17,7 @@ use phpbb\config\config; use phpbb\console\command\command; use phpbb\language\language; use phpbb\log\log_interface; +use phpbb\messenger\method\email; use phpbb\notification\manager; use phpbb\user; use phpbb\user_loader; @@ -32,6 +33,9 @@ class activate extends command /** @var config */ protected $config; + /** @var email */ + protected $email_method; + /** @var language */ protected $language; @@ -65,14 +69,16 @@ class activate extends command * @param config $config * @param language $language * @param log_interface $log + * @param email $email_method * @param manager $notifications * @param user_loader $user_loader * @param string $phpbb_root_path * @param string $php_ext */ - public function __construct(user $user, config $config, language $language, log_interface $log, manager $notifications, user_loader $user_loader, $phpbb_root_path, $php_ext) + public function __construct(user $user, config $config, language $language, log_interface $log, email $email_method, manager $notifications, user_loader $user_loader, $phpbb_root_path, $php_ext) { $this->config = $config; + $this->email_method = $email_method; $this->language = $language; $this->log = $log; $this->notifications = $notifications; @@ -194,20 +200,14 @@ class activate extends command if ($input->getOption('send-email')) { - if (!class_exists('messenger')) - { - require($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext); - } - - $messenger = new \messenger(false); - $messenger->template('admin_welcome_activated', $user_row['user_lang']); - $messenger->set_addresses($user_row); - $messenger->anti_abuse_headers($this->config, $this->user); - $messenger->assign_vars(array( - 'USERNAME' => html_entity_decode($user_row['username'], ENT_COMPAT)) - ); - - $messenger->send(NOTIFY_EMAIL); + $this->email_method->set_use_queue(false); + $this->email_method->template('admin_welcome_activated', $user_row['user_lang']); + $this->email_method->set_addresses($user_row); + $this->email_method->anti_abuse_headers($this->config, $this->user); + $this->email_method->assign_vars([ + 'USERNAME' => html_entity_decode($user_row['username'], ENT_COMPAT), + ]); + $this->email_method->send(); } } } diff --git a/phpBB/phpbb/console/command/user/add.php b/phpBB/phpbb/console/command/user/add.php index c01aac7cb6..aeb0ee87eb 100644 --- a/phpBB/phpbb/console/command/user/add.php +++ b/phpBB/phpbb/console/command/user/add.php @@ -18,6 +18,7 @@ use phpbb\console\command\command; use phpbb\db\driver\driver_interface; use phpbb\exception\runtime_exception; use phpbb\language\language; +use phpbb\messenger\method\email; use phpbb\passwords\manager; use phpbb\user; use Symfony\Component\Console\Command\Command as symfony_command; @@ -39,6 +40,9 @@ class add extends command /** @var config */ protected $config; + /** @var email */ + protected $email_method; + /** @var language */ protected $language; @@ -66,14 +70,16 @@ class add extends command * @param driver_interface $db * @param config $config * @param language $language + * @param service_collection $messenger * @param manager $password_manager * @param string $phpbb_root_path * @param string $php_ext */ - public function __construct(user $user, driver_interface $db, config $config, language $language, manager $password_manager, $phpbb_root_path, $php_ext) + public function __construct(user $user, driver_interface $db, config $config, language $language, email $email_method, manager $password_manager, $phpbb_root_path, $php_ext) { - $this->db = $db; $this->config = $config; + $this->db = $db; + $this->email_method = $email_method; $this->language = $language; $this->password_manager = $password_manager; $this->phpbb_root_path = $phpbb_root_path; @@ -307,23 +313,17 @@ class add extends command $user_actkey = $this->get_activation_key($user_id); - if (!class_exists('messenger')) - { - require($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext); - } - - $messenger = new \messenger(false); - $messenger->template($email_template, $this->user->lang_name); - $messenger->to($this->data['email'], $this->data['username']); - $messenger->anti_abuse_headers($this->config, $this->user); - $messenger->assign_vars(array( + $this->email_method->set_use_queue(false); + $this->email_method->template($email_template, $this->user->lang_name); + $this->email_method->to($this->data['email'], $this->data['username']); + $this->email_method->anti_abuse_headers($this->config, $this->user); + $this->email_method->assign_vars([ 'WELCOME_MSG' => html_entity_decode($this->language->lang('WELCOME_SUBJECT', $this->config['sitename']), ENT_COMPAT), 'USERNAME' => html_entity_decode($this->data['username'], ENT_COMPAT), 'PASSWORD' => html_entity_decode($this->data['new_password'], ENT_COMPAT), - 'U_ACTIVATE' => generate_board_url() . "/ucp.{$this->php_ext}?mode=activate&u=$user_id&k=$user_actkey") - ); - - $messenger->send(NOTIFY_EMAIL); + 'U_ACTIVATE' => generate_board_url() . "/ucp.{$this->php_ext}?mode=activate&u=$user_id&k=$user_actkey", + ]); + $this->email_method->send(); } /** diff --git a/phpBB/phpbb/cron/task/core/queue.php b/phpBB/phpbb/cron/task/core/queue.php index 2f0d91d046..9395a538de 100644 --- a/phpBB/phpbb/cron/task/core/queue.php +++ b/phpBB/phpbb/cron/task/core/queue.php @@ -13,30 +13,34 @@ namespace phpbb\cron\task\core; +use phpbb\config\config; + /** * Queue cron task. Sends email and jabber messages queued by other scripts. */ class queue extends \phpbb\cron\task\base { - protected $phpbb_root_path; - protected $php_ext; - protected $cache_dir; + /** var config */ protected $config; + /** var \phpbb\messenger\queue */ + protected $queue; + + /** var string */ + protected $queue_cache_file; + /** * Constructor. * - * @param string $phpbb_root_path The root path - * @param string $php_ext PHP file extension - * @param \phpbb\config\config $config The config - * @param string $cache_dir phpBB cache directory + * @param config $config The config + * @param string $queue_cache_file The messenger file queue cache filename + * @param \phpbb\messenger\queue $queue The messenger file queue object */ - public function __construct($phpbb_root_path, $php_ext, \phpbb\config\config $config, $cache_dir) + public function __construct(config $config, \phpbb\messenger\queue $queue, $queue_cache_file) { - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; $this->config = $config; - $this->cache_dir = $cache_dir; + $this->queue = $queue; + $this->queue_cache_file = $queue_cache_file; } /** @@ -46,12 +50,7 @@ class queue extends \phpbb\cron\task\base */ public function run() { - if (!class_exists('queue')) - { - include($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext); - } - $queue = new \queue(); - $queue->process(); + $this->queue->process(); } /** @@ -63,7 +62,7 @@ class queue extends \phpbb\cron\task\base */ public function is_runnable() { - return file_exists($this->cache_dir . 'queue.' . $this->php_ext); + return file_exists($this->queue_cache_file); } /** diff --git a/phpBB/phpbb/db/migration/data/v310/notification_options_reconvert.php b/phpBB/phpbb/db/migration/data/v310/notification_options_reconvert.php index 7c03eef347..7f58076a8d 100644 --- a/phpBB/phpbb/db/migration/data/v310/notification_options_reconvert.php +++ b/phpBB/phpbb/db/migration/data/v310/notification_options_reconvert.php @@ -13,6 +13,8 @@ namespace phpbb\db\migration\data\v310; +use phpbb\messenger\method\messenger_interface; + class notification_options_reconvert extends \phpbb\db\migration\migration { public static function depends_on() @@ -67,12 +69,12 @@ class notification_options_reconvert extends \phpbb\db\migration\migration // In-board notification $notification_methods[] = ''; - if ($row['user_notify_type'] == NOTIFY_EMAIL || $row['user_notify_type'] == NOTIFY_BOTH) + if ($row['user_notify_type'] == messenger_interface::NOTIFY_EMAIL || $row['user_notify_type'] == messenger_interface::NOTIFY_BOTH) { $notification_methods[] = 'email'; } - if ($row['user_notify_type'] == NOTIFY_IM || $row['user_notify_type'] == NOTIFY_BOTH) + if ($row['user_notify_type'] == messenger_interface::NOTIFY_IM || $row['user_notify_type'] == messenger_interface::NOTIFY_BOTH) { $notification_methods[] = 'jabber'; } diff --git a/phpBB/phpbb/db/migration/data/v400/remove_smtp_auth_method.php b/phpBB/phpbb/db/migration/data/v400/remove_smtp_auth_method.php new file mode 100644 index 0000000000..830307c1e8 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v400/remove_smtp_auth_method.php @@ -0,0 +1,45 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v400; + +use phpbb\db\migration\migration; + +class remove_smtp_auth_method extends migration +{ + public function effectively_installed() + { + return !$this->config->offsetExists('smtp_auth_method'); + } + + public static function depends_on() + { + return [ + '\phpbb\db\migration\data\v400\dev', + ]; + } + + public function update_data() + { + return [ + ['config.remove', ['smtp_auth_method']], + ]; + } + + public function revert_data() + { + return [ + ['config.add', ['smtp_auth_method', 'PLAIN']], + ]; + } +} diff --git a/phpBB/phpbb/install/console/command/install/install.php b/phpBB/phpbb/install/console/command/install/install.php index 84c8aa688a..6641f9b944 100644 --- a/phpBB/phpbb/install/console/command/install/install.php +++ b/phpBB/phpbb/install/console/command/install/install.php @@ -195,7 +195,6 @@ class install extends \phpbb\console\command\command $iohandler->set_input('smtp_delivery', $config['email']['smtp_delivery']); $iohandler->set_input('smtp_host', $config['email']['smtp_host']); $iohandler->set_input('smtp_port', $config['email']['smtp_port']); - $iohandler->set_input('smtp_auth', $config['email']['smtp_auth']); $iohandler->set_input('smtp_user', $config['email']['smtp_user']); $iohandler->set_input('smtp_pass', $config['email']['smtp_pass']); $iohandler->set_input('submit_email', 'submit'); diff --git a/phpBB/phpbb/install/installer_configuration.php b/phpBB/phpbb/install/installer_configuration.php index 974080dc55..f1051095e2 100644 --- a/phpBB/phpbb/install/installer_configuration.php +++ b/phpBB/phpbb/install/installer_configuration.php @@ -97,9 +97,6 @@ class installer_configuration implements ConfigurationInterface ->scalarNode('smtp_port') ->defaultValue(null) ->end() - ->scalarNode('smtp_auth') - ->defaultValue(null) - ->end() ->scalarNode('smtp_user') ->defaultValue(null) ->end() diff --git a/phpBB/phpbb/install/module/install_database/task/add_config_settings.php b/phpBB/phpbb/install/module/install_database/task/add_config_settings.php index 5b9a9da536..14c88a04d3 100644 --- a/phpBB/phpbb/install/module/install_database/task/add_config_settings.php +++ b/phpBB/phpbb/install/module/install_database/task/add_config_settings.php @@ -150,7 +150,6 @@ class add_config_settings extends database_task 'smtp_delivery' => $this->install_config->get('smtp_delivery'), 'smtp_host' => $this->install_config->get('smtp_host'), 'smtp_port' => $this->install_config->get('smtp_port'), - 'smtp_auth_method' => $this->install_config->get('smtp_auth'), 'smtp_username' => $this->install_config->get('smtp_user'), 'smtp_password' => $this->install_config->get('smtp_pass'), diff --git a/phpBB/phpbb/install/module/install_finish/task/notify_user.php b/phpBB/phpbb/install/module/install_finish/task/notify_user.php index 6fb7bc2743..ff575130a4 100644 --- a/phpBB/phpbb/install/module/install_finish/task/notify_user.php +++ b/phpBB/phpbb/install/module/install_finish/task/notify_user.php @@ -14,62 +14,52 @@ namespace phpbb\install\module\install_finish\task; use phpbb\config\db; +use phpbb\install\helper\config; +use phpbb\install\helper\iohandler\iohandler_interface; +use phpbb\auth\auth; +use phpbb\log\log_interface; +use phpbb\user; +use phpbb\install\helper\container_factory; +use phpbb\messenger\method\email; /** * Logs installation and sends an email to the admin */ class notify_user extends \phpbb\install\task_base { - /** - * @var \phpbb\install\helper\config - */ + /** @var config */ protected $install_config; - /** - * @var \phpbb\install\helper\iohandler\iohandler_interface - */ + /** @var iohandler_interface */ protected $iohandler; - /** - * @var \phpbb\auth\auth - */ + /** @var auth */ protected $auth; - /** - * @var db - */ + /** @var db */ protected $config; - /** - * @var \phpbb\log\log_interface - */ + /** @var email */ + protected $email_method; + + /** @var log_interface */ protected $log; - /** - * @var \phpbb\user - */ - protected $user; - - /** - * @var string - */ + /** @var string */ protected $phpbb_root_path; - /** - * @var string - */ - protected $php_ext; + /** @var user */ + protected $user; /** * Constructor * - * @param \phpbb\install\helper\container_factory $container - * @param \phpbb\install\helper\config $install_config - * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler - * @param string $phpbb_root_path - * @param string $php_ext + * @param container_factory $container + * @param config $install_config + * @param iohandler_interface $iohandler + * @param string $phpbb_root_path */ - public function __construct(\phpbb\install\helper\container_factory $container, \phpbb\install\helper\config $install_config, \phpbb\install\helper\iohandler\iohandler_interface $iohandler, $phpbb_root_path, $php_ext) + public function __construct(container_factory $container, config $install_config, iohandler_interface $iohandler, $phpbb_root_path) { $this->install_config = $install_config; $this->iohandler = $iohandler; @@ -77,8 +67,8 @@ class notify_user extends \phpbb\install\task_base $this->auth = $container->get('auth'); $this->log = $container->get('log'); $this->user = $container->get('user'); + $this->email_method = $container->get('messenger.method.email'); $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; // We need to reload config for cases when it doesn't have all values /** @var \phpbb\cache\driver\driver_interface $cache */ @@ -107,17 +97,15 @@ class notify_user extends \phpbb\install\task_base if ($this->config['email_enable']) { - include ($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext); - - $messenger = new \messenger(false); - $messenger->template('installed', $this->install_config->get('user_language', 'en')); - $messenger->to($this->config['board_email'], $this->install_config->get('admin_name')); - $messenger->anti_abuse_headers($this->config, $this->user); - $messenger->assign_vars(array( - 'USERNAME' => html_entity_decode($this->install_config->get('admin_name'), ENT_COMPAT), - 'PASSWORD' => html_entity_decode($this->install_config->get('admin_passwd'), ENT_COMPAT)) - ); - $messenger->send(NOTIFY_EMAIL); + $this->email_method->set_use_queue(false); + $this->email_method->template('installed', $this->install_config->get('user_language', 'en')); + $this->email_method->to($this->config['board_email'], $this->install_config->get('admin_name')); + $this->email_method->anti_abuse_headers($this->config, $this->user); + $this->email_method->assign_vars([ + 'USERNAME' => html_entity_decode($this->install_config->get('admin_name'), ENT_COMPAT), + 'PASSWORD' => html_entity_decode($this->install_config->get('admin_passwd'), ENT_COMPAT), + ]); + $this->email_method->send(); } // Login admin @@ -141,7 +129,7 @@ class notify_user extends \phpbb\install\task_base $this->user->ip, 'LOG_INSTALL_INSTALLED', false, - array($this->config['version']) + [$this->config['version']] ); // Remove install_lock diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_email_data.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_email_data.php index 93c0eb385e..3c6508f6a7 100644 --- a/phpBB/phpbb/install/module/obtain_data/task/obtain_email_data.php +++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_email_data.php @@ -52,12 +52,9 @@ class obtain_email_data extends \phpbb\install\task_base implements \phpbb\insta $smtp_delivery = $this->io_handler->get_input('smtp_delivery', ''); $smtp_host = $this->io_handler->get_input('smtp_host', '', true); $smtp_port = $this->io_handler->get_input('smtp_port', ''); - $smtp_auth = $this->io_handler->get_input('smtp_auth', ''); $smtp_user = $this->io_handler->get_input('smtp_user', '', true); $smtp_passwd = $this->io_handler->get_input('smtp_pass', '', true); - $auth_methods = array('PLAIN', 'LOGIN', 'CRAM-MD5', 'DIGEST-MD5', 'POP-BEFORE-SMTP'); - // Check if data is sent if ($this->io_handler->get_input('submit_email', false)) { @@ -65,22 +62,11 @@ class obtain_email_data extends \phpbb\install\task_base implements \phpbb\insta $this->install_config->set('smtp_delivery', $smtp_delivery); $this->install_config->set('smtp_host', $smtp_host); $this->install_config->set('smtp_port', $smtp_port); - $this->install_config->set('smtp_auth', $smtp_auth); $this->install_config->set('smtp_user', $smtp_user); $this->install_config->set('smtp_pass', $smtp_passwd); } else { - $auth_options = array(); - foreach ($auth_methods as $method) - { - $auth_options[] = array( - 'value' => $method, - 'label' => 'SMTP_' . str_replace('-', '_', $method), - 'selected' => false, - ); - } - $email_form = array( 'email_enable' => array( 'label' => 'ENABLE_EMAIL', @@ -126,12 +112,6 @@ class obtain_email_data extends \phpbb\install\task_base implements \phpbb\insta 'type' => 'text', 'default' => $smtp_port, ), - 'smtp_auth' => array( - 'label' => 'SMTP_AUTH_METHOD', - 'description' => 'SMTP_AUTH_METHOD_EXPLAIN', - 'type' => 'select', - 'options' => $auth_options, - ), 'smtp_user' => array( 'label' => 'SMTP_USERNAME', 'description' => 'SMTP_USERNAME_EXPLAIN', diff --git a/phpBB/phpbb/message/admin_form.php b/phpBB/phpbb/message/admin_form.php index ae1c1d8614..72beaa38a6 100644 --- a/phpBB/phpbb/message/admin_form.php +++ b/phpBB/phpbb/message/admin_form.php @@ -13,6 +13,8 @@ namespace phpbb\message; +use phpbb\messenger\method\messenger_interface; + /** * Class admin_form * Displays a message to the user and allows him to send an email @@ -85,7 +87,7 @@ class admin_form extends form /** * {inheritDoc} */ - public function submit(\messenger $messenger) + public function submit(\phpbb\di\service_collection $messenger) { if (!$this->subject) { @@ -155,7 +157,7 @@ class admin_form extends form } $this->message->set_sender($this->user->ip, $this->sender_name, $this->sender_address, $this->user->lang_name); - $this->message->set_sender_notify_type(NOTIFY_EMAIL); + $this->message->set_sender_notify_type(messenger_interface::NOTIFY_EMAIL); } $this->message->set_template('contact_admin'); @@ -165,7 +167,7 @@ class admin_form extends form $this->user->lang['ADMINISTRATOR'], $this->config['board_contact'], $this->config['default_lang'], - NOTIFY_EMAIL + messenger_interface::NOTIFY_EMAIL ); $this->message->set_template_vars(array( diff --git a/phpBB/phpbb/message/form.php b/phpBB/phpbb/message/form.php index c23b168906..479d687212 100644 --- a/phpBB/phpbb/message/form.php +++ b/phpBB/phpbb/message/form.php @@ -129,10 +129,10 @@ abstract class form /** * Submit form, generate the email and send it * - * @param \messenger $messenger + * @param \phpbb\di\service_collection $messenger * @return void */ - public function submit(\messenger $messenger) + public function submit(\phpbb\di\service_collection $messenger) { if (!check_form_key('memberlist_email')) { diff --git a/phpBB/phpbb/message/message.php b/phpBB/phpbb/message/message.php index d77f56c73f..90b8a1ff5f 100644 --- a/phpBB/phpbb/message/message.php +++ b/phpBB/phpbb/message/message.php @@ -13,6 +13,8 @@ namespace phpbb\message; +use phpbb\messenger\method\messenger_interface; + /** * Class message * Holds all information for an email and sends it in the end @@ -46,7 +48,7 @@ class message /** @var string */ protected $sender_jabber = ''; /** @var int */ - protected $sender_notify_type = NOTIFY_EMAIL; + protected $sender_notify_type = messenger_interface::NOTIFY_EMAIL; /** @var array */ protected $recipients; @@ -134,14 +136,14 @@ class message * @param string $recipient_jabber * @return void */ - public function add_recipient($recipient_name, $recipient_address, $recipient_lang, $recipient_notify_type = NOTIFY_EMAIL, $recipient_username = '', $recipient_jabber = '') + public function add_recipient($recipient_name, $recipient_address, $recipient_lang, $recipient_notify_type = messenger_interface::NOTIFY_EMAIL, $recipient_username = '', $recipient_jabber = '') { $this->recipients[] = array( 'name' => $recipient_name, - 'address' => $recipient_address, + 'user_email' => $recipient_address, 'lang' => $recipient_lang, 'username' => $recipient_username, - 'jabber' => $recipient_jabber, + 'user_jabber' => $recipient_jabber, 'notify_type' => $recipient_notify_type, 'to_name' => $recipient_name, ); @@ -220,10 +222,10 @@ class message $this->recipients[] = array( 'lang' => $this->sender_lang, - 'address' => $this->sender_address, + 'user_email' => $this->sender_address, 'name' => $this->sender_name, 'username' => $this->sender_username, - 'jabber' => $this->sender_jabber, + 'user_jabber' => $this->sender_jabber, 'notify_type' => $this->sender_notify_type, 'to_name' => $this->recipients[0]['to_name'], ); @@ -232,11 +234,11 @@ class message /** * Send the email * - * @param \messenger $messenger + * @param \phpbb\di\service_collection $messenger * @param string $contact * @return void */ - public function send(\messenger $messenger, $contact) + public function send(\phpbb\di\service_collection $messenger, $contact) { if (!count($this->recipients)) { @@ -245,38 +247,45 @@ class message foreach ($this->recipients as $recipient) { - $messenger->template($this->template, $recipient['lang']); - $messenger->replyto($this->sender_address); - $messenger->to($recipient['address'], $recipient['name']); - $messenger->im($recipient['jabber'], $recipient['username']); - - $messenger->headers('X-AntiAbuse: Board servername - ' . $this->server_name); - $messenger->headers('X-AntiAbuse: User IP - ' . $this->sender_ip); - - if ($this->sender_id) + /** @psalm-suppress InvalidTemplateParam */ + $messenger_collection_iterator = $messenger->getIterator(); + foreach ($messenger_collection_iterator as $messenger_method) { - $messenger->headers('X-AntiAbuse: User_id - ' . $this->sender_id); + $messenger_method->set_use_queue(false); + if ($messenger_method->get_id() == $recipient['notify_type'] || $recipient['notify_type'] == $messenger_method::NOTIFY_BOTH) + { + $messenger_method->template($this->template, $recipient['lang']); + $messenger_method->set_addresses($recipient); + $messenger_method->reply_to($this->sender_address); + + $messenger_method->header('X-AntiAbuse', 'Board servername - ' . $this->server_name); + $messenger_method->header('X-AntiAbuse', 'User IP - ' . $this->sender_ip); + if ($this->sender_id) + { + $messenger_method->header('X-AntiAbuse', 'User_id - ' . $this->sender_id); + } + if ($this->sender_username) + { + $messenger_method->header('X-AntiAbuse', 'Username - ' . $this->sender_username); + } + + $messenger_method->subject(html_entity_decode($this->subject, ENT_COMPAT)); + + $messenger_method->assign_vars([ + 'BOARD_CONTACT' => $contact, + 'TO_USERNAME' => html_entity_decode($recipient['to_name'], ENT_COMPAT), + 'FROM_USERNAME' => html_entity_decode($this->sender_name, ENT_COMPAT), + 'MESSAGE' => html_entity_decode($this->body, ENT_COMPAT), + ]); + + if (count($this->template_vars)) + { + $messenger_method->assign_vars($this->template_vars); + } + + $messenger_method->send(); + } } - if ($this->sender_username) - { - $messenger->headers('X-AntiAbuse: Username - ' . $this->sender_username); - } - - $messenger->subject(html_entity_decode($this->subject, ENT_COMPAT)); - - $messenger->assign_vars(array( - 'BOARD_CONTACT' => $contact, - 'TO_USERNAME' => html_entity_decode($recipient['to_name'], ENT_COMPAT), - 'FROM_USERNAME' => html_entity_decode($this->sender_name, ENT_COMPAT), - 'MESSAGE' => html_entity_decode($this->body, ENT_COMPAT)) - ); - - if (count($this->template_vars)) - { - $messenger->assign_vars($this->template_vars); - } - - $messenger->send($recipient['notify_type']); } } } diff --git a/phpBB/phpbb/message/topic_form.php b/phpBB/phpbb/message/topic_form.php index e8344417ef..dd73a67ab2 100644 --- a/phpBB/phpbb/message/topic_form.php +++ b/phpBB/phpbb/message/topic_form.php @@ -13,6 +13,8 @@ namespace phpbb\message; +use phpbb\messenger\method\messenger_interface; + /** * Class topic_form * Form used to send topics as notification emails @@ -108,7 +110,7 @@ class topic_form extends form /** * {inheritDoc} */ - public function submit(\messenger $messenger) + public function submit(\phpbb\di\service_collection $messenger) { if (!$this->recipient_address || !preg_match('/^' . get_preg_expression('email') . '$/i', $this->recipient_address)) { @@ -130,9 +132,9 @@ class topic_form extends form $this->recipient_name, $this->recipient_address, $this->recipient_lang, - NOTIFY_EMAIL + messenger_interface::NOTIFY_EMAIL ); - $this->message->set_sender_notify_type(NOTIFY_EMAIL); + $this->message->set_sender_notify_type(messenger_interface::NOTIFY_EMAIL); parent::submit($messenger); } diff --git a/phpBB/phpbb/message/user_form.php b/phpBB/phpbb/message/user_form.php index 007e575407..46a012297d 100644 --- a/phpBB/phpbb/message/user_form.php +++ b/phpBB/phpbb/message/user_form.php @@ -96,7 +96,7 @@ class user_form extends form /** * {inheritDoc} */ - public function submit(\messenger $messenger) + public function submit(\phpbb\di\service_collection $messenger) { if (!$this->subject) { diff --git a/phpBB/phpbb/messenger/method/base.php b/phpBB/phpbb/messenger/method/base.php new file mode 100644 index 0000000000..46d676013c --- /dev/null +++ b/phpBB/phpbb/messenger/method/base.php @@ -0,0 +1,484 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\messenger\method; + +use phpbb\config\config; +use phpbb\di\service_collection; +use phpbb\event\dispatcher; +use phpbb\extension\manager; +use phpbb\language\language; +use phpbb\log\log_interface; +use phpbb\path_helper; +use phpbb\request\request; +use phpbb\messenger\queue; +use phpbb\template\assets_bag; +use phpbb\template\twig\lexer; +use phpbb\user; + +/** + * Messenger base class + */ +abstract class base implements messenger_interface +{ + /** @var array */ + protected $additional_headers = []; + + /** @var assets_bag */ + protected $assets_bag; + + /** @var config */ + protected $config; + + /** @var dispatcher */ + protected $dispatcher; + + /** @var manager */ + protected $ext_manager; + + /** @var language */ + protected $language; + + /** @var log_interface */ + protected $log; + + /** @var string */ + protected $msg = ''; + + /** @var queue */ + protected $queue; + + /** @var path_helper */ + protected $path_helper; + + /** @var request */ + protected $request; + + /** @var string */ + protected $root_path; + + /** @var string */ + protected $subject = ''; + + /** @var \phpbb\template\template */ + protected $template; + + /** @var string */ + protected $template_cache_path; + + /** @var service_collection */ + protected $twig_extensions_collection; + + /** @var lexer */ + protected $twig_lexer; + + /** @var bool */ + protected $use_queue = true; + + /** @var user */ + protected $user; + + /** + * Messenger base class constructor + * + * @param assets_bag $assets_bag + * @param config $config + * @param dispatcher $dispatcher + * @param language $language + * @param queue $queue + * @param path_helper $path_helper + * @param request $request + * @param service_collection $twig_extensions_collection + * @param lexer $twig_lexer + * @param user $user + * @param string $phpbb_root_path + * @param string $template_cache_path + * @param manager $ext_manager + * @param log_interface $log + */ + public function __construct( + assets_bag $assets_bag, + config $config, + dispatcher $dispatcher, + language $language, + queue $queue, + path_helper $path_helper, + request $request, + service_collection $twig_extensions_collection, + lexer $twig_lexer, + user $user, + string $phpbb_root_path, + string $template_cache_path, + ?manager $ext_manager = null, + ?log_interface $log = null + ) + { + $this->assets_bag = $assets_bag; + $this->config = $config; + $this->dispatcher = $dispatcher; + $this->ext_manager = $ext_manager; + $this->language = $language; + $this->log = $log; + $this->queue = $queue; + $this->path_helper = $path_helper; + $this->request = $request; + $this->twig_extensions_collection = $twig_extensions_collection; + $this->twig_lexer = $twig_lexer; + $this->user = $user; + $this->root_path = $phpbb_root_path; + $this->template_cache_path = $template_cache_path; + + $this->set_use_queue(); + } + + /** + * {@inheritdoc} + */ + abstract public function get_id(): int; + + /** + * {@inheritdoc} + */ + abstract public function is_enabled(): bool; + + /** + * Sets the use of messenger queue flag + * + * @param bool $use_queue Flag indicating if cached queue to be used + * + * @return void + */ + public function set_use_queue(bool $use_queue = true): void + { + $this->use_queue = $use_queue; + } + + /** + * Initializes all the data (address, template file, etc) or resets to default + * + * @return void + */ + abstract public function init(): void; + + /** + * Set addresses for to/im as available + * + * @param array $user_row User row + * + * @return void + */ + abstract public function set_addresses(array $user_row): void; + + /** + * Get messenger method fie queue object name + * + * @return string + */ + abstract public function get_queue_object_name(): string; + + /** + * {@inheritdoc} + */ + public function subject(string $subject = ''): void + { + $this->subject = $subject; + } + + /** + * {@inheritdoc} + */ + abstract public function send(): bool; + + /** + * Send messages from the queue + * + * @param array $queue_data Queue data array + * + * @return void + */ + abstract public function process_queue(array &$queue_data): void; + + /** + * Set email template to use + * + * @param string $template_file Email template file name + * @param string $template_lang Email template language + * @param string $template_path Email template path + * @param string $template_dir_prefix Email template directory prefix + * + * @return bool + */ + public function template(string $template_file, string $template_lang = '', string $template_path = '', string $template_dir_prefix = ''): bool + { + $template_dir_prefix = (!$template_dir_prefix || $template_dir_prefix[0] === '/') ? $template_dir_prefix : '/' . $template_dir_prefix; + + $this->setup_template(); + + if (!trim($template_lang)) + { + // fall back to board default language if the user's language is + // missing $template_file. If this does not exist either, + // $this->template->set_filenames will do a trigger_error + $template_lang = basename($this->config['default_lang']); + } + + $ext_template_paths = [ + [ + 'name' => $template_lang . '_email', + 'ext_path' => 'language/' . $template_lang . '/email' . $template_dir_prefix, + ], + ]; + + if ($template_path) + { + $template_paths = [ + $template_path . $template_dir_prefix, + ]; + } + else + { + $template_path = (!empty($this->user->lang_path)) ? $this->user->lang_path : $this->root_path . 'language/'; + $template_path .= $template_lang . '/email'; + + $template_paths = [ + $template_path . $template_dir_prefix, + ]; + + $board_language = basename($this->config['default_lang']); + + // we can only specify default language fallback when the path is not a custom one for which we + // do not know the default language alternative + if ($template_lang !== $board_language) + { + $fallback_template_path = (!empty($this->user->lang_path)) ? $this->user->lang_path : $this->root_path . 'language/'; + $fallback_template_path .= $board_language . '/email'; + + $template_paths[] = $fallback_template_path . $template_dir_prefix; + + $ext_template_paths[] = [ + 'name' => $board_language . '_email', + 'ext_path' => 'language/' . $board_language . '/email' . $template_dir_prefix, + ]; + } + // If everything fails just fall back to en template + if ($template_lang !== 'en' && $board_language !== 'en') + { + $fallback_template_path = (!empty($this->user->lang_path)) ? $this->user->lang_path : $this->root_path . 'language/'; + $fallback_template_path .= 'en/email'; + + $template_paths[] = $fallback_template_path . $template_dir_prefix; + + $ext_template_paths[] = [ + 'name' => 'en_email', + 'ext_path' => 'language/en/email' . $template_dir_prefix, + ]; + } + } + + $this->set_template_paths($ext_template_paths, $template_paths); + + $this->template->set_filenames([ + 'body' => $template_file . '.txt', + ]); + + return true; + } + + /** + * Assign variables to email template + * + * @param array $vars Array of VAR => VALUE to assign to email template + * + * @return void + */ + public function assign_vars(array $vars): void + { + $this->setup_template(); + $this->template->assign_vars($vars); + } + + /** + * Assign block of variables to email template + * + * @param string $blockname Template block name + * @param array $vars Array of VAR => VALUE to assign to email template block + * + * @return void + */ + public function assign_block_vars(string $blockname, array $vars): void + { + $this->setup_template(); + + $this->template->assign_block_vars($blockname, $vars); + } + + /** + * Prepare message before sending out to the recipients + * + * @return void + */ + public function prepare_message(): void + { + // We add some standard variables we always use, no need to specify them always + $this->assign_vars([ + 'U_BOARD' => generate_board_url(), + 'EMAIL_SIG' => str_replace('
', "\n", "-- \n" . html_entity_decode($this->config['board_email_sig'], ENT_COMPAT)), + 'SITENAME' => html_entity_decode($this->config['sitename'], ENT_COMPAT), + ]); + + $subject = $this->subject; + $template = $this->template; + /** + * Event to modify the template before parsing + * + * @event core.modify_notification_template + * @var string subject The message subject + * @var string template The (readonly) template object + * @since 3.2.4-RC1 + * @changed 4.0.0-a1 Removed vars: method, break. + */ + $vars = ['subject', 'template']; + extract($this->dispatcher->trigger_event('core.modify_notification_template', compact($vars))); + + // Parse message through template + $message = trim($this->template->assign_display('body')); + + /** + * Event to modify notification message text after parsing + * + * @event core.modify_notification_message + * @var string message The message text + * @var string subject The message subject + * @since 3.1.11-RC1 + * @changed 4.0.0-a1 Removed vars: method, break. + */ + $vars = ['message', 'subject']; + extract($this->dispatcher->trigger_event('core.modify_notification_message', compact($vars))); + + $this->subject = $subject; + $this->msg = $message; + unset($subject, $message, $template); + + // Because we use \n for newlines in the body message we need to fix line encoding errors for those admins who uploaded email template files in the wrong encoding + $this->msg = str_replace("\r\n", "\n", $this->msg); + + // We now try and pull a subject from the email body ... if it exists, + // do this here because the subject may contain a variable + $drop_header = ''; + $match = []; + if (preg_match('#^(Subject):(.*?)$#m', $this->msg, $match)) + { + $this->subject = (trim($match[2]) != '') ? trim($match[2]) : (($this->subject != '') ? $this->subject : $this->language->lang('NO_EMAIL_SUBJECT')); + $drop_header .= '[\r\n]*?' . preg_quote($match[0], '#'); + } + else + { + $this->subject = (($this->subject != '') ? $this->subject : $this->language->lang('NO_EMAIL_SUBJECT')); + } + + if (preg_match('#^(List-Unsubscribe):(.*?)$#m', $this->msg, $match)) + { + $drop_header .= '[\r\n]*?' . preg_quote($match[0], '#'); + $this->additional_headers[$match[1]] = trim($match[2]); + } + + if ($drop_header) + { + $this->msg = trim(preg_replace('#' . $drop_header . '#s', '', $this->msg)); + } + } + + /** + * {@inheritdoc} + */ + public function error(string $msg): void + { + // Session doesn't exist, create it + if (!isset($this->user->session_id) || $this->user->session_id === '') + { + $this->user->session_begin(); + } + + $type = strtoupper($this->get_queue_object_name()); + $calling_page = html_entity_decode($this->request->server('PHP_SELF'), ENT_COMPAT); + $message = '' . $type . '
' . htmlspecialchars($calling_page, ENT_COMPAT) . '

' . $msg . '
'; + if ($this->log) + { + $this->log->add('critical', $this->user->data['user_id'], $this->user->ip, 'LOG_ERROR_' . $type, false, [$message]); + } + } + + /** + * Save message data to the messenger file queue + * + * @return void + */ + public function save_queue(): void + { + if ($this->use_queue && !empty($this->queue)) + { + $this->queue->save(); + } + } + + /** + * Setup template engine + * + * @return void + */ + protected function setup_template(): void + { + if (isset($this->template) && $this->template instanceof \phpbb\template\template) + { + return; + } + + $template_environment = new \phpbb\template\twig\environment( + $this->assets_bag, + $this->config, + new \phpbb\filesystem\filesystem(), + $this->path_helper, + $this->template_cache_path, + $this->ext_manager, + new \phpbb\template\twig\loader(), + $this->dispatcher, + [] + ); + $template_environment->setLexer($this->twig_lexer); + + $this->template = new \phpbb\template\twig\twig( + $this->path_helper, + $this->config, + new \phpbb\template\context(), + $template_environment, + $this->template_cache_path, + $this->user, + $this->twig_extensions_collection, + $this->ext_manager + ); + } + + /** + * Set template paths to load + * + * @param string|array $path_name Email template path name + * @param string|array $paths Email template paths + * + * @return void + */ + protected function set_template_paths(string|array $path_name, string|array $paths): void + { + $this->setup_template(); + $this->template->set_custom_style($path_name, $paths); + } +} diff --git a/phpBB/phpbb/messenger/method/email.php b/phpBB/phpbb/messenger/method/email.php new file mode 100644 index 0000000000..1bad23760c --- /dev/null +++ b/phpBB/phpbb/messenger/method/email.php @@ -0,0 +1,579 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\messenger\method; + +use Symfony\Component\Mailer\Transport; +use Symfony\Component\Mailer\Mailer; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email as symfony_email; +use Symfony\Component\Mime\Header\Headers; + +/** + * Messenger class + */ +class email extends base +{ + /** @var array */ + private const PRIORITY_MAP = [ + symfony_email::PRIORITY_HIGHEST => 'Highest', + symfony_email::PRIORITY_HIGH => 'High', + symfony_email::PRIORITY_NORMAL => 'Normal', + symfony_email::PRIORITY_LOW => 'Low', + symfony_email::PRIORITY_LOWEST => 'Lowest', + ]; + + /** + * @var string + * + * Symfony Mailer transport DSN + */ + protected $dsn = ''; + + /** @var symfony_email */ + protected $email; + + /** @var Address */ + protected $from; + + /** @var Headers */ + protected $headers; + + /** + * @var int + * + * Possible values are: + * symfony_email::PRIORITY_HIGHEST + * symfony_email::PRIORITY_HIGH + * symfony_email::PRIORITY_NORMAL + * symfony_email::PRIORITY_LOW + * symfony_email::PRIORITY_LOWEST + */ + protected $mail_priority = symfony_email::PRIORITY_NORMAL; + + /** @var \phpbb\messenger\queue */ + protected $queue; + + /** @var Address */ + protected $reply_to; + + /** @var \Symfony\Component\Mailer\Transport\AbstractTransport */ + protected $transport; + + /** + * {@inheritDoc} + */ + public function get_id(): int + { + return self::NOTIFY_EMAIL; + } + + /** + * {@inheritDoc} + */ + public function get_queue_object_name(): string + { + return 'email'; + } + + /** + * {@inheritDoc} + */ + public function is_enabled(): bool + { + return (bool) $this->config['email_enable']; + } + + /** + * {@inheritDoc} + */ + public function init(): void + { + $this->email = new symfony_email(); + $this->headers = $this->email->getHeaders(); + $this->subject = $this->msg = ''; + $this->mail_priority = symfony_email::PRIORITY_NORMAL; + + $this->additional_headers = []; + $this->use_queue = true; + unset($this->template, $this->reply_to, $this->from); + } + + /** + * {@inheritdoc} + */ + public function set_use_queue(bool $use_queue = true): void + { + $this->use_queue = !$this->config['email_package_size'] ? false : $use_queue; + } + + /** + * {@inheritDoc} + */ + public function set_addresses(array $user_row): void + { + if (!empty($user_row['user_email'])) + { + $this->to($user_row['user_email'], $user_row['username'] ?: ''); + } + } + + /** + * Sets email address to send to + * + * @param string $address Email "To" recipient address + * @param string $realname Email "To" recipient name + * @return void + */ + public function to(string $address, string $realname = ''): void + { + if (!$address = trim($address)) + { + return; + } + + // If empty sendmail_path on windows, PHP changes the to line + $windows_empty_sendmail_path = !$this->config['smtp_delivery'] && DIRECTORY_SEPARATOR == '\\'; + + $to = new Address($address, $windows_empty_sendmail_path ? '' : trim($realname)); + $this->email->getTo() ? $this->email->addTo($to) : $this->email->to($to); + } + + /** + * Sets cc address to send to + * + * @param string $address Email carbon copy recipient address + * @param string $realname Email carbon copy recipient name + * @return void + */ + public function cc(string $address, string $realname = ''): void + { + if (!$address = trim($address)) + { + return; + } + + $cc = new Address($address, trim($realname)); + $this->email->getCc() ? $this->email->addCc($cc) : $this->email->cc($cc); + } + + /** + * Sets bcc address to send to + * + * @param string $address Email black carbon copy recipient address + * @param string $realname Email black carbon copy recipient name + * @return void + */ + public function bcc(string $address, string $realname = ''): void + { + if (!$address = trim($address)) + { + return; + } + + $bcc = new Address($address, trim($realname)); + $this->email->getBcc() ? $this->email->addBcc($bcc) : $this->email->bcc($bcc); + } + + /** + * Set the reply to address + * + * @param string $address Email "Reply to" address + * @param string $realname Email "Reply to" recipient name + * @return void + */ + public function reply_to(string $address, string $realname = ''): void + { + if (!$address = trim($address)) + { + return; + } + + $this->reply_to = new Address($address, trim($realname)); + $this->email->getReplyTo() ? $this->email->addReplyTo($this->reply_to) : $this->email->replyTo($this->reply_to); + } + + /** + * Set the from address + * + * @param string $address Email "from" address + * @param string $realname Email "from" recipient name + * @return void + */ + public function from(string $address, string $realname = ''): void + { + if (!$address = trim($address)) + { + return; + } + + $this->from = new Address($address, trim($realname)); + $this->email->getFrom() ? $this->email->addFrom($this->from) : $this->email->from($this->from); + } + + /** + * Set up subject for mail + * + * @param string $subject Email subject + * @return void + */ + public function subject(string $subject = ''): void + { + parent::subject(trim($subject)); + $this->email->subject($this->subject); + } + + /** + * Adds X-AntiAbuse headers + * + * @param \phpbb\config\config $config Config object + * @param \phpbb\user $user User object + * @return void + */ + public function anti_abuse_headers(\phpbb\config\config $config, \phpbb\user $user): void + { + $this->headers->addHeader('X-AntiAbuse', 'Board servername - ' . $config['server_name']); + $this->headers->addHeader('X-AntiAbuse', 'User_id - ' . $user->data['user_id']); + $this->headers->addHeader('X-AntiAbuse', 'Username - ' . $user->data['username']); + $this->headers->addHeader('X-AntiAbuse', 'User IP - ' . $user->ip); + } + + /** + * Set the email priority + * + * Possible values are: + * symfony_email::PRIORITY_HIGHEST = 1 + * symfony_email::PRIORITY_HIGH = 2 + * symfony_email::PRIORITY_NORMAL = 3 + * symfony_email::PRIORITY_LOW = 4 + * symfony_email::PRIORITY_LOWEST = 5 + * + * @param int $priority Email priority level + * @return void + */ + public function set_mail_priority(int $priority = symfony_email::PRIORITY_NORMAL): void + { + $this->email->priority($priority); + } + + /** + * Set email headers + * + * @return void + */ + protected function build_headers(): void + { + + $board_contact = trim($this->config['board_contact']); + $contact_name = html_entity_decode($this->config['board_contact_name'], ENT_COMPAT); + + if (empty($this->email->getReplyTo())) + { + $this->reply_to($board_contact, $contact_name); + } + + if (empty($this->email->getFrom())) + { + $this->from($board_contact, $contact_name); + } + + $this->email->priority($this->mail_priority); + + $headers = [ + 'Return-Path' => new Address($this->config['board_email']), + 'Sender' => new Address($this->config['board_email']), + 'X-MSMail-Priority' => self::PRIORITY_MAP[$this->mail_priority], + 'X-Mailer' => 'phpBB', + 'X-MimeOLE' => 'phpBB', + 'X-phpBB-Origin' => 'phpbb://' . str_replace(['http://', 'https://'], ['', ''], generate_board_url()), + ]; + + // Add additional headers + $headers = array_merge($headers, $this->additional_headers); + + /** + * Event to modify email header entries + * + * @event core.modify_email_headers + * @var array headers Array containing email header entries + * @since 3.1.11-RC1 + */ + $vars = ['headers']; + extract($this->dispatcher->trigger_event('core.modify_email_headers', compact($vars))); + + foreach ($headers as $header => $value) + { + $this->headers->addHeader($header, $value); + } + + } + + /** + * Generates valid DSN for Symfony Mailer transport + * + * @param string $dsn Symfony Mailer transport DSN + * @return void + */ + public function set_dsn(string $dsn = ''): void + { + if (!empty($dsn)) + { + $this->dsn = $dsn; + } + else if ($this->config['smtp_delivery']) + { + if (empty($this->config['smtp_host'])) + { + $this->dsn = 'null://null'; + } + else + { + $user = urlencode($this->config['smtp_username']); + $password = urlencode($this->config['smtp_password']); + $smtp_host = urlencode($this->config['smtp_host']); + $smtp_port = $this->config['smtp_port']; + + $this->dsn = "smtp://$user:$password@$smtp_host:$smtp_port"; + } + } + else + { + $this->dsn = 'sendmail://default'; + } + } + + /** + * Get Symfony Mailer transport DSN + * + * @return string + */ + public function get_dsn(): string + { + return $this->dsn; + } + + /** + * Generates a valid transport to send email + * + * @return void + */ + public function set_transport(): void + { + if (empty($this->dsn)) + { + $this->set_dsn(); + } + + $this->transport = Transport::fromDsn($this->dsn); + + if ($this->config['smtp_delivery'] && method_exists($this->transport, 'getStream')) + { + // Set ssl context options, see http://php.net/manual/en/context.ssl.php + $options['ssl'] = [ + 'verify_peer' => (bool) $this->config['smtp_verify_peer'], + 'verify_peer_name' => (bool) $this->config['smtp_verify_peer_name'], + 'allow_self_signed' => (bool) $this->config['smtp_allow_self_signed'], + ]; + $this->transport->getStream()->setStreamOptions($options); + } + } + + /** + * {@inheritDoc} + */ + public function process_queue(array &$queue_data): void + { + $queue_object_name = $this->get_queue_object_name(); + $messages_count = count($queue_data[$queue_object_name]['data']); + + if (!$this->is_enabled() || !$messages_count) + { + unset($queue_data[$queue_object_name]); + return; + } + + @set_time_limit(0); + + $package_size = $queue_data[$queue_object_name]['package_size'] ?? 0; + $num_items = (!$package_size || $messages_count < $package_size) ? $messages_count : $package_size; + $mailer = new Mailer($this->transport); + + for ($i = 0; $i < $num_items; $i++) + { + // Make variables available... + extract(array_shift($queue_data[$queue_object_name]['data'])); + + $break = false; + /** + * Event to send message via external transport + * + * @event core.notification_message_process + * @var string break Flag indicating if the function return after hook + * @var string email The Symfony Email object + * @since 3.2.4-RC1 + * @changed 4.0.0-a1 Added vars: email. Removed vars: addresses, subject, msg. + */ + $vars = [ + 'break', + 'email', + ]; + extract($this->dispatcher->trigger_event('core.notification_message_process', compact($vars))); + + if (!$break) + { + try + { + $mailer->send($email); + } + catch (\Symfony\Component\Mailer\Exception\TransportExceptionInterface $e) + { + $this->error($e->getDebug()); + continue; + } + } + } + + // No more data for this object? Unset it + if (!count($queue_data[$queue_object_name]['data'])) + { + unset($queue_data[$queue_object_name]); + } + } + + /** + * Get mailer transport object + * + * @return \Symfony\Component\Mailer\Transport\TransportInterface Symfony Mailer transport object + */ + public function get_transport(): \Symfony\Component\Mailer\Transport\TransportInterface + { + return $this->transport; + } + + /** + * {@inheritDoc} + */ + public function send(): bool + { + $this->prepare_message(); + + $this->email->subject($this->subject); + $this->email->text($this->msg); + + $break = false; + $subject = $this->subject; + $msg = $this->msg; + $email = $this->email; + /** + * Event to send message via external transport + * + * @event core.notification_message_email + * @var bool break Flag indicating if the function return after hook + * @var string subject The message subject + * @var string msg The message text + * @var string email The Symfony Email object + * @since 3.2.4-RC1 + * @changed 4.0.0-a1 Added vars: email. Removed vars: addresses + */ + $vars = [ + 'break', + 'subject', + 'msg', + 'email', + ]; + extract($this->dispatcher->trigger_event('core.notification_message_email', compact($vars))); + $this->email = $email; + + $this->build_headers(); + + if ($break) + { + return true; + } + + // Send message ... + if (!$this->use_queue) + { + $mailer = new Mailer($this->transport); + + $subject = $this->subject; + $msg = $this->msg; + $headers = $this->headers; + $email = $this->email; + /** + * Modify data before sending out emails with PHP's mail function + * + * @event core.phpbb_mail_before + * @var string email The Symfony Email object + * @var string subject The message subject + * @var string msg The message text + * @var string headers The email headers + * @since 3.3.6-RC1 + * @changed 4.0.0-a1 Added vars: email. Removed vars: to, eol, additional_parameters. + */ + $vars = [ + 'email', + 'subject', + 'msg', + 'headers', + ]; + extract($this->dispatcher->trigger_event('core.phpbb_mail_before', compact($vars))); + + $this->subject = $subject; + $this->msg = $msg; + $this->headers = $headers; + $this->email = $email; + + try + { + $mailer->send($this->email); + } + catch (\Symfony\Component\Mailer\Exception\TransportExceptionInterface $e) + { + $this->error($e->getDebug()); + return false; + } + + /** + * Execute code after sending out emails with PHP's mail function + * + * @event core.phpbb_mail_after + * @var string email The Symfony Email object + * @var string subject The message subject + * @var string msg The message text + * @var string headers The email headers + * @since 3.3.6-RC1 + * @changed 4.0.0-a1 Added vars: email. Removed vars: to, eol, additional_parameters, $result. + */ + $vars = [ + 'email', + 'subject', + 'msg', + 'headers', + ]; + extract($this->dispatcher->trigger_event('core.phpbb_mail_after', compact($vars))); + } + else + { + $this->queue->init('email', $this->config['email_package_size']); + $this->queue->put('email', [ + 'email' => $this->email, + ]); + } + + // Reset the object + $this->init(); + + return true; + } +} diff --git a/phpBB/includes/functions_jabber.php b/phpBB/phpbb/messenger/method/jabber.php similarity index 52% rename from phpBB/includes/functions_jabber.php rename to phpBB/phpbb/messenger/method/jabber.php index ec7d090257..a4a2c07f61 100644 --- a/phpBB/includes/functions_jabber.php +++ b/phpBB/phpbb/messenger/method/jabber.php @@ -1,95 +1,197 @@ -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\messenger\method; /** -* @ignore -*/ -if (!defined('IN_PHPBB')) + * + * Based on Jabber class from Flyspray project + * + * @version class.jabber2.php 1595 2008-09-19 (0.9.9) + * @copyright 2006 Flyspray.org + * @author Florian Schmitz (floele) + * + * Slightly modified by Acyd Burn (2006) + * Refactored to a service (2024) + */ +class jabber extends base { - exit; -} + /** @var string */ + protected $connect_server; -/** -* -* Jabber class from Flyspray project -* -* @version class.jabber2.php 1595 2008-09-19 (0.9.9) -* @copyright 2006 Flyspray.org -* @author Florian Schmitz (floele) -* -* Only slightly modified by Acyd Burn -*/ -class jabber -{ - var $connection = null; - var $session = array(); - var $timeout = 10; + /** @var resource|null */ + protected $connection = null; - var $server; - var $connect_server; - var $port; - var $username; - var $password; - var $use_ssl; - var $verify_peer; - var $verify_peer_name; - var $allow_self_signed; - var $resource = 'functions_jabber.phpbb.php'; + /** @var bool */ + protected $enable_logging = true; - var $enable_logging; - var $log_array; + /** @var array */ + protected $features = []; - var $features = array(); + /** @var array */ + protected $jid = []; + + /** @var array */ + protected $log_array = []; + + /** @var string */ + protected $password; + + /** @var int */ + protected $port; + + /** @var string */ + protected $resource = 'functions_jabber.phpbb.php'; + + /** @var string */ + protected $server; + + /** @var array */ + protected $session = []; + + /** @var array */ + protected $stream_options = []; + + /** @var int */ + protected $timeout = 10; + + /** @var array */ + protected $to = []; + + /** @var bool */ + protected $use_ssl = false; + + /** @var string */ + protected $username; /** @var string Stream close handshake */ private const STREAM_CLOSE_HANDSHAKE = ''; /** - * Constructor - * - * @param string $server Jabber server - * @param int $port Jabber server port - * @param string $username Jabber username or JID - * @param string $password Jabber password - * @param bool $use_ssl Use ssl - * @param bool $verify_peer Verify SSL certificate - * @param bool $verify_peer_name Verify Jabber peer name - * @param bool $allow_self_signed Allow self signed certificates - */ - function __construct($server, $port, $username, $password, $use_ssl = false, $verify_peer = true, $verify_peer_name = true, $allow_self_signed = false) + * Set initial parameter values + * To init correctly, username() call should go before server() + * and ssl() call should go before port() and stream_options() calls. + * + * Example: + * $this->username($username) + * ->password($password) + * ->ssl($use_ssl) + * ->server($server) + * ->port($port) + * ->stream_options( + * 'verify_peer' => true, + * 'verify_peer_name' => true, + * 'allow_self_signed' => false, + * ); + * + * @return void + */ + public function init(): void { - $this->connect_server = ($server) ? $server : 'localhost'; - $this->port = ($port) ? $port : 5222; + $this->username($this->config['jab_username']) + ->password($this->config['jab_password']) + ->ssl((bool) $this->config['jab_use_ssl']) + ->server($this->config['jab_host']) + ->port($this->config['jab_port']) + ->stream_options['ssl'] = [ + 'verify_peer' => $this->config['jab_verify_peer'], + 'verify_peer_name' => $this->config['jab_verify_peer_name'], + 'allow_self_signed' => $this->config['jab_allow_self_signed'], + ]; + } - // Get the server and the username - if (strpos($username, '@') === false) - { - $this->server = $this->connect_server; - $this->username = $username; - } - else - { - $jid = explode('@', $username, 2); + /** + * {@inheritDoc} + */ + public function get_id(): int + { + return self::NOTIFY_IM; + } - $this->username = $jid[0]; - $this->server = $jid[1]; + /** + * {@inheritDoc} + */ + public function get_queue_object_name(): string + { + return 'jabber'; + } + + /** + * {@inheritDoc} + */ + public function is_enabled(): bool + { + return + !empty($this->config['jab_enable']) && + !empty($this->config['jab_host']) && + !empty($this->config['jab_username']) && + !empty($this->config['jab_password']); + } + + /** + * Set ssl context options + * See http://php.net/manual/en/context.ssl.php + * + * @param array $options SSL context options array + * @return self + */ + public function stream_options(array $options = []): self + { + if ($this->use_ssl) + { + // Change default stream options if needed + $this->stream_options['ssl'] = array_merge($this->stream_options['ssl'], $options); } - $this->password = $password; - $this->use_ssl = ($use_ssl && self::can_use_ssl()) ? true : false; - $this->verify_peer = $verify_peer; - $this->verify_peer_name = $verify_peer_name; - $this->allow_self_signed = $allow_self_signed; + return $this; + } + + /** + * Set password to connect to server + * + * @param string $password Password to connect to server + * @return self + */ + public function password(string $password = ''): self + { + $this->password = html_entity_decode($password, ENT_COMPAT); + + return $this; + } + + /** + * Set use of ssl to connect to server + * + * @param bool $use_ssl Flag indicating use of ssl to connect to server + * @return self + */ + public function ssl(bool $use_ssl = false): self + { + $this->use_ssl = $use_ssl && self::can_use_ssl(); + + return $this; + } + + /** + * Set port to connect to server + * use_ssl flag should be set first + * + * @param int $port Port to connect to server + * @return self + */ + public function port(int $port = 5222): self + { + $this->port = ($port > 0) ? $port : 5222; // Change port if we use SSL if ($this->port == 5222 && $this->use_ssl) @@ -97,22 +199,61 @@ class jabber $this->port = 5223; } - $this->enable_logging = true; - $this->log_array = array(); + return $this; } /** - * Able to use the SSL functionality? - */ - public static function can_use_ssl() + * Set username to connect to server + * + * @param string $username Username to connect to server + * @return self + */ + public function username(string $username = ''): self + { + if (str_contains($username, '@')) + { + $this->jid = explode('@', $username, 2); + $this->username = $this->jid[0]; + } + else + { + $this->username = $username; + } + + return $this; + } + + /** + * Set server to connect + * Username should be set first + * + * @param string $server Server to connect + * @return self + */ + public function server(string $server = ''): self + { + $this->connect_server = $server ?: 'localhost'; + $this->server = $this->jid[1] ?? $this->connect_server; + + return $this; + } + + /** + * Check if it's possible to use the SSL functionality + * + * @return bool + */ + public static function can_use_ssl(): bool { return @extension_loaded('openssl'); } /** - * Able to use TLS? - */ - public static function can_use_tls() + * Check if it's possible to use TLS functionality + * + * @return bool + */ + public static function can_use_tls(): bool { if (!@extension_loaded('openssl') || !function_exists('stream_socket_enable_crypto') || !function_exists('stream_get_meta_data') || !function_exists('stream_set_blocking') || !function_exists('stream_get_wrappers')) { @@ -135,19 +276,22 @@ class jabber } /** - * Sets the resource which is used. No validation is done here, only escaping. - * @param string $name - * @access public - */ - function set_resource($name) + * Sets the resource which is used. No validation is done here, only escaping + * + * @param string $name + * @return void + */ + public function set_resource(string $name): void { $this->resource = $name; } /** - * Connect - */ - function connect() + * Connect to the server + * + * @return bool + */ + public function connect(): bool { /* if (!$this->check_jid($this->username . '@' . $this->server)) { @@ -157,10 +301,10 @@ class jabber $this->session['ssl'] = $this->use_ssl; - if ($this->open_socket($this->connect_server, $this->port, $this->use_ssl, $this->verify_peer, $this->verify_peer_name, $this->allow_self_signed)) + if ($this->open_socket($this->connect_server, $this->port)) { - $this->send("\n"); - $this->send("\n"); + $this->send_xml("\n"); + $this->send_xml("\n"); } else { @@ -174,9 +318,11 @@ class jabber } /** - * Disconnect - */ - function disconnect() + * Disconnect from the server + * + * @return bool + */ + public function disconnect(): bool { if ($this->connected()) { @@ -195,7 +341,8 @@ class jabber $this->add_to_log("Error: Unexpected stream close handshake reply ”{$stream_close_reply}”"); } - $this->session = array(); + $this->session = []; + /** @psalm-suppress InvalidPropertyAssignmentValue */ return fclose($this->connection); } @@ -203,20 +350,21 @@ class jabber } /** - * Connected? - */ - function connected() + * Check if it's still connected to the server + * + * @return bool + */ + public function connected(): bool { - return (is_resource($this->connection) && !feof($this->connection)) ? true : false; + return is_resource($this->connection) && !feof($this->connection); } - /** - * Initiates login (using data from contructor, after calling connect()) - * @access public - * @return bool - */ - function login() + * Initiates login (using data from contructor, after calling connect()) + * + * @return bool + */ + public function login(): bool { if (empty($this->features)) { @@ -228,12 +376,178 @@ class jabber } /** - * Send data to the Jabber server - * @param string $xml - * @access public - * @return bool - */ - function send($xml) + * {@inheritDoc} + */ + public function set_addresses(array $user_row): void + { + if (isset($user_row['user_jabber']) && $user_row['user_jabber']) + { + $this->to($user_row['user_jabber'], (isset($user_row['username']) ? $user_row['username'] : '')); + } + } + + /** + * Sets jabber contact to send message to + * + * @param string $address Jabber "To" recipient address + * @param string $realname Jabber "To" recipient name + * @return void + */ + public function to(string $address, string $realname = ''): void + { + // IM-Addresses could be empty + if (!trim($address)) + { + return; + } + + $pos = !empty($this->to) ? count($this->to) : 0; + $this->to[$pos]['uid'] = trim($address); + $this->to[$pos]['name'] = trim($realname); + } + + /** + * Resets all the data (address, template file, etc) to default + */ + public function reset(): void + { + $this->subject = $this->msg = ''; + $this->additional_headers = $this->to = []; + $this->use_queue = true; + unset($this->template); + } + + /** + * {@inheritDoc} + */ + public function set_use_queue(bool $use_queue = true): void + { + $this->use_queue = !$this->config['jab_package_size'] ? false : $use_queue; + } + + /** + * {@inheritDoc} + */ + public function process_queue(array &$queue_data): void + { + $queue_object_name = $this->get_queue_object_name(); + $messages_count = count($queue_data[$queue_object_name]['data']); + + if (!$this->is_enabled() || !$messages_count) + { + unset($queue_data[$queue_object_name]); + return; + } + + @set_time_limit(0); + + $package_size = $queue_data[$queue_object_name]['package_size'] ?? 0; + $num_items = (!$package_size || $messages_count < $package_size) ? $messages_count : $package_size; + + for ($i = 0; $i < $num_items; $i++) + { + // Make variables available... + extract(array_shift($queue_data[$queue_object_name]['data'])); + + if (!$this->connect()) + { + $this->error($this->user->lang['ERR_JAB_CONNECT'] . '
' . $this->get_log()); + return; + } + + if (!$this->login()) + { + $this->error($this->user->lang['ERR_JAB_AUTH'] . '
' . $this->get_log()); + return; + } + + foreach ($addresses as $address) + { + if ($this->send_message($address, $msg, $subject) === false) + { + $this->error($this->get_log()); + continue; + } + } + } + + // No more data for this object? Unset it + if (!count($queue_data[$queue_object_name]['data'])) + { + unset($queue_data[$queue_object_name]); + } + + $this->disconnect(); + } + + /** + * {@inheritDoc} + */ + public function send(): bool + { + $this->prepare_message(); + + if (empty($this->to)) + { + $this->add_to_log('Error: Could not send, recepient addresses undefined.'); + return false; + } + + $addresses = []; + foreach ($this->to as $uid_ary) + { + $addresses[] = $uid_ary['uid']; + } + $addresses = array_unique($addresses); + + if (!$this->use_queue) + { + if (!$this->connect()) + { + $this->error($this->user->lang['ERR_JAB_CONNECT'] . '
' . $this->get_log()); + return false; + } + + if (!$this->login()) + { + $this->error($this->user->lang['ERR_JAB_AUTH'] . '
' . $this->get_log()); + return false; + } + + foreach ($addresses as $address) + { + if ($this->send_message($address, $this->msg, $this->subject) === false) + { + $this->error($this->get_log()); + continue; + } + } + + $this->disconnect(); + } + else + { + $this->queue->init('jabber', $this->config['jab_package_size']); + $this->queue->put('jabber', [ + 'addresses' => $addresses, + 'subject' => $this->subject, + 'msg' => $this->msg, + ]); + } + unset($addresses); + + $this->reset(); + + return true; + } + + /** + * Send data to the Jabber server + * + * @param string $xml + * @return int|bool + */ + public function send_xml(string $xml): int|bool { if ($this->connected()) { @@ -248,17 +562,14 @@ class jabber } /** - * OpenSocket - * @param string $server host to connect to - * @param int $port port number - * @param bool $use_ssl use ssl or not - * @param bool $verify_peer verify ssl certificate - * @param bool $verify_peer_name verify peer name - * @param bool $allow_self_signed allow self-signed ssl certificates - * @access public - * @return bool - */ - function open_socket($server, $port, $use_ssl, $verify_peer, $verify_peer_name, $allow_self_signed) + * Open socket + * + * @param string $server Host to connect to + * @param int $port Port number + * + * @return bool + */ + public function open_socket(string $server, int $port): bool { if (@function_exists('dns_get_record')) { @@ -269,21 +580,8 @@ class jabber } } - $options = array(); - - if ($use_ssl) - { - $remote_socket = 'ssl://' . $server . ':' . $port; - - // Set ssl context options, see http://php.net/manual/en/context.ssl.php - $options['ssl'] = array('verify_peer' => $verify_peer, 'verify_peer_name' => $verify_peer_name, 'allow_self_signed' => $allow_self_signed); - } - else - { - $remote_socket = $server . ':' . $port; - } - - $socket_context = stream_context_create($options); + $remote_socket = $this->use_ssl ? 'ssl://' . $server . ':' . $port : $server . ':' . $port; + $socket_context = stream_context_create($this->stream_options); if ($this->connection = @stream_socket_client($remote_socket, $errorno, $errorstr, $this->timeout, STREAM_CLIENT_CONNECT, $socket_context)) { @@ -299,9 +597,11 @@ class jabber } /** - * Return log - */ - function get_log() + * Get connection log + * + * @return string + */ + public function get_log(): string { if ($this->enable_logging && count($this->log_array)) { @@ -312,9 +612,12 @@ class jabber } /** - * Add information to log - */ - function add_to_log($string) + * Add information to log + * + * @param string $string Log entry + * @return void + */ + protected function add_to_log(string $string): void { if ($this->enable_logging) { @@ -323,12 +626,14 @@ class jabber } /** - * Listens to the connection until it gets data or the timeout is reached. - * Thus, it should only be called if data is expected to be received. - * @access public - * @return mixed either false for timeout or an array with the received data - */ - function listen($timeout = 10, $wait = false) + * Listens to the connection until it gets data or the timeout is reached. + * Thus, it should only be called if data is expected to be received. + * + * @param int $timeout Connection timeout + * @param bool $wait Flag indicating if it should wait for the responce until timeout + * @return bool|array Either false for timeout or an array with the received data + */ + public function listen(int $timeout = 10, bool $wait = false): bool|array { if (!$this->connected()) { @@ -358,11 +663,11 @@ class jabber } /** - * Initiates account registration (based on data used for contructor) - * @access public - * @return bool - */ - function register() + * Initiates account registration (based on data used for constructor) + * + * @return bool|null + */ + public function register(): bool|null { if (!isset($this->session['id']) || isset($this->session['jid'])) { @@ -370,19 +675,19 @@ class jabber return false; } - $this->send(""); + $this->send_xml(""); return $this->response($this->listen()); } /** - * Sets account presence. No additional info required (default is "online" status) - * @param $message online, offline... - * @param $type dnd, away, chat, xa or nothing - * @param $unavailable set this to true if you want to become unavailable - * @access public - * @return bool - */ - function send_presence($message = '', $type = '', $unavailable = false) + * Sets account presence. No additional info required (default is "online" status) + * + * @param string $message Account status (online, offline) + * @param string $type Status type (dnd, away, chat, xa or nothing) + * @param bool $unavailable Set to true to make unavailable status + * @return int|bool + */ + function send_presence(string $message = '', string $type = '', bool $unavailable = false): int|bool { if (!isset($this->session['jid'])) { @@ -398,18 +703,18 @@ class jabber $this->session['sent_presence'] = !$unavailable; - return $this->send("" . $type . $message . ''); + return $this->send_xml("" . $type . $message . ''); } /** - * This handles all the different XML elements - * @param array $xml - * @access public - * @return bool - */ - function response($xml) + * This handles all the different XML elements + * + * @param array $xml + * @return bool + */ + function response(array $xml): bool { - if (!is_array($xml) || !count($xml)) + if (!count($xml)) { return false; } @@ -422,20 +727,17 @@ class jabber { $this->response(array($key => $value)); } - return; + return true; } - else + else if (is_array(reset($xml)) && count(reset($xml)) > 1) { // or even multiple elements of the same type? // array('message' => array(0 => ..., 1 => ...)) - if (is_array(reset($xml)) && count(reset($xml)) > 1) + foreach (reset($xml) as $value) { - foreach (reset($xml) as $value) - { - $this->response(array(key($xml) => array(0 => $value))); - } - return; + $this->response(array(key($xml) => array(0 => $value))); } + return true; } switch (key($xml)) @@ -467,6 +769,7 @@ class jabber { return $this->response($this->features); } + return false; break; case 'stream:features': @@ -476,7 +779,7 @@ class jabber // session required? $this->session['sess_required'] = isset($xml['stream:features'][0]['#']['session']); - $this->send(" + $this->send_xml(" " . utf8_htmlspecialchars($this->resource) . ' @@ -488,7 +791,7 @@ class jabber if (!$this->session['ssl'] && self::can_use_tls() && self::can_use_ssl() && isset($xml['stream:features'][0]['#']['starttls'])) { $this->add_to_log('Switching to TLS.'); - $this->send("\n"); + $this->send_xml("\n"); return $this->response($this->listen()); } @@ -514,18 +817,18 @@ class jabber if (in_array('DIGEST-MD5', $methods)) { - $this->send(""); + $this->send_xml(""); } else if (in_array('PLAIN', $methods) && ($this->session['ssl'] || !empty($this->session['tls']))) { // http://www.ietf.org/rfc/rfc4616.txt (PLAIN SASL Mechanism) - $this->send("" + $this->send_xml("" . base64_encode($this->username . '@' . $this->server . chr(0) . $this->username . chr(0) . $this->password) . ''); } else if (in_array('ANONYMOUS', $methods)) { - $this->send(""); + $this->send_xml(""); } else { @@ -562,7 +865,7 @@ class jabber // second challenge? if (isset($decoded['rspauth'])) { - $this->send(""); + $this->send_xml(""); } else { @@ -589,7 +892,7 @@ class jabber } } - $this->send("" . base64_encode($this->implode_data($response)) . ''); + $this->send_xml("" . base64_encode($this->implode_data($response)) . ''); } return $this->response($this->listen()); @@ -616,15 +919,15 @@ class jabber $this->session['tls'] = true; // new stream - $this->send("\n"); - $this->send("\n"); + $this->send_xml("\n"); + $this->send_xml("\n"); return $this->response($this->listen()); break; case 'success': // Yay, authentication successful. - $this->send("\n"); + $this->send_xml("\n"); $this->session['authenticated'] = true; // we have to wait for another response @@ -647,7 +950,7 @@ class jabber // and (maybe) yet another request to be able to send messages *finally* if ($this->session['sess_required']) { - $this->send(" + $this->send_xml(" "); return $this->response($this->listen()); @@ -661,7 +964,7 @@ class jabber break; case 'reg_1': - $this->send(" + $this->send_xml(" " . utf8_htmlspecialchars($this->username) . " " . utf8_htmlspecialchars($this->password) . " @@ -706,6 +1009,7 @@ class jabber $message['subject'] = $xml['message'][0]['#']['subject'][0]['#']; } $this->session['messages'][] = $message; + return true; break; default: @@ -716,7 +1020,17 @@ class jabber } } - function send_message($to, $text, $subject = '', $type = 'normal') + /** + * Send Jabber message + * + * @param string $to Recepient usermane + * @param string $text Message text + * @param string $subject Message subject + * @param string $type Message type + * + * @return int|bool + */ + public function send_message(string $to, string $text, string $subject = '', string $type = 'normal'): int|bool { if (!isset($this->session['jid'])) { @@ -728,7 +1042,7 @@ class jabber $type = 'normal'; } - return $this->send(" + return $this->send_xml(" " . utf8_htmlspecialchars($subject) . " " . utf8_htmlspecialchars($text) . " " @@ -736,12 +1050,12 @@ class jabber } /** - * Encrypts a password as in RFC 2831 - * @param array $data Needs data from the client-server connection - * @access public - * @return string - */ - function encrypt_password($data) + * Encrypts a password as in RFC 2831 + * + * @param array $data Needs data from the client-server connection + * @return string + */ + public function encrypt_password(array $data): string { // let's me think about again... foreach (array('realm', 'cnonce', 'digest-uri') as $key) @@ -770,12 +1084,12 @@ class jabber } /** - * parse_data like a="b",c="d",... or like a="a, b", c, d="e", f=g,... - * @param string $data - * @access public - * @return array a => b ... - */ - function parse_data($data) + * Parse data string like a="b",c="d",... or like a="a, b", c, d="e", f=g,... + * + * @param string $data + * @return array a => b ... + */ + public function parse_data(string $data): array { $data = explode(',', $data); $pairs = array(); @@ -802,12 +1116,12 @@ class jabber } /** - * opposite of jabber::parse_data() - * @param array $data - * @access public - * @return string - */ - function implode_data($data) + * The opposite of jabber::parse_data() + * + * @param array $data Data array + * @return string + */ + public function implode_data(array $data): string { $return = array(); foreach ($data as $key => $value) @@ -818,11 +1132,16 @@ class jabber } /** - * xmlize() - * @author Hans Anderson - * @copyright Hans Anderson / http://www.hansanderson.com/php/xml/ - */ - function xmlize($data, $skip_white = 1, $encoding = 'UTF-8') + * xmlize() + * @author Hans Anderson + * @copyright Hans Anderson / http://www.hansanderson.com/php/xml/ + * + * @param string $data Data string + * @param string|int|bool $skip_white New XML parser option value + * @param string $encoding Encoding value + * @return array + */ + function xmlize(string $data, string|int|bool $skip_white = 1, string $encoding = 'UTF-8'): array { $data = trim($data); @@ -854,11 +1173,15 @@ class jabber } /** - * _xml_depth() - * @author Hans Anderson - * @copyright Hans Anderson / http://www.hansanderson.com/php/xml/ - */ - function _xml_depth($vals, &$i) + * _xml_depth() + * @author Hans Anderson + * @copyright Hans Anderson / http://www.hansanderson.com/php/xml/ + * + * @param array $vals XML data array + * @param int $i XML tags depth level + * @return array + */ + function _xml_depth(array $vals, int &$i): array { $children = array(); diff --git a/phpBB/phpbb/messenger/method/messenger_interface.php b/phpBB/phpbb/messenger/method/messenger_interface.php new file mode 100644 index 0000000000..b733f3d3d4 --- /dev/null +++ b/phpBB/phpbb/messenger/method/messenger_interface.php @@ -0,0 +1,68 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\messenger\method; + +/** + * Messenger method interface class + */ +interface messenger_interface +{ + /** @var int Email notify method used */ + public const NOTIFY_EMAIL = 0; + + /** @var int Instant messaging (Jabber) notify method used */ + public const NOTIFY_IM = 1; + + /** @var int Both notify methods used */ + public const NOTIFY_BOTH = 2; + + /** + * Get messenger method id + * + * @return int + */ + public function get_id(): int; + + /** + * Check if the messenger method is enabled + * + * @return bool + */ + public function is_enabled(): bool; + + /** + * Set up subject for the message + * + * @param string $subject Email subject + * + * @return void + */ + public function subject(string $subject = ''): void; + + /** + * Send out messages + * + * @return bool + */ + public function send(): bool; + + /** + * Add error message to log + * + * @param string $msg Error message text + * + * @return void + */ + public function error(string $msg): void; +} diff --git a/phpBB/phpbb/messenger/queue.php b/phpBB/phpbb/messenger/queue.php new file mode 100644 index 0000000000..abcc29c1bd --- /dev/null +++ b/phpBB/phpbb/messenger/queue.php @@ -0,0 +1,213 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\messenger; + +use phpbb\config\config; +use phpbb\event\dispatcher; +use phpbb\di\service_collection; +use phpbb\filesystem\filesystem; + +/** + * Handling messenger file queue + */ +class queue +{ + /** @var string */ + protected $cache_file; + + /** @var config */ + protected $config; + + /** @var array */ + protected $data = []; + + /** @var dispatcher */ + protected $dispatcher; + + /** @var \phpbb\filesystem\filesystem_interface */ + protected $filesystem; + + /** @var service_collection */ + protected $messenger_method_collection; + + /** @var array */ + protected $queue_data = []; + + /** + * Messenger queue constructor. + * + * @param config $config + * @param dispatcher $dispatcher + * @param service_collection $messenger_method_collection + * @param string $cache_file + */ + public function __construct(config $config, dispatcher $dispatcher, service_collection $messenger_method_collection, $cache_file) + { + $this->config = $config; + $this->dispatcher = $dispatcher; + $this->messenger_method_collection = $messenger_method_collection; + $this->filesystem = new filesystem(); + $this->cache_file = $cache_file; + } + + /** + * Init a queue object + * + * @param string $object Queue object type: email/jabber/etc + * @param int $package_size Size of the messenger package to send + * @return void + */ + public function init(string $object, int $package_size): void + { + $this->data[$object] = []; + $this->data[$object]['package_size'] = $package_size; + $this->data[$object]['data'] = []; + } + + /** + * Put message into the messenger file queue + * + * @param string $object Queue object type: email/jabber/etc + * @param array $message_data Message data to send + * @return void + */ + public function put(string $object, array $message_data): void + { + $this->data[$object]['data'][] = $message_data; + } + + /** + * Process the messenger file queue (using lock file) + * + * @return void + */ + public function process(): void + { + $lock = new \phpbb\lock\flock($this->cache_file); + $lock->acquire(); + + // avoid races, check file existence once + $have_cache_file = file_exists($this->cache_file); + if (!$have_cache_file || $this->config['last_queue_run'] > time() - $this->config['queue_interval']) + { + if (!$have_cache_file) + { + $this->config->set('last_queue_run', time(), false); + } + + $lock->release(); + return; + } + + $this->config->set('last_queue_run', time(), false); + + include($this->cache_file); + + /** @psalm-suppress InvalidTemplateParam */ + $messenger_collection_iterator = $this->messenger_method_collection->getIterator(); + foreach ($messenger_collection_iterator as $messenger_method) + { + if (isset($this->queue_data[$messenger_method->get_queue_object_name()])) + { + $messenger_method->process_queue($this->queue_data); + } + } + + if (!count($this->queue_data)) + { + @unlink($this->cache_file); + } + else + { + if ($fp = @fopen($this->cache_file, 'wb')) + { + fwrite($fp, "queue_data = unserialize(" . var_export(serialize($this->queue_data), true) . ");\n\n?>"); + fclose($fp); + + if (function_exists('opcache_invalidate')) + { + @opcache_invalidate($this->cache_file); + } + + try + { + $this->filesystem->phpbb_chmod($this->cache_file, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE); + } + catch (\phpbb\filesystem\exception\filesystem_exception $e) + { + // Do nothing + } + } + } + + $lock->release(); + } + + /** + * Save message data to the messenger file queue + * + * @return void + */ + public function save(): void + { + if (!count($this->data)) + { + return; + } + + $lock = new \phpbb\lock\flock($this->cache_file); + $lock->acquire(); + + if (file_exists($this->cache_file)) + { + include($this->cache_file); + + foreach ($this->queue_data as $object => $data_ary) + { + if (isset($this->data[$object]) && count($this->data[$object])) + { + $this->data[$object]['data'] = array_merge($data_ary['data'], $this->data[$object]['data']); + } + else + { + $this->data[$object]['data'] = $data_ary['data']; + } + } + } + + if ($fp = @fopen($this->cache_file, 'w')) + { + fwrite($fp, "queue_data = unserialize(" . var_export(serialize($this->data), true) . ");\n\n?>"); + fclose($fp); + + if (function_exists('opcache_invalidate')) + { + @opcache_invalidate($this->cache_file); + } + + try + { + $this->filesystem->phpbb_chmod($this->cache_file, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE); + } + catch (\phpbb\filesystem\exception\filesystem_exception $e) + { + // Do nothing + } + + $this->data = []; + } + + $lock->release(); + } +} diff --git a/phpBB/phpbb/notification/method/email.php b/phpBB/phpbb/notification/method/email.php index cffd259c0e..8a2fff1bb9 100644 --- a/phpBB/phpbb/notification/method/email.php +++ b/phpBB/phpbb/notification/method/email.php @@ -14,6 +14,12 @@ namespace phpbb\notification\method; use phpbb\notification\type\type_interface; +use phpbb\user; +use phpbb\user_loader; +use phpbb\config\config; +use phpbb\db\driver\driver_interface; +use phpbb\di\service_collection; +use phpbb\messenger\method\messenger_interface; /** * Email notification method class @@ -22,32 +28,45 @@ use phpbb\notification\type\type_interface; class email extends \phpbb\notification\method\messenger_base { - /** @var \phpbb\user */ + /** @var user */ protected $user; - /** @var \phpbb\config\config */ + /** @var config */ protected $config; - /** @var \phpbb\db\driver\driver_interface */ + /** @var driver_interface */ protected $db; /** @var string Notification emails table */ protected $notification_emails_table; + /** @var service_collection */ + protected $messenger; + /** * Notification Method email Constructor * - * @param \phpbb\user_loader $user_loader - * @param \phpbb\user $user - * @param \phpbb\config\config $config - * @param \phpbb\db\driver\driver_interface $db + * @param user_loader $user_loader + * @param user $user + * @param config $config + * @param driver_interface $db * @param string $phpbb_root_path * @param string $php_ext * @param string $notification_emails_table + * @param service_collection $messenger */ - public function __construct(\phpbb\user_loader $user_loader, \phpbb\user $user, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, $phpbb_root_path, $php_ext, $notification_emails_table) + public function __construct( + user_loader $user_loader, + user $user, + config $config, + driver_interface $db, + $phpbb_root_path, + $php_ext, + $notification_emails_table, + service_collection $messenger + ) { - parent::__construct($user_loader, $phpbb_root_path, $php_ext); + parent::__construct($messenger, $user_loader, $phpbb_root_path, $php_ext); $this->user = $user; $this->config = $config; @@ -117,7 +136,7 @@ class email extends \phpbb\notification\method\messenger_base $insert_buffer->flush(); - $this->notify_using_messenger(NOTIFY_EMAIL); + $this->notify_using_messenger(messenger_interface::NOTIFY_EMAIL); } /** diff --git a/phpBB/phpbb/notification/method/jabber.php b/phpBB/phpbb/notification/method/jabber.php index 9a1aadb9a0..e3482f98be 100644 --- a/phpBB/phpbb/notification/method/jabber.php +++ b/phpBB/phpbb/notification/method/jabber.php @@ -14,6 +14,11 @@ namespace phpbb\notification\method; use phpbb\notification\type\type_interface; +use phpbb\user; +use phpbb\user_loader; +use phpbb\config\config; +use phpbb\di\service_collection; +use phpbb\messenger\method\messenger_interface; /** * Jabber notification method class @@ -22,24 +27,28 @@ use phpbb\notification\type\type_interface; class jabber extends \phpbb\notification\method\messenger_base { - /** @var \phpbb\user */ + /** @var user */ protected $user; - /** @var \phpbb\config\config */ + /** @var config */ protected $config; + /** @var service_collection */ + protected $messenger; + /** * Notification Method jabber Constructor * - * @param \phpbb\user_loader $user_loader - * @param \phpbb\user $user - * @param \phpbb\config\config $config + * @param user_loader $user_loader + * @param user $user + * @param config $config * @param string $phpbb_root_path * @param string $php_ext + * @param service_collection $messenger */ - public function __construct(\phpbb\user_loader $user_loader, \phpbb\user $user, \phpbb\config\config $config, $phpbb_root_path, $php_ext) + public function __construct(user_loader $user_loader, user $user, config $config, $phpbb_root_path, $php_ext, service_collection $messenger) { - parent::__construct($user_loader, $phpbb_root_path, $php_ext); + parent::__construct($messenger, $user_loader, $phpbb_root_path, $php_ext); $this->user = $user; $this->config = $config; @@ -90,6 +99,6 @@ class jabber extends \phpbb\notification\method\messenger_base return; } - $this->notify_using_messenger(NOTIFY_IM, 'short/'); + $this->notify_using_messenger(messenger_interface::NOTIFY_IM, 'short/'); } } diff --git a/phpBB/phpbb/notification/method/messenger_base.php b/phpBB/phpbb/notification/method/messenger_base.php index 85461b282d..e4b97b7cac 100644 --- a/phpBB/phpbb/notification/method/messenger_base.php +++ b/phpBB/phpbb/notification/method/messenger_base.php @@ -14,6 +14,8 @@ namespace phpbb\notification\method; use phpbb\notification\type\type_interface; +use phpbb\di\service_collection; +use phpbb\user_loader; /** * Abstract notification method handling email and jabber notifications @@ -21,7 +23,10 @@ use phpbb\notification\type\type_interface; */ abstract class messenger_base extends \phpbb\notification\method\base { - /** @var \phpbb\user_loader */ + /** @var service_collection */ + protected $messenger; + + /** @var user_loader */ protected $user_loader; /** @var string */ @@ -33,12 +38,14 @@ abstract class messenger_base extends \phpbb\notification\method\base /** * Notification Method Board Constructor * - * @param \phpbb\user_loader $user_loader + * @param service_collection $messenger + * @param user_loader $user_loader * @param string $phpbb_root_path * @param string $php_ext */ - public function __construct(\phpbb\user_loader $user_loader, $phpbb_root_path, $php_ext) + public function __construct(service_collection $messenger, user_loader $user_loader, $phpbb_root_path, $php_ext) { + $this->messenger = $messenger; $this->user_loader = $user_loader; $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; @@ -60,7 +67,7 @@ abstract class messenger_base extends \phpbb\notification\method\base /** * Notify using phpBB messenger * - * @param int $notify_method Notify method for messenger (e.g. NOTIFY_IM) + * @param int $notify_method Notify method for messenger (e.g. \phpbb\messenger\method\messenger_interface::NOTIFY_IM) * @param string $template_dir_prefix Base directory to prepend to the email template name * * @return void @@ -73,13 +80,13 @@ abstract class messenger_base extends \phpbb\notification\method\base } // Load all users we want to notify (we need their email address) - $user_ids = array(); + $user_ids = []; foreach ($this->queue as $notification) { $user_ids[] = $notification->user_id; } - // We do not send emails to banned users + // We do not notify banned users if (!function_exists('phpbb_get_banned_user_ids')) { include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); @@ -89,14 +96,9 @@ abstract class messenger_base extends \phpbb\notification\method\base // Load all the users we need $this->user_loader->load_users(array_diff($user_ids, $banned_users), array(USER_IGNORE)); - // Load the messenger - if (!class_exists('messenger')) - { - include($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext); - } - $messenger = new \messenger(); + // Time to go through the queue and send notifications + $messenger_collection_iterator = $this->messenger->getIterator(); - // Time to go through the queue and send emails /** @var type_interface $notification */ foreach ($this->queue as $notification) { @@ -112,21 +114,27 @@ abstract class messenger_base extends \phpbb\notification\method\base continue; } - $messenger->template($notification->get_email_template(), $user['user_lang'], '', $template_dir_prefix); + foreach ($messenger_collection_iterator as $messenger_method) + { + if ($messenger_method->get_id() == $notify_method || $notify_method == $messenger_method::NOTIFY_BOTH) + { + $messenger_method->template($notification->get_email_template(), $user['user_lang'], '', $template_dir_prefix); + $messenger_method->set_addresses($user); + $messenger_method->assign_vars(array_merge([ + 'USERNAME' => $user['username'], + 'U_NOTIFICATION_SETTINGS' => generate_board_url() . '/ucp.' . $this->php_ext . '?i=ucp_notifications&mode=notification_options', + ], $notification->get_email_template_variables())); - $messenger->set_addresses($user); - - $messenger->assign_vars(array_merge(array( - 'USERNAME' => $user['username'], - - 'U_NOTIFICATION_SETTINGS' => generate_board_url() . '/ucp.' . $this->php_ext . '?i=ucp_notifications&mode=notification_options', - ), $notification->get_email_template_variables())); - - $messenger->send($notify_method); + $messenger_method->send(); + } + } } - // Save the queue in the messenger class (has to be called or these emails could be lost?) - $messenger->save_queue(); + // Save the queue in the messenger method class (has to be called or these messages could be lost) + foreach ($messenger_collection_iterator as $messenger_method) + { + $messenger_method->save_queue(); + } // We're done, empty the queue $this->empty_queue(); diff --git a/phpBB/phpbb/template/twig/extension.php b/phpBB/phpbb/template/twig/extension.php index 7fde9e2cac..982601e41b 100644 --- a/phpBB/phpbb/template/twig/extension.php +++ b/phpBB/phpbb/template/twig/extension.php @@ -14,6 +14,8 @@ namespace phpbb\template\twig; use Twig\Error\RuntimeError; +use Twig\Extension\CoreExtension; +use Twig\Runtime\EscaperRuntime; class extension extends \Twig\Extension\AbstractExtension { @@ -164,7 +166,7 @@ class extension extends \Twig\Extension\AbstractExtension // We always include the last element (this was the past design) $end = ($end == -1 || $end === null) ? null : $end + 1; - return twig_slice($env, $item, $start, $end, $preserveKeys); + return CoreExtension::slice($env->getCharset(), $item, $start, $end, $preserveKeys); } /** @@ -213,7 +215,7 @@ class extension extends \Twig\Extension\AbstractExtension { $args = func_get_args(); - return twig_escape_filter($this->environment, call_user_func_array([$this, 'lang'], $args), 'js'); + return $this->environment->getRuntime(EscaperRuntime::class)->escape(call_user_func_array([$this, 'lang'], $args), 'js'); } /** diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index 64c43a5d00..95a2a82b12 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -25,6 +25,7 @@ use phpbb\passwords\manager; use phpbb\request\request; use phpbb\template\template; use phpbb\user; +use phpbb\messenger\method\email; use Symfony\Component\HttpFoundation\Response; /** @@ -50,6 +51,9 @@ class reset_password /** @var log_interface */ protected $log; + /** @var email */ + protected $email_method; + /** @var manager */ protected $passwords_manager; @@ -80,6 +84,7 @@ class reset_password * @param helper $helper * @param language $language * @param log_interface $log + * @param email $email_method * @param manager $passwords_manager * @param request $request * @param template $template @@ -89,7 +94,7 @@ class reset_password * @param string $php_ext */ public function __construct(config $config, driver_interface $db, dispatcher $dispatcher, helper $helper, - language $language, log_interface $log, manager $passwords_manager, + language $language, log_interface $log, email $email_method, manager $passwords_manager, request $request, template $template, user $user, string $users_table, string $root_path, string $php_ext) { @@ -99,6 +104,7 @@ class reset_password $this->helper = $helper; $this->language = $language; $this->log = $log; + $this->email_method = $email_method; $this->passwords_manager = $passwords_manager; $this->request = $request; $this->template = $template; @@ -250,29 +256,18 @@ class reset_password WHERE user_id = ' . $user_row['user_id']; $this->db->sql_query($sql); - if (!class_exists('messenger')) - { - include($this->root_path . 'includes/functions_messenger.' . $this->php_ext); - } - - /** @var \messenger $messenger */ - $messenger = new \messenger(false); - - $messenger->template('user_forgot_password', $user_row['user_lang']); - - $messenger->set_addresses($user_row); - - $messenger->anti_abuse_headers($this->config, $this->user); - - $messenger->assign_vars([ - 'USERNAME' => html_entity_decode($user_row['username'], ENT_COMPAT), - 'U_RESET_PASSWORD' => generate_board_url(true) . $this->helper->route('phpbb_ucp_reset_password_controller', [ - 'u' => $user_row['user_id'], - 'token' => $reset_token, - ], false) + $this->email_method->set_use_queue(false); + $this->email_method->template('user_forgot_password', $user_row['user_lang']); + $this->email_method->set_addresses($user_row); + $this->email_method->anti_abuse_headers($this->config, $this->user); + $this->email_method->assign_vars([ + 'USERNAME' => html_entity_decode($user_row['username'], ENT_COMPAT), + 'U_RESET_PASSWORD' => generate_board_url(true) . $this->helper->route('phpbb_ucp_reset_password_controller', [ + 'u' => $user_row['user_id'], + 'token' => $reset_token, + ], false) ]); - - $messenger->send($user_row['user_notify_type']); + $this->email_method->send(); return $this->helper->message($message); } diff --git a/tests/console/user/activate_test.php b/tests/console/user/activate_test.php index 8eaaa4e4fc..2ff65c3e3b 100644 --- a/tests/console/user/activate_test.php +++ b/tests/console/user/activate_test.php @@ -38,6 +38,7 @@ class phpbb_console_user_activate_test extends phpbb_console_user_base $this->config, $this->language, $this->log, + $this->email, $this->notifications, $this->user_loader, $this->phpbb_root_path, diff --git a/tests/console/user/add_test.php b/tests/console/user/add_test.php index 67f1c84e72..fb2618787e 100644 --- a/tests/console/user/add_test.php +++ b/tests/console/user/add_test.php @@ -30,6 +30,7 @@ class phpbb_console_user_add_test extends phpbb_console_user_base $this->db, $this->config, $this->language, + $this->email, $this->passwords_manager, $this->phpbb_root_path, $this->php_ext diff --git a/tests/console/user/base.php b/tests/console/user/base.php index 008ac23d05..511cfff9a3 100644 --- a/tests/console/user/base.php +++ b/tests/console/user/base.php @@ -34,7 +34,7 @@ abstract class phpbb_console_user_base extends phpbb_database_test_case { global $auth, $db, $cache, $config, $user, $phpbb_dispatcher, $phpbb_container, $phpbb_root_path, $phpEx; - $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); + $phpbb_dispatcher = new \phpbb\event\dispatcher(); $phpbb_container = new phpbb_mock_container_builder(); $phpbb_container->set('cache.driver', new phpbb_mock_cache()); $phpbb_container->set('notification_manager', new phpbb_mock_notification_manager()); @@ -105,6 +105,120 @@ abstract class phpbb_console_user_base extends phpbb_database_test_case $phpbb_container->setParameter('tables.user_notifications', 'phpbb_user_notifications'); + $assets_bag = new \phpbb\template\assets_bag(); + $phpbb_container->set('assets.bag', $assets_bag); + + $phpbb_container->set('dispatcher', $phpbb_dispatcher); + + $core_cache_dir = $phpbb_root_path . 'cache/' . PHPBB_ENVIRONMENT . '/'; + $phpbb_container->setParameter('core.cache_dir', $core_cache_dir); + + $core_messenger_queue_file = $core_cache_dir . 'queue.' . $phpEx; + $phpbb_container->setParameter('core.messenger_queue_file', $core_messenger_queue_file); + + $messenger_method_collection = new \phpbb\di\service_collection($phpbb_container); + $messenger_method_collection->add('messenger.method.email'); + $phpbb_container->set('messenger.method_collection', $messenger_method_collection); + + $messenger_queue = new \phpbb\messenger\queue($config, $phpbb_dispatcher, $messenger_method_collection, $core_messenger_queue_file); + $phpbb_container->set('messenger.queue', $messenger_queue); + + $request = new phpbb_mock_request; + $phpbb_container->set('request', $request); + + $symfony_request = new \phpbb\symfony_request( + $request + ); + + $phpbb_path_helper = new \phpbb\path_helper( + $symfony_request, + $request, + $phpbb_root_path, + $phpEx + ); + $phpbb_container->set('path_helper', $phpbb_path_helper); + + $factory = new \phpbb\db\tools\factory(); + $db_doctrine = $this->new_doctrine_dbal(); + $db_tools = $factory->get($db_doctrine); + $migrator = new \phpbb\db\migrator( + $phpbb_container, + $config, + $db, + $db_tools, + 'phpbb_migrations', + $phpbb_root_path, + $this->php_ext, + 'phpbb_', + self::get_core_tables(), + [], + new \phpbb\db\migration\helper() + ); + $phpbb_container->set('migrator', $migrator); + + $finder_factory = new \phpbb\finder\factory(null, false, $phpbb_root_path, $this->php_ext); + $extension_manager = new \phpbb\extension\manager( + $phpbb_container, + $db, + $config, + $finder_factory, + 'phpbb_ext', + __DIR__ . '/', + new \phpbb\cache\service(new phpbb_mock_cache(), $config, $db, $phpbb_dispatcher, $phpbb_root_path, $this->php_ext) + ); + $phpbb_container->set('ext.manager', $extension_manager); + + $context = new \phpbb\template\context(); + $cache_path = $phpbb_root_path . 'cache/' . PHPBB_ENVIRONMENT . '/twig'; + $phpbb_container->setParameter('core.template.cache_path', $cache_path); + $filesystem = new \phpbb\filesystem\filesystem(); + $phpbb_container->set('filesystem', $filesystem); + + $twig = new \phpbb\template\twig\environment( + $assets_bag, + $this->config, + $filesystem, + $phpbb_path_helper, + $cache_path, + null, + new \phpbb\template\twig\loader(''), + $phpbb_dispatcher, + [ + 'cache' => false, + 'debug' => false, + 'auto_reload' => true, + 'autoescape' => false, + ] + ); + $twig_extension = new \phpbb\template\twig\extension($context, $twig, $this->language); + $phpbb_container->set('template.twig.extensions.phpbb', $twig_extension); + + $twig_extensions_collection = new \phpbb\di\service_collection($phpbb_container); + $twig_extensions_collection->add('template.twig.extensions.phpbb'); + $phpbb_container->set('template.twig.extensions.collection', $twig_extensions_collection); + + $twig->addExtension($twig_extension); + $twig_lexer = new \phpbb\template\twig\lexer($twig); + $phpbb_container->set('template.twig.lexer', $twig_lexer); + + $this->email = new \phpbb\messenger\method\email( + $assets_bag, + $this->config, + $phpbb_dispatcher, + $this->language, + $messenger_queue, + $phpbb_path_helper, + $request, + $twig_extensions_collection, + $twig_lexer, + $user, + $phpbb_root_path, + $cache_path, + $extension_manager, + $this->log + ); + $phpbb_container->set('messenger.method.email', $this->email); + parent::setUp(); } diff --git a/tests/email/email_parsing_test.php b/tests/email/email_parsing_test.php index a346508624..fc1d1ef3be 100644 --- a/tests/email/email_parsing_test.php +++ b/tests/email/email_parsing_test.php @@ -70,6 +70,7 @@ class phpbb_email_parsing_test extends phpbb_test_case $phpbb_container->set('assets.bag', $assets_bag); $context = new \phpbb\template\context(); + $dispatcher = new \phpbb\event\dispatcher(); $twig = new \phpbb\template\twig\environment( $assets_bag, $config, @@ -78,7 +79,7 @@ class phpbb_email_parsing_test extends phpbb_test_case $cache_path, null, new \phpbb\template\twig\loader(''), - new \phpbb\event\dispatcher(), + $dispatcher, array( 'cache' => false, 'debug' => false, @@ -94,16 +95,53 @@ class phpbb_email_parsing_test extends phpbb_test_case $phpbb_container->set('template.twig.extensions.collection', $twig_extensions_collection); $twig->addExtension($twig_extension); - $phpbb_container->set('template.twig.lexer', new \phpbb\template\twig\lexer($twig)); + $twig_lexer = new \phpbb\template\twig\lexer($twig); + $phpbb_container->set('template.twig.lexer', $twig_lexer); + $phpbb_container->set('dispatcher', $dispatcher); + $phpbb_container->set('language', $lang); + $phpbb_container->set('request', $request); - if (!class_exists('messenger')) - { - include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - } + $db = $this->getMockBuilder('\phpbb\db\driver\mysqli') + ->disableOriginalConstructor() + ->getMock(); + $auth = $this->createMock('\phpbb\auth\auth'); + $log = new \phpbb\log\log($db, $user, $auth, $dispatcher, $phpbb_root_path, 'adm/', $phpEx, LOG_TABLE); + $phpbb_container->set('log', $log); + $phpbb_container->setParameter('core.root_path', $phpbb_root_path); + $phpbb_container->setParameter('core.php_ext', $phpEx); - $this->messenger = new \messenger(); + $core_cache_dir = $phpbb_root_path . 'cache/' . PHPBB_ENVIRONMENT . '/'; + $phpbb_container->setParameter('core.cache_dir', $core_cache_dir); - $reflection = new ReflectionObject($this->messenger); + $core_messenger_queue_file = $core_cache_dir . 'queue.' . $phpEx; + $phpbb_container->setParameter('core.messenger_queue_file', $core_messenger_queue_file); + + $messenger_method_collection = new \phpbb\di\service_collection($phpbb_container); + $messenger_method_collection->add('messenger.method.email'); + $phpbb_container->set('messenger.method_collection', $messenger_method_collection); + + $messenger_queue = new \phpbb\messenger\queue($config, $dispatcher, $messenger_method_collection, $core_messenger_queue_file); + $phpbb_container->set('messenger.queue', $messenger_queue); + + $this->email = new \phpbb\messenger\method\email( + $assets_bag, + $config, + $dispatcher, + $lang, + $messenger_queue, + $phpbb_path_helper, + $request, + $twig_extensions_collection, + $twig_lexer, + $user, + $phpbb_root_path, + $cache_path, + $extension_manager, + $log + ); + $phpbb_container->set('messenger.method.email', $this->email); + + $reflection = new ReflectionObject($this->email); $this->reflection_template_property = $reflection->getProperty('template'); $this->reflection_template_property->setAccessible(true); } @@ -123,9 +161,9 @@ class phpbb_email_parsing_test extends phpbb_test_case { global $config, $phpEx, $user; - $this->messenger->set_addresses($user->data); + $this->email->set_addresses($user->data); - $this->messenger->assign_vars(array( + $this->email->assign_vars(array( 'EMAIL_SIG' => str_replace('
', "\n", "-- \n" . html_entity_decode($config['board_email_sig'], ENT_COMPAT)), 'SITENAME' => html_entity_decode($config['sitename'], ENT_COMPAT), @@ -137,9 +175,9 @@ class phpbb_email_parsing_test extends phpbb_test_case 'U_FORUM' => generate_board_url() . "/viewforum.{$phpEx}?f=1", 'U_STOP_WATCHING_FORUM' => generate_board_url() . "/viewforum.{$phpEx}?uid=2&f=1&unwatch=forum", )); - $this->messenger->template('newtopic_notify', $user->data['user_lang'], '', ''); + $this->email->template('newtopic_notify', $user->data['user_lang'], '', ''); - $reflection_template = $this->reflection_template_property->getValue($this->messenger); + $reflection_template = $this->reflection_template_property->getValue($this->email); $msg = trim($reflection_template->assign_display('body')); $this->assertStringContainsString($author_name, $msg); diff --git a/tests/email/headers_encoding_test.php b/tests/email/headers_encoding_test.php deleted file mode 100644 index a884a4cc21..0000000000 --- a/tests/email/headers_encoding_test.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @license GNU General Public License, version 2 (GPL-2.0) - * - * For full copyright and license information, please see - * the docs/CREDITS.txt file. - * - */ - -class phpbb_headers_encoding_test extends phpbb_test_case -{ - protected function setUp(): void - { - global $phpbb_root_path, $phpEx; - - if (!function_exists('mail_encode')) - { - include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - } - } - - public function headers_encoding_data() - { - return [ - ['test@yourdomain.com ', 'Q', 'US-ASCII'], - ['test@yourdomain.com <Несуществующий почтовый адрес phpBB>', 'B', 'UTF-8'], - ["\xE3\x83\x86\xE3\x82\xB9\xE3\x83\x88\xE3\x83\x86\xE3\x82\xB9\xE3\x83\x88", 'B', 'UTF-8'], - ]; - } - - /** - * @dataProvider headers_encoding_data - */ - public function test_headers_encoding($header, $scheme, $encoding) - { - $encoded_string = mail_encode($header); - $this->assertStringStartsWith("=?$encoding?$scheme?", $encoded_string); - $this->assertStringEndsWith('?=', $encoded_string); - - // Result of iconv_mime_decode() on decoded header should be equal to initial header - $decoded_string = iconv_mime_decode($encoded_string, 0, $encoding); - $this->assertEquals(0, strcmp($header, $decoded_string)); - } -} diff --git a/tests/functional/acp_test.php b/tests/functional/acp_test.php new file mode 100644 index 0000000000..bf37fc7203 --- /dev/null +++ b/tests/functional/acp_test.php @@ -0,0 +1,65 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +/** +* @group functional +*/ +class phpbb_functional_acp_test extends phpbb_functional_test_case +{ + public function test_all_acp_module_links() + { + $this->login(); + $this->admin_login(); + $this->add_lang(['common']); + + // Browse ACP main page + $crawler = self::request('GET', 'index.php'); + $crawler = self::$client->click($crawler->selectLink($this->lang('ACP_SHORT'))->link()); + self::assert_response_html(); + + // Get all ACP module URLs array + $acp_modules = $crawler->filter('li.tab a')->each( + function ($node, $i) + { + // Filter out responsive mode links + if (empty($node->attr('class'))) + { + return $node->link(); + } + } + ); + $this->assertNotEmpty($acp_modules); + + // Browse all ACP modules and get their mode URLs array + $acp_submodules = []; + foreach ($acp_modules as $module) + { + $crawler = self::$client->click($module); + self::assert_response_html(); + $acp_submodules = array_merge($acp_submodules, $crawler->filter('div.menu-block li a')->each( + function ($node, $i) + { + return $node->link(); + } + )); + } + $this->assertNotEmpty($acp_submodules); + + // Browse all ACP submodules' modes + foreach ($acp_submodules as $acp_submodule) + { + self::$client->click($acp_submodule); + self::assert_response_html(); + } + } +} diff --git a/tests/functional/mcp/mcp_test.php b/tests/functional/mcp/mcp_test.php index ff8dff4564..b2d8fd6cac 100644 --- a/tests/functional/mcp/mcp_test.php +++ b/tests/functional/mcp/mcp_test.php @@ -24,6 +24,7 @@ class phpbb_functional_mcp_test extends phpbb_functional_test_case // Browse MCP main page $crawler = self::request('GET', 'index.php'); $crawler = self::$client->click($crawler->selectLink($this->lang('MCP_SHORT'))->link()); + self::assert_response_html(); // Get all MCP module URLs array $mcp_modules = $crawler->filter('.tabs a')->each( @@ -32,12 +33,14 @@ class phpbb_functional_mcp_test extends phpbb_functional_test_case return $node->link(); } ); + $this->assertNotEmpty($mcp_modules); // Browse all MCP modules and get their mode URLs array $mcp_submodules = []; foreach ($mcp_modules as $module) { $crawler = self::$client->click($module); + self::assert_response_html(); $mcp_submodules = array_merge($mcp_submodules, $crawler->filter('.cp-menu a')->each( function ($node, $i) { @@ -45,11 +48,13 @@ class phpbb_functional_mcp_test extends phpbb_functional_test_case } )); } + $this->assertNotEmpty($mcp_submodules); // Browse all MCP submodules' modes foreach ($mcp_submodules as $mcp_submodule) { self::$client->click($mcp_submodule); + self::assert_response_html(); } } } diff --git a/tests/notification/base.php b/tests/notification/base.php index 8e6f67c219..07fef3a1c5 100644 --- a/tests/notification/base.php +++ b/tests/notification/base.php @@ -146,6 +146,11 @@ abstract class phpbb_tests_notification_base extends phpbb_database_test_case $phpbb_container->addCompilerPass(new phpbb\di\pass\markpublic_pass()); + $messenger_method_collection = new \phpbb\di\service_collection($phpbb_container); + $messenger_method_collection->add('messenger.method.email'); + $messenger_method_collection->add('messenger.method.jabber'); + $phpbb_container->set('messenger.method_collection', $messenger_method_collection); + $phpbb_container->compile(); $this->notifications->setDependencies($this->auth, $this->config); diff --git a/tests/notification/notification_method_email_test.php b/tests/notification/notification_method_email_test.php index 6b464b1c42..15811cc968 100644 --- a/tests/notification/notification_method_email_test.php +++ b/tests/notification/notification_method_email_test.php @@ -105,6 +105,11 @@ class notification_method_email_test extends phpbb_tests_notification_base ) ); + $messenger_method_collection = new \phpbb\di\service_collection($phpbb_container); + $messenger_method_collection->add('messenger.method.email'); + $messenger_method_collection->add('messenger.method.jabber'); + $phpbb_container->set('messenger.method_collection', $messenger_method_collection); + $this->notification_method_email = $this->getMockBuilder('\phpbb\notification\method\email') ->setConstructorArgs([ $phpbb_container->get('user_loader'), @@ -113,7 +118,8 @@ class notification_method_email_test extends phpbb_tests_notification_base $phpbb_container->get('dbal.conn'), $phpbb_root_path, $phpEx, - $phpbb_container->getParameter('tables.notification_emails') + $phpbb_container->getParameter('tables.notification_emails'), + $phpbb_container->get('messenger.method_collection') ]) ->setMethods(['notify_using_messenger']) ->getMock(); diff --git a/tests/notification/notification_method_webpush_test.php b/tests/notification/notification_method_webpush_test.php index 1116a62c6f..7967a0f7c6 100644 --- a/tests/notification/notification_method_webpush_test.php +++ b/tests/notification/notification_method_webpush_test.php @@ -171,6 +171,9 @@ class notification_method_webpush_test extends phpbb_tests_notification_base $ban_manager = new \phpbb\ban\manager($collection, new \phpbb\cache\driver\dummy(), $this->db, $this->language, $this->log, $user, 'phpbb_bans', 'phpbb_users'); $phpbb_container->set('ban.manager', $ban_manager); + $messenger_method_collection = new \phpbb\di\service_collection($phpbb_container); + $phpbb_container->set('messenger.method_collection', $messenger_method_collection); + $this->notification_method_webpush = new \phpbb\notification\method\webpush( $phpbb_container->get('config'), $phpbb_container->get('dbal.conn'), diff --git a/tests/notification/submit_post_base.php b/tests/notification/submit_post_base.php index 124ac4d1b4..57b1242509 100644 --- a/tests/notification/submit_post_base.php +++ b/tests/notification/submit_post_base.php @@ -158,6 +158,12 @@ abstract class phpbb_notification_submit_post_base extends phpbb_database_test_c $phpbb_container->setParameter('tables.notification_push', 'phpbb_notification_push'); $phpbb_container->setParameter('tables.push_subscriptions', 'phpbb_push_subscriptions'); $phpbb_container->set('content.visibility', new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE)); + + $messenger_method_collection = new \phpbb\di\service_collection($phpbb_container); + $messenger_method_collection->add('messenger.method.email'); + $messenger_method_collection->add('messenger.method.jabber'); + $phpbb_container->set('messenger.method_collection', $messenger_method_collection); + $phpbb_container->addCompilerPass(new phpbb\di\pass\markpublic_pass()); $phpbb_container->compile(); diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 2ce670d390..79e76fd1ae 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -324,6 +324,123 @@ class phpbb_functional_test_case extends phpbb_test_case return $extension_manager; } + protected static function get_messenger_method_email($container) + { + global $phpbb_root_path, $phpEx; + + $config = new \phpbb\config\config( + [ + 'version' => PHPBB_VERSION, + 'email_enable' => false, + 'email_package_size' => 0, + 'smtp_delivery' => 0, + 'default_lang' => 'en', + ] + ); + + $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); + $lang = new \phpbb\language\language($lang_loader); + $user = new \phpbb\user($lang, '\phpbb\datetime'); + $container->set('user', $user); + $container->set('language', $lang); + + $assets_bag = new \phpbb\template\assets_bag(); + $container->set('assets.bag', $assets_bag); + + $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); + $container->set('dispatcher', $phpbb_dispatcher); + + $core_cache_dir = $phpbb_root_path . 'cache/' . PHPBB_ENVIRONMENT . '/'; + $container->setParameter('core.cache_dir', $core_cache_dir); + + $core_messenger_queue_file = $core_cache_dir . 'queue.' . $phpEx; + $container->setParameter('core.messenger_queue_file', $core_messenger_queue_file); + + $messenger_method_collection = new \phpbb\di\service_collection($container); + $messenger_method_collection->add('messenger.method.email'); + $container->set('messenger.method_collection', $messenger_method_collection); + + $messenger_queue = new \phpbb\messenger\queue($config, $phpbb_dispatcher, $messenger_method_collection, $core_messenger_queue_file); + $container->set('messenger.queue', $messenger_queue); + + $request = new phpbb_mock_request; + $container->set('request', $request); + + $symfony_request = new \phpbb\symfony_request( + $request + ); + + $phpbb_path_helper = new \phpbb\path_helper( + $symfony_request, + $request, + $phpbb_root_path, + $phpEx + ); + $container->set('path_helper', $phpbb_path_helper); + + $dbms = self::$config['dbms']; + $db = new $dbms(); + $db->sql_connect(self::$config['dbhost'], self::$config['dbuser'], self::$config['dbpasswd'], self::$config['dbname'], self::$config['dbport']); + + $extension_manager = new phpbb_mock_extension_manager($phpbb_root_path, [], $container); + $container->set('ext.manager', $extension_manager); + + $context = new \phpbb\template\context(); + $cache_path = $phpbb_root_path . 'cache/' . PHPBB_ENVIRONMENT . '/twig'; + $container->setParameter('core.template.cache_path', $cache_path); + $filesystem = new \phpbb\filesystem\filesystem(); + $container->set('filesystem', $filesystem); + + $twig = new \phpbb\template\twig\environment( + $assets_bag, + $config, + $filesystem, + $phpbb_path_helper, + $cache_path, + null, + new \phpbb\template\twig\loader(''), + $phpbb_dispatcher, + [ + 'cache' => false, + 'debug' => false, + 'auto_reload' => true, + 'autoescape' => false, + ] + ); + $twig_extension = new \phpbb\template\twig\extension($context, $twig, $lang); + $container->set('template.twig.extensions.phpbb', $twig_extension); + + $twig_extensions_collection = new \phpbb\di\service_collection($container); + $twig_extensions_collection->add('template.twig.extensions.phpbb'); + $container->set('template.twig.extensions.collection', $twig_extensions_collection); + + $twig->addExtension($twig_extension); + $twig_lexer = new \phpbb\template\twig\lexer($twig); + $container->set('template.twig.lexer', $twig_lexer); + + $auth = new \phpbb\auth\auth(); + $log = new \phpbb\log\log($db, $user, $auth, $phpbb_dispatcher, $phpbb_root_path, 'adm/', $phpEx, LOG_TABLE); + $container->set('log', $log); + + $email_method = new \phpbb\messenger\method\email( + $assets_bag, + $config, + $phpbb_dispatcher, + $lang, + $messenger_queue, + $phpbb_path_helper, + $request, + $twig_extensions_collection, + $twig_lexer, + $user, + $phpbb_root_path, + $cache_path, + $extension_manager, + $log + ); + $container->set('messenger.method.email', $email_method); + } + protected static function install_board() { global $phpbb_root_path, $phpEx; @@ -374,6 +491,7 @@ class phpbb_functional_test_case extends phpbb_test_case $container->set('installer.install_finish.notify_user', new phpbb_mock_null_installer_task()); $container->register('installer.install_finish.install_extensions')->setSynthetic(true); $container->set('installer.install_finish.install_extensions', new phpbb_mock_null_installer_task()); + self::get_messenger_method_email($container); $container->compile(); $language = $container->get('language'); @@ -418,8 +536,7 @@ class phpbb_functional_test_case extends phpbb_test_case $iohandler->set_input('email_enable', true); $iohandler->set_input('smtp_delivery', '1'); - $iohandler->set_input('smtp_host', 'nxdomain.phpbb.com'); - $iohandler->set_input('smtp_auth', 'PLAIN'); + $iohandler->set_input('smtp_host', ''); $iohandler->set_input('smtp_user', 'nxuser'); $iohandler->set_input('smtp_pass', 'nxpass'); $iohandler->set_input('submit_email', 'submit'); diff --git a/vagrant/phpbb-install-config.yml b/vagrant/phpbb-install-config.yml index db7b525b9f..0b89958299 100644 --- a/vagrant/phpbb-install-config.yml +++ b/vagrant/phpbb-install-config.yml @@ -38,7 +38,6 @@ installer: enabled: false smtp_delivery : ~ smtp_host: ~ - smtp_auth: ~ smtp_user: ~ smtp_pass: ~