diff -uprN terms_of_use.orig/terms_of_use.admin.inc terms_of_use/terms_of_use.admin.inc
--- terms_of_use.orig/terms_of_use.admin.inc	1969-12-31 16:00:00.000000000 -0800
+++ terms_of_use/terms_of_use.admin.inc	2010-04-03 21:00:04.000000000 -0700
@@ -0,0 +1,528 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Administration settings for Terms of Use module.
+ */
+
+/**
+ * Get an associative array of all checkbox label translations
+ */
+function _terms_of_use_checkbox_label_all_translations() {
+  $ret = array();
+  if (module_exists('i18n')) {
+    $result = db_query("SELECT * FROM {i18n_variable} WHERE name='%s'", 'terms_of_use_checkbox_label');
+    while ($variable = db_fetch_object($result)) {
+      if ($variable->language) // Ignore default settings (it is in one of the language variables)
+        $ret[$variable->language] = unserialize($variable->value);
+    }
+  } else {
+    global $language;
+    $ret[$language->language] = check_plain(variable_get('terms_of_use_checkbox_label', t('I agree with these terms.')));
+  }
+  return $ret;
+}
+
+/**
+ * Menu callback; show settings form.
+ * @see terms_of_use_admin_settings_validate()
+ *
+ */
+function terms_of_use_admin_settings() {
+
+  // Adding the fieldset for node specification.
+  $form['terms_of_use_text'] = array(
+    '#type' => 'fieldset',
+    '#prefix' => '<div id="fieldset-wrapper">',
+    '#suffix' => '</div>',
+    //'#title' => t('Terms of Use text'),
+  );
+  // Node may have been renamed... pick current title
+  $title = '';
+  $nid = variable_get('terms_of_use_node_id', '');
+  if ($nid != '') {
+    $node = node_load($nid);
+    variable_set('terms_of_use_node_title', $node->title);
+  }
+  $form['terms_of_use_text']['terms_of_use_node_title'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Title of the post where your Terms of Use are published'),
+    '#default_value' => variable_get('terms_of_use_node_title', ''),
+    '#description' => t('Node <em>title</em> of the page or story (or blog entry or book page) where your Terms of Use are published. Leave empty to disable Terms of Use.'),
+    '#autocomplete_path' => 'node/autocomplete',
+  );
+  $form['terms_of_use_text']['terms_of_use_pick_node_id'] = array(
+    '#type' => 'button',
+    '#value' => t('I prefer to specify the node id'),
+    '#weight' => 10,
+    '#ahah' => array(
+      'path' => 'terms_of_use/js',
+      'wrapper' => 'fieldset-wrapper',
+    ),
+  );
+  // Adding the fieldset for form specification.
+  $form['terms_of_use_form'] = array(
+    '#type' => 'fieldset',
+  );
+  $form['terms_of_use_form']['terms_of_use_title'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Title for Terms of Use'),
+    '#default_value' => variable_get('terms_of_use_title', t('Terms of Use')),
+    '#description' => t('The title for the Terms of Use revision acceptance form and fieldset on user registration.'),
+  );
+  $form['terms_of_use_form']['terms_of_use_fieldset'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Use fieldset for Terms of Use'),
+    '#default_value' => variable_get('terms_of_use_fieldset', 1),
+    '#description' => t('Enclose the text for the Terms of Use and the [x] checkbox in a fieldset.'),
+  );
+  $form['terms_of_use_form']['terms_of_use_checkbox_label'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Label for the ckeckbox'),
+    '#default_value' => variable_get('terms_of_use_checkbox_label', t('I agree with these terms.')),
+    '#description' => t('Type here something like "I agree with these terms." or "I CERTIFY THAT I AM OVER THE AGE OF 18 YEARS OLD.", without quotes.<br>You can use the token @link to insert a link to the Terms in this label, or @"Post Title" to insert a link to a post with title "Post Title" (without quotes).<br>For example, the label can be: "I agree with the @link.", without quotes. You may want to link to the Terms if you prefer not to show the full text of the Terms in the registration form.<br>If you use any tokens, the full text of the Terms will not be shown.'),
+  );
+  $form['terms_of_use_form']['terms_of_use_node_height'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Limit height of the full text of the Terms'),
+    '#default_value' => variable_get('terms_of_use_node_height', ''),
+    '#description' => t('Leave empty to show Terms text in full height. Type here something like "20em" or "120px" without quotes to set the height of the full text and use vertical scrollbar.'),
+  );
+  
+  $form['terms_of_use_advanced'] = array(
+    '#type' => 'fieldset',
+  );
+  $version = variable_get('terms_of_use_version', 1);
+  $options = array(
+    $version => t('@version (current version)', array('@version' => $version)),
+    $version + 1 => t('@version (add a new version)', array('@version' => $version + 1)),
+  );
+  
+  $form['terms_of_use_advanced']['terms_of_use_version'] = array(
+    '#type' => 'radios',
+    '#title' => t('Terms of use version'),
+    '#description' => t('WARNING: Changing this value will force all logged-in users to accept the new terms of use before they can do anything else on the site.'),
+    '#options' => $options,
+    '#default_value' => $version,
+  );
+
+  //Show a preview of terms of use form
+  $preview_form = array();
+  $form_state = array();
+  terms_of_use_form_user_register_alter($preview_form, $form_state);
+  unset($preview_form['terms_of_use']['I_agree']['#element_validate']);
+  unset($preview_form['I_agree']['#element_validate']);
+
+  $form['terms_of_use_preview'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Preview'),
+    '#description' => t('This is a preview of current configuration. To see how your changes will look, you have to save configuration.'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+  if ($preview_form) {
+    $form['terms_of_use_preview'] += $preview_form;
+  } else {
+    $form['terms_of_use_preview']['#description'] .= '<br>' . t('(Terms of Use disabled)');
+  }
+  $form = system_settings_form($form);
+  $form['#submit'][] = 'terms_of_use_admin_settings_submit';
+  return $form;
+}
+
+/**
+ * Validate the terms_of_use_admin_settings form.
+ *
+ * @see terms_of_use_admin_settings()
+ */
+function terms_of_use_admin_settings_validate($form, &$form_state) {
+  // Check if settings require node id (for @link)
+  $checkbox_label = check_plain($form_state['values']['terms_of_use_checkbox_label']);
+  $use_node = (strpos($checkbox_label, '@link') !== FALSE);
+  $use_links = (strpos($checkbox_label, '@&quot;') !== FALSE);
+  
+  // Check node_id or node_title
+  $nid = $form_state['values']['terms_of_use_node_id'];
+  if (isset($nid)) {
+    if (empty($nid)) {
+      // Empty means "disabled", unless @link is set
+      if ($use_node) {
+        form_set_error('terms_of_use_node_id', t('You used @link token. You must specify a node <em>nid</em>.')); 
+      } else {
+        variable_set('terms_of_use_node_title', '');
+        drupal_set_message($use_links ? t('Terms of Use will use links in the checkbox.') : t('Terms of Use disabled.'));
+      }
+    }
+    else {
+      $node = node_load($nid);
+      if ($node == FALSE) {
+        form_set_error('terms_of_use_node_id', t('No post was published with <em>nid</em> !nid.', array('!nid' => $nid)));
+      }
+      else {
+        variable_set('terms_of_use_node_title', $node->title);
+      }
+    }
+  }
+  else if (!empty($form_state['values']['terms_of_use_node_title'])) {
+    $node = node_load(array('title' => $form_state['values']['terms_of_use_node_title']));
+    if ($node == FALSE) {
+      form_set_error('terms_of_use_node_title', t('No post was published with this title.'));
+    }
+    else {
+      variable_set('terms_of_use_node_id', $node->nid);
+    }
+  }
+  else {
+    // Empty means "disabled", unless @link is set
+    if ($use_node) {
+      form_set_error('terms_of_use_node_title', t('You used @link token. You must specify a node title.'));
+    } else {
+      variable_set('terms_of_use_node_id', '');
+      drupal_set_message($use_links ? t('Terms of Use will use links in the checkbox.') : t('Terms of Use disabled.'));
+    }
+  }
+}
+
+/**
+ * Submit the terms_of_use_admin_settings form.
+ *
+ * @see terms_of_use_admin_settings()
+ */
+function terms_of_use_admin_settings_submit($form, &$form_state) {
+  if (!empty($form_state['values']['terms_of_use_node_id'])) {
+    $nid = $form_state['values']['terms_of_use_node_id'];
+  }
+  else if (!empty($form_state['values']['terms_of_use_node_title'])) {
+    $nid = variable_get('terms_of_use_node_id', '');
+  }
+  else {
+    $nid = '';
+  }
+  // Rebuild allowed paths
+  _terms_of_use_prep_allowed_paths($nid);
+}
+
+/**
+ * Get the path of an URL (copied from _linkchecker_absolute_content_path() linkchecker.module).
+ *
+ * @param $url
+ *   The http/https URL to parse.
+ *
+ * @return
+ *   Full qualified URL with absolute path of the URL.
+ */
+function _terms_of_use_absolute_content_path($url) {
+
+  // Parse the URL and make sure we can handle the schema.
+  $uri = @parse_url($url);
+
+  if ($uri == FALSE) {
+    return NULL;
+  }
+
+  if (!isset($uri['scheme'])) {
+    return NULL;
+  }
+
+  // Break if the schema is not supported.
+  if (!in_array($uri['scheme'], array('http', 'https'))) {
+    return NULL;
+  }
+
+  $scheme = isset($uri['scheme']) ? $uri['scheme'] . '://' : '';
+  $user = isset($uri['user']) ? $uri['user'] . ($uri['pass'] ? ':' . $uri['pass'] : '') . '@' : '';
+  $port = isset($uri['port']) ? $uri['port'] : 80;
+  $host = $uri['host'] . ($port != 80 ? ':'. $port : '');
+  $path = isset($uri['path']) ? $uri['path'] : '/';
+
+  // Glue the URL variables.
+  $absolute_url = $scheme . $user . $host . $path;
+
+  // Find the last slash and remove all after the last slash to get the path.
+  $last_slash = strrpos($absolute_url, '/');
+  $absolute_content_url = drupal_substr($absolute_url, 0, $last_slash + 1);
+
+  return $absolute_content_url;
+}
+
+/**
+ * Extract links from content (copied from _linkchecker_extract_links() linkchecker.module).
+ *
+ * @param $text
+ *    The text to be scanned for links.
+ *
+ * @param $content_path
+ *    Path to the content that is currently scanned for links. This value is
+ *    required to build full qualified links from relative links. Relative links
+ *    are not extracted from content, if path is not provided.
+ *
+ * @return
+ *    Array of full qualified and unique URLs found in content.
+ */
+function _terms_of_use_extract_links($text = '', $content_path = NULL) {
+// Just in case the linkchecker.module is more up to date.
+//if (module_exists('linkchecker')) return _linkchecker_extract_links($text, $path);
+  global $base_root;
+
+  // Get full qualified url with base path of content.
+  $absolute_content_path = _terms_of_use_absolute_content_path($content_path);
+
+  // Finds all hyperlinks in the content.
+  $matches_a = array();
+  if (1 || variable_get('linkchecker_extract_from_a', 1) == 1) {
+    // Extract all chars in the href value, except double and single quotes.
+    $pattern_a = '/<(a|area)\s[^>]*href=["\']([^"\']*)["\'][^>]*>/i';
+    preg_match_all($pattern_a, $text, $matches_a);
+  }
+
+  // Finds all audio links in the content.
+  $matches_audio = array();
+  if (0 && variable_get('linkchecker_extract_from_audio', 1) == 1) {
+    $pattern_audio = '/<audio\s[^>]*src=["\']([^"\']*)["\'][^>]*>/i';
+    preg_match_all($pattern_audio, $text, $matches_audio);
+  }
+
+  // Finds embed tags with links in the content.
+  $matches_embed = array();
+  if (0 && variable_get('linkchecker_extract_from_embed', 0) == 1) {
+    $pattern_embed_src = '/<embed\s[^>]*src=["\']([^"\']*)["\'][^>]*>/i';
+    $pattern_embed_pluginurl = '/<embed\s[^>]*pluginurl=["\']([^"\']*)["\'][^>]*>/i';
+    $pattern_embed_pluginspage = '/<embed\s[^>]*pluginspage=["\']([^"\']*)["\'][^>]*>/i';
+
+    preg_match_all($pattern_embed_src, $text, $matches_embed_src);
+    preg_match_all($pattern_embed_pluginurl, $text, $matches_embed_pluginurl);
+    preg_match_all($pattern_embed_pluginspage, $text, $matches_embed_pluginspage);
+
+    $matches_embed = array_merge(
+      (array)$matches_embed_src[1],
+      (array)$matches_embed_pluginurl[1],
+      (array)$matches_embed_pluginspage[1]
+    );
+  }
+
+  // Finds iframe tags with links in the content.
+  $matches_iframe = array();
+  if (1 || variable_get('linkchecker_extract_from_iframe', 0) == 1) {
+    $pattern_iframe = '/<iframe\s[^>]*src=["\']([^"\']*)["\'][^>]*>/i';
+    preg_match_all($pattern_iframe, $text, $matches_iframe);
+  }
+
+  // Finds img tags with links in the content.
+  $matches_img = array();
+  if (1 || variable_get('linkchecker_extract_from_img', 0) == 1) {
+    $pattern_img = '/<img\s[^>]*src=["\']([^"\']*)["\'][^>]*>/i';
+    preg_match_all($pattern_img, $text, $matches_img);
+  }
+
+  // Finds object/param tags with links in the content.
+  $matches_object = array();
+  if (0 && variable_get('linkchecker_extract_from_object', 0) == 1) {
+    // TODO's:
+    //  * Allow flipped order of attributes in "param".
+    //  * Try to extract links in unkown "flashvars" values (for e.g. file=http://, data=http://).
+    $pattern_object_data = '/<object\s[^>]*data=["\']([^"\']*)["\'][^>]*>/i';
+    $pattern_object_codebase = '/<object\s[^>]*codebase=["\']([^"\']*)["\'][^>]*>/i';
+    $pattern_param = '/<param\s[^>]*((name|src)=["\'](archive|filename|href|movie|src|url)["\']\s[^>]*)+value=["\']([^"\']*)["\'][^>]*>/i';
+
+    preg_match_all($pattern_object_data, $text, $matches_object_data);
+    preg_match_all($pattern_object_codebase, $text, $matches_object_codebase);
+    preg_match_all($pattern_param, $text, $matches_param);
+
+    $matches_object = array_merge(
+      (array)$matches_object_data[1],
+      (array)$matches_object_codebase[1],
+      (array)$matches_param[4]
+    );
+  }
+
+  // Finds source tags with links in the content.
+  $matches_source = array();
+  if (0 || variable_get('linkchecker_extract_from_source', 0) == 1) {
+    $pattern_source = '/<source\s[^>]*src=["\']([^"\']*)["\'][^>]*>/i';
+    preg_match_all($pattern_source, $text, $matches_source);
+  }
+
+  // Finds video tags with links in the content.
+  $matches_video = array();
+  if (0 || variable_get('linkchecker_extract_from_video', 0) == 1) {
+    $pattern_video_poster = '/<video\s[^>]*poster=["\']([^"\']*)["\'][^>]*>/i';
+    $pattern_video_src = '/<video\s[^>]*src=["\']([^"\']*)["\'][^>]*>/i';
+
+    preg_match_all($pattern_video_poster, $text, $matches_video_poster);
+    preg_match_all($pattern_video_src, $text, $matches_video_src);
+
+    $matches_video = array_merge(
+      (array)$matches_video_poster[1],
+      (array)$matches_video_src[1]
+    );
+  }
+
+  // Merge all extracted links into one array.
+  $urls = array_merge(
+    (array)$matches_a[2],
+    (array)$matches_audio[1],
+    (array)$matches_embed,
+    (array)$matches_iframe[1],
+    (array)$matches_img[1],
+    (array)$matches_object,
+    (array)$matches_source[1],
+    (array)$matches_video
+  );
+
+  // Remove empty values.
+  $urls = array_filter($urls);
+  // Decode HTML links into plain text links.
+  $urls = array_map('decode_entities', $urls);
+  // Remove duplicate urls.
+  $urls = array_unique($urls);
+
+  $links = array();
+  foreach ($urls as $url) {
+    // Full qualified URLs.
+    if (valid_url($url, TRUE)) {
+      // Add to Array and change HTML links into plain text links.
+      $links[] = $url;
+    }
+    // Skip mailto:, javascript:, etc.
+    elseif (preg_match('/^\w[\w.+]*:/', $url)) {
+      continue;
+    }
+    // Local URLs.
+    elseif (valid_url($url, FALSE) && (1 || variable_get('linkchecker_fqdn_only', 1) == 0)) {
+
+      // Absolute local URLs need to start with [/].
+      if (preg_match('!^/!', $url)) {
+        // Add to Array and change HTML encoded links into plain text links.
+        $links[] = $base_root . $url;
+      }
+      // Anchors and URL parameters like "#foo" and "?foo=bar".
+      elseif (!empty($content_path) && preg_match('!^[?#]!', $url)) {
+        // Add to Array and change HTML encoded links into plain text links.
+        $links[] = $content_path . $url;
+      }
+      // Relative URLs like "./foo/bar" and "../foo/bar".
+      elseif (!empty($absolute_content_path) && preg_match('!^\.{1,2}/!', $url)) {
+        $path = $absolute_content_path . $url;
+
+        // Remove './' segments where possible.
+        $path = str_replace('/./', '/', $path);
+
+        // Remove '../' segments where possible. Loop until all segments are removed.
+        // Taken over from _drupal_build_css_path() in common.inc.
+        $last = '';
+        while ($path != $last) {
+          $last = $path;
+          $path = preg_replace('`(^|/)(?!\.\./)([^/]+)/\.\./`', '$1', $path);
+        }
+
+        // Add URLs to array.
+        $links[] = $path;
+      }
+      // Relative URLs like "test.png".
+      elseif (!empty($absolute_content_path) && preg_match('!^[^/]!', $url)) {
+        $links[] = $absolute_content_path . $url;
+      }
+      else {
+        // TODO: Are there more special cases the module need to handle?
+      }
+    }
+  }
+
+  return array_unique($links);
+}
+
+/**
+ * Create 'terms_of_use_allow_nodes' variable from links found in:
+ * - all translations of Checkbox labels, 
+ * - all translations of Terms of Use nodes,
+ * @param $nid
+ *  Terms of Use node nid.
+ * @param $delete_nid
+ *  If supplied, nid of node being deleted.
+ */
+function _terms_of_use_prep_allowed_paths($nid, $delete_nid=NULL) {
+  $links = array();
+  $languages = language_list();
+
+  $nids = _terms_of_use_nid_all_translations($nid);
+
+  // Get all translations of checkbox label
+  $checkbox_labels = _terms_of_use_checkbox_label_all_translations();
+  $path = NULL;  // We don't know which path we will have (the checkbox can appear on multiple forms)
+  $nodes = array();  // Collect nodes that we parse
+  foreach ($checkbox_labels as $language => $checkbox_label) {
+    $links[$language] = array();
+    $tnid = isset($nids[$language]) ? $nids[$language] : '';
+    $node = ($tnid != '') ? node_load($tnid) : NULL;
+    $use_node = (strpos($checkbox_label, '@link') !== FALSE);
+    $use_links = (strpos($checkbox_label, '@&quot;') !== FALSE);
+    $show_node = $node && !$use_node && !$use_links;
+    if ($use_node || $use_links) {
+      $text = theme('terms_of_use_checkbox_label', $checkbox_label, $node ? $node->title : '', $node ? $node->nid : 0);
+      $urls = _terms_of_use_extract_links($text, $path);
+      $links[$language] += $urls;
+    }
+    if ($show_node && $node) {
+//?      $terms = node_build_content($node);
+      $terms = node_prepare($node);
+      $node_language = isset($node->language) ? $node->language : '';
+      // Get the absolute node path for extraction of relative links.
+      $path = url('node/'. $node->nid, array('language' => $languages[$node_language], 'absolute' => TRUE));
+      // Extract all links in a node.
+      $urls = _terms_of_use_extract_links($terms->body, $path);
+      $links[$language] += $urls;
+      $nodes[$language] = $node->nid;
+    }
+  }
+
+  // Remove all parsed nodes. We postpone it so there are no orphaned @link tokens in theme_terms_of_use_checkbox_label().
+  foreach ($nodes as $language => $tnid) {
+    unset($nids[$language]);
+  }
+  // All remaining node translations may be shown in other languages - extract links from them
+  foreach ($nids as $language => $tnid) {
+    $node = node_load($tnid);
+    if ($node) {
+//?      $terms = node_build_content($node);
+      $terms = node_prepare($node);
+      $node_language = isset($node->language) ? $node->language : '';
+      // Get the absolute node path for extraction of relative links.
+      $path = url('node/'. $node->nid, array('language' => $languages[$node_language], 'absolute' => TRUE));
+      // Extract all links in a node.
+      $urls = _terms_of_use_extract_links($terms->body, $path);
+      if (!isset($links[$language])) $links[$language] = $urls;
+      else $links[$language] += $urls;
+    }
+  }
+
+  // Parse all links, extract only node ids
+  $nodes = array();
+  global $base_url, $base_root;
+  $len = strlen($base_url)+1;  // Remove base and slash prefix
+  foreach ($links as $language => $urls) foreach ($urls as $link) {
+    if (strpos($link, $base_url) === 0) {
+      $end = strpos($link,'?');
+      if ($end === FALSE) $end = strpos($link,'#');
+      if ($end === FALSE) $end = strlen($link);
+      $link = substr($link, $len, ($end-$len));
+      $path = drupal_get_normal_path($link, $language);
+      if (!$path || $path == $link)
+        $path = drupal_get_normal_path($link, '');
+      if (!$path || $path == $link)
+        $path = drupal_get_normal_path($link, language_default('language'));
+      $ret = preg_match('!^node/(.*)!i', $path, $matches);
+      if ($ret == 1) {
+        if (!isset($delete_nid) || $delete_nid != $matches[1]) {
+          $nodes[] = $matches[1];
+        }
+      }
+    }
+  }
+  $nodes = array_unique($nodes);
+//watchdog('debug','terms_of_use_allow_nodes=<pre>'.print_r($nodes,1).'</pre>');
+  // 'terms_of_use_allow_nodes' lists all nodes that will avoid a goto to an acceptance form.
+  variable_set('terms_of_use_allow_nodes', $nodes);
+//variable_del('terms_of_use_nodes');
+}
+
diff -uprN terms_of_use.orig/terms_of_use.install terms_of_use/terms_of_use.install
--- terms_of_use.orig/terms_of_use.install	2009-03-23 14:19:34.000000000 -0700
+++ terms_of_use/terms_of_use.install	2010-04-03 16:19:44.000000000 -0700
@@ -7,8 +7,11 @@
 function terms_of_use_uninstall() {
   // Delete variables.
   variable_del('terms_of_use_node_title');
-  variable_del('terms_of_use_fieldset_name');
+  variable_del('terms_of_use_title');
+  variable_del('terms_of_use_fieldset');
   variable_del('terms_of_use_checkbox_label');
   variable_del('terms_of_use_node_id');
+  variable_del('terms_of_use_version');
+  variable_del('terms_of_use_allow_nodes');
 }
 
diff -uprN terms_of_use.orig/terms_of_use.module terms_of_use/terms_of_use.module
--- terms_of_use.orig/terms_of_use.module	2009-03-23 14:20:27.000000000 -0700
+++ terms_of_use/terms_of_use.module	2010-04-03 20:19:10.000000000 -0700
@@ -20,6 +20,7 @@ function terms_of_use_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('terms_of_use_admin_settings'),
     'access arguments' => array('administer site configuration'),
+    'file'             => 'terms_of_use.admin.inc',
   );
 
   $items['node/autocomplete'] = array(
@@ -29,147 +30,118 @@ function terms_of_use_menu() {
     'type' => MENU_CALLBACK,
     'file' => 'terms_of_use.pages.inc',
   );
-  
+
   $items['terms_of_use/js'] = array(
     'page callback' => 'terms_of_use_js',
     'access arguments' => array('administer site configuration'),
     'type' => MENU_CALLBACK,
     'file' => 'terms_of_use.pages.inc',
   );
+
+  $items['_terms_of_use'] = array(
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('terms_of_use_confirm'),
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+    'file' => 'terms_of_use.pages.inc',
+  );
   
   return $items;
 }
 
 /**
- * Menu callback; show settings form.
- * @see terms_of_use_admin_settings_validate()
- *
+ * Get translation of a node for the current language.
  */
-function terms_of_use_admin_settings() {
-  
-  // Adding the fieldset for node specification.
-  $form['terms_of_use_text'] = array(
-    '#type' => 'fieldset',
-    '#prefix' => '<div id="fieldset-wrapper">',
-    '#suffix' => '</div>',
-    //'#title' => t('Terms of Use text'),
-  );
-  $form['terms_of_use_text']['terms_of_use_node_title'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Title of the post where your Terms of Use are published'),
-    '#default_value' => variable_get('terms_of_use_node_title', ''),
-    '#description' => t('Node <em>title</em> of the page or story (or blog entry or book page) where your Terms of Use are published.'),
-    '#autocomplete_path' => 'node/autocomplete',
-  );
-  $form['terms_of_use_text']['terms_of_use_pick_node_id'] = array(
-    '#type' => 'button',
-    '#value' => t('I prefer to specify the node id'),
-    '#weight' => 10,
-    '#ahah' => array(
-      'path' => 'terms_of_use/js',
-      'wrapper' => 'fieldset-wrapper',
-    ),
-  );
-  // Adding the fieldset for form specification.
-  $form['terms_of_use_form'] = array(
-    '#type' => 'fieldset',
-  );
-  $form['terms_of_use_form']['terms_of_use_fieldset_name'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Label for the fieldset'),
-    '#default_value' => variable_get('terms_of_use_fieldset_name', t('Terms of Use')),
-    '#description' => t('The text for the Terms of Use and the [x] checkbox are contained in a fieldset. Type here the title for that fieldset.'),
-  );
-  $form['terms_of_use_form']['terms_of_use_checkbox_label'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Label for the ckeckbox'),
-    '#default_value' => variable_get('terms_of_use_checkbox_label', t('I agree with these terms.')),
-    '#description' => t('Type here something like "I agree with these terms." or "I CERTIFY THAT I AM OVER THE AGE OF 18 YEARS OLD.", without quotes. You can use the token @link to insert a link to the Terms in this label. For example, the label can be: "I agree with the @link.", without quotes. You may want to link to the Terms if you prefer not to show the full text of the Terms in the registration form. If you use the token, the Terms will not be shown.'),
-  );
-
-  return system_settings_form($form);
+function _terms_of_use_nid_translated($nid) {
+  if ($nid != '' && module_exists('translation')) {
+    global $language;
+    $translations = translation_node_get_translations($nid);
+    if ($translations[$language->language]) {
+      $nid = $translations[$language->language]->nid;
+    }
+  }
+  return $nid;
 }
 
 /**
- * Validate the terms_of_use_admin_settings form.
- *
- * @see terms_of_use_admin_settings()
+ * Get an associative array of all node translations
  */
-function terms_of_use_admin_settings_validate($form, &$form_state) {
-  $nid = $form_state['values']['terms_of_use_node_id'];
-  if (isset($nid)) {
-    if (empty($nid)) {
-      form_set_error('terms_of_use_node_id', t('You must specify a node <em>nid</em>.'));   
-    }
-    else {
-      $node = node_load($nid);
-      if ($node == FALSE) {
-        form_set_error('terms_of_use_node_id', t('No post was published with <em>nid</em> !nid.', array('!nid' => $nid))); 
-      }
-      else {
-        variable_set('terms_of_use_node_title', $node->title);
-      }
-    }
-  }
-  else if (!empty($form_state['values']['terms_of_use_node_title'])) {
-    $node = node_load(array('title' => $form_state['values']['terms_of_use_node_title']));
-    if ($node == FALSE) {
-      form_set_error('terms_of_use_node_title', t('No post was published with this title.'));
-    }
-    else {
-      variable_set('terms_of_use_node_id', $node->nid);
+function _terms_of_use_nid_all_translations($nid) {
+  global $language;
+  $nids = array($language->language => $nid);
+  if ($nid != '' && module_exists('translation')) {
+    $translations = translation_node_get_translations($nid);
+    foreach ($translations as $lang => $translation) {
+      $nids[$lang] = $translation->nid;
     }
   }
-  else {
-    form_set_error('terms_of_use_node_title', t('You must specify a node title.'));
-  }
+  return $nids;
 }
 
 /**
  * Implementation of hook_form_form_id_alter().
  */
-function terms_of_use_form_user_register_alter(&$form, $form_state) {
-  // Adding the fieldset.
-  $form['terms_of_use'] = array(
-    '#type' => 'fieldset',
-    '#title' => check_plain(variable_get('terms_of_use_fieldset_name', t('Terms of Use'))),
-    '#weight' => 10,
-  );
-
-  // Getting the node that contains the Terms of Use.
-  $terms_of_use_node_id = variable_get('terms_of_use_node_id', '');
-  if (module_exists('translation')) {
-    global $language;
-    $translations = translation_node_get_translations($terms_of_use_node_id);
-    if ($translations[$language->language]) {
-      $terms_of_use_node_id = $translations[$language->language]->nid;
-    }
+function terms_of_use_form_user_register_alter(&$form, $form_state, $fieldset_en=NULL) {
+  // Only change the registration form (with any language).
+  // There is also form at /admin/user/user/create path, but we leave it alone.
+  if (isset($form['#action']) && strpos($form['#action'], url('user/register')) !== 0)
+    return;
+  
+  $height = variable_get('terms_of_use_node_height', '');
+  if ($height) {
+    $css = '#terms-of-use { height:' . check_plain($height) .'; overflow:auto; }';
+    drupal_set_html_head('<style type="text/css">' . $css . '</style>');
+    // Revert the styling so print shows full text.
+    $css = '#terms-of-use { height:auto; overflow:visible; }';
+    drupal_set_html_head('<style type="text/css" media="print">' . $css . '</style>');
   }
-  $node = node_load($terms_of_use_node_id);
   
+  // Getting the node that contains the Terms of Use.
+  $nid = _terms_of_use_nid_translated(variable_get('terms_of_use_node_id', ''));
+  $node = ($nid != '') ? node_load($nid) : NULL;
+
   // Will we show the full text of the Terms or only provide a link to the Terms.
   // Reading the checkbox label to find out.
-  $show_terms = TRUE;
   $checkbox_label = check_plain(variable_get('terms_of_use_checkbox_label', t('I agree with these terms.')));
-  if (strpos($checkbox_label, '@link') !== FALSE) {
-    $checkbox_label = str_replace('@link', l(check_plain($node->title), 'node/'. $node->nid), $checkbox_label);
-    $show_terms = FALSE;
-  }  
-    
-  // Adding the Terms of Use to the fieldset. 
-  if ($show_terms && $node) {
+  $use_node = (strpos($checkbox_label, '@link') !== FALSE);
+  $use_links = (strpos($checkbox_label, '@&quot;') !== FALSE);
+  $show_node = $node && !$use_node && !$use_links;
+
+  // If there is no node to show and no links in the $checkbox_label, we don't show the terms form.
+  if (!$use_links && !$node)
+    return;
+
+  $checkbox_label = theme('terms_of_use_checkbox_label', $checkbox_label, $node ? $node->title : '', $node ? $node->nid : 0);
+  if (!isset($fieldset_en))
+    $fieldset_en = variable_get('terms_of_use_fieldset', 1);
+  if ($fieldset_en) {
+    // Adding the fieldset.
+    $form['terms_of_use'] = array(
+      '#type' => 'fieldset',
+      '#title' => check_plain(variable_get('terms_of_use_title', t('Terms of Use'))),
+      '#weight' => 10,
+    );
+    $fieldset = &$form['terms_of_use'];
+  } else {
+    $fieldset = &$form;
+  }
+  // Adding the Terms of Use to the fieldset.
+  if ($show_node && $node) {
+//?    $terms = node_build_content($node);
     $terms = node_prepare($node);
-    $form['terms_of_use']['terms_of_use_text'] = array(
+    $fieldset['terms_of_use_text'] = array(
       '#value' => theme('terms_of_use', $terms->body, $node),
     );
   }
 
   // Adding the checkbox to the fieldset.
-  $form['terms_of_use']['I_agree'] = array(
+  $fieldset['I_agree'] = array(
     '#type' => 'checkbox',
-    '#title' => $checkbox_label . '&nbsp;<span class="form-required" title="' . t('This field is required') . '">*</span>',
+    '#title' => $checkbox_label,
     '#required' => TRUE,
+    // The following adds "required" validation to the checkbox (patches core missing functionality as of D6.16)
     '#element_validate' => array('_terms_of_use_validate_checkbox'),
+    '#return_value' => variable_get('terms_of_use_version', 1),
   );
 
   return $form;
@@ -180,8 +152,68 @@ function terms_of_use_form_user_register
  */
 function _terms_of_use_validate_checkbox($form, &$form_state) {
   $value = $form_state['values']['I_agree'];
-  if ($value == 0) {
-    form_set_error('I_agree', t('You must agree with the !terms to get an account.', array('!terms' => variable_get('terms_of_use_fieldset_name', t('Terms of Use')))));
+  if ($value != variable_get('terms_of_use_version', 1)) {
+    form_set_error('I_agree', t('You must agree with the !terms to get an account.', 
+      array('!terms' => variable_get('terms_of_use_title', t('Terms of Use')))));
+  }
+}
+
+/**
+ * Implementation of hook_user().
+ */
+function terms_of_use_user($op, &$edit, &$account, $category = NULL) {
+  switch ($op) {
+    case 'insert':
+//drupal_set_message(print_r($account, TRUE));
+//drupal_set_message(print_r($edit, TRUE));
+      
+      if (isset($edit['I_agree'])) {
+        $edit['terms_of_use'] = $edit['I_agree'];
+        unset ($edit['I_agree']);
+      }
+//drupal_set_message(print_r($account, TRUE));
+      break;
+  }
+}
+
+function _terms_of_use_i18n() {
+  $variables = array(
+// Rely on node translations.
+//    'terms_of_use_node_title',
+//    'terms_of_use_node_id',
+    'terms_of_use_title',
+    'terms_of_use_fieldset',
+    'terms_of_use_checkbox_label',
+  );
+  $i18n_variables = variable_get('i18n_variables', array());
+  $i18n_variables = array_merge($i18n_variables, $variables);
+  variable_set('i18n_variables', $i18n_variables);
+}
+
+/**
+ * Implementation of hook_init().
+ */
+function terms_of_use_init() {
+  global $user;
+
+  // http://drupal.org/node/313272#comment-2786004
+  // This is a performance hit. We need it here because $conf in settings.php 
+  // overrides database variable value in variable_init().
+  // Faster performance will be achieved if the variables in 
+  // _terms_of_use_i18n() are added to $conf in settings.php.
+  _terms_of_use_i18n();
+  
+  if ($user->uid > 1) {
+    $terms_of_use_version = variable_get('terms_of_use_version', 1);
+    $terms_of_use_node_id = variable_get('terms_of_use_node_id', '');
+    if ($terms_of_use_node_id > 0 && (!isset($user->terms_of_use) || $user->terms_of_use < $terms_of_use_version)) {
+      // Any links in the terms of use node or in the checkbox should also be allowed.
+      if (arg(0) != '_terms_of_use'
+        && (arg(0) != 'node' || !in_array(arg(1), variable_get('terms_of_use_allow_nodes', array())))
+      ) {
+        drupal_goto('_terms_of_use', drupal_get_destination());
+      }
+    }
   }
 }
 
@@ -194,6 +226,9 @@ function terms_of_use_theme() {
     'terms_of_use' => array(
       'arguments' => array('terms' => NULL, 'node' => NULL),
     ),
+    'terms_of_use_checkbox_label' => array(
+      'arguments' => array('checkbox_label' => '', 'node_title' => '', 'node_nid' => 0),
+    ),
   );
 }
 
@@ -215,3 +250,91 @@ function theme_terms_of_use($terms, $nod
 
   return $output;
 }
+
+/**
+ * Output the terms of service checkbox label.
+ *
+ * @param $checkbox_label
+ *  The label from the admin form saved in the DB.
+ * @param $node_title
+ *  The Terms of Use $node title, in case we need it.
+ * @param $node_nid
+ *  The Terms of Use $node nid, in case we need it.
+ * @return
+ *  HTML output.
+ * @ingroup themeable
+ */
+function theme_terms_of_use_checkbox_label($checkbox_label = '', $node_title = '', $node_nid = 0){
+  if (!strlen($checkbox_label)) { return ''; }
+
+  $output = $checkbox_label;
+  if ($node_nid && strlen($node_title)) {
+    //We are linking to the terms instead, replace the link.
+    $output = str_replace('@link', l(check_plain($node_title), 'node/'. $node_nid), $checkbox_label);
+  }
+  // Go through the $output string, replacing @"Terms Link" with an actual node link
+  $output = str_replace('&quot;', '"', $output);
+  while ( $i < strlen($output) ) {
+    if (substr($output, $i, 2) == '@"') {
+      $start = $i+2;
+      $end = strpos($output, '"', $start);
+      while (substr($output, $end-1, 1) == "\\") {
+        $end = strpos($output, '"', $end+1);
+      }
+      $title = substr($output, $start, ($end-$start));
+      $node = node_load(array('title' => str_replace('\\"', '"', $title) ) );
+      if ($node) {
+        $link = l($node->title, 'node/' . $node->nid);
+        $output = str_replace('@"'.$title.'"', $link, $output);
+        $i += strlen($link) - 1;
+      }
+    }
+    $i++;
+  }
+
+  // The following adds "required" styling to the checkbox (patches core missing functionality as of D6.16)
+  // Checkbox validate handles denoting required checkboxes for us
+  if (!module_exists('checkbox_validate')) {
+    $output .= '&nbsp;<span class="form-required" title="' . t('This field is required') . '">*</span>';
+  }
+
+  return $output;
+}
+
+/*
+ * Implementation of hook_nodeapi().
+ */
+function terms_of_use_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
+  switch ($op) {
+    case 'insert':
+    case 'update':
+    case 'delete':
+      $nid = variable_get('terms_of_use_node_id', '');
+      $nids = ($nid != '') ? _terms_of_use_nid_all_translations($nid) : array();
+      $nids += variable_get('terms_of_use_allow_nodes', array());
+
+      // Figure out translation relationships of the node
+      if (isset($node->tnid) && $node->tnid) {
+        $node_tnid = $node->tnid;
+      } else if (!empty($node->translation_source)) {
+        $node_tnid = $node->translation_source->tnid 
+          ? $node->translation_source->tnid
+          : $node->translation_source->nid;
+      }
+	  if (!$tnid) {
+        $tnid = $_GET['translation'];
+      }
+
+//watchdog('debug', 'terms_of_use_nodeapi('.$op.') nid='.$node->nid.' tnid='.$node_tnid.' nids=<pre>'.print_r($nids,1).'</pre>');
+      if (isset($node->nid) && in_array($node->nid, $nids)
+        || isset($node_tnid) && in_array($node_tnid, $nids)
+      ) {
+        require_once('terms_of_use.admin.inc');
+        _terms_of_use_prep_allowed_paths($nid, ($op=='delete') ? $node->nid : NULL);
+      }
+      break;
+
+    case 'prepare':
+      break;
+  }
+}
diff -uprN terms_of_use.orig/terms_of_use.pages.inc terms_of_use/terms_of_use.pages.inc
--- terms_of_use.orig/terms_of_use.pages.inc	2008-06-06 14:19:28.000000000 -0700
+++ terms_of_use/terms_of_use.pages.inc	2010-04-03 07:19:38.000000000 -0700
@@ -12,7 +12,9 @@
 function terms_of_use_autocomplete($string = '') {
   $matches = array();
   if ($string != '') {
-    $result = db_query_range(db_rewrite_sql("SELECT nr.title FROM {node_revisions} nr WHERE LOWER(nr.title) LIKE LOWER('%%%s%%')"), $string, 0, 10);
+    $result = db_query_range(
+      db_rewrite_sql("SELECT nr.title FROM {node_revisions} nr WHERE LOWER(nr.title) LIKE LOWER('%%%s%%')", 'nr'),
+        $string, 0, 10);
 
     while ($node = db_fetch_object($result)) {
       $matches[$node->title] = $node->title;
@@ -39,8 +41,9 @@ function terms_of_use_js() {
     $form['terms_of_use_text']['terms_of_use_node_id'] = array(
       '#type' => 'textfield',
       '#title' => t('Node id where your Terms of Use are published'),
+      '#value' => variable_get('terms_of_use_node_id', ''),
       '#default_value' => variable_get('terms_of_use_node_id', ''),
-      '#description' => t('Node <em>id</em> of the page or story (or blog entry or book page) where your Terms of Use are published.'),
+      '#description' => t('Node <em>id</em> of the page or story (or blog entry or book page) where your Terms of Use are published. Leave empty to disable Terms of Use.'),
     );  
     unset($form['terms_of_use_text']['terms_of_use_node_title']);
     $form['terms_of_use_text']['terms_of_use_pick_node_id']['#value'] = t('I prefer to provide the title of the post');    
@@ -50,8 +53,9 @@ function terms_of_use_js() {
     $form['terms_of_use_text']['terms_of_use_node_title'] = array(
       '#type' => 'textfield',
       '#title' => t('Title of the post where your Terms of Use are published'),
+      '#value' => variable_get('terms_of_use_node_title', ''),
       '#default_value' => variable_get('terms_of_use_node_title', ''),
-      '#description' => t('Node <em>title</em> of the page or story (or blog entry or book page) where your Terms of Use are published.'),
+      '#description' => t('Node <em>title</em> of the page or story (or blog entry or book page) where your Terms of Use are published. Leave empty to disable Terms of Use.'),
       '#autocomplete_path' => 'node/autocomplete',
     ); 
     unset($form['terms_of_use_text']['terms_of_use_node_id']);
@@ -71,4 +75,41 @@ function terms_of_use_js() {
   $output = drupal_render($form['terms_of_use_text']);
   
   drupal_json(array('status' => TRUE, 'data' => $output));      
-}
\ No newline at end of file
+}
+
+/**
+ * Display the terms of use, when a user needs to confirm them after registering.
+ */
+function terms_of_use_confirm($form_state) {
+  $title = check_plain(variable_get('terms_of_use_title', t('Terms of Use')));
+  drupal_set_title($title);
+  $changes = '.';    // No changes, put a period to finish sentence.
+// [iva2k] FIXME: combine a list of changes into $changes:
+//$changes = ':<ul><li>Item 1</ul>';
+  $form = array();
+  $form['intro'] = array(
+    '#type' => 'item',
+    '#value' => t('There were recent changes to the !terms!changes Please review them below. You must accept the following to continue.',
+       array(
+         '!terms' => $title,
+         '!changes' => $changes,
+       )),
+  );
+  terms_of_use_form_user_register_alter($form, $form_state, FALSE);
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Continue'),
+    '#weight' => 50, 
+  );
+  
+  return $form;
+}
+
+function terms_of_use_confirm_submit($form, &$form_state) {
+  global $user;
+  $edit = array(
+    'terms_of_use' => $form_state['values']['I_agree'],
+  );
+  user_save($user, $edit);
+}
+
