system.module 64.6 KB
Newer Older
Dries's avatar
 
Dries committed
1
<?php
2
// $Id$
Dries's avatar
 
Dries committed
3

Dries's avatar
   
Dries committed
4
5
6
7
8
/**
 * @file
 * Configuration system that lets administrators modify the workings of the site.
 */

Gábor Hojtsy's avatar
Gábor Hojtsy committed
9
define('VERSION', '6.0-dev');
10
define('DRUPAL_CORE_COMPATIBILITY', '6.x');
11

12
13
14
15
16
define('DRUPAL_MINIMUM_PHP',    '4.3.3');
define('DRUPAL_MINIMUM_MYSQL',  '4.1.0'); // If using MySQL
define('DRUPAL_MINIMUM_PGSQL',  '7.4');   // If using PostgreSQL
define('DRUPAL_MINIMUM_APACHE', '1.3');   // If using Apache

17
18
19
// Maximum age of temporary files in seconds.
define('DRUPAL_MAXIMUM_TEMP_FILE_AGE', 1440);

Dries's avatar
   
Dries committed
20
21
22
/**
 * Implementation of hook_help().
 */
23
function system_help($path, $arg) {
24
25
  global $base_url;

26
  switch ($path) {
27
    case 'admin/help#system':
28
      $output = '<p>'. t('The system module provides system-wide defaults such as running jobs at a particular time, and storing web pages to improve efficiency. The ability to run scheduled jobs makes administering the website more usable, as administrators do not have to manually start jobs. The storing of web pages, or caching, allows the site to efficiently re-use web pages and improve website performance. The system module provides control over preferences, behaviors including visual and operational settings.') .'</p>';
29
      $output .= '<p>'. t('Some modules require regularly scheduled actions, such as cleaning up logfiles. Cron, which stands for chronograph, is a periodic command scheduler executing commands at intervals specified in seconds. It can be used to control the execution of daily, weekly and monthly jobs (or anything with a period measured in seconds). The aggregator module periodically updates feeds using cron. Ping periodically notifies services of new content on your site. Search periodically indexes the content on your site. Automating tasks is one of the best ways to keep a system running smoothly, and if most of your administration does not require your direct involvement, cron is an ideal solution. Cron can, if necessary, also be run manually.') .'</p>';
30
      $output .= '<p>'. t("There is a caching mechanism which stores dynamically generated web pages in a database. By caching a web page, the system module does not have to create the page each time someone wants to view it, instead it takes only one SQL query to display it, reducing response time and the server's load. Only pages requested by <em>anonymous</em> users are cached. In order to reduce server load and save bandwidth, the system module stores and sends cached pages compressed.") .'</p>';
31
      $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="@system">System page</a>.', array('@system' => 'http://drupal.org/handbook/modules/system/')) .'</p>';
32
      return $output;
33
    case 'admin':
34
      return '<p>'. t('Welcome to the administration section. Here you may control how your site functions.') .'</p>';
35
    case 'admin/by-module':
36
      return '<p>'. t('This page shows you all available administration tasks for each module.') .'</p>';
37
    case 'admin/build/themes':
38
      return '<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. Alternately, to override these settings in a specific theme, click the "configure" link for the corresponding theme. Note that different themes may have different regions available for rendering content like blocks. If you want consistency in what your users see, you may wish to enable only one theme.') .'</p>';
39
40
    case 'admin/build/themes/settings/'. $arg[4]:
      $reference = explode('.', $arg[4], 2);
41
      $theme = array_pop($reference);
42
      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>';
43
44
    case 'admin/build/themes/settings':
      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>';
45
    case 'admin/build/modules':
46
      $output = '<p>'. t('Modules are plugins for Drupal that extend its core functionality. Here you can select which modules are enabled. Once a module is enabled, new <a href="@permissions">permissions</a> might be made available. Modules can automatically be temporarily disabled to reduce server load when your site becomes extremely busy by enabling the throttle.module and checking throttle.', array('@permissions' => url('admin/user/permissions')));
47
48
49
50
51
52
      if (module_exists('throttle')) {
        $output .= ' '. t('The auto-throttle functionality must be enabled on the <a href="@throttle">throttle configuration page</a> after having enabled the throttle module.', array('@throttle' => url('admin/settings/throttle')));
      }
      $output .= '</p>';
      $output .= t('<p>It is important that <a href="@update-php">update.php</a> is run every time a module is updated to a newer version.</p><p>You can find all administration tasks belonging to a particular module on the <a href="@by-module">administration by module page</a>.</p>', array('@update-php' => $base_url .'/update.php', '@by-module' => url('admin/by-module')));
      return $output;
53
    case 'admin/build/modules/uninstall':
54
      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>';
55
56
57
58
    case 'admin/build/block/configure':
      if ($arg[4] == 'system' && $arg[5] == 0) {
        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>';
      }
59
      break;
60
61
62
63
64
65
66
    case 'admin/settings/actions':
    case 'admin/settings/actions/manage':
      $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>';
      $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>';
      if (module_exists('trigger')) {
        $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>';
      }
67
      return $output;
68
69
    case 'admin/settings/actions/configure':
      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").');
70
    case 'admin/reports/status':
71
      return '<p>'. t("Here you can find a short overview of your Drupal site's parameters as well as any problems detected with your installation. It is useful to copy/paste this information when you need support.") .'</p>';
72
  }
