--- profile.module?rev=1.127	2006-02-07 16:33:41.000000000 +1100
+++ profile_5.module	2006-02-07 12:33:59.000000000 +1100
@@ -109,6 +109,22 @@
 }
 
 /**
+ * Implementation of hook_perm().
+ */
+function profile_perm() {
+    // Compile the permissions for each individual profile field.
+    $perms = array();
+    $result = db_query('SELECT name FROM {profile_fields}');
+    while ($record = db_fetch_object($result)) {
+      $perms[] = 'access ' .$record->name;
+      $perms[] = 'access own ' .$record->name;
+      $perms[] = 'edit own ' .$record->name;
+    }
+  
+  return $perms;
+}
+
+/**
  * Implementation of hook_menu().
  */
 function profile_menu($may_cache) {
@@ -153,12 +169,20 @@
        return;
     }
 
+    // Do not allow browsing of fields by users who can't access the fields content
+    if (!_profile_perm_access_field($field)) {
+       drupal_access_denied();
+       return;
+    }
+
     // Compile a list of fields to show
     $fields = array();
     $result = db_query('SELECT name, title, type, weight FROM {profile_fields} WHERE fid != %d AND visibility = %d ORDER BY weight', $field->fid, PROFILE_PUBLIC_LISTINGS);
     while ($record = db_fetch_object($result)) {
+      if (_profile_perm_access_field($record)) {
       $fields[] = $record;
     }
+    }
 
     // Determine what query to use:
     $arguments = array($field->fid);
