=== modified file 'includes/actions.inc' --- includes/actions.inc 2008-06-29 12:07:15 +0000 +++ includes/actions.inc 2008-07-26 08:29:07 +0000 @@ -83,7 +83,10 @@ function actions_do($action_ids, $object } // Singleton action; $action_id is the function name. else { - $result[$action_id] = $action_id($object, $context, $a1, $a2); + $function = $action_id; + } + if (drupal_function_exists($function)) { + $result[$action_id] = $function($object, $context, $a1, $a2); } } } @@ -250,7 +253,7 @@ function actions_function_lookup($hash) */ function actions_synchronize($actions_in_code = array(), $delete_orphans = FALSE) { if (!$actions_in_code) { - $actions_in_code = actions_list(); + $actions_in_code = actions_list(TRUE); } $actions_in_db = array(); $result = db_query("SELECT * FROM {actions} WHERE parameters = ''"); === modified file 'includes/batch.inc' --- includes/batch.inc 2008-06-24 21:51:02 +0000 +++ includes/batch.inc 2008-07-26 08:29:07 +0000 @@ -190,7 +190,7 @@ function _batch_process() { // We assume a single pass operation and set the completion level // to 1 by default. $finished = 1; - if ((list($function, $args) = reset($current_set['operations'])) && function_exists($function)) { + if ((list($function, $args) = reset($current_set['operations'])) && drupal_function_exists($function)) { // Build the 'context' array, execute the function call, // and retrieve the user message. $batch_context = array('sandbox' => &$current_set['sandbox'], 'results' => &$current_set['results'], 'finished' => &$finished, 'message' => &$task_message); @@ -282,7 +282,7 @@ function _batch_next_set() { if (isset($batch['sets'][$batch['current_set'] + 1])) { $batch['current_set']++; $current_set =& _batch_current_set(); - if (isset($current_set['form_submit']) && ($function = $current_set['form_submit']) && function_exists($function)) { + if (isset($current_set['form_submit']) && ($function = $current_set['form_submit']) && drupal_function_exists($function)) { // We use our stored copies of $form and $form_state, to account for // possible alteration by the submit handlers. $function($batch['form'], $batch['form_state']); @@ -306,7 +306,7 @@ function _batch_finished() { if (isset($batch_set['file']) && is_file($batch_set['file'])) { include_once($batch_set['file']); } - if (function_exists($batch_set['finished'])) { + if (drupal_function_exists($batch_set['finished'])) { $batch_set['finished']($batch_set['success'], $batch_set['results'], $batch_set['operations']); } } === modified file 'includes/bootstrap.inc' --- includes/bootstrap.inc 2008-07-17 21:10:38 +0000 +++ includes/bootstrap.inc 2008-07-27 19:54:09 +0000 @@ -430,10 +430,11 @@ function drupal_get_filename($type, $nam // nothing } // Verify that we have an active database connection, before querying - // the database. This is required because this function is called both + // the database. This is required because this function is called both // before we have a database connection (i.e. during installation) and - // when a database connection fails. - elseif (db_is_active() && (($file = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s' AND type = '%s'", $name, $type))) && file_exists($file))) { + // when a database connection fails. As this is called very, very early + // during the install process, even database.inc might not be loaded. + elseif (function_exists('db_is_active') && db_is_active() && (($file = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s' AND type = '%s'", $name, $type))) && file_exists($file))) { $files[$type][$name] = $file; } else { @@ -507,17 +508,21 @@ function variable_get($name, $default) { * @param $value * The value to set. This can be any PHP data type; these functions take care * of serialization as necessary. + * @param $permanent + * Whether to persist this variable value after the current request. */ -function variable_set($name, $value) { +function variable_set($name, $value, $permanent = TRUE) { global $conf; - $serialized_value = serialize($value); - db_query("UPDATE {variable} SET value = '%s' WHERE name = '%s'", $serialized_value, $name); - if (!db_affected_rows()) { - @db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", $name, $serialized_value); - } + if ($permanent) { + $serialized_value = serialize($value); + db_query("UPDATE {variable} SET value = '%s' WHERE name = '%s'", $serialized_value, $name); + if (!db_affected_rows()) { + @db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", $name, $serialized_value); + } - cache_clear_all('variables', 'cache'); + cache_clear_all('variables', 'cache'); + } $conf[$name] = $value; } @@ -527,12 +532,16 @@ function variable_set($name, $value) { * * @param $name * The name of the variable to undefine. + * @param $permanent + * If FALSE, the value will be available again on the next page load. */ -function variable_del($name) { +function variable_del($name, $permanent = TRUE) { global $conf; - db_query("DELETE FROM {variable} WHERE name = '%s'", $name); - cache_clear_all('variables', 'cache'); + if ($permanent) { + db_query("DELETE FROM {variable} WHERE name = '%s'", $name); + cache_clear_all('variables', 'cache'); + } unset($conf[$name]); } @@ -561,42 +570,55 @@ function page_get_cache() { } /** - * Call all init or exit hooks without including all modules. - * - * @param $hook - * The name of the bootstrap hook we wish to invoke. - */ -function bootstrap_invoke_all($hook) { - foreach (module_list(TRUE, TRUE) as $module) { - module_invoke($module, $hook); - } -} - -/** * Includes a file with the provided type and name. This prevents * including a theme, engine, module, etc., more than once. * * @param $type - * The type of item to load (i.e. theme, theme_engine, module). + * The type of item to load (i.e. theme, theme_engine, module). If left out, + * only an array of already loaded files is returned. * @param $name * The name of the item to load. + * @param $filename + * The name of the file to be loaded. Optional. * * @return * TRUE if the item is loaded or has already been loaded. */ -function drupal_load($type, $name) { - static $files = array(); +function drupal_load($type = NULL, $name = NULL, $filename = '') { + static $files = array(), $module_dependencies = NULL, $file_cache = array(); - if (isset($files[$type][$name])) { + if (!isset($type)) { + return $file_cache; + } + if (isset($files[$type][$name][$filename])) { return TRUE; } - $filename = drupal_get_filename($type, $name); + $index = $filename; + if (!$filename) { + $filename = './'. drupal_get_filename($type, $name); + } if ($filename) { - include_once "./$filename"; - $files[$type][$name] = TRUE; - + include_once $filename; + $files[$type][$name][$index] = TRUE; + $file_cache[$filename] = $filename; + if ($type == 'module') { + if (!isset($dependencies)) { + $dependencies = variable_get('module_dependencies', array()); + } + if (isset($dependencies[$name])) { + foreach ($dependencies[$name] as $dependency => $dependency_filename) { + // There is no need for recursively calling back drupal_load because + // dependencies are already filled out by _module_build_dependencies. + if (!isset($files[$type][$dependency][$dependency_filename])) { + include_once $dependency_filename; + $file_cache[$dependency_filename] = $dependency_filename; + $files[$type][$dependency][$dependency_filename] = TRUE; + } + } + } + } return TRUE; } @@ -677,13 +699,6 @@ function drupal_page_cache_header($cache } /** - * Define the critical hooks that force modules to always be loaded. - */ -function bootstrap_hooks() { - return array('boot', 'exit'); -} - -/** * Unserializes and appends elements from a serialized string. * * @param $obj @@ -819,7 +834,7 @@ function watchdog($type, $message, $vari ); // Call the logging hooks to log/process the message - foreach (module_implements('watchdog', TRUE) as $module) { + foreach (module_implements('watchdog') as $module) { module_invoke($module, 'watchdog', $log_message); } } @@ -956,15 +971,24 @@ function drupal_anonymous_user($session * DRUPAL_BOOTSTRAP_LANGUAGE: identify the language used on the page. * DRUPAL_BOOTSTRAP_PATH: set $_GET['q'] to Drupal path of request. * DRUPAL_BOOTSTRAP_FULL: Drupal is fully loaded, validate and fix input data. + * + * Optional. If drupal_bootstrap is called without parameters, it only + * returns the array of phases left. + * + * @return + * Array of phases left. */ -function drupal_bootstrap($phase) { +function drupal_bootstrap($phase = NULL) { static $phases = array(DRUPAL_BOOTSTRAP_CONFIGURATION, DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE, DRUPAL_BOOTSTRAP_DATABASE, DRUPAL_BOOTSTRAP_ACCESS, DRUPAL_BOOTSTRAP_SESSION, DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE, DRUPAL_BOOTSTRAP_LANGUAGE, DRUPAL_BOOTSTRAP_PATH, DRUPAL_BOOTSTRAP_FULL), $phase_index = 0; - while ($phase >= $phase_index && isset($phases[$phase_index])) { - $current_phase = $phases[$phase_index]; - unset($phases[$phase_index++]); - _drupal_bootstrap($current_phase); + if (isset($phase)) { + while ($phase >= $phase_index && isset($phases[$phase_index])) { + $current_phase = $phases[$phase_index]; + unset($phases[$phase_index++]); + _drupal_bootstrap($current_phase); + } } + return $phases; } function _drupal_bootstrap($phase) { @@ -1027,14 +1051,14 @@ function _drupal_bootstrap($phase) { $cache = $cache_mode == CACHE_DISABLED ? '' : page_get_cache(); // If the skipping of the bootstrap hooks is not enforced, call hook_boot. if ($cache_mode != CACHE_AGGRESSIVE) { - bootstrap_invoke_all('boot'); + module_invoke_all('boot'); } // If there is a cached page, display it. if ($cache) { drupal_page_cache_header($cache); // If the skipping of the bootstrap hooks is not enforced, call hook_exit. if ($cache_mode != CACHE_AGGRESSIVE) { - bootstrap_invoke_all('exit'); + module_invoke_all('exit'); } // We are done. exit; @@ -1069,6 +1093,9 @@ function _drupal_bootstrap($phase) { * @see _drupal_maintenance_theme() */ function drupal_maintenance_theme() { + // We essentially need to rebuild our theme information so we need this + // file, and the registry might not be around to load it for us. + require_once './modules/system/system.build.inc'; require_once './includes/theme.maintenance.inc'; _drupal_maintenance_theme(); } @@ -1215,36 +1242,46 @@ function ip_address($reset = false) { * * @param $function * The name of the function to check or load. + * @param $file + * The name of the file this function belongs to. Optional. + * @param $module + * The name of the module $file belongs to. Optional but if you specify + * $file this is required as well. + * @param $module_filename + * The filename of the module $file belongs to. Optional but if you specify + * $file this is required as well. * @return - * TRUE if the function is now available, FALSE otherwise. + * $function if the function is now available, FALSE otherwise. */ -function drupal_function_exists($function) { - static $checked = array(); +function drupal_function_exists($function, $file = '', $module = '', $module_filename = '') { + static $checked = array(), $modules = array(); - if (defined('MAINTENANCE_MODE')) { - return function_exists($function); - } - - if (isset($checked[$function])) { - return $checked[$function]; - } - $checked[$function] = FALSE; - - if (function_exists($function)) { - registry_mark_code('function', $function); - $checked[$function] = TRUE; - return TRUE; - } - - $file = db_result(db_query("SELECT filename FROM {registry} WHERE name = '%s' AND type = '%s'", $function, 'function')); - if ($file) { - require_once($file); - $checked[$function] = function_exists($function); - if ($checked[$function]) { - registry_mark_code('function', $function); + // Is this the first time we see this function? + if (!isset($checked[$function])) { + $checked[$function] = function_exists($function) ? $function : FALSE; + // It does not exist, let's try include files. + if (!$checked[$function]) { + // If we are not given a file but have the database loaded already, + // we try to look it up. + if (!$file && !defined('MAINTENANCE_MODE') && ($result = db_fetch_object(db_query("SELECT filename, module, module_filename FROM {registry} WHERE name = '%s' AND type = 'function'", $function)))) { + $file = $result->filename; + $module_filename = $result->module_filename; + $module = $result->module; + } + // Either a $file was passed to the function or one was found in the database. + if ($file) { + // Load it. + drupal_load('module', $module, $file); + // Does it exist now? + $checked[$function] = function_exists($function) ? $function : FALSE; + // Modules are files where we store common functionality so we need to + // make sure they are loaded along with the function itself. + if ($module && $file != $module_filename) { + drupal_load('module', $module, $module_filename); + } + } } } - return $checked[$function]; } @@ -1286,36 +1323,7 @@ function drupal_autoload_class($class) { function _registry_check_code($type, $name) { $file = db_result(db_query("SELECT filename FROM {registry} WHERE name = '%s' AND type = '%s'", $name, $type)); if ($file) { - require_once($file); - registry_mark_code($type, $name); - return TRUE; - } -} - -/** - * Collect the resources used for this request. - * - * @param $type - * The type of resource. - * @param $name - * The name of the resource. - * @param $return - * Boolean flag to indicate whether to return the resources. - */ -function registry_mark_code($type, $name, $return = FALSE) { - static $resources = array(); - - if ($type && $name) { - if (!isset($resources[$type])) { - $resources[$type] = array(); - } - if (!in_array($name, $resources[$type])) { - $resources[$type][] = $name; - } - } - - if ($return) { - return $resources; + return drupal_load($type, $name, $file); } } @@ -1331,56 +1339,21 @@ function drupal_rebuild_code_registry() } /** - * Save hook implementations cache. - * - * @param $hook - * Array with the hook name and list of modules that implement it. - * @param $write_to_persistent_cache - * Whether to write to the persistent cache. - */ -function registry_cache_hook_implementations($hook, $write_to_persistent_cache = FALSE) { - static $implementations; - - if ($hook) { - // Newer is always better, so overwrite anything that's come before. - $implementations[$hook['hook']] = $hook['modules']; - } - - if ($write_to_persistent_cache === TRUE) { - // Only write this to cache if the implementations data we are going to cache - // is different to what we loaded earlier in the request. - if ($implementations != registry_get_hook_implementations_cache()) { - cache_set('hooks', $implementations, 'cache_registry'); - } - } -} - -/** * Save the files required by the registry for this path. + * + * @param $cache_allowed + * Set to FALSE to stop caching the files loaded during this request. */ -function registry_cache_path_files() { - if ($used_code = registry_mark_code(NULL, NULL, TRUE)) { - $files = array(); - $type_sql = array(); - $params = array(); - foreach ($used_code as $type => $names) { - $type_sql[] = "(name IN (" . db_placeholders($names, 'varchar') . ") AND type = '%s')"; - $params = array_merge($params, $names); - $params[] = $type; - } - $res = db_query("SELECT DISTINCT filename FROM {registry} WHERE " . implode(' OR ', $type_sql), $params); - while ($row = db_fetch_object($res)) { - $files[] = $row->filename; - } - if ($files) { - sort($files); - // Only write this to cache if the file list we are going to cache - // is different to what we loaded earlier in the request. - if ($files != registry_load_path_files(TRUE)) { - $menu = menu_get_item(); - cache_set('registry:' . $menu['path'], implode(';', $files), 'cache_registry'); - } - } +function registry_cache_path_files($cache_allowed = NULL) { + static $cache_allowed_stored = TRUE; + if (isset($cache_allowed)) { + $cache_allowed_stored = $cache_allowed; + } + // Only write this to cache if the file list we are going to cache is + // different to what we loaded earlier in the request. + if ($cache_allowed_stored && ($files = drupal_load()) && $files != registry_load_path_files(TRUE)) { + $menu = menu_get_item(); + cache_set('registry:' . $menu['path'], implode(';', $files), 'cache_registry'); } } @@ -1404,22 +1377,6 @@ function registry_load_path_files($retur } /** - * registry_get_hook_implementations_cache - */ -function registry_get_hook_implementations_cache() { - static $implementations; - if ($implementations === NULL) { - if ($cache = cache_get('hooks', 'cache_registry')) { - $implementations = $cache->data; - } - else { - $implementations = array(); - } - } - return $implementations; -} - -/** * @} End of "ingroup registry". */ === modified file 'includes/common.inc' --- includes/common.inc 2008-07-19 10:38:13 +0000 +++ includes/common.inc 2008-07-26 08:29:07 +0000 @@ -1475,6 +1475,7 @@ function l($text, $path, $options = arra * react to the closing of the page by calling hook_exit(). */ function drupal_page_footer() { + drupal_lookup_path('footer'); if (variable_get('cache', CACHE_DISABLED) != CACHE_DISABLED) { page_set_cache(); @@ -1482,7 +1483,8 @@ function drupal_page_footer() { module_invoke_all('exit'); - registry_cache_hook_implementations(FALSE, TRUE); + // Write the implementation cache. + module_implements(); registry_cache_path_files(); } @@ -2465,8 +2467,8 @@ function _drupal_bootstrap_full() { unicode_check(); // Undo magic quotes fix_gpc_magic(); - // Load all enabled modules - module_load_all(); + // Load all essential modules. + module_load(); // Let all modules take action before menu system handles the request // We do not want this while running update.php. if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') { @@ -3052,9 +3054,6 @@ function drupal_get_schema($table = NULL // Otherwise, rebuild the schema cache. else { $schema = array(); - // Load the .install files to get hook_schema. - module_load_all_includes('install'); - // Invoke hook_schema for all modules. foreach (module_implements('schema') as $module) { $current = module_invoke($module, 'schema'); === modified file 'includes/file.inc' --- includes/file.inc 2008-07-05 18:34:29 +0000 +++ includes/file.inc 2008-07-26 08:29:08 +0000 @@ -585,6 +585,7 @@ function file_save_upload($source, $vali $errors = array(); foreach ($validators as $function => $args) { array_unshift($args, $file); + drupal_function_exists($function); $errors = array_merge($errors, call_user_func_array($function, $args)); } === modified file 'includes/install.inc' --- includes/install.inc 2008-05-26 17:12:54 +0000 +++ includes/install.inc 2008-07-27 21:39:40 +0000 @@ -408,6 +408,7 @@ function _drupal_install_module($module) */ function drupal_install_system() { $system_path = dirname(drupal_get_filename('module', 'system', NULL)); + require_once './' . $system_path . '/system.build.inc'; require_once './' . $system_path . '/system.install'; module_invoke('system', 'install'); $system_versions = drupal_get_schema_versions('system'); === modified file 'includes/menu.inc' --- includes/menu.inc 2008-07-10 10:58:01 +0000 +++ includes/menu.inc 2008-07-26 09:06:14 +0000 @@ -454,9 +454,11 @@ function _menu_load_objects(&$item, &$ma } } array_unshift($args, $value); - $return = call_user_func_array($function, $args); + if (drupal_function_exists($function)) { + $return = call_user_func_array($function, $args); + } } - else { + elseif (drupal_function_exists($function)) { $return = $function($value); } // If callback returned an error or there is no callback, trigger 404. @@ -498,7 +500,7 @@ function _menu_check_access(&$item, $map if ($callback == 'user_access') { $item['access'] = (count($arguments) == 1) ? user_access($arguments[0]) : user_access($arguments[0], $arguments[1]); } - else { + elseif (drupal_function_exists($callback)) { $item['access'] = call_user_func_array($callback, $arguments); } } @@ -545,7 +547,7 @@ function _menu_item_localize(&$item, $ma $item['title'] = t($item['title'], menu_unserialize($item['title_arguments'], $map)); } } - elseif ($callback) { + elseif ($callback && drupal_function_exists($callback)) { if (empty($item['title_arguments'])) { $item['title'] = $callback($item['title']); } @@ -1726,7 +1728,8 @@ function menu_router_build($reset = FALS // We need to manually call each module so that we can know which module // a given item came from. $callbacks = array(); - foreach (module_implements('menu', NULL, TRUE) as $module) { + registry_cache_path_files(FALSE); + foreach (module_implements('menu') as $module) { $router_items = call_user_func($module . '_menu'); if (isset($router_items) && is_array($router_items)) { foreach (array_keys($router_items) as $path) { === modified file 'includes/module.inc' --- includes/module.inc 2008-07-23 07:34:34 +0000 +++ includes/module.inc 2008-07-27 19:11:39 +0000 @@ -9,67 +9,21 @@ /** * Load all the modules that have been enabled in the system table. */ -function module_load_all() { - foreach (module_list(TRUE, FALSE) as $module) { - drupal_load('module', $module); +function module_load($modules = array('node', 'user', 'filter')) { + foreach ($modules as $module) { + drupal_load('module', $module, "./modules/$module/$module.module"); } } /** - * Collect a list of all loaded modules. During the bootstrap, return only - * vital modules. See bootstrap.inc + * Collect a list of all loaded modules. * - * @param $refresh - * Whether to force the module list to be regenerated (such as after the - * administrator has changed the system settings). - * @param $bootstrap - * Whether to return the reduced set of modules loaded in "bootstrap mode" - * for cached pages. See bootstrap.inc. - * @param $sort - * By default, modules are ordered by weight and filename, settings this option - * to TRUE, module list will be ordered by module name. - * @param $fixed_list - * (Optional) Override the module list with the given modules. Stays until the - * next call with $refresh = TRUE. * @return * An associative array whose keys and values are the names of all loaded * modules. */ -function module_list($refresh = FALSE, $bootstrap = TRUE, $sort = FALSE, $fixed_list = NULL) { - static $list, $sorted_list; - - if ($refresh || $fixed_list) { - unset($sorted_list); - $list = array(); - if ($fixed_list) { - foreach ($fixed_list as $name => $module) { - drupal_get_filename('module', $name, $module['filename']); - $list[$name] = $name; - } - } - else { - if ($bootstrap) { - $result = db_query("SELECT name, filename FROM {system} WHERE type = 'module' AND status = 1 AND bootstrap = 1 ORDER BY weight ASC, filename ASC"); - } - else { - $result = db_query("SELECT name, filename FROM {system} WHERE type = 'module' AND status = 1 ORDER BY weight ASC, filename ASC"); - } - while ($module = db_fetch_object($result)) { - if (file_exists($module->filename)) { - drupal_get_filename('module', $module->name, $module->filename); - $list[$module->name] = $module->name; - } - } - } - } - if ($sort) { - if (!isset($sorted_list)) { - $sorted_list = $list; - ksort($sorted_list); - } - return $sorted_list; - } - return $list; +function module_list() { + return variable_get('module_list', array()); } /** @@ -112,26 +66,21 @@ function module_rebuild_cache() { // modify the data in the .info files if necessary. drupal_alter('system_info', $files[$filename]->info, $files[$filename]); - // Log the critical hooks implemented by this module. - $bootstrap = 0; - foreach (bootstrap_hooks() as $hook) { - if (module_hook($file->name, $hook)) { - $bootstrap = 1; - break; - } - } - // Update the contents of the system table: if (isset($file->status) || (isset($file->old_filename) && $file->old_filename != $file->filename)) { - db_query("UPDATE {system} SET info = '%s', name = '%s', filename = '%s', bootstrap = %d WHERE filename = '%s'", serialize($files[$filename]->info), $file->name, $file->filename, $bootstrap, $file->old_filename); + db_query("UPDATE {system} SET info = '%s', name = '%s', filename = '%s' WHERE filename = '%s'", serialize($files[$filename]->info), $file->name, $file->filename, $file->old_filename); + if ($file->status) { + $module_list[$file->name] = $file->name; + } } else { // This is a new module. $files[$filename]->status = 0; - db_query("INSERT INTO {system} (name, info, type, filename, status, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d)", $file->name, serialize($files[$filename]->info), 'module', $file->filename, 0, $bootstrap); + db_query("INSERT INTO {system} (name, info, type, filename, status) VALUES ('%s', '%s', '%s', '%s', %d)", $file->name, serialize($files[$filename]->info), 'module', $file->filename, 0); } } $files = _module_build_dependencies($files); + variable_set('module_list', $module_list); return $files; } @@ -154,13 +103,15 @@ function module_rebuild_cache() { * The same array with dependencies and dependents added where applicable. */ function _module_build_dependencies($files) { + $module_depencies = array(); do { $new_dependency = FALSE; - foreach ($files as $filename => $file) { - // We will modify this object (module A, see doxygen for module A, B, C). - $file = &$files[$filename]; + foreach ($files as $filename => &$file) { if (isset($file->info['dependencies']) && is_array($file->info['dependencies'])) { foreach ($file->info['dependencies'] as $dependency_name) { + if ($file->status) { + $module_depencies[$file->name][$dependency_name] = $files[$dependency_name]->filename; + } // This is a nonexistent module. if ($dependency_name == '-circular-' || !isset($files[$dependency_name])) { continue; @@ -195,15 +146,14 @@ function _module_build_dependencies($fil } } } - // Don't forget to break the reference. - unset($file); } } while ($new_dependency); + variable_set('module_dependencies', $module_depencies); return $files; } /** - * Determine whether a given module exists. + * Determine whether a given module exists and load it if it does. * * @param $module * The name of the module (without the .module extension). @@ -212,7 +162,10 @@ function _module_build_dependencies($fil */ function module_exists($module) { $list = module_list(); - return isset($list[$module]); + if (isset($list[$module])) { + drupal_load('module', $module); + return TRUE; + } } /** @@ -252,17 +205,6 @@ function module_load_include($type, $mod } /** - * Load an include file for each of the modules that have been enabled in - * the system table. - */ -function module_load_all_includes($type, $name = NULL) { - $modules = module_list(); - foreach ($modules as $module) { - module_load_include($type, $module, $name); - } -} - -/** * Enable a given list of modules. * * @param $module_list @@ -273,7 +215,6 @@ function module_enable($module_list) { foreach ($module_list as $module) { $existing = db_fetch_object(db_query("SELECT status FROM {system} WHERE type = '%s' AND name = '%s'", 'module', $module)); if ($existing->status == 0) { - module_load_install($module); db_query("UPDATE {system} SET status = %d WHERE type = '%s' AND name = '%s'", 1, 'module', $module); drupal_load('module', $module); $invoke_modules[] = $module; @@ -281,8 +222,6 @@ function module_enable($module_list) { } if (!empty($invoke_modules)) { - // Refresh the module list to include the new enabled module. - module_list(TRUE, FALSE); // Force to regenerate the stored list of hook implementations. drupal_rebuild_code_registry(); } @@ -314,7 +253,6 @@ function module_disable($module_list) { node_access_needs_rebuild(TRUE); } - module_load_install($module); module_invoke($module, 'disable'); db_query("UPDATE {system} SET status = %d WHERE type = '%s' AND name = '%s'", 0, 'module', $module); $invoke_modules[] = $module; @@ -322,8 +260,6 @@ function module_disable($module_list) { } if (!empty($invoke_modules)) { - // Refresh the module list to exclude the disabled modules. - module_list(TRUE, FALSE); // Force to regenerate the stored list of hook implementations. drupal_rebuild_code_registry(); } @@ -368,13 +304,7 @@ function module_disable($module_list) { * implemented in that module. */ function module_hook($module, $hook) { - $function = $module . '_' . $hook; - if (defined('MAINTENANCE_MODE')) { - return function_exists($function); - } - else { - return drupal_function_exists($function); - } + return drupal_function_exists($module . '_' . $hook); } /** @@ -382,9 +312,6 @@ function module_hook($module, $hook) { * * @param $hook * The name of the hook (e.g. "help" or "menu"). - * @param $sort - * By default, modules are ordered by weight and filename, settings this option - * to TRUE, module list will be ordered by module name. * @param $refresh * For internal use only: Whether to force the stored list of hook * implementations to be regenerated (such as after enabling a new module, @@ -392,25 +319,64 @@ function module_hook($module, $hook) { * @return * An array with the names of the modules which are implementing this hook. */ -function module_implements($hook, $sort = FALSE, $refresh = FALSE) { - static $implementations = array(); +function module_implements($hook = '', $refresh = FALSE) { + static $implementations = array(), $loaded = array(), $cache; - if ($refresh) { + // If we are in maintenance mode but managed to bootstrap fully then we can + // use the registry. + if (defined('MAINTENANCE_MODE') && drupal_bootstrap()) { $implementations = array(); - } - else if (!defined('MAINTENANCE_MODE') && empty($implementations)) { - $implementations = registry_get_hook_implementations_cache(); - } - - if (!isset($implementations[$hook])) { - $implementations[$hook] = array(); foreach (module_list() as $module) { if (module_hook($module, $hook)) { - $implementations[$hook][] = $module; + $implementations[] = $module; + } + } + return $implementations; + } + if ($refresh) { + $implementations = array(); + $loaded = array(); + cache_clear_all('hooks', 'cache_registry'); + return; + } + if (!$hook) { + // Only write this to cache if the implementations data we are going to cache + // is different to what we loaded earlier in the request. + if ($cache && $implementations != $cache->data) { + cache_set('hooks', $implementations, 'cache_registry'); + } + return; + } + + if (empty($implementations) && ($cache = cache_get('hooks', 'cache_registry'))) { + $implementations = $cache->data; + } + + if (empty($loaded[$hook])) { + if (isset($implementations[$hook])) { + $cached = TRUE; + // $candidate_list holds the possible implementations. + foreach ($implementations[$hook] as $module) { + $function = $module .'_'. $hook; + // If the implementations are already cached but there are functions + // to be looked up, then we discard the cache. The per router path + // caching will make this rare. + if (!function_exists($function)) { + unset($implementations[$hook]); + break; + } + } + } + if (!isset($implementations[$hook])) { + $implementations[$hook] = array(); + $result = db_query("SELECT name, filename, module, module_filename FROM {registry} WHERE type = 'function' AND hook = '%s'", $hook); + while ($function = db_fetch_object($result)) { + $implementations[$hook][] = $function->module; + drupal_function_exists($function->name, $function->filename, $function->module, $function->module_filename); } } + $loaded[$hook] = TRUE; } - registry_cache_hook_implementations(array('hook' => $hook, 'modules' => $implementations[$hook])); // The explicit cast forces a copy to be made. This is needed because // $implementations[$hook] is only a reference to an element of === modified file 'includes/registry.inc' --- includes/registry.inc 2008-05-06 12:32:02 +0000 +++ includes/registry.inc 2008-07-27 19:45:18 +0000 @@ -23,6 +23,10 @@ * @See drupal_rebuild_code_registry. */ function _drupal_rebuild_code_registry() { + include_once './includes/module.inc'; + include_once './includes/common.inc'; + include_once './includes/file.inc'; + drupal_load('module', 'system', 'modules/system/system.module'); // Reset the resources cache. _registry_get_resource_name(); // Get the list of files we are going to parse. @@ -31,7 +35,7 @@ function _drupal_rebuild_code_registry() if ($module->status) { $dir = dirname($module->filename); foreach ($module->info['files'] as $file) { - $files["./$dir/$file"] = array(); + $files["./$dir/$file"] = array('module' => $module); } } } @@ -53,6 +57,7 @@ function _drupal_rebuild_code_registry() } _registry_parse_files($files); + module_implements('', TRUE); cache_clear_all('*', 'cache_registry'); } @@ -72,7 +77,7 @@ function registry_get_parsed_files() { * Parse all files that have changed since the registry was last built, and save their function and class listings. * * @param $files - * The list of files to check and parse. + * The list of files to check and parse. */ function _registry_parse_files($files) { $changed_files = array(); @@ -83,7 +88,7 @@ function _registry_parse_files($files) { if ($new_file || $md5 != $file['md5']) { // We update the md5 after we've saved the files resources rather than here, so if we // don't make it through this rebuild, the next run will reparse the file. - _registry_parse_file($filename, $contents); + _registry_parse_file($filename, $contents, $file); $file['md5'] = $md5; if ($new_file) { db_query("INSERT INTO {registry_file} (md5, filename) VALUES ('%s', '%s')", $md5, $filename); @@ -99,11 +104,14 @@ function _registry_parse_files($files) { * Parse a file and save its function and class listings. * * @param $filename - * Name of the file we are going to parse. + * Name of the file we are going to parse. * @param $contents - * Contents of the file we are going to parse as a string. + * Contents of the file we are going to parse as a string. + * @param $file + * An array of information about the file. If key 'module' is present, it's + * a stdClass as returned by module_rebuild_cache. */ -function _registry_parse_file($filename, $contents) { +function _registry_parse_file($filename, $contents, $file = array()) { static $map = array(T_FUNCTION => 'function', T_CLASS => 'class', T_INTERFACE => 'interface'); // Delete registry entries for this file, so we can insert the new resources. db_query("DELETE FROM {registry} WHERE filename = '%s'", $filename); @@ -113,7 +121,18 @@ function _registry_parse_file($filename, if (is_array($token) && isset($map[$token[0]])) { $type = $map[$token[0]]; if ($resource_name = _registry_get_resource_name($tokens, $type)) { - db_query("INSERT INTO {registry} (name, type, filename) VALUES ('%s', '%s', '%s')", $resource_name, $type, $filename); + $hook = ''; + $module = ''; + $module_filename = ''; + if ($type == 'function' && isset($file['module'])) { + $module = $file['module']->name; + $module_filename = './'. $file['module']->filename; + $n = strlen($module); + if (substr($resource_name, 0, $n) == $module) { + $hook = substr($resource_name, $n + 1); + } + } + db_query("INSERT INTO {registry} (name, type, filename, module_filename, module, hook) VALUES ('%s', '%s', '%s', '%s', '%s', '%s')", $resource_name, $type, $filename, $module_filename, $module, $hook); // We skip the body because classes may contain functions. _registry_skip_body($tokens); } @@ -127,11 +146,11 @@ function _registry_parse_file($filename, * When called without arguments, it resets its static cache. * * @param $tokens - * The collection of tokens for the current file being parsed. + * The collection of tokens for the current file being parsed. * @param $type - * The human-readable token name, either: "function", "class", or "interface". + * The human-readable token name, either: "function", "class", or "interface". * @return - * The name of the resource, or FALSE if the resource has already been processed. + * The name of the resource, or FALSE if the resource has already been processed. */ function _registry_get_resource_name(&$tokens = NULL, $type = NULL) { // Keep a running list of all resources we've saved so far, so that we never @@ -166,6 +185,7 @@ function _registry_get_resource_name(&$t * of { from the current position. * * @param $tokens + * Array of tokens as returned by token_get_all. */ function _registry_skip_body(&$tokens) { $num_braces = 1; @@ -176,6 +196,7 @@ function _registry_skip_body(&$tokens) { // Scan through the rest of the tokens until we reach the matching // end brace. + $count = 0; while ($num_braces && ($token = next($tokens))) { if ($token == '{') { ++$num_braces; === modified file 'includes/theme.inc' --- includes/theme.inc 2008-07-11 02:23:08 +0000 +++ includes/theme.inc 2008-07-27 19:11:28 +0000 @@ -277,7 +277,7 @@ function drupal_rebuild_theme_registry() */ function _theme_process_registry(&$cache, $name, $type, $theme, $path) { $function = $name . '_theme'; - if (function_exists($function)) { + if (drupal_function_exists($function)) { $result = $function($cache, $type, $theme, $path); foreach ($result as $hook => $info) { @@ -382,6 +382,7 @@ function _theme_build_registry($theme, $ $cache = array(); // First, process the theme hooks advertised by modules. This will // serve as the basic registry. + registry_cache_path_files(FALSE); foreach (module_implements('theme') as $module) { _theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module)); } @@ -1596,7 +1597,7 @@ function theme_closure($main = 0) { function theme_blocks($region) { $output = ''; - if ($list = block_list($region)) { + if ($list = module_invoke('block', 'list', $region)) { foreach ($list as $key => $block) { // $key == module_delta $output .= theme('block', $block); === modified file 'install.php' --- install.php 2008-07-18 07:24:29 +0000 +++ install.php 2008-07-27 19:33:03 +0000 @@ -45,11 +45,9 @@ function install_main() { // Load module basics (needed for hook invokes). include_once './includes/module.inc'; - $module_list['system']['filename'] = 'modules/system/system.module'; - $module_list['filter']['filename'] = 'modules/filter/filter.module'; - module_list(TRUE, FALSE, FALSE, $module_list); - drupal_load('module', 'system'); - drupal_load('module', 'filter'); + $modules = array('system', 'filter'); + variable_set('module_list', $modules, FALSE); + module_load($modules); // Set up theme system for the maintenance page. drupal_maintenance_theme(); @@ -145,6 +143,8 @@ function install_main() { variable_set('install_profile_modules', array_diff($modules, array('system'))); } + // Delete our temporary module list. + variable_del('module_list', FALSE); // The database is set up, turn to further tasks. install_tasks($profile, $task); } === modified file 'modules/aggregator/aggregator.info' --- modules/aggregator/aggregator.info 2008-05-15 21:27:32 +0000 +++ modules/aggregator/aggregator.info 2008-07-26 08:29:08 +0000 @@ -8,3 +8,4 @@ core = 7.x files[] = aggregator.module files[] = aggregator.admin.inc files[] = aggregator.pages.inc +files[] = aggregator.install === modified file 'modules/block/block.info' --- modules/block/block.info 2008-05-15 21:30:02 +0000 +++ modules/block/block.info 2008-07-26 08:29:08 +0000 @@ -7,3 +7,4 @@ version = VERSION core = 7.x files[] = block.module files[] = block.admin.inc +files[] = block.install === modified file 'modules/blogapi/blogapi.info' --- modules/blogapi/blogapi.info 2008-05-13 18:13:43 +0000 +++ modules/blogapi/blogapi.info 2008-07-26 08:29:08 +0000 @@ -6,3 +6,4 @@ package = Core - optional version = VERSION core = 7.x files[] = blogapi.module +files[] = blogapi.install === modified file 'modules/book/book.info' --- modules/book/book.info 2008-05-15 21:19:24 +0000 +++ modules/book/book.info 2008-07-26 08:29:08 +0000 @@ -8,3 +8,4 @@ core = 7.x files[] = book.module files[] = book.admin.inc files[] = book.pages.inc +files[] = book.install === modified file 'modules/color/color.info' --- modules/color/color.info 2008-05-19 19:36:41 +0000 +++ modules/color/color.info 2008-07-26 08:29:08 +0000 @@ -6,3 +6,4 @@ package = Core - optional version = VERSION core = 7.x files[] = color.module +files[] = color.install === modified file 'modules/contact/contact.info' --- modules/contact/contact.info 2008-05-06 12:18:44 +0000 +++ modules/contact/contact.info 2008-07-26 08:29:08 +0000 @@ -7,3 +7,4 @@ core = 7.x files[] = contact.module files[] = contact.admin.inc files[] = contact.pages.inc +files[] = contact.install === modified file 'modules/dblog/dblog.info' --- modules/dblog/dblog.info 2008-05-06 12:18:44 +0000 +++ modules/dblog/dblog.info 2008-07-26 08:29:08 +0000 @@ -6,3 +6,4 @@ version = VERSION core = 7.x files[] = dblog.module files[] = dblog.admin.inc +files[] = dblog.install === modified file 'modules/filter/filter.info' --- modules/filter/filter.info 2008-05-06 12:18:44 +0000 +++ modules/filter/filter.info 2008-07-26 08:29:08 +0000 @@ -7,3 +7,4 @@ core = 7.x files[] = filter.module files[] = filter.admin.inc files[] = filter.pages.inc +files[] = filter.install === modified file 'modules/forum/forum.info' --- modules/forum/forum.info 2008-05-06 12:18:44 +0000 +++ modules/forum/forum.info 2008-07-26 08:29:08 +0000 @@ -9,3 +9,4 @@ core = 7.x files[] = forum.module files[] = forum.admin.inc files[] = forum.pages.inc +files[] = forum.install === modified file 'modules/help/help.module' --- modules/help/help.module 2008-05-06 12:18:44 +0000 +++ modules/help/help.module 2008-07-26 08:29:08 +0000 @@ -17,7 +17,7 @@ function help_menu() { 'weight' => 9, ); - foreach (module_implements('help', TRUE) as $module) { + foreach (module_implements('help') as $module) { $items['admin/help/' . $module] = array( 'title' => $module, 'page callback' => 'help_page', === modified file 'modules/locale/locale.info' --- modules/locale/locale.info 2008-05-06 12:18:44 +0000 +++ modules/locale/locale.info 2008-07-26 08:29:08 +0000 @@ -5,3 +5,4 @@ package = Core - optional version = VERSION core = 7.x files[] = locale.module +files[] = locale.install === modified file 'modules/menu/menu.info' --- modules/menu/menu.info 2008-05-06 12:18:44 +0000 +++ modules/menu/menu.info 2008-07-26 08:29:08 +0000 @@ -6,3 +6,4 @@ version = VERSION core = 7.x files[] = menu.module files[] = menu.admin.inc +files[] = menu.install === modified file 'modules/node/node.admin.inc' --- modules/node/node.admin.inc 2008-07-19 19:04:24 +0000 +++ modules/node/node.admin.inc 2008-07-26 08:29:08 +0000 @@ -528,7 +528,7 @@ function node_admin_nodes_submit($form, $operation = $operations[$form_state['values']['operation']]; // Filter out unchecked nodes $nodes = array_filter($form_state['values']['nodes']); - if ($function = $operation['callback']) { + if (($function = $operation['callback']) && drupal_function_exists($function)) { // Add in callback arguments if present. if (isset($operation['callback arguments'])) { $args = array_merge(array($nodes), $operation['callback arguments']); === modified file 'modules/node/node.info' --- modules/node/node.info 2008-05-06 12:18:44 +0000 +++ modules/node/node.info 2008-07-26 08:29:08 +0000 @@ -8,3 +8,4 @@ files[] = node.module files[] = content_types.inc files[] = node.admin.inc files[] = node.pages.inc +files[] = node.install === modified file 'modules/node/node.pages.inc' --- modules/node/node.pages.inc 2008-07-10 11:12:02 +0000 +++ modules/node/node.pages.inc 2008-07-28 04:36:43 +0000 @@ -17,7 +17,7 @@ function node_page_edit($node) { function node_add_page() { $item = menu_get_item(); - $content = system_admin_menu_block($item); + $content = module_invoke('system', 'admin_menu_block', $item); return theme('node_add_list', $content); } === modified file 'modules/openid/openid.info' --- modules/openid/openid.info 2008-05-06 12:18:44 +0000 +++ modules/openid/openid.info 2008-07-26 08:29:08 +0000 @@ -8,3 +8,4 @@ files[] = openid.module files[] = openid.inc files[] = openid.pages.inc files[] = xrds.inc +files[] = openid.install === modified file 'modules/php/php.info' --- modules/php/php.info 2008-05-06 12:18:44 +0000 +++ modules/php/php.info 2008-07-26 08:29:08 +0000 @@ -5,3 +5,4 @@ package = Core - optional version = VERSION core = 7.x files[] = php.module +files[] = php.install === modified file 'modules/poll/poll.info' --- modules/poll/poll.info 2008-05-06 12:18:44 +0000 +++ modules/poll/poll.info 2008-07-26 08:29:08 +0000 @@ -6,3 +6,4 @@ version = VERSION core = 7.x files[] = poll.module files[] = poll.pages.inc +files[] = poll.install === modified file 'modules/profile/profile.info' --- modules/profile/profile.info 2008-05-06 12:18:44 +0000 +++ modules/profile/profile.info 2008-07-26 08:29:08 +0000 @@ -7,3 +7,4 @@ core = 7.x files[] = profile.module files[] = profile.admin.inc files[] = profile.pages.inc +files[] = profile.install === modified file 'modules/search/search.info' --- modules/search/search.info 2008-05-06 12:18:44 +0000 +++ modules/search/search.info 2008-07-26 08:29:08 +0000 @@ -7,3 +7,4 @@ core = 7.x files[] = search.module files[] = search.admin.inc files[] = search.pages.inc +files[] = search.install === modified file 'modules/simpletest/simpletest.info' --- modules/simpletest/simpletest.info 2008-05-06 12:18:44 +0000 +++ modules/simpletest/simpletest.info 2008-07-26 08:29:08 +0000 @@ -5,3 +5,4 @@ package = Core - optional version = VERSION core = 7.x files[] = simpletest.module +files[] = simpletest.install === modified file 'modules/statistics/statistics.info' --- modules/statistics/statistics.info 2008-05-06 12:18:44 +0000 +++ modules/statistics/statistics.info 2008-07-26 08:29:08 +0000 @@ -7,3 +7,4 @@ core = 7.x files[] = statistics.module files[] = statistics.admin.inc files[] = statistics.pages.inc +files[] = statistics.install === added file 'modules/system/system.actions.inc' --- modules/system/system.actions.inc 1970-01-01 00:00:00 +0000 +++ modules/system/system.actions.inc 2008-07-27 19:21:56 +0000 @@ -0,0 +1,537 @@ + array( + 'type' => 'system', + 'description' => t('Display a message to the user'), + 'configurable' => TRUE, + 'hooks' => array( + 'nodeapi' => array('view', 'insert', 'update', 'delete'), + 'comment' => array('view', 'insert', 'update', 'delete'), + 'user' => array('view', 'insert', 'update', 'delete', 'login'), + 'taxonomy' => array('insert', 'update', 'delete'), + ), + ), + 'system_send_email_action' => array( + 'description' => t('Send e-mail'), + 'type' => 'system', + 'configurable' => TRUE, + 'hooks' => array( + 'nodeapi' => array('view', 'insert', 'update', 'delete'), + 'comment' => array('view', 'insert', 'update', 'delete'), + 'user' => array('view', 'insert', 'update', 'delete', 'login'), + 'taxonomy' => array('insert', 'update', 'delete'), + ) + ), + 'system_block_ip_action' => array( + 'description' => t('Ban IP address of current user'), + 'type' => 'user', + 'configurable' => FALSE, + 'hooks' => array(), + ), + 'system_goto_action' => array( + 'description' => t('Redirect to URL'), + 'type' => 'system', + 'configurable' => TRUE, + 'hooks' => array( + 'nodeapi' => array('view', 'insert', 'update', 'delete'), + 'comment' => array('view', 'insert', 'update', 'delete'), + 'user' => array('view', 'insert', 'update', 'delete', 'login'), + ) + ) + ); +} + +/** + * Menu callback. Display an overview of available and configured actions. + */ +function system_actions_manage() { + $output = ''; + $actions = actions_list(); + actions_synchronize($actions); + $actions_map = actions_actions_map($actions); + $options = array(t('Choose an advanced action')); + $unconfigurable = array(); + + foreach ($actions_map as $key => $array) { + if ($array['configurable']) { + $options[$key] = $array['description'] . '...'; + } + else { + $unconfigurable[] = $array; + } + } + + $row = array(); + $instances_present = db_fetch_object(db_query("SELECT aid FROM {actions} WHERE parameters != ''")); + $header = array( + array('data' => t('Action type'), 'field' => 'type'), + array('data' => t('Description'), 'field' => 'description'), + array('data' => $instances_present ? t('Operations') : '', 'colspan' => '2') + ); + $sql = 'SELECT * FROM {actions}'; + $result = pager_query($sql . tablesort_sql($header), 50); + while ($action = db_fetch_object($result)) { + $row[] = array( + array('data' => $action->type), + array('data' => $action->description), + array('data' => $action->parameters ? l(t('configure'), "admin/settings/actions/configure/$action->aid") : ''), + array('data' => $action->parameters ? l(t('delete'), "admin/settings/actions/delete/$action->aid") : '') + ); + } + + if ($row) { + $pager = theme('pager', NULL, 50, 0); + if (!empty($pager)) { + $row[] = array(array('data' => $pager, 'colspan' => '3')); + } + $output .= '