Dries's avatar
   
Dries committed
73
74
}

75
76
77
78
function system_theme() {
  return array_merge(drupal_common_themes(), array(
    'system_theme_select_form' => array(
      'arguments' => array('form' => NULL),
79
      'file' => 'system.admin.inc',
80
81
82
    ),
    'system_themes_form' => array(
      'arguments' => array('form' => NULL),
83
      'file' => 'system.admin.inc',
84
85
86
    ),
    'system_modules' => array(
      'arguments' => array('form' => NULL),
87
      'file' => 'system.admin.inc',
88
89
90
    ),
    'system_modules_uninstall' => array(
      'arguments' => array('form' => NULL),
91
      'file' => 'system.admin.inc',
92
93
94
    ),
    'status_report' => array(
      'arguments' => array('requirements' => NULL),
95
      'file' => 'system.admin.inc',
96
97
98
    ),
    'admin_page' => array(
      'arguments' => array('blocks' => NULL),
99
      'file' => 'system.admin.inc',
100
101
102
    ),
    'admin_block' => array(
      'arguments' => array('block' => NULL),
103
      'file' => 'system.admin.inc',
104
105
106
    ),
    'admin_block_content' => array(
      'arguments' => array('content' => NULL),
107
      'file' => 'system.admin.inc',
108
109
110
    ),
    'system_admin_by_module' => array(
      'arguments' => array('menu_items' => NULL),
111
      'file' => 'system.admin.inc',
112
    ),
113
114
115
    'system_powered_by' => array(
      'arguments' => array('image_path' => NULL),
    ),
116
117
  ));
}
Dries's avatar
   
Dries committed
118
119
120
/**
 * Implementation of hook_perm().
 */
Dries's avatar
 
Dries committed
121
function system_perm() {
122
  return array('administer site configuration', 'access administration pages', 'administer actions', 'select different theme', 'administer files');
Dries's avatar
   
Dries committed
123
124
}

125
126
127
128
129
/**
 * Implementation of hook_elements().
 */
function system_elements() {
  // Top level form
130
  $type['form'] = array('#method' => 'post', '#action' => request_uri());
131
132

  // Inputs
133
134
135
136
137
  $type['submit'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => TRUE, '#process' => array('form_expand_ahah'));
  $type['button'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => FALSE, '#process' => array('form_expand_ahah'));
  $type['image_button'] = array('#input' => TRUE, '#button_type' => 'submit','#executes_submit_callback' => TRUE, '#process' => array('form_expand_ahah'), '#return_value' => TRUE, '#has_garbage_value' => TRUE, '#src' => NULL);
  $type['textfield'] = array('#input' => TRUE, '#size' => 60, '#maxlength' => 128, '#autocomplete_path' => FALSE, '#process' => array('form_expand_ahah'));
  $type['password'] = array('#input' => TRUE, '#size' => 60, '#maxlength' => 128, '#process' => array('form_expand_ahah'));
138
  $type['password_confirm'] = array('#input' => TRUE, '#process' => array('expand_password_confirm'));
139
  $type['textarea'] = array('#input' => TRUE, '#cols' => 60, '#rows' => 5, '#resizable' => TRUE, '#process' => array('form_expand_ahah'));
140
  $type['radios'] = array('#input' => TRUE, '#process' => array('expand_radios'));
141
  $type['radio'] = array('#input' => TRUE, '#default_value' => NULL, '#process' => array('form_expand_ahah'));
142
  $type['checkboxes'] = array('#input' => TRUE, '#process' => array('expand_checkboxes'), '#tree' => TRUE);
143
144
145
  $type['checkbox'] = array('#input' => TRUE, '#return_value' => 1, '#process' => array('form_expand_ahah'));
  $type['select'] = array('#input' => TRUE, '#size' => 0, '#multiple' => FALSE, '#process' => array('form_expand_ahah'));
  $type['weight'] = array('#input' => TRUE, '#delta' => 10, '#default_value' => 0, '#process' => array('process_weight', 'form_expand_ahah'));
146
  $type['date'] = array('#input' => TRUE, '#process' => array('expand_date'), '#element_validate' => array('date_validate'));
147
  $type['file'] = array('#input' => TRUE, '#size' => 60);
148
149

  // Form structure
150
  $type['item'] = array('#value' => '');
151
  $type['hidden'] = array('#input' => TRUE, '#process' => array('form_expand_ahah'));
152
153
  $type['value'] = array('#input' => TRUE);
  $type['markup'] = array('#prefix' => '', '#suffix' => '');
154
  $type['fieldset'] = array('#collapsible' => FALSE, '#collapsed' => FALSE, '#value' => NULL, '#process' => array('form_expand_ahah'));
Dries's avatar
Dries committed
155
  $type['token'] = array('#input' => TRUE);
156
157
158
  return $type;
}

Dries's avatar
   
Dries committed
159
/**
Dries's avatar
   
Dries committed
160
 * Implementation of hook_menu().
Dries's avatar
   
Dries committed
161
 */
