Post SMTP Mailer/Email Log - Version 2.1.2

Version Description

Download this release

Release Info

Developer wpexpertsio
Plugin Icon 128x128 Post SMTP Mailer/Email Log
Version 2.1.2
Comparing to
See all releases

Code changes from version 2.1.2-rc.2 to 2.1.2

Postman/Extensions/Admin/PostmanAdmin.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) exit;
3
+
4
+ class PostmanAdmin {
5
+
6
+ public function __construct()
7
+ {
8
+ $PostmanLicenseManager = PostmanLicenseManager::get_instance();
9
+ $extensions = $PostmanLicenseManager->get_extensions();
10
+
11
+ if ( count( $extensions ) > 0 ) {
12
+ add_action('admin_menu', [ $this, 'add_menu' ], 20 );
13
+ }
14
+
15
+ }
16
+
17
+ public function add_menu() {
18
+ add_submenu_page(
19
+ PostmanViewController::POSTMAN_MENU_SLUG,
20
+ __('Extensions', 'post-smtp'),
21
+ __('Extensions', 'post-smtp'),
22
+ 'manage_options',
23
+ 'post-smtp-extensions',
24
+ [ $this, 'render_menu' ]
25
+ );
26
+ }
27
+
28
+ public function render_menu() {
29
+ include_once 'PostmanAdminView.php';
30
+ }
31
+ }
Postman/Extensions/Admin/PostmanAdminView.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'ABSPATH' ) ) exit; ?>
2
+
3
+ <style>
4
+ .form-table .row {
5
+ display: flex;
6
+ justify-content: space-between;
7
+ margin-bottom: 15px;
8
+ }
9
+
10
+ .form-table .row .flex > *:not(:last-child) {
11
+ margin-right: 5px;
12
+ }
13
+
14
+ .form-table .label {
15
+ align-self: center;
16
+ font-weight: bold;
17
+ }
18
+
19
+ .form-table .flex {
20
+ display: flex;
21
+ }
22
+
23
+ .form-table .flex input {
24
+ border-radius: 3px;
25
+ height: 30px;
26
+ margin: 0;
27
+ margin-left: 5px;
28
+ }
29
+
30
+ .form-table .flex button {
31
+ box-shadow: none;
32
+ height: 100%;
33
+ }
34
+ </style>
35
+
36
+ <div class="wrap">
37
+ <h1>Post SMTP Installed Extensions</h1>
38
+ <form action="" method="post">
39
+ <div class="form-table">
40
+ <?php
41
+ $PostmanLicenseManager = PostmanLicenseManager::get_instance();
42
+ $extensions = $PostmanLicenseManager->get_extensions();
43
+
44
+ foreach ( $extensions as $slug => $extension) :
45
+ $short_name = $extension['license_manager']->get_slug( $extension['plugin_data']['Name'] );
46
+ $nonce = $short_name . '_license_key-nonce';
47
+
48
+ $license_data = get_option( $short_name . '_license_active' );
49
+ $license_key = get_option( $short_name . '_license_key' );
50
+
51
+ $license_valid = is_object( $license_data ) && $license_data->license === 'valid';
52
+ $license_field_class = $license_valid ? 'readonly' : '';
53
+ $license_field_value = $license_valid ? base64_encode($license_key) : '';
54
+
55
+ wp_nonce_field( $nonce, $nonce );
56
+ ?>
57
+
58
+ <div class="row">
59
+ <div class="label">
60
+ <?php echo esc_html( $extension['plugin_data']['Name'] ); ?>
61
+ </div>
62
+
63
+ <div class="flex">
64
+ <div class="input">
65
+ <input <?php echo $license_field_class; ?>
66
+ type="password"
67
+ name="post_smtp_extension[<?php echo $short_name . '_license_key'; ?>]"
68
+ class="regular-text"
69
+ value="<?php echo $license_field_value; ?>"
70
+ placeholder="Serial Key">
71
+ </div>
72
+
73
+ <div class="buttons">
74
+ <?php if ( ! $license_valid ) :?>
75
+ <button type="submit" name="post_smtp_extension[<?php echo $short_name; ?>_activate]" class="button button-primary">Activate</button>
76
+ <?php endif; ?>
77
+
78
+ <?php if ( $license_data->license === 'expired' ) : ?>
79
+ <a href="<?php echo $license_data->renew_url; ?>" target="_blank" class="button button-primary">Renew License</a>
80
+ <?php endif; ?>
81
+
82
+ <button type="submit" name="post_smtp_extension[<?php echo $short_name; ?>_deactivate]" class="button button-secondary">Deactivate</button>
83
+ </div>
84
+ </div>
85
+
86
+ </div>
87
+
88
+ <?php endforeach; ?>
89
+
90
+ </div>
91
+ </form>
92
+ </div>
Postman/Extensions/License/EDD_SL_Plugin_Updater.php ADDED
@@ -0,0 +1,585 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Exit if accessed directly
4
+ if ( ! defined( 'ABSPATH' ) ) exit;
5
+
6
+ /**
7
+ * Allows plugins to use their own update API.
8
+ *
9
+ * @author Easy Digital Downloads
10
+ * @version 1.6.19
11
+ */
12
+ class EDD_SL_Plugin_Updater {
13
+
14
+ private $api_url = '';
15
+ private $api_data = array();
16
+ private $name = '';
17
+ private $slug = '';
18
+ private $version = '';
19
+ private $wp_override = false;
20
+ private $cache_key = '';
21
+
22
+ private $health_check_timeout = 5;
23
+
24
+ /**
25
+ * Class constructor.
26
+ *
27
+ * @uses plugin_basename()
28
+ * @uses hook()
29
+ *
30
+ * @param string $_api_url The URL pointing to the custom API endpoint.
31
+ * @param string $_plugin_file Path to the plugin file.
32
+ * @param array $_api_data Optional data to send with API calls.
33
+ */
34
+ public function __construct( $_api_url, $_plugin_file, $_api_data = null ) {
35
+
36
+ global $edd_plugin_data;
37
+
38
+ $this->api_url = trailingslashit( $_api_url );
39
+ $this->api_data = $_api_data;
40
+ $this->name = plugin_basename( $_plugin_file );
41
+ $this->slug = basename( $_plugin_file, '.php' );
42
+ $this->version = $_api_data['version'];
43
+ $this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
44
+ $this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
45
+ $this->cache_key = 'edd_sl_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) );
46
+
47
+ $edd_plugin_data[ $this->slug ] = $this->api_data;
48
+
49
+ /**
50
+ * Fires after the $edd_plugin_data is setup.
51
+ *
52
+ * @since x.x.x
53
+ *
54
+ * @param array $edd_plugin_data Array of EDD SL plugin data.
55
+ */
56
+ do_action( 'post_edd_sl_plugin_updater_setup', $edd_plugin_data );
57
+
58
+ // Set up hooks.
59
+ $this->init();
60
+
61
+ }
62
+
63
+ /**
64
+ * Set up WordPress filters to hook into WP's update process.
65
+ *
66
+ * @uses add_filter()
67
+ *
68
+ * @return void
69
+ */
70
+ public function init() {
71
+
72
+ add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
73
+ add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
74
+ remove_action( 'after_plugin_row_' . $this->name, 'wp_plugin_update_row', 10 );
75
+ add_action( 'after_plugin_row_' . $this->name, array( $this, 'show_update_notification' ), 10, 2 );
76
+ add_action( 'admin_init', array( $this, 'show_changelog' ) );
77
+
78
+ }
79
+
80
+ /**
81
+ * Check for Updates at the defined API endpoint and modify the update array.
82
+ *
83
+ * This function dives into the update API just when WordPress creates its update array,
84
+ * then adds a custom API call and injects the custom plugin data retrieved from the API.
85
+ * It is reassembled from parts of the native WordPress plugin update code.
86
+ * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
87
+ *
88
+ * @uses api_request()
89
+ *
90
+ * @param array $_transient_data Update array build by WordPress.
91
+ * @return array Modified update array with custom plugin data.
92
+ */
93
+ public function check_update( $_transient_data ) {
94
+
95
+ global $pagenow;
96
+
97
+ if ( ! is_object( $_transient_data ) ) {
98
+ $_transient_data = new stdClass;
99
+ }
100
+
101
+ if ( 'plugins.php' == $pagenow && is_multisite() ) {
102
+ return $_transient_data;
103
+ }
104
+
105
+ if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) {
106
+ return $_transient_data;
107
+ }
108
+
109
+ $version_info = $this->get_cached_version_info();
110
+
111
+ if ( false === $version_info ) {
112
+ $version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug, 'beta' => $this->beta ) );
113
+
114
+ $this->set_version_info_cache( $version_info );
115
+
116
+ }
117
+
118
+ if ( false !== $version_info && is_object( $version_info ) && isset( $version_info->new_version ) ) {
119
+
120
+ if ( version_compare( $this->version, $version_info->new_version, '<' ) ) {
121
+
122
+ $_transient_data->response[ $this->name ] = $version_info;
123
+
124
+ // Make sure the plugin property is set to the plugin's name/location. See issue 1463 on Software Licensing's GitHub repo.
125
+ $_transient_data->response[ $this->name ]->plugin = $this->name;
126
+
127
+ }
128
+
129
+ $_transient_data->last_checked = time();
130
+ $_transient_data->checked[ $this->name ] = $this->version;
131
+
132
+ }
133
+
134
+ return $_transient_data;
135
+ }
136
+
137
+ /**
138
+ * show update nofication row -- needed for multisite subsites, because WP won't tell you otherwise!
139
+ *
140
+ * @param string $file
141
+ * @param array $plugin
142
+ */
143
+ public function show_update_notification( $file, $plugin ) {
144
+
145
+ if ( is_network_admin() ) {
146
+ return;
147
+ }
148
+
149
+ if( ! current_user_can( 'update_plugins' ) ) {
150
+ return;
151
+ }
152
+
153
+ if( ! is_multisite() ) {
154
+ return;
155
+ }
156
+
157
+ if ( $this->name != $file ) {
158
+ return;
159
+ }
160
+
161
+ // Remove our filter on the site transient
162
+ remove_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ), 10 );
163
+
164
+ $update_cache = get_site_transient( 'update_plugins' );
165
+
166
+ $update_cache = is_object( $update_cache ) ? $update_cache : new stdClass();
167
+
168
+ if ( empty( $update_cache->response ) || empty( $update_cache->response[ $this->name ] ) ) {
169
+
170
+ $version_info = $this->get_cached_version_info();
171
+
172
+ if ( false === $version_info ) {
173
+ $version_info = $this->api_request( 'plugin_latest_version', array( 'slug' => $this->slug, 'beta' => $this->beta ) );
174
+
175
+ // Since we disabled our filter for the transient, we aren't running our object conversion on banners, sections, or icons. Do this now:
176
+ if ( isset( $version_info->banners ) && ! is_array( $version_info->banners ) ) {
177
+ $version_info->banners = $this->convert_object_to_array( $version_info->banners );
178
+ }
179
+
180
+ if ( isset( $version_info->sections ) && ! is_array( $version_info->sections ) ) {
181
+ $version_info->sections = $this->convert_object_to_array( $version_info->sections );
182
+ }
183
+
184
+ if ( isset( $version_info->icons ) && ! is_array( $version_info->icons ) ) {
185
+ $version_info->icons = $this->convert_object_to_array( $version_info->icons );
186
+ }
187
+
188
+ if ( isset( $version_info->icons ) && ! is_array( $version_info->icons ) ) {
189
+ $version_info->icons = $this->convert_object_to_array( $version_info->icons );
190
+ }
191
+
192
+ if ( isset( $version_info->contributors ) && ! is_array( $version_info->contributors ) ) {
193
+ $version_info->contributors = $this->convert_object_to_array( $version_info->contributors );
194
+ }
195
+
196
+ $this->set_version_info_cache( $version_info );
197
+ }
198
+
199
+ if ( ! is_object( $version_info ) ) {
200
+ return;
201
+ }
202
+
203
+ if ( version_compare( $this->version, $version_info->new_version, '<' ) ) {
204
+
205
+ $update_cache->response[ $this->name ] = $version_info;
206
+
207
+ }
208
+
209
+ $update_cache->last_checked = time();
210
+ $update_cache->checked[ $this->name ] = $this->version;
211
+
212
+ set_site_transient( 'update_plugins', $update_cache );
213
+
214
+ } else {
215
+
216
+ $version_info = $update_cache->response[ $this->name ];
217
+
218
+ }
219
+
220
+ // Restore our filter
221
+ add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
222
+
223
+ if ( ! empty( $update_cache->response[ $this->name ] ) && version_compare( $this->version, $version_info->new_version, '<' ) ) {
224
+
225
+ // build a plugin list row, with update notification
226
+ $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
227
+ # <tr class="plugin-update-tr"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange">
228
+ echo '<tr class="plugin-update-tr" id="' . $this->slug . '-update" data-slug="' . $this->slug . '" data-plugin="' . $this->slug . '/' . $file . '">';
229
+ echo '<td colspan="3" class="plugin-update colspanchange">';
230
+ echo '<div class="update-message notice inline notice-warning notice-alt">';
231
+
232
+ $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' );
233
+
234
+ if ( empty( $version_info->download_link ) ) {
235
+ printf(
236
+ __( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s.', 'easy-digital-downloads' ),
237
+ esc_html( $version_info->name ),
238
+ '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
239
+ esc_html( $version_info->new_version ),
240
+ '</a>'
241
+ );
242
+ } else {
243
+ printf(
244
+ __( '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' ),
245
+ esc_html( $version_info->name ),
246
+ '<a target="_blank" class="thickbox" href="' . esc_url( $changelog_link ) . '">',
247
+ esc_html( $version_info->new_version ),
248
+ '</a>',
249
+ '<a href="' . esc_url( wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $this->name, 'upgrade-plugin_' . $this->name ) ) .'">',
250
+ '</a>'
251
+ );
252
+ }
253
+
254
+ do_action( "in_plugin_update_message-{$file}", $plugin, $version_info );
255
+
256
+ echo '</div></td></tr>';
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Updates information on the "View version x.x details" page with custom data.
262
+ *
263
+ * @uses api_request()
264
+ *
265
+ * @param mixed $_data
266
+ * @param string $_action
267
+ * @param object $_args
268
+ * @return object $_data
269
+ */
270
+ public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
271
+
272
+ if ( $_action != 'plugin_information' ) {
273
+
274
+ return $_data;
275
+
276
+ }
277
+
278
+ if ( ! isset( $_args->slug ) || ( $_args->slug != $this->slug ) ) {
279
+
280
+ return $_data;
281
+
282
+ }
283
+
284
+ $to_send = array(
285
+ 'slug' => $this->slug,
286
+ 'is_ssl' => is_ssl(),
287
+ 'fields' => array(
288
+ 'banners' => array(),
289
+ 'reviews' => false,
290
+ 'icons' => array(),
291
+ )
292
+ );
293
+
294
+ $cache_key = 'edd_api_request_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) );
295
+
296
+ // Get the transient where we store the api request for this plugin for 24 hours
297
+ $edd_api_request_transient = $this->get_cached_version_info( $cache_key );
298
+
299
+ //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.
300
+ if ( empty( $edd_api_request_transient ) ) {
301
+
302
+ $api_response = $this->api_request( 'plugin_information', $to_send );
303
+
304
+ // Expires in 3 hours
305
+ $this->set_version_info_cache( $api_response, $cache_key );
306
+
307
+ if ( false !== $api_response ) {
308
+ $_data = $api_response;
309
+ }
310
+
311
+ } else {
312
+ $_data = $edd_api_request_transient;
313
+ }
314
+
315
+ // Convert sections into an associative array, since we're getting an object, but Core expects an array.
316
+ if ( isset( $_data->sections ) && ! is_array( $_data->sections ) ) {
317
+ $_data->sections = $this->convert_object_to_array( $_data->sections );
318
+ }
319
+
320
+ // Convert banners into an associative array, since we're getting an object, but Core expects an array.
321
+ if ( isset( $_data->banners ) && ! is_array( $_data->banners ) ) {
322
+ $_data->banners = $this->convert_object_to_array( $_data->banners );
323
+ }
324
+
325
+ // Convert icons into an associative array, since we're getting an object, but Core expects an array.
326
+ if ( isset( $_data->icons ) && ! is_array( $_data->icons ) ) {
327
+ $_data->icons = $this->convert_object_to_array( $_data->icons );
328
+ }
329
+
330
+ // Convert contributors into an associative array, since we're getting an object, but Core expects an array.
331
+ if ( isset( $_data->contributors ) && ! is_array( $_data->contributors ) ) {
332
+ $_data->contributors = $this->convert_object_to_array( $_data->contributors );
333
+ }
334
+
335
+ if( ! isset( $_data->plugin ) ) {
336
+ $_data->plugin = $this->name;
337
+ }
338
+
339
+ return $_data;
340
+ }
341
+
342
+ /**
343
+ * Convert some objects to arrays when injecting data into the update API
344
+ *
345
+ * Some data like sections, banners, and icons are expected to be an associative array, however due to the JSON
346
+ * decoding, they are objects. This method allows us to pass in the object and return an associative array.
347
+ *
348
+ * @since 3.6.5
349
+ *
350
+ * @param stdClass $data
351
+ *
352
+ * @return array
353
+ */
354
+ private function convert_object_to_array( $data ) {
355
+ $new_data = array();
356
+ foreach ( $data as $key => $value ) {
357
+ $new_data[ $key ] = is_object( $value ) ? $this->convert_object_to_array( $value ) : $value;
358
+ }
359
+
360
+ return $new_data;
361
+ }
362
+
363
+ /**
364
+ * Disable SSL verification in order to prevent download update failures
365
+ *
366
+ * @param array $args
367
+ * @param string $url
368
+ * @return object $array
369
+ */
370
+ public function http_request_args( $args, $url ) {
371
+
372
+ $verify_ssl = $this->verify_ssl();
373
+ if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
374
+ $args['sslverify'] = $verify_ssl;
375
+ }
376
+ return $args;
377
+
378
+ }
379
+
380
+ /**
381
+ * Calls the API and, if successfull, returns the object delivered by the API.
382
+ *
383
+ * @uses get_bloginfo()
384
+ * @uses wp_remote_post()
385
+ * @uses is_wp_error()
386
+ *
387
+ * @param string $_action The requested action.
388
+ * @param array $_data Parameters for the API action.
389
+ * @return false|object
390
+ */
391
+ private function api_request( $_action, $_data ) {
392
+
393
+ global $wp_version, $edd_plugin_url_available;
394
+
395
+ $verify_ssl = $this->verify_ssl();
396
+
397
+ // Do a quick status check on this domain if we haven't already checked it.
398
+ $store_hash = md5( $this->api_url );
399
+ if ( ! is_array( $edd_plugin_url_available ) || ! isset( $edd_plugin_url_available[ $store_hash ] ) ) {
400
+ $test_url_parts = parse_url( $this->api_url );
401
+
402
+ $scheme = ! empty( $test_url_parts['scheme'] ) ? $test_url_parts['scheme'] : 'http';
403
+ $host = ! empty( $test_url_parts['host'] ) ? $test_url_parts['host'] : '';
404
+ $port = ! empty( $test_url_parts['port'] ) ? ':' . $test_url_parts['port'] : '';
405
+
406
+ if ( empty( $host ) ) {
407
+ $edd_plugin_url_available[ $store_hash ] = false;
408
+ } else {
409
+ $test_url = $scheme . '://' . $host . $port;
410
+ $response = wp_remote_get( $test_url, array( 'timeout' => $this->health_check_timeout, 'sslverify' => $verify_ssl ) );
411
+ $edd_plugin_url_available[ $store_hash ] = is_wp_error( $response ) ? false : true;
412
+ }
413
+ }
414
+
415
+ if ( false === $edd_plugin_url_available[ $store_hash ] ) {
416
+ return;
417
+ }
418
+
419
+ $data = array_merge( $this->api_data, $_data );
420
+
421
+ if ( $data['slug'] != $this->slug ) {
422
+ return;
423
+ }
424
+
425
+ if( $this->api_url == trailingslashit ( home_url() ) ) {
426
+ return false; // Don't allow a plugin to ping itself
427
+ }
428
+
429
+ $api_params = array(
430
+ 'edd_action' => 'get_version',
431
+ 'license' => ! empty( $data['license'] ) ? $data['license'] : '',
432
+ 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
433
+ 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
434
+ 'version' => isset( $data['version'] ) ? $data['version'] : false,
435
+ 'slug' => $data['slug'],
436
+ 'author' => $data['author'],
437
+ 'url' => home_url(),
438
+ 'beta' => ! empty( $data['beta'] ),
439
+ );
440
+
441
+ $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => $verify_ssl, 'body' => $api_params ) );
442
+
443
+ if ( ! is_wp_error( $request ) ) {
444
+ $request = json_decode( wp_remote_retrieve_body( $request ) );
445
+ }
446
+
447
+ if ( $request && isset( $request->sections ) ) {
448
+ $request->sections = maybe_unserialize( $request->sections );
449
+ } else {
450
+ $request = false;
451
+ }
452
+
453
+ if ( $request && isset( $request->banners ) ) {
454
+ $request->banners = maybe_unserialize( $request->banners );
455
+ }
456
+
457
+ if ( $request && isset( $request->icons ) ) {
458
+ $request->icons = maybe_unserialize( $request->icons );
459
+ }
460
+
461
+ if( ! empty( $request->sections ) ) {
462
+ foreach( $request->sections as $key => $section ) {
463
+ $request->$key = (array) $section;
464
+ }
465
+ }
466
+
467
+ return $request;
468
+ }
469
+
470
+ public function show_changelog() {
471
+
472
+ global $edd_plugin_data;
473
+
474
+ if( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' != $_REQUEST['edd_sl_action'] ) {
475
+ return;
476
+ }
477
+
478
+ if( empty( $_REQUEST['plugin'] ) ) {
479
+ return;
480
+ }
481
+
482
+ if( empty( $_REQUEST['slug'] ) ) {
483
+ return;
484
+ }
485
+
486
+ if( ! current_user_can( 'update_plugins' ) ) {
487
+ wp_die( __( 'You do not have permission to install plugin updates', 'easy-digital-downloads' ), __( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) );
488
+ }
489
+
490
+ $data = $edd_plugin_data[ $_REQUEST['slug'] ];
491
+ $beta = ! empty( $data['beta'] ) ? true : false;
492
+ $cache_key = md5( 'edd_plugin_' . sanitize_key( $_REQUEST['plugin'] ) . '_' . $beta . '_version_info' );
493
+ $version_info = $this->get_cached_version_info( $cache_key );
494
+
495
+ if( false === $version_info ) {
496
+
497
+ $api_params = array(
498
+ 'edd_action' => 'get_version',
499
+ 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false,
500
+ 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false,
501
+ 'slug' => $_REQUEST['slug'],
502
+ 'author' => $data['author'],
503
+ 'url' => home_url(),
504
+ 'beta' => ! empty( $data['beta'] )
505
+ );
506
+
507
+ $verify_ssl = $this->verify_ssl();
508
+ $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => $verify_ssl, 'body' => $api_params ) );
509
+
510
+ if ( ! is_wp_error( $request ) ) {
511
+ $version_info = json_decode( wp_remote_retrieve_body( $request ) );
512
+ }
513
+
514
+
515
+ if ( ! empty( $version_info ) && isset( $version_info->sections ) ) {
516
+ $version_info->sections = maybe_unserialize( $version_info->sections );
517
+ } else {
518
+ $version_info = false;
519
+ }
520
+
521
+ if( ! empty( $version_info ) ) {
522
+ foreach( $version_info->sections as $key => $section ) {
523
+ $version_info->$key = (array) $section;
524
+ }
525
+ }
526
+
527
+ $this->set_version_info_cache( $version_info, $cache_key );
528
+
529
+ }
530
+
531
+ if( ! empty( $version_info ) && isset( $version_info->sections['changelog'] ) ) {
532
+ echo '<div style="background:#fff;padding:10px;">' . $version_info->sections['changelog'] . '</div>';
533
+ }
534
+
535
+ exit;
536
+ }
537
+
538
+ public function get_cached_version_info( $cache_key = '' ) {
539
+
540
+ if( empty( $cache_key ) ) {
541
+ $cache_key = $this->cache_key;
542
+ }
543
+
544
+ $cache = get_option( $cache_key );
545
+
546
+ if( empty( $cache['timeout'] ) || time() > $cache['timeout'] ) {
547
+ return false; // Cache is expired
548
+ }
549
+
550
+ // We need to turn the icons into an array, thanks to WP Core forcing these into an object at some point.
551
+ $cache['value'] = json_decode( $cache['value'] );
552
+ if ( ! empty( $cache['value']->icons ) ) {
553
+ $cache['value']->icons = (array) $cache['value']->icons;
554
+ }
555
+
556
+ return $cache['value'];
557
+
558
+ }
559
+
560
+ public function set_version_info_cache( $value = '', $cache_key = '' ) {
561
+
562
+ if( empty( $cache_key ) ) {
563
+ $cache_key = $this->cache_key;
564
+ }
565
+
566
+ $data = array(
567
+ 'timeout' => strtotime( '+3 hours', time() ),
568
+ 'value' => json_encode( $value )
569
+ );
570
+
571
+ update_option( $cache_key, $data, 'no' );
572
+
573
+ }
574
+
575
+ /**
576
+ * Returns if the SSL of the store should be verified.
577
+ *
578
+ * @since 1.6.13
579
+ * @return bool
580
+ */
581
+ private function verify_ssl() {
582
+ return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this );
583
+ }
584
+
585
+ }
Postman/Extensions/License/PostmanLicenseHandler.php ADDED
@@ -0,0 +1,482 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Exit if accessed directly
4
+ if ( ! defined( 'ABSPATH' ) ) exit;
5
+
6
+ if ( ! class_exists( 'PostmanLicenseHandler' ) ) :
7
+
8
+
9
+ class PostmanLicenseHandler {
10
+
11
+ const DAYS_TO_ALERT = array( 30, 14, 7, 1);
12
+
13
+ private $file;
14
+ private $license;
15
+ private $license_data;
16
+ private $item_name;
17
+ private $item_id;
18
+ private $item_shortname;
19
+ private $version;
20
+ private $author;
21
+ private $api_url = 'https://postmansmtp.com';
22
+
23
+
24
+ function __construct( $_file, $_item_name, $_version, $_author, $_optname = null, $_api_url = null, $_item_id = null ) {
25
+ $this->file = $_file;
26
+ $this->item_name = $_item_name;
27
+
28
+ if ( is_numeric( $_item_id ) ) {
29
+ $this->item_id = absint( $_item_id );
30
+ }
31
+
32
+ $this->item_shortname = $this->get_slug();
33
+ $this->version = $_version;
34
+ $this->license = trim( get_option( $this->item_shortname . '_license_key', '' ) );
35
+ $this->license_data = get_option( $this->item_shortname . '_license_active', '' );
36
+ $this->author = $_author;
37
+ $this->api_url = is_null( $_api_url ) ? $this->api_url : $_api_url;
38
+
39
+ /**
40
+ * Allows for backwards compatibility with old license options,
41
+ * i.e. if the plugins had license key fields previously, the license
42
+ * handler will automatically pick these up and use those in lieu of the
43
+ * user having to reactive their license.
44
+ */
45
+ if ( ! empty( $_optname ) ) {
46
+ $opt = get_option( $_optname, false );
47
+
48
+ if( isset( $opt ) && empty( $this->license ) ) {
49
+ $this->license = trim( $opt );
50
+ }
51
+ }
52
+
53
+ // Setup hooks
54
+ $this->includes();
55
+ $this->hooks();
56
+
57
+ }
58
+
59
+ /**
60
+ * Include the updater class
61
+ *
62
+ * @access private
63
+ * @return void
64
+ */
65
+ private function includes() {
66
+ if ( ! class_exists( 'EDD_SL_Plugin_Updater' ) ) {
67
+ require_once 'EDD_SL_Plugin_Updater.php';
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Setup hooks
73
+ *
74
+ * @access private
75
+ * @return void
76
+ */
77
+ public function hooks() {
78
+
79
+ // Activate license key on settings save
80
+ add_action( 'admin_init', array( $this, 'activate_license' ) );
81
+
82
+ // Deactivate license key
83
+ add_action( 'admin_init', array( $this, 'deactivate_license' ) );
84
+
85
+ add_action( 'init', array( $this, 'cron' ), 20 );
86
+
87
+ add_action( 'admin_init', array( $this, 'validate_license' ) );
88
+
89
+ // Updater
90
+ add_action( 'admin_init', array( $this, 'auto_updater' ), 0 );
91
+
92
+ // Display notices to admins
93
+ add_action( 'admin_notices', array( $this, 'notices' ) );
94
+
95
+ //add_action( 'in_plugin_update_message-' . plugin_basename( $this->file ), array( $this, 'plugin_row_license_missing' ), 10, 2 );
96
+ }
97
+
98
+ /**
99
+ * Auto updater
100
+ *
101
+ * @access private
102
+ * @return void
103
+ */
104
+ public function auto_updater() {
105
+
106
+ $args = array(
107
+ 'version' => $this->version,
108
+ 'license' => $this->license,
109
+ 'author' => $this->author,
110
+ 'beta' => function_exists( 'edd_extension_has_beta_support' ) && edd_extension_has_beta_support( $this->item_shortname ),
111
+ );
112
+
113
+ if( ! empty( $this->item_id ) ) {
114
+ $args['item_id'] = $this->item_id;
115
+ } else {
116
+ $args['item_name'] = $this->item_name;
117
+ }
118
+
119
+ // Setup the updater
120
+ $edd_updater = new EDD_SL_Plugin_Updater(
121
+ $this->api_url,
122
+ $this->file,
123
+ $args
124
+ );
125
+ }
126
+
127
+ public function cron() {
128
+ if ( ! wp_next_scheduled( $this->item_shortname . '_scheduled_events' ) ) {
129
+ wp_schedule_event( current_time( 'timestamp', true ), 'daily', $this->item_shortname . '_scheduled_events' );
130
+ }
131
+ }
132
+
133
+ public function get_slug() {
134
+ return preg_replace( '/[^a-zA-Z0-9_\s]/', '', str_replace( ' ', '_', strtolower( $this->item_name ) ) );
135
+ }
136
+
137
+ /**
138
+ * Display help text at the top of the Licenses tag
139
+ *
140
+ * @since 2.5
141
+ * @param string $active_tab
142
+ * @return void
143
+ */
144
+ public function license_help_text( $active_tab = '' ) {
145
+
146
+ static $has_ran;
147
+
148
+ if( 'licenses' !== $active_tab ) {
149
+ return;
150
+ }
151
+
152
+ if( ! empty( $has_ran ) ) {
153
+ return;
154
+ }
155
+
156
+ echo '<p>' . sprintf(
157
+ __( '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' ),
158
+ 'http://docs.easydigitaldownloads.com/article/1000-license-renewal'
159
+ ) . '</p>';
160
+
161
+ $has_ran = true;
162
+
163
+ }
164
+
165
+
166
+ /**
167
+ * Activate the license key
168
+ *
169
+ * @return void
170
+ */
171
+ public function activate_license() {
172
+
173
+ if ( ! isset( $_POST['post_smtp_extension'][ $this->item_shortname . '_activate'] ) ) {
174
+ return;
175
+ }
176
+
177
+ 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' ) ) {
178
+
179
+ return;
180
+
181
+ }
182
+
183
+ if ( ! current_user_can( 'manage_options' ) ) {
184
+ return;
185
+ }
186
+
187
+ if ( empty( $_POST['post_smtp_extension'][ $this->item_shortname . '_license_key'] ) ) {
188
+
189
+ delete_option( $this->item_shortname . '_license_active' );
190
+ delete_option( $this->item_shortname . '_license_key' );
191
+
192
+ return;
193
+
194
+ }
195
+
196
+ foreach ( $_POST as $key => $value ) {
197
+ if( false !== strpos( $key, 'license_key_deactivate' ) ) {
198
+ // Don't activate a key when deactivating a different key
199
+ return;
200
+ }
201
+ }
202
+
203
+ $details = get_option( $this->item_shortname . '_license_active' );
204
+
205
+ if ( is_object( $details ) && 'valid' === $details->license ) {
206
+ return;
207
+ }
208
+
209
+ $license = sanitize_text_field( $_POST['post_smtp_extension'][ $this->item_shortname . '_license_key'] );
210
+
211
+ if( empty( $license ) ) {
212
+ return;
213
+ }
214
+
215
+ // Data to send to the API
216
+ $api_params = array(
217
+ 'edd_action' => 'activate_license',
218
+ 'license' => $license,
219
+ 'item_name' => urlencode( $this->item_name ),
220
+ 'url' => home_url()
221
+ );
222
+
223
+ if ( ! empty( $this->item_id ) ) {
224
+ $api_params['item_id'] = $this->item_id;
225
+ }
226
+
227
+ // Call the API
228
+ $response = wp_remote_post(
229
+ $this->api_url,
230
+ array(
231
+ 'timeout' => 15,
232
+ 'sslverify' => false,
233
+ 'body' => $api_params
234
+ )
235
+ );
236
+
237
+ // Make sure there are no errors
238
+ if ( is_wp_error( $response ) ) {
239
+ return;
240
+ }
241
+
242
+ // Tell WordPress to look for updates
243
+ set_site_transient( 'update_plugins', null );
244
+
245
+ // Decode license data
246
+ $this->license_data = json_decode( wp_remote_retrieve_body( $response ) );
247
+
248
+ update_option( $this->item_shortname . '_license_active', $this->license_data );
249
+ update_option( $this->item_shortname . '_license_key', $license );
250
+
251
+ if ( $this->license_data->success && $this->license_data->license == 'valid' ) {
252
+ $slug = plugin_basename($this->file);
253
+ PostmanLicenseManager::get_instance()->add_extension($slug);
254
+ }
255
+ }
256
+
257
+
258
+ /**
259
+ * Deactivate the license key
260
+ *
261
+ * @return void
262
+ */
263
+ public function deactivate_license() {
264
+
265
+ if ( ! isset( $_POST['post_smtp_extension'][ $this->item_shortname . '_deactivate'] ) ) {
266
+ return;
267
+ }
268
+
269
+ if ( ! isset( $_POST['post_smtp_extension'][ $this->item_shortname . '_license_key'] ) )
270
+ return;
271
+
272
+ if( ! wp_verify_nonce( $_REQUEST[ $this->item_shortname . '_license_key-nonce'], $this->item_shortname . '_license_key-nonce' ) ) {
273
+
274
+ wp_die( __( 'Nonce verification failed', 'easy-digital-downloads' ), __( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) );
275
+
276
+ }
277
+
278
+ if( ! current_user_can( 'manage_options' ) ) {
279
+ return;
280
+ }
281
+
282
+ $license_key = sanitize_text_field( base64_decode( $_POST['post_smtp_extension'][ $this->item_shortname . '_license_key'] ) );
283
+
284
+ // Run on deactivate button press
285
+ // Data to send to the API
286
+ $api_params = array(
287
+ 'edd_action' => 'deactivate_license',
288
+ 'license' => $license_key,
289
+ 'item_name' => urlencode( $this->item_name ),
290
+ 'url' => home_url()
291
+ );
292
+
293
+ if ( ! empty( $this->item_id ) ) {
294
+ $api_params['item_id'] = $this->item_id;
295
+ }
296
+
297
+ // Call the API
298
+ $response = wp_remote_post(
299
+ $this->api_url,
300
+ array(
301
+ 'timeout' => 15,
302
+ 'sslverify' => false,
303
+ 'body' => $api_params
304
+ )
305
+ );
306
+
307
+ // Make sure there are no errors
308
+ if ( is_wp_error( $response ) ) {
309
+ return;
310
+ }
311
+
312
+ // Decode the license data
313
+ $this->license_data = json_decode( wp_remote_retrieve_body( $response ) );
314
+
315
+ delete_option( $this->item_shortname . '_license_active' );
316
+ delete_option( $this->item_shortname . '_license_key' );
317
+
318
+ $slug = plugin_basename($this->file);
319
+ PostmanLicenseManager::get_instance()->remove_extension($slug);
320
+
321
+ }
322
+
323
+ public function validate_license() {
324
+ if ( false === ( $cron_data = get_transient( $this->item_shortname . '_cron' ) ) ) {
325
+ $this->license_check();
326
+
327
+ set_transient( $this->item_shortname . '_cron', true, rand( 12, 48 ) * HOUR_IN_SECONDS );
328
+ }
329
+
330
+ $license_data = $this->license_data;
331
+
332
+ if ( $license_data && isset( $license_data->expires ) ) {
333
+ if ( $license_data->expires == 'lifetime' ) {
334
+ $expires = '2500/12/12';
335
+ } else {
336
+ $expires = $license_data->expires;
337
+ }
338
+ } else {
339
+ return;
340
+ }
341
+
342
+ $datetime1 = new DateTime();
343
+
344
+ if ( is_numeric( $expires ) ) {
345
+ $datetime2 = new DateTime();
346
+ $datetime2->setTimestamp( $expires );
347
+ } else {
348
+ $datetime2 = new DateTime( $expires );
349
+ }
350
+
351
+ foreach ( self::DAYS_TO_ALERT as $day_to_alert ) {
352
+
353
+ $interval = $datetime1->diff($datetime2);
354
+ if( $interval->days == $day_to_alert ){
355
+ add_action( 'admin_notices', function () use ( $day_to_alert, $license_data ) {
356
+ //echo $this->item_name . ' is about to expire in ' . $day_to_alert . ' days: ' . $license_data->expires;
357
+ });
358
+
359
+ return;
360
+ }
361
+
362
+ if ( $interval->days == 0 ) {
363
+ add_action( 'admin_notices', function () use ( $license_data ) {
364
+ //echo $this->item_name . ' license expire today at: ' . $license_data->expires;
365
+ });
366
+
367
+ return;
368
+ }
369
+ }
370
+
371
+ if ( $license_data->activations_left == 0 ) {
372
+ add_action( 'admin_notices', function () use ( $license_data ) {
373
+ //echo $this->item_name . ' has no activations';
374
+ });
375
+
376
+ return;
377
+ }
378
+ }
379
+
380
+
381
+ /**
382
+ * Check if license key is valid once per week
383
+ *
384
+ * @since 2.5
385
+ * @return void
386
+ */
387
+ public function license_check() {
388
+
389
+ // data to send in our API request
390
+ $api_params = array(
391
+ 'edd_action'=> 'check_license',
392
+ 'license' => $this->license,
393
+ 'item_name' => urlencode( $this->item_name ),
394
+ 'url' => home_url()
395
+ );
396
+
397
+ // Call the API
398
+ $response = wp_remote_post(
399
+ $this->api_url,
400
+ array(
401
+ 'timeout' => 15,
402
+ 'sslverify' => false,
403
+ 'body' => $api_params
404
+ )
405
+ );
406
+
407
+ // make sure the response came back okay
408
+ if ( is_wp_error( $response ) ) {
409
+ return false;
410
+ }
411
+
412
+ if ( wp_remote_retrieve_response_code( $response ) !== 200 ) {
413
+ return false;
414
+ }
415
+
416
+ $this->license_data = json_decode( wp_remote_retrieve_body( $response ) );
417
+
418
+ update_option( $this->item_shortname . '_license_active', $this->license_data );
419
+
420
+ }
421
+
422
+ private function get_license_data() {
423
+ return get_option( $this->item_shortname . '_license_active' );
424
+ }
425
+
426
+
427
+ /**
428
+ * Admin notices for errors
429
+ *
430
+ * @return void
431
+ */
432
+ public function notices() {
433
+
434
+ $showed_invalid_message = null;
435
+
436
+ if( empty( $this->license ) ) {
437
+ return;
438
+ }
439
+
440
+ if( ! current_user_can( 'manage_options' ) ) {
441
+ return;
442
+ }
443
+
444
+ $messages = array();
445
+
446
+ $license = get_option( $this->item_shortname . '_license_active' );
447
+
448
+ if( is_object( $license ) && 'valid' !== $license->license && empty( $showed_invalid_message ) ) {
449
+
450
+ if( isset( $_GET['page'] ) && 'post-smtp-extensions' === $_GET['page'] ) {
451
+
452
+ $messages[] = sprintf(
453
+ __( '%s has invalid or expired license key for Post SMTP.'),
454
+ '<strong>' . $this->item_name . '</strong>'
455
+ );
456
+
457
+ $showed_invalid_message = true;
458
+
459
+ }
460
+
461
+ }
462
+
463
+ if( ! empty( $messages ) ) {
464
+
465
+ foreach( $messages as $message ) {
466
+
467
+ echo '<div class="error">';
468
+ echo '<p>' . $message . '</p>';
469
+ echo '</div>';
470
+
471
+ }
472
+
473
+ }
474
+
475
+ }
476
+
477
+ public function is_licensed() {
478
+ return is_object($this->license_data) && 'valid' === $this->license_data->license;
479
+ }
480
+ }
481
+
482
+ endif; // end class_exists check
Postman/Extensions/License/PostmanLicenseManager.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) exit;
3
+
4
+ class PostmanLicenseManager {
5
+
6
+ const ENDPOINT = 'https://postmansmtp.com';
7
+
8
+ const CORE_EXTENSIONS = [ 'gmail_api', 'sendgrid_api', 'mandrill_api', 'mailgun_api' ];
9
+
10
+ private $extensions;
11
+
12
+ private $rand_cache_interval = 12;
13
+
14
+ private static $instance;
15
+
16
+ public static function get_instance() {
17
+ if ( ! self::$instance ) {
18
+ self::$instance = new static();
19
+ }
20
+
21
+ return self::$instance;
22
+ }
23
+
24
+ /**
25
+ * PostmanLicenseManager constructor.
26
+ */
27
+ private function __construct()
28
+ {
29
+ $this->includes();
30
+ $this->rand_cache_interval = rand( 1, 24 );
31
+ }
32
+
33
+ public function includes() {
34
+ include_once 'PostmanLicenseHandler.php';
35
+
36
+ include_once ABSPATH . '/wp-admin/includes/plugin.php';
37
+
38
+ }
39
+
40
+ /**
41
+ * Init
42
+ */
43
+ public function init() {
44
+
45
+ $plugins = get_plugins();
46
+ foreach ( $plugins as $plugin_dir_and_filename => $plugin_data ) {
47
+
48
+ if ( ! is_plugin_active( $plugin_dir_and_filename ) ) {
49
+ continue;
50
+ }
51
+
52
+ if ( false !== strpos( $plugin_dir_and_filename, 'post-smtp-extension' ) ) {
53
+ $slug = $plugin_dir_and_filename;
54
+ $class = $plugin_data['Class'];
55
+ $plugin_path = WP_CONTENT_DIR . '/plugins/' . $plugin_dir_and_filename;
56
+
57
+ $this->extensions[$slug]['plugin_data'] = $plugin_data;
58
+ $this->extensions[$slug]['plugin_dir_and_filename'] = $plugin_dir_and_filename;
59
+ $this->extensions[$slug]['license_manager'] = new PostmanLicenseHandler(
60
+ $plugin_path, $plugin_data['Name'],
61
+ $plugin_data['Version'], $plugin_data['Author'], null, self::ENDPOINT
62
+ );
63
+ if ( $this->extensions[$slug]['license_manager']->is_licensed() ) {
64
+ $this->extensions[$slug]['instance'] = new $class;
65
+ }
66
+ }
67
+ }
68
+
69
+ if ( ! empty( $this->extensions ) ) {
70
+ new PostmanAdmin();
71
+ }
72
+ }
73
+
74
+ public function add_extension($slug) {
75
+ $plugin_path = WP_CONTENT_DIR . '/plugins/' . $this->extensions[$slug]['plugin_dir_and_filename'];
76
+ $class = $this->extensions[$slug]['plugin_data']['Class'];
77
+
78
+ include_once $plugin_path;
79
+ $this->extensions[$slug]['instance'] = new $class;
80
+ }
81
+
82
+ public function remove_extension($slug) {
83
+ $this->extensions[$slug]['instance'] = null;
84
+ unset($this->extensions[$slug]['instance']);
85
+ }
86
+
87
+ public function get_extensions() {
88
+ return $this->extensions;
89
+ }
90
+ }
Postman/Postman-Mail/PostmanSendinblueMailEngine.php CHANGED
@@ -206,9 +206,13 @@ class PostmanSendinblueMailEngine implements PostmanMailEngine {
206
 
207
  $recipient->log($this->logger, 'Bcc');
208
  $bcc[] = array(
209
- 'email' => $recipient->getEmail(),
210
- 'name' => '$recipient->getName()'
211
  );
 
 
 
 
 
212
  $duplicates[] = $recipient->getEmail();
213
 
214
  }