' . t('Actions available to Drupal:') . '

'; + $output .= theme('table', $header, $row); + } + + if ($actions_map) { + $output .= drupal_get_form('system_actions_manage_form', $options); + } + + return $output; +} + +/** + * Define the form for the actions overview page. + * + * @see system_actions_manage_form_submit() + * @ingroup forms + * @param $form_state + * An associative array containing the current state of the form; not used. + * @param $options + * An array of configurable actions. + * @return + * Form definition. + */ +function system_actions_manage_form($form_state, $options = array()) { + $form['parent'] = array( + '#type' => 'fieldset', + '#title' => t('Make a new advanced action available'), + '#prefix' => '
', + '#suffix' => '
', + ); + $form['parent']['action'] = array( + '#type' => 'select', + '#default_value' => '', + '#options' => $options, + '#description' => '', + ); + $form['parent']['buttons']['submit'] = array( + '#type' => 'submit', + '#value' => t('Create'), + ); + return $form; +} + +/** + * Process system_actions_manage form submissions. + */ +function system_actions_manage_form_submit($form, &$form_state) { + if ($form_state['values']['action']) { + $form_state['redirect'] = 'admin/settings/actions/configure/' . $form_state['values']['action']; + } +} + +/** + * Menu callback. Create the form for configuration of a single action. + * + * We provide the "Description" field. The rest of the form + * is provided by the action. We then provide the Save button. + * Because we are combining unknown form elements with the action + * configuration form, we use actions_ prefix on our elements. + * + * @see system_actions_configure_validate() + * @see system_actions_configure_submit() + * @param $action + * md5 hash of action ID or an integer. If it's an md5 hash, we + * are creating a new instance. If it's an integer, we're editing + * an existing instance. + * @return + * Form definition. + */ +function system_actions_configure($form_state, $action = NULL) { + if ($action === NULL) { + drupal_goto('admin/settings/actions'); + } + + $actions_map = actions_actions_map(actions_list()); + $edit = array(); + + // Numeric action denotes saved instance of a configurable action; + // else we are creating a new action instance. + if (is_numeric($action)) { + $aid = $action; + // Load stored parameter values from database. + $data = db_fetch_object(db_query("SELECT * FROM {actions} WHERE aid = %d", intval($aid))); + $edit['actions_description'] = $data->description; + $edit['actions_type'] = $data->type; + $function = $data->callback; + $action = md5($data->callback); + $params = unserialize($data->parameters); + if ($params) { + foreach ($params as $name => $val) { + $edit[$name] = $val; + } + } + } + else { + $function = $actions_map[$action]['callback']; + $edit['actions_description'] = $actions_map[$action]['description']; + $edit['actions_type'] = $actions_map[$action]['type']; + } + + $form['actions_description'] = array( + '#type' => 'textfield', + '#title' => t('Description'), + '#default_value' => $edit['actions_description'], + '#maxlength' => '255', + '#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.'), + '#weight' => -10 + ); + $action_form = $function . '_form'; + $form = array_merge($form, $action_form($edit)); + $form['actions_type'] = array( + '#type' => 'value', + '#value' => $edit['actions_type'], + ); + $form['actions_action'] = array( + '#type' => 'hidden', + '#value' => $action, + ); + // $aid is set when configuring an existing action instance. + if (isset($aid)) { + $form['actions_aid'] = array( + '#type' => 'hidden', + '#value' => $aid, + ); + } + $form['actions_configured'] = array( + '#type' => 'hidden', + '#value' => '1', + ); + $form['buttons']['submit'] = array( + '#type' => 'submit', + '#value' => t('Save'), + '#weight' => 13 + ); + + return $form; +} + +/** + * Validate system_actions_configure form submissions. + */ +function system_actions_configure_validate($form, $form_state) { + $function = actions_function_lookup($form_state['values']['actions_action']) . '_validate'; + // Hand off validation to the action. + if (drupal_function_exists($function)) { + $function($form, $form_state); + } +} + +/** + * Process system_actions_configure form submissions. + */ +function system_actions_configure_submit($form, &$form_state) { + $function = actions_function_lookup($form_state['values']['actions_action']); + $submit_function = $function . '_submit'; + + // Action will return keyed array of values to store. + $params = $submit_function($form, $form_state); + $aid = isset($form_state['values']['actions_aid']) ? $form_state['values']['actions_aid'] : NULL; + + actions_save($function, $form_state['values']['actions_type'], $params, $form_state['values']['actions_description'], $aid); + drupal_set_message(t('The action has been successfully saved.')); + + $form_state['redirect'] = 'admin/settings/actions/manage'; +} + +/** + * Create the form for confirmation of deleting an action. + * + * @ingroup forms + * @see system_actions_delete_form_submit() + */ +function system_actions_delete_form($form_state, $action) { + + $form['aid'] = array( + '#type' => 'hidden', + '#value' => $action->aid, + ); + return confirm_form($form, + t('Are you sure you want to delete the action %action?', array('%action' => $action->description)), + 'admin/settings/actions/manage', + t('This cannot be undone.'), + t('Delete'), t('Cancel') + ); +} + +/** + * Process system_actions_delete form submissions. + * + * Post-deletion operations for action deletion. + */ +function system_actions_delete_form_submit($form, &$form_state) { + $aid = $form_state['values']['aid']; + $action = actions_load($aid); + actions_delete($aid); + $description = check_plain($action->description); + watchdog('user', 'Deleted action %aid (%action)', array('%aid' => $aid, '%action' => $description)); + drupal_set_message(t('Action %action was deleted', array('%action' => $description))); + $form_state['redirect'] = 'admin/settings/actions/manage'; +} + +/** + * Post-deletion operations for deleting action orphans. + * + * @param $orphaned + * An array of orphaned actions. + */ +function system_action_delete_orphans_post($orphaned) { + foreach ($orphaned as $callback) { + drupal_set_message(t("Deleted orphaned action (%action).", array('%action' => $callback))); + } +} + +/** + * Remove actions that are in the database but not supported by any enabled module. + */ +function system_actions_remove_orphans() { + actions_synchronize(actions_list(), TRUE); + drupal_goto('admin/settings/actions/manage'); +} + +/** + * Return a form definition so the Send email action can be configured. + * + * @see system_send_email_action_validate() + * @see system_send_email_action_submit() + * @param $context + * Default values (if we are editing an existing action instance). + * @return + * Form definition. + */ +function system_send_email_action_form($context) { + // Set default values for form. + if (!isset($context['recipient'])) { + $context['recipient'] = ''; + } + if (!isset($context['subject'])) { + $context['subject'] = ''; + } + if (!isset($context['message'])) { + $context['message'] = ''; + } + + $form['recipient'] = array( + '#type' => 'textfield', + '#title' => t('Recipient'), + '#default_value' => $context['recipient'], + '#maxlength' => '254', + '#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')), + ); + $form['subject'] = array( + '#type' => 'textfield', + '#title' => t('Subject'), + '#default_value' => $context['subject'], + '#maxlength' => '254', + '#description' => t('The subject of the message.'), + ); + $form['message'] = array( + '#type' => 'textarea', + '#title' => t('Message'), + '#default_value' => $context['message'], + '#cols' => '80', + '#rows' => '20', + '#description' => t('The message that should be sent. You may include the following variables: %site_name, %username, %node_url, %node_type, %title, %teaser, %body. Not all variables will be available in all contexts.'), + ); + return $form; +} + +/** + * Validate system_send_email_action form submissions. + */ +function system_send_email_action_validate($form, $form_state) { + $form_values = $form_state['values']; + // Validate the configuration form. + if (!valid_email_address($form_values['recipient']) && $form_values['recipient'] != '%author') { + // We want the literal %author placeholder to be emphasized in the error message. + form_set_error('recipient', t('Please enter a valid email address or %author.', array('%author' => '%author'))); + } +} + +/** + * Process system_send_email_action form submissions. + */ +function system_send_email_action_submit($form, $form_state) { + $form_values = $form_state['values']; + // Process the HTML form to store configuration. The keyed array that + // we return will be serialized to the database. + $params = array( + 'recipient' => $form_values['recipient'], + 'subject' => $form_values['subject'], + 'message' => $form_values['message'], + ); + return $params; +} + +/** + * Implementation of a configurable Drupal action. Sends an email. + */ +function system_send_email_action($object, $context) { + global $user; + + switch ($context['hook']) { + case 'nodeapi': + // Because this is not an action of type 'node' the node + // will not be passed as $object, but it will still be available + // in $context. + $node = $context['node']; + break; + // The comment hook provides nid, in $context. + case 'comment': + $comment = $context['comment']; + $node = node_load($comment->nid); + break; + case 'user': + // Because this is not an action of type 'user' the user + // object is not passed as $object, but it will still be available + // in $context. + $account = $context['account']; + if (isset($context['node'])) { + $node = $context['node']; + } + elseif ($context['recipient'] == '%author') { + // If we don't have a node, we don't have a node author. + watchdog('error', 'Cannot use %author token in this context.'); + return; + } + break; + default: + // We are being called directly. + $node = $object; + } + + $recipient = $context['recipient']; + + if (isset($node)) { + if (!isset($account)) { + $account = user_load(array('uid' => $node->uid)); + } + if ($recipient == '%author') { + $recipient = $account->mail; + } + } + + if (!isset($account)) { + $account = $user; + + } + $language = user_preferred_language($account); + $params = array('account' => $account, 'object' => $object, 'context' => $context); + if (isset($node)) { + $params['node'] = $node; + } + + if (drupal_mail('system', 'action_send_email', $recipient, $language, $params)) { + watchdog('action', 'Sent email to %recipient', array('%recipient' => $recipient)); + } + else { + watchdog('error', 'Unable to send email to %recipient', array('%recipient' => $recipient)); + } +} + +function system_message_action_submit($form, $form_state) { + return array('message' => $form_state['values']['message']); +} + +/** + * A configurable Drupal action. Sends a message to the current user's screen. + */ +function system_message_action(&$object, $context = array()) { + global $user; + $variables = array( + '%site_name' => variable_get('site_name', 'Drupal'), + '%username' => $user->name ? $user->name : variable_get('anonymous', t('Anonymous')), + ); + + // This action can be called in any context, but if placeholders + // are used a node object must be present to be the source + // of substituted text. + switch ($context['hook']) { + case 'nodeapi': + // Because this is not an action of type 'node' the node + // will not be passed as $object, but it will still be available + // in $context. + $node = $context['node']; + break; + // The comment hook also provides the node, in context. + case 'comment': + $comment = $context['comment']; + $node = node_load($comment->nid); + break; + case 'taxonomy': + $vocabulary = taxonomy_vocabulary_load($object->vid); + $variables = array_merge($variables, array( + '%term_name' => $object->name, + '%term_description' => $object->description, + '%term_id' => $object->tid, + '%vocabulary_name' => $vocabulary->name, + '%vocabulary_description' => $vocabulary->description, + '%vocabulary_id' => $vocabulary->vid, + ) + ); + break; + default: + // We are being called directly. + $node = $object; + } + + if (isset($node) && is_object($node)) { + $variables = array_merge($variables, array( + '%uid' => $node->uid, + '%node_url' => url('node/' . $node->nid, array('absolute' => TRUE)), + '%node_type' => check_plain(node_get_types('name', $node)), + '%title' => filter_xss($node->title), + '%teaser' => filter_xss($node->teaser), + '%body' => filter_xss($node->body), + ) + ); + } + $context['message'] = strtr($context['message'], $variables); + drupal_set_message($context['message']); +} + +/** + * Implementation of a configurable Drupal action. Redirect user to a URL. + */ +function system_goto_action_form($context) { + $form['url'] = array( + '#type' => 'textfield', + '#title' => t('URL'), + '#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.'), + '#default_value' => isset($context['url']) ? $context['url'] : '', + '#required' => TRUE, + ); + return $form; +} + +function system_goto_action_submit($form, $form_state) { + return array( + 'url' => $form_state['values']['url'] + ); +} + +function system_goto_action($object, $context) { + drupal_goto($context['url']); +} + === modified file 'modules/system/system.admin.inc' --- modules/system/system.admin.inc 2008-07-23 07:37:06 +0000 +++ modules/system/system.admin.inc 2008-07-27 19:35:47 +0000 @@ -7,6 +7,40 @@ */ /** + * Provide a single block on the administration overview page. + * + * @param $item + * The menu item to be displayed. + */ +function system_admin_menu_block($item) { + $content = array(); + if (!isset($item['mlid'])) { + $item += db_fetch_array(db_query("SELECT mlid, menu_name FROM {menu_links} ml WHERE ml.router_path = '%s' AND module = 'system'", $item['path'])); + } + $result = db_query(" + 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.* + FROM {menu_links} ml + LEFT JOIN {menu_router} m ON ml.router_path = m.path + WHERE ml.plid = %d AND ml.menu_name = '%s' AND hidden = 0", $item['mlid'], $item['menu_name']); + while ($item = db_fetch_array($result)) { + _menu_link_translate($item); + if (!$item['access']) { + continue; + } + // The link 'description' either derived from the hook_menu 'description' or + // entered by the user via menu module is saved as the title attribute. + if (!empty($item['localized_options']['attributes']['title'])) { + $item['description'] = $item['localized_options']['attributes']['title']; + } + // Prepare for sorting as in function _menu_tree_check_access(). + // The weight is offset so it is always positive, with a uniform 5-digits. + $content[(50000 + $item['weight']) . ' ' . $item['title'] . ' ' . $item['mlid']] = $item; + } + ksort($content); + return $content; +} + +/** * Menu callback; Provide the administration overview page. */ function system_main_admin_page($arg = NULL) { @@ -59,7 +93,6 @@ function system_main_admin_page($arg = N } } - /** * Provide a single block from the administration menu as a page. * This function is often a destination for these blocks. @@ -168,6 +201,19 @@ function system_admin_theme_settings() { } /** + * Process admin theme form submissions. + */ +function system_admin_theme_submit($form, &$form_state) { + // If we're changing themes, make sure the theme has its blocks initialized. + if ($form_state['values']['admin_theme'] && $form_state['values']['admin_theme'] != variable_get('admin_theme', '0')) { + $result = db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme = '%s'", $form_state['values']['admin_theme'])); + if (!$result) { + system_initialize_theme_blocks($form_state['values']['admin_theme']); + } + } +} + +/** * Menu callback; displays a listing of all themes. * * @ingroup forms @@ -705,7 +751,7 @@ function system_sort_modules_by_info_nam return strcasecmp($a->info['name'], $b->info['name']); } -/** +/** * Build a table row for the system modules page. */ function _system_modules_build_row($info, $extra) { @@ -881,7 +927,7 @@ function system_modules_submit($form, &$ ); } else { - $dependencies[$name]['dependencies'][$dependency] = $files[$dependency]->info['name']; + $dependencies[$name]['dependencies'][$dependency] = $files[$dependency]->info['name']; } $modules[$dependency] = array('group' => $files[$dependency]->info['package'], 'enabled' => TRUE); } @@ -1880,6 +1926,40 @@ function system_batch_page() { } /** + * Execute the system_settings_form. + * + * If you want node type configure style handling of your checkboxes, + * add an array_filter value to your form. + */ +function system_settings_form_submit($form, &$form_state) { + $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : ''; + + // Exclude unnecessary elements. + 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']); + + foreach ($form_state['values'] as $key => $value) { + if ($op == t('Reset to defaults')) { + variable_del($key); + } + else { + if (is_array($value) && isset($form_state['values']['array_filter'])) { + $value = array_keys(array_filter($value)); + } + variable_set($key, $value); + } + } + if ($op == t('Reset to defaults')) { + drupal_set_message(t('The configuration options have been reset to their default values.')); + } + else { + drupal_set_message(t('The configuration options have been saved.')); + } + + cache_clear_all(); + drupal_rebuild_theme_registry(); +} + +/** * This function formats an administrative block for display. * * @param $block @@ -2092,10 +2172,10 @@ function theme_system_modules_fieldset($ // Add the description, along with any dependencies. $description .= drupal_render($module['description']); if ($module['#dependencies']) { - $description .= '
' . t('Depends on: ') . implode(', ', $module['#dependencies']) . '
'; + $description .= '
' . t('Depends on: ') . implode(', ', $module['#dependencies']) . '
'; } if ($module['#dependents']) { - $description .= '
' . t('Required by: ') . implode(', ', $module['#dependents']) . '
'; + $description .= '
' . t('Required by: ') . implode(', ', $module['#dependents']) . '
'; } $row[] = array('data' => $description, 'class' => 'description'); $rows[] = $row; === added file 'modules/system/system.build.inc' --- modules/system/system.build.inc 1970-01-01 00:00:00 +0000 +++ modules/system/system.build.inc 2008-07-27 20:56:47 +0000 @@ -0,0 +1,524 @@ + array( + 'arguments' => array('form' => NULL), + 'file' => 'system.admin.inc', + ), + 'system_themes_form' => array( + 'arguments' => array('form' => NULL), + 'file' => 'system.admin.inc', + ), + 'system_modules_fieldset' => array( + 'arguments' => array('form' => NULL), + 'file' => 'system.admin.inc', + ), + 'system_modules_incompatible' => array( + 'arguments' => array('message' => NULL), + 'file' => 'system.admin.inc', + ), + 'system_modules_uninstall' => array( + 'arguments' => array('form' => NULL), + 'file' => 'system.admin.inc', + ), + 'status_report' => array( + 'arguments' => array('requirements' => NULL), + 'file' => 'system.admin.inc', + ), + 'admin_page' => array( + 'arguments' => array('blocks' => NULL), + 'file' => 'system.admin.inc', + ), + 'admin_block' => array( + 'arguments' => array('block' => NULL), + 'file' => 'system.admin.inc', + ), + 'admin_block_content' => array( + 'arguments' => array('content' => NULL), + 'file' => 'system.admin.inc', + ), + 'system_admin_by_module' => array( + 'arguments' => array('menu_items' => NULL), + 'file' => 'system.admin.inc', + ), + 'system_powered_by' => array( + 'arguments' => array('image_path' => NULL), + ), + 'meta_generator_html' => array( + 'arguments' => array('version' => NULL), + ), + 'meta_generator_header' => array( + 'arguments' => array('version' => NULL), + ), + 'system_compact_link' => array(), + )); +} + +/** + * Implementation of hook_perm(). + */ +function system_perm() { + return array( + 'administer site configuration' => t('Configure site-wide settings such as module or theme administration settings.'), + 'access administration pages' => t('View the administration panel and browse the help system.'), + 'administer actions' => t('Manage the actions defined for your site.'), + 'access site reports' => t('View reports from system logs and other status information.'), + 'select different theme' => t('Select a theme other than the default theme set by the site administrator.'), + 'administer files' => t('Manage user-uploaded files.'), + 'block IP addresses' => t('Block IP addresses from accessing your site.'), + ); +} + +/** + * Implementation of hook_menu(). + */ +function system_menu() { + $items['system/files'] = array( + 'title' => 'File download', + 'page callback' => 'file_download', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + $items['admin'] = array( + 'title' => 'Administer', + 'access arguments' => array('access administration pages'), + 'page callback' => 'system_main_admin_page', + 'weight' => 9, + ); + $items['admin/compact'] = array( + 'title' => 'Compact mode', + 'page callback' => 'system_admin_compact_page', + 'access arguments' => array('access administration pages'), + 'type' => MENU_CALLBACK, + ); + $items['admin/by-task'] = array( + 'title' => 'By task', + 'page callback' => 'system_main_admin_page', + 'access arguments' => array('access administration pages'), + 'type' => MENU_DEFAULT_LOCAL_TASK, + ); + $items['admin/by-module'] = array( + 'title' => 'By module', + 'page callback' => 'system_admin_by_module', + 'access arguments' => array('access administration pages'), + 'type' => MENU_LOCAL_TASK, + 'weight' => 2, + ); + $items['admin/content'] = array( + 'title' => 'Content management', + 'description' => "Manage your site's content.", + 'position' => 'left', + 'weight' => -10, + 'page callback' => 'system_admin_menu_block_page', + 'access arguments' => array('access administration pages'), + ); + + // menu items that are basically just menu blocks + $items['admin/settings'] = array( + 'title' => 'Site configuration', + 'description' => 'Adjust basic site configuration options.', + 'position' => 'right', + 'weight' => -5, + 'page callback' => 'system_settings_overview', + 'access arguments' => array('access administration pages'), + ); + $items['admin/build'] = array( + 'title' => 'Site building', + 'description' => 'Control how your site looks and feels.', + 'position' => 'right', + 'weight' => -10, + 'page callback' => 'system_admin_menu_block_page', + 'access arguments' => array('access administration pages'), + ); + $items['admin/settings/admin'] = array( + 'title' => 'Administration theme', + 'description' => 'Settings for how your administrative pages should look.', + 'position' => 'left', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_admin_theme_settings'), + 'access arguments' => array('administer site configuration'), + 'block callback' => 'system_admin_theme_settings', + ); + // Themes: + $items['admin/build/themes'] = array( + 'title' => 'Themes', + 'description' => 'Change which theme your site uses or allows users to set.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_themes_form', NULL), + 'access arguments' => array('administer site configuration'), + ); + $items['admin/build/themes/select'] = array( + 'title' => 'List', + 'description' => 'Select the default theme.', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => -1, + ); + $items['admin/build/themes/settings'] = array( + 'title' => 'Configure', + 'page arguments' => array('system_theme_settings'), + 'access arguments' => array('administer site configuration'), + 'type' => MENU_LOCAL_TASK, + ); + // Theme configuration subtabs + $items['admin/build/themes/settings/global'] = array( + 'title' => 'Global settings', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => -1, + ); + + foreach (list_themes() as $theme) { + $items['admin/build/themes/settings/' . $theme->name] = array( + 'title' => $theme->info['name'], + 'page arguments' => array('system_theme_settings', $theme->name), + 'type' => MENU_LOCAL_TASK, + 'access callback' => '_system_themes_access', + 'access arguments' => array($theme), + ); + } + + // Modules: + $items['admin/build/modules'] = array( + 'title' => 'Modules', + 'description' => 'Enable or disable add-on modules for your site.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_modules'), + 'access arguments' => array('administer site configuration'), + ); + $items['admin/build/modules/list'] = array( + 'title' => 'List', + 'type' => MENU_DEFAULT_LOCAL_TASK, + ); + $items['admin/build/modules/list/confirm'] = array( + 'title' => 'List', + 'access arguments' => array('administer site configuration'), + 'type' => MENU_CALLBACK, + ); + $items['admin/build/modules/uninstall'] = array( + 'title' => 'Uninstall', + 'page arguments' => array('system_modules_uninstall'), + 'access arguments' => array('administer site configuration'), + 'type' => MENU_LOCAL_TASK, + ); + $items['admin/build/modules/uninstall/confirm'] = array( + 'title' => 'Uninstall', + 'access arguments' => array('administer site configuration'), + 'type' => MENU_CALLBACK, + ); + + // Actions: + $items['admin/settings/actions'] = array( + 'title' => 'Actions', + 'description' => 'Manage the actions defined for your site.', + 'access arguments' => array('administer actions'), + 'page callback' => 'system_actions_manage' + ); + $items['admin/settings/actions/manage'] = array( + 'title' => 'Manage actions', + 'description' => 'Manage the actions defined for your site.', + 'page callback' => 'system_actions_manage', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => -2, + ); + $items['admin/settings/actions/configure'] = array( + 'title' => 'Configure an advanced action', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_actions_configure'), + 'access arguments' => array('administer actions'), + 'type' => MENU_CALLBACK, + ); + $items['admin/settings/actions/delete/%actions'] = array( + 'title' => 'Delete action', + 'description' => 'Delete an action.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_actions_delete_form', 4), + 'access arguments' => array('administer actions'), + 'type' => MENU_CALLBACK, + ); + $items['admin/settings/actions/orphan'] = array( + 'title' => 'Remove orphans', + 'page callback' => 'system_actions_remove_orphans', + 'access arguments' => array('administer actions'), + 'type' => MENU_CALLBACK, + ); + + // IP address blocking. + $items['admin/settings/ip-blocking'] = array( + 'title' => 'IP address blocking', + 'description' => 'Manage blocked IP addresses.', + 'page callback' => 'system_ip_blocking', + 'access arguments' => array('block IP addresses'), + ); + $items['admin/settings/ip-blocking/%'] = array( + 'title' => 'IP address blocking', + 'description' => 'Manage blocked IP addresses.', + 'page callback' => 'system_ip_blocking', + 'access arguments' => array('block IP addresses'), + 'type' => MENU_CALLBACK, + ); + $items['admin/settings/ip-blocking/delete/%blocked_ip'] = array( + 'title' => 'Delete IP address', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_ip_blocking_delete', 4), + 'access arguments' => array('block IP addresses'), + 'type' => MENU_CALLBACK, + ); + + // Settings: + $items['admin/settings/site-information'] = array( + 'title' => 'Site information', + 'description' => 'Change basic site information, such as the site name, slogan, e-mail address, mission, front page and more.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_site_information_settings'), + 'access arguments' => array('administer site configuration'), + ); + $items['admin/settings/error-reporting'] = array( + 'title' => 'Error reporting', + 'description' => 'Control how Drupal deals with errors including 403/404 errors as well as PHP error reporting.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_error_reporting_settings'), + 'access arguments' => array('administer site configuration'), + ); + $items['admin/settings/logging'] = array( + 'title' => 'Logging and alerts', + 'description' => "Settings for logging and alerts modules. Various modules can route Drupal's system events to different destination, such as syslog, database, email, ...etc.", + 'page callback' => 'system_logging_overview', + 'access arguments' => array('administer site configuration'), + ); + $items['admin/settings/performance'] = array( + 'title' => 'Performance', + 'description' => 'Enable or disable page caching for anonymous users and set CSS and JS bandwidth optimization options.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_performance_settings'), + 'access arguments' => array('administer site configuration'), + ); + $items['admin/settings/file-system'] = array( + 'title' => 'File system', + 'description' => 'Tell Drupal where to store uploaded files and how they are accessed.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_file_system_settings'), + 'access arguments' => array('administer site configuration'), + ); + $items['admin/settings/image-toolkit'] = array( + 'title' => 'Image toolkit', + 'description' => 'Choose which image toolkit to use if you have installed optional toolkits.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_image_toolkit_settings'), + 'access arguments' => array('administer site configuration'), + ); + $items['admin/content/rss-publishing'] = array( + 'title' => 'RSS publishing', + 'description' => 'Configure the number of items per feed and whether feeds should be titles/teasers/full-text.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_rss_feeds_settings'), + 'access arguments' => array('administer site configuration'), + ); + $items['admin/settings/date-time'] = array( + 'title' => 'Date and time', + 'description' => "Settings for how Drupal displays date and time, as well as the system's default timezone.", + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_date_time_settings'), + 'access arguments' => array('administer site configuration'), + ); + $items['admin/settings/date-time/lookup'] = array( + 'title' => 'Date and time lookup', + 'type' => MENU_CALLBACK, + 'page callback' => 'system_date_time_lookup', + 'access arguments' => array('administer site configuration'), + ); + $items['admin/settings/site-maintenance'] = array( + 'title' => 'Site maintenance', + 'description' => 'Take the site offline for maintenance or bring it back online.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_site_maintenance_settings'), + 'access arguments' => array('administer site configuration'), + ); + $items['admin/settings/clean-urls'] = array( + 'title' => 'Clean URLs', + 'description' => 'Enable or disable clean URLs for your site.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_clean_url_settings'), + 'access arguments' => array('administer site configuration'), + ); + $items['admin/settings/clean-urls/check'] = array( + 'title' => 'Clean URL check', + 'page callback' => 'drupal_json', + 'page arguments' => array(array('status' => TRUE)), + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + // Menu handler to test that drupal_http_request() works locally. + // @see system_check_http_request() + $items['admin/reports/request-test'] = array( + 'title' => 'Request test', + 'page callback' => 'printf', + 'page arguments' => array('request test'), + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + + // Reports: + $items['admin/reports'] = array( + 'title' => 'Reports', + 'description' => 'View reports from system logs and other status information.', + 'page callback' => 'system_admin_menu_block_page', + 'access arguments' => array('access site reports'), + 'weight' => 5, + 'position' => 'left', + ); + $items['admin/reports/status'] = array( + 'title' => 'Status report', + 'description' => "Get a status report about your site's operation and any detected problems.", + 'page callback' => 'system_status', + 'weight' => 10, + 'access arguments' => array('administer site configuration'), + ); + $items['admin/reports/status/run-cron'] = array( + 'title' => 'Run cron', + 'page callback' => 'system_run_cron', + 'access arguments' => array('administer site configuration'), + 'type' => MENU_CALLBACK, + ); + $items['admin/reports/status/php'] = array( + 'title' => 'PHP', + 'page callback' => 'system_php', + 'access arguments' => array('administer site configuration'), + 'type' => MENU_CALLBACK, + ); + $items['admin/reports/status/sql'] = array( + 'title' => 'SQL', + 'page callback' => 'system_sql', + 'access arguments' => array('administer site configuration'), + 'type' => MENU_CALLBACK, + ); + // Default page for batch operations + $items['batch'] = array( + 'page callback' => 'system_batch_page', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + return $items; +} + +/** + * Collect data about all currently available themes. + * + * @return + * Array of all available themes and their data. + */ +function system_theme_data() { + // Scan the installation theme .info files and their engines. + $themes = _system_theme_data(); + + // Extract current files from database. + system_get_files_database($themes, 'theme'); + + db_query("DELETE FROM {system} WHERE type = 'theme'"); + + foreach ($themes as $theme) { + if (!isset($theme->owner)) { + $theme->owner = ''; + } + + db_query("INSERT INTO {system} (name, owner, info, type, filename, status, bootstrap) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d)", $theme->name, $theme->owner, serialize($theme->info), 'theme', $theme->filename, isset($theme->status) ? $theme->status : 0, 0); + } + + return $themes; +} + +/** + * Helper function to scan and collect theme .info data and their engines. + * + * @return + * An associative array of themes information. + */ +function _system_theme_data() { + static $themes_info = array(); + + if (empty($themes_info)) { + // Find themes + $themes = drupal_system_listing('\.info$', 'themes'); + // Find theme engines + $engines = drupal_system_listing('\.engine$', 'themes/engines'); + + $defaults = system_theme_default(); + + $sub_themes = array(); + // Read info files for each theme + foreach ($themes as $key => $theme) { + $themes[$key]->info = drupal_parse_info_file($theme->filename) + $defaults; + + // Invoke hook_system_info_alter() to give installed modules a chance to + // modify the data in the .info files if necessary. + drupal_alter('system_info', $themes[$key]->info, $themes[$key]); + + if (!empty($themes[$key]->info['base theme'])) { + $sub_themes[] = $key; + } + if (empty($themes[$key]->info['engine'])) { + $filename = dirname($themes[$key]->filename) . '/' . $themes[$key]->name . '.theme'; + if (file_exists($filename)) { + $themes[$key]->owner = $filename; + $themes[$key]->prefix = $key; + } + } + else { + $engine = $themes[$key]->info['engine']; + if (isset($engines[$engine])) { + $themes[$key]->owner = $engines[$engine]->filename; + $themes[$key]->prefix = $engines[$engine]->name; + $themes[$key]->template = TRUE; + } + } + + // Give the stylesheets proper path information. + $pathed_stylesheets = array(); + foreach ($themes[$key]->info['stylesheets'] as $media => $stylesheets) { + foreach ($stylesheets as $stylesheet) { + $pathed_stylesheets[$media][$stylesheet] = dirname($themes[$key]->filename) . '/' . $stylesheet; + } + } + $themes[$key]->info['stylesheets'] = $pathed_stylesheets; + + // Give the scripts proper path information. + $scripts = array(); + foreach ($themes[$key]->info['scripts'] as $script) { + $scripts[$script] = dirname($themes[$key]->filename) . '/' . $script; + } + $themes[$key]->info['scripts'] = $scripts; + // Give the screenshot proper path information. + if (!empty($themes[$key]->info['screenshot'])) { + $themes[$key]->info['screenshot'] = dirname($themes[$key]->filename) . '/' . $themes[$key]->info['screenshot']; + } + } + + // Now that we've established all our master themes, go back and fill in + // data for subthemes. + foreach ($sub_themes as $key) { + $base_key = system_find_base_theme($themes, $key); + if (!$base_key) { + continue; + } + // Copy the 'owner' and 'engine' over if the top level theme uses a + // theme engine. + if (isset($themes[$base_key]->owner)) { + if (isset($themes[$base_key]->info['engine'])) { + $themes[$key]->info['engine'] = $themes[$base_key]->info['engine']; + $themes[$key]->owner = $themes[$base_key]->owner; + $themes[$key]->prefix = $themes[$base_key]->prefix; + } + else { + $themes[$key]->prefix = $key; + } + } + } + + $themes_info = $themes; + } + + return $themes_info; +} + === modified file 'modules/system/system.info' --- modules/system/system.info 2008-07-08 01:08:15 +0000 +++ modules/system/system.info 2008-07-27 19:25:24 +0000 @@ -5,5 +5,8 @@ package = Core - required version = VERSION core = 7.x files[] = system.module +files[] = system.actions.inc +files[] = system.build.inc files[] = system.admin.inc files[] = image.gd.inc +files[] = system.install === modified file 'modules/system/system.install' --- modules/system/system.install 2008-07-01 20:36:39 +0000 +++ modules/system/system.install 2008-07-27 19:10:47 +0000 @@ -1083,6 +1083,24 @@ function system_schema() { 'length' => 255, 'not null' => TRUE, ), + 'module_filename' => array( + 'description' => t('The filename of the module this file belongs to.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ), + 'module' => array( + 'description' => t('The name of the module this file belongs to.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ), + 'hook' => array( + 'description' => t('The hook this function could implement, if any.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ), ), 'primary key' => array('name', 'type'), ); @@ -2919,16 +2937,19 @@ function system_update_7006() { db_drop_field($ret, 'menu_router', 'file'); $schema['registry'] = array( 'fields' => array( - 'name' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), - 'type' => array('type' => 'varchar', 'length' => 9, 'not null' => TRUE, 'default' => ''), - 'filename' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), + 'name' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), + 'type' => array('type' => 'varchar', 'length' => 9, 'not null' => TRUE, 'default' => ''), + 'filename' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), + 'module_filename' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), + 'module' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), + 'hook' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), ), 'primary key' => array('name', 'type'), ); $schema['registry_file'] = array( 'fields' => array( - 'filename' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), - 'md5' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''), + 'filename' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), + 'md5' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''), ), 'primary key' => array('filename'), ); === modified file 'modules/system/system.module' --- modules/system/system.module 2008-07-23 07:37:06 +0000 +++ modules/system/system.module 2008-07-27 20:56:41 +0000 @@ -103,79 +103,6 @@ function system_help($path, $arg) { } /** - * Implementation of hook_theme(). - */ -function system_theme() { - return array_merge(drupal_common_theme(), array( - 'system_theme_select_form' => array( - 'arguments' => array('form' => NULL), - 'file' => 'system.admin.inc', - ), - 'system_themes_form' => array( - 'arguments' => array('form' => NULL), - 'file' => 'system.admin.inc', - ), - 'system_modules_fieldset' => array( - 'arguments' => array('form' => NULL), - 'file' => 'system.admin.inc', - ), - 'system_modules_incompatible' => array( - 'arguments' => array('message' => NULL), - 'file' => 'system.admin.inc', - ), - 'system_modules_uninstall' => array( - 'arguments' => array('form' => NULL), - 'file' => 'system.admin.inc', - ), - 'status_report' => array( - 'arguments' => array('requirements' => NULL), - 'file' => 'system.admin.inc', - ), - 'admin_page' => array( - 'arguments' => array('blocks' => NULL), - 'file' => 'system.admin.inc', - ), - 'admin_block' => array( - 'arguments' => array('block' => NULL), - 'file' => 'system.admin.inc', - ), - 'admin_block_content' => array( - 'arguments' => array('content' => NULL), - 'file' => 'system.admin.inc', - ), - 'system_admin_by_module' => array( - 'arguments' => array('menu_items' => NULL), - 'file' => 'system.admin.inc', - ), - 'system_powered_by' => array( - 'arguments' => array('image_path' => NULL), - ), - 'meta_generator_html' => array( - 'arguments' => array('version' => NULL), - ), - 'meta_generator_header' => array( - 'arguments' => array('version' => NULL), - ), - 'system_compact_link' => array(), - )); -} - -/** - * Implementation of hook_perm(). - */ -function system_perm() { - return array( - 'administer site configuration' => t('Configure site-wide settings such as module or theme administration settings.'), - 'access administration pages' => t('View the administration panel and browse the help system.'), - 'administer actions' => t('Manage the actions defined for your site.'), - 'access site reports' => t('View reports from system logs and other status information.'), - 'select different theme' => t('Select a theme other than the default theme set by the site administrator.'), - 'administer files' => t('Manage user-uploaded files.'), - 'block IP addresses' => t('Block IP addresses from accessing your site.'), - ); -} - -/** * Implementation of hook_elements(). */ function system_elements() { @@ -327,336 +254,6 @@ function system_elements() { } /** - * Implementation of hook_menu(). - */ -function system_menu() { - $items['system/files'] = array( - 'title' => 'File download', - 'page callback' => 'file_download', - 'access callback' => TRUE, - 'type' => MENU_CALLBACK, - ); - $items['admin'] = array( - 'title' => 'Administer', - 'access arguments' => array('access administration pages'), - 'page callback' => 'system_main_admin_page', - 'weight' => 9, - ); - $items['admin/compact'] = array( - 'title' => 'Compact mode', - 'page callback' => 'system_admin_compact_page', - 'access arguments' => array('access administration pages'), - 'type' => MENU_CALLBACK, - ); - $items['admin/by-task'] = array( - 'title' => 'By task', - 'page callback' => 'system_main_admin_page', - 'access arguments' => array('access administration pages'), - 'type' => MENU_DEFAULT_LOCAL_TASK, - ); - $items['admin/by-module'] = array( - 'title' => 'By module', - 'page callback' => 'system_admin_by_module', - 'access arguments' => array('access administration pages'), - 'type' => MENU_LOCAL_TASK, - 'weight' => 2, - ); - $items['admin/content'] = array( - 'title' => 'Content management', - 'description' => "Manage your site's content.", - 'position' => 'left', - 'weight' => -10, - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access administration pages'), - ); - - // menu items that are basically just menu blocks - $items['admin/settings'] = array( - 'title' => 'Site configuration', - 'description' => 'Adjust basic site configuration options.', - 'position' => 'right', - 'weight' => -5, - 'page callback' => 'system_settings_overview', - 'access arguments' => array('access administration pages'), - ); - $items['admin/build'] = array( - 'title' => 'Site building', - 'description' => 'Control how your site looks and feels.', - 'position' => 'right', - 'weight' => -10, - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access administration pages'), - ); - $items['admin/settings/admin'] = array( - 'title' => 'Administration theme', - 'description' => 'Settings for how your administrative pages should look.', - 'position' => 'left', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_admin_theme_settings'), - 'access arguments' => array('administer site configuration'), - 'block callback' => 'system_admin_theme_settings', - ); - // Themes: - $items['admin/build/themes'] = array( - 'title' => 'Themes', - 'description' => 'Change which theme your site uses or allows users to set.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_themes_form', NULL), - 'access arguments' => array('administer site configuration'), - ); - $items['admin/build/themes/select'] = array( - 'title' => 'List', - 'description' => 'Select the default theme.', - 'type' => MENU_DEFAULT_LOCAL_TASK, - 'weight' => -1, - ); - $items['admin/build/themes/settings'] = array( - 'title' => 'Configure', - 'page arguments' => array('system_theme_settings'), - 'access arguments' => array('administer site configuration'), - 'type' => MENU_LOCAL_TASK, - ); - // Theme configuration subtabs - $items['admin/build/themes/settings/global'] = array( - 'title' => 'Global settings', - 'type' => MENU_DEFAULT_LOCAL_TASK, - 'weight' => -1, - ); - - foreach (list_themes() as $theme) { - $items['admin/build/themes/settings/' . $theme->name] = array( - 'title' => $theme->info['name'], - 'page arguments' => array('system_theme_settings', $theme->name), - 'type' => MENU_LOCAL_TASK, - 'access callback' => '_system_themes_access', - 'access arguments' => array($theme), - ); - } - - // Modules: - $items['admin/build/modules'] = array( - 'title' => 'Modules', - 'description' => 'Enable or disable add-on modules for your site.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_modules'), - 'access arguments' => array('administer site configuration'), - ); - $items['admin/build/modules/list'] = array( - 'title' => 'List', - 'type' => MENU_DEFAULT_LOCAL_TASK, - ); - $items['admin/build/modules/list/confirm'] = array( - 'title' => 'List', - 'access arguments' => array('administer site configuration'), - 'type' => MENU_CALLBACK, - ); - $items['admin/build/modules/uninstall'] = array( - 'title' => 'Uninstall', - 'page arguments' => array('system_modules_uninstall'), - 'access arguments' => array('administer site configuration'), - 'type' => MENU_LOCAL_TASK, - ); - $items['admin/build/modules/uninstall/confirm'] = array( - 'title' => 'Uninstall', - 'access arguments' => array('administer site configuration'), - 'type' => MENU_CALLBACK, - ); - - // Actions: - $items['admin/settings/actions'] = array( - 'title' => 'Actions', - 'description' => 'Manage the actions defined for your site.', - 'access arguments' => array('administer actions'), - 'page callback' => 'system_actions_manage' - ); - $items['admin/settings/actions/manage'] = array( - 'title' => 'Manage actions', - 'description' => 'Manage the actions defined for your site.', - 'page callback' => 'system_actions_manage', - 'type' => MENU_DEFAULT_LOCAL_TASK, - 'weight' => -2, - ); - $items['admin/settings/actions/configure'] = array( - 'title' => 'Configure an advanced action', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_actions_configure'), - 'access arguments' => array('administer actions'), - 'type' => MENU_CALLBACK, - ); - $items['admin/settings/actions/delete/%actions'] = array( - 'title' => 'Delete action', - 'description' => 'Delete an action.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_actions_delete_form', 4), - 'access arguments' => array('administer actions'), - 'type' => MENU_CALLBACK, - ); - $items['admin/settings/actions/orphan'] = array( - 'title' => 'Remove orphans', - 'page callback' => 'system_actions_remove_orphans', - 'access arguments' => array('administer actions'), - 'type' => MENU_CALLBACK, - ); - - // IP address blocking. - $items['admin/settings/ip-blocking'] = array( - 'title' => 'IP address blocking', - 'description' => 'Manage blocked IP addresses.', - 'page callback' => 'system_ip_blocking', - 'access arguments' => array('block IP addresses'), - ); - $items['admin/settings/ip-blocking/%'] = array( - 'title' => 'IP address blocking', - 'description' => 'Manage blocked IP addresses.', - 'page callback' => 'system_ip_blocking', - 'access arguments' => array('block IP addresses'), - 'type' => MENU_CALLBACK, - ); - $items['admin/settings/ip-blocking/delete/%blocked_ip'] = array( - 'title' => 'Delete IP address', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_ip_blocking_delete', 4), - 'access arguments' => array('block IP addresses'), - 'type' => MENU_CALLBACK, - ); - - // Settings: - $items['admin/settings/site-information'] = array( - 'title' => 'Site information', - 'description' => 'Change basic site information, such as the site name, slogan, e-mail address, mission, front page and more.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_site_information_settings'), - 'access arguments' => array('administer site configuration'), - ); - $items['admin/settings/error-reporting'] = array( - 'title' => 'Error reporting', - 'description' => 'Control how Drupal deals with errors including 403/404 errors as well as PHP error reporting.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_error_reporting_settings'), - 'access arguments' => array('administer site configuration'), - ); - $items['admin/settings/logging'] = array( - 'title' => 'Logging and alerts', - 'description' => "Settings for logging and alerts modules. Various modules can route Drupal's system events to different destination, such as syslog, database, email, ...etc.", - 'page callback' => 'system_logging_overview', - 'access arguments' => array('administer site configuration'), - ); - $items['admin/settings/performance'] = array( - 'title' => 'Performance', - 'description' => 'Enable or disable page caching for anonymous users and set CSS and JS bandwidth optimization options.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_performance_settings'), - 'access arguments' => array('administer site configuration'), - ); - $items['admin/settings/file-system'] = array( - 'title' => 'File system', - 'description' => 'Tell Drupal where to store uploaded files and how they are accessed.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_file_system_settings'), - 'access arguments' => array('administer site configuration'), - ); - $items['admin/settings/image-toolkit'] = array( - 'title' => 'Image toolkit', - 'description' => 'Choose which image toolkit to use if you have installed optional toolkits.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_image_toolkit_settings'), - 'access arguments' => array('administer site configuration'), - ); - $items['admin/content/rss-publishing'] = array( - 'title' => 'RSS publishing', - 'description' => 'Configure the number of items per feed and whether feeds should be titles/teasers/full-text.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_rss_feeds_settings'), - 'access arguments' => array('administer site configuration'), - ); - $items['admin/settings/date-time'] = array( - 'title' => 'Date and time', - 'description' => "Settings for how Drupal displays date and time, as well as the system's default timezone.", - 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_date_time_settings'), - 'access arguments' => array('administer site configuration'), - ); - $items['admin/settings/date-time/lookup'] = array( - 'title' => 'Date and time lookup', - 'type' => MENU_CALLBACK, - 'page callback' => 'system_date_time_lookup', - 'access arguments' => array('administer site configuration'), - ); - $items['admin/settings/site-maintenance'] = array( - 'title' => 'Site maintenance', - 'description' => 'Take the site offline for maintenance or bring it back online.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_site_maintenance_settings'), - 'access arguments' => array('administer site configuration'), - ); - $items['admin/settings/clean-urls'] = array( - 'title' => 'Clean URLs', - 'description' => 'Enable or disable clean URLs for your site.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('system_clean_url_settings'), - 'access arguments' => array('administer site configuration'), - ); - $items['admin/settings/clean-urls/check'] = array( - 'title' => 'Clean URL check', - 'page callback' => 'drupal_json', - 'page arguments' => array(array('status' => TRUE)), - 'access callback' => TRUE, - 'type' => MENU_CALLBACK, - ); - // Menu handler to test that drupal_http_request() works locally. - // @see system_check_http_request() - $items['admin/reports/request-test'] = array( - 'title' => 'Request test', - 'page callback' => 'printf', - 'page arguments' => array('request test'), - 'access callback' => TRUE, - 'type' => MENU_CALLBACK, - ); - - // Reports: - $items['admin/reports'] = array( - 'title' => 'Reports', - 'description' => 'View reports from system logs and other status information.', - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access site reports'), - 'weight' => 5, - 'position' => 'left', - ); - $items['admin/reports/status'] = array( - 'title' => 'Status report', - 'description' => "Get a status report about your site's operation and any detected problems.", - 'page callback' => 'system_status', - 'weight' => 10, - 'access arguments' => array('administer site configuration'), - ); - $items['admin/reports/status/run-cron'] = array( - 'title' => 'Run cron', - 'page callback' => 'system_run_cron', - 'access arguments' => array('administer site configuration'), - 'type' => MENU_CALLBACK, - ); - $items['admin/reports/status/php'] = array( - 'title' => 'PHP', - 'page callback' => 'system_php', - 'access arguments' => array('administer site configuration'), - 'type' => MENU_CALLBACK, - ); - $items['admin/reports/status/sql'] = array( - 'title' => 'SQL', - 'page callback' => 'system_sql', - 'access arguments' => array('administer site configuration'), - 'type' => MENU_CALLBACK, - ); - // Default page for batch operations - $items['batch'] = array( - 'page callback' => 'system_batch_page', - 'access callback' => TRUE, - 'type' => MENU_CALLBACK, - ); - return $items; -} - -/** * Retrieve a blocked IP address from the database. * * @param $iid integer @@ -776,53 +373,6 @@ function system_block($op = 'list', $del } /** - * Provide a single block on the administration overview page. - * - * @param $item - * The menu item to be displayed. - */ -function system_admin_menu_block($item) { - $content = array(); - if (!isset($item['mlid'])) { - $item += db_fetch_array(db_query("SELECT mlid, menu_name FROM {menu_links} ml WHERE ml.router_path = '%s' AND module = 'system'", $item['path'])); - } - $result = db_query(" - 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.* - FROM {menu_links} ml - LEFT JOIN {menu_router} m ON ml.router_path = m.path - WHERE ml.plid = %d AND ml.menu_name = '%s' AND hidden = 0", $item['mlid'], $item['menu_name']); - while ($item = db_fetch_array($result)) { - _menu_link_translate($item); - if (!$item['access']) { - continue; - } - // The link 'description' either derived from the hook_menu 'description' or - // entered by the user via menu module is saved as the title attribute. - if (!empty($item['localized_options']['attributes']['title'])) { - $item['description'] = $item['localized_options']['attributes']['title']; - } - // Prepare for sorting as in function _menu_tree_check_access(). - // The weight is offset so it is always positive, with a uniform 5-digits. - $content[(50000 + $item['weight']) . ' ' . $item['title'] . ' ' . $item['mlid']] = $item; - } - ksort($content); - return $content; -} - -/** - * Process admin theme form submissions. - */ -function system_admin_theme_submit($form, &$form_state) { - // If we're changing themes, make sure the theme has its blocks initialized. - if ($form_state['values']['admin_theme'] && $form_state['values']['admin_theme'] != variable_get('admin_theme', '0')) { - $result = db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme = '%s'", $form_state['values']['admin_theme'])); - if (!$result) { - system_initialize_theme_blocks($form_state['values']['admin_theme']); - } - } -} - -/** * Returns a fieldset containing the theme select form. * * @param $description @@ -960,125 +510,6 @@ function system_theme_default() { } /** - * Collect data about all currently available themes. - * - * @return - * Array of all available themes and their data. - */ -function system_theme_data() { - // Scan the installation theme .info files and their engines. - $themes = _system_theme_data(); - - // Extract current files from database. - system_get_files_database($themes, 'theme'); - - db_query("DELETE FROM {system} WHERE type = 'theme'"); - - foreach ($themes as $theme) { - if (!isset($theme->owner)) { - $theme->owner = ''; - } - - db_query("INSERT INTO {system} (name, owner, info, type, filename, status, bootstrap) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d)", $theme->name, $theme->owner, serialize($theme->info), 'theme', $theme->filename, isset($theme->status) ? $theme->status : 0, 0); - } - - return $themes; -} - -/** - * Helper function to scan and collect theme .info data and their engines. - * - * @return - * An associative array of themes information. - */ -function _system_theme_data() { - static $themes_info = array(); - - if (empty($themes_info)) { - // Find themes - $themes = drupal_system_listing('\.info$', 'themes'); - // Find theme engines - $engines = drupal_system_listing('\.engine$', 'themes/engines'); - - $defaults = system_theme_default(); - - $sub_themes = array(); - // Read info files for each theme - foreach ($themes as $key => $theme) { - $themes[$key]->info = drupal_parse_info_file($theme->filename) + $defaults; - - // Invoke hook_system_info_alter() to give installed modules a chance to - // modify the data in the .info files if necessary. - drupal_alter('system_info', $themes[$key]->info, $themes[$key]); - - if (!empty($themes[$key]->info['base theme'])) { - $sub_themes[] = $key; - } - if (empty($themes[$key]->info['engine'])) { - $filename = dirname($themes[$key]->filename) . '/' . $themes[$key]->name . '.theme'; - if (file_exists($filename)) { - $themes[$key]->owner = $filename; - $themes[$key]->prefix = $key; - } - } - else { - $engine = $themes[$key]->info['engine']; - if (isset($engines[$engine])) { - $themes[$key]->owner = $engines[$engine]->filename; - $themes[$key]->prefix = $engines[$engine]->name; - $themes[$key]->template = TRUE; - } - } - - // Give the stylesheets proper path information. - $pathed_stylesheets = array(); - foreach ($themes[$key]->info['stylesheets'] as $media => $stylesheets) { - foreach ($stylesheets as $stylesheet) { - $pathed_stylesheets[$media][$stylesheet] = dirname($themes[$key]->filename) . '/' . $stylesheet; - } - } - $themes[$key]->info['stylesheets'] = $pathed_stylesheets; - - // Give the scripts proper path information. - $scripts = array(); - foreach ($themes[$key]->info['scripts'] as $script) { - $scripts[$script] = dirname($themes[$key]->filename) . '/' . $script; - } - $themes[$key]->info['scripts'] = $scripts; - // Give the screenshot proper path information. - if (!empty($themes[$key]->info['screenshot'])) { - $themes[$key]->info['screenshot'] = dirname($themes[$key]->filename) . '/' . $themes[$key]->info['screenshot']; - } - } - - // Now that we've established all our master themes, go back and fill in - // data for subthemes. - foreach ($sub_themes as $key) { - $base_key = system_find_base_theme($themes, $key); - if (!$base_key) { - continue; - } - // Copy the 'owner' and 'engine' over if the top level theme uses a - // theme engine. - if (isset($themes[$base_key]->owner)) { - if (isset($themes[$base_key]->info['engine'])) { - $themes[$key]->info['engine'] = $themes[$base_key]->info['engine']; - $themes[$key]->owner = $themes[$base_key]->owner; - $themes[$key]->prefix = $themes[$base_key]->prefix; - } - else { - $themes[$key]->prefix = $key; - } - } - } - - $themes_info = $themes; - } - - return $themes_info; -} - -/** * Recursive function to find the top level base theme. Themes can inherit * templates and function implementations from earlier themes. * @@ -1194,40 +625,6 @@ function system_settings_form($form) { } /** - * Execute the system_settings_form. - * - * If you want node type configure style handling of your checkboxes, - * add an array_filter value to your form. - */ -function system_settings_form_submit($form, &$form_state) { - $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : ''; - - // Exclude unnecessary elements. - 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']); - - foreach ($form_state['values'] as $key => $value) { - if ($op == t('Reset to defaults')) { - variable_del($key); - } - else { - if (is_array($value) && isset($form_state['values']['array_filter'])) { - $value = array_keys(array_filter($value)); - } - variable_set($key, $value); - } - } - if ($op == t('Reset to defaults')) { - drupal_set_message(t('The configuration options have been reset to their default values.')); - } - else { - drupal_set_message(t('The configuration options have been saved.')); - } - - cache_clear_all(); - drupal_rebuild_theme_registry(); -} - -/** * Helper function to sort requirements. */ function _system_sort_requirements($a, $b) { @@ -1426,456 +823,6 @@ function system_hook_info() { } /** - * Implementation of hook_action_info(). - */ -function system_action_info() { - return array( - 'system_message_action' => array( - 'type' => 'system', - 'description' => t('Display a message to the user'), - 'configurable' => TRUE, - 'hooks' => array( - 'nodeapi' => array('view', 'insert', 'update', 'delete'), - 'comment' => array('view', 'insert', 'update', 'delete'), - 'user' => array('view', 'insert', 'update', 'delete', 'login'), - 'taxonomy' => array('insert', 'update', 'delete'), - ), - ), - 'system_send_email_action' => array( - 'description' => t('Send e-mail'), - 'type' => 'system', - 'configurable' => TRUE, - 'hooks' => array( - 'nodeapi' => array('view', 'insert', 'update', 'delete'), - 'comment' => array('view', 'insert', 'update', 'delete'), - 'user' => array('view', 'insert', 'update', 'delete', 'login'), - 'taxonomy' => array('insert', 'update', 'delete'), - ) - ), - 'system_block_ip_action' => array( - 'description' => t('Ban IP address of current user'), - 'type' => 'user', - 'configurable' => FALSE, - 'hooks' => array(), - ), - 'system_goto_action' => array( - 'description' => t('Redirect to URL'), - 'type' => 'system', - 'configurable' => TRUE, - 'hooks' => array( - 'nodeapi' => array('view', 'insert', 'update', 'delete'), - 'comment' => array('view', 'insert', 'update', 'delete'), - 'user' => array('view', 'insert', 'update', 'delete', 'login'), - ) - ) - ); -} - -/** - * Menu callback. Display an overview of available and configured actions. - */ -function system_actions_manage() { - $output = ''; - $actions = actions_list(); - actions_synchronize($actions); - $actions_map = actions_actions_map($actions); - $options = array(t('Choose an advanced action')); - $unconfigurable = array(); - - foreach ($actions_map as $key => $array) { - if ($array['configurable']) { - $options[$key] = $array['description'] . '...'; - } - else { - $unconfigurable[] = $array; - } - } - - $row = array(); - $instances_present = db_fetch_object(db_query("SELECT aid FROM {actions} WHERE parameters != ''")); - $header = array( - array('data' => t('Action type'), 'field' => 'type'), - array('data' => t('Description'), 'field' => 'description'), - array('data' => $instances_present ? t('Operations') : '', 'colspan' => '2') - ); - $sql = 'SELECT * FROM {actions}'; - $result = pager_query($sql . tablesort_sql($header), 50); - while ($action = db_fetch_object($result)) { - $row[] = array( - array('data' => $action->type), - array('data' => $action->description), - array('data' => $action->parameters ? l(t('configure'), "admin/settings/actions/configure/$action->aid") : ''), - array('data' => $action->parameters ? l(t('delete'), "admin/settings/actions/delete/$action->aid") : '') - ); - } - - if ($row) { - $pager = theme('pager', NULL, 50, 0); - if (!empty($pager)) { - $row[] = array(array('data' => $pager, 'colspan' => '3')); - } - $output .= '