162
163
function system_menu() {
  $items['system/files'] = array(
164
    'title' => 'File download',
165
166
167
168
169
    'page callback' => 'file_download',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  $items['admin'] = array(
170
    'title' => 'Administer',
171
172
173
    'access arguments' => array('access administration pages'),
    'page callback' => 'system_main_admin_page',
    'weight' => 9,
174
    'file' => 'system.admin.inc',
175
176
  );
  $items['admin/compact'] = array(
177
    'title' => 'Compact mode',
178
179
    'page callback' => 'system_admin_compact_page',
    'type' => MENU_CALLBACK,
180
    'file' => 'system.admin.inc',
181
182
  );
  $items['admin/by-task'] = array(
183
    'title' => 'By task',
184
    'page callback' => 'system_main_admin_page',
185
    'file' => 'system.admin.inc',
186
187
188
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/by-module'] = array(
189
    'title' => 'By module',
190
    'page callback' => 'system_admin_by_module',
191
    'file' => 'system.admin.inc',
192
193
194
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
  );
195
196
197
198
199
200
201
202
203
204
  $items['admin/content'] = array(
    'title' => 'Content management',
    'description' => "Manage your site's content.",
    'position' => 'left',
    'weight' => -10,
    'page callback' => 'system_admin_menu_block_page',
    'access arguments' => array('access administration pages'),
    'file' => 'system.admin.inc',
  );

205
206
  // menu items that are basically just menu blocks
  $items['admin/settings'] = array(
207
208
    'title' => 'Site configuration',
    'description' => 'Adjust basic site configuration options.',
209
210
211
212
    'position' => 'right',
    'weight' => -5,
    'page callback' => 'system_settings_overview',
    'access arguments' => array('administer site configuration'),
213
    'file' => 'system.admin.inc',
214
215
  );
  $items['admin/build'] = array(
216
217
    'title' => 'Site building',
    'description' => 'Control how your site looks and feels.',
218
219
220
221
    'position' => 'right',
    'weight' => -10,
    'page callback' => 'system_admin_menu_block_page',
    'access arguments' => array('administer site configuration'),
222
    'file' => 'system.admin.inc',
223
224
  );
  $items['admin/settings/admin'] = array(
225
226
    'title' => 'Administration theme',
    'description' => 'Settings for how your administrative pages should look.',
227
228
229
230
    'position' => 'left',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_admin_theme_settings'),
    'block callback' => 'system_admin_theme_settings',
231
    'file' => 'system.admin.inc',
232
233
234
  );
  // Themes:
  $items['admin/build/themes'] = array(
235
236
    'title' => 'Themes',
    'description' => 'Change which theme your site uses or allows users to set.',
237
    'page callback' => 'drupal_get_form',
238
    'page arguments' => array('system_themes_form', NULL),
239
    'file' => 'system.admin.inc',
240
241
  );
  $items['admin/build/themes/select'] = array(
242
243
    'title' => 'List',
    'description' => 'Select the default theme.',
244
245
246
247
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -1,
  );
  $items['admin/build/themes/settings'] = array(
248
    'title' => 'Configure',
249
    'page arguments' => array('system_theme_settings'),
250
251
252
253
    'type' => MENU_LOCAL_TASK,
  );
  // Theme configuration subtabs
  $items['admin/build/themes/settings/global'] = array(
254
    'title' => 'Global settings',
255
256
257
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -1,
  );
Dries's avatar
   
Dries committed
258

259
260
261
  foreach (list_themes() as $theme) {
    if ($theme->status) {
      $items['admin/build/themes/settings/'. $theme->name] = array(
262
        'title' => $theme->info['name'],
263
264
265
        'page arguments' => array('system_theme_settings', $theme->name),
        'type' => MENU_LOCAL_TASK,
      );
Dries's avatar
   
Dries committed
266
    }
Dries's avatar
   
Dries committed
267
  }
drumm's avatar
drumm committed
268

269
270
  // Modules:
  $items['admin/build/modules'] = array(
271
272
    'title' => 'Modules',
    'description' => 'Enable or disable add-on modules for your site.',
273
274
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_modules'),
275
    'file' => 'system.admin.inc',
276
277
  );
  $items['admin/build/modules/list'] = array(
278
    'title' => 'List',
279
280
281
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/build/modules/list/confirm'] = array(
282
    'title' => 'List',
283
284
285
    'type' => MENU_CALLBACK,
  );
  $items['admin/build/modules/uninstall'] = array(
286
    'title' => 'Uninstall',
287
288
289
290
    'page arguments' => array('system_modules_uninstall'),
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/build/modules/uninstall/confirm'] = array(
291
    'title' => 'Uninstall',
292
293
    'type' => MENU_CALLBACK,
  );
Dries's avatar
   
Dries committed
294

295
  // Actions:
296
  $items['admin/settings/actions'] = array(
297
298
299
300
301
    'title' => 'Actions',
    'description' => 'Manage the actions defined for your site.',
    'access arguments' => array('administer actions'),
    'page callback' => 'system_actions_manage'
  );
302
  $items['admin/settings/actions/manage'] = array(
303
304
305
306
307
308
    'title' => 'Manage actions',
    'description' => 'Manage the actions defined for your site.',
    'page callback' => 'system_actions_manage',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -2,
  );
309
310
  $items['admin/settings/actions/configure'] = array(
    'title' => 'Configure an advanced action',
311
312
313
314
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_actions_configure'),
    'type' => MENU_CALLBACK,
  );
315
  $items['admin/settings/actions/delete/%actions'] = array(
316
317
318
319
320
321
    'title' => 'Delete action',
    'description' => 'Delete an action.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_actions_delete_form', 4),
    'type' => MENU_CALLBACK,
  );
322
  $items['admin/settings/actions/orphan'] = array(
323
324
325
326
327
    'title' => 'Remove orphans',
    'page callback' => 'system_actions_remove_orphans',
    'type' => MENU_CALLBACK,
  );

328
329
  // Settings:
  $items['admin/settings/site-information'] = array(
330
331
    'title' => 'Site information',
    'description' => 'Change basic site information, such as the site name, slogan, e-mail address, mission, front page and more.',
332
333
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_site_information_settings'),
334
    'file' => 'system.admin.inc',
335
336
  );
  $items['admin/settings/error-reporting'] = array(
337
338
    'title' => 'Error reporting',
    'description' => 'Control how Drupal deals with errors including 403/404 errors as well as PHP error reporting.',
339
340
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_error_reporting_settings'),
341
    'file' => 'system.admin.inc',
342
  );
343
  $items['admin/settings/logging'] = array(
344
345
    'title' => 'Logging and alerts',
    'description' => "Settings for logging and alerts modules. Various modules can route Drupal's system events to different destination, such as syslog, database, email, ...etc.",
346
    'page callback' => 'system_logging_overview',
347
    'file' => 'system.admin.inc',
348
  );
349
  $items['admin/settings/performance'] = array(
350
    'title' => 'Performance',
351
    'description' => 'Enable or disable page caching for anonymous users and set CSS and JS bandwidth optimization options.',
352
353
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_performance_settings'),
354
    'file' => 'system.admin.inc',
355
356
  );
  $items['admin/settings/file-system'] = array(
357
358
    'title' => 'File system',
    'description' => 'Tell Drupal where to store uploaded files and how they are accessed.',
359
360
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_file_system_settings'),
361
    'file' => 'system.admin.inc',
362
363
  );
  $items['admin/settings/image-toolkit'] = array(
364
365
    'title' => 'Image toolkit',
    'description' => 'Choose which image toolkit to use if you have installed optional toolkits.',
366
367
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_image_toolkit_settings'),
368
    'file' => 'system.admin.inc',
369
370
  );
  $items['admin/content/rss-publishing'] = array(
371
372
    'title' => 'RSS publishing',
    'description' => 'Configure the number of items per feed and whether feeds should be titles/teasers/full-text.',
373
374
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_rss_feeds_settings'),
375
    'access arguments' => array('administer site configuration'),
376
    'file' => 'system.admin.inc',
377
378
  );
  $items['admin/settings/date-time'] = array(
379
380
    'title' => 'Date and time',
    'description' => "Settings for how Drupal displays date and time, as well as the system's default timezone.",
381
382
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_date_time_settings'),
383
    'file' => 'system.admin.inc',
384
  );
385
  $items['admin/settings/date-time/lookup'] = array(
386
    'title' => 'Date and time lookup',
387
388
    'type' => MENU_CALLBACK,
    'page callback' => 'system_date_time_lookup',
389
    'file' => 'system.admin.inc',
390
  );
391
  $items['admin/settings/site-maintenance'] = array(
392
393
    'title' => 'Site maintenance',
    'description' => 'Take the site off-line for maintenance or bring it back online.',
394
395
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_site_maintenance_settings'),
396
    'file' => 'system.admin.inc',
397
398
  );
  $items['admin/settings/clean-urls'] = array(
399
400
    'title' => 'Clean URLs',
    'description' => 'Enable or disable clean URLs for your site.',
401
402
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_clean_url_settings'),
403
    'file' => 'system.admin.inc',
404
  );
405
406
407
408
409
410
411
  $items['admin/settings/clean-urls/check'] = array(
    'title' => 'Clean URL check',
    'page callback' => 'drupal_json',
    'page arguments' => array(array('status' => TRUE)),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
412

413
414
415
416
  // Reports:
  $items['admin/reports'] = array(
    'title' => 'Reports',
    'description' => 'View reports from system logs and other status information.',
417
418
419
    'page callback' => 'system_admin_menu_block_page',
    'weight' => 5,
    'position' => 'left',
420
    'file' => 'system.admin.inc',
421
  );
422
  $items['admin/reports/status'] = array(
423
424
    'title' => 'Status report',
    'description' => "Get a status report about your site's operation and any detected problems.",
425
426
427
    'page callback' => 'system_status',
    'weight' => 10,
    'access arguments' => array('administer site configuration'),
428
    'file' => 'system.admin.inc',
429
  );
430
  $items['admin/reports/status/run-cron'] = array(
431
    'title' => 'Run cron',
432
433
    'page callback' => 'system_run_cron',
    'type' => MENU_CALLBACK,
434
    'file' => 'system.admin.inc',
435
  );
436
  $items['admin/reports/status/php'] = array(
437
    'title' => 'PHP',
438
439
    'page callback' => 'system_php',
    'type' => MENU_CALLBACK,
440
    'file' => 'system.admin.inc',
441
  );
442
  $items['admin/reports/status/sql'] = array(
443
    'title' => 'SQL',
444
445
    'page callback' => 'system_sql',
    'type' => MENU_CALLBACK,
446
    'file' => 'system.admin.inc',
447
  );
448
449
450
451
452
  // Default page for batch operations
  $items['batch'] = array(
    'page callback' => 'system_batch_page',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
453
    'file' => 'system.admin.inc',
454
  );
Dries's avatar
   
Dries committed
455
  return $items;
Dries's avatar
 
Dries committed
456
457
}

458
459
function system_init() {
  // Use the administrative theme if the user is looking at a page in the admin/* path.
460
  if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit'))) {
461
462
463
464
465
466
467
468
    global $custom_theme;
    $custom_theme = variable_get('admin_theme', '0');
    drupal_add_css(drupal_get_path('module', 'system') .'/admin.css', 'module');
  }

  // Add the CSS for this module.
  drupal_add_css(drupal_get_path('module', 'system') .'/defaults.css', 'module');
  drupal_add_css(drupal_get_path('module', 'system') .'/system.css', 'module');
469
  drupal_add_css(drupal_get_path('module', 'system') .'/system-menus.css', 'module');
470
471
}

