Code coverage for /20081101/modules/system/system.module

Line #Times calledCode
1
<?php
2
// $Id: system.module,v 1.635 2008/10/31 02:18:22 dries Exp $
3
4
/**
5
 * @file
6
 * Configuration system that lets administrators modify the workings of the
site.
7
 */
8
9
/**
10
 * The current system version.
11
 */
122366
define('VERSION', '7.0-dev');
13
14
/**
15
 * Core API compatibility.
16
 */
172366
define('DRUPAL_CORE_COMPATIBILITY', '7.x');
18
19
/**
20
 * Minimum supported version of PHP.
21
 */
222366
define('DRUPAL_MINIMUM_PHP',    '5.2.0');
23
24
/**
25
 * Minimum recommended value of PHP memory_limit.
26
 */
272366
define('DRUPAL_MINIMUM_PHP_MEMORY_LIMIT',    '16M');
28
29
/**
30
 * Minimum supported version of MySQL, if it is used.
31
 */
322366
define('DRUPAL_MINIMUM_MYSQL',  '5.0');
33
34
/**
35
 * Minimum supported version of PostgreSQL, if it is used.
36
 */
372366
define('DRUPAL_MINIMUM_PGSQL',  '8.1');
38
39
/**
40
 * Maximum age of temporary files in seconds.
41
 */
422366
define('DRUPAL_MAXIMUM_TEMP_FILE_AGE', 21600);
43
44
/**
45
 * Implementation of hook_help().
46
 */
472366
function system_help($path, $arg) {
481676
  global $base_url;
49
50
  switch ($path) {
511676
    case 'admin/help#system':
521
      $output = '<p>' . t('The system module is at the foundation of your
Drupal website, and provides basic but extensible functionality for use by
other modules and themes. Some integral elements of Drupal are contained in
and managed by the system module, including caching, enabling or disabling
of modules and themes, preparing and displaying the administrative page,
and configuring fundamental site settings. A number of key system
maintenance operations are also part of the system module.') . '</p>';
531
      $output .= '<p>' . t('The system module provides:') . '</p>';
541
      $output .= '<ul><li>' . t('support for enabling and disabling <a
href="@modules">modules</a>. Drupal comes packaged with a number of core
modules; each module provides a discrete set of features and may be enabled
depending on the needs of your site. A wide array of additional modules
contributed by members of the Drupal community are available for download
at the <a href="@drupal-modules">Drupal.org module page</a>.',
array('@modules' => url('admin/build/modules'), '@drupal-modules' =>
'http://drupal.org/project/modules')) . '</li>';
551
      $output .= '<li>' . t('support for enabling and disabling <a
href="@themes">themes</a>, which determine the design and presentation of
your site. Drupal comes packaged with several core themes and additional
contributed themes are available at the <a href="@drupal-themes">Drupal.org
theme page</a>.', array('@themes' => url('admin/build/themes'),
'@drupal-themes' => 'http://drupal.org/project/themes')) . '</li>';
561
      $output .= '<li>' . t('a robust <a href="@cache-settings">caching
system</a> that allows the efficient re-use of previously-constructed web
pages and web page components. Drupal stores the pages requested by
anonymous users in a compressed format; depending on your site
configuration and the amount of your web traffic tied to anonymous
visitors, Drupal\'s caching system may significantly increase the speed of
your site.', array('@cache-settings' => url('admin/settings/performance')))
. '</li>';
571
      $output .= '<li>' . t('a set of routine administrative operations
that rely on a correctly-configured <a href="@cron">cron maintenance
task</a> to run automatically. A number of other modules, including the
feed aggregator, and search also rely on <a href="@cron">cron maintenance
tasks</a>. For more information, see the online handbook entry for <a
href="@handbook">configuring cron jobs</a>.', array('@cron' =>
url('admin/reports/status'), '@handbook' => 'http://drupal.org/cron')) .
'</li>';
581
      $output .= '<li>' . t('basic configuration options for your site,
including <a href="@date-settings">date and time settings</a>, <a
href="@file-system">file system settings</a>, <a href="@clean-url">clean
URL support</a>, <a href="@site-info">site name and other information</a>,
and a <a href="@site-maintenance">site maintenance</a> function for taking
your site temporarily offline.', array('@date-settings' =>
url('admin/settings/date-time'), '@file-system' =>
url('admin/settings/file-system'), '@clean-url' =>
url('admin/settings/clean-urls'), '@site-info' =>
url('admin/settings/site-information'), '@site-maintenance' =>
url('admin/settings/site-maintenance'))) . '</li></ul>';
591
      $output .= '<p>' . t('For more information, see the online handbook
entry for <a href="@system">System module</a>.', array('@system' =>
'http://drupal.org/handbook/modules/system/')) . '</p>';
601
      return $output;
611676
    case 'admin':
