~ubuntu-branches/ubuntu/oneiric/drupal5/oneiric

« back to all changes in this revision

Viewing changes to modules/user/user.module

  • Committer: Bazaar Package Importer
  • Author(s): Luigi Gangitano
  • Date: 2007-03-10 20:04:24 UTC
  • Revision ID: james.westby@ubuntu.com-20070310200424-w6v3crmyowlx2zsq
Tags: upstream-5.1
ImportĀ upstreamĀ versionĀ 5.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
// $Id: user.module,v 1.745.2.1 2007/01/29 19:08:46 dries Exp $
 
3
 
 
4
/**
 
5
 * @file
 
6
 * Enables the user registration and login system.
 
7
 */
 
8
 
 
9
define('USERNAME_MAX_LENGTH', 60);
 
10
define('EMAIL_MAX_LENGTH', 64);
 
11
 
 
12
/**
 
13
 * Invokes hook_user() in every module.
 
14
 *
 
15
 * We cannot use module_invoke() for this, because the arguments need to
 
16
 * be passed by reference.
 
17
 */
 
18
function user_module_invoke($type, &$array, &$user, $category = NULL) {
 
19
  foreach (module_list() as $module) {
 
20
    $function = $module .'_user';
 
21
    if (function_exists($function)) {
 
22
      $function($type, $array, $user, $category);
 
23
    }
 
24
  }
 
25
}
 
26
 
 
27
function user_external_load($authname) {
 
28
  $result = db_query("SELECT uid FROM {authmap} WHERE authname = '%s'", $authname);
 
29
 
 
30
  if ($user = db_fetch_array($result)) {
 
31
    return user_load($user);
 
32
  }
 
33
  else {
 
34
    return 0;
 
35
  }
 
36
}
 
37
 
 
38
/**
 
39
 * Fetch a user object.
 
40
 *
 
41
 * @param $array
 
42
 *   An associative array of attributes to search for in selecting the
 
43
 *   user, such as user name or e-mail address.
 
44
 *
 
45
 * @return
 
46
 *   A fully-loaded $user object upon successful user load or FALSE if user cannot be loaded.
 
47
 */
 
48
function user_load($array = array()) {
 
49
  // Dynamically compose a SQL query:
 
50
  $query = array();
 
51
  $params = array();
 
52
 
 
53
  foreach ($array as $key => $value) {
 
54
    if ($key == 'uid' || $key == 'status') {
 
55
      $query[] = "$key = %d";
 
56
      $params[] = $value;
 
57
    }
 
58
    else if ($key == 'pass') {
 
59
      $query[] = "pass = '%s'";
 
60
      $params[] = md5($value);
 
61
    }
 
62
    else {
 
63
      $query[]= "LOWER($key) = LOWER('%s')";
 
64
      $params[] = $value;
 
65
    }
 
66
  }
 
67
  $result = db_query('SELECT * FROM {users} u WHERE '. implode(' AND ', $query), $params);
 
68
 
 
69
  if (db_num_rows($result)) {
 
70
    $user = db_fetch_object($result);
 
71
    $user = drupal_unpack($user);
 
72
 
 
73
    $user->roles = array();
 
74
    if ($user->uid) {
 
75
      $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
 
76
    }
 
77
    else {
 
78
      $user->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user';
 
79
    }
 
80
    $result = db_query('SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d', $user->uid);
 
81
    while ($role = db_fetch_object($result)) {
 
82
      $user->roles[$role->rid] = $role->name;
 
83
    }
 
84
    user_module_invoke('load', $array, $user);
 
85
  }
 
86
  else {
 
87
    $user = FALSE;
 
88
  }
 
89
 
 
90
  return $user;
 
91
}
 
92
 
 
93
/**
 
94
 * Save changes to a user account or add a new user.
 
95
 *
 
96
 * @param $account
 
97
 *   The $user object for the user to modify or add. If $user->uid is
 
98
 *   omitted, a new user will be added.
 
99
 *
 
100
 * @param $array
 
101
 *   An array of fields and values to save. For example array('name' => 'My name');
 
102
 *   Setting a field to NULL deletes it from the data column.
 
103
 *
 
104
 * @param $category
 
105
 *   (optional) The category for storing profile information in.
 
106
 */
 
107
function user_save($account, $array = array(), $category = 'account') {
 
108
  // Dynamically compose a SQL query:
 
109
  $user_fields = user_fields();
 
110
  if ($account->uid) {
 
111
    user_module_invoke('update', $array, $account, $category);
 
112
 
 
113
    $data = unserialize(db_result(db_query('SELECT data FROM {users} WHERE uid = %d', $account->uid)));
 
114
    foreach ($array as $key => $value) {
 
115
      if ($key == 'pass' && !empty($value)) {
 
116
        $query .= "$key = '%s', ";
 
117
        $v[] = md5($value);
 
118
      }
 
119
      else if ((substr($key, 0, 4) !== 'auth') && ($key != 'pass')) {
 
120
        if (in_array($key, $user_fields)) {
 
121
          // Save standard fields
 
122
          $query .= "$key = '%s', ";
 
123
          $v[] = $value;
 
124
        }
 
125
        else if ($key != 'roles') {
 
126
          // Roles is a special case: it used below.
 
127
          if ($value === NULL) {
 
128
            unset($data[$key]);
 
129
          }
 
130
          else {
 
131
            $data[$key] = $value;
 
132
          }
 
133
        }
 
134
      }
 
135
    }
 
136
    $query .= "data = '%s' ";
 
137
    $v[] = serialize($data);
 
138
 
 
139
    db_query("UPDATE {users} SET $query WHERE uid = %d", array_merge($v, array($account->uid)));
 
140
 
 
141
    // Reload user roles if provided
 
142
    if (is_array($array['roles'])) {
 
143
      db_query('DELETE FROM {users_roles} WHERE uid = %d', $account->uid);
 
144
 
 
145
      foreach (array_keys($array['roles']) as $rid) {
 
146
        if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
 
147
          db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)', $account->uid, $rid);
 
148
        }
 
149
      }
 
150
    }
 
151
 
 
152
    // Delete a blocked user's sessions to kick them if they are online.
 
153
    if (isset($array['status']) && $array['status'] == 0) {
 
154
      sess_destroy_uid($account->uid);
 
155
    }
 
156
 
 
157
    // Refresh user object
 
158
    $user = user_load(array('uid' => $account->uid));
 
159
    user_module_invoke('after_update', $array, $user, $category);
 
160
  }
 
161
  else {
 
162
    $array['uid'] = db_next_id('{users}_uid');
 
163
 
 
164
    if (!isset($array['created'])) {    // Allow 'created' to be set by hook_auth
 
165
      $array['created'] = time();
 
166
    }
 
167
 
 
168
    // Note, we wait with saving the data column to prevent module-handled
 
169
    // fields from being saved there. We cannot invoke hook_user('insert') here
 
170
    // because we don't have a fully initialized user object yet.
 
171
    foreach ($array as $key => $value) {
 
172
      switch ($key) {
 
173
        case 'pass':
 
174
          $fields[] = $key;
 
175
          $values[] = md5($value);
 
176
          $s[] = "'%s'";
 
177
          break;
 
178
        case 'uid':        case 'mode':     case 'sort':
 
179
        case 'threshold':  case 'created':  case 'access':
 
180
        case 'login':      case 'status':
 
181
          $fields[] = $key;
 
182
          $values[] = $value;
 
183
          $s[] = "%d";
 
184
          break;
 
185
        default:
 
186
          if (substr($key, 0, 4) !== 'auth' && in_array($key, $user_fields)) {
 
187
            $fields[] = $key;
 
188
            $values[] = $value;
 
189
            $s[] = "'%s'";
 
190
          }
 
191
          break;
 
192
      }
 
193
    }
 
194
    db_query('INSERT INTO {users} ('. implode(', ', $fields) .') VALUES ('. implode(', ', $s) .')', $values);
 
195
 
 
196
    // Build the initial user object.
 
197
    $user = user_load(array('uid' => $array['uid']));
 
198
 
 
199
    user_module_invoke('insert', $array, $user, $category);
 
200
 
 
201
    // Build and save the serialized data field now
 
202
    $data = array();
 
203
    foreach ($array as $key => $value) {
 
204
      if ((substr($key, 0, 4) !== 'auth') && ($key != 'roles') && (!in_array($key, $user_fields)) && ($value !== NULL)) {
 
205
        $data[$key] = $value;
 
206
      }
 
207
    }
 
208
    db_query("UPDATE {users} SET data = '%s' WHERE uid = %d", serialize($data), $user->uid);
 
209
 
 
210
    // Save user roles (delete just to be safe).
 
211
    if (is_array($array['roles'])) {
 
212
      db_query('DELETE FROM {users_roles} WHERE uid = %d', $array['uid']);
 
213
      foreach (array_keys($array['roles']) as $rid) {
 
214
        if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
 
215
          db_query('INSERT INTO {users_roles} (uid, rid) VALUES (%d, %d)', $array['uid'], $rid);
 
216
        }
 
217
      }
 
218
    }
 
219
 
 
220
    // Build the finished user object.
 
221
    $user = user_load(array('uid' => $array['uid']));
 
222
  }
 
223
 
 
224
  // Save distributed authentication mappings
 
225
  $authmaps = array();
 
226
  foreach ($array as $key => $value) {
 
227
    if (substr($key, 0, 4) == 'auth') {
 
228
      $authmaps[$key] = $value;
 
229
    }
 
230
  }
 
231
  if (sizeof($authmaps) > 0) {
 
232
    user_set_authmaps($user, $authmaps);
 
233
  }
 
234
 
 
235
  return $user;
 
236
}
 
237
 
 
238
/**
 
239
 * Verify the syntax of the given name.
 
240
 */
 
241
function user_validate_name($name) {
 
242
  if (!strlen($name)) return t('You must enter a username.');
 
243
  if (substr($name, 0, 1) == ' ') return t('The username cannot begin with a space.');
 
244
  if (substr($name, -1) == ' ') return t('The username cannot end with a space.');
 
245
  if (strpos($name, '  ') !== FALSE) return t('The username cannot contain multiple spaces in a row.');
 
246
  if (ereg("[^\x80-\xF7 [:alnum:]@_.-]", $name)) return t('The username contains an illegal character.');
 
247
  if (preg_match('/[\x{80}-\x{A0}'.          // Non-printable ISO-8859-1 + NBSP
 
248
                   '\x{AD}'.                 // Soft-hyphen
 
249
                   '\x{2000}-\x{200F}'.      // Various space characters
 
250
                   '\x{2028}-\x{202F}'.      // Bidirectional text overrides
 
251
                   '\x{205F}-\x{206F}'.      // Various text hinting characters
 
252
                   '\x{FEFF}'.               // Byte order mark
 
253
                   '\x{FF01}-\x{FF60}'.      // Full-width latin
 
254
                   '\x{FFF9}-\x{FFFD}'.      // Replacement characters
 
255
                   '\x{0}]/u',               // NULL byte
 
256
                   $name)) {
 
257
    return t('The username contains an illegal character.');
 
258
  }
 
259
  if (strpos($name, '@') !== FALSE && !eregi('@([0-9a-z](-?[0-9a-z])*.)+[a-z]{2}([zmuvtg]|fo|me)?$', $name)) return t('The username is not a valid authentication ID.');
 
260
  if (strlen($name) > USERNAME_MAX_LENGTH) return t('The username %name is too long: it must be %max characters or less.', array('%name' => $name, '%max' => USERNAME_MAX_LENGTH));
 
261
}
 
262
 
 
263
function user_validate_mail($mail) {
 
264
  if (!$mail) return t('You must enter an e-mail address.');
 
265
  if (!valid_email_address($mail)) {
 
266
    return t('The e-mail address %mail is not valid.', array('%mail' => $mail));
 
267
  }
 
268
}
 
