=== modified file 'includes/form.inc'
--- includes/form.inc	
+++ includes/form.inc	
@@ -17,17 +17,16 @@
  * $output = drupal_get_form('user_register');
  *
  * Forms can also be built and submitted programmatically without any user input
- * by populating $form['#post']['edit'] with values to be submitted. For example:
+ * using the drupal_execute() function. For example:
  *
  * // register a new user
- * $form = drupal_retrieve_form('user_register');
- * $form['#post']['edit']['name'] = 'robo-user';
- * $form['#post']['edit']['mail'] = 'robouser@example.com';
- * $form['#post']['edit']['pass'] = 'password';
- * drupal_process_form('user_register', $form);
+ * $values['name'] = 'robo-user';
+ * $values['mail'] = 'robouser@example.com';
+ * $values['pass'] = 'password';
+ * $errors = drupal_execute('user_register', $values);
  *
- * Calling form_get_errors() will list any validation errors that prevented the
- * form from being submitted.
+ * drupal_execute() returns an array containing any validation errors
+ * encountered during processing.
  *
  * For information on the format of the structured arrays used to define forms,
  * and more detailed explanations of the Form API workflow, see the reference at
@@ -39,7 +38,9 @@
 /**
  * Retrieves a form from a builder function, passes it on for
  * processing, and renders the form or redirects to its destination
- * as appropriate.
+ * as appropriate. In multi-step form scenerios, it handles properly
+ * processing the values using the previous step's form definition,
+ * then rendering the requested step for display.
  *
  * @param $form_id
  *   The unique string identifying the desired form. If a function
@@ -53,11 +54,95 @@
  * @return
  *   The rendered form.
  */