622
      return '<p>' . t('Welcome to the administration section. Here you may
control how your site functions.') . '</p>';
631676
    case 'admin/by-module':
642
      return '<p>' . t('This page shows you all available administration
tasks for each module.') . '</p>';
651676
    case 'admin/build/themes':
662
      $output = '<p>' . t('Select which themes are available to your users
and specify the default theme. To configure site-wide display settings,
click the "configure" task above. Alternatively, to override these settings
in a specific theme, click the "configure" link for that theme. Note that
different themes may have different regions available for displaying
content; for consistency in presentation, you may wish to enable only one
theme.') . '</p>';
672
      $output .= '<p>' . t('To change the appearance of your site, a number
of <a href="@themes">contributed themes</a> are available.',
array('@themes' => 'http://drupal.org/project/themes')) . '</p>';
682
      return $output;
691676
    case 'admin/build/themes/settings/' . $arg[4]:
700
      $reference = explode('.', $arg[4], 2);
710
      $theme = array_pop($reference);
720
      return '<p>' . t('These options control the display settings for the
<code>%template</code> theme. When your site is displayed using this theme,
these settings will be used. By clicking "Reset to defaults," you can
choose to use the <a href="@global">global settings</a> for this theme.',
array('%template' => $theme, '@global' =>
url('admin/build/themes/settings'))) . '</p>';
731676
    case 'admin/build/themes/settings':
740
      return '<p>' . t('These options control the default display settings
for your entire site, across all themes. Unless they have been overridden
by a specific theme, these settings will be used.') . '</p>';
751676
    case 'admin/build/modules':
768
      $output = '<p>' . t('Modules are plugins that extend Drupal\'s core
functionality. Enable modules by selecting the <em>Enabled</em> checkboxes
below and clicking the <em>Save configuration</em> button. Once a module is
enabled, new <a href="@permissions">permissions</a> may be available.)',
array('@permissions' => url('admin/user/permissions'))) . '</p>';
778
      $output .= '<p>' . t('It is important that <a
href="@update-php">update.php</a> is run every time a module is updated to
a newer version.', array('@update-php' => $base_url . '/update.php')) .
'</p>';
788
      $output .= '<p>' . t('You can find all administration tasks belonging
to a particular module on the <a href="@by-module">administration by module
page</a>.', array('@by-module' => url('admin/by-module'))) . '</p>';
798
      $output .= '<p>' . t('To extend the functionality of your site, a
number of <a href="@modules">contributed modules</a> are available.',
array('@modules' => 'http://drupal.org/project/modules')) . '</p>';
808
      return $output;
811676
    case 'admin/build/modules/uninstall':
822
      return '<p>' . t('The uninstall process removes all data related to a
module. To uninstall a module, you must first disable it. Not all modules
support this feature.') . '</p>';
831676
    case 'admin/build/block/configure':
842
      if ($arg[4] == 'system' && $arg[5] == 0) {
850
        return '<p>' . t('The <em>Powered by Drupal</em> block is an
optional link to the home page of the Drupal project. While there is
absolutely no requirement that sites feature this link, it may be used to
show support for Drupal.') . '</p>';
860
      }
872
      break;
881676
    case 'admin/settings/actions':
891676
    case 'admin/settings/actions/manage':
905
      $output = '<p>' . t('Actions are individual tasks that the system can
do, such as unpublishing a piece of content or banning a user. Modules,
such as the trigger module, can fire these actions when certain system
events happen; for example, when a new post is added or when a user logs
in. Modules may also provide additional actions.') . '</p>';
915
      $output .= '<p>' . t('There are two types of actions: simple and
advanced. Simple actions do not require any additional configuration, and
are listed here automatically. Advanced actions can do more than simple
actions; for example, send an e-mail to a specified address, or check for
certain words within a piece of content. These actions need to be created
and configured first before they may be used. To create an advanced action,
select the action from the drop-down below and click the <em>Create</em>
button.') . '</p>';
925
      if (module_exists('trigger')) {
930
        $output .= '<p>' . t('You may proceed to the <a
href="@url">Triggers</a> page to assign these actions to system events.',
array('@url' => url('admin/build/trigger'))) . '</p>';
940
      }
955
      return $output;
961676
    case 'admin/settings/actions/configure':
974
      return t('An advanced action offers additional configuration options
which may be filled out below. Changing the <em>Description</em> field is
recommended, in order to better identify the precise action taking place.
This description will be displayed in modules such as the trigger module
when assigning actions to system events, so it is best if it is as
descriptive as possible (for example, "Send e-mail to Moderation Team"
rather than simply "Send e-mail").');
981676
    case 'admin/settings/ip-blocking':
9914
      return '<p>' . t('IP addresses listed here are blocked from your site
before any modules are loaded. You may add IP addresses to the list, or
delete existing entries.') . '</p>';
1001676
    case 'admin/reports/status':
1011
      return '<p>' . t("Here you can find a short overview of your site's
parameters as well as any problems detected with your installation. It may
be useful to copy and paste this information into support requests filed on
drupal.org's support forums and project issue queues.") . '</p>';
1020
  }
1031676
}
104
105
/**
106
 * Implementation of hook_theme().
107
 */
1082366
function system_theme() {
109178
  return array_merge(drupal_common_theme(), array(
110
    'system_theme_select_form' => array(
111178
      'arguments' => array('form' => NULL),
112178
      'file' => 'system.admin.inc',
113178
    ),
114
    'system_themes_form' => array(
115178
      'arguments' => array('form' => NULL),
116178
      'file' => 'system.admin.inc',
117178
    ),
118
    'system_modules_fieldset' => array(
119178
      'arguments' => array('form' => NULL),
120178
      'file' => 'system.admin.inc',
121178
    ),
122
    'system_modules_incompatible' => array(
123178
      'arguments' => array('message' => NULL),
124178
      'file' => 'system.admin.inc',
125178
    ),
126
    'system_modules_uninstall' => array(
127178
      'arguments' => array('form' => NULL),
128178
      'file' => 'system.admin.inc',
129178
    ),
130
    'status_report' => array(
131178
      'arguments' => array('requirements' => NULL),
132178
      'file' => 'system.admin.inc',
133178
    ),
134
    'admin_page' => array(
135178
      'arguments' => array('blocks' => NULL),
136178
      'file' => 'system.admin.inc',
137178
    ),
138
    'admin_block' => array(
139178
      'arguments' => array('block' => NULL),
140178
      'file' => 'system.admin.inc',
141178
    ),
142
    'admin_block_content' => array(
143178
      'arguments' => array('content' => NULL),
144178
      'file' => 'system.admin.inc',
145178
    ),
146
    'system_admin_by_module' => array(
147178
      'arguments' => array('menu_items' => NULL),
148178
      'file' => 'system.admin.inc',
149178
    ),
150
    'system_powered_by' => array(
151178
      'arguments' => array('image_path' => NULL),
152178
    ),
153
    'meta_generator_html' => array(
154178
      'arguments' => array('version' => NULL),
155178
    ),
156
    'meta_generator_header' => array(
157178
      'arguments' => array('version' => NULL),
158178
    ),
159178
    'system_compact_link' => array(),
160178
  ));
1610
}
162
163
/**
164
 * Implementation of hook_perm().
165
 */
1662366
function system_perm() {
167
  return array(
168
    'administer site configuration' => array(
169172
      'title' => t('Administer site configuration'),
170172
      'description' => t('Configure site-wide settings such as module or
theme administration settings.'),
171172
    ),
172
    'administer actions' => array(
173172
      'title' => t('Administer actions'),
174172
      'description' => t('Manage the actions defined for your site.'),
175172
    ),
176
    'administer files' => array(
177172
      'title' => t('Administer files'),
178172
      'description' => t('Manage user-uploaded files.'),
179172
    ),
180
    'access administration pages' => array(
181172
      'title' => t('Access administration pages'),
182172
      'description' => t('View the administration panel and browse the help
system.'),
183172
    ),
184
    'access site reports' => array(
185172
      'title' => t('Access site reports'),
186172
      'description' => t('View reports from system logs and other status
information.'),
187172
    ),
188
    'select different theme' => array(
189172
      'title' => t('Select different theme'),
190172
      'description' => t('Select a theme other than the default theme set
by the site administrator.'),
191172
    ),
192
    'block IP addresses' => array(
193172
      'title' => t('Block IP addresses'),
194172
      'description' => t('Block IP addresses from accessing your site.'),
195172
    ),
196172
  );
1970
}
198
199
/**
200
 * Implementation of hook_elements().
201
 */
2022366
function system_elements() {
203
  // Top level form
2041837
  $type['form'] = array(
2051837
    '#method' => 'post',
2061837
    '#action' => request_uri(),
207
  );
208
209
  /**
210
   * Input elements.
211
   */
2121837
  $type['submit'] = array(
2131837
    '#input' => TRUE,
2141837
    '#name' => 'op',
2151837
    '#button_type' => 'submit',
2161837
    '#executes_submit_callback' => TRUE,
2171837
    '#process' => array('form_process_ahah'),
218
  );
219
2201837
  $type['button'] = array(
2211837
    '#input' => TRUE,
2221837
    '#name' => 'op',
2231837
    '#button_type' => 'submit',
2241837
    '#executes_submit_callback' => FALSE,
2251837
    '#process' => array('form_process_ahah'),
226
  );
227
2281837
  $type['image_button'] = array(
2291837
    '#input' => TRUE,
2301837
    '#button_type' => 'submit',
2311837
    '#executes_submit_callback' => TRUE,
2321837
    '#process' => array('form_process_ahah'),
2331837
    '#return_value' => TRUE,
2341837
    '#has_garbage_value' => TRUE,
2351837
    '#src' => NULL,
236
  );
237
2381837
  $type['textfield'] = array(
2391837
    '#input' => TRUE,
2401837
    '#size' => 60,
2411837
    '#maxlength' => 128,
2421837
    '#autocomplete_path' => FALSE,
2431837
    '#process' => array('form_process_input_format', 'form_process_ahah'),
244
  );
245
2461837
  $type['password'] = array(
2471837
    '#input' => TRUE,
2481837
    '#size' => 60,
2491837
    '#maxlength' => 128,
2501837
    '#process' => array('form_process_ahah'),
251
  );
252
2531837
  $type['password_confirm'] = array(
2541837
    '#input' => TRUE,
2551837
    '#process' => array('form_process_password_confirm'),
256
  );
257
2581837
  $type['textarea'] = array(
2591837
    '#input' => TRUE,
2601837
    '#cols' => 60,
2611837
    '#rows' => 5,
2621837
    '#resizable' => TRUE,
2631837
    '#process' => array('form_process_input_format', 'form_process_ahah'),
264
  );
265
2661837
  $type['radios'] = array(
2671837
    '#input' => TRUE,
2681837
    '#process' => array('form_process_radios'),
269
  );
270
2711837
  $type['radio'] = array(
2721837
    '#input' => TRUE,
2731837
    '#default_value' => NULL,
2741837
    '#process' => array('form_process_ahah'),
275
  );
276
2771837
  $type['checkboxes'] = array(
2781837
    '#input' => TRUE,
2791837
    '#tree' => TRUE,
2801837
    '#process' => array('form_process_checkboxes'),
281
  );
282
2831837
  $type['checkbox'] = array(
2841837
    '#input' => TRUE,
2851837
    '#return_value' => 1,
2861837
    '#process' => array('form_process_ahah'),
287
  );
288
2891837
  $type['select'] = array(
2901837
    '#input' => TRUE,
2911837
    '#size' => 0,
2921837
    '#multiple' => FALSE,
2931837
    '#process' => array('form_process_ahah'),
294
  );
295
2961837
  $type['weight'] = array(
2971837
    '#input' => TRUE,
2981837
    '#delta' => 10,
2991837
    '#default_value' => 0,
3001837
    '#process' => array('form_process_weight', 'form_process_ahah'),
301
  );
302
3031837
  $type['date'] = array(
3041837
    '#input' => TRUE,
3051837
    '#element_validate' => array('date_validate'),
3061837
    '#process' => array('form_process_date'),
307
  );
308
3091837
  $type['file'] = array(
3101837
    '#input' => TRUE,
3111837
    '#size' => 60,
312
  );
313
314
315
  /**
316
   * Form structure.
317
   */
3181837
  $type['item'] = array(
3191837
    '#markup' => '',
320
  );
321
3221837
  $type['hidden'] = array(
3231837
    '#input' => TRUE,
3241837
    '#process' => array('form_process_ahah'),
325
  );
326
3271837
  $type['value'] = array(
3281837
    '#input' => TRUE,
329
  );
330
3311837
  $type['markup'] = array(
3321837
    '#prefix' => '',
3331837
    '#suffix' => '',
334
  );
335
3361837
  $type['fieldset'] = array(
3371837
    '#collapsible' => FALSE,
3381837
    '#collapsed' => FALSE,
3391837
    '#value' => NULL,
3401837
    '#process' => array('form_process_ahah'),
341
  );
342
3431837
  $type['token'] = array(
3441837
    '#input' => TRUE,
345
  );
346
3471837
  return $type;
3480
}
349
350
/**
351
 * Implementation of hook_menu().
352
 */
3532366
function system_menu() {
354161
  $items['system/files'] = array(
355161
    'title' => 'File download',
356161
    'page callback' => 'file_download',
357161
    'access callback' => TRUE,
358161
    'type' => MENU_CALLBACK,
359
  );
360161
  $items['admin'] = array(
361161
    'title' => 'Administer',
362161
    'access arguments' => array('access administration pages'),
363161
    'page callback' => 'system_main_admin_page',
364161
    'weight' => 9,
365
  );
366161
  $items['admin/compact'] = array(
367161
    'title' => 'Compact mode',
368161
    'page callback' => 'system_admin_compact_page',
369161
    'access arguments' => array('access administration pages'),
370161
    'type' => MENU_CALLBACK,
371
  );
372161
  $items['admin/by-task'] = array(
373161
    'title' => 'By task',
374161
    'page callback' => 'system_main_admin_page',
375161
    'access arguments' => array('access administration pages'),
376161
    'type' => MENU_DEFAULT_LOCAL_TASK,
377
  );
378161
  $items['admin/by-module'] = array(
379161
    'title' => 'By module',
380161
    'page callback' => 'system_admin_by_module',
381161
    'access arguments' => array('access administration pages'),
382161
    'type' => MENU_LOCAL_TASK,
383161
    'weight' => 2,
384
  );
385161
  $items['admin/content'] = array(
386161
    'title' => 'Content management',
387161
    'description' => "Manage your site's content.",
388161
    'position' => 'left',
389161
    'weight' => -10,
390161
    'page callback' => 'system_admin_menu_block_page',
391161
    'access arguments' => array('access administration pages'),
392
  );
393
394
  // menu items that are basically just menu blocks
395161
  $items['admin/settings'] = array(
396161
    'title' => 'Site configuration',
397161
    'description' => 'Configure site settings.',
398161
    'position' => 'right',
399161
    'weight' => -5,
400161
    'page callback' => 'system_settings_overview',
401161
    'access arguments' => array('access administration pages'),
402
  );
403161
  $items['admin/build'] = array(
404161
    'title' => 'Site building',
405161
    'description' => 'Control how your site looks and feels.',
406161
    'position' => 'right',
407161
    'weight' => -10,
408161
    'page callback' => 'system_admin_menu_block_page',
409161
    'access arguments' => array('access administration pages'),
410
  );
411161
  $items['admin/settings/admin'] = array(
412161
    'title' => 'Administration theme',
413161
    'description' => 'Settings for how your administrative pages should
look.',
414161
    'position' => 'left',
415161
    'page callback' => 'drupal_get_form',
416161
    'page arguments' => array('system_admin_theme_settings'),
417161
    'access arguments' => array('administer site configuration'),
418161
    'block callback' => 'system_admin_theme_settings',
419
  );
420
  // Themes:
421161
  $items['admin/build/themes'] = array(
422161
    'title' => 'Themes',
423161
    'description' => 'Change which theme your site uses or allows users to
set.',
424161
    'page callback' => 'drupal_get_form',
425161
    'page arguments' => array('system_themes_form', NULL),
426161
    'access arguments' => array('administer site configuration'),
427
  );
428161
  $items['admin/build/themes/select'] = array(
429161
    'title' => 'List',
430161
    'description' => 'Select the default theme.',
431161
    'type' => MENU_DEFAULT_LOCAL_TASK,
432161
    'weight' => -1,
433
  );
434161
  $items['admin/build/themes/settings'] = array(
435161
    'title' => 'Configure',
436161
    'page arguments' => array('system_theme_settings'),
437161
    'access arguments' => array('administer site configuration'),
438161
    'type' => MENU_LOCAL_TASK,
439
  );
440
  // Theme configuration subtabs
441161
  $items['admin/build/themes/settings/global'] = array(
442161
    'title' => 'Global settings',
443161
    'type' => MENU_DEFAULT_LOCAL_TASK,
444161
    'weight' => -1,
445
  );
446
447161
  foreach (list_themes() as $theme) {
448161
    $items['admin/build/themes/settings/' . $theme->name] = array(
449161
      'title' => $theme->info['name'],
450161
      'page arguments' => array('system_theme_settings', $theme->name),
451161
      'type' => MENU_LOCAL_TASK,
452161
      'access callback' => '_system_themes_access',
453161
      'access arguments' => array($theme),
454
    );
455161
  }
456
457
  // Modules:
458161
  $items['admin/build/modules'] = array(
459161
    'title' => 'Modules',
460161
    'description' => 'Enable or disable add-on modules for your site.',
461161
    'page callback' => 'drupal_get_form',
462161
    'page arguments' => array('system_modules'),
463161
    'access arguments' => array('administer site configuration'),
464
  );
465161
  $items['admin/build/modules/list'] = array(
466161
    'title' => 'List',
467161
    'type' => MENU_DEFAULT_LOCAL_TASK,
468
  );
469161
  $items['admin/build/modules/list/confirm'] = array(
470161
    'title' => 'List',
471161
    'access arguments' => array('administer site configuration'),
472161
    'type' => MENU_CALLBACK,
473
  );
474161
  $items['admin/build/modules/uninstall'] = array(
475161
    'title' => 'Uninstall',
476161
    'page arguments' => array('system_modules_uninstall'),
477161
    'access arguments' => array('administer site configuration'),
478161
    'type' => MENU_LOCAL_TASK,
479
  );
480161
  $items['admin/build/modules/uninstall/confirm'] = array(
481161
    'title' => 'Uninstall',
482161
    'access arguments' => array('administer site configuration'),
483161
    'type' => MENU_CALLBACK,
484
  );
485
486
  // Actions:
487161
  $items['admin/settings/actions'] = array(
488161
    'title' => 'Actions',
489161
    'description' => 'Manage the actions defined for your site.',
490161
    'access arguments' => array('administer actions'),
491
    'page callback' => 'system_actions_manage'
492161
  );
493161
  $items['admin/settings/actions/manage'] = array(
494161
    'title' => 'Manage actions',
495161
    'description' => 'Manage the actions defined for your site.',
496161
    'page callback' => 'system_actions_manage',
497161
    'type' => MENU_DEFAULT_LOCAL_TASK,
498161
    'weight' => -2,
499
  );
500161
  $items['admin/settings/actions/configure'] = array(
501161
    'title' => 'Configure an advanced action',
502161
    'page callback' => 'drupal_get_form',
503161
    'page arguments' => array('system_actions_configure'),
504161
    'access arguments' => array('administer actions'),
505161
    'type' => MENU_CALLBACK,
506
  );
507161
  $items['admin/settings/actions/delete/%actions'] = array(
508161
    'title' => 'Delete action',
509161
    'description' => 'Delete an action.',
510161
    'page callback' => 'drupal_get_form',
511161
    'page arguments' => array('system_actions_delete_form', 4),
512161
    'access arguments' => array('administer actions'),
513161
    'type' => MENU_CALLBACK,
514
  );
515161
  $items['admin/settings/actions/orphan'] = array(
516161
    'title' => 'Remove orphans',
517161
    'page callback' => 'system_actions_remove_orphans',
518161
    'access arguments' => array('administer actions'),
519161
    'type' => MENU_CALLBACK,
520
  );
521
522
  // IP address blocking.
523161
  $items['admin/settings/ip-blocking'] = array(
524161
    'title' => 'IP address blocking',
525161
    'description' => 'Manage blocked IP addresses.',
526161
    'page callback' => 'system_ip_blocking',
527161
    'access arguments' => array('block IP addresses'),
528
  );
529161
  $items['admin/settings/ip-blocking/%'] = array(
530161
    'title' => 'IP address blocking',
531161
    'description' => 'Manage blocked IP addresses.',
532161
    'page callback' => 'system_ip_blocking',
533161
    'access arguments' => array('block IP addresses'),
534161
    'type' => MENU_CALLBACK,
535
  );
536161
  $items['admin/settings/ip-blocking/delete/%blocked_ip'] = array(
537161
    'title' => 'Delete IP address',
538161
    'page callback' => 'drupal_get_form',
539161
    'page arguments' => array('system_ip_blocking_delete', 4),
540161
    'access arguments' => array('block IP addresses'),
541161
    'type' => MENU_CALLBACK,
542
  );
543
544
  // Settings:
545161
  $items['admin/settings/site-information'] = array(
546161
    'title' => 'Site information',
547161
    'description' => 'Change basic site information, such as the site name,
slogan, e-mail address, mission, front page and more.',
548161
    'page callback' => 'drupal_get_form',
549161
    'page arguments' => array('system_site_information_settings'),
550161
    'access arguments' => array('administer site configuration'),
551
  );
552161
  $items['admin/settings/error-reporting'] = array(
553161
    'title' => 'Error reporting',
554161
    'description' => 'Control how Drupal deals with errors including
403/404 errors as well as PHP error reporting.',
555161
    'page callback' => 'drupal_get_form',
556161
    'page arguments' => array('system_error_reporting_settings'),
557161
    'access arguments' => array('administer site configuration'),
558
  );
559161
  $items['admin/settings/logging'] = array(
560161
    'title' => 'Logging and alerts',
561161
    'description' => "Settings for logging and alerts modules. Various
modules can route Drupal's system events to different destination, such as
syslog, database, email, ...etc.",
562161
    'page callback' => 'system_logging_overview',
563161
    'access arguments' => array('administer site configuration'),
564
  );
565161
  $items['admin/settings/performance'] = array(
566161
    'title' => 'Performance',
567161
    'description' => 'Enable or disable page caching for anonymous users
and set CSS and JS bandwidth optimization options.',
568161
    'page callback' => 'drupal_get_form',
569161
    'page arguments' => array('system_performance_settings'),
570161
    'access arguments' => array('administer site configuration'),
571
  );
572161
  $items['admin/settings/file-system'] = array(
573161
    'title' => 'File system',
574161
    'description' => 'Tell Drupal where to store uploaded files and how
they are accessed.',
575161
    'page callback' => 'drupal_get_form',
576161
    'page arguments' => array('system_file_system_settings'),
577161
    'access arguments' => array('administer site configuration'),
578
  );
579161
  $items['admin/settings/image-toolkit'] = array(
580161
    'title' => 'Image toolkit',
581161
    'description' => 'Choose which image toolkit to use if you have
installed optional toolkits.',
582161
    'page callback' => 'drupal_get_form',
583161
    'page arguments' => array('system_image_toolkit_settings'),
584161
    'access arguments' => array('administer site configuration'),
585
  );
586161
  $items['admin/content/rss-publishing'] = array(
587161
    'title' => 'RSS publishing',
588161
    'description' => 'Configure the number of items per feed and whether
feeds should be titles/teasers/full-text.',
589161
    'page callback' => 'drupal_get_form',
590161
    'page arguments' => array('system_rss_feeds_settings'),
591161
    'access arguments' => array('administer site configuration'),
592
  );
593161
  $items['admin/settings/date-time'] = array(
594161
    'title' => 'Date and time',
595161
    'description' => "Settings for how Drupal displays date and time, as
well as the system's default timezone.",
596161
    'page callback' => 'drupal_get_form',
597161
    'page arguments' => array('system_date_time_settings'),
598161
    'access arguments' => array('administer site configuration'),
599
  );
600161
  $items['admin/settings/date-time/lookup'] = array(
601161
    'title' => 'Date and time lookup',
602161
    'type' => MENU_CALLBACK,
603161
    'page callback' => 'system_date_time_lookup',
604161
    'access arguments' => array('administer site configuration'),
605
  );
606161
  $items['admin/settings/site-maintenance'] = array(
607161
    'title' => 'Site maintenance',
608161
    'description' => 'Take the site offline for maintenance or bring it
back online.',
609161
    'page callback' => 'drupal_get_form',
610161
    'page arguments' => array('system_site_maintenance_settings'),
611161
    'access arguments' => array('administer site configuration'),
612
  );
613161
  $items['admin/settings/clean-urls'] = array(
614161
    'title' => 'Clean URLs',
615161
    'description' => 'Enable or disable clean URLs for your site.',
616161
    'page callback' => 'drupal_get_form',
617161
    'page arguments' => array('system_clean_url_settings'),
618161
    'access arguments' => array('administer site configuration'),
619
  );
620161
  $items['admin/settings/clean-urls/check'] = array(
621161
    'title' => 'Clean URL check',
622161
    'page callback' => 'drupal_json',
623161
    'page arguments' => array(array('status' => TRUE)),
624161
    'access callback' => TRUE,
625161
    'type' => MENU_CALLBACK,
626
  );
627
  // Menu handler to test that drupal_http_request() works locally.
628
  // @see system_check_http_request()
629161
  $items['admin/reports/request-test'] = array(
630161
    'title' => 'Request test',
631161
    'page callback' => 'printf',
632161
    'page arguments' => array('request test'),
633161
    'access callback' => TRUE,
634161
    'type' => MENU_CALLBACK,
635
  );
636
637
  // Reports:
638161
  $items['admin/reports'] = array(
639161
    'title' => 'Reports',
640161
    'description' => 'View reports from system logs and other status
information.',
641161
    'page callback' => 'system_admin_menu_block_page',
642161
    'access arguments' => array('access site reports'),
643161
    'weight' => 5,
644161
    'position' => 'left',
645
  );
646161
  $items['admin/reports/status'] = array(
647161
    'title' => 'Status report',
648161
    'description' => "Get a status report about your site's operation and
any detected problems.",
649161
    'page callback' => 'system_status',
650161
    'weight' => 10,
651161
    'access arguments' => array('administer site configuration'),
652
  );
653161
  $items['admin/reports/status/run-cron'] = array(
654161
    'title' => 'Run cron',
655161
    'page callback' => 'system_run_cron',
656161
    'access arguments' => array('administer site configuration'),
657161
    'type' => MENU_CALLBACK,
658
  );
659161
  $items['admin/reports/status/php'] = array(
660161
    'title' => 'PHP',
661161
    'page callback' => 'system_php',
662161
    'access arguments' => array('administer site configuration'),
663161
    'type' => MENU_CALLBACK,
664
  );
665161
  $items['admin/reports/status/sql'] = array(
666161
    'title' => 'SQL',
667161
    'page callback' => 'system_sql',
668161
    'access arguments' => array('administer site configuration'),
669161
    'type' => MENU_CALLBACK,
670
  );
671
  // Default page for batch operations
672161
  $items['batch'] = array(
673161
    'page callback' => 'system_batch_page',
674161
    'access callback' => TRUE,
675161
    'type' => MENU_CALLBACK,
676
  );
677161
  return $items;
6780
}
679
680
/**
681
 * Retrieve a blocked IP address from the database.
682
 *
683
 * @param $iid integer
684
 *   The ID of the blocked IP address to retrieve.
685
 *
686
 * @return
687
 *   The blocked IP address from the database as an array.
688
 */
6892366
function blocked_ip_load($iid) {
6903
  $blocked_ip = db_fetch_array(db_query("SELECT * FROM {blocked_ips} WHERE
iid = %d", $iid));
6913
  return $blocked_ip;
6920
}
693
694
/**
695
 * Menu item access callback - only admin or enabled themes can be
accessed.
696
 */
6972366
function _system_themes_access($theme) {
6982
  return user_access('administer site configuration') && ($theme->status ||
$theme->name == variable_get('admin_theme', '0'));
6990
}
700
701
/**
702
 * Implementation of hook_init().
703
 */
7042366
function system_init() {
705
  // Use the administrative theme if the user is looking at a page in the
admin/* path.
7062366
  if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0)
== 'node' && (arg(1) == 'add' || arg(2) == 'edit'))) {
707701
    global $custom_theme;
708701
    $custom_theme = variable_get('admin_theme', '0');
709701
    drupal_add_css(drupal_get_path('module', 'system') . '/admin.css');
710701
  }
711
712
  // Add the CSS for this module.
7132366
  drupal_add_css(drupal_get_path('module', 'system') . '/defaults.css');
7142366
  drupal_add_css(drupal_get_path('module', 'system') . '/system.css');
7152366
  drupal_add_css(drupal_get_path('module', 'system') .
'/system-menus.css');
7162366
}
717
718
/**
719
 * Implementation of MODULE_preprocess_HOOK().
720
 */
7212366
function system_preprocess_page(&$variables) {
722
  // Get the major version
7231740
  list($version,) = explode('.', VERSION);
724
725
  // Emit the META tag in the HTML HEAD section
7261740
  theme('meta_generator_html', $version);
727
728
  // Emit the HTTP Header too
7291740
  theme('meta_generator_header', $version);
730
7311740
  $variables['head'] = drupal_get_html_head();
7321740
}
733
734
/**
735
 * Implementation of hook_user_form().
736
 */
7372366
function system_user_form(&$edit, &$user, $category = NULL) {
73858
  if ($category == 'account') {
73915
    $form['theme_select'] = system_theme_select_form(t('Selecting a
different theme will change the look and feel of the site.'),
isset($edit['theme']) ? $edit['theme'] : NULL, 2);
740
74115
    if (variable_get('configurable_timezones', 1)) {
74215
      $zones = _system_zonelist();
74315
      $form['timezone'] = array(
74415
        '#type' => 'fieldset',
74515
        '#title' => t('Locale settings'),
74615
        '#weight' => 6,
74715
        '#collapsible' => TRUE,
748
      );
74915
      $form['timezone']['timezone'] = array(
75015
        '#type' => 'select',
75115
        '#title' => t('Time zone'),
75215
        '#default_value' => strlen($edit['timezone']) ? $edit['timezone'] :
variable_get('date_default_timezone', 0),
75315
        '#options' => $zones,
75415
        '#description' => t('Select your current local time. Dates and
times throughout this site will be displayed using this time zone.'),
755
      );
75615
    }
757
75815
    return $form;
7590
  }
76043
}
761
762
/**
763
 * Implementation of hook_block().
764
 *
765
 * Generate a block with a promotional link to Drupal.org.
766
 */
7672366
function system_block($op = 'list', $delta = '', $edit = NULL) {
768
  switch ($op) {
7691748
    case 'list':
77029
      $blocks['powered-by'] = array(
77129
        'info' => t('Powered by Drupal'),
77229
        'weight' => '10',
773
         // Not worth caching.
77429
        'cache' => BLOCK_NO_CACHE,
775
      );
77629
      return $blocks;
7771740
    case 'configure':
778
      // Compile a list of fields to show
7790
      $form['wrapper']['color'] = array(
7800
        '#type' => 'select',
7810
        '#title' => t('Badge color'),
7820
        '#default_value' => variable_get('drupal_badge_color',
'powered-blue'),
7830
        '#options' => array('powered-black' => t('Black'), 'powered-blue'
=> t('Blue'), 'powered-gray' => t('Gray')),
784
      );
7850
      $form['wrapper']['size'] = array(
7860
        '#type' => 'select',
7870
        '#title' => t('Badge size'),
7880
        '#default_value' => variable_get('drupal_badge_size', '80x15'),
7890
        '#options' => array('80x15' => t('Small'), '88x31' => t('Medium'),
'135x42' => t('Large')),
790
      );
7910
      return $form;
7921740
    case 'save':
7930
      variable_set('drupal_badge_color', $edit['color']);
7940
      variable_set('drupal_badge_size', $edit['size']);
7950
      break;
7961740
    case 'view':
7971740
      $image_path = 'misc/' . variable_get('drupal_badge_color',
'powered-blue') . '-' . variable_get('drupal_badge_size', '80x15') .
'.png';
7981740
      $block['subject'] = NULL; // Don't display a title
7991740
      $block['content'] = theme('system_powered_by', $image_path);
8001740
      return $block;
8010
  }
8020
}
803
804
/**
805
 * Provide a single block on the administration overview page.
806
 *
807
 * @param $item
808
 *   The menu item to be displayed.
809
 */
8102366
function system_admin_menu_block($item) {
8112
  $content = array();
8122
  if (!isset($item['mlid'])) {
8130
    $item += db_fetch_array(db_query("SELECT mlid, menu_name FROM
{menu_links} ml WHERE ml.router_path = '%s' AND module = 'system'",
$item['path']));
8140
  }
8152
  $result = db_query("
816
    SELECT m.load_functions, m.to_arg_functions, m.access_callback,
m.access_arguments, m.page_callback, m.page_arguments, m.title,
m.title_callback, m.title_arguments, m.type, m.description, ml.*
817
    FROM {menu_links} ml
818
    LEFT JOIN {menu_router} m ON ml.router_path = m.path
8192
    WHERE ml.plid = %d AND ml.menu_name = '%s' AND hidden = 0",
$item['mlid'], $item['menu_name']);
8202
  while ($item = db_fetch_array($result)) {
8212
    _menu_link_translate($item);
8222
    if (!$item['access']) {
8232
      continue;
8240
    }
825
    // The link 'description' either derived from the hook_menu
'description' or
826
    // entered by the user via menu module is saved as the title attribute.
8271
    if (!empty($item['localized_options']['attributes']['title'])) {
8281
      $item['description'] =
$item['localized_options']['attributes']['title'];
8291
    }
830
    // Prepare for sorting as in function _menu_tree_check_access().
831
    // The weight is offset so it is always positive, with a uniform
5-digits.
8321
    $content[(50000 + $item['weight']) . ' ' . $item['title'] . ' ' .
$item['mlid']] = $item;
8331
  }
8342
  ksort($content);
8352
  return $content;
8360
}
837
838
/**
839
 * Process admin theme form submissions.
840
 */
8412366
function system_admin_theme_submit($form, &$form_state) {
842
  // If we're changing themes, make sure the theme has its blocks
initialized.
8430
  if ($form_state['values']['admin_theme'] &&
$form_state['values']['admin_theme'] != variable_get('admin_theme', '0')) {
8440
    $result = db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme
= '%s'", $form_state['values']['admin_theme']));
8450
    if (!$result) {
8460
      system_initialize_theme_blocks($form_state['values']['admin_theme']);
8470
    }
8480
  }
8490
}
850
851
/**
852
 * Returns a fieldset containing the theme select form.
853
 *
854
 * @param $description
855
 *    description of the fieldset
856
 * @param $default_value
857
 *    default value of theme radios
858
 * @param $weight
859
 *    weight of the fieldset
860
 * @return
861
 *    a form array
862
 */
8632366
function system_theme_select_form($description = '', $default_value = '',
$weight = 0) {
86415
  if (user_access('select different theme')) {
8650
    $enabled = array();
8660
    $themes = list_themes();
867
8680
    foreach ($themes as $theme) {
8690
      if ($theme->status) {
8700
        $enabled[] = $theme;
8710
      }
8720
    }
873
8740
    if (count($enabled) > 1) {
8750
      ksort($enabled);
876
8770
      $form['themes'] = array(
8780
        '#type' => 'fieldset',
8790
        '#title' => t('Theme configuration'),
8800
        '#description' => $description,
8810
        '#collapsible' => TRUE,
882
        '#theme' => 'system_theme_select_form'
8830
      );
884
8850
      foreach ($enabled as $info) {
886
        // For the default theme, revert to an empty string so the user's
theme updates when the site theme is changed.
8870
        $info->key = $info->name == variable_get('theme_default',
'garland') ? '' : $info->name;
888
8890
        $screenshot = NULL;
8900
        $theme_key = $info->name;
8910
        while ($theme_key) {
8920
          if (file_exists($themes[$theme_key]->info['screenshot'])) {
8930
            $screenshot = $themes[$theme_key]->info['screenshot'];
8940
            break;
8950
          }
8960
          $theme_key = isset($themes[$theme_key]->info['base theme']) ?
$themes[$theme_key]->info['base theme'] : NULL;
8970
        }
898
8990
        $screenshot = $screenshot ? theme('image', $screenshot,
t('Screenshot for %theme theme', array('%theme' => $info->name)), '',
array('class' => 'screenshot'), FALSE) : t('no screenshot');
900
9010
        $form['themes'][$info->key]['screenshot'] = array('#markup' =>
$screenshot);
9020
        $form['themes'][$info->key]['description'] = array('#type' =>
'item', '#title' => $info->name, '#markup' => dirname($info->filename) .
($info->name == variable_get('theme_default', 'garland') ? '<br /> <em>' .
t('(site default theme)') . '</em>' : ''));
9030
        $options[$info->key] = '';
9040
      }
905
9060
      $form['themes']['theme'] = array('#type' => 'radios', '#options' =>
$options, '#default_value' => $default_value ? $default_value : '');
9070
      $form['#weight'] = $weight;
9080
      return $form;
9090
    }
9100
  }
91115
}
912
913
/**
914
 * Checks the existence of the directory specified in $form_element. This
915
 * function is called from the system_settings form to check both the
916
 * file_directory_path and file_directory_temp directories. If validation
917
 * fails, the form element is flagged with an error from within the
918
 * file_check_directory function.
919
 *
920
 * @param $form_element
921
 *   The form element containing the name of the directory to check.
922
 */
9232366
function system_check_directory($form_element) {
9240
  file_check_directory($form_element['#value'], FILE_CREATE_DIRECTORY,
$form_element['#parents'][0]);
9250
  return $form_element;
9260
}
927
928
/**
929
 * Retrieves the current status of an array of files in the system table.
930
 *
931
 * @param $files
932
 *   An array of files to check.
933
 * @param $type
934
 *   The type of the files.
935
 */
9362366
function system_get_files_database(&$files, $type) {
937
  // Extract current files from database.
938157
  $result = db_query("SELECT filename, name, type, status, schema_version,
weight FROM {system} WHERE type = '%s'", $type);
939157
  while ($file = db_fetch_object($result)) {
940157
    if (isset($files[$file->name]) && is_object($files[$file->name])) {
941157
      $file->old_filename = $file->filename;
942157
      foreach ($file as $key => $value) {
943157
        if (!isset($files[$file->name]) ||
!isset($files[$file->name]->$key)) {
944157
          $files[$file->name]->$key = $value;
945157
        }
946157
      }
947157
    }
948157
  }
949157
}
950
951
/**
952
 * Prepare defaults for themes.
953
 *
954
 * @return
955
 *   An array of default themes settings.
956
 */
9572366
function system_theme_default() {
958
  return array(
959
    'regions' => array(
960137
      'left' => 'Left sidebar',
961137
      'right' => 'Right sidebar',
962137
      'content' => 'Content',
963137
      'header' => 'Header',
964137
      'footer' => 'Footer',
965137
    ),
966137
    'description' => '',
967
    'features' => array(
968137
      'comment_user_picture',
969137
      'favicon',
970137
      'mission',
971137
      'logo',
972137
      'name',
973137
      'node_user_picture',
974137
      'search',
975137
      'slogan',
976137
      'main_menu',
977137
      'secondary_menu',
978137
    ),
979
    'stylesheets' => array(
980137
      'all' => array('style.css')
981137
    ),
982137
    'scripts' => array('script.js'),
983137
    'screenshot' => 'screenshot.png',
984137
    'php' => DRUPAL_MINIMUM_PHP,
985137
  );
9860
}
987
988
/**
989
 * Collect data about all currently available themes.
990
 *
991
 * @return
992
 *   Array of all available themes and their data.
993
 */
9942366
function system_theme_data() {
995
  // Scan the installation theme .info files and their engines.
996137
  $themes = _system_theme_data();
997
998
  // Extract current files from database.
999137
  system_get_files_database($themes, 'theme');
1000
1001137
  db_query("DELETE FROM {system} WHERE type = 'theme'");
1002
1003137
  foreach ($themes as $theme) {
1004137
    if (!isset($theme->owner)) {
1005137
      $theme->owner = '';
1006137
    }
1007
1008137
    db_query("INSERT INTO {system} (name, owner, info, type, filename,
status, bootstrap) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d)",
$theme->name, $theme->owner, serialize($theme->info), 'theme',
$theme->filename, isset($theme->status) ? $theme->status : 0, 0);
1009137
  }
1010
1011137
  return $themes;
10120
}
1013
1014
/**
1015
 * Helper function to scan and collect theme .info data and their engines.
1016
 *
1017
 * @return
1018
 *   An associative array of themes information.
1019
 */
10202366
function _system_theme_data() {
1021137
  static $themes_info = array();
1022
1023137
  if (empty($themes_info)) {
1024
    // Find themes
1025137
    $themes = drupal_system_listing('/\.info$/', 'themes');
1026
    // Find theme engines
1027137
    $engines = drupal_system_listing('/\.engine$/', 'themes/engines');
1028
1029137
    $defaults = system_theme_default();
1030
1031137
    $sub_themes = array();
1032
    // Read info files for each theme
1033137
    foreach ($themes as $key => $theme) {
1034137
      $themes[$key]->info = drupal_parse_info_file($theme->filename) +
$defaults;
1035
1036
      // Invoke hook_system_info_alter() to give installed modules a chance
to
1037
      // modify the data in the .info files if necessary.
1038137
      drupal_alter('system_info', $themes[$key]->info, $themes[$key]);
1039
1040137
      if (!empty($themes[$key]->info['base theme'])) {
1041137
        $sub_themes[] = $key;
1042137
      }
1043137
      if (empty($themes[$key]->info['engine'])) {
1044137
        $filename = dirname($themes[$key]->filename) . '/' .
$themes[$key]->name . '.theme';
1045137
        if (file_exists($filename)) {
1046137
          $themes[$key]->owner = $filename;
1047137
          $themes[$key]->prefix = $key;
1048137
        }
1049137
      }
1050
      else {
1051137
        $engine = $themes[$key]->info['engine'];
1052137
        if (isset($engines[$engine])) {
1053137
          $themes[$key]->owner = $engines[$engine]->filename;
1054137
          $themes[$key]->prefix = $engines[$engine]->name;
1055137
          $themes[$key]->template = TRUE;
1056137
        }
1057
      }
1058
1059
      // Give the stylesheets proper path information.
1060137
      $pathed_stylesheets = array();
1061137
      foreach ($themes[$key]->info['stylesheets'] as $media =>
$stylesheets) {
1062137
        foreach ($stylesheets as $stylesheet) {
1063137
          $pathed_stylesheets[$media][$stylesheet] =
dirname($themes[$key]->filename) . '/' . $stylesheet;
1064137
        }
1065137
      }
1066137
      $themes[$key]->info['stylesheets'] = $pathed_stylesheets;
1067
1068
      // Give the scripts proper path information.
1069137
      $scripts = array();
1070137
      foreach ($themes[$key]->info['scripts'] as $script) {
1071137
        $scripts[$script] = dirname($themes[$key]->filename) . '/' .
$script;
1072137
      }
1073137
      $themes[$key]->info['scripts'] = $scripts;
1074
      // Give the screenshot proper path information.
1075137
      if (!empty($themes[$key]->info['screenshot'])) {
1076137
        $themes[$key]->info['screenshot'] =
dirname($themes[$key]->filename) . '/' . $themes[$key]->info['screenshot'];
1077137
      }
1078137
    }
1079
1080
    // Now that we've established all our master themes, go back and fill
in
1081
    // data for subthemes.
1082137
    foreach ($sub_themes as $key) {
1083137
      $base_key = system_find_base_theme($themes, $key);
1084137
      if (!$base_key) {
10850
        continue;
10860
      }
1087
      // Copy the 'owner' and 'engine' over if the top level theme uses a
1088
      // theme engine.
1089137
      if (isset($themes[$base_key]->owner)) {
1090137
        if (isset($themes[$base_key]->info['engine'])) {
1091137
          $themes[$key]->info['engine'] =
$themes[$base_key]->info['engine'];
1092137
          $themes[$key]->owner = $themes[$base_key]->owner;
1093137
          $themes[$key]->prefix = $themes[$base_key]->prefix;
1094137
        }
1095
        else {
1096137
          $themes[$key]->prefix = $key;
1097
        }
1098137
      }
1099137
    }
1100
1101137
    $themes_info = $themes;
1102137
  }
1103
1104137
  return $themes_info;
11050
}
1106
1107
/**
1108
 * Recursive function to find the top level base theme. Themes can inherit
1109
 * templates and function implementations from earlier themes.
1110
 *
1111
 * @param $themes
1112
 *   An array of available themes.
1113
 * @param $key
1114
 *   The name of the theme whose base we are looking for.
1115
 * @param $used_keys
1116
 *   A recursion parameter preventing endless loops.
1117
 * @return
1118
 *   Returns the top level parent that has no ancestor or returns NULL if
there isn't a valid parent.
1119
 */
11202366
function system_find_base_theme($themes, $key, $used_keys = array()) {
1121137
  $base_key = $themes[$key]->info['base theme'];
1122
  // Does the base theme exist?
1123137
  if (!isset($themes[$base_key])) {
11240
    return NULL;
11250
  }
1126
1127
  // Is the base theme itself a child of another theme?
1128137
  if (isset($themes[$base_key]->info['base theme'])) {
1129
    // Prevent loops.
11300
    if (!empty($used_keys[$base_key])) {
11310
      return NULL;
11320
    }
11330
    $used_keys[$base_key] = TRUE;
11340
    return system_find_base_theme($themes, $base_key, $used_keys);
11350
  }
1136
  // If we get here, then this is our parent theme.
1137137
  return $base_key;
11380
}
1139
1140
/**
1141
 * Get a list of available regions from a specified theme.
1142
 *
1143
 * @param $theme_key
1144
 *   The name of a theme.
1145
 * @return
1146
 *   An array of regions in the form $region['name'] = 'description'.
1147
 */
11482366
function system_region_list($theme_key) {
11491750
  static $list = array();
1150
11511750
  if (!array_key_exists($theme_key, $list)) {
11521750
    $info = unserialize(db_result(db_query("SELECT info FROM {system} WHERE
type = :type AND name = :name", array(':type' => 'theme', ':name' =>
$theme_key))));
11531750
    $list[$theme_key] = array_map('t', $info['regions']);
11541750
  }
1155
11561750
  return $list[$theme_key];
11570
}
1158
1159
/**
1160
 * Get the name of the default region for a given theme.
1161
 *
1162
 * @param $theme
1163
 *   The name of a theme.
1164
 * @return
1165
 *   A string that is the region name.
1166
 */
11672366
function system_default_region($theme) {
11680
  $regions = array_keys(system_region_list($theme));
11690
  return isset($regions[0]) ? $regions[0] : '';
11700
}
1171
1172
/**
1173
 * Assign an initial, default set of blocks for a theme.
1174
 *
1175
 * This function is called the first time a new theme is enabled. The new
theme
1176
 * gets a copy of the default theme's blocks, with the difference that if a
1177
 * particular region isn't available in the new theme, the block is
assigned
1178
 * to the new theme's default region.
1179
 *
1180
 * @param $theme
1181
 *   The name of a theme.
1182
 */
11832366
function system_initialize_theme_blocks($theme) {
1184
  // Initialize theme's blocks if none already registered.
11851
  if (!(db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme =
'%s'", $theme)))) {
11861
    $default_theme = variable_get('theme_default', 'garland');
11871
    $regions = system_region_list($theme);
11881
    $result = db_query("SELECT * FROM {blocks} WHERE theme = '%s'",
$default_theme);
11891
    while ($block = db_fetch_array($result)) {
1190
      // If the region isn't supported by the theme, assign the block to
the theme's default region.
11911
      if (!array_key_exists($block['region'], $regions)) {
11920
        $block['region'] = system_default_region($theme);
11930
      }
11941
      db_query("INSERT INTO {blocks} (module, delta, theme, status, weight,
region, visibility, pages, custom, cache) VALUES ('%s', '%s', '%s', %d, %d,
'%s', %d, '%s', %d, %d)",
11951
          $block['module'], $block['delta'], $theme, $block['status'],
$block['weight'], $block['region'], $block['visibility'], $block['pages'],
$block['custom'], $block['cache']);
11961
    }
11971
  }
11981
}
1199
1200
/**
1201
 * Add default buttons to a form and set its prefix.
1202
 *
1203
 * @ingroup forms
1204
 * @see system_settings_form_submit()
1205
 * @param $form
1206
 *   An associative array containing the structure of the form.
1207
 * @return
1208
 *   The form structure.
1209
 */
12102366
function system_settings_form($form) {
121143
  $form['buttons']['submit'] = array('#type' => 'submit', '#value' =>
t('Save configuration') );
121243
  $form['buttons']['reset'] = array('#type' => 'submit', '#value' =>
t('Reset to defaults') );
1213
121443
  if (!empty($_POST) && form_get_errors()) {
12150
    drupal_set_message(t('The settings have not been saved because of the
errors.'), 'error');
12160
  }
121743
  $form['#submit'][] = 'system_settings_form_submit';
121843
  $form['#theme'] = 'system_settings_form';
121943
  return $form;
12200
}
1221
1222
/**
1223
 * Execute the system_settings_form.
1224
 *
1225
 * If you want node type configure style handling of your checkboxes,
1226
 * add an array_filter value to your form.
1227
 */
12282366
function system_settings_form_submit($form, &$form_state) {
122914
  $op = isset($form_state['values']['op']) ? $form_state['values']['op'] :
'';
1230
1231
  // Exclude unnecessary elements.
123214
  unset($form_state['values']['submit'], $form_state['values']['reset'],
$form_state['values']['form_id'], $form_state['values']['op'],
$form_state['values']['form_token'],
$form_state['values']['form_build_id']);
1233
123414
  foreach ($form_state['values'] as $key => $value) {
123514
    if ($op == t('Reset to defaults')) {
12362
      variable_del($key);
12372
    }
1238
    else {
123912
      if (is_array($value) && isset($form_state['values']['array_filter']))
{
12400
        $value = array_keys(array_filter($value));
12410
      }
124212
      variable_set($key, $value);
1243
    }
124414
  }
124514
  if ($op == t('Reset to defaults')) {
12462
    drupal_set_message(t('The configuration options have been reset to
their default values.'));
12472
  }
1248
  else {
124912
    drupal_set_message(t('The configuration options have been saved.'));
1250
  }
1251
125214
  cache_clear_all();
125314
  drupal_theme_rebuild();
125414
}
1255
1256
/**
1257
 * Helper function to sort requirements.
1258
 */
12592366
function _system_sort_requirements($a, $b) {
12603
  if (!isset($a['weight'])) {
12613
    if (!isset($b['weight'])) {
12623
      return strcmp($a['title'], $b['title']);
12630
    }
12643
    return -$b['weight'];
12650
  }
12663
  return isset($b['weight']) ? $a['weight'] - $b['weight'] : $a['weight'];
12670
}
1268
1269
/**
1270
 * Implementation of hook_node_type().
1271
 *
1272
 * Updates theme settings after a node type change.
1273
 */
12742366
function system_node_type($op, $info) {
1275135
  if ($op == 'update' && !empty($info->old_type) && $info->type !=
$info->old_type) {
12760
    $old = 'toggle_node_info_' . $info->old_type;
12770
    $new = 'toggle_node_info_' . $info->type;
1278
12790
    $theme_settings = variable_get('theme_settings', array());
12800
    if (isset($theme_settings[$old])) {
12810
      $theme_settings[$new] = $theme_settings[$old];
12820
      unset($theme_settings[$old]);
12830
      variable_set('theme_settings', $theme_settings);
12840
    }
12850
  }
1286135
}
1287
1288
/**
1289
 * Output a confirmation form
1290
 *
1291
 * This function returns a complete form for confirming an action. A link
is
1292
 * offered to go back to the item that is being changed in case the user
changes
1293
 * his/her mind.
1294
 *
1295
 * If the submit handler for this form is invoked, the user successfully
1296
 * confirmed the action. You should never directly inspect $_POST to see if
an
1297
 * action was confirmed.
1298
 *
1299
 * Note - if the parameters $question, $description, $yes, or $no could
contain
1300
 * any user input (such as node titles or taxonomy terms), it is the
1301
 * responsibility of the code calling confirm_form() to sanitize them first
with
1302
 * a function like check_plain() or filter_xss().
1303
 *
1304
 * @ingroup forms
1305
 * @param $form
1306
 *   Additional elements to inject into the form, for example hidden
elements.
1307
 * @param $question
1308
 *   The question to ask the user (e.g. "Are you sure you want to delete
the
1309
 *   block <em>foo</em>?").
1310
 * @param $path
1311
 *   The page to go to if the user denies the action.
1312
 *   Can be either a drupal path, or an array with the keys 'path',
'query', 'fragment'.
1313
 * @param $description
1314
 *   Additional text to display (defaults to "This action cannot be
undone.").
1315
 * @param $yes
1316
 *   A caption for the button which confirms the action (e.g. "Delete",
1317
 *   "Replace", ...).
1318
 * @param $no
1319
 *   A caption for the link which denies the action (e.g. "Cancel").
1320
 * @param $name
1321
 *   The internal name used to refer to the confirmation item.
1322
 * @return
1323
 *   The form.
1324
 */
13252366
function confirm_form($form, $question, $path, $description = NULL, $yes =
NULL, $no = NULL, $name = 'confirm') {
1326100
  $description = isset($description) ? $description : t('This action cannot
be undone.');
1327
1328
  // Prepare cancel link
1329100
  $query = $fragment = NULL;
1330100
  if (is_array($path)) {
13310
    $query = isset($path['query']) ? $path['query'] : NULL;
13320
    $fragment = isset($path['fragment']) ? $path['fragment'] : NULL;
13330
    $path = isset($path['path']) ? $path['path'] : NULL;
13340
  }
1335100
  $cancel = l($no ? $no : t('Cancel'), $path, array('query' => $query,
'fragment' => $fragment));
1336
1337100
  drupal_set_title($question, PASS_THROUGH);
1338
1339
  // Confirm form fails duplication check, as the form values rarely change
-- so skip it.
1340100
  $form['#skip_duplicate_check'] = TRUE;
1341
1342100
  $form['#attributes'] = array('class' => 'confirmation');
1343100
  $form['description'] = array('#markup' => $description);
1344100
  $form[$name] = array('#type' => 'hidden', '#value' => 1);
1345
1346100
  $form['actions'] = array('#prefix' => '<div class="container-inline">',
'#suffix' => '</div>');
1347100
  $form['actions']['submit'] = array('#type' => 'submit', '#value' => $yes
? $yes : t('Confirm'));
1348100
  $form['actions']['cancel'] = array('#markup' => $cancel);
1349100
  $form['#theme'] = 'confirm_form';
1350100
  return $form;
13510
}
1352
1353
/**
1354
 * Determine if a user is in compact mode.
1355
 */
13562366
function system_admin_compact_mode() {
135734
  global $user;
135834
  return (isset($user->admin_compact_mode)) ? $user->admin_compact_mode :
variable_get('admin_compact_mode', FALSE);
13590
}
1360
1361
/**
1362
 * Menu callback; Sets whether the admin menu is in compact mode or not.
1363
 *
1364
 * @param $mode
1365
 *   Valid values are 'on' and 'off'.
1366
 */
13672366
function system_admin_compact_page($mode = 'off') {
13680
  global $user;
13690
  user_save($user, array('admin_compact_mode' => ($mode == 'on')));
13700
  drupal_goto(drupal_get_destination());
13710
}
1372
1373
/**
1374
 * Generate a list of tasks offered by a specified module.
1375
 *
1376
 * @param $module
1377
 *   Module name.
1378
 * @return
1379
 *   An array of task links.
1380
 */
13812366
function system_get_module_admin_tasks($module) {
138218
  static $items;
1383
138418
  if (!isset($items)) {
138518
    $result = db_query("
1386
       SELECT m.load_functions, m.to_arg_functions, m.access_callback,
m.access_arguments, m.page_callback, m.page_arguments, m.title,
m.title_callback, m.title_arguments, m.type, ml.*
138718
       FROM {menu_links} ml INNER JOIN {menu_router} m ON ml.router_path =
m.path WHERE ml.link_path LIKE 'admin/%' AND hidden >= 0 AND module =
'system' AND m.number_parts > 2");
138818
    $items = array();
138918
    while ($item = db_fetch_array($result)) {
139018
      _menu_link_translate($item);
139118
      if ($item['access']) {
13922
        $items[$item['router_path']] = $item;
13932
      }
139418
    }
139518
  }
1396
139718
  $admin_access = user_access('administer permissions');
139818
  $admin_tasks = array();
139918
  $admin_task_count = 0;
1400
  // Check for permissions.
140118
  if (module_hook($module, 'perm') && $admin_access) {
14020
    $admin_tasks[-1] = l(t('Configure permissions'),
'admin/user/permissions', array('fragment' => 'module-' . $module));
14030
  }
1404
1405
  // Check for menu items that are admin links.
140618
  if ($menu = module_invoke($module, 'menu')) {
140717
    foreach (array_keys($menu) as $path) {
140817
      if (isset($items[$path])) {
14092
        $admin_tasks[$items[$path]['title'] . $admin_task_count ++] =
l($items[$path]['title'], $path);
14102
      }
141117
    }
141217
  }
1413
141418
  return $admin_tasks;
14150
}
1416
1417
/**
1418
 * Implementation of hook_cron().
1419
 *
1420
 * Remove older rows from flood and batch table. Remove old temporary
files.
1421
 */
14222366
function system_cron() {
1423
  // Cleanup the flood.
14242
  db_query('DELETE FROM {flood} WHERE timestamp < %d', REQUEST_TIME -
3600);
1425
  // Cleanup the batch table.
14262
  db_query('DELETE FROM {batch} WHERE timestamp < %d', REQUEST_TIME -
864000);
1427
1428
  // Remove temporary files that are older than
DRUPAL_MAXIMUM_TEMP_FILE_AGE.
14292
  $result = db_query('SELECT * FROM {files} WHERE status = %d and timestamp
< %d', FILE_STATUS_TEMPORARY, REQUEST_TIME - DRUPAL_MAXIMUM_TEMP_FILE_AGE);
14302
  while ($file = db_fetch_object($result)) {
14310
    if (file_exists($file->filepath)) {
1432
      // If files that exist cannot be deleted, continue so the database
remains
1433
      // consistent.
14340
      if (!file_delete($file)) {
14350
        watchdog('file system', 'Could not delete temporary file "%path"
during garbage collection', array('%path' => $file->filepath),
WATCHDOG_ERROR);
14360
        continue;
14370
      }
14380
    }
14390
    db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
14400
  }
14412
  $core = array('cache', 'cache_block', 'cache_filter', 'cache_page',
'cache_form', 'cache_menu');
14422
  $cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
14432
  foreach ($cache_tables as $table) {
14442
    cache_clear_all(NULL, $table);
14452
  }
14462
}
1447
1448
/**
1449
 * Implementation of hook_hook_info().
1450
 */
14512366
function system_hook_info() {
1452
  return array(
1453
    'system' => array(
1454
      'cron' => array(
1455
        'run' => array(
145655
          'runs when' => t('When cron runs'),
145755
        ),
145855
      ),
145955
    ),
146055
  );
14610
}
1462
1463
/**
1464
 * Implementation of hook_action_info().
1465
 */
14662366
function system_action_info() {
1467
  return array(
1468
    'system_message_action' => array(
1469215
      'type' => 'system',
1470215
      'description' => t('Display a message to the user'),
1471215
      'configurable' => TRUE,
1472
      'hooks' => array(
1473215
        'nodeapi' => array('view', 'insert', 'update', 'delete'),
1474215
        'comment' => array('view', 'insert', 'update', 'delete'),
1475215
        'user' => array('view', 'insert', 'update', 'delete', 'login'),
1476215
        'taxonomy' => array('insert', 'update', 'delete'),
1477215
      ),
1478215
    ),
1479
    'system_send_email_action' => array(
1480215
      'description' => t('Send e-mail'),
1481215
      'type' => 'system',
1482215
      'configurable' => TRUE,
1483
      'hooks' => array(
1484215
        'nodeapi' => array('view', 'insert', 'update', 'delete'),
1485215
        'comment' => array('view', 'insert', 'update', 'delete'),
1486215
        'user' => array('view', 'insert', 'update', 'delete', 'login'),
1487215
        'taxonomy' => array('insert', 'update', 'delete'),
1488
      )
1489215
    ),
1490
    'system_block_ip_action' => array(
1491215
      'description' => t('Ban IP address of current user'),
1492215
      'type' => 'user',
1493215
      'configurable' => FALSE,
1494215
      'hooks' => array(),
1495215
    ),
1496
    'system_goto_action' => array(
1497215
      'description' => t('Redirect to URL'),
1498215
      'type' => 'system',
1499215
      'configurable' => TRUE,
1500
      'hooks' => array(
1501215
        'nodeapi' => array('view', 'insert', 'update', 'delete'),
1502215
        'comment' => array('view', 'insert', 'update', 'delete'),
1503215
        'user' => array('view', 'insert', 'update', 'delete', 'login'),
1504
      )
1505215
    )
1506215
  );
15070
}
1508
1509
/**
1510
 * Menu callback. Display an overview of available and configured actions.
1511
 */
15122366
function system_actions_manage() {
15136
  $output = '';
15146
  $actions = actions_list();
15156
  actions_synchronize($actions);
15166
  $actions_map = actions_actions_map($actions);
15176
  $options = array(t('Choose an advanced action'));
15186
  $unconfigurable = array();
1519
15206
  foreach ($actions_map as $key => $array) {
15216
    if ($array['configurable']) {
15226
      $options[$key] = $array['description'] . '...';
15236
    }
1524
    else {
15256
      $unconfigurable[] = $array;
1526
    }
15276
  }
1528
15296
  $row = array();
15306
  $instances_present = db_fetch_object(db_query("SELECT aid FROM {actions}
WHERE parameters <> ''"));
1531
  $header = array(
15326
    array('data' => t('Action type'), 'field' => 'type'),
15336
    array('data' => t('Description'), 'field' => 'description'),
15346
    array('data' => $instances_present ? t('Operations') : '', 'colspan' =>
'2')
15356
  );
15366
  $sql = 'SELECT * FROM {actions}';
15376
  $result = pager_query($sql . tablesort_sql($header), 50);
15386
  while ($action = db_fetch_object($result)) {
15396
    $row[] = array(
15406
      array('data' => $action->type),
15416
      array('data' => $action->description),
15426
      array('data' => $action->parameters ? l(t('configure'),
"admin/settings/actions/configure/$action->aid") : ''),
15436
      array('data' => $action->parameters ? l(t('delete'),
"admin/settings/actions/delete/$action->aid") : '')
15446
    );
15456
  }
1546
15476
  if ($row) {
15486
    $pager = theme('pager', NULL, 50, 0);
15496
    if (!empty($pager)) {
15500
      $row[] = array(array('data' => $pager, 'colspan' => '3'));
15510
    }
15526
    $output .= '<h3>' . t('Actions available to Drupal:') . '</h3>';
15536
    $output .= theme('table', $header, $row);
15546
  }
1555
15566
  if ($actions_map) {
15576
    $output .= drupal_get_form('system_actions_manage_form', $options);
15585
  }
1559
15605
  return $output;
15610
}
1562
1563
/**
1564
 * Define the form for the actions overview page.
1565
 *
1566
 * @see system_actions_manage_form_submit()
1567
 * @ingroup forms
1568
 * @param $form_state
1569
 *   An associative array containing the current state of the form; not
used.
1570
 * @param $options
1571
 *   An array of configurable actions.
1572
 * @return
1573
 *   Form definition.
1574
 */
15752366
function system_actions_manage_form($form_state, $options = array()) {
15766
  $form['parent'] = array(
15776
    '#type' => 'fieldset',
15786
    '#title' => t('Make a new advanced action available'),
15796
    '#prefix' => '<div class="container-inline">',
15806
    '#suffix' => '</div>',
1581
  );
15826
  $form['parent']['action'] = array(
15836
    '#type' => 'select',
15846
    '#default_value' => '',
15856
    '#options' => $options,
15866
    '#description' => '',
1587
  );
15886
  $form['parent']['buttons']['submit'] = array(
15896
    '#type' => 'submit',
15906
    '#value' => t('Create'),
1591
  );
15926
  return $form;
15930
}
1594
1595
/**
1596
 * Process system_actions_manage form submissions.
1597
 */
15982366
function system_actions_manage_form_submit($form, &$form_state) {
15991
  if ($form_state['values']['action']) {
16001
    $form_state['redirect'] = 'admin/settings/actions/configure/' .
$form_state['values']['action'];
16011
  }
16021
}
1603
1604
/**
1605
 * Menu callback. Create the form for configuration of a single action.
1606
 *
1607
 * We provide the "Description" field. The rest of the form
1608
 * is provided by the action. We then provide the Save button.
1609
 * Because we are combining unknown form elements with the action
1610
 * configuration form, we use actions_ prefix on our elements.
1611
 *
1612
 * @see system_actions_configure_validate()
1613
 * @see system_actions_configure_submit()
1614
 * @param $action
1615
 *   md5 hash of action ID or an integer. If it's an md5 hash, we
1616
 *   are creating a new instance. If it's an integer, we're editing
1617
 *   an existing instance.
1618
 * @return
1619
 *   Form definition.
1620
 */
16212366
function system_actions_configure($form_state, $action = NULL) {
16226
  if ($action === NULL) {
16230
    drupal_goto('admin/settings/actions');
16240
  }
1625
16266
  $actions_map = actions_actions_map(actions_list());
16276
  $edit = array();
1628
1629
  // Numeric action denotes saved instance of a configurable action;
1630
  // else we are creating a new action instance.
16316
  if (is_numeric($action)) {
16323
    $aid = $action;
1633
    // Load stored parameter values from database.
16343
    $data = db_fetch_object(db_query("SELECT * FROM {actions} WHERE aid =
'%s'", $aid));
16353
    $edit['actions_description'] = $data->description;
16363
    $edit['actions_type'] = $data->type;
16373
    $function = $data->callback;
16383
    $action = md5($data->callback);
16393
    $params = unserialize($data->parameters);
16403
    if ($params) {
16413
      foreach ($params as $name => $val) {
16423
        $edit[$name] = $val;
16433
      }
16443
    }
16453
  }
1646
  else {
16473
    $function = $actions_map[$action]['callback'];
16483
    $edit['actions_description'] = $actions_map[$action]['description'];
16493
    $edit['actions_type'] = $actions_map[$action]['type'];
1650
  }
1651
16526
  $form['actions_description'] = array(
16536
    '#type' => 'textfield',
16546
    '#title' => t('Description'),
16556
    '#default_value' => $edit['actions_description'],
16566
    '#maxlength' => '255',
16576
    '#description' => t('A unique description for this advanced action.
This description will be displayed in the interface of modules that
integrate with actions, such as Trigger module.'),
16580
    '#weight' => -10
16596
  );
16606
  $action_form = $function . '_form';
16616
  $form = array_merge($form, $action_form($edit));
16626
  $form['actions_type'] = array(
16636
    '#type' => 'value',
16646
    '#value' => $edit['actions_type'],
1665
  );
16666
  $form['actions_action'] = array(
16676
    '#type' => 'hidden',
16686
    '#value' => $action,
1669
  );
1670
  // $aid is set when configuring an existing action instance.
16716
  if (isset($aid)) {
16723
    $form['actions_aid'] = array(
16733
      '#type' => 'hidden',
16743
      '#value' => $aid,
1675
    );
16763
  }
16776
  $form['actions_configured'] = array(
16786
    '#type' => 'hidden',
16796
    '#value' => '1',
1680
  );
16816
  $form['buttons']['submit'] = array(
16826
    '#type' => 'submit',
16836
    '#value' => t('Save'),
1684
    '#weight' => 13
16856
  );
1686
16876
  return $form;
16880
}
1689
1690
/**
1691
 * Validate system_actions_configure form submissions.
1692
 */
16932366
function system_actions_configure_validate($form, $form_state) {
16942
  $function =
actions_function_lookup($form_state['values']['actions_action']) .
'_validate';
1695
  // Hand off validation to the action.
16962
  if (function_exists($function)) {
16970
    $function($form, $form_state);
16980
  }
16992
}
1700
1701
/**
1702
 * Process system_actions_configure form submissions.
1703
 */
17042366
function system_actions_configure_submit($form, &$form_state) {
17052
  $function =
actions_function_lookup($form_state['values']['actions_action']);
17062
  $submit_function = $function . '_submit';
1707
1708
  // Action will return keyed array of values to store.
17092
  $params = $submit_function($form, $form_state);
17102
  $aid = isset($form_state['values']['actions_aid']) ?
$form_state['values']['actions_aid'] : NULL;
1711
17122
  actions_save($function, $form_state['values']['actions_type'], $params,
$form_state['values']['actions_description'], $aid);
17132
  drupal_set_message(t('The action has been successfully saved.'));
1714
17152
  $form_state['redirect'] = 'admin/settings/actions/manage';
17162
}
1717
1718
/**
1719
 * Create the form for confirmation of deleting an action.
1720
 *
1721
 * @ingroup forms
1722
 * @see system_actions_delete_form_submit()
1723
 */
17242366
function system_actions_delete_form($form_state, $action) {
1725
17263
  $form['aid'] = array(
17273
    '#type' => 'hidden',
17283
    '#value' => $action->aid,
1729
  );
17303
  return confirm_form($form,
17313
    t('Are you sure you want to delete the action %action?',
array('%action' => $action->description)),
17323
    'admin/settings/actions/manage',
17333
    t('This cannot be undone.'),
17343
    t('Delete'), t('Cancel')
17353
  );
17360
}
1737
1738
/**
1739
 * Process system_actions_delete form submissions.
1740
 *
1741
 * Post-deletion operations for action deletion.
1742
 */
17432366
function system_actions_delete_form_submit($form, &$form_state) {
17441
  $aid = $form_state['values']['aid'];
17451
  $action = actions_load($aid);
17461
  actions_delete($aid);
17471
  $description = check_plain($action->description);
17481
  watchdog('user', 'Deleted action %aid (%action)', array('%aid' => $aid,
'%action' => $description));
17491
  drupal_set_message(t('Action %action was deleted', array('%action' =>
$description)));
17501
  $form_state['redirect'] = 'admin/settings/actions/manage';
17511
}
1752
1753
/**
1754
 * Post-deletion operations for deleting action orphans.
1755
 *
1756
 * @param $orphaned
1757
 *   An array of orphaned actions.
1758
 */
17592366
function system_action_delete_orphans_post($orphaned) {
17600
  foreach ($orphaned as $callback) {
17610
    drupal_set_message(t("Deleted orphaned action (%action).",
array('%action' => $callback)));
17620
  }
17630
}
1764
1765
/**
1766
 * Remove actions that are in the database but not supported by any enabled
module.
1767
 */
17682366
function system_actions_remove_orphans() {
17690
  actions_synchronize(actions_list(), TRUE);
17700
  drupal_goto('admin/settings/actions/manage');
17710
}
1772
1773
/**
1774
 * Return a form definition so the Send email action can be configured.
1775
 *
1776
 * @see system_send_email_action_validate()
1777
 * @see system_send_email_action_submit()
1778
 * @param $context
1779
 *   Default values (if we are editing an existing action instance).
1780
 * @return
1781
 *   Form definition.
1782
 */
17832366
function system_send_email_action_form($context) {
1784
  // Set default values for form.
17850
  if (!isset($context['recipient'])) {
17860
    $context['recipient'] = '';
17870
  }
17880
  if (!isset($context['subject'])) {
17890
    $context['subject'] = '';
17900
  }
17910
  if (!isset($context['message'])) {
17920
    $context['message'] = '';
17930
  }
1794
17950
  $form['recipient'] = array(
17960
    '#type' => 'textfield',
17970
    '#title' => t('Recipient'),
17980
    '#default_value' => $context['recipient'],
17990
    '#maxlength' => '254',
18000
    '#description' => t('The email address to which the message should be
sent OR enter %author if you would like to send an e-mail to the author of
the original post.', array('%author' => '%author')),
1801
  );
18020
  $form['subject'] = array(
18030
    '#type' => 'textfield',
18040
    '#title' => t('Subject'),
18050
    '#default_value' => $context['subject'],
18060
    '#maxlength' => '254',
18070
    '#description' => t('The subject of the message.'),
1808
  );
18090
  $form['message'] = array(
18100
    '#type' => 'textarea',
18110
    '#title' => t('Message'),
18120
    '#default_value' => $context['message'],
18130
    '#cols' => '80',
18140
    '#rows' => '20',
18150
    '#description' => t('The message that should be sent. You may include
the following variables: %site_name, %username, %node_url, %node_type,
%title, %teaser, %body. Not all variables will be available in all
contexts.'),
1816
  );
18170
  return $form;
18180
}
1819
1820
/**
1821
 * Validate system_send_email_action form submissions.
1822
 */
18232366
function system_send_email_action_validate($form, $form_state) {
18240
  $form_values = $form_state['values'];
1825
  // Validate the configuration form.
18260
  if (!valid_email_address($form_values['recipient']) &&
$form_values['recipient'] != '%author') {
1827
    // We want the literal %author placeholder to be emphasized in the
error message.
18280
    form_set_error('recipient', t('Please enter a valid email address or
%author.', array('%author' => '%author')));
18290
  }
18300
}
1831
1832
/**
1833
 * Process system_send_email_action form submissions.
1834
 */
18352366
function system_send_email_action_submit($form, $form_state) {
18360
  $form_values = $form_state['values'];
1837
  // Process the HTML form to store configuration. The keyed array that
1838
  // we return will be serialized to the database.
1839
  $params = array(
18400
    'recipient' => $form_values['recipient'],
18410
    'subject'   => $form_values['subject'],
18420
    'message'   => $form_values['message'],
18430
  );
18440
  return $params;
18450
}
1846
1847
/**
1848
 * Implementation of a configurable Drupal action. Sends an email.
1849
 */
18502366
function system_send_email_action($object, $context) {
18510
  global $user;
1852
18530
  switch ($context['hook']) {
18540
    case 'nodeapi':
1855
      // Because this is not an action of type 'node' the node
1856
      // will not be passed as $object, but it will still be available
1857
      // in $context.
18580
      $node = $context['node'];
18590
      break;
1860
    // The comment hook provides nid, in $context.
18610
    case 'comment':
18620
      $comment = $context['comment'];
18630
      $node = node_load($comment->nid);
18640
      break;
18650
    case 'user':
1866
      // Because this is not an action of type 'user' the user
1867
      // object is not passed as $object, but it will still be available
1868
      // in $context.
18690
      $account = $context['account'];
18700
      if (isset($context['node'])) {
18710
        $node = $context['node'];
18720
      }
18730
      elseif ($context['recipient'] == '%author') {
1874
        // If we don't have a node, we don't have a node author.
18750
        watchdog('error', 'Cannot use %author token in this context.');
18760
        return;
18770
      }
18780
      break;
18790
    default:
1880
      // We are being called directly.
18810
      $node = $object;
18820
  }
1883
18840
  $recipient = $context['recipient'];
1885
18860
  if (isset($node)) {
18870
    if (!isset($account)) {
18880
      $account = user_load(array('uid' => $node->uid));
18890
    }
18900
    if ($recipient == '%author') {
18910
      $recipient = $account->mail;
18920
    }
18930
  }
1894
18950
  if (!isset($account)) {
18960
    $account = $user;
1897
18980
  }
18990
  $language = user_preferred_language($account);
19000
  $params = array('account' => $account, 'object' => $object, 'context' =>
$context);
19010
  if (isset($node)) {
19020
    $params['node'] = $node;
19030
  }
1904
19050
  if (drupal_mail('system', 'action_send_email', $recipient, $language,
$params)) {
19060
    watchdog('action', 'Sent email to %recipient', array('%recipient' =>
$recipient));
19070
  }
1908
  else {
19090
    watchdog('error', 'Unable to send email to %recipient',
array('%recipient' => $recipient));
1910
  }
19110
}
1912
1913
/**
1914
 * Implementation of hook_mail().
1915
 */
19162366
function system_mail($key, &$message, $params) {
19170
  $account = $params['account'];
19180
  $context = $params['context'];
1919
  $variables = array(
19200
    '%site_name' => variable_get('site_name', 'Drupal'),
19210
    '%username' => $account->name,
19220
  );
19230
  if ($context['hook'] == 'taxonomy') {
19240
    $object = $params['object'];
19250
    $vocabulary = taxonomy_vocabulary_load($object->vid);
1926
    $variables += array(
19270
      '%term_name' => $object->name,
19280
      '%term_description' => $object->description,
19290
      '%term_id' => $object->tid,
19300
      '%vocabulary_name' => $vocabulary->name,
19310
      '%vocabulary_description' => $vocabulary->description,
19320
      '%vocabulary_id' => $vocabulary->vid,
19330
    );
19340
  }
1935
1936
  // Node-based variable translation is only available if we have a node.
19370
  if (isset($params['node'])) {
19380
    $node = $params['node'];
1939
    $variables += array(
19400
      '%uid' => $node->uid,
19410
      '%node_url' => url('node/' . $node->nid, array('absolute' => TRUE)),
19420
      '%node_type' => node_get_types('name', $node),
19430
      '%title' => $node->title,
19440
      '%teaser' => $node->teaser,
19450
      '%body' => $node->body,
19460
    );
19470
  }
19480
  $subject = strtr($context['subject'], $variables);
19490
  $body = strtr($context['message'], $variables);
19500
  $message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
19510
  $message['body'][] = drupal_html_to_text($body);
19520
}
1953
19542366
function system_message_action_form($context) {
19550
  $form['message'] = array(
19560
    '#type' => 'textarea',
19570
    '#title' => t('Message'),
19580
    '#default_value' => isset($context['message']) ? $context['message'] :
'',
19590
    '#required' => TRUE,
19600
    '#rows' => '8',
19610
    '#description' => t('The message to be displayed to the current user.
You may include the following variables: %site_name, %username, %node_url,
%node_type, %title, %teaser, %body. Not all variables will be available in
all contexts.'),
1962
  );
19630
  return $form;
19640
}
1965
19662366
function system_message_action_submit($form, $form_state) {
19670
  return array('message' => $form_state['values']['message']);
19680
}
1969
1970
/**
1971
 * A configurable Drupal action. Sends a message to the current user's
screen.
1972
 */
19732366
function system_message_action(&$object, $context = array()) {
19740
  global $user;
1975
  $variables = array(
19760
    '%site_name' => variable_get('site_name', 'Drupal'),
19770
    '%username' => $user->name ? $user->name : variable_get('anonymous',
t('Anonymous')),
19780
  );
1979
1980
  // This action can be called in any context, but if placeholders
1981
  // are used a node object must be present to be the source
1982
  // of substituted text.
19830
  switch ($context['hook']) {
19840
    case 'nodeapi':
1985
      // Because this is not an action of type 'node' the node
1986
      // will not be passed as $object, but it will still be available
1987
      // in $context.
19880
      $node = $context['node'];
19890
      break;
1990
    // The comment hook also provides the node, in context.
19910
    case 'comment':
19920
      $comment = $context['comment'];
19930
      $node = node_load($comment->nid);
19940
      break;
19950
    case 'taxonomy':
19960
      $vocabulary = taxonomy_vocabulary_load($object->vid);
19970
      $variables = array_merge($variables, array(
19980
        '%term_name' => $object->name,
19990
        '%term_description' => $object->description,
20000
        '%term_id' => $object->tid,
20010
        '%vocabulary_name' => $vocabulary->name,
20020
        '%vocabulary_description' => $vocabulary->description,
20030
        '%vocabulary_id' => $vocabulary->vid,
2004
        )
20050
      );
20060
      break;
20070
    default:
2008
      // We are being called directly.
20090
      $node = $object;
20100
  }
2011
20120
  if (isset($node) && is_object($node)) {
20130
    $variables = array_merge($variables, array(
20140
      '%uid' => $node->uid,
20150
      '%node_url' => url('node/' . $node->nid, array('absolute' => TRUE)),
20160
      '%node_type' => check_plain(node_get_types('name', $node)),
20170
      '%title' => filter_xss($node->title),
20180
      '%teaser' => filter_xss($node->teaser),
20190
      '%body' => filter_xss($node->body),
2020
      )
20210
    );
20220
  }
20230
  $context['message'] = strtr($context['message'], $variables);
20240
  drupal_set_message($context['message']);
20250
}
2026
2027
/**
2028
 * Implementation of a configurable Drupal action. Redirect user to a URL.
2029
 */
20302366
function system_goto_action_form($context) {
20316
  $form['url'] = array(
20326
    '#type' => 'textfield',
20336
    '#title' => t('URL'),
20346
    '#description' => t('The URL to which the user should be redirected.
This can be an internal URL like node/1234 or an external URL like
http://drupal.org.'),
20356
    '#default_value' => isset($context['url']) ? $context['url'] : '',
20366
    '#required' => TRUE,
2037
  );
20386
  return $form;
20390
}
2040
20412366
function system_goto_action_submit($form, $form_state) {
2042
  return array(
20432
    'url' => $form_state['values']['url']
20442
  );
20450
}
2046
20472366
function system_goto_action($object, $context) {
20480
  drupal_goto($context['url']);
20490
}
2050
2051
/**
2052
 * Implementation of a Drupal action.
2053
 * Blocks the user's IP address.
2054
 */
20552366
function system_block_ip_action() {
20560
  $ip = ip_address();
20570
  db_query("INSERT INTO {blocked_ips} (ip) VALUES ('%s')", $ip);
20580
  watchdog('action', 'Banned IP address %ip', array('%ip' => $ip));
20590
}
2060
2061
/**
2062
 * Generate an array of time zones and their local time&date.
2063
 */
20642366
function _system_zonelist() {
206515
  $timestamp = REQUEST_TIME;
206615
  $zonelist = array(-11, -10, -9.5, -9, -8, -7, -6, -5, -4, -3.5, -3, -2,
-1, 0, 1, 2, 3, 3.5, 4, 5, 5.5, 5.75, 6, 6.5, 7, 8, 9, 9.5, 10, 10.5, 11,
11.5, 12, 12.75, 13, 14);
206715
  $zones = array();
206815
  foreach ($zonelist as $offset) {
206915
    $zone = $offset * 3600;
207015
    $zones[$zone] = format_date($timestamp, 'custom',
variable_get('date_format_long', 'l, F j, Y - H:i') . ' O', $zone);
207115
  }
207215
  return $zones;
20730
}
2074
2075
/**
2076
 * Checks whether the server is capable of issuing HTTP requests.
2077
 *
2078
 * The function sets the drupal_http_request_fail system variable to TRUE
if
2079
 * drupal_http_request() does not work and then the system status report
page
2080
 * will contain an error.
2081
 *
2082
 * @return
2083
 *  Whether the admin/reports/request-test page can be requested via HTTP
2084
 *  and contains the same output as if called via the menu system.
2085
 */
20862366
function system_check_http_request() {
2087
  // Check whether we can do any request at all. First get the results for
2088
  // a very simple page which has access TRUE set via the menu system.
Then,
2089
  // try to drupal_http_request() the same page and compare.
20900
  ob_start();
20910
  $path = 'admin/reports/request-test';
20920
  menu_execute_active_handler($path);
20930
  $nothing = ob_get_contents();
20940
  ob_end_clean();
20950
  $result = drupal_http_request(url($path, array('absolute' => TRUE)));
20960
  $works = isset($result->data) && $result->data == $nothing;
20970
  variable_set('drupal_http_request_fails', !$works);
20980
  return $works;
20990
}
2100
2101
/**
2102
 * Format the Powered by Drupal text.
2103
 *
2104
 * @ingroup themeable
2105
 */
21062366
function theme_system_powered_by($image_path) {
21071740
  $image = theme('image', $image_path, t('Powered by Drupal, an open source
content management system'), t('Powered by Drupal, an open source content
management system'));
21081740
  return l($image, 'http://drupal.org', array('html' => TRUE, 'absolute' =>
TRUE, 'external' => TRUE));
21090
}
2110
2111
/**
2112
 * Display the link to show or hide inline help descriptions.
2113
 *
2114
 * @ingroup themeable
2115
 */
21162366
function theme_system_compact_link() {
211722
  $output = '<div class="compact-link">';
211822
  if (system_admin_compact_mode()) {
21190
    $output .= l(t('Show descriptions'), 'admin/compact/off',
array('attributes' => array('title' => t('Expand layout to include
descriptions.')), 'query' => drupal_get_destination()));
21200
  }
2121
  else {
212222
    $output .= l(t('Hide descriptions'), 'admin/compact/on',
array('attributes' => array('title' => t('Compress layout by hiding
descriptions.')), 'query' => drupal_get_destination()));
2123
  }
212422
  $output .= '</div>';
2125
212622
  return $output;
21270
}
2128
2129
2130
/**
2131
 * Send Drupal and the major version number in the META GENERATOR HTML.
2132
 *
2133
 * @ingroup themeable
2134
 */
21352366
function theme_meta_generator_html($version = VERSION) {
21361740
  drupal_set_html_head('<meta name="Generator" content="Drupal ' . $version
. ' (http://drupal.org)" />');
21371740
}
2138
2139
/**
2140
 * Send Drupal and the major version number in the HTTP headers.
2141
 *
2142
 * @ingroup themeable
2143
 */
21442366
function theme_meta_generator_header($version = VERSION) {
21451740
  drupal_set_header('X-Generator: Drupal ' . $version . '
(http://drupal.org)');
21461740
}
2147
2148
/**
2149
 * Implementation of hook_image_toolkits().
2150
 */
21512366
function system_image_toolkits() {
21520
  return array('gd');
21530
}
21542366