diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php
index b8b0407356abab13001ba16987a13660b512e403..2cf45e83cb460d9fe946eb63db28ce1bdd40cf55 100644
--- a/include/class.dynamic_forms.php
+++ b/include/class.dynamic_forms.php
@@ -480,6 +480,74 @@ class DynamicFormField extends VerySimpleModel {
         return (($this->get('edit_mask') & 32) == 0);
     }
 
+    function allRequirementModes() {
+        $modes = array(
+            'a' => array('desc' => 'Optional',
+                'private' => 0, 'required' => 0),
+            'b' => array('desc' => 'Required',
+                'private' => 0, 'required' => 1),
+            'c' => array('desc' => 'Required for Users',
+                'private' => 0, 'required' => 2),
+            'd' => array('desc' => 'Required for Agents',
+                'private' => 0, 'required' => 3),
+            'e' => array('desc' => 'Internal, Optional',
+                'private' => 1, 'required' => 0),
+            'f' => array('desc' => 'Internal, Required',
+                'private' => 1, 'required' => 1),
+            'g' => array('desc' => 'For Users Only',
+                'private' => 2, 'required' => 2),
+        );
+
+        if ($this->isPrivacyForced()) {
+            // Required to be internal
+            foreach ($modes as $m=>$info) {
+                if ($info['private'] != $this->get('private'))
+                    unset($modes[$m]);
+            }
+        }
+
+        if ($this->isRequirementForced()) {
+            // Required to be required
+            foreach ($modes as $m=>$info) {
+                if ($info['required'] != $this->get('required'))
+                    unset($modes[$m]);
+            }
+        }
+        return $modes;
+    }
+
+    function getRequirementMode() {
+        foreach ($this->allRequirementModes() as $m=>$info) {
+            if ($this->get('private') == $info['private']
+                    && $this->get('required') == $info['required'])
+                return $m;
+        }
+        return false;
+    }
+
+    function setRequirementMode($mode) {
+        $modes = $this->allRequirementModes();
+        if (!isset($modes[$mode]))
+            return false;
+
+        $info = $modes[$mode];
+        $this->set('required', $info['required']);
+        $this->set('private', $info['private']);
+    }
+
+    function isRequiredForStaff() {
+        return in_array($this->get('required'), array(1, 3));
+    }
+    function isRequiredForUsers() {
+        return in_array($this->get('required'), array(1, 2));
+    }
+    function isVisibleToStaff() {
+        return in_array($this->get('private'), array(0, 1));
+    }
+    function isVisibleToUsers() {
+        return in_array($this->get('private'), array(0, 2));
+    }
+
     /**
      * Used when updating the form via the admin panel. This represents
      * validation on the form field template, not data entered into a form
@@ -652,11 +720,16 @@ class DynamicFormEntry extends VerySimpleModel {
     }
 
     function isValidForClient() {
-
         $filter = function($f) {
-            return !$f->get('private');
+            return !$f->isRequiredForUsers();
         };
+        return $this->isValid($filter);
+    }
 
+    function isValidForStaff() {
+        $filter = function($f) {
+            return !$f->isRequiredForStaff();
+        };
         return $this->isValid($filter);
     }
 
diff --git a/include/class.forms.php b/include/class.forms.php
index 1c1f7017859194af35c7b253223a35baf00fca70..c80c9a6827ea85344ce9cab356fd3048e2dd0e96 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -86,7 +86,7 @@ class Form {
         if (!$this->_clean) {
             $this->_clean = array();
             foreach ($this->getFields() as $key=>$field) {
-                if (!$field->hasData())
+                if ($field->isPresentationOnly())
                     continue;
                 $this->_clean[$key] = $this->_clean[$field->get('name')]
                     = $field->getClean();
diff --git a/include/class.user.php b/include/class.user.php
index 19f83efafb2f825109053e971ba0ea998eb22f19..6ec2c5a940894becc389c5d5580f88ebd32d2842 100644
--- a/include/class.user.php
+++ b/include/class.user.php
@@ -194,12 +194,16 @@ class User extends UserModel {
     }
 
     static function fromForm($form) {
+        global $thisstaff;
 
         if(!$form) return null;
 
         //Validate the form
         $valid = true;
-        if (!$form->isValid())
+        $filter = function($f) use ($thisstaff) {
+            return !isset($thisstaff) || $f->isRequiredForStaff();
+        };
+        if (!$form->isValid($filter))
             $valid  = false;
 
         //Make sure the email is not in-use
diff --git a/include/client/templates/dynamic-form.tmpl.php b/include/client/templates/dynamic-form.tmpl.php
index 57f1aa2951aed93e9e50cf6d6868c7e9f7c15041..12b3944075e71ad3788be4be515fadb5478a56e8 100644
--- a/include/client/templates/dynamic-form.tmpl.php
+++ b/include/client/templates/dynamic-form.tmpl.php
@@ -16,7 +16,7 @@
     // 'private' are not included in the output for clients
     global $thisclient;
     foreach ($form->getFields() as $field) {
-        if ($field->get('private'))
+        if (!$field->isVisibleToUsers())
             continue;
         ?>
         <tr>
diff --git a/include/staff/dynamic-form.inc.php b/include/staff/dynamic-form.inc.php
index e0bf6a4552b68b761ff0d78efb3fad9502acf4fa..44d41081dfb8e866b1167af4b24a888b3f5e5bb5 100644
--- a/include/staff/dynamic-form.inc.php
+++ b/include/staff/dynamic-form.inc.php
@@ -124,8 +124,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
         $id = $f->get('id');
         $deletable = !$f->isDeletable() ? 'disabled="disabled"' : '';
         $force_name = $f->isNameForced() ? 'disabled="disabled"' : '';
-        $force_privacy = $f->isPrivacyForced() ? 'disabled="disabled"' : '';
-        $force_required = $f->isRequirementForced() ? 'disabled="disabled"' : '';
+        $rmode = $f->getRequirementMode();
         $fi = $f->getImpl();
         $ferrors = $f->errors(); ?>
         <tr>
@@ -157,17 +156,14 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                         $.dialog($(this).attr('href').substr(1), [201]);
                         return false;
                     "><i class="icon-edit"></i> <?php echo __('Config'); ?></a>
-            <?php } ?>
-            <div class="error" style="white-space:normal"><?php
-                if ($ferrors['type']) echo $ferrors['type'];
-            ?></div>
-            </td>
-            <td><input type="checkbox" name="private-<?php echo $id; ?>"
-                <?php if ($f->get('private')) echo 'checked="checked"'; ?>
-                <?php echo $force_privacy ?>/></td>
-            <td><input type="checkbox" name="required-<?php echo $id; ?>"
-                <?php if ($f->get('required')) echo 'checked="checked"'; ?>
-                <?php echo $force_required ?>/>
+            <?php } ?></td>
+            <td colspan="2">
+                <select name="requirement-<?php echo $id; ?>">
+<?php foreach ($f->allRequirementModes() as $m=>$info) { ?>
+    <option value="<?php echo $m; ?>" <?php if ($rmode == $m)
+         echo 'selected="selected"'; ?>><?php echo $info['desc']; ?></option>
+<?php } ?>
+                <select>
             </td>
             <td>
                 <input type="text" size="20" name="name-<?php echo $id; ?>"
diff --git a/include/staff/templates/dynamic-form.tmpl.php b/include/staff/templates/dynamic-form.tmpl.php
index 79ebe981bad0798a851d2e61285be0f38613c5d3..611306d1ba831a32f54a1cca0a1d2bfe7b44b7dd 100644
--- a/include/staff/templates/dynamic-form.tmpl.php
+++ b/include/staff/templates/dynamic-form.tmpl.php
@@ -39,6 +39,13 @@ if (isset($options['entry']) && $options['mode'] == 'edit') { ?>
     <?php
     }
     foreach ($form->getFields() as $field) {
+        try {
+            if (!$field->isVisibleToStaff())
+                continue;
+        }
+        catch (Exception $e) {
+            // Not connected to a DynamicFormField
+        }
         ?>
         <tr><?php if ($field->isBlockLevel()) { ?>
                 <td colspan="2">
diff --git a/scp/forms.php b/scp/forms.php
index dae8ecaf71849f4e3558f2d34f3c181ddad593e1..5d174d5a359846bdb2a6c90b5a66ba4eec48f1a5 100644
--- a/scp/forms.php
+++ b/scp/forms.php
@@ -38,10 +38,8 @@ if($_POST) {
                 if (isset($_POST["name-$id"]) && !$field->isNameForced())
                     $field->set('name', $_POST["name-$id"]);
                 # TODO: make sure all help topics still have all required fields
-                if (!$field->isRequirementForced())
-                    $field->set('required', $_POST["required-$id"] == 'on' ?  1 : 0);
-                if (!$field->isPrivacyForced())
-                    $field->set('private', $_POST["private-$id"] == 'on' ?  1 : 0);
+                $field->setRequirementMode($_POST["requirement-$id"]);
+
                 foreach (array('sort','label') as $f) {
                     if (isset($_POST["$f-$id"])) {
                         $field->set($f, $_POST["$f-$id"]);