-function drupal_get_form($form_id) {
+function drupal_get_form($form_id) { 
+  // In multi-step form scenerios, the incoming $_POST values are not
+  // necessarily intended for the current form. We need to build
+  // a copy of the previously built form for validation and processing,
+  // then go on to the one that was requested if everything works.
+
+  $form_build_id = md5(mt_rand());
+  if (isset($_POST['form_build_id']) && isset($_SESSION['form'][$_POST['form_build_id']])) {
+    // There's a previously stored multi-step form. We should handle
+    // IT first.
+    $stored = TRUE;
+    $args = $_SESSION['form'][$_POST['form_build_id']];
+    $form = call_user_func_array('drupal_retrieve_form', $args);
+  }
+  else {
+    // We're coming in fresh; build things as they would be. If the
+    // form's #multistep flag is set, store the build parameters so
+    // the same form can be reconstituted for validation.
+    $args = func_get_args();
+    $form = call_user_func_array('drupal_retrieve_form', $args);
+    if (isset($form['#multistep']) && $form['#multistep']) {
+      $_SESSION['form'][$form_build_id] = $args;
+      $form['#build_id'] = $form_build_id;
+    }
+    $stored = FALSE;
+  }
+
+  // Process the form, submit it, and store any errors if necessary.
+  drupal_process_form($args[0], $form);
+
+  if ($stored && !form_get_errors()) {
+    // If it's a stored form and there were no errors, we processed the
+    // stored form successfully. Now we need to build the form that was
+    // actually requested. We always pass in the current $_POST values
+    // to the builder function, as values from one stage of a multistep
+    // form can determine how subsequent steps are displayed.
+    $args = func_get_args();
+    $args[] = $_POST['edit'];
+    $form = call_user_func_array('drupal_retrieve_form', $args);
+    unset($_SESSION['form'][$_POST['form_build_id']]);
+    if (isset($form['#multistep']) && $form['#multistep']) {
+      $_SESSION['form'][$form_build_id] = $args;
+      $form['#build_id'] = $form_build_id;
+    }
+    // If we're in this part of the code, $_POST['edit'] always contains
+    // values from the previously submitted form. Unset it to avoid
+    // any accidental submission of doubled data, then process the form
+    // to prep it for rendering.
+    unset($_POST['edit']);
+    drupal_process_form($args[0], $form);
+  }
+
+  return drupal_render_form($args[0], $form);
+}
+
+/**
+ * Retrieves a form using a form_id, populates it with $form_values,
+ * processes it, and returns any validation errors encountered. This
+ * function is the programmatic counterpart to drupal_get_form().
+ *
+ * @param $form_id
+ *   The unique string identifying the desired form. If a function
+ *   with that name exists, it is called to build the form array.
+ *   Modules that need to generate the same form (or very similar forms)
+ *   using different $form_ids can implement hook_forms(), which maps
+ *   different $form_id values to the proper form building function. Examples
+ *   may be found in node_forms(), search_forms(), and user_forms().
+ * @param $form_values
+ *   An array of values mirroring the values returned by a given form
+ *   when it is submitted by a user.
+ * @param ...
+ *   Any additional arguments needed by the form building function.
+ * @return
+ *   Any form validation errors encountered.
+ */
+ function drupal_execute($form_id, $form_values) {
   $args = func_get_args();
-  $form = call_user_func_array('drupal_retrieve_form', $args);
-  drupal_process_form($form_id, $form);
-  return drupal_render_form($form_id, $form);
+
+  $form_id = array_shift($args);
+  $form_values = array_shift($args);
+  array_unshift($args, $form_id);
+  
+  if (isset($form_values)) {
+    $form = call_user_func_array('drupal_retrieve_form', $args);
+    $form['#post']['edit'] = $form_values;
+    drupal_process_form($form_id, $form);
+    
+    return form_get_errors();
+  }
 }
 
 /**
@@ -90,7 +175,9 @@ function drupal_retrieve_form($form_id) 
     }
   }
   // $callback comes from a hook_forms() implementation
-  return call_user_func_array(isset($callback) ? $callback : $form_id, $args);
+  $form = call_user_func_array(isset($callback) ? $callback : $form_id, $args);
+  $form['#parameters'] = func_get_args();
+  return $form;
 }
 
 /**
@@ -158,6 +245,17 @@ function drupal_prepare_form($form_id, &
     $form['#programmed'] = TRUE;
   }
 
+  // In multi-step form scenerios, this id is used to identify
+  // a unique instance of a particular form for retrieval.
+  if (isset($form['#build_id'])) {
+    $form['form_build_id'] = array(
+      '#type' => 'hidden',
+      '#value' => $form['#build_id'],
+      '#id' => $form['#build_id'],
+      '#name' => 'form_build_id',
+    );
+  }
+
   // If $base is set, it is used in place of $form_id when constructing validation,
   // submission, and theming functions. Useful for mapping many similar or duplicate
   // forms with different $form_ids to the same processing functions.
@@ -500,38 +598,40 @@ function form_builder($form_id, $form) {
         foreach ($form['#parents'] as $parent) {
           $edit = isset($edit[$parent]) ? $edit[$parent] : NULL;
         }
-        switch ($form['#type']) {
-          case 'checkbox':
-            $form['#value'] = !empty($edit) ? $form['#return_value'] : 0;
-            break;
-          case 'select':
-            if (isset($form['#multiple']) && $form['#multiple']) {
-              if (isset($edit) && is_array($edit)) {
-                $form['#value'] = drupal_map_assoc($edit);
+        if (!$form['#programmed'] || isset($edit)) {
+          switch ($form['#type']) {
+            case 'checkbox':
+              $form['#value'] = !empty($edit) ? $form['#return_value'] : 0;
+              break;
+            case 'select':
+              if (isset($form['#multiple']) && $form['#multiple']) {
+                if (isset($edit) && is_array($edit)) {
+                  $form['#value'] = drupal_map_assoc($edit);
+                }
+                else {
+                  $form['#value'] = array();
+                }
               }
-              else {
-                $form['#value'] = array();
+              elseif (isset($edit)) {
+                $form['#value'] = $edit;
               }
-            }
-            elseif (isset($edit)) {
-              $form['#value'] = $edit;
-            }
-            break;
-          case 'textfield':
-            if (isset($edit)) {
-              // Equate $edit to the form value to ensure it's marked for validation
-              $edit = str_replace(array("\r", "\n"), '', $edit);
-              $form['#value'] = $edit;
-            }
-            break;
-          default:
-            if (isset($edit)) {
-              $form['#value'] = $edit;
-            }
-        }
-        // Mark all posted values for validation
-        if ((isset($form['#value']) && $form['#value'] === $edit) || (isset($form['#required']) && $form['#required'])) {
-          $form['#needs_validation'] = TRUE;
+              break;
+            case 'textfield':
+              if (isset($edit)) {
+                // Equate $edit to the form value to ensure it's marked for validation
+                $edit = str_replace(array("\r", "\n"), '', $edit);
+                $form['#value'] = $edit;
+              }
+              break;
+            default:
+              if (isset($edit)) {
+                $form['#value'] = $edit;
+              }
+          }
+          // Mark all posted values for validation
+          if ((isset($form['#value']) && $form['#value'] === $edit) || (isset($form['#required']) && $form['#required'])) {
+            $form['#needs_validation'] = TRUE;
+          }
         }
       }
       if (!isset($form['#value'])) {
