Index: wp-admin/admin-ajax.php
===================================================================
--- wp-admin/admin-ajax.php	(revision 12285)
+++ wp-admin/admin-ajax.php	(working copy)
@@ -220,6 +220,10 @@
 		if ( 'spam' == $status )
 			die( (string) time() );
 		$r = wp_set_comment_status( $comment->comment_ID, 'spam' );
+	} elseif ( isset($_POST['unspam']) && ( 0 == $_POST['unspam'] || 1 == $_POST['unspam'] ) ) {
+		if ( 'spam' != $status )
+			die( (string) time() );
+		$r = wp_set_comment_status( $comment->comment_ID, $_POST['unspam'] );
 	} elseif ( isset($_POST['delete']) && 1 == $_POST['delete'] ) {
 		$r = wp_delete_comment( $comment->comment_ID );
 	} else {
Index: wp-admin/includes/template.php
===================================================================
--- wp-admin/includes/template.php	(revision 12285)
+++ wp-admin/includes/template.php	(working copy)
@@ -2371,9 +2371,12 @@
  */
 function wp_comment_trashnotice() {
 ?>
-<div class="hidden" id="undo-holder">
-<div class="trash-undo-inside"><?php _e('Comment by'); ?> <strong></strong> <?php _e('moved to the trash.'); ?> <span class="untrash"><a class="undo-trash" href="#"><?php _e('Undo'); ?></a></span></div>
+<div class="hidden" id="trash-undo-holder">
+	<div class="trash-undo-inside"><?php printf(__('Comment by %s moved to the trash.'), '<strong></strong>'); ?> <span class="undo untrash"><a href="#"><?php _e('Undo'); ?></a></span></div>
 </div>
+<div class="hidden" id="spam-undo-holder">
+	<div class="spam-undo-inside"><?php printf(__('Comment by %s marked as spam.'), '<strong></strong>'); ?> <span class="undo unspam"><a href="#"><?php _e('Undo'); ?></a></span></div>
+</div>
 <?php
 }
 
Index: wp-admin/js/edit-comments.dev.js
===================================================================
--- wp-admin/js/edit-comments.dev.js	(revision 12285)
+++ wp-admin/js/edit-comments.dev.js	(working copy)
@@ -38,11 +38,17 @@
 		settings.data._per_page = perPageInput.val() || 0;
 		settings.data._page = pageInput.val() || 0;
 		settings.data._url = document.location.href;
+		
+		var action;
+		if ( cl.indexOf(':trash=1') != -1 )
+			action = 'trash';
+		else if ( cl.indexOf(':spam=1') != -1 )
+			action = 'spam';
 
-		if ( cl.indexOf(':trash=1') != -1 ) {
+		if ( action == 'trash' || action == 'spam' ) {
 			id = cl.replace(/.*?comment-([0-9]+).*/, '$1');
 			el = $('#comment-' + id);
-			note = $('#undo-holder').html();
+			note = $('#'+action+'-undo-holder').html();
 
 			if ( el.siblings('#replyrow').length && commentReply.cid == id )
 				commentReply.close();
@@ -50,23 +56,39 @@
 			if ( el.is('tr') ) {
 				n = el.children(':visible').length;
 				author = $('.author strong', el).text();
-				h = $('<tr id="trashundo-' + id + '" class="trash-undo" style="display:none;"><td colspan="' + n + '">' + note + '</td></tr>');
+				h = $('<tr id="undo-' + id + '" class="undo un' + action + '" style="display:none;"><td colspan="' + n + '">' + note + '</td></tr>');
 			} else {
 				author = $('.comment-author', el).text();
-				h = $('<div id="trashundo-' + id + '" style="display:none;" class="trash-undo">' + note + '</div>');
+				h = $('<div id="undo-' + id + '" style="display:none;" class="undo un' + action + '">' + note + '</div>');
 			}
 
 			el.before(h);
 
-			$('strong', '#trashundo-' + id).text(author + ' ');
-			a = $('a.undo-trash', '#trashundo-' + id);
-			a.attr('href', 'comment.php?action=untrashcomment&c=' + id + '&_ajax_nonce=' + settings.data._ajax_nonce);
-			a.attr('className', 'delete:the-comment-list:comment-' + id + '::untrash=1 vim-z vim-destructive');
-			$('.avatar', el).clone().prependTo('#trashundo-' + id + ' .trash-undo-inside');
+			$('strong', '#undo-' + id).text(author + ' ');
+			a = $('.undo a', '#undo-' + id);
+			if ( action == 'trash' ) {
+				a.attr('href', 'comment.php?action=untrashcomment&c=' + id + '&_wpnonce=' + settings.data._ajax_nonce);
+				a.attr('className', 'delete:the-comment-list:comment-' + id + '::untrash=1 vim-z vim-destructive');
+			}
+			else if ( action == 'spam' ) {
+				a.attr('href', 'comment.php?action=deletecomment&dt=unspam&s=' + ($(el).is('.approved') ? '1' : '0') + '&c=' + id + '&_wpnonce=' + settings.data._ajax_nonce);
+				a.attr('className', 'delete:the-comment-list:comment-' + id + '::unspam=' + ($(el).is('.approved') ? '1' : '0') + ' vim-z vim-destructive');
+/*
+				if ( $(el).is('.approved') ) {
+					a.attr('href', $('.approve a', el).attr('href'));
+					a.attr('className', $('.approve a', el).attr('className'));
+				}
+				else {
+					a.attr('href', $('.unapprove a', el).attr('href'));
+					a.attr('className', $('.unapprove a', el).attr('className'));
+				}
+*/
+			}
+			$('.avatar', el).clone().prependTo('#undo-' + id + ' .' + action + '-undo-inside');
 
 			a.click(function(){
 				list.wpList.del(this);
-				$('#trashundo-' + id).fadeOut(300, function(){
+				$('#undo-' + id).fadeOut(300, function(){
 					$(this).remove();
 					$('#comment-' + id).css('backgroundColor', '').fadeIn(300, function(){ $(this).show() });
 				});
@@ -135,7 +157,7 @@
 
 	// In admin-ajax.php, we send back the unix time stamp instead of 1 on success
 	delAfter = function( r, settings ) {
-		var total, pageLinks, N, untrash = $(settings.target).parent().is('span.untrash'), spam, trash;
+		var total, pageLinks, N, untrash = $(settings.target).parent().is('span.untrash'), unspam = $(settings.target).parent().is('span.unspam'), spam, trash;
 
 		function getUpdate(s) {
 			if ( $(settings.target).parent().is('span.' + s) )
@@ -150,11 +172,13 @@
 
 		if ( untrash )
 			trash = -1;
+		if ( unspam )
+			spam = -1;
 
 		$('span.pending-count').each( function() {
 			var a = $(this), n = getCount(a), unapproved = $('#' + settings.element).is('.unapproved');
 
-			if ( $(settings.target).parent().is('span.unapprove') || ( untrash && unapproved ) ) { // we "deleted" an approved comment from the approved list by clicking "Unapprove"
+			if ( $(settings.target).parent().is('span.unapprove') || ( (untrash||unspam) && unapproved ) ) { // we "deleted" an approved comment from the approved list by clicking "Unapprove"
 				n = n + 1;
 			} else if ( unapproved ) { // we deleted a formerly unapproved comment
 				n = n - 1;
@@ -212,8 +236,8 @@
 		.bind('wpListDelEnd', function(e, s){
 			var id = s.element.replace(/[^0-9]+/g, '');
 
-			if ( s.target.className.indexOf(':trash=1') != -1 )
-				$('#trashundo-' + id).fadeIn(300, function(){ $(this).show() });
+			if ( s.target.className.indexOf(':trash=1') != -1 || s.target.className.indexOf(':spam=1') != -1 )
+				$('#undo-' + id).fadeIn(300, function(){ $(this).show() });
 		});
 };
 
Index: wp-admin/comment.php
===================================================================
--- wp-admin/comment.php	(revision 12285)
+++ wp-admin/comment.php	(working copy)
@@ -153,6 +153,8 @@
 
 	if ( 'spam' == $_REQUEST['dt'] )
 		wp_set_comment_status( $comment->comment_ID, 'spam' );
+	elseif ( 'unspam' == $_REQUEST['dt'] && isset($_REQUEST['s']) )
+		wp_set_comment_status( $comment->comment_ID, $_REQUEST['s'] );
 	else
 		wp_delete_comment( $comment->comment_ID );
 
Index: wp-admin/wp-admin.dev.css
===================================================================
--- wp-admin/wp-admin.dev.css	(revision 12285)
+++ wp-admin/wp-admin.dev.css	(working copy)
@@ -3524,11 +3524,13 @@
 	font-size: 11px;
 }
 
-.trash-undo-inside {
+.trash-undo-inside,
+.spam-undo-inside {
 	margin: 1px 8px 1px 0;
 	line-height: 16px;
 }
 
+.spam-undo-inside .avatar,
 .trash-undo-inside .avatar {
 	height: 20px;
 	width: 20px;
