Index: wp-admin/admin-ajax.php
===================================================================
--- wp-admin/admin-ajax.php	(revision 11676)
+++ wp-admin/admin-ajax.php	(working copy)
@@ -111,6 +111,11 @@
 
 	die('0');
 	break;
+case 'spellcheck':
+	require_once(ABSPATH . 'wp-admin/includes/spellchecker.php');
+	wp_spellcheck_ajax();
+	die('0');
+break;
 default :
 	do_action( 'wp_ajax_' . $_GET['action'] );
 	die('0');
Index: wp-admin/includes/class-wp-googlespell.php
===================================================================
--- wp-admin/includes/class-wp-googlespell.php	(revision 0)
+++ wp-admin/includes/class-wp-googlespell.php	(revision 0)
@@ -0,0 +1,65 @@
+<?php
+/**
+ * File contains a wordpress adapted version of TinyMCE's GoogleSpell class.
+ *
+ * @package WordPress
+ * @author Benedikt Forchhammer <b.forchhammer@mind2.de>
+ * @since	2.9.0
+ */
+
+// The SpellChecking Engine that we want to extend
+require_once( MCE_SPELLCHECKER_DIR . "/classes/GoogleSpell.php" );
+
+/**
+ * Extension of TinyMCE GoogleSpell class for Wordpress
+ * 
+ * WP_GoogleSpell extends TinyMCE's GoogleSpell class. It overrides the way in which the 
+ * http request to google is executed and uses wp_remote_post() instead of curl/fsockopen.
+ *
+ * @link http://trac.wordpress.org/ticket/9798 Request for proxy support for spellchecking
+ * @since	2.9.0
+ */
+class WP_GoogleSpell extends GoogleSpell {
+
+	function &_getMatches($lang, $str) {
+		if (function_exists('wp_remote_post')) {
+			// request url
+			$url = "https://www.google.com/tbproxy/spell?lang=" . $lang . "&hl=en";
+			
+			// Setup XML request
+			$xml = '<?xml version="1.0" encoding="utf-8" ?><spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1"><text>' . $str . '</text></spellrequest>';
+			
+			// set up request arguments.
+			$args = array( 'body' => $xml, 'sslverify' => false );
+
+			// execute request and get response
+			$response = wp_remote_post($url, $args);
+			
+			if (is_wp_error($response)) {
+				wp_spellcheck_rpc_error(implode("\n", $response->get_error_messages()));
+			}
+			else {
+				// Grab and parse content
+				$matches = array();
+				preg_match_all('/<c o="([^"]*)" l="([^"]*)" s="([^"]*)">([^<]*)<\/c>/', wp_remote_retrieve_body($response), $matches, PREG_SET_ORDER);
+			
+				return $matches;
+			}
+		}
+		else {
+			wp_spellcheck_rpc_error('wp_remote_post() function has not been loaded.');
+		}
+	}
+	
+	/**
+	 * Use wordpress function unhtmlentities()
+	 *
+	 * @see http://core.trac.wordpress.org/ticket/8689
+	 * @see http://core.trac.wordpress.org/ticket/9805
+	 */
+	function _unhtmlentities($string) {
+		if (function_exists('unhtmlentities')) return unhtmlentities($string);
+		else return parent::_unhtmlentities($string);
+	}
+}
+?>
\ No newline at end of file
Index: wp-admin/includes/post.php
===================================================================
--- wp-admin/includes/post.php	(revision 11676)
+++ wp-admin/includes/post.php	(working copy)
@@ -1299,6 +1299,7 @@
 		'theme_advanced_buttons4' => "$mce_buttons_4",
 		'language' => "$mce_locale",
 		'spellchecker_languages' => "$mce_spellchecker_languages",
+		'spellchecker_rpc_url' => admin_url( 'admin-ajax.php?action=spellcheck' ),
 		'theme_advanced_toolbar_location' => 'top',
 		'theme_advanced_toolbar_align' => 'left',
 		'theme_advanced_statusbar_location' => 'bottom',
