Index: /trunk/bp-core/bp-core-hooks.php
===================================================================
--- /trunk/bp-core/bp-core-hooks.php	(revision 5796)
+++ /trunk/bp-core/bp-core-hooks.php	(revision 5797)
@@ -77,4 +77,9 @@
 add_action( 'admin_bar_menu', 'bp_setup_admin_bar', 11 );
 
+/** Roles and Capabilities ****************************************************/
+
+// Map our custom capabilities onto WP's
+add_filter( 'map_meta_cap', 'bp_map_meta_caps', 10, 4 );
+
 /** The hooks *****************************************************************/
 
Index: /trunk/bp-themes/bp-default/_inc/css/default.css
===================================================================
--- /trunk/bp-themes/bp-default/_inc/css/default.css	(revision 5796)
+++ /trunk/bp-themes/bp-default/_inc/css/default.css	(revision 5797)
@@ -2385,4 +2385,9 @@
 	font-weight: bold;
 }
+.field-visibility-settings,
+.field-visibility-settings-toggle,
+.field-visibility-settings-notoggle {
+	color: #888;
+}
 .field-visibility-settings-toggle a,
 .field-visibility-settings a {
Index: /trunk/bp-themes/bp-default/members/single/profile/edit.php
===================================================================
--- /trunk/bp-themes/bp-default/members/single/profile/edit.php	(revision 5796)
+++ /trunk/bp-themes/bp-default/members/single/profile/edit.php	(revision 5797)
@@ -114,6 +114,5 @@
 				<?php endif; ?>
 				
-				<?php /* The fullname field is always public */ ?>
-				<?php if ( 1 != bp_get_the_profile_field_id() ) : ?>
+				<?php if ( bp_current_user_can( 'bp_xprofile_change_field_visibility' ) ) : ?>
 					<div class="field-visibility-settings-toggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
 						<?php printf( __( 'This field can be seen by: <span class="current-visibility-level">%s</span>', 'buddypress' ), bp_get_the_profile_field_visibility_level_label() ) ?> <a href="#" class="visibility-toggle-link">Change</a>
@@ -127,4 +126,8 @@
 						<a class="field-visibility-settings-close" href="#"><?php _e( 'Close', 'buddypress' ) ?></a>
 					</div>
+				<?php else : ?>
+					<div class="field-visibility-settings-notoggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
+						<?php printf( __( 'This field can be seen by: <span class="current-visibility-level">%s</span>', 'buddypress' ), bp_get_the_profile_field_visibility_level_label() ) ?>
+					</div>			
 				<?php endif ?>
 
Index: /trunk/bp-xprofile/bp-xprofile-admin.php
===================================================================
--- /trunk/bp-xprofile/bp-xprofile-admin.php	(revision 5796)
+++ /trunk/bp-xprofile/bp-xprofile-admin.php	(revision 5797)
@@ -274,4 +274,8 @@
 				if ( !empty( $_POST['default-visibility'] ) ) {
 					bp_xprofile_update_field_meta( $field_id, 'default_visibility', $_POST['default-visibility'] );
+				}
+				
+				if ( !empty( $_POST['allow-custom-visibility'] ) ) {
+					bp_xprofile_update_field_meta( $field_id, 'allow_custom_visibility', $_POST['allow-custom-visibility'] );
 				}
 
Index: /trunk/bp-xprofile/bp-xprofile-caps.php
===================================================================
--- /trunk/bp-xprofile/bp-xprofile-caps.php	(revision 5797)
+++ /trunk/bp-xprofile/bp-xprofile-caps.php	(revision 5797)
@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * Roles and capabilities logic for the XProfile component
+ *
+ * @package BuddyPress
+ * @since 1.6
+ */
+
+/**
+ * Maps XProfile caps to built in WordPress caps
+ *
+ * @since 1.6
+ *
+ * @param array $caps Capabilities for meta capability
+ * @param string $cap Capability name
+ * @param int $user_id User id
+ * @param mixed $args Arguments
+ * @uses get_post() To get the post
+ * @uses get_post_type_object() To get the post type object
+ * @uses apply_filters() Calls 'bp_map_meta_caps' with caps, cap, user id and
+ *                        args
+ * @return array Actual capabilities for meta capability
+ */
+function bp_xprofile_map_meta_caps( $caps, $cap, $user_id, $args ) {
+	switch ( $cap ) {
+		case 'bp_xprofile_change_field_visibility' :
+			$caps = array( 'read' );
+			
+			// You may pass args manually: $field_id, $profile_user_id
+			$field_id 	 = isset( $args[0] ) ? (int)$args[0] : bp_get_the_profile_field_id();
+			$profile_user_id = isset( $args[1] ) ? (int)$args[1] : bp_displayed_user_id();
+			
+			// Visibility on the fullname field is not editable
+			if ( 1 == $field_id ) {
+				$caps[] = 'do_not_allow';
+				break;
+			}
+			
+			// Has the admin disabled visibility modification for this field?
+			if ( 'disabled' == bp_xprofile_get_meta( $field_id, 'field', 'allow_custom_visibility' ) ) {
+				$caps[] = 'do_not_allow';
+				break;
+			}
+
+			// Friends don't let friends edit each other's visibility
+			// @todo - This would be a proper map if we used CPTs?
+			if ( $profile_user_id != bp_displayed_user_id() && !bp_current_user_can( 'bp_moderate' ) ) {
+				$caps[] = 'do_not_allow'; 
+				break;
+			}
+
+			break;
+	}
+	
+	return apply_filters( 'bp_xprofile_map_meta_caps', $caps, $cap, $user_id, $args );
+}
+add_filter( 'bp_map_meta_caps', 'bp_xprofile_map_meta_caps', 10, 4 );
+
+?>
Index: /trunk/bp-xprofile/bp-xprofile-classes.php
===================================================================
--- /trunk/bp-xprofile/bp-xprofile-classes.php	(revision 5796)
+++ /trunk/bp-xprofile/bp-xprofile-classes.php	(revision 5797)
@@ -284,5 +284,11 @@
 	
 	/**
-	 * Fetch the field visibility level for the returned fielddata
+	 * Fetch the field visibility level for the fields returned by the query
+	 *
+	 * @since 1.6
+	 *
+	 * @param int $user_id The profile owner's user_id
+	 * @param array $fields The database results returned by the get() query
+	 * @return array $fields The database results, with field_visibility added
 	 */
 	function fetch_visibility_level( $user_id, $fields ) {
@@ -292,16 +298,17 @@
 		$visibility_levels = bp_get_user_meta( $user_id, 'bp_xprofile_visibility_levels', true );
 		
+		// Get the admin-set preferences
+		$admin_set_levels  = self::fetch_default_visibility_levels();
+		
 		foreach( (array)$fields as $key => $field ) {
+			// Does the admin allow this field to be customized?
+			$allow_custom = !empty( $admin_set_levels[$field->id]['allow_custom'] ) && 'disabled' != $admin_set_levels[$field->id]['allow_custom'];
+			
 			// Look to see if the user has set the visibility for this field
-			if ( isset( $visibility_levels[$field->id] ) ) {
+			if ( $allow_custom && isset( $visibility_levels[$field->id] ) ) {
 				$field_visibility = $visibility_levels[$field->id];
-			} else {
-				// If not, bring up the admin-set defaults
-				if ( !isset( $default_visibility_levels ) ) {
-					$default_visibility_levels = self::fetch_default_visibility_levels();
-				}
-				
+			} else {				
 				// If no admin-set default is saved, fall back on a global default
-				$field_visibility = !empty( $default_visibility_levels[$field->id] ) ? $default_visibility_levels[$field->id] : apply_filters( 'bp_xprofile_default_visibility_level', 'public' );
+				$field_visibility = !empty( $admin_set_levels[$field->id]['default'] ) ? $admin_set_levels[$field->id]['default'] : apply_filters( 'bp_xprofile_default_visibility_level', 'public' );
 			}
 			
@@ -313,15 +320,24 @@
 	
 	/**
-	 * Fetch the admin-set default visibility levels for all fields
+	 * Fetch the admin-set preferences for all fields
+	 *
+	 * @since 1.6
+	 *
+	 * @return array $default_visibility_levels An array, keyed by field_id, of default
+	 *   visibility level + allow_custom (whether the admin allows this field to be set by user)
 	 */
 	function fetch_default_visibility_levels() {
 		global $wpdb, $bp;
 		
-		$levels = $wpdb->get_results( $wpdb->prepare( "SELECT object_id, meta_value FROM {$bp->profile->table_name_meta} WHERE object_type = 'field' AND meta_key = 'default_visibility'" ) );
+		$levels = $wpdb->get_results( $wpdb->prepare( "SELECT object_id, meta_key, meta_value FROM {$bp->profile->table_name_meta} WHERE object_type = 'field' AND ( meta_key = 'default_visibility' OR meta_key = 'allow_custom_visibility' )" ) );
 		
 		// Arrange so that the field id is the key and the visibility level the value
 		$default_visibility_levels = array();
 		foreach( $levels as $level ) {
-			$default_visibility_levels[$level->object_id] = $level->meta_value;
+			if ( 'default_visibility' == $level->meta_key ) {
+				$default_visibility_levels[$level->object_id]['default'] = $level->meta_value;		
+			} else if ( 'allow_custom_visibility' == $level->meta_key ) {
+				$default_visibility_levels[$level->object_id]['allow_custom'] = $level->meta_value;		
+			}
 		}
 		
@@ -409,4 +425,5 @@
 	var $is_default_option;
 	var $default_visibility;
+	var $allow_custom_visibility;
 
 	var $data;
@@ -452,4 +469,6 @@
 				$this->default_visibility = 'public';
 			}
+			
+			$this->allow_custom_visibility = 'disabled' == bp_xprofile_get_meta( $id, 'field', 'allow_custom_visibility' ) ? 'disabled' : 'allowed';
 		}
 	}
@@ -867,10 +886,20 @@
 
 						<div id="titlediv">
-							<h3><label for="default-visibility"><?php _e( "Default Visibility Level", 'buddypress' ); ?></label></h3>
+							
 							<div id="titlewrap">
+								<h3><label for="default-visibility"><?php _e( "Default Visibility", 'buddypress' ); ?></label></h3>
 								<ul>
 								<?php foreach( bp_xprofile_get_visibility_levels() as $level ) : ?>
 									<li><input type="radio" name="default-visibility" value="<?php echo esc_attr( $level['id'] ) ?>" <?php checked( $this->default_visibility, $level['id'] ) ?>> <?php echo esc_html( $level['label'] ) ?></li> 
 								<?php endforeach ?>
+								</ul>
+							</div>
+							
+							<div id="titlewrap">
+								<h3><label for="allow-custom-visibility"><?php _e( "Per-Member Visibility", 'buddypress' ); ?></label></h3>
+								<ul>
+									<li><input type="radio" name="allow-custom-visibility" value="allowed" <?php checked( $this->allow_custom_visibility, 'allowed' ) ?>> <?php _e( "Let members change the this field's visibility", 'buddypress' ) ?></li>
+									
+									<li><input type="radio" name="allow-custom-visibility" value="disabled" <?php checked( $this->allow_custom_visibility, 'disabled' ) ?>> <?php _e( 'Enforce the default visibility for all members', 'buddypress' ) ?></li>
 								</ul>
 							</div>
Index: /trunk/bp-xprofile/bp-xprofile-filters.php
===================================================================
--- /trunk/bp-xprofile/bp-xprofile-filters.php	(revision 5796)
+++ /trunk/bp-xprofile/bp-xprofile-filters.php	(revision 5797)
@@ -212,3 +212,5 @@
 add_filter( 'comments_array', 'xprofile_filter_comments', 10, 2 );
 
+
+
 ?>
Index: /trunk/bp-xprofile/bp-xprofile-loader.php
===================================================================
--- /trunk/bp-xprofile/bp-xprofile-loader.php	(revision 5796)
+++ /trunk/bp-xprofile/bp-xprofile-loader.php	(revision 5797)
@@ -45,4 +45,5 @@
 			'activity',
 			'screens',
+			'caps',
 			'classes',
 			'filters',