@@ -247,21 +271,23 @@
     // We use LOWER('%s') instead of PHP's strtolower() to avoid UTF-8 conversion issues.
   }
   while ($field = db_fetch_object($result)) {
+    if (isset($edit[$field->name])) {
     if (_profile_field_serialize($field->type)) {
        $edit[$field->name] = serialize($edit[$field->name]);
     }
     db_query("DELETE FROM {profile_values} WHERE fid = %d AND uid = %d", $field->fid, $user->uid);
     db_query("INSERT INTO {profile_values} (fid, uid, value) VALUES (%d, %d, '%s')", $field->fid, $user->uid, $edit[$field->name]);
     // Mark field as handled (prevents saving to user->data).
-    $edit[$field->name] = NULL;
+      $edit[$field->name] = null;
+    }
   }
 }
 
 function profile_view_field($user, $field) {
-  // Only allow browsing of private fields for admins
-  $browse = user_access('administer users') || $field->visibility != PROFILE_PRIVATE;
+  // Only allow browsing of  fields by users who can access the fields content for all users
+  $browse = _profile_perm_access_field($field);
 
-  if ($value = $user->{$field->name}) {
+  if (($value = $user->{$field->name}) && _profile_perm_access_field($field, $user)) {
     switch ($field->type) {
       case 'textfield':
         return check_plain($value);
@@ -300,18 +326,11 @@
 function profile_view_profile($user) {
 
   profile_load_profile($user);
-
-  // Show private fields to administrators and people viewing their own account.
-  if (user_access('administer users') || $GLOBALS['user']->uid == $user->uid) {
     $result = db_query('SELECT * FROM {profile_fields} WHERE visibility != %d ORDER BY category, weight', PROFILE_HIDDEN);
-  }
-  else {
-    $result = db_query('SELECT * FROM {profile_fields} WHERE visibility != %d AND visibility != %d ORDER BY category, weight', PROFILE_PRIVATE, PROFILE_HIDDEN);
-  }
 
   while ($field = db_fetch_object($result)) {
     if ($value = profile_view_field($user, $field)) {
-      $description = ($field->visibility == PROFILE_PRIVATE) ? t('The content of this field is private and only visible to yourself.') : '';
+      //$description = ($field->visibility == PROFILE_PRIVATE) ? t('The content of this field is private and only visible to yourself.') : '';
       $title = ($field->type != 'checkbox') ? check_plain($field->title) : '';
       $form = array('#title' => $title, '#value' => $value, '#description' => $description);
       $fields[$field->category][$field->name] = theme('item', $form);
@@ -328,9 +347,10 @@
     $output .= ' '. t('Put each item on a separate line or separate them by commas.  No HTML allowed.');
   }
 
-  if ($field->visibility == PROFILE_PRIVATE) {
-    $output .= ' '. t('The content of this field is kept private and will not be shown publicly.');
-  }
+  //  We could read the roles with permission to access this field and print them here.
+  //if ($field->visibility == PROFILE_PRIVATE) {
+  //  $output .= ' '. t('The content of this field is kept private and will not be shown publicly.');
+  //}
 
   return $output;
 }
@@ -346,6 +366,7 @@
   }
 
   while ($field = db_fetch_object($result)) {
+    if (_profile_perm_edit_field($field, $user)) {
     $category = $field->category;
     if (!isset($fields[$category])) {
       $fields[$category] = array('#type' => 'fieldset', '#title' => $category, '#weight' => $w++);
@@ -379,6 +400,7 @@
         break;
     }
   }
+  }
   return $fields;
 }
 
@@ -394,7 +416,7 @@
   return $fields;
 }
 
-function profile_validate_profile($edit, $category) {
+function profile_validate_profile($edit, $user, $category) {
 
   if ($_GET['q'] == 'user/register' || $_GET['q'] == 'admin/user/create') {
     $result = db_query('SELECT * FROM {profile_fields} WHERE register = 1 ORDER BY category, weight');
@@ -406,13 +428,17 @@
 
   while ($field = db_fetch_object($result)) {
     if ($edit[$field->name]) {
+      if (!_profile_perm_edit_field($field, $user)) {
+        form_set_error($field->name, t('You do not have permission to edit %field.', array('%field' => theme('placeholder', $field->title))));      
+      }
+      
       if ($field->type == 'url') {
         if (!valid_url($edit[$field->name], true)) {
           form_set_error($field->name, t('The value provided for %field is not a valid URL.', array('%field' => theme('placeholder', $field->title))));
         }
       }
     }
-    else if ($field->required && !user_access('administer users')) {
+    else if ($field->required && !user_access('administer users') && _profile_perm_edit_field($field, $user)) {
       form_set_error($field->name, t('The field %field is required.', array('%field' => theme('placeholder', $field->title))));
     }
   }
@@ -445,7 +471,7 @@
     case 'form':
       return profile_form_profile($edit, $user, $category);
     case 'validate':
-      return profile_validate_profile($edit, $category);
+      return profile_validate_profile($edit, $user, $category);
     case 'categories':
       return profile_categories();
   }
@@ -660,4 +686,46 @@
   return $type == 'date';
 }
 
+/*
+ *  Returns true if the logged in user has permission to access/view the $field for $user.
+ */
+function _profile_perm_access_field($field, $user = NULL) {
+  return user_access('administer users') || user_access('access ' .$field->name) || (($user != NULL) && ($GLOBALS['user']->uid == $user->uid) && user_access('access own ' .$field->name));
+}
+
+/*
+ *  Returns true if the logged in user has permission to edit the $field for $user.
+ */
+function _profile_perm_edit_field($field, $user) {
+  return user_access('administer users') || user_access('edit own ' .$field->name);
+}
+
+function profile_search($op = 'search', $keys = null) {
+  switch ($op) {
+    case 'name':
+      if (user_access('access user profiles')) {
+        return t('profiles');
+      }
+    case 'search':
+      if (user_access('access user profiles')) {
+        $find = array();
+        // Replace wildcards with MySQL/PostgreSQL wildcards.
+        $keys = preg_replace('!\*+!', '%', $keys);
+        if (user_access('administer users')) {
+          // administrators don't have restrictions
+          $result = pager_query("SELECT u.* FROM {users} u INNER JOIN {profile_values} pv ON u.uid = pv.uid INNER JOIN {profile_fields} pf ON pv.fid = pf.fid WHERE LOWER(pv.value) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys);
+        }
+        else {
+          // non-administrators can only search public fields and active users
+          $result = pager_query("SELECT u.* FROM {users} u INNER JOIN {profile_values} pv ON u.uid = pv.uid INNER JOIN {profile_fields} pf ON pv.fid = pf.fid WHERE LOWER(pv.value) LIKE LOWER('%%%s%%') AND pf.visibility IN (%d, %d) AND u.status = 1", 15, 0, NULL, $keys, PROFILE_PUBLIC, PROFILE_PUBLIC_LISTINGS);
+        }
+        while ($account = db_fetch_object($result)) {
+          $user = user_load(array('uid'=>$account->uid));
+          $view = implode(' | ', profile_view_profile($user));
+          $find[] = array('title' => $account->name, 'link' => url("user/$account->uid/view"), 'snippet'=>search_excerpt($keys, $view));
+        }
+        return $find;
+      }
+  }
+}
 
