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
- 'tv',
738
- 'tw',
739
- 'tz',
740
- 'ua',
741
- 'ug',
742
- 'uk',
743
- 'university',
744
- 'uno',
745
- 'uol',
746
- 'us',
747
- 'uy',
748
- 'uz',
749
- 'va',
750
- 'vacations',
751
- 'vc',
752
- 've',
753
- 'vegas',
754
- 'ventures',
755
- 'versicherung',
756
- 'vet',
757
- 'vg',
758
- 'vi',
759
- 'viajes',
760
- 'villas',
761
- 'vision',
762
- 'vlaanderen',
763
- 'vn',
764
- 'vodka',
765
- 'vote',
766
- 'voting',
767
- 'voto',
768
- 'voyage',
769
- 'vu',
770
- 'wales',
771
- 'wang',
772
- 'watch',
773
- 'webcam',
774
- 'website',
775
- 'wed',
776
- 'wedding',
777
- 'wf',
778
- 'whoswho',
779
- 'wien',
780
- 'wiki',
781
- 'williamhill',
782
- 'wme',
783
- 'work',
784
- 'works',
785
- 'world',
786
- 'ws',
787
- 'wtc',
788
- 'wtf',
789
- 'xn--1qqw23a',
790
- 'xn--3bst00m',
791
- 'xn--3ds443g',
792
- 'xn--3e0b707e',
793
- 'xn--45brj9c',
794
- 'xn--45q11c',
795
- 'xn--4gbrim',
796
- 'xn--55qw42g',
797
- 'xn--55qx5d',
798
- 'xn--6frz82g',
799
- 'xn--6qq986b3xl',
800
- 'xn--80adxhks',
801
- 'xn--80ao21a',
802
- 'xn--80asehdb',
803
- 'xn--80aswg',
804
- 'xn--90a3ac',
805
- 'xn--c1avg',
806
- 'xn--cg4bki',
807
- 'xn--clchc0ea0b2g2a9gcd',
808
- 'xn--czr694b',
809
- 'xn--czru2d',
810
- 'xn--d1acj3b',
811
- 'xn--d1alf',
812
- 'xn--fiq228c5hs',
813
- 'xn--fiq64b',
814
- 'xn--fiqs8s',
815
- 'xn--fiqz9s',
816
- 'xn--flw351e',
817
- 'xn--fpcrj9c3d',
818
- 'xn--fzc2c9e2c',
819
- 'xn--gecrj9c',
820
- 'xn--h2brj9c',
821
- 'xn--i1b6b1a6a2e',
822
- 'xn--io0a7i',
823
- 'xn--j1amh',
824
- 'xn--j6w193g',
825
- 'xn--kprw13d',
826
- 'xn--kpry57d',
827
- 'xn--kput3i',
828
- 'xn--l1acc',
829
- 'xn--lgbbat1ad8j',
830
- 'xn--mgb9awbf',
831
- 'xn--mgba3a4f16a',
832
- 'xn--mgbaam7a8h',
833
- 'xn--mgbab2bd',
834
- 'xn--mgbayh7gpa',
835
- 'xn--mgbbh1a71e',
836
- 'xn--mgbc0a9azcg',
837
- 'xn--mgberp4a5d4ar',
838
- 'xn--mgbx4cd0ab',
839
- 'xn--ngbc5azd',
840
- 'xn--node',
841
- 'xn--nqv7f',
842
- 'xn--nqv7fs00ema',
843
- 'xn--o3cw4h',
844
- 'xn--ogbpf8fl',
845
- 'xn--p1acf',
846
- 'xn--p1ai',
847
- 'xn--pgbs0dh',
848
- 'xn--q9jyb4c',
849
- 'xn--qcka1pmc',
850
- 'xn--rhqv96g',
851
- 'xn--s9brj9c',
852
- 'xn--ses554g',
853
- 'xn--unup4y',
854
- 'xn--vermgensberater-ctb',
855
- 'xn--vermgensberatung-pwb',
856
- 'xn--vhquv',
857
- 'xn--wgbh1c',
858
- 'xn--wgbl6a',
859
- 'xn--xhq521b',
860
- 'xn--xkc2al3hye2a',
861
- 'xn--xkc2dl3a5ee0h',
862
- 'xn--yfro4i67o',
863
- 'xn--ygbi2ammx',
864
- 'xn--zfr164b',
865
- 'xxx',
866
- 'xyz',
867
- 'yachts',
868
- 'yandex',
869
- 'ye',
870
- 'yoga',