Post SMTP Mailer/Email Log - Version 1.7.8

Version Description

  • 2017-11-17 *
Download this release

Release Info

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

Code changes from version 1.7.7 to 1.7.8

Postman/Postman-Configuration/PostmanRegisterConfigurationSettings.php CHANGED
@@ -347,7 +347,7 @@ class PostmanSettingsRegistry {
347
  * Get the settings option array and print one of its values
348
  */
349
  public function log_level_callback() {
350
- $inputDescription = sprintf ( __ ( 'Log Level specifies the level of detail written to the <a target="_new" href="%s">WordPress Debug log</a> - view the log with <a target-"_new" href="%s">Debug</a>.', Postman::TEXT_DOMAIN ), 'https://codex.wordpress.org/Debugging_in_WordPress', 'https://wordpress.org/plugins/debug/' );
351
  printf ( '<select id="input_%2$s" class="input_%2$s" name="%1$s[%2$s]">', PostmanOptions::POSTMAN_OPTIONS, PostmanOptions::LOG_LEVEL );
352
  $currentKey = $this->options->getLogLevel ();
353
  $this->printSelectOption ( __ ( 'Off', Postman::TEXT_DOMAIN ), PostmanLogger::OFF_INT, $currentKey );
347
  * Get the settings option array and print one of its values
348
  */
349
  public function log_level_callback() {
350
+ $inputDescription = sprintf ( __ ( 'Log Level specifies the level of detail written to the <a target="_blank" href="%s">WordPress Debug log</a> - view the log with <a target-"_new" href="%s">Debug</a>.', Postman::TEXT_DOMAIN ), 'https://codex.wordpress.org/Debugging_in_WordPress', 'https://wordpress.org/plugins/debug/' );
351
  printf ( '<select id="input_%2$s" class="input_%2$s" name="%1$s[%2$s]">', PostmanOptions::POSTMAN_OPTIONS, PostmanOptions::LOG_LEVEL );
352
  $currentKey = $this->options->getLogLevel ();
353
  $this->printSelectOption ( __ ( 'Off', Postman::TEXT_DOMAIN ), PostmanLogger::OFF_INT, $currentKey );
Postman/Postman-Connectivity-Test/PostmanConnectivityTestController.php CHANGED
@@ -154,7 +154,7 @@ class PostmanConnectivityTestController {
154
  }
155
  print '</table>';
156
  /* Translators: Where %s is the name of the service providing Internet connectivity test */
157
- printf( '<p class="portquiz" style="display:none; font-size:0.8em">* %s</p>', sprintf( __( 'According to %s', Postman::TEXT_DOMAIN ), '<a target="_new" href="http://ww.downor.me/portquiz.net">portquiz.net</a>' ) );
158
  printf( '<p class="ajax-loader" style="display:none"><img src="%s"/></p>', plugins_url( 'post-smtp/style/ajax-loader.gif' ) );
159
  print '<section id="conclusion" style="display:none">';
160
  print sprintf( '<h3>%s:</h3>', __( 'Summary', Postman::TEXT_DOMAIN ) );
154
  }
155
  print '</table>';
156
  /* Translators: Where %s is the name of the service providing Internet connectivity test */
157
+ printf( '<p class="portquiz" style="display:none; font-size:0.8em">* %s</p>', sprintf( __( 'According to %s', Postman::TEXT_DOMAIN ), '<a target="_blank" href="http://ww.downor.me/portquiz.net">portquiz.net</a>' ) );
158
  printf( '<p class="ajax-loader" style="display:none"><img src="%s"/></p>', plugins_url( 'post-smtp/style/ajax-loader.gif' ) );
159
  print '<section id="conclusion" style="display:none">';
160
  print sprintf( '<h3>%s:</h3>', __( 'Summary', Postman::TEXT_DOMAIN ) );
Postman/Postman-Connectivity-Test/registered-domain-libs-master/generateEffectiveTLDs.php CHANGED
@@ -150,7 +150,7 @@ error_reporting(E_ERROR);
150
  $tldTree = array();
151
  $list = file_get_contents(URL);
152
  // $list = "bg\na.bg\n0.bg\n!c.bg\n";
153
- $lines = split("\n", $list);
154
  $licence = TRUE;
155
 
156
  if ($format == "php") echo "<?php\n";
@@ -176,7 +176,7 @@ foreach ($lines as $line) {
176
  }
177
 
178
  // this must be a TLD
179
- $tldParts = split('\.', $line);
180
  buildSubdomain($tldTree, $tldParts);
181
  }
182
 
150
  $tldTree = array();
151
  $list = file_get_contents(URL);
152
  // $list = "bg\na.bg\n0.bg\n!c.bg\n";
153
+ $lines = explode("\n", $list);
154
  $licence = TRUE;
155
 
156
  if ($format == "php") echo "<?php\n";
176
  }
177
 
178
  // this must be a TLD
179
+ $tldParts = preg_split('\.', $line);
180
  buildSubdomain($tldTree, $tldParts);
181
  }
182
 
Postman/Postman-Email-Log/PostmanEmailLogController.php CHANGED
@@ -5,194 +5,193 @@ require_once 'PostmanEmailLogView.php';
5
  /**
6
  *
7
  * @author jasonhendriks
8
- *
9
  */
