Index: CHANGELOG.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drupalvb/CHANGELOG.txt,v
retrieving revision 1.7.4.33
diff -u -p -r1.7.4.33 CHANGELOG.txt
--- CHANGELOG.txt	16 Jul 2008 22:12:00 -0000	1.7.4.33
+++ CHANGELOG.txt	22 Jul 2008 10:53:48 -0000
@@ -6,6 +6,9 @@ Drupal vB x.x-x.x, xxxx-xx-xx
 
 Drupal vB 5.x-2.x, xxxx-xx-xx
 -----------------------------
+by smk-ka: Added protection against timing problems on heavy Drupal
+  installations, where the redirector could try to register a user twice,
+  resulting in broken user mappings.
 
 
 Drupal vB 5.x-2.1, 2008-07-17
Index: drupalvb.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drupalvb/drupalvb.module,v
retrieving revision 1.11.4.17
diff -u -p -r1.11.4.17 drupalvb.module
--- drupalvb.module	16 Jul 2008 01:11:21 -0000	1.11.4.17
+++ drupalvb.module	22 Jul 2008 10:51:44 -0000
@@ -158,8 +158,7 @@ function drupalvb_auth($username, $passw
       // find a user with the given password, otherwise we wouldn't be here.
       // This can happen if the user has been temporarily created by
       // drupalvb_redirect().
-      $uid = db_result(db_query("SELECT uid FROM {drupalvb_users} WHERE userid = %d", $vbuser['userid']));
-      if ($uid) {
+      if ($uid = drupalvb_user_load($vbuser['userid'])) {
         // Only update the password of the existing Drupal user record.
         $account = user_load(array('uid' => $uid));
         $userinfo['pass'] = $password;
@@ -176,7 +175,7 @@ function drupalvb_auth($username, $passw
           'status' => 1,
         );
         $user = user_save('', $userinfo);
-        watchdog('drupalvb', t('New external user: %user.', array('%user' => $username)), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $user->uid .'/edit'));
+        watchdog('drupalvb', t('New external user: %user.', array('%user' => $user->name)), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $user->uid .'/edit'));
 
         // Update the mapping table.
         drupalvb_set_mapping($user->uid, $vbuser['userid']);
@@ -187,6 +186,17 @@ function drupalvb_auth($username, $passw
 }
 
 /**
+ * Try to lookup a Drupal user account for a vBulletin user id, using the mapping
+ * table.
+ *
+ * @param $userid
+ *   A vBulletin user id.
+ */
+function drupalvb_user_load($userid) {
+  return db_result(db_query("SELECT uid FROM {drupalvb_users} WHERE userid = %d", $userid));
+}
+
+/**
  * Implementation of hook_user().
  */
 function drupalvb_user($op, &$edit, &$account, $category = NULL) {
@@ -811,12 +821,17 @@ function drupalvb_private_messages() {
  *   A Drupal path. Numeric path arguments will be mapped to Drupal uids.
  */
 function drupalvb_redirect() {
+  // Keep script running even if a request was terminated to ensure user
+  // table integrity.
+  ignore_user_abort(TRUE);
+
   $path = func_get_args();
   foreach ($path as $key => $arg) {
     if (is_numeric($arg) && ($uid = drupalvb_lookup_drupal_user($arg))) {
       $path[$key] = $uid;
     }
   }
+
   // Issue a 301 Moved Permanently response code to make search engines
   // forget about the redirector page.
   drupal_goto(implode('/', $path), NULL, NULL, 301);
@@ -837,7 +852,7 @@ function drupalvb_lookup_drupal_user($us
   require_once drupal_get_path('module', 'drupalvb') .'/drupalvb.inc';
 
   // Check if this vBulletin user id already exists as Drupal user.
-  if ($uid = db_result(db_query("SELECT uid FROM {drupalvb_users} WHERE userid = %d", $userid))) {
+  if ($uid = drupalvb_user_load($userid)) {
     return $uid;
   }
 
@@ -845,7 +860,7 @@ function drupalvb_lookup_drupal_user($us
   if ($vbuser = db_fetch_array(drupalvb_db_query("SELECT userid, username, email, joindate FROM {user} WHERE userid = %d", $userid))) {
     // Register this user in Drupal using a temporary password, since we don't
     // know the real one. It will be updated when the user logs in to Drupal
-    // for the first time.
+    // for the first time using its vBulletin credentials.
     // @see drupalvb_auth()
     $userinfo = array(
       'name' => $vbuser['username'],
@@ -856,12 +871,28 @@ function drupalvb_lookup_drupal_user($us
       'status' => 1,
     );
     $user = user_save('', $userinfo);
-    watchdog('drupalvb', t('New external user: %user.', array('%user' => $name)), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $user->uid .'/edit'));
-
-    // Update the mapping table.
-    drupalvb_set_mapping($user->uid, $vbuser['userid']);
 
-    return $user->uid;
+    // On a heavy Drupal installation, it can happen that when a user accidently
+    // double-clicks on a redirector link we run into a timing problem:
+    // while the first request is in the middle of registering the Drupal account,
+    // the immediate second request tries to do the same again, resulting
+    // in an error.
+    if ($user->uid) {
+      watchdog('drupalvb', t('New external user: %user (unverified).', array('%user' => $user->name)), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $user->uid .'/edit'));
+
+      // Update the mapping table.
+      drupalvb_set_mapping($user->uid, $vbuser['userid']);
+
+      return $user->uid;
+    }
+    // In case the user couldn't be registered, try to load it from the database.
+    else if ($uid = drupalvb_user_load($vbuser['userid'])) {
+      return $uid;
+    }
+    // We're out of luck...
+    else {
+      watchdog('drupalvb', t('Failed to create external user: %user (unverified).', array('%user' => $vbuser['username'])), WATCHDOG_ERROR);
+    }
   }
   return 0;
 }
