Index: wp-includes/version.php
===================================================================
--- wp-includes/version.php	(revision 7102)
+++ wp-includes/version.php	(working copy)
@@ -16,6 +16,6 @@
  *
  * @global int $wp_db_version
  */
-$wp_db_version = 6846;
+$wp_db_version = 7098;
 
 ?>
Index: wp-includes/js/autosave.js
===================================================================
--- wp-includes/js/autosave.js	(revision 7102)
+++ wp-includes/js/autosave.js	(working copy)
@@ -1,65 +1,75 @@
 var autosaveLast = '';
 var autosavePeriodical;
 
-function autosave_start_timer() {
-	autosaveLast = jQuery('#post #title').val()+jQuery('#post #content').val();
-	// Keep autosave_interval in sync with edit_post().
-	autosavePeriodical = jQuery.schedule({time: autosaveL10n.autosaveInterval * 1000, func: autosave, repeat: true, protect: true});
+jQuery(function($) {
+	autosaveLast = $('#post #title').val()+$('#post #content').val();
+	autosavePeriodical = $.schedule({time: autosaveL10n.autosaveInterval * 1000, func: function() { autosave(); }, repeat: true, protect: true});
 
 	//Disable autosave after the form has been submitted
-	jQuery("#post #submit").submit(function() { jQuery.cancel(autosavePeriodical); });
-	jQuery("#post #save").click(function() { jQuery.cancel(autosavePeriodical); });
-	jQuery("#post #submit").click(function() { jQuery.cancel(autosavePeriodical); });
-	jQuery("#post #publish").click(function() { jQuery.cancel(autosavePeriodical); });
-	jQuery("#post #deletepost").click(function() { jQuery.cancel(autosavePeriodical); });
+	$("#post").submit(function() { $.cancel(autosavePeriodical); });
 
-	// Autosave early on for a new post
-	jQuery("#content").keypress(function() {
-		if ( 1 === ( jQuery(this).val().length % 15 ) && 1 > parseInt(jQuery("#post_ID").val(),10) )
+	// Autosave early on for a new post.  Why?  Should this only be run once?
+	$("#content").keypress(function() {
+		if ( 1 === ( $(this).val().length % 15 ) && 1 > parseInt($("#post_ID").val(),10) )
 			setTimeout(autosave, 5000);
 	});
-}
-addLoadEvent(autosave_start_timer)
+});
 
-function autosave_cur_time() {
-	var now = new Date();
-	return "" + ((now.getHours() >12) ? now.getHours() -12 : now.getHours()) + 
-	((now.getMinutes() < 10) ? ":0" : ":") + now.getMinutes() +
-	((now.getSeconds() < 10) ? ":0" : ":") + now.getSeconds();
+// called when autosaving pre-existing post
+function autosave_saved(response) {
+	var res = wpAjax.parseAjaxResponse(response, 'autosave'); // parse the ajax response
+	var message = '';
+
+	if ( res && res.responses.length ) {
+		message = res.responses[0].data; // The saved message or error.
+		// someone else is editing: disable autosave, set errors
+		if ( res.responses[0].supplemental && 'disable' == res.responses[0].supplemental['disable_autosave'] ) {
+			autosave = function() {};
+			res = { errors: true };
+		}
+
+		// if no errors: add preview link and slug UI
+		if ( !res.errors ) {
+			var postID = parseInt( res.responses[0].id );
+			if ( !isNaN(postID) && postID > 0 ) {
+				autosave_update_preview_link(postID);
+				autosave_update_slug(postID);
+			}
+		}
+	}
+	if ( message ) { jQuery('#autosave').html(message); } // update autosave message
+	autosave_enable_buttons(); // re-enable disabled form buttons
+	return res;
 }
 
+// called when autosaving new post
 function autosave_update_post_ID(response) {
-	var res = parseInt(response);
-	var message;
+	var res = autosave_saved(response); // parse the ajax response do the above
 
-	if(isNaN(res)) {
-		message = autosaveL10n.errorText.replace(/%response%/g, response);
-	} else if( res > 0 ) {
-		message = autosaveL10n.saveText.replace(/%time%/g, autosave_cur_time());
-		jQuery('#post_ID').attr({name: "post_ID"});
-		jQuery('#post_ID').val(res);
-		// We need new nonces
-		jQuery.post(autosaveL10n.requestFile, {
-			action: "autosave-generate-nonces",
-			post_ID: res,
-			autosavenonce: jQuery('#autosavenonce').val(),
-			post_type: jQuery('#post_type').val()
-		}, function(html) {
-			jQuery('#_wpnonce').val(html);
-		});
-		jQuery('#hiddenaction').val('editpost');
-	} else {
-		message = autosaveL10n.failText;
+	// if no errors: update post_ID from the temporary value, grab new save-nonce for that new ID
+	if ( res && res.responses.length && !res.errors ) {
+		var postID = parseInt( res.responses[0].id );
+		if ( !isNaN(postID) && postID > 0 ) {
+			if ( postID == parseInt(jQuery('#post_ID').val()) ) { return; } // no need to do this more than once
+			jQuery('#post_ID').attr({name: "post_ID"});
+			jQuery('#post_ID').val(postID);
+			// We need new nonces
+			jQuery.post(autosaveL10n.requestFile, {
+				action: "autosave-generate-nonces",
+				post_ID: postID,
+				autosavenonce: jQuery('#autosavenonce').val(),
+				post_type: jQuery('#post_type').val()
+			}, function(html) {
+				jQuery('#_wpnonce').val(html);
+			});
+			jQuery('#hiddenaction').val('editpost');
+		}
 	}
-	jQuery('#autosave').html(message);
-	autosave_update_preview_link(res);
-	autosave_update_slug(res);
-	autosave_enable_buttons();
 }
 
 function autosave_update_preview_link(post_id) {
 	// Add preview button if not already there
-	if ( ! jQuery('#previewview > *').get()[0] ) {
+	if ( !jQuery('#previewview > *').size() ) {
 		var post_type = jQuery('#post_type').val();
 		var previewText = 'page' == post_type ? autosaveL10n.previewPageText : autosaveL10n.previewPostText;
 		jQuery.post(autosaveL10n.requestFile, {
@@ -74,79 +84,70 @@
 
 function autosave_update_slug(post_id) {
 	// create slug area only if not already there
-	if ( 'undefined' != typeof make_slugedit_clickable && ! jQuery('#edit-slug-box > *').get()[0] ) {
-		jQuery.post(slugL10n.requestFile, {
-			action: 'sample-permalink',
-			post_id: post_id,
-			samplepermalinknonce: jQuery('#samplepermalinknonce').val()}, function(data) {
+	if ( jQuery.isFunction(make_slugedit_clickable) && !jQuery('#edit-slug-box > *').size() ) {
+		jQuery.post(
+			slugL10n.requestFile,
+			{
+				action: 'sample-permalink',
+				post_id: post_id,
+				samplepermalinknonce: jQuery('#samplepermalinknonce').val()
+			},
+			function(data) {
 				jQuery('#edit-slug-box').html(data);
 				make_slugedit_clickable();
-			});
+			}
+		);
 	}
 }
 
 function autosave_loading() {
-	jQuery('#autosave').html(autosaveL10n.savingText);
+	jQuery('#autosave').html('<div class="updated"><p>' + autosaveL10n.savingText + '</p></div>');
 }
 
-function autosave_saved(response) {
-	var res = parseInt(response);
-	var message;
-
-	if(isNaN(res)) {
-		message = autosaveL10n.errorText.replace(/%response%/g, response);
-	} else {
-		message = autosaveL10n.saveText.replace(/%time%/g, autosave_cur_time());
-	}
-	jQuery('#autosave').html(message);
-	autosave_update_preview_link(res);
-	autosave_update_slug(res);
-	autosave_enable_buttons();
+function autosave_enable_buttons() {
+	jQuery("#submitpost :button:disabled, #submitpost :submit:disabled").attr('disabled', '');
 }
 
 function autosave_disable_buttons() {
-	jQuery("#post #save:enabled").attr('disabled', 'disabled');
-	jQuery("#post #submit:enabled").attr('disabled', 'disabled');
-	jQuery("#post #publish:enabled").attr('disabled', 'disabled');
-	jQuery("#post #deletepost:enabled").attr('disabled', 'disabled');
-	setTimeout('autosave_enable_buttons();', 1000); // Re-enable 1 sec later.  Just gives autosave a head start to avoid collisions.
+	jQuery("#submitpost :button:enabled, #submitpost :submit:enabled").attr('disabled', 'disabled');
+	setTimeout(autosave_enable_buttons, 1000); // Re-enable 1 sec later.  Just gives autosave a head start to avoid collisions.
 }
 
-function autosave_enable_buttons() {
-	jQuery("#post #save:disabled").attr('disabled', '');
-	jQuery("#post #submit:disabled").attr('disabled', '');
-	jQuery("#post #publish:disabled").attr('disabled', '');
-	jQuery("#post #deletepost:disabled").attr('disabled', '');
-}
-
-function autosave() {
-	var rich = ( (typeof tinyMCE != "undefined") && tinyMCE.activeEditor && ! tinyMCE.activeEditor.isHidden() ) ? true : false;
+var autosave = function() {
+	// (bool) is rich editor enabled and active
+	var rich = (typeof tinyMCE != "undefined") && tinyMCE.activeEditor && !tinyMCE.activeEditor.isHidden();
 	var post_data = {
-			action: "autosave",
-			post_ID:  jQuery("#post_ID").val() || 0,
-			post_title: jQuery("#title").val() || "",
-			autosavenonce: jQuery('#autosavenonce').val(),
-			tags_input: jQuery("#tags-input").val() || "",
-			post_type: jQuery('#post_type').val() || ""
-		};
+		action: "autosave",
+		post_ID:  jQuery("#post_ID").val() || 0,
+		post_title: jQuery("#title").val() || "",
+		autosavenonce: jQuery('#autosavenonce').val(),
+		tags_input: jQuery("#tags-input").val() || "",
+		post_type: jQuery('#post_type').val() || "",
+		autosave: 1
+	};
 
+	// We always send the ajax request in order to keep the post lock fresh.
+	// This (bool) tells whether or not to write the post to the DB during the ajax request.
+	var doAutoSave = true;
+
 	/* Gotta do this up here so we can check the length when tinyMCE is in use */
-	if ( rich ) {
-		// Don't run while the TinyMCE spellcheck is on.
-		if ( tinyMCE.activeEditor.plugins.spellchecker && tinyMCE.activeEditor.plugins.spellchecker.active ) return;
-		tinyMCE.triggerSave();
-	} 
+	if ( rich ) { tinyMCE.triggerSave(); }
 	
 	post_data["content"] = jQuery("#content").val();
 	if ( jQuery('#post_name').val() )
 		post_data["post_name"] = jQuery('#post_name').val();
 
+	// Nothing to save or no change.
 	if(post_data["post_title"].length==0 || post_data["content"].length==0 || post_data["post_title"] + post_data["content"] == autosaveLast) {
-		return;
+		doAutoSave = false
 	}
 
 	autosave_disable_buttons();
 
+	var origStatus = jQuery('#original_post_status').val();
+	if ( 'draft' != origStatus ) // autosave currently only turned on for drafts
+		doAutoSave = false;
+
 	autosaveLast = jQuery("#title").val()+jQuery("#content").val();
 	goodcats = ([]);
 	jQuery("[@name='post_category[]']:checked").each( function(i) {
@@ -161,25 +162,27 @@
 	if( jQuery("#excerpt"))
 		post_data["excerpt"] = jQuery("#excerpt").val();
 
-	if ( rich ) 
-        tinyMCE.triggerSave();
-    
-	post_data["content"] = jQuery("#content").val();
+	// Don't run while the TinyMCE spellcheck is on.  Why?  Who knows.
+	if ( rich && tinyMCE.activeEditor.plugins.spellchecker && tinyMCE.activeEditor.plugins.spellchecker.active ) {
+		doAutoSave = false;
+	}
 
 	if(parseInt(post_data["post_ID"]) < 1) {
 		post_data["temp_ID"] = post_data["post_ID"];
-		jQuery.ajaxSetup({
-			success: function(html) { autosave_update_post_ID(html); }
-		});
+		var successCallback = autosave_update_post_ID; // new post
 	} else {
-		jQuery.ajaxSetup({
-			success: function(html) { autosave_saved(html); }
-		});
+		var successCallback = autosave_saved; // pre-existing post
 	}
+
+	if ( !doAutoSave ) {
+		post_data['autosave'] = 0;
+	}
+
 	jQuery.ajax({
 		data: post_data,
-		beforeSend: function() { autosave_loading() },
+		beforeSend: doAutoSave ? autosave_loading : null,
 		type: "POST",
-		url: autosaveL10n.requestFile
+		url: autosaveL10n.requestFile,
+		success: successCallback
 	});
 }
Index: wp-includes/js/wp-lists.js
===================================================================
--- wp-includes/js/wp-lists.js	(revision 7102)
+++ wp-includes/js/wp-lists.js	(working copy)
@@ -2,46 +2,6 @@
 var currentFormEl = false;
 var fs = {add:'ajaxAdd',del:'ajaxDel',dim:'ajaxDim',process:'process',recolor:'recolor'};
 
-wpAjax = {
-	unserialize: function( s ) {
-		var r = {}; if ( !s ) { return r; }
-		var q = s.split('?'); if ( q[1] ) { s = q[1]; }
-		var pp = s.split('&');
-		for ( var i in pp ) {
-			if ( $.isFunction(pp.hasOwnProperty) && !pp.hasOwnProperty(i) ) { continue; }
-			var p = pp[i].split('=');
-			r[p[0]] = p[1];
-		}
-		return r;
-	},
-	parseAjaxResponse: function( x, r, e ) { // 1 = good, 0 = strange (bad data?), -1 = you lack permission
-		var re = $('#' + r).html('');
-		if ( x && typeof x == 'object' && x.getElementsByTagName('wp_ajax') ) {
-			var errs = $('wp_error', x);
-			if ( errs.size() ) {
-				var err = '';
-				errs.each( function() {
-					var code = $(this).attr('code');
-					if ( formField = $('wp_error_data[code="' + code + '"] form-field', x).text() )
-						code = formField;
-					wpAjax.invalidateForm( $('#' + e + ' :input[name="' + code + '"]' ).parents('.form-field:first') );
-					err += '<p>' + this.firstChild.nodeValue + '</p>';
-				} );
-				return !re.html( '<div class="error">' + err + '</div>' );
-			}
-			return true;
-		}
-		if ( isNaN(x) ) { return !re.html('<div class="error"><p>' + x + '</p></div>'); }
-		x = parseInt(x,10);
-		if ( -1 == x ) { return !re.html('<div class="error"><p>You do not have permission to do that.</p></div>'); }
-		else if ( 0 === x ) { return !re.html('<div class="error"><p>AJAX is teh b0rked.</p></div>'); }
-		return true;
-	},
-	invalidateForm: function( jQ ) {
-		jQ.addClass( 'form-invalid' ).change( function() { $(this).removeClass( 'form-invalid' ); } );
-	}
-};
-
 var wpList = {
 	settings: {
 		url: wpListL10n.url, type: 'POST',
@@ -127,21 +87,21 @@
 		if ( !s.data.match(/_ajax_nonce=[a-f0-9]+/) ) { return true; }
 
 		s.success = function(r) {
-			if ( !wpAjax.parseAjaxResponse(r, s.response, s.element) ) { return false; }
+			var res = wpAjax.parseAjaxResponse(r, s.response, s.element);
+			if ( !res || res.errors ) { return false; }
 
-			$(s.what + ' response_data', r).each( function() {
-				var t = $(this);
-				wpList.add.call( list, t.text(), $.extend( {}, s, { // this.firstChild.nodevalue
-					pos: t.parent().attr( 'position' ) || 0,
-					id: t.parent().attr( 'id' ) || 0,
-					oldId: t.parent().attr( 'old_id' ) || null
+			jQuery.each( res.responses, function() {
+				wpList.add.call( list, this.data, $.extend( {}, s, { // this.firstChild.nodevalue
+					pos: this.position || 0,
+					id: this.id || 0,
+					oldId: this.oldId || null
 				} ) );
 			} );
 
 			if ( $.isFunction(s.addAfter) ) {
 				var o = this.complete;
 				this.complete = function(x,st) {
-					var _s = $.extend( { xml: x, status: st }, s );
+					var _s = $.extend( { xml: x, status: st, parsed: res }, s );
 					s.addAfter( r, _s );
 					if ( $.isFunction(o) ) { o(x,st); }
 				};
@@ -194,7 +154,8 @@
 		}
 
 		s.success = function(r) {
-			if ( !wpAjax.parseAjaxResponse(r, s.response, s.element) ) {
+			var res = wpAjax.parseAjaxResponse(r, s.response, s.element);
+			if ( !res || res.errors ) {
 				element.stop().css( 'backgroundColor', '#FF3333' ).show().queue( function() { list.wpList.recolor(); $(this).dequeue(); } );
 				return false;
 			}
@@ -202,7 +163,7 @@
 				var o = this.complete;
 				this.complete = function(x,st) {
 					element.queue( function() {
-						var _s = $.extend( { xml: x, status: st }, s );
+						var _s = $.extend( { xml: x, status: st, parsed: res }, s );
 						s.delAfter( r, _s );
 						if ( $.isFunction(o) ) { o(x,st); }
 					} ).dequeue();
@@ -256,7 +217,8 @@
 		if ( !s.data._ajax_nonce ) { return true; }
 
 		s.success = function(r) {
-			if ( !wpAjax.parseAjaxResponse(r, s.response, s.element) ) {
+			var res = wpAjax.parseAjaxResponse(r, s.response, s.element);
+			if ( !res || res.errors ) {
 				element.stop().css( 'backgroundColor', '#FF3333' )[isClass?'removeClass':'addClass'](s.dimClass).show().queue( function() { list.wpList.recolor(); $(this).dequeue(); } );
 				return false;
 			}
@@ -264,7 +226,7 @@
 				var o = this.complete;
 				this.complete = function(x,st) {
 					element.queue( function() {
-						var _s = $.extend( { xml: x, status: st }, s );
+						var _s = $.extend( { xml: x, status: st, parsed: res }, s );
 						s.dimAfter( r, _s );
 						if ( $.isFunction(o) ) { o(x,st); }
 					} ).dequeue();
Index: wp-includes/js/wp-ajax-response.js
===================================================================
--- wp-includes/js/wp-ajax-response.js	(revision 0)
+++ wp-includes/js/wp-ajax-response.js	(revision 0)
@@ -0,0 +1,56 @@
+wpAjax = jQuery.extend( {
+	unserialize: function( s ) {
+		var r = {}; if ( !s ) { return r; }
+		var q = s.split('?'); if ( q[1] ) { s = q[1]; }
+		var pp = s.split('&');
+		for ( var i in pp ) {
+			if ( jQuery.isFunction(pp.hasOwnProperty) && !pp.hasOwnProperty(i) ) { continue; }
+			var p = pp[i].split('=');
+			r[p[0]] = p[1];
+		}
+		return r;
+	},
+	parseAjaxResponse: function( x, r, e ) { // 1 = good, 0 = strange (bad data?), -1 = you lack permission
+		var parsed = {};
+		var re = jQuery('#' + r).html('');
+		if ( x && typeof x == 'object' && x.getElementsByTagName('wp_ajax') ) {
+			parsed.responses = [];
+			parsed.errors = false;
+			var err = '';
+			jQuery('response', x).each( function() {
+				var th = jQuery(this);
+				var child = jQuery(this.firstChild);
+				var response = { action: th.attr('action'), what: child.get(0).nodeName, id: child.attr('id'), oldId: child.attr('old_id'), position: child.attr('position') };
+				response.data = jQuery( 'response_data', child ).text();
+				response.supplemental = {};
+				if ( !jQuery( 'supplemental', child ).children().each( function() {
+					response.supplemental[this.nodeName] = jQuery(this).text();
+				} ).size() ) { response.supplemental = false }
+				response.errors = [];
+				if ( !jQuery('wp_error', child).each( function() {
+					var code = jQuery(this).attr('code');
+					var anError = { code: code, message: this.firstChild.nodeValue, data: false };
+					var errorData = jQuery('wp_error_data[code="' + code + '"]', x);
+					if ( errorData ) { anError.data = errorData.get(); }
+					var formField = jQuery( 'form-field', errorData ).text();
+					if ( formField ) { code = formField; }
+					if ( e ) { wpAjax.invalidateForm( jQuery('#' + e + ' :input[name="' + code + '"]' ).parents('.form-field:first') ); }
+					err += '<p>' + anError.message + '</p>';
+					response.errors.push( anError );
+					parsed.errors = true;
+				} ).size() ) { response.errors = false; }
+				parsed.responses.push( response );
+			} );
+			if ( err.length ) { re.html( '<div class="error">' + err + '</div>' ); }
+			return parsed;
+		}
+		if ( isNaN(x) ) { return !re.html('<div class="error"><p>' + x + '</p></div>'); }
+		x = parseInt(x,10);
+		if ( -1 == x ) { return !re.html('<div class="error"><p>' + this.noPerm + '</p></div>'); }
+		else if ( 0 === x ) { return !re.html('<div class="error"><p>' + this.broken  + '</p></div>'); }
+		return true;
+	},
+	invalidateForm: function( jQ ) {
+		jQ.addClass( 'form-invalid' ).change( function() { jQuery(this).removeClass( 'form-invalid' ); } );
+	}
+}, wpAjax || { noPerm: 'You do not have permission to do that.', broken: 'AJAX is teh b0rked.' } );
Index: wp-includes/classes.php
===================================================================
--- wp-includes/classes.php	(revision 7102)
+++ wp-includes/classes.php	(working copy)
@@ -777,9 +777,11 @@
 		}
 
 		$s = '';
-		if ( (array) $supplemental )
+		if ( (array) $supplemental ) {
 			foreach ( $supplemental as $k => $v )
 				$s .= "<$k><![CDATA[$v]]></$k>";
+			$s = "<supplemental>$s</supplemental>";
+		}
 
 		if ( false === $action )
 			$action = $_POST['action'];
Index: wp-includes/script-loader.php
===================================================================
--- wp-includes/script-loader.php	(revision 7102)
+++ wp-includes/script-loader.php	(working copy)
@@ -41,16 +41,19 @@
 		
 		$this->add( 'prototype', '/wp-includes/js/prototype.js', false, '1.6');
 
-		$this->add( 'autosave', '/wp-includes/js/autosave.js', array('jquery', 'schedule'), '20080221');
+		$this->add( 'wp-ajax-response', '/wp-includes/js/wp-ajax-response.js', array('jquery'), '20080229' . mt_rand() );
+		$this->localize( 'wp-ajax-response', 'wpAjax', array(
+			'noPerm' => 'You do not have permission to do that.',
+			'broken' => 'AJAX is teh b0rked.'
+		) );
+
+		$this->add( 'autosave', '/wp-includes/js/autosave.js', array('schedule', 'wp-ajax-response'), '20080221' . mt_rand());
 		$this->localize( 'autosave', 'autosaveL10n', array(
-			'autosaveInterval' => apply_filters('autosave_interval', '60'),
-			'errorText' => __('Error: %response%'),
-			'failText' => __('Error: Autosave Failed.'),
-			'previewPageText' => __('Preview this Page'),
-			'previewPostText' => __('Preview this Post'),
-			'saveText' => __('Saved at %time%.'),
+			'autosaveInterval' => get_option( 'autosave_interval' ),
+			'previewPageText' => __('View this Page'),
+			'previewPostText' => __('View this Post'),
 			'requestFile' => get_option( 'siteurl' ) . '/wp-admin/admin-ajax.php',
-			'savingText' => __('Saving Draft...')
+			'savingText' => __('Saving&#8230;')
 		) );
 
 		$this->add( 'wp-ajax', '/wp-includes/js/wp-ajax.js', array('prototype'), '20070306');
@@ -61,7 +64,7 @@
 			'whoaText' => __("Slow down, I'm still sending your data!")
 		) );
 
-		$this->add( 'wp-lists', '/wp-includes/js/wp-lists.js', array('jquery'), '20080228' );
+		$this->add( 'wp-lists', '/wp-includes/js/wp-lists.js', array('wp-ajax-response'), '20080228' . mt_rand());
 		$this->localize( 'wp-lists', 'wpListL10n', array(
 			'url' => get_option( 'siteurl' ) . '/wp-admin/admin-ajax.php'
 		) );
Index: wp-admin/admin-ajax.php
===================================================================
--- wp-admin/admin-ajax.php	(revision 7102)
+++ wp-admin/admin-ajax.php	(working copy)
@@ -470,6 +470,8 @@
 	break;
 case 'autosave' : // The name of this action is hardcoded in edit_post()
 	check_ajax_referer( 'autosave', 'autosavenonce' );
+	global $current_user;
+
 	$_POST['post_content'] = $_POST['content'];
 	$_POST['post_excerpt'] = $_POST['excerpt'];
 	$_POST['post_status'] = 'draft';
@@ -478,17 +480,36 @@
 	if($_POST['post_type'] == 'page' || empty($_POST['post_category']))
 		unset($_POST['post_category']);
 
+	$do_autosave = (bool) $_POST['autosave'];
+	$do_lock = true;
+
+	$data = '<div class="updated"><p>' . sprintf( __('Saved at %s.'), date( __('g:i:s a'), current_time( 'timestamp', true ) ) ) . '</p></div>';
+
+	$supplemental = array();
+
+	$id = 0;
 	if($_POST['post_ID'] < 0) {
 		$_POST['temp_ID'] = $_POST['post_ID'];
-		$id = wp_write_post();
-		if( is_wp_error($id) )
-			die($id->get_error_message());
-		else
-			die("$id");
+		if ( $do_autosave )
+			$id = wp_write_post();
 	} else {
 		$post_ID = (int) $_POST['post_ID'];
 		$_POST['ID'] = $post_ID;
 		$post = get_post($post_ID);
+
+		if ( $last = wp_check_post_lock( $post->ID ) ) {
+			$do_autosave = $do_lock = false;
+
+			$last_user = get_userdata( $last );
+			$last_user_name = $last_user ? $last_user->display_name : __( 'Someone' );
+			$data = new WP_Error( 'locked', sprintf(
+				$_POST['post_type'] == 'page' ? __( 'Autosave disabled: %s is currently editing this page.' ) : __( 'Autosave disabled: %s is currently editing this post.' ),
+				wp_specialchars( $last_user_name )
+			) );
+
+			$supplemental['disable_autosave'] = 'disable';
+		}
+
 		if ( 'page' == $post->post_type ) {
 			if ( !current_user_can('edit_page', $post_ID) )
 				die(__('You are not allowed to edit this page.'));
@@ -496,10 +517,23 @@
 			if ( !current_user_can('edit_post', $post_ID) )
 				die(__('You are not allowed to edit this post.'));
 		}
-		wp_update_post($_POST);
+		if ( $do_autosave )
+			$id = wp_update_post($_POST);
+		else
+			$id = $post->ID;
 	}
-	die('0');
-break;
+
+	if ( $do_lock && $id && is_numeric($id) )
+		wp_set_post_lock( $id );
+
+	$x = new WP_Ajax_Response( array(
+		'what' => 'autosave',
+		'id' => $id,
+		'data' => $id ? $data : '',
+		'supplemental' => $supplemental
+	) );
+	$x->send();
+	break;
 case 'autosave-generate-nonces' :
 	check_ajax_referer( 'autosave', 'autosavenonce' );
 	$ID = (int) $_POST['post_ID'];
Index: wp-admin/wp-admin.css
===================================================================
--- wp-admin/wp-admin.css	(revision 7102)
+++ wp-admin/wp-admin.css	(working copy)
@@ -1033,6 +1033,15 @@
 	margin-right: 8px;
 }
 
+#poststuff #autosave {
+	margin: 0;
+	padding: 0;
+}
+
+#poststuff #autosave div.updated, #poststuff #autosave div.error {
+	margin: 0 8px 10px 20px;
+}
+
 #poststuff .inside {
 	margin: 0 12px 15px;
 	font-size: 11px;
@@ -1406,4 +1415,4 @@
 
 #the-comment-list td.comment p {
 	margin-left: 8px;
-}
\ No newline at end of file
+}
Index: wp-admin/includes/post.php
===================================================================
--- wp-admin/includes/post.php	(revision 7102)
+++ wp-admin/includes/post.php	(working copy)
@@ -18,8 +18,7 @@
 		$post =& get_post( $post_ID );
 		$now = time();
 		$then = strtotime($post->post_date_gmt . ' +0000');
-		// Keep autosave_interval in sync with autosave-js.php.
-		$delta = apply_filters( 'autosave_interval', 120 ) / 2;
+		$delta = get_option( 'autosave_interval' ) / 2;
 		if ( ($now - $then) < $delta )
 			return $post_ID;
 	}
@@ -619,4 +618,37 @@
 	return $return;
 }
 
+// false: not locked or locked by current user
+// int: user ID of user with lock
+function wp_check_post_lock( $post_id ) {
+	global $current_user;
+
+	if ( !$post = get_post( $post_id ) )
+		return false;
+
+	$lock = get_post_meta( $post->ID, '_edit_lock', true );
+	$last = get_post_meta( $post->ID, '_edit_last', true );
+
+	$time_window = apply_filters( 'wp_check_post_lock_window', get_option( 'autosave_interval' ) * 2 );
+
+	if ( $lock && $lock > time() - $time_window && $last != $current_user->ID )
+		return $last;
+	return false;
+}
+
+function wp_set_post_lock( $post_id ) {
+	global $current_user;
+	if ( !$post = get_post( $post_id ) )
+		return false;
+	if ( !$current_user || !$current_user->ID )
+		return false;
+	
+	$now = time();
+
+	if ( !add_post_meta( $post->ID, '_edit_lock', $now, true ) )
+		update_post_meta( $post->ID, '_edit_lock', $now );
+	if ( !add_post_meta( $post->ID, '_edit_last', $current_user->ID, true ) )
+		update_post_meta( $post->ID, '_edit_last', $current_user->ID );
+}
+
 ?>
Index: wp-admin/includes/upgrade.php
===================================================================
--- wp-admin/includes/upgrade.php	(revision 7102)
+++ wp-admin/includes/upgrade.php	(working copy)
@@ -198,7 +198,7 @@
 	if ( $wp_current_db_version < 6124 )
 		upgrade_230_old_tables();
 
-	if ( $wp_current_db_version < 6689 )
+	if ( $wp_current_db_version < 7098 )
 		upgrade_250();
 
 	maybe_disable_automattic_widgets();
@@ -725,6 +725,8 @@
 	if ( $wp_current_db_version < 6689 ) {
 		populate_roles_250();
 	}
+
+	add_option('autosave_interval', 60);
 }
 
 // The functions we use to actually do stuff
Index: wp-admin/post.php
===================================================================
--- wp-admin/post.php	(revision 7102)
+++ wp-admin/post.php	(working copy)
@@ -66,9 +66,16 @@
 		wp_enqueue_script('editor');
 	wp_enqueue_script('thickbox');
 	wp_enqueue_script('media-upload');
-
-	if ( 'draft' == $post->post_status )
+	if ( $last = wp_check_post_lock( $post->ID ) ) {
+		$last_user = get_userdata( $last );
+		$last_user_name = $last_user ? $last_user->display_name : __('Somebody');
+		$message = sprintf( __( '%s is currently editing this post' ), wp_specialchars( $last_user_name ) );
+		$message = str_replace( "'", "\'", "<div class='error'><p>$message</p></div>" );
+		add_action('admin_notices', create_function( '', "echo '$message';" ) );
+	} else {
+		wp_set_post_lock( $post->ID );
 		wp_enqueue_script('autosave');
+	}
 
 	require_once('admin-header.php');
 
Index: wp-admin/edit-page-form.php
===================================================================
--- wp-admin/edit-page-form.php	(revision 7102)
+++ wp-admin/edit-page-form.php	(working copy)
@@ -36,6 +36,7 @@
 <input type="hidden" id="originalaction" name="originalaction" value="<?php echo $form_action ?>" />
 <?php echo $form_extra ?>
 <input type="hidden" id="post_type" name="post_type" value="<?php echo $post->post_type ?>" />
+<input type="hidden" id="original_post_status" name="original_post_status" value="<?php echo $post->post_status ?>" />
 <input name="referredby" type="hidden" id="referredby" value="<?php
 if ( url_to_postid(wp_get_referer()) == $post_ID )
 	echo 'redo';
@@ -169,12 +170,8 @@
 <?php wp_nonce_field( 'samplepermalink', 'samplepermalinknonce', false ); ?>
 </div>
 
-<p class="submit">
+<div id="autosave"></div>
 
-<span id="autosave"></span>
-
-</p>
-
 <?php do_meta_boxes('page', 'normal', $post); ?>
 
 <?php do_action('edit_page_form'); ?>
Index: wp-admin/edit-form-advanced.php
===================================================================
--- wp-admin/edit-form-advanced.php	(revision 7102)
+++ wp-admin/edit-form-advanced.php	(working copy)
@@ -55,6 +55,15 @@
 <input type="hidden" id="originalaction" name="originalaction" value="<?php echo $form_action ?>" />
 <input type="hidden" name="post_author" value="<?php echo attribute_escape( $post->post_author ); ?>" />
 <input type="hidden" id="post_type" name="post_type" value="<?php echo $post->post_type ?>" />
+<input type="hidden" id="original_post_status" name="original_post_status" value="<?php echo $post->post_status ?>" />
+<input name="referredby" type="hidden" id="referredby" value="<?php
+if ( !empty($_REQUEST['popupurl']) )
+	echo clean_url(stripslashes($_REQUEST['popupurl']));
+else if ( url_to_postid(wp_get_referer()) == $post_ID )
+	echo 'redo';
+else
+	echo clean_url(stripslashes(wp_get_referer()));
+?>" />
 
 <?php echo $form_extra ?>
 <?php if ((isset($post->post_title) && '' == $post->post_title) || (isset($_GET['message']) && 2 > $_GET['message'])) : ?>
@@ -189,20 +198,8 @@
 <?php echo $form_pingback ?>
 <?php echo $form_prevstatus ?>
 
-<p class="submit">
+<div id="autosave"></div>
 
-<span id="autosave"></span>
-
-
-<input name="referredby" type="hidden" id="referredby" value="<?php
-if ( !empty($_REQUEST['popupurl']) )
-	echo clean_url(stripslashes($_REQUEST['popupurl']));
-else if ( url_to_postid(wp_get_referer()) == $post_ID )
-	echo 'redo';
-else
-	echo clean_url(stripslashes(wp_get_referer()));
-?>" /></p>
-
 <div id="tagsdiv" class="postbox <?php echo postbox_classes('tagsdiv', 'post'); ?>">
 <h3><?php _e('Tags'); ?></h3>
 <div class="inside">
Index: wp-admin/page.php
===================================================================
--- wp-admin/page.php	(revision 7102)
+++ wp-admin/page.php	(working copy)
@@ -57,9 +57,16 @@
 		wp_enqueue_script('editor');
 	wp_enqueue_script('thickbox');
 	wp_enqueue_script('media-upload');
-
-	if ( 'draft' == $post->post_status )
+	if ( $last = wp_check_post_lock( $post->ID ) ) {
+		$last_user = get_userdata( $last );
+		$last_user_name = $last_user ? $last_user->display_name : __('Somebody');
+		$message = sprintf( __( '%s is currently editing this page' ), wp_specialchars( $last_user_name ) );
+		$message = str_replace( "'", "\'", "<div class='error'><p>$message</p></div>" );
+		add_action('admin_notices', create_function( '', "echo '$message';" ) );
+	} else {
+		wp_set_post_lock( $post->ID );
 		wp_enqueue_script('autosave');
+	}
 
 	require_once('admin-header.php');
 
