? .bakery.module.swp
? .git
Index: bakery.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/bakery/bakery.module,v
retrieving revision 1.52.4.16
diff -u -F '^f' -r1.52.4.16 bakery.module
--- bakery.module	7 Dec 2010 00:38:01 -0000	1.52.4.16
+++ bakery.module	26 Jan 2011 01:02:48 -0000
@@ -40,6 +40,12 @@ function bakery_menu() {
       'page callback' => 'bakery_eat_gingerbread_cookie',
       'type' => MENU_CALLBACK,
     );
+    $items['bakery/autocomplete-master'] = array(
+      'title' => 'Bakery autocomplete on master',
+      'access callback' => 'bakery_taste_fortune_cookie',
+      'page callback' => 'bakery_eat_fortune_cookie',
+      'type' => MENU_CALLBACK,
+    );
   }
   else {
     $items['bakery'] = array(
@@ -67,6 +73,13 @@ function bakery_menu() {
       'page arguments' => array('bakery_uncrumble'),
       'type' => MENU_CALLBACK,
     );
+    $items['bakery/autocomplete'] = array(
+      'title' => 'User autocomplete',
+      'page callback' => 'bakery_autocomplete',
+      'access callback' => 'user_access',
+      'access arguments' => array('access user profiles'),
+      'type' => MENU_CALLBACK,
+    );
   }
 
   return $items;
@@ -297,12 +310,90 @@ function bakery_form_alter(&$form, $form
         $form['#validate'] = array_diff($form['#validate'], array('user_login_authenticate_validate', 'user_login_final_validate'));
       }
       break;
+
     default:
+      // Autocomplete user fields to include master site. Remember what forms
+      // have autocomplete fields.
+      if (!variable_get('bakery_is_master', FALSE) && user_access('access user profiles')) {
+        $cache = variable_get('bakery_user_forms', array());
+        if (!isset($cache[$form_id]) || $cache[$form_id]) {
+          $cache[$form_id] = _bakery_find_user_autocomplete($form);
+          variable_set('bakery_user_forms', $cache);
+        }
+      }
       break;
   }
 }
 
 /**
+ * Recursively look for user autocomplete fields, and alter.
+ *
+ * @param &$elements
+ *   A form API array.
+ *
+ * @return
+ *   TRUE if $elements was altered.
+ */
+function _bakery_find_user_autocomplete(&$elements) {
+  // Is this an user autocomplete field?
+  if (isset($elements['#autocomplete_path']) && $elements['#autocomplete_path'] === 'user/autocomplete') {
+    $elements['#autocomplete_path'] = 'bakery/autocomplete';
+    $elements['#element_validate'][] = 'bakery_check_account';
+    return TRUE;
+  }
+
+  // Scan child elements.
+  $return = FALSE;
+  foreach (element_children($elements) as $key) {
+    $return = _bakery_find_user_autocomplete($elements[$key]) || $return;
+  }
+  return $return;
+}
+
+/**
+ * Request an account for the username. bakery_request_account() does necessary
+ * checks, like if the user already exists.
+ */
+function bakery_check_account($element, &$form_state) {
+  bakery_request_account($element['#value']);
+}
+
+/**
+ * Menu callback; Retrieve a JSON object containing autocomplete suggestions
+ * for existing users and users on the master site.
+ */
+function bakery_autocomplete($string = '') {
+  $matches = array();
+  if ($string) {
+    // Find local matches
+    $result = db_query_range("SELECT name FROM {users} WHERE name LIKE '%s%%'", $string, 0, 10);
+    while ($user = db_fetch_object($result)) {
+      $matches[$user->name] = check_plain($user->name);
+    }
+
+    if (count($matches) < 10) {
+      $master = variable_get('bakery_master', 'http://drupal.org/');
+      $key = variable_get('bakery_key', '');
+
+      $payload = array();
+      $payload['string'] = $string;
+      $payload['timestamp'] = $_SERVER['REQUEST_TIME'];
+      $payload['signature'] = hash_hmac('sha256', $payload['string'] . '/' . $payload['timestamp'], $key);
+      $payload = drupal_query_string_encode(array('fortune' => bakery_mix(serialize($payload), 1)));
+      // Make request to master for account information.
+      $result = drupal_http_request($master . 'bakery/autocomplete-master', array('Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8'), 'POST', $payload);
+      // Parse result and create account.
+      if ($result->code == 200) {
+        $cookie = unserialize(bakery_mix($result->data, 0));
+        $matches = array_merge($matches, $cookie['matches']);
+      }
+    }
+  }
+
+  drupal_json($matches);
+}
+
+/**
  * Validate handler for the password reset login.
  */
 function _bakery_pass_validate($form, &$form_state) {
@@ -1286,6 +1377,56 @@ function bakery_eat_gingerbread_cookie()
 }
 
 /**
+ * Validate the autocomplete information request.
+ */
+function bakery_taste_fortune_cookie() {
+  $valid = FALSE;
+
+  if (isset($_POST['fortune'])) {
+    $payload = $_POST['fortune'];
+    $cookie = unserialize(bakery_mix($payload, 0));
+    watchdog('!', print_r($cookie, TRUE));
+    $key = variable_get('bakery_key', '');
+    $signature = hash_hmac('sha256', $cookie['string'] . '/' . $cookie['timestamp'], $key);
+    watchdog('!', $signature);
+
+    if ($signature == $cookie['signature'] && $cookie['timestamp'] + variable_get('bakery_freshness', '3600') >= $_SERVER['REQUEST_TIME']) {
+      $valid = TRUE;
+      $_SESSION['bakery']['string'] = $cookie['string'];
+    }
+  }
+
+  return $valid;
+}
+
+/**
+ * Respond with autocomplete information.
+ */
+function bakery_eat_fortune_cookie() {
+  // Session was set in validate.
+  $string = $_SESSION['bakery']['string'];
+  unset($_SESSION['bakery']['string']);
+  $key = variable_get('bakery_key', '');
+
+  $payload = array(
+    'matches' => array(),
+  );
+  $result = db_query_range("SELECT name FROM {users} WHERE name LIKE '%s%%'", $string, 0, 10);
+  while ($user = db_fetch_object($result)) {
+    $payload['matches'][$user->name] = check_plain($user->name);
+  }
+  $payload['timestamp'] = $_SERVER['REQUEST_TIME'];
+  $payload['signature'] = hash_hmac('sha256', $payload['name'] . '/' . $payload['timestamp'], $key);
+
+  // Respond with encrypted and signed account information.
+  $message = bakery_mix(serialize($payload), 1);
+
+  module_invoke_all('exit');
+  print $message;
+  exit();
+}
+
+/**
  * Destroy unwanted cookies
  */
 function _bakery_eat_cookie($type = 'CHOCOLATECHIP') {
