Index: wp-includes/user.php
===================================================================
--- wp-includes/user.php	(revision 23297)
+++ wp-includes/user.php	(working copy)
@@ -650,6 +650,90 @@
 }
 
 /**
+ * WordPress Pending User Query class.
+ *
+ * @since 3.6.0
+ */
+class WP_Pending_User_Query extends WP_User_Query {
+
+	public function prepare_query() {
+		global $wpdb;
+
+		$qv =& $this->query_vars;
+		$this->query_fields = "{$wpdb->signups}.*";
+
+		$this->query_from = "FROM {$wpdb->signups}";
+		$this->query_where = "WHERE 1=1 AND active != 1";
+
+		// sorting
+		if ( in_array( $qv['orderby'], array( 'nicename', 'email' ) ) ) {
+			$orderby = 'user_' . $qv['orderby'];
+		} elseif ( in_array( $qv['orderby'], array( 'user_email', 'registered' ) ) ) {
+			$orderby = $qv['orderby'];
+		} else {
+			$orderby = 'user_login';
+		}
+
+		$qv['order'] = strtoupper( $qv['order'] );
+		$order = 'ASC' == $qv['order'] ? 'ASC' : 'DESC';
+		$this->query_orderby = "ORDER BY $orderby $order";
+
+		// limit
+		if ( $qv['number'] ) {
+			if ( $qv['offset'] )
+				$this->query_limit = $wpdb->prepare( "LIMIT %d, %d", $qv['offset'], $qv['number'] );
+			else
+				$this->query_limit = $wpdb->prepare( "LIMIT %d", $qv['number'] );
+		}
+
+		$search = trim( $qv['search'] );
+		if ( $search ) {
+			$leading_wild = ( ltrim( $search, '*' ) != $search );
+			$trailing_wild = ( rtrim( $search, '*' ) != $search );
+
+			$wild = false;
+			if ( $leading_wild && $trailing_wild )
+				$wild = 'both';
+			elseif ( $leading_wild )
+				$wild = 'leading';
+			elseif ( $trailing_wild )
+				$wild = 'trailing';
+
+			if ( $wild )
+				$search = trim($search, '*');
+
+			if ( false !== strpos( $search, '@') )
+				$search_columns = array( 'user_email' );
+			else
+				$search_columns = array( 'user_login' );
+
+			$this->query_where .= $this->get_search_sql( $search, $search_columns, $wild );
+		}
+
+		$blog_id = absint( $qv['blog_id'] );
+
+		do_action_ref_array( 'pre_user_query', array( $this ) );
+	}
+
+	/**
+	 * Execute the query, with the current variables
+	 *
+	 * @since 3.6.0
+	 */
+	public function query() {
+		global $wpdb;
+
+		$this->results = $wpdb->get_results( "SELECT $this->query_fields $this->query_from $this->query_where $this->query_orderby $this->query_limit" );
+
+		if ( ! $this->results )
+			return;
+
+		if ( $this->query_vars['count_total'] )
+			$this->total_users = $wpdb->get_var( "SELECT COUNT(*) $this->query_from $this->query_where" );
+	}
+}
+
+/**
  * Retrieve list of users matching criteria.
  *
  * @since 3.1.0
Index: wp-includes/ms-functions.php
===================================================================
--- wp-includes/ms-functions.php	(revision 23297)
+++ wp-includes/ms-functions.php	(working copy)
@@ -128,10 +128,31 @@
  * @return int
  */
 function get_user_count() {
-	return get_site_option( 'user_count' );
+	$option = get_site_option( 'user_count' );
+	if ( is_numeric( $option ) )
+		return (int) $option;
+
+	return 0;
 }
 
 /**
+ * The number of pending users in your installation.
+ *
+ * The count is cached and updated twice daily. This is not a live count.
+ *
+ * @since 3.6
+ *
+ * @return int
+ */
+function get_pending_user_count() {
+	$option = get_site_option( 'pending_user_count' );
+	if ( is_numeric( $option ) )
+		return (int) $option;
+
+	return 0;
+}
+
+/**
  * The number of active sites on your installation.
  *
  * The count is cached and updated twice daily. This is not a live count.
@@ -926,6 +947,47 @@
 }
 
 /**
+ * Active user automatically after looking up via user_login
+ *
+ * @since 3.6.0
+ *
+ * @uses wpmu_activate_signup()
+ *
+ * @global wpdb $wpdb
+ *
+ * @param string $user_login
+ * @return array An array containing information about the activated user and/or blog
+ */
+function wp_activate_by_user_login( $user_login ) {
+	global $wpdb;
+
+	$key = $wpdb->get_var( $wpdb->prepare( "SELECT activation_key FROM {$wpdb->signups} WHERE active != 1 AND user_login = %s", $user_login ) );
+	if ( $key )
+	    return wpmu_activate_signup( $key );
+}
+
+/**
+ * Lookup signup and, when valid, resend the signup notification
+ *
+ * @since 3.6.0
+ *
+ * @uses wpmu_signup_user_notification()
+ *
+ * @global wpdb $wpdb
+ *
+ * @param string $user_login
+ * @return bool
+ */
+function wp_resend_by_user_login( $user_login ) {
+	global $wpdb;
+
+	$user = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->signups} WHERE active !=1 AND user_login = %s", $user_login ) );
+
+	if ( $user )
+	    return wpmu_signup_user_notification( $user->user_login, $user->user_email, $user->activation_key, $user->meta );
+}
+
+/**
  * Create a site.
  *
  * This function runs when a user self-registers a new site as well
@@ -1925,11 +1987,14 @@
 function wp_update_network_counts() {
 	global $wpdb;
 
-	$count = $wpdb->get_var( $wpdb->prepare("SELECT COUNT(blog_id) as c FROM $wpdb->blogs WHERE site_id = %d AND spam = '0' AND deleted = '0' and archived = '0'", $wpdb->siteid) );
+	$count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(blog_id) as c FROM $wpdb->blogs WHERE site_id = %d AND spam = '0' AND deleted = '0' and archived = '0'", $wpdb->siteid ) );
 	update_site_option( 'blog_count', $count );
 
 	$count = $wpdb->get_var( "SELECT COUNT(ID) as c FROM $wpdb->users WHERE spam = '0' AND deleted = '0'" );
 	update_site_option( 'user_count', $count );
+
+	$count = $wpdb->get_var( "SELECT COUNT(user_login) AS c FROM $wpdb->signups WHERE active != 1" );
+	update_site_option( 'pending_user_count', $count );
 }
 
 /**
Index: wp-admin/includes/class-wp-ms-users-list-table.php
===================================================================
--- wp-admin/includes/class-wp-ms-users-list-table.php	(revision 23297)
+++ wp-admin/includes/class-wp-ms-users-list-table.php	(working copy)
@@ -58,8 +58,10 @@
 
 		$mode = empty( $_REQUEST['mode'] ) ? 'list' : $_REQUEST['mode'];
 
-		// Query the user IDs for this page
-		$wp_user_search = new WP_User_Query( $args );
+		if ( 'pending' === $role )
+			$wp_user_search = new WP_Pending_User_Query( $args ); // Query for pending users
+		else
+			$wp_user_search = new WP_User_Query( $args ); // Query the user IDs for this page
 
 		$this->items = $wp_user_search->get_results();
 
@@ -70,12 +72,24 @@
 	}
 
 	function get_bulk_actions() {
+		global $role;
+
 		$actions = array();
-		if ( current_user_can( 'delete_users' ) )
-			$actions['delete'] = __( 'Delete' );
-		$actions['spam'] = _x( 'Mark as Spam', 'user' );
-		$actions['notspam'] = _x( 'Not Spam', 'user' );
 
+		if ( $role == 'pending' ) {
+			if ( current_user_can( 'delete_users' ) )
+				$actions['deletesignup'] = __( 'Delete' );
+
+			$actions['activate'] = _x( 'Activate', 'user' );
+			$actions['resend'] = __( 'Resend Email', 'user' );
+		} else {
+			if ( current_user_can( 'delete_users' ) )
+				$actions['delete'] = __( 'Delete' );
+
+			$actions['spam'] = _x( 'Mark as Spam', 'user' );
+			$actions['notspam'] = _x( 'Not Spam', 'user' );
+		}
+
 		return $actions;
 	}
 
@@ -89,13 +103,15 @@
 		$total_users = get_user_count();
 		$super_admins = get_super_admins();
 		$total_admins = count( $super_admins );
+		$total_pendings = get_pending_user_count();
 
-		$current_role = false;
-		$class = $role != 'super' ? ' class="current"' : '';
+		$class = in_array( $role, array( 'super', 'pending' ) ) ? '' : ' class="current"';
 		$role_links = array();
-		$role_links['all'] = "<a href='" . network_admin_url('users.php') . "'$class>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_users, 'users' ), number_format_i18n( $total_users ) ) . '</a>';
+		$role_links['all'] = "<a href='" . network_admin_url( 'users.php' ) . "'$class>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_users, 'users' ), number_format_i18n( $total_users ) ) . '</a>';
 		$class = $role == 'super' ? ' class="current"' : '';
-		$role_links['super'] = "<a href='" . network_admin_url('users.php?role=super') . "'$class>" . sprintf( _n( 'Super Admin <span class="count">(%s)</span>', 'Super Admins <span class="count">(%s)</span>', $total_admins ), number_format_i18n( $total_admins ) ) . '</a>';
+		$role_links['super'] = "<a href='" . network_admin_url( 'users.php?role=super' ) . "'$class>" . sprintf( _n( 'Super Admin <span class="count">(%s)</span>', 'Super Admins <span class="count">(%s)</span>', $total_admins ), number_format_i18n( $total_admins ) ) . '</a>';
+		$class = $role == 'pending' ? ' class="current"' : '';
+		$role_links['pending'] = "<a href='" . network_admin_url( 'users.php?role=pending' ) . "'$class>" . sprintf( _n( 'Pending Confirmation <span class="count">(%s)</span>', 'Pending Confirmation <span class="count">(%s)</span>', $total_pendings ), number_format_i18n( $total_pendings ) ) . '</a>';
 
 		return $role_links;
 	}
@@ -110,30 +126,40 @@
 	}
 
 	function get_columns() {
+		global $role;
+
 		$users_columns = array(
 			'cb'         => '<input type="checkbox" />',
 			'username'   => __( 'Username' ),
-			'name'       => __( 'Name' ),
 			'email'      => __( 'E-mail' ),
 			'registered' => _x( 'Registered', 'user' ),
-			'blogs'      => __( 'Sites' )
 		);
-		$users_columns = apply_filters( 'wpmu_users_columns', $users_columns );
 
-		return $users_columns;
+		if ( 'pending' !== $role ) {
+			$users_columns['name'] = __( 'Name' );
+			$users_columns['blogs'] = __( 'Sites' );
+		}
+
+		return apply_filters( 'wpmu_users_columns', $users_columns );
 	}
 
 	function get_sortable_columns() {
-		return array(
+		global $role;
+
+		$sortables = array(
 			'username'   => 'login',
-			'name'       => 'name',
 			'email'      => 'email',
 			'registered' => 'id',
 		);
+
+		if ( 'pending' !== $role )
+			$sortables['name'] = 'name';
+
+		return $sortables;
 	}
 
 	function display_rows() {
-		global $current_site, $mode;
+		global $current_site, $mode, $role;
 
 		$alt = '';
 		$super_admins = get_super_admins();
@@ -142,9 +168,13 @@
 
 			$status_list = array( 'spam' => 'site-spammed', 'deleted' => 'site-deleted' );
 
-			foreach ( $status_list as $status => $col ) {
-				if ( $user->$status )
-					$alt .= " $col";
+			if ( 'pending' === $role ) {
+				$user->ID = $user->user_login;
+				$user->user_registered = $user->registered;
+			} else {
+				foreach ( $status_list as $status => $col )
+					if ( $user->$status )
+						$alt .= " $col";
 			}
 
 			?>
@@ -173,20 +203,44 @@
 
 					case 'username':
 						$avatar	= get_avatar( $user->user_email, 32 );
-						$edit_link = esc_url( add_query_arg( 'wp_http_referer', urlencode( stripslashes( $_SERVER['REQUEST_URI'] ) ), get_edit_user_link( $user->ID ) ) );
+						if ( get_current_user_id() == $user->ID ) {
+							$edit_link = esc_url( self_admin_url( 'profile.php' ) );
+						} else {
+							$edit_link = esc_url( add_query_arg( 'wp_http_referer', urlencode( stripslashes( $_SERVER['REQUEST_URI'] ) ), get_edit_user_link( $user->ID ) ) );
+						}
 
+						$activate_link = esc_url( network_admin_url( add_query_arg( '_wp_http_referer', urlencode( stripslashes( $_SERVER['REQUEST_URI'] ) ), wp_nonce_url( 'users.php', 'activatesignup' ) . '&amp;action=activatesignup&amp;user_login=' . $user->user_login ) ) );
+						$resend_link = esc_url( network_admin_url( add_query_arg( '_wp_http_referer', urlencode( stripslashes( $_SERVER['REQUEST_URI'] ) ), wp_nonce_url( 'users.php', 'resendsignup' ) . '&amp;action=resendsignup&amp;user_login=' . $user->user_login ) ) );
+
 						echo "<td $attributes>"; ?>
-							<?php echo $avatar; ?><strong><a href="<?php echo $edit_link; ?>" class="edit"><?php echo stripslashes( $user->user_login ); ?></a><?php
+							<?php echo $avatar; ?><strong><?php
+
+							if ( $role == 'pending' ): ?>
+								<?php echo stripslashes( $user->user_login ); ?>
+							<?php else: ?>
+								<a href="<?php echo $edit_link; ?>" class="edit"><?php echo stripslashes( $user->user_login ); ?></a>
+							<?php endif;
+
 							if ( in_array( $user->user_login, $super_admins ) )
 								echo ' - ' . __( 'Super Admin' );
 							?></strong>
 							<br/>
 							<?php
 								$actions = array();
-								$actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>';
 
+								if ( 'pending' === $role ) {
+									$actions['activate'] = '<a href="' . $activate_link . '">' . __( 'Activate' ) . '</a>';
+									$actions['resend'] = '<a href="' . $resend_link . '">' . __( 'Resend Email' ) . '</a>';
+								} else {
+									$actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>';
+								}
+
 								if ( current_user_can( 'delete_user', $user->ID ) && ! in_array( $user->user_login, $super_admins ) ) {
-									$actions['delete'] = '<a href="' . $delete = esc_url( network_admin_url( add_query_arg( '_wp_http_referer', urlencode( stripslashes( $_SERVER['REQUEST_URI'] ) ), wp_nonce_url( 'users.php', 'deleteuser' ) . '&amp;action=deleteuser&amp;id=' . $user->ID ) ) ) . '" class="delete">' . __( 'Delete' ) . '</a>';
+									if ( 'pending' === $role ) {
+										$actions['delete'] = '<a href="' . $delete = esc_url( network_admin_url( add_query_arg( '_wp_http_referer', urlencode( stripslashes( $_SERVER['REQUEST_URI'] ) ), wp_nonce_url( 'edit.php', 'deletesignup' ) . '&amp;action=deletesignup&amp;user_login=' . $user->user_login ) ) ) . '" class="delete">' . __( 'Delete' ) . '</a>';
+									} else {
+										$actions['delete'] = '<a href="' . $delete = esc_url( network_admin_url( add_query_arg( '_wp_http_referer', urlencode( stripslashes( $_SERVER['REQUEST_URI'] ) ), wp_nonce_url( 'users.php', 'deleteuser' ) . '&amp;action=deleteuser&amp;id=' . $user->ID ) ) ) . '" class="delete">' . __( 'Delete' ) . '</a>';
+									}
 								}
 
 								$actions = apply_filters( 'ms_user_row_actions', $actions, $user );
Index: wp-admin/network/users.php
===================================================================
--- wp-admin/network/users.php	(revision 23297)
+++ wp-admin/network/users.php	(working copy)
@@ -16,9 +16,31 @@
 if ( ! current_user_can( 'manage_network_users' ) )
 	wp_die( __( 'You do not have permission to access this page.' ) );
 
+function confirm_delete_signups( $signups ) {
+	if ( ! is_array( $signups ) )
+		return false;
+	?>
+	<h2><?php esc_html_e( 'Users' ); ?></h2>
+	<p><?php _e( 'Transfer or delete posts before deleting users.' ); ?></p>
+	<form action="users.php?action=dodeletesignup" method="post">
+	<input type="hidden" name="dodeletesignup" />
+	<?php wp_nonce_field( 'ms-signups-delete' ); ?>
+	<ul>
+	<?php
+	foreach ( $signups as $delete_signup ) {
+		echo "<li><input type='hidden' name='user[]' value='{$delete_signup}'/>{$delete_signup}</li>\n";
+	}
+	?>
+	</ul>
+	<?php submit_button( __( 'Confirm Deletion' ), 'delete' ); ?>
+	</form>
+	<?php
+	return true;
+}
+
 function confirm_delete_users( $users ) {
 	$current_user = wp_get_current_user();
-	if ( !is_array( $users ) )
+	if ( ! is_array( $users ) )
 		return false;
 
 	screen_icon();
@@ -91,9 +113,6 @@
 
 	switch ( $_GET['action'] ) {
 		case 'deleteuser':
-			if ( ! current_user_can( 'manage_network_users' ) )
-				wp_die( __( 'You do not have permission to access this page.' ) );
-
 			check_admin_referer( 'deleteuser' );
 
 			$id = intval( $_GET['id'] );
@@ -113,9 +132,6 @@
 		break;
 
 		case 'allusers':
-			if ( !current_user_can( 'manage_network_users' ) )
-				wp_die( __( 'You do not have permission to access this page.' ) );
-
 			if ( ( isset( $_POST['action']) || isset($_POST['action2'] ) ) && isset( $_POST['allusers'] ) ) {
 				check_admin_referer( 'bulk-users-network' );
 
@@ -123,7 +139,7 @@
 				$userfunction = '';
 
 				foreach ( (array) $_POST['allusers'] as $key => $val ) {
-					if ( !empty( $val ) ) {
+					if ( ! empty( $val ) ) {
 						switch ( $doaction ) {
 							case 'delete':
 								if ( ! current_user_can( 'delete_users' ) )
@@ -160,6 +176,30 @@
 
 								update_user_status( $val, 'spam', '0' );
 							break;
+
+							case 'activate':
+								$userfunction = 'all_activate';
+								wp_activate_by_user_login( $val );
+							break;
+
+							case 'resend':
+								$userfunction = 'all_resend';
+								wp_resend_by_user_login( $val );
+							break;
+
+							case 'deletesignup':
+								if ( ! current_user_can( 'delete_users' ) )
+									wp_die( __( 'You do not have permission to access this page.' ) );
+
+								$title = __( 'Users' );
+								$parent_file = 'users.php';
+								require_once( '../admin-header.php' );
+								echo '<div class="wrap">';
+								confirm_delete_signups( $_POST['allusers'] );
+								echo '</div>';
+								require_once( '../admin-footer.php' );
+								exit();
+							break;
 						}
 					}
 				}
@@ -177,7 +217,7 @@
 
 		case 'dodelete':
 			check_admin_referer( 'ms-users-delete' );
-			if ( ! ( current_user_can( 'manage_network_users' ) && current_user_can( 'delete_users' ) ) )
+			if ( ! current_user_can( 'delete_users' ) )
 				wp_die( __( 'You do not have permission to access this page.' ) );
 
 			if ( ! empty( $_POST['blog'] ) && is_array( $_POST['blog'] ) ) {
@@ -210,6 +250,62 @@
 			wp_redirect( add_query_arg( array( 'updated' => 'true', 'action' => $deletefunction ), network_admin_url( 'users.php' ) ) );
 			exit();
 		break;
+
+		case 'activatesignup':
+			check_admin_referer( 'activatesignup' );
+
+			wp_activate_by_user_login( $_GET['user_login'] );
+
+			wp_redirect( add_query_arg( array( 'role' => 'pending', 'updated' => 'true', 'action' => 'activate' ), network_admin_url( 'users.php' ) ) );
+			exit();
+		break;
+
+		case 'resendsignup':
+			check_admin_referer( 'resendsignup' );
+
+			wp_resend_by_user_login( $_GET['user_login'] );
+
+			wp_redirect( add_query_arg( array( 'role' => 'pending', 'updated' => 'true', 'action' => 'resend' ), network_admin_url( 'users.php' ) ) );
+			exit();
+		break;
+
+		case 'deletesignup':
+			check_admin_referer( 'deletesignup' );
+
+			if ( ! empty( $_GET['user_login'] ) ) {
+				$title = __( 'Users' );
+				$parent_file = 'users.php';
+				require_once( '../admin-header.php' );
+				echo '<div class="wrap">';
+				confirm_delete_signups( array( $_GET['user_login'] ) );
+				echo '</div>';
+				require_once( '../admin-footer.php' );
+			} else {
+				wp_redirect( add_query_arg( array( 'role' => 'pending' ), network_admin_url( 'users.php' ) ) );
+			}
+			exit();
+		break;
+
+		case 'dodeletesignup':
+			if ( ! current_user_can( 'delete_users' ) )
+				wp_die( __( 'You do not have permission to access this page.' ) );
+
+			check_admin_referer( 'ms-signups-delete' );
+
+			if ( ! empty( $_POST['user'] ) ) {
+				array_walk( $_POST['user'], array( &$wpdb, 'escape_by_ref' ) );
+				$wpdb->query( "DELETE FROM {$wpdb->signups} WHERE active != 1 AND user_login IN ('" . implode( "','", $_POST['user'] ) . "')" );
+			}
+
+			if ( count( $_POST['user'] ) > 1 ) {
+				$delete_action = 'all_delete';
+			} else {
+				$delete_action = 'delete';
+			}
+
+			wp_redirect( add_query_arg( array( 'role' => 'pending', 'updated' => 'true', 'action' => $delete_action ), network_admin_url( 'users.php' ) ) );
+			exit();
+		break;
 	}
 }
 
@@ -267,6 +363,18 @@
 			case 'add':
 				_e( 'User added.' );
 			break;
+			case 'activate':
+				_e( 'User activated.' );
+			break;
+			case 'resend':
+				_e( 'Activation instruction resent to user.');
+			break;
+			case 'all_activate':
+				_e( 'Users activated.' );
+			break;
+			case 'all_resend':
+				_e( 'Activation instruction resent to users.');
+			break;
 		}
 		?>
 	</p></div>