Index: wp-admin/includes/spellchecker.php
===================================================================
--- wp-admin/includes/spellchecker.php	(revision 0)
+++ wp-admin/includes/spellchecker.php	(revision 0)
@@ -0,0 +1,358 @@
+<?php
+/**
+ * This File contains functions used to handle Ajax spellchecking requests.
+ *
+ * @package WordPress
+ * @author 	Benedikt Forchhammer <b.forchhammer@mind2.de>
+ * @since	2.9.0
+ */
+
+/**
+ * Allows for the tinymce SpellChecker plugin directory to be moved from the default location.
+ *
+ * @since 	2.9.0
+ */
+if ( !defined('MCE_SPELLCHECKER_DIR') )
+	define( 'MCE_SPELLCHECKER_DIR', ABSPATH . WPINC . '/js/tinymce/plugins/spellchecker');
+
+add_filter('wp_spellcheck_engine_config','wp_spellcheck_engine_replacements');
+
+/**
+ * Changes config to use WP_GoogleSpell instead of GoogleSpell.
+ * 
+ * @param	array	$config		Config array for SpellChecker
+ * @since 	2.9.0
+ * @return	array
+ */
+function wp_spellcheck_engine_replacements($config) {
+	// replace GoogleSpell with WP_GoogleSpell
+	if ($config['general.engine'] == 'GoogleSpell') {
+		$config['general.engine'] = 'WP_GoogleSpell';
+		$config['general.engine.path'] =  ABSPATH . 'wp-admin/includes/class-wp-googlespell.php';
+	}
+	return $config;
+}
+
+/**
+ * Handle ajax request for "spellcheck" action.
+ *
+ * This function is called admin-ajax.php for the GET action "spellcheck".
+ *
+ * @uses	apply_filters	wp_spellcheck_rpc_request
+ * @uses	do_action		wp_spellcheck_rpc_result
+ * @since 	2.9.0
+ * @return	void
+ */
+function wp_spellcheck_ajax() {
+
+	// set headers at this point so that they are set fatal error responses as well.
+	wp_spellcheck_rpc_response_headers();
+
+	// get request data
+	$request = wp_spellcheck_rpc_get_request();
+	if (is_wp_error($request)) {
+		wp_spellcheck_rpc_error($request->get_error_message());
+	}
+	$request = apply_filters('wp_spellcheck_rpc_request', $request);
+	
+	// execute and return spellcheck
+	$result = wp_spellcheck_do_spellcheck($request['method'], $request['params']);
+	if (is_wp_error($result)) {
+		wp_spellcheck_rpc_error($result->get_error_message());
+	}
+	do_action_ref_array('wp_spellcheck_rpc_result', array( $request, &$result ));
+	
+	wp_spellcheck_rpc_send_response($request['id'], $result);
+}
+
+/**
+ * Calls a method on the SpellChecking Engine and returns the result.
+ *
+ * This function calls the method specified in $request['method']
+ * with the parameters specified in $request['params'] on the configured
+ * SpellChecker Engine.
+ *
+ * The two methods which are available by default are:
+ *
+ * <ul>
+ * <li><strong>checkWords<strong>: checks an array of words for misspellings and returns array of misspelled words</li>
+ * <li><strong>getSuggestions</strong>: retrieves a list of suggestions for a given misspelled word</li>
+ * </ul>
+ *
+ * @param 	string	$method 	name of method
+ * @param	array	$params		parameters
+ * @since 	2.9.0
+ * @return	mixed	The spellchecking result or WP_Error object
+ */
+function wp_spellcheck_do_spellcheck ($method, $params = array()) {
+	$spellchecker =& wp_spellcheck_get_engine();
+	
+	if (is_wp_error($spellchecker)) {
+		return $spellchecker;
+	}
+	
+	if (!is_object($spellchecker)) {
+		return new WP_Error('wp-spellcheck-engine-null', __('Failed to get SpellChecker engine instance.'));
+	}
+		
+	if (!method_exists($spellchecker, $method)) {
+		// Either invalid method name or incomplete spellchecker class
+		return new WP_Error('wp-spellcheck-engine-method-notfound', __('Failed to call method on spellchecking engine. ')); 
+	}
+	
+	if (!is_array($params)) {
+		$params = array($params);
+	}
+	
+	$result = call_user_func_array(array($spellchecker, $method), $params);
+	
+	return $result;
+}
+
+/**
+ * Get spellcheck request data.
+ *
+ * @since 	2.9.0
+ * @return 	mixed 	
+ */
+function wp_spellcheck_rpc_get_request() {
+
+	// try to get raw data
+	$raw = wp_spellcheck_rpc_raw_input();
+	if (empty($raw)) {
+		return new WP_Error("wp-spellcheck-request-empty", __("Could not get raw post data."));
+	}
+	
+	// try to parse data as json
+	$request = wp_spellcheck_json_decode($raw);
+	
+	// check we have good request data
+	if (!is_array($request)) {
+		return new WP_Error("wp-spellcheck-request-malformed", __("Failed parsing request as JSON: ") . print_r($request, 1) );
+	}
+	if (empty($request['method'])) {
+		return new WP_Error("wp-spellcheck-request-malformed", __("Malformed JSON: missing \"method\" parameter."));
+	}
+	if (empty($request['params'])) {
+		$request['params'] = array();
+	}
+	
+	return $request;
+}
+
+/**
+ * Retrieves the raw request data for spellchecking request.
+ *
+ * The function tries the following sources and returns the
+ * first non-empty one found:
+ *
+ * <ul>
+ * <li>$_POST[json_data]</li>
+ * <li>$_GLOBALS[HTTP_RAW_POST_DATA]</li>
+ * <li>$HTTP_RAW_POST_DATA</li>
+ * <li>file_get_contents("php://input")</li>
+ * <li>fopen("php://input", "r");</li>
+ * </ul>
+ *
+ * @link 	http://core.trac.wordpress.org/browser/trunk/wp-includes/js/tinymce/plugins/spellchecker/rpc.php Roughly based on respective code in this file.
+ * @since 	2.9.0
+ * @return 	string Raw request data (json encoded)
+ */
+function wp_spellcheck_rpc_raw_input() {
+	$raw = "";
+
+	// Try param
+	if (isset($_POST["json_data"])) {
+		$raw = $_POST["json_data"];
+	}
+
+	// Try globals array
+	if (!$raw && isset($_GLOBALS) && isset($_GLOBALS["HTTP_RAW_POST_DATA"])) {
+		$raw = $_GLOBALS["HTTP_RAW_POST_DATA"];
+	}
+
+	// Try globals variable
+	if (!$raw && isset($HTTP_RAW_POST_DATA)) {
+		$raw = $HTTP_RAW_POST_DATA;
+	}
+		
+	// Try stream
+	if (!$raw) {
+		if (!function_exists('file_get_contents')) {
+			$fp = fopen("php://input", "r");
+			if ($fp) {
+				$raw = "";
+
+				while (!feof($fp)) $raw = fread($fp, 1024);
+				fclose($fp);
+			}
+		}
+		else {
+			$raw = "" . file_get_contents("php://input");
+		}
+	}
+
+	return $raw;
+}
+
+/**
+ * Send the given result to client. This will stop all execution.
+ *
+ * @param	string	$id		Request id which was passed to the server in the request.
+ * @param 	array	$result	Result of the request
+ * @since 	2.9.0
+ * @return	void
+ */
+function wp_spellcheck_rpc_send_response($request_id, $result) {
+
+	// Request and response id should always be the same
+	$output = array(
+		"id" => $request_id,
+		"result" => $result,
+		"error" => null
+	);
+	
+	// Return JSON encoded string
+	echo wp_spellcheck_json_encode($output);
+	exit();
+}
+
+/**
+ * Set headers for the spellcheck rpc response
+ *
+ * @uses 	do_action	wp_spellcheck_rpc_headers 
+ * @since 	2.9.0
+ * @return	void
+ */
+function wp_spellcheck_rpc_response_headers() {
+	header('Content-Type: text/plain');
+	header('Content-Encoding: UTF-8');
+	header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
+	header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
+	header("Cache-Control: no-store, no-cache, must-revalidate");
+	header("Cache-Control: post-check=0, pre-check=0", false);
+	header("Pragma: no-cache");	
+	
+	do_action('wp_spellcheck_rpc_headers');
+}
+
+/**
+ * Send json encoded error message to client. This will stop all execution.
+ *
+ * Note: this is a clone of TinyMCE's throwError() function in the
+ * SpellChecker class (spellchecker plugin).
+ *
+ * @param 	string 	$msg 	Message to send back to user.
+ * @since 	2.9.0
+ * @return	void
+ */
+function wp_spellcheck_rpc_error($msg) {
+	die('{"result":null,"id":null,"error":{"errstr":"' . addslashes($msg) . '","errfile":"","errline":null,"errcontext":"","level":"FATAL"}}');
+}
+
+/**
+ * Get the SpellChecker Engine Object
+ *
+ * @uses 	apply_filters 	wp_spellcheck_engine_class
+ * @uses 	apply_filters 	wp_spellcheck_engine_path
+ * @since 	2.9.0
+ * @return	SpellChecker	spell checking engine
+ */
+function &wp_spellcheck_get_engine() {
+	static $spellchecker = null;
+	
+	if ($spellchecker === null) {
+		// load base class for all spellcheckers
+		if ( !class_exists('SpellChecker') ) {
+			require_once( MCE_SPELLCHECKER_DIR . "/classes/SpellChecker.php" );
+		}
+		
+		$config = wp_spellcheck_get_engine_config();
+		
+		// get engine class name
+		$engine_class = apply_filters('wp_spellcheck_engine_class', $config['general.engine']);
+
+		// try to load engine class if necessary
+		if ( !class_exists($engine_class) ) {
+
+			// determine engine file path
+			$engine_path = $config['general.engine.path'];
+			if (empty($engine_path)) {
+				$engine_path = MCE_SPELLCHECKER_DIR . "/classes/$engine_class.php";
+			}
+			$engine_path = apply_filters('wp_spellcheck_engine_path', $engine_path, $engine_class);
+			
+			if ( !file_exists($engine_path) ) {
+				return new WP_Error('wp-spellcheck-engine-not-found', __('Cannot load SpellChecker Engine; class file not found: ') . $engine_path );
+			}
+			require_once( $engine_path );
+			
+			if (!class_exists($engine_class)) {
+				return new WP_Error('wp-spellcheck-engine-not-found', __('Cannot load SpellChecker Engine; class not found: ') . $engine_class );
+			}
+		}
+		
+		$spellchecker = new $engine_class($config);
+	}
+	
+	return $spellchecker;
+}
+
+/**
+ * Get configuration values for the SpellChecker Engine.
+ *
+ * @uses 	apply_filters	wp_spellcheck_engine_config
+ * @since 	2.9.0
+ * @return	Array	array of config values
+ */
+function wp_spellcheck_get_engine_config() {
+	$config = array();
+	$config['general.engine'] = 'GoogleSpell';
+	
+	// load default tinymce config
+	require_once( MCE_SPELLCHECKER_DIR . "/config.php" );
+	
+	return apply_filters('wp_spellcheck_engine_config', $config);
+}
+
+/**
+ * Encodes a php object into json
+ * 
+ * @param	mixed	the thing to encode
+ * @since 	2.9.0
+ * @return 	string	json string
+ */
+function wp_spellcheck_json_encode($thing) {
+	$json =& wp_spellcheck_json_object();
+	return $json->encode($thing);
+}
+
+/**
+ * Decodes a json string into the respective php object
+ * 
+ * @param 	string	json string
+ * @since 	2.9.0
+ * @return 	mixed 	json decoded thing
+ */
+function wp_spellcheck_json_decode($string) {
+	$json =& wp_spellcheck_json_object();
+	return $json->decode($string);
+}
+
+/**
+ * Returns an object of the moxiecode json encoder/transcoder class.
+ *
+ * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/JSON.php Moxiecode JSON Class
+ * @since 	2.9.0
+ * @return	Moxiecode_JSON	JSON Encoder/Transcoder Object
+ */
+function &wp_spellcheck_json_object() {
+	static $json = null;
+	if ($json == null) {
+		require_once( MCE_SPELLCHECKER_DIR . "/classes/utils/JSON.php" );
+		$json = new Moxiecode_JSON();
+	}
+	return $json;
+}
+
+?>
\ No newline at end of file
