Index: SpecialUserrights.php
===================================================================
--- SpecialUserrights.php	(revision 22060)
+++ SpecialUserrights.php	(working copy)
@@ -27,7 +27,7 @@
 	var $action;
 
 	/** Constructor*/
-	function UserrightsForm ( &$request ) {
+	public function UserrightsForm ( &$request ) {
 		$this->mPosted = $request->wasPosted();
 		$this->mRequest =& $request;
 		$this->mName = 'userrights';
@@ -94,21 +94,25 @@
 		if(isset($removegroup)) {
 			$newGroups = array_diff($newGroups, $removegroup);
 			foreach( $removegroup as $group ) {
+				if ( $this->canRemove( $group ) ) {
 				$u->removeGroup( $group );
 			}
 		}
+		}
 		if(isset($addgroup)) {
 			$newGroups = array_merge($newGroups, $addgroup);
 			foreach( $addgroup as $group ) {
+				if ( $this->canAdd( $group ) ) {
 				$u->addGroup( $group );
 			}
 		}
+		}
 		$newGroups = array_unique( $newGroups );
 
 		wfDebug( 'oldGroups: ' . print_r( $oldGroups, true ) );
 		wfDebug( 'newGroups: ' . print_r( $newGroups, true ) );
 
-		wfRunHooks( 'UserRights', array( &$u, $addgroup, $removegroup ) );
+		wfRunHooks( 'UserRights', array( &$u, $addgroup, $removegroup ) );	
 		$log = new LogPage( 'rights' );
 		$log->addEntry( 'rights', Title::makeTitle( NS_USER, $u->getName() ), $reason, array( $this->makeGroupNameList( $oldGroups ),
 			$this->makeGroupNameList( $newGroups ) ) );
@@ -138,8 +142,6 @@
 	 * @param string $username Name of the user.
 	 */
 	function editUserGroupsForm($username) {
-		global $wgOut;
-
 		$user = User::newFromName($username);
 		if( is_null( $user ) ) {
 			$wgOut->addWikiText( wfMsg( 'nouserspecified' ) );
@@ -149,13 +151,24 @@
 			return;
 		}
 
-		$groups = $user->getGroups();
-		$this->showEditUserGroupsForm( $username, $groups );
+		list($addable, $removable) = $this->getGroups();
+		$removable = array_intersect($removable, $user->getGroups()); // Can't remove groups the user doesn't have
+		$addable   = array_diff(     $addable,   $user->getGroups()); // Can't add groups the user does have
+
+		$this->showEditUserGroupsForm( $username, $addable, $removable );
 	}
-	
-	function showEditUserGroupsForm( $username, $groups ) {
+
+	/**
+	 * Show the form to edit group memberships.
+	 *
+	 * @param $username  String: Name of user you're editing
+	 * @param $addable   Array:  Array of groups that can be added
+	 * @param $removable Array:  Array of groups that can be removed
+	 */
+	private function showEditUserGroupsForm( $username, $addable, $removable ) {
 		global $wgOut, $wgUser;
-		$wgOut->addHTML(
+
+		$wgOut->addHtml(
 			Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->action, 'name' => 'editGroup' ) ) .
 			Xml::hidden( 'user-editname', $username ) .
 			Xml::hidden( 'wpEditToken', $wgUser->editToken( $username ) ) .
@@ -168,8 +181,8 @@
 				<td>
 				<table width='400'>
 					<tr>
-						<td width='50%'>" . HTMLSelectGroups( 'member', $this->mName.'-groupsmember', $groups, true, 6 ) . "</td>
-						<td width='50%'>" . HTMLSelectGroups( 'available', $this->mName.'-groupsavailable', $groups, true, 6, true) . "</td>
+						<td width='50%'>" . $this->removeSelect( $removable ) . "</td>
+						<td width='50%'>" . $this->addSelect( $addable ) . "</td>
 					</tr>
 				</table>
 			</tr>
@@ -197,5 +210,103 @@
 			Xml::closeElement( 'form' ) . "\n"
 		);
 	}
+
+	/**
+	 * Adds the <select> thingie where you can select what groups to remove
+	 *
+	 * @param array $groups The groups that can be removed
+	 * @return string XHTML <select> element
+	 */
+	private function removeSelect( $groups ) {
+		return $this->doSelect( $groups, 'member' );
+	}
+
+	/**
+	 * Adds the <select> thingie where you can select what groups to add
+	 *
+	 * @param array $groups The groups that can be added
+	 * @return string XHTML <select> element
+	 */
+	private function addSelect( $groups ) {
+		return $this->doSelect( $groups, 'available' );
+	}
+
+	/**
+	 * Adds the <select> thingie where you can select what groups to add/remove
+	 *
+	 * @param array  $groups The groups that can be added/removed
+	 * @param string $name   'member' or 'available'
+	 * @return string XHTML <select> element
+	 */
+	private function doSelect( $groups, $name ) {
+		$ret = wfMsgHtml( "{$this->mName}-groups$name" ) .
+		Xml::openElement( 'select', array(
+				'name' => "{$name}[]",
+				'multiple' => 'multiple',
+				'size' => '6',
+				'style' => 'width: 100%;'
+			)
+		);
+		foreach ($groups as $group) {
+			$ret .= Xml::element( 'option', array( 'value' => $group ), User::getGroupName( $group ) );
+		}
+		$ret .= Xml::closeElement( 'select' );
+		return $ret;
+	}
+
+	/**
+	 * @param  string $group The name of the group to check
+	 * @return bool Can we remove the group?
+	 */
+	private function canRemove( $group ) {
+		$groups = $this->getGroups(); // $this->getGroups()[1] doesn't seem to work . . .
+		return in_array( $group, $groups[1] );
+	}
+
+	/**
+	 * @param  string $group The name of the group to check
+	 * @return bool Can we add the group?
+	 */
+	private function canAdd( $group ) {
+		$groups = $this->getGroups();
+		return in_array( $group, $groups[0] );
+	}
+
+	/**
+	 * Returns an array of the groups that the user can add/remove.
+	 *
+	 * @return Array array( array( 'addablegroup1', 'addablegroup2', ...), array( 'removablegroup1', ... ) )
+	 */
+	private function getGroups() {
+		global $wgUser, $wgGroupPermissions;
+
+		$groups = array( 'add' => array(), 'remove' => array() );
+		$addergroups = $wgUser->getEffectiveGroups();
+
+		foreach ($addergroups as $addergroup) {
+			if (!isset($wgGroupPermissions[$addergroup]['userrights'])
+				|| !$wgGroupPermissions[$addergroup]['userrights'] ) {
+				continue;
+			}
+			if ($wgGroupPermissions[$addergroup]['userrights'] === true) {
+				$groups['add'] = $groups['remove'] = User::getAllGroups();
+				break;
+			}
+
+			foreach( array( 'add', 'remove' ) as $type ) {
+				if (!isset($wgGroupPermissions[$addergroup]['userrights'][$type])) {
+					// Don't add anything to $groups
+				} elseif ($wgGroupPermissions[$addergroup]['userrights'][$type] === true) {
+					$groups[$type] = User::getAllGroups();
+				} else {
+					$groups[$type] = array_merge(
+						$groups[$type],
+						array_keys($wgGroupPermissions[$addergroup]['userrights'][$type], true)
+					);
+				}
+			}
+		}
+		return array( $groups['add'], $groups['remove'] );
+	}
 } // end class UserrightsForm
 ?>
