Simpletest Coverage - modules/system/system.module

1 <?php
2 // $Id: system.module,v 1.748 2009/08/15 15:57:44 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 */
12 define('VERSION', '7.0-dev');
13
14 /**
15 * Core API compatibility.
16 */
17 define('DRUPAL_CORE_COMPATIBILITY', '7.x');
18
19 /**
20 * Minimum supported version of PHP.
21 */
22 define('DRUPAL_MINIMUM_PHP', '5.2.0');
23
24 /**
25 * Minimum recommended value of PHP memory_limit.
26 */
27 define('DRUPAL_MINIMUM_PHP_MEMORY_LIMIT', '16M');
28
29 /**
30 * Minimum supported version of MySQL, if it is used.
31 */
32 define('DRUPAL_MINIMUM_MYSQL', '5.0');
33
34 /**
35 * Minimum supported version of PostgreSQL, if it is used.
36 */
37 define('DRUPAL_MINIMUM_PGSQL', '8.3');
38
39 /**
40 * Maximum age of temporary files in seconds.
41 */
42 define('DRUPAL_MAXIMUM_TEMP_FILE_AGE', 21600);
43
44 /**
45 * New users will be set to the default time zone at registration.
46 */
47 define('DRUPAL_USER_TIMEZONE_DEFAULT', 0);
48
49 /**
50 * New users will get an empty time zone at registration.
51 */
52 define('DRUPAL_USER_TIMEZONE_EMPTY', 1);
53
54 /**
55 * New users will select their own timezone at registration.
56 */
57 define('DRUPAL_USER_TIMEZONE_SELECT', 2);
58
59 /**
60 * Disabled option on forms and settings
61 */
62 define('DRUPAL_DISABLED', 0);
63
64 /**
65 * Optional option on forms and settings
66 */
67 define('DRUPAL_OPTIONAL', 1);
68
69 /**
70 * Required option on forms and settings
71 */
72 define('DRUPAL_REQUIRED', 2);
73
74 /**
75 * Return only visible regions. @see system_region_list().
76 */
77 define('REGIONS_VISIBLE', 'visible');
78
79 /**
80 * Return all visible regions. @see system_region_list().
81 */
82 define('REGIONS_ALL', 'all');
83
84
85 /**
86 * Implement hook_help().
87 */
88 function system_help($path, $arg) {
89 global $base_url;
90
91 switch ($path) {
92 case 'admin/help#system':
93 $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>';
94 $output .= '<p>' . t('The system module provides:') . '</p>';
95 $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/config/modules'), '@drupal-modules' => 'http://drupal.org/project/modules')) . '</li>';
96 $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/appearance'), '@drupal-themes' => 'http://drupal.org/project/themes')) . '</li>';
97 $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/config/development/performance'))) . '</li>';
98 $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>';
99 $output .= '<li>' . t('basic configuration options for your site, including <a href="@regional-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="@maintenance-mode">maintenance mode</a> for taking your site temporarily offline.', array('@regional-settings' => url('admin/settings/regional-settings'), '@file-system' => url('admin/settings/file-system'), '@clean-url' => url('admin/settings/clean-urls'), '@site-info' => url('admin/settings/site-information'), '@maintenance-mode' => url('admin/config/development/maintenance'))) . '</li></ul>';
100 $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>';
101 return $output;
102 case 'admin/by-module':
103 return '<p>' . t('This page shows you all available administration tasks for each module.') . '</p>';
104 case 'admin/appearance':
105 $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>';
106 $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>';
107 return $output;
108 case 'admin/appearance/settings/' . $arg[4]:
109 $reference = explode('.', $arg[4], 2);
110 $theme = array_pop($reference);
111 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/appearance/settings'))) . '</p>';
112 case 'admin/appearance/settings':
113 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>';
114 case 'admin/config/modules':
115 $output = '<p>' . t('Modules are plugins that extend Drupal\'s core functionality. To further extend your site\'s functionality, a number of <a href="@modules">contributed modules</a> are available for download.', array('@permissions' => url('admin/settings/permissions'), '@modules' => 'http://drupal.org/project/modules')) . '</p>';
116 $output .= '<p>' . t('Module-related tasks can be located on the <a href="@by-module">administration by module page</a>. New <a href="@permissions">module-related permissions</a> may also become available as new modules are enabled.', array('@by-module' => url('admin/by-module'), '@permissions' => url('admin/settings/permissions'))) . '</p>';
117 $output .= '<p>' . t('Each time a module is updated, it is important that <a href="@update-php">update.php</a> is run. To help manage the update process, the <em>Update status</em> module, if enabled, provides <a href="@updates">information on new versions of modules (and themes)</a> as they are released. Regular review of the <a href="@updates">available updates page</a> is essential to maintaining a secure and current site.', array('@update-php' => $base_url . '/update.php', '@updates' => url('admin/reports/updates'))) . '</p>';
118 return $output;
119 case 'admin/config/modules/uninstall':
120 return '<p>' . t('The uninstall process removes all data related to a module. To uninstall a module, you must first disable it on the main <a href="@modules">modules page</a>. Not all modules support this feature.', array('@modules' => url('admin/config/modules'))) . '</p>';
121 case 'admin/structure/block/configure':
122 if ($arg[4] == 'system' && $arg[5] == 'powered-by') {
123 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>';
124 }
125 break;
126 case 'admin/config/development/maintenance':
127 global $user;
128 if ($user->uid == 1) {
129 return '<p>' . t('If you are upgrading to a newer version of Drupal or upgrading contributed modules or themes you may need to run !update-php.', array('!update-php' => l('update.php', 'update.php'))) . '</p>';
130 }
131 case 'admin/settings/actions':
132 case 'admin/settings/actions/manage':
133 $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>';
134 $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>';
135 if (module_exists('trigger')) {
136 $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/structure/trigger'))) . '</p>';
137 }
138 return $output;
139 case 'admin/settings/actions/configure':
140 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").');
141 case 'admin/settings/ip-blocking':
142 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>';
143 case 'admin/reports/status':
144 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>';
145 }
146 }
147
148 /**
149 * Implement hook_theme().
150 */
151 function system_theme() {
152 return array_merge(drupal_common_theme(), array(
153 'system_themes_form' => array(
154 'arguments' => array('form' => NULL),
155 'file' => 'system.admin.inc',
156 ),
157 'system_modules_fieldset' => array(
158 'arguments' => array('form' => NULL),
159 'file' => 'system.admin.inc',
160 ),
161 'system_modules_incompatible' => array(
162 'arguments' => array('message' => NULL),
163 'file' => 'system.admin.inc',
164 ),
165 'system_modules_uninstall' => array(
166 'arguments' => array('form' => NULL),
167 'file' => 'system.admin.inc',
168 ),
169 'status_report' => array(
170 'arguments' => array('requirements' => NULL),
171 'file' => 'system.admin.inc',
172 ),
173 'admin_page' => array(
174 'arguments' => array('blocks' => NULL),
175 'file' => 'system.admin.inc',
176 ),
177 'admin_block' => array(
178 'arguments' => array('block' => NULL),
179 'file' => 'system.admin.inc',
180 ),
181 'admin_block_content' => array(
182 'arguments' => array('content' => NULL),
183 'file' => 'system.admin.inc',
184 ),
185 'system_admin_by_module' => array(
186 'arguments' => array('menu_items' => NULL),
187 'file' => 'system.admin.inc',
188 ),
189 'system_powered_by' => array(
190 'arguments' => array('image_path' => NULL),
191 ),
192 'meta_generator_html' => array(
193 'arguments' => array('version' => NULL),
194 ),
195 'meta_generator_header' => array(
196 'arguments' => array('version' => NULL),
197 ),
198 'system_compact_link' => array(),
199 ));
200 }
201
202 /**
203 * Implement hook_permission().
204 */
205 function system_permission() {
206 return array(
207 'administer site configuration' => array(
208 'title' => t('Administer site configuration'),
209 'description' => t('Configure site-wide settings such as module or theme administration settings.'),
210 ),
211 'administer actions' => array(
212 'title' => t('Administer actions'),
213 'description' => t('Manage the actions defined for your site.'),
214 ),
215 'administer files' => array(
216 'title' => t('Administer files'),
217 'description' => t('Manage user-uploaded files.'),
218 ),
219 'access administration pages' => array(
220 'title' => t('Access administration pages'),
221 'description' => t('View the administration panel and browse the help system.'),
222 ),
223 'access site reports' => array(
224 'title' => t('Access site reports'),
225 'description' => t('View reports from system logs and other status information.'),
226 ),
227 'select different theme' => array(
228 'title' => t('Select different theme'),
229 'description' => t('Select a theme other than the default theme set by the site administrator.'),
230 ),
231 'block IP addresses' => array(
232 'title' => t('Block IP addresses'),
233 'description' => t('Block IP addresses from accessing your site.'),
234 ),
235 );
236 }
237
238 /**
239 * Implement hook_rdf_namespaces().
240 */
241 function system_rdf_namespaces() {
242 return array(
243 'admin' => 'http://webns.net/mvcb/',
244 'content' => 'http://purl.org/rss/1.0/modules/content/',
245 'dc' => 'http://purl.org/dc/elements/1.1/',
246 'dcterms' => 'http://purl.org/dc/terms/',
247 'foaf' => 'http://xmlns.com/foaf/0.1/',
248 'owl' => 'http://www.w3.org/2002/07/owl#',
249 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
250 'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
251 'rss' => 'http://purl.org/rss/1.0/',
252 'sioc' => 'http://rdfs.org/sioc/ns#',
253 'xsd' => 'http://www.w3.org/2001/XMLSchema',
254 );
255 }
256
257 /**
258 * Implement hook_elements().
259 */
260 function system_elements() {
261 // Top level form
262 $type['form'] = array(
263 '#method' => 'post',
264 '#action' => request_uri(),
265 '#theme_wrappers' => array('form'),
266 );
267
268 $type['page'] = array(
269 '#show_messages' => TRUE,
270 '#show_blocks' => TRUE,
271 '#theme' => 'page',
272 );
273
274 $type['list'] = array(
275 '#title' => '',
276 '#list_type' => 'ul',
277 '#attributes' => array(),
278 '#items' => array(),
279 );
280
281 /**
282 * Input elements.
283 */
284 $type['submit'] = array(
285 '#input' => TRUE,
286 '#name' => 'op',
287 '#button_type' => 'submit',
288 '#executes_submit_callback' => TRUE,
289 '#process' => array('form_process_ahah'),
290 '#theme_wrappers' => array('button'),
291 );
292
293 $type['button'] = array(
294 '#input' => TRUE,
295 '#name' => 'op',
296 '#button_type' => 'submit',
297 '#executes_submit_callback' => FALSE,
298 '#process' => array('form_process_ahah'),
299 '#theme_wrappers' => array('button'),
300 );
301
302 $type['image_button'] = array(
303 '#input' => TRUE,
304 '#button_type' => 'submit',
305 '#executes_submit_callback' => TRUE,
306 '#process' => array('form_process_ahah'),
307 '#return_value' => TRUE,
308 '#has_garbage_value' => TRUE,
309 '#src' => NULL,
310 '#theme_wrappers' => array('image_button'),
311 );
312
313 $type['textfield'] = array(
314 '#input' => TRUE,
315 '#size' => 60,
316 '#maxlength' => 128,
317 '#autocomplete_path' => FALSE,
318 '#process' => array('form_process_text_format', 'form_process_ahah'),
319 '#theme' => 'textfield',
320 '#theme_wrappers' => array('form_element'),
321 );
322
323 $type['password'] = array(
324 '#input' => TRUE,
325 '#size' => 60,
326 '#maxlength' => 128,
327 '#process' => array('form_process_ahah'),
328 '#theme' => 'password',
329 '#theme_wrappers' => array('form_element'),
330 );
331
332 $type['password_confirm'] = array(
333 '#input' => TRUE,
334 '#process' => array('form_process_password_confirm'),
335 '#theme_wrappers' => array('form_element'),
336 );
337
338 $type['textarea'] = array(
339 '#input' => TRUE,
340 '#cols' => 60,
341 '#rows' => 5,
342 '#resizable' => TRUE,
343 '#process' => array('form_process_text_format', 'form_process_ahah'),
344 '#theme' => 'textarea',
345 '#theme_wrappers' => array('form_element'),
346 );
347
348 $type['radios'] = array(
349 '#input' => TRUE,
350 '#process' => array('form_process_radios'),
351 '#theme_wrappers' => array('radios'),
352 '#pre_render' => array('form_pre_render_conditional_form_element'),
353 );
354
355 $type['radio'] = array(
356 '#input' => TRUE,
357 '#default_value' => NULL,
358 '#process' => array('form_process_ahah'),
359 '#theme' => 'radio',
360 '#theme_wrappers' => array('form_element'),
361 '#form_element_skip_title' => TRUE,
362 );
363
364 $type['checkboxes'] = array(
365 '#input' => TRUE,
366 '#tree' => TRUE,
367 '#process' => array('form_process_checkboxes'),
368 '#theme_wrappers' => array('checkboxes'),
369 '#pre_render' => array('form_pre_render_conditional_form_element'),
370 );
371
372 $type['checkbox'] = array(
373 '#input' => TRUE,
374 '#return_value' => 1,
375 '#process' => array('form_process_ahah'),
376 '#theme' => 'checkbox',
377 '#theme_wrappers' => array('form_element'),
378 '#form_element_skip_title' => TRUE,
379 );
380
381 $type['select'] = array(
382 '#input' => TRUE,
383 '#size' => 0,
384 '#multiple' => FALSE,
385 '#process' => array('form_process_ahah'),
386 '#theme' => 'select',
387 '#theme_wrappers' => array('form_element'),
388 );
389
390 $type['weight'] = array(
391 '#input' => TRUE,
392 '#delta' => 10,
393 '#default_value' => 0,
394 '#process' => array('form_process_weight', 'form_process_ahah'),
395 );
396
397 $type['date'] = array(
398 '#input' => TRUE,
399 '#element_validate' => array('date_validate'),
400 '#process' => array('form_process_date'),
401 '#theme' => 'date',
402 '#theme_wrappers' => array('form_element'),
403 );
404
405 $type['file'] = array(
406 '#input' => TRUE,
407 '#size' => 60,
408 '#theme' => 'file',
409 '#theme_wrappers' => array('form_element'),
410 );
411
412 $type['tableselect'] = array(
413 '#input' => TRUE,
414 '#js_select' => TRUE,
415 '#multiple' => TRUE,
416 '#process' => array('form_process_tableselect'),
417 '#options' => array(),
418 '#empty' => '',
419 '#theme' => 'tableselect'
420 );
421
422 /**
423 * Form structure.
424 */
425 $type['item'] = array(
426 '#markup' => '',
427 '#theme' => 'markup',
428 '#theme_wrappers' => array('form_element'),
429 );
430
431 $type['hidden'] = array(
432 '#input' => TRUE,
433 '#process' => array('form_process_ahah'),
434 '#theme' => 'hidden',
435 );
436
437 $type['value'] = array(
438 '#input' => TRUE,
439 );
440
441 $type['markup'] = array(
442 '#markup' => '',
443 '#theme' => 'markup',
444 );
445
446 $type['fieldset'] = array(
447 '#collapsible' => FALSE,
448 '#collapsed' => FALSE,
449 '#value' => NULL,
450 '#process' => array('form_process_fieldset', 'form_process_ahah'),
451 '#pre_render' => array('form_pre_render_fieldset'),
452 '#theme_wrappers' => array('fieldset'),
453 );
454
455 $type['vertical_tabs'] = array(
456 '#theme_wrappers' => array('vertical_tabs'),
457 '#default_tab' => '',
458 '#process' => array('form_process_vertical_tabs'),
459 );
460
461 $type['token'] = array(
462 '#input' => TRUE,
463 '#theme' => array('hidden'),
464 );
465
466 return $type;
467 }
468
469 /**
470 * Implement hook_menu().
471 */
472 function system_menu() {
473 $items['system/files'] = array(
474 'title' => 'File download',
475 'page callback' => 'file_download',
476 'access callback' => TRUE,
477 'type' => MENU_CALLBACK,
478 );
479 $items['system/ahah'] = array(
480 'title' => 'AHAH callback',
481 'page callback' => 'form_ahah_callback',
482 'access callback' => TRUE,
483 'type' => MENU_CALLBACK,
484 );
485 $items['system/timezone'] = array(
486 'title' => 'Time zone',
487 'page callback' => 'system_timezone',
488 'access callback' => TRUE,
489 'type' => MENU_CALLBACK,
490 );
491 $items['admin'] = array(
492 'title' => 'Administer',
493 'access arguments' => array('access administration pages'),
494 'page callback' => 'system_main_admin_page',
495 'weight' => 9,
496 'menu_name' => 'management',
497 );
498 $items['admin/compact'] = array(
499 'title' => 'Compact mode',
500 'page callback' => 'system_admin_compact_page',
501 'access arguments' => array('access administration pages'),
502 'type' => MENU_CALLBACK,
503 );
504 $items['admin/by-task'] = array(
505 'title' => 'By task',
506 'page callback' => 'system_main_admin_page',
507 'access arguments' => array('access administration pages'),
508 'type' => MENU_DEFAULT_LOCAL_TASK,
509 );
510 $items['admin/by-module'] = array(
511 'title' => 'By module',
512 'page callback' => 'system_admin_by_module',
513 'access arguments' => array('access administration pages'),
514 'type' => MENU_LOCAL_TASK,
515 'weight' => 2,
516 );
517
518 // Menu items that are basically just menu blocks.
519 $items['admin/settings'] = array(
520 'title' => 'Site configuration',
521 'description' => 'Configure site settings.',
522 'position' => 'right',
523 'weight' => -2,
524 'page callback' => 'system_settings_overview',
525 'access callback' => 'system_admin_menu_block_access',
526 'access arguments' => array('admin/settings', 'access administration pages'),
527 );
528 $items['admin/structure'] = array(
529 'title' => 'Structure',
530 'description' => 'Control how your site looks and feels.',
531 'position' => 'right',
532 'weight' => -8,
533 'page callback' => 'system_admin_menu_block_page',
534 'access callback' => 'system_admin_menu_block_access',
535 'access arguments' => array('admin/structure', 'access administration pages'),
536 );
537 // Appearance.
538 $items['admin/appearance'] = array(
539 'title' => 'Appearance',
540 'page callback' => 'drupal_get_form',
541 'page arguments' => array('system_themes_form'),
542 'access arguments' => array('administer site configuration'),
543 'weight' => -6,
544 );
545 $items['admin/appearance/select'] = array(
546 'title' => 'List',
547 'description' => 'Select the default theme for your site.',
548 'type' => MENU_DEFAULT_LOCAL_TASK,
549 'weight' => -1,
550 );
551 $items['admin/appearance/settings'] = array(
552 'title' => 'Configure',
553 'page arguments' => array('system_theme_settings'),
554 'access arguments' => array('administer site configuration'),
555 'type' => MENU_LOCAL_TASK,
556 );
557 // Theme configuration subtabs.
558 $items['admin/appearance/settings/global'] = array(
559 'title' => 'Global settings',
560 'type' => MENU_DEFAULT_LOCAL_TASK,
561 'weight' => -1,
562 );
563
564 foreach (list_themes() as $theme) {
565 $items['admin/appearance/settings/' . $theme->name] = array(
566 'title' => $theme->info['name'],
567 'page arguments' => array('system_theme_settings', $theme->name),
568 'type' => MENU_LOCAL_TASK,
569 'access callback' => '_system_themes_access',
570 'access arguments' => array($theme),
571 );
572 }
573
574 // Configuration and modules.
575 $items['admin/config'] = array(
576 'title' => 'Configuration and modules',
577 'page callback' => 'system_admin_config_page',
578 'access arguments' => array('access administration pages'),
579 );
580 $items['admin/config/config'] = array(
581 'title' => 'Configuration',
582 'access arguments' => array('administer site configuration'),
583 'type' => MENU_DEFAULT_LOCAL_TASK,
584 'weight' => -10,
585 );
586 $items['admin/config/modules'] = array(
587 'title' => 'Modules',
588 'description' => 'Enable or disable add-on modules for your site.',
589 'page callback' => 'drupal_get_form',
590 'page arguments' => array('system_modules'),
591 'access arguments' => array('administer site configuration'),
592 'type' => MENU_LOCAL_TASK,
593 'weight' => 10,
594 );
595 $items['admin/config/modules/list'] = array(
596 'title' => 'List',
597 'type' => MENU_DEFAULT_LOCAL_TASK,
598 );
599 $items['admin/config/modules/list/confirm'] = array(
600 'title' => 'List',
601 'access arguments' => array('administer site configuration'),
602 'type' => MENU_CALLBACK,
603 );
604 $items['admin/config/modules/uninstall'] = array(
605 'title' => 'Uninstall',
606 'page arguments' => array('system_modules_uninstall'),
607 'access arguments' => array('administer site configuration'),
608 'type' => MENU_LOCAL_TASK,
609 );
610 $items['admin/config/modules/uninstall/confirm'] = array(
611 'title' => 'Uninstall',
612 'access arguments' => array('administer site configuration'),
613 'type' => MENU_CALLBACK,
614 );
615
616 // Actions.
617 $items['admin/settings/actions'] = array(
618 'title' => 'Actions',
619 'description' => 'Manage the actions defined for your site.',
620 'access arguments' => array('administer actions'),
621 'page callback' => 'system_actions_manage'
622 );
623 $items['admin/settings/actions/manage'] = array(
624 'title' => 'Manage actions',
625 'description' => 'Manage the actions defined for your site.',
626 'page callback' => 'system_actions_manage',
627 'type' => MENU_DEFAULT_LOCAL_TASK,
628 'weight' => -2,
629 );
630 $items['admin/settings/actions/configure'] = array(
631 'title' => 'Configure an advanced action',
632 'page callback' => 'drupal_get_form',
633 'page arguments' => array('system_actions_configure'),
634 'access arguments' => array('administer actions'),
635 'type' => MENU_CALLBACK,
636 );
637 $items['admin/settings/actions/delete/%actions'] = array(
638 'title' => 'Delete action',
639 'description' => 'Delete an action.',
640 'page callback' => 'drupal_get_form',
641 'page arguments' => array('system_actions_delete_form', 4),
642 'access arguments' => array('administer actions'),
643 'type' => MENU_CALLBACK,
644 );
645 $items['admin/settings/actions/orphan'] = array(
646 'title' => 'Remove orphans',
647 'page callback' => 'system_actions_remove_orphans',
648 'access arguments' => array('administer actions'),
649 'type' => MENU_CALLBACK,
650 );
651
652 // IP address blocking.
653 $items['admin/settings/ip-blocking'] = array(
654 'title' => 'IP address blocking',
655 'description' => 'Manage blocked IP addresses.',
656 'page callback' => 'system_ip_blocking',
657 'access arguments' => array('block IP addresses'),
658 );
659 $items['admin/settings/ip-blocking/%'] = array(
660 'title' => 'IP address blocking',
661 'description' => 'Manage blocked IP addresses.',
662 'page callback' => 'system_ip_blocking',
663 'access arguments' => array('block IP addresses'),
664 'type' => MENU_CALLBACK,
665 );
666 $items['admin/settings/ip-blocking/delete/%blocked_ip'] = array(
667 'title' => 'Delete IP address',
668 'page callback' => 'drupal_get_form',
669 'page arguments' => array('system_ip_blocking_delete', 4),
670 'access arguments' => array('block IP addresses'),
671 'type' => MENU_CALLBACK,
672 );
673
674 // Configuration.
675 $items['admin/config/development'] = array(
676 'title' => 'Development',
677 'description' => 'Development tools.',
678 'position' => 'left',
679 'weight' => 10,
680 'page callback' => 'system_admin_menu_block_page',
681 'access callback' => 'system_admin_menu_block_access',
682 'access arguments' => array('admin/config/development', 'access administration pages'),
683 );
684 $items['admin/config/development/maintenance'] = array(
685 'title' => 'Maintenance mode',
686 'description' => 'Take the site offline for maintenance or bring it back online.',
687 'page callback' => 'drupal_get_form',
688 'page arguments' => array('system_site_maintenance_mode'),
689 'access arguments' => array('administer site configuration'),
690 );
691 $items['admin/config/development/performance'] = array(
692 'title' => 'Performance',
693 'description' => 'Enable or disable page caching for anonymous users and set CSS and JS bandwidth optimization options.',
694 'page callback' => 'drupal_get_form',
695 'page arguments' => array('system_performance_settings'),
696 'access arguments' => array('administer site configuration'),
697 );
698
699 // Settings.
700 $items['admin/settings/site-information'] = array(
701 'title' => 'Site information',
702 'description' => 'Change basic site information, such as the site name, slogan, e-mail address, mission, front page and more.',
703 'page callback' => 'drupal_get_form',
704 'page arguments' => array('system_site_information_settings'),
705 'access arguments' => array('administer site configuration'),
706 );
707 $items['admin/config/development/logging'] = array(
708 'title' => 'Logging and errors',
709 'description' => "Settings for logging and alerts modules. Various modules can route Drupal's system events to different destinations, such as syslog, database, email, etc.",
710 'page callback' => 'drupal_get_form',
711 'page arguments' => array('system_logging_settings'),
712 'access arguments' => array('administer site configuration'),
713 );
714 $items['admin/settings/file-system'] = array(
715 'title' => 'File system',
716 'description' => 'Tell Drupal where to store uploaded files and how they are accessed.',
717 'page callback' => 'drupal_get_form',
718 'page arguments' => array('system_file_system_settings'),
719 'access arguments' => array('administer site configuration'),
720 );
721 $items['admin/settings/image-toolkit'] = array(
722 'title' => 'Image toolkit',
723 'description' => 'Choose which image toolkit to use if you have installed optional toolkits.',
724 'page callback' => 'drupal_get_form',
725 'page arguments' => array('system_image_toolkit_settings'),
726 'access arguments' => array('administer site configuration'),
727 );
728 $items['admin/settings/rss-publishing'] = array(
729 'title' => 'RSS publishing',
730 'description' => 'Configure the site description, the number of items per feed and whether feeds should be titles/teasers/full-text.',
731 'page callback' => 'drupal_get_form',
732 'page arguments' => array('system_rss_feeds_settings'),
733 'access arguments' => array('administer site configuration'),
734 );
735 $items['admin/settings/regional-settings'] = array(
736 'title' => 'Regional settings',
737 'description' => "Settings for how Drupal displays date and time, as well as the system's default time zone.",
738 'page callback' => 'drupal_get_form',
739 'page arguments' => array('system_regional_settings'),
740 'access arguments' => array('administer site configuration'),
741 );
742 $items['admin/settings/regional-settings/lookup'] = array(
743 'title' => 'Date and time lookup',
744 'type' => MENU_CALLBACK,
745 'page callback' => 'system_date_time_lookup',
746 'access arguments' => array('administer site configuration'),
747 );
748 $items['admin/settings/clean-urls'] = array(
749 'title' => 'Clean URLs',
750 'description' => 'Enable or disable clean URLs for your site.',
751 'page callback' => 'drupal_get_form',
752 'page arguments' => array('system_clean_url_settings'),
753 'access arguments' => array('administer site configuration'),
754 );
755 $items['admin/settings/clean-urls/check'] = array(
756 'title' => 'Clean URL check',
757 'page callback' => 'drupal_json',
758 'page arguments' => array(array('status' => TRUE)),
759 'access callback' => TRUE,
760 'type' => MENU_CALLBACK,
761 );
762
763 // Reports.
764 $items['admin/reports'] = array(
765 'title' => 'Reports',
766 'description' => 'View reports from system logs and other status information.',
767 'page callback' => 'system_admin_menu_block_page',
768 'access callback' => 'system_admin_menu_block_access',
769 'access arguments' => array('admin/reports', 'access site reports'),
770 'weight' => 5,
771 'position' => 'left',
772 );
773 $items['admin/reports/status'] = array(
774 'title' => 'Status report',
775 'description' => "Get a status report about your site's operation and any detected problems.",
776 'page callback' => 'system_status',
777 'weight' => 10,
778 'access arguments' => array('administer site configuration'),
779 );
780 $items['admin/reports/status/run-cron'] = array(
781 'title' => 'Run cron',
782 'page callback' => 'system_run_cron',
783 'access arguments' => array('administer site configuration'),
784 'type' => MENU_CALLBACK,
785 );
786 $items['admin/reports/status/php'] = array(
787 'title' => 'PHP',
788 'page callback' => 'system_php',
789 'access arguments' => array('administer site configuration'),
790 'type' => MENU_CALLBACK,
791 );
792 // Default page for batch operations.
793 $items['batch'] = array(
794 'page callback' => 'system_batch_page',
795 'access callback' => TRUE,
796 'type' => MENU_CALLBACK,
797 );
798 return $items;
799 }
800
801 /**
802 * Implementation of hook_library().
803 */
804 function system_library() {
805 // jQuery.
806 $libraries['jquery'] = array(
807 'title' => 'jQuery',
808 'website' => 'http://jquery.com',
809 'version' => '1.3.2',
810 'js' => array(
811 'misc/jquery.js' => array('weight' => JS_LIBRARY - 20),
812 ),
813 );
814
815 // jQuery Form Plugin.
816 $libraries['form'] = array(
817 'title' => 'jQuery Form Plugin',
818 'website' => 'http://malsup.com/jquery/form/',
819 'version' => '2.16',
820 'js' => array(
821 'misc/jquery.form.js' => array(),
822 ),
823 );
824
825 // Farbtastic.
826 $libraries['farbtastic'] = array(
827 'title' => 'Farbtastic',
828 'website' => 'http://code.google.com/p/farbtastic/',
829 'version' => '1.2',
830 'js' => array(
831 'misc/farbtastic/farbtastic.js' => array(),
832 ),
833 'css' => array(
834 'misc/farbtastic/farbtastic.css' => array('preprocess' => FALSE),
835 ),
836 );
837
838 // Cookie.
839 $libraries['cookie'] = array(
840 'title' => 'Cookie',
841 'website' => 'http://plugins.jquery.com/project/cookie',
842 'version' => '1.0',
843 'js' => array(
844 'misc/jquery.cookie.js' => array(),
845 ),
846 );
847
848 // jQuery UI.
849 $libraries['ui'] = array(
850 'title' => 'jQuery UI: Core',
851 'website' => 'http://jqueryui.com',
852 'version' => '1.7.2',
853 'js' => array(
854 'misc/ui/ui.core.js' => array('weight' => JS_LIBRARY - 10),
855 ),
856 'css' => array(
857 'misc/ui/ui.core.css' => array(),
858 'misc/ui/ui.theme.css' => array(),
859 ),
860 );
861 $libraries['ui.accordion'] = array(
862 'title' => 'jQuery UI: Accordion',
863 'website' => 'http://jqueryui.com/demos/accordion/',
864 'version' => '1.7.2',
865 'js' => array(
866 'misc/ui/ui.accordion.js' => array(),
867 ),
868 'css' => array(
869 'misc/ui/ui.accordion.css' => array(),
870 ),
871 'dependencies' => array(
872 array('system', 'ui'),
873 ),
874 );
875 $libraries['ui.datepicker'] = array(
876 'title' => 'jQuery UI: Date Picker',
877 'website' => 'http://jqueryui.com/demos/datepicker/',
878 'version' => '1.7.2',
879 'js' => array(
880 'misc/ui/ui.datepicker.js' => array(),
881 ),
882 'css' => array(
883 'misc/ui/ui.datepicker.css' => array(),
884 ),
885 'dependencies' => array(
886 array('system', 'ui'),
887 ),
888 );
889 $libraries['ui.dialog'] = array(
890 'title' => 'jQuery UI: Dialog',
891 'website' => 'http://jqueryui.com/demos/dialog/',
892 'version' => '1.7.2',
893 'js' => array(
894 'misc/ui/ui.dialog.js' => array(),
895 ),
896 'css' => array(
897 'misc/ui/ui.dialog.css' => array(),
898 ),
899 'dependencies' => array(
900 array('system', 'ui'),
901 ),
902 );
903 $libraries['ui.draggable'] = array(
904 'title' => 'jQuery UI: Dialog',
905 'website' => 'http://jqueryui.com/demos/draggable/',
906 'version' => '1.7.2',
907 'js' => array(
908 'misc/ui/ui.draggable.js' => array(),
909 ),
910 'dependencies' => array(
911 array('system', 'ui'),
912 ),
913 );
914 $libraries['ui.droppable'] = array(
915 'title' => 'jQuery UI: Droppable',
916 'website' => 'http://jqueryui.com/demos/droppable/',
917 'version' => '1.7.2',
918 'js' => array(
919 'misc/ui/ui.droppable.js' => array(),
920 ),
921 'dependencies' => array(
922 array('system', 'ui'),
923 array('system', 'ui.draggable'),
924 ),
925 );
926 $libraries['ui.progressbar'] = array(
927 'title' => 'jQuery UI: Progress Bar',
928 'website' => 'http://jqueryui.com/demos/progressbar/',
929 'version' => '1.7.2',
930 'js' => array(
931 'misc/ui/ui.progressbar.js' => array(),
932 ),
933 'css' => array(
934 'misc/ui/ui.progressbar.css' => array(),
935 ),
936 'dependencies' => array(
937 array('system', 'ui'),
938 ),
939 );
940 $libraries['ui.resizable'] = array(
941 'title' => 'jQuery UI: Resizable',
942 'website' => 'http://jqueryui.com/demos/resizable/',
943 'version' => '1.7.2',
944 'js' => array(
945 'misc/ui/ui.resizable.js' => array(),
946 ),
947 'css' => array(
948 'misc/ui/ui.resizable.css' => array(),
949 ),
950 'dependencies' => array(
951 array('system', 'ui'),
952 ),
953 );
954 $libraries['ui.selectable'] = array(
955 'title' => 'jQuery UI: Selectable',
956 'website' => 'http://jqueryui.com/demos/selectable/',
957 'version' => '1.7.2',
958 'js' => array(
959 'misc/ui/ui.selectable.js' => array(),
960 ),
961 'css' => array(
962 'misc/ui/ui.selectable.css' => array(),
963 ),
964 'dependencies' => array(
965 array('system', 'ui'),
966 ),
967 );
968 $libraries['ui.slider'] = array(
969 'title' => 'jQuery UI: Slider',
970 'website' => 'http://jqueryui.com/demos/slider/',
971 'version' => '1.7.2',
972 'js' => array(
973 'misc/ui/ui.slider.js' => array(),
974 ),
975 'css' => array(
976 'misc/ui/ui.slider.css' => array(),
977 ),
978 'dependencies' => array(
979 array('system', 'ui'),
980 ),
981 );
982 $libraries['ui.sortable'] = array(
983 'title' => 'jQuery UI: Sortable',
984 'website' => 'http://jqueryui.com/demos/sortable/',
985 'version' => '1.7.2',
986 'js' => array(
987 'misc/ui/ui.sortable.js' => array(),
988 ),
989 'dependencies' => array(
990 array('system', 'ui'),
991 ),
992 );
993 $libraries['ui.tabs'] = array(
994 'title' => 'jQuery UI: Tabs',
995 'website' => 'http://jqueryui.com/demos/tabs/',
996 'version' => '1.7.2',
997 'js' => array(
998 'misc/ui/ui.tabs.js' => array(),
999 ),
1000 'css' => array(
1001 'misc/ui/ui.tabs.css' => array(),
1002 ),
1003 'dependencies' => array(
1004 array('system', 'ui'),
1005 ),
1006 );
1007 $libraries['effects'] = array(
1008 'title' => 'jQuery UI: Effects',
1009 'website' => 'http://jqueryui.com/demos/effect/',
1010 'version' => '1.7.2',
1011 'js' => array(
1012 'misc/ui/effects.core.js' => array('weight' => JS_LIBRARY - 9),
1013 ),
1014 'dependencies' => array(
1015 array('system', 'ui'),
1016 ),
1017 );
1018 $libraries['effects.blind'] = array(
1019 'title' => 'jQuery UI: Effects Blind',
1020 'website' => 'http://jqueryui.com/demos/effect/',
1021 'version' => '1.7.2',
1022 'js' => array(
1023 'misc/ui/effects.blind.js' => array(),
1024 ),
1025 'dependencies' => array(
1026 array('system', 'effects'),
1027 ),
1028 );
1029 $libraries['effects.bounce'] = array(
1030 'title' => 'jQuery UI: Effects Bounce',
1031 'website' => 'http://jqueryui.com/demos/effect/',
1032 'version' => '1.7.2',
1033 'js' => array(
1034 'misc/ui/effects.bounce.js' => array(),
1035 ),
1036 'dependencies' => array(
1037 array('system', 'effects'),
1038 ),
1039 );
1040 $libraries['effects.clip'] = array(
1041 'title' => 'jQuery UI: Effects Clip',
1042 'website' => 'http://jqueryui.com/demos/effect/',
1043 'version' => '1.7.2',
1044 'js' => array(
1045 'misc/ui/effects.clip.js' => array(),
1046 ),
1047 'dependencies' => array(
1048 array('system', 'effects'),
1049 ),
1050 );
1051 $libraries['effects.drop'] = array(
1052 'title' => 'jQuery UI: Effects Drop',
1053 'website' => 'http://jqueryui.com/demos/effect/',
1054 'version' => '1.7.2',
1055 'js' => array(
1056 'misc/ui/effects.drop.js' => array(),
1057 ),
1058 'dependencies' => array(
1059 array('system', 'effects'),
1060 ),
1061 );
1062 $libraries['effects.explode'] = array(
1063 'title' => 'jQuery UI: Effects Explode',
1064 'website' => 'http://jqueryui.com/demos/effect/',
1065 'version' => '1.7.2',
1066 'js' => array(
1067 'misc/ui/effects.explode.js' => array(),
1068 ),
1069 'dependencies' => array(
1070 array('system', 'effects'),
1071 ),
1072 );
1073 $libraries['effects.fold'] = array(
1074 'title' => 'jQuery UI: Effects Fold',
1075 'website' => 'http://jqueryui.com/demos/effect/',
1076 'version' => '1.7.2',
1077 'js' => array(
1078 'misc/ui/effects.fold.js' => array(),
1079 ),
1080 'dependencies' => array(
1081 array('system', 'effects'),
1082 ),
1083 );
1084 $libraries['effects.highlight'] = array(
1085 'title' => 'jQuery UI: Effects Fold',
1086 'website' => 'http://jqueryui.com/demos/effect/',
1087 'version' => '1.7.2',
1088 'js' => array(
1089 'misc/ui/effects.highlight.js' => array(),
1090 ),
1091 'dependencies' => array(
1092 array('system', 'effects'),
1093 ),
1094 );
1095 $libraries['effects.pulsate'] = array(
1096 'title' => 'jQuery UI: Effects Pulsate',
1097 'website' => 'http://jqueryui.com/demos/effect/',
1098 'version' => '1.7.2',
1099 'js' => array(
1100 'misc/ui/effects.pulsate.js' => array(),
1101 ),
1102 'dependencies' => array(
1103 array('system', 'effects'),
1104 ),
1105 );
1106 $libraries['effects.scale'] = array(
1107 'title' => 'jQuery UI: Effects Pulsate',
1108 'website' => 'http://jqueryui.com/demos/effect/',
1109 'version' => '1.7.2',
1110 'js' => array(
1111 'misc/ui/effects.scale.js' => array(),
1112 ),
1113 'dependencies' => array(
1114 array('system', 'effects'),
1115 ),
1116 );
1117 $libraries['effects.shake'] = array(
1118 'title' => 'jQuery UI: Effects Shake',
1119 'website' => 'http://jqueryui.com/demos/effect/',
1120 'version' => '1.7.2',
1121 'js' => array(
1122 'misc/ui/effects.scale.js' => array(),
1123 ),
1124 'dependencies' => array(
1125 array('system', 'effects'),
1126 ),
1127 );
1128 $libraries['effects.slide'] = array(
1129 'title' => 'jQuery UI: Effects Slide',
1130 'website' => 'http://jqueryui.com/demos/effect/',
1131 'version' => '1.7.2',
1132 'js' => array(
1133 'misc/ui/effects.slide.js' => array(),
1134 ),
1135 'dependencies' => array(
1136 array('system', 'effects'),
1137 ),
1138 );
1139 $libraries['effects.transfer'] = array(
1140 'title' => 'jQuery UI: Effects Transfer',
1141 'website' => 'http://jqueryui.com/demos/effect/',
1142 'version' => '1.7.2',
1143 'js' => array(
1144 'misc/ui/effects.transfer.js' => array(),
1145 ),
1146 'dependencies' => array(
1147 array('system', 'effects'),
1148 ),
1149 );
1150
1151 return $libraries;
1152 }
1153
1154 /**
1155 * Implement hook_stream_wrappers().
1156 */
1157 function system_stream_wrappers() {
1158 return array(
1159 'public' => array(
1160 'name' => t('Public files'),
1161 'class' => 'DrupalPublicStreamWrapper',
1162 'description' => t('Public local files served by the webserver.'),
1163 ),
1164 'private' => array(
1165 'name' => t('Private files'),
1166 'class' => 'DrupalPrivateStreamWrapper',
1167 'description' => t('Private local files served by Drupal.'),
1168 ),
1169 'temporary' => array(
1170 'name' => t('Temporary files'),
1171 'class' => 'DrupalTemporaryStreamWrapper',
1172 'description' => t('Temporary local files for upload and previews.'),
1173 )
1174 );
1175 }
1176
1177 /**
1178 * Retrieve a blocked IP address from the database.
1179 *
1180 * @param $iid integer
1181 * The ID of the blocked IP address to retrieve.
1182 *
1183 * @return
1184 * The blocked IP address from the database as an array.
1185 */
1186 function blocked_ip_load($iid) {
1187 return db_query("SELECT * FROM {blocked_ips} WHERE iid = :iid", array(':iid' => $iid))->fetchAssoc();
1188 }
1189
1190 /**
1191 * Menu item access callback - only admin or enabled themes can be accessed.
1192 */
1193 function _system_themes_access($theme) {
1194 return user_access('administer site configuration') && ($theme->status || $theme->name == variable_get('admin_theme', 0));
1195 }
1196
1197 /**
1198 * Menu item access callback - hides empty system settings overview pages.
1199 *
1200 * @param $path
1201 * The path of the menu item to check for child menu entries.
1202 * @param $string
1203 * The permission, such as "administer nodes", being checked for.
1204 * @return
1205 * Boolean TRUE if the current user has the requested permission and the
1206 * current menu item has children.
1207 */
1208 function system_admin_menu_block_access($path, $permission) {
1209 if (!user_access($permission)) {
1210 return FALSE;
1211 }
1212 $content = system_admin_menu_block(array('path' => $path));
1213 return !empty($content);
1214 }
1215
1216 /**
1217 * Implement hook_filetransfer_backends().
1218 */
1219 function system_filetransfer_backends() {
1220 $backends = array();
1221
1222 //This is the default, will be available on most systems
1223 if (function_exists('ftp_connect')) {
1224 $backends['ftp_extension'] = array(
1225 'title' => t('FTP'),
1226 'class' => 'FileTransferFTPExtension',
1227 'settings_form' => 'system_filetransfer_backend_form_ftp',
1228 'weight' => 0,
1229 );
1230 }
1231
1232 if (ini_get('allow_url_fopen')) {
1233 $backends['ftp_wrapper'] = array(
1234 'title' => t('FTP using file streams'),
1235 'class' => 'FileTransferFTPWrapper',
1236 'settings_form' => 'system_filetransfer_backend_form_ftp',
1237 'weight' => 10,
1238 );
1239 }
1240
1241 // SSH2 lib connection is only available if the proper PHP extension is
1242 // installed.
1243 if (function_exists('ssh2_connect')) {
1244 $backends['ssh'] = array(
1245 'title' => t('SSH'),
1246 'class' => 'FileTransferSSH',
1247 'settings_form' => 'system_filetransfer_backend_form_ssh',
1248 'weight' => 20,
1249 );
1250 }
1251 return $backends;
1252 }
1253
1254 /**
1255 * Helper function to return a form for configuring a filetransfer backend.
1256 *
1257 * @param string $filetransfer_backend_name
1258 * The name of the backend to return a form for.
1259 *
1260 * @param string $defaults
1261 * An associative array of settings to pre-populate the form with.
1262 */
1263 function system_get_filetransfer_settings_form($filetransfer_backend_name, $defaults) {
1264 $available_backends = module_invoke_all('filetransfer_backends');
1265 $form = call_user_func($available_backends[$filetransfer_backend_name]['settings_form']);
1266
1267 foreach ($form as $name => &$element) {
1268 if (isset($defaults[$name])) {
1269 $element['#default_value'] = $defaults[$name];
1270 }
1271 }
1272 return $form;
1273 }
1274
1275 /**
1276 * Returns the form to configure the filetransfer class for FTP
1277 */
1278 function system_filetransfer_backend_form_ftp() {
1279 $form = _system_filetransfer_backend_form_common();
1280 $form['port']['#default_value'] = 21;
1281 return $form;
1282 }
1283
1284 /**
1285 * Returns the form to configure the filetransfer class for SSH
1286 */
1287 function system_filetransfer_backend_form_ssh() {
1288 $form = _system_filetransfer_backend_form_common();
1289 $form['port']['#default_value'] = 22;
1290 return $form;
1291 }
1292
1293 /**
1294 * Helper function because SSH and FTP backends share the same elements
1295 */
1296 function _system_filetransfer_backend_form_common() {
1297 $form = array();
1298
1299 $form['hostname'] = array (
1300 '#type' => 'textfield',
1301 '#title' => t('Host'),
1302 '#default_value' => 'localhost',
1303 );
1304
1305 $form['port'] = array (
1306 '#type' => 'textfield',
1307 '#title' => t('Port'),
1308 '#default_value' => NULL,
1309 );
1310
1311 $form['username'] = array (
1312 '#type' => 'textfield',
1313 '#title' => t('Username'),
1314 );
1315
1316 $form['password'] = array (
1317 '#type' => 'password',
1318 '#title' => t('Password'),
1319 '#description' => t('This is not saved in the database and is only used to test the connection'),
1320 );
1321
1322 return $form;
1323 }
1324
1325 /**
1326 * Implement hook_init().
1327 */
1328 function system_init() {
1329 // Use the administrative theme if the user is looking at a page in the admin/* path.
1330 if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit'))) {
1331 global $custom_theme;
1332 $custom_theme = variable_get('admin_theme', 0);
1333 drupal_add_css(drupal_get_path('module', 'system') . '/admin.css', array('weight' => CSS_SYSTEM));
1334 }
1335
1336 // Add the CSS for this module.
1337 drupal_add_css(drupal_get_path('module', 'system') . '/defaults.css', array('weight' => CSS_SYSTEM));
1338 drupal_add_css(drupal_get_path('module', 'system') . '/system.css', array('weight' => CSS_SYSTEM));
1339 drupal_add_css(drupal_get_path('module', 'system') . '/system-menus.css', array('weight' => CSS_SYSTEM));
1340
1341
1342 // Ignore slave database servers for this request.
1343 //
1344 // In Drupal's distributed database structure, new data is written to the master
1345 // and then propagated to the slave servers. This means there is a lag
1346 // between when data is written to the master and when it is available on the slave.
1347 // At these times, we will want to avoid using a slave server temporarily.
1348 // For example, if a user posts a new node then we want to disable the slave
1349 // server for that user temporarily to allow the slave server to catch up.
1350 // That way, that user will see their changes immediately while for other
1351 // users we still get the benefits of having a slave server, just with slightly
1352 // stale data. Code that wants to disable the slave server should use the
1353 // db_set_ignore_slave() function to set $_SESSION['ignore_slave_server'] to
1354 // the timestamp after which the slave can be re-enabled.
1355 if (isset($_SESSION['ignore_slave_server'])) {
1356 if ($_SESSION['ignore_slave_server'] >= REQUEST_TIME) {
1357 Database::ignoreTarget('default', 'slave');
1358 }
1359 else {
1360 unset($_SESSION['ignore_slave_server']);
1361 }
1362 }
1363 }
1364
1365 /**
1366 * Implement MODULE_preprocess_HOOK().
1367 */
1368 function system_preprocess_page(&$variables) {
1369 // Get the major version
1370 list($version, ) = explode('.', VERSION);
1371
1372 // Emit the META tag in the HTML HEAD section
1373 theme('meta_generator_html', $version);
1374
1375 // Emit the HTTP Header too
1376 theme('meta_generator_header', $version);
1377
1378 $variables['head'] = drupal_get_html_head();
1379 }
1380
1381 /**
1382 * Implement hook_user_form().
1383 */
1384 function system_user_form(&$edit, $account, $category) {
1385 if ($category == 'account') {
1386 if (variable_get('configurable_timezones', 1)) {
1387 system_user_timezone($edit, $form);
1388 }
1389 return $form;
1390 }
1391 }
1392
1393 /**
1394 * Implement hook_user_register().
1395 */
1396 function system_user_register(&$edit, $account, $category) {
1397 if (variable_get('configurable_timezones', 1)) {
1398 $form = array();
1399 if (variable_get('user_default_timezone', DRUPAL_USER_TIMEZONE_DEFAULT) == DRUPAL_USER_TIMEZONE_SELECT) {
1400 system_user_timezone($edit, $form);
1401 }
1402 else {
1403 $form['account']['timezone'] = array(
1404 '#type' => 'hidden',
1405 '#value' => variable_get('user_default_timezone', DRUPAL_USER_TIMEZONE_DEFAULT) ? '' : variable_get('date_default_timezone', ''),
1406 );
1407 }
1408 return $form;
1409 }
1410 }
1411
1412 /**
1413 * Implement hook_user_login().
1414 */
1415 function system_user_login(&$edit, $account) {
1416 // If the user has a NULL time zone, notify them to set a time zone.
1417 if (!$account->timezone && variable_get('configurable_timezones', 1) && variable_get('empty_timezone_message', 0)) {
1418 drupal_set_message(t('Please configure your <a href="@user-edit">account time zone setting</a>.', array('@user-edit' => url("user/$account->uid/edit", array('query' => drupal_get_destination(), 'fragment' => 'edit-timezone')))));
1419 }
1420 }
1421
1422 /**
1423 * Add the time zone field to the user edit and register forms.
1424 */
1425 function system_user_timezone(&$edit, &$form) {
1426 global $user;
1427 $form['timezone'] = array(
1428 '#type' => 'fieldset',
1429 '#title' => t('Locale settings'),
1430 '#weight' => 6,
1431 '#collapsible' => TRUE,
1432 );
1433 $form['timezone']['timezone'] = array(
1434 '#type' => 'select',
1435 '#title' => t('Time zone'),
1436 '#default_value' => $edit['timezone'] ? $edit['timezone'] : ($edit['uid'] == $user->uid ? variable_get('date_default_timezone', '') : ''),
1437 '#options' => system_time_zones(($edit['uid'] != $user->uid)),
1438 '#description' => t('Select the desired local time and time zone. Dates and times throughout this site will be displayed using this time zone.'),
1439 );
1440 if (!$edit['timezone'] && $edit['uid'] == $user->uid) {
1441 $form['timezone']['#description'] = t('Your time zone setting will be automatically detected if possible. Please confirm the selection and click save.');
1442 $form['timezone']['timezone']['#attributes'] = array('class' => 'timezone-detect');
1443 drupal_add_js('misc/timezone.js');
1444 }
1445 }
1446
1447 /**
1448 * Implement hook_block_list().
1449 */
1450 function system_block_list() {
1451 $blocks['main'] = array(
1452 'info' => t('Main page content'),
1453 // Cached elsewhere.
1454 'cache' => BLOCK_NO_CACHE,
1455 );
1456 $blocks['powered-by'] = array(
1457 'info' => t('Powered by Drupal'),
1458 'weight' => '10',
1459 'cache' => BLOCK_NO_CACHE,
1460 );
1461 $blocks['help'] = array(
1462 'info' => t('System help'),
1463 'weight' => '5',
1464 );
1465 // System-defined menu blocks.
1466 foreach (menu_list_system_menus() as $menu_name => $title) {
1467 $blocks[$menu_name]['info'] = t($title);
1468 // Menu blocks can't be cached because each menu item can have
1469 // a custom access callback. menu.inc manages its own caching.
1470 $blocks[$menu_name]['cache'] = BLOCK_NO_CACHE;
1471 }
1472 return $blocks;
1473 }
1474
1475 /**
1476 * Implement hook_block_configure().
1477 */
1478 function system_block_configure($delta = '') {
1479 if ($delta == 'powered-by') {
1480 $image_path = 'misc/' . variable_get('drupal_badge_color', 'powered-blue') . '-' . variable_get('drupal_badge_size', '80x15') . '.png';
1481 drupal_add_js(drupal_get_path('module', 'system') . '/system.js');
1482 // Compile a list of fields to show
1483 $form['wrapper']['color'] = array(
1484 '#type' => 'select',
1485 '#title' => t('Badge color'),
1486 '#default_value' => variable_get('drupal_badge_color', 'powered-blue'),
1487 '#options' => array('powered-black' => t('Black'), 'powered-blue' => t('Blue'), 'powered-gray' => t('Gray')),
1488 );
1489 $form['wrapper']['size'] = array(
1490 '#type' => 'select',
1491 '#title' => t('Badge size'),
1492 '#default_value' => variable_get('drupal_badge_size', '80x15'),
1493 '#options' => array('80x15' => t('Small'), '88x31' => t('Medium'), '135x42' => t('Large')),
1494 );
1495 $form['wrapper']['preview'] = array(
1496 '#type' => 'item',
1497 '#title' => 'Preview',
1498 '#markup' => theme('image', $image_path, t('Powered by Drupal, an open source content management system'), t('Powered by Drupal, an open source content management system'), array('class' => 'powered-by-preview'), FALSE),
1499 );
1500 return $form;
1501 }
1502 }
1503
1504 /**
1505 * Implement hook_block_save().
1506 */
1507 function system_block_save($delta = '', $edit = NULL) {
1508 if ($delta == 'powered-by') {
1509 $image_path = 'misc/' . variable_get('drupal_badge_color', 'powered-blue') . '-' . variable_get('drupal_badge_size', '80x15') . '.png';
1510 variable_set('drupal_badge_color', $edit['color']);
1511 variable_set('drupal_badge_size', $edit['size']);
1512 }
1513 }
1514
1515 /**
1516 * Implement hook_block_view().
1517 *
1518 * Generate a block with a promotional link to Drupal.org and
1519 * all system menu blocks.
1520 */
1521 function system_block_view($delta = '') {
1522 $block = array();
1523 switch ($delta) {
1524 case 'main':
1525 $block['subject'] = NULL;
1526 $block['content'] = drupal_set_page_content();
1527 return $block;
1528 case 'powered-by':
1529 $image_path = 'misc/' . variable_get('drupal_badge_color', 'powered-blue') . '-' . variable_get('drupal_badge_size', '80x15') . '.png';
1530 $block['subject'] = NULL;
1531 $block['content'] = theme('system_powered_by', $image_path);
1532 return $block;
1533 case 'help':
1534 $block['subject'] = NULL;
1535 $block['content'] = menu_get_active_help();
1536 return $block;
1537 default:
1538 // All system menu blocks.
1539 $system_menus = menu_list_system_menus();
1540 if (isset($system_menus[$delta])) {
1541 $block['subject'] = t($system_menus[$delta]);
1542 $block['content'] = menu_tree($delta);
1543 return $block;
1544 }
1545 break;
1546 }
1547 }
1548
1549 /**
1550 * Provide a single block on the administration overview page.
1551 *
1552 * @param $item
1553 * The menu item to be displayed.
1554 */
1555 function system_admin_menu_block($item) {
1556 $cache = &drupal_static(__FUNCTION__, array());
1557 if (!isset($item['mlid'])) {
1558 $item += db_query("SELECT mlid, menu_name FROM {menu_links} ml WHERE ml.router_path = :path AND module = 'system'", array(':path' => $item['path']))->fetchAssoc();
1559 }
1560
1561 if (isset($cache[$item['mlid']])) {
1562 return $cache[$item['mlid']];
1563 }
1564
1565 $content = array();
1566 $result = db_query("
1567 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.*
1568 FROM {menu_links} ml
1569 LEFT JOIN {menu_router} m ON ml.router_path = m.path
1570 WHERE ml.plid = :plid AND ml.menu_name = :name AND hidden = 0", array(':plid' => $item['mlid'], ':name' => $item['menu_name']), array('fetch' => PDO::FETCH_ASSOC));
1571 foreach ($result as $link) {
1572 _menu_link_translate($link);
1573 if (!$link['access']) {
1574 continue;
1575 }
1576 // The link 'description' either derived from the hook_menu 'description' or
1577 // entered by the user via menu module is saved as the title attribute.
1578 if (!empty($link['localized_options']['attributes']['title'])) {
1579 $link['description'] = $link['localized_options']['attributes']['title'];
1580 }
1581 // Prepare for sorting as in function _menu_tree_check_access().
1582 // The weight is offset so it is always positive, with a uniform 5-digits.
1583 $content[(50000 + $link['weight']) . ' ' . drupal_strtolower($link['title']) . ' ' . $link['mlid']] = $link;
1584 }
1585 ksort($content);
1586 $cache[$item['mlid']] = $content;
1587 return $content;
1588 }
1589
1590 /**
1591 * Checks the existence of the directory specified in $form_element. This
1592 * function is called from the system_settings form to check both the
1593 * file_directory_path and file_directory_temp directories. If validation
1594 * fails, the form element is flagged with an error from within the
1595 * file_check_directory function.
1596 *
1597 * @param $form_element
1598 * The form element containing the name of the directory to check.
1599 */
1600 function system_check_directory($form_element) {
1601 file_check_directory($form_element['#value'], FILE_CREATE_DIRECTORY, $form_element['#parents'][0]);
1602 return $form_element;
1603 }
1604
1605 /**
1606 * Retrieves the current status of an array of files in the system table.
1607 *
1608 * @param $files
1609 * An array of files to check.
1610 * @param $type
1611 * The type of the files.
1612 */
1613 function system_get_files_database(&$files, $type) {
1614 // Extract current files from database.
1615 $result = db_query("SELECT filename, name, type, status, schema_version, weight FROM {system} WHERE type = :type", array(':type' => $type));
1616 foreach ($result as $file) {
1617 if (isset($files[$file->name]) && is_object($files[$file->name])) {
1618 $file->filepath = $file->filename;
1619 foreach ($file as $key => $value) {
1620 if (!isset($files[$file->name]->key)) {
1621 $files[$file->name]->$key = $value;
1622 }
1623 }
1624 }
1625 }
1626 }
1627
1628 /**
1629 * Updates the records in the system table based on the files array.
1630 *
1631 * @param $files
1632 * An array of files.
1633 * @param $type
1634 * The type of the files.
1635 */
1636 function system_update_files_database(&$files, $type) {
1637 $result = db_query("SELECT * FROM {system} WHERE type = :type", array(':type' => $type));
1638
1639 // Add all files that need to be deleted to a DatabaseCondition.
1640 $delete = db_or();
1641 foreach ($result as $file) {
1642 if (isset($files[$file->name]) && is_object($files[$file->name])) {
1643 // Keep the old filename from the database in case the file has moved.
1644 $old_filename = $file->filename;
1645
1646 $updated_fields = array();
1647
1648 // Handle info specially, compare the serialized value.
1649 $serialized_info = serialize($files[$file->name]->info);
1650 if ($serialized_info != $file->info) {
1651 $updated_fields['info'] = $serialized_info;
1652 }
1653 unset($file->info);
1654
1655 // Scan remaining fields to find only the updated values.
1656 foreach ($file as $key => $value) {
1657 if (isset($files[$file->name]->$key) && $files[$file->name]->$key != $value) {
1658 $updated_fields[$key] = $files[$file->name]->$key;
1659 }
1660 }
1661
1662 // Update the record.
1663 if (count($updated_fields)) {
1664 db_update('system')
1665 ->fields($updated_fields)
1666 ->condition('filename', $old_filename)
1667 ->execute();
1668 }
1669
1670 // Indiciate that the file exists already.
1671 $files[$file->name]->exists = TRUE;
1672 }
1673 else {
1674 // File is not found in file system, so delete record from the system table.
1675 $delete->condition('filename', $file->filename);
1676 }
1677 }
1678
1679 if (count($delete) > 0) {
1680 // Delete all missing files from the system table
1681 db_delete('system')
1682 ->condition($delete)
1683 ->execute();
1684 }
1685
1686 // All remaining files are not in the system table, so we need to add them.
1687 $query = db_insert('system')->fields(array('filename', 'name', 'type', 'owner', 'info'));
1688 foreach($files as &$file) {
1689 if (isset($file->exists)) {
1690 unset($file->exists);
1691 }
1692 else {
1693 $query->values(array(
1694 'filename' => $file->filepath,
1695 'name' => $file->name,
1696 'type' => $type,
1697 'owner' => isset($file->owner) ? $file->owner : '',
1698 'info' => serialize($file->info),
1699 ));
1700 $file->type = $type;
1701 $file->status = 0;
1702 $file->schema_version = -1;
1703 }
1704 }
1705 $query->execute();
1706 }
1707
1708 /**
1709 * Helper function to scan and collect module .info data.
1710 *
1711 * @return
1712 * An associative array of module information.
1713 */
1714 function _system_get_module_data() {
1715 // Find modules
1716 $modules = drupal_system_listing('/\.module$/', 'modules', 'name', 0);
1717
1718 // Set defaults for module info.
1719 $defaults = array(
1720 'dependencies' => array(),
1721 'dependents' => array(),
1722 'description' => '',
1723 'package' => 'Other',
1724 'version' => NULL,
1725 'php' => DRUPAL_MINIMUM_PHP,
1726 'files' => array(),
1727 );
1728
1729 // Read info files for each module.
1730 foreach ($modules as $key => $module) {
1731 // Look for the info file.
1732 $module->info = drupal_parse_info_file(dirname($module->filepath) . '/' . $module->name . '.info');
1733
1734 // Skip modules that don't provide info.
1735 if (empty($module->info)) {
1736 unset($modules[$key]);
1737 continue;
1738 }
1739
1740 // Merge in defaults and save.
1741 $modules[$key]->info = $module->info + $defaults;
1742
1743 // Invoke hook_system_info_alter() to give installed modules a chance to
1744 // modify the data in the .info files if necessary.
1745 drupal_alter('system_info', $modules[$key]->info, $modules[$key]);
1746 }
1747
1748 return $modules;
1749 }
1750
1751 /**
1752 * Collect data about all currently available modules.
1753 *
1754 * @return
1755 * Array of all available modules and their data.
1756 */
1757 function system_get_module_data() {
1758 $modules = _system_get_module_data();
1759 ksort($modules);
1760 system_get_files_database($modules, 'module');
1761 system_update_files_database($modules, 'module');
1762 $modules = _module_build_dependencies($modules);
1763 return $modules;
1764 }
1765
1766 /**
1767 * Helper function to scan and collect theme .info data and their engines.
1768 *
1769 * @return
1770 * An associative array of themes information.
1771 */
1772 function _system_get_theme_data() {
1773 $themes_info = &drupal_static(__FUNCTION__, array());
1774
1775 if (empty($themes_info)) {
1776 // Find themes
1777 $themes = drupal_system_listing('/\.info$/', 'themes');
1778 // Find theme engines
1779 $engines = drupal_system_listing('/\.engine$/', 'themes/engines');
1780
1781 // Set defaults for theme info.
1782 $defaults = array(
1783 'regions' => array(
1784 'sidebar_first' => 'Left sidebar',
1785 'sidebar_second' => 'Right sidebar',
1786 'content' => 'Content',
1787 'header' => 'Header',
1788 'footer' => 'Footer',
1789 'highlight' => 'Highlighted content',
1790 'help' => 'Help',
1791 'page_top' => 'Page top',
1792 'page_bottom' => 'Page bottom',
1793 ),
1794 'description' => '',
1795 'features' => array(
1796 'comment_user_picture',
1797 'comment_user_verification',
1798 'favicon',
1799 'logo',
1800 'name',
1801 'node_user_picture',
1802 'search',
1803 'slogan',
1804 'main_menu',
1805 'secondary_menu',
1806 ),
1807 'screenshot' => 'screenshot.png',
1808 'php' => DRUPAL_MINIMUM_PHP,
1809 );
1810
1811 $sub_themes = array();
1812 // Read info files for each theme
1813 foreach ($themes as $key => $theme) {
1814 $themes[$key]->filename = $theme->filepath;
1815 $themes[$key]->info = drupal_parse_info_file($theme->filepath) + $defaults;
1816
1817 // Invoke hook_system_info_alter() to give installed modules a chance to
1818 // modify the data in the .info files if necessary.
1819 drupal_alter('system_info', $themes[$key]->info, $themes[$key]);
1820
1821 if (!empty($themes[$key]->info['base theme'])) {
1822 $sub_themes[] = $key;
1823 }
1824 if (empty($themes[$key]->info['engine'])) {
1825 $filename = dirname($themes[$key]->filepath) . '/' . $themes[$key]->name . '.theme';
1826 if (file_exists($filename)) {
1827 $themes[$key]->owner = $filename;
1828 $themes[$key]->prefix = $key;
1829 }
1830 }
1831 else {
1832 $engine = $themes[$key]->info['engine'];
1833 if (isset($engines[$engine])) {
1834 $themes[$key]->owner = $engines[$engine]->filepath;
1835 $themes[$key]->prefix = $engines[$engine]->name;
1836 $themes[$key]->template = TRUE;
1837 }
1838 }
1839
1840 // Give the stylesheets proper path information.
1841 $pathed_stylesheets = array();
1842 if (isset($themes[$key]->info['stylesheets'])) {
1843 foreach ($themes[$key]->info['stylesheets'] as $media => $stylesheets) {
1844 foreach ($stylesheets as $stylesheet) {
1845 $pathed_stylesheets[$media][$stylesheet] = dirname($themes[$key]->filepath) . '/' . $stylesheet;
1846 }
1847 }
1848 }
1849 $themes[$key]->info['stylesheets'] = $pathed_stylesheets;
1850
1851 // Give the scripts proper path information.
1852 $scripts = array();
1853 if (isset($themes[$key]->info['scripts'])) {
1854 foreach ($themes[$key]->info['scripts'] as $script) {
1855 $scripts[$script] = dirname($themes[$key]->filepath) . '/' . $script;
1856 }
1857 }
1858 $themes[$key]->info['scripts'] = $scripts;
1859 // Give the screenshot proper path information.
1860 if (!empty($themes[$key]->info['screenshot'])) {
1861 $themes[$key]->info['screenshot'] = dirname($themes[$key]->filepath) . '/' . $themes[$key]->info['screenshot'];
1862 }
1863 }
1864
1865 // Now that we've established all our master themes, go back and fill in
1866 // data for subthemes.
1867 foreach ($sub_themes as $key) {
1868 $themes[$key]->base_themes = system_find_base_themes($themes, $key);
1869 // Don't proceed if there was a problem with the root base theme.
1870 if (!current($themes[$key]->base_themes)) {
1871 continue;
1872 }
1873 $base_key = key($themes[$key]->base_themes);
1874 foreach (array_keys($themes[$key]->base_themes) as $base_theme) {
1875 $themes[$base_theme]->sub_themes[$key] = $themes[$key]->info['name'];
1876 }
1877 // Copy the 'owner' and 'engine' over if the top level theme uses a
1878 // theme engine.
1879 if (isset($themes[$base_key]->owner)) {
1880 if (isset($themes[$base_key]->info['engine'])) {
1881 $themes[$key]->info['engine'] = $themes[$base_key]->info['engine'];
1882 $themes[$key]->owner = $themes[$base_key]->owner;
1883 $themes[$key]->prefix = $themes[$base_key]->prefix;
1884 }
1885 else {
1886 $themes[$key]->prefix = $key;
1887 }
1888 }
1889 }
1890
1891 $themes_info = $themes;
1892 }
1893
1894 return $themes_info;
1895 }
1896
1897 /**
1898 * Collect data about all currently available themes.
1899 *
1900 * @return
1901 * Array of all available themes and their data.
1902 */
1903 function system_get_theme_data() {
1904 $themes = _system_get_theme_data();
1905 ksort($themes);
1906 system_get_files_database($themes, 'theme');
1907 system_update_files_database($themes, 'theme');
1908 return $themes;
1909 }
1910
1911 /**
1912 * Find all the base themes for the specified theme.
1913 *
1914 * Themes can inherit templates and function implementations from earlier themes.
1915 *
1916 * @param $themes
1917 * An array of available themes.
1918 * @param $key
1919 * The name of the theme whose base we are looking for.
1920 * @param $used_keys
1921 * A recursion parameter preventing endless loops.
1922 * @return
1923 * Returns an array of all of the theme's ancestors; the first element's value
1924 * will be NULL if an error occurred.
1925 */
1926 function system_find_base_themes($themes, $key, $used_keys = array()) {
1927 $base_key = $themes[$key]->info['base theme'];
1928 // Does the base theme exist?
1929 if (!isset($themes[$base_key])) {
1930 return array($base_key => NULL);
1931 }
1932
1933 $current_base_theme = array($base_key => $themes[$base_key]->info['name']);
1934
1935 // Is the base theme itself a child of another theme?
1936 if (isset($themes[$base_key]->info['base theme'])) {
1937 // Do we already know the base themes of this theme?
1938 if (isset($themes[$base_key]->base_themes)) {
1939 return $themes[$base_key]->base_themes + $current_base_theme;
1940 }
1941 // Prevent loops.
1942 if (!empty($used_keys[$base_key])) {
1943 return array($base_key => NULL);
1944 }
1945 $used_keys[$base_key] = TRUE;
1946 return system_find_base_themes($themes, $base_key, $used_keys) + $current_base_theme;
1947 }
1948 // If we get here, then this is our parent theme.
1949 return $current_base_theme;
1950 }
1951
1952 /**
1953 * Get a list of available regions from a specified theme.
1954 *
1955 * @param $theme_key
1956 * The name of a theme.
1957 * @param $show
1958 * Possible values: REGIONS_ALL or REGIONS_VISIBLE. Visible excludes hidden
1959 * regions.
1960 * @return
1961 * An array of regions in the form $region['name'] = 'description'.
1962 */
1963 function system_region_list($theme_key, $show = REGIONS_ALL) {
1964 $list = &drupal_static(__FUNCTION__, array());
1965
1966 if (empty($list[$theme_key][$show])) {
1967 $info = unserialize(db_query("SELECT info FROM {system} WHERE type = :type AND name = :name", array(':type' => 'theme', ':name' => $theme_key))->fetchField());
1968 // If requested, suppress hidden regions. @see block_admin_display_form().
1969 foreach ($info['regions'] as $name => $label) {
1970 if ($show == REGIONS_ALL || !isset($info['regions_hidden']) || !in_array($name, $info['regions_hidden'])) {
1971 $list[$theme_key][$show][$name] = $label;
1972 }
1973 }
1974 }
1975 return $list[$theme_key][$show];
1976 }
1977
1978 /**
1979 * Implement hook_system_info_alter().
1980 */
1981 function system_system_info_alter(&$info, $file) {
1982 // Remove page-top from the blocks UI since it is reserved for modules to
1983 // populate from outside the blocks system.
1984 $info['regions_hidden'][] = 'page_top';
1985 $info['regions_hidden'][] = 'page_bottom';
1986 }
1987
1988 /**
1989 * Get the name of the default region for a given theme.
1990 *
1991 * @param $theme
1992 * The name of a theme.
1993 * @return
1994 * A string that is the region name.
1995 */
1996 function system_default_region($theme) {
1997 $regions = array_keys(system_region_list($theme));
1998 return isset($regions[0]) ? $regions[0] : '';
1999 }
2000
2001 function _system_settings_form_automatic_defaults($form) {
2002 // Get an array of all non-property keys
2003 $keys = element_children($form);
2004
2005 foreach ($keys as $key) {
2006 // If the property (key) '#default_value' exists, replace it.
2007 if (array_key_exists('#default_value', $form[$key])) {
2008 $form[$key]['#default_value'] = variable_get($key, $form[$key]['#default_value']);
2009 }
2010 else {
2011 // Recurse through child elements
2012 $form[$key] = _system_settings_form_automatic_defaults($form[$key]);
2013 }
2014 }
2015
2016 return $form;
2017 }
2018
2019 /**
2020 * Add default buttons to a form and set its prefix.
2021 *
2022 * @ingroup forms
2023 * @see system_settings_form_submit()
2024 * @param $form
2025 * An associative array containing the structure of the form.
2026 * @param $automatic_defaults
2027 * Automatically load the saved values for each field from the system variables (defaults to TRUE).
2028 * @return
2029 * The form structure.
2030 */
2031 function system_settings_form($form, $automatic_defaults = TRUE) {
2032 $form['buttons']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration') );
2033
2034 if ($automatic_defaults) {
2035 $form = _system_settings_form_automatic_defaults($form);
2036 }
2037
2038 if (!empty($_POST) && form_get_errors()) {
2039 drupal_set_message(t('The settings have not been saved because of the errors.'), 'error');
2040 }
2041 $form['#submit'][] = 'system_settings_form_submit';
2042 $form['#theme'] = 'system_settings_form';
2043 return $form;
2044 }
2045
2046 /**
2047 * Execute the system_settings_form.
2048 *
2049 * If you want node type configure style handling of your checkboxes,
2050 * add an array_filter value to your form.
2051 */
2052 function system_settings_form_submit($form, &$form_state) {
2053 // Exclude unnecessary elements.
2054 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']);
2055
2056 foreach ($form_state['values'] as $key => $value) {
2057 if (is_array($value) && isset($form_state['values']['array_filter'])) {
2058 $value = array_keys(array_filter($value));
2059 }
2060 variable_set($key, $value);
2061 }
2062
2063 drupal_set_message(t('The configuration options have been saved.'));
2064
2065 cache_clear_all();
2066 drupal_theme_rebuild();
2067 }
2068
2069 /**
2070 * Helper function to sort requirements.
2071 */
2072 function _system_sort_requirements($a, $b) {
2073 if (!isset($a['weight'])) {
2074 if (!isset($b['weight'])) {
2075 return strcmp($a['title'], $b['title']);
2076 }
2077 return -$b['weight'];
2078 }
2079 return isset($b['weight']) ? $a['weight'] - $b['weight'] : $a['weight'];
2080 }
2081
2082 /**
2083 * Output a confirmation form
2084 *
2085 * This function returns a complete form for confirming an action. A link is
2086 * offered to go back to the item that is being changed in case the user changes
2087 * his/her mind.
2088 *
2089 * If the submit handler for this form is invoked, the user successfully
2090 * confirmed the action. You should never directly inspect $_POST to see if an
2091 * action was confirmed.
2092 *
2093 * Note - if the parameters $question, $description, $yes, or $no could contain
2094 * any user input (such as node titles or taxonomy terms), it is the
2095 * responsibility of the code calling confirm_form() to sanitize them first with
2096 * a function like check_plain() or filter_xss().
2097 *
2098 * @ingroup forms
2099 * @param $form
2100 * Additional elements to inject into the form, for example hidden elements.
2101 * @param $question
2102 * The question to ask the user (e.g. "Are you sure you want to delete the
2103 * block <em>foo</em>?").
2104 * @param $path
2105 * The page to go to if the user denies the action.
2106 * Can be either a drupal path, or an array with the keys 'path', 'query', 'fragment'.
2107 * @param $description
2108 * Additional text to display (defaults to "This action cannot be undone.").
2109 * @param $yes
2110 * A caption for the button which confirms the action (e.g. "Delete",
2111 * "Replace", ...).
2112 * @param $no
2113 * A caption for the link which denies the action (e.g. "Cancel").
2114 * @param $name
2115 * The internal name used to refer to the confirmation item.
2116 * @return
2117 * The form.
2118 */
2119 function confirm_form($form, $question, $path, $description = NULL, $yes = NULL, $no = NULL, $name = 'confirm') {
2120 $description = isset($description) ? $description : t('This action cannot be undone.');
2121
2122 // Prepare cancel link
2123 $query = $fragment = NULL;
2124 if (is_array($path)) {
2125 $query = isset($path['query']) ? $path['query'] : NULL;
2126 $fragment = isset($path['fragment']) ? $path['fragment'] : NULL;
2127 $path = isset($path['path']) ? $path['path'] : NULL;
2128 }
2129 $cancel = l($no ? $no : t('Cancel'), $path, array('query' => $query, 'fragment' => $fragment));
2130
2131 drupal_set_title($question, PASS_THROUGH);
2132
2133 // Confirm form fails duplication check, as the form values rarely change -- so skip it.
2134 $form['#skip_duplicate_check'] = TRUE;
2135
2136 $form['#attributes'] = array('class' => 'confirmation');
2137 $form['description'] = array('#markup' => $description);
2138 $form[$name] = array('#type' => 'hidden', '#value' => 1);
2139
2140 $form['actions'] = array('#prefix' => '<div class="container-inline">', '#suffix' => '</div>');
2141 $form['actions']['submit'] = array('#type' => 'submit', '#value' => $yes ? $yes : t('Confirm'));
2142 $form['actions']['cancel'] = array('#markup' => $cancel);
2143 $form['#theme'] = 'confirm_form';
2144 return $form;
2145 }
2146
2147 /**
2148 * Determine if a user is in compact mode.
2149 */
2150 function system_admin_compact_mode() {
2151 global $user;
2152 return (isset($user->admin_compact_mode)) ? $user->admin_compact_mode : variable_get('admin_compact_mode', FALSE);
2153 }
2154
2155 /**
2156 * Menu callback; Sets whether the admin menu is in compact mode or not.
2157 *
2158 * @param $mode
2159 * Valid values are 'on' and 'off'.
2160 */
2161 function system_admin_compact_page($mode = 'off') {
2162 global $user;
2163 user_save($user, array('admin_compact_mode' => ($mode == 'on')));
2164 drupal_goto(drupal_get_destination());
2165 }
2166
2167 /**
2168 * Generate a list of tasks offered by a specified module.
2169 *
2170 * @param $module
2171 * Module name.
2172 * @return
2173 * An array of task links.
2174 */
2175 function system_get_module_admin_tasks($module) {
2176 $items = &drupal_static(__FUNCTION__, array());
2177
2178 if (empty($items)) {
2179 $result = db_query("
2180 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.*
2181 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", array(), array('fetch' => PDO::FETCH_ASSOC));
2182 foreach ($result as $item) {
2183 _menu_link_translate($item);
2184 if ($item['access']) {
2185 $items[$item['router_path']] = $item;
2186 }
2187 }
2188 }
2189
2190 $admin_access = user_access('administer permissions');
2191 $admin_tasks = array();
2192 $admin_task_count = 0;
2193 // Check for permissions.
2194 if (in_array($module, module_implements('permission')) && $admin_access) {
2195 $admin_tasks[-1] = l(t('Configure permissions'), 'admin/settings/permissions', array('fragment' => 'module-' . $module));
2196 }
2197
2198 // Check for menu items that are admin links.
2199 if (in_array($module, module_implements('menu')) && $menu = module_invoke($module, 'menu')) {
2200 foreach (array_keys($menu) as $path) {
2201 if (isset($items[$path])) {
2202 $admin_tasks[$items[$path]['title'] . $admin_task_count ++] = l($items[$path]['title'], $path);
2203 }
2204 }
2205 }
2206
2207 return $admin_tasks;
2208 }
2209
2210 /**
2211 * Implement hook_cron().
2212 *
2213 * Remove older rows from flood and batch table. Remove old temporary files.
2214 */
2215 function system_cron() {
2216 // Cleanup the flood.
2217 db_delete('flood')
2218 ->condition('timestamp', REQUEST_TIME - 3600, '<')
2219 ->execute();
2220 // Cleanup the batch table.
2221 db_delete('batch')
2222 ->condition('timestamp', REQUEST_TIME - 864000, '<')
2223 ->execute();
2224
2225 // Remove temporary files that are older than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
2226 // Use separate placeholders for the status to avoid a bug in some versions
2227 // of PHP. See http://drupal.org/node/352956
2228 $result = db_query('SELECT fid FROM {files} WHERE status & :permanent1 <> :permanent2 AND timestamp < :timestamp', array(
2229 ':permanent1' => FILE_STATUS_PERMANENT,
2230 ':permanent2' => FILE_STATUS_PERMANENT,
2231 ':timestamp' => REQUEST_TIME - DRUPAL_MAXIMUM_TEMP_FILE_AGE
2232 ));
2233 foreach ($result as $row) {
2234 if ($file = file_load($row->fid)) {
2235 if (!file_delete($file)) {
2236 watchdog('file system', 'Could not delete temporary file "%path" during garbage collection', array('%path' => $file->filepath), WATCHDOG_ERROR);
2237 }
2238 }
2239 }
2240
2241 $core = array('cache', 'cache_filter', 'cache_page', 'cache_form', 'cache_menu');
2242 $cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
2243 foreach ($cache_tables as $table) {
2244 cache_clear_all(NULL, $table);
2245 }
2246
2247 // Reset expired items in the default queue implementation table. If that's
2248 // not used, this will simply be a no-op.
2249 db_update('queue')
2250 ->fields(array(
2251 'consumer_id' => 0,
2252 'expire' => 0,
2253 ))
2254 ->condition('expire', REQUEST_TIME, '<')
2255 ->execute();
2256 }
2257
2258 /**
2259 * Implement hook_hook_info().
2260 */
2261 function system_hook_info() {
2262 return array(
2263 'system' => array(
2264 'cron' => array(
2265 'run' => array(
2266 'runs when' => t('When cron runs'),
2267 ),
2268 ),
2269 ),
2270 );
2271 }
2272
2273 /**
2274 * Implement hook_action_info().
2275 */
2276 function system_action_info() {
2277 return array(
2278 'system_message_action' => array(
2279 'type' => 'system',
2280 'description' => t('Display a message to the user'),
2281 'configurable' => TRUE,
2282 'hooks' => array(
2283 'node' => array('view', 'insert', 'update', 'delete'),
2284 'comment' => array('view', 'insert', 'update', 'delete'),
2285 'user' => array('view', 'insert', 'update', 'delete', 'login'),
2286 'taxonomy' => array('insert', 'update', 'delete'),
2287 ),
2288 ),
2289 'system_send_email_action' => array(
2290 'description' => t('Send e-mail'),
2291 'type' => 'system',
2292 'configurable' => TRUE,
2293 'hooks' => array(
2294 'node' => array('view', 'insert', 'update', 'delete'),
2295 'comment' => array('view', 'insert', 'update', 'delete'),
2296 'user' => array('view', 'insert', 'update', 'delete', 'login'),
2297 'taxonomy' => array('insert', 'update', 'delete'),
2298 'cron' => array('run'),
2299 )
2300 ),
2301 'system_block_ip_action' => array(
2302 'description' => t('Ban IP address of current user'),
2303 'type' => 'user',
2304 'configurable' => FALSE,
2305 'hooks' => array(),
2306 ),
2307 'system_goto_action' => array(
2308 'description' => t('Redirect to URL'),
2309 'type' => 'system',
2310 'configurable' => TRUE,
2311 'hooks' => array(
2312 'node' => array('view', 'insert', 'update', 'delete'),
2313 'comment' => array('view', 'insert', 'update', 'delete'),
2314 'user' => array('view', 'insert', 'update', 'delete', 'login'),
2315 )
2316 )
2317 );
2318 }
2319
2320 /**
2321 * Menu callback. Display an overview of available and configured actions.
2322 */
2323 function system_actions_manage() {
2324 actions_synchronize();
2325 $actions = actions_list();
2326 $actions_map = actions_actions_map($actions);
2327 $options = array(t('Choose an advanced action'));
2328 $unconfigurable = array();
2329
2330 foreach ($actions_map as $key => $array) {
2331 if ($array['configurable']) {
2332 $options[$key] = $array['description'] . '...';
2333 }
2334 else {
2335 $unconfigurable[] = $array;
2336 }
2337 }
2338
2339 $row = array();
2340 $instances_present = db_query("SELECT aid FROM {actions} WHERE parameters <> ''")->fetchField();
2341 $header = array(
2342 array('data' => t('Action type'), 'field' => 'type'),
2343 array('data' => t('Description'), 'field' => 'description'),
2344 array('data' => $instances_present ? t('Operations') : '', 'colspan' => '2')
2345 );
2346 $query = db_select('actions')->extend('PagerDefault')->extend('TableSort');
2347 $result = $query
2348 ->fields('actions')
2349 ->limit(50)
2350 ->orderByHeader($header)
2351 ->execute();
2352
2353 foreach ($result as $action) {
2354 $row[] = array(
2355 array('data' => $action->type),
2356 array('data' => $action->description),
2357 array('data' => $action->parameters ? l(t('configure'), "admin/settings/actions/configure/$action->aid") : ''),
2358 array('data' => $action->parameters ? l(t('delete'), "admin/settings/actions/delete/$action->aid") : '')
2359 );
2360 }
2361
2362 if ($row) {
2363 $pager = theme('pager', NULL);
2364 if (!empty($pager)) {
2365 $row[] = array(array('data' => $pager, 'colspan' => '3'));
2366 }
2367 $build['system_actions_header'] = array('#markup' => '<h3>' . t('Actions available to Drupal:') . '</h3>');
2368 $build['system_actions_table'] = array('#markup' => theme('table', $header, $row));
2369 }
2370
2371 if ($actions_map) {
2372 $build['system_actions_manage_form'] = drupal_get_form('system_actions_manage_form', $options);
2373 }
2374
2375 return $build;
2376 }
2377
2378 /**
2379 * Define the form for the actions overview page.
2380 *
2381 * @see system_actions_manage_form_submit()
2382 * @ingroup forms
2383 * @param $form_state
2384 * An associative array containing the current state of the form; not used.
2385 * @param $options
2386 * An array of configurable actions.
2387 * @return
2388 * Form definition.
2389 */
2390 function system_actions_manage_form($form_state, $options = array()) {
2391 $form['parent'] = array(
2392 '#type' => 'fieldset',
2393 '#title' => t('Make a new advanced action available'),
2394 '#prefix' => '<div class="container-inline">',
2395 '#suffix' => '</div>',
2396 );
2397 $form['parent']['action'] = array(
2398 '#type' => 'select',
2399 '#default_value' => '',
2400 '#options' => $options,
2401 '#description' => '',
2402 );
2403 $form['parent']['buttons']['submit'] = array(
2404 '#type' => 'submit',
2405 '#value' => t('Create'),
2406 );
2407 return $form;
2408 }
2409
2410 /**
2411 * Process system_actions_manage form submissions.
2412 */
2413 function system_actions_manage_form_submit($form, &$form_state) {
2414 if ($form_state['values']['action']) {
2415 $form_state['redirect'] = 'admin/settings/actions/configure/' . $form_state['values']['action'];
2416 }
2417 }
2418
2419 /**
2420 * Menu callback. Create the form for configuration of a single action.
2421 *
2422 * We provide the "Description" field. The rest of the form
2423 * is provided by the action. We then provide the Save button.
2424 * Because we are combining unknown form elements with the action
2425 * configuration form, we use actions_ prefix on our elements.
2426 *
2427 * @see system_actions_configure_validate()
2428 * @see system_actions_configure_submit()
2429 * @param $action
2430 * md5 hash of action ID or an integer. If it's an md5 hash, we
2431 * are creating a new instance. If it's an integer, we're editing
2432 * an existing instance.
2433 * @return
2434 * Form definition.
2435 */
2436 function system_actions_configure($form_state, $action = NULL) {
2437 if ($action === NULL) {
2438 drupal_goto('admin/settings/actions');
2439 }
2440
2441 $actions_map = actions_actions_map(actions_list());
2442 $edit = array();
2443
2444 // Numeric action denotes saved instance of a configurable action;
2445 // else we are creating a new action instance.
2446 if (is_numeric($action)) {
2447 $aid = $action;
2448 // Load stored parameter values from database.
2449 $data = db_query("SELECT * FROM {actions} WHERE aid = :aid", array(':aid' => $aid))->fetch();
2450 $edit['actions_description'] = $data->description;
2451 $edit['actions_type'] = $data->type;
2452 $function = $data->callback;
2453 $action = md5($data->callback);
2454 $params = unserialize($data->parameters);
2455 if ($params) {
2456 foreach ($params as $name => $val) {
2457 $edit[$name] = $val;
2458 }
2459 }
2460 }
2461 else {
2462 $function = $actions_map[$action]['callback'];
2463 $edit['actions_description'] = $actions_map[$action]['description'];
2464 $edit['actions_type'] = $actions_map[$action]['type'];
2465 }
2466
2467 $form['actions_description'] = array(
2468 '#type' => 'textfield',
2469 '#title' => t('Description'),
2470 '#default_value' => $edit['actions_description'],
2471 '#maxlength' => '255',
2472 '#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.'),
2473 '#weight' => -10
2474 );
2475 $action_form = $function . '_form';
2476 $form = array_merge($form, $action_form($edit));
2477 $form['actions_type'] = array(
2478 '#type' => 'value',
2479 '#value' => $edit['actions_type'],
2480 );
2481 $form['actions_action'] = array(
2482 '#type' => 'hidden',
2483 '#value' => $action,
2484 );
2485 // $aid is set when configuring an existing action instance.
2486 if (isset($aid)) {
2487 $form['actions_aid'] = array(
2488 '#type' => 'hidden',
2489 '#value' => $aid,
2490 );
2491 }
2492 $form['actions_configured'] = array(
2493 '#type' => 'hidden',
2494 '#value' => '1',
2495 );
2496 $form['buttons']['submit'] = array(
2497 '#type' => 'submit',
2498 '#value' => t('Save'),
2499 '#weight' => 13
2500 );
2501
2502 return $form;
2503 }
2504
2505 /**
2506 * Validate system_actions_configure form submissions.
2507 */
2508 function system_actions_configure_validate($form, $form_state) {
2509 $function = actions_function_lookup($form_state['values']['actions_action']) . '_validate';
2510 // Hand off validation to the action.
2511 if (drupal_function_exists($function)) {
2512 $function($form, $form_state);
2513 }
2514 }
2515
2516 /**
2517 * Process system_actions_configure form submissions.
2518 */
2519 function system_actions_configure_submit($form, &$form_state) {
2520 $function = actions_function_lookup($form_state['values']['actions_action']);
2521 $submit_function = $function . '_submit';
2522
2523 // Action will return keyed array of values to store.
2524 $params = $submit_function($form, $form_state);
2525 $aid = isset($form_state['values']['actions_aid']) ? $form_state['values']['actions_aid'] : NULL;
2526
2527 actions_save($function, $form_state['values']['actions_type'], $params, $form_state['values']['actions_description'], $aid);
2528 drupal_set_message(t('The action has been successfully saved.'));
2529
2530 $form_state['redirect'] = 'admin/settings/actions/manage';
2531 }
2532
2533 /**
2534 * Create the form for confirmation of deleting an action.
2535 *
2536 * @ingroup forms
2537 * @see system_actions_delete_form_submit()
2538 */
2539 function system_actions_delete_form($form_state, $action) {
2540
2541 $form['aid'] = array(
2542 '#type' => 'hidden',
2543 '#value' => $action->aid,
2544 );
2545 return confirm_form($form,
2546 t('Are you sure you want to delete the action %action?', array('%action' => $action->description)),
2547 'admin/settings/actions/manage',
2548 t('This cannot be undone.'),
2549 t('Delete'), t('Cancel')
2550 );
2551 }
2552
2553 /**
2554 * Process system_actions_delete form submissions.
2555 *
2556 * Post-deletion operations for action deletion.
2557 */
2558 function system_actions_delete_form_submit($form, &$form_state) {
2559 $aid = $form_state['values']['aid'];
2560 $action = actions_load($aid);
2561 actions_delete($aid);
2562 $description = check_plain($action->description);
2563 watchdog('user', 'Deleted action %aid (%action)', array('%aid' => $aid, '%action' => $description));
2564 drupal_set_message(t('Action %action was deleted', array('%action' => $description)));
2565 $form_state['redirect'] = 'admin/settings/actions/manage';
2566 }
2567
2568 /**
2569 * Post-deletion operations for deleting action orphans.
2570 *
2571 * @param $orphaned
2572 * An array of orphaned actions.
2573 */
2574 function system_action_delete_orphans_post($orphaned) {
2575 foreach ($orphaned as $callback) {
2576 drupal_set_message(t("Deleted orphaned action (%action).", array('%action' => $callback)));
2577 }
2578 }
2579
2580 /**
2581 * Remove actions that are in the database but not supported by any enabled module.
2582 */
2583 function system_actions_remove_orphans() {
2584 actions_synchronize(TRUE);
2585 drupal_goto('admin/settings/actions/manage');
2586 }
2587
2588 /**
2589 * Return a form definition so the Send email action can be configured.
2590 *
2591 * @see system_send_email_action_validate()
2592 * @see system_send_email_action_submit()
2593 * @param $context
2594 * Default values (if we are editing an existing action instance).
2595 * @return
2596 * Form definition.
2597 */
2598 function system_send_email_action_form($context) {
2599 // Set default values for form.
2600 if (!isset($context['recipient'])) {
2601 $context['recipient'] = '';
2602 }
2603 if (!isset($context['subject'])) {
2604 $context['subject'] = '';
2605 }
2606 if (!isset($context['message'])) {
2607 $context['message'] = '';
2608 }
2609
2610 $form['recipient'] = array(
2611 '#type' => 'textfield',
2612 '#title' => t('Recipient'),
2613 '#default_value' => $context['recipient'],
2614 '#maxlength' => '254',
2615 '#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')),
2616 );
2617 $form['subject'] = array(
2618 '#type' => 'textfield',
2619 '#title' => t('Subject'),
2620 '#default_value' => $context['subject'],
2621 '#maxlength' => '254',
2622 '#description' => t('The subject of the message.'),
2623 );
2624 $form['message'] = array(
2625 '#type' => 'textarea',
2626 '#title' => t('Message'),
2627 '#default_value' => $context['message'],
2628 '#cols' => '80',
2629 '#rows' => '20',
2630 '#description' => t('The message that should be sent. You may include the following variables: %site_name, %username, %node_url, %node_type, %title, %teaser, %body, %term_name, %term_description, %term_id, %vocabulary_name, %vocabulary_description, %vocabulary_id. Not all variables will be available in all contexts.'),
2631 );
2632 return $form;
2633 }
2634
2635 /**
2636 * Validate system_send_email_action form submissions.
2637 */
2638 function system_send_email_action_validate($form, $form_state) {
2639 $form_values = $form_state['values'];
2640 // Validate the configuration form.
2641 if (!valid_email_address($form_values['recipient']) && $form_values['recipient'] != '%author') {
2642 // We want the literal %author placeholder to be emphasized in the error message.
2643 form_set_error('recipient', t('Please enter a valid email address or %author.', array('%author' => '%author')));
2644 }
2645 }
2646
2647 /**
2648 * Process system_send_email_action form submissions.
2649 */
2650 function system_send_email_action_submit($form, $form_state) {
2651 $form_values = $form_state['values'];
2652 // Process the HTML form to store configuration. The keyed array that
2653 // we return will be serialized to the database.
2654 $params = array(
2655 'recipient' => $form_values['recipient'],
2656 'subject' => $form_values['subject'],
2657 'message' => $form_values['message'],
2658 );
2659 return $params;
2660 }
2661
2662 /**
2663 * Implement a configurable Drupal action. Sends an email.
2664 */
2665 function system_send_email_action($object, $context) {
2666 global $user;
2667
2668 switch ($context['hook']) {
2669 case 'node':
2670 // Because this is not an action of type 'node' the node
2671 // will not be passed as $object, but it will still be available
2672 // in $context.
2673 $node = $context['node'];
2674 break;
2675 // The comment hook provides nid, in $context.
2676 case 'comment':
2677 $comment = $context['comment'];
2678 $node = node_load($comment->nid);
2679 break;
2680 case 'user':
2681 // Because this is not an action of type 'user' the user
2682 // object is not passed as $object, but it will still be available
2683 // in $context.
2684 $account = $context['account'];
2685 if (isset($context['node'])) {
2686 $node = $context['node'];
2687 }
2688 elseif ($context['recipient'] == '%author') {
2689 // If we don't have a node, we don't have a node author.
2690 watchdog('error', 'Cannot use %author token in this context.');
2691 return;
2692 }
2693 break;
2694 default:
2695 // We are being called directly.
2696 $node = $object;
2697 }
2698
2699 $recipient = $context['recipient'];
2700
2701 if (isset($node)) {
2702 if (!isset($account)) {
2703 $account = user_load($node->uid);
2704 }
2705 if ($recipient == '%author') {
2706 $recipient = $account->mail;
2707 }
2708 }
2709
2710 if (!isset($account)) {
2711 $account = $user;
2712
2713 }
2714 $language = user_preferred_language($account);
2715 $params = array('account' => $account, 'object' => $object, 'context' => $context);
2716 if (isset($node)) {
2717 $params['node'] = $node;
2718 }
2719
2720 if (drupal_mail('system', 'action_send_email', $recipient, $language, $params)) {
2721 watchdog('action', 'Sent email to %recipient', array('%recipient' => $recipient));
2722 }
2723 else {
2724 watchdog('error', 'Unable to send email to %recipient', array('%recipient' => $recipient));
2725 }
2726 }
2727
2728 /**
2729 * Implement hook_mail().
2730 */
2731 function system_mail($key, &$message, $params) {
2732 $account = $params['account'];
2733 $context = $params['context'];
2734 $variables = array(
2735 '%site_name' => variable_get('site_name', 'Drupal'),
2736 '%username' => $account->name,
2737 );
2738 if ($context['hook'] == 'taxonomy') {
2739 $object = $params['object'];
2740 $vocabulary = taxonomy_vocabulary_load($object->vid);
2741 $variables += array(
2742 '%term_name' => $object->name,
2743 '%term_description' => $object->description,
2744 '%term_id' => $object->tid,
2745 '%vocabulary_name' => $vocabulary->name,
2746 '%vocabulary_description' => $vocabulary->description,
2747 '%vocabulary_id' => $vocabulary->vid,
2748 );
2749 }
2750
2751 // Node-based variable translation is only available if we have a node.
2752 if (isset($params['node'])) {
2753 $node = $params['node'];
2754 $variables += array(
2755 '%uid' => $node->uid,
2756 '%node_url' => url('node/' . $node->nid, array('absolute' => TRUE)),
2757 '%node_type' => node_type_get_name($node),
2758 '%title' => $node->title,
2759 '%teaser' => $node->teaser,
2760 '%body' => $node->body,
2761 );
2762 }
2763 $subject = strtr($context['subject'], $variables);
2764 $body = strtr($context['message'], $variables);
2765 $message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
2766 $message['body'][] = drupal_html_to_text($body);
2767 }
2768
2769 function system_message_action_form($context) {
2770 $form['message'] = array(
2771 '#type' => 'textarea',
2772 '#title' => t('Message'),
2773 '#default_value' => isset($context['message']) ? $context['message'] : '',
2774 '#required' => TRUE,
2775 '#rows' => '8',
2776 '#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, %term_name, %term_description, %term_id, %vocabulary_name, %vocabulary_description, %vocabulary_id. Not all variables will be available in all contexts.'),
2777 );
2778 return $form;
2779 }
2780
2781 function system_message_action_submit($form, $form_state) {
2782 return array('message' => $form_state['values']['message']);
2783 }
2784
2785 /**
2786 * A configurable Drupal action. Sends a message to the current user's screen.
2787 */
2788 function system_message_action(&$object, $context = array()) {
2789 global $user;
2790 $variables = array(
2791 '%site_name' => variable_get('site_name', 'Drupal'),
2792 '%username' => $user->name ? $user->name : variable_get('anonymous', t('Anonymous')),
2793 );
2794
2795 // This action can be called in any context, but if placeholders
2796 // are used a node object must be present to be the source
2797 // of substituted text.
2798 switch ($context['hook']) {
2799 case 'node':
2800 // Because this is not an action of type 'node' the node
2801 // will not be passed as $object, but it will still be available
2802 // in $context.
2803 $node = $context['node'];
2804 break;
2805 // The comment hook also provides the node, in context.
2806 case 'comment':
2807 $comment = $context['comment'];
2808 $node = node_load($comment->nid);
2809 break;
2810 case 'taxonomy':
2811 $vocabulary = taxonomy_vocabulary_load($object->vid);
2812 $variables = array_merge($variables, array(
2813 '%term_name' => $object->name,
2814 '%term_description' => $object->description,
2815 '%term_id' => $object->tid,
2816 '%vocabulary_name' => $vocabulary->name,
2817 '%vocabulary_description' => $vocabulary->description,
2818 '%vocabulary_id' => $vocabulary->vid,
2819 )
2820 );
2821 break;
2822 default:
2823 // We are being called directly.
2824 $node = $object;
2825 }
2826
2827 if (isset($node) && is_object($node)) {
2828 $variables = array_merge($variables, array(
2829 '%uid' => $node->uid,
2830 '%node_url' => url('node/' . $node->nid, array('absolute' => TRUE)),
2831 '%node_type' => check_plain(node_type_get_name($node)),
2832 '%title' => filter_xss($node->title),
2833 '%teaser' => filter_xss($node->teaser),
2834 '%body' => filter_xss($node->body),
2835 )
2836 );
2837 }
2838 $context['message'] = strtr($context['message'], $variables);
2839 drupal_set_message($context['message']);
2840 }
2841
2842 /**
2843 * Implement a configurable Drupal action. Redirect user to a URL.
2844 */
2845 function system_goto_action_form($context) {
2846 $form['url'] = array(
2847 '#type' => 'textfield',
2848 '#title' => t('URL'),
2849 '#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.'),
2850 '#default_value' => isset($context['url']) ? $context['url'] : '',
2851 '#required' => TRUE,
2852 );
2853 return $form;
2854 }
2855
2856 function system_goto_action_submit($form, $form_state) {
2857 return array(
2858 'url' => $form_state['values']['url']
2859 );
2860 }
2861
2862 function system_goto_action($object, $context) {
2863 drupal_goto($context['url']);
2864 }
2865
2866 /**
2867 * Implement a Drupal action.
2868 * Blocks the user's IP address.
2869 */
2870 function system_block_ip_action() {
2871 $ip = ip_address();
2872 db_insert('blocked_ips')
2873 ->fields(array('ip' => $ip))
2874 ->execute();
2875 watchdog('action', 'Banned IP address %ip', array('%ip' => $ip));
2876 }
2877
2878 /**
2879 * Generate an array of time zones and their local time&date.
2880 *
2881 * @param $blank
2882 * If evaluates true, prepend an empty time zone option to the array.
2883 */
2884 function system_time_zones($blank = NULL) {
2885 $zonelist = timezone_identifiers_list();
2886 $zones = $blank ? array('' => t('- None selected -')) : array();
2887 foreach ($zonelist as $zone) {
2888 // Because many time zones exist in PHP only for backward compatibility
2889 // reasons and should not be used, the list is filtered by a regular
2890 // expression.
2891 if (preg_match('!^((Africa|America|Antarctica|Arctic|Asia|Atlantic|Australia|Europe|Indian|Pacific)/|UTC$)!', $zone)) {
2892 $zones[$zone] = t('@zone: @date', array('@zone' => t(str_replace('_', ' ', $zone)), '@date' => format_date(REQUEST_TIME, 'custom', variable_get('date_format_long', 'l, F j, Y - H:i') . ' O', $zone)));
2893 }
2894 }
2895 // Sort the translated time zones alphabetically.
2896 asort($zones);
2897 return $zones;
2898 }
2899
2900 /**
2901 * Checks whether the server is capable of issuing HTTP requests.
2902 *
2903 * The function sets the drupal_http_request_fail system variable to TRUE if
2904 * drupal_http_request() does not work and then the system status report page
2905 * will contain an error.
2906 *
2907 * @return
2908 * TRUE if this installation can issue HTTP requests.
2909 */
2910 function system_check_http_request() {
2911 // Try to get the content of the front page via drupal_http_request().
2912 $result = drupal_http_request(url('', array('absolute' => TRUE)));
2913 // We only care that we get a http response - this means that Drupal
2914 // can make a http request.
2915 $works = isset($result->code) && ($result->code >= 100) && ($result->code < 600);
2916 variable_set('drupal_http_request_fails', !$works);
2917 return $works;
2918 }
2919
2920 /**
2921 * Menu callback; Retrieve a JSON object containing a suggested time zone name.
2922 */
2923 function system_timezone($abbreviation = '', $offset = -1, $is_daylight_saving_time = NULL) {
2924 // An abbreviation of "0" passed in the callback arguments should be
2925 // interpreted as the empty string.
2926 $abbreviation = $abbreviation ? $abbreviation : '';
2927 $timezone = timezone_name_from_abbr($abbreviation, intval($offset), $is_daylight_saving_time);
2928 drupal_json($timezone);
2929 }
2930
2931 /**
2932 * Format the Powered by Drupal text.
2933 *
2934 * @ingroup themeable
2935 */
2936 function theme_system_powered_by($image_path) {
2937 $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'));
2938 return l($image, 'http://drupal.org', array('html' => TRUE, 'absolute' => TRUE, 'external' => TRUE));
2939 }
2940
2941 /**
2942 * Display the link to show or hide inline help descriptions.
2943 *
2944 * @ingroup themeable
2945 */
2946 function theme_system_compact_link() {
2947 $output = '<div class="compact-link">';
2948 if (system_admin_compact_mode()) {
2949 $output .= l(t('Show descriptions'), 'admin/compact/off', array('attributes' => array('title' => t('Expand layout to include descriptions.')), 'query' => drupal_get_destination()));
2950 }
2951 else {
2952 $output .= l(t('Hide descriptions'), 'admin/compact/on', array('attributes' => array('title' => t('Compress layout by hiding descriptions.')), 'query' => drupal_get_destination()));
2953 }
2954 $output .= '</div>';
2955
2956 return $output;
2957 }
2958
2959
2960 /**
2961 * Send Drupal and the major version number in the META GENERATOR HTML.
2962 *
2963 * @ingroup themeable
2964 */
2965 function theme_meta_generator_html($version = VERSION) {
2966 drupal_add_html_head('<meta name="Generator" content="Drupal ' . $version . ' (http://drupal.org)" />');
2967 }
2968
2969 /**
2970 * Send Drupal and the major version number in the HTTP headers.
2971 *
2972 * @ingroup themeable
2973 */
2974 function theme_meta_generator_header($version = VERSION) {
2975 drupal_set_header('X-Generator', 'Drupal ' . $version . ' (http://drupal.org)');
2976 }
2977
2978 /**
2979 * Implement hook_image_toolkits().
2980 */
2981 function system_image_toolkits() {
2982 return array(
2983 'gd' => array(
2984 'title' => t('GD2 image manipulation toolkit'),
2985 'available' => drupal_function_exists('image_gd_check_settings') && image_gd_check_settings(),
2986 ),
2987 );
2988 }
2989
2990 /**
2991 * Attempts to get a file using drupal_http_request and to store it locally.
2992 *
2993 * @param $url
2994 * The URL of the file to grab.
2995 *
2996 * @param $destination
2997 * Where the file should be saved, if a directory is provided, file is saved
2998 * in that directory with its original name. If a filename is provided,
2999 * remote fileis stored to that location. NOTE: Relative to drupal "files" directory"
3000 *
3001 * @param $overwrite boolean
3002 * Defaults to TRUE, will overwrite existing files of the same name.
3003 *
3004 * @return
3005 * On success the address the files was saved to, FALSE on failure.
3006 */
3007 function system_retrieve_file($url, $destination = NULL, $overwrite = TRUE) {
3008 if (!$destination) {
3009 $destination = file_directory_temp();
3010 }
3011 $parsed_url = parse_url($url);
3012 $local = is_dir(file_directory_path() . '/' . $destination) ? $destination . '/' . basename($parsed_url['path']) : $destination;
3013
3014 if (!$overwrite && file_exists($local)) {
3015 drupal_set_message(t('@remote could not be saved. @local already exists', array('@remote' => $url, '@local' => $local)), 'error');
3016 return FALSE;
3017 }
3018
3019 $result = drupal_http_request($url);
3020 if ($result->code != 200 || !file_save_data($result->data, $local)) {
3021 drupal_set_message(t('@remote could not be saved.', array('@remote' => $url)), 'error');
3022 return FALSE;
3023 }
3024
3025 return $local;
3026 }
3027

Legend

Missed
lines code that were not excersized during program execution.
Covered
lines code were excersized during program execution.
Comment/non executable
Comment or non-executable line of code.
Dead
lines of code that according to xdebug could not be executed. This is counted as coverage code because in almost all cases it is code that runnable.