9d7673f59c407a1e950c7718d2020e5360647ee3
[autoinstalls/wordpress.git] / wp-content / plugins / akismet / admin.php
1 <?php
2 add_action( 'admin_menu', 'akismet_admin_menu' );
3         
4 akismet_admin_warnings();
5
6 function akismet_admin_init() {
7     global $wp_version;
8     
9     // all admin functions are disabled in old versions
10     if ( !function_exists('is_multisite') && version_compare( $wp_version, '3.0', '<' ) ) {
11         
12         function akismet_version_warning() {
13             echo "
14             <div id='akismet-warning' class='updated fade'><p><strong>".sprintf(__('Akismet %s requires WordPress 3.0 or higher.'), AKISMET_VERSION) ."</strong> ".sprintf(__('Please <a href="%s">upgrade WordPress</a> to a current version, or <a href="%s">downgrade to version 2.4 of the Akismet plugin</a>.'), 'http://codex.wordpress.org/Upgrading_WordPress', 'http://wordpress.org/extend/plugins/akismet/download/'). "</p></div>
15             ";
16         }
17         add_action('admin_notices', 'akismet_version_warning'); 
18         
19         return; 
20     }
21
22     if ( function_exists( 'get_plugin_page_hook' ) )
23         $hook = get_plugin_page_hook( 'akismet-stats-display', 'index.php' );
24     else
25         $hook = 'dashboard_page_akismet-stats-display';
26     add_meta_box('akismet-status', __('Comment History'), 'akismet_comment_status_meta_box', 'comment', 'normal');
27 }
28 add_action('admin_init', 'akismet_admin_init');
29
30 add_action( 'admin_enqueue_scripts', 'akismet_load_js_and_css' );
31 function akismet_load_js_and_css() {
32         global $hook_suffix;
33
34         if (
35                 $hook_suffix == 'index.php'     # dashboard
36                 || $hook_suffix == 'edit-comments.php' 
37                 || $hook_suffix == 'comment.php' 
38                 || $hook_suffix == 'post.php' 
39                 || $hook_suffix == 'plugins_page_akismet-key-config'
40         ) {
41                 wp_register_style( 'akismet.css', AKISMET_PLUGIN_URL . 'akismet.css', array(), '2.5.4.4' );
42                 wp_enqueue_style( 'akismet.css');
43         
44                 wp_register_script( 'akismet.js', AKISMET_PLUGIN_URL . 'akismet.js', array('jquery'), '2.5.4.6' );
45                 wp_enqueue_script( 'akismet.js' );
46                 wp_localize_script( 'akismet.js', 'WPAkismet', array(
47                         'comment_author_url_nonce' => wp_create_nonce( 'comment_author_url_nonce' )
48                 ) );
49         }
50 }
51
52
53 function akismet_nonce_field($action = -1) { return wp_nonce_field($action); }
54 $akismet_nonce = 'akismet-update-key';
55
56 function akismet_plugin_action_links( $links, $file ) {
57         if ( $file == plugin_basename( dirname(__FILE__).'/akismet.php' ) ) {
58                 $links[] = '<a href="' . admin_url( 'admin.php?page=akismet-key-config' ) . '">'.__( 'Settings' ).'</a>';
59         }
60
61         return $links;
62 }
63
64 add_filter( 'plugin_action_links', 'akismet_plugin_action_links', 10, 2 );
65
66 function akismet_conf() {
67         global $akismet_nonce, $wpcom_api_key;
68
69         if ( isset($_POST['submit']) ) {
70                 if ( function_exists('current_user_can') && !current_user_can('manage_options') )
71                         die(__('Cheatin&#8217; uh?'));
72
73                 check_admin_referer( $akismet_nonce );
74                 $key = preg_replace( '/[^a-h0-9]/i', '', $_POST['key'] );
75                 $home_url = parse_url( get_bloginfo('url') );
76
77                 if ( empty($key) ) {
78                         $key_status = 'empty';
79                         $ms[] = 'new_key_empty';
80                         delete_option('wordpress_api_key');
81                 } elseif ( empty($home_url['host']) ) {
82                         $key_status = 'empty';
83                         $ms[] = 'bad_home_url';
84                 } else {
85                         $key_status = akismet_verify_key( $key );
86                 }
87
88                 if ( $key_status == 'valid' ) {
89                         update_option('wordpress_api_key', $key);
90                         $ms[] = 'new_key_valid';
91                 } else if ( $key_status == 'invalid' ) {
92                         $ms[] = 'new_key_invalid';
93                 } else if ( $key_status == 'failed' ) {
94                         $ms[] = 'new_key_failed';
95                 }
96
97                 if ( isset( $_POST['akismet_discard_month'] ) )
98                         update_option( 'akismet_discard_month', 'true' );
99                 else
100                         update_option( 'akismet_discard_month', 'false' );
101
102                 if ( isset( $_POST['akismet_show_user_comments_approved'] ) )
103                         update_option( 'akismet_show_user_comments_approved', 'true' );
104                 else
105                         update_option( 'akismet_show_user_comments_approved', 'false' );
106
107         } elseif ( isset($_POST['check']) ) {
108                 akismet_get_server_connectivity(0);
109         }
110
111         if ( empty( $key_status) ||  $key_status != 'valid' ) {
112                 $key = get_option('wordpress_api_key');
113                 if ( empty( $key ) ) {
114                         if ( empty( $key_status ) || $key_status != 'failed' ) {
115                                 if ( akismet_verify_key( '1234567890ab' ) == 'failed' )
116                                         $ms[] = 'no_connection';
117                                 else
118                                         $ms[] = 'key_empty';
119                         }
120                         $key_status = 'empty';
121                 } else {
122                         $key_status = akismet_verify_key( $key );
123                 }
124                 if ( $key_status == 'valid' ) {
125                         $ms[] = 'key_valid';
126                 } else if ( $key_status == 'invalid' ) {
127                         $ms[] = 'key_invalid';
128                 } else if ( !empty($key) && $key_status == 'failed' ) {
129                         $ms[] = 'key_failed';
130                 }
131         }
132
133         $messages = array(
134                 'new_key_empty' => array('color' => 'aa0', 'text' => __('Your key has been cleared.')),
135                 'new_key_valid' => array('color' => '4AB915', 'text' => __('Your key has been verified. Happy blogging!')),
136                 'new_key_invalid' => array('color' => '888', 'text' => __('The key you entered is invalid. Please double-check it.')),
137                 'new_key_failed' => array('color' => '888', 'text' => __('The key you entered could not be verified because a connection to akismet.com could not be established. Please check your server configuration.')),
138                 'no_connection' => array('color' => '888', 'text' => __('There was a problem connecting to the Akismet server. Please check your server configuration.')),
139                 'key_empty' => array('color' => 'aa0', 'text' => sprintf(__('Please enter an API key. (<a href="%s" style="color:#fff">Get your key.</a>)'), 'http://akismet.com/get/?return=true')),
140                 'key_valid' => array('color' => '4AB915', 'text' => __('This key is valid.')),
141                 'key_invalid' => array('color' => '888', 'text' => __('This key is invalid.')),
142                 'key_failed' => array('color' => 'aa0', 'text' => __('The key below was previously validated but a connection to akismet.com can not be established at this time. Please check your server configuration.')),
143                 'bad_home_url' => array('color' => '888', 'text' => sprintf( __('Your WordPress home URL %s is invalid.  Please fix the <a href="%s">home option</a>.'), esc_html( get_bloginfo('url') ), admin_url('options.php#home') ) ),
144         );
145 ?>
146 <?php if ( !empty($_POST['submit'] ) ) : ?>
147 <div id="message" class="updated fade"><p><strong><?php _e('Options saved.') ?></strong></p></div>
148 <?php endif; ?>
149 <div class="wrap">
150 <h2><?php _e('Akismet Configuration'); ?></h2>
151 <?php if (isset($_GET['message']) && $_GET['message'] == 'success') { ?>
152         <div class="updated below-h2" id="message"><p><?php _e( '<strong>Sign up success!</strong> Please check your email for your Akismet API Key and enter it below.' ); ?></p></div>
153 <?php } ?>
154 <div class="narrow">
155 <form action="" method="post" id="akismet-conf" style="margin: auto; width: 400px; ">
156 <?php if ( !$wpcom_api_key ) { ?>
157         <p><?php printf(__('For many people, <a href="%1$s">Akismet</a> will greatly reduce or even completely eliminate the comment and trackback spam you get on your site. If one does happen to get through, simply mark it as "spam" on the moderation screen and Akismet will learn from the mistakes. If you don\'t have an API key yet, you can get one at <a href="%2$s">Akismet.com</a>.'), 'http://akismet.com/?return=true', 'http://akismet.com/get/?return=true'); ?></p>
158
159 <h3><label for="key"><?php _e('Akismet API Key'); ?></label></h3>
160 <?php foreach ( $ms as $m ) : ?>
161         <p style="padding: .5em; background-color: #<?php echo $messages[$m]['color']; ?>; color: #fff; font-weight: bold;"><?php echo $messages[$m]['text']; ?></p>
162 <?php endforeach; ?>
163 <p><input id="key" name="key" type="text" size="15" maxlength="12" value="<?php echo get_option('wordpress_api_key'); ?>" style="font-family: 'Courier New', Courier, mono; font-size: 1.5em;" /> (<?php _e('<a href="http://akismet.com/get/?return=true">What is this?</a>'); ?>)</p>
164 <?php if ( isset( $invalid_key) && $invalid_key ) { ?>
165 <h3><?php _e('Why might my key be invalid?'); ?></h3>
166 <p><?php _e('This can mean one of two things, either you copied the key wrong or that the plugin is unable to reach the Akismet servers, which is most often caused by an issue with your web host around firewalls or similar.'); ?></p>
167 <?php } ?>
168 <?php } ?>
169 <?php akismet_nonce_field($akismet_nonce) ?>
170 <p><label><input name="akismet_discard_month" id="akismet_discard_month" value="true" type="checkbox" <?php if ( get_option('akismet_discard_month') == 'true' ) echo ' checked="checked" '; ?> /> <?php _e('Auto-delete spam submitted on posts more than a month old.'); ?></label></p>
171 <p><label><input name="akismet_show_user_comments_approved" id="akismet_show_user_comments_approved" value="true" type="checkbox" <?php if ( get_option('akismet_show_user_comments_approved') == 'true' ) echo ' checked="checked" '; ?> /> <?php _e('Show the number of comments you\'ve approved beside each comment author.'); ?></label></p>
172         <p class="submit"><input type="submit" name="submit" value="<?php _e('Update options &raquo;'); ?>" /></p>
173 </form>
174
175 <form action="" method="post" id="akismet-connectivity" style="margin: auto; width: 400px; ">
176
177 <h3><?php _e('Server Connectivity'); ?></h3>
178 <?php
179         if ( !function_exists('fsockopen') || !function_exists('gethostbynamel') ) {
180                 ?>
181                         <p style="padding: .5em; background-color: #888; color: #fff; font-weight:bold;"><?php _e('Network functions are disabled.'); ?></p>
182                         <p><?php echo sprintf( __('Your web host or server administrator has disabled PHP\'s <code>fsockopen</code> or <code>gethostbynamel</code> functions.  <strong>Akismet cannot work correctly until this is fixed.</strong>  Please contact your web host or firewall administrator and give them <a href="%s" target="_blank">this information about Akismet\'s system requirements</a>.'), 'http://blog.akismet.com/akismet-hosting-faq/'); ?></p>
183                 <?php
184         } else {
185                 $servers = akismet_get_server_connectivity();
186                 $fail_count = count($servers) - count( array_filter($servers) );
187                 if ( is_array($servers) && count($servers) > 0 ) {
188                         // some connections work, some fail
189                         if ( $fail_count > 0 && $fail_count < count($servers) ) { ?>
190                                 <p style="padding: .5em; background-color: #aa0; color: #fff; font-weight:bold;"><?php _e('Unable to reach some Akismet servers.'); ?></p>
191                                 <p><?php echo sprintf( __('A network problem or firewall is blocking some connections from your web server to Akismet.com.  Akismet is working but this may cause problems during times of network congestion.  Please contact your web host or firewall administrator and give them <a href="%s" target="_blank">this information about Akismet and firewalls</a>.'), 'http://blog.akismet.com/akismet-hosting-faq/'); ?></p>
192                         <?php
193                         // all connections fail
194                         } elseif ( $fail_count > 0 ) { ?>
195                                 <p style="padding: .5em; background-color: #888; color: #fff; font-weight:bold;"><?php _e('Unable to reach any Akismet servers.'); ?></p>
196                                 <p><?php echo sprintf( __('A network problem or firewall is blocking all connections from your web server to Akismet.com.  <strong>Akismet cannot work correctly until this is fixed.</strong>  Please contact your web host or firewall administrator and give them <a href="%s" target="_blank">this information about Akismet and firewalls</a>.'), 'http://blog.akismet.com/akismet-hosting-faq/'); ?></p>
197                         <?php
198                         // all connections work
199                         } else { ?>
200                                 <p style="padding: .5em; background-color: #4AB915; color: #fff; font-weight:bold;"><?php  _e('All Akismet servers are available.'); ?></p>
201                                 <p><?php _e('Akismet is working correctly.  All servers are accessible.'); ?></p>
202                         <?php
203                         }
204                 } else {
205                         ?>
206                                 <p style="padding: .5em; background-color: #888; color: #fff; font-weight:bold;"><?php _e('Unable to find Akismet servers.'); ?></p>
207                                 <p><?php echo sprintf( __('A DNS problem or firewall is preventing all access from your web server to Akismet.com.  <strong>Akismet cannot work correctly until this is fixed.</strong>  Please contact your web host or firewall administrator and give them <a href="%s" target="_blank">this information about Akismet and firewalls</a>.'), 'http://blog.akismet.com/akismet-hosting-faq/'); ?></p>
208                         <?php
209                 }
210         }
211         
212         if ( !empty($servers) ) {
213 ?>
214 <table style="width: 100%;">
215 <thead><th><?php _e('Akismet server'); ?></th><th><?php _e('Network Status'); ?></th></thead>
216 <tbody>
217 <?php
218                 asort($servers);
219                 foreach ( $servers as $ip => $status ) {
220                         $color = ( $status ? '#4AB915' : '#888');
221         ?>
222                 <tr>
223                 <td><?php echo htmlspecialchars($ip); ?></td>
224                 <td style="padding: 0 .5em; font-weight:bold; color: #fff; background-color: <?php echo $color; ?>"><?php echo ($status ? __('Accessible') : __('Re-trying') ); ?></td>
225                 
226         <?php
227                 }
228         }
229 ?>
230 </tbody>
231 </table>
232         <p><?php if ( get_option('akismet_connectivity_time') ) echo sprintf( __('Last checked %s ago.'), human_time_diff( get_option('akismet_connectivity_time') ) ); ?></p>
233         <p class="submit"><input type="submit" name="check" value="<?php _e('Check network status &raquo;'); ?>" /></p>
234         <p><?php printf( __('<a href="%s" target="_blank">Click here</a> to confirm that <a href="%s" target="_blank">Akismet.com is up</a>.'), 'http://status.automattic.com/9931/136079/Akismet-API', 'http://status.automattic.com/9931/136079/Akismet-API' ); ?></p>
235 </form>
236
237 </div>
238 </div>
239 <?php
240 }
241
242 function akismet_stats_display() {
243         global $akismet_api_host, $akismet_api_port, $wpcom_api_key;
244         $blog = urlencode( get_bloginfo('url') );
245
246         $url = 'http://';
247         if ( is_ssl() )
248                 $url = 'https://';
249
250         $url .= 'akismet.com/web/1.0/user-stats.php';
251         $url .= "?blog={$blog}&api_key=" . akismet_get_key();
252         ?>
253         <div class="wrap">
254         <iframe src="<?php echo $url; ?>" width="100%" height="2500px" frameborder="0" id="akismet-stats-frame"></iframe>
255         </div>
256         <?php
257 }
258
259 function akismet_stats() {
260         if ( !function_exists('did_action') || did_action( 'rightnow_end' ) ) // We already displayed this info in the "Right Now" section
261                 return;
262         if ( !$count = get_option('akismet_spam_count') )
263                 return;
264         $path = plugin_basename(__FILE__);
265         echo '<h3>' . _x( 'Spam', 'comments' ) . '</h3>';
266         global $submenu;
267         if ( isset( $submenu['edit-comments.php'] ) )
268                 $link = 'edit-comments.php';
269         else
270                 $link = 'edit.php';
271         echo '<p>'.sprintf( _n( '<a href="%1$s">Akismet</a> has protected your site from <a href="%2$s">%3$s spam comments</a>.', '<a href="%1$s">Akismet</a> has protected your site from <a href="%2$s">%3$s spam comments</a>.', $count ), 'http://akismet.com/?return=true', clean_url("$link?page=akismet-admin"), number_format_i18n($count) ).'</p>';
272 }
273 add_action('activity_box_end', 'akismet_stats');
274
275 function akismet_admin_warnings() {
276         global $wpcom_api_key, $pagenow;
277
278         if (
279                 $pagenow == 'edit-comments.php'
280                 || ( !empty( $_GET['page'] ) && $_GET['page'] == 'akismet-key-config' )
281                 || ( !empty( $_GET['page'] ) && $_GET['page'] == 'akismet-stats-display' )
282         ) {
283                 if ( get_option( 'akismet_alert_code' ) ) {
284                         function akismet_alert() {
285                                 $alert = array(
286                                         'code' => (int) get_option( 'akismet_alert_code' ),
287                                         'msg' => get_option( 'akismet_alert_msg' )
288                                 );
289                         ?>
290                                 <div class='error'>
291                                         <p><strong>Akismet Error Code: <?php echo $alert['code']; ?></strong></p>
292                                         <p><?php esc_html_e( $alert['msg'] ); ?></p>
293                                         <p>More information is available at <a href="https://akismet.com/errors/<?php echo $alert['code']; ?>">https://akismet.com/errors/<?php echo $alert['code']; ?></a></p>
294                                 </div>
295                         <?php
296                         }
297
298                         add_action( 'admin_notices', 'akismet_alert' );
299                 }
300         }
301
302         if ( !get_option('wordpress_api_key') && !$wpcom_api_key && !isset($_POST['submit']) ) {
303                 function akismet_warning() {
304                         echo "
305                         <div id='akismet-warning' class='updated fade'><p><strong>".__('Akismet is almost ready.')."</strong> ".sprintf(__('You must <a href="%1$s">enter your Akismet API key</a> for it to work.'), "admin.php?page=akismet-key-config")."</p></div>
306                         ";
307                 }
308                 add_action('admin_notices', 'akismet_warning');
309                 return;
310         } elseif ( ( empty($_SERVER['SCRIPT_FILENAME']) || basename($_SERVER['SCRIPT_FILENAME']) == 'edit-comments.php' ) &&  wp_next_scheduled('akismet_schedule_cron_recheck') ) {
311                 function akismet_warning() {
312                         global $wpdb;
313                                 akismet_fix_scheduled_recheck();
314                                 $waiting = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->commentmeta WHERE meta_key = 'akismet_error'" );
315                                 $next_check = wp_next_scheduled('akismet_schedule_cron_recheck');
316                                 if ( $waiting > 0 && $next_check > time() )
317                                         echo "
318                         <div id='akismet-warning' class='updated fade'><p><strong>".__('Akismet has detected a problem.')."</strong> ".sprintf(__('Some comments have not yet been checked for spam by Akismet. They have been temporarily held for moderation. Please check your <a href="%s">Akismet configuration</a> and contact your web host if problems persist.'), 'admin.php?page=akismet-key-config')."</p></div>
319                         ";
320                 }
321                 add_action('admin_notices', 'akismet_warning');
322                 return;
323         }
324 }
325
326 // FIXME placeholder
327
328 function akismet_comment_row_action( $a, $comment ) {
329
330         // failsafe for old WP versions
331         if ( !function_exists('add_comment_meta') )
332                 return $a;
333
334         $akismet_result = get_comment_meta( $comment->comment_ID, 'akismet_result', true );
335         $akismet_error = get_comment_meta( $comment->comment_ID, 'akismet_error', true );
336         $user_result = get_comment_meta( $comment->comment_ID, 'akismet_user_result', true);
337         $comment_status = wp_get_comment_status( $comment->comment_ID );
338         $desc = null;
339         if ( $akismet_error ) {
340                 $desc = __( 'Awaiting spam check' );
341         } elseif ( !$user_result || $user_result == $akismet_result ) {
342                 // Show the original Akismet result if the user hasn't overridden it, or if their decision was the same
343                 if ( $akismet_result == 'true' && $comment_status != 'spam' && $comment_status != 'trash' )
344                         $desc = __( 'Flagged as spam by Akismet' );
345                 elseif ( $akismet_result == 'false' && $comment_status == 'spam' )
346                         $desc = __( 'Cleared by Akismet' );
347         } else {
348                 $who = get_comment_meta( $comment->comment_ID, 'akismet_user', true );
349                 if ( $user_result == 'true' )
350                         $desc = sprintf( __('Flagged as spam by %s'), $who );
351                 else
352                         $desc = sprintf( __('Un-spammed by %s'), $who );
353         }
354
355         // add a History item to the hover links, just after Edit
356         if ( $akismet_result ) {
357                 $b = array();
358                 foreach ( $a as $k => $item ) {
359                         $b[ $k ] = $item;
360                         if (
361                                 $k == 'edit'
362                                 || ( $k == 'unspam' && $GLOBALS['wp_version'] >= 3.4 )
363                         ) {
364                                 $b['history'] = '<a href="comment.php?action=editcomment&amp;c='.$comment->comment_ID.'#akismet-status" title="'. esc_attr__( 'View comment history' ) . '"> '. __('History') . '</a>';
365                         }
366                 }
367                 
368                 $a = $b;
369         }
370                 
371         if ( $desc )
372                 echo '<span class="akismet-status" commentid="'.$comment->comment_ID.'"><a href="comment.php?action=editcomment&amp;c='.$comment->comment_ID.'#akismet-status" title="' . esc_attr__( 'View comment history' ) . '">'.htmlspecialchars($desc).'</a></span>';
373                 
374         if ( apply_filters( 'akismet_show_user_comments_approved', get_option('akismet_show_user_comments_approved') ) == 'true' ) {
375                 $comment_count = akismet_get_user_comments_approved( $comment->user_id, $comment->comment_author_email, $comment->comment_author, $comment->comment_author_url );
376                 $comment_count = intval( $comment_count );
377                 echo '<span class="akismet-user-comment-count" commentid="'.$comment->comment_ID.'" style="display:none;"><br><span class="akismet-user-comment-counts">'.sprintf( _n( '%s approved', '%s approved', $comment_count ), number_format_i18n( $comment_count ) ) . '</span></span>';
378         }
379         
380         return $a;
381 }
382
383 add_filter( 'comment_row_actions', 'akismet_comment_row_action', 10, 2 );
384
385 function akismet_comment_status_meta_box($comment) {
386         $history = akismet_get_comment_history( $comment->comment_ID );
387
388         if ( $history ) {
389                 echo '<div class="akismet-history" style="margin: 13px;">';
390                 foreach ( $history as $row ) {
391                         $time = date( 'D d M Y @ h:i:m a', $row['time'] ) . ' GMT';
392                         echo '<div style="margin-bottom: 13px;"><span style="color: #999;" alt="' . $time . '" title="' . $time . '">' . sprintf( __('%s ago'), human_time_diff( $row['time'] ) ) . '</span> - ';
393                         echo htmlspecialchars( $row['message'] ) . '</div>';
394                 }
395                 
396                 echo '</div>';
397
398         }
399 }
400
401
402 // add an extra column header to the comments screen
403 function akismet_comments_columns( $columns ) {
404         $columns[ 'akismet' ] = __( 'Akismet' );
405         return $columns;
406 }
407
408 #add_filter( 'manage_edit-comments_columns', 'akismet_comments_columns' );
409
410 // Show stuff in the extra column
411 function akismet_comment_column_row( $column, $comment_id ) {
412         if ( $column != 'akismet' )
413                 return;
414                 
415         $history = akismet_get_comment_history( $comment_id );
416         
417         if ( $history ) {
418                 echo '<dl class="akismet-history">';
419                 foreach ( $history as $row ) {
420                         echo '<dt>' . sprintf( __('%s ago'), human_time_diff( $row['time'] ) ) . '</dt>';
421                         echo '<dd>' . htmlspecialchars( $row['message'] ) . '</dd>';
422                 }
423                 
424                 echo '</dl>';
425         }
426 }
427
428 #add_action( 'manage_comments_custom_column', 'akismet_comment_column_row', 10, 2 );
429
430 // END FIXME
431
432 // call out URLS in comments
433 function akismet_text_add_link_callback( $m ) {
434         
435                 // bare link?
436         if ( $m[4] == $m[2] )
437                 return '<a '.$m[1].' href="'.$m[2].'" '.$m[3].' class="comment-link">'.$m[4].'</a>';
438         else
439                 return '<span title="'.$m[2].'" class="comment-link"><a '.$m[1].' href="'.$m[2].'" '.$m[3].' class="comment-link">'.$m[4].'</a></span>';
440 }
441
442 function akismet_text_add_link_class( $comment_text ) {
443
444         return preg_replace_callback( '#<a ([^>]*)href="([^"]+)"([^>]*)>(.*?)</a>#i', 'akismet_text_add_link_callback', $comment_text );
445 }
446
447 add_filter('comment_text', 'akismet_text_add_link_class');
448
449
450 // WP 2.5+
451 function akismet_rightnow() {
452         global $submenu, $wp_db_version;
453
454         if ( 8645 < $wp_db_version  ) // 2.7
455                 $link = 'edit-comments.php?comment_status=spam';
456         elseif ( isset( $submenu['edit-comments.php'] ) )
457                 $link = 'edit-comments.php?page=akismet-admin';
458         else
459                 $link = 'edit.php?page=akismet-admin';
460
461         if ( $count = get_option('akismet_spam_count') ) {
462                 $intro = sprintf( _n(
463                         '<a href="%1$s">Akismet</a> has protected your site from %2$s spam comment already. ',
464                         '<a href="%1$s">Akismet</a> has protected your site from %2$s spam comments already. ',
465                         $count
466                 ), 'http://akismet.com/?return=true', number_format_i18n( $count ) );
467         } else {
468                 $intro = sprintf( __('<a href="%1$s">Akismet</a> blocks spam from getting to your blog. '), 'http://akismet.com/?return=true' );
469         }
470
471         $link = function_exists( 'esc_url' ) ? esc_url( $link ) : clean_url( $link );
472         if ( $queue_count = akismet_spam_count() ) {
473                 $queue_text = sprintf( _n(
474                         'There\'s <a href="%2$s">%1$s comment</a> in your spam queue right now.',
475                         'There are <a href="%2$s">%1$s comments</a> in your spam queue right now.',
476                         $queue_count
477                 ), number_format_i18n( $queue_count ), $link );
478         } else {
479                 $queue_text = sprintf( __( "There's nothing in your <a href='%1\$s'>spam queue</a> at the moment." ), $link );
480         }
481
482         $text = $intro . '<br />' . $queue_text;
483         echo "<p class='akismet-right-now'>$text</p>\n";
484 }
485         
486 add_action('rightnow_end', 'akismet_rightnow');
487
488
489 // For WP >= 2.5
490 function akismet_check_for_spam_button($comment_status) {
491         if ( 'approved' == $comment_status )
492                 return;
493         if ( function_exists('plugins_url') )
494                 $link = 'admin.php?action=akismet_recheck_queue';
495         else
496                 $link = 'edit-comments.php?page=akismet-admin&amp;recheckqueue=true&amp;noheader=true';
497         echo "</div><div class='alignleft'><a class='button-secondary checkforspam' href='$link'>" . __('Check for Spam') . "</a>";
498 }
499 add_action('manage_comments_nav', 'akismet_check_for_spam_button');
500
501 function akismet_submit_nonspam_comment ( $comment_id ) {
502         global $wpdb, $akismet_api_host, $akismet_api_port, $current_user, $current_site;
503         $comment_id = (int) $comment_id;
504
505         $comment = $wpdb->get_row("SELECT * FROM $wpdb->comments WHERE comment_ID = '$comment_id'");
506         if ( !$comment ) // it was deleted
507                 return;
508                 
509         // use the original version stored in comment_meta if available 
510         $as_submitted = get_comment_meta( $comment_id, 'akismet_as_submitted', true);
511         if ( $as_submitted && is_array($as_submitted) && isset($as_submitted['comment_content']) ) {
512                 $comment = (object) array_merge( (array)$comment, $as_submitted );
513         }
514         
515         $comment->blog = get_bloginfo('url');
516         $comment->blog_lang = get_locale();
517         $comment->blog_charset = get_option('blog_charset');
518         $comment->permalink = get_permalink($comment->comment_post_ID);
519         $comment->reporter_ip = $_SERVER['REMOTE_ADDR'];
520         if ( is_object($current_user) ) {
521             $comment->reporter = $current_user->user_login;
522         }
523         if ( is_object($current_site) ) {
524                 $comment->site_domain = $current_site->domain;
525         }
526
527         $comment->user_role = '';
528         if ( isset( $comment->user_ID ) )
529                 $comment->user_role = akismet_get_user_roles($comment->user_ID);
530
531         if ( akismet_test_mode() )
532                 $comment->is_test = 'true';
533
534         $post = get_post( $comment->comment_post_ID );
535         $comment->comment_post_modified_gmt = $post->post_modified_gmt;
536
537         $query_string = '';
538         foreach ( $comment as $key => $data )
539                 $query_string .= $key . '=' . urlencode( stripslashes($data) ) . '&';
540
541         $response = akismet_http_post($query_string, $akismet_api_host, "/1.1/submit-ham", $akismet_api_port);
542         if ( $comment->reporter ) {
543                 akismet_update_comment_history( $comment_id, sprintf( __('%s reported this comment as not spam'), $comment->reporter ), 'report-ham' );
544                 update_comment_meta( $comment_id, 'akismet_user_result', 'false' );
545                 update_comment_meta( $comment_id, 'akismet_user', $comment->reporter );
546         }
547         
548         do_action('akismet_submit_nonspam_comment', $comment_id, $response[1]);
549 }
550
551 function akismet_submit_spam_comment ( $comment_id ) {
552         global $wpdb, $akismet_api_host, $akismet_api_port, $current_user, $current_site;
553         $comment_id = (int) $comment_id;
554
555         $comment = $wpdb->get_row("SELECT * FROM $wpdb->comments WHERE comment_ID = '$comment_id'");
556         if ( !$comment ) // it was deleted
557                 return;
558         if ( 'spam' != $comment->comment_approved )
559                 return;
560         
561         // use the original version stored in comment_meta if available 
562         $as_submitted = get_comment_meta( $comment_id, 'akismet_as_submitted', true);
563         if ( $as_submitted && is_array($as_submitted) && isset($as_submitted['comment_content']) ) {
564                 $comment = (object) array_merge( (array)$comment, $as_submitted );
565         }
566         
567         $comment->blog = get_bloginfo('url');
568         $comment->blog_lang = get_locale();
569         $comment->blog_charset = get_option('blog_charset');
570         $comment->permalink = get_permalink($comment->comment_post_ID);
571         $comment->reporter_ip = $_SERVER['REMOTE_ADDR'];
572         if ( is_object($current_user) ) {
573             $comment->reporter = $current_user->user_login;
574         }
575         if ( is_object($current_site) ) {
576                 $comment->site_domain = $current_site->domain;
577         }
578
579         $comment->user_role = '';
580         if ( isset( $comment->user_ID ) )
581                 $comment->user_role = akismet_get_user_roles($comment->user_ID);
582
583         if ( akismet_test_mode() )
584                 $comment->is_test = 'true';
585
586         $post = get_post( $comment->comment_post_ID );
587         $comment->comment_post_modified_gmt = $post->post_modified_gmt;
588
589         $query_string = '';
590         foreach ( $comment as $key => $data )
591                 $query_string .= $key . '=' . urlencode( stripslashes($data) ) . '&';
592
593         $response = akismet_http_post($query_string, $akismet_api_host, "/1.1/submit-spam", $akismet_api_port);
594         if ( $comment->reporter ) {
595                 akismet_update_comment_history( $comment_id, sprintf( __('%s reported this comment as spam'), $comment->reporter ), 'report-spam' );
596                 update_comment_meta( $comment_id, 'akismet_user_result', 'true' );
597                 update_comment_meta( $comment_id, 'akismet_user', $comment->reporter );
598         }
599         do_action('akismet_submit_spam_comment', $comment_id, $response[1]);
600 }
601
602 // For WP 2.7+
603 function akismet_transition_comment_status( $new_status, $old_status, $comment ) {
604         if ( $new_status == $old_status )
605                 return;
606
607         # we don't need to record a history item for deleted comments
608         if ( $new_status == 'delete' )
609                 return;
610                 
611         if ( !is_admin() )
612                 return;
613                 
614         if ( !current_user_can( 'edit_post', $comment->comment_post_ID ) && !current_user_can( 'moderate_comments' ) )
615                 return;
616
617         if ( defined('WP_IMPORTING') && WP_IMPORTING == true )
618                 return;
619
620         // if this is present, it means the status has been changed by a re-check, not an explicit user action
621         if ( get_comment_meta( $comment->comment_ID, 'akismet_rechecking' ) )
622                 return;
623                 
624         global $current_user;
625         $reporter = '';
626         if ( is_object( $current_user ) )
627                 $reporter = $current_user->user_login;
628         
629         // Assumption alert:
630         // We want to submit comments to Akismet only when a moderator explicitly spams or approves it - not if the status
631         // is changed automatically by another plugin.  Unfortunately WordPress doesn't provide an unambiguous way to
632         // determine why the transition_comment_status action was triggered.  And there are several different ways by which
633         // to spam and unspam comments: bulk actions, ajax, links in moderation emails, the dashboard, and perhaps others.
634         // We'll assume that this is an explicit user action if POST or GET has an 'action' key.
635         if ( isset($_POST['action']) || isset($_GET['action']) ) {
636                 if ( $new_status == 'spam' && ( $old_status == 'approved' || $old_status == 'unapproved' || !$old_status ) ) {
637                                 return akismet_submit_spam_comment( $comment->comment_ID );
638                 } elseif ( $old_status == 'spam' && ( $new_status == 'approved' || $new_status == 'unapproved' ) ) {
639                                 return akismet_submit_nonspam_comment( $comment->comment_ID );
640                 }
641         }
642         
643         akismet_update_comment_history( $comment->comment_ID, sprintf( __('%s changed the comment status to %s'), $reporter, $new_status ), 'status-' . $new_status );
644 }
645
646 add_action( 'transition_comment_status', 'akismet_transition_comment_status', 10, 3 );
647
648 // Total spam in queue
649 // get_option( 'akismet_spam_count' ) is the total caught ever
650 function akismet_spam_count( $type = false ) {
651         global $wpdb;
652
653         if ( !$type ) { // total
654                 $count = wp_cache_get( 'akismet_spam_count', 'widget' );
655                 if ( false === $count ) {
656                         if ( function_exists('wp_count_comments') ) {
657                                 $count = wp_count_comments();
658                                 $count = $count->spam;
659                         } else {
660                                 $count = (int) $wpdb->get_var("SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_approved = 'spam'");
661                         }
662                         wp_cache_set( 'akismet_spam_count', $count, 'widget', 3600 );
663                 }
664                 return $count;
665         } elseif ( 'comments' == $type || 'comment' == $type ) { // comments
666                 $type = '';
667         } else { // pingback, trackback, ...
668                 $type  = $wpdb->escape( $type );
669         }
670
671         return (int) $wpdb->get_var("SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_approved = 'spam' AND comment_type='$type'");
672 }
673
674
675 function akismet_recheck_queue() {
676         global $wpdb, $akismet_api_host, $akismet_api_port;
677
678         akismet_fix_scheduled_recheck();
679
680         if ( ! ( isset( $_GET['recheckqueue'] ) || ( isset( $_REQUEST['action'] ) && 'akismet_recheck_queue' == $_REQUEST['action'] ) ) )
681                 return;
682                 
683         $moderation = $wpdb->get_results( "SELECT * FROM $wpdb->comments WHERE comment_approved = '0'", ARRAY_A );
684         foreach ( (array) $moderation as $c ) {
685                 $c['user_ip']    = $c['comment_author_IP'];
686                 $c['user_agent'] = $c['comment_agent'];
687                 $c['referrer']   = '';
688                 $c['blog']       = get_bloginfo('url');
689                 $c['blog_lang']  = get_locale();
690                 $c['blog_charset'] = get_option('blog_charset');
691                 $c['permalink']  = get_permalink($c['comment_post_ID']);
692
693                 $c['user_role'] = '';
694                 if ( isset( $c['user_ID'] ) )
695                         $c['user_role']  = akismet_get_user_roles($c['user_ID']);
696
697                 if ( akismet_test_mode() )
698                         $c['is_test'] = 'true';
699
700                 $id = (int) $c['comment_ID'];
701
702                 $query_string = '';
703                 foreach ( $c as $key => $data )
704                 $query_string .= $key . '=' . urlencode( stripslashes($data) ) . '&';
705
706                 add_comment_meta( $c['comment_ID'], 'akismet_rechecking', true );
707                 $response = akismet_http_post($query_string, $akismet_api_host, '/1.1/comment-check', $akismet_api_port);
708                 if ( 'true' == $response[1] ) {
709                         wp_set_comment_status($c['comment_ID'], 'spam');
710                         update_comment_meta( $c['comment_ID'], 'akismet_result', 'true' );
711                         delete_comment_meta( $c['comment_ID'], 'akismet_error' );
712                         akismet_update_comment_history( $c['comment_ID'], __('Akismet re-checked and caught this comment as spam'), 'check-spam' );
713                 
714                 } elseif ( 'false' == $response[1] ) {
715                         update_comment_meta( $c['comment_ID'], 'akismet_result', 'false' );
716                         delete_comment_meta( $c['comment_ID'], 'akismet_error' );
717                         akismet_update_comment_history( $c['comment_ID'], __('Akismet re-checked and cleared this comment'), 'check-ham' );
718                 // abnormal result: error
719                 } else {
720                         update_comment_meta( $c['comment_ID'], 'akismet_result', 'error' );
721                         akismet_update_comment_history( $c['comment_ID'], sprintf( __('Akismet was unable to re-check this comment (response: %s)'), substr($response[1], 0, 50)), 'check-error' );
722                 }
723
724                 delete_comment_meta( $c['comment_ID'], 'akismet_rechecking' );
725         }
726         $redirect_to = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : admin_url( 'edit-comments.php' );
727         wp_safe_redirect( $redirect_to );
728         exit;
729 }
730
731 add_action('admin_action_akismet_recheck_queue', 'akismet_recheck_queue');
732
733 // Adds an 'x' link next to author URLs, clicking will remove the author URL and show an undo link
734 function akismet_remove_comment_author_url() {
735     if ( !empty($_POST['id'] ) && check_admin_referer( 'comment_author_url_nonce' ) ) {
736         global $wpdb;
737         $comment = get_comment( intval($_POST['id']), ARRAY_A );
738         if (current_user_can('edit_comment', $comment['comment_ID'])) {
739             $comment['comment_author_url'] = '';
740             do_action( 'comment_remove_author_url' );
741             print(wp_update_comment( $comment ));
742             die();
743         }
744     }
745 }
746
747 add_action('wp_ajax_comment_author_deurl', 'akismet_remove_comment_author_url');
748
749 function akismet_add_comment_author_url() {
750     if ( !empty( $_POST['id'] ) && !empty( $_POST['url'] ) && check_admin_referer( 'comment_author_url_nonce' ) ) {
751         global $wpdb;
752         $comment = get_comment( intval($_POST['id']), ARRAY_A );
753         if (current_user_can('edit_comment', $comment['comment_ID'])) {
754             $comment['comment_author_url'] = esc_url($_POST['url']);
755             do_action( 'comment_add_author_url' );
756             print(wp_update_comment( $comment ));
757             die();
758         }
759     }
760 }
761
762 add_action('wp_ajax_comment_author_reurl', 'akismet_add_comment_author_url');
763
764 // Check connectivity between the WordPress blog and Akismet's servers.
765 // Returns an associative array of server IP addresses, where the key is the IP address, and value is true (available) or false (unable to connect).
766 function akismet_check_server_connectivity() {
767         global $akismet_api_host, $akismet_api_port, $wpcom_api_key;
768         
769         $test_host = 'rest.akismet.com';
770         
771         // Some web hosts may disable one or both functions
772         if ( !function_exists('fsockopen') || !function_exists('gethostbynamel') )
773                 return array();
774         
775         $ips = gethostbynamel($test_host);
776         if ( !$ips || !is_array($ips) || !count($ips) )
777                 return array();
778                 
779         $servers = array();
780         foreach ( $ips as $ip ) {
781                 $response = akismet_verify_key( akismet_get_key(), $ip );
782                 // even if the key is invalid, at least we know we have connectivity
783                 if ( $response == 'valid' || $response == 'invalid' )
784                         $servers[$ip] = true;
785                 else
786                         $servers[$ip] = false;
787         }
788
789         return $servers;
790 }
791
792 // Check the server connectivity and store the results in an option.
793 // Cached results will be used if not older than the specified timeout in seconds; use $cache_timeout = 0 to force an update.
794 // Returns the same associative array as akismet_check_server_connectivity()
795 function akismet_get_server_connectivity( $cache_timeout = 86400 ) {
796         $servers = get_option('akismet_available_servers');
797         if ( (time() - get_option('akismet_connectivity_time') < $cache_timeout) && $servers !== false )
798                 return $servers;
799         
800         // There's a race condition here but the effect is harmless.
801         $servers = akismet_check_server_connectivity();
802         update_option('akismet_available_servers', $servers);
803         update_option('akismet_connectivity_time', time());
804         return $servers;
805 }
806
807 // Returns true if server connectivity was OK at the last check, false if there was a problem that needs to be fixed.
808 function akismet_server_connectivity_ok() {
809         // skip the check on WPMU because the status page is hidden
810         global $wpcom_api_key;
811         if ( $wpcom_api_key )
812                 return true;
813         $servers = akismet_get_server_connectivity();
814         return !( empty($servers) || !count($servers) || count( array_filter($servers) ) < count($servers) );
815 }
816
817 function akismet_admin_menu() {
818         if ( class_exists( 'Jetpack' ) ) {
819                 add_action( 'jetpack_admin_menu', 'akismet_load_menu' );
820         } else {
821                 akismet_load_menu();
822         }
823 }
824
825 function akismet_load_menu() {
826         if ( class_exists( 'Jetpack' ) ) {
827                 add_submenu_page( 'jetpack', __( 'Akismet Configuration' ), __( 'Akismet Configuration' ), 'manage_options', 'akismet-key-config', 'akismet_conf' );
828                 add_submenu_page( 'jetpack', __( 'Akismet Stats' ), __( 'Akismet Stats' ), 'manage_options', 'akismet-stats-display', 'akismet_stats_display' );
829         } else {
830                 add_submenu_page('plugins.php', __('Akismet Configuration'), __('Akismet Configuration'), 'manage_options', 'akismet-key-config', 'akismet_conf');
831                 add_submenu_page('index.php', __('Akismet Stats'), __('Akismet Stats'), 'manage_options', 'akismet-stats-display', 'akismet_stats_display');
832         }
833 }