10
  class PostmanEmailLogController {
11
  const RESEND_MAIL_AJAX_SLUG = 'postman_resend_mail';
12
  private $rootPluginFilenameAndPath;
13
  private $logger;
14
-
15
  /**
16
  */
17
- function __construct($rootPluginFilenameAndPath) {
18
  $this->rootPluginFilenameAndPath = $rootPluginFilenameAndPath;
19
- $this->logger = new PostmanLogger ( get_class ( $this ) );
20
- if (PostmanOptions::getInstance ()->isMailLoggingEnabled ()) {
21
- add_action ( 'admin_menu', array (
22
  $this,
23
- 'postmanAddMenuItem'
24
- ) );
25
  } else {
26
- $this->logger->trace ( 'not creating PostmanEmailLog admin menu item' );
27
  }
28
- if (PostmanUtils::isCurrentPagePostmanAdmin ( 'postman_email_log' )) {
29
- $this->logger->trace ( 'on postman email log page' );
30
  // $this->logger->debug ( 'Registering ' . $actionName . ' Action Post handler' );
31
- add_action ( 'admin_post_delete', array (
32
  $this,
33
- 'delete_log_item'
34
  ) );
35
- add_action ( 'admin_post_view', array (
36
  $this,
37
- 'view_log_item'
38
  ) );
39
- add_action ( 'admin_post_transcript', array (
40
  $this,
41
- 'view_transcript_log_item'
42
  ) );
43
- add_action ( 'admin_init', array (
44
  $this,
45
- 'on_admin_init'
46
  ) );
47
  }
48
- if (is_admin ()) {
49
  $actionName = self::RESEND_MAIL_AJAX_SLUG;
50
  $fullname = 'wp_ajax_' . $actionName;
51
  // $this->logger->debug ( 'Registering ' . 'wp_ajax_' . $fullname . ' Ajax handler' );
52
- add_action ( $fullname, array (
53
  $this,
54
- 'resendMail'
55
  ) );
56
  }
57
  }
58
-
59
  /**
60
  */
61
  function on_admin_init() {
62
- $this->handleBulkAction ();
63
  // register the stylesheet and javascript external resources
64
- $pluginData = apply_filters ( 'postman_get_plugin_metadata', null );
65
- wp_register_script ( 'postman_resend_email_script', plugins_url ( 'script/postman_resend_email_sript.js', $this->rootPluginFilenameAndPath ), array (
66
  PostmanViewController::JQUERY_SCRIPT,
67
- PostmanViewController::POSTMAN_SCRIPT
68
  ), $pluginData ['version'] );
69
  }
70
-
71
  /**
72
  */
73
  public function resendMail() {
74
  // get the email address of the recipient from the HTTP Request
75
- $postid = $this->getRequestParameter ( 'email' );
76
- if (! empty ( $postid )) {
77
- $post = get_post ( $postid );
78
- $meta_values = get_post_meta ( $postid );
79
-
80
- $success = wp_mail ( $meta_values ['original_to'] [0], $meta_values ['original_subject'] [0], $meta_values ['original_message'] [0], $meta_values ['original_headers'] [0] );
81
-
82
  // Postman API: retrieve the result of sending this message from Postman
83
- $result = apply_filters ( 'postman_wp_mail_result', null );
84
  $transcript = $result ['transcript'];
85
-
86
  // post-handling
87
- if ($success) {
88
- $this->logger->debug ( 'Email was successfully re-sent' );
89
  // the message was sent successfully, generate an appropriate message for the user
90
- $statusMessage = sprintf ( __ ( 'Your message was delivered (%d ms) to the SMTP server! Congratulations :)', Postman::TEXT_DOMAIN ), $result ['time'] );
91
-
92
  // compose the JSON response for the caller
93
- $response = array (
94
  'message' => $statusMessage,
95
- 'transcript' => $transcript
96
  );
97
- $this->logger->trace ( 'AJAX response' );
98
- $this->logger->trace ( $response );
99
  // send the JSON response
100
- wp_send_json_success ( $response );
101
  } else {
102
- $this->logger->error ( 'Email was not successfully re-sent - ' . $result ['exception']->getCode () );
103
  // the message was NOT sent successfully, generate an appropriate message for the user
104
- $statusMessage = $result ['exception']->getMessage ();
105
-
106
  // compose the JSON response for the caller
107
- $response = array (
108
  'message' => $statusMessage,
109
- 'transcript' => $transcript
110
  );
111
- $this->logger->trace ( 'AJAX response' );
112
- $this->logger->trace ( $response );
113
  // send the JSON response
114
- wp_send_json_error ( $response );
115
  }
116
  } else {
117
  // compose the JSON response for the caller
118
- $response = array ();
119
  // send the JSON response
120
- wp_send_json_error ( $response );
121
  }
122
  }
123
-
124
  /**
125
  * TODO move this somewhere reusable
126
  *
127
- * @param unknown $parameterName
128
  * @return unknown
129
  */
130
- private function getRequestParameter($parameterName) {
131
- if (isset ( $_POST [$parameterName] )) {
132
- $value = filter_var( $_POST [$parameterName], FILTER_SANITIZE_STRING );
133
- $this->logger->trace ( sprintf ( 'Found parameter "%s"', $parameterName ) );
134
- $this->logger->trace ( $value );
135
  return $value;
136
  }
137
  }
138
-
139
  /**
140
  * From https://www.skyverge.com/blog/add-custom-bulk-action/
141
  */
142
  function handleBulkAction() {
143
  // only do this for administrators
144
- if (PostmanUtils::isAdmin () && isset ( $_REQUEST ['email_log_entry'] )) {
145
- $this->logger->trace ( 'handling bulk action' );
146
- if (wp_verify_nonce ( $_REQUEST ['_wpnonce'], 'bulk-email_log_entries' )) {
147
- $this->logger->trace ( sprintf ( 'nonce "%s" passed validation', $_REQUEST ['_wpnonce'] ) );
148
- if (isset ( $_REQUEST ['action'] ) && ($_REQUEST ['action'] == 'bulk_delete' || $_REQUEST ['action2'] == 'bulk_delete')) {
149
- $this->logger->trace ( sprintf ( 'handling bulk delete' ) );
150
- $purger = new PostmanEmailLogPurger ();
151
  $postids = $_REQUEST ['email_log_entry'];
152
  foreach ( $postids as $postid ) {
153
- $purger->verifyLogItemExistsAndRemove ( $postid );
154
  }
155
- $mh = new PostmanMessageHandler ();
156
- $mh->addMessage ( __ ( 'Mail Log Entries were deleted.', Postman::TEXT_DOMAIN ) );
157
  } else {
158
- $this->logger->warn ( sprintf ( 'action "%s" not recognized', $_REQUEST ['action'] ) );
159
  }
160
  } else {
161
- $this->logger->warn ( sprintf ( 'nonce "%s" failed validation', $_REQUEST ['_wpnonce'] ) );
162
  }
163
- $this->redirectToLogPage ();
164
  }
165
  }
166
-
167
  /**
168
  */
169
  function delete_log_item() {
170
  // only do this for administrators
171
- if (PostmanUtils::isAdmin ()) {
172
- $this->logger->trace ( 'handling delete item' );
173
  $postid = $_REQUEST ['email'];
174
- if (wp_verify_nonce ( $_REQUEST ['_wpnonce'], 'delete_email_log_item_' . $postid )) {
175
- $this->logger->trace ( sprintf ( 'nonce "%s" passed validation', $_REQUEST ['_wpnonce'] ) );
176
- $purger = new PostmanEmailLogPurger ();
177
- $purger->verifyLogItemExistsAndRemove ( $postid );
178
- $mh = new PostmanMessageHandler ();
179
- $mh->addMessage ( __ ( 'Mail Log Entry was deleted.', Postman::TEXT_DOMAIN ) );
180
  } else {
181
- $this->logger->warn ( sprintf ( 'nonce "%s" failed validation', $_REQUEST ['_wpnonce'] ) );
182
  }
183
- $this->redirectToLogPage ();
184
  }
185
  }
186
-
187
  /**
188
  */
189
  function view_log_item() {
190
  // only do this for administrators
191
- if (PostmanUtils::isAdmin ()) {
192
- $this->logger->trace ( 'handling view item' );
193
  $postid = $_REQUEST ['email'];
194
- $post = get_post ( $postid );
195
- $meta_values = get_post_meta ( $postid );
196
  // https://css-tricks.com/examples/hrs/
197
  print '<html><head><style>body {font-family: monospace;} hr {
198
  border: 0;
@@ -200,110 +199,119 @@ class PostmanEmailLogController {
200
  background: #bbb;
201
  }</style></head><body>';
202
  print '<table>';
203
- if (! empty ( $meta_values ['from_header'] [0] )) {
204
- printf ( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x ( 'From', 'Who is this message From?', Postman::TEXT_DOMAIN ), esc_html ( $meta_values ['from_header'] [0] ) );
205
  }
206
  // show the To header (it's optional)
207
- if (! empty ( $meta_values ['to_header'] [0] )) {
208
- printf ( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x ( 'To', 'Who is this message To?', Postman::TEXT_DOMAIN ), esc_html ( $meta_values ['to_header'] [0] ) );
209
  }
210
  // show the Cc header (it's optional)
211
- if (! empty ( $meta_values ['cc_header'] [0] )) {
212
- printf ( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x ( 'Cc', 'Who is this message Cc\'d to?', Postman::TEXT_DOMAIN ), esc_html ( $meta_values ['cc_header'] [0] ) );
213
  }
214
  // show the Bcc header (it's optional)
215
- if (! empty ( $meta_values ['bcc_header'] [0] )) {
216
- printf ( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x ( 'Bcc', 'Who is this message Bcc\'d to?', Postman::TEXT_DOMAIN ), esc_html ( $meta_values ['bcc_header'] [0] ) );
217
  }
218
  // show the Reply-To header (it's optional)
219
- if (! empty ( $meta_values ['reply_to_header'] [0] )) {
220
- printf ( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', __ ( 'Reply-To', Postman::TEXT_DOMAIN ), esc_html ( $meta_values ['reply_to_header'] [0] ) );
221
  }
222
- printf ( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x ( 'Date', 'What is the date today?', Postman::TEXT_DOMAIN ), $post->post_date );
223
- printf ( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x ( 'Subject', 'What is the subject of this message?', Postman::TEXT_DOMAIN ), esc_html ( $post->post_title ) );
224
  // The Transport UI is always there, in more recent versions that is
225
- if (! empty ( $meta_values ['transport_uri'] [0] )) {
226
- printf ( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x ( 'Delivery-URI', 'What is the unique URI of the configuration?', Postman::TEXT_DOMAIN ), esc_html ( $meta_values ['transport_uri'] [0] ) );
227
  }
228
  print '</table>';
229
  print '<hr/>';
230
  print '<pre>';
231
- print esc_html ( $post->post_content );
232
  print '</pre>';
233
  print '</body></html>';
234
- die ();
235
  }
236
  }
237
-
 
 
 
 
 
 
 
238
  /**
239
  */
240
  function view_transcript_log_item() {
241
  // only do this for administrators
242
- if (PostmanUtils::isAdmin ()) {
243
- $this->logger->trace ( 'handling view transcript item' );
244
  $postid = $_REQUEST ['email'];
245
- $post = get_post ( $postid );
246
- $meta_values = get_post_meta ( $postid );
247
  // https://css-tricks.com/examples/hrs/
248
  print '<html><head><style>body {font-family: monospace;} hr {
249
  border: 0;
250
  border-bottom: 1px dashed #ccc;
251
  background: #bbb;
252
  }</style></head><body>';
253
- printf ( '<p>%s</p>', __ ( 'This is the conversation between Postman and the mail server. It can be useful for diagnosing problems. <b>DO NOT</b> post it on-line, it may contain your account password.', Postman::TEXT_DOMAIN ) );
254
  print '<hr/>';
255
  print '<pre>';
256
- if (! empty ( $meta_values ['session_transcript'] [0] )) {
257
- print esc_html ( $meta_values ['session_transcript'] [0] );
258
  } else {
259
  /* Translators: Meaning "Not Applicable" */
260
- print __ ( 'n/a', Postman::TEXT_DOMAIN );
261
  }
262
  print '</pre>';
263
  print '</body></html>';
264
- die ();
265
  }
266
  }
267
-
268
  /**
269
  * For whatever reason, PostmanUtils::get..url doesn't work here? :(
270
  */
271
  function redirectToLogPage() {
272
- PostmanUtils::redirect ( PostmanUtils::POSTMAN_EMAIL_LOG_PAGE_RELATIVE_URL );
273
- die ();
274
  }
275
-
276
  /**
277
  * Register the page
278
  */
279
  function postmanAddMenuItem() {
280
  // only do this for administrators
281
- if (PostmanUtils::isAdmin ()) {
282
- $this->logger->trace ( 'created PostmanEmailLog admin menu item' );
283
- /* Translators where (%s) is the name of the plugin */
284
- $page = add_management_page ( sprintf ( __ ( '%s Email Log', Postman::TEXT_DOMAIN ), __ ( 'Postman SMTP', Postman::TEXT_DOMAIN ) ), _x ( 'Email Log', 'The log of Emails that have been delivered', Postman::TEXT_DOMAIN ), 'read_private_posts', 'postman_email_log', array (
285
- $this,
286
- 'postman_render_email_page'
287
- ) );
 
 
288
  // When the plugin options page is loaded, also load the stylesheet
289
- add_action ( 'admin_print_styles-' . $page, array (
290
  $this,
291
- 'postman_email_log_enqueue_resources'
292
  ) );
293
  }
294
  }
295
  function postman_email_log_enqueue_resources() {
296
- $pluginData = apply_filters ( 'postman_get_plugin_metadata', null );
297
- wp_register_style ( 'postman_email_log', plugins_url ( 'style/postman-email-log.css', $this->rootPluginFilenameAndPath ), null, $pluginData ['version'] );
298
- wp_enqueue_style ( 'postman_email_log' );
299
- wp_enqueue_script ( 'postman_resend_email_script' );
300
- wp_enqueue_script ( 'sprintf' );
301
- wp_localize_script ( 'postman_resend_email_script', 'postman_js_email_was_resent', __ ( 'Email was successfully resent (but without attachments)', Postman::TEXT_DOMAIN ) );
302
  /* Translators: Where %s is an error message */
303
- wp_localize_script ( 'postman_resend_email_script', 'postman_js_email_not_resent', __ ( 'Email could not be resent. Error: %s', Postman::TEXT_DOMAIN ) );
304
- wp_localize_script ( 'postman_resend_email_script', 'postman_js_resend_label', __ ( 'Resend', Postman::TEXT_DOMAIN ) );
305
  }
306
-
307
  /**
308
  * *************************** RENDER TEST PAGE ********************************
309
  * ******************************************************************************
@@ -315,40 +323,71 @@ class PostmanEmailLogController {
315
  * it's the way the list tables are used in the WordPress core.
316
  */
317
  function postman_render_email_page() {
318
-
319
  // Create an instance of our package class...
320
- $testListTable = new PostmanEmailLogView ();
321
- wp_enqueue_script ( 'postman_resend_email_script' );
322
  // Fetch, prepare, sort, and filter our data...
323
- $testListTable->prepare_items ();
324
-
325
  ?>
326
  <div class="wrap">
327
 
328
  <div id="icon-users" class="icon32">
329
  <br />
330
  </div>
331
- <h2><?php
332
- /* Translators where (%s) is the name of the plugin */
333
- echo sprintf ( __ ( '%s Email Log', Postman::TEXT_DOMAIN ), __ ( 'Postman SMTP', Postman::TEXT_DOMAIN ) )?></h2>
334
 
335
  <div
336
  style="background: #ECECEC; border: 1px solid #CCC; padding: 0 10px; margin-top: 5px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px;">
337
  <p><?php
338
-
339
- echo __ ( 'This is a record of deliveries made to the mail server. It does not neccessarily indicate sucessful delivery to the recipient.', Postman::TEXT_DOMAIN )?></p>
340
  </div>
341
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  <!-- Forms are NOT created automatically, so you need to wrap the table in one to use features like bulk actions -->
343
  <form id="movies-filter" method="get">
344
  <!-- For plugins, we also need to ensure that the form posts back to our current page -->
345
  <input type="hidden" name="page"
346
  value="<?php echo filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING ); ?>" />
 
347
  <!-- Now we can render the completed list table -->
348
- <?php $testListTable->display()?>
349
- </form>
350
-
351
- <?php add_thickbox(); ?>
352
 
353
  </div>
354
  <?php
5
  /**
6
  *
7
  * @author jasonhendriks
 
8
  */
9
  class PostmanEmailLogController {
10
  const RESEND_MAIL_AJAX_SLUG = 'postman_resend_mail';
11
  private $rootPluginFilenameAndPath;
12
  private $logger;
13
+
14
  /**
15
  */
16
+ function __construct( $rootPluginFilenameAndPath ) {
17
  $this->rootPluginFilenameAndPath = $rootPluginFilenameAndPath;
18
+ $this->logger = new PostmanLogger( get_class( $this ) );
19
+ if ( PostmanOptions::getInstance()->isMailLoggingEnabled() ) {
20
+ add_action( 'admin_menu', array(
21
  $this,
22
+ 'postmanAddMenuItem',
23
+ ),20 );
24
  } else {
25
+ $this->logger->trace( 'not creating PostmanEmailLog admin menu item' );
26
  }
27
+ if ( PostmanUtils::isCurrentPagePostmanAdmin( 'postman_email_log' ) ) {
28
+ $this->logger->trace( 'on postman email log page' );
29
  // $this->logger->debug ( 'Registering ' . $actionName . ' Action Post handler' );
30
+ add_action( 'admin_post_delete', array(
31
  $this,
32
+ 'delete_log_item',
33
  ) );
34
+ add_action( 'admin_post_view', array(
35
  $this,
36
+ 'view_log_item',
37
  ) );
38
+ add_action( 'admin_post_transcript', array(
39
  $this,
40
+ 'view_transcript_log_item',
41
  ) );
42
+ add_action( 'admin_init', array(
43
  $this,
44
+ 'on_admin_init',
45
  ) );
46
  }
47
+ if ( is_admin() ) {
48
  $actionName = self::RESEND_MAIL_AJAX_SLUG;
49
  $fullname = 'wp_ajax_' . $actionName;
50
  // $this->logger->debug ( 'Registering ' . 'wp_ajax_' . $fullname . ' Ajax handler' );
51
+ add_action( $fullname, array(
52
  $this,
53
+ 'resendMail',
54
  ) );
55
  }
56
  }
57
+
58
  /**
59
  */
60
  function on_admin_init() {
61
+ $this->handleBulkAction();
62
  // register the stylesheet and javascript external resources
63
+ $pluginData = apply_filters( 'postman_get_plugin_metadata', null );
64
+ wp_register_script( 'postman_resend_email_script', plugins_url( 'script/postman_resend_email_sript.js', $this->rootPluginFilenameAndPath ), array(
65
  PostmanViewController::JQUERY_SCRIPT,
66
+ PostmanViewController::POSTMAN_SCRIPT,
67
  ), $pluginData ['version'] );
68
  }
69
+
70
  /**
71
  */
72
  public function resendMail() {
73
  // get the email address of the recipient from the HTTP Request
74
+ $postid = $this->getRequestParameter( 'email' );
75
+ if ( ! empty( $postid ) ) {
76
+ $post = get_post( $postid );
77
+ $meta_values = get_post_meta( $postid );
78
+
79
+ $success = wp_mail( $meta_values ['original_to'] [0], $meta_values ['original_subject'] [0], $meta_values ['original_message'] [0], $meta_values ['original_headers'] [0] );
80
+
81
  // Postman API: retrieve the result of sending this message from Postman
82
+ $result = apply_filters( 'postman_wp_mail_result', null );
83
  $transcript = $result ['transcript'];
84
+
85
  // post-handling
86
+ if ( $success ) {
87
+ $this->logger->debug( 'Email was successfully re-sent' );
88
  // the message was sent successfully, generate an appropriate message for the user
89
+ $statusMessage = sprintf( __( 'Your message was delivered (%d ms) to the SMTP server! Congratulations :)', Postman::TEXT_DOMAIN ), $result ['time'] );
90
+
91
  // compose the JSON response for the caller
92
+ $response = array(
93
  'message' => $statusMessage,
94
+ 'transcript' => $transcript,
95
  );
96
+ $this->logger->trace( 'AJAX response' );
97
+ $this->logger->trace( $response );
98
  // send the JSON response
99
+ wp_send_json_success( $response );
100
  } else {
101
+ $this->logger->error( 'Email was not successfully re-sent - ' . $result ['exception']->getCode() );
102
  // the message was NOT sent successfully, generate an appropriate message for the user
103
+ $statusMessage = $result ['exception']->getMessage();
104
+
105
  // compose the JSON response for the caller
106
+ $response = array(
107
  'message' => $statusMessage,
108
+ 'transcript' => $transcript,
109
  );
110
+ $this->logger->trace( 'AJAX response' );
111
+ $this->logger->trace( $response );
112
  // send the JSON response
113
+ wp_send_json_error( $response );
114
  }
115
  } else {
116
  // compose the JSON response for the caller
117
+ $response = array();
118
  // send the JSON response
119
+ wp_send_json_error( $response );
120
  }
121
  }
122
+
123
  /**
124
  * TODO move this somewhere reusable
125
  *
126
+ * @param unknown $parameterName
127
  * @return unknown
128
  */
129
+ private function getRequestParameter( $parameterName ) {
130
+ if ( isset( $_POST [ $parameterName ] ) ) {
131
+ $value = filter_var( $_POST [ $parameterName ], FILTER_SANITIZE_STRING );
132
+ $this->logger->trace( sprintf( 'Found parameter "%s"', $parameterName ) );
133
+ $this->logger->trace( $value );
134
  return $value;
135
  }
136
  }
137
+
138
  /**
139
  * From https://www.skyverge.com/blog/add-custom-bulk-action/
140
  */
141
  function handleBulkAction() {
142
  // only do this for administrators
143
+ if ( PostmanUtils::isAdmin() && isset( $_REQUEST ['email_log_entry'] ) ) {
144
+ $this->logger->trace( 'handling bulk action' );
145
+ if ( wp_verify_nonce( $_REQUEST ['_wpnonce'], 'bulk-email_log_entries' ) ) {
146
+ $this->logger->trace( sprintf( 'nonce "%s" passed validation', $_REQUEST ['_wpnonce'] ) );
147
+ if ( isset( $_REQUEST ['action'] ) && ($_REQUEST ['action'] == 'bulk_delete' || $_REQUEST ['action2'] == 'bulk_delete') ) {
148
+ $this->logger->trace( sprintf( 'handling bulk delete' ) );
149
+ $purger = new PostmanEmailLogPurger();
150
  $postids = $_REQUEST ['email_log_entry'];
151
  foreach ( $postids as $postid ) {
152
+ $purger->verifyLogItemExistsAndRemove( $postid );
153
  }
154
+ $mh = new PostmanMessageHandler();
155
+ $mh->addMessage( __( 'Mail Log Entries were deleted.', Postman::TEXT_DOMAIN ) );
156
  } else {
157
+ $this->logger->warn( sprintf( 'action "%s" not recognized', $_REQUEST ['action'] ) );
158
  }
159
  } else {
160
+ $this->logger->warn( sprintf( 'nonce "%s" failed validation', $_REQUEST ['_wpnonce'] ) );
161
  }
162
+ $this->redirectToLogPage();
163
  }
164
  }
165
+
166
  /**
167
  */
168
  function delete_log_item() {
169
  // only do this for administrators
170
+ if ( PostmanUtils::isAdmin() ) {
171
+ $this->logger->trace( 'handling delete item' );
172
  $postid = $_REQUEST ['email'];
173
+ if ( wp_verify_nonce( $_REQUEST ['_wpnonce'], 'delete_email_log_item_' . $postid ) ) {
174
+ $this->logger->trace( sprintf( 'nonce "%s" passed validation', $_REQUEST ['_wpnonce'] ) );
175
+ $purger = new PostmanEmailLogPurger();
176
+ $purger->verifyLogItemExistsAndRemove( $postid );
177
+ $mh = new PostmanMessageHandler();
178
+ $mh->addMessage( __( 'Mail Log Entry was deleted.', Postman::TEXT_DOMAIN ) );
179
  } else {
180
+ $this->logger->warn( sprintf( 'nonce "%s" failed validation', $_REQUEST ['_wpnonce'] ) );
181
  }
182
+ $this->redirectToLogPage();
183
  }
184
  }
185
+
186
  /**
187
  */
188
  function view_log_item() {
189
  // only do this for administrators
190
+ if ( PostmanUtils::isAdmin() ) {
191
+ $this->logger->trace( 'handling view item' );
192
  $postid = $_REQUEST ['email'];
193
+ $post = get_post( $postid );
194
+ $meta_values = get_post_meta( $postid );
195
  // https://css-tricks.com/examples/hrs/
196
  print '<html><head><style>body {font-family: monospace;} hr {
197
  border: 0;
199
  background: #bbb;
200
  }</style></head><body>';
201
  print '<table>';
202
+ if ( ! empty( $meta_values ['from_header'] [0] ) ) {
203
+ printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x( 'From', 'Who is this message From?', Postman::TEXT_DOMAIN ), esc_html( $meta_values ['from_header'] [0] ) );
204
  }
205
  // show the To header (it's optional)
206
+ if ( ! empty( $meta_values ['to_header'] [0] ) ) {
207
+ printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x( 'To', 'Who is this message To?', Postman::TEXT_DOMAIN ), esc_html( $meta_values ['to_header'] [0] ) );
208
  }
209
  // show the Cc header (it's optional)
210
+ if ( ! empty( $meta_values ['cc_header'] [0] ) ) {
211
+ printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x( 'Cc', 'Who is this message Cc\'d to?', Postman::TEXT_DOMAIN ), esc_html( $meta_values ['cc_header'] [0] ) );
212
  }
213
  // show the Bcc header (it's optional)
214
+ if ( ! empty( $meta_values ['bcc_header'] [0] ) ) {
215
+ printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x( 'Bcc', 'Who is this message Bcc\'d to?', Postman::TEXT_DOMAIN ), esc_html( $meta_values ['bcc_header'] [0] ) );
216
  }
