diff -urN members.cvs/CHANGELOG.txt members/CHANGELOG.txt
--- members.cvs/CHANGELOG.txt	1970-01-01 10:00:00.000000000 +1000
+++ members/CHANGELOG.txt	2004-11-05 04:35:35.000000000 +1100
@@ -0,0 +1,50 @@
+04. November 2004
+-----------------
+- Change maintainers to James Walker <walkah@walkah.net>
+- Update for 4.5.0
+- Use new profile.module for extra fields
+
+13. November 2003
+-----------------
+- Updated to 4.3.0.
+- Users table() to create table.
+- Added permission 'access members list'.
+- Added database-prefix support.
+- Improved translation support.
+
+15. July 2003
+-------------
+members.module [Matt Westgate]
+- Eliminate the MySQL specific CONCAT() in order to work with all databases.
+
+10. June 2003
+-------------
+members.module [Matt Westgate]
+- updated module to work with latest CVS.
+- Displays user's homepage when profile module is enabled.
+
+02. May 2002
+------------
+members.module [Kjartan Mannes]
+- updated module to work with latest CVS.
+- updated INSTALL instructions.
+
+25. September 2001
+------------------
+members.module [Kjartan Mannes]
+- cleaned up the code and removed obsolete code.
+- removed check for "access content".
+
+members.module [Axel Kollmorgen]
+- added links to blog and recent comments.
+
+24. September 2001
+------------------
+members.module
+- updated to support new user system.
+- changed link on user name to use format_name().
+- other minor changes.
+
+11. July 2001
+-------------
+- initial release.
diff -urN members.cvs/contrib/membersbuddylist/membersbuddylist.module members/contrib/membersbuddylist/membersbuddylist.module
--- members.cvs/contrib/membersbuddylist/membersbuddylist.module	1970-01-01 10:00:00.000000000 +1000
+++ members/contrib/membersbuddylist/membersbuddylist.module	2007-12-11 14:36:44.000000000 +1100
@@ -0,0 +1,51 @@
+<?php
+
+function membersbuddylist_help($section) {
+  switch ($section) {
+    case 'admin/modules#description':
+      return t('Integrates the %buddylist and members modules.', buddylist_translation());
+    break;
+    case 'admin/help#buddylistmembers':
+      return t("<p>Allows some extra fields into the %buddy module.</p>", buddylist_translation());
+    break;
+  }
+}
+
+function membersbuddylist_members($op, $a='', $b='') {
+  global $user;
+    
+  switch($op) {
+    // return array of what fields we can define for members module
+    case 'fields':
+      // this module only has one field of use
+      $fields['ismybuddy'] = array ('title'=> 'Is a buddy', 'type' => 'bool');
+      return $fields;
+    break;
+    
+    case 'process':
+      // create a temporary table with our results of who is the current users buddy
+      // members module will be expecting this table ($b) todo a LEFT JOIN on to gather more information
+      if($a == 'ismybuddy') {
+        db_query("CREATE TEMPORARY TABLE {%s} (uid int, %s int, INDEX (uid))",$b,$a);
+        db_query("INSERT INTO {%s} SELECT buddy,buddy FROM buddylist where uid=%d and received=1 ",$b,$user->uid);
+       }
+    break;
+  }
+}
+
+/**
+ * hook_theme
+ *
+ * @param $user row from table join
+ * @param field_id
+ * @param $row_value value of the join in the current members row
+ * @return string with better representation of the row
+ */
+function theme_membersbuddylist_field($user, $field_id, $row_value) {
+  if($row_value->ismybuddy) {
+    return "Yes";
+  } else {
+    return "No";
+  }
+}
+
diff -urN members.cvs/contrib/membersprofile/membersprofile.module members/contrib/membersprofile/membersprofile.module
--- members.cvs/contrib/membersprofile/membersprofile.module	1970-01-01 10:00:00.000000000 +1000
+++ members/contrib/membersprofile/membersprofile.module	2007-12-11 13:33:01.000000000 +1100
@@ -0,0 +1,115 @@
+<?php
+
+function membersprofile_help($section) {
+  switch ($section) {
+    case 'admin/modules#description':
+      return t('Integrates the profile and members modules, allowing search and sort by profile details');
+    break;
+  }
+}
+
+  $items[] = array('path' => 'membersprofile/auto',
+                                'title' => t('members autocomplete callback'),
+                                'callback' => 'hello_world_autocomplete',
+                                'type' => MENU_CALLBACK);         
+/**
+  *
+  * hook_members
+  * handles temp tables for returning data to the members module for sorting
+  *
+  */
+function membersprofile_members($op, $a='', $b='', $c='') {
+  global $user;
+    
+  switch($op) {
+    // return array of what fields we can define for members module
+    case 'fields':
+                  
+      $result=db_query("SELECT name,title,type,options from {profile_fields}");
+      while ( $row = db_fetch_array($result) ) {
+        // clean up the list of possible values
+        $options = array();
+        if(is_string($row['options'])) {
+          $o = preg_split('/[\n,\s]/',$row['options']);
+          if(is_array($o)) {
+            $options['any']='Any';
+            foreach($o as $option) {
+              if(strlen($option)) {
+                $options[$option]=$option;
+              }
+            }
+          }
+        }
+        // todo: not sure how you get a single non-question like title for these fields
+        // as some people put for example "What is your gender?" into the profile_field title
+        // so we just do some string cleaning of the 'name' fields
+        // this could also be themable?
+        $name = eregi_replace('^profile_','',$row['name']);
+        $name = ucfirst(str_replace('_',' ',$name));
+        
+        // if type is a textfield, then set autocomplete to true
+        $autocomplete = $row['type']=='textfield' ? true : false;
+        
+        $fields[$row['name']]=array ('title'=>$name,'type'=>$row['type'],'options'=>$options, 'autocomplete'=>$autocomplete);
+      }
+      
+      return $fields;
+    break;
+    
+    case 'process':
+      
+      db_query("CREATE TEMPORARY TABLE {%s} (uid int, %s int, INDEX (uid), INDEX(%s))",$b,$a,$a);
+      
+      $result=db_fetch_array(db_query("SELECT fid FROM {profile_fields} where name = '%s'",check_plain($a)));
+      if(strlen($c)) {
+        db_query('INSERT INTO {%s} SELECT uid,uid from profile_values where fid=%d AND value LIKE "%%%s%%"',$b,$result['fid'],$c);    
+      } else {
+        db_query('INSERT INTO {%s} SELECT uid,uid from profile_values where fid=%d',$b,$result['fid']);    
+      }
+      
+    break;
+  }
+}
+
+function membersprofile_autocomplete($field_name, $string) {
+  $matches=array();
+  
+  $field_info=db_fetch_array(db_query("SELECT fid FROM {profile_fields} where name = '%s'",check_plain($field_name)));
+  $result = db_query("SELECT value,count(*) as c FROM {profile_values} WHERE value like '%%%s%%' and fid =%d group by value order by c desc limit 0,15", $string, $field_info['fid']);
+
+  while ($row = db_fetch_object($result)) {
+    $matches[$row->value]=$row->value.' ('.$row->c.')';
+  }
+  
+  return $matches;
+}
+
+/**
+ * hook_theme
+ *
+ * @param $account row from table join
+ * @param $field_id id of field for profile module reference
+ * @param $row_value value of the join in the current members row
+ * @return string with better representation of the row
+ * 
+ * because we are using profile module for the data, we just need to pass
+ * the account and the field_id (name) and it will return the value for us
+ * 
+ */
+function theme_membersprofile_field($account, $field_id) {
+
+  static $profile_fields;
+  
+  if (!$profile_fields[$field_id]) {
+    $profile_fields[$field_id] = db_fetch_object(db_query("SELECT * FROM {profile_fields} WHERE name='%s'", $field_id));
+  }
+  
+  $data = profile_view_field($account, $profile_fields[$field_id]);
+  $length = variable_get('members_field_length', 0);
+  if ($length && is_numeric($length)) {
+    $data  = truncate_utf8($data, $length, TRUE);
+  }
+  
+  return $data;
+          
+}
diff -urN members.cvs/INSTALL.txt members/INSTALL.txt
--- members.cvs/INSTALL.txt	1970-01-01 10:00:00.000000000 +1000
+++ members/INSTALL.txt	2004-11-05 04:35:35.000000000 +1100
@@ -0,0 +1,15 @@
+Installation
+------------
+
+1. Copy the members.module to the Drupal modules/ directory.
+
+2. Go to "modules" under "site configuration" in the administration pages and
+   enable the module.
+
+3. Check the "settings" page and set the fields and roles to be displayed
+
+
+Maintainer
+----------
+
+James Walker <walkah@walkah.net>
diff -urN members.cvs/LICENSE.txt members/LICENSE.txt
--- members.cvs/LICENSE.txt	1970-01-01 10:00:00.000000000 +1000
+++ members/LICENSE.txt	2006-04-23 19:54:26.000000000 +1000
@@ -0,0 +1,274 @@
+GNU GENERAL PUBLIC LICENSE
+
+              Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave,
+Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute
+verbatim copies of this license document, but changing it is not allowed.
+
+                  Preamble
+
+The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public License is
+intended to guarantee your freedom to share and change free software--to
+make sure the software is free for all its users. This General Public License
+applies to most of the Free Software Foundation's software and to any other
+program whose authors commit to using it. (Some other Free Software
+Foundation software is covered by the GNU Library General Public License
+instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the
+freedom to distribute copies of free software (and charge for this service if
+you wish), that you receive source code or can get it if you want it, that you
+can change the software or use pieces of it in new free programs; and that
+you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to
+deny you these rights or to ask you to surrender the rights. These restrictions
+translate to certain responsibilities for you if you distribute copies of the
+software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for
+a fee, you must give the recipients all the rights that you have. You must make
+sure that they, too, receive or can get the source code. And you must show
+them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2)
+offer you this license which gives you legal permission to copy, distribute
+and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that
+everyone understands that there is no warranty for this free software. If the
+software is modified by someone else and passed on, we want its recipients
+to know that what they have is not the original, so that any problems
+introduced by others will not reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents. We
+wish to avoid the danger that redistributors of a free program will individually
+obtain patent licenses, in effect making the program proprietary. To prevent
+this, we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification
+follow.
+
+           GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
+               MODIFICATION
+
+0. This License applies to any program or other work which contains a notice
+placed by the copyright holder saying it may be distributed under the terms
+of this General Public License. The "Program", below, refers to any such
+program or work, and a "work based on the Program" means either the
+Program or any derivative work under copyright law: that is to say, a work
+containing the Program or a portion of it, either verbatim or with
+modifications and/or translated into another language. (Hereinafter, translation
+is included without limitation in the term "modification".) Each licensee is
+addressed as "you".
+
+Activities other than copying, distribution and modification are not covered
+by this License; they are outside its scope. The act of running the Program is
+not restricted, and the output from the Program is covered only if its contents
+constitute a work based on the Program (independent of having been made
+by running the Program). Whether that is true depends on what the Program
+does.
+
+1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this License
+and to the absence of any warranty; and give any other recipients of the
+Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you
+may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it,
+thus forming a work based on the Program, and copy and distribute such
+modifications or work under the terms of Section 1 above, provided that you
+also meet all of these conditions:
+
+a) You must cause the modified files to carry prominent notices stating that
+you changed the files and the date of any change.
+
+b) You must cause any work that you distribute or publish, that in whole or in
+part contains or is derived from the Program or any part thereof, to be
+licensed as a whole at no charge to all third parties under the terms of this
+License.
+
+c) If the modified program normally reads commands interactively when run,
+you must cause it, when started running for such interactive use in the most
+ordinary way, to print or display an announcement including an appropriate
+copyright notice and a notice that there is no warranty (or else, saying that
+you provide a warranty) and that users may redistribute the program under
+these conditions, and telling the user how to view a copy of this License.
+(Exception: if the Program itself is interactive but does not normally print such
+an announcement, your work based on the Program is not required to print
+an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Program, and can be
+reasonably considered independent and separate works in themselves, then
+this License, and its terms, do not apply to those sections when you distribute
+them as separate works. But when you distribute the same sections as part
+of a whole which is a work based on the Program, the distribution of the
+whole must be on the terms of this License, whose permissions for other
+licensees extend to the entire whole, and thus to each and every part
+regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your rights to
+work written entirely by you; rather, the intent is to exercise the right to
+control the distribution of derivative or collective works based on the
+Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of a
+storage or distribution medium does not bring the other work under the scope
+of this License.
+
+3. You may copy and distribute the Program (or a work based on it, under
+Section 2) in object code or executable form under the terms of Sections 1
+and 2 above provided that you also do one of the following:
+
+a) Accompany it with the complete corresponding machine-readable source
+code, which must be distributed under the terms of Sections 1 and 2 above
+on a medium customarily used for software interchange; or,
+
+b) Accompany it with a written offer, valid for at least three years, to give
+any third party, for a charge no more than your cost of physically performing
+source distribution, a complete machine-readable copy of the corresponding
+source code, to be distributed under the terms of Sections 1 and 2 above on
+a medium customarily used for software interchange; or,
+
+c) Accompany it with the information you received as to the offer to distribute
+corresponding source code. (This alternative is allowed only for
+noncommercial distribution and only if you received the program in object
+code or executable form with such an offer, in accord with Subsection b
+above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source code
+means all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation and
+installation of the executable. However, as a special exception, the source
+code distributed need not include anything that is normally distributed (in
+either source or binary form) with the major components (compiler, kernel,
+and so on) of the operating system on which the executable runs, unless that
+component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to
+copy from a designated place, then offering equivalent access to copy the
+source code from the same place counts as distribution of the source code,
+even though third parties are not compelled to copy the source along with the
+object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as
+expressly provided under this License. Any attempt otherwise to copy,
+modify, sublicense or distribute the Program is void, and will automatically
+terminate your rights under this License. However, parties who have received
+copies, or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it.
+However, nothing else grants you permission to modify or distribute the
+Program or its derivative works. These actions are prohibited by law if you
+do not accept this License. Therefore, by modifying or distributing the
+Program (or any work based on the Program), you indicate your acceptance
+of this License to do so, and all its terms and conditions for copying,
+distributing or modifying the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these terms and
+conditions. You may not impose any further restrictions on the recipients'
+exercise of the rights granted herein. You are not responsible for enforcing
+compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues), conditions
+are imposed on you (whether by court order, agreement or otherwise) that
+contradict the conditions of this License, they do not excuse you from the
+conditions of this License. If you cannot distribute so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not distribute the Program at all.
+For example, if a patent license would not permit royalty-free redistribution
+of the Program by all those who receive copies directly or indirectly through
+you, then the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply and
+the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or
+other property right claims or to contest validity of any such claims; this
+section has the sole purpose of protecting the integrity of the free software
+distribution system, which is implemented by public license practices. Many
+people have made generous contributions to the wide range of software
+distributed through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing to
+distribute software through any other system and a licensee cannot impose
+that choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain
+countries either by patents or by copyrighted interfaces, the original copyright
+holder who places the Program under this License may add an explicit
+geographical distribution limitation excluding those countries, so that
+distribution is permitted only in or among countries not thus excluded. In such
+case, this License incorporates the limitation as if written in the body of this
+License.
+
+9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will be
+similar in spirit to the present version, but may differ in detail to address new
+problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies
+a version number of this License which applies to it and "any later version",
+you have the option of following the terms and conditions either of that
+version or of any later version published by the Free Software Foundation. If
+the Program does not specify a version number of this License, you may
+choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs
+whose distribution conditions are different, write to the author to ask for
+permission. For software which is copyrighted by the Free Software
+Foundation, write to the Free Software Foundation; we sometimes make
+exceptions for this. Our decision will be guided by the two goals of
+preserving the free status of all derivatives of our free software and of
+promoting the sharing and reuse of software generally.
+
+               NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT
+PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
+STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
+WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
+AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR
+ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
+LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
+SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OR INABILITY TO USE THE
+PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
+OR DATA BEING RENDERED INACCURATE OR LOSSES
+SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
+PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN
+IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGES.
+
+          END OF TERMS AND CONDITIONS
diff -urN members.cvs/members.module members/members.module
--- members.cvs/members.module	1970-01-01 10:00:00.000000000 +1000
+++ members/members.module	2007-12-11 16:08:16.000000000 +1100
@@ -0,0 +1,422 @@
+<?php
+// $Id: members.module,v 1.39 2007/02/01 16:35:48 walkah Exp $
+
+function members_help($section) {
+  switch ($section) {
+    case 'admin/modules#description':
+      return t('Enables users to list all members.');
+      break;
+  }
+}
+
+function members_settings() {
+  $form['members_roles'] = array(
+    '#type' => 'select',
+    '#title' => t('Roles to show'),
+    '#default_value' => variable_get('members_roles', array()),
+    '#options' => user_roles(1),
+    '#description' => t('Select roles to show in the members listing.'),
+    '#extra' => 0,
+    '#multiple' => 1,
+    '#size' => 5,
+  );
+  $form['members_fields'] = array(
+    '#type' => 'select',
+    '#title' => t('Columns to show'),
+    '#default_value' => variable_get('members_fields', _member_fields()),
+    '#options' => _member_fields(),
+    '#description' => t('Select the fields which should be displayed on your members overview page. Note that some fields require certain modules to be active.'),
+    '#extra' => 0,
+    '#multiple' => 1,
+    '#size' => 8,
+  );
+  
+  $form['members_fields_search'] = array(
+    '#type' => 'select',
+    '#title' => t('Columns to search'),
+    '#default_value' => variable_get('members_fields_search', _member_fields()),
+    '#options' => _member_fields(),
+    '#description' => t('Select the fields which are offered to search on your members overview page. Note that some fields require certain modules to be active.'),
+    '#extra' => 0,
+    '#multiple' => 1,
+    '#size' => 8,
+  );
+  
+  $form['members_encode_mailto'] = array(
+   '#type' => 'checkbox',
+   '#title' => t('Obfuscate e-mail addresses using JavaScript'),
+   '#return_value' => 1,
+   '#default_value' => variable_get('members_encode_mailto', 1),
+   '#description' => t('When checked, email addresses will not be included directly in the HTML source to deter spam crawlers. Note: this requires users have a JavaScript-enabled browser.'),
+  );
+  $form['members_field_length'] = array(
+   '#type' => 'textfield',
+   '#title' => t('Truncated field length'),
+   '#default_value' => variable_get('members_field_length', 0),
+   '#size' => 4,
+   '#maxlength' => 6,
+   '#description' => t('If set (and non-zero), all fields will be truncated to this length (in characters) to preserve table layouts.'),
+  );
+
+  return $form;
+}
+
+function members_menu($may_cache) {
+  $items = array();
+
+  if ($may_cache) {
+    $items[] = array('path' => 'members',
+                     'title' => t("members"),
+                     'callback' => "members_page",
+                     'access' => user_access("access members list"),
+                     'type' => MENU_MODIFIABLE_BY_ADMIN );
+
+  }
+            
+  $items[] = array('path' => 'members/auto',
+                                'title' => t('members autocomplete callback'),
+                                'callback' => 'members_autocomplete_dispatch',
+                                'access' => user_access("access members list"),
+                                'type' => MENU_CALLBACK);         
+                                
+  return $items;
+}
+
+// autocomplete mechanism
+function members_autocomplete_dispatch($modulename,$field_id,$string) {
+
+  // ask the appropriate module if there is an autocomplete hook it supports
+  $matches = array();
+  if(strlen($string) > 2 ) {
+    $function=check_plain($modulename."_autocomplete");
+    if(function_exists($function)) {
+      $matches = $function($field_id, $string);
+    }
+  }
+  print drupal_to_js($matches);
+  exit();
+}
+
+
+function members_perm() {
+  return array("access members list");
+}
+
+
+function add_where_joins_from_search(&$w_joins) {
+  
+  foreach($_SESSION['members_search_form'] as $field => $value) {
+    $search_type = _search_item_type($field) ;
+
+     $hook_info=explode(".",$field);
+     $hook_temp_table = 't_'.$hook_info[1].'_'.$hook_info[2];
+    
+    switch($search_type['type']) {
+      case 'bool':      
+          if($value == 'yes') {
+            $w_joins[]=$hook_temp_table.'.'.$hook_info[2].' IS NOT NULL';
+          } 
+      break;
+      case 'selection':
+        // if we care about doing a search for the profile selection field
+        if($value != 'any') {
+          $w_joins[]="$hook_temp_table".'.'.$hook_info[2]." IS NOT NULL";
+        }
+      
+      break;
+      case 'textfield':
+        $w_joins[]="$hook_temp_table".'.'.$hook_info[2]." IS NOT NULL";
+      break;
+      
+    }
+    
+  }
+  return;
+}
+
+
+function members_page($rids = null) {
+
+  $output = _members_search_form();
+  
+  if (user_access("access members list")) {
+
+  /* $output .= drupal_get_form('members_search',_members_search_form($_POST)); */
+    
+    // you may specify roles using second url argument. otherwise, use admin pref
+    if ($rids) {
+      $roles = explode(',', $rids);
+    }
+    else {
+      $roles = variable_get("members_roles", array());
+    }
+
+    if ($roles) {
+      $fields = array();
+      $enabled_fields = variable_get("members_fields", _member_fields());
+      foreach (_member_fields() as $field => $data) {
+        if (in_array($field, $enabled_fields)) {
+          $fields[$field] = $data;
+        }
+      }
+      
+      $q_joins = array();
+      $s_joins = array();
+      $w_joins = array();
+      $hook_fields = array();
+      
+      foreach ($fields as $field => $data) {
+        
+        if(drupal_substr($field, 0, 5) == 'hook.') {
+          
+          $hook_info=explode(".",$field);
+          $hook_temp_table = 't_'.$hook_info[1].'_'.$hook_info[2];
+          
+          //invoke that hook so it creates a temp table with the infos
+          $function = $hook_info[1] .'_members';
+          if(function_exists($function)) {
+            $function('process',$hook_info[2],$hook_temp_table,$_SESSION['members_search_form'][$field]);
+            // get the hook fields available from this module
+            $avail_fields =  $function('fields');
+              
+            $q_joins[] = "LEFT JOIN {$hook_temp_table} ON $hook_temp_table.uid=u.uid";
+            $s_joins[] = $hook_temp_table.'.'.$hook_info[2];
+          }
+          $header[] = array("data" => $avail_fields[$hook_info[2]]['title'], "field" => $hook_temp_table.'.'.$hook_info[2]);
+          
+        } else {
+          $header[] = array("data" => $data, "field" => $field);
+        }
+      }
+      
+      // todo: this roles stuff could be moved to its own module
+      if (in_array('2', $roles)) {
+        $allusers = 1;
+        $w_joins[] = 'u.status=1';
+      }
+      else {
+        $allusers = 0;
+        $w_joins[]="r.rid IN ($list) AND u.status = 1";
+        foreach ($roles as $rid) {
+          $list[] = "'" . db_escape_string($rid) ."'";
+        }
+        $list = implode(',', $list);
+        $q_joins[]=' LEFT JOIN {users_roles} r ON u.uid = r.uid ';
+      }
+
+      // depending on the search form, add some extra WHERE's
+      add_where_joins_from_search($w_joins);
+         
+      $query = 'SELECT DISTINCT(u.uid) '; // SELECTS
+      if(sizeof($s_joins) > 0) {
+        $query .= ',';
+        $query .= implode($s_joins,', ');
+      }
+      
+      
+      $query .= ' FROM {users} u ';
+      $query .= ' '.implode($q_joins,' ').' '; // LEFT JOINS
+      $query .= ' WHERE '.implode($w_joins,' AND '); // WHERE
+      $query .= ' '.tablesort_sql($header);
+      
+      $result = pager_query($query, 50); // this needs to know the total todo:
+
+      $rows = array();
+      
+      while ($userid = db_fetch_object($result)) {
+        $account = user_load(array('uid' => $userid->uid));
+        $row = array();
+        foreach ($fields as $field => $title) {
+          $data = NULL;
+          // if this field is a hook, then do some theme callbacks
+          if (drupal_substr($field, 0, 5) == 'hook.') {
+            $hook_info=explode(".",$field);
+            // hooks provide each field to be themeable
+            $account = user_load(array('uid'=>$userid->uid));
+            $data=theme($hook_info[1].'_field',$account,$hook_info[2], $userid);
+          } // else it is a local code field (which should be depreciated in the future)
+          else if ($field == 'rid') {
+            $data = array();
+            foreach ($account->roles as $rid => $role) {
+              if (in_array($rid, $roles)) {
+                $data[] = l($role, 'members/'.$rid);
+              }
+            }
+            $data = implode (', ', $data);
+          }
+          else if ($field == 'picture') {
+            $data = theme_user_picture($account);
+          }
+          else if ($field == 'access') {
+            $data = ($account->login) ? format_interval(time() - $account->access) : t('Never logged in');
+          }
+          else if ($field == 'mail') {
+            if (variable_get('members_encode_mailto', 1)) {
+              $data = _members_encode_mailto($account->mail);
+            }
+            else {
+              $data = $account->mail;
+            }
+          }
+          else {
+            $data = $account->$field;
+          }
+
+          if (stristr($field, 'name')) {
+            $data = l($data, 'user/'.$account->uid);
+          }
+          $row[] = array('data' => $data);
+        }
+        $rows[] = $row;
+      }
+
+      if ($pager = theme('pager', NULL, 50, 0)) {
+        $rows[] = array(array("data" => $pager, "colspan" => count($header)));
+      }
+
+      $output.= '<div id="members-main">'. theme("table", $header, $rows) .'</div>';
+      return $output;
+    }
+    else {
+      return t("Warning: there aren't any users with roles configured to be shown here.");
+    }
+  }
+}
+
+function _member_fields() {
+  $output = array();
+
+  $output['rid'] = t('Roles');
+  $output['name'] = t('Username');
+  $output['mail'] = t('Email');
+  $output['access'] = t('Last Seen');
+  $output['picture'] = t('Picture');
+
+  // hook_members fields
+  // Look for extensions from other modules
+  foreach (module_implements('members') as $module) {
+    $function = $module .'_members';
+    $fields = $function('fields');
+    foreach($fields as $field_id =>$field ) {
+      $output['hook.'.$module.'.'.$field_id] = check_plain($field['title']);
+    }
+  }
+
+  return $output;
+}
+
+function _members_encode_mailto($mail) {
+  $link = 'document.write(\'<a href="mailto:' . $mail . '">' . $mail . '</a>\');';
+
+  $js_encode = '';
+  for ($x = 0; $x < strlen($link); $x++) {
+    $js_encode .= '%' . bin2hex($link{$x});
+  }
+
+  $link = '<script type="text/javascript" language="javascript">eval(unescape(\''.$js_encode.'\'))</script>';
+  if (isset($matches[3])) {
+    $link = $matches[1] . $link;
+  }
+
+  return $link;
+}
+
+/**
+ * return the type of search that this field name can do
+ * 
+ *
+ * @param string $field_name
+ */
+function _search_item_type($field) {
+
+  if (drupal_substr($field, 0, 5) == 'hook.') {
+    $hook_info=explode(".",$field);
+    $function = $hook_info[1] .'_members';
+    if(function_exists($function)) {
+      // get the label/title/type of the field
+      $fields = $function('fields');
+      $field = $fields[$hook_info[2]];
+
+    }
+  } else {
+    $field['type']='string';
+  }
+
+  return $field;
+}
+
+function _members_search_form() {
+
+  if($_POST['op']=='Reset Filter') {
+    unset($_SESSION['members_search_form']);
+    drupal_goto("members");
+  } else {
+    $defaults = $_SESSION['members_search_form'];
+  }
+  
+  $search_fields = variable_get("members_fields_search", _member_fields());
+
+  drupal_set_message($reset_session);
+  foreach ($search_fields as $field => $data) {
+    $search_type = _search_item_type($field);
+    
+    $field_name = $field;
+    $title = $search_type['title'];
+    $options = $search_type['options'];
+    
+    
+    switch($search_type['type']) {
+      case 'bool':
+        $form['filter'][$field_name] = array(
+          '#type' => 'select',
+          '#title' => $title,
+          '#options' => array('any'=>'Any','yes'=>'Yes'),
+          '#default_value' => $defaults[$field_name]
+        );
+      break;
+      case 'selection':
+        $form['filter'][$field_name] = array(
+          '#type' => 'select',
+          '#title' => $title,
+          '#options' => $options,
+          '#default_value' => $defaults[$field_name]
+        );
+      break;
+      
+      case 'textfield':
+        $form['filter'][$field_name] = array(
+          '#type' => 'textfield',
+          '#title' => $title,
+          '#default_value' => $defaults[$field_name]
+        );
+      break;
+    }
+    
+    if ( $search_type['type']=='textfield' && $search_type['autocomplete'] == true ) {
+      $hook_info=explode(".",$field);
+      $form['filter'][$field_name]['#autocomplete_path'] = 'members/auto/'.$hook_info[1].'/'.$hook_info[2];
+    }
+    
+  }
+  
+  $form['submit'] = array('#type' => 'submit', '#value' =>t('Search'));
+  
+  $form['reset'] = array('#type' => 'button', '#value' =>t('Reset Filter'));
+  
+  $output = drupal_get_form('members_search_form', $form);
+
+  return $output;
+}
+
+function members_search_form_submit($form_id, $form) {
+  if(!is_array($_SESSION['members_search_form'])) {
+    $_SESSION['members_search_form']=array();
+  } else {
+    unset($_SESSION['members_search_form']);
+  }
+  foreach($form as $key => $value) {
+    $_SESSION['members_search_form'][$key]=$value;
+  }
+  
+}
+  
\ No newline at end of file
diff -urN members.cvs/po/da.po members/po/da.po
--- members.cvs/po/da.po	1970-01-01 10:00:00.000000000 +1000
+++ members/po/da.po	2006-01-13 23:40:30.000000000 +1100
@@ -0,0 +1,69 @@
+# Danish translation of Drupal (members.module)
+# Copyright 2005 Morten Wulff <wulff@tem.dtu.dk>
+msgid ""
+msgstr ""
+"Project-Id-Version: Danish translation of Drupal (members.module) $Id: da.po,v 1.2 2006/01/13 12:40:30 wulff Exp $\n"
+"POT-Creation-Date: 2005-07-06 14:43+0200\n"
+"PO-Revision-Date: 2006-01-13 13:39+0100\n"
+"Last-Translator: Morten Wulff <wulff@tem.dtu.dk>\n"
+"Language-Team: Danish <danish@psyke.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+
+#: members.module:7
+msgid "Enables users to list all members."
+msgstr "Gør det muligt at vise alle medlemmer."
+
+#: members.module:13
+msgid "Roles to show"
+msgstr "Vis roller"
+
+#: members.module:13
+msgid "Select roles to show in the members listing."
+msgstr "Vælg hvilke roller der skal vises i medlemsoversigten."
+
+#: members.module:14
+msgid "Columns to show"
+msgstr "Vis kolonner"
+
+#: members.module:14
+msgid "Select the fields which should be displayed on your members overview page. Note that some fields require certain modules to be active."
+msgstr "Vælg hvilke felter der skal vises i medlemsoversigten. Bemærk at nogle felter kræver at bestemte moduler er aktiveret."
+
+#: members.module:24
+#: ;0
+msgid "members"
+msgstr "medlemmer"
+
+#: members.module:134
+msgid "Warning: there aren't any users with roles configured to be shown here."
+msgstr "Advarsel: Der er ingen brugere med de valgte roller."
+
+#: members.module:142
+msgid "Roles"
+msgstr "Roller"
+
+#: members.module:143
+msgid "Username"
+msgstr "Brugernavn"
+
+#: members.module:153
+msgid "Email"
+msgstr "E-mail"
+
+#: members.module:154
+msgid "Last Seen"
+msgstr "Sidst set"
+
+#: members.module:155
+msgid "Picture"
+msgstr "Billede"
+
+#: members.module:35
+msgid "access members list"
+msgstr "tilgå medlemsliste"
+
diff -urN members.cvs/po/fr.po members/po/fr.po
--- members.cvs/po/fr.po	1970-01-01 10:00:00.000000000 +1000
+++ members/po/fr.po	2006-08-02 07:17:49.000000000 +1000
@@ -0,0 +1,66 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: members\n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: 2006-07-02 16:14-0500\n"
+"Last-Translator: Cernick <cernick@hotmail.com>\n"
+"Language-Team: Cernick <cernick@hotmail.com>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-Language: French\n"
+"X-Poedit-Country: CANADA\n"
+
+#: members.module:7
+msgid "Enables users to list all members."
+msgstr "Permet aux utilisateurs de voir la liste de tous les membres."
+
+#: members.module:13
+msgid "Roles to show"
+msgstr "Rôles à afficher"
+
+#: members.module:13
+msgid "Select roles to show in the members listing."
+msgstr "Sélectionnez les rôles à afficher dans la liste des membres."
+
+#: members.module:14
+msgid "Columns to show"
+msgstr "Colonnes à afficher"
+
+#: members.module:14
+msgid "Select the fields which should be displayed on your members overview page. Note that some fields require certain modules to be active."
+msgstr "Sélectionner les champs qui devraient être affichés sur la page de la liste des membres. Notez que certains champs requièrent que certains modules soient actifs."
+
+#: members.module:24
+#: ;0
+msgid "members"
+msgstr "membres"
+
+#: members.module:134
+msgid "Warning: there aren't any users with roles configured to be shown here."
+msgstr "Attention: il n'y a aucun utilisateur avec les rôles configurés pour être affichés ici."
+
+#: members.module:142
+msgid "Roles"
+msgstr "rôles"
+
+#: members.module:143
+msgid "Username"
+msgstr "Nom d'usager"
+
+#: members.module:153
+msgid "Email"
+msgstr "Courriel"
+
+#: members.module:154
+msgid "Last Seen"
+msgstr "Dernière visite"
+
+#: members.module:155
+msgid "Picture"
+msgstr "Avatar"
+
+#: members.module:35
+msgid "access members list"
+msgstr "accéder à la liste des membres"
+
diff -urN members.cvs/po/members-module.pot members/po/members-module.pot
--- members.cvs/po/members-module.pot	1970-01-01 10:00:00.000000000 +1000
+++ members/po/members-module.pot	2006-01-13 23:40:30.000000000 +1100
@@ -0,0 +1,69 @@
+# LANGUAGE translation of Drupal (members.module)
+# Copyright YEAR NAME <EMAIL@ADDRESS>
+# Generated from file: members.module,v 1.37 2005/04/25 06:01:07 walkah
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PROJECT VERSION\n"
+"POT-Creation-Date: 2005-10-04 08:47+0200\n"
+"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
+"Last-Translator: NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+
+#: members.module:7
+msgid "Enables users to list all members."
+msgstr ""
+
+#: members.module:13
+msgid "Roles to show"
+msgstr ""
+
+#: members.module:13
+msgid "Select roles to show in the members listing."
+msgstr ""
+
+#: members.module:14
+msgid "Columns to show"
+msgstr ""
+
+#: members.module:14
+msgid "Select the fields which should be displayed on your members overview page. Note that some fields require certain modules to be active."
+msgstr ""
+
+#: members.module:24;0
+msgid "members"
+msgstr ""
+
+#: members.module:134
+msgid "Warning: there aren't any users with roles configured to be shown here."
+msgstr ""
+
+#: members.module:142
+msgid "Roles"
+msgstr ""
+
+#: members.module:143
+msgid "Username"
+msgstr ""
+
+#: members.module:153
+msgid "Email"
+msgstr ""
+
+#: members.module:154
+msgid "Last Seen"
+msgstr ""
+
+#: members.module:155
+msgid "Picture"
+msgstr ""
+
+#: members.module:35
+msgid "access members list"
+msgstr ""
+
diff -urN members.cvs/README.txt members/README.txt
--- members.cvs/README.txt	1970-01-01 10:00:00.000000000 +1000
+++ members/README.txt	2004-11-05 04:35:35.000000000 +1100
@@ -0,0 +1,12 @@
+Members.module
+------
+
+Members provides an alternate listing style to profile.module, with a
+focus on tabular display and an emphasis on roles (including listing by
+role).
+
+
+Currently maintained by:
+
+James Walker <walkah@walkah.net>
+
