Ticket #52283: 52283.patch
| File 52283.patch, 22.9 KB (added by , 5 years ago) |
|---|
-
new file src/wp-includes/class-plancake-email-parser.php
diff --git src/wp-includes/class-plancake-email-parser.php src/wp-includes/class-plancake-email-parser.php new file mode 100755 index 0000000000..ba8d4bafb2
- + 1 <?php 2 3 /************************************************************************************* 4 * ===================================================================================* 5 * Software by: Danyuki Software Limited * 6 * This file is part of Plancake. * 7 * * 8 * Copyright 2009-2010-2011 by: Danyuki Software Limited * 9 * Support, News, Updates at: http://www.plancake.com * 10 * Licensed under the LGPL version 3 license. * * 11 * Danyuki Software Limited is registered in England and Wales (Company No. 07554549) * 12 ************************************************************************************** 13 * Plancake is distributed in the hope that it will be useful, * 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 16 * GNU Lesser General Public License v3.0 for more details. * 17 * * 18 * You should have received a copy of the GNU Lesser General Public License * 19 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 20 * * 21 ************************************************************************************** 22 * 23 * Valuable contributions by: 24 * - Chris 25 * 26 ************************************************************************************** 27 * 28 * Adaptations for WordPress use: 29 * - imath 30 * 31 * **************************************************************************************/ 32 33 /** 34 * Extracts the headers and the body of an email 35 * Obviously it can't extract the bcc header because it doesn't appear in the content 36 * of the email. 37 * 38 * N.B.: if you deal with non-English languages, we recommend you install the IMAP PHP extension: 39 * the Plancake PHP Email Parser will detect it and used it automatically for better results. 40 * 41 * For more info, check: 42 * https://github.com/plancake/official-library-php-email-parser 43 * 44 * @author dan 45 */ 46 class Plancake_Email_Parser { 47 /** 48 * Plaintext code. 49 * 50 * @var int 51 */ 52 const PLAINTEXT = 1; 53 54 /** 55 * HTML code. 56 * 57 * @var int 58 */ 59 const HTML = 2; 60 61 /** 62 * IMAP extension availability. 63 * 64 * @var boolean 65 */ 66 private $is_imap_extension_available = false; 67 68 /** 69 * The Email raw content. 70 * 71 * @var string 72 */ 73 private $email_raw_content; 74 75 /** 76 * Email header fields. 77 * 78 * @var array 79 */ 80 protected $raw_fields; 81 82 /** 83 * Lines of the Email body. 84 * 85 * @var array 86 */ 87 protected $raw_body_lines; 88 89 /** 90 * Class constructor. 91 * 92 * @param string $email_raw_content The Email raw content. 93 */ 94 public function __construct( $email_raw_content ) { 95 $this->email_raw_content = $email_raw_content; 96 97 $this->extract_headers_and_rawbody(); 98 99 if ( function_exists( 'imap_open' ) ) { 100 $this->is_imap_extension_available = true; 101 } 102 } 103 104 /** 105 * Extracts the email header and body. 106 * 107 * @access private 108 */ 109 private function extract_headers_and_rawbody() { 110 $lines = preg_split( "/(\r?\n|\r)/", $this->email_raw_content ); 111 $current_header = ''; 112 $i = 0; 113 114 foreach ( $lines as $line ) { 115 if ( self::is_new_line( $line ) ) { 116 // end of headers. 117 $this->raw_body_lines = array_slice( $lines, $i ); 118 break; 119 } 120 121 if ( $this->is_line_starting_with_printable_char( $line ) ) { 122 // start of new header. 123 preg_match( '/([^:]+): ?(.*)$/', $line, $matches ); 124 $new_header = strtolower( $matches[1] ); 125 $value = $matches[2]; 126 127 // Sets the header field value. 128 $this->raw_fields[ $new_header ] = $value; 129 $current_header = $new_header; 130 } else { 131 // more lines related to the current header. 132 133 if ( $current_header ) { 134 // to prevent notice from empty lines. 135 $this->raw_fields[ $current_header ] .= substr( $line, 1 ); 136 } 137 } 138 139 $i++; 140 } 141 } 142 143 /** 144 * Gets the Email subject. 145 * 146 * @throws Exception if a subject header is not found. 147 * @return string An UTF-8 formatted string. 148 */ 149 public function get_subject() { 150 if ( ! isset( $this->raw_fields['subject'] ) ) { 151 throw new Exception( "Couldn't find the subject of the email" ); 152 } 153 154 $ret = ''; 155 156 if ( $this->is_imap_extension_available ) { 157 // Subject can span into several lines. 158 foreach ( imap_mime_header_decode( $this->raw_fields['subject'] ) as $h ) { 159 $charset = ( 'default' === $h->charset ) ? 'US-ASCII' : $h->charset; 160 $ret .= iconv( $charset, 'UTF-8//TRANSLIT', $h->text ); 161 } 162 } else { 163 $ret = utf8_encode( iconv_mime_decode( $this->raw_fields['subject'] ) ); 164 } 165 166 return $ret; 167 } 168 169 /** 170 * Gets the list of recipients in copy. 171 * 172 * @return array The list of recipients in copy. 173 */ 174 public function get_cc() { 175 if ( ! isset( $this->raw_fields['cc'] ) ) { 176 return array(); 177 } 178 179 return explode( ',', $this->raw_fields['cc'] ); 180 } 181 182 /** 183 * Gets the list of recipients. 184 * 185 * @throws Exception if a to header is not found or if there are no recipient. 186 * @return array The list of recipients. 187 */ 188 public function get_to() { 189 if ( ! isset( $this->raw_fields['to'] ) || ! count( $this->raw_fields['to'] ) ) { 190 throw new Exception( "Couldn't find the recipients of the email" ); 191 } 192 193 return explode( ',', $this->raw_fields['to'] ); 194 } 195 196 /** 197 * Returns the email body, UTF8 encoded. 198 * 199 * Example of an email body 200 * 201 * --0016e65b5ec22721580487cb20fd 202 * Content-Type: text/plain; charset=ISO-8859-1 203 * Hi all. I am new to Android development. 204 * Please help me. 205 * 206 * -- 207 * My signature 208 * email: myemail@gmail.com 209 * web: http://www.example.com 210 * --0016e65b5ec22721580487cb20fd 211 * Content-Type: text/html; charset=ISO-8859-1 212 * 213 * @param int $return_type The code of the type of content to return. 214 * Default: 1. 215 * @return string The email body, UTF8 encoded. 216 */ 217 public function get_body( $return_type = self::PLAINTEXT ) { 218 $body = ''; 219 $detected_content_type = false; 220 $content_transfer_encoding = null; 221 $charset = 'ASCII'; 222 $waiting_for_content_start = true; 223 224 if ( self::HTML === $return_type ) { 225 $content_type_regex = '/^Content-Type: ?text\/html/i'; 226 } else { 227 $content_type_regex = '/^Content-Type: ?text\/plain/i'; 228 } 229 230 // There could be more than one boundary. 231 preg_match_all( '!boundary=(.*)$!mi', $this->email_raw_content, $matches ); 232 $boundaries = array(); 233 234 if ( isset( $matches[1] ) && $matches[1] ) { 235 // Sometimes boundaries are delimited by quotes - we want to remove them. 236 foreach ( $matches[1] as $boundary ) { 237 $boundaries[] = trim( str_replace( array( "'", '"' ), '', $boundary ) ); 238 } 239 } 240 241 foreach ( $this->raw_body_lines as $line ) { 242 if ( null === $content_transfer_encoding && preg_match( '/^Content-Transfer-Encoding: ?(.*)/i', $line, $matches ) ) { 243 $content_transfer_encoding = $matches[1]; 244 } 245 246 if ( ! $detected_content_type ) { 247 248 if ( preg_match( $content_type_regex, $line, $matches ) ) { 249 $detected_content_type = true; 250 } 251 252 if ( preg_match( '/charset=(.*)/i', $line, $matches ) ) { 253 $charset = strtoupper( trim( $matches[1], '"' ) ); 254 } 255 } elseif ( $detected_content_type && $waiting_for_content_start ) { 256 257 if ( preg_match( '/charset=(.*)/i', $line, $matches ) ) { 258 $charset = strtoupper( trim( $matches[1], '"' ) ); 259 } 260 261 if ( self::is_new_line( $line ) ) { 262 $waiting_for_content_start = false; 263 } 264 } else { 265 /* 266 * Collecting the actual content until we find the delimiter. 267 * If the delimited is AAAAA, the line will be --AAAAA - that's why we use substr. 268 */ 269 if ( is_array( $boundaries ) && in_array( substr( $line, 2 ), $boundaries, true ) ) { 270 break; 271 } 272 273 $body .= $line . "\n"; 274 } 275 } 276 277 if ( ! $detected_content_type ) { 278 /* 279 * If here, we missed the text/plain content-type (probably it was 280 * in the header), thus we assume the whole body is what we are after. 281 */ 282 $body = implode( "\n", $this->raw_body_lines ); 283 } 284 285 // removing trailing new lines 286 $body = preg_replace( '/((\r?\n)*)$/', '', $body ); 287 288 if ( 'base64' === $content_transfer_encoding ) { 289 $body = base64_decode( $body ); 290 } elseif ( 'quoted-printable' === $content_transfer_encoding ) { 291 $body = quoted_printable_decode( $body ); 292 } 293 294 if ( 'UTF-8' !== $charset ) { 295 /* 296 * FORMAT=FLOWED, despite being popular in emails, it is not 297 * supported by iconv 298 */ 299 $charset = str_replace( 'FORMAT=FLOWED', '', $charset ); 300 $body_copy = $body; 301 $body = iconv( $charset, 'UTF-8//TRANSLIT', $body ); 302 303 // iconv returns false on failure. 304 if ( false === $body ) { 305 $body = utf8_encode( $body_copy ); 306 } 307 } 308 309 return $body; 310 } 311 312 /** 313 * Gets the text/plain body, UTF8 encoded. 314 * 315 * @return string The text/plain body, UTF8 encoded. 316 */ 317 public function get_plain_body() { 318 return $this->get_body( self::PLAINTEXT ); 319 } 320 321 /** 322 * Gets the text/html body, UTF8 encoded. 323 * 324 * @return string The text/html body, UTF8 encoded. 325 */ 326 public function get_html_body() { 327 return $this->get_body( self::HTML ); 328 } 329 330 /** 331 * Gets the value of a specific email header. 332 * 333 * N.B.: if the header doesn't exist an empty string is returned. 334 * 335 * @param string $header_name - the header we want to retrieve 336 * @return string - the value of the header 337 */ 338 public function get_header( $header_name ) { 339 $header_name = strtolower( $header_name ); 340 341 if ( isset( $this->raw_fields[ $header_name ] ) ) { 342 return $this->raw_fields[ $header_name ]; 343 } 344 345 return ''; 346 } 347 348 /** 349 * Checks if the current line is a new one. 350 * 351 * @param string $line One of the lines of the raw content. 352 * @return bool True if it's a new line. False otherwise. 353 */ 354 public static function is_new_line( $line ) { 355 $line = str_replace( "\r", '', $line ); 356 $line = str_replace( "\n", '', $line ); 357 358 return ( strlen( $line ) === 0 ); 359 } 360 361 /** 362 * Checks if the current line starts with a printable char. 363 * 364 * @param string $line One of the lines of the raw content. 365 * @return bool True if the line starts with a printable char. 366 * False otherwise. 367 * @access private 368 */ 369 private function is_line_starting_with_printable_char( $line ) { 370 return preg_match( '/^[A-Za-z]/', $line ); 371 } 372 } -
src/wp-includes/comment.php
diff --git src/wp-includes/comment.php src/wp-includes/comment.php index 116e66a57c..b9a89209fb 100644
function _wp_check_for_scheduled_update_comment_type() { 3903 3903 wp_schedule_single_event( time() + MINUTE_IN_SECONDS, 'wp_update_comment_type_batch' ); 3904 3904 } 3905 3905 } 3906 3907 /** 3908 * Checks the mail server (if enabled) is not restricted to posts. 3909 * 3910 * @since 5.7.0 3911 * 3912 * @return bool True if the mail server can be used for comments. False otherwise. 3913 */ 3914 function wp_check_comment_mailserver_usability() { 3915 /** 3916 * Filter here to disable mail server usage to comments. 3917 * 3918 * @since 5.7.0 3919 * 3920 * @param $value bool Whether to enable mail server usage to comments. 3921 */ 3922 return apply_filters( 'wp_check_comment_mailserver_usability', wp_is_mailserver_enabled() ); 3923 } -
src/wp-includes/functions.php
diff --git src/wp-includes/functions.php src/wp-includes/functions.php index eb4c4b6961..577f926846 100644
function is_php_version_compatible( $required ) { 7779 7779 function wp_fuzzy_number_match( $expected, $actual, $precision = 1 ) { 7780 7780 return abs( (float) $expected - (float) $actual ) <= $precision; 7781 7781 } 7782 7783 /** 7784 * Check if the mail server to fetch posts or comments sent by email is enabled. 7785 * 7786 * @since 5.7.0 7787 * 7788 * @return bool Whether the mail server to fetch posts or comments sent by email is enabled. 7789 */ 7790 function wp_is_mailserver_enabled() { 7791 $mailserver_url = get_option( 'mailserver_url', 'mail.example.com' ); 7792 7793 return $mailserver_url && 'mail.example.com' !== $mailserver_url; 7794 } -
src/wp-includes/pluggable.php
diff --git src/wp-includes/pluggable.php src/wp-includes/pluggable.php index 7dee482170..024319e14a 100644
if ( ! function_exists( 'wp_notify_postauthor' ) ) : 1672 1672 } 1673 1673 1674 1674 $notify_message .= get_permalink( $comment->comment_post_ID ) . "#comments\r\n\r\n"; 1675 1676 // Can authors reply to the comment directly by email? 1677 $can_reply_by_email = wp_check_comment_mailserver_usability(); 1678 1679 if ( $can_reply_by_email ) { 1680 /* translators: %s: Site name. */ 1681 $notify_message .= sprintf( __( 'Reply to this email directly or view it on %s:' ), $blogname ) . "\r\n"; 1682 } 1683 1675 1684 /* translators: %s: Comment URL. */ 1676 1685 $notify_message .= sprintf( __( 'Permalink: %s' ), get_comment_link( $comment ) ) . "\r\n"; 1677 1686 … … if ( ! function_exists( 'wp_notify_postauthor' ) ) : 1687 1696 $notify_message .= sprintf( __( 'Spam it: %s' ), admin_url( "comment.php?action=spam&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n"; 1688 1697 } 1689 1698 1690 $wp_email = 'wordpress@' . preg_replace( '#^www\.#', '', wp_parse_url( network_home_url(), PHP_URL_HOST ) ); 1699 $domain = preg_replace( '#^www\.#', '', wp_parse_url( network_home_url(), PHP_URL_HOST ) ); 1700 $wp_email = 'wordpress@' . $domain; 1691 1701 1692 1702 if ( '' === $comment->comment_author ) { 1693 1703 $from = "From: \"$blogname\" <$wp_email>"; … … if ( ! function_exists( 'wp_notify_postauthor' ) ) : 1704 1714 $message_headers = "$from\n" 1705 1715 . 'Content-Type: text/plain; charset="' . get_option( 'blog_charset' ) . "\"\n"; 1706 1716 1707 if ( isset( $reply_to ) ) { 1717 /** 1718 * Use the Reply by Email feature if enabled. 1719 */ 1720 if ( $can_reply_by_email ) { 1721 $mailserver_login = get_option( 'mailserver_login' ); 1722 $message_headers .= "Reply-To: \"$blogname\" <$mailserver_login>\n"; 1723 1724 $message_id = sprintf( 1725 /** 1726 * This Message-ID header is unique for the domain. 1727 * It identifies the author, the post type and the comment type. 1728 * It will be transported into the email reply. 1729 */ 1730 '%1$s/type/%2$s/%3$s/comment-type/%4$s/%5$s@%6$s', 1731 $author->user_nicename, 1732 get_post_type( $post ), 1733 $post->ID, 1734 get_comment_type( $comment ), 1735 $comment->comment_ID, 1736 $domain 1737 ); 1738 1739 // Use the Message ID as one of the references to make it available into the email reply. 1740 $message_headers .= "References: <$message_id>\n"; 1741 } elseif ( isset( $reply_to ) ) { 1708 1742 $message_headers .= $reply_to . "\n"; 1709 1743 } 1710 1744 -
src/wp-mail.php
diff --git src/wp-mail.php src/wp-mail.php index 1d5fbedf03..91fb26271b 100644
if ( ! apply_filters( 'enable_post_by_email_configuration', true ) ) { 15 15 wp_die( __( 'This action has been disabled by the administrator.' ), 403 ); 16 16 } 17 17 18 $mailserver_url = get_option( 'mailserver_url' ); 19 20 if ( 'mail.example.com' === $mailserver_url || empty( $mailserver_url ) ) { 18 if ( ! wp_is_mailserver_enabled() ) { 21 19 wp_die( __( 'This action has been disabled by the administrator.' ), 403 ); 22 20 } 23 24 21 /** 25 22 * Fires to allow a plugin to do a complete takeover of Post by Email. 26 23 * … … do_action( 'wp-mail.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHoo 30 27 31 28 /** Get the POP3 class with which to access the mailbox. */ 32 29 require_once ABSPATH . WPINC . '/class-pop3.php'; 30 require_once ABSPATH . WPINC . '/class-plancake-email-parser.php'; 33 31 34 32 /** Only check at this interval for new messages. */ 35 33 if ( ! defined( 'WP_MAIL_INTERVAL' ) ) { … … if ( 0 === $count ) { 65 63 wp_die( __( 'There doesn’t seem to be any new mail.' ) ); 66 64 } 67 65 68 for ( $i = 1; $i <= $count; $i++ ) { 66 $domain = preg_replace( '#^www\.#', '', wp_parse_url( network_home_url(), PHP_URL_HOST ) ); 67 $can_reply_by_email = wp_check_comment_mailserver_usability(); 69 68 69 for ( $i = 1; $i <= $count; $i++ ) { 70 // Set the message. 70 71 $message = $pop3->get( $i ); 71 72 73 if ( $can_reply_by_email ) { 74 // Possibly set the comment reply. 75 $reply = implode( '', $message ); 76 77 // Parse the reply. 78 $email_parser = new Plancake_Email_Parser( $reply ); 79 $email_address = preg_replace( '/(.*?)\<(.*?)\>/', '$2', iconv_mime_decode( $email_parser->get_header( 'From' ) ) ); 80 $author_email = sanitize_email( $email_address ); 81 $body = $email_parser->get_plain_body(); 82 $wp_references = array(); 83 $references = iconv_mime_decode( $email_parser->get_header( 'References' ) ); 84 $content_type = explode( ';', $email_parser->get_header( 'Content-Type' ) ); 85 86 $author = get_user_by( 'email', $author_email ); 87 if ( $author ) { 88 // Try to get the references. 89 preg_match( "/\<(.*?)\/type\/(.*?)\/(\d*?)\/comment-type\/(.*?)\/(\d*?)@$domain\>/", $references, $matches ); 90 array_shift( $matches ); 91 $wp_references = array_filter( $matches ); 92 $comment = null; 93 94 // Fallback to the comment's link inside the quoted message. 95 if ( ! $wp_references ) { 96 $url = addcslashes( site_url(), '/.' ); 97 98 // Reset matches. 99 $matches = array(); 100 101 /** 102 * @todo 103 * If the comment parent does not exist anymore and this is used, 104 * a post might be created. This needs extra checks. 105 */ 106 preg_match( "/$url(.*)#comment-(\d*)/", $body, $matches ); 107 if ( ! empty( $matches[0] ) && ! empty( $matches[2] ) ) { 108 $post_id = url_to_postid( $matches[0] ); 109 110 if ( $post_id ) { 111 $comment = get_comment( $matches[2] ); 112 if ( ! empty( $comment->comment_post_ID ) && $post_id === (int) $comment->comment_post_ID ) { 113 $wp_references = array( 114 $author->user_nicename, 115 get_post_type( $post_id ), 116 $post_id, 117 get_comment_type( $comment ), 118 $comment->comment_ID, 119 ); 120 } 121 } 122 } 123 } 124 125 // Let's process. 126 if ( 5 === count( $wp_references ) ) { 127 list( $author_user_nicename, $post_type, $post_id, $comment_type, $comment_id ) = $wp_references; 128 129 if ( null === $comment ) { 130 $comment = get_comment( $comment_id ); 131 } 132 133 // Set comment data. 134 if ( null !== $comment && $author_user_nicename === $author->user_nicename ) { 135 // Set comment author. 136 $comment_author = $author->display_name; 137 $comment_author_email = $author->user_email; 138 $comment_author_url = $author->user_url; 139 140 // Set comment content. 141 $comment_content = $body; 142 $content_type = reset( $content_type ); 143 144 // Most of the time emails are multipart, but some are not (eg: gmx.com). 145 if ( 'text/html' === strtolower( $content_type ) ) { 146 $comment_content = str_replace( ' ', ' ', wp_kses( $body, array() ) ); 147 $comment_content = html_entity_decode( $comment_content, ENT_QUOTES, get_bloginfo( 'charset' ) ); 148 } 149 150 // Reset matches. 151 $matches = array(); 152 153 // Look for <email> into the content to only keep what's above. 154 preg_match( '/^(.*)\<(.*)@(.*)\>(.*)$/im', $comment_content, $matches ); 155 if ( ! empty( $matches[0] ) ) { 156 $comment_content_parts = explode( $matches[0], $comment_content ); 157 if ( 2 === count( $comment_content_parts ) ) { 158 $comment_content = reset( $comment_content_parts ); 159 } 160 } else { 161 $commented_post = get_post( $post_id ); 162 163 // Look for the post title into the content to only keep what's above. 164 preg_match( "/^\>(.*)$commented_post->post_title(.*)$/im", $comment_content, $matches ); 165 if ( ! empty( $matches[0] ) ) { 166 $comment_content_parts = explode( $matches[0], $comment_content ); 167 if ( 2 === count( $comment_content_parts ) ) { 168 $comment_content = reset( $comment_content_parts ); 169 } 170 } 171 } 172 173 // Reset matches. 174 $matches = array(); 175 176 // Look for specific separators into the content to only keep what's above. 177 preg_match( '/---*|___*|Sent:.*$/', $comment_content, $matches ); 178 if ( ! empty( $matches[0] ) ) { 179 $comment_content_parts = explode( $matches[0], $comment_content ); 180 181 if ( 2 === count( $comment_content_parts ) ) { 182 $comment_content = reset( $comment_content_parts ); 183 } 184 } 185 186 // Trim extra characters from the content. 187 $comment_content = trim( $comment_content, "\n \t\r" ); 188 189 // Set comment date and GMT date. 190 $reply_date = iconv_mime_decode( $email_parser->get_header( 'Date' ) ); 191 $r_date = preg_replace( '!\s*\(.+\)\s*$!', '', $reply_date ); 192 $reply_timestamp = strtotime( $r_date ); 193 $comment_date = gmdate( 'Y-m-d H:i:s', $reply_timestamp + $time_difference ); 194 $comment_date_gmt = gmdate( 'Y-m-d H:i:s', $reply_timestamp ); 195 196 // The comment parent is the refernces' $comment_id. 197 $comment_parent = (int) $comment_id; 198 199 // Set the comment post ID. 200 $comment_post_ID = (int) $post_id; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase 201 202 // Set the user ID. 203 $user_id = $author->ID; 204 205 // Build arguments. 206 $commentdata = compact( 207 'comment_author', 208 'comment_author_email', 209 'comment_author_url', 210 'comment_content', 211 'comment_date', 212 'comment_date_gmt', 213 'comment_type', 214 'comment_parent', 215 'comment_post_ID', 216 'user_id' 217 ); 218 219 $comment_reply_id = wp_new_comment( wp_slash( $commentdata ), true ); 220 if ( ! is_wp_error( $comment_reply_id ) ) { 221 echo "\n<p><strong>" . __( 'Author:' ) . '</strong> ' . esc_html( $comment_author ) . '</p>'; 222 echo "\n<p><strong>" . __( 'Replied:' ) . '</strong> ' . esc_html( $comment_content ) . '</p>'; 223 224 // Delete the email. 225 if ( ! $pop3->delete( $i ) ) { 226 echo '<p>' . sprintf( 227 /* translators: %s: POP3 error. */ 228 __( 'Oops: %s' ), 229 esc_html( $pop3->ERROR ) 230 ) . '</p>'; 231 $pop3->reset(); 232 exit; 233 } else { 234 echo '<p>' . sprintf( 235 /* translators: %s: The message ID. */ 236 __( 'Mission complete. Reply %s deleted.' ), 237 '<strong>' . $i . '</strong>' 238 ) . '</p>'; 239 } 240 } else { 241 echo "\n" . $comment_reply_id->get_error_message(); 242 } 243 } 244 245 // Jump to next message/reply to avoid creating a post. 246 continue; 247 } 248 } 249 } 250 72 251 $bodysignal = false; 73 252 $boundary = ''; 74 253 $charset = '';