217
  // show the Reply-To header (it's optional)
218
+ if ( ! empty( $meta_values ['reply_to_header'] [0] ) ) {
219
+ printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', __( 'Reply-To', Postman::TEXT_DOMAIN ), esc_html( $meta_values ['reply_to_header'] [0] ) );
220
  }
221
+ printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x( 'Date', 'What is the date today?', Postman::TEXT_DOMAIN ), $post->post_date );
222
+ printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x( 'Subject', 'What is the subject of this message?', Postman::TEXT_DOMAIN ), esc_html( $post->post_title ) );
223
  // The Transport UI is always there, in more recent versions that is
224
+ if ( ! empty( $meta_values ['transport_uri'] [0] ) ) {
225
+ printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x( 'Delivery-URI', 'What is the unique URI of the configuration?', Postman::TEXT_DOMAIN ), esc_html( $meta_values ['transport_uri'] [0] ) );
226
  }
227
  print '</table>';
228
  print '<hr/>';
229
  print '<pre>';
230
+ print $this->sanitize_message( $post->post_content );
231
  print '</pre>';
232
  print '</body></html>';
233
+ die();
234
  }
235
  }
236
+
237
+ function sanitize_message( $message ) {
238
+ $allowed_tags = wp_kses_allowed_html( 'post' );
239
+ $allowed_tags['style'] = array();
240
+
241
+ return wp_kses( $message, $allowed_tags );
242
+ }
243
+
244
  /**
245
  */
246
  function view_transcript_log_item() {
247
  // only do this for administrators
248
+ if ( PostmanUtils::isAdmin() ) {
249
+ $this->logger->trace( 'handling view transcript item' );
250
  $postid = $_REQUEST ['email'];
251
+ $post = get_post( $postid );
252
+ $meta_values = get_post_meta( $postid );
253
  // https://css-tricks.com/examples/hrs/
254
  print '<html><head><style>body {font-family: monospace;} hr {
255
  border: 0;
256
  border-bottom: 1px dashed #ccc;
257
  background: #bbb;
258
  }</style></head><body>';
259
+ printf( '<p>%s</p>', __( 'This is the conversation between Postman and the mail server. It can be useful for diagnosing problems. <b>DO NOT</b> post it on-line, it may contain your account password.', Postman::TEXT_DOMAIN ) );
260
  print '<hr/>';
261
  print '<pre>';
262
+ if ( ! empty( $meta_values ['session_transcript'] [0] ) ) {
263
+ print esc_html( $meta_values ['session_transcript'] [0] );
264
  } else {
265
  /* Translators: Meaning "Not Applicable" */
266
+ print __( 'n/a', Postman::TEXT_DOMAIN );
267
  }
268
  print '</pre>';
269
  print '</body></html>';
270
+ die();
271
  }
272
  }
273
+
274
  /**
275
  * For whatever reason, PostmanUtils::get..url doesn't work here? :(
276
  */
277
  function redirectToLogPage() {
278
+ PostmanUtils::redirect( PostmanUtils::POSTMAN_EMAIL_LOG_PAGE_RELATIVE_URL );
279
+ die();
280
  }
281
+
282
  /**
283
  * Register the page
284
  */
285
  function postmanAddMenuItem() {
286
  // only do this for administrators
287
+ if ( PostmanUtils::isAdmin() ) {
288
+ $this->logger->trace( 'created PostmanEmailLog admin menu item' );
289
+ /*
290
+ Translators where (%s) is the name of the plugin */
291
+ $pageTitle = sprintf( __( '%s Email Log', Postman::TEXT_DOMAIN ), __( 'Postman SMTP', Postman::TEXT_DOMAIN ) );
292
+ $pluginName = _x( 'Email Log', 'The log of Emails that have been delivered', Postman::TEXT_DOMAIN );
293
+
294
+ $page = add_submenu_page( PostmanViewController::POSTMAN_MENU_SLUG, $pageTitle, $pluginName, 'read_private_posts', 'postman_email_log', array( $this, 'postman_render_email_page' ) );
295
+
296
  // When the plugin options page is loaded, also load the stylesheet
297
+ add_action( 'admin_print_styles-' . $page, array(
298
  $this,
299
+ 'postman_email_log_enqueue_resources',
300
  ) );
301
  }
302
  }
303
  function postman_email_log_enqueue_resources() {
304
+ $pluginData = apply_filters( 'postman_get_plugin_metadata', null );
305
+ wp_register_style( 'postman_email_log', plugins_url( 'style/postman-email-log.css', $this->rootPluginFilenameAndPath ), null, $pluginData ['version'] );
306
+ wp_enqueue_style( 'postman_email_log' );
307
+ wp_enqueue_script( 'postman_resend_email_script' );
308
+ wp_enqueue_script( 'sprintf' );
309
+ wp_localize_script( 'postman_resend_email_script', 'postman_js_email_was_resent', __( 'Email was successfully resent (but without attachments)', Postman::TEXT_DOMAIN ) );
310
  /* Translators: Where %s is an error message */
311
+ wp_localize_script( 'postman_resend_email_script', 'postman_js_email_not_resent', __( 'Email could not be resent. Error: %s', Postman::TEXT_DOMAIN ) );
312
+ wp_localize_script( 'postman_resend_email_script', 'postman_js_resend_label', __( 'Resend', Postman::TEXT_DOMAIN ) );
313
  }
314
+
315
  /**
316
  * *************************** RENDER TEST PAGE ********************************
317
  * ******************************************************************************
323
  * it's the way the list tables are used in the WordPress core.
324
  */
