diff --git a/modules/blog.module b/modules/blog.module
index 4b8ca34fbc2f61d7aa783229016b6c4f0064faee..16e6c78a64594449f666760fe02e99c38360a473 100644
--- a/modules/blog.module
+++ b/modules/blog.module
@@ -198,7 +198,7 @@ function blog_page_last() {
 /**
  * Implementation of hook_validate().
  */
-function blog_validate(&$node) {
+function blog_validate($node) {
   node_validate_title($node);
 }
 
diff --git a/modules/blog/blog.module b/modules/blog/blog.module
index 4b8ca34fbc2f61d7aa783229016b6c4f0064faee..16e6c78a64594449f666760fe02e99c38360a473 100644
--- a/modules/blog/blog.module
+++ b/modules/blog/blog.module
@@ -198,7 +198,7 @@ function blog_page_last() {
 /**
  * Implementation of hook_validate().
  */
-function blog_validate(&$node) {
+function blog_validate($node) {
   node_validate_title($node);
 }
 
diff --git a/modules/book.module b/modules/book.module
index f190c57d24e5af5d49b5fc468824ae5cf36aa7f4..ceeeff80dbec9c26535fce945fc8e4f1751b9256 100644
--- a/modules/book.module
+++ b/modules/book.module
@@ -221,15 +221,20 @@ function book_delete(&$node) {
 }
 
 /**
- * Implementation of hook_validate().
+ * Implementation of hook_execute().
  */
-function book_validate(&$node) {
+function book_execute(&$node) {
   // Set default values for non-administrators.
   if (!user_access('administer nodes')) {
     $node->weight = 0;
     $node->revision = 1;
   }
+}
 
+/**
+ * Implementation of hook_validate().
+ */
+function book_validate($node) {
   node_validate_title($node);
 }
 
diff --git a/modules/book/book.module b/modules/book/book.module
index f190c57d24e5af5d49b5fc468824ae5cf36aa7f4..ceeeff80dbec9c26535fce945fc8e4f1751b9256 100644
--- a/modules/book/book.module
+++ b/modules/book/book.module
@@ -221,15 +221,20 @@ function book_delete(&$node) {
 }
 
 /**
- * Implementation of hook_validate().
+ * Implementation of hook_execute().
  */
-function book_validate(&$node) {
+function book_execute(&$node) {
   // Set default values for non-administrators.
   if (!user_access('administer nodes')) {
     $node->weight = 0;
     $node->revision = 1;
   }
+}
 
+/**
+ * Implementation of hook_validate().
+ */
+function book_validate($node) {
   node_validate_title($node);
 }
 
diff --git a/modules/forum.module b/modules/forum.module
index 931033a9846b7f48a6cb62c40432057fad903943..726bbf938b4d787785218481bea9b8962061d500 100644
--- a/modules/forum.module
+++ b/modules/forum.module
@@ -506,30 +506,21 @@ function forum_view(&$node, $teaser = FALSE, $page = FALSE) {
 }
 
 /**
- * Implementation of hook_validate().
+ * Implementation of hook_execute().
  *
  * Check in particular that only a "leaf" term in the associated taxonomy
  * vocabulary is selected, not a "container" term.
  */
-function forum_validate(&$node) {
+function forum_execute(&$node) {
   // Make sure all fields are set properly:
   $node->icon = $node->icon ? $node->icon : '';
 
-  node_validate_title($node,t('You have to specify a subject.'));
-
   if ($node->taxonomy) {
     // Extract the node's proper topic ID.
     $vocabulary = variable_get('forum_nav_vocabulary', '');
-    $containers = variable_get('forum_containers', array());
     foreach ($node->taxonomy as $term) {
       if (db_result(db_query('SELECT COUNT(*) FROM {term_data} WHERE tid = %d AND vid = %d', $term, $vocabulary))) {
-        if (in_array($term, $containers)) {
-          $term = taxonomy_get_term($term);
-          form_set_error('taxonomy', t('The item %forum is only a container for forums. Please select one of the forums below it.', array('%forum' => theme('placeholder', $term->name))));
-        }
-        else {
-          $node->tid = $term;
-        }
+        $node->tid = $term;
       }
     }
     if ($node->tid && $node->shadow) {
@@ -542,6 +533,30 @@ function forum_validate(&$node) {
   }
 }
 
+/**
+ * Implementation of hook_validate().
+ *
+ * Check in particular that only a "leaf" term in the associated taxonomy
+ * vocabulary is selected, not a "container" term.
+ */
+function forum_validate($node) {
+  node_validate_title($node,t('You have to specify a subject.'));
+
+  if ($node->taxonomy) {
+    // Extract the node's proper topic ID.
+    $vocabulary = variable_get('forum_nav_vocabulary', '');
+    $containers = variable_get('forum_containers', array());
+    foreach ($node->taxonomy as $term) {
+      if (db_result(db_query('SELECT COUNT(*) FROM {term_data} WHERE tid = %d AND vid = %d', $term, $vocabulary))) {
+        if (in_array($term, $containers)) {
+          $term = taxonomy_get_term($term);
+          form_set_error('taxonomy', t('The item %forum is only a container for forums. Please select one of the forums below it.', array('%forum' => theme('placeholder', $term->name))));
+        }
+      }
+    }
+  }
+}
+
 /**
  * Implementation of hook_update().
  */
@@ -571,7 +586,7 @@ function forum_form(&$node) {
   if ($node->nid) {
     // if editing, give option to leave shadows
     $shadow = (count(taxonomy_node_get_terms($node->nid)) > 1);
-    $form['shadow'] = array('#type' => 'checkbox', 'title' => t('Leave shadow copy'),  '#default_value' => $shadow, '#description' => t('If you move this topic, you can leave a link in the old forum to the new forum.'));
+    $form['shadow'] = array('#type' => 'checkbox', '#title' => t('Leave shadow copy'), '#default_value' => $shadow, '#description' => t('If you move this topic, you can leave a link in the old forum to the new forum.'));
   }
 
   $form['body'] = array('#type' => 'textarea', '#title' => t('Body'), '#default_value' => $node->body, '#required' => TRUE
diff --git a/modules/forum/forum.module b/modules/forum/forum.module
index 931033a9846b7f48a6cb62c40432057fad903943..726bbf938b4d787785218481bea9b8962061d500 100644
--- a/modules/forum/forum.module
+++ b/modules/forum/forum.module
@@ -506,30 +506,21 @@ function forum_view(&$node, $teaser = FALSE, $page = FALSE) {
 }
 
 /**
- * Implementation of hook_validate().
+ * Implementation of hook_execute().
  *
  * Check in particular that only a "leaf" term in the associated taxonomy
  * vocabulary is selected, not a "container" term.
  */
-function forum_validate(&$node) {
+function forum_execute(&$node) {
   // Make sure all fields are set properly:
   $node->icon = $node->icon ? $node->icon : '';
 
-  node_validate_title($node,t('You have to specify a subject.'));
-
   if ($node->taxonomy) {
     // Extract the node's proper topic ID.
     $vocabulary = variable_get('forum_nav_vocabulary', '');
-    $containers = variable_get('forum_containers', array());
     foreach ($node->taxonomy as $term) {
       if (db_result(db_query('SELECT COUNT(*) FROM {term_data} WHERE tid = %d AND vid = %d', $term, $vocabulary))) {
-        if (in_array($term, $containers)) {
-          $term = taxonomy_get_term($term);
-          form_set_error('taxonomy', t('The item %forum is only a container for forums. Please select one of the forums below it.', array('%forum' => theme('placeholder', $term->name))));
-        }
-        else {
-          $node->tid = $term;
-        }
+        $node->tid = $term;
       }
     }
     if ($node->tid && $node->shadow) {
@@ -542,6 +533,30 @@ function forum_validate(&$node) {
   }
 }
 
+/**
+ * Implementation of hook_validate().
+ *
+ * Check in particular that only a "leaf" term in the associated taxonomy
+ * vocabulary is selected, not a "container" term.
+ */
+function forum_validate($node) {
+  node_validate_title($node,t('You have to specify a subject.'));
+
+  if ($node->taxonomy) {
+    // Extract the node's proper topic ID.
+    $vocabulary = variable_get('forum_nav_vocabulary', '');
+    $containers = variable_get('forum_containers', array());
+    foreach ($node->taxonomy as $term) {
+      if (db_result(db_query('SELECT COUNT(*) FROM {term_data} WHERE tid = %d AND vid = %d', $term, $vocabulary))) {
+        if (in_array($term, $containers)) {
+          $term = taxonomy_get_term($term);
+          form_set_error('taxonomy', t('The item %forum is only a container for forums. Please select one of the forums below it.', array('%forum' => theme('placeholder', $term->name))));
+        }
+      }
+    }
+  }
+}
+
 /**
  * Implementation of hook_update().
  */
@@ -571,7 +586,7 @@ function forum_form(&$node) {
   if ($node->nid) {
     // if editing, give option to leave shadows
     $shadow = (count(taxonomy_node_get_terms($node->nid)) > 1);
-    $form['shadow'] = array('#type' => 'checkbox', 'title' => t('Leave shadow copy'),  '#default_value' => $shadow, '#description' => t('If you move this topic, you can leave a link in the old forum to the new forum.'));
+    $form['shadow'] = array('#type' => 'checkbox', '#title' => t('Leave shadow copy'), '#default_value' => $shadow, '#description' => t('If you move this topic, you can leave a link in the old forum to the new forum.'));
   }
 
   $form['body'] = array('#type' => 'textarea', '#title' => t('Body'), '#default_value' => $node->body, '#required' => TRUE
diff --git a/modules/node.module b/modules/node.module
index bc9881bd507e2ff671117cee6f216c0f583a7997..875124154328c65c82241a25bb687c9c366b2b3e 100644
--- a/modules/node.module
+++ b/modules/node.module
@@ -1476,52 +1476,30 @@ function node_feed($nodes = 0, $channel = array()) {
 }
 
 /**
- * Perform validation checks on the given node.
+ * Prepare node for save and allow modules to make changes.
  */
-function node_validate($node) {
+function node_execute($node) {
   global $user;
 
   // Convert the node to an object, if necessary.
   $node = array2object($node);
 
-  // Make sure the body has the minimum number of words.
-  // todo use a better word counting algorithm that will work in other languages
-  if (isset($node->body) && count(explode(' ', $node->body)) < variable_get('minimum_'. $node->type .'_size', 0)) {
-    form_set_error('body', t('The body of your %type is too short. You need at least %words words.', array('%words' => variable_get('minimum_'. $node->type .'_size', 0), '%type' => node_get_name($node))));
-  }
-
   // Auto-generate the teaser, but only if it hasn't been set (e.g. by a
   // module-provided 'teaser' form item).
   if (!isset($node->teaser)) {
     $node->teaser = isset($node->body) ? node_teaser($node->body, isset($node->format) ? $node->format : NULL) : '';
   }
 
-  if (isset($node->nid) && (node_last_changed($node->nid) > $node->changed)) {
-    form_set_error('changed', t('This content has been modified by another user, unable to save changes.'));
-  }
-
   if (user_access('administer nodes')) {
-    // Validate the "authored by" field.
-    if (empty($node->name)) {
-      // The use of empty() is mandatory in the context of usernames
-      // as the empty string denotes the anonymous user.  In case we
-      // are dealing with an anonymous user we set the user ID to 0.
-      $node->uid = 0;
-    }
-    else if ($account = user_load(array('name' => $node->name))) {
+    // Populate the "authored by" field.
+    if ($account = user_load(array('name' => $node->name))) {
       $node->uid = $account->uid;
     }
     else {
-      form_set_error('name', t('The username %name does not exist.', array ('%name' => theme('placeholder', $node->name))));
+      $node->uid = 0;
     }
 
-    // Validate the "authored on" field.
-    if (strtotime($node->date) != -1) {
-      $node->created = strtotime($node->date);
-    }
-    else {
-      form_set_error('date', t('You have to specify a valid date.'));
-    }
+    $node->created = strtotime($node->date);
   }
   else {
     // Validate for normal users:
@@ -1537,14 +1515,51 @@ function node_validate($node) {
   }
 
   // Do node-type-specific validation checks.
-  node_invoke($node, 'validate');
-  node_invoke_nodeapi($node, 'validate');
+  node_invoke($node, 'execute');
+  node_invoke_nodeapi($node, 'execute');
 
   $node->validated = TRUE;
 
   return $node;
 }
 
+/**
+ * Perform validation checks on the given node.
+ */
+function node_validate($node) {
+  // Convert the node to an object, if necessary.
+  $node = array2object($node);
+
+  // Make sure the body has the minimum number of words.
+  // todo use a better word counting algorithm that will work in other languages
+  if (isset($node->body) && count(explode(' ', $node->body)) < variable_get('minimum_'. $node->type .'_size', 0)) {
+    form_set_error('body', t('The body of your %type is too short. You need at least %words words.', array('%words' => variable_get('minimum_'. $node->type .'_size', 0), '%type' => node_get_name($node))));
+  }
+
+  if (isset($node->nid) && (node_last_changed($node->nid) > $node->changed)) {
+    form_set_error('changed', t('This content has been modified by another user, unable to save changes.'));
+  }
+
+  if (user_access('administer nodes')) {
+    // Validate the "authored by" field.
+    if (!empty($node->name) && !($account = user_load(array('name' => $node->name)))) {
+      // The use of empty() is mandatory in the context of usernames
+      // as the empty string denotes the anonymous user.  In case we
+      // are dealing with an anonymous user we set the user ID to 0.
+      form_set_error('name', t('The username %name does not exist.', array ('%name' => theme('placeholder', $node->name))));
+    }
+
+    // Validate the "authored on" field.
+    if (strtotime($node->date) == -1) {
+      form_set_error('date', t('You have to specify a valid date.'));
+    }
+  }
+
+  // Do node-type-specific validation checks.
+  node_invoke($node, 'validate');
+  node_invoke_nodeapi($node, 'validate');
+}
+
 
 /**
  * Validate the title of a node
@@ -1796,12 +1811,7 @@ function node_form_execute($form_id, $edit) {
   global $user;
 
   // Fix up the node when required:
-  $node = node_validate($edit);
-
-  // If something went wrong, go back to the preview form.
-  if (form_get_errors()) {
-    return node_form($edit);
-  }
+  $node = node_execute($edit);
 
   // Prepare the node's body:
   if ($node->nid) {
diff --git a/modules/node/node.module b/modules/node/node.module
index bc9881bd507e2ff671117cee6f216c0f583a7997..875124154328c65c82241a25bb687c9c366b2b3e 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -1476,52 +1476,30 @@ function node_feed($nodes = 0, $channel = array()) {
 }
 
 /**
- * Perform validation checks on the given node.
+ * Prepare node for save and allow modules to make changes.
  */
-function node_validate($node) {
+function node_execute($node) {
   global $user;
 
   // Convert the node to an object, if necessary.
   $node = array2object($node);
 
-  // Make sure the body has the minimum number of words.
-  // todo use a better word counting algorithm that will work in other languages
-  if (isset($node->body) && count(explode(' ', $node->body)) < variable_get('minimum_'. $node->type .'_size', 0)) {
-    form_set_error('body', t('The body of your %type is too short. You need at least %words words.', array('%words' => variable_get('minimum_'. $node->type .'_size', 0), '%type' => node_get_name($node))));
-  }
-
   // Auto-generate the teaser, but only if it hasn't been set (e.g. by a
   // module-provided 'teaser' form item).
   if (!isset($node->teaser)) {
     $node->teaser = isset($node->body) ? node_teaser($node->body, isset($node->format) ? $node->format : NULL) : '';
   }
 
-  if (isset($node->nid) && (node_last_changed($node->nid) > $node->changed)) {
-    form_set_error('changed', t('This content has been modified by another user, unable to save changes.'));
-  }
-
   if (user_access('administer nodes')) {
-    // Validate the "authored by" field.
-    if (empty($node->name)) {
-      // The use of empty() is mandatory in the context of usernames
-      // as the empty string denotes the anonymous user.  In case we
-      // are dealing with an anonymous user we set the user ID to 0.
-      $node->uid = 0;
-    }
-    else if ($account = user_load(array('name' => $node->name))) {
+    // Populate the "authored by" field.
+    if ($account = user_load(array('name' => $node->name))) {
       $node->uid = $account->uid;
     }
     else {
-      form_set_error('name', t('The username %name does not exist.', array ('%name' => theme('placeholder', $node->name))));
+      $node->uid = 0;
     }
 
-    // Validate the "authored on" field.
-    if (strtotime($node->date) != -1) {
-      $node->created = strtotime($node->date);
-    }
-    else {
-      form_set_error('date', t('You have to specify a valid date.'));
-    }
+    $node->created = strtotime($node->date);
   }
   else {
     // Validate for normal users:
@@ -1537,14 +1515,51 @@ function node_validate($node) {
   }
 
   // Do node-type-specific validation checks.
-  node_invoke($node, 'validate');
-  node_invoke_nodeapi($node, 'validate');
+  node_invoke($node, 'execute');
+  node_invoke_nodeapi($node, 'execute');
 
   $node->validated = TRUE;
 
   return $node;
 }
 
+/**
+ * Perform validation checks on the given node.
+ */
+function node_validate($node) {
+  // Convert the node to an object, if necessary.
+  $node = array2object($node);
+
+  // Make sure the body has the minimum number of words.
+  // todo use a better word counting algorithm that will work in other languages
+  if (isset($node->body) && count(explode(' ', $node->body)) < variable_get('minimum_'. $node->type .'_size', 0)) {
+    form_set_error('body', t('The body of your %type is too short. You need at least %words words.', array('%words' => variable_get('minimum_'. $node->type .'_size', 0), '%type' => node_get_name($node))));
+  }
+
+  if (isset($node->nid) && (node_last_changed($node->nid) > $node->changed)) {
+    form_set_error('changed', t('This content has been modified by another user, unable to save changes.'));
+  }
+
+  if (user_access('administer nodes')) {
+    // Validate the "authored by" field.
+    if (!empty($node->name) && !($account = user_load(array('name' => $node->name)))) {
+      // The use of empty() is mandatory in the context of usernames
+      // as the empty string denotes the anonymous user.  In case we
+      // are dealing with an anonymous user we set the user ID to 0.
+      form_set_error('name', t('The username %name does not exist.', array ('%name' => theme('placeholder', $node->name))));
+    }
+
+    // Validate the "authored on" field.
+    if (strtotime($node->date) == -1) {
+      form_set_error('date', t('You have to specify a valid date.'));
+    }
+  }
+
+  // Do node-type-specific validation checks.
+  node_invoke($node, 'validate');
+  node_invoke_nodeapi($node, 'validate');
+}
+
 
 /**
  * Validate the title of a node
@@ -1796,12 +1811,7 @@ function node_form_execute($form_id, $edit) {
   global $user;
 
   // Fix up the node when required:
-  $node = node_validate($edit);
-
-  // If something went wrong, go back to the preview form.
-  if (form_get_errors()) {
-    return node_form($edit);
-  }
+  $node = node_execute($edit);
 
   // Prepare the node's body:
   if ($node->nid) {
diff --git a/modules/page.module b/modules/page.module
index 56fb29ad568af479c69bbde1a2462948996e71a2..cd86d24b4594030780ce9a5f8aced270b630db2a 100644
--- a/modules/page.module
+++ b/modules/page.module
@@ -82,7 +82,7 @@ function page_menu($may_cache) {
 /**
  * Implementation of hook_validate().
  */
-function page_validate(&$node) {
+function page_validate($node) {
   node_validate_title($node);
 }
 
diff --git a/modules/page/page.module b/modules/page/page.module
index 56fb29ad568af479c69bbde1a2462948996e71a2..cd86d24b4594030780ce9a5f8aced270b630db2a 100644
--- a/modules/page/page.module
+++ b/modules/page/page.module
@@ -82,7 +82,7 @@ function page_menu($may_cache) {
 /**
  * Implementation of hook_validate().
  */
-function page_validate(&$node) {
+function page_validate($node) {
   node_validate_title($node);
 }
 
diff --git a/modules/poll.module b/modules/poll.module
index 89e2757f316b1dd75233f79b5f4b9a8425a2b931..8ee7c3b3a562e77185e234cba79aef2e08ee8791 100644
--- a/modules/poll.module
+++ b/modules/poll.module
@@ -89,12 +89,20 @@ function poll_delete($node) {
   db_query("DELETE FROM {poll_choices} WHERE nid = %d", $node->nid);
 }
 
+/**
+ * Implementation of hook_execute().
+ */
+function poll_execute(&$node) {
+  // Renumber fields
+  $node->choice = array_values($node->choice);
+  $node->teaser = poll_teaser($node);
+}
+ 
 /**
  * Implementation of hook_validate().
  */
-function poll_validate(&$node) {
-
-  node_validate_title($node,t('You have to specify a question.'));
+function poll_validate($node) {
+  node_validate_title($node, t('You have to specify a question.'));
 
   if (isset($node->title)) {
     // Check for at least two options and validate amount of votes:
@@ -114,8 +122,6 @@ function poll_validate(&$node) {
       form_set_error("choice][$realchoices][chtext", t('You must fill in at least two choices.'));
     }
   }
-
-  $node->teaser = poll_teaser($node);
 }
 
 /**
diff --git a/modules/poll/poll.module b/modules/poll/poll.module
index 89e2757f316b1dd75233f79b5f4b9a8425a2b931..8ee7c3b3a562e77185e234cba79aef2e08ee8791 100644
--- a/modules/poll/poll.module
+++ b/modules/poll/poll.module
@@ -89,12 +89,20 @@ function poll_delete($node) {
   db_query("DELETE FROM {poll_choices} WHERE nid = %d", $node->nid);
 }
 
+/**
+ * Implementation of hook_execute().
+ */
+function poll_execute(&$node) {
+  // Renumber fields
+  $node->choice = array_values($node->choice);
+  $node->teaser = poll_teaser($node);
+}
+ 
 /**
  * Implementation of hook_validate().
  */
-function poll_validate(&$node) {
-
-  node_validate_title($node,t('You have to specify a question.'));
+function poll_validate($node) {
+  node_validate_title($node, t('You have to specify a question.'));
 
   if (isset($node->title)) {
     // Check for at least two options and validate amount of votes:
@@ -114,8 +122,6 @@ function poll_validate(&$node) {
       form_set_error("choice][$realchoices][chtext", t('You must fill in at least two choices.'));
     }
   }
-
-  $node->teaser = poll_teaser($node);
 }
 
 /**
diff --git a/modules/story.module b/modules/story.module
index 272e86a3bd1633af4f8668fa1301bab71bd7aee2..6f7621be47bbc0eae2e766221b60aa509ffb5232 100644
--- a/modules/story.module
+++ b/modules/story.module
@@ -77,7 +77,7 @@ function story_menu($may_cache) {
 /**
  * Implementation of hook_validate().
  */
-function story_validate(&$node) {
+function story_validate($node) {
   node_validate_title($node);
 }
 
diff --git a/modules/story/story.module b/modules/story/story.module
index 272e86a3bd1633af4f8668fa1301bab71bd7aee2..6f7621be47bbc0eae2e766221b60aa509ffb5232 100644
--- a/modules/story/story.module
+++ b/modules/story/story.module
@@ -77,7 +77,7 @@ function story_menu($may_cache) {
 /**
  * Implementation of hook_validate().
  */
-function story_validate(&$node) {
+function story_validate($node) {
   node_validate_title($node);
 }