=== modified file 'includes/common.inc'
--- includes/common.inc	2010-07-24 17:28:25 +0000
+++ includes/common.inc	2010-08-01 01:43:41 +0000
@@ -658,6 +658,13 @@ function drupal_encode_path($path) {
  * @see url()
  */
 function drupal_goto($path = '', array $options = array(), $http_response_code = 302) {
+  if ($delayed = &drupal_static('drupal_goto_delayed')) {
+    // Avoid infinite loop by deleting the delayed flag.
+    $delayed = FALSE;
+    // By quitting here the registered drupal_goto() will fire.
+    exit;
+  }
+
   // A destination in $_GET always overrides the function arguments.
   // We do not allow absolute URLs to be passed via $_GET, as this can be an attack vector.
   if (isset($_GET['destination']) && !url_is_external($_GET['destination'])) {
@@ -683,6 +690,18 @@ function drupal_goto($path = '', array $
 }
 
 /**
+ * Send the user to a different Drupal page.
+ *
+ * This function behaves the same as drupal_goto() does but the redirect only
+ * fires at the end of the request.
+ */
+function drupal_goto_delayed($path = '', array $options = array(), $http_response_code = 302) {
+  $delayed = &drupal_static(__FUNCTION__);
+  $delayed = TRUE;
+  drupal_register_shutdown_function('drupal_goto', $path, $options, $http_response_code);
+}
+
+/**
  * Deliver a "site is under maintenance" message to the browser.
  *
  * Page callback functions wanting to report a "site offline" message should
@@ -2149,7 +2168,7 @@ function url($path = NULL, array $option
  * @param $path
  *   The internal path or external URL being linked to, such as "node/34" or
  *   "http://example.com/foo".
- * @return 
+ * @return
  *   Boolean TRUE or FALSE, where TRUE indicates an external path.
  */
 function url_is_external($path) {
@@ -6698,7 +6717,7 @@ function entity_form_field_validate($ent
  * For some entity forms (e.g., forms with complex non-field data and forms that
  * simultaneously edit multiple entities), this behavior may be inappropriate,
  * so the #builder_function for such forms needs to implement the required
- * functionality instead of calling this function. 
+ * functionality instead of calling this function.
  */
 function entity_form_submit_build_entity($entity_type, $entity, $form, &$form_state) {
   $info = entity_get_info($entity_type);

=== modified file 'modules/system/system.module'
--- modules/system/system.module	2010-07-26 03:04:29 +0000
+++ modules/system/system.module	2010-08-01 01:44:52 +0000
@@ -3081,7 +3081,11 @@ function system_goto_action_submit($form
  * @ingroup actions
  */
 function system_goto_action($entity, $context) {
-  drupal_goto(token_replace($context['url'], $context));
+  unset($_GET['destination']);
+  // Do not redirect during batch processing.
+  if (arg(0) != 'batch') {
+    drupal_goto_delayed(token_replace($context['url'], $context));
+  }
 }
 
 /**

=== modified file 'modules/trigger/trigger.test'
--- modules/trigger/trigger.test	2010-06-29 18:24:10 +0000
+++ modules/trigger/trigger.test	2010-08-01 01:55:03 +0000
@@ -567,7 +567,7 @@ class TriggerOtherTestCase extends Trigg
     $this->drupalPost('admin/structure/trigger/user', $edit, t('Assign'), array(), array(), 'trigger-user-insert-assign-form');
 
     // Set action variable to FALSE.
-    variable_set( $action_id, FALSE );
+    variable_set($action_id, FALSE);
 
     // Create an unblocked user
     $web_user = $this->drupalCreateUser(array('administer users'));
@@ -600,15 +600,35 @@ class TriggerOtherTestCase extends Trigg
     $edit = array('aid' => drupal_hash_base64($aid));
     $this->drupalPost('admin/structure/trigger/user', $edit, t('Assign'), array(), array(), 'trigger-user-login-assign-form');
 
+    // Assign a configurable action 'Redirect to URL' to the user_login trigger.
+    $action_url_edit = array(
+      'actions_label' => $this->randomName(16),
+      'url' => 'contact',
+    );
+    $aid_url = $this->configureAdvancedAction('system_goto_action', $action_url_edit);
+    $edit = array('aid' => drupal_hash_base64($aid_url));
+    $this->drupalPost('admin/structure/trigger/user', $edit, t('Assign'), array(), array(), 'trigger-user-login-assign-form');
+
     // Verify that the action has been assigned to the correct hook.
     $actions = trigger_get_assigned_actions('user_login');
-    $this->assertEqual(1, count($actions), t('One Action assigned to the hook'));
+    $this->assertEqual(2, count($actions), t('Two Actions assigned to the hook'));
     $this->assertEqual($actions[$aid]['label'], $action_edit['actions_label'], t('Correct action label found.'));
+    $this->assertEqual($actions[$aid_url]['label'], $action_url_edit['actions_label'], t('Correct action label found.'));
 
     // User should get the configured message at login.
-    $contact_user = $this->drupalCreateUser(array('access site-wide contact form'));;
-    $this->drupalLogin($contact_user);
+    $contact_user = $this->drupalCreateUser(array('access site-wide contact form'));
+    $this->drupalLogout();
+
+    // Trying to login from different page to be redirected.
+    $edit = array(
+      'name' => $contact_user->name,
+      'pass' => $contact_user->pass_raw,
+    );
+    $this->drupalPost('filter/tips', $edit, t('Log in'));
     $this->assertText($action_edit['message']);
+
+    // Verify that redirect happened.
+    $this->assertEqual(url('contact', array('absolute' => TRUE)), $this->url, t('Redirected successfully by the trigger.'));
   }
 
   /**