Dries's avatar
   
Dries committed
472
473
474
475
476
/**
 * Implementation of hook_user().
 *
 * Allows users to individually set their theme and time zone.
 */
477
function system_user($type, $edit, &$user, $category = NULL) {
Dries's avatar
Dries committed
478
  if ($type == 'form' && $category == 'account') {
479
    $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);
Dries's avatar
Dries committed
480

481
    if (variable_get('configurable_timezones', 1)) {
Steven Wittens's avatar
Steven Wittens committed
482
      $zones = _system_zonelist();
483
      $form['timezone'] = array(
484
        '#type' => 'fieldset',
485
486
487
488
        '#title' => t('Locale settings'),
        '#weight' => 6,
        '#collapsible' => TRUE,
      );
489
      $form['timezone']['timezone'] = array(
490
491
492
493
494
        '#type' => 'select',
        '#title' => t('Time zone'),
        '#default_value' => strlen($edit['timezone']) ? $edit['timezone'] : variable_get('date_default_timezone', 0),
        '#options' => $zones,
        '#description' => t('Select your current local time. Dates and times throughout this site will be displayed using this time zone.'),
495
      );
Dries's avatar
   
Dries committed
496
    }
Dries's avatar
Dries committed
497

498
    return $form;
Dries's avatar
   
Dries committed
499
  }