325
  function postman_render_email_page() {
326
+
327
  // Create an instance of our package class...
328
+ $testListTable = new PostmanEmailLogView();
329
+ wp_enqueue_script( 'postman_resend_email_script' );
330
  // Fetch, prepare, sort, and filter our data...
331
+ $testListTable->prepare_items();
332
+
333
  ?>
334
  <div class="wrap">
335
 
336
  <div id="icon-users" class="icon32">
337
  <br />
338
  </div>
339
+ <h2><?php
340
+ /* Translators where (%s) is the name of the plugin */
341
+ echo sprintf( __( '%s Email Log', Postman::TEXT_DOMAIN ), __( 'Postman SMTP', Postman::TEXT_DOMAIN ) )?></h2>
342
 
343
  <div
344
  style="background: #ECECEC; border: 1px solid #CCC; padding: 0 10px; margin-top: 5px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px;">
345
  <p><?php
346
+
347
+ echo __( 'This is a record of deliveries made to the mail server. It does not neccessarily indicate sucessful delivery to the recipient.', Postman::TEXT_DOMAIN )?></p>
348
  </div>
349
 
350
+ <?php
351
+ $from_date = isset( $_POST['from_date'] ) ? sanitize_text_field( $_POST['from_date'] ) : '';
352
+ $to_date = isset( $_POST['to_date'] ) ? sanitize_text_field( $_POST['to_date'] ) : '';
353
+ $search = isset( $_POST['search'] ) ? sanitize_text_field( $_POST['search'] ) : '';
354
+ ?>
355
+
356
+ <form id="postman-email-log-filter" method="post">
357
+ <div id="email-log-filter">
358
+ <div class="form-control">
359
+ <label for="from_date"><?php _e( 'From Date', Postman::TEXT_DOMAIN ); ?></label>
360
+ <input id="from_date" class="email-log-date" value="<?php echo $from_date; ?>" type="text" name="from_date" placeholder="<?php _e( 'From Date', Postman::TEXT_DOMAIN ); ?>">
361
+ </div>
362
+ <div class="form-control">
363
+ <label for="to_date"><?php _e( 'To Date', Postman::TEXT_DOMAIN ); ?></label>
364
+ <input id="to_date" class="email-log-date" value="<?php echo $to_date; ?>" type="text" name="to_date" placeholder="<?php _e( 'To Date', Postman::TEXT_DOMAIN ); ?>">
365
+ </div>
366
+ <div class="form-control">
367
+ <label for="search"><?php _e( 'Search', Postman::TEXT_DOMAIN ); ?></label>
368
+ <input id="search" type="text" name="search" value="<?php echo $search; ?>" placeholder="<?php _e( 'Search', Postman::TEXT_DOMAIN ); ?>">
369
+ </div>
370
+ <div class="form-control">
371
+ <button type="submit" name="filter" class="button button-primary"><?php _e( 'Filter', Postman::TEXT_DOMAIN ); ?></button>
372
+ </div>
373
+
374
+ <div class="form-control">
375
+ <!-- <button type="submit" name="export_email_logs" class="button button-primary">Export To CSV</button> -->
376
+ </div>
377
+ </div>
378
+ </form>
379
+
380
  <!-- Forms are NOT created automatically, so you need to wrap the table in one to use features like bulk actions -->
381
  <form id="movies-filter" method="get">
382
  <!-- For plugins, we also need to ensure that the form posts back to our current page -->
383
  <input type="hidden" name="page"
384
  value="<?php echo filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING ); ?>" />
385
+
386
  <!-- Now we can render the completed list table -->
387
+ <?php $testListTable->display()?>
388
+ </form>
389
+
390
+ <?php add_thickbox(); ?>
391
 
392
  </div>
393
  <?php
Postman/Postman-Email-Log/PostmanEmailLogService.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- if (! class_exists ( 'PostmanEmailLog' )) {
3
  class PostmanEmailLog {
4
  public $sender;
5
  public $toRecipients;
@@ -19,15 +19,15 @@ if (! class_exists ( 'PostmanEmailLog' )) {
19
  }
20
  }
21
 
22
- if (! class_exists ( 'PostmanEmailLogService' )) {
23
-
24
  /**
25
  * This class creates the Custom Post Type for Email Logs and handles writing these posts.
26
  *
27
  * @author jasonhendriks
28
  */
29
  class PostmanEmailLogService {
30
-
31
  /*
32
  * Private content is published only for your eyes, or the eyes of only those with authorization
33
  * permission levels to see private content. Normal users and visitors will not be aware of
@@ -36,170 +36,182 @@ if (! class_exists ( 'PostmanEmailLogService' )) {
36
  * the private content when you are logged into your WordPress blog.
37
  */
38
  const POSTMAN_CUSTOM_POST_STATUS_PRIVATE = 'private';
39
-
40
  // member variables
41
  private $logger;
42
  private $inst;
43
-
44
  /**
45
  * Constructor
46
  */
47
  private function __construct() {
48
- $this->logger = new PostmanLogger ( get_class ( $this ) );
49
  }
50
-
51
  /**
52
  * singleton instance
53
  */
54
  public static function getInstance() {
55
  static $inst = null;
56
- if ($inst === null) {
57
- $inst = new PostmanEmailLogService ();
58
  }
59
  return $inst;
60
  }
61
-
62
  /**
63
  * Logs successful email attempts
64
  *
65
- * @param PostmanMessage $message
66
- * @param unknown $transcript
67
- * @param PostmanModuleTransport $transport
68
  */
69
- public function writeSuccessLog(PostmanEmailLog $log, PostmanMessage $message, $transcript, PostmanModuleTransport $transport) {
70
- if (PostmanOptions::getInstance ()->isMailLoggingEnabled ()) {
71
  $statusMessage = '';
72
  $status = true;
73
- $subject = $message->getSubject ();
74
- if (empty ( $subject )) {
75
- $statusMessage = sprintf ( '%s: %s', __ ( 'Warning', Postman::TEXT_DOMAIN ), __ ( 'An empty subject line can result in delivery failure.', Postman::TEXT_DOMAIN ) );
76
  $status = 'WARN';
77
  }
78
- $this->createLog ( $log, $message, $transcript, $statusMessage, $status, $transport );
79
- $this->writeToEmailLog ( $log );
80
  }
81
  }
82
-
83
  /**
84
  * Logs failed email attempts, requires more metadata so the email can be resent in the future
85
  *
86
- * @param PostmanMessage $message
87
- * @param unknown $transcript
88
- * @param PostmanModuleTransport $transport
89
- * @param unknown $statusMessage
90
- * @param unknown $originalTo
91
- * @param unknown $originalSubject
92
- * @param unknown $originalMessage
93
- * @param unknown $originalHeaders
94
  */
95
- public function writeFailureLog(PostmanEmailLog $log, PostmanMessage $message = null, $transcript, PostmanModuleTransport $transport, $statusMessage) {
96
- if (PostmanOptions::getInstance ()->isMailLoggingEnabled ()) {
97
- $this->createLog ( $log, $message, $transcript, $statusMessage, false, $transport );
98
- $this->writeToEmailLog ( $log );
99
  }
100
  }
101
-
102
  /**
103
  * Writes an email sending attempt to the Email Log
104
  *
105
  * From http://wordpress.stackexchange.com/questions/8569/wp-insert-post-php-function-and-custom-fields
106
  */
107
- private function writeToEmailLog(PostmanEmailLog $log) {
 
 
108
  // nothing here is sanitized as WordPress should take care of
109
  // making database writes safe
110
- $my_post = array (
111
  'post_type' => PostmanEmailLogPostType::POSTMAN_CUSTOM_POST_TYPE_SLUG,
112
  'post_title' => $log->subject,
113
  'post_content' => $log->body,
114
  'post_excerpt' => $log->statusMessage,
115
- 'post_status' => PostmanEmailLogService::POSTMAN_CUSTOM_POST_STATUS_PRIVATE
116
  );
117
-
118
  // Insert the post into the database (WordPress gives us the Post ID)
119
- $post_id = wp_insert_post ( $my_post );
120
- $this->logger->debug ( sprintf ( 'Saved message #%s to the database', $post_id ) );
121
- $this->logger->trace ( $log );
122
-
123
  // Write the meta data related to the email
124
- update_post_meta ( $post_id, 'success', $log->success );
125
- update_post_meta ( $post_id, 'from_header', $log->sender );
126
- if (! empty ( $log->toRecipients )) {
127
- update_post_meta ( $post_id, 'to_header', $log->toRecipients );
128
  }
129
- if (! empty ( $log->ccRecipients )) {
130
- update_post_meta ( $post_id, 'cc_header', $log->ccRecipients );
131
  }
132
- if (! empty ( $log->bccRecipients )) {
133
- update_post_meta ( $post_id, 'bcc_header', $log->bccRecipients );
134
  }
135
- if (! empty ( $log->replyTo )) {
136
- update_post_meta ( $post_id, 'reply_to_header', $log->replyTo );
137
  }
138
- update_post_meta ( $post_id, 'transport_uri', $log->transportUri );
139
-
140
- if (! $log->success || true) {
141
  // alwas add the meta data so we can re-send it
142
- update_post_meta ( $post_id, 'original_to', $log->originalTo );
143
- update_post_meta ( $post_id, 'original_subject', $log->originalSubject );
144
- update_post_meta ( $post_id, 'original_message', $log->originalMessage );
145
- update_post_meta ( $post_id, 'original_headers', $log->originalHeaders );
146
  }
147
-
148
  // we do not sanitize the session transcript - let the reader decide how to handle the data
149
- update_post_meta ( $post_id, 'session_transcript', $log->sessionTranscript );
150
-
151
  // truncate the log (remove older entries)
152
- $purger = new PostmanEmailLogPurger ();
153
- $purger->truncateLogItems ( PostmanOptions::getInstance ()->getMailLoggingMaxEntries () );
 
 
 
 
 
 
 
 
 
 
154
  }
155
-
156
  /**
157
  * Creates a Log object for use by writeToEmailLog()
158
  *
159
- * @param PostmanMessage $message
160
- * @param unknown $transcript
161
- * @param unknown $statusMessage
162
- * @param unknown $success
163
- * @param PostmanModuleTransport $transport
164
  * @return PostmanEmailLog
165
  */
166
- private function createLog(PostmanEmailLog $log, PostmanMessage $message = null, $transcript, $statusMessage, $success, PostmanModuleTransport $transport) {
167
- if ($message) {
168
- $log->sender = $message->getFromAddress ()->format ();
169
- $log->toRecipients = $this->flattenEmails ( $message->getToRecipients () );
170
- $log->ccRecipients = $this->flattenEmails ( $message->getCcRecipients () );
171
- $log->bccRecipients = $this->flattenEmails ( $message->getBccRecipients () );
172
- $log->subject = $message->getSubject ();
173
- $log->body = $message->getBody ();
174
- if (null !== $message->getReplyTo ()) {
175
- $log->replyTo = $message->getReplyTo ()->format ();
176
  }
177
  }
178
  $log->success = $success;
179
  $log->statusMessage = $statusMessage;
180
- $log->transportUri = PostmanTransportRegistry::getInstance ()->getPublicTransportUri ( $transport );
181
  $log->sessionTranscript = $log->transportUri . "\n\n" . $transcript;
182
  return $log;
183
  }
184
-
185
  /**
186
  * Creates a readable "TO" entry based on the recipient header
187
  *
188
- * @param array $addresses
189
  * @return string
190
  */
191
- private static function flattenEmails(array $addresses) {
192
  $flat = '';
193
  $count = 0;
194
  foreach ( $addresses as $address ) {
195
- if ($count >= 3) {
196
- $flat .= sprintf ( __ ( '.. +%d more', Postman::TEXT_DOMAIN ), sizeof ( $addresses ) - $count );
197
  break;
198
  }
199
- if ($count > 0) {
200
  $flat .= ', ';
201
  }
202
- $flat .= $address->format ();
203
  $count ++;
204
  }
205
  return $flat;
@@ -207,18 +219,18 @@ if (! class_exists ( 'PostmanEmailLogService' )) {
207
  }
208
  }
209
 
210
- if (! class_exists ( 'PostmanEmailLogPurger' )) {
211
  class PostmanEmailLogPurger {
212
  private $posts;
213
  private $logger;
214
-
215
  /**
216
  *
217
  * @return unknown
218
  */
219
  function __construct() {
220
- $this->logger = new PostmanLogger ( get_class ( $this ) );
221
- $args = array (
222
  'posts_per_page' => 1000,
223
  'offset' => 0,
224
  'category' => '',
@@ -233,46 +245,46 @@ if (! class_exists ( 'PostmanEmailLogPurger' )) {
233
  'post_mime_type' => '',
234
  'post_parent' => '',
235
  'post_status' => 'private',
236
- 'suppress_filters' => true
237
  );
238
- $this->posts = get_posts ( $args );
239
  }
240
-
241
  /**
242
  *
243
- * @param array $posts
244
- * @param unknown $postid
245
  */
246
- function verifyLogItemExistsAndRemove($postid) {
247
  $force_delete = true;
248
  foreach ( $this->posts as $post ) {
249
- if ($post->ID == $postid) {
250
- $this->logger->debug ( 'deleting log item ' . intval($postid) );
251
- wp_delete_post ( $postid, $force_delete );
252
  return;
253
  }
254
  }
255
- $this->logger->warn ( 'could not find Postman Log Item #' . $postid );
256
  }
257
  function removeAll() {
258
- $this->logger->debug ( sprintf ( 'deleting %d log items ', sizeof ( $this->posts ) ) );
259
  $force_delete = true;
260
  foreach ( $this->posts as $post ) {
261
- wp_delete_post ( $post->ID, $force_delete );
262
  }
263
  }
264
-
265
  /**
266
  *
267
- * @param unknown $size
268
  */
269
- function truncateLogItems($size) {
270
- $index = count ( $this->posts );
271
  $force_delete = true;
272
  while ( $index > $size ) {
273
- $postid = $this->posts [-- $index]->ID;
274
- $this->logger->debug ( 'deleting log item ' . $postid );
275
- wp_delete_post ( $postid, $force_delete );
276
  }
277
  }
278
  }
1
  <?php
2
+ if ( ! class_exists( 'PostmanEmailLog' ) ) {
3
  class PostmanEmailLog {
4
  public $sender;
5
  public $toRecipients;
19
  }
20
  }
21
 
22
+ if ( ! class_exists( 'PostmanEmailLogService' ) ) {
23
+
24
  /**
25
  * This class creates the Custom Post Type for Email Logs and handles writing these posts.
26
  *
27
  * @author jasonhendriks
28
  */
29
  class PostmanEmailLogService {
30
+
31
  /*
32
  * Private content is published only for your eyes, or the eyes of only those with authorization
33
  * permission levels to see private content. Normal users and visitors will not be aware of
36
  * the private content when you are logged into your WordPress blog.
37
  */
38
  const POSTMAN_CUSTOM_POST_STATUS_PRIVATE = 'private';
39
+
40
  // member variables
41
  private $logger;
42
  private $inst;
43
+
44
  /**
45
  * Constructor
46
  */
47
  private function __construct() {
48
+ $this->logger = new PostmanLogger( get_class( $this ) );
49
  }
50
+
51
  /**
52
  * singleton instance
53
  */
54
  public static function getInstance() {
55
  static $inst = null;
56
+ if ( $inst === null ) {
57
+ $inst = new PostmanEmailLogService();
58
  }
59
  return $inst;
60
  }
61
+
62
  /**
63
  * Logs successful email attempts
64
  *
65
+ * @param PostmanMessage $message
66
+ * @param unknown $transcript
67
+ * @param PostmanModuleTransport $transport
68
  */
69
+ public function writeSuccessLog( PostmanEmailLog $log, PostmanMessage $message, $transcript, PostmanModuleTransport $transport ) {
70
+ if ( PostmanOptions::getInstance()->isMailLoggingEnabled() ) {
71
  $statusMessage = '';
72
  $status = true;
73
+ $subject = $message->getSubject();
74
+ if ( empty( $subject ) ) {
75
+ $statusMessage = sprintf( '%s: %s', __( 'Warning', Postman::TEXT_DOMAIN ), __( 'An empty subject line can result in delivery failure.', Postman::TEXT_DOMAIN ) );
76
  $status = 'WARN';
77
  }
78
+ $this->createLog( $log, $message, $transcript, $statusMessage, $status, $transport );
79
+ $this->writeToEmailLog( $log );
80
  }
81
  }
82
+
83
  /**
84
  * Logs failed email attempts, requires more metadata so the email can be resent in the future
85
  *
86
+ * @param PostmanMessage $message
87
+ * @param unknown $transcript
88
+ * @param PostmanModuleTransport $transport
89
+ * @param unknown $statusMessage
90
+ * @param unknown $originalTo
91
+ * @param unknown $originalSubject
92
+ * @param unknown $originalMessage
93
+ * @param unknown $originalHeaders
94
  */
95
+ public function writeFailureLog( PostmanEmailLog $log, PostmanMessage $message = null, $transcript, PostmanModuleTransport $transport, $statusMessage ) {
96
+ if ( PostmanOptions::getInstance()->isMailLoggingEnabled() ) {
97
+ $this->createLog( $log, $message, $transcript, $statusMessage, false, $transport );
98
+ $this->writeToEmailLog( $log );
99
  }
100
  }
101
+
102
  /**
103
  * Writes an email sending attempt to the Email Log
104
  *
105
  * From http://wordpress.stackexchange.com/questions/8569/wp-insert-post-php-function-and-custom-fields
106
  */
107
+ private function writeToEmailLog( PostmanEmailLog $log ) {
108
+
109
+ $this->checkForLogErrors( $log );
110
  // nothing here is sanitized as WordPress should take care of
111
  // making database writes safe
112
+ $my_post = array(
113
  'post_type' => PostmanEmailLogPostType::POSTMAN_CUSTOM_POST_TYPE_SLUG,
114
  'post_title' => $log->subject,
115
  'post_content' => $log->body,
116
  'post_excerpt' => $log->statusMessage,
117
+ 'post_status' => PostmanEmailLogService::POSTMAN_CUSTOM_POST_STATUS_PRIVATE,
118
  );
119
+
120
  // Insert the post into the database (WordPress gives us the Post ID)
121
+ $post_id = wp_insert_post( $my_post );
122
+ $this->logger->debug( sprintf( 'Saved message #%s to the database', $post_id ) );
123
+ $this->logger->trace( $log );
124
+
125
  // Write the meta data related to the email
126
+ update_post_meta( $post_id, 'success', $log->success );
127
+ update_post_meta( $post_id, 'from_header', $log->sender );
128
+ if ( ! empty( $log->toRecipients ) ) {
129
+ update_post_meta( $post_id, 'to_header', $log->toRecipients );
130
  }
131
+ if ( ! empty( $log->ccRecipients ) ) {
132
+ update_post_meta( $post_id, 'cc_header', $log->ccRecipients );
133
  }
134
+ if ( ! empty( $log->bccRecipients ) ) {
135
+ update_post_meta( $post_id, 'bcc_header', $log->bccRecipients );
136
  }
137
+ if ( ! empty( $log->replyTo ) ) {
138
+ update_post_meta( $post_id, 'reply_to_header', $log->replyTo );
139
  }
140
+ update_post_meta( $post_id, 'transport_uri', $log->transportUri );
141
+
142
+ if ( ! $log->success || true ) {
143
  // alwas add the meta data so we can re-send it
144
+ update_post_meta( $post_id, 'original_to', $log->originalTo );
145
+ update_post_meta( $post_id, 'original_subject', $log->originalSubject );
146
+ update_post_meta( $post_id, 'original_message', $log->originalMessage );
147
+ update_post_meta( $post_id, 'original_headers', $log->originalHeaders );
148
  }
149
+
150
  // we do not sanitize the session transcript - let the reader decide how to handle the data
151
+ update_post_meta( $post_id, 'session_transcript', $log->sessionTranscript );
152
+
153
  // truncate the log (remove older entries)
154
+ $purger = new PostmanEmailLogPurger();
155
+ $purger->truncateLogItems( PostmanOptions::getInstance()->getMailLoggingMaxEntries() );
156
+ }
157
+
158
+ private function checkForLogErrors( PostmanEmailLog $log ) {
159
+ if ( $log->statusMessage && ! empty( $log->statusMessage ) ) {
160
+ mail( get_bloginfo( 'admin_email' ), __( 'Post SMTP email error', Postman::TEXT_DOMAIN ), $log->statusMessage );
161
+ }
162
+
163
+ if ( strpos( strtolower( $log->sessionTranscript ), 'error' ) !== false ) {
164
+ mail( get_bloginfo( 'admin_email' ), __( 'Post SMTP session transcript error', Postman::TEXT_DOMAIN ), $log->sessionTranscript );
165
+ }
166
  }
167
+
168
  /**
169
  * Creates a Log object for use by writeToEmailLog()
170
  *
171
+ * @param PostmanMessage $message
172
+ * @param unknown $transcript
173
+ * @param unknown $statusMessage
174
+ * @param unknown $success
175
+ * @param PostmanModuleTransport $transport
176
  * @return PostmanEmailLog
177
  */
178
+ private function createLog( PostmanEmailLog $log, PostmanMessage $message = null, $transcript, $statusMessage, $success, PostmanModuleTransport $transport ) {
179
+ if ( $message ) {
180
+ $log->sender = $message->getFromAddress()->format();
181
+ $log->toRecipients = $this->flattenEmails( $message->getToRecipients() );
182
+ $log->ccRecipients = $this->flattenEmails( $message->getCcRecipients() );
183
+ $log->bccRecipients = $this->flattenEmails( $message->getBccRecipients() );
184
+ $log->subject = $message->getSubject();
185
+ $log->body = $message->getBody();
186
+ if ( null !== $message->getReplyTo() ) {
187
+ $log->replyTo = $message->getReplyTo()->format();
188
  }
189
  }
190
  $log->success = $success;
191
  $log->statusMessage = $statusMessage;
192
+ $log->transportUri = PostmanTransportRegistry::getInstance()->getPublicTransportUri( $transport );
193
  $log->sessionTranscript = $log->transportUri . "\n\n" . $transcript;
194
  return $log;
195
  }
196
+
197
  /**
198
  * Creates a readable "TO" entry based on the recipient header
199
  *
200
+ * @param array $addresses
201
  * @return string
202
  */
203
+ private static function flattenEmails( array $addresses ) {
204
  $flat = '';
205
  $count = 0;
206
  foreach ( $addresses as $address ) {
207
+ if ( $count >= 3 ) {
208
+ $flat .= sprintf( __( '.. +%d more', Postman::TEXT_DOMAIN ), sizeof( $addresses ) - $count );
209
  break;
210
  }
211
+ if ( $count > 0 ) {
212
  $flat .= ', ';
213
  }
214
+ $flat .= $address->format();
215
  $count ++;
216
  }
217
  return $flat;
219
  }
220
  }
221
 
222
+ if ( ! class_exists( 'PostmanEmailLogPurger' ) ) {
223
  class PostmanEmailLogPurger {
224
  private $posts;
225
  private $logger;
226
+
227
  /**
228
  *
229
  * @return unknown
230
  */
231
  function __construct() {
232
+ $this->logger = new PostmanLogger( get_class( $this ) );
233
+ $args = array(
234
  'posts_per_page' => 1000,
235
  'offset' => 0,
236
  'category' => '',
245
  'post_mime_type' => '',
246
  'post_parent' => '',
247
  'post_status' => 'private',
248
+ 'suppress_filters' => true,
249
  );
250
+ $this->posts = get_posts( $args );
251
  }
252
+
253
  /**
254
  *
255
+ * @param array $posts
256
+ * @param unknown $postid
257
  */
258
+ function verifyLogItemExistsAndRemove( $postid ) {
259
  $force_delete = true;
260
  foreach ( $this->posts as $post ) {
261
+ if ( $post->ID == $postid ) {
262
+ $this->logger->debug( 'deleting log item ' . intval( $postid ) );
263
+ wp_delete_post( $postid, $force_delete );
264
  return;
265
  }
266
  }
267
+ $this->logger->warn( 'could not find Postman Log Item #' . $postid );
268
  }
269
  function removeAll() {
270
+ $this->logger->debug( sprintf( 'deleting %d log items ', sizeof( $this->posts ) ) );
271
  $force_delete = true;
272
  foreach ( $this->posts as $post ) {
273
+ wp_delete_post( $post->ID, $force_delete );
274
  }
275
  }
276
+
277
  /**
278
  *
279
+ * @param unknown $size
280
  */
281
+ function truncateLogItems( $size ) {
282
+ $index = count( $this->posts );
283
  $force_delete = true;
284
  while ( $index > $size ) {
285
+ $postid = $this->posts [ -- $index ]->ID;
286
+ $this->logger->debug( 'deleting log item ' . $postid );
287
+ wp_delete_post( $postid, $force_delete );
288
  }
289
  }
290
  }
Postman/Postman-Email-Log/PostmanEmailLogView.php CHANGED
@@ -2,14 +2,13 @@
2
 
3
  /**
4
  * See http://wpengineer.com/2426/wp_list_table-a-step-by-step-guide/
5
- *
6
  */
7
- if (! class_exists ( 'WP_List_Table' )) {
8
- require_once (ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
9
  }
10
  class PostmanEmailLogView extends WP_List_Table {
11
  private $logger;
12
-
13
  /**
14
  * ************************************************************************
15
  * REQUIRED.
@@ -18,16 +17,16 @@ class PostmanEmailLogView extends WP_List_Table {
18
  * *************************************************************************
19
  */
20
  function __construct() {
21
- $this->logger = new PostmanLogger ( get_class ( $this ) );
22
-
23
  // Set parent defaults
24
- parent::__construct ( array (
25
  'singular' => 'email_log_entry', // singular name of the listed records
26
  'plural' => 'email_log_entries', // plural name of the listed records
27
- 'ajax' => false
28
  ) ); // does this table support ajax?
29
  }
30
-
31
  /**
32
  * ************************************************************************
33
  * Recommended.
@@ -54,16 +53,16 @@ class PostmanEmailLogView extends WP_List_Table {
54
  * @return string Text or HTML to be placed inside the column <td>
55
  * ************************************************************************
56
  */
57
- function column_default($item, $column_name) {
58
- switch ($column_name) {
59
  case 'date' :
60
  case 'status' :
61
- return $item [$column_name];
62
  default :
63
- return print_r ( $item, true ); // Show the whole array for troubleshooting purposes
64
  }
65
  }
66
-
67
  /**
68
  * ************************************************************************
69
  * Recommended.
@@ -77,48 +76,47 @@ class PostmanEmailLogView extends WP_List_Table {
77
  * should be an associative array formatted as 'slug'=>'link html' - and you
78
  * will need to generate the URLs yourself. You could even ensure the links
79
  *
80
- *
81
  * @see WP_List_Table::::single_row_columns()
82
  * @param array $item
83
  * A singular item (one full row's worth of data)
84
  * @return string Text to be placed inside the column <td> (movie title only)
85
  * ************************************************************************
86
  */
87
- function column_title($item) {
88
-
89
  // Build row actions
90
  $iframeUri = 'admin-post.php?page=postman_email_log&action=%s&email=%s&TB_iframe=true&width=700&height=550';
91
- $deleteUrl = wp_nonce_url ( admin_url ( sprintf ( 'admin-post.php?page=postman_email_log&action=%s&email=%s', 'delete', $item ['ID'] ) ), 'delete_email_log_item_' . $item ['ID'] );
92
- $viewUrl = admin_url ( sprintf ( $iframeUri, 'view', $item ['ID'] ) );
93
- $transcriptUrl = admin_url ( sprintf ( $iframeUri, 'transcript', $item ['ID'] ) );
94
- $resendUrl = admin_url ( sprintf ( $iframeUri, 'resend', $item ['ID'] ) );
95
-
96
- $meta_values = get_post_meta ( $item ['ID'] );
97
-
98
- $actions = array (
99
- 'delete' => sprintf ( '<a href="%s">%s</a>', $deleteUrl, _x ( 'Delete', 'Delete an item from the email log', Postman::TEXT_DOMAIN ) ),
100
- 'view' => sprintf ( '<a href="%s" class="thickbox">%s</a>', $viewUrl, _x ( 'View', 'View an item from the email log', Postman::TEXT_DOMAIN ) )
101
  );
102
-
103
- if (! empty ( $meta_values ['session_transcript'] [0] )) {
104
- $actions ['transcript'] = sprintf ( '<a href="%1$s" class="thickbox">%2$s</a>', $transcriptUrl, __ ( 'Session Transcript', Postman::TEXT_DOMAIN ) );
105
  } else {
106
- $actions ['transcript'] = sprintf ( '%2$s', $transcriptUrl, __ ( 'Session Transcript', Postman::TEXT_DOMAIN ) );
107
  }
108
- if (! (empty ( $meta_values ['original_to'] [0] ) && empty ( $meta_values ['originalHeaders'] [0] ))) {
109
  // $actions ['resend'] = sprintf ( '<a href="%s">%s</a>', $resendUrl, __ ( 'Resend', Postman::TEXT_DOMAIN ) );
110
- $actions ['resend'] = sprintf ( '<span id="%3$s"><a href="javascript:postman_resend_email(%1$s);">%2$s</a></span>', $item ['ID'], __ ( 'Resend', Postman::TEXT_DOMAIN ), 'resend-' . $item ['ID'] );
111
  } else {
112
- $actions ['resend'] = sprintf ( '%2$s', $resendUrl, __ ( 'Resend', Postman::TEXT_DOMAIN ) );
113
  }
114
-
115
  // Return the title contents
116
- return sprintf ( '%1$s %3$s',
117
- /*$1%s*/ $item ['title'],
118
- /*$2%s*/ $item ['ID'],
119
- /*$3%s*/ $this->row_actions ( $actions ) );
120
  }
121
-
122
  /**
123
  * ************************************************************************
124
  * REQUIRED if displaying checkboxes or using bulk actions! The 'cb' column
@@ -132,13 +130,13 @@ class PostmanEmailLogView extends WP_List_Table {
132
  * @return string Text to be placed inside the column <td> (movie title only)
133
  * ************************************************************************
134
  */
135
- function column_cb($item) {
136
- return sprintf ( '<input type="checkbox" name="%1$s[]" value="%2$s" />',
137
- /*$1%s*/ $this->_args ['singular'], // Let's simply repurpose the table's singular label ("movie")
138
- /* $2%s */
139
  $item ['ID'] ); // The value of the checkbox should be the record's id
140
  }
141
-
142
  /**
143
  * ************************************************************************
144
  * REQUIRED! This method dictates the table's columns and titles.
@@ -156,15 +154,15 @@ class PostmanEmailLogView extends WP_List_Table {
156
  * ************************************************************************
157
  */
158
  function get_columns() {
159
- $columns = array (
160
  'cb' => '<input type="checkbox" />', // Render a checkbox instead of text
161
- 'title' => _x ( 'Subject', 'What is the subject of this message?', Postman::TEXT_DOMAIN ),
162
- 'status' => __ ( 'Status', Postman::TEXT_DOMAIN ),
163
- 'date' => _x ( 'Delivery Time', 'When was this email sent?', Postman::TEXT_DOMAIN )
164
  );
165
  return $columns;
166
  }
167
-
168
  /**
169
  * ************************************************************************
170
  * Optional.
@@ -183,24 +181,24 @@ class PostmanEmailLogView extends WP_List_Table {
183
  * ************************************************************************
184
  */
185
  function get_sortable_columns() {
186
- return array ();
187
- $sortable_columns = array (
188
- 'title' => array (
189
  'title',
190
- false
191
  ), // true means it's already sorted
192
- 'status' => array (
193
  'status',
194
- false
195
  ),
196
- 'date' => array (
197
  'date',
198
- false
199
- )
200
  );
201
  return $sortable_columns;
202
  }
203
-
204
  /**
205
  * ************************************************************************
206
  * Optional.
@@ -219,12 +217,12 @@ class PostmanEmailLogView extends WP_List_Table {
219
  * ************************************************************************
220
  */
221
  function get_bulk_actions() {
222
- $actions = array (
223
- 'bulk_delete' => _x ( 'Delete', 'Delete an item from the email log', Postman::TEXT_DOMAIN )
224
  );
225
  return $actions;
226
  }
227
-
228
  /**
229
  * ************************************************************************
230
  * Optional.
@@ -236,7 +234,7 @@ class PostmanEmailLogView extends WP_List_Table {
236
  */
237
  function process_bulk_action() {
238
  }
239
-
240
  /**
241
  * ************************************************************************
242
  * REQUIRED! This is where you prepare your data for display.
@@ -256,12 +254,12 @@ class PostmanEmailLogView extends WP_List_Table {
256
  * ************************************************************************
257
  */
258
  function prepare_items() {
259
-
260
  /**
261
  * First, lets decide how many records per page to show
262
  */
263
  $per_page = 10;
264
-
265
  /**
266
  * REQUIRED.
267
  * Now we need to define our column headers. This includes a complete
@@ -270,10 +268,10 @@ class PostmanEmailLogView extends WP_List_Table {
270
  * can be defined in another method (as we've done here) before being
271
  * used to build the value for our _column_headers property.
272
  */
273
- $columns = $this->get_columns ();
274
- $hidden = array ();
275
- $sortable = $this->get_sortable_columns ();
276
-
277
  /**
278
  * REQUIRED.
279
  * Finally, we build an array to be used by the class for column
@@ -281,19 +279,19 @@ class PostmanEmailLogView extends WP_List_Table {
281
  * 3 other arrays. One for all columns, one for hidden columns, and one
282
  * for sortable columns.
283
  */
284
- $this->_column_headers = array (
285
  $columns,
286
  $hidden,
287
- $sortable
288
  );
289
-
290
  /**
291
  * Optional.
292
  * You can handle your bulk actions however you see fit. In this
293
  * case, we'll handle them within our package just to keep things clean.
294
  */
295
- $this->process_bulk_action ();
296
-
297
  /**
298
  * Instead of querying a database, we're going to fetch the example data
299
  * property we created for use in this plugin.
@@ -304,44 +302,61 @@ class PostmanEmailLogView extends WP_List_Table {
304
  * use sort and pagination data to build a custom query instead, as you'll
305
  * be able to use your precisely-queried data immediately.
306
  */
307
- $data = array ();
308
- $args = array (
309
  'posts_per_page' => 1000,
310
  'offset' => 0,
311
- 'category' => '',
312
- 'category_name' => '',
313
  'orderby' => 'date',
314
  'order' => 'DESC',
315
- 'include' => '',
316
- 'exclude' => '',
317
- 'meta_key' => '',
318
- 'meta_value' => '',
319
  'post_type' => PostmanEmailLogPostType::POSTMAN_CUSTOM_POST_TYPE_SLUG,
320
- 'post_mime_type' => '',
321
- 'post_parent' => '',
322
  'post_status' => 'private',
323
- 'suppress_filters' => true
324
  );
325
- $posts = get_posts ( $args );
326
- foreach ( $posts as $post ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
327
  $date = $post->post_date;
328
- $humanTime = human_time_diff ( strtotime ( $post->post_date_gmt ) );
329
  // if this PHP system support humanTime, than use it
330
- if (! empty ( $humanTime )) {
331
  /* Translators: where %s indicates the relative time from now */
332
- $date = sprintf ( _x ( '%s ago', 'A relative time as in "five days ago"', Postman::TEXT_DOMAIN ), $humanTime );
333
  }
334
- $flattenedPost = array (
 
335
  // the post title must be escaped as they are displayed in the HTML output
336
- 'title' => esc_html ( $post->post_title ),
337
  // the post status must be escaped as they are displayed in the HTML output
338
- 'status' => ($post->post_excerpt != null ? esc_html ( $post->post_excerpt ) : __ ( 'Sent', Postman::TEXT_DOMAIN )),
339
  'date' => $date,
340
- 'ID' => $post->ID
341
  );
342
- array_push ( $data, $flattenedPost );
343
  }
344
-
345
  /**
346
  * This checks for sorting input and sorts the data in our array accordingly.
347
  *
@@ -350,14 +365,13 @@ class PostmanEmailLogView extends WP_List_Table {
350
  * to a custom query. The returned data will be pre-sorted, and this array
351
  * sorting technique would be unnecessary.
352
  */
353
- function usort_reorder($a, $b) {
354
- $orderby = (! empty ( $_REQUEST ['orderby'] )) ? $_REQUEST ['orderby'] : 'title'; // If no sort, default to title
355
- $order = (! empty ( $_REQUEST ['order'] )) ? $_REQUEST ['order'] : 'asc'; // If no order, default to asc
356
- $result = strcmp ( $a [$orderby], $b [$orderby] ); // Determine sort order
357
  return ($order === 'asc') ? $result : - $result; // Send final sort direction to usort
358
  }
359
  // usort($data, 'usort_reorder');
360
-
361
  /**
362
  * *********************************************************************
363
  * ---------------------------------------------------------------------
@@ -372,15 +386,15 @@ class PostmanEmailLogView extends WP_List_Table {
372
  * ---------------------------------------------------------------------
373
  * ********************************************************************
374
  */
375
-
376
  /**
377
  * REQUIRED for pagination.
378
  * Let's figure out what page the user is currently
379
  * looking at. We'll need this later, so you should always include it in
380
  * your own package classes.
381
  */
382
- $current_page = $this->get_pagenum ();
383
-
384
  /**
385
  * REQUIRED for pagination.
386
  * Let's check how many items are in our data array.
@@ -388,31 +402,31 @@ class PostmanEmailLogView extends WP_List_Table {
388
  * without filtering. We'll need this later, so you should always include it
389
  * in your own package classes.
390
  */
391
- $total_items = count ( $data );
392
-
393
  /**
394
  * The WP_List_Table class does not handle pagination for us, so we need
395
  * to ensure that the data is trimmed to only the current page.
396
  * We can use
397
  * array_slice() to
398
  */
399
- $data = array_slice ( $data, (($current_page - 1) * $per_page), $per_page );
400
-
401
  /**
402
  * REQUIRED.
403
  * Now we can add our *sorted* data to the items property, where
404
  * it can be used by the rest of the class.
405
  */
406
  $this->items = $data;
407
-
408
  /**
409
  * REQUIRED.
410
  * We also have to register our pagination options & calculations.
411
  */
412
- $this->set_pagination_args ( array (
413
  'total_items' => $total_items, // WE have to calculate the total number of items
414
  'per_page' => $per_page, // WE have to determine how many items to show on a page
415
- 'total_pages' => ceil ( $total_items / $per_page )
416
  ) ); // WE have to calculate the total number of pages
417
  }
418
  }
2
 
3
  /**
4
  * See http://wpengineer.com/2426/wp_list_table-a-step-by-step-guide/
 
5
  */
6
+ if ( ! class_exists( 'WP_List_Table' ) ) {
7
+ require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
8
  }
9
  class PostmanEmailLogView extends WP_List_Table {
10
  private $logger;
11
+
12
  /**
13
  * ************************************************************************
14
  * REQUIRED.
17
  * *************************************************************************
18
  */
19
  function __construct() {
20
+ $this->logger = new PostmanLogger( get_class( $this ) );
21
+
22
  // Set parent defaults
23
+ parent::__construct( array(
24
  'singular' => 'email_log_entry', // singular name of the listed records
25
  'plural' => 'email_log_entries', // plural name of the listed records
26
+ 'ajax' => false,
27
  ) ); // does this table support ajax?
28
  }
29
+
30
  /**
31
  * ************************************************************************
32
  * Recommended.
53
  * @return string Text or HTML to be placed inside the column <td>
54
  * ************************************************************************
55
  */
56
+ function column_default( $item, $column_name ) {
57
+ switch ( $column_name ) {
58
  case 'date' :
59
  case 'status' :
60
+ return $item [ $column_name ];
61
  default :
62
+ return print_r( $item, true ); // Show the whole array for troubleshooting purposes
63
  }
64
  }
65
+
66
  /**
67
  * ************************************************************************
68
  * Recommended.
76
  * should be an associative array formatted as 'slug'=>'link html' - and you
77
  * will need to generate the URLs yourself. You could even ensure the links
78
  *
 
79
  * @see WP_List_Table::::single_row_columns()
80
  * @param array $item
81
  * A singular item (one full row's worth of data)
82
  * @return string Text to be placed inside the column <td> (movie title only)
83
  * ************************************************************************
84
  */
85
+ function column_title( $item ) {
86
+
87
  // Build row actions
88
  $iframeUri = 'admin-post.php?page=postman_email_log&action=%s&email=%s&TB_iframe=true&width=700&height=550';
89
+ $deleteUrl = wp_nonce_url( admin_url( sprintf( 'admin-post.php?page=postman_email_log&action=%s&email=%s', 'delete', $item ['ID'] ) ), 'delete_email_log_item_' . $item ['ID'] );
90
+ $viewUrl = admin_url( sprintf( $iframeUri, 'view', $item ['ID'] ) );
91
+ $transcriptUrl = admin_url( sprintf( $iframeUri, 'transcript', $item ['ID'] ) );
92
+ $resendUrl = admin_url( sprintf( $iframeUri, 'resend', $item ['ID'] ) );
93
+
94
+ $meta_values = get_post_meta( $item ['ID'] );
95
+
96
+ $actions = array(
97
+ 'delete' => sprintf( '<a href="%s">%s</a>', $deleteUrl, _x( 'Delete', 'Delete an item from the email log', Postman::TEXT_DOMAIN ) ),
98
+ 'view' => sprintf( '<a href="%s" class="thickbox">%s</a>', $viewUrl, _x( 'View', 'View an item from the email log', Postman::TEXT_DOMAIN ) ),
99
  );
100
+
101
+ if ( ! empty( $meta_values ['session_transcript'] [0] ) ) {
102
+ $actions ['transcript'] = sprintf( '<a href="%1$s" class="thickbox">%2$s</a>', $transcriptUrl, __( 'Session Transcript', Postman::TEXT_DOMAIN ) );
103
  } else {
104
+ $actions ['transcript'] = sprintf( '%2$s', $transcriptUrl, __( 'Session Transcript', Postman::TEXT_DOMAIN ) );
105
  }
106
+ if ( ! (empty( $meta_values ['original_to'] [0] ) && empty( $meta_values ['originalHeaders'] [0] )) ) {
107
  // $actions ['resend'] = sprintf ( '<a href="%s">%s</a>', $resendUrl, __ ( 'Resend', Postman::TEXT_DOMAIN ) );
108
+ $actions ['resend'] = sprintf( '<span id="%3$s"><a href="javascript:postman_resend_email(%1$s);">%2$s</a></span>', $item ['ID'], __( 'Resend', Postman::TEXT_DOMAIN ), 'resend-' . $item ['ID'] );
109
  } else {
110
+ $actions ['resend'] = sprintf( '%2$s', $resendUrl, __( 'Resend', Postman::TEXT_DOMAIN ) );
111
  }
112
+
113
  // Return the title contents
114
+ return sprintf( '%1$s %3$s',
115
+ /*$1%s*/ $item ['title'],
116
+ /*$2%s*/ $item ['ID'],
117
+ /*$3%s*/ $this->row_actions( $actions ) );
118
  }
119
+
120
  /**
121
  * ************************************************************************
122
  * REQUIRED if displaying checkboxes or using bulk actions! The 'cb' column
130
  * @return string Text to be placed inside the column <td> (movie title only)
131
  * ************************************************************************
132
  */
133
+ function column_cb( $item ) {
134
+ return sprintf( '<input type="checkbox" name="%1$s[]" value="%2$s" />',
135
+ /*$1%s*/ $this->_args ['singular'], // Let's simply repurpose the table's singular label ("movie")
136
+ /* $2%s */
137
  $item ['ID'] ); // The value of the checkbox should be the record's id
138
  }
139
+
140
  /**
141
  * ************************************************************************
142
  * REQUIRED! This method dictates the table's columns and titles.
154
  * ************************************************************************
155
  */
156
  function get_columns() {
157
+ $columns = array(
158
  'cb' => '<input type="checkbox" />', // Render a checkbox instead of text
159
+ 'title' => _x( 'Subject', 'What is the subject of this message?', Postman::TEXT_DOMAIN ),
160
+ 'status' => __( 'Status', Postman::TEXT_DOMAIN ),
161
+ 'date' => _x( 'Delivery Time', 'When was this email sent?', Postman::TEXT_DOMAIN ),
162
  );
163
  return $columns;
164
  }
165
+
166
  /**
167
  * ************************************************************************
168
  * Optional.
181
  * ************************************************************************
182
  */
183
  function get_sortable_columns() {
184
+ return array();
185
+ $sortable_columns = array(
186
+ 'title' => array(
187
  'title',
188
+ false,
189
  ), // true means it's already sorted
190
+ 'status' => array(
191
  'status',
192
+ false,
193
  ),
194
+ 'date' => array(
195
  'date',
196
+ false,
197
+ ),
198
  );
199
  return $sortable_columns;
200
  }
201
+
202
  /**
203
  * ************************************************************************
204
  * Optional.
217
  * ************************************************************************
218
  */
219
  function get_bulk_actions() {
220
+ $actions = array(
221
+ 'bulk_delete' => _x( 'Delete', 'Delete an item from the email log', Postman::TEXT_DOMAIN ),
222
  );
223
  return $actions;
224
  }
225
+
226
  /**
227
  * ************************************************************************
228
  * Optional.
234
  */
235
  function process_bulk_action() {
236
  }
237
+
238
  /**
239
  * ************************************************************************
240
  * REQUIRED! This is where you prepare your data for display.
254
  * ************************************************************************
255
  */
256
  function prepare_items() {
257
+
258
  /**
259
  * First, lets decide how many records per page to show
260
  */
261
  $per_page = 10;
262
+
263
  /**
264
  * REQUIRED.
265
  * Now we need to define our column headers. This includes a complete
268
  * can be defined in another method (as we've done here) before being
269
  * used to build the value for our _column_headers property.
270
  */
271
+ $columns = $this->get_columns();
272
+ $hidden = array();
273
+ $sortable = $this->get_sortable_columns();
274
+
275
  /**
276
  * REQUIRED.
277
  * Finally, we build an array to be used by the class for column
279
  * 3 other arrays. One for all columns, one for hidden columns, and one
280
  * for sortable columns.
281
  */
282
+ $this->_column_headers = array(
283
  $columns,
284
  $hidden,
285
+ $sortable,
286
  );
287
+
288
  /**
289
  * Optional.
290
  * You can handle your bulk actions however you see fit. In this
291
  * case, we'll handle them within our package just to keep things clean.
292
  */
293
+ $this->process_bulk_action();
294
+
295
  /**
296
  * Instead of querying a database, we're going to fetch the example data
297
  * property we created for use in this plugin.
302
  * use sort and pagination data to build a custom query instead, as you'll
303
  * be able to use your precisely-queried data immediately.
304
  */
305
+ $data = array();
306
+ $args = array(
307
  'posts_per_page' => 1000,
308
  'offset' => 0,
 
 
309
  'orderby' => 'date',
310
  'order' => 'DESC',
 
 
 
 
311
  'post_type' => PostmanEmailLogPostType::POSTMAN_CUSTOM_POST_TYPE_SLUG,
 
 
312
  'post_status' => 'private',
313
+ 'suppress_filters' => true,
314
  );
315
+
316
+ if ( isset( $_POST['from_date'] ) && ! empty( $_POST['from_date'] ) ) {
317
+ $from_date = sanitize_text_field( $_POST['from_date'] );
318
+
319
+ $args['date_query']['after'] = $from_date;
320
+ $args['date_query']['inclusive'] = false;
321
+ }
322
+
323
+ if ( isset( $_POST['to_date'] ) && ! empty( $_POST['to_date'] ) ) {
324
+ $to_date = sanitize_text_field( $_POST['to_date'] );
325
+
326
+ $args['date_query']['before'] = $to_date;
327
+ $args['date_query']['inclusive'] = true;
328
+ }
329
+
330
+ if ( ! empty( $_POST['search'] ) ) {
331
+
332
+ if ( isset( $args['date_query'] ) ) {
333
+ unset( $args['date_query'] ); }
334
+
335
+ $args['s'] = sanitize_text_field( $_POST['search'] );
336
+ }
337
+
338
+ $posts = new WP_query( $args );
339
+
340
+ foreach ( $posts->posts as $post ) {
341
  $date = $post->post_date;
342
+ $humanTime = human_time_diff( strtotime( $post->post_date_gmt ) );
343
  // if this PHP system support humanTime, than use it
344
+ if ( ! empty( $humanTime ) ) {
345
  /* Translators: where %s indicates the relative time from now */
346
+ $date = sprintf( _x( '%s ago', 'A relative time as in "five days ago"', Postman::TEXT_DOMAIN ), $humanTime );
347
  }
348
+
349
+ $flattenedPost = array(
350
  // the post title must be escaped as they are displayed in the HTML output
351
+ 'title' => esc_html( $post->post_title ),
352
  // the post status must be escaped as they are displayed in the HTML output
353
+ 'status' => ($post->post_excerpt != null ? esc_html( $post->post_excerpt ) : __( 'Sent', Postman::TEXT_DOMAIN )),
354
  'date' => $date,
355
+ 'ID' => $post->ID,
356
  );
357
+ array_push( $data, $flattenedPost );
358
  }
359
+
360
  /**
361
  * This checks for sorting input and sorts the data in our array accordingly.
362
  *
365
  * to a custom query. The returned data will be pre-sorted, and this array
366
  * sorting technique would be unnecessary.
367
  */
368
+ function usort_reorder( $a, $b ) {
369
+ $orderby = ( ! empty( $_REQUEST ['orderby'] )) ? $_REQUEST ['orderby'] : 'title'; // If no sort, default to title
370
+ $order = ( ! empty( $_REQUEST ['order'] )) ? $_REQUEST ['order'] : 'asc'; // If no order, default to asc
371
+ $result = strcmp( $a [ $orderby ], $b [ $orderby ] ); // Determine sort order
372
  return ($order === 'asc') ? $result : - $result; // Send final sort direction to usort
373
  }
374
  // usort($data, 'usort_reorder');
 
375
  /**
376
  * *********************************************************************
377
  * ---------------------------------------------------------------------
386
  * ---------------------------------------------------------------------
387
  * ********************************************************************
388
  */
389
+
390
  /**
391
  * REQUIRED for pagination.
392
  * Let's figure out what page the user is currently
393
  * looking at. We'll need this later, so you should always include it in
394
  * your own package classes.
395
  */
396
+ $current_page = $this->get_pagenum();
397
+
398
  /**
399
  * REQUIRED for pagination.
400
  * Let's check how many items are in our data array.
402
  * without filtering. We'll need this later, so you should always include it
403
  * in your own package classes.
404
  */
405
+ $total_items = count( $data );
406
+
407
  /**
408
  * The WP_List_Table class does not handle pagination for us, so we need
409
  * to ensure that the data is trimmed to only the current page.
410
  * We can use
411
  * array_slice() to
412
  */
413
+ $data = array_slice( $data, (($current_page - 1) * $per_page), $per_page );
414
+
415
  /**
416
  * REQUIRED.
417
  * Now we can add our *sorted* data to the items property, where
418
  * it can be used by the rest of the class.
419
  */
420
  $this->items = $data;
421
+
422
  /**
423
  * REQUIRED.
424
  * We also have to register our pagination options & calculations.
425
  */
426
+ $this->set_pagination_args( array(
427
  'total_items' => $total_items, // WE have to calculate the total number of items
428
  'per_page' => $per_page, // WE have to determine how many items to show on a page
429
+ 'total_pages' => ceil( $total_items / $per_page ),
430
  ) ); // WE have to calculate the total number of pages
431
  }
432
  }
Postman/Postman-Mail/PostmanMandrillTransport.php CHANGED
@@ -235,7 +235,7 @@ class PostmanMandrillTransport extends PostmanAbstractModuleTransport implements
235
  */
236
  public function printMandrillAuthSectionInfo() {
237
  /* Translators: Where (1) is the service URL and (2) is the service name and (3) is a api key URL */
238
- printf ( '<p id="wizard_mandrill_auth_help">%s</p>', sprintf ( __ ( 'Create an account at <a href="%1$s" target="_new">%2$s</a> and enter <a href="%3$s" target="_new">an API key</a> below.', Postman::TEXT_DOMAIN ), 'https://mandrillapp.com', 'Mandrillapp.com', 'https://mandrillapp.com/settings' ) );
239
  }
240
 
241
  /**
235
  */
236
  public function printMandrillAuthSectionInfo() {
237
  /* Translators: Where (1) is the service URL and (2) is the service name and (3) is a api key URL */
238
+ printf ( '<p id="wizard_mandrill_auth_help">%s</p>', sprintf ( __ ( 'Create an account at <a href="%1$s" target="_blank">%2$s</a> and enter <a href="%3$s" target="_blank">an API key</a> below.', Postman::TEXT_DOMAIN ), 'https://mandrillapp.com', 'Mandrillapp.com', 'https://mandrillapp.com/settings' ) );
239
  }
240
 
241
  /**
Postman/Postman-Mail/PostmanSendGridTransport.php CHANGED
@@ -186,7 +186,7 @@ class PostmanSendGridTransport extends PostmanAbstractModuleTransport implements
186
  }
187
  public function printSendGridAuthSectionInfo() {
188
  /* Translators: Where (1) is the service URL and (2) is the service name and (3) is a api key URL */
189
- printf ( '<p id="wizard_sendgrid_auth_help">%s</p>', sprintf ( __ ( 'Create an account at <a href="%1$s" target="_new">%2$s</a> and enter <a href="%3$s" target="_new">an API key</a> below.', Postman::TEXT_DOMAIN ), 'https://sendgrid.com', 'SendGrid.com', 'https://app.sendgrid.com/settings/api_keys' ) );
190
  }
191
 
192
  /**
186
  }
187
  public function printSendGridAuthSectionInfo() {
188
  /* Translators: Where (1) is the service URL and (2) is the service name and (3) is a api key URL */
189
+ printf ( '<p id="wizard_sendgrid_auth_help">%s</p>', sprintf ( __ ( 'Create an account at <a href="%1$s" target="_blank">%2$s</a> and enter <a href="%3$s" target="_blank">an API key</a> below.', Postman::TEXT_DOMAIN ), 'https://sendgrid.com', 'SendGrid.com', 'https://app.sendgrid.com/settings/api_keys' ) );
190
  }
191
 
192
  /**
Postman/Postman-Mail/PostmanSmtpModuleTransport.php CHANGED
@@ -528,7 +528,7 @@ class PostmanSmtpModuleTransport extends PostmanAbstractZendModuleTransport impl
528
  $inputValue = (null !== $this->options->getEnvelopeSender() ? esc_attr( $this->options->getEnvelopeSender() ) : '');
529
  $requiredLabel = __( 'Required', Postman::TEXT_DOMAIN );
530
  $envelopeFromMessage = __( 'This address, like the <b>return address</b> printed on an envelope, identifies the account owner to the SMTP server.', Postman::TEXT_DOMAIN );
531
- $spfMessage = sprintf( __( 'For reliable delivery, this domain must specify an <a target="_new" href="%s">SPF record</a> permitting the use of the SMTP server named above.', Postman::TEXT_DOMAIN ), 'https://www.mail-tester.com/spf/' );
532
  printf( '<input type="email" id="input_envelope_sender_email" name="postman_options[envelope_sender]" value="%s" size="40" class="required" placeholder="%s"/> <br/><span class="postman_input_description">%s %s</span>', $inputValue, $requiredLabel, $envelopeFromMessage, $spfMessage );
533
  }
534
 
528
  $inputValue = (null !== $this->options->getEnvelopeSender() ? esc_attr( $this->options->getEnvelopeSender() ) : '');
529
  $requiredLabel = __( 'Required', Postman::TEXT_DOMAIN );
530
  $envelopeFromMessage = __( 'This address, like the <b>return address</b> printed on an envelope, identifies the account owner to the SMTP server.', Postman::TEXT_DOMAIN );
531
+ $spfMessage = sprintf( __( 'For reliable delivery, this domain must specify an <a target="_blank" href="%s">SPF record</a> permitting the use of the SMTP server named above.', Postman::TEXT_DOMAIN ), 'https://www.mail-tester.com/spf/' );
532
  printf( '<input type="email" id="input_envelope_sender_email" name="postman_options[envelope_sender]" value="%s" size="40" class="required" placeholder="%s"/> <br/><span class="postman_input_description">%s %s</span>', $inputValue, $requiredLabel, $envelopeFromMessage, $spfMessage );
533
  }
534
 
Postman/Postman-Mail/Zend-1.12.10/Mail/Protocol/Smtp.php CHANGED
@@ -203,6 +203,11 @@ class Postman_Zend_Mail_Protocol_Smtp extends Postman_Zend_Mail_Protocol_Abstrac
203
  if ($this->_secure == 'tls') {
204
  $this->_send('STARTTLS');
205
  $this->_expect(220, 180);
 
 
 
 
 
206
  if (!stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
207
  /**
208
  * @see Postman_Zend_Mail_Protocol_Exception
203
  if ($this->_secure == 'tls') {
204
  $this->_send('STARTTLS');
205
  $this->_expect(220, 180);
206
+
207
+ stream_context_set_option($this->_socket, 'ssl', 'verify_peer', false);
208
+ //stream_context_set_option($this->_socket, 'ssl', 'verify_peer_name', false);
209
+ stream_context_set_option($this->_socket, 'ssl', 'allow_self_signed', true);
210
+
211
  if (!stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
212
  /**
213
  * @see Postman_Zend_Mail_Protocol_Exception
Postman/Postman-Mail/Zend-1.12.10/Validate/Hostname.php CHANGED
@@ -23,12 +23,10 @@
23
  * @see Postman_Zend_Validate_Abstract
24
  */
25
  // require_once 'Zend/Validate/Abstract.php';
26
-
27
  /**
28
  * @see Postman_Zend_Validate_Ip
29
  */
30
  // require_once 'Zend/Validate/Ip.php';
31
-
32
  /**
33
  * Please note there are two standalone test scripts for testing IDN characters due to problems
34
  * with file encoding.
@@ -46,1618 +44,2316 @@
46
  */
47
  class Postman_Zend_Validate_Hostname extends Postman_Zend_Validate_Abstract
48
  {
49
- const CANNOT_DECODE_PUNYCODE = 'hostnameCannotDecodePunycode';
50
- const INVALID = 'hostnameInvalid';
51
- const INVALID_DASH = 'hostnameDashCharacter';
52
- const INVALID_HOSTNAME = 'hostnameInvalidHostname';
53
- const INVALID_HOSTNAME_SCHEMA = 'hostnameInvalidHostnameSchema';
54
- const INVALID_LOCAL_NAME = 'hostnameInvalidLocalName';
55
- const INVALID_URI = 'hostnameInvalidUri';
56
- const IP_ADDRESS_NOT_ALLOWED = 'hostnameIpAddressNotAllowed';
57
- const LOCAL_NAME_NOT_ALLOWED = 'hostnameLocalNameNotAllowed';
58
- const UNDECIPHERABLE_TLD = 'hostnameUndecipherableTld';
59
- const UNKNOWN_TLD = 'hostnameUnknownTld';
60
-
61
- /**
62
- * @var array
63
- */
64
- protected $_messageTemplates = array(
65
- self::CANNOT_DECODE_PUNYCODE => "'%value%' appears to be a DNS hostname but the given punycode notation cannot be decoded",
66
- self::INVALID => "Invalid type given. String expected",
67
- self::INVALID_DASH => "'%value%' appears to be a DNS hostname but contains a dash in an invalid position",
68
- self::INVALID_HOSTNAME => "'%value%' does not match the expected structure for a DNS hostname",
69
- self::INVALID_HOSTNAME_SCHEMA => "'%value%' appears to be a DNS hostname but cannot match against hostname schema for TLD '%tld%'",
70
- self::INVALID_LOCAL_NAME => "'%value%' does not appear to be a valid local network name",
71
- self::INVALID_URI => "'%value%' does not appear to be a valid URI hostname",
72
- self::IP_ADDRESS_NOT_ALLOWED => "'%value%' appears to be an IP address, but IP addresses are not allowed",
73
- self::LOCAL_NAME_NOT_ALLOWED => "'%value%' appears to be a local network name but local network names are not allowed",
74
- self::UNDECIPHERABLE_TLD => "'%value%' appears to be a DNS hostname but cannot extract TLD part",
75
- self::UNKNOWN_TLD => "'%value%' appears to be a DNS hostname but cannot match TLD against known list",
76
- );
77
-
78
- /**
79
- * @var array
80
- */
81
- protected $_messageVariables = array(
82
- 'tld' => '_tld'
83
- );
84
-
85
- /**
86
- * Allows Internet domain names (e.g., example.com)
87
- */
88
- const ALLOW_DNS = 1;
89
-
90
- /**
91
- * Allows IP addresses
92
- */
93
- const ALLOW_IP = 2;
94
-
95
- /**
96
- * Allows local network names (e.g., localhost, www.localdomain)
97
- */
98
- const ALLOW_LOCAL = 4;
99
-
100
- /**
101
- * Allows all types of hostnames
102
- */
103
- const ALLOW_URI = 8;
104
-
105
- /**
106
- * Allows all types of hostnames
107
- */
108
- const ALLOW_ALL = 15;
109
-
110
- /**
111
- * Array of valid top-level-domains
112
- *
113
- * Version 2014112800, Last Updated Fri Nov 28 07:07:01 2014 UTC
114
- *
115
- * @see http://data.iana.org/TLD/tlds-alpha-by-domain.txt List of all TLDs by domain
116
- * @see http://www.iana.org/domains/root/db/ Official list of supported TLDs
117
- * @var array
118
- */
119
- protected $_validTlds = array(
120
- 'abogado',
121
- 'ac',
122
- 'academy',
123
- 'accountants',
124
- 'active',
125
- 'actor',
126
- 'ad',
127
- 'ae',
128
- 'aero',
129
- 'af',
130
- 'ag',
131
- 'agency',
132
- 'ai',
133
- 'airforce',
134
- 'al',
135
- 'allfinanz',
136
- 'alsace',
137
- 'am',
138
- 'an',
139
- 'android',
140
- 'ao',
141
- 'aq',
142
- 'ar',
143
- 'archi',
144
- 'army',
145
- 'arpa',
146
- 'as',
147
- 'asia',
148
- 'associates',
149
- 'at',
150
- 'attorney',
151
- 'au',
152
- 'auction',
153
- 'audio',
154
- 'autos',
155
- 'aw',
156
- 'ax',
157
- 'axa',
158
- 'az',
159
- 'ba',
160
- 'band',
161
- 'bar',
162
- 'bargains',
163
- 'bayern',
164
- 'bb',
165
- 'bd',
166
- 'be',
167
- 'beer',
168
- 'berlin',
169
- 'best',
170
- 'bf',
171
- 'bg',
172
- 'bh',
173
- 'bi',
174
- 'bid',
175
- 'bike',
176
- 'bio',
177
- 'biz',
178
- 'bj',
179
- 'black',
180
- 'blackfriday',
181
- 'bloomberg',
182
- 'blue',
183
- 'bm',
184
- 'bmw',
185
- 'bn',
186
- 'bnpparibas',
187
- 'bo',
188
- 'boo',
189
- 'boutique',
190
- 'br',
191
- 'brussels',
192
- 'bs',
193
- 'bt',
194
- 'budapest',
195
- 'build',
196
- 'builders',
197
- 'business',
198
- 'buzz',
199
- 'bv',
200
- 'bw',
201
- 'by',
202
- 'bz',
203
- 'bzh',
204
- 'ca',
205
- 'cab',
206
- 'cal',
207
- 'camera',
208
- 'camp',
209
- 'cancerresearch',
210
- 'capetown',
211
- 'capital',
212
- 'caravan',
213
- 'cards',
214
- 'care',
215
- 'career',
216
- 'careers',
217
- 'casa',
218
- 'cash',
219
- 'cat',
220
- 'catering',
221
- 'cc',
222
- 'cd',
223
- 'center',
224
- 'ceo',
225
- 'cern',
226
- 'cf',
227
- 'cg',
228
- 'ch',
229
- 'channel',
230
- 'cheap',
231
- 'christmas',
232
- 'chrome',
233
- 'church',
234
- 'ci',
235
- 'citic',
236
- 'city',
237
- 'ck',
238
- 'cl',
239
- 'claims',
240
- 'cleaning',
241
- 'click',
242
- 'clinic',
243
- 'clothing',
244
- 'club',
245
- 'cm',
246
- 'cn',
247
- 'co',
248
- 'coach',
249
- 'codes',
250
- 'coffee',
251
- 'college',
252
- 'cologne',
253
- 'com',
254
- 'community',
255
- 'company',
256
- 'computer',
257
- 'condos',
258
- 'construction',
259
- 'consulting',
260
- 'contractors',
261
- 'cooking',
262
- 'cool',
263
- 'coop',
264
- 'country',
265
- 'cr',
266
- 'credit',
267
- 'creditcard',
268
- 'cricket',
269
- 'crs',
270
- 'cruises',
271
- 'cu',
272
- 'cuisinella',
273
- 'cv',
274
- 'cw',
275
- 'cx',
276
- 'cy',
277
- 'cymru',
278
- 'cz',
279
- 'dad',
280
- 'dance',
281
- 'dating',
282
- 'day',
283
- 'de',
284
- 'deals',
285
- 'degree',
286
- 'delivery',
287
- 'democrat',
288
- 'dental',
289
- 'dentist',
290
- 'desi',
291
- 'diamonds',
292
- 'diet',
293
- 'digital',
294
- 'direct',
295
- 'directory',
296
- 'discount',
297
- 'dj',
298
- 'dk',
299
- 'dm',
300
- 'dnp',
301
- 'do',
302
- 'domains',
303
- 'durban',
304
- 'dvag',
305
- 'dz',
306
- 'eat',
307
- 'ec',
308
- 'edu',
309
- 'education',
310
- 'ee',
311
- 'eg',
312
- 'email',
313
- 'emerck',
314
- 'energy',
315
- 'engineer',
316
- 'engineering',
317
- 'enterprises',
318
- 'equipment',
319
- 'er',
320
- 'es',
321
- 'esq',
322
- 'estate',
323
- 'et',
324
- 'eu',
325
- 'eus',
326
- 'events',
327
- 'everbank',
328
- 'exchange',
329
- 'expert',
330
- 'exposed',
331
- 'fail',
332
- 'farm',
333
- 'feedback',
334
- 'fi',
335
- 'finance',
336
- 'financial',
337
- 'firmdale',
338
- 'fish',
339
- 'fishing',
340
- 'fitness',
341
- 'fj',
342
- 'fk',
343
- 'flights',
344
- 'florist',
345
- 'flsmidth',
346
- 'fly',
347
- 'fm',
348
- 'fo',
349
- 'foo',
350
- 'forsale',
351
- 'foundation',
352
- 'fr',
353
- 'frl',
354
- 'frogans',
355
- 'fund',
356
- 'furniture',
357
- 'futbol',
358
- 'ga',
359
- 'gal',
360
- 'gallery',
361
- 'gb',
362
- 'gbiz',
363
- 'gd',
364
- 'ge',
365
- 'gent',
366
- 'gf',
367
- 'gg',
368
- 'gh',
369
- 'gi',
370
- 'gift',
371
- 'gifts',
372
- 'gives',
373
- 'gl',
374
- 'glass',
375
- 'gle',
376
- 'global',
377
- 'globo',
378
- 'gm',
379
- 'gmail',
380
- 'gmo',
381
- 'gmx',
382
- 'gn',
383
- 'google',
384
- 'gop',
385
- 'gov',
386
- 'gp',
387
- 'gq',
388
- 'gr',
389
- 'graphics',
390
- 'gratis',
391
- 'green',
392
- 'gripe',
393
- 'gs',
394
- 'gt',
395
- 'gu',
396
- 'guide',
397
- 'guitars',
398
- 'guru',
399
- 'gw',
400
- 'gy',
401
- 'hamburg',
402
- 'haus',
403
- 'healthcare',
404
- 'help',
405
- 'here',
406
- 'hiphop',
407
- 'hiv',
408
- 'hk',
409
- 'hm',
410
- 'hn',
411
- 'holdings',
412
- 'holiday',
413
- 'homes',
414
- 'horse',
415
- 'host',
416
- 'hosting',
417
- 'house',
418
- 'how',
419
- 'hr',
420
- 'ht',
421
- 'hu',
422
- 'ibm',
423
- 'id',
424
- 'ie',
425
- 'il',
426
- 'im',
427
- 'immo',
428
- 'immobilien',
429
- 'in',
430
- 'industries',
431
- 'info',
432
- 'ing',
433
- 'ink',
434
- 'institute',
435
- 'insure',
436
- 'int',
437
- 'international',
438
- 'investments',
439
- 'io',
440
- 'iq',
441
- 'ir',
442
- 'is',
443
- 'it',
444
- 'je',
445
- 'jetzt',
446
- 'jm',
447
- 'jo',
448
- 'jobs',
449
- 'joburg',
450
- 'jp',
451
- 'juegos',
452
- 'kaufen',
453
- 'ke',
454
- 'kg',
455
- 'kh',
456
- 'ki',
457
- 'kim',
458
- 'kitchen',
459
- 'kiwi',
460
- 'km',
461
- 'kn',
462
- 'koeln',
463
- 'kp',
464
- 'kr',
465
- 'krd',
466
- 'kred',
467
- 'kw',
468
- 'ky',
469
- 'kz',
470
- 'la',
471
- 'lacaixa',
472
- 'land',
473
- 'lawyer',
474
- 'lb',
475
- 'lc',
476
- 'lds',
477
- 'lease',
478
- 'legal',
479
- 'lgbt',
480
- 'li',
481
- 'life',
482
- 'lighting',
483
- 'limited',
484
- 'limo',
485
- 'link',
486
- 'lk',
487
- 'loans',
488
- 'london',
489
- 'lotto',
490
- 'lr',
491
- 'ls',
492
- 'lt',
493
- 'ltda',
494
- 'lu',
495
- 'luxe',
496
- 'luxury',
497
- 'lv',
498
- 'ly',
499
- 'ma',
500
- 'madrid',
501
- 'maison',
502
- 'management',
503
- 'mango',
504
- 'market',
505
- 'marketing',
506
- 'mc',
507
- 'md',
508
- 'me',
509
- 'media',
510
- 'meet',
511
- 'melbourne',
512
- 'meme',
513
- 'memorial',
514
- 'menu',
515
- 'mg',
516
- 'mh',
517
- 'miami',
518
- 'mil',
519
- 'mini',
520
- 'mk',
521
- 'ml',
522
- 'mm',
523
- 'mn',
524
- 'mo',
525
- 'mobi',
526
- 'moda',
527
- 'moe',
528
- 'monash',
529
- 'money',
530
- 'mormon',
531
- 'mortgage',
532
- 'moscow',
533
- 'motorcycles',
534
- 'mov',
535
- 'mp',
536
- 'mq',
537
- 'mr',
538
- 'ms',
539
- 'mt',
540
- 'mu',
541
- 'museum',
542
- 'mv',
543
- 'mw',
544
- 'mx',
545
- 'my',
546
- 'mz',
547
- 'na',
548
- 'nagoya',
549
- 'name',
550
- 'navy',
551
- 'nc',
552
- 'ne',
553
- 'net',
554
- 'network',
555
- 'neustar',
556
- 'new',
557
- 'nexus',
558
- 'nf',
559
- 'ng',
560
- 'ngo',
561
- 'nhk',
562
- 'ni',
563
- 'ninja',
564
- 'nl',
565
- 'no',
566
- 'np',
567
- 'nr',
568
- 'nra',
569
- 'nrw',
570
- 'nu',
571
- 'nyc',
572
- 'nz',
573
- 'okinawa',
574
- 'om',
575
- 'ong',
576
- 'onl',
577
- 'ooo',
578
- 'org',
579
- 'organic',
580
- 'otsuka',
581
- 'ovh',
582
- 'pa',
583
- 'paris',
584
- 'partners',
585
- 'parts',
586
- 'party',
587
- 'pe',
588
- 'pf',
589
- 'pg',
590
- 'ph',
591
- 'pharmacy',
592
- 'photo',
593
- 'photography',
594
- 'photos',
595
- 'physio',
596
- 'pics',
597
- 'pictures',
598
- 'pink',
599
- 'pizza',
600
- 'pk',
601
- 'pl',
602
- 'place',
603
- 'plumbing',
604
- 'pm',
605
- 'pn',
606
- 'pohl',
607
- 'poker',
608
- 'post',
609
- 'pr',
610
- 'praxi',
611
- 'press',
612
- 'pro',
613
- 'prod',
614
- 'productions',
615
- 'prof',
616
- 'properties',
617
- 'property',
618
- 'ps',
619
- 'pt',
620
- 'pub',
621
- 'pw',
622
- 'py',
623
- 'qa',
624
- 'qpon',
625
- 'quebec',
626
- 're',
627
- 'realtor',
628
- 'recipes',
629
- 'red',
630
- 'rehab',
631
- 'reise',
632
- 'reisen',
633
- 'reit',
634
- 'ren',
635
- 'rentals',
636
- 'repair',
637
- 'report',
638
- 'republican',
639
- 'rest',
640
- 'restaurant',
641
- 'reviews',
642
- 'rich',
643
- 'rio',
644
- 'rip',
645
- 'ro',
646
- 'rocks',
647
- 'rodeo',
648
- 'rs',
649
- 'rsvp',
650
- 'ru',
651
- 'ruhr',
652
- 'rw',
653
- 'ryukyu',
654
- 'sa',
655
- 'saarland',
656
- 'sarl',
657
- 'sb',
658
- 'sc',
659
- 'sca',
660
- 'scb',
661
- 'schmidt',
662
- 'schule',
663
- 'science',
664
- 'scot',
665
- 'sd',
666
- 'se',
667
- 'services',
668
- 'sexy',
669
- 'sg',
670
- 'sh',
671
- 'shiksha',
672
- 'shoes',
673
- 'si',
674
- 'singles',
675
- 'sj',
676
- 'sk',
677
- 'sl',
678
- 'sm',
679
- 'sn',
680
- 'so',
681
- 'social',
682
- 'software',
683
- 'sohu',
684
- 'solar',
685
- 'solutions',
686
- 'soy',
687
- 'space',
688
- 'spiegel',
689
- 'sr',
690
- 'st',
691
- 'su',
692
- 'supplies',
693
- 'supply',
694
- 'support',
695
- 'surf',
696
- 'surgery',
697
- 'suzuki',
698
- 'sv',
699
- 'sx',
700
- 'sy',
701
- 'sydney',
702
- 'systems',
703
- 'sz',
704
- 'taipei',
705
- 'tatar',
706
- 'tattoo',
707
- 'tax',
708
- 'tc',
709
- 'td',
710
- 'technology',
711
- 'tel',
712
- 'tf',
713
- 'tg',
714
- 'th',
715
- 'tienda',
716
- 'tips',
717
- 'tirol',
718
- 'tj',
719
- 'tk',
720
- 'tl',
721
- 'tm',
722
- 'tn',
723
- 'to',
724
- 'today',
725
- 'tokyo',
726
- 'tools',
727
- 'top',
728
- 'town',
729
- 'toys',
730
- 'tp',
731
- 'tr',
732
- 'trade',
733
- 'training',
734
- 'travel',
735
- 'tt',
736
- 'tui',
737
-