' . t('Actions available to Drupal:') . '

'; - $output .= theme('table', $header, $row); - } - - if ($actions_map) { - $output .= drupal_get_form('system_actions_manage_form', $options); - } - - return $output; -} - -/** - * Define the form for the actions overview page. - * - * @see system_actions_manage_form_submit() - * @ingroup forms - * @param $form_state - * An associative array containing the current state of the form; not used. - * @param $options - * An array of configurable actions. - * @return - * Form definition. - */ -function system_actions_manage_form($form_state, $options = array()) { - $form['parent'] = array( - '#type' => 'fieldset', - '#title' => t('Make a new advanced action available'), - '#prefix' => '
', - '#suffix' => '
', - ); - $form['parent']['action'] = array( - '#type' => 'select', - '#default_value' => '', - '#options' => $options, - '#description' => '', - ); - $form['parent']['buttons']['submit'] = array( - '#type' => 'submit', - '#value' => t('Create'), - ); - return $form; -} - -/** - * Process system_actions_manage form submissions. - */ -function system_actions_manage_form_submit($form, &$form_state) { - if ($form_state['values']['action']) { - $form_state['redirect'] = 'admin/settings/actions/configure/' . $form_state['values']['action']; - } -} - -/** - * Menu callback. Create the form for configuration of a single action. - * - * We provide the "Description" field. The rest of the form - * is provided by the action. We then provide the Save button. - * Because we are combining unknown form elements with the action - * configuration form, we use actions_ prefix on our elements. - * - * @see system_actions_configure_validate() - * @see system_actions_configure_submit() - * @param $action - * md5 hash of action ID or an integer. If it's an md5 hash, we - * are creating a new instance. If it's an integer, we're editing - * an existing instance. - * @return - * Form definition. - */ -function system_actions_configure($form_state, $action = NULL) { - if ($action === NULL) { - drupal_goto('admin/settings/actions'); - } - - $actions_map = actions_actions_map(actions_list()); - $edit = array(); - - // Numeric action denotes saved instance of a configurable action; - // else we are creating a new action instance. - if (is_numeric($action)) { - $aid = $action; - // Load stored parameter values from database. - $data = db_fetch_object(db_query("SELECT * FROM {actions} WHERE aid = %d", intval($aid))); - $edit['actions_description'] = $data->description; - $edit['actions_type'] = $data->type; - $function = $data->callback; - $action = md5($data->callback); - $params = unserialize($data->parameters); - if ($params) { - foreach ($params as $name => $val) { - $edit[$name] = $val; - } - } - } - else { - $function = $actions_map[$action]['callback']; - $edit['actions_description'] = $actions_map[$action]['description']; - $edit['actions_type'] = $actions_map[$action]['type']; - } - - $form['actions_description'] = array( - '#type' => 'textfield', - '#title' => t('Description'), - '#default_value' => $edit['actions_description'], - '#maxlength' => '255', - '#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.'), - '#weight' => -10 - ); - $action_form = $function . '_form'; - $form = array_merge($form, $action_form($edit)); - $form['actions_type'] = array( - '#type' => 'value', - '#value' => $edit['actions_type'], - ); - $form['actions_action'] = array( - '#type' => 'hidden', - '#value' => $action, - ); - // $aid is set when configuring an existing action instance. - if (isset($aid)) { - $form['actions_aid'] = array( - '#type' => 'hidden', - '#value' => $aid, - ); - } - $form['actions_configured'] = array( - '#type' => 'hidden', - '#value' => '1', - ); - $form['buttons']['submit'] = array( - '#type' => 'submit', - '#value' => t('Save'), - '#weight' => 13 - ); - - return $form; -} - -/** - * Validate system_actions_configure form submissions. - */ -function system_actions_configure_validate($form, $form_state) { - $function = actions_function_lookup($form_state['values']['actions_action']) . '_validate'; - // Hand off validation to the action. - if (function_exists($function)) { - $function($form, $form_state); - } -} - -/** - * Process system_actions_configure form submissions. - */ -function system_actions_configure_submit($form, &$form_state) { - $function = actions_function_lookup($form_state['values']['actions_action']); - $submit_function = $function . '_submit'; - - // Action will return keyed array of values to store. - $params = $submit_function($form, $form_state); - $aid = isset($form_state['values']['actions_aid']) ? $form_state['values']['actions_aid'] : NULL; - - actions_save($function, $form_state['values']['actions_type'], $params, $form_state['values']['actions_description'], $aid); - drupal_set_message(t('The action has been successfully saved.')); - - $form_state['redirect'] = 'admin/settings/actions/manage'; -} - -/** - * Create the form for confirmation of deleting an action. - * - * @ingroup forms - * @see system_actions_delete_form_submit() - */ -function system_actions_delete_form($form_state, $action) { - - $form['aid'] = array( - '#type' => 'hidden', - '#value' => $action->aid, - ); - return confirm_form($form, - t('Are you sure you want to delete the action %action?', array('%action' => $action->description)), - 'admin/settings/actions/manage', - t('This cannot be undone.'), - t('Delete'), t('Cancel') - ); -} - -/** - * Process system_actions_delete form submissions. - * - * Post-deletion operations for action deletion. - */ -function system_actions_delete_form_submit($form, &$form_state) { - $aid = $form_state['values']['aid']; - $action = actions_load($aid); - actions_delete($aid); - $description = check_plain($action->description); - watchdog('user', 'Deleted action %aid (%action)', array('%aid' => $aid, '%action' => $description)); - drupal_set_message(t('Action %action was deleted', array('%action' => $description))); - $form_state['redirect'] = 'admin/settings/actions/manage'; -} - -/** - * Post-deletion operations for deleting action orphans. - * - * @param $orphaned - * An array of orphaned actions. - */ -function system_action_delete_orphans_post($orphaned) { - foreach ($orphaned as $callback) { - drupal_set_message(t("Deleted orphaned action (%action).", array('%action' => $callback))); - } -} - -/** - * Remove actions that are in the database but not supported by any enabled module. - */ -function system_actions_remove_orphans() { - actions_synchronize(actions_list(), TRUE); - drupal_goto('admin/settings/actions/manage'); -} - -/** - * Return a form definition so the Send email action can be configured. - * - * @see system_send_email_action_validate() - * @see system_send_email_action_submit() - * @param $context - * Default values (if we are editing an existing action instance). - * @return - * Form definition. - */ -function system_send_email_action_form($context) { - // Set default values for form. - if (!isset($context['recipient'])) { - $context['recipient'] = ''; - } - if (!isset($context['subject'])) { - $context['subject'] = ''; - } - if (!isset($context['message'])) { - $context['message'] = ''; - } - - $form['recipient'] = array( - '#type' => 'textfield', - '#title' => t('Recipient'), - '#default_value' => $context['recipient'], - '#maxlength' => '254', - '#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')), - ); - $form['subject'] = array( - '#type' => 'textfield', - '#title' => t('Subject'), - '#default_value' => $context['subject'], - '#maxlength' => '254', - '#description' => t('The subject of the message.'), - ); - $form['message'] = array( - '#type' => 'textarea', - '#title' => t('Message'), - '#default_value' => $context['message'], - '#cols' => '80', - '#rows' => '20', - '#description' => t('The message that should be sent. You may include the following variables: %site_name, %username, %node_url, %node_type, %title, %teaser, %body. Not all variables will be available in all contexts.'), - ); - return $form; -} - -/** - * Validate system_send_email_action form submissions. - */ -function system_send_email_action_validate($form, $form_state) { - $form_values = $form_state['values']; - // Validate the configuration form. - if (!valid_email_address($form_values['recipient']) && $form_values['recipient'] != '%author') { - // We want the literal %author placeholder to be emphasized in the error message. - form_set_error('recipient', t('Please enter a valid email address or %author.', array('%author' => '%author'))); - } -} - -/** - * Process system_send_email_action form submissions. - */ -function system_send_email_action_submit($form, $form_state) { - $form_values = $form_state['values']; - // Process the HTML form to store configuration. The keyed array that - // we return will be serialized to the database. - $params = array( - 'recipient' => $form_values['recipient'], - 'subject' => $form_values['subject'], - 'message' => $form_values['message'], - ); - return $params; -} - -/** - * Implementation of a configurable Drupal action. Sends an email. - */ -function system_send_email_action($object, $context) { - global $user; - - switch ($context['hook']) { - case 'nodeapi': - // Because this is not an action of type 'node' the node - // will not be passed as $object, but it will still be available - // in $context. - $node = $context['node']; - break; - // The comment hook provides nid, in $context. - case 'comment': - $comment = $context['comment']; - $node = node_load($comment->nid); - break; - case 'user': - // Because this is not an action of type 'user' the user - // object is not passed as $object, but it will still be available - // in $context. - $account = $context['account']; - if (isset($context['node'])) { - $node = $context['node']; - } - elseif ($context['recipient'] == '%author') { - // If we don't have a node, we don't have a node author. - watchdog('error', 'Cannot use %author token in this context.'); - return; - } - break; - default: - // We are being called directly. - $node = $object; - } - - $recipient = $context['recipient']; - - if (isset($node)) { - if (!isset($account)) { - $account = user_load(array('uid' => $node->uid)); - } - if ($recipient == '%author') { - $recipient = $account->mail; - } - } - - if (!isset($account)) { - $account = $user; - - } - $language = user_preferred_language($account); - $params = array('account' => $account, 'object' => $object, 'context' => $context); - if (isset($node)) { - $params['node'] = $node; - } - - if (drupal_mail('system', 'action_send_email', $recipient, $language, $params)) { - watchdog('action', 'Sent email to %recipient', array('%recipient' => $recipient)); - } - else { - watchdog('error', 'Unable to send email to %recipient', array('%recipient' => $recipient)); - } -} - -/** * Implementation of hook_mail(). */ function system_mail($key, &$message, $params) { @@ -1928,91 +875,6 @@ function system_message_action_form($con return $form; } -function system_message_action_submit($form, $form_state) { - return array('message' => $form_state['values']['message']); -} - -/** - * A configurable Drupal action. Sends a message to the current user's screen. - */ -function system_message_action(&$object, $context = array()) { - global $user; - $variables = array( - '%site_name' => variable_get('site_name', 'Drupal'), - '%username' => $user->name ? $user->name : variable_get('anonymous', t('Anonymous')), - ); - - // This action can be called in any context, but if placeholders - // are used a node object must be present to be the source - // of substituted text. - switch ($context['hook']) { - case 'nodeapi': - // Because this is not an action of type 'node' the node - // will not be passed as $object, but it will still be available - // in $context. - $node = $context['node']; - break; - // The comment hook also provides the node, in context. - case 'comment': - $comment = $context['comment']; - $node = node_load($comment->nid); - break; - case 'taxonomy': - $vocabulary = taxonomy_vocabulary_load($object->vid); - $variables = array_merge($variables, array( - '%term_name' => $object->name, - '%term_description' => $object->description, - '%term_id' => $object->tid, - '%vocabulary_name' => $vocabulary->name, - '%vocabulary_description' => $vocabulary->description, - '%vocabulary_id' => $vocabulary->vid, - ) - ); - break; - default: - // We are being called directly. - $node = $object; - } - - if (isset($node) && is_object($node)) { - $variables = array_merge($variables, array( - '%uid' => $node->uid, - '%node_url' => url('node/' . $node->nid, array('absolute' => TRUE)), - '%node_type' => check_plain(node_get_types('name', $node)), - '%title' => filter_xss($node->title), - '%teaser' => filter_xss($node->teaser), - '%body' => filter_xss($node->body), - ) - ); - } - $context['message'] = strtr($context['message'], $variables); - drupal_set_message($context['message']); -} - -/** - * Implementation of a configurable Drupal action. Redirect user to a URL. - */ -function system_goto_action_form($context) { - $form['url'] = array( - '#type' => 'textfield', - '#title' => t('URL'), - '#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.'), - '#default_value' => isset($context['url']) ? $context['url'] : '', - '#required' => TRUE, - ); - return $form; -} - -function system_goto_action_submit($form, $form_state) { - return array( - 'url' => $form_state['values']['url'] - ); -} - -function system_goto_action($object, $context) { - drupal_goto($context['url']); -} - /** * Implementation of a Drupal action. * Blocks the user's IP address. === modified file 'modules/taxonomy/taxonomy.info' --- modules/taxonomy/taxonomy.info 2008-05-06 12:18:44 +0000 +++ modules/taxonomy/taxonomy.info 2008-07-26 08:29:08 +0000 @@ -7,3 +7,4 @@ core = 7.x files[] = taxonomy.module files[] = taxonomy.admin.inc files[] = taxonomy.pages.inc +files[] = taxonomy.install === modified file 'modules/trigger/trigger.info' --- modules/trigger/trigger.info 2008-05-06 12:18:44 +0000 +++ modules/trigger/trigger.info 2008-07-26 08:29:08 +0000 @@ -6,3 +6,4 @@ version = VERSION core = 7.x files[] = trigger.module files[] = trigger.admin.inc +files[] = trigger.install === modified file 'modules/trigger/trigger.install' --- modules/trigger/trigger.install 2007-12-28 12:02:49 +0000 +++ modules/trigger/trigger.install 2008-07-26 08:29:08 +0000 @@ -7,9 +7,9 @@ function trigger_install() { // Create tables. drupal_install_schema('trigger'); - - // Do initial synchronization of actions in code and the database. - actions_synchronize(actions_list()); + // Initial synchronization of actions in code and the database needs to be + // done once all modules are installed. install.php and + // drupal_web_test_case.php and system_modules does so. } /** === modified file 'modules/update/update.compare.inc' --- modules/update/update.compare.inc 2008-04-14 17:48:33 +0000 +++ modules/update/update.compare.inc 2008-07-27 20:58:06 +0000 @@ -28,7 +28,7 @@ function update_get_projects() { if (empty($projects)) { // Still empty, so we have to rebuild the cache. _update_process_info_list($projects, module_rebuild_cache(), 'module'); - _update_process_info_list($projects, system_theme_data(), 'theme'); + _update_process_info_list($projects, module_invoke('system', 'theme_data'), 'theme'); // Set the projects array into the cache table. cache_set('update_project_projects', $projects, 'cache_update', time() + 3600); } === modified file 'modules/update/update.info' --- modules/update/update.info 2008-05-06 12:18:44 +0000 +++ modules/update/update.info 2008-07-26 08:29:08 +0000 @@ -9,3 +9,4 @@ files[] = update.compare.inc files[] = update.fetch.inc files[] = update.report.inc files[] = update.settings.inc +files[] = update.install === modified file 'modules/upload/upload.info' --- modules/upload/upload.info 2008-05-06 12:18:44 +0000 +++ modules/upload/upload.info 2008-07-26 08:29:08 +0000 @@ -6,3 +6,4 @@ version = VERSION core = 7.x files[] = upload.module files[] = upload.admin.inc +files[] = upload.install === modified file 'modules/user/user.admin.inc' --- modules/user/user.admin.inc 2008-07-24 16:28:52 +0000 +++ modules/user/user.admin.inc 2008-07-27 20:03:50 +0000 @@ -201,7 +201,7 @@ function user_admin_account_submit($form $operation = $operations[$form_state['values']['operation']]; // Filter out unchecked accounts. $accounts = array_filter($form_state['values']['accounts']); - if ($function = $operation['callback']) { + if (($function = $operation['callback']) && drupal_function_exists($function)) { // Add in callback arguments if present. if (isset($operation['callback arguments'])) { $args = array_merge(array($accounts), $operation['callback arguments']); @@ -222,6 +222,93 @@ function user_admin_account_validate($fo } } + +/** + * Callback function for admin mass unblocking users. + */ +function user_user_operations_unblock($accounts) { + foreach ($accounts as $uid) { + $account = user_load(array('uid' => (int)$uid)); + // Skip unblocking user if they are already unblocked. + if ($account !== FALSE && $account->status == 0) { + user_save($account, array('status' => 1)); + } + } +} + +/** + * Callback function for admin mass blocking users. + */ +function user_user_operations_block($accounts) { + foreach ($accounts as $uid) { + $account = user_load(array('uid' => (int)$uid)); + // Skip blocking user if they are already blocked. + if ($account !== FALSE && $account->status == 1) { + user_save($account, array('status' => 0)); + } + } +} + +/** + * Callback function for admin mass adding/deleting a user role. + */ +function user_multiple_role_edit($accounts, $operation, $rid) { + // The role name is not necessary as user_save() will reload the user + // object, but some modules' hook_user() may look at this first. + $role_name = db_result(db_query('SELECT name FROM {role} WHERE rid = %d', $rid)); + + switch ($operation) { + case 'add_role': + foreach ($accounts as $uid) { + $account = user_load(array('uid' => (int)$uid)); + // Skip adding the role to the user if they already have it. + if ($account !== FALSE && !isset($account->roles[$rid])) { + $roles = $account->roles + array($rid => $role_name); + user_save($account, array('roles' => $roles)); + } + } + break; + case 'remove_role': + foreach ($accounts as $uid) { + $account = user_load(array('uid' => (int)$uid)); + // Skip removing the role from the user if they already don't have it. + if ($account !== FALSE && isset($account->roles[$rid])) { + $roles = array_diff($account->roles, array($rid => $role_name)); + user_save($account, array('roles' => $roles)); + } + } + break; + } +} + +function user_multiple_delete_confirm(&$form_state) { + $edit = $form_state['post']; + + $form['accounts'] = array('#prefix' => '', '#tree' => TRUE); + // array_filter() returns only elements with TRUE values. + foreach (array_filter($edit['accounts']) as $uid => $value) { + $user = db_result(db_query('SELECT name FROM {users} WHERE uid = %d', $uid)); + $form['accounts'][$uid] = array('#type' => 'hidden', '#value' => $uid, '#prefix' => '
  • ', '#suffix' => check_plain($user) . "
  • \n"); + } + $form['operation'] = array('#type' => 'hidden', '#value' => 'delete'); + + return confirm_form($form, + t('Are you sure you want to delete these users?'), + 'admin/user/user', t('This action cannot be undone.'), + t('Delete all'), t('Cancel')); +} + +function user_multiple_delete_confirm_submit($form, &$form_state) { + if ($form_state['values']['confirm']) { + foreach ($form_state['values']['accounts'] as $uid => $value) { + user_delete($form_state['values'], $uid); + } + drupal_set_message(t('The users have been deleted.')); + } + $form_state['redirect'] = 'admin/user/user'; + return; +} + /** * Form builder; Configure user settings for this site. * === added file 'modules/user/user.build.inc' --- modules/user/user.build.inc 1970-01-01 00:00:00 +0000 +++ modules/user/user.build.inc 2008-07-27 20:01:06 +0000 @@ -0,0 +1,244 @@ + array( + 'arguments' => array('account' => NULL), + 'template' => 'user-picture', + ), + 'user_profile' => array( + 'arguments' => array('account' => NULL), + 'template' => 'user-profile', + 'file' => 'user.pages.inc', + ), + 'user_profile_category' => array( + 'arguments' => array('element' => NULL), + 'template' => 'user-profile-category', + 'file' => 'user.pages.inc', + ), + 'user_profile_item' => array( + 'arguments' => array('element' => NULL), + 'template' => 'user-profile-item', + 'file' => 'user.pages.inc', + ), + 'user_list' => array( + 'arguments' => array('users' => NULL, 'title' => NULL), + ), + 'user_admin_perm' => array( + 'arguments' => array('form' => NULL), + 'file' => 'user.admin.inc', + ), + 'user_admin_new_role' => array( + 'arguments' => array('form' => NULL), + 'file' => 'user.admin.inc', + ), + 'user_admin_account' => array( + 'arguments' => array('form' => NULL), + 'file' => 'user.admin.inc', + ), + 'user_filter_form' => array( + 'arguments' => array('form' => NULL), + 'file' => 'user.admin.inc', + ), + 'user_filters' => array( + 'arguments' => array('form' => NULL), + 'file' => 'user.admin.inc', + ), + 'user_signature' => array( + 'arguments' => array('signature' => NULL), + ), + ); +} + +/** + * Implementation of hook_menu(). + */ +function user_menu() { + $items['user/autocomplete'] = array( + 'title' => 'User autocomplete', + 'page callback' => 'user_autocomplete', + 'access callback' => 'user_access', + 'access arguments' => array('access user profiles'), + 'type' => MENU_CALLBACK, + ); + + // Registration and login pages. + $items['user'] = array( + 'title' => 'User account', + 'page callback' => 'user_page', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + + $items['user/login'] = array( + 'title' => 'Log in', + 'access callback' => 'user_is_anonymous', + 'type' => MENU_DEFAULT_LOCAL_TASK, + ); + + $items['user/register'] = array( + 'title' => 'Create new account', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('user_register'), + 'access callback' => 'user_register_access', + 'type' => MENU_LOCAL_TASK, + ); + + $items['user/password'] = array( + 'title' => 'Request new password', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('user_pass'), + 'access callback' => 'user_is_anonymous', + 'type' => MENU_LOCAL_TASK, + ); + $items['user/reset/%/%/%'] = array( + 'title' => 'Reset password', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('user_pass_reset', 2, 3, 4), + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + + // User administration pages. + $items['admin/user'] = array( + 'title' => 'User management', + 'description' => "Manage your site's users, groups and access to site features.", + 'position' => 'left', + 'page callback' => 'system_admin_menu_block_page', + 'access arguments' => array('access administration pages'), + ); + $items['admin/user/user'] = array( + 'title' => 'Users', + 'description' => 'List, add, and edit users.', + 'page callback' => 'user_admin', + 'page arguments' => array('list'), + 'access arguments' => array('administer users'), + ); + $items['admin/user/user/list'] = array( + 'title' => 'List', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => -10, + ); + $items['admin/user/user/create'] = array( + 'title' => 'Add user', + 'page arguments' => array('create'), + 'access arguments' => array('administer users'), + 'type' => MENU_LOCAL_TASK, + ); + $items['admin/user/settings'] = array( + 'title' => 'User settings', + 'description' => 'Configure default behavior of users, including registration requirements, e-mails, and user pictures.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('user_admin_settings'), + 'access arguments' => array('administer users'), + ); + + // Permission administration pages. + $items['admin/user/permissions'] = array( + 'title' => 'Permissions', + 'description' => 'Determine access to features by selecting permissions for roles.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('user_admin_perm'), + 'access arguments' => array('administer permissions'), + ); + $items['admin/user/roles'] = array( + 'title' => 'Roles', + 'description' => 'List, edit, or add user roles.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('user_admin_new_role'), + 'access arguments' => array('administer permissions'), + ); + $items['admin/user/roles/edit'] = array( + 'title' => 'Edit role', + 'page arguments' => array('user_admin_role'), + 'access arguments' => array('administer permissions'), + 'type' => MENU_CALLBACK, + ); + + $items['logout'] = array( + 'title' => 'Log out', + 'access callback' => 'user_is_logged_in', + 'page callback' => 'user_logout', + 'weight' => 10, + ); + + $items['user/%user_uid_optional'] = array( + 'title' => 'My account', + 'title callback' => 'user_page_title', + 'title arguments' => array(1), + 'page callback' => 'user_view', + 'page arguments' => array(1), + 'access callback' => 'user_view_access', + 'access arguments' => array(1), + 'parent' => '', + ); + + $items['user/%user/view'] = array( + 'title' => 'View', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => -10, + ); + + $items['user/%user/delete'] = array( + 'title' => 'Delete', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('user_confirm_delete', 1), + 'access callback' => 'user_access', + 'access arguments' => array('administer users'), + 'type' => MENU_CALLBACK, + ); + + $items['user/%user_category/edit'] = array( + 'title' => 'Edit', + 'page callback' => 'user_edit', + 'page arguments' => array(1), + 'access callback' => 'user_edit_access', + 'access arguments' => array(1), + 'type' => MENU_LOCAL_TASK, + 'load arguments' => array('%map', '%index'), + ); + + $items['user/%user_category/edit/account'] = array( + 'title' => 'Account', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'load arguments' => array('%map', '%index'), + ); + + $empty_account = new stdClass(); + if (($categories = _user_categories($empty_account)) && (count($categories) > 1)) { + foreach ($categories as $key => $category) { + // 'account' is already handled by the MENU_DEFAULT_LOCAL_TASK. + if ($category['name'] != 'account') { + $items['user/%user_category/edit/' . $category['name']] = array( + 'title callback' => 'check_plain', + 'title arguments' => array($category['title']), + 'page callback' => 'user_edit', + 'page arguments' => array(1, 3), + 'access callback' => isset($category['access callback']) ? $category['access callback'] : 'user_edit_access', + 'access arguments' => isset($category['access arguments']) ? $category['access arguments'] : array(1), + 'type' => MENU_LOCAL_TASK, + 'weight' => $category['weight'], + 'load arguments' => array('%map', '%index'), + 'tab_parent' => 'user/%/edit', + ); + } + } + } + return $items; +} + +/** + * Implementation of hook_perm(). + */ +function user_perm() { + return array( + 'administer permissions' => t('Manage the permissions assigned to user roles. %warning', array('%warning' => t('Warning: Give to trusted roles only; this permission has security implications.'))), + 'administer users' => t('Manage or block users, and manage their role assignments.'), + 'access user profiles' => t('View profiles of users on the site, which may contain personal information.'), + 'change own username' => t('Select a different username.'), + ); +} + === modified file 'modules/user/user.info' --- modules/user/user.info 2008-05-06 12:18:44 +0000 +++ modules/user/user.info 2008-07-27 20:04:09 +0000 @@ -7,3 +7,5 @@ core = 7.x files[] = user.module files[] = user.admin.inc files[] = user.pages.inc +files[] = user.build.inc +files[] = user.install === modified file 'modules/user/user.module' --- modules/user/user.module 2008-07-16 21:59:24 +0000 +++ modules/user/user.module 2008-07-27 20:03:15 +0000 @@ -23,67 +23,12 @@ define('EMAIL_MAX_LENGTH', 64); * be passed by reference. */ function user_module_invoke($type, &$array, &$user, $category = NULL) { - foreach (module_list() as $module) { + foreach (module_implements('user') as $module) { $function = $module . '_user'; - if (function_exists($function)) { - $function($type, $array, $user, $category); - } + $function($type, $array, $user, $category); } } -/** - * Implementation of hook_theme(). - */ -function user_theme() { - return array( - 'user_picture' => array( - 'arguments' => array('account' => NULL), - 'template' => 'user-picture', - ), - 'user_profile' => array( - 'arguments' => array('account' => NULL), - 'template' => 'user-profile', - 'file' => 'user.pages.inc', - ), - 'user_profile_category' => array( - 'arguments' => array('element' => NULL), - 'template' => 'user-profile-category', - 'file' => 'user.pages.inc', - ), - 'user_profile_item' => array( - 'arguments' => array('element' => NULL), - 'template' => 'user-profile-item', - 'file' => 'user.pages.inc', - ), - 'user_list' => array( - 'arguments' => array('users' => NULL, 'title' => NULL), - ), - 'user_admin_perm' => array( - 'arguments' => array('form' => NULL), - 'file' => 'user.admin.inc', - ), - 'user_admin_new_role' => array( - 'arguments' => array('form' => NULL), - 'file' => 'user.admin.inc', - ), - 'user_admin_account' => array( - 'arguments' => array('form' => NULL), - 'file' => 'user.admin.inc', - ), - 'user_filter_form' => array( - 'arguments' => array('form' => NULL), - 'file' => 'user.admin.inc', - ), - 'user_filters' => array( - 'arguments' => array('form' => NULL), - 'file' => 'user.admin.inc', - ), - 'user_signature' => array( - 'arguments' => array('signature' => NULL), - ), - ); -} - function user_external_load($authname) { $result = db_query("SELECT uid FROM {authmap} WHERE authname = '%s'", $authname); @@ -567,18 +512,6 @@ function user_is_blocked($name) { } /** - * Implementation of hook_perm(). - */ -function user_perm() { - return array( - 'administer permissions' => t('Manage the permissions assigned to user roles. %warning', array('%warning' => t('Warning: Give to trusted roles only; this permission has security implications.'))), - 'administer users' => t('Manage or block users, and manage their role assignments.'), - 'access user profiles' => t('View profiles of users on the site, which may contain personal information.'), - 'change own username' => t('Select a different username.'), - ); -} - -/** * Implementation of hook_file_download(). * * Ensure that user pictures (avatars) are always downloadable. @@ -913,183 +846,6 @@ function user_load_self($arg) { return $arg; } -/** - * Implementation of hook_menu(). - */ -function user_menu() { - $items['user/autocomplete'] = array( - 'title' => 'User autocomplete', - 'page callback' => 'user_autocomplete', - 'access callback' => 'user_access', - 'access arguments' => array('access user profiles'), - 'type' => MENU_CALLBACK, - ); - - // Registration and login pages. - $items['user'] = array( - 'title' => 'User account', - 'page callback' => 'user_page', - 'access callback' => TRUE, - 'type' => MENU_CALLBACK, - ); - - $items['user/login'] = array( - 'title' => 'Log in', - 'access callback' => 'user_is_anonymous', - 'type' => MENU_DEFAULT_LOCAL_TASK, - ); - - $items['user/register'] = array( - 'title' => 'Create new account', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('user_register'), - 'access callback' => 'user_register_access', - 'type' => MENU_LOCAL_TASK, - ); - - $items['user/password'] = array( - 'title' => 'Request new password', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('user_pass'), - 'access callback' => 'user_is_anonymous', - 'type' => MENU_LOCAL_TASK, - ); - $items['user/reset/%/%/%'] = array( - 'title' => 'Reset password', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('user_pass_reset', 2, 3, 4), - 'access callback' => TRUE, - 'type' => MENU_CALLBACK, - ); - - // User administration pages. - $items['admin/user'] = array( - 'title' => 'User management', - 'description' => "Manage your site's users, groups and access to site features.", - 'position' => 'left', - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access administration pages'), - ); - $items['admin/user/user'] = array( - 'title' => 'Users', - 'description' => 'List, add, and edit users.', - 'page callback' => 'user_admin', - 'page arguments' => array('list'), - 'access arguments' => array('administer users'), - ); - $items['admin/user/user/list'] = array( - 'title' => 'List', - 'type' => MENU_DEFAULT_LOCAL_TASK, - 'weight' => -10, - ); - $items['admin/user/user/create'] = array( - 'title' => 'Add user', - 'page arguments' => array('create'), - 'access arguments' => array('administer users'), - 'type' => MENU_LOCAL_TASK, - ); - $items['admin/user/settings'] = array( - 'title' => 'User settings', - 'description' => 'Configure default behavior of users, including registration requirements, e-mails, and user pictures.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('user_admin_settings'), - 'access arguments' => array('administer users'), - ); - - // Permission administration pages. - $items['admin/user/permissions'] = array( - 'title' => 'Permissions', - 'description' => 'Determine access to features by selecting permissions for roles.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('user_admin_perm'), - 'access arguments' => array('administer permissions'), - ); - $items['admin/user/roles'] = array( - 'title' => 'Roles', - 'description' => 'List, edit, or add user roles.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('user_admin_new_role'), - 'access arguments' => array('administer permissions'), - ); - $items['admin/user/roles/edit'] = array( - 'title' => 'Edit role', - 'page arguments' => array('user_admin_role'), - 'access arguments' => array('administer permissions'), - 'type' => MENU_CALLBACK, - ); - - $items['logout'] = array( - 'title' => 'Log out', - 'access callback' => 'user_is_logged_in', - 'page callback' => 'user_logout', - 'weight' => 10, - ); - - $items['user/%user_uid_optional'] = array( - 'title' => 'My account', - 'title callback' => 'user_page_title', - 'title arguments' => array(1), - 'page callback' => 'user_view', - 'page arguments' => array(1), - 'access callback' => 'user_view_access', - 'access arguments' => array(1), - 'parent' => '', - ); - - $items['user/%user/view'] = array( - 'title' => 'View', - 'type' => MENU_DEFAULT_LOCAL_TASK, - 'weight' => -10, - ); - - $items['user/%user/delete'] = array( - 'title' => 'Delete', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('user_confirm_delete', 1), - 'access callback' => 'user_access', - 'access arguments' => array('administer users'), - 'type' => MENU_CALLBACK, - ); - - $items['user/%user_category/edit'] = array( - 'title' => 'Edit', - 'page callback' => 'user_edit', - 'page arguments' => array(1), - 'access callback' => 'user_edit_access', - 'access arguments' => array(1), - 'type' => MENU_LOCAL_TASK, - 'load arguments' => array('%map', '%index'), - ); - - $items['user/%user_category/edit/account'] = array( - 'title' => 'Account', - 'type' => MENU_DEFAULT_LOCAL_TASK, - 'load arguments' => array('%map', '%index'), - ); - - $empty_account = new stdClass(); - if (($categories = _user_categories($empty_account)) && (count($categories) > 1)) { - foreach ($categories as $key => $category) { - // 'account' is already handled by the MENU_DEFAULT_LOCAL_TASK. - if ($category['name'] != 'account') { - $items['user/%user_category/edit/' . $category['name']] = array( - 'title callback' => 'check_plain', - 'title arguments' => array($category['title']), - 'page callback' => 'user_edit', - 'page arguments' => array(1, 3), - 'access callback' => isset($category['access callback']) ? $category['access callback'] : 'user_edit_access', - 'access arguments' => isset($category['access arguments']) ? $category['access arguments'] : array(1), - 'type' => MENU_LOCAL_TASK, - 'weight' => $category['weight'], - 'load arguments' => array('%map', '%index'), - 'tab_parent' => 'user/%/edit', - ); - } - } - } - return $items; -} - function user_init() { drupal_add_css(drupal_get_path('module', 'user') . '/user.css', 'module'); } @@ -1757,92 +1513,6 @@ function user_user_operations($form_stat } /** - * Callback function for admin mass unblocking users. - */ -function user_user_operations_unblock($accounts) { - foreach ($accounts as $uid) { - $account = user_load(array('uid' => (int)$uid)); - // Skip unblocking user if they are already unblocked. - if ($account !== FALSE && $account->status == 0) { - user_save($account, array('status' => 1)); - } - } -} - -/** - * Callback function for admin mass blocking users. - */ -function user_user_operations_block($accounts) { - foreach ($accounts as $uid) { - $account = user_load(array('uid' => (int)$uid)); - // Skip blocking user if they are already blocked. - if ($account !== FALSE && $account->status == 1) { - user_save($account, array('status' => 0)); - } - } -} - -/** - * Callback function for admin mass adding/deleting a user role. - */ -function user_multiple_role_edit($accounts, $operation, $rid) { - // The role name is not necessary as user_save() will reload the user - // object, but some modules' hook_user() may look at this first. - $role_name = db_result(db_query('SELECT name FROM {role} WHERE rid = %d', $rid)); - - switch ($operation) { - case 'add_role': - foreach ($accounts as $uid) { - $account = user_load(array('uid' => (int)$uid)); - // Skip adding the role to the user if they already have it. - if ($account !== FALSE && !isset($account->roles[$rid])) { - $roles = $account->roles + array($rid => $role_name); - user_save($account, array('roles' => $roles)); - } - } - break; - case 'remove_role': - foreach ($accounts as $uid) { - $account = user_load(array('uid' => (int)$uid)); - // Skip removing the role from the user if they already don't have it. - if ($account !== FALSE && isset($account->roles[$rid])) { - $roles = array_diff($account->roles, array($rid => $role_name)); - user_save($account, array('roles' => $roles)); - } - } - break; - } -} - -function user_multiple_delete_confirm(&$form_state) { - $edit = $form_state['post']; - - $form['accounts'] = array('#prefix' => '', '#tree' => TRUE); - // array_filter() returns only elements with TRUE values. - foreach (array_filter($edit['accounts']) as $uid => $value) { - $user = db_result(db_query('SELECT name FROM {users} WHERE uid = %d', $uid)); - $form['accounts'][$uid] = array('#type' => 'hidden', '#value' => $uid, '#prefix' => '
  • ', '#suffix' => check_plain($user) . "
  • \n"); - } - $form['operation'] = array('#type' => 'hidden', '#value' => 'delete'); - - return confirm_form($form, - t('Are you sure you want to delete these users?'), - 'admin/user/user', t('This action cannot be undone.'), - t('Delete all'), t('Cancel')); -} - -function user_multiple_delete_confirm_submit($form, &$form_state) { - if ($form_state['values']['confirm']) { - foreach ($form_state['values']['accounts'] as $uid => $value) { - user_delete($form_state['values'], $uid); - } - drupal_set_message(t('The users have been deleted.')); - } - $form_state['redirect'] = 'admin/user/user'; - return; -} - -/** * Implementation of hook_help(). */ function user_help($path, $arg) { === modified file 'profiles/default/default.profile' --- profiles/default/default.profile 2008-06-24 21:26:48 +0000 +++ profiles/default/default.profile 2008-07-26 08:29:08 +0000 @@ -126,6 +126,7 @@ function default_profile_tasks(&$task, $ // Default page to not be promoted and have comments disabled. variable_set('node_options_page', array('status')); + drupal_load('module', 'comment'); variable_set('comment_page', COMMENT_NODE_DISABLED); // Don't display date and author information for page nodes by default. === modified file 'scripts/run-tests.sh' --- scripts/run-tests.sh 2008-07-24 06:46:28 +0000 +++ scripts/run-tests.sh 2008-07-26 08:29:08 +0000 @@ -313,7 +313,7 @@ function simpletest_script_execute_batch * Run a single test (assume a Drupal bootstrapped environnement). */ function simpletest_script_run_one_test($test_id, $test_class) { - simpletest_get_all_tests(); + module_invoke('simpletest', 'get_all_tests'); $test = new $test_class($test_id); $test->run(); $info = $test->getInfo();