Dries's avatar
   
Dries committed
500
501
}

502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
/**
 * Generate a block with a promotional link to Drupal.org.
 */
function system_block($op = 'list', $delta = 0, $edit = NULL) {
  switch($op) {
    case 'list':
      $blocks[0] = array(
        'info' => t('Powered by Drupal'),
        'weight' => '10',
      );
      return $blocks;
    case 'configure':
      // Compile a list of fields to show
      $form['wrapper']['color'] = array(
        '#type' => 'select',
        '#title' => t('Badge color'),
        '#default_value' => variable_get('drupal_badge_color', 'powered-blue'),
        '#options' => array('powered-black' => t('Black'), 'powered-blue' => t('Blue'), 'powered-gray' => t('Gray')),
      );
      $form['wrapper']['size'] = array(
        '#type' => 'select',
        '#title' => t('Badge size'),
        '#default_value' => variable_get('drupal_badge_size', '80x15'),
        '#options' => array('80x15' => t('Small'), '88x31' => t('Medium'), '135x42' => t('Large')),
      );
      return $form;
    case 'save':
      variable_set('drupal_badge_color', $edit['color']);
      variable_set('drupal_badge_size', $edit['size']);
      break;
    case 'view':
      $image_path = 'misc/'. variable_get('drupal_badge_color', 'powered-blue') .'-'. variable_get('drupal_badge_size', '80x15') .'.png';
      $block['subject'] = NULL; // Don't display a title
      $block['content'] = theme('system_powered_by', $image_path);
      return $block;
  }
}

540
541
542
/**
 * Provide a single block on the administration overview page.
 */
