diff options
22 files changed, 1689 insertions, 351 deletions
diff --git a/Postman/Extensions/Admin/PostmanAdmin.php b/Postman/Extensions/Admin/PostmanAdmin.php new file mode 100644 index 0000000..3b61a0a --- /dev/null +++ b/Postman/Extensions/Admin/PostmanAdmin.php @@ -0,0 +1,31 @@ +<?php +if ( ! defined( 'ABSPATH' ) ) exit; + +class PostmanAdmin { + + public function __construct() + { + $PostmanLicenseManager = PostmanLicenseManager::get_instance(); + $extensions = $PostmanLicenseManager->get_extensions(); + + if ( count( $extensions ) > 0 ) { + add_action('admin_menu', [ $this, 'add_menu' ], 20 ); + } + + } + + public function add_menu() { + add_submenu_page( + PostmanViewController::POSTMAN_MENU_SLUG, + __('Extensions', 'post-smtp'), + __('Extensions', 'post-smtp'), + 'manage_options', + 'post-smtp-extensions', + [ $this, 'render_menu' ] + ); + } + + public function render_menu() { + include_once 'PostmanAdminView.php'; + } +} diff --git a/Postman/Extensions/Admin/PostmanAdminView.php b/Postman/Extensions/Admin/PostmanAdminView.php new file mode 100644 index 0000000..c9f0509 --- /dev/null +++ b/Postman/Extensions/Admin/PostmanAdminView.php @@ -0,0 +1,86 @@ +<?php if ( ! defined( 'ABSPATH' ) ) exit; ?> + +<style> + .form-table .row { + display: flex; + } + + .form-table .row .flex > *:not(:last-child) { + margin-right: 5px; + } + + .form-table .label { + align-self: center; + font-weight: bold; + } + + .form-table .flex { + display: flex; + } + + .form-table .flex input { + border-radius: 3px; + height: 30px; + margin: 0; + margin-left: 5px; + } + + .form-table .flex button { + box-shadow: none; + height: 100%; + } +</style> + +<div class="wrap"> + <h1>Post SMTP Installed Extensions</h1> + <form action="" method="post"> + <div class="form-table"> + <?php + $PostmanLicenseManager = PostmanLicenseManager::get_instance(); + $extensions = $PostmanLicenseManager->get_extensions(); + + foreach ( $extensions as $slug => $extension) : + $short_name = $extension['license_manager']->get_slug( $extension['plugin_data']['Name'] ); + $nonce = $short_name . '_license_key-nonce'; + + $license_data = get_option( $short_name . '_license_active' ); + $license_key = get_option( $short_name . '_license_key' ); + + $license_valid = is_object( $license_data ) && $license_data->license === 'valid'; + $license_field_class = $license_valid ? 'readonly' : ''; + $license_field_value = $license_valid ? base64_encode($license_key) : ''; + + wp_nonce_field( $nonce, $nonce ); + ?> + + <div class="row"> + <div class="label"> + <?php echo esc_html( $extension['plugin_data']['Name'] ); ?> + </div> + + <div class="flex"> + <div class="input"> + <input <?php echo $license_field_class; ?> + type="password" + name="post_smtp_extension[<?php echo $short_name . '_license_key'; ?>]" + class="regular-text" + value="<?php echo $license_field_value; ?>" + placeholder="Serial Key"> + </div> + + <div class="buttons"> + <?php if ( ! $license_valid ) :?> + <button type="submit" name="post_smtp_extension[<?php echo $short_name; ?>_activate]" class="button button-primary">Activate</button> + <?php endif; ?> + + <button type="submit" name="post_smtp_extension[<?php echo $short_name; ?>_deactivate]" class="button button-secondary">Deactivate</button> + </div> + </div> + + </div> + + <?php endforeach; ?> + + </div> + </form> +</div> diff --git a/Postman/notifications/INotify.php b/Postman/Extensions/Core/Notifications/INotify.php index f40548d..f40548d 100644 --- a/Postman/notifications/INotify.php +++ b/Postman/Extensions/Core/Notifications/INotify.php diff --git a/Postman/notifications/PostmanMailNotify.php b/Postman/Extensions/Core/Notifications/PostmanMailNotify.php index 922c304..922c304 100644 --- a/Postman/notifications/PostmanMailNotify.php +++ b/Postman/Extensions/Core/Notifications/PostmanMailNotify.php diff --git a/Postman/Extensions/Core/Notifications/PostmanNotify.php b/Postman/Extensions/Core/Notifications/PostmanNotify.php new file mode 100644 index 0000000..d9f6a58 --- /dev/null +++ b/Postman/Extensions/Core/Notifications/PostmanNotify.php @@ -0,0 +1,241 @@ +<?php +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly +} +require_once 'INotify.php'; +require_once 'PostmanMailNotify.php'; +require_once 'PostmanPushoverNotify.php'; +require_once 'PostmanSlackNotify.php'; +require_once 'PostmanNotifyOptions.php'; + +class PostmanNotify { + + const NOTIFICATIONS_OPTIONS = 'postman_notifications_options'; + const NOTIFICATIONS_SECTION = 'postman_notifications_section'; + const NOTIFICATIONS_PUSHOVER_CRED = 'postman_pushover_cred'; + const NOTIFICATIONS_SLACK_CRED = 'postman_slack_cred'; + + public function __construct() { + + $this->options = new PostmanNotifyOptions(); + + add_filter( 'post_smtp_admin_tabs', array( $this, 'tabs' ) ); + add_action( 'post_smtp_settings_menu', array( $this, 'menu' ) ); + add_action( 'post_smtp_settings_fields', array( $this, 'settings' ) ); + add_action( 'post_smtp_on_failed', array( $this, 'notify' ), 10, 5 ); + add_filter( 'post_smtp_sanitize', array( $this, 'sanitize' ), 10, 3 ); + } + + public function menu() { + print '<section id="notifications">'; + do_settings_sections( self::NOTIFICATIONS_OPTIONS ); + + $currentKey = $this->options->getNotificationService(); + $pushover = $currentKey == 'pushover' ? 'block' : 'none'; + $slack = $currentKey == 'slack' ? 'block' : 'none'; + + echo '<div id="pushover_cred" style="display: ' . $pushover . ';">'; + do_settings_sections( self::NOTIFICATIONS_PUSHOVER_CRED ); + echo '</div>'; + + echo '<div id="slack_cred" style="display: ' . $slack . ';">'; + do_settings_sections( self::NOTIFICATIONS_SLACK_CRED ); + echo '</div>'; + + do_action( 'post_smtp_notification_settings' ); + + print '</section>'; + } + + public function sanitize($new_input, $input, $sanitizer) { + // Notifications + $sanitizer->sanitizeString( 'Pushover Service', PostmanNotifyOptions::NOTIFICATION_SERVICE, $input, $new_input, $this->options->getNotificationService() ); + $sanitizer->sanitizePassword( 'Pushover Username', PostmanNotifyOptions::PUSHOVER_USER, $input, $new_input, $this->options->getPushoverUser() ); + $sanitizer->sanitizePassword( 'Pushover Token', PostmanNotifyOptions::PUSHOVER_TOKEN, $input, $new_input, $this->options->getPushoverToken() ); + $sanitizer->sanitizePassword( 'Slack Token', PostmanNotifyOptions::SLACK_TOKEN, $input, $new_input, $this->options->getSlackToken() ); + + // Chrome extension + $sanitizer->sanitizeString( 'Push Chrome Extension', PostmanNotifyOptions::NOTIFICATION_USE_CHROME, $input, $new_input ); + $sanitizer->sanitizePassword( 'Push Chrome Extension UID', PostmanNotifyOptions::NOTIFICATION_CHROME_UID, $input, $new_input, $this->options->getNotificationChromeUid() ); + + return $new_input; + } + + public function tabs($tabs) { + $tabs['notifications'] = __( 'Notifications', 'post-smtp' ); + + return $tabs; + } + + public function settings() { + // Notifications + add_settings_section( self::NOTIFICATIONS_SECTION, _x( 'Notifications Settings', 'Configuration Section Title', 'post-smtp' ), array( + $this, + 'printNotificationsSectionInfo', + ), self::NOTIFICATIONS_OPTIONS ); + + add_settings_field( PostmanNotifyOptions::NOTIFICATION_SERVICE, _x( 'Notification Service', 'Configuration Input Field', 'post-smtp' ), array( + $this, + 'notification_service_callback', + ), self::NOTIFICATIONS_OPTIONS, self::NOTIFICATIONS_SECTION ); + + // Pushover + add_settings_section( 'pushover_credentials', _x( 'Pushover Credentials', 'Configuration Section Title', 'post-smtp' ), array( + $this, + 'printNotificationsSectionInfo', + ), self::NOTIFICATIONS_PUSHOVER_CRED ); + + add_settings_field( PostmanNotifyOptions::PUSHOVER_USER, _x( 'Pushover User Key', 'Configuration Input Field', 'post-smtp' ), array( + $this, + 'pushover_user_callback', + ), self::NOTIFICATIONS_PUSHOVER_CRED, 'pushover_credentials' ); + + add_settings_field( PostmanNotifyOptions::PUSHOVER_TOKEN, _x( 'Pushover App Token', 'Configuration Input Field', 'post-smtp' ), array( + $this, + 'pushover_token_callback', + ), self::NOTIFICATIONS_PUSHOVER_CRED, 'pushover_credentials' ); + + // Slack + add_settings_section( 'slack_credentials', _x( 'Slack Credentials', 'Configuration Section Title', 'post-smtp' ), array( + $this, + 'printNotificationsSectionInfo', + ), self::NOTIFICATIONS_SLACK_CRED ); + + add_settings_field( PostmanNotifyOptions::SLACK_TOKEN, _x( 'Slack Webhook', 'Configuration Input Field', 'post-smtp' ), array( + $this, + 'slack_token_callback', + ), self::NOTIFICATIONS_SLACK_CRED, 'slack_credentials' ); + + add_settings_field( PostmanNotifyOptions::NOTIFICATION_USE_CHROME, _x( 'Push to chrome extension', 'Configuration Input Field', 'post-smtp' ), array( + $this, + 'notification_use_chrome_callback', + ), self::NOTIFICATIONS_OPTIONS, self::NOTIFICATIONS_SECTION ); + + add_settings_field( 'notification_chrome_uid', _x( 'Chrome Extension UID', 'Configuration Input Field', 'post-smtp' ), array( + $this, + 'notification_chrome_uid_callback', + ), self::NOTIFICATIONS_OPTIONS, self::NOTIFICATIONS_SECTION ); + } + + /** + * Print the Section text + */ + public function printNotificationsSectionInfo() { + } + + public function notification_service_callback() { + $inputDescription = __( 'Select the notification service you want to recieve alerts about failed emails.' ); + + $options = apply_filters('post_smtp_notification_service', array( + 'none' => __( 'None', 'post-smtp' ), + 'default' => __( 'WP Admin Email', 'post-smtp' ), + 'pushover' => __( 'Pushover', 'post-smtp' ), + 'slack' => __( 'Slack', 'post-smtp' ), + )); + + printf( '<select id="input_%2$s" class="input_%2$s" name="%1$s[%2$s]">', 'postman_options', PostmanNotifyOptions::NOTIFICATION_SERVICE ); + $currentKey = $this->options->getNotificationService(); + + foreach ( $options as $key => $label ) { + $this->printSelectOption( $label, $key, $currentKey ); + } + + printf( '</select><br/><span class="postman_input_description">%s</span>', $inputDescription ); + } + + public function notification_use_chrome_callback() { + $value = $this->options->useChromeExtension(); + printf( '<input type="checkbox" id="input_%2$s" class="input_%2$s" name="%1$s[%2$s]" %3$s />', 'postman_options', PostmanNotifyOptions::NOTIFICATION_USE_CHROME, $value ? 'checked="checked"' : '' ); + } + + public function notification_chrome_uid_callback() { + printf( '<input type="password" id="input_%2$s" class="input_%2$s" name="%1$s[%2$s]" value="%3$s" />', 'postman_options', 'notification_chrome_uid', PostmanUtils::obfuscatePassword( $this->options->getNotificationChromeUid() ) ); + } + + public function pushover_user_callback() { + printf( '<input type="password" id="pushover_user" name="%s[%s]" value="%s" />', 'postman_options', PostmanNotifyOptions::PUSHOVER_USER, $this->options->getPushoverUser() ); + } + + public function pushover_token_callback() { + printf( '<input type="password" id="pushover_token" name="%s[%s]" value="%s" />', 'postman_options', PostmanNotifyOptions::PUSHOVER_TOKEN, $this->options->getPushoverToken() ); + } + + public function slack_token_callback() { + printf( '<input type="password" id="slack_token" name="%s[%s]" value="%s" />', 'postman_options', PostmanNotifyOptions::SLACK_TOKEN, $this->options->getSlackToken() ); + echo '<a target="_blank" href="https://slack.postmansmtp.com/">' . __( 'Get your webhook URL here', 'post-smtp' ) . '</a>'; + + } + + /** + * @param PostmanEmailLog $log + * @param PostmanMessage $message + * @param string $transcript + * @param PostmanTransport $transport + * @param string $errorMessage + */ + public function notify ($log, $postmanMessage, $transcript, $transport, $errorMessage ) { + $message = __( 'You getting this message because an error detected while delivered your email.', 'post-smtp' ); + $message .= "\r\n" . sprintf( __( 'For the domain: %1$s','post-smtp' ), get_bloginfo('url') ); + $message .= "\r\n" . __( 'The log to paste when you open a support issue:', 'post-smtp' ) . "\r\n"; + + if ( $errorMessage && ! empty( $errorMessage ) ) { + + $message = $message . $errorMessage; + + $notification_service = PostmanNotifyOptions::getInstance()->getNotificationService(); + switch ($notification_service) { + case 'none': + $notifyer = false; + break; + case 'default': + $notifyer = new PostmanMailNotify; + break; + case 'pushover': + $notifyer = new PostmanPushoverNotify; + break; + case 'slack': + $notifyer = new PostmanSlackNotify; + break; + default: + $notifyer = new PostmanMailNotify; + } + + $notifyer = apply_filters('post_smtp_notifier', $notifyer, $notification_service); + + // Notifications + if ( $notifyer ) { + $notifyer->send_message($message, $log); + } + + $this->push_to_chrome($errorMessage); + } + } + + public function push_to_chrome($message) { + $push_chrome = PostmanNotifyOptions::getInstance()->useChromeExtension(); + + if ( $push_chrome ) { + $uid = PostmanNotifyOptions::getInstance()->getNotificationChromeUid(); + + if ( empty( $uid ) ) { + return; + } + + $url = 'https://postmansmtp.com/chrome/' . $uid; + + $args = array( + 'body' => array( + 'message' => $message + ) + ); + + $response = wp_remote_post( $url , $args ); + } + } + + private function printSelectOption( $label, $optionKey, $currentKey ) { + $optionPattern = '<option value="%1$s" %2$s>%3$s</option>'; + printf( $optionPattern, $optionKey, $optionKey == $currentKey ? 'selected="selected"' : '', $label ); + } +} +new PostmanNotify();
\ No newline at end of file diff --git a/Postman/Extensions/Core/Notifications/PostmanNotifyOptions.php b/Postman/Extensions/Core/Notifications/PostmanNotifyOptions.php new file mode 100644 index 0000000..08c27db --- /dev/null +++ b/Postman/Extensions/Core/Notifications/PostmanNotifyOptions.php @@ -0,0 +1,57 @@ +<?php + +class PostmanNotifyOptions { + + const DEFAULT_NOTIFICATION_SERVICE = 'default'; + const NOTIFICATION_SERVICE = 'notification_service'; + const NOTIFICATION_USE_CHROME = 'notification_use_chrome'; + const NOTIFICATION_CHROME_UID = 'notification_chrome_uid'; + const PUSHOVER_USER = 'pushover_user'; + const PUSHOVER_TOKEN = 'pushover_token'; + const SLACK_TOKEN = 'slack_token'; + + private $options; + + public function __construct() + { + $this->options = get_option( 'postman_options' ); + } + + public function getNotificationService() { + if ( isset( $this->options [ self::NOTIFICATION_SERVICE ] ) ) { + return $this->options [ self::NOTIFICATION_SERVICE ]; + } else { + return self::DEFAULT_NOTIFICATION_SERVICE; + } + } + + public function getPushoverUser() { + if ( isset( $this->options [ self::PUSHOVER_USER ] ) ) { + return base64_decode( $this->options [ self::PUSHOVER_USER ] ); + } + } + + public function getPushoverToken() { + if ( isset( $this->options [ self::PUSHOVER_TOKEN ] ) ) { + return base64_decode( $this->options [ self::PUSHOVER_TOKEN ] ); + } + } + + public function getSlackToken() { + if ( isset( $this->options [ self::SLACK_TOKEN ] ) ) { + return base64_decode( $this->options [ self::SLACK_TOKEN ] ); + } + } + + public function useChromeExtension() { + if ( isset( $this->options [ self::NOTIFICATION_USE_CHROME ] ) ) { + return $this->options [ self::NOTIFICATION_USE_CHROME ]; + } + } + + public function getNotificationChromeUid() { + if ( isset( $this->options [ self::NOTIFICATION_CHROME_UID ] ) ) { + return base64_decode( $this->options [ self::NOTIFICATION_CHROME_UID ] ); + } + } +}
\ No newline at end of file diff --git a/Postman/notifications/PostmanPushoverNotify.php b/Postman/Extensions/Core/Notifications/PostmanPushoverNotify.php index 14ef7d2..14ef7d2 100644 --- a/Postman/notifications/PostmanPushoverNotify.php +++ b/Postman/Extensions/Core/Notifications/PostmanPushoverNotify.php diff --git a/Postman/notifications/PostmanSlackNotify.php b/Postman/Extensions/Core/Notifications/PostmanSlackNotify.php index 5b6fae3..5b6fae3 100644 --- a/Postman/notifications/PostmanSlackNotify.php +++ b/Postman/Extensions/Core/Notifications/PostmanSlackNotify.php diff --git a/Postman/Extensions/License/EDD_SL_Plugin_Updater.php b/Postman/Extensions/License/EDD_SL_Plugin_Updater.php new file mode 100644 index 0000000..0673834 --- /dev/null +++ b/Postman/Extensions/License/EDD_SL_Plugin_Updater.php @@ -0,0 +1,585 @@ +<?php + +// Exit if accessed directly +if ( ! defined( 'ABSPATH' ) ) exit; + +/** + * Allows plugins to use their own update API. + * + * @author Easy Digital Downloads + * @version 1.6.19 + */ +class EDD_SL_Plugin_Updater { + + private $api_url = ''; + private $api_data = array(); + private $name = ''; + private $slug = ''; + private $version = ''; + private $wp_override = false; + private $cache_key = ''; + + private $health_check_timeout = 5; + + /** + * Class constructor. + * + * @uses plugin_basename() + * @uses hook() + * + * @param string $_api_url The URL pointing to the custom API endpoint. + * @param string $_plugin_file Path to the plugin file. + * @param array $_api_data Optional data to send with API calls. + */ + public function __construct( $_api_url, $_plugin_file, $_api_data = null ) { + + global $edd_plugin_data; + + $this->api_url = trailingslashit( $_api_url ); + $this->api_data = $_api_data; + $this->name = plugin_basename( $_plugin_file ); + $this->slug = basename( $_plugin_file, '.php' ); + $this->version = $_api_data['version']; + $this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false; + $this->beta = ! empty( $this->api_data['beta'] ) ? true : false; + $this->cache_key = 'edd_sl_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) ); + + $edd_plugin_data[ $this->slug ] = $this->api_data; + + /** + * Fires after the $edd_plugin_data is setup. + * + * @since x.x.x + * + * @param array $edd_plugin_data Array of EDD SL plugin data. + */ + do_action( 'post_edd_sl_plugin_updater_setup', $edd_plugin_data ); + + // Set up hooks. + $this->init(); + + } + + /** + * Set up WordPress filters to hook into WP's update process. + * + * @uses add_filter() + * + * @return void + */ + public function init() { + + add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) ); + add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 ); + remove_action( 'after_plugin_row_' . $this->name, 'wp_plugin_update_row', 10 ); + add_action( 'after_plugin_row_' . $this->name, array( $this, 'show_update_notification' ), 10, 2 ); + add_action( 'admin_init', array( $this, 'show_changelog' ) ); + + } + + /** + * Check for Updates at the defined API endpoint and modify the update array. + * + * This function dives into the update API just when WordPress creates its update array, + * then adds a custom API call and injects the custom plugin data retrieved from the API. + * It is reassembled from parts of the native WordPress plugin update code. + * See wp-includes/update.php line 121 for the original wp_update_plugins() function. + * + * @uses api_request() + * + * @param array $_transient_data Update array build by WordPress. + * @return array Modified update array with custom plugin data. + */ + public function check_update( $_transient_data ) { + + global $pagenow; + + if ( ! is_object( $_transient_data ) ) { + $_transient_data = new stdClass; + } + + if ( 'plugins.php' == $pagenow && is_multisite() ) { + return $_transient_data; + } + + if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) { + return $_transient_data; + } + + $version_info = $this->get_cached_version_info(); + + if ( false === $version_info ) { + $version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug, 'beta' => $this->beta ) ); + + $this->set_version_info_cache( $version_info ); + + } + + if ( false !== $version_info && is_object( $version_info ) && isset( $version_info->new_version ) ) { + + if ( version_compare( $this->version, $version_info->new_version, '<' ) ) { + + $_transient_data->response[ $this->name ] = $version_info; + + // Make sure the plugin property is set to the plugin's name/location. See issue 1463 on Software Licensing's GitHub repo. + $_transient_data->response[ $this->name ]->plugin = $this->name; + + } + + $_transient_data->last_checked = time(); + $_transient_data->checked[ $this->name ] = $this->version; + + } + + return $_transient_data; + } + + /** + * show update nofication row -- needed for multisite subsites, because WP won't tell you otherwise! + * + * @param string $file + * @param array $plugin + */ + public function show_update_notification( $file, $plugin ) { + + if ( is_network_admin() ) { + return; + } + + if( ! current_user_can( 'update_plugins' ) ) { + return; + } + + if( ! is_multisite() ) { + return; + } + + if ( $this->name != $file ) { + return; + } + + // Remove our filter on the site transient + remove_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ), 10 ); + + $update_cache = get_site_transient( 'update_plugins' ); + + $update_cache = is_object( $update_cache ) ? $update_cache : new stdClass(); + + if ( empty( $update_cache->response ) || empty( $update_cache->response[ $this->name ] ) ) { + + $version_info = $this->get_cached_version_info(); + + if ( false === $version_info ) { + $version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug, 'beta' => $this->beta ) ); + + // Since we disabled our filter for the transient, we aren't running our object conversion on banners, sections, or icons. Do this now: + if ( isset( $version_info->banners ) && ! is_array( $version_info->banners ) ) { + $version_info->banners = $this->convert_object_to_array( $version_info->banners ); + } + + if ( isset( $version_info->sections ) && ! is_array( $version_info->sections ) ) { + $version_info->sections = $this->convert_object_to_array( $version_info->sections ); + } + + if ( isset( $version_info->icons ) && ! is_array( $version_info->icons ) ) { + $version_info->icons = $this->convert_object_to_array( $version_info->icons ); + } + + if ( isset( $version_info->icons ) && ! is_array( $version_info->icons ) ) { + $version_info->icons = $this->convert_object_to_array( $version_info->icons ); + } + + if ( isset( $version_info->contributors ) && ! is_array( $version_info->contributors ) ) { + $version_info->contributors = $this->convert_object_to_array( $version_info->contributors ); + } + + $this->set_version_info_cache( $version_info ); + } + + if ( ! is_object( $version_info ) ) { + return; + } + + if ( version_compare( $this->version, $version_info->new_version, '<' ) ) { + + $update_cache->response[ $this->name ] = $version_info; + + } + + $update_cache->last_checked = time(); + $update_cache->checked[ $this->name ] = $this->version; + + set_site_transient( 'update_plugins', $update_cache ); + + } else { + + $version_info = $update_cache->response[ $this->name ]; + + } + + // Restore our filter + add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) ); + + if ( ! empty( $update_cache->response[ $this->name ] ) && version_compare( $this->version, $version_info->new_version, '<' ) ) { + + // build a plugin list row, with update notification + $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' ); + # <tr class="plugin-update-tr"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange"> + echo '<tr class="plugin-update-tr" id="' . $this->slug . '-update" data-slug="' . $this->slug . '" data-plugin="' . $this->slug . '/' . $file . '">'; + echo '<td colspan="3" class="plugin-update colspanchange">'; + echo '<div class="update-message notice inline notice-warning notice-alt">'; + + $changelog_link = self_admin_url( 'index.php?edd_sl_action=view_plugin_changelog&plugin=' . $this->name . '&slug=' . $this->slug . '&TB_iframe=true&width=772&height=911' ); + + if ( empty( $version_info->download_link ) ) { + printf( + __( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s.', 'easy-digital-downloads' ), + esc_html( $version_info->name ), + '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">', + esc_html( $version_info->new_version ), + '</a>' + ); + } else { + printf( + __( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s or %5$supdate now%6$s.', 'easy-digital-downloads' ), + esc_html( $version_info->name ), + '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">', + esc_html( $version_info->new_version ), + '</a>', + '<a href="' . esc_url( wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $this->name, 'upgrade-plugin_' . $this->name ) ) .'">', + '</a>' + ); + } + + do_action( "in_plugin_update_message-{$file}", $plugin, $version_info ); + + echo '</div></td></tr>'; + } + } + + /** + * Updates information on the "View version x.x details" page with custom data. + * + * @uses api_request() + * + * @param mixed $_data + * @param string $_action + * @param object $_args + * @return object $_data + */ + public function plugins_api_filter( $_data, $_action = '', $_args = null ) { + + if ( $_action != 'plugin_information' ) { + + return $_data; + + } + + if ( ! isset( $_args->slug ) || ( $_args->slug != $this->slug ) ) { + + return $_data; + + } + + $to_send = array( + 'slug' => $this->slug, + 'is_ssl' => is_ssl(), + 'fields' => array( + 'banners' => array(), + 'reviews' => false, + 'icons' => array(), + ) + ); + + $cache_key = 'edd_api_request_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) ); + + // Get the transient where we store the api request for this plugin for 24 hours + $edd_api_request_transient = $this->get_cached_version_info( $cache_key ); + + //If we have no transient-saved value, run the API, set a fresh transient with the API value, and return that value too right now. + if ( empty( $edd_api_request_transient ) ) { + + $api_response = $this->api_request( 'plugin_information', $to_send ); + + // Expires in 3 hours + $this->set_version_info_cache( $api_response, $cache_key ); + + if ( false !== $api_response ) { + $_data = $api_response; + } + + } else { + $_data = $edd_api_request_transient; + } + + // Convert sections into an associative array, since we're getting an object, but Core expects an array. + if ( isset( $_data->sections ) && ! is_array( $_data->sections ) ) { + $_data->sections = $this->convert_object_to_array( $_data->sections ); + } + + // Convert banners into an associative array, since we're getting an object, but Core expects an array. + if ( isset( $_data->banners ) && ! is_array( $_data->banners ) ) { + $_data->banners = $this->convert_object_to_array( $_data->banners ); + } + + // Convert icons into an associative array, since we're getting an object, but Core expects an array. + if ( isset( $_data->icons ) && ! is_array( $_data->icons ) ) { + $_data->icons = $this->convert_object_to_array( $_data->icons ); + } + + // Convert contributors into an associative array, since we're getting an object, but Core expects an array. + if ( isset( $_data->contributors ) && ! is_array( $_data->contributors ) ) { + $_data->contributors = $this->convert_object_to_array( $_data->contributors ); + } + + if( ! isset( $_data->plugin ) ) { + $_data->plugin = $this->name; + } + + return $_data; + } + + /** + * Convert some objects to arrays when injecting data into the update API + * + * Some data like sections, banners, and icons are expected to be an associative array, however due to the JSON + * decoding, they are objects. This method allows us to pass in the object and return an associative array. + * + * @since 3.6.5 + * + * @param stdClass $data + * + * @return array + */ + private function convert_object_to_array( $data ) { + $new_data = array(); + foreach ( $data as $key => $value ) { + $new_data[ $key ] = is_object( $value ) ? $this->convert_object_to_array( $value ) : $value; + } + + return $new_data; + } + + /** + * Disable SSL verification in order to prevent download update failures + * + * @param array $args + * @param string $url + * @return object $array + */ + public function http_request_args( $args, $url ) { + + $verify_ssl = $this->verify_ssl(); + if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) { + $args['sslverify'] = $verify_ssl; + } + return $args; + + } + + /** + * Calls the API and, if successfull, returns the object delivered by the API. + * + * @uses get_bloginfo() + * @uses wp_remote_post() + * @uses is_wp_error() + * + * @param string $_action The requested action. + * @param array $_data Parameters for the API action. + * @return false|object + */ + private function api_request( $_action, $_data ) { + + global $wp_version, $edd_plugin_url_available; + + $verify_ssl = $this->verify_ssl(); + + // Do a quick status check on this domain if we haven't already checked it. + $store_hash = md5( $this->api_url ); + if ( ! is_array( $edd_plugin_url_available ) || ! isset( $edd_plugin_url_available[ $store_hash ] ) ) { + $test_url_parts = parse_url( $this->api_url ); + + $scheme = ! empty( $test_url_parts['scheme'] ) ? $test_url_parts['scheme'] : 'http'; + $host = ! empty( $test_url_parts['host'] ) ? $test_url_parts['host'] : ''; + $port = ! empty( $test_url_parts['port'] ) ? ':' . $test_url_parts['port'] : ''; + + if ( empty( $host ) ) { + $edd_plugin_url_available[ $store_hash ] = false; + } else { + $test_url = $scheme . '://' . $host . $port; + $response = wp_remote_get( $test_url, array( 'timeout' => $this->health_check_timeout, 'sslverify' => $verify_ssl ) ); + $edd_plugin_url_available[ $store_hash ] = is_wp_error( $response ) ? false : true; + } + } + + if ( false === $edd_plugin_url_available[ $store_hash ] ) { + return; + } + + $data = array_merge( $this->api_data, $_data ); + + if ( $data['slug'] != $this->slug ) { + return; + } + + if( $this->api_url == trailingslashit ( home_url() ) ) { + return false; // Don't allow a plugin to ping itself + } + + $api_params = array( + 'edd_action' => 'get_version', + 'license' => ! empty( $data['license'] ) ? $data['license'] : '', + 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false, + 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false, + 'version' => isset( $data['version'] ) ? $data['version'] : false, + 'slug' => $data['slug'], + 'author' => $data['author'], + 'url' => home_url(), + 'beta' => ! empty( $data['beta'] ), + ); + + $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => $verify_ssl, 'body' => $api_params ) ); + + if ( ! is_wp_error( $request ) ) { + $request = json_decode( wp_remote_retrieve_body( $request ) ); + } + + if ( $request && isset( $request->sections ) ) { + $request->sections = maybe_unserialize( $request->sections ); + } else { + $request = false; + } + + if ( $request && isset( $request->banners ) ) { + $request->banners = maybe_unserialize( $request->banners ); + } + + if ( $request && isset( $request->icons ) ) { + $request->icons = maybe_unserialize( $request->icons ); + } + + if( ! empty( $request->sections ) ) { + foreach( $request->sections as $key => $section ) { + $request->$key = (array) $section; + } + } + + return $request; + } + + public function show_changelog() { + + global $edd_plugin_data; + + if( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' != $_REQUEST['edd_sl_action'] ) { + return; + } + + if( empty( $_REQUEST['plugin'] ) ) { + return; + } + + if( empty( $_REQUEST['slug'] ) ) { + return; + } + + if( ! current_user_can( 'update_plugins' ) ) { + wp_die( __( 'You do not have permission to install plugin updates', 'easy-digital-downloads' ), __( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) ); + } + + $data = $edd_plugin_data[ $_REQUEST['slug'] ]; + $beta = ! empty( $data['beta'] ) ? true : false; + $cache_key = md5( 'edd_plugin_' . sanitize_key( $_REQUEST['plugin'] ) . '_' . $beta . '_version_info' ); + $version_info = $this->get_cached_version_info( $cache_key ); + + if( false === $version_info ) { + + $api_params = array( + 'edd_action' => 'get_version', + 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false, + 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false, + 'slug' => $_REQUEST['slug'], + 'author' => $data['author'], + 'url' => home_url(), + 'beta' => ! empty( $data['beta'] ) + ); + + $verify_ssl = $this->verify_ssl(); + $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => $verify_ssl, 'body' => $api_params ) ); + + if ( ! is_wp_error( $request ) ) { + $version_info = json_decode( wp_remote_retrieve_body( $request ) ); + } + + + if ( ! empty( $version_info ) && isset( $version_info->sections ) ) { + $version_info->sections = maybe_unserialize( $version_info->sections ); + } else { + $version_info = false; + } + + if( ! empty( $version_info ) ) { + foreach( $version_info->sections as $key => $section ) { + $version_info->$key = (array) $section; + } + } + + $this->set_version_info_cache( $version_info, $cache_key ); + + } + + if( ! empty( $version_info ) && isset( $version_info->sections['changelog'] ) ) { + echo '<div style="background:#fff;padding:10px;">' . $version_info->sections['changelog'] . '</div>'; + } + + exit; + } + + public function get_cached_version_info( $cache_key = '' ) { + + if( empty( $cache_key ) ) { + $cache_key = $this->cache_key; + } + + $cache = get_option( $cache_key ); + + if( empty( $cache['timeout'] ) || time() > $cache['timeout'] ) { + return false; // Cache is expired + } + + // We need to turn the icons into an array, thanks to WP Core forcing these into an object at some point. + $cache['value'] = json_decode( $cache['value'] ); + if ( ! empty( $cache['value']->icons ) ) { + $cache['value']->icons = (array) $cache['value']->icons; + } + + return $cache['value']; + + } + + public function set_version_info_cache( $value = '', $cache_key = '' ) { + + if( empty( $cache_key ) ) { + $cache_key = $this->cache_key; + } + + $data = array( + 'timeout' => strtotime( '+3 hours', time() ), + 'value' => json_encode( $value ) + ); + + update_option( $cache_key, $data, 'no' ); + + } + + /** + * Returns if the SSL of the store should be verified. + * + * @since 1.6.13 + * @return bool + */ + private function verify_ssl() { + return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this ); + } + +} diff --git a/Postman/Extensions/License/PostmanLicenseHandler.php b/Postman/Extensions/License/PostmanLicenseHandler.php new file mode 100644 index 0000000..b24aa14 --- /dev/null +++ b/Postman/Extensions/License/PostmanLicenseHandler.php @@ -0,0 +1,422 @@ +<?php + +// Exit if accessed directly +if ( ! defined( 'ABSPATH' ) ) exit; + +if ( ! class_exists( 'PostmanLicenseHandler' ) ) : + + +class PostmanLicenseHandler { + private $file; + private $license; + private $license_data; + private $item_name; + private $item_id; + private $item_shortname; + private $version; + private $author; + private $api_url = 'http://localhost/psp/'; + + + function __construct( $_file, $_item_name, $_version, $_author, $_optname = null, $_api_url = null, $_item_id = null ) { + $this->file = $_file; + $this->item_name = $_item_name; + + if ( is_numeric( $_item_id ) ) { + $this->item_id = absint( $_item_id ); + } + + $this->item_shortname = $this->get_slug(); + $this->version = $_version; + $this->license = trim( get_option( $this->item_shortname . '_license_key', '' ) ); + $this->license_data = get_option( $this->item_shortname . '_license_active', '' ); + $this->author = $_author; + $this->api_url = is_null( $_api_url ) ? $this->api_url : $_api_url; + + /** + * Allows for backwards compatibility with old license options, + * i.e. if the plugins had license key fields previously, the license + * handler will automatically pick these up and use those in lieu of the + * user having to reactive their license. + */ + if ( ! empty( $_optname ) ) { + $opt = get_option( $_optname, false ); + + if( isset( $opt ) && empty( $this->license ) ) { + $this->license = trim( $opt ); + } + } + + // Setup hooks + $this->includes(); + $this->hooks(); + + } + + /** + * Include the updater class + * + * @access private + * @return void + */ + private function includes() { + if ( ! class_exists( 'EDD_SL_Plugin_Updater' ) ) { + require_once 'EDD_SL_Plugin_Updater.php'; + } + } + + /** + * Setup hooks + * + * @access private + * @return void + */ + public function hooks() { + + // Activate license key on settings save + add_action( 'admin_init', array( $this, 'activate_license' ) ); + + // Deactivate license key + add_action( 'admin_init', array( $this, 'deactivate_license' ) ); + + add_action( 'init', array( $this, 'cron' ), 20 ); + + // Check that license is valid once per week + add_action( 'admin_init', array( $this, 'validate_license' ) ); + + // Updater + add_action( 'admin_init', array( $this, 'auto_updater' ), 0 ); + + // Display notices to admins + add_action( 'admin_notices', array( $this, 'notices' ) ); + + add_action( 'in_plugin_update_message-' . plugin_basename( $this->file ), array( $this, 'plugin_row_license_missing' ), 10, 2 ); + } + + /** + * Auto updater + * + * @access private + * @return void + */ + public function auto_updater() { + + $args = array( + 'version' => $this->version, + 'license' => $this->license, + 'author' => $this->author, + 'beta' => function_exists( 'edd_extension_has_beta_support' ) && edd_extension_has_beta_support( $this->item_shortname ), + ); + + if( ! empty( $this->item_id ) ) { + $args['item_id'] = $this->item_id; + } else { + $args['item_name'] = $this->item_name; + } + + // Setup the updater + $edd_updater = new EDD_SL_Plugin_Updater( + $this->api_url, + $this->file, + $args + ); + } + + public function cron() { + if ( ! wp_next_scheduled( $this->item_shortname . '_scheduled_events' ) ) { + wp_schedule_event( current_time( 'timestamp', true ), 'daily', $this->item_shortname . '_scheduled_events' ); + } + } + + public function get_slug() { + return preg_replace( '/[^a-zA-Z0-9_\s]/', '', str_replace( ' ', '_', strtolower( $this->item_name ) ) ); + } + + /** + * Display help text at the top of the Licenses tag + * + * @since 2.5 + * @param string $active_tab + * @return void + */ + public function license_help_text( $active_tab = '' ) { + + static $has_ran; + + if( 'licenses' !== $active_tab ) { + return; + } + + if( ! empty( $has_ran ) ) { + return; + } + + echo '<p>' . sprintf( + __( 'Enter your extension license keys here to receive updates for purchased extensions. If your license key has expired, please <a href="%s" target="_blank">renew your license</a>.', 'easy-digital-downloads' ), + 'http://docs.easydigitaldownloads.com/article/1000-license-renewal' + ) . '</p>'; + + $has_ran = true; + + } + + + /** + * Activate the license key + * + * @return void + */ + public function activate_license() { + + if ( ! isset( $_POST['post_smtp_extension'][ $this->item_shortname . '_activate'] ) ) { + return; + } + + if ( ! isset( $_REQUEST[ $this->item_shortname . '_license_key-nonce'] ) || ! wp_verify_nonce( $_REQUEST[ $this->item_shortname . '_license_key-nonce'], $this->item_shortname . '_license_key-nonce' ) ) { + + return; + + } + + if ( ! current_user_can( 'manage_options' ) ) { + return; + } + + if ( empty( $_POST['post_smtp_extension'][ $this->item_shortname . '_license_key'] ) ) { + + delete_option( $this->item_shortname . '_license_active' ); + delete_option( $this->item_shortname . '_license_key' ); + + return; + + } + + foreach ( $_POST as $key => $value ) { + if( false !== strpos( $key, 'license_key_deactivate' ) ) { + // Don't activate a key when deactivating a different key + return; + } + } + + $details = get_option( $this->item_shortname . '_license_active' ); + + if ( is_object( $details ) && 'valid' === $details->license ) { + return; + } + + $license = sanitize_text_field( $_POST['post_smtp_extension'][ $this->item_shortname . '_license_key'] ); + + if( empty( $license ) ) { + return; + } + + // Data to send to the API + $api_params = array( + 'edd_action' => 'activate_license', + 'license' => $license, + 'item_name' => urlencode( $this->item_name ), + 'url' => home_url() + ); + + if ( ! empty( $this->item_id ) ) { + $api_params['item_id'] = $this->item_id; + } + + // Call the API + $response = wp_remote_post( + $this->api_url, + array( + 'timeout' => 15, + 'sslverify' => false, + 'body' => $api_params + ) + ); + + // Make sure there are no errors + if ( is_wp_error( $response ) ) { + return; + } + + // Tell WordPress to look for updates + set_site_transient( 'update_plugins', null ); + + // Decode license data + $license_data = json_decode( wp_remote_retrieve_body( $response ) ); + + update_option( $this->item_shortname . '_license_active', $license_data ); + update_option( $this->item_shortname . '_license_key', $license ); + + $slug = plugin_basename($this->file); + PostmanLicenseManager::get_instance()->add_extension($slug); + + } + + + /** + * Deactivate the license key + * + * @return void + */ + public function deactivate_license() { + + if ( ! isset( $_POST['post_smtp_extension'][ $this->item_shortname . '_deactivate'] ) ) { + return; + } + + if ( ! isset( $_POST['post_smtp_extension'][ $this->item_shortname . '_license_key'] ) ) + return; + + if( ! wp_verify_nonce( $_REQUEST[ $this->item_shortname . '_license_key-nonce'], $this->item_shortname . '_license_key-nonce' ) ) { + + wp_die( __( 'Nonce verification failed', 'easy-digital-downloads' ), __( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) ); + + } + + if( ! current_user_can( 'manage_options' ) ) { + return; + } + + $license_key = sanitize_text_field( base64_decode( $_POST['post_smtp_extension'][ $this->item_shortname . '_license_key'] ) ); + + // Run on deactivate button press + // Data to send to the API + $api_params = array( + 'edd_action' => 'deactivate_license', + 'license' => $license_key, + 'item_name' => urlencode( $this->item_name ), + 'url' => home_url() + ); + + if ( ! empty( $this->item_id ) ) { + $api_params['item_id'] = $this->item_id; + } + + // Call the API + $response = wp_remote_post( + $this->api_url, + array( + 'timeout' => 15, + 'sslverify' => false, + 'body' => $api_params + ) + ); + + // Make sure there are no errors + if ( is_wp_error( $response ) ) { + return; + } + + // Decode the license data + $license_data = json_decode( wp_remote_retrieve_body( $response ) ); + + delete_option( $this->item_shortname . '_license_active' ); + delete_option( $this->item_shortname . '_license_key' ); + + $slug = plugin_basename($this->file); + PostmanLicenseManager::get_instance()->remove_extension($slug); + + } + + public function validate_license() { + if ( false === ( $cron_data = get_transient( $this->item_shortname . '_cron' ) ) ) { + $this->license_check(); + + set_transient( $this->item_shortname . '_cron', true, rand( 12, 48 ) * HOUR_IN_SECONDS ); + } + } + + + /** + * Check if license key is valid once per week + * + * @since 2.5 + * @return void + */ + public function license_check() { + + // data to send in our API request + $api_params = array( + 'edd_action'=> 'check_license', + 'license' => $this->license, + 'item_name' => urlencode( $this->item_name ), + 'url' => home_url() + ); + + // Call the API + $response = wp_remote_post( + $this->api_url, + array( + 'timeout' => 15, + 'sslverify' => false, + 'body' => $api_params + ) + ); + + // make sure the response came back okay + if ( is_wp_error( $response ) ) { + return false; + } + + $license_data = json_decode( wp_remote_retrieve_body( $response ) ); + + update_option( $this->item_shortname . '_license_active', $license_data ); + + } + + + /** + * Admin notices for errors + * + * @return void + */ + public function notices() { + + $showed_invalid_message = null; + + if( empty( $this->license ) ) { + return; + } + + if( ! current_user_can( 'manage_options' ) ) { + return; + } + + $messages = array(); + + $license = get_option( $this->item_shortname . '_license_active' ); + + if( is_object( $license ) && 'valid' !== $license->license && empty( $showed_invalid_message ) ) { + + if( isset( $_GET['page'] ) && 'post-smtp-extensions' === $_GET['page'] ) { + + $messages[] = sprintf( + __( '%s has invalid or expired license key for Post SMTP.'), + '<strong>' . $this->item_name . '</strong>' + ); + + $showed_invalid_message = true; + + } + + } + + if( ! empty( $messages ) ) { + + foreach( $messages as $message ) { + + echo '<div class="error">'; + echo '<p>' . $message . '</p>'; + echo '</div>'; + + } + + } + + } + + public function is_licensed() { + return is_object($this->license_data) && 'valid' === $this->license_data->license; + } +} + +endif; // end class_exists check diff --git a/Postman/Extensions/License/PostmanLicenseManager.php b/Postman/Extensions/License/PostmanLicenseManager.php new file mode 100644 index 0000000..280b564 --- /dev/null +++ b/Postman/Extensions/License/PostmanLicenseManager.php @@ -0,0 +1,102 @@ +<?php +if ( ! defined( 'ABSPATH' ) ) exit; + +class PostmanLicenseManager { + + const ENDPOINT = 'https://postmansmtp.com'; + + const CORE_EXTENSIONS = [ 'gmail_api', 'sendgrid_api', 'mandrill_api', 'mailgun_api' ]; + + private $extensions; + + private $rand_cache_interval = 12; + + private static $instance; + + public static function get_instance() { + if ( ! self::$instance ) { + self::$instance = new static(); + } + + return self::$instance; + } + + /** + * PostmanLicenseManager constructor. + */ + private function __construct() + { + $this->includes(); + $this->rand_cache_interval = rand( 1, 24 ); + + add_filter( 'extra_plugin_headers', [ $this, 'add_extension_headers' ] ); + } + + public function includes() { + include_once 'PostmanLicenseHandler.php'; + + include_once ABSPATH . '/wp-admin/includes/plugin.php'; + + } + + + function add_extension_headers($headers) { + $headers[] = 'Class'; + $headers[] = 'Slug'; + + return $headers; + } + + /** + * Init + */ + public function init() { + + $plugins = get_plugins(); + foreach ( $plugins as $plugin_dir_and_filename => $plugin_data ) { + + if ( ! is_plugin_active( $plugin_dir_and_filename ) ) { + continue; + } + + if ( false !== strpos( $plugin_dir_and_filename, 'post-smtp-extension' ) ) { + $slug = $plugin_dir_and_filename; + $class = $plugin_data['Class']; + $plugin_path = WP_CONTENT_DIR . '/plugins/' . $plugin_dir_and_filename; + + $this->extensions[$slug]['plugin_data'] = $plugin_data; + $this->extensions[$slug]['plugin_dir_and_filename'] = $plugin_dir_and_filename; + $this->extensions[$slug]['license_manager'] = new PostmanLicenseHandler( + $plugin_path, $plugin_data['Name'], + $plugin_data['Version'], $plugin_data['Author'] + ); + if ( $this->extensions[$slug]['license_manager']->is_licensed() ) { + include_once $plugin_path; + + $this->extensions[$slug]['instance'] = new $class; + } + } + } + + if ( ! empty( $this->extensions ) ) { + new PostmanAdmin(); + } + } + + public function add_extension($slug) { + $plugin_path = WP_CONTENT_DIR . '/plugins/' . $this->extensions[$slug]['plugin_dir_and_filename']; + $class = $this->extensions[$slug]['plugin_data']['Class']; + + include_once $plugin_path; + $this->extensions[$slug]['instance'] = new $class; + } + + public function remove_extension($slug) { + $this->extensions[$slug]['instance'] = null; + unset($this->extensions[$slug]['instance']); + } + + public function get_extensions() { + return $this->extensions; + } +}
\ No newline at end of file diff --git a/Postman/Phpmailer/PostsmtpMailer.php b/Postman/Phpmailer/PostsmtpMailer.php index b3a421b..e52091d 100644 --- a/Postman/Phpmailer/PostsmtpMailer.php +++ b/Postman/Phpmailer/PostsmtpMailer.php @@ -2,8 +2,10 @@ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } -require_once ABSPATH . WPINC . '/class-phpmailer.php'; -require_once ABSPATH . WPINC . '/class-smtp.php'; + +if ( ! class_exists( 'PHPMailer', false ) ) { + require_once ABSPATH . WPINC . '/class-phpmailer.php'; +} add_action('plugins_loaded', function() { global $phpmailer; @@ -17,12 +19,53 @@ class PostsmtpMailer extends PHPMailer { private $error; + private $transcript = ''; + public function __construct($exceptions = null) { parent::__construct($exceptions); + $this->set_vars(); + $this->hooks(); + + } + + public function set_vars() { $this->options = PostmanOptions::getInstance(); - add_filter( 'postman_wp_mail_result', [ $this, 'postman_wp_mail_result' ] ); + $this->Debugoutput = function($str, $level) { + $this->transcript .= $str; + }; + } + + public function hooks() { + if ( $this->options->getTransportType() == 'smtp' ) { + add_action( 'phpmailer_init', array( $this, 'phpmailer_smtp_init' ) ); + } + } + + /** + * @param PHPMailer $mail + */ + public function phpmailer_smtp_init($mail) { + $mail->SMTPDebug = 3; + $mail->isSMTP(); + $mail->Host = $this->options->getHostname(); + + if ( $this->options->getAuthenticationType() !== 'none' ) { + $mail->SMTPAuth = true; + $mail->Username = $this->options->getUsername(); + $mail->Password = $this->options->getPassword(); + } + + if ( $this->options->getEncryptionType() !== 'none' ) { + $mail->SMTPSecure = $this->options->getEncryptionType(); + } + + $mail->Port = $this->options->getPort(); + + if ( $this->options->isPluginSenderEmailEnforced() ) { + $mail->setFrom( $this->options->getMessageSenderEmail() , $this->options->getMessageSenderName () ); + } } public function send() @@ -33,40 +76,46 @@ class PostsmtpMailer extends PHPMailer { $postmanWpMail = new PostmanWpMail(); $postmanWpMail->init(); - $senderEmail = $this->options->getMessageSenderEmail(); - $senderName = $this->options->getMessageSenderName(); - - // create a PostmanMessage instance - $message = $postmanWpMail->createNewMessage(); - - $message->setFrom( $senderEmail, $senderName ); - $message->addHeaders( $this->getHeaders() ); - $message->setBodyTextPart( $this->AltBody ); - $message->setBodyHtmlPart( $this->Body ); - $message->setBody( $this->Body ); - $message->setSubject( $this->Subject ); - $message->addTo( $this->flatArray($this->getToAddresses() ) ); - $message->setReplyTo( $this->flatArray( $this->getReplyToAddresses() ) ); - $message->addCc( $this->flatArray($this->getCcAddresses() ) ); - $message->addBCc( $this->flatArray( $this->getBccAddresses() ) ); - $message->setReplyTo( $this->flatArray( $this->getReplyToAddresses() ) ); - $message->setAttachments( $this->getAttachments() ); - - // create a PostmanEmailLog instance + $backtrace = debug_backtrace(); + + list($to, $subject, $body, $headers, $attachments) = array_pad( $backtrace[1]['args'], 5, null ); + + // build the message + $postmanMessage = $postmanWpMail->processWpMailCall( $to, $subject, $body, $headers, $attachments ); + + // build the email log entry $log = new PostmanEmailLog(); + $log->originalTo = $to; + $log->originalSubject = $subject; + $log->originalMessage = $body; + $log->originalHeaders = $headers; - $log->originalTo = $this->flatArray($this->getToAddresses() ); - $log->originalSubject = $this->Subject; - $log->originalMessage = $this->Body; - $log->originalHeaders = $this->getCustomHeaders(); + // get the transport and create the transportConfig and engine + $transport = PostmanTransportRegistry::getInstance()->getActiveTransport(); + + add_filter( 'postman_wp_mail_result', [ $this, 'postman_wp_mail_result' ] ); try { - return $postmanWpMail->sendMessage( $message, $log ); + + if ( $send_email = apply_filters( 'post_smtp_do_send_email', true ) ) { + $result = $this->options->getTransportType() !== 'smtp' ? + $postmanWpMail->send( $to, $subject, $body, $headers, $attachments ) : + $this->sendSmtp(); + } + + + do_action( 'post_smtp_on_success', $log, $postmanMessage, $this->transcript, $transport ); + + return $result; + } catch (phpmailerException $exc) { $this->error = $exc; $this->mailHeader = ''; + + do_action( 'post_smtp_on_failed', $log, $postmanMessage, $this->transcript, $transport, $exc->getMessage() ); + $this->setError($exc->getMessage()); if ($this->exceptions) { throw $exc; @@ -76,50 +125,20 @@ class PostsmtpMailer extends PHPMailer { } - public function getAttachments() { - $attachments = parent::getAttachments(); - - $data = array(); - foreach ( $attachments as $attachment ) { - $data[] = $attachment[0]; + public function sendSmtp() { + if (!$this->preSend()) { + return false; } - - return $data; + return $this->postSend(); } - private function getHeaders() { - $headers = array(); - foreach ( $this->getCustomHeaders() as $header ) { - $headers[] = "{$header[0]}: {$header[1]}"; - } - return $headers; - } - - public function postman_wp_mail_result() { + public function postman_wp_mail_result() { $result = [ 'time' => '', 'exception' => $this->error, - 'transcript' => '', + 'transcript' => $this->transcript, ]; return $result; } - - private function flatArray($arr) { - $result = []; - foreach ( $arr as $key => $value ) { - if ( is_array( $value ) ) { - foreach ($value as $k => $v ) { - if ( empty( $v ) ) { - continue; - } - $value = $v; - } - } - - $result[] = $value; - } - - return implode(',', $result ); - } }
\ No newline at end of file diff --git a/Postman/Postman-Configuration/PostmanConfigurationController.php b/Postman/Postman-Configuration/PostmanConfigurationController.php index 59fbdb8..c63d6a9 100644 --- a/Postman/Postman-Configuration/PostmanConfigurationController.php +++ b/Postman/Postman-Configuration/PostmanConfigurationController.php @@ -201,13 +201,21 @@ class PostmanConfigurationController { print '<div class="wrap">'; PostmanViewController::outputChildPageHeader( __( 'Settings', 'post-smtp' ), 'advanced_config' ); + + $config_tabs = apply_filters( 'post_smtp_admin_tabs', array( + 'account_config' => __( 'Account', 'post-smtp' ), + 'fallback' => __( 'Fallback', 'post-smtp' ), + 'message_config' => __( 'Message', 'post-smtp' ), + 'logging_config' => __( 'Logging', 'post-smtp' ), + 'advanced_options_config' => __( 'Advanced', 'post-smtp' ), + ) ); + print '<div id="config_tabs"><ul>'; - print sprintf( '<li><a href="#account_config">%s</a></li>', __( 'Account', 'post-smtp' ) ); - print sprintf( '<li><a href="#fallback">%s</a></li>', __( 'Fallback', 'post-smtp' ) ); - print sprintf( '<li><a href="#message_config">%s</a></li>', __( 'Message', 'post-smtp' ) ); - print sprintf( '<li><a href="#logging_config">%s</a></li>', __( 'Logging', 'post-smtp' ) ); - print sprintf( '<li><a href="#advanced_options_config">%s</a></li>', __( 'Advanced', 'post-smtp' ) ); - print sprintf( '<li><a href="#notifications">%s</a></li>', __( 'Notifications', 'post-smtp' ) ); + + foreach ( $config_tabs as $slug => $tab ) : + printf( '<li><a href="#%s">%s</a></li>', $slug, $tab ); + endforeach; + print '</ul>'; print '<form method="post" action="options.php">'; @@ -294,9 +302,9 @@ class PostmanConfigurationController { <th scope="row"><?php _e('Security', 'post-smtp' ); ?></th> <?php $security_options = array( - 'none' => __( 'None', 'post-smtp' ), - 'ssl' => __( 'SSL', 'post-smtp' ), - 'tls' => __( 'TLS', 'post-smtp' ), + 'none' => __( 'None', 'post-smtp' ), + 'ssl' => __( 'SSL', 'post-smtp' ), + 'tls' => __( 'TLS', 'post-smtp' ), ); ?> <td> @@ -313,17 +321,17 @@ class PostmanConfigurationController { </td> </tr> - <tr> - <th scope="row"><?php _e('From Email', 'post-smtp' ); ?></th> - <td> - <input type="email" id="fallback-smtp-from-email" - value="<?php echo $this->options->getFallbackFromEmail(); ?>" - name="postman_options[<?php echo PostmanOptions::FALLBACK_FROM_EMAIL; ?>]" - > - <br> - <small><?php _e( "Use allowed email, for example: If you are using Gmail, type your Gmail adress.", 'post-smtp' ); ?></small> - </td> - </tr> + <tr> + <th scope="row"><?php _e('From Email', 'post-smtp' ); ?></th> + <td> + <input type="email" id="fallback-smtp-from-email" + value="<?php echo $this->options->getFallbackFromEmail(); ?>" + name="postman_options[<?php echo PostmanOptions::FALLBACK_FROM_EMAIL; ?>]" + > + <br> + <small><?php _e( "Use allowed email, for example: If you are using Gmail, type your Gmail adress.", 'post-smtp' ); ?></small> + </td> + </tr> <tr valign=""> <th scope="row"><?php _e( 'Use SMTP Authentication?', 'post-smtp' ); ?></th> @@ -387,24 +395,7 @@ class PostmanConfigurationController { do_settings_sections( PostmanAdminController::ADVANCED_OPTIONS ); print '</section>'; - print '<section id="notifications">'; - do_settings_sections( PostmanAdminController::NOTIFICATIONS_OPTIONS ); - - $currentKey = $this->options->getNotificationService(); - $pushover = $currentKey == 'pushover' ? 'block' : 'none'; - $slack = $currentKey == 'slack' ? 'block' : 'none'; - - echo '<div id="pushover_cred" style="display: ' . $pushover . ';">'; - do_settings_sections( PostmanAdminController::NOTIFICATIONS_PUSHOVER_CRED ); - echo '</div>'; - - echo '<div id="slack_cred" style="display: ' . $slack . ';">'; - do_settings_sections( PostmanAdminController::NOTIFICATIONS_SLACK_CRED ); - echo '</div>'; - - do_action( 'post_smtp_notification_settings' ); - - print '</section>'; + do_action( 'post_smtp_settings_menu' ); submit_button(); print '</form>'; @@ -762,7 +753,7 @@ class PostmanManageConfigurationAjaxHandler extends PostmanAbstractAjaxHandler { wp_send_json_success( $response ); } else { /* translators: where %s is the URL to the Connectivity Test page */ - $configuration ['message'] = sprintf( __( 'Postman can\'t find any way to send mail on your system. Run a <a href="%s">connectivity test</a>.', 'post-smtp' ), PostmanViewController::getPageUrl( PostmanViewController::PORT_TEST_SLUG ) ); + $configuration ['message'] = sprintf( __( 'Postman can\'t find any way to send mail on your system. Run a <a href="%s">connectivity test</a>.', 'post-smtp' ), PostmanViewController::getPageUrl( PostmanConnectivityTestController::PORT_TEST_SLUG ) ); $response ['configuration'] = $configuration; if ( $this->logger->isTrace() ) { $this->logger->trace( 'configuration:' ); diff --git a/Postman/Postman-Configuration/PostmanRegisterConfigurationSettings.php b/Postman/Postman-Configuration/PostmanRegisterConfigurationSettings.php index 705ef23..9c0170b 100644 --- a/Postman/Postman-Configuration/PostmanRegisterConfigurationSettings.php +++ b/Postman/Postman-Configuration/PostmanRegisterConfigurationSettings.php @@ -186,55 +186,7 @@ class PostmanSettingsRegistry { 'temporaryDirectoryCallback', ), PostmanAdminController::ADVANCED_OPTIONS, PostmanAdminController::ADVANCED_SECTION ); - // Notifications - add_settings_section( PostmanAdminController::NOTIFICATIONS_SECTION, _x( 'Notifications Settings', 'Configuration Section Title', 'post-smtp' ), array( - $this, - 'printNotificationsSectionInfo', - ), PostmanAdminController::NOTIFICATIONS_OPTIONS ); - - add_settings_field( PostmanOptions::NOTIFICATION_SERVICE, _x( 'Notification Service', 'Configuration Input Field', 'post-smtp' ), array( - $this, - 'notification_service_callback', - ), PostmanAdminController::NOTIFICATIONS_OPTIONS, PostmanAdminController::NOTIFICATIONS_SECTION ); - - // Pushover - add_settings_section( 'pushover_credentials', _x( 'Pushover Credentials', 'Configuration Section Title', 'post-smtp' ), array( - $this, - 'printNotificationsSectionInfo', - ), PostmanAdminController::NOTIFICATIONS_PUSHOVER_CRED ); - - add_settings_field( PostmanOptions::PUSHOVER_USER, _x( 'Pushover User Key', 'Configuration Input Field', 'post-smtp' ), array( - $this, - 'pushover_user_callback', - ), PostmanAdminController::NOTIFICATIONS_PUSHOVER_CRED, 'pushover_credentials' ); - - add_settings_field( PostmanOptions::PUSHOVER_TOKEN, _x( 'Pushover App Token', 'Configuration Input Field', 'post-smtp' ), array( - $this, - 'pushover_token_callback', - ), PostmanAdminController::NOTIFICATIONS_PUSHOVER_CRED, 'pushover_credentials' ); - - // Slack - add_settings_section( 'slack_credentials', _x( 'Slack Credentials', 'Configuration Section Title', 'post-smtp' ), array( - $this, - 'printNotificationsSectionInfo', - ), PostmanAdminController::NOTIFICATIONS_SLACK_CRED ); - - add_settings_field( PostmanOptions::SLACK_TOKEN, _x( 'Slack Webhook', 'Configuration Input Field', 'post-smtp' ), array( - $this, - 'slack_token_callback', - ), PostmanAdminController::NOTIFICATIONS_SLACK_CRED, 'slack_credentials' ); - - add_settings_field( PostmanOptions::NOTIFICATION_USE_CHROME, _x( 'Push to chrome extension', 'Configuration Input Field', 'post-smtp' ), array( - $this, - 'notification_use_chrome_callback', - ), PostmanAdminController::NOTIFICATIONS_OPTIONS, PostmanAdminController::NOTIFICATIONS_SECTION ); - - add_settings_field( PostmanOptions::NOTIFICATION_CHROME_UID, _x( 'Chrome Extension UID', 'Configuration Input Field', 'post-smtp' ), array( - $this, - 'notification_chrome_uid_callback', - ), PostmanAdminController::NOTIFICATIONS_OPTIONS, PostmanAdminController::NOTIFICATIONS_SECTION ); - - do_action( 'post_smtp_settings' ); + do_action( 'post_smtp_settings_fields' ); } } @@ -442,48 +394,6 @@ class PostmanSettingsRegistry { printf( '</select><br/><span class="postman_input_description">%s</span>', $inputDescription ); } - public function notification_service_callback() { - $inputDescription = __( 'Select the notification service you want to recieve alerts about failed emails.' ); - - $options = apply_filters('post_smtp_notification_service', array( - 'default' => __( 'WP Admin Email', 'post-smtp' ), - 'pushover' => __( 'Pushover', 'post-smtp' ), - 'slack' => __( 'Slack', 'post-smtp' ), - )); - - printf( '<select id="input_%2$s" class="input_%2$s" name="%1$s[%2$s]">', PostmanOptions::POSTMAN_OPTIONS, PostmanOptions::NOTIFICATION_SERVICE ); - $currentKey = $this->options->getNotificationService(); - - foreach ( $options as $key => $label ) { - $this->printSelectOption( $label, $key, $currentKey ); - } - - printf( '</select><br/><span class="postman_input_description">%s</span>', $inputDescription ); - } - - public function notification_use_chrome_callback() { - $value = $this->options->useChromeExtension(); - printf( '<input type="checkbox" id="input_%2$s" class="input_%2$s" name="%1$s[%2$s]" %3$s />', PostmanOptions::POSTMAN_OPTIONS, PostmanOptions::NOTIFICATION_USE_CHROME, $value ? 'checked="checked"' : '' ); - } - - public function notification_chrome_uid_callback() { - printf( '<input type="password" id="input_%2$s" class="input_%2$s" name="%1$s[%2$s]" value="%3$s" />', PostmanOptions::POSTMAN_OPTIONS, PostmanOptions::NOTIFICATION_CHROME_UID, PostmanUtils::obfuscatePassword( $this->options->getNotificationChromeUid() ) ); - } - - public function pushover_user_callback() { - printf( '<input type="password" id="pushover_user" name="%s[%s]" value="%s" />', PostmanOptions::POSTMAN_OPTIONS, PostmanOptions::PUSHOVER_USER, $this->options->getPushoverUser() ); - } - - public function pushover_token_callback() { - printf( '<input type="password" id="pushover_token" name="%s[%s]" value="%s" />', PostmanOptions::POSTMAN_OPTIONS, PostmanOptions::PUSHOVER_TOKEN, $this->options->getPushoverToken() ); - } - - public function slack_token_callback() { - printf( '<input type="password" id="slack_token" name="%s[%s]" value="%s" />', PostmanOptions::POSTMAN_OPTIONS, PostmanOptions::SLACK_TOKEN, $this->options->getSlackToken() ); - echo '<a target="_blank" href="https://slack.postmansmtp.com/">' . __( 'Get your webhook URL here', 'post-smtp' ) . '</a>'; - - } - private function printSelectOption( $label, $optionKey, $currentKey ) { $optionPattern = '<option value="%1$s" %2$s>%3$s</option>'; printf( $optionPattern, $optionKey, $optionKey == $currentKey ? 'selected="selected"' : '', $label ); diff --git a/Postman/Postman-Email-Log/PostmanEmailLogService.php b/Postman/Postman-Email-Log/PostmanEmailLogService.php index 2538700..624342d 100644 --- a/Postman/Postman-Email-Log/PostmanEmailLogService.php +++ b/Postman/Postman-Email-Log/PostmanEmailLogService.php @@ -4,6 +4,7 @@ if ( ! defined( 'ABSPATH' ) ) { } require_once dirname(__DIR__ ) . '/PostmanLogFields.php'; +require_once POST_SMTP_PATH . '/Postman/Extensions/Core/Notifications/PostmanNotify.php'; if ( ! class_exists( 'PostmanEmailLog' ) ) { class PostmanEmailLog { @@ -56,6 +57,9 @@ if ( ! class_exists( 'PostmanEmailLogService' ) ) { */ private function __construct() { $this->logger = new PostmanLogger( get_class( $this ) ); + + add_action('post_smtp_on_success', array( $this, 'write_success_log' ), 10, 4 ); + add_action('post_smtp_on_failed', array( $this, 'write_failed_log' ), 10, 5 ); } /** @@ -69,6 +73,20 @@ if ( ! class_exists( 'PostmanEmailLogService' ) ) { return $inst; } + public function write_success_log($log, $message, $transcript, $transport) { + $options = PostmanOptions::getInstance(); + if ( $options->getRunMode() == PostmanOptions::RUN_MODE_PRODUCTION || $options->getRunMode() == PostmanOptions::RUN_MODE_LOG_ONLY ) { + $this->writeSuccessLog( $log, $message, $transcript, $transport ); + } + } + + public function write_failed_log($log, $message, $transcript, $transport, $statusMessage) { + $options = PostmanOptions::getInstance(); + if ( $options->getRunMode() == PostmanOptions::RUN_MODE_PRODUCTION || $options->getRunMode() == PostmanOptions::RUN_MODE_LOG_ONLY ) { + $this->writeFailureLog( $log, $message, $transcript, $transport, $statusMessage ); + } + } + /** * Logs successful email attempts * @@ -118,7 +136,6 @@ if ( ! class_exists( 'PostmanEmailLogService' ) ) { $options = PostmanOptions::getInstance(); - $this->checkForLogErrors( $log ,$message ); $new_status = $log->statusMessage; if ( $options->is_fallback && empty( $log->statusMessage ) ) { @@ -129,6 +146,8 @@ if ( ! class_exists( 'PostmanEmailLogService' ) ) { $new_status = '( ** Fallback ** ) ' . $log->statusMessage; } + $new_status = apply_filters( 'post_smtp_log_status', $new_status, $log, $message ); + // nothing here is sanitized as WordPress should take care of // making database writes safe $my_post = array( @@ -187,50 +206,6 @@ if ( ! class_exists( 'PostmanEmailLogService' ) ) { $purger->truncateLogItems( PostmanOptions::getInstance()->getMailLoggingMaxEntries() ); } - private function checkForLogErrors( PostmanEmailLog $log, $postMessage ) { - $message = __( 'You getting this message because an error detected while delivered your email.', 'post-smtp' ); - $message .= "\r\n" . sprintf( __( 'For the domain: %1$s','post-smtp' ), get_bloginfo('url') ); - $message .= "\r\n" . __( 'The log to paste when you open a support issue:', 'post-smtp' ) . "\r\n"; - - if ( $log->statusMessage && ! empty( $log->statusMessage ) ) { - require_once POST_SMTP_PATH . '/Postman/notifications/PostmanNotify.php'; - - $message = $message . $log->statusMessage; - - $notification_service = PostmanOptions::getInstance()->getNotificationService(); - switch ($notification_service) { - case 'default': - $notifyer = new PostmanMailNotify; - break; - case 'pushover': - $notifyer = new PostmanPushoverNotify; - break; - case 'slack': - $notifyer = new PostmanSlackNotify; - break; - default: - $notifyer = new PostmanMailNotify; - } - - $notifyer = apply_filters( 'post_smtp_notifier', $notifyer, $notification_service ); - - // Notifications - $notify = new PostmanNotify( $notifyer ); - $notify->send($message, $log); - $notify->push_to_chrome($log->statusMessage); - } - - /** - * @todo - * After commented by me, check if it was needed. - */ - preg_match_all( '/(.*)From/s', $log->sessionTranscript, $matches ); - - if ( isset( $matches[1][0] ) && ! empty( $matches[1][0] ) && strpos( strtolower( $matches[1][0] ), 'error' ) !== false ) { - $message = $message . $log->sessionTranscript; - } - } - /** * Creates a Log object for use by writeToEmailLog() * diff --git a/Postman/Postman-Mail/PostmanMessage.php b/Postman/Postman-Mail/PostmanMessage.php index 12099ba..4099a02 100644 --- a/Postman/Postman-Mail/PostmanMessage.php +++ b/Postman/Postman-Mail/PostmanMessage.php @@ -450,7 +450,13 @@ if ( ! class_exists( 'PostmanMessage' ) ) { break; case 'reply-to' : $this->logProcessHeader( 'Reply-To', $name, $content ); - $this->setReplyTo( $content ); + $pattern = '/[a-z0-9_\-\+\.]+@[a-z0-9\-]+\.([a-z]{2,4})(?:\.[a-z]{2})?/i'; + preg_match_all($pattern, $content, $matches); + + if ( isset( $matches[0] ) && is_email( $matches[0] ) ) { + $this->setReplyTo( $content ); + } + break; case 'sender' : $this->logProcessHeader( 'Sender', $name, $content ); diff --git a/Postman/Postman.php b/Postman/Postman.php index 51b2ab1..9f4f7ce 100644 --- a/Postman/Postman.php +++ b/Postman/Postman.php @@ -70,6 +70,8 @@ class Postman { require_once 'Postman-Mail/PostmanMyMailConnector.php'; require_once 'Postman-Mail/PostmanContactForm7.php'; require_once 'Phpmailer/PostsmtpMailer.php'; + require_once 'Extensions/License/PostmanLicenseManager.php'; + require_once 'Extensions/Admin/PostmanAdmin.php'; //require_once 'Postman-Mail/PostmanWooCommerce.php'; // get plugin metadata - alternative to get_plugin_data @@ -188,6 +190,9 @@ class Postman { * ref: http://codex.wordpress.org/Plugin_API/Action_Reference#Actions_Run_During_a_Typical_Request */ public function on_plugins_loaded() { + + PostmanLicenseManager::get_instance()->init(); + // load the text domain $this->loadTextDomain(); @@ -215,6 +220,7 @@ class Postman { * ref: https://codex.wordpress.org/Function_Reference/register_activation_hook */ public function on_activation() { + if ( $this->logger->isInfo() ) { $this->logger->info( 'Activating plugin' ); } diff --git a/Postman/PostmanAdminController.php b/Postman/PostmanAdminController.php index 1e43c6d..128fa16 100644 --- a/Postman/PostmanAdminController.php +++ b/Postman/PostmanAdminController.php @@ -55,10 +55,6 @@ if ( ! class_exists( 'PostmanAdminController' ) ) { const MULTISITE_SECTION = 'postman_multisite_section'; const ADVANCED_OPTIONS = 'postman_advanced_options'; const ADVANCED_SECTION = 'postman_advanced_section'; - const NOTIFICATIONS_OPTIONS = 'postman_notifications_options'; - const NOTIFICATIONS_SECTION = 'postman_notifications_section'; - const NOTIFICATIONS_PUSHOVER_CRED = 'postman_pushover_cred'; - const NOTIFICATIONS_SLACK_CRED = 'postman_slack_cred'; const EMAIL_VALIDATION_SECTION = 'postman_email_validation_section'; const EMAIL_VALIDATION_OPTIONS = 'postman_email_validation_options'; diff --git a/Postman/PostmanInputSanitizer.php b/Postman/PostmanInputSanitizer.php index 75a0041..a8cdca7 100644 --- a/Postman/PostmanInputSanitizer.php +++ b/Postman/PostmanInputSanitizer.php @@ -73,16 +73,6 @@ if ( ! class_exists( 'PostmanInputSanitizer' ) ) { $this->sanitizeInt( 'Transcript Size', PostmanOptions::TRANSCRIPT_SIZE, $input, $new_input ); $this->sanitizeString( 'Temporary Directory', PostmanOptions::TEMPORARY_DIRECTORY, $input, $new_input ); - // Notifications - $this->sanitizeString( 'Pushover Service', PostmanOptions::NOTIFICATION_SERVICE, $input, $new_input, $this->options->getNotificationService() ); - $this->sanitizePassword( 'Pushover Username', PostmanOptions::PUSHOVER_USER, $input, $new_input, $this->options->getPushoverUser() ); - $this->sanitizePassword( 'Pushover Token', PostmanOptions::PUSHOVER_TOKEN, $input, $new_input, $this->options->getPushoverToken() ); - $this->sanitizePassword( 'Slack Token', PostmanOptions::SLACK_TOKEN, $input, $new_input, $this->options->getSlackToken() ); - - // Chrome extension - $this->sanitizeString( 'Push Chrome Extension', PostmanOptions::NOTIFICATION_USE_CHROME, $input, $new_input ); - $this->sanitizePassword( 'Push Chrome Extension UID', PostmanOptions::NOTIFICATION_CHROME_UID, $input, $new_input, $this->options->getNotificationChromeUid() ); - // Fallback $this->sanitizeString( 'Use fallback', PostmanOptions::FALLBACK_SMTP_ENABLED, $input, $new_input ); $this->sanitizeString( 'Fallback hostname', PostmanOptions::FALLBACK_SMTP_HOSTNAME, $input, $new_input ); diff --git a/Postman/PostmanOptions.php b/Postman/PostmanOptions.php index e2e78d6..30434bd 100644 --- a/Postman/PostmanOptions.php +++ b/Postman/PostmanOptions.php @@ -109,12 +109,6 @@ if ( ! class_exists( 'PostmanOptions' ) ) { const TRANSCRIPT_SIZE = 'transcript_size'; const TEMPORARY_DIRECTORY = 'tmp_dir'; const DISABLE_EMAIL_VALIDAITON = 'disable_email_validation'; - const NOTIFICATION_SERVICE = 'notification_service'; - const NOTIFICATION_USE_CHROME = 'notification_use_chrome'; - const NOTIFICATION_CHROME_UID = 'notification_chrome_uid'; - const PUSHOVER_USER = 'pushover_user'; - const PUSHOVER_TOKEN = 'pushover_token'; - const SLACK_TOKEN = 'slack_token'; // Fallback const FALLBACK_SMTP_ENABLED = 'fallback_smtp_enabled'; @@ -133,7 +127,6 @@ if ( ! class_exists( 'PostmanOptions' ) ) { const DEFAULT_MAIL_LOG_ENABLED = self::MAIL_LOG_ENABLED_OPTION_YES; const DEFAULT_MAIL_LOG_ENTRIES = 250; const DEFAULT_LOG_LEVEL = PostmanLogger::ERROR_INT; - const DEFAULT_NOTIFICATION_SERVICE = 'default'; const DEFAULT_TRANSPORT_TYPE = 'smtp'; // must match what's in PostmanSmtpModuleTransport const DEFAULT_TCP_READ_TIMEOUT = 60; const DEFAULT_TCP_CONNECTION_TIMEOUT = 10; @@ -247,13 +240,6 @@ if ( ! class_exists( 'PostmanOptions' ) ) { } else { return self::DEFAULT_LOG_LEVEL; } } - public function getNotificationService() { - if ( isset( $this->options [ PostmanOptions::NOTIFICATION_SERVICE ] ) ) { - return $this->options [ PostmanOptions::NOTIFICATION_SERVICE ]; - } else { - return self::DEFAULT_NOTIFICATION_SERVICE; - } - } public function getForcedToRecipients() { if ( isset( $this->options [ self::FORCED_TO_RECIPIENTS ] ) ) { @@ -481,36 +467,6 @@ if ( ! class_exists( 'PostmanOptions' ) ) { return $this->options [ PostmanOptions::MAILGUN_REGION ]; } } - - public function getPushoverUser() { - if ( isset( $this->options [ PostmanOptions::PUSHOVER_USER ] ) ) { - return base64_decode( $this->options [ PostmanOptions::PUSHOVER_USER ] ); - } - } - - public function getPushoverToken() { - if ( isset( $this->options [ PostmanOptions::PUSHOVER_TOKEN ] ) ) { - return base64_decode( $this->options [ PostmanOptions::PUSHOVER_TOKEN ] ); - } - } - - public function getSlackToken() { - if ( isset( $this->options [ PostmanOptions::SLACK_TOKEN ] ) ) { - return base64_decode( $this->options [ PostmanOptions::SLACK_TOKEN ] ); - } - } - - public function useChromeExtension() { - if ( isset( $this->options [ PostmanOptions::NOTIFICATION_USE_CHROME ] ) ) { - return $this->options [ PostmanOptions::NOTIFICATION_USE_CHROME ]; - } - } - - public function getNotificationChromeUid() { - if ( isset( $this->options [ PostmanOptions::NOTIFICATION_CHROME_UID ] ) ) { - return base64_decode( $this->options [ PostmanOptions::NOTIFICATION_CHROME_UID ] ); - } - } public function getReplyTo() { if ( isset( $this->options [ PostmanOptions::REPLY_TO ] ) ) { diff --git a/Postman/PostmanWpMail.php b/Postman/PostmanWpMail.php index 3a2b508..c108cce 100644 --- a/Postman/PostmanWpMail.php +++ b/Postman/PostmanWpMail.php @@ -25,6 +25,8 @@ if ( ! class_exists( 'PostmanWpMail' ) ) { require_once 'Postman-Mail/PostmanMailEngine.php'; require_once 'Postman-Auth/PostmanAuthenticationManagerFactory.php'; require_once 'PostmanState.php'; + + PostmanEmailLogService::getInstance(); } /** @@ -95,7 +97,7 @@ if ( ! class_exists( 'PostmanWpMail' ) ) { * @param mixed $headers * @param mixed $attachments */ - private function processWpMailCall( $to, $subject, $message, $headers, $attachments ) { + public function processWpMailCall( $to, $subject, $message, $headers, $attachments ) { $this->logger->trace( 'wp_mail parameters before applying WordPress wp_mail filter:' ); $this->traceParameters( $to, $subject, $message, $headers, $attachments ); @@ -199,7 +201,6 @@ if ( ! class_exists( 'PostmanWpMail' ) ) { // apply the WordPress filters // may impact the from address, from email, charset and content-type $message->applyFilters(); - //do_action_ref_array( 'phpmailer_init', array( &$message ) ); // create the body parts (if they are both missing) if ( $message->isBodyPartsEmpty() ) { @@ -229,8 +230,13 @@ if ( ! class_exists( 'PostmanWpMail' ) ) { } $this->logger->debug( 'Sending mail' ); + // may throw an exception attempting to contact the SMTP server - $engine->send( $message ); + if ( $send_email = apply_filters( 'post_smtp_do_send_email', true ) ) { + $engine->send($message); + } else { + $this->transcript = 'Bypassed By MailControl For Post SMTP'; + } // increment the success counter, unless we are just tesitng if ( ! $testMode ) { @@ -241,10 +247,10 @@ if ( ! class_exists( 'PostmanWpMail' ) ) { // clean up $this->postSend( $engine, $startTime, $options, $transport ); - if ( $options->getRunMode() == PostmanOptions::RUN_MODE_PRODUCTION || $options->getRunMode() == PostmanOptions::RUN_MODE_LOG_ONLY ) { - // log the successful delivery - PostmanEmailLogService::getInstance()->writeSuccessLog( $log, $message, $engine->getTranscript(), $transport ); - } + /** + * Do stuff after successful delivery + */ + do_action( 'post_smtp_on_success', $log, $message, $engine->getTranscript(), $transport ); // return successful return true; @@ -263,10 +269,11 @@ if ( ! class_exists( 'PostmanWpMail' ) ) { // clean up $this->postSend( $engine, $startTime, $options, $transport ); - if ( $options->getRunMode() == PostmanOptions::RUN_MODE_PRODUCTION || $options->getRunMode() == PostmanOptions::RUN_MODE_LOG_ONLY ) { - // log the failed delivery - PostmanEmailLogService::getInstance()->writeFailureLog( $log, $message, $engine->getTranscript(), $transport, $e->getMessage() ); - } + + /** + * Do stuff after failed delivery + */ + do_action( 'post_smtp_on_failed', $log, $message, $engine->getTranscript(), $transport, $e->getMessage() ); // Fallback if ( $this->fallback( $log, $message, $options ) ) { diff --git a/Postman/notifications/PostmanNotify.php b/Postman/notifications/PostmanNotify.php deleted file mode 100644 index 7654ecb..0000000 --- a/Postman/notifications/PostmanNotify.php +++ /dev/null @@ -1,42 +0,0 @@ -<?php -if ( ! defined( 'ABSPATH' ) ) { - exit; // Exit if accessed directly -} -require_once 'INotify.php'; -require_once 'PostmanMailNotify.php'; -require_once 'PostmanPushoverNotify.php'; -require_once 'PostmanSlackNotify.php'; - -class PostmanNotify { - private $notify; - - public function __construct( Postman_Notify $notify ) { - $this->notify = $notify; - } - - public function send( $message, $log ) { - $this->notify->send_message( $message ); - } - - public function push_to_chrome($message) { - $push_chrome = PostmanOptions::getInstance()->useChromeExtension(); - - if ( $push_chrome ) { - $uid = PostmanOptions::getInstance()->getNotificationChromeUid(); - - if ( empty( $uid ) ) { - return; - } - - $url = 'https://postmansmtp.com/chrome/' . $uid; - - $args = array( - 'body' => array( - 'message' => $message - ) - ); - - $response = wp_remote_post( $url , $args ); - } - } -}
\ No newline at end of file |