269
 
 
270
function user_validate_picture($file, &$edit, $user) {
 
271
  global $form_values;
 
272
  // Initialize the picture:
 
273
  $form_values['picture'] = $user->picture;
 
274
 
 
275
  // Check that uploaded file is an image, with a maximum file size
 
276
  // and maximum height/width.
 
277
  $info = image_get_info($file->filepath);
 
278
  list($maxwidth, $maxheight) = explode('x', variable_get('user_picture_dimensions', '85x85'));
 
279
 
 
280
  if (!$info || !$info['extension']) {
 
281
    form_set_error('picture_upload', t('The uploaded file was not an image.'));
 
282
  }
 
283
  else if (image_get_toolkit()) {
 
284
    image_scale($file->filepath, $file->filepath, $maxwidth, $maxheight);
 
285
  }
 
286
  else if (filesize($file->filepath) > (variable_get('user_picture_file_size', '30') * 1000)) {
 
287
    form_set_error('picture_upload', t('The uploaded image is too large; the maximum file size is %size kB.', array('%size' => variable_get('user_picture_file_size', '30'))));
 
288
  }
 
289
  else if ($info['width'] > $maxwidth || $info['height'] > $maxheight) {
 
290
    form_set_error('picture_upload', t('The uploaded image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => variable_get('user_picture_dimensions', '85x85'))));
 
291
  }
 
292
 
 
293
  if (!form_get_errors()) {
 
294
    if ($file = file_save_upload('picture_upload', variable_get('user_picture_path', 'pictures') .'/picture-'. $user->uid .'.'. $info['extension'], 1)) {
 
295
      $form_values['picture'] = $file->filepath;
 
296
    }
 
297
    else {
 
298
      form_set_error('picture_upload', t("Failed to upload the picture image; the %directory directory doesn't exist.", array('%directory' => variable_get('user_picture_path', 'pictures'))));
 
299
    }
 
300
  }
 
301
}
 
302
 
 
303
/**
 
304
 * Generate a random alphanumeric password.
 
305
 */
 
306
function user_password($length = 10) {
 
307
  // This variable contains the list of allowable characters for the
 
308
  // password. Note that the number 0 and the letter 'O' have been
 
309
  // removed to avoid confusion between the two. The same is true
 
310
  // of 'I', 1, and l.
 
311
  $allowable_characters = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
 
312
 
 
313
  // Zero-based count of characters in the allowable list:
 
314
  $len = strlen($allowable_characters) - 1;
 
315
 
 
316
  // Declare the password as a blank string.
 
317
  $pass = '';
 
318
 
 
319
  // Loop the number of times specified by $length.
 
320
  for ($i = 0; $i < $length; $i++) {
 
321
 
 
322
    // Each iteration, pick a random character from the
 
323
    // allowable string and append it to the password:
 
324
    $pass .= $allowable_characters[mt_rand(0, $len)];
 
325
  }
 
326
 
 
327
  return $pass;
 
328
}
 
329
 
 
330
/**
 
331
 * Determine whether the user has a given privilege.
 
332
 *
 
333
 * @param $string
 
334
 *   The permission, such as "administer nodes", being checked for.
 
335
 * @param $account
 
336
 *   (optional) The account to check, if not given use currently logged in user.
 
337
 *
 
338
 * @return
 
339
 *   boolean TRUE if the current user has the requested permission.
 
340
 *
 
341
 * All permission checks in Drupal should go through this function. This
 
342
 * way, we guarantee consistent behavior, and ensure that the superuser
 
343
 * can perform all actions.
 
344
 */
 
345
function user_access($string, $account = NULL) {
 
346
  global $user;
 
347
  static $perm = array();
 
348
 
 
349
  if (is_null($account)) {
 
350
    $account = $user;
 
351
  }
 
352
 
 
353
  // User #1 has all privileges:
 
354
  if ($account->uid == 1) {
 
355
    return TRUE;
 
356
  }
 
357
 
 
358
  // To reduce the number of SQL queries, we cache the user's permissions
 
359
  // in a static variable.
 
360
  if (!isset($perm[$account->uid])) {
 
361
    $result = db_query("SELECT DISTINCT(p.perm) FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid WHERE r.rid IN (%s)", implode(',', array_keys($account->roles)));
 
362
 
 
363
    $perm[$account->uid] = '';
 
364
    while ($row = db_fetch_object($result)) {
 
365
      $perm[$account->uid] .= "$row->perm, ";
 
366
    }
 
367
  }
 
368
 
 
369
  if (isset($perm[$account->uid])) {
 
370
    return strpos($perm[$account->uid], "$string, ") !== FALSE;
 
371
  }
 
372
 
 
373
  return FALSE;
 
374
}
 
375
 
 
376
/**
 
377
 * Checks for usernames blocked by user administration
 
378
 *
 
379
 * @return boolean TRUE for blocked users, FALSE for active
 
380
 */
 
381
function user_is_blocked($name) {
 
382
  $deny  = db_fetch_object(db_query("SELECT name FROM {users} WHERE status = 0 AND name = LOWER('%s')", $name));
 
383
 
 
384
  return $deny;
 
385
}
 
386
 
 
387
function user_fields() {
 
388
  static $fields;
 
389
 
 
390
  if (!$fields) {
 
391
    $result = db_query('SELECT * FROM {users} WHERE uid = 1');
 
392
    if (db_num_rows($result)) {
 
393
      $fields = array_keys(db_fetch_array($result));
 
394
    }
 
395
    else {
 
396
      // Make sure we return the default fields at least
 
397
      $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'created', 'access', 'login', 'status', 'timezone', 'language', 'init', 'data');
 
398
    }
 
399
  }
 
400
 
 
401
  return $fields;
 
402
}
 
403
 
 
404
/**
 
405
 * Implementation of hook_perm().
 
406
 */
 
407
function user_perm() {
 
408
  return array('administer access control', 'administer users', 'access user profiles', 'change own username');
 
409
}
 
410
 
 
411
/**
 
412
 * Implementation of hook_file_download().
 
413
 *
 
414
 * Ensure that user pictures (avatars) are always downloadable.
 
415
 */
 
416
function user_file_download($file) {
 
417
  if (strpos($file, variable_get('user_picture_path', 'pictures') .'/picture-') === 0) {
 
418
    $info = image_get_info(file_create_path($file));
 
419
    return array('Content-type: '. $info['mime_type']);
 
420
  }
 
421
}
 
422
 
 
423
/**
 
424
 * Implementation of hook_search().
 
425
 */
 
426
function user_search($op = 'search', $keys = NULL) {
 
427
  switch ($op) {
 
428
    case 'name':
 
429
      if (user_access('access user profiles')) {
 
430
        return t('Users');
 
431
      }
 
432
    case 'search':
 
433
      if (user_access('access user profiles')) {
 
434
        $find = array();
 
435
        // Replace wildcards with MySQL/PostgreSQL wildcards.
 
436
        $keys = preg_replace('!\*+!', '%', $keys);
 
437
        $result = pager_query("SELECT * FROM {users} WHERE LOWER(name) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys);
 
438
        while ($account = db_fetch_object($result)) {
 
439
          $find[] = array('title' => $account->name, 'link' => url('user/'. $account->uid, NULL, NULL, TRUE));
 
440
        }
 
441
        return $find;
 
442
      }
 
443
  }
 
444
}
 
445
 
 
446
/**
 
447
 * Implementation of hook_user().
 
448
 */
 
449
function user_user($type, &$edit, &$user, $category = NULL) {
 
450
  if ($type == 'view') {
 
451
    $items['history'] = array('title' => t('Member for'),
 
452
      'value' => format_interval(time() - $user->created),
 
453
      'class' => 'member',
 
454
    );
 
455
 
 
456
    return array(t('History') => $items);
 
457
  }
 
458
  if ($type == 'form' && $category == 'account') {
 
459
    return user_edit_form(arg(1), $edit);
 
460
  }
 
461
 
 
462
  if ($type == 'validate' && $category == 'account') {
 
463
    return _user_edit_validate(arg(1), $edit);
 
464
  }
 
465
 
 
466
  if ($type == 'submit' && $category == 'account') {
 
467
    return _user_edit_submit(arg(1), $edit);
 
468
  }
 
469
 
 
470
  if ($type == 'categories') {
 
471
    return array(array('name' => 'account', 'title' => t('Account settings'), 'weight' => 1));
 
472
  }
 
473
}
 
474
 
 
475
function user_login_block() {
 
476
  $form = array(
 
477
    '#action' => url($_GET['q'], drupal_get_destination()),
 
478
    '#id' => 'user-login-form',
 
479
    '#base' => 'user_login',
 
480
  );
 
481
  $form['name'] = array('#type' => 'textfield',
 
482
    '#title' => t('Username'),
 
483
    '#maxlength' => USERNAME_MAX_LENGTH,
 
484
    '#size' => 15,
 
485
    '#required' => TRUE,
 
486
  );
 
487
  $form['pass'] = array('#type' => 'password',
 
488
    '#title' => t('Password'),
 
489
    '#maxlength' => 60,
 
490
    '#size' => 15,
 
491
    '#required' => TRUE,
 
492
  );
 
493
  $form['submit'] = array('#type' => 'submit',
 
494
    '#value' => t('Log in'),
 
495
  );
 
496
  $items = array();
 
497
  if (variable_get('user_register', 1)) {
 
498
    $items[] = l(t('Create new account'), 'user/register', array('title' => t('Create a new user account.')));
 
499
  }
 
500
  $items[] = l(t('Request new password'), 'user/password', array('title' => t('Request new password via e-mail.')));
 
501
  $form['links'] = array('#value' => theme('item_list', $items));
 
502
  return $form;
 
503
}
 
504
 
 
505
/**
 
506
 * Implementation of hook_block().
 
507
 */
 
508
function user_block($op = 'list', $delta = 0, $edit = array()) {
 
509
  global $user;
 
510
 
 
511
  if ($op == 'list') {
 
512
     $blocks[0]['info'] = t('User login');
 
513
     $blocks[1]['info'] = t('Navigation');
 
514
     $blocks[2]['info'] = t('Who\'s new');
 
515
     $blocks[3]['info'] = t('Who\'s online');
 
516
 
 
517
     return $blocks;
 
518
  }
 
519
  else if ($op == 'configure' && $delta == 2) {
 
520
    $form['user_block_whois_new_count'] = array(
 
521
      '#type' => 'select',
 
522
      '#title' => t('Number of users to display'),
 
523
      '#default_value' => variable_get('user_block_whois_new_count', 5),
 
524
      '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)),
 
525
    );
 
526
    return $form;
 
527
  }
 
528
  else if ($op == 'configure' && $delta == 3) {
 
529
    $period = drupal_map_assoc(array(30, 60, 120, 180, 300, 600, 900, 1800, 2700, 3600, 5400, 7200, 10800, 21600, 43200, 86400), 'format_interval');
 
530
    $form['user_block_seconds_online'] = array('#type' => 'select', '#title' => t('User activity'), '#default_value' => variable_get('user_block_seconds_online', 900), '#options' => $period, '#description' => t('A user is considered online for this long after they have last viewed a page.'));
 
531
    $form['user_block_max_list_count'] = array('#type' => 'select', '#title' => t('User list length'), '#default_value' => variable_get('user_block_max_list_count', 10), '#options' => drupal_map_assoc(array(0, 5, 10, 15, 20, 25, 30, 40, 50, 75, 100)), '#description' => t('Maximum number of currently online users to display.'));
 
532
 
 
533
    return $form;
 
534
  }
 
535
  else if ($op == 'save' && $delta == 2) {
 
536
    variable_set('user_block_whois_new_count', $edit['user_block_whois_new_count']);
 
537
  }
 
538
  else if ($op == 'save' && $delta == 3) {
 
539
    variable_set('user_block_seconds_online', $edit['user_block_seconds_online']);
 
540
    variable_set('user_block_max_list_count', $edit['user_block_max_list_count']);
 
541
  }
 
542
  else if ($op == 'view') {
 
543
    $block = array();
 
544
 
 
545
    switch ($delta) {
 
546
      case 0:
 
547
        // For usability's sake, avoid showing two login forms on one page.
 
548
        if (!$user->uid && !(arg(0) == 'user' && !is_numeric(arg(1)))) {
 
549
 
 
550
          $block['subject'] = t('User login');
 
551
          $block['content'] = drupal_get_form('user_login_block');
 
552
        }
 
553
        return $block;
 
554
 
 
555
      case 1:
 
556
        if ($menu = theme('menu_tree')) {
 
557
           $block['subject'] = $user->uid ? check_plain($user->name) : t('Navigation');
 
558
           $block['content'] = $menu;
 
559
        }
 
560
        return $block;
 
561
 
 
562
      case 2:
 
563
        if (user_access('access content')) {
 
564
          // Retrieve a list of new users who have subsequently accessed the site successfully.
 
565
          $result = db_query_range('SELECT uid, name FROM {users} WHERE status != 0 AND access != 0 ORDER BY created DESC', 0, variable_get('user_block_whois_new_count', 5));
 
566
          while ($account = db_fetch_object($result)) {
 
567
            $items[] = $account;
 
568
          }
 
569
          $output = theme('user_list', $items);
 
570
 
 
571
          $block['subject'] = t('Who\'s new');
 
572
          $block['content'] = $output;
 
573
        }
 
574
        return $block;
 
575
 
 
576
      case 3:
 
577
        if (user_access('access content')) {
 
578
          // Count users with activity in the past defined period.
 
579
          $interval = time() - variable_get('user_block_seconds_online', 900);
 
580
 
 
581
          // Perform database queries to gather online user lists.  We use s.timestamp
 
582
          // rather than u.access because it is much faster is much faster..
 
583
          $anonymous_count = sess_count($interval);
 
584
          $authenticated_users = db_query('SELECT u.uid, u.name FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.timestamp >= %d AND s.uid > 0 ORDER BY s.timestamp DESC', $interval);
 
585
          $authenticated_count = db_num_rows($authenticated_users);
 
586
 
 
587
          // Format the output with proper grammar.
 
588
          if ($anonymous_count == 1 && $authenticated_count == 1) {
 
589
            $output = t('There is currently %members and %visitors online.', array('%members' => format_plural($authenticated_count, '1 user', '@count users'), '%visitors' => format_plural($anonymous_count, '1 guest', '@count guests')));
 
590
          }
 
591
          else {
 
592
            $output = t('There are currently %members and %visitors online.', array('%members' => format_plural($authenticated_count, '1 user', '@count users'), '%visitors' => format_plural($anonymous_count, '1 guest', '@count guests')));
 
593
          }
 
594
 
 
595
          // Display a list of currently online users.
 
596
          $max_users = variable_get('user_block_max_list_count', 10);
 
597
          if ($authenticated_count && $max_users) {
 
598
            $items = array();
 
599
 
 
600
            while ($max_users-- && $account = db_fetch_object($authenticated_users)) {
 
601
              $items[] = $account;
 
602
            }
 
603
 
 
604
            $output .= theme('user_list', $items, t('Online users'));
 
605
          }
 
606
 
 
607
          $block['subject'] = t('Who\'s online');
 
608
          $block['content'] = $output;
 
609
        }
 
610
        return $block;
 
611
    }
 
612
  }
 
613
}
 
614
 
 
615
function theme_user_picture($account) {
 
616
  if (variable_get('user_pictures', 0)) {
 
617
    if ($account->picture && file_exists($account->picture)) {
 
618
      $picture = file_create_url($account->picture);
 
619
    }
 
620
    else if (variable_get('user_picture_default', '')) {
 
621
      $picture = variable_get('user_picture_default', '');
 
622
    }
 
623
 
 
624
    if (isset($picture)) {
 
625
      $alt = t("@user's picture", array('@user' => $account->name ? $account->name : variable_get('anonymous', t('Anonymous'))));
 
626
      $picture = theme('image', $picture, $alt, $alt, '', FALSE);
 
627
      if (!empty($account->uid) && user_access('access user profiles')) {
 
628
        $picture = l($picture, "user/$account->uid", array('title' => t('View user profile.')), NULL, NULL, FALSE, TRUE);
 
629
      }
 
630
 
 
631
      return "<div class=\"picture\">$picture</div>";
 
632
    }
 
633
  }
 
634
}
 
635
 
 
636
/**
 
637
 * Theme a user page
 
638
 * @param $account the user object
 
639
 * @param $fields a multidimensional array for the fields, in the form of array (
 
640
 *   'category1' => array(item_array1, item_array2), 'category2' => array(item_array3,
 
641
 *    .. etc.). Item arrays are formatted as array(array('title' => 'item title',
 
642
 * 'value' => 'item value', 'class' => 'class-name'), ... etc.). Module names are incorporated
 
643
 * into the CSS class.
 
644
 *
 
645
 * @ingroup themeable
 
646
 */
 
647
function theme_user_profile($account, $fields) {
 
648
  $output = '<div class="profile">';
 
649
  $output .= theme('user_picture', $account);
 
650
  foreach ($fields as $category => $items) {
 
651
    if (strlen($category) > 0) {
 
652
      $output .= '<h2 class="title">'. $category .'</h2>';
 
653
    }
 
654
    $output .= '<dl>';
 
655
    foreach ($items as $item) {
 
656
      if (isset($item['title'])) {
 
657
        $output .= '<dt class="'. $item['class'] .'">'. $item['title'] .'</dt>';
 
658
      }
 
659
      $output .= '<dd class="'. $item['class'] .'">'. $item['value'] .'</dd>';
 
660
    }
 
661
    $output .= '</dl>';
 
662
  }
 
663
  $output .= '</div>';
 
664
 
 
665
  return $output;
 
666
}
 
667
 
 
668
/**
 
669
 * Make a list of users.
 
670
 * @param $items an array with user objects. Should contain at least the name and uid
 
671
 *
 
672
 * @ingroup themeable
 
673
 */
 
674
function theme_user_list($users, $title = NULL) {
 
675
  if (!empty($users)) {
 
676
    foreach ($users as $user) {
 
677
      $items[] = theme('username', $user);
 
678
    }
 
679
  }
 
680
  return theme('item_list', $items, $title);
 
681
}
 
682
 
 
683
/**
 
684
 * Implementation of hook_menu().
 
685
 */
 
686
function user_menu($may_cache) {
 
687
  global $user;
 
688
 
 
689
  $items = array();
 
690
 
 
691
  $admin_access = user_access('administer users');
 
692
  $access_access = user_access('administer access control');
 
693
  $view_access = user_access('access user profiles');
 
694
 
 
695
  if ($may_cache) {
 
696
    $items[] = array('path' => 'user', 'title' => t('User account'),
 
697
      'callback' => 'drupal_get_form', 'callback arguments' => array('user_login'),
 
698
      'access' => !$user->uid, 'type' => MENU_CALLBACK);
 
699
 
 
700
    $items[] = array('path' => 'user/autocomplete', 'title' => t('User autocomplete'),
 
701
      'callback' => 'user_autocomplete', 'access' => $view_access, 'type' => MENU_CALLBACK);
 
702
 
 
703
    // Registration and login pages.
 
704
    $items[] = array('path' => 'user/login', 'title' => t('Log in'),
 
705
      'callback' => 'drupal_get_form', 'callback arguments' => array('user_login'),
 
706
      'access' => !$user->uid, 'type' => MENU_DEFAULT_LOCAL_TASK);
 
707
    $items[] = array('path' => 'user/register', 'title' => t('Create new account'),
 
708
      'callback' => 'drupal_get_form', 'callback arguments' => array('user_register'), 'access' => !$user->uid && variable_get('user_register', 1), 'type' => MENU_LOCAL_TASK);
 
709
    $items[] = array('path' => 'user/password', 'title' => t('Request new password'),
 
710
      'callback' => 'drupal_get_form', 'callback arguments' => array('user_pass'), 'access' => !$user->uid, 'type' => MENU_LOCAL_TASK);
 
711
    $items[] = array('path' => 'user/reset', 'title' => t('Reset password'),
 
712
      'callback' => 'drupal_get_form', 'callback arguments' => array('user_pass_reset'), 'access' => TRUE, 'type' => MENU_CALLBACK);
 
713
    $items[] = array('path' => 'user/help', 'title' => t('Help'),
 
714
      'callback' => 'user_help_page', 'type' => MENU_CALLBACK);
 
715
 
 
716
    // Admin user pages
 
717
    $items[] = array('path' => 'admin/user',
 
718
      'title' => t('User management'),
 
719
      'description' => t('Manage your site\'s users, groups and access to site features.'),
 
720
      'position' => 'left',
 
721
      'callback' => 'system_admin_menu_block_page',
 
722
      'access' => user_access('administer site configuration'),
 
723
    );
 
724
    $items[] = array('path' => 'admin/user/user', 'title' => t('Users'),
 
725
      'description' => t('List, add, and edit users.'),
 
726
      'callback' => 'user_admin', 'callback arguments' => array('list'), 'access' => $admin_access);
 
727
    $items[] = array('path' => 'admin/user/user/list', 'title' => t('List'),
 
728
      'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
 
729
    $items[] = array('path' => 'admin/user/user/create', 'title' => t('Add user'),
 
730
      'callback' => 'user_admin', 'callback arguments' => array('create'), 'access' => $admin_access,
 
731
      'type' => MENU_LOCAL_TASK);
 
732
    $items[] = array('path' => 'admin/user/settings', 'title' => t('User settings'),
 
733
      'description' => t('Configure default behavior of users, including registration requirements, e-mails, and user pictures.'),
 
734
      'callback' => 'drupal_get_form', 'callback arguments' => array('user_admin_settings'));
 
735
 
 
736
    // Admin access pages
 
737
    $items[] = array('path' => 'admin/user/access', 'title' => t('Access control'),
 
738
      'description' => t('Determine access to features by selecting permissions for roles.'),
 
739
      'callback' => 'drupal_get_form', 'callback arguments' => array('user_admin_perm'), 'access' => $access_access);
 
740
    $items[] = array('path' => 'admin/user/roles', 'title' => t('Roles'),
 
741
      'description' => t('List, edit, or add user roles.'),
 
742
      'callback' => 'drupal_get_form', 'callback arguments' => array('user_admin_new_role'), 'access' => $access_access,
 
743
      'type' => MENU_NORMAL_ITEM);
 
744
    $items[] = array('path' => 'admin/user/roles/edit', 'title' => t('Edit role'),
 
745
       'callback' => 'drupal_get_form', 'callback arguments' => array('user_admin_role'), 'access' => $access_access,
 
746
      'type' => MENU_CALLBACK);
 
747
    $items[] = array('path' => 'admin/user/rules', 'title' => t('Access rules'),
 
748
      'description' => t('List and create rules to disallow usernames, e-mail addresses, and IP addresses.'),
 
749
      'callback' => 'user_admin_access', 'access' => $access_access);
 
750
    $items[] = array('path' => 'admin/user/rules/list', 'title' => t('List'),
 
751
      'access' => $access_access, 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
 
752
    $items[] = array('path' => 'admin/user/rules/add', 'title' => t('Add rule'),
 
753
      'callback' => 'user_admin_access_add', 'access' => $access_access,
 
754
      'type' => MENU_LOCAL_TASK);
 
755
    $items[] = array('path' => 'admin/user/rules/check', 'title' => t('Check rules'),
 
756
      'callback' => 'user_admin_access_check', 'access' => $access_access,
 
757
      'type' => MENU_LOCAL_TASK);
 
758
    $items[] = array('path' => 'admin/user/rules/edit', 'title' => t('Edit rule'),
 
759
      'callback' => 'user_admin_access_edit', 'access' => $access_access,
 
760
      'type' => MENU_CALLBACK);
 
761
    $items[] = array('path' => 'admin/user/rules/delete', 'title' => t('Delete rule'),
 
762
      'callback' => 'drupal_get_form', 'callback arguments' => array('user_admin_access_delete_confirm'),
 
763
      'access' => $access_access, 'type' => MENU_CALLBACK);
 
764
 
 
765
    if (module_exists('search')) {
 
766
      $items[] = array('path' => 'admin/user/search', 'title' => t('Search users'),
 
767
        'description' => t('Search users by name.'),
 
768
        'callback' => 'user_admin', 'callback arguments' => array('search'), 'access' => $admin_access,
 
769
        'type' => MENU_NORMAL_ITEM);
 
770
    }
 
771
 
 
772
    // Your personal page
 
773
    if ($user->uid) {
 
774
      $items[] = array('path' => 'user/'. $user->uid, 'title' => t('My account'),
 
775
        'callback' => 'user_view', 'callback arguments' => array(arg(1)), 'access' => TRUE,
 
776
        'type' => MENU_DYNAMIC_ITEM);
 
777
    }
 
778
 
 
779
    $items[] = array('path' => 'logout', 'title' => t('Log out'),
 
780
      'access' => $user->uid,
 
781
      'callback' => 'user_logout',
 
782
      'weight' => 10);
 
783
  }
 
784
  else {
 
785
    // Add the CSS for this module. We put this in !$may_cache so it is only
 
786
    // added once per request.
 
787
    drupal_add_css(drupal_get_path('module', 'user') .'/user.css', 'module');
 
788
    if ($_GET['q'] == 'user' && $user->uid) {
 
789
      // We want to make the current user's profile accessible without knowing
 
790
      // their uid, so just linking to /user is enough.
 
791
      drupal_goto('user/'. $user->uid);
 
792
    }
 
793
 
 
794
    if (arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0) {
 
795
      $account = user_load(array('uid' => arg(1)));
 
796
 
 
797
      if ($user !== FALSE) {
 
798
        // Always let a user view their own account
 
799
        $view_access |= $user->uid == arg(1);
 
800
        // Only admins can view blocked accounts
 
801
        $view_access &= $account->status || $admin_access;
 
802
 
 
803
        $items[] = array('path' => 'user/'. arg(1), 'title' => t('User'),
 
804
          'type' => MENU_CALLBACK, 'callback' => 'user_view',
 
805
          'callback arguments' => array(arg(1)), 'access' => $view_access);
 
806
 
 
807
        $items[] = array('path' => 'user/'. arg(1) .'/view', 'title' => t('View'),
 
808
          'access' => $view_access, 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
 
809
 
 
810
        $items[] = array('path' => 'user/'. arg(1) .'/edit', 'title' => t('Edit'),
 
811
          'callback' => 'drupal_get_form', 'callback arguments' => array('user_edit'),
 
812
          'access' => $admin_access || $user->uid == arg(1), 'type' => MENU_LOCAL_TASK);
 
813
        $items[] = array('path' => 'user/'. arg(1) .'/delete', 'title' => t('Delete'),
 
814
          'callback' => 'user_edit', 'access' => $admin_access,
 
815
          'type' => MENU_CALLBACK);
 
816
 
 
817
        if (arg(2) == 'edit') {
 
818
          if (($categories = _user_categories($account)) && (count($categories) > 1)) {
 
819
            foreach ($categories as $key => $category) {
 
820
              $items[] = array(
 
821
                'path' => 'user/'. arg(1) .'/edit/'. $category['name'],
 
822
                'title' => $category['title'],
 
823
                'type' => $category['name'] == 'account' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
 
824
                'weight' => $category['weight'],
 
825
                'access' => ($admin_access || $user->uid == arg(1)));
 
826
            }
 
827
          }
 
828
        }
 
829
      }
 
830
    }
 
831
  }
 
832
 
 
833
  return $items;
 
834
}
 
835
 
 
836
/**
 
837
 * Accepts an user object, $account, or a DA name and returns an associative
 
838
 * array of modules and DA names. Called at external login.
 
839
 */
 
840
function user_get_authmaps($authname = NULL) {
 
841
  $result = db_query("SELECT authname, module FROM {authmap} WHERE authname = '%s'", $authname);
 
842
  if (db_num_rows($result) > 0) {
 
843
    while ($authmap = db_fetch_object($result)) {
 
844
      $authmaps[$authmap->module] = $authmap->authname;
 
845
    }
 
846
    return $authmaps;
 
847
  }
 
848
  else {
 
849
    return 0;
 
850
  }
 
851
}
 
852
 
 
853
function user_set_authmaps($account, $authmaps) {
 
854
  foreach ($authmaps as $key => $value) {
 
855
    $module = explode('_', $key, 2);
 
856
    if ($value) {
 
857
      db_query("UPDATE {authmap} SET authname = '%s' WHERE uid = %d AND module = '%s'", $value, $account->uid, $module[1]);
 
858
      if (!db_affected_rows()) {
 
859
        db_query("INSERT INTO {authmap} (authname, uid, module) VALUES ('%s', %d, '%s')", $value, $account->uid, $module[1]);
 
860
      }
 
861
    }
 
862
    else {
 
863
      db_query("DELETE FROM {authmap} WHERE uid = %d AND module = '%s'", $account->uid, $module[1]);
 
864
    }
 
865
  }
 
866
}
 
867
 
 
868
function user_auth_help_links() {
 
869
  $links = array();
 
870
  foreach (module_list() as $module) {
 
871
    if (module_hook($module, 'auth')) {
 
872
      $links[] = l(module_invoke($module, 'info', 'name'), 'user/help', array(), NULL, $module);
 
873
    }
 
874
  }
 
875
  return $links;
 
876
}
 
877
 
 
878
/*** User features *********************************************************/
 
879
 
 
880
 
 
881
 
 
882
function user_login($msg = '') {
 
883
  global $user;
 
884
 
 
885
  // If we are already logged on, go to the user page instead.
 
886
  if ($user->uid) {
 
887
    drupal_goto('user/'. $user->uid);
 
888
  }
 
889
 
 
890
  // Display login form:
 
891
  if ($msg) {
 
892
    $form['message'] = array('#value' => '<p>'. check_plain($msg) .'</p>');
 
893
  }
 
894
  $form['name'] = array('#type' => 'textfield',
 
895
    '#title' => t('Username'),
 
896
    '#size' => 60,
 
897
    '#maxlength' => USERNAME_MAX_LENGTH,
 
898
    '#required' => TRUE,
 
899
    '#attributes' => array('tabindex' => '1'),
 
900
  );
 
901
  if (variable_get('drupal_authentication_service', FALSE) && count(user_auth_help_links()) > 0) {
 
902
    $form['name']['#description'] = t('Enter your @s username, or an ID from one of our affiliates: !a.', array('@s' => variable_get('site_name', 'Drupal'), '!a' => implode(', ', user_auth_help_links())));
 
903
  }
 
904
  else {
 
905
    $form['name']['#description'] = t('Enter your @s username.', array('@s' => variable_get('site_name', 'Drupal')));
 
906
  }
 
907
  $form['pass'] = array('#type' => 'password',
 
908
    '#title' => t('Password'),
 
909
    '#description' => t('Enter the password that accompanies your username.'),
 
910
    '#required' => TRUE,
 
911
    '#attributes' => array('tabindex' => '2'),
 
912
  );
 
913
  $form['submit'] = array('#type' => 'submit', '#value' => t('Log in'), '#weight' => 2, '#attributes' => array('tabindex' => '3'));
 
914
 
 
915
  return $form;
 
916
}
 
917
 
 
918
function user_login_validate($form_id, $form_values) {
 
919
  if ($form_values['name']) {
 
920
    if (user_is_blocked($form_values['name'])) {
 
921
      // blocked in user administration
 
922
      form_set_error('login', t('The username %name has not been activated or is blocked.', array('%name' => $form_values['name'])));
 
923
    }
 
924
    else if (drupal_is_denied('user', $form_values['name'])) {
 
925
      // denied by access controls
 
926
      form_set_error('login', t('The name %name is a reserved username.', array('%name' => $form_values['name'])));
 
927
    }
 
928
    else if ($form_values['pass']) {
 
929
      $user = user_authenticate($form_values['name'], trim($form_values['pass']));
 
930
 
 
931
      if (!$user->uid) {
 
932
        form_set_error('login', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
 
933
        watchdog('user', t('Login attempt failed for %user.', array('%user' => $form_values['name'])));
 
934
      }
 
935
    }
 
936
  }
 
937
}
 
938
 
 
939
function user_login_submit($form_id, $form_values) {
 
940
  global $user;
 
941
  if ($user->uid) {
 
942
    // To handle the edge case where this function is called during a
 
943
    // bootstrap, check for the existence of t().
 
944
    if (function_exists('t')) {
 
945
      $message = t('Session opened for %name.', array('%name' => $user->name));
 
946
    }
 
947
    else {
 
948
       $message = "Session opened for ". check_plain($user->name);
 
949
    }
 
950
    watchdog('user', $message);
 
951
 
 
952
    // Update the user table timestamp noting user has logged in.
 
953
    db_query("UPDATE {users} SET login = %d WHERE uid = %d", time(), $user->uid);
 
954
 
 
955
    user_module_invoke('login', $form_values, $user);
 
956
 
 
957
    sess_regenerate();
 
958
    return 'user/'. $user->uid;
 
959
  }
 
960
}
 
961
 
 
962
function user_authenticate($name, $pass) {
 
963
  global $user;
 
964
 
 
965
  // Try to log in the user locally. Don't set $user unless successful.
 
966
  if ($account = user_load(array('name' => $name, 'pass' => $pass, 'status' => 1))) {
 
967
    $user = $account;
 
968
    return $user;
 
969
  }
 
970
 
 
971
  // Strip name and server from ID:
 
972
  if ($server = strrchr($name, '@')) {
 
973
    $name = substr($name, 0, strlen($name) - strlen($server));
 
974
    $server = substr($server, 1);
 
975
  }
 
976
 
 
977
  // When possible, determine corresponding external auth source. Invoke
 
978
  // source, and log in user if successful:
 
979
  if ($server && ($result = user_get_authmaps("$name@$server"))) {
 
980
    if (module_invoke(key($result), 'auth', $name, $pass, $server)) {
 
981
      $user = user_external_load("$name@$server");
 
982
      watchdog('user', t('External load by %user using module %module.', array('%user' => $name .'@'. $server, '%module' => key($result))));
 
983
    }
 
984
  }
 
985
 
 
986
  // Try each external authentication source in series. Register user if
 
987
  // successful.
 
988
  else {
 
989
    foreach (module_implements('auth') as $module) {
 
990
      if (module_invoke($module, 'auth', $name, $pass, $server)) {
 
991
        if ($server) {
 
992
          $name .= '@'. $server;
 
993
        }
 
994
        $user = user_load(array('name' => $name));
 
995
        if (!$user->uid) { // Register this new user.
 
996
          $userinfo = array('name' => $name, 'pass' => user_password(), 'init' => $name, 'status' => 1);
 
997
          if ($server) {
 
998
            $userinfo["authname_$module"] = $name;
 
999
          }
 
1000
          $user = user_save('', $userinfo);
 
1001
          watchdog('user', t('New external user: %user using module %module.', array('%user' => $name, '%module' => $module)), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $user->uid .'/edit'));
 
1002
          break;
 
1003
        }
 
1004
      }
 
1005
    }
 
1006
  }
 
1007
  return $user;
 
1008
}
 
1009
 
 
1010
/**
 
1011
 * Menu callback; logs the current user out, and redirects to the home page.
 
1012
 */
 
1013
function user_logout() {
 
1014
  global $user;
 
1015
 
 
1016
  watchdog('user', t('Session closed for %name.', array('%name' => $user->name)));
 
1017
 
 
1018
  // Destroy the current session:
 
1019
  session_destroy();
 
1020
  module_invoke_all('user', 'logout', NULL, $user);
 
1021
 
 
1022
  // Load the anonymous user
 
1023
  $user = drupal_anonymous_user();
 
1024
 
 
1025
  drupal_goto();
 
1026
}
 
1027
 
 
1028
function user_pass() {
 
1029
 
 
1030
  // Display form:
 
1031
  $form['name'] = array('#type' => 'textfield',
 
1032
    '#title' => t('Username or e-mail address'),
 
1033
    '#size' => 60,
 
1034
    '#maxlength' => max(USERNAME_MAX_LENGTH, EMAIL_MAX_LENGTH),
 
1035
    '#required' => TRUE,
 
1036
  );
 
1037
  $form['submit'] = array('#type' => 'submit',
 
1038
    '#value' => t('E-mail new password'),
 
1039
    '#weight' => 2,
 
1040
  );
 
1041
  return $form;
 
1042
}
 
1043
 
 
1044
function user_pass_validate($form_id, $form_values) {
 
1045
  $name = $form_values['name'];
 
1046
  $account = user_load(array('mail' => $name, 'status' => 1));
 
1047
  if (!$account) {
 
1048
    $account = user_load(array('name' => $name, 'status' => 1));
 
1049
  }
 
1050
  if ($account->uid) {
 
1051
    form_set_value(array('#parents' => array('account')), $account);
 
1052
  }
 
1053
  else {
 
1054
    form_set_error('name', t('Sorry, %name is not recognized as a user name or an email address.', array('%name' => $name)));
 
1055
  }
 
1056
}
 
1057
 
 
1058
function user_pass_submit($form_id, $form_values) {
 
1059
  global $base_url;
 
1060
 
 
1061
  $account = $form_values['account'];
 
1062
  $from = variable_get('site_mail', ini_get('sendmail_from'));
 
1063
 
 
1064
  // Mail one time login URL and instructions.
 
1065
  $variables = array('!username' => $account->name, '!site' => variable_get('site_name', 'Drupal'), '!login_url' => user_pass_reset_url($account), '!uri' => $base_url, '!uri_brief' => substr($base_url, strlen('http://')), '!mailto' => $account->mail, '!date' => format_date(time()), '!login_uri' => url('user', NULL, NULL, TRUE), '!edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE));
 
1066
  $subject = _user_mail_text('pass_subject', $variables);
 
1067
  $body = _user_mail_text('pass_body', $variables);
 
1068
  $mail_success = drupal_mail('user-pass', $account->mail, $subject, $body, $from);
 
1069
 
 
1070
  if ($mail_success) {
 
1071
    watchdog('user', t('Password reset instructions mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail)));
 
1072
    drupal_set_message(t('Further instructions have been sent to your e-mail address.'));
 
1073
  }
 
1074
  else {
 
1075
    watchdog('user', t('Error mailing password reset instructions to %name at %email.', array('%name' => $account->name, '%email' => $account->mail)), WATCHDOG_ERROR);
 
1076
    drupal_set_message(t('Unable to send mail. Please contact the site admin.'));
 
1077
  }
 
1078
  return 'user';
 
1079
}
 
1080
 
 
1081
/**
 
1082
 * Menu callback; process one time login link and redirects to the user page on success.
 
1083
 */
 
1084
function user_pass_reset($uid, $timestamp, $hashed_pass, $action = NULL) {
 
1085
  global $user;
 
1086
 
 
1087
  // Check if the user is already logged in. The back button is often the culprit here.
 
1088
  if ($user->uid) {
 
1089
    drupal_set_message(t('You have already used this one-time login link. It is not necessary to use this link to login anymore. You are already logged in.'));
 
1090
    drupal_goto();
 
1091
  }
 
1092
  else {
 
1093
    // Time out, in seconds, until login URL expires. 24 hours = 86400 seconds.
 
1094
    $timeout = 86400;
 
1095
    $current = time();
 
1096
    // Some redundant checks for extra security ?
 
1097
    if ($timestamp < $current && $account = user_load(array('uid' => $uid, 'status' => 1)) ) {
 
1098
      // No time out for first time login.
 
1099
      if ($account->login && $current - $timestamp > $timeout) {
 
1100
        drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'));
 
1101
        drupal_goto('user/password');
 
1102
      }
 
1103
      else if ($account->uid && $timestamp > $account->login && $timestamp < $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
 
1104
        // First stage is a confirmation form, then login
 
1105
        if ($action == 'login') {
 
1106
          watchdog('user', t('User %name used one-time login link at time %timestamp.', array('%name' => $account->name, '%timestamp' => $timestamp)));
 
1107
          // Update the user table noting user has logged in.
 
1108
          // And this also makes this hashed password a one-time-only login.
 
1109
          db_query("UPDATE {users} SET login = %d WHERE uid = %d", time(), $account->uid);
 
1110
          // Now we can set the new user.
 
1111
          $user = $account;
 
1112
          // And proceed with normal login, going to user page.
 
1113
          $edit = array();
 
1114
          user_module_invoke('login', $edit, $user);
 
1115
          drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to login. Please change your password.'));
 
1116
          drupal_goto('user/'. $user->uid .'/edit');
 
1117
        }
 
1118
        else {
 
1119
          $form['message'] = array('#value' => t('<p>This is a one-time login for %user_name and will expire on %expiration_date</p><p>Click on this button to login to the site and change your password.</p>', array('%user_name' => $account->name, '%expiration_date' => format_date($timestamp + $timeout))));
 
1120
          $form['help'] = array('#value' => '<p>'. t('This login can be used only once.') .'</p>');
 
1121
          $form['submit'] = array('#type' => 'submit', '#value' => t('Log in'));
 
1122
          $form['#action'] = url("user/reset/$uid/$timestamp/$hashed_pass/login");
 
1123
          return $form;
 
1124
        }
 
1125
      }
 
1126
      else {
 
1127
        drupal_set_message(t('You have tried to use a one-time login link which has either been used or is no longer valid. Please request a new one using the form below.'));
 
1128
        drupal_goto('user/password');
 
1129
      }
 
1130
    }
 
1131
    else {
 
1132
      // Deny access, no more clues.
 
1133
      // Everything will be in the watchdog's URL for the administrator to check.
 
1134
      drupal_access_denied();
 
1135
    }
 
1136
  }
 
1137
}
 
1138
 
 
1139
function user_pass_reset_url($account) {
 
1140
  $timestamp = time();
 
1141
  return url("user/reset/$account->uid/$timestamp/".user_pass_rehash($account->pass, $timestamp, $account->login), NULL, NULL, TRUE);
 
1142
}
 
1143
 
 
1144
function user_pass_rehash($password, $timestamp, $login) {
 
1145
  return md5($timestamp . $password . $login);
 
1146
}
 
1147
 
 
1148
function user_register() {
 
1149
  global $user;
 
1150
 
 
1151
  $admin = user_access('administer users');
 
1152
 
 
1153
  // If we aren't admin but already logged on, go to the user page instead.
 
1154
  if (!$admin && $user->uid) {
 
1155
    drupal_goto('user/'. $user->uid);
 
1156
  }
 
1157
 
 
1158
  $form = array();
 
1159
 
 
1160
  // Display the registration form.
 
1161
  if (!$admin) {
 
1162
    $form['user_registration_help'] = array('#value' => filter_xss_admin(variable_get('user_registration_help', '')));
 
1163
  }
 
1164
  $affiliates = user_auth_help_links();
 
1165
  if (!$admin && count($affiliates) > 0) {
 
1166
    $affiliates = implode(', ', $affiliates);
 
1167
    $form['affiliates'] = array('#value' => '<p>'. t('Note: if you have an account with one of our affiliates (!s), you may <a href="@login_uri">login now</a> instead of registering.', array('!s' => $affiliates, '@login_uri' => url('user'))) .'</p>');
 
1168
  }
 
1169
  // Merge in the default user edit fields.
 
1170
  $form = array_merge($form, user_edit_form(NULL, NULL, TRUE));
 
1171
  if ($admin) {
 
1172
    $form['account']['notify'] = array(
 
1173
     '#type' => 'checkbox',
 
1174
     '#title' => t('Notify user of new account')
 
1175
    );
 
1176
    // Redirect back to page which initiated the create request; usually admin/user/user/create
 
1177
    $form['destination'] = array('#type' => 'hidden', '#value' => $_GET['q']);
 
1178
  }
 
1179
 
 
1180
  // Create a dummy variable for pass-by-reference parameters.
 
1181
  $null = NULL;
 
1182
  $extra = _user_forms($null, NULL, NULL, 'register');
 
1183
 
 
1184
  // Remove form_group around default fields if there are no other groups.
 
1185
  if (!$extra) {
 
1186
    $form['name'] = $form['account']['name'];
 
1187
    $form['mail'] = $form['account']['mail'];
 
1188
    $form['pass'] = $form['account']['pass'];
 
1189
    $form['status'] = $form['account']['status'];
 
1190
    $form['roles'] = $form['account']['roles'];
 
1191
    $form['notify'] = $form['account']['notify'];
 
1192
    unset($form['account']);
 
1193
  }
 
1194
  else {
 
1195
    $form = array_merge($form, $extra);
 
1196
  }
 
1197
  $form['submit'] = array('#type' => 'submit', '#value' => t('Create new account'), '#weight' => 30);
 
1198
 
 
1199
  return $form;
 
1200
}
 
1201
 
 
1202
function user_register_validate($form_id, $form_values) {
 
1203
  user_module_invoke('validate', $form_values, $form_values, 'account');
 
1204
}
 
1205
 
 
1206
function user_register_submit($form_id, $form_values) {
 
1207
  global $base_url;
 
1208
  $admin = user_access('administer users');
 
1209
 
 
1210
  $mail = $form_values['mail'];
 
1211
  $name = $form_values['name'];
 
1212
  if (!variable_get('user_email_verification', TRUE) || $admin) {
 
1213
    $pass = $form_values['pass'];
 
1214
  }
 
1215
  else {
 
1216
    $pass = user_password();
 
1217
  };
 
1218
  $notify = $form_values['notify'];
 
1219
  $from = variable_get('site_mail', ini_get('sendmail_from'));
 
1220
  if (isset($form_values['roles'])) {
 
1221
    $roles = array_filter($form_values['roles']);     // Remove unset roles
 
1222
  }
 
1223
 
 
1224
  if (!$admin && array_intersect(array_keys($form_values), array('uid', 'roles', 'init', 'session', 'status'))) {
 
1225
    watchdog('security', t('Detected malicious attempt to alter protected user fields.'), WATCHDOG_WARNING);
 
1226
    return 'user/register';
 
1227
  }
 
1228
  //the unset below is needed to prevent these form values from being saved as user data
 
1229
  unset($form_values['form_token'], $form_values['submit'], $form_values['op'], $form_values['notify'], $form_values['form_id'], $form_values['affiliates'], $form_values['destination']);
 
1230
 
 
1231
  $merge_data = array('pass' => $pass, 'init' => $mail, 'roles' => $roles);
 
1232
  if (!$admin) {
 
1233
    // Set the user's status because it was not displayed in the form.
 
1234
    $merge_data['status'] = variable_get('user_register', 1) == 1;
 
1235
  }
 
1236
  $account = user_save('', array_merge($form_values, $merge_data));
 
1237
  watchdog('user', t('New user: %name %email.', array('%name' => $name, '%email' => '<'. $mail .'>')), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $account->uid .'/edit'));
 
1238
 
 
1239
  $variables = array('!username' => $name, '!site' => variable_get('site_name', 'Drupal'), '!password' => $pass, '!uri' => $base_url, '!uri_brief' => substr($base_url, strlen('http://')), '!mailto' => $mail, '!date' => format_date(time()), '!login_uri' => url('user', NULL, NULL, TRUE), '!edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE), '!login_url' => user_pass_reset_url($account));
 
1240
 
 
1241
  // The first user may login immediately, and receives a customized welcome e-mail.
 
1242
  if ($account->uid == 1) {
 
1243
    drupal_mail('user-register-admin', $mail, t('Drupal user account details for !s', array('!s' => $name)), strtr(t("!username,\n\nYou may now login to !uri using the following username and password:\n\n  username: !username\n  password: !password\n\n!edit_uri\n\n--drupal"), $variables), $from);
 
1244
    drupal_set_message(t('<p>Welcome to Drupal. You are user #1, which gives you full and immediate access. All future registrants will receive their passwords via e-mail, so please make sure your website e-mail address is set properly under the general settings on the <a href="@settings">site information settings page</a>.</p><p> Your password is <strong>%pass</strong>. You may change your password below.</p>', array('%pass' => $pass, '@settings' => url('admin/settings/site-information'))));
 
1245
    user_authenticate($account->name, trim($pass));
 
1246
 
 
1247
    return 'user/1/edit';
 
1248
  }
 
1249
  else {
 
1250
    if ($admin && !$notify) {
 
1251
      drupal_set_message(t('Created a new user account. No e-mail has been sent.'));
 
1252
    }
 
1253
    else if (!variable_get('user_email_verification', TRUE) && $account->status && !$admin) {
 
1254
      // No e-mail verification is required, create new user account, and login user immediately.
 
1255
      $subject = _user_mail_text('welcome_subject', $variables);
 
1256
      $body = _user_mail_text('welcome_body', $variables);
 
1257
      drupal_mail('user-register-welcome', $mail, $subject, $body, $from);
 
1258
      user_authenticate($account->name, trim($pass));
 
1259
      drupal_goto();
 
1260
    }
 
1261
    else if ($account->status || $notify) {
 
1262
      // Create new user account, no administrator approval required.
 
1263
      $subject = $notify ? _user_mail_text('admin_subject', $variables) : _user_mail_text('welcome_subject', $variables);
 
1264
      $body = $notify ? _user_mail_text('admin_body', $variables) : _user_mail_text('welcome_body', $variables);
 
1265
 
 
1266
      drupal_mail(($notify ? 'user-register-notify' : 'user-register-welcome'), $mail, $subject, $body, $from);
 
1267
 
 
1268
      if ($notify) {
 
1269
        drupal_set_message(t('Password and further instructions have been e-mailed to the new user %user.', array('%user' => $name)));
 
1270
      }
 
1271
      else {
 
1272
        drupal_set_message(t('Your password and further instructions have been sent to your e-mail address.'));
 
1273
        return '';
 
1274
      }
 
1275
    }
 
1276
    else {
 
1277
      // Create new user account, administrator approval required.
 
1278
      $subject = _user_mail_text('approval_subject', $variables);
 
1279
      $body = _user_mail_text('approval_body', $variables);
 
1280
 
 
1281
      drupal_mail('user-register-approval-user', $mail, $subject, $body, $from);
 
1282
      drupal_mail('user-register-approval-admin', $from, $subject, t("!username has applied for an account.\n\n!edit_uri", $variables), $from);
 
1283
      drupal_set_message(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.<br />In the meantime, your password and further instructions have been sent to your e-mail address.'));
 
1284
 
 
1285
    }
 
1286
  }
 
1287
}
 
1288
 
 
1289
function user_edit_form($uid, $edit, $register = FALSE) {
 
1290
  $admin = user_access('administer users');
 
1291
 
 
1292
  // Account information:
 
1293
  $form['account'] = array('#type' => 'fieldset',
 
1294
    '#title' => t('Account information'),
 
1295
  );
 
1296
  if (user_access('change own username') || $admin || $register) {
 
1297
    $form['account']['name'] = array('#type' => 'textfield',
 
1298
      '#title' => t('Username'),
 
1299
      '#default_value' => $edit['name'],
 
1300
      '#maxlength' => USERNAME_MAX_LENGTH,
 
1301
      '#description' => t('Your preferred username; punctuation is not allowed except for periods, hyphens, and underscores.'),
 
1302
      '#required' => TRUE,
 
1303
    );
 
1304
  }
 
1305
  $form['account']['mail'] = array('#type' => 'textfield',
 
1306
    '#title' => t('E-mail address'),
 
1307
    '#default_value' => $edit['mail'],
 
1308
    '#maxlength' => EMAIL_MAX_LENGTH,
 
1309
    '#description' => t('A valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.'),
 
1310
    '#required' => TRUE,
 
1311
  );
 
1312
  if (!$register) {
 
1313
    $form['account']['pass'] = array('#type' => 'password_confirm',
 
1314
      '#description' => t('To change the current user password, enter the new password in both fields.'),
 
1315
      '#size' => 25,
 
1316
    );
 
1317
  }
 
1318
  elseif (!variable_get('user_email_verification', TRUE) || $admin) {
 
1319
    $form['account']['pass'] = array(
 
1320
      '#type' => 'password_confirm',
 
1321
      '#description' => t('Provide a password for the new account in both fields.'),
 
1322
      '#required' => TRUE,
 
1323
      '#size' => 25,
 
1324
    );
 
1325
  }
 
1326
  if ($admin) {
 
1327
    $form['account']['status'] = array('#type' => 'radios', '#title' => t('Status'), '#default_value' => isset($edit['status']) ? $edit['status'] : 1, '#options' => array(t('Blocked'), t('Active')));
 
1328
  }
 
1329
  if (user_access('administer access control')) {
 
1330
    $roles = user_roles(1);
 
1331
    unset($roles[DRUPAL_AUTHENTICATED_RID]);
 
1332
    if ($roles) {
 
1333
      $form['account']['roles'] = array('#type' => 'checkboxes', '#title' => t('Roles'), '#default_value' => array_keys((array)$edit['roles']), '#options' => $roles, '#description' => t('The user receives the combined permissions of the %au role, and all roles selected here.', array('%au' => t('authenticated user'))));
 
1334
    }
 
1335
  }
 
1336
 
 
1337
  // Picture/avatar:
 
1338
  if (variable_get('user_pictures', 0) && !$register) {
 
1339
    $form['picture'] = array('#type' => 'fieldset', '#title' => t('Picture'), '#weight' => 1);
 
1340
    $picture = theme('user_picture', (object)$edit);
 
1341
    if ($picture) {
 
1342
      $form['picture']['current_picture'] = array('#value' => $picture);
 
1343
      $form['picture']['picture_delete'] = array('#type' => 'checkbox', '#title' => t('Delete picture'), '#description' => t('Check this box to delete your current picture.'));
 
1344
    }
 
1345
    else {
 
1346
      $form['picture']['picture_delete'] = array('#type' => 'hidden');
 
1347
    }
 
1348
    $form['picture']['picture_upload'] = array('#type' => 'file', '#title' => t('Upload picture'), '#size' => 48, '#description' => t('Your virtual face or picture. Maximum dimensions are %dimensions and the maximum size is %size kB.', array('%dimensions' => variable_get('user_picture_dimensions', '85x85'), '%size' => variable_get('user_picture_file_size', '30'))) .' '. variable_get('user_picture_guidelines', ''));
 
1349
  }
 
1350
 
 
1351
  return $form;
 
1352
}
 
1353
 
 
1354
function _user_edit_validate($uid, &$edit) {
 
1355
  $user = user_load(array('uid' => $uid));
 
1356
  // Validate the username:
 
1357
  if (user_access('change own username') || user_access('administer users') || arg(1) == 'register') {
 
1358
    if ($error = user_validate_name($edit['name'])) {
 
1359
      form_set_error('name', $error);
 
1360
    }
 
1361
    else if (db_num_rows(db_query("SELECT uid FROM {users} WHERE uid != %d AND LOWER(name) = LOWER('%s')", $uid, $edit['name'])) > 0) {
 
1362
      form_set_error('name', t('The name %name is already taken.', array('%name' => $edit['name'])));
 
1363
    }
 
1364
    else if (drupal_is_denied('user', $edit['name'])) {
 
1365
      form_set_error('name', t('The name %name has been denied access.', array('%name' => $edit['name'])));
 
1366
    }
 
1367
  }
 
1368
 
 
1369
  // Validate the e-mail address:
 
1370
  if ($error = user_validate_mail($edit['mail'])) {
 
1371
    form_set_error('mail', $error);
 
1372
  }
 
1373
  else if (db_num_rows(db_query("SELECT uid FROM {users} WHERE uid != %d AND LOWER(mail) = LOWER('%s')", $uid, $edit['mail'])) > 0) {
 
1374
    form_set_error('mail', t('The e-mail address %email is already registered. <a href="@password">Have you forgotten your password?</a>', array('%email' => $edit['mail'], '@password' => url('user/password'))));
 
1375
  }
 
1376
  else if (drupal_is_denied('mail', $edit['mail'])) {
 
1377
    form_set_error('mail', t('The e-mail address %email has been denied access.', array('%email' => $edit['mail'])));
 
1378
  }
 
1379
 
 
1380
  // If required, validate the uploaded picture.
 
1381
  if ($file = file_check_upload('picture_upload')) {
 
1382
    user_validate_picture($file, $edit, $user);
 
1383
  }
 
1384
}
 
1385
 
 
1386
function _user_edit_submit($uid, &$edit) {
 
1387
  $user = user_load(array('uid' => $uid));
 
1388
  // Delete picture if requested, and if no replacement picture was given.
 
1389
  if ($edit['picture_delete']) {
 
1390
    if ($user->picture && file_exists($user->picture)) {
 
1391
      file_delete($user->picture);
 
1392
    }
 
1393
    $edit['picture'] = '';
 
1394
  }
 
1395
  if (isset($edit['roles'])) {
 
1396
    $edit['roles'] = array_filter($edit['roles']);
 
1397
  }
 
1398
}
 
1399
 
 
1400
function user_edit($category = 'account') {
 
1401
  global $user;
 
1402
 
 
1403
  $account = user_load(array('uid' => arg(1)));
 
1404
  if ($account === FALSE) {
 
1405
    drupal_set_message(t('The account does not exist or has already been deleted.'));
 
1406
    drupal_goto('admin/user/user');
 
1407
  }
 
1408
  $edit = $_POST['op'] ? $_POST : (array)$account;
 
1409
 
 
1410
  if (arg(2) == 'delete') {
 
1411
    if ($edit['confirm']) {
 
1412
      user_delete($edit, $account->uid);
 
1413
      drupal_goto('admin/user/user');
 
1414
    }
 
1415
    else {
 
1416
      return drupal_get_form('user_confirm_delete', $account->name, $account->uid);
 
1417
    }
 
1418
  }
 
1419
  else if ($_POST['op'] == t('Delete')) {
 
1420
    if ($_REQUEST['destination']) {
 
1421
      $destination = drupal_get_destination();
 
1422
      unset($_REQUEST['destination']);
 
1423
    }
 
1424
    // Note: we redirect from user/uid/edit to user/uid/delete to make the tabs disappear.
 
1425
    drupal_goto("user/$account->uid/delete", $destination);
 
1426
  }
 
1427
 
 
1428
  $form = _user_forms($edit, $account, $category);
 
1429
  $form['_category'] = array('#type' => 'value', '#value' => $category);
 
1430
  $form['_account'] = array('#type' => 'value', '#value' => $account);
 
1431
  $form['submit'] = array('#type' => 'submit', '#value' => t('Submit'), '#weight' => 30);
 
1432
  if (user_access('administer users')) {
 
1433
    $form['delete'] = array('#type' => 'submit', '#value' => t('Delete'), '#weight' => 31);
 
1434
  }
 
1435
  $form['#attributes']['enctype'] = 'multipart/form-data';
 
1436
 
 
1437
  drupal_set_title(check_plain($account->name));
 
1438
  return $form;
 
1439
}
 
1440
 
 
1441
function user_confirm_delete($name, $uid) {
 
1442
  return confirm_form(array(),
 
1443
    t('Are you sure you want to delete the account %name?', array('%name' => $name)),
 
1444
    'user/'. $uid,
 
1445
    t('All submissions made by this user will be attributed to the anonymous account. This action cannot be undone.'),
 
1446
    t('Delete'), t('Cancel'));
 
1447
}
 
1448
 
 
1449
/**
 
1450
 * Delete a user.
 
1451
 *
 
1452
 * @param $edit An array of submitted form values.
 
1453
 * @param $uid The user ID of the user to delete.
 
1454
 */
 
1455
function user_delete($edit, $uid) {
 
1456
  $account = user_load(array('uid' => $uid));
 
1457
  sess_destroy_uid($uid);
 
1458
  db_query('DELETE FROM {users} WHERE uid = %d', $uid);
 
1459
  db_query('DELETE FROM {users_roles} WHERE uid = %d', $uid);
 
1460
  db_query('DELETE FROM {authmap} WHERE uid = %d', $uid);
 
1461
  $array = array('%name' => $account->name, '%email' => '<'. $account->mail .'>');
 
1462
  watchdog('user', t('Deleted user: %name %email.', $array), WATCHDOG_NOTICE);
 
1463
  drupal_set_message(t('%name has been deleted.', $array));
 
1464
  module_invoke_all('user', 'delete', $edit, $account);
 
1465
}
 
1466
 
 
1467
function user_edit_validate($form_id, $form_values) {
 
1468
  user_module_invoke('validate', $form_values, $form_values['_account'], $form_values['_category']);
 
1469
  // Validate input to ensure that non-privileged users can't alter protected data.
 
1470
  if ((!user_access('administer users') && array_intersect(array_keys($form_values), array('uid', 'init', 'session'))) || (!user_access('administer access control') && isset($form_values['roles']))) {
 
1471
    $message = t('Detected malicious attempt to alter protected user fields.');
 
1472
    watchdog('security', $message, WATCHDOG_WARNING);
 
1473
    // set this to a value type field
 
1474
    form_set_error('category', $message);
 
1475
  }
 
1476
}
 
1477
 
 
1478
function user_edit_submit($form_id, $form_values) {
 
1479
  $account = $form_values['_account'];
 
1480
  $category = $form_values['_category'];
 
1481
  unset($form_values['_account'], $form_values['op'], $form_values['submit'], $form_values['delete'], $form_values['form_token'], $form_values['form_id'], $form_values['_category']);
 
1482
  user_module_invoke('submit', $form_values, $account, $category);
 
1483
  user_save($account, $form_values, $category);
 
1484
 
 
1485
  // Delete that user's menu cache:
 
1486
  cache_clear_all($account->uid .':', 'cache_menu', TRUE);
 
1487
 
 
1488
  // Clear the page cache because pages can contain usernames and/or profile information:
 
1489
  cache_clear_all();
 
1490
 
 
1491
  drupal_set_message(t('The changes have been saved.'));
 
1492
  return 'user/'. $account->uid;
 
1493
}
 
1494
 
 
1495
function user_view($uid = 0) {
 
1496
  global $user;
 
1497
 
 
1498
  $account = user_load(array('uid' => $uid));
 
1499
  if ($account === FALSE || ($account->access == 0 && !user_access('administer users'))) {
 
1500
    return drupal_not_found();
 
1501
  }
 
1502
  // Retrieve and merge all profile fields:
 
1503
  $fields = array();
 
1504
  foreach (module_list() as $module) {
 
1505
    if ($data = module_invoke($module, 'user', 'view', '', $account)) {
 
1506
      foreach ($data as $category => $items) {
 
1507
        foreach ($items as $key => $item) {
 
1508
          $item['class'] = "$module-". $item['class'];
 
1509
          $fields[$category][$key] = $item;
 
1510
        }
 
1511
      }
 
1512
    }
 
1513
  }
 
1514
 
 
1515
  // Let modules change the returned fields - useful for personal privacy
 
1516
  // controls. Since modules communicate changes by reference, we cannot use
 
1517
  // module_invoke_all().
 
1518
  foreach (module_implements('profile_alter') as $module) {
 
1519
    $function = $module .'_profile_alter';
 
1520
    $function($account, $fields);
 
1521
  }
 
1522
 
 
1523
  drupal_set_title(check_plain($account->name));
 
1524
  return theme('user_profile', $account, $fields);
 
1525
}
 
1526
 
 
1527
/*** Administrative features ***********************************************/
 
1528
 
 
1529
function _user_mail_text($messageid, $variables = array()) {
 
1530
 
 
1531
  // Check if an admin setting overrides the default string.
 
1532
  if ($admin_setting = variable_get('user_mail_'. $messageid, FALSE)) {
 
1533
    return strtr($admin_setting, $variables);
 
1534
  }
 
1535
  // No override, return with default strings.
 
1536
  else {
 
1537
    switch ($messageid) {
 
1538
      case 'welcome_subject':
 
1539
        return t('Account details for !username at !site', $variables);
 
1540
      case 'welcome_body':
 
1541
        return t("!username,\n\nThank you for registering at !site. You may now log in to !login_uri using the following username and password:\n\nusername: !username\npassword: !password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.\n\n\n--  !site team", $variables);
 
1542
      case 'admin_subject':
 
1543
        return t('An administrator created an account for you at !site', $variables);
 
1544
      case 'admin_body':
 
1545
        return t("!username,\n\nA site administrator at !site has created an account for you. You may now log in to !login_uri using the following username and password:\n\nusername: !username\npassword: !password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.\n\n\n--  !site team", $variables);
 
1546
      case 'approval_subject':
 
1547
        return t('Account details for !username at !site (pending admin approval)', $variables);
 
1548
      case 'approval_body':
 
1549
        return t("!username,\n\nThank you for registering at !site. Your application for an account is currently pending approval. Once it has been granted, you may log in to !login_uri using the following username and password:\n\nusername: !username\npassword: !password\n\nYou may also log in by clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you may wish to change your password at !edit_uri\n\n\n--  !site team", $variables);
 
1550
      case 'pass_subject':
 
1551
        return t('Replacement login information for !username at !site', $variables);
 
1552
      case 'pass_body':
 
1553
        return t("!username,\n\nA request to reset the password for your account has been made at !site.\n\nYou may now log in to !uri_brief clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once. It expires after one day and nothing will happen if it's not used.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.", $variables);
 
1554
    }
 
1555
  }
 
1556
}
 
1557
 
 
1558
function user_admin_check_user() {
 
1559
  $form['user'] = array('#type' => 'fieldset', '#title' => t('Username'));
 
1560
  $form['user']['test'] = array('#type' => 'textfield', '#title' => '', '#description' => t('Enter a username to check if it will be denied or allowed.'), '#size' => 30, '#maxlength' => USERNAME_MAX_LENGTH);
 
1561
  $form['user']['type'] = array('#type' => 'hidden', '#value' => 'user');
 
1562
  $form['user']['submit'] = array('#type' => 'submit', '#value' => t('Check username'));
 
1563
  $form['#base'] = 'user_admin_access_check';
 
1564
  return $form;
 
1565
}
 
1566
 
 
1567
function user_admin_check_mail() {
 
1568
  $form['mail'] = array('#type' => 'fieldset', '#title' => t('E-mail'));
 
1569
  $form['mail']['test'] = array('#type' => 'textfield', '#title' => '', '#description' => t('Enter an e-mail address to check if it will be denied or allowed.'), '#size' => 30, '#maxlength' => EMAIL_MAX_LENGTH);
 
1570
  $form['mail']['type'] = array('#type' => 'hidden', '#value' => 'mail');
 
1571
  $form['mail']['submit'] = array('#type' => 'submit', '#value' => t('Check e-mail'));
 
1572
  $form['#base'] = 'user_admin_access_check';
 
1573
  return $form;
 
1574
}
 
1575
 
 
1576
function user_admin_check_host() {
 
1577
  $form['host'] = array('#type' => 'fieldset', '#title' => t('Hostname'));
 
1578
  $form['host']['test'] = array('#type' => 'textfield', '#title' => '', '#description' => t('Enter a hostname or IP address to check if it will be denied or allowed.'), '#size' => 30, '#maxlength' => 64);
 
1579
  $form['host']['type'] = array('#type' => 'hidden', '#value' => 'host');
 
1580
  $form['host']['submit'] = array('#type' => 'submit', '#value' => t('Check hostname'));
 
1581
  $form['#base'] = 'user_admin_access_check';
 
1582
  return $form;
 
1583
}
 
1584
 
 
1585
/**
 
1586
 * Menu callback: check an access rule
 
1587
 */
 
1588
function user_admin_access_check() {
 
1589
  $output = drupal_get_form('user_admin_check_user');
 
1590
  $output .= drupal_get_form('user_admin_check_mail');
 
1591
  $output .= drupal_get_form('user_admin_check_host');
 
1592
  return $output;
 
1593
}
 
1594
 
 
1595
function user_admin_access_check_validate($form_id, $form_values) {
 
1596
  if (empty($form_values['test'])) {
 
1597
    form_set_error($form_values['type'], t('No value entered. Please enter a test string and try again.'));
 
1598
  }
 
1599
}
 
1600
 
 
1601
function user_admin_access_check_submit($form_id, $form_values) {
 
1602
  switch ($form_values['type']) {
 
1603
    case 'user':
 
1604
      if (drupal_is_denied('user', $form_values['test'])) {
 
1605
        drupal_set_message(t('The username %name is not allowed.', array('%name' => $form_values['test'])));
 
1606
      }
 
1607
      else {
 
1608
        drupal_set_message(t('The username %name is allowed.', array('%name' => $form_values['test'])));
 
1609
      }
 
1610
      break;
 
1611
    case 'mail':
 
1612
      if (drupal_is_denied('mail', $form_values['test'])) {
 
1613
        drupal_set_message(t('The e-mail address %mail is not allowed.', array('%mail' => $form_values['test'])));
 
1614
      }
 
1615
      else {
 
1616
        drupal_set_message(t('The e-mail address %mail is allowed.', array('%mail' => $form_values['test'])));
 
1617
      }
 
1618
      break;
 
1619
    case 'host':
 
1620
      if (drupal_is_denied('host', $form_values['test'])) {
 
1621
        drupal_set_message(t('The hostname %host is not allowed.', array('%host' => $form_values['test'])));
 
1622
      }
 
1623
      else {
 
1624
        drupal_set_message(t('The hostname %host is allowed.', array('%host' => $form_values['test'])));
 
1625
      }
 
1626
      break;
 
1627
    default:
 
1628
      break;
 
1629
  }
 
1630
}
 
1631
 
 
1632
/**
 
1633
 * Menu callback: add an access rule
 
1634
 */
 
1635
function user_admin_access_add($mask = NULL, $type = NULL) {
 
1636
  if ($edit = $_POST) {
 
1637
    if (!$edit['mask']) {
 
1638
      form_set_error('mask', t('You must enter a mask.'));
 
1639
    }
 
1640
    else {
 
1641
      $aid = db_next_id('{access}_aid');
 
1642
      db_query("INSERT INTO {access} (aid, mask, type, status) VALUES ('%s', '%s', '%s', %d)", $aid, $edit['mask'], $edit['type'], $edit['status']);
 
1643
      drupal_set_message(t('The access rule has been added.'));
 
1644
      drupal_goto('admin/user/rules');
 
1645
    }
 
1646
  }
 
1647
  else {
 
1648
    $edit['mask'] = $mask;
 
1649
    $edit['type'] = $type;
 
1650
  }
 
1651
  return drupal_get_form('user_admin_access_add_form', $edit, t('Add rule'));
 
1652
}
 
1653
 
 
1654
/**
 
1655
 * Menu callback: delete an access rule
 
1656
 */
 
1657
function user_admin_access_delete_confirm($aid = 0) {
 
1658
  $access_types = array('user' => t('username'), 'mail' => t('e-mail'), 'host' => t('host'));
 
1659
  $edit = db_fetch_object(db_query('SELECT aid, type, status, mask FROM {access} WHERE aid = %d', $aid));
 
1660
 
 
1661
  $form = array();
 
1662
  $form['aid'] = array('#type' => 'hidden', '#value' => $aid);
 
1663
  $output = confirm_form($form,
 
1664
                  t('Are you sure you want to delete the @type rule for %rule?', array('@type' => $access_types[$edit->type], '%rule' => $edit->mask)),
 
1665
                  'admin/user/rules',
 
1666
                  t('This action cannot be undone.'),
 
1667
                  t('Delete'),
 
1668
                  t('Cancel'));
 
1669
  return $output;
 
1670
}
 
1671
 
 
1672
function user_admin_access_delete_confirm_submit($form_id, $form_values) {
 
1673
  db_query('DELETE FROM {access} WHERE aid = %d', $form_values['aid']);
 
1674
  drupal_set_message(t('The access rule has been deleted.'));
 
1675
  return 'admin/user/rules';
 
1676
}
 
1677
 
 
1678
/**
 
1679
 * Menu callback: edit an access rule
 
1680
 */
 
1681
function user_admin_access_edit($aid = 0) {
 
1682
  if ($edit = $_POST) {
 
1683
    if (!$edit['mask']) {
 
1684
      form_set_error('mask', t('You must enter a mask.'));
 
1685
    }
 
1686
    else {
 
1687
      db_query("UPDATE {access} SET mask = '%s', type = '%s', status = '%s' WHERE aid = %d", $edit['mask'], $edit['type'], $edit['status'], $aid);
 
1688
      drupal_set_message(t('The access rule has been saved.'));
 
1689
      drupal_goto('admin/user/rules');
 
1690
    }
 
1691
  }
 
1692
  else {
 
1693
    $edit = db_fetch_array(db_query('SELECT aid, type, status, mask FROM {access} WHERE aid = %d', $aid));
 
1694
  }
 
1695
  return drupal_get_form('user_admin_access_edit_form', $edit, t('Save rule'));
 
1696
}
 
1697
 
 
1698
function user_admin_access_form($edit, $submit) {
 
1699
  $form['status'] = array(
 
1700
    '#type' => 'radios',
 
1701
    '#title' => t('Access type'),
 
1702
    '#default_value' => $edit['status'],
 
1703
    '#options' => array('1' => t('Allow'), '0' => t('Deny')),
 
1704
  );
 
1705
  $type_options = array('user' => t('Username'), 'mail' => t('E-mail'), 'host' => t('Host'));
 
1706
  $form['type'] = array(
 
1707
    '#type' => 'radios',
 
1708
    '#title' => t('Rule type'),
 
1709
    '#default_value' => (isset($type_options[$edit['type']]) ? $edit['type'] : 'user'),
 
1710
    '#options' => $type_options,
 
1711
  );
 
1712
  $form['mask'] = array(
 
1713
    '#type' => 'textfield',
 
1714
    '#title' => t('Mask'),
 
1715
    '#size' => 30,
 
1716
    '#maxlength' => 64,
 
1717
    '#default_value' => $edit['mask'],
 
1718
    '#description' => '%: '. t('Matches any number of characters, even zero characters') .'.<br />_: '. t('Matches exactly one character.'),
 
1719
    '#required' => TRUE,
 
1720
  );
 
1721
  $form['submit'] = array('#type' => 'submit', '#value' => $submit);
 
1722
 
 
1723
  return $form;
 
1724
}
 
1725
 
 
1726
/**
 
1727
 * Menu callback: list all access rules
 
1728
 */
 
1729
function user_admin_access() {
 
1730
  $header = array(array('data' => t('Access type'), 'field' => 'status'), array('data' => t('Rule type'), 'field' => 'type'), array('data' => t('Mask'), 'field' => 'mask'), array('data' => t('Operations'), 'colspan' => 2));
 
1731
  $result = db_query("SELECT aid, type, status, mask FROM {access}". tablesort_sql($header));
 
1732
  $access_types = array('user' => t('username'), 'mail' => t('e-mail'), 'host' => t('host'));
 
1733
  $rows = array();
 
1734
  while ($rule = db_fetch_object($result)) {
 
1735
    $rows[] = array($rule->status ? t('allow') : t('deny'), $access_types[$rule->type], $rule->mask, l(t('edit'), 'admin/user/rules/edit/'. $rule->aid), l(t('delete'), 'admin/user/rules/delete/'. $rule->aid));
 
1736
  }
 
1737
  if (count($rows) == 0) {
 
1738
    $rows[] = array(array('data' => '<em>'. t('There are currently no access rules.') .'</em>', 'colspan' => 5));
 
1739
  }
 
1740
  $output .= theme('table', $header, $rows);
 
1741
 
 
1742
  return $output;
 
1743
}
 
1744
 
 
1745
/**
 
1746
 * Retrieve an array of roles matching specified conditions.
 
1747
 *
 
1748
 * @param $membersonly
 
1749
 *   Set this to TRUE to exclude the 'anonymous' role.
 
1750
 * @param $permission
 
1751
 *   A string containing a permission. If set, only roles containing that permission are returned.
 
1752
 *
 
1753
 * @return
 
1754
 *   An associative array with the role id as the key and the role name as value.
 
1755
 */
 
1756
function user_roles($membersonly = 0, $permission = 0) {
 
1757
  $roles = array();
 
1758
 
 
1759
  if ($permission) {
 
1760
    $result = db_query("SELECT r.* FROM {role} r INNER JOIN {permission} p ON r.rid = p.rid WHERE p.perm LIKE '%%%s%%' ORDER BY r.name", $permission);
 
1761
  }
 
1762
  else {
 
1763
    $result = db_query('SELECT * FROM {role} ORDER BY name');
 
1764
  }
 
1765
  while ($role = db_fetch_object($result)) {
 
1766
    if (!$membersonly || ($membersonly && $role->rid != DRUPAL_ANONYMOUS_RID)) {
 
1767
      $roles[$role->rid] = $role->name;
 
1768
    }
 
1769
  }
 
1770
  return $roles;
 
1771
}
 
1772
 
 
1773
/**
 
1774
 * Menu callback: administer permissions.
 
1775
 */
 
1776
function user_admin_perm($rid = NULL) {
 
1777
  if (is_numeric($rid)) {
 
1778
    $result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid WHERE r.rid = %d', $rid);
 
1779
  }
 
1780
  else {
 
1781
    $result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid ORDER BY name');
 
1782
  }
 
1783
 
 
1784
  // Compile role array:
 
1785
  // Add a comma at the end so when searching for a permission, we can
 
1786
  // always search for "$perm," to make sure we do not confuse
 
1787
  // permissions that are substrings of each other.
 
1788
  while ($role = db_fetch_object($result)) {
 
1789
    $role_permissions[$role->rid] = $role->perm .',';
 
1790
  }
 
1791
 
 
1792
  if (is_numeric($rid)) {
 
1793
    $result = db_query('SELECT rid, name FROM {role} r WHERE r.rid = %d ORDER BY name', $rid);
 
1794
  }
 
1795
  else {
 
1796
    $result = db_query('SELECT rid, name FROM {role} ORDER BY name');
 
1797
  }
 
1798
 
 
1799
  $role_names = array();
 
1800
  while ($role = db_fetch_object($result)) {
 
1801
    $role_names[$role->rid] = $role->name;
 
1802
  }
 
1803
 
 
1804
  // Render role/permission overview:
 
1805
  $options = array();
 
1806
  foreach (module_list(FALSE, FALSE, TRUE) as $module) {
 
1807
    if ($permissions = module_invoke($module, 'perm')) {
 
1808
      $form['permission'][] = array(
 
1809
        '#value' => $module,
 
1810
      );
 
1811
      asort($permissions);
 
1812
      foreach ($permissions as $perm) {
 
1813
        $options[$perm] = '';
 
1814
        $form['permission'][$perm] = array('#value' => t($perm));
 
1815
        foreach ($role_names as $rid => $name) {
 
1816
          // Builds arrays for checked boxes for each role
 
1817
          if (strpos($role_permissions[$rid], $perm .',') !== FALSE) {
 
1818
            $status[$rid][] = $perm;
 
1819
          }
 
1820
        }
 
1821
      }
 
1822
    }
 
1823
  }
 
1824
 
 
1825
  // Have to build checkboxes here after checkbox arrays are built
 
1826
  foreach ($role_names as $rid => $name) {
 
1827
    $form['checkboxes'][$rid] = array('#type' => 'checkboxes', '#options' => $options, '#default_value' => $status[$rid]);
 
1828
    $form['role_names'][$rid] = array('#value' => $name, '#tree' => TRUE);
 
1829
  }
 
1830
  $form['submit'] = array('#type' => 'submit', '#value' => t('Save permissions'));
 
1831
 
 
1832
  return $form;
 
1833
}
 
1834
 
 
1835
function theme_user_admin_perm($form) {
 
1836
  foreach (element_children($form['permission']) as $key) {
 
1837
    // Don't take form control structures
 
1838
    if (is_array($form['permission'][$key])) {
 
1839
      $row = array();
 
1840
      // Module name
 
1841
      if (is_numeric($key)) {
 
1842
        $row[] = array('data' => t('@module module', array('@module' => drupal_render($form['permission'][$key]))), 'class' => 'module', 'id' => 'module-'. $form['permission'][$key]['#value'], 'colspan' => count($form['role_names']) + 1);
 
1843
      }
 
1844
      else {
 
1845
        $row[] = array('data' => drupal_render($form['permission'][$key]), 'class' => 'permission');
 
1846
        foreach (element_children($form['checkboxes']) as $rid) {
 
1847
          if (is_array($form['checkboxes'][$rid])) {
 
1848
            $row[] = array('data' => drupal_render($form['checkboxes'][$rid][$key]), 'align' => 'center', 'title' => t($key));
 
1849
          }
 
1850
        }
 
1851
      }
 
1852
      $rows[] = $row;
 
1853
    }
 
1854
  }
 
1855
  $header[] = (t('Permission'));
 
1856
  foreach (element_children($form['role_names']) as $rid) {
 
1857
    if (is_array($form['role_names'][$rid])) {
 
1858
      $header[] = drupal_render($form['role_names'][$rid]);
 
1859
    }
 
1860
  }
 
1861
  $output = theme('table', $header, $rows, array('id' => 'permissions'));
 
1862
  $output .= drupal_render($form);
 
1863
  return $output;
 
1864
}
 
1865
 
 
1866
function user_admin_perm_submit($form_id, $form_values) {
 
1867
  // Save permissions:
 
1868
  $result = db_query('SELECT * FROM {role}');
 
1869
  while ($role = db_fetch_object($result)) {
 
1870
    if (isset($form_values[$role->rid])) {
 
1871
      // Delete, so if we clear every checkbox we reset that role;
 
1872
      // otherwise permissions are active and denied everywhere.
 
1873
      db_query('DELETE FROM {permission} WHERE rid = %d', $role->rid);
 
1874
      $form_values[$role->rid] = array_filter($form_values[$role->rid]);
 
1875
      if (count($form_values[$role->rid])) {
 
1876
        db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $role->rid, implode(', ', array_keys($form_values[$role->rid])));
 
1877
      }
 
1878
    }
 
1879
  }
 
1880
 
 
1881
  drupal_set_message(t('The changes have been saved.'));
 
1882
 
 
1883
  // Clear the cached pages and menus:
 
1884
  menu_rebuild();
 
1885
 
 
1886
}
 
1887
 
 
1888
/**
 
1889
 * Menu callback: administer roles.
 
1890
 */
 
1891
function user_admin_role() {
 
1892
  $id = arg(4);
 
1893
  if ($id) {
 
1894
    if (DRUPAL_ANONYMOUS_RID == $id || DRUPAL_AUTHENTICATED_RID == $id) {
 
1895
      drupal_goto('admin/user/roles');
 
1896
    }
 
1897
    // Display the edit role form.
 
1898
    $role = db_fetch_object(db_query('SELECT * FROM {role} WHERE rid = %d', $id));
 
1899
    $form['name'] = array(
 
1900
      '#type' => 'textfield',
 
1901
      '#title' => t('Role name'),
 
1902
      '#default_value' => $role->name,
 
1903
      '#size' => 30,
 
1904
      '#required' => TRUE,
 
1905
      '#maxlength' => 64,
 
1906
      '#description' => t('The name for this role. Example: "moderator", "editorial board", "site architect".'),
 
1907
    );
 
1908
    $form['rid'] = array(
 
1909
      '#type' => 'value',
 
1910
      '#value' => $id,
 
1911
    );
 
1912
    $form['submit'] = array(
 
1913
      '#type' => 'submit',
 
1914
      '#value' => t('Save role'),
 
1915
    );
 
1916
    $form['delete'] = array(
 
1917
      '#type' => 'submit',
 
1918
      '#value' => t('Delete role'),
 
1919
    );
 
1920
  }
 
1921
  else {
 
1922
    $form['name'] = array(
 
1923
      '#type' => 'textfield',
 
1924
      '#size' => 32,
 
1925
      '#maxlength' => 64,
 
1926
    );
 
1927
    $form['submit'] = array(
 
1928
      '#type' => 'submit',
 
1929
      '#value' => t('Add role'),
 
1930
    );
 
1931
    $form['#base'] = 'user_admin_role';
 
1932
  }
 
1933
  return $form;
 
1934
}
 
1935
 
 
1936
function user_admin_role_validate($form_id, $form_values) {
 
1937
  if ($form_values['name']) {
 
1938
    if ($form_values['op'] == t('Save role')) {
 
1939
      if (db_result(db_query("SELECT COUNT(*) FROM {role} WHERE name = '%s' AND rid != %d", $form_values['name'], $form_values['rid']))) {
 
1940
        form_set_error('name', t('The role name %name already exists. Please choose another role name.', array('%name' => $form_values['name'])));
 
1941
      }
 
1942
    }
 
1943
    else if ($form_values['op'] == t('Add role')) {
 
1944
      if (db_result(db_query("SELECT COUNT(*) FROM {role} WHERE name = '%s'", $form_values['name']))) {
 
1945
        form_set_error('name', t('The role name %name already exists. Please choose another role name.', array('%name' => $form_values['name'])));
 
1946
      }
 
1947
    }
 
1948
  }
 
1949
  else {
 
1950
    form_set_error('name', t('You must specify a valid role name.'));
 
1951
  }
 
1952
}
 
1953
 
 
1954
function user_admin_role_submit($form_id, $form_values) {
 
1955
  if ($form_values['op'] == t('Save role')) {
 
1956
    db_query("UPDATE {role} SET name = '%s' WHERE rid = %d", $form_values['name'], $form_values['rid']);
 
1957
    drupal_set_message(t('The role has been renamed.'));
 
1958
  }
 
1959
  else if ($form_values['op'] == t('Delete role')) {
 
1960
    db_query('DELETE FROM {role} WHERE rid = %d', $form_values['rid']);
 
1961
    db_query('DELETE FROM {permission} WHERE rid = %d', $form_values['rid']);
 
1962
    // Update the users who have this role set:
 
1963
    db_query('DELETE FROM {users_roles} WHERE rid = %d', $form_values['rid']);
 
1964
 
 
1965
    drupal_set_message(t('The role has been deleted.'));
 
1966
  }
 
1967
  else if ($form_values['op'] == t('Add role')) {
 
1968
    db_query("INSERT INTO {role} (name) VALUES ('%s')", $form_values['name']);
 
1969
    drupal_set_message(t('The role has been added.'));
 
1970
  }
 
1971
  return 'admin/user/roles';
 
1972
}
 
1973
 
 
1974
function theme_user_admin_new_role($form) {
 
1975
  $header = array(t('Name'), array('data' => t('Operations'), 'colspan' => 2));
 
1976
  foreach (user_roles() as $rid => $name) {
 
1977
    $edit_permissions = l(t('edit permissions'), 'admin/user/access/'. $rid);
 
1978
    if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
 
1979
      $rows[] = array($name, l(t('edit role'), 'admin/user/roles/edit/'. $rid), $edit_permissions);
 
1980
    }
 
1981
    else {
 
1982
      $rows[] = array($name, t('locked'), $edit_permissions);
 
1983
    }
 
1984
  }
 
1985
  $rows[] = array(drupal_render($form['name']), array('data' => drupal_render($form['submit']), colspan => 2));
 
1986
 
 
1987
  $output = drupal_render($form);
 
1988
  $output .= theme('table', $header, $rows);
 
1989
 
 
1990
  return $output;
 
1991
}
 
1992
 
 
1993
function user_admin_account() {
 
1994
  $filter = user_build_filter_query();
 
1995
 
 
1996
  $header = array(
 
1997
    array(),
 
1998
    array('data' => t('Username'), 'field' => 'u.name'),
 
1999
    array('data' => t('Status'), 'field' => 'u.status'),
 
2000
    t('Roles'),
 
2001
    array('data' => t('Member for'), 'field' => 'u.created', 'sort' => 'desc'),
 
2002
    array('data' => t('Last access'), 'field' => 'u.access'),
 
2003
    t('Operations')
 
2004
  );
 
2005
 
 
2006
  $sql = 'SELECT DISTINCT u.uid, u.name, u.status, u.created, u.access FROM {users} u LEFT JOIN {users_roles} ur ON u.uid = ur.uid '. $filter['join'] .' WHERE u.uid != 0 '. $filter['where'];
 
2007
  $sql .= tablesort_sql($header);
 
2008
  $result = pager_query($sql, 50, 0, NULL, $filter['args']);
 
2009
 
 
2010
  $form['options'] = array(
 
2011
    '#type' => 'fieldset',
 
2012
    '#title' => t('Update options'),
 
2013
    '#prefix' => '<div class="container-inline">',
 
2014
    '#suffix' => '</div>',
 
2015
  );
 
2016
  $options = array();
 
2017
  foreach (module_invoke_all('user_operations') as $operation => $array) {
 
2018
    $options[$operation] = $array['label'];
 
2019
  }
 
2020
  $form['options']['operation'] = array(
 
2021
    '#type' => 'select',
 
2022
    '#options' => $options,
 
2023
    '#default_value' => 'unblock',
 
2024
  );
 
2025
  $form['options']['submit'] = array(
 
2026
    '#type' => 'submit',
 
2027
    '#value' => t('Update'),
 
2028
  );
 
2029
 
 
2030
  $destination = drupal_get_destination();
 
2031
 
 
2032
  $status = array(t('blocked'), t('active'));
 
2033
  $roles = user_roles(1);
 
2034
 
 
2035
  while ($account = db_fetch_object($result)) {
 
2036
    $accounts[$account->uid] = '';
 
2037
    $form['name'][$account->uid] = array('#value' => theme('username', $account));
 
2038
    $form['status'][$account->uid] =  array('#value' => $status[$account->status]);
 
2039
    $users_roles = array();
 
2040
    $roles_result = db_query('SELECT rid FROM {users_roles} WHERE uid = %d', $account->uid);
 
2041
    while ($user_role = db_fetch_object($roles_result)) {
 
2042
      $users_roles[] = $roles[$user_role->rid];
 
2043
    }
 
2044
    asort($users_roles);
 
2045
    $form['roles'][$account->uid][0] = array('#value' => theme('item_list', $users_roles));
 
2046
    $form['member_for'][$account->uid] = array('#value' => format_interval(time() - $account->created));
 
2047
    $form['last_access'][$account->uid] =  array('#value' => $account->access ? t('@time ago', array('@time' => format_interval(time() - $account->access))) : t('never'));
 
2048
    $form['operations'][$account->uid] = array('#value' => l(t('edit'), "user/$account->uid/edit", array(), $destination));
 
2049
  }
 
2050
  $form['accounts'] = array(
 
2051
    '#type' => 'checkboxes',
 
2052
    '#options' => $accounts
 
2053
  );
 
2054
  $form['pager'] = array('#value' => theme('pager', NULL, 50, 0));
 
2055
 
 
2056
  return $form;
 
2057
}
 
2058
 
 
2059
/**
 
2060
 * Theme user administration overview.
 
2061
 */
 
2062
function theme_user_admin_account($form) {
 
2063
  // Overview table:
 
2064
  $header = array(
 
2065
    theme('table_select_header_cell'),
 
2066
    array('data' => t('Username'), 'field' => 'u.name'),
 
2067
    array('data' => t('Status'), 'field' => 'u.status'),
 
2068
    t('Roles'),
 
2069
    array('data' => t('Member for'), 'field' => 'u.created', 'sort' => 'desc'),
 
2070
    array('data' => t('Last access'), 'field' => 'u.access'),
 
2071
    t('Operations')
 
2072
  );
 
2073
 
 
2074
  $output = drupal_render($form['options']);
 
2075
  if (isset($form['name']) && is_array($form['name'])) {
 
2076
    foreach (element_children($form['name']) as $key) {
 
2077
      $rows[] = array(
 
2078
        drupal_render($form['accounts'][$key]),
 
2079
        drupal_render($form['name'][$key]),
 
2080
        drupal_render($form['status'][$key]),
 
2081
        drupal_render($form['roles'][$key]),
 
2082
        drupal_render($form['member_for'][$key]),
 
2083
        drupal_render($form['last_access'][$key]),
 
2084
        drupal_render($form['operations'][$key]),
 
2085
      );
 
2086
    }
 
2087
  }
 
2088
  else  {
 
2089
    $rows[] = array(array('data' => t('No users available.'), 'colspan' => '7'));
 
2090
  }
 
2091
 
 
2092
  $output .= theme('table', $header, $rows);
 
2093
  if ($form['pager']['#value']) {
 
2094
    $output .= drupal_render($form['pager']);
 
2095
  }
 
2096
 
 
2097
  $output .= drupal_render($form);
 
2098
 
 
2099
  return $output;
 
2100
}
 
2101
 
 
2102
/**
 
2103
 * Submit the user administration update form.
 
2104
 */
 
2105
function user_admin_account_submit($form_id, $form_values) {
 
2106
  $operations = module_invoke_all('user_operations');
 
2107
  $operation = $operations[$form_values['operation']];
 
2108
  // Filter out unchecked accounts.
 
2109
  $accounts = array_filter($form_values['accounts']);
 
2110
  if ($function = $operation['callback']) {
 
2111
    // Add in callback arguments if present.
 
2112
    if (isset($operation['callback arguments'])) {
 
2113
      $args = array_merge(array($accounts), $operation['callback arguments']);
 
2114
    }
 
2115
    else {
 
2116
      $args = array($accounts);
 
2117
    }
 
2118
    call_user_func_array($function, $args);
 
2119
 
 
2120
    cache_clear_all('*', 'cache_menu', TRUE);
 
2121
    drupal_set_message(t('The update has been performed.'));
 
2122
  }
 
2123
}
 
2124
 
 
2125
function user_admin_account_validate($form_id, $form_values) {
 
2126
  $form_values['accounts'] = array_filter($form_values['accounts']);
 
2127
  if (count($form_values['accounts']) == 0) {
 
2128
    form_set_error('', t('No users selected.'));
 
2129
  }
 
2130
}
 
2131
 
 
2132
/**
 
2133
 * Implementation of hook_user_operations().
 
2134
 */
 
2135
function user_user_operations() {
 
2136
  global $form_values;
 
2137
 
 
2138
  $operations = array(
 
2139
    'unblock' => array(
 
2140
      'label' => t('Unblock the selected users'),
 
2141
      'callback' => 'user_user_operations_unblock',
 
2142
    ),
 
2143
    'block' => array(
 
2144
      'label' => t('Block the selected users'),
 
2145
      'callback' => 'user_user_operations_block',
 
2146
    ),
 
2147
    'delete' => array(
 
2148
      'label' => t('Delete the selected users'),
 
2149
    ),
 
2150
  );
 
2151
 
 
2152
  if (user_access('administer access control')) {
 
2153
    $roles = user_roles(1);
 
2154
    unset($roles[DRUPAL_AUTHENTICATED_RID]);  // Can't edit authenticated role.
 
2155
 
 
2156
    $add_roles = array();
 
2157
    foreach ($roles as $key => $value) {
 
2158
      $add_roles['add_role-'. $key] = $value;
 
2159
    }
 
2160
 
 
2161
    $remove_roles = array();
 
2162
    foreach ($roles as $key => $value) {
 
2163
      $remove_roles['remove_role-'. $key] = $value;
 
2164
    }
 
2165
 
 
2166
    if (count($roles)) {
 
2167
      $role_operations = array(
 
2168
        t('Add a role to the selected users') => array(
 
2169
          'label' => $add_roles,
 
2170
        ),
 
2171
        t('Remove a role from the selected users') => array(
 
2172
          'label' => $remove_roles,
 
2173
        ),
 
2174
      );
 
2175
 
 
2176
      $operations += $role_operations;
 
2177
    }
 
2178
  }
 
2179
 
 
2180
  // If the form has been posted, we need to insert the proper data for role editing if necessary.
 
2181
  if ($form_values) {
 
2182
    $operation_rid = explode('-', $form_values['operation']);
 
2183
    $operation = $operation_rid[0];
 
2184
    $rid = $operation_rid[1];
 
2185
    if ($operation == 'add_role' || $operation == 'remove_role') {
 
2186
      if (user_access('administer access control')) {
 
2187
        $operations[$form_values['operation']] = array(
 
2188
          'callback' => 'user_multiple_role_edit',
 
2189
          'callback arguments' => array($operation, $rid),
 
2190
        );
 
2191
      }
 
2192
      else {
 
2193
        watchdog('security', t('Detected malicious attempt to alter protected user fields.'), WATCHDOG_WARNING);
 
2194
        return;
 
2195
      }
 
2196
    }
 
2197
  }
 
2198
 
 
2199
  return $operations;
 
2200
}
 
2201
 
 
2202
/**
 
2203
 * Callback function for admin mass unblocking users.
 
2204
 */
 
2205
function user_user_operations_unblock($accounts) {
 
2206
  foreach ($accounts as $uid) {
 
2207
    $account = user_load(array('uid' => (int)$uid));
 
2208
    // Skip unblocking user if they are already unblocked.
 
2209
    if ($account !== FALSE && $account->status == 0) {
 
2210
      user_save($account, array('status' => 1));
 
2211
    }
 
2212
  }
 
2213
}
 
2214
 
 
2215
/**
 
2216
 * Callback function for admin mass blocking users.
 
2217
 */
 
2218
function user_user_operations_block($accounts) {
 
2219
  foreach ($accounts as $uid) {
 
2220
    $account = user_load(array('uid' => (int)$uid));
 
2221
    // Skip blocking user if they are already blocked.
 
2222
    if ($account !== FALSE && $account->status == 1) {
 
2223
      user_save($account, array('status' => 0));
 
2224
    }
 
2225
  }
 
2226
}
 
2227
 
 
2228
/**
 
2229
 * Callback function for admin mass adding/deleting a user role.
 
2230
 */
 
2231
function user_multiple_role_edit($accounts, $operation, $rid) {
 
2232
  // The role name is not necessary as user_save() will reload the user
 
2233
  // object, but some modules' hook_user() may look at this first.
 
2234
  $role_name = db_result(db_query('SELECT name FROM {role} WHERE rid = %d', $rid));
 
2235
 
 
2236
  switch ($operation) {
 
2237
    case 'add_role':
 
2238
      foreach ($accounts as $uid) {
 
2239
        $account = user_load(array('uid' => (int)$uid));
 
2240
        // Skip adding the role to the user if they already have it.
 
2241
        if ($account !== FALSE && !isset($account->roles[$rid])) {
 
2242
          $roles = $account->roles + array($rid => $role_name);
 
2243
          user_save($account, array('roles' => $roles));
 
2244
        }
 
2245
      }
 
2246
      break;
 
2247
    case 'remove_role':
 
2248
      foreach ($accounts as $uid) {
 
2249
        $account = user_load(array('uid' => (int)$uid));
 
2250
        // Skip removing the role from the user if they already don't have it.
 
2251
        if ($account !== FALSE && isset($account->roles[$rid])) {
 
2252
          $roles = array_diff($account->roles, array($rid => $role_name));
 
2253
          user_save($account, array('roles' => $roles));
 
2254
        }
 
2255
      }
 
2256
      break;
 
2257
  }
 
2258
}
 
2259
 
 
2260
function user_multiple_delete_confirm() {
 
2261
  $edit = $_POST;
 
2262
 
 
2263
  $form['accounts'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
 
2264
  // array_filter returns only elements with TRUE values
 
2265
  foreach (array_filter($edit['accounts']) as $uid => $value) {
 
2266
    $user = db_result(db_query('SELECT name FROM {users} WHERE uid = %d', $uid));
 
2267
    $form['accounts'][$uid] = array('#type' => 'hidden', '#value' => $uid, '#prefix' => '<li>', '#suffix' => check_plain($user) ."</li>\n");
 
2268
  }
 
2269
  $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
 
2270
 
 
2271
  return confirm_form($form,
 
2272
                      t('Are you sure you want to delete these users?'),
 
2273
                      'admin/user/user', t('This action cannot be undone.'),
 
2274
                      t('Delete all'), t('Cancel'));
 
2275
}
 
2276
 
 
2277
function user_multiple_delete_confirm_submit($form_id, $form_values) {
 
2278
  if ($form_values['confirm']) {
 
2279
    foreach ($form_values['accounts'] as $uid => $value) {
 
2280
      user_delete($form_values, $uid);
 
2281
    }
 
2282
    drupal_set_message(t('The users have been deleted.'));
 
2283
  }
 
2284
  return 'admin/user/user';
 
2285
}
 
2286
 
 
2287
function user_admin_settings() {
 
2288
  // User registration settings.
 
2289
  $form['registration'] = array('#type' => 'fieldset', '#title' => t('User registration settings'));
 
2290
  $form['registration']['user_register'] = array('#type' => 'radios', '#title' => t('Public registrations'), '#default_value' => variable_get('user_register', 1), '#options' => array(t('Only site administrators can create new user accounts.'), t('Visitors can create accounts and no administrator approval is required.'), t('Visitors can create accounts but administrator approval is required.')));
 
2291
  $form['registration']['user_email_verification'] = array('#type' => 'checkbox', '#title' => t('Require e-mail verification when a visitor creates an account'), '#default_value' => variable_get('user_email_verification', TRUE), '#description' => t('If this box is checked, new users will be required to validate their e-mail address prior to logging into to the site, and will be assigned a system-generated password. With it unchecked, users will be logged in immediately upon registering, and may select their own passwords during registration.'));
 
2292
  $form['registration']['user_registration_help'] = array('#type' => 'textarea', '#title' => t('User registration guidelines'), '#default_value' => variable_get('user_registration_help', ''), '#description' => t("This text is displayed at the top of the user registration form. It's useful for helping or instructing your users."));
 
2293
 
 
2294
  // User e-mail settings.
 
2295
  $form['email'] = array('#type' => 'fieldset', '#title' => t('User e-mail settings'));
 
2296
  $form['email']['user_mail_welcome_subject'] = array('#type' => 'textfield', '#title' => t('Subject of welcome e-mail'), '#default_value' => _user_mail_text('welcome_subject'), '#maxlength' => 180, '#description' => t('Customize the subject of your welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' !username, !site, !password, !uri, !uri_brief, !mailto, !date, !login_uri, !edit_uri, !login_url.');
 
2297
  $form['email']['user_mail_welcome_body'] = array('#type' => 'textarea', '#title' => t('Body of welcome e-mail'), '#default_value' => _user_mail_text('welcome_body'), '#rows' => 15, '#description' => t('Customize the body of the welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' !username, !site, !password, !uri, !uri_brief, !mailto, !login_uri, !edit_uri, !login_url.');
 
2298
  $form['email']['user_mail_admin_subject'] = array('#type' => 'textfield', '#title' => t('Subject of welcome e-mail (user created by administrator)'), '#default_value' => _user_mail_text('admin_subject'), '#maxlength' => 180, '#description' => t('Customize the subject of your welcome e-mail, which is sent to new member accounts created by an administrator.') .' '. t('Available variables are:') .' !username, !site, !password, !uri, !uri_brief, !mailto, !date, !login_uri, !edit_uri, !login_url.');
 
2299
  $form['email']['user_mail_admin_body'] = array('#type' => 'textarea', '#title' => t('Body of welcome e-mail (user created by administrator)'), '#default_value' => _user_mail_text('admin_body'), '#rows' => 15, '#description' => t('Customize the body of the welcome e-mail, which is sent to new member accounts created by an administrator.') .' '. t('Available variables are:') .' !username, !site, !password, !uri, !uri_brief, !mailto, !login_uri, !edit_uri, !login_url.');
 
2300
  $form['email']['user_mail_approval_subject'] = array('#type' => 'textfield', '#title' => t('Subject of welcome e-mail (awaiting admin approval)'), '#default_value' => _user_mail_text('approval_subject'), '#maxlength' => 180, '#description' => t('Customize the subject of your awaiting approval welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' !username, !site, !password, !uri, !uri_brief, !mailto, !date, !login_uri, !edit_uri, !login_url.');
 
2301
  $form['email']['user_mail_approval_body'] = array('#type' => 'textarea', '#title' => t('Body of welcome e-mail (awaiting admin approval)'), '#default_value' => _user_mail_text('approval_body'), '#rows' => 15, '#description' => t('Customize the body of the awaiting approval welcome e-mail, which is sent to new members upon registering.') .' '. t('Available variables are:') .' !username, !site, !password, !uri, !uri_brief, !mailto, !login_uri, !edit_uri, !login_url.');
 
2302
  $form['email']['user_mail_pass_subject'] = array('#type' => 'textfield', '#title' => t('Subject of password recovery e-mail'), '#default_value' => _user_mail_text('pass_subject'), '#maxlength' => 180, '#description' => t('Customize the subject of your forgotten password e-mail.') .' '. t('Available variables are:') .' !username, !site, !login_url, !uri, !uri_brief, !mailto, !date, !login_uri, !edit_uri.');
 
2303
  $form['email']['user_mail_pass_body'] = array('#type' => 'textarea', '#title' => t('Body of password recovery e-mail'), '#default_value' => _user_mail_text('pass_body'), '#rows' => 15, '#description' => t('Customize the body of the forgotten password e-mail.') .' '. t('Available variables are:') .' !username, !site, !login_url, !uri, !uri_brief, !mailto, !login_uri, !edit_uri.');
 
2304
 
 
2305
  // If picture support is enabled, check whether the picture directory exists:
 
2306
  if (variable_get('user_pictures', 0)) {
 
2307
    $picture_path = file_create_path(variable_get('user_picture_path', 'pictures'));
 
2308
    file_check_directory($picture_path, 1, 'user_picture_path');
 
2309
  }
 
2310
 
 
2311
  $form['pictures'] = array('#type' => 'fieldset', '#title' => t('Pictures'));
 
2312
  $form['pictures']['user_pictures'] = array('#type' => 'radios', '#title' => t('Picture support'), '#default_value' => variable_get('user_pictures', 0), '#options' => array(t('Disabled'), t('Enabled')), '#description' => t('Enable picture support.'));
 
2313
  $form['pictures']['user_picture_path'] = array('#type' => 'textfield', '#title' => t('Picture image path'), '#default_value' => variable_get('user_picture_path', 'pictures'), '#size' => 30, '#maxlength' => 255, '#description' => t('Subdirectory in the directory %dir where pictures will be stored.', array('%dir' => file_directory_path() .'/')));
 
2314
  $form['pictures']['user_picture_default'] = array('#type' => 'textfield', '#title' => t('Default picture'), '#default_value' => variable_get('user_picture_default', ''), '#size' => 30, '#maxlength' => 255, '#description' => t('URL of picture to display for users with no custom picture selected. Leave blank for none.'));
 
2315
  $form['pictures']['user_picture_dimensions'] = array('#type' => 'textfield', '#title' => t('Picture maximum dimensions'), '#default_value' => variable_get('user_picture_dimensions', '85x85'), '#size' => 15, '#maxlength' => 10, '#description' => t('Maximum dimensions for pictures, in pixels.'));
 
2316
  $form['pictures']['user_picture_file_size'] = array('#type' => 'textfield', '#title' => t('Picture maximum file size'), '#default_value' => variable_get('user_picture_file_size', '30'), '#size' => 15, '#maxlength' => 10, '#description' => t('Maximum file size for pictures, in kB.'));
 
2317
  $form['pictures']['user_picture_guidelines'] = array('#type' => 'textarea', '#title' => t('Picture guidelines'), '#default_value' => variable_get('user_picture_guidelines', ''), '#description' => t("This text is displayed at the picture upload form in addition to the default guidelines. It's useful for helping or instructing your users."));
 
2318
 
 
2319
  return system_settings_form($form);
 
2320
}
 
2321
 
 
2322
function user_admin($callback_arg = '') {
 
2323
  $op = isset($_POST['op']) ? $_POST['op'] : $callback_arg;
 
2324
 
 
2325
  switch ($op) {
 
2326
    case 'search':
 
2327
    case t('Search'):
 
2328
      $output = drupal_get_form('search_form', url('admin/user/search'), $_POST['keys'], 'user') . search_data($_POST['keys'], 'user');
 
2329
      break;
 
2330
    case t('Create new account'):
 
2331
    case 'create':
 
2332
      $output = drupal_get_form('user_register');
 
2333
      break;
 
2334
    default:
 
2335
      if ($_POST['accounts'] && $_POST['operation'] == 'delete') {
 
2336
        $output = drupal_get_form('user_multiple_delete_confirm');
 
2337
      }
 
2338
      else {
 
2339
        $output = drupal_get_form('user_filter_form');
 
2340
        $output .= drupal_get_form('user_admin_account');
 
2341
      }
 
2342
  }
 
2343
  return $output;
 
2344
}
 
2345
 
 
2346
/**
 
2347
 * Implementation of hook_help().
 
2348
 */
 
2349
function user_help($section) {
 
2350
  global $user;
 
2351
 
 
2352
  switch ($section) {
 
2353
    case 'admin/help#user':
 
2354
      $output = '<p>'. t('The user module allows users to register, login, and log out. Users benefit from being able to sign on because it associates content they create with their account and allows various permissions to be set for their roles. The user module supports user roles which can setup fine grained permissions allowing each role to do only what the administrator wants them to. Each user is assigned to one or more roles. By default there are two roles <em>anonymous</em> - a user who has not logged in, and <em>authenticated</em> a user who has signed up and who has been authorized.') .'</p>';
 
2355
      $output .= '<p>'. t('Users can use their own name or handle and can fine tune some personal configuration settings through their individual my account page. Registered users need to authenticate by supplying either a local username and password, or a remote username and password such as DelphiForums ID, or one from a Drupal powered website. A visitor accessing your website is assigned an unique ID, the so-called session ID, which is stored in a cookie. For security\'s sake, the cookie does not contain personal information but acts as a key to retrieve the information stored on your server.') .'</p>';
 
2356
      $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="@user">User page</a>.', array('@user' => 'http://drupal.org/handbook/modules/user/')) .'</p>';
 
2357
      return $output;
 
2358
    case 'admin/user/user':
 
2359
      return '<p>'. t('Drupal allows users to register, login, log out, maintain user profiles, etc. Users of the site may not use their own names to post content until they have signed up for a user account.') .'</p>';
 
2360
    case 'admin/user/user/create':
 
2361
    case 'admin/user/user/account/create':
 
2362
      return '<p>'. t('This web page allows the administrators to register a new users by hand. Note that you cannot have a user where either the e-mail address or the username match another user in the system.') .'</p>';
 
2363
    case 'admin/user/rules':
 
2364
      return '<p>'. t('Set up username and e-mail address access rules for new <em>and</em> existing accounts (currently logged in accounts will not be logged out). If a username or e-mail address for an account matches any deny rule, but not an allow rule, then the account will not be allowed to be created or to log in. A host rule is effective for every page view, not just registrations.') .'</p>';
 
2365
    case 'admin/user/access':
 
2366
      return '<p>'. t('Permissions let you control what users can do on your site. Each user role (defined on the <a href="@role">user roles page</a>) has its own set of permissions. For example, you could give users classified as "Administrators" permission to "administer nodes" but deny this power to ordinary, "authenticated" users. You can use permissions to reveal new features to privileged users (those with subscriptions, for example). Permissions also allow trusted users to share the administrative burden of running a busy site.', array('@role' => url('admin/user/roles'))) .'</p>';
 
2367
    case 'admin/user/roles':
 
2368
      return t('<p>Roles allow you to fine tune the security and administration of Drupal. A role defines a group of users that have certain privileges as defined in <a href="@permissions">user permissions</a>. Examples of roles include: anonymous user, authenticated user, moderator, administrator and so on. In this area you will define the <em>role names</em> of the various roles. To delete a role choose "edit".</p><p>By default, Drupal comes with two user roles:</p>
 
2369
      <ul>
 
2370
      <li>Anonymous user: this role is used for users that don\'t have a user account or that are not authenticated.</li>
 
2371
      <li>Authenticated user: this role is automatically granted to all logged in users.</li>
 
2372
      </ul>', array('@permissions' => url('admin/user/access')));
 
2373
    case 'admin/user/search':
 
2374
      return '<p>'. t('Enter a simple pattern ("*" may be used as a wildcard match) to search for a username. For example, one may search for "br" and Drupal might return "brian", "brad", and "brenda".') .'</p>';
 
2375
    case 'user/help#user':
 
2376
      $site = variable_get('site_name', 'Drupal');
 
2377
 
 
2378
      $affiliates = user_auth_help_links();
 
2379
      if (count($affiliates)) {
 
2380
        $affiliate_info = implode(', ', user_auth_help_links());
 
2381
      }
 
2382
      else {
 
2383
        $affiliate_info = t('one of our affiliates');
 
2384
      }
 
2385
 
 
2386
      $output = t('
 
2387
      <h3>Distributed authentication<a id="da"></a></h3>
 
2388
      <p>One of the more tedious moments in visiting a new website is filling out the registration form. Here at @site, you do not have to fill out a registration form if you are already a member of !affiliate-info. This capability is called <em>distributed authentication</em>, and <a href="@drupal">Drupal</a>, the software which powers @site, fully supports it.</p>
 
2389
      <p>Distributed authentication enables a new user to input a username and password into the login box, and immediately be recognized, even if that user never registered at @site. This works because Drupal knows how to communicate with external registration databases. For example, lets say that new user \'Joe\' is already a registered member of <a href="@delphi-forums">Delphi Forums</a>. Drupal informs Joe on registration and login screens that he may login with his Delphi ID instead of registering with @site. Joe likes that idea, and logs in with a username of joe@remote.delphiforums.com and his usual Delphi password. Drupal then contacts the <em>remote.delphiforums.com</em> server behind the scenes (usually using <a href="@xml">XML-RPC</a>, <a href="@http-post">HTTP POST</a>, or <a href="@soap">SOAP</a>) and asks: "Is the password for user Joe correct?". If Delphi replies yes, then we create a new @site account for Joe and log him into it. Joe may keep on logging into @site in the same manner, and he will always be logged into the same account.</p>', array('!affiliate-info' => $affiliate_info, '@site' => $site, '@drupal' => 'http://drupal.org', '@delphi-forums' => 'http://www.delphiforums.com', '@xml' => 'http://www.xmlrpc.com', '@http-post' => 'http://www.w3.org/Protocols/', '@soap' => 'http://www.soapware.org'));
 
2390
 
 
2391
        foreach (module_list() as $module) {
 
2392
          if (module_hook($module, 'auth')) {
 
2393
            $output .= "<h4><a id=\"$module\"></a>". module_invoke($module, 'info', 'name') .'</h4>';
 
2394
            $output .= module_invoke($module, 'help', "user/help#$module");
 
2395
          }
 
2396
        }
 
2397
 
 
2398
        return $output;
 
2399
  }
 
2400
 
 
2401
}
 
2402
 
 
2403
/**
 
2404
 * Menu callback; Prints user-specific help information.
 
2405
 */
 
2406
function user_help_page() {
 
2407
  return user_help('user/help#user');
 
2408
}
 
2409
 
 
2410
/**
 
2411
 * Retrieve a list of all user setting/information categories and sort them by weight.
 
2412
 */
 
2413
function _user_categories($account) {
 
2414
  $categories = array();
 
2415
 
 
2416
  foreach (module_list() as $module) {
 
2417
    if ($data = module_invoke($module, 'user', 'categories', NULL, $account, '')) {
 
2418
      $categories = array_merge($data, $categories);
 
2419
    }
 
2420
  }
 
2421
 
 
2422
  usort($categories, '_user_sort');
 
2423
 
 
2424
  return $categories;
 
2425
}
 
2426
 
 
2427
function _user_sort($a, $b) {
 
2428
  return $a['weight'] < $b['weight'] ? -1 : ($a['weight'] > $b['weight'] ? 1 : ($a['title'] < $b['title'] ? -1 : 1));
 
2429
}
 
2430
 
 
2431
/**
 
2432
 * Retrieve a list of all form elements for the specified category.
 
2433
 */
 
2434
function _user_forms(&$edit, $account, $category, $hook = 'form') {
 
2435
  $groups = array();
 
2436
  foreach (module_list() as $module) {
 
2437
    if ($data = module_invoke($module, 'user', $hook, $edit, $account, $category)) {
 
2438
      $groups = array_merge_recursive($data, $groups);
 
2439
    }
 
2440
  }
 
2441
  uasort($groups, '_user_sort');
 
2442
 
 
2443
  return empty($groups) ? FALSE : $groups;
 
2444
}
 
2445
 
 
2446
/**
 
2447
 * Retrieve a pipe delimited string of autocomplete suggestions for existing users
 
2448
 */
 
2449
function user_autocomplete($string = '') {
 
2450
  $matches = array();
 
2451
  if ($string) {
 
2452
    $result = db_query_range("SELECT name FROM {users} WHERE LOWER(name) LIKE LOWER('%s%%')", $string, 0, 10);
 
2453
    while ($user = db_fetch_object($result)) {
 
2454
      $matches[$user->name] = check_plain($user->name);
 
2455
   }
 
2456
  }
 
2457
  print drupal_to_js($matches);
 
2458
  exit();
 
2459
}
 
2460
 
 
2461
/**
 
2462
 * List user administration filters that can be applied.
 
2463
 */
 
2464
function user_filters() {
 
2465
  // Regular filters
 
2466
  $filters = array();
 
2467
  $roles = user_roles(1);
 
2468
  unset($roles[DRUPAL_AUTHENTICATED_RID]); // Don't list authorized role.
 
2469
  if (count($roles)) {
 
2470
    $filters['role'] = array('title' => t('role'),
 
2471
                         'where' => "ur.rid = %d",
 
2472
                         'options' => $roles,
 
2473
                       );
 
2474
  }
 
2475
 
 
2476
  $options = array();
 
2477
  $t_module = t('module');
 
2478
  foreach (module_list() as $module) {
 
2479
    if ($permissions = module_invoke($module, 'perm')) {
 
2480
      asort($permissions);
 
2481
      foreach ($permissions as $permission) {
 
2482
        $options["$module $t_module"][$permission] = t($permission);
 
2483
      }
 
2484
    }
 
2485
  }
 
2486
  ksort($options);
 
2487
  $filters['permission'] = array('title' => t('permission'),
 
2488
                             'join' => 'LEFT JOIN {permission} p ON ur.rid = p.rid',
 
2489
                             'where' => " ((p.perm IS NOT NULL AND p.perm LIKE '%%%s%%') OR u.uid = 1) ",
 
2490
                             'options' => $options,
 
2491
                           );
 
2492
 
 
2493
  $filters['status'] = array('title' => t('status'),
 
2494
                         'where' => 'u.status = %d',
 
2495
                         'options' => array(1 => t('active'), 0 => t('blocked')),
 
2496
                       );
 
2497
  return $filters;
 
2498
}
 
2499
 
 
2500
/**
 
2501
 * Build query for user administration filters based on session.
 
2502
 */
 
2503
function user_build_filter_query() {
 
2504
  $filters = user_filters();
 
2505
 
 
2506
  // Build query
 
2507
  $where = $args = $join = array();
 
2508
  foreach ($_SESSION['user_overview_filter'] as $filter) {
 
2509
    list($key, $value) = $filter;
 
2510
    // This checks to see if this permission filter is an enabled permission for the authenticated role.
 
2511
    // If so, then all users would be listed, and we can skip adding it to the filter query.
 
2512
    if ($key == 'permission') {
 
2513
      $account = new stdClass();
 
2514
      $account->uid = 'user_filter';
 
2515
      $account->roles = array(DRUPAL_AUTHENTICATED_RID => 1);
 
2516
      if (user_access($value, $account)) {
 
2517
        continue;
 
2518
      }
 
2519
    }
 
2520
    $where[] = $filters[$key]['where'];
 
2521
    $args[] = $value;
 
2522
    $join[] = $filters[$key]['join'];
 
2523
  }
 
2524
  $where = count($where) ? 'AND '. implode(' AND ', $where) : '';
 
2525
  $join = count($join) ? ' '. implode(' ', array_unique($join)) : '';
 
2526
 
 
2527
  return array('where' => $where,
 
2528
           'join' => $join,
 
2529
           'args' => $args,
 
2530
         );
 
2531
}
 
2532
 
 
2533
/**
 
2534
 * Return form for user administration filters.
 
2535
 */
 
2536
function user_filter_form() {
 
2537
  $session = &$_SESSION['user_overview_filter'];
 
2538
  $session = is_array($session) ? $session : array();
 
2539
  $filters = user_filters();
 
2540
 
 
2541
  $i = 0;
 
2542
  $form['filters'] = array('#type' => 'fieldset',
 
2543
                       '#title' => t('Show only users where'),
 
2544
                       '#theme' => 'user_filters',
 
2545
                     );
 
2546
  foreach ($session as $filter) {
 
2547
    list($type, $value) = $filter;
 
2548
    $string = ($i++ ? '<em>and</em> where <strong>%a</strong> is <strong>%b</strong>' : '<strong>%a</strong> is <strong>%b</strong>');
 
2549
    // Merge an array of arrays into one if necessary.
 
2550
    $options = $type == 'permission' ? call_user_func_array('array_merge', $filters[$type]['options']) : $filters[$type]['options'];
 
2551
    $form['filters']['current'][] = array('#value' => t($string, array('%a' => $filters[$type]['title'] , '%b' => $options[$value])));
 
2552
  }
 
2553
 
 
2554
  foreach ($filters as $key => $filter) {
 
2555
    $names[$key] = $filter['title'];
 
2556
    $form['filters']['status'][$key] = array('#type' => 'select',
 
2557
                                         '#options' => $filter['options'],
 
2558
                                       );
 
2559
  }
 
2560
 
 
2561
  $form['filters']['filter'] = array('#type' => 'radios',
 
2562
                                 '#options' => $names,
 
2563
                               );
 
2564
  $form['filters']['buttons']['submit'] = array('#type' => 'submit',
 
2565
                                            '#value' => (count($session) ? t('Refine') : t('Filter'))
 
2566
                                          );
 
2567
  if (count($session)) {
 
2568
    $form['filters']['buttons']['undo'] = array('#type' => 'submit',
 
2569
                                            '#value' => t('Undo')
 
2570
                                          );
 
2571
    $form['filters']['buttons']['reset'] = array('#type' => 'submit',
 
2572
                                             '#value' => t('Reset')
 
2573
                                           );
 
2574
  }
 
2575
 
 
2576
  return $form;
 
2577
}
 
2578
 
 
2579
/**
 
2580
 * Theme user administration filter form.
 
2581
 */
 
2582
function theme_user_filter_form($form) {
 
2583
  $output = '<div id="user-admin-filter">';
 
2584
  $output .= drupal_render($form['filters']);
 
2585
  $output .= '</div>';
 
2586
  $output .= drupal_render($form);
 
2587
  return $output;
 
2588
}
 
2589
 
 
2590
/**
 
2591
 * Theme user administration filter selector.
 
2592
 */
 
2593
function theme_user_filters($form) {
 
2594
  $output = '<ul class="clear-block">';
 
2595
  if (sizeof($form['current'])) {
 
2596
    foreach (element_children($form['current']) as $key) {
 
2597
      $output .= '<li>'. drupal_render($form['current'][$key]) .'</li>';
 
2598
    }
 
2599
  }
 
2600
 
 
2601
  $output .= '<li><dl class="multiselect">'. (sizeof($form['current']) ? '<dt><em>'. t('and') .'</em> '. t('where') .'</dt>' : '') .'<dd class="a">';
 
2602
  foreach (element_children($form['filter']) as $key) {
 
2603
    $output .= drupal_render($form['filter'][$key]);
 
2604
  }
 
2605
  $output .= '</dd>';
 
2606
 
 
2607
  $output .= '<dt>'. t('is') .'</dt><dd class="b">';
 
2608
 
 
2609
  foreach (element_children($form['status']) as $key) {
 
2610
    $output .= drupal_render($form['status'][$key]);
 
2611
  }
 
2612
  $output .= '</dd>';
 
2613
 
 
2614
  $output .= '</dl>';
 
2615
  $output .= '<div class="container-inline" id="user-admin-buttons">'. drupal_render($form['buttons']) .'</div>';
 
2616
  $output .= '</li></ul>';
 
2617
 
 
2618
  return $output;
 
2619
}
 
2620
 
 
2621
/**
 
2622
 * Process result from user administration filter form.
 
2623
 */
 
2624
function user_filter_form_submit($form_id, $form_values) {
 
2625
  $op = $form_values['op'];
 
2626
  $filters = user_filters();
 
2627
  switch ($op) {
 
2628
    case t('Filter'): case t('Refine'):
 
2629
      if (isset($form_values['filter'])) {
 
2630
        $filter = $form_values['filter'];
 
2631
        // Merge an array of arrays into one if necessary.
 
2632
        $options = $filter == 'permission' ? call_user_func_array('array_merge', $filters[$filter]['options']) : $filters[$filter]['options'];
 
2633
        if (isset($options[$form_values[$filter]])) {
 
2634
          $_SESSION['user_overview_filter'][] = array($filter, $form_values[$filter]);
 
2635
        }
 
2636
      }
 
2637
      break;
 
2638
    case t('Undo'):
 
2639
      array_pop($_SESSION['user_overview_filter']);
 
2640
      break;
 
2641
    case t('Reset'):
 
2642
      $_SESSION['user_overview_filter'] = array();
 
2643
      break;
 
2644
    case t('Update'):
 
2645
      return;
 
2646
  }
 
2647
 
 
2648
  return 'admin/user/user';
 
2649
}
 
2650
 
 
2651
 
 
2652
function user_forms() {
 
2653
  $forms['user_admin_access_add_form']['callback'] = 'user_admin_access_form';
 
2654
  $forms['user_admin_access_edit_form']['callback'] = 'user_admin_access_form';
 
2655
  $forms['user_admin_new_role']['callback'] = 'user_admin_role';
 
2656
  return $forms;
 
2657
}
 
2658