543
function system_admin_menu_block($item) {
544
  $content = array();
545
  if (!isset($item['mlid'])) {
546
    $item += db_fetch_array(db_query("SELECT mlid, menu_name FROM {menu_links} ml WHERE ml.router_path = '%s' AND module = 'system'", $item['path']));
547
  }
548
  $result = db_query("
549
    SELECT m.*, ml.*
550
551
    FROM {menu_links} ml
    INNER JOIN {menu_router} m ON ml.router_path = m.path
552
    WHERE ml.plid = %d AND ml.menu_name = '%s' AND hidden = 0", $item['mlid'], $item['menu_name']);
553
  while ($item = db_fetch_array($result)) {
554
    _menu_link_translate($item);
555
    if (!$item['access']) {
556
      continue;
557
    }
558
559
560
561
562
563
564
565
    // The link 'description' either derived from the hook_menu 'description' or
    // entered by the user via menu module is saved as the title attribute.
    if (!empty($item['options']['attributes']['title'])) {
      $item['description'] = $item['options']['attributes']['title'];
    }
    // Prepare for sorting as in function _menu_tree_check_access().
    // The weight is offset so it is always positive, with a uniform 5-digits.
    $content[(50000 + $item['weight']) .' '. $item['title'] .' '. $item['mlid']] = $item;
566
  }
567
  ksort($content);
568
569
570
571
  return $content;
}


572
function system_admin_theme_submit($form, &$form_state) {
573
  // If we're changing themes, make sure the theme has its blocks initialized.
574
  if ($form_state['values']['admin_theme'] && $form_state['values']['admin_theme'] != variable_get('admin_theme', '0')) {
575
576
    $result = db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme = '%s'", $form_state['values']['admin_theme']));
    if (!$result) {
577
      system_initialize_theme_blocks($form_state['values']['admin_theme']);
578
579
580
581
    }
  }
}

582
/**
583
584
585
586
587
588
589
590
591
592
593
 * Returns a fieldset containing the theme select form.
 *
 * @param $description
 *    description of the fieldset
 * @param $default_value
 *    default value of theme radios
 * @param $weight
 *    weight of the fieldset
 * @return
 *    a form array
 */
594
function system_theme_select_form($description = '', $default_value = '', $weight = 0) {
595
  if (user_access('select different theme')) {
596
    $enabled = array();
597
598
599
    $themes = list_themes();

    foreach ($themes as $theme) {
600
601
602
603
604
605
606
607
608
      if ($theme->status) {
        $enabled[] = $theme;
      }
    }

    if (count($enabled) > 1) {
      ksort($enabled);

      $form['themes'] = array(
Dries's avatar
Dries committed
609
610
611
612
        '#type' => 'fieldset',
        '#title' => t('Theme configuration'),
        '#description' => $description,
        '#collapsible' => TRUE,
613
614
615
616
617
        '#theme' => 'system_theme_select_form'
      );

      foreach ($enabled as $info) {
        // For the default theme, revert to an empty string so the user's theme updates when the site theme is changed.
618
        $info->key = $info->name == variable_get('theme_default', 'garland') ? '' : $info->name;
619

620
621
622
623
624
625
626
627
628
629
630
        $screenshot = NULL;
        $theme_key = $info->name;
        while ($theme_key) {
          if (file_exists($themes[$theme_key]->info['screenshot'])) {
            $screenshot = $themes[$theme_key]->info['screenshot'];
            break;
          }
          $theme_key = isset($themes[$theme_key]->info['base theme']) ? $themes[$theme_key]->info['base theme'] : NULL;
        }

        $screenshot = $screenshot ? theme('image', $screenshot, t('Screenshot for %theme theme', array('%theme' => $info->name)), '', array('class' => 'screenshot'), FALSE) : t('no screenshot');
631

632
        $form['themes'][$info->key]['screenshot'] = array('#value' => $screenshot);
633
        $form['themes'][$info->key]['description'] = array('#type' => 'item', '#title' => $info->name,  '#value' => dirname($info->filename) . ($info->name == variable_get('theme_default', 'garland') ? '<br /> <em>'. t('(site default theme)') .'</em>' : ''));
634
635
636
637
638
639
640
641
642
643
        $options[$info->key] = '';
      }

      $form['themes']['theme'] = array('#type' => 'radios', '#options' => $options, '#default_value' => $default_value ? $default_value : '');
      $form['#weight'] = $weight;
      return $form;
    }
  }
}

644
645
/**
 * Checks the existence of the directory specified in $form_element. This
Dries's avatar
Dries committed
646
 * function is called from the system_settings form to check both the
647
648
649
650
651
652
653
 * file_directory_path and file_directory_temp directories. If validation
 * fails, the form element is flagged with an error from within the
 * file_check_directory function.
 *
 * @param $form_element
 *   The form element containing the name of the directory to check.
 */
654
function system_check_directory($form_element) {
655
656
657
658
  file_check_directory($form_element['#value'], FILE_CREATE_DIRECTORY, $form_element['#parents'][0]);
  return $form_element;
}

Dries's avatar
   
Dries committed
659
660
661
662
/**
 * Retrieves the current status of an array of files in the system table.
 */
function system_get_files_database(&$files, $type) {
Dries's avatar
   
Dries committed
663
  // Extract current files from database.
664
  $result = db_query("SELECT filename, name, type, status, throttle, schema_version FROM {system} WHERE type = '%s'", $type);
Dries's avatar
   
Dries committed
665
  while ($file = db_fetch_object($result)) {
666
    if (isset($files[$file->name]) && is_object($files[$file->name])) {
667
      $file->old_filename = $file->filename;
Dries's avatar
   
Dries committed
668
      foreach ($file as $key => $value) {
669
        if (!isset($files[$file->name]) || !isset($files[$file->name]->$key)) {
Dries's avatar
Dries committed
670
671
          $files[$file->name]->$key = $value;
        }
Dries's avatar
   
Dries committed
672
      }
673
    }
Dries's avatar
 
Dries committed
674
  }
Dries's avatar
   
Dries committed
675
}
Dries's avatar
 
Dries committed
676

677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
function system_theme_default() {
  // Prepare defaults for themes.
  return array(
    'regions' => array(
      'left' => 'Left sidebar',
      'right' => 'Right sidebar',
      'content' => 'Content',
      'header' => 'Header',
      'footer' => 'Footer',
    ),
    'description' => '',
    'features' => array(
      'comment_user_picture',
      'favicon',
      'mission',
      'logo',
      'name',
      'node_user_picture',
      'search',
696
697
698
      'slogan',
      'primary_links',
      'secondary_links',
699
    ),
700
701
702
703
    'stylesheets' => array(
      'all' => array('style.css')
    ),
    'scripts' => array('script.js'),
704
    'screenshot' => 'screenshot.png',
705
    'php' => DRUPAL_MINIMUM_PHP,
706
707
708
  );
}

Dries's avatar
   
Dries committed
709
710
711
/**
 * Collect data about all currently available themes
 */
Dries's avatar
Dries committed
712
713
function system_theme_data() {
  // Find themes
714
  $themes = drupal_system_listing('\.info$', 'themes');
Dries's avatar
Dries committed
715

Dries's avatar
   
Dries committed
716
  // Find theme engines
717
  $engines = drupal_system_listing('\.engine$', 'themes/engines');
Dries's avatar
Dries committed
718
719

  // Remove all theme engines from the system table
720
  db_query("DELETE FROM {system} WHERE type = '%s'", 'theme_engine');
Dries's avatar
   
Dries committed
721
722

  foreach ($engines as $engine) {
Dries's avatar
   
Dries committed
723
    // Insert theme engine into system table
Dries's avatar
Dries committed
724
725
726
    drupal_get_filename('theme_engine', $engine->name, $engine->filename);
    drupal_load('theme_engine', $engine->name);
    db_query("INSERT INTO {system} (name, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', %d, %d, %d)", $engine->name, 'theme_engine', $engine->filename, 1, 0, 0);
727
  }
Dries's avatar
Dries committed
728

729
  $defaults = system_theme_default();
730

731
732
733
734
  $sub_themes = array();
  // Read info files for each theme
  foreach ($themes as $key => $theme) {
    $themes[$key]->info = drupal_parse_info_file($theme->filename) + $defaults;
735
736
737
738
739

    // Invoke hook_system_info_alter() to give installed modules a chance to
    // modify the data in the .info files if necessary.
    drupal_alter('system_info', $themes[$key]->info, $themes[$key]);

740
741
742
743
744
745
746
747
    if (!empty($themes[$key]->info['base theme'])) {
      $sub_themes[] = $key;
    }
    if (empty($themes[$key]->info['engine'])) {
      $filename = dirname($themes[$key]->filename) .'/'. $themes[$key]->name .'.theme';
      if (file_exists($filename)) {
        $themes[$key]->owner = $filename;
        $themes[$key]->prefix = $key;
Dries's avatar
   
Dries committed
748
      }
Dries's avatar
   
Dries committed
749
    }
750
751
752
753
754
755
756
757
758
    else {
      $engine = $themes[$key]->info['engine'];
      if (isset($engines[$engine])) {
        $themes[$key]->owner = $engines[$engine]->filename;
        $themes[$key]->prefix = $engines[$engine]->name;
        $themes[$key]->template = TRUE;
      }
    }

759
760
761
762
763
764
    // Give the stylesheets proper path information.
    $pathed_stylesheets = array();
    foreach ($themes[$key]->info['stylesheets'] as $media => $stylesheets) {
      foreach ($stylesheets as $stylesheet) {
        $pathed_stylesheets[$media][$stylesheet] = dirname($themes[$key]->filename) .'/'. $stylesheet;
      }
765
    }
766
    $themes[$key]->info['stylesheets'] = $pathed_stylesheets;
Dries's avatar
Dries committed
767

768
769
770
771
    // Give the scripts proper path information.
    $scripts = array();
    foreach ($themes[$key]->info['scripts'] as $script) {
      $scripts[$script] = dirname($themes[$key]->filename) .'/'. $script;
772
    }
773
    $themes[$key]->info['scripts'] = $scripts;
774
775
776
777
    // Give the screenshot proper path information.
    if (!empty($themes[$key]->info['screenshot'])) {
      $themes[$key]->info['screenshot'] = dirname($themes[$key]->filename) .'/'. $themes[$key]->info['screenshot'];
    }
Dries's avatar
   
Dries committed
778
779
  }

780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
  // Now that we've established all our master themes, go back and fill in
  // data for subthemes.
  foreach ($sub_themes as $key) {
    $base_key = system_find_base_theme($themes, $key);
    if (!$base_key) {
      continue;
    }
    // Copy the 'owner' and 'engine' over if the top level theme uses a
    // theme engine.
    if (isset($themes[$base_key]->owner)) {
      if (isset($themes[$base_key]->info['engine'])) {
        $themes[$key]->info['engine'] = $themes[$base_key]->info['engine'];
        $themes[$key]->owner = $themes[$base_key]->owner;
        $themes[$key]->prefix = $themes[$base_key]->prefix;
      }
      else {
        $themes[$key]->prefix = $key;
Dries's avatar
   
Dries committed
797
798
      }
    }
Dries's avatar
   
Dries committed
799
  }
Dries's avatar
   
Dries committed
800
801

  // Extract current files from database.
Dries's avatar
Dries committed
802
803
804
  system_get_files_database($themes, 'theme');

  db_query("DELETE FROM {system} WHERE type = 'theme'");
Dries's avatar
   
Dries committed
805

Dries's avatar
Dries committed
806
  foreach ($themes as $theme) {
807
808
809
810
    if (!isset($theme->owner)) {
      $theme->owner = '';
    }

811
    db_query("INSERT INTO {system} (name, owner, info, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d, %d)", $theme->name, $theme->owner, serialize($theme->info), 'theme', $theme->filename, isset($theme->status) ? $theme->status : 0, 0, 0);
Dries's avatar
Dries committed
812
813
814
815
816
  }

  return $themes;
}

817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
/**
 * Recursive function to find the top level base theme. Themes can inherit
 * templates and function implementations from earlier themes; this function
 * finds the top level parent that has no ancestor, or returns NULL if there
 * isn't a valid parent.
 */
function system_find_base_theme($themes, $key, $used_keys = array()) {
  $base_key = $themes[$key]->info['base theme'];
  // Does the base theme exist?
  if (!isset($themes[$base_key])) {
    return NULL;
  }

  // Is the base theme itself a child of another theme?
  if (isset($themes[$base_key]->info['base theme'])) {
    // Prevent loops.
833
    if (!empty($used_keys[$base_key])) {
834
835
836
837
838
839
840
841
842
      return NULL;
    }
    $used_keys[$base_key] = TRUE;
    return system_find_base_theme($themes, $base_key, $used_keys);
  }
  // If we get here, then this is our parent theme.
  return $base_key;
}

843
844
845
/**
 * Get a list of available regions from a specified theme.
 *
846
 * @param $theme_key
847
848
849
850
 *   The name of a theme.
 * @return
 *   An array of regions in the form $region['name'] = 'description'.
 */
851
function system_region_list($theme_key) {
852
853
  static $list = array();

854
  if (!array_key_exists($theme_key, $list)) {
855
856
    $info = unserialize(db_result(db_query("SELECT info FROM {system} WHERE type = 'theme' AND name = '%s'", $theme_key)));
    $list[$theme_key] = array_map('t', $info['regions']);
857
858
  }

859
  return $list[$theme_key];
860
861
862
863
864
865
866
867
868
869
870
871
}

/**
 * Get the name of the default region for a given theme.
 *
 * @param $theme
 *   The name of a theme.
 * @return
 *   A string that is the region name.
 */
function system_default_region($theme) {
  $regions = array_keys(system_region_list($theme));
872
  return isset($regions[0]) ? $regions[0] : '';
873
874
}

Dries's avatar
   
Dries committed
875
/**
876
877
 * Assign an initial, default set of blocks for a theme.
 *
878
 * This function is called the first time a new theme is enabled. The new theme
879
880
881
882
883
884
885
886
887
 * gets a copy of the default theme's blocks, with the difference that if a
 * particular region isn't available in the new theme, the block is assigned
 * to the new theme's default region.
 *
 * @param $theme
 *   The name of a theme.
 */
function system_initialize_theme_blocks($theme) {
  // Initialize theme's blocks if none already registered.
888
  if (!(db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme = '%s'", $theme)))) {
889
    $default_theme = variable_get('theme_default', 'garland');
890
891
    $regions = system_region_list($theme);
    $result = db_query("SELECT * FROM {blocks} WHERE theme = '%s'", $default_theme);
892
    while ($block = db_fetch_array($result)) {
893
894
895
896
      // If the region isn't supported by the theme, assign the block to the theme's default region.
      if (!array_key_exists($block['region'], $regions)) {
        $block['region'] = system_default_region($theme);
      }
897
898
      db_query("INSERT INTO {blocks} (module, delta, theme, status, weight, region, visibility, pages, custom, throttle, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', %d, '%s', %d, %d, %d)",
          $block['module'], $block['delta'], $theme, $block['status'], $block['weight'], $block['region'], $block['visibility'], $block['pages'], $block['custom'], $block['throttle'], $block['cache']);
899
900
901
902
    }
  }
}

903
904
905
906
/**
 * Add default buttons to a form and set its prefix
 */
function system_settings_form($form) {
907
908
  $form['buttons']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration') );
  $form['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset to defaults') );
909

910
  if (!empty($_POST) && form_get_errors()) {
911
    drupal_set_message(t('The settings have not been saved because of the errors.'), 'error');
912
  }
913
914
  $form['#submit'][] = 'system_settings_form_submit';
  $form['#validate'][] = 'system_settings_form_validate';
915
  $form['#theme'] = 'system_settings_form';
916
  return $form;
917
918
}

919

Steven Wittens's avatar
Steven Wittens committed
920

921
922
923
/**
 * Execute the system_settings_form.
 *
924
925
926
 * If you want node type configure style handling of your checkboxes,
 * add an array_filter value to your form.
 *
927
 */
928
929
function system_settings_form_submit($form, &$form_state) {
  $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
930

931
  // Exclude unnecessary elements.
932
  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']);