206
 
207
  $recipient->log($this->logger, 'Bcc');
208
  $bcc[] = array(
209
+ 'email' => $recipient->getEmail()
 
210
  );
211
+
212
+ if( !empty( $recipient->getName() ) ) {
213
+ $bcc['name'] = $recipient->getName();
214
+ }
215
+
216
  $duplicates[] = $recipient->getEmail();
217
 
218
  }
Postman/PostmanViewController.php CHANGED
@@ -33,6 +33,7 @@ if ( ! class_exists( 'PostmanViewController' ) ) {
33
  $this->adminController = $adminController;
34
  $this->logger = new PostmanLogger( get_class( $this ) );
35
  $hostname = PostmanOptions::getInstance()->getHostname();
 
36
  $auth_type = PostmanOptions::getInstance()->getAuthenticationType();
37
 
38
  PostmanUtils::registerAdminMenu( $this, 'generateDefaultContent' );
@@ -43,8 +44,11 @@ if ( ! class_exists( 'PostmanViewController' ) ) {
43
  add_action( 'wp_ajax_delete_lock_file', array( $this, 'delete_lock_file' ) );
44
  add_action( 'wp_ajax_dismiss_version_notify', array( $this, 'dismiss_version_notify' ) );
45
  add_action( 'wp_ajax_dismiss_donation_notify', array( $this, 'dismiss_donation_notify' ) );
46
-
47
- if( $hostname == 'smtp.gmail.com' && $auth_type == 'plain' ) {
 
 
 
48
  add_action( 'admin_notices', array( $this, 'google_less_secure_notice' ) );
49
  }
50
 
@@ -177,9 +181,13 @@ if ( ! class_exists( 'PostmanViewController' ) ) {
177
  ), '1.13.1' );
178
 
179
  wp_localize_script( PostmanViewController::POSTMAN_SCRIPT, 'postman_ajax_msg', array(
180
- 'bad_response' => __( 'An unexpected error occurred', 'post-smtp' ),
181
- 'corrupt_response' => __( 'Unexpected PHP messages corrupted the Ajax response', 'post-smtp' ),
182
  ) );
 
 
 
 
183
  }
184
 
185
  /**
@@ -236,8 +244,17 @@ if ( ! class_exists( 'PostmanViewController' ) ) {
236
  }
237
  } else {
238
  printf(
239
- '<div class="ps-config-bar"><span >%s</span><span style="color: red" class="dashicons dashicons-dismiss"></span></div>',
240
- wp_kses_post( $statusMessage )
 
 
 
 
 
 
 
 
 
241
  );
242
  }
243
 
@@ -649,19 +666,48 @@ if ( ! class_exists( 'PostmanViewController' ) ) {
649
  public function google_less_secure_notice() {
650
 
651
  ?>
652
- <div class="notice notice-error is-dismissible">
653
  <?php
654
  printf(
655
- '<p>%1$s <br />%2$s <a href="%3$s" target="_blank">%4$s</a></p>',
656
  esc_html__( '"To help keep your account secure, starting May 30, 2022, ​​Google will no longer support the use of third-party apps or devices which ask you to sign in to your Google Account using only your username and password."', 'post-smtp' ),
657
  esc_html__( 'You can switch to Auth 2.0 option to continue without any downtime.', 'post-smtp' ),
658
  esc_url( 'https://postmansmtp.com/gmail-is-disabling-less-secure-apps' ),
659
- esc_html__( 'Click here for more info', 'post-smtp' )
 
660
  );
661
  ?>
662
  </div>
663
  <?php
664
 
665
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
666
  }
667
  }
33
  $this->adminController = $adminController;
34
  $this->logger = new PostmanLogger( get_class( $this ) );
35
  $hostname = PostmanOptions::getInstance()->getHostname();
36
+ $transportType = PostmanOptions::getInstance()->getTransportType();
37
  $auth_type = PostmanOptions::getInstance()->getAuthenticationType();
38
 
39
  PostmanUtils::registerAdminMenu( $this, 'generateDefaultContent' );
44
  add_action( 'wp_ajax_delete_lock_file', array( $this, 'delete_lock_file' ) );
45
  add_action( 'wp_ajax_dismiss_version_notify', array( $this, 'dismiss_version_notify' ) );
46
  add_action( 'wp_ajax_dismiss_donation_notify', array( $this, 'dismiss_donation_notify' ) );
47
+ add_action( 'wp_ajax_ps-discard-less-secure-notification', array( $this, 'discard_less_secure_notification' ) );
48
+
49
+ $show_less_secure_notification = get_option( 'ps_hide_less_secure' );
50
+
51
+ if( !$show_less_secure_notification && $transportType == 'smtp' && $hostname == 'smtp.gmail.com' && ( $auth_type == 'plain' || $auth_type == 'login' ) ) {
52
  add_action( 'admin_notices', array( $this, 'google_less_secure_notice' ) );
53
  }
54
 
181
  ), '1.13.1' );
182
 
183
  wp_localize_script( PostmanViewController::POSTMAN_SCRIPT, 'postman_ajax_msg', array(
184
+ 'bad_response' => __( 'An unexpected error occurred', 'post-smtp' ),
185
+ 'corrupt_response' => __( 'Unexpected PHP messages corrupted the Ajax response', 'post-smtp' )
186
  ) );
187
+
188
+ wp_localize_script( PostmanViewController::POSTMAN_SCRIPT, 'postman_ajax', array(
189
+ 'lessSecureNotice' => wp_create_nonce( 'less-secure-security' )
190
+ ) );
191
  }
192
 
193
  /**
244
  }
245
  } else {
246
  printf(
247
+ '<div class="ps-config-bar">
248
+ <span >%s</span>
249
+ <span style="color: red" class="dashicons dashicons-dismiss"></span>
250
+ <div class="ps-right">
251
+ %s <a href="%s" class="ps-btn-orange">%s</a>
252
+ </div>
253
+ </div>',
254
+ wp_kses_post( $statusMessage ),
255
+ esc_html__( 'Get Started by Setup Wizard!', 'post-smtp' ),
256
+ esc_attr( $this->getPageUrl( PostmanConfigurationController::CONFIGURATION_WIZARD_SLUG ) ),
257
+ esc_html__( 'Start the Wizard', 'post-smtp' )
258
  );
259
  }
260
 
666
  public function google_less_secure_notice() {
667
 
668
  ?>
669
+ <div class="notice notice-error is-dismissible ps-less-secure-notice">
670
  <?php
671
  printf(
672
+ '<p>%1$s <br />%2$s <a href="%3$s" target="_blank">%4$s</a><br /><a href="" id="discard-less-secure-notification">%5$s</a></p>',
673
  esc_html__( '"To help keep your account secure, starting May 30, 2022, ​​Google will no longer support the use of third-party apps or devices which ask you to sign in to your Google Account using only your username and password."', 'post-smtp' ),
674
  esc_html__( 'You can switch to Auth 2.0 option to continue without any downtime.', 'post-smtp' ),
675
  esc_url( 'https://postmansmtp.com/gmail-is-disabling-less-secure-apps' ),
676
+ esc_html__( 'Click here for more info', 'post-smtp' ),
677
+ esc_html__( 'I understand and would like to discard this notice', 'post-smtp' ),
678
  );
679
  ?>
680
  </div>
681
  <?php
682
 
683
  }
684
+
685
+ /**
686
+ * Discards less secure notification
687
+ *
688
+ * @since 2.1.2
689
+ * @version 1.0
690
+ */
691
+ public function discard_less_secure_notification() {
692
+
693
+ if( !wp_verify_nonce( $_POST['_wp_nonce'], 'less-secure-security' ) ) {
694
+ die( 'Not Secure.' );
695
+ }
696
+
697
+ $result = update_option( 'ps_hide_less_secure', 1 );
698
+
699
+ if( $result ) {
700
+