Index: CHANGELOG.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drupalvb/CHANGELOG.txt,v
retrieving revision 1.7.4.36
diff -u -p -r1.7.4.36 CHANGELOG.txt
--- CHANGELOG.txt	15 Oct 2008 00:07:50 -0000	1.7.4.36
+++ CHANGELOG.txt	15 Oct 2008 00:28:34 -0000
@@ -6,6 +6,9 @@ Drupal vB x.x-x.x, xxxx-xx-xx
 
 Drupal vB 5.x-2.x, xxxx-xx-xx
 -----------------------------
+#285718 by smk-ka: Added protection against timing problems on heavy Drupal
+  sites, where the redirector could try to register a user twice, resulting in
+  broken user mappings.
 #308860 by smk-ka: Added separate login/logout menu handlers to accommodate
   different session lifetimes.
 #308857 by smk-ka: Fixed usernames containing non-latin1 characters not synced
Index: drupalvb.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/drupalvb/drupalvb.module,v
retrieving revision 1.11.4.19
diff -u -p -r1.11.4.19 drupalvb.module
--- drupalvb.module	15 Oct 2008 00:07:50 -0000	1.11.4.19
+++ drupalvb.module	15 Oct 2008 00:25:23 -0000
@@ -170,8 +170,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;
@@ -179,16 +178,19 @@ function drupalvb_auth($username, $passw
       }
       else {
         // This user is completely unknown to Drupal, register a new account.
+        // Fall back on the user submitted user name if the vBulletin name
+        // contains encoded &amp;'s.
+        $username = (strpos($vbuser['username'], '&amp;') === FALSE ? $vbuser['username'] : $username);
         $userinfo = array(
-          'name' => $vbuser['username'],
+          'name' => $username,
           'pass' => $password,
           'mail' => $vbuser['email'],
-          'init' => $vbuser['username'],
+          'init' => $username,
           'created' => $vbuser['joindate'],
           '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']);
@@ -199,6 +201,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) {
@@ -298,7 +311,7 @@ function drupalvb_user_validate($uid, &$
   $userid = db_result(db_query("SELECT userid FROM {drupalvb_users} WHERE uid = %d", $uid));
   // Validate the username.
   if (arg(1) == 'register' || user_access('change own username') || user_access('administer users')) {
-    if (db_result(drupalvb_db_query("SELECT userid FROM {user} WHERE userid != %d AND LOWER(username) = LOWER('%s')", $userid, drupalvb_htmlspecialchars($edit['name']))) > 0) {
+    if (db_result(drupalvb_db_query("SELECT userid FROM {user} WHERE userid <> %d AND LOWER(username) = LOWER('%s')", $userid, drupalvb_htmlspecialchars($edit['name']))) > 0) {
       form_set_error('name', t('The name %name is already taken.', array('%name' => $edit['name'])));
     }
   }
@@ -858,7 +871,7 @@ function drupalvb_private_messages() {
       array('data' => t('Operations')),
     );
 
-    $result = drupalvb_db_query("SELECT pm.pmid, pm.userid, pm.messageread, pmtext.fromusername, pmtext.fromuserid, pmtext.title, pmtext.message, pmtext.dateline FROM {pmtext} AS pmtext LEFT JOIN {pm} AS pm ON (pm.pmtextid = pmtext.pmtextid) WHERE pm.userid = %d AND pm.folderid != -1 ORDER BY pmtext.dateline DESC", $userinfo['userid']);
+    $result = drupalvb_db_query("SELECT pm.pmid, pm.userid, pm.messageread, pmtext.fromusername, pmtext.fromuserid, pmtext.title, pmtext.message, pmtext.dateline FROM {pmtext} AS pmtext LEFT JOIN {pm} AS pm ON (pm.pmtextid = pmtext.pmtextid) WHERE pm.userid = %d AND pm.folderid <> -1 ORDER BY pmtext.dateline DESC", $userinfo['userid']);
     while ($pm = db_fetch_array($result)) {
       $rows[] = array(
         l($pm['fromusername'], $vb_options['bburl'] .'/member.php?u='. $pm['fromuserid']),
@@ -922,7 +935,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;
   }
 
@@ -930,7 +943,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'],
@@ -941,12 +954,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']);
+    // 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;
+      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;
 }
