/** install the theme
 *
 * this routine performs the necessary actions to make this theme usable.
 * More specific, this routine adds a handfull of default values into the
 * themes_properties table. Once a theme is actually used in an area, these
 * defaults are copied from the themes_properties table to the
 * themes_areas_properties table for the selected area. The user can subsequently
 * edit these properties in the Area Manager.
 *
 * @param array &$messages collects the (error) messages
 * @param int $theme_id the key for this theme in the themes table
 * @return bool TRUE on success + output via $messages, FALSE otherwise
 */
function frugal_install(&$messages, $theme_id)
{
    $now = strftime('%Y-%m-%d %T');
    $properties = array(array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'quicktop_section_id', 'type' => 'i', 'value' => '0', 'sort_order' => 10, 'extra' => 'minvalue=0', 'description' => 'indicates which section to use for the quicklinks at the top of the page')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'quickbottom_section_id', 'type' => 'i', 'value' => '0', 'sort_order' => 20, 'extra' => 'minvalue=0', 'description' => 'indicates which section to use for the quicklinks at the bottom of the page')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'logo_image', 'type' => 's', 'value' => 'program/graphics/waslogo-284x71.png', 'sort_order' => 30, 'extra' => 'maxlength=255', 'description' => 'the URL of the logo file or a path relative to the directory holding index.php')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'logo_width', 'type' => 'i', 'value' => '284', 'sort_order' => 40, 'extra' => 'minvalue=0;maxvalue=2048', 'description' => 'the width of the logo in pixels')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'logo_height', 'type' => 'i', 'value' => '71', 'sort_order' => 50, 'extra' => 'minvalue=0;maxvalue=1536', 'description' => 'the height of the logo in pixels')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'show_breadcrumb_trail', 'type' => 'b', 'value' => '1', 'sort_order' => 60, 'description' => 'this enables/disables the display of the breadcrumb trail in the navigation')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'style_usage_static', 'type' => 'b', 'value' => '1', 'sort_order' => 70, 'extra' => '', 'description' => 'if TRUE this includes the static stylesheet')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'stylesheet', 'type' => 's', 'value' => 'program/styles/base.css', 'sort_order' => 80, 'extra' => 'maxlength=255', 'description' => 'the URL of the stylesheet or a path relative to the directory holding index.php')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'style_usage_area', 'type' => 'b', 'value' => '1', 'sort_order' => 90, 'extra' => '', 'description' => 'if TRUE this includes the additional style information')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'style', 'type' => 's', 'value' => "/* Demo of Bazaar Style Style sheets */\n" . "#content h1 {\n" . "  background-color: #FF33FF;\n" . "}\n", 'sort_order' => 100, 'extra' => 'maxlength=65535;rows=10;columns=70', 'description' => 'additional style information that will be processed AFTER the static stylesheet file')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'style_usage_node', 'type' => 'b', 'value' => '1', 'sort_order' => 110, 'extra' => '', 'description' => 'if TRUE this allows for addition style information from individual sections/pages')));
    $retval = TRUE;
    // assume success
    foreach ($properties as $property) {
        if (db_insert_into($property['table'], $property['fields']) === FALSE) {
            $messages[] = __FUNCTION__ . '(): ' . db_errormessage();
            $retval = FALSE;
        }
    }
    return $retval;
}
/** install the module
 *
 * this routine installs the module. For this module there
 * are a few properties that need to be stored in the main
 * modules_properties table.  The specific table for this module is
 * already  created based on the tabledefs); see install/crew_tabledefs.php.
 *
 * Note that the record for this module is already created in the
 * modules table; the pkey is $module_id.
 *
 * @param array &$messages collects the (error) messages
 * @param int $module_id the key for this module in the modules table
 * @return bool TRUE on success + output via $messages, FALSE otherwise
 */
function crew_install(&$messages, $module_id)
{
    $properties = array('origin' => array('type' => 's', 'value' => isset($_SERVER['HTTP_HOST']) ? 'http://' . $_SERVER['HTTP_HOST'] : '', 'extra' => 'maxlength=255', 'description' => 'this must match the origin as seen by the browser of the CREW-user'), 'location' => array('type' => 's', 'value' => '', 'extra' => 'maxlength=255', 'description' => 'this is the location (URL) of the websocket server'), 'secret' => array('type' => 's', 'value' => '', 'extra' => 'maxlength=255', 'description' => 'this shared secret is necessary to access the websocket server'));
    $retval = TRUE;
    // assume success
    $table = 'modules_properties';
    $sort_order = 0;
    foreach ($properties as $name => $property) {
        $property['module_id'] = $module_id;
        $property['name'] = $name;
        $sort_order += 10;
        $property['sort_order'] = $sort_order;
        if (db_insert_into($table, $property) === FALSE) {
            $messages[] = __FUNCTION__ . '(): ' . db_errormessage();
            $retval = FALSE;
        }
    }
    return $retval;
}
 /** attempt to lock all node records in a subtree
  *
  * this recursively walks the subtree starting at $node_id and attempts to
  *  - lock every node in the subtree, AND
  *  - write the new area_id in an auxiliary field of every node in the subtree
  *
  * With at least two trips to the database (at least one for the lock and
  * another one for writing the auxiliary field) per node, this is an expensive
  * routine. Maybe it is possible to combine locking and writing the auxiliary
  * field. However, in order to keep things readable I decided against that.
  *
  * This routine returns FALSE if any of the nodes in the subtree could NOT be
  * locked. If each and every node in the subtree is successfully locked, TRUE is
  * returned.
  *
  * Note that all these locks are reset/released the moment the actual move is
  * done, by resetting both the locked_by field and the area_id field. That may
  * hurt readability too, but less than combining lock + setting auxiliary field.
  * See {@link save_node_new_area_mass_move()} for more information.
  *
  * @param int $node_id the node which we are going to move to $new_area_id
  * @param int $new_area_id the area to which we want to move the subtree $node_id
  * @return bool FALSE on error, TRUE on success
  * @uses lock_records_subtree()
  */
 function lock_records_subtree($node_id, $new_area_id)
 {
     static $level = 0;
     $lockinfo = array();
     while ($node_id != 0) {
         $is_page = $this->tree[$node_id]['is_page'];
         if (!lock_record_node($node_id, $lockinfo)) {
             $msg = message_from_lockinfo($lockinfo, $node_id, $is_page);
             $this->output->add_message($msg);
             logger(__FUNCTION__ . "(): cannot lock node {$node_id} in subtree: {$msg}", WLOG_DEBUG);
             return FALSE;
         } elseif (db_update('nodes', array('auxiliary' => $new_area_id), array('node_id' => $node_id)) === FALSE) {
             logger(__FUNCTION__ . "(): cannot write new area_id {$new_area_id} to auxiliary field in node {$node_id}: " . db_errormessage(), WLOG_DEBUG);
             return FALSE;
         }
         if (!$is_page && $this->tree[$node_id]['first_child_id'] != 0) {
             if ($level >= MAXIMUM_ITERATIONS) {
                 $this->output->add_message(t('too_many_levels', 'admin', array('{NODE}' => strval($node_id))));
                 logger(__FUNCTION__ . '(): too many levels in node ' . $node_id, WLOG_DEBUG);
                 return FALSE;
             } else {
                 ++$level;
                 $retval = $this->lock_records_subtree($this->tree[$node_id]['first_child_id'], $new_area_id);
                 --$level;
                 if ($retval === FALSE) {
                     return FALSE;
                 }
             }
         }
         $node_id = $this->tree[$node_id]['next_sibling_id'];
     }
     return TRUE;
 }
Пример #4
0
/** retrieve the records of the groups of which user $user_id is a member
 *
 * @param int $user_id the user we're looking at
 * @return array 0, 1 or more acl_id => $group_record pairs
 * @uses $DB
 */
function get_user_groups($user_id)
{
    global $DB;
    $records = array();
    $sql = sprintf("SELECT g.* " . "FROM %sgroups g " . "INNER JOIN %susers_groups_capacities ugc " . "USING (group_id) " . "WHERE ugc.capacity_code <> 0 AND ugc.user_id = %d " . "ORDER BY g.groupname", $DB->prefix, $DB->prefix, $user_id);
    if (($DBResult = $DB->query($sql)) !== FALSE) {
        $records = $DBResult->fetch_all_assoc('group_id');
        $DBResult->close();
    } else {
        logger(sprintf("%s(): cannot retrieve groups for user '%d': %s", __FUNCTION__, $user_id, db_errormessage()));
    }
    return $records;
}
/** retrieve the current version of the document + other workshop data
 *
 * @param int $node_id which one are we looking at?
 * @return bool|array FALSE on error, array with record from db otherwise
 */
function crew_view_get_workshop_data($node_id)
{
    global $DB;
    $sql = sprintf('SELECT w.*, u.username, u.full_name ' . 'FROM %sworkshops w LEFT JOIN %susers u ON w.muser_id = u.user_id ' . 'WHERE node_id = %d', $DB->prefix, $DB->prefix, $node_id);
    if (($db_result = $DB->query($sql, 1)) === FALSE || $db_result->num_rows != 1) {
        logger(sprintf('%s(): workshop %d data error: %s', __FUNCTION__, $node_id, db_errormessage()));
        return FALSE;
    }
    $record = $db_result->fetch_row_assoc();
    $db_result->close();
    return $record;
}
/** add demonstration data to the system
 *
 * this routine adds demonstration data to the freshly installed system
 *
 * Note
 * If the theme is installed via the Install Wizard, this routine is
 * called. However, if a theme is installed as an additional theme
 * after installation, the {$theme}_demodata() routine is never called.
 * This is because the only time you know that demodata is installed is
 * when the Install Wizard runs. If we're called from admin.php, the
 * webmaster may have already deleted existing (core) demodata so you
 * never can be sure what to expect. To put it another way: it is hard
 * to re-construct $config when we're NOT the Instal Wizard.
 *
 * The array $config contains the following information.
 *
 * <code>
 * $config['language_key']   => install language code (eg. 'en')
 * $config['dir']            => path to CMS Root Directory (eg. /home/httpd/htdocs)
 * $config['www']            => URL of CMS Root Directory (eg. http://exemplum.eu)
 * $config['progdir']        => path to program directory (eg. /home/httpd/htdocs/program)
 * $config['progwww']        => URL of program directory (eg. http://exemplum.eu/program)
 * $config['datadir']        => path to data directory (eg. /home/httpd/wasdata/a1b2c3d4e5f6)
 * $config['title']          => the name of the site (as entered by Wilhelmina Bladergroen)
 * $config['user_username']  => userid of webmaster (eg. wblader)
 * $config['user_full_name'] => full name of webmaster (eg. Wilhelmina Bladergroen)
 * $config['user_email']     => email of webmaster (eg. w.bladergroen@exemplum.eu)
 * $config['user_id']        => numerical user_id (usually 1)
 * $config['demo_salt']      => password salt for all demodata accounts
 * $config['demo_password']  => password for all demodata accounts
 * $config['demo_areas']     => array with demo area data
 * $config['demo_groups']    => array with demo group data
 * $config['demo_users']     => array with demo user data
 * $config['demo_nodes']     => array with demo node data
 * $config['demo_string']    => array with demo strings from /program/install/languages/LL/demodata.php
 * $config['demo_replace']   => array with search/replace pairs to 'jazz up' the demo strings
 * </code>
 *
 * With this information, we can add a demonstration configuration for the public area,
 * which shows off the possibilities.
 *
 * @param array &$messages collects the (error) messages
 * @param int $theme_id the key for this theme in the themes table
 * @param array $config pertinent data for the new website + demodata foundation
 * @param array $manifest a copy from the manifest for this theme
 * @return bool TRUE on success + output via $messages, FALSE otherwise
 */
function sophia_demodata(&$messages, $theme_id, $config, $manifest)
{
    global $DB;
    $retval = TRUE;
    // assume success
    // 1A -- prepare for setting up demo settings
    $quicktop_section_id = intval($config['demo_nodes']['quicktop']['node_id']);
    $quickbottom_section_id = intval($config['demo_nodes']['quickbottom']['node_id']);
    $progwww = $config['progwww'];
    $slogan = $config['demo_string']['welcome_title'];
    $area_id = intval($config['demo_areas']['public']['area_id']);
    $theme_id = intval($theme_id);
    $theme_name = $manifest['name'];
    $aboutus = $config['demo_string']['aboutus_content'];
    $email = $config['replyto'];
    // 1B -- actually construct settings
    $settings = array('quicktop_section_id' => strval($quicktop_section_id), 'quickbottom_section_id' => strval($quickbottom_section_id), 'style' => sprintf("#navigation ul li { background-image:  url('%s/themes/%s/stencil0.png'); }\n" . "#navigation ul li.navigation_button5 { background-color: #FF3399; }\n", $progwww, $theme_name), 'header_text' => $slogan, 'left_top_html' => sprintf("<img src=\"%s/themes/%s/calendula.jpg\" width=\"120\" height=\"90\" alt=\"\">\n", $progwww, $theme_name), 'left_bottom_html' => sprintf("<div style=\"margin-bottom: 30px;\">\n%s\n</div>\n", $aboutus), 'footer_text' => sprintf('<b><a href="mailto:%s">%s</a></b>', $email, $email));
    // 2A -- start with the default settings (copy from theme_properties)
    $sql = sprintf('INSERT INTO %s%s(area_id,theme_id,name,type,value,extra,sort_order,description) ' . 'SELECT %d AS area_id,theme_id,name,type,value,extra,sort_order,description ' . 'FROM %s%s ' . 'WHERE theme_id = %d', $DB->prefix, 'themes_areas_properties', $area_id, $DB->prefix, 'themes_properties', $theme_id);
    if ($DB->exec($sql) === FALSE) {
        $messages[] = __FUNCTION__ . '(): ' . db_errormessage();
        $retval = FALSE;
    }
    // 2B -- update/overwrite the default settings with our own demo-data for area $area_id
    foreach ($settings as $name => $value) {
        $fields = array('value' => strval($value));
        $where = array('area_id' => $area_id, 'theme_id' => $theme_id, 'name' => strval($name));
        if (db_update('themes_areas_properties', $fields, $where) === FALSE) {
            $messages[] = __FUNCTION__ . '(): ' . db_errormessage();
            $retval = FALSE;
        }
    }
    return $retval;
}
/** retrieve a list of modules that should appear in the module manager
 *
 * this routine returns an array with id, name, title and
 * description of all active modules that have at least
 * one parameter in the modules_properties table.
 * If there are no modules available (or an error occurs)
 * an empty array is returned. The modules in the list is ordered
 * by the translated name (title) of the module, i.e. the order
 * depends on the current translation language.
 *
 * @param bool $forced if TRUE a fresh trip to the database is forced
 * @return array list of modules sorted by (translated) title
 */
function modulemanager_get_modules($forced = FALSE)
{
    global $DB;
    static $modules = NULL;
    if ($modules === NULL || $forced) {
        $sql = sprintf('SELECT DISTINCT m.module_id,m.name ' . 'FROM %smodules m ' . 'INNER JOIN %smodules_properties mp USING(module_id) ' . 'WHERE (is_active)', $DB->prefix, $DB->prefix);
        if (($result = $DB->query($sql)) === FALSE) {
            logger('modulemanager: ' . db_errormessage());
            return array();
        }
        $records = $result->fetch_all_assoc('module_id');
        $result->close();
        // we now have an array with id's and (short) names keyed by id.
        // now pickup translated names
        foreach ($records as $module_id => $module) {
            $name = $module['name'];
            $records[$module_id]['title'] = t('title', 'm_' . $name);
            $records[$module_id]['description'] = t('description', 'm_' . $name);
        }
        uasort($records, 'modulemanager_cmp');
        $modules = $records;
    }
    return $modules;
}
/** save the modified content data of this module linked to node $node_id
 *
 * this validates and saves the data that was submitted by the user.
 * If validation fails, or storing the data doesn't work, the flag $edit_again
 * is set to TRUE and the return value is FALSE.
 *
 * If the user has cancelled the operation, the flag $edit_again is set to FALSE
 * and the return value is also FALSE.
 *
 * If the modified data is stored successfully, the return value is TRUE (and
 * the value of $edit_again is a don't care).
 *
 * Here is a summary of return values.
 *
 *  - retval = TRUE ==> data saved successfully
 *  - retval = FALSE && edit_again = TRUE ==> re-edit the data, show the edit dialog again
 *  - retval = FALSE && edit_again = FALSE ==> cancelled, do nothing
 *
 * @param object &$output collects the html output (if any)
 * @param int $area_id the area in which $node_id resides
 * @param int $node_id the node to which the content is connected
 * @param array $module the module record straight from the database
 * @param bool $viewonly if TRUE, editing and hence saving is not allowed
 * @param bool &$edit_again set to TRUE if we need to edit the content again, FALSE otherwise
 * @return bool TRUE on success + output stored via $output, FALSE otherwise
 */
function snapshots_save(&$output, $area_id, $node_id, $module, $viewonly, &$edit_again)
{
    global $USER;
    // 1 -- bail out if cancelled or viewonly
    if (isset($_POST['button_cancel']) || $viewonly) {
        $edit_again = FALSE;
        return FALSE;
    }
    // 2 -- redo if invalid data was submitted
    $invalid = FALSE;
    $dialogdef = snapshots_get_dialogdef($viewonly);
    if (!dialog_validate($dialogdef)) {
        $invalid = TRUE;
    }
    if (!snapshots_check_path($dialogdef['snapshots_path'], $area_id, $node_id)) {
        $invalid = TRUE;
    }
    if (isset($dialogdef['snapshots_path']['warnings']) && $dialogdef['snapshots_path']['warnings'] > 0) {
        $output->add_message($dialogdef['snapshots_path']['warning_messages']);
    }
    // show errors to the user and redo
    if ($invalid) {
        foreach ($dialogdef as $k => $item) {
            if (isset($item['errors']) && $item['errors'] > 0) {
                $output->add_message($item['error_messages']);
            }
        }
        $edit_again = TRUE;
        return FALSE;
    }
    // 3 -- actually save the new setting
    $now = strftime('%Y-%m-%d %T');
    $table = 'snapshots';
    $fields = array('header' => $dialogdef['header']['value'], 'introduction' => $dialogdef['introduction']['value'], 'snapshots_path' => $dialogdef['snapshots_path']['value'], 'variant' => $dialogdef['variant']['value'], 'dimension' => intval($dialogdef['dimension']['value']), 'mtime' => $now, 'muser_id' => $USER->user_id);
    $where = array('node_id' => intval($node_id));
    if (db_update($table, $fields, $where) === FALSE) {
        logger(sprintf('%s(): error saving config value: %s', __FUNCTION__, db_errormessage()));
        $edit_again = TRUE;
        return FALSE;
    } else {
        return TRUE;
        // $edit_again is a don't care
    }
}
/** perform actual update to version 2012041900
 *
 * Changes between 2011093000 and 2012041900:
 *  - addition of the ckeditor-option in the site configuration table
 *
 * @param object &$output collects the html output
 * @return bool TRUE on success, FALSE otherwise
 */
function update_core_2012041900(&$output)
{
    global $CFG, $DB;
    $version = 2012041900;
    if ($CFG->version >= $version) {
        return TRUE;
    }
    //
    // 1 -- maybe change default editor to CKEditor
    //
    $table = 'config';
    $fields = array('extra' => 'options=ckeditor,fckeditor,plain', 'description' => 'Default rich text editor - USER-defined, default ckeditor');
    $where = array('name' => 'editor');
    if (!isset($CFG->editor) || $CFG->editor == 'fckeditor') {
        $fields['value'] = 'ckeditor';
    }
    if (db_update($table, $fields, $where) === FALSE) {
        $msg = sprintf("%s(): cannot update editor configuration: %s", __FUNCTION__, db_errormessage());
        logger($msg);
        $output->add_message(htmlspecialchars($msg));
        $output->add_message(t('update_core_error', 'admin', array('{VERSION}' => strval($version))));
        return FALSE;
    }
    //
    // 2 -- maybe add some additional fields to nodes, users
    //
    $addfielddefs = array('nodes:style' => array('name' => 'style', 'type' => 'text', 'notnull' => TRUE, 'comment' => 'additional style information to add AFTER static and area-level style'), 'users:skin' => array('name' => 'skin', 'type' => 'varchar', 'length' => 20, 'notnull' => TRUE, 'default' => 'base', 'comment' => 'preferred skin'));
    foreach ($addfielddefs as $table_field => $fielddef) {
        list($table, $field) = explode(':', $table_field);
        if (($DBResult = $DB->query(db_select_sql($table, $field), 1)) !== FALSE) {
            $DBResult->close();
            logger(sprintf("%s(): field '%s' already exists in '%s', skipping ALTER TABLE", __FUNCTION__, $field, $table));
        } else {
            $sql = sprintf('ALTER TABLE %s%s ADD COLUMN (%s)', $DB->prefix, $table, $DB->column_definition($fielddef));
            if (($retval = $DB->exec($sql)) === FALSE) {
                $msg = sprintf("%s(): cannot add field '%s' to table '%s': %s", __FUNCTION__, $field, $table, db_errormessage());
                logger($msg);
                $output->add_message(htmlspecialchars($msg));
                $output->add_message(t('update_core_error', 'admin', array('{VERSION}' => strval($version))));
                return FALSE;
            } else {
                logger(sprintf("%s(): success adding field '%s' to table '%s'", __FUNCTION__, $field, $table));
            }
        }
    }
    //
    // 3 -- maybe get rid of old field 'high_visibility'
    //
    if (($DBResult = $DB->query(db_select_sql('users', 'high_visibility'), 1)) === FALSE) {
        logger(sprintf("%s(): field 'high_visibility' no longer exists in 'users', skipping ALTER TABLE", __FUNCTION__));
    } else {
        $DBResult->close();
        $changes = array('base' => FALSE, 'textonly' => TRUE);
        foreach ($changes as $newval => $oldval) {
            if (($retval = db_update('users', array('skin' => $newval), array('high_visibility' => $oldval))) === FALSE) {
                $msg = sprintf("%s(): cannot update field 'users.skin' to '%s': %s", __FUNCTION__, $newval, db_errormessage());
                logger($msg);
                $output->add_message(htmlspecialchars($msg));
                $output->add_message(t('update_core_error', 'admin', array('{VERSION}' => strval($version))));
                return FALSE;
            } else {
                logger(sprintf("%s(): success setting 'users.skin' to '%s' in %d record(s)", __FUNCTION__, $newval, $retval));
            }
        }
        $sql = sprintf('ALTER TABLE %susers DROP COLUMN high_visibility', $DB->prefix);
        if (($retval = $DB->exec($sql)) === FALSE) {
            $msg = sprintf("%s(): cannot drop field 'high_visibility' from table 'users': %s", __FUNCTION__, db_errormessage());
            logger($msg);
            $output->add_message(htmlspecialchars($msg));
            $output->add_message(t('update_core_error', 'admin', array('{VERSION}' => strval($version))));
            return FALSE;
        } else {
            logger(sprintf("%s(): success dropping field 'high_visibility' from table 'users'", __FUNCTION__));
        }
    }
    //
    // 4 -- If all is well, we update the version number in the database AND in $CFG->version
    //
    return update_core_version($output, $version);
}
 /** determine the number of existing properties for a theme in an area
  *
  * @param int $area_id
  * @param int $theme_id
  * @return int number of existing properties
  */
 function count_existing_theme_properties($area_id, $theme_id)
 {
     $where = array('area_id' => intval($area_id), 'theme_id' => intval($theme_id));
     $record = db_select_single_record('themes_areas_properties', 'count(*) as properties', $where);
     if ($record === FALSE) {
         logger("areamanager: error counting properties in theme '{$theme_id} and area '{$area_id}': " . db_errormessage());
         $num = 0;
     } else {
         $num = intval($record['properties']);
     }
     return $num;
 }
 /** retrieve page data for htmlpage module on a node
  *
  * this retrieves data from the page $node_id (requires knowledge of
  * internals of htmlpage module/table) in order to show that in a box
  * in the 3rd column.
  * The content is wrapped in a div which has a unique ID of the form
  * sidebar_blockN where N counts from 1 upward and a common class
  * sidebar_htmlpage. This allows for connecting style information to
  * a particular sidebar block in a flexible way.
  *
  * @param in $index block number (1-based)
  * @param int $node_id identifies the pagedata to retrieve 
  * @param string $m increased readbility
  * @return string ready-to-use HTML-code
  */
 function cornelia_get_sidebar_htmlpage($index, $node_id, $m = '')
 {
     $attributes = array('id' => 'sidebar_block' . strval($index), 'class' => 'sidebar_htmlpage');
     $s = $m . html_tag('div', $attributes) . "\n";
     // fetch actual content from database (requires knowledge of internals of htmlpage module/table)
     $table = 'htmlpages';
     $node_id = intval($node_id);
     $where = array('node_id' => $node_id);
     $fields = array('page_data');
     if (($record = db_select_single_record($table, $fields, $where)) === FALSE) {
         logger(sprintf('%s: no pagedata (node=%d): %s', __FUNCTION__, $node_id, db_errormessage()));
     } else {
         $s .= $record['page_data'] . "\n";
     }
     $s .= $m . "</div>\n";
     return $s;
 }
 /** retrieve acl-data from table into a sparse array
  *
  * @param string $table name of the table which holds the acls
  * @return array zero or more elements with permissions
  */
 function fetch_acls_from_table($table)
 {
     $where = $this->where_acl_id();
     $a = array();
     switch ($table) {
         case 'acls_areas':
             $fields = array('permissions_intranet', 'permissions_modules', 'permissions_nodes');
             $keys = array('area_id');
             break;
         case 'acls_nodes':
             $fields = array('permissions_modules', 'permissions_nodes');
             $keys = array('node_id');
             break;
         case 'acls_modules':
             $fields = array('permissions_modules');
             $keys = array('module_id');
             break;
         case 'acls_modules_areas':
             $fields = array('permissions_modules');
             $keys = array('module_id', 'area_id');
             break;
         case 'acls_modules_nodes':
             $fields = array('permissions_modules');
             $keys = array('module_id', 'node_id');
             break;
         default:
             logger(sprintf("%s(): unknown table '%s'; cannot retrieve acls", __FUNCTION__, $table));
             return array();
             // empty array equates to: no access
             break;
     }
     $records = db_select_all_records($table, '*', $where);
     if ($records === FALSE) {
         logger(sprintf("%s(): cannot get acls from '%s'; %s'", __FUNCTION__, $table, db_errormessage()));
         return array();
         // empty array equates to: no access
     }
     if (sizeof($keys) == 1) {
         $key = $keys[0];
         if (sizeof($fields) > 1) {
             // acls_areas, acls_nodes
             foreach ($records as $record) {
                 $k = intval($record[$key]);
                 foreach ($fields as $f) {
                     if (($v = intval($record[$f])) != 0) {
                         $a[$k][$f] = isset($a[$k][$f]) ? $a[$k][$f] | $v : $v;
                     }
                 }
             }
         } else {
             // acls_modules
             $field = $fields[0];
             foreach ($records as $record) {
                 $k = intval($record[$key]);
                 if (($v = intval($record[$field])) != 0) {
                     $a[$k] = isset($a[$k]) ? $a[$k] | $v : $v;
                 }
             }
         }
     } else {
         // acls_modules_areas, acls_modules_nodes
         $field = $fields[0];
         foreach ($records as $record) {
             if (($v = intval($record[$field])) != 0) {
                 $k0 = intval($record[$keys[0]]);
                 $k1 = intval($record[$keys[1]]);
                 $a[$k0][$k1] = isset($a[$k0][$k1]) ? $a[$k0][$k1] | $v : $v;
             }
         }
     }
     unset($records);
     return $a;
 }
/** save the modified content data of this module linked to node $node_id
 *
 * this validates and saves the data that was submitted by the user.
 * If validation fails, or storing the data doesn't work, the flag $edit_again
 * is set to TRUE and the return value is FALSE.
 *
 * If the user has cancelled the operation, the flag $edit_again is set to FALSE
 * and the return value is also FALSE.
 *
 * If the modified data is stored successfully, the return value is TRUE (and
 * the value of $edit_again is a don't care).
 *
 * Here is a summary of return values.
 *
 *  - retval = TRUE ==> data saved successfully
 *  - retval = FALSE && edit_again = TRUE ==> re-edit the data, show the edit dialog again
 *  - retval = FALSE && edit_again = FALSE ==> cancelled, do nothing
 *
 * @param object &$output collects the html output (if any)
 * @param int $area_id the area in which $node_id resides
 * @param int $node_id the node to which the content is connected
 * @param array $module the module record straight from the database
 * @param bool $viewonly if TRUE, editing and hence saving is not allowed
 * @param bool &$edit_again set to TRUE if we need to edit the content again, FALSE otherwise
 * @return bool TRUE on success + output stored via $output, FALSE otherwise
 */
function redirect_save(&$output, $area_id, $node_id, $module, $viewonly, &$edit_again)
{
    global $USER;
    // 1 -- bail out if cancelled or viewonly
    if (isset($_POST['button_cancel']) || $viewonly) {
        $edit_again = FALSE;
        return FALSE;
    }
    // 2 -- redo if invalid data was submitted
    $dialogdef = redirect_get_dialogdef($viewonly);
    if (!dialog_validate($dialogdef)) {
        // there were errors, show them to the user and do it again
        foreach ($dialogdef as $k => $item) {
            if (isset($item['errors']) && $item['errors'] > 0) {
                $output->add_message($item['error_messages']);
            }
        }
        $edit_again = TRUE;
        return FALSE;
    }
    // 3 -- actually save the new setting
    $now = strftime('%Y-%m-%d %T');
    $table = 'nodes';
    $fields = array('link_href' => trim($dialogdef['link_href']['value']), 'link_target' => trim($dialogdef['link_target']['value']), 'mtime' => $now);
    $where = array('node_id' => intval($node_id));
    $retval = db_update($table, $fields, $where);
    if (db_update($table, $fields, $where) === FALSE) {
        logger(sprintf('%s(): error saving config value: %s', __FUNCTION__, db_errormessage()));
        $edit_again = TRUE;
        return FALSE;
    } else {
        return TRUE;
        // $edit_again is a don't care
    }
}
/** retrieve current list of addresses in an array (could be empty)
 *
 * this retrieves the addresses associated with $node_id from the
 * database. As an important side effect all entries' sort order values
 * are renumbered. This means that we always have a neat set of sort
 * order numbers 10, 20, ...
 *
 * On error we return an empty array as a sort of best effort.
 * The error is logged though.
 *
 * @param int $node_id indicates page
 * @return array records from the database with sort order renumbered OR an empty array
 */
function mailpage_get_addresses($node_id)
{
    $table = 'mailpages_addresses';
    $keyfield = 'mailpage_address_id';
    $fields = '*';
    $where = array('node_id' => intval($node_id));
    $order = array('sort_order', $keyfield);
    if (($records = db_select_all_records($table, $fields, $where, $order, $keyfield)) === FALSE) {
        logger(sprintf('%s(): error retrieving addresses: %s', __FUNCTION__, db_errormessage()));
        return array();
    }
    // side-effect: renumber the sort order of the addresses if not a nice list of 10, 20, ...
    $sort_order = 0;
    foreach ($records as $k => $record) {
        $sort_order += 10;
        if ($record['sort_order'] == $sort_order) {
            continue;
        }
        $records[$k]['sort_order'] = $sort_order;
        $where = array($keyfield => intval($record[$keyfield]));
        $fields = array('sort_order' => $sort_order);
        if (db_update($table, $fields, $where) === FALSE) {
            logger(sprintf('%s(): error renumbering addresses: %s', __FUNCTION__, db_errormessage()));
        }
    }
    return $records;
}
Пример #15
0
/** create a few alerts
 *
 *
 * @param array &$messages used to return (error) messages to caller
 * @param array &$config pertinent information about the site
 * @param array &$tr translations of demodata texts
 * @return bool TRUE on success + data entered into database, FALSE on error
 */
function demodata_alerts(&$messages, &$config, &$tr)
{
    $retval = TRUE;
    $now = strftime("%Y-%m-%d %T");
    $email = $config['user_email'];
    $alerts = array('webmaster' => array('full_name' => $config['user_full_name'], 'email' => $email, 'cron_interval' => 1440, 'cron_next' => $now, 'messages' => 1, 'message_buffer' => $now . "\n" . $tr['alerts_initial_load'] . "\n" . $tr['alerts_every_1440_minutes'] . "\n" . $tr['alerts_all_areas'] . "\n" . $tr['alerts_email_address'] . "\n" . $email . " (" . $config['user_full_name'] . ")\n", 'is_active' => TRUE), 'acackl' => array('full_name' => 'Amelia Cackle', 'email' => $email, 'cron_interval' => 60, 'cron_next' => $now, 'messages' => 1, 'message_buffer' => $now . "\n" . $tr['alerts_initial_load'] . "\n" . $tr['alerts_every_60_minutes'] . "\n" . $tr['alerts_private_area'] . "\n" . $tr['alerts_email_address'] . "\n" . $email . " (Amelia Cackle)\n", 'is_active' => TRUE));
    foreach ($alerts as $alert => $fields) {
        if (($alert_id = db_insert_into_and_get_id('alerts', $fields, 'alert_id')) === FALSE) {
            $messages[] = $tr['error'] . ' ' . db_errormessage();
            $retval = FALSE;
        }
        $alerts[$alert]['alert_id'] = intval($alert_id);
    }
    $alerts_areas_nodes = array('webmaster' => array('alert_id' => $alerts['webmaster']['alert_id'], 'area_id' => 0, 'node_id' => 0, 'flag' => TRUE), 'acackl' => array('alert_id' => $alerts['acackl']['alert_id'], 'area_id' => $config['demo_areas']['private']['area_id'], 'node_id' => 0, 'flag' => TRUE));
    foreach ($alerts_areas_nodes as $fields) {
        if (db_insert_into('alerts_areas_nodes', $fields) === FALSE) {
            $messages[] = $tr['error'] . ' ' . db_errormessage();
            $retval = FALSE;
        }
    }
    return $retval;
}
 /** construct a Theme object
  *
  * this stores the information about this theme from the database.
  * Also, we construct/read the tree of nodes for this area $area_id. This
  * information will be used lateron when constructing the navigation.
  * The node to display is $node_id.
  *
  * Also, we prepare a list of areas where the current user is allowed to go.
  * This is handy when constructing a jumpmenu and doing it here saves a trip
  * to the database lateron in {@link get_jumpmenu()}.
  *
  * @param array $theme_record the record straight from the database
  * @param int $area_id the area of interest
  * @param int $node_id the node that will be displayed
  * @return void
  */
 function Theme($theme_record, $area_id, $node_id)
 {
     global $USER, $CFG;
     $charset = 'UTF-8';
     $content_type = 'text/html; charset=' . $charset;
     $this->add_http_header('Content-Type: ' . $content_type);
     $this->theme_record = $theme_record;
     $this->theme_id = intval($theme_record['theme_id']);
     $this->area_id = intval($area_id);
     $this->jumps = array();
     // extract areas information and
     //  - grab a copy of the full area_record 'for future reference', and
     //  - make a list of areas accessible for this user (for the area jumpmenu)
     if (($areas = get_area_records()) !== FALSE) {
         $this->area_record = $areas[$this->area_id];
         foreach ($areas as $id => $area) {
             if (db_bool_is(TRUE, $area['is_active']) && (db_bool_is(FALSE, $area['is_private']) || $USER->has_intranet_permissions(ACL_ROLE_INTRANET_ACCESS, $id))) {
                 $this->jumps[$id] = $area['title'];
             }
         }
     } else {
         $this->area_record = array('area_id' => $this->area_id, 'title' => '?');
         logger(sprintf('constructor %s(): cannot get list of areas: %s', __FUNCTION__, db_errormessage()), WLOG_DEBUG);
     }
     $this->node_id = intval($node_id);
     $this->tree = $this->construct_tree($this->area_id);
     $this->node_record = $this->tree[$node_id]['record'];
     $this->config = $this->get_properties($this->theme_id, $this->area_id);
     $this->add_meta_http_equiv(array('Content-Type' => $content_type, 'Content-Script-Type' => 'text/javascript', 'Content-Style-Type' => 'text/css'));
     $this->title = $this->area_record['title'];
     $this->add_meta(array('MSSmartTagsPreventParsing' => 'TRUE', 'generator' => 'Website@School', 'description' => 'Website@School Content Management System for schools', 'keywords' => 'Website@School, CMS for schools'));
     $this->calc_breadcrumb_trail($node_id);
     // only set markers in tree, don't collect anchors yet
     $this->domain = 't_' . $this->theme_record['name'];
     // indicates where to look for translations
     if (isset($this->config['style_usage_static']) && $this->config['style_usage_static'] && isset($this->config['stylesheet'])) {
         $this->add_stylesheet($this->config['stylesheet']);
     }
 }
 /** retrieve a single group's record possibly from the cache
  *
  * @param int $group_id identifies the group record
  * @param bool $forced if TRUE unconditionally fetch the record from the database 
  * @return bool|array FALSE if there were errors, the group record otherwise
  */
 function get_group_record($group_id, $forced = FALSE)
 {
     $group_id = intval($group_id);
     if (!isset($this->groups[$group_id]) || $forced) {
         $table = 'groups';
         $fields = '*';
         $where = array('group_id' => $group_id);
         if (($record = db_select_single_record($table, $fields, $where)) === FALSE) {
             logger(sprintf("%s.%s(): cannot retrieve record for group '%d': %s", __CLASS__, __FUNCTION__, $group_id, db_errormessage()));
             $this->output->add_message(t('error_retrieving_data', 'admin'));
             return FALSE;
         } else {
             $this->groups[$group_id] = $record;
         }
     }
     return isset($this->groups[$group_id]) ? $this->groups[$group_id] : FALSE;
 }
/** add demonstration data to the system
 *
 * this routine adds to the existing set of demonstration data as specified
 * in $config. Here we add a few nodes as follows:
 *
 * 'snapshots0': a section containing one page connected to the snapshots_module
 * 'snapshots1': a page in section 'snapshots0' acting as an example set of snapshots
 *
 * The section 'snapshots0' is added at the bottom of the demo-section 'news'
 * Maybe not the best place, but at least we don't add yet another top level
 * menu item.
 *
 * Note
 * If the module is installed via the Install Wizard, this routine is
 * called. However, if a module is installed as an additional module
 * after installation, the {$module}_demodata() routine is never called.
 * This is because the only time you know that demodata is installed is
 * when the Install Wizard runs. If we're called from admin.php, the
 * webmaster may have already deleted existing (core) demodata so you
 * never can be sure what to expect. To put it another way: it is hard
 * to re-construct $config when we're NOT the Instal Wizard.
 *
 * The array $config contains the following information.
 *
 * <code>
 * $config['language_key']   => install language code (eg. 'en')
 * $config['dir']            => path to CMS Root Directory (eg. /home/httpd/htdocs)
 * $config['www']            => URL of CMS Root Directory (eg. http://exemplum.eu)
 * $config['progdir']        => path to program directory (eg. /home/httpd/htdocs/program)
 * $config['progwww']        => URL of program directory (eg. http://exemplum.eu/program)
 * $config['datadir']        => path to data directory (eg. /home/httpd/wasdata/a1b2c3d4e5f6)
 * $config['user_username']  => userid of webmaster (eg. wblader)
 * $config['user_full_name'] => full name of webmaster (eg. Wilhelmina Bladergroen)
 * $config['user_email']     => email of webmaster (eg. w.bladergroen@exemplum.eu)
 * $config['user_id']        => numerical user_id (usually 1)
 * $config['demo_salt']      => password salt for all demodata accounts
 * $config['demo_password']  => password for all demodata accounts
 * $config['demo_areas']     => array with demo area data
 * $config['demo_groups']    => array with demo group data
 * $config['demo_users']     => array with demo user data
 * $config['demo_nodes']     => array with demo node data
 * $config['demo_string']    => array with demo strings from /program/install/languages/LL/demodata.php
 * $config['demo_replace']   => array with search/replace pairs to 'jazz up' the demo strings
 * </code>
 *
 * With this information, we can add a demonstration configuration for the public area,
 * which shows off the possibilities. Note that we add our own additions to the array
 * $config so other modules and themes can determine the correct status quo w.r.t. the
 * demodata nodes etc.
 *
 * @param array &$messages collects the (error) messages
 * @param int $module_id the key for this module in the modules table
 * @param array $configuration pertinent data for the new website + demodata foundation
 * @param array $manifest a copy of the manifest for this module
 * @return bool TRUE on success + output via $messages, FALSE otherwise
 */
function snapshots_demodata(&$messages, $module_id, $config, $manifest)
{
    global $DB;
    $retval = TRUE;
    // assume success
    // 0 -- get hold of the module-specific translations in $string[]
    $string = array();
    $language_key = $config['language_key'];
    $filename = dirname(__FILE__) . '/languages/' . $language_key . '/snapshots.php';
    if (!file_exists($filename)) {
        $filename = dirname(__FILE__) . '/languages/en/snapshots.php';
    }
    @(include $filename);
    if (empty($string)) {
        $messages[] = 'Internal error: no translations in ' . $filename;
        return FALSE;
    }
    // 1A -- prepare for addition of a few nodes
    $sort_order = 0;
    $parent_id = $config['demo_nodes']['news']['node_id'];
    foreach ($config['demo_nodes'] as $node => $fields) {
        if ($fields['parent_id'] == $parent_id && $fields['node_id'] != $parent_id) {
            $sort_order = max($sort_order, $fields['sort_order']);
        }
    }
    $sort_order += 10;
    // place the snapshots-section at the end of the parent section
    $nodes = array('snapshots0' => array('parent_id' => $parent_id, 'is_page' => FALSE, 'title' => strtr($string['snapshots0_title'], $config['demo_replace']), 'link_text' => strtr($string['snapshots0_link_text'], $config['demo_replace']), 'sort_order' => $sort_order), 'snapshots1' => array('parent_id' => 0, 'is_page' => TRUE, 'is_default' => TRUE, 'title' => strtr($string['snapshots1_title'], $config['demo_replace']), 'link_text' => strtr($string['snapshots1_link_text'], $config['demo_replace']), 'sort_order' => 10, 'module_id' => $module_id, 'style' => "div.thumbnail_image a:hover img { border: 5px solid #00FF00; }\n"));
    // 1B -- actually add the necessary nodes
    $now = strftime('%Y-%m-%d %T');
    $user_id = $config['user_id'];
    $area_id = $config['demo_areas']['public']['area_id'];
    foreach ($nodes as $node => $fields) {
        $fields['area_id'] = $area_id;
        $fields['ctime'] = $now;
        $fields['mtime'] = $now;
        $fields['atime'] = $now;
        $fields['owner_id'] = $user_id;
        if ($fields['parent_id'] == 0) {
            $fields['parent_id'] = $config['demo_nodes']['snapshots0']['node_id'];
            // plug in real node_id of 'our' section
        }
        if (($node_id = db_insert_into_and_get_id('nodes', $fields, 'node_id')) === FALSE) {
            $messages[] = $config['demo_string']['error'] . db_errormessage();
            $retval = FALSE;
        }
        $node_id = intval($node_id);
        $fields['node_id'] = $node_id;
        $config['demo_nodes'][$node] = $fields;
    }
    // 2 -- Simulate a series of snapshots in the exemplum area data storage
    // 2A -- copy from module demodata directory to exemplum path
    $pictures = array("allium.jpg", "calendula.jpg", "cynara.jpg", "lagos.jpg", "lavandula.jpg", "mentha.jpg", "nepeta.jpg", "ocimum.jpg", "origanum.jpg", "petroselinum.jpg", "salvia.jpg", "thymus.jpg");
    $thumb_prefix = 'zz_thumb_';
    $path_snapshots = '/areas/' . $config['demo_areas']['public']['path'] . '/snapshots';
    // relative to $datadir
    $fullpath_source = dirname(__FILE__) . '/install/demodata';
    $fullpath_target = $config['datadir'] . $path_snapshots;
    if (@mkdir($fullpath_target, 0700) === FALSE) {
        $messages[] = $config['demo_string']['error'] . "mkdir('{$fullpath_target}')";
        $retval = FALSE;
    } else {
        @touch($fullpath_target . '/index.html');
        // try to "protect" directory
        foreach ($pictures as $picture) {
            $filenames = array($picture, $thumb_prefix . $picture);
            foreach ($filenames as $filename) {
                if (!@copy($fullpath_source . '/' . $filename, $fullpath_target . '/' . $filename)) {
                    $messages[] = $config['demo_string']['error'] . "copy('{$path_snapshots}/{$filename}')";
                    $retval = FALSE;
                }
            }
        }
    }
    $fields = array('node_id' => $config['demo_nodes']['snapshots1']['node_id'], 'header' => strtr($string['snapshots1_header'], $config['demo_replace']), 'introduction' => strtr($string['snapshots1_introduction'], $config['demo_replace']), 'snapshots_path' => $path_snapshots, 'variant' => 1, 'dimension' => 512, 'ctime' => $now, 'cuser_id' => $user_id, 'mtime' => $now, 'muser_id' => $user_id);
    if (db_insert_into('snapshots', $fields) === FALSE) {
        $messages[] = $config['demo_string']['error'] . db_errormessage();
        $retval = FALSE;
    }
    return $retval;
}
/** retrieve all configuration data for this mailpage
 *
 * this retrieves all configuration data for this mailpage,
 * i.e. both the general parameters (header/intro/etc.) and
 * the full list of configured destination addresses.
 * Here is a quick reminder of the structure in $config.
 * <pre>
 * 'node_id'
 * 'header'
 * 'introduction'
 * 'message'
 * 'addresses' = ['mailpage_address_id','node_id','sort_order','name','email','description','thankyou'],...
 * </pre>
 *
 * @param int $node_id identifies the page
 * @return bool|array configuration data in a (nested) array or FALSE on error
 */
function mailpage_view_get_config($node_id)
{
    // 1 -- generic configuration
    $table = 'mailpages';
    $fields = array('node_id', 'header', 'introduction', 'message');
    $where = array('node_id' => intval($node_id));
    if (($config = db_select_single_record($table, $fields, $where)) === FALSE) {
        logger(sprintf('%s(): error retrieving configuration: %s', __FUNCTION__, db_errormessage()));
        return FALSE;
    }
    // 2 -- fetch all configured destinations
    $table = 'mailpages_addresses';
    $fields = '*';
    $where = array('node_id' => intval($node_id));
    $order = array('sort_order', 'mailpage_address_id');
    if (($records = db_select_all_records($table, $fields, $where, $order)) === FALSE) {
        logger(sprintf('%s(): error retrieving addresses: %s', __FUNCTION__, db_errormessage()));
        return FALSE;
    }
    $config['addresses'] = $records;
    // simple 0-based array, not keyed by mailpage_address_id
    return $config;
}
/** add demonstration data to the system
 *
 * this routine adds demonstration data to the freshly installed system
 *
 * Note
 * If the theme is installed via the Install Wizard, this routine is
 * called. However, if a theme is installed as an additional theme
 * after installation, the {$theme}_demodata() routine is never called.
 * This is because the only time you know that demodata is installed is
 * when the Install Wizard runs. If we're called from admin.php, the
 * webmaster may have already deleted existing (core) demodata so you
 * never can be sure what to expect. To put it another way: it is hard
 * to re-construct $config when we're NOT the Instal Wizard.
 *
 * The array $config contains the following information.
 *
 * <code>
 * $config['language_key']   => install language code (eg. 'en')
 * $config['dir']            => path to CMS Root Directory (eg. /home/httpd/htdocs)
 * $config['www']            => URL of CMS Root Directory (eg. http://exemplum.eu)
 * $config['progdir']        => path to program directory (eg. /home/httpd/htdocs/program)
 * $config['progwww']        => URL of program directory (eg. http://exemplum.eu/program)
 * $config['datadir']        => path to data directory (eg. /home/httpd/wasdata/a1b2c3d4e5f6)
 * $config['user_username']  => userid of webmaster (eg. wblader)
 * $config['user_full_name'] => full name of webmaster (eg. Wilhelmina Bladergroen)
 * $config['user_email']     => email of webmaster (eg. w.bladergroen@exemplum.eu)
 * $config['user_id']        => numerical user_id (usually 1)
 * $config['demo_salt']      => password salt for all demodata accounts
 * $config['demo_password']  => password for all demodata accounts
 * $config['demo_areas']     => array with demo area data
 * $config['demo_groups']    => array with demo group data
 * $config['demo_users']     => array with demo user data
 * $config['demo_nodes']     => array with demo node data
 * </code>
 *
 * With this information, we can add a demonstration configuration for the public area,
 * which shows off the possibilities.
 *
 * @param array &$messages collects the (error) messages
 * @param int $theme_id the key for this theme in the themes table
 * @param array $config pertinent data for the new website + demodata foundation
 * @param array $manifest a copy from the manifest for this theme
 * @return bool TRUE on success + output via $messages, FALSE otherwise
 */
function axis_demodata(&$messages, $theme_id, $config, $manifest)
{
    global $DB;
    $retval = TRUE;
    // assume success
    // 1A -- prepare for setting up demo settings
    $area_id = intval($config['demo_areas']['public']['area_id']);
    $theme_id = intval($theme_id);
    // 1B -- actually setup settings
    $style = sprintf("#page {\n" . "  background-image: url('%s/themes/axis/axis.gif');\n" . "}\n", $config['progwww']);
    $settings = array('style_usage_static' => '1', 'stylesheet' => 'program/themes/axis/style.css', 'stylesheet_print' => 'program/themes/axis/print.css', 'style_usage_area' => '1', 'style' => $style, 'style_usage_node' => '1');
    // 2A -- start with the default settings (copy from theme_properties)
    $sql = sprintf('INSERT INTO %s%s(area_id,theme_id,name,type,value,extra,sort_order,description) ' . 'SELECT %d AS area_id,theme_id,name,type,value,extra,sort_order,description ' . 'FROM %s%s ' . 'WHERE theme_id = %d', $DB->prefix, 'themes_areas_properties', $area_id, $DB->prefix, 'themes_properties', $theme_id);
    if ($DB->exec($sql) === FALSE) {
        $messages[] = __FUNCTION__ . '(): ' . db_errormessage();
        $retval = FALSE;
    }
    // 2B -- update/overwrite the default settings with our own demo-data for area $area_id
    foreach ($settings as $name => $value) {
        $fields = array('value' => strval($value));
        $where = array('area_id' => $area_id, 'theme_id' => $theme_id, 'name' => strval($name));
        if (db_update('themes_areas_properties', $fields, $where) === FALSE) {
            $messages[] = __FUNCTION__ . '(): ' . db_errormessage();
            $retval = FALSE;
        }
    }
    return $retval;
}
/** add demonstration data to the system
 *
 * this routine adds demonstration data to the freshly installed system
 *
 * Note
 * If the theme is installed via the Install Wizard, this routine is
 * called. However, if a theme is installed as an additional theme
 * after installation, the {$theme}_demodata() routine is never called.
 * This is because the only time you know that demodata is installed is
 * when the Install Wizard runs. If we're called from admin.php, the
 * webmaster may have already deleted existing (core) demodata so you
 * never can be sure what to expect. To put it another way: it is hard
 * to re-construct $config when we're NOT the Instal Wizard.
 *
 * The array $config contains the following information.
 *
 * <code>
 * $config['language_key']   => install language code (eg. 'en')
 * $config['dir']            => path to CMS Root Directory (eg. /home/httpd/htdocs)
 * $config['www']            => URL of CMS Root Directory (eg. http://exemplum.eu)
 * $config['progdir']        => path to program directory (eg. /home/httpd/htdocs/program)
 * $config['progwww']        => URL of program directory (eg. http://exemplum.eu/program)
 * $config['datadir']        => path to data directory (eg. /home/httpd/wasdata/a1b2c3d4e5f6)
 * $config['title']          => the name of the site (as entered by Wilhelmina Bladergroen)
 * $config['user_username']  => userid of webmaster (eg. wblader)
 * $config['user_full_name'] => full name of webmaster (eg. Wilhelmina Bladergroen)
 * $config['user_email']     => email of webmaster (eg. w.bladergroen@exemplum.eu)
 * $config['user_id']        => numerical user_id (usually 1)
 * $config['demo_salt']      => password salt for all demodata accounts
 * $config['demo_password']  => password for all demodata accounts
 * $config['demo_areas']     => array with demo area data
 * $config['demo_groups']    => array with demo group data
 * $config['demo_users']     => array with demo user data
 * $config['demo_nodes']     => array with demo node data
 * $config['demo_string']    => array with demo strings from /program/install/languages/LL/demodata.php
 * $config['demo_replace']   => array with search/replace pairs to 'jazz up' the demo strings
 * </code>
 *
 * With this information, we can add a demonstration configuration for the public area,
 * which shows off the possibilities.
 *
 * @param array &$messages collects the (error) messages
 * @param int $theme_id the key for this theme in the themes table
 * @param array $config pertinent data for the new website + demodata foundation
 * @param array $manifest a copy from the manifest for this theme
 * @return bool TRUE on success + output via $messages, FALSE otherwise
 */
function cornelia_demodata(&$messages, $theme_id, $config, $manifest)
{
    global $DB;
    $retval = TRUE;
    // assume success
    // 1A -- prepare for setting up demo settings
    $quicktop_section_id = intval($config['demo_nodes']['quicktop']['node_id']);
    $quickbottom_section_id = intval($config['demo_nodes']['quickbottom']['node_id']);
    $schoolterms2_id = intval($config['demo_nodes']['schoolterms2']['node_id']);
    $latestnews_id = intval($config['demo_nodes']['latestnews']['node_id']);
    $progwww = $config['progwww'];
    $slogan = $config['demo_string']['welcome_title'];
    $area_id = intval($config['demo_areas']['public']['area_id']);
    $theme_id = intval($theme_id);
    $theme_name = $manifest['name'];
    $aboutus = $config['demo_string']['aboutus_content'];
    $email = $config['replyto'];
    $lorem = strtr('{LOREM}', $config['demo_replace']);
    $ipsum = strtr('{IPSUM}', $config['demo_replace']);
    $sidebar_nodelist = sprintf('%d,0,%d,0,-', $latestnews_id, $schoolterms2_id);
    $style = "#leftmargin { min-height: 300px; }\n" . "#rightmargin { min-height: 300px; }\n";
    // 1B -- actually construct settings
    $settings = array('quicktop_section_id' => strval($quicktop_section_id), 'quickbottom_section_id' => strval($quickbottom_section_id), 'header_text' => sprintf('<span style="background-color: #FFFF00;">%s</span>', $slogan), 'left_top_html' => sprintf("<img src=\"%s/themes/%s/origanum.jpg\" width=\"120\" height=\"90\" alt=\"\">\n", $progwww, $theme_name), 'left_bottom_html' => sprintf("<div style=\"margin-bottom: 30px;\">\n%s\n</div>\n", $aboutus), 'right_top_html' => $lorem, 'sidebar_nodelist' => $sidebar_nodelist, 'right_bottom_html' => $ipsum, 'footer_text' => sprintf('<b><a href="mailto:%s">%s</a></b>', $email, $email), 'style' => $style);
    // 2A -- start with the default settings (copy from theme_properties)
    $sql = sprintf('INSERT INTO %s%s(area_id,theme_id,name,type,value,extra,sort_order,description) ' . 'SELECT %d AS area_id,theme_id,name,type,value,extra,sort_order,description ' . 'FROM %s%s ' . 'WHERE theme_id = %d', $DB->prefix, 'themes_areas_properties', $area_id, $DB->prefix, 'themes_properties', $theme_id);
    if ($DB->exec($sql) === FALSE) {
        $messages[] = __FUNCTION__ . '(): ' . db_errormessage();
        $retval = FALSE;
    }
    // 2B -- update/overwrite the default settings with our own demo-data for area $area_id
    foreach ($settings as $name => $value) {
        $fields = array('value' => strval($value));
        $where = array('area_id' => $area_id, 'theme_id' => $theme_id, 'name' => strval($name));
        if (db_update('themes_areas_properties', $fields, $where) === FALSE) {
            $messages[] = __FUNCTION__ . '(): ' . db_errormessage();
            $retval = FALSE;
        }
    }
    return $retval;
}
/** construct a title, summary and readmore prompt for an htmlpage page
 *
 * this routine uses a heuristic approach to snip N paragraphs from
 * the actual text in the html-page. Because we cannot be sure that
 * stripos() is available we resort to first changing any '<P' to
 * '<p ' and subsequently searching the string until the N+1'th '<p '.
 * The offset we calculate this way should contain exactly N
 * paragraphs. Obviously this assumes (dangerous...) that the htmlpage
 * page_data actually contains paragraphs. However, if not enough '<p
 * strings are found, the complete page is used. Heuristics...
 *
 * @param int $counter is a sequential number identifying the aggregated nodes
 * @param object &$theme points to theme where the output goes
 * @param array &$node points to the node record of this htmlpage
 * @param array &$config points to the aggregator configuration
 * @return array ordered list of nodes to aggregate (could be empty)
 */
function aggregator_view_htmlpage($counter, &$theme, &$node, &$config)
{
    $id = strval($counter);
    // used to make all id's within this item unique
    // 1 -- outer div holds title+blurb+readmore...
    $attributes = array('class' => 'aggregator_htmlpage_outer', 'id' => 'aggregator_outer_' . $id);
    $theme->add_content(html_tag('div', $attributes));
    // 2A -- title
    $attributes = array('class' => 'aggregator_htmlpage_header', 'id' => 'aggregator_header_' . $id);
    $theme->add_content('  ' . html_tag('h3', $attributes, $node['title']));
    // 2B -- blurb (enclosed in inner div)
    $attributes = array('class' => 'aggregator_htmlpage_inner', 'id' => 'aggregator_inner_' . $id);
    $theme->add_content('  ' . html_tag('div', $attributes));
    // fetch actual content from database (requires knowledge of internals of htmlpage module/table)
    $table = 'htmlpages';
    $node_id = intval($node['node_id']);
    $where = array('node_id' => $node_id);
    $fields = array('page_data');
    if (($record = db_select_single_record($table, $fields, $where)) === FALSE) {
        logger(sprintf('%s: no pagedata (node=%d): %s', __FUNCTION__, $node_id, db_errormessage()));
        $pagedata = '';
    } else {
        // make SURE we only have lowercase <p followed by a space in the text (easy strpos'ing)
        $pattern = '/(<[pP])([^a-zA-Z0-9])/';
        $replace = '<p $2';
        $pagedata = preg_replace($pattern, $replace, $record['page_data']);
    }
    $offset = -1;
    $limit = $config['htmlpage_length'];
    for ($i = 0; $i <= $limit; ++$i) {
        if (($offset = strpos($pagedata, '<p ', $offset + 1)) === FALSE) {
            break;
        }
    }
    if ($offset === FALSE) {
        // not enough '<p ' seen => show everything
        $theme->add_content($pagedata . "\n");
    } else {
        $theme->add_content(substr($pagedata, 0, $offset) . "\n");
    }
    $theme->add_content('  </div>');
    // 2C -- readmore prompt
    $anchor = t('htmlpage_more', 'm_aggregator');
    $title = t('htmlpage_more_title', 'm_aggregator');
    $attr = array('title' => $title);
    $href = was_node_url($node, NULL, '', $theme->preview_mode);
    $attributes = array('class' => 'aggregator_htmlpage_more', 'id' => 'aggregator_more_' . $id);
    $theme->add_content('  ' . html_tag('div', $attributes, html_a($href, NULL, $attr, $anchor)));
    $theme->add_content('  <div style="clear:both;"></div>');
    // 3 -- close outer div
    $theme->add_content('</div>');
}
/** construct a dialog definition for the workshop configuration
 *
 * this generates an array which defines the dialog for workshop configuration.
 * There are a few plain fields that simply go into the appropriate workshops
 * record and the save and cancel button. However, there may also be items
 * related to ACLs. These fields are used to define the user's roles and the
 * should be presented in a table. We abuse the field names for this purpose:
 * if the first 3 characters are 'acl' we put the widgets in an HTML-table, otherwise
 * it is just an ordinary widget.
 *
 * Note that in the case of a single simple user without any aquaintances (ie. a user
 * that is not member of any group) the user is not able to add herself to the list
 * of authorised users. What is the point of having a _collaborative_ workshop when
 * you are the only one to collaborate with? (However, it would be fairly easy to force/add
 * an entry for this user if the tmp table would turn out empty. Maybe later....?)
 * @param object &$output collects the html output (if any)
 * @param int $viewonly if TRUE the Save button is not displayed and values cannot be changed
 * @param int $module_id indicates the id of the crew module in the database (needed for ACL)
 * @param int $area_id indicates the area where node_id lives (needed for ACL)
 * @param int $node_id indicates which page we are loooking at (needed for ACL)
 * @param int $user_id indicates the current user (needed for ACL)
 * @return array dialog definition
 */
function crew_get_dialogdef(&$output, $viewonly, $module_id, $area_id, $node_id, $user_id)
{
    global $DB, $USER;
    static $dialogdef = NULL;
    if (!is_null($dialogdef)) {
        // recycle
        return $dialogdef;
    }
    $visibilities = array('2' => array('option' => t('visibility_world_label', 'm_crew'), 'title' => t('visibility_world_title', 'm_crew')), '1' => array('option' => t('visibility_all_label', 'm_crew'), 'title' => t('visibility_all_title', 'm_crew')), '0' => array('option' => t('visibility_workers_label', 'm_crew'), 'title' => t('visibility_workers_title', 'm_crew')));
    $roles = array(ACL_ROLE_NONE => array('option' => t('acl_role_none_option', 'admin'), 'title' => t('acl_role_none_title', 'admin')), CREW_ACL_ROLE_READONLY => array('option' => t('crew_acl_role_readonly_option', 'm_crew'), 'title' => t('crew_acl_role_readonly_title', 'm_crew')), CREW_ACL_ROLE_READWRITE => array('option' => t('crew_acl_role_readwrite_option', 'm_crew'), 'title' => t('crew_acl_role_readwrite_title', 'm_crew')), ACL_ROLE_GURU => array('option' => t('acl_role_guru_option', 'admin'), 'title' => t('acl_role_guru_title', 'admin')));
    // 1 -- plain & simple fields
    // make a fresh start with data from the database
    $dialogdef = array('header' => array('type' => F_ALPHANUMERIC, 'name' => 'header', 'minlength' => 0, 'maxlength' => 240, 'columns' => 30, 'label' => t('header_label', 'm_crew'), 'title' => t('header_title', 'm_crew'), 'viewonly' => $viewonly, 'value' => '', 'old_value' => ''), 'introduction' => array('type' => F_ALPHANUMERIC, 'name' => 'introduction', 'minlength' => 0, 'maxlength' => 32768, 'columns' => 50, 'rows' => 10, 'label' => t('introduction_label', 'm_crew'), 'title' => t('introduction_title', 'm_crew'), 'viewonly' => $viewonly, 'value' => '', 'old_value' => ''), 'visibility' => array('type' => F_RADIO, 'name' => 'visibility', 'value' => 0, 'old_value' => 0, 'options' => $visibilities, 'viewonly' => $viewonly, 'title' => t('visibility_title', 'm_crew'), 'label' => t('visibility_label', 'm_crew')));
    $table = 'workshops';
    $fields = array('header', 'introduction', 'visibility');
    $where = array('node_id' => intval($node_id));
    if (($record = db_select_single_record($table, $fields, $where)) === FALSE) {
        logger(sprintf('%s(): error retrieving CREW configuration: %s', __FUNCTION__, db_errormessage()));
        $output->add_message(t('error_retrieving_data', 'admin'));
    } else {
        foreach ($record as $name => $value) {
            $dialogdef[$name]['value'] = $dialogdef[$name]['old_value'] = $value;
        }
    }
    $sql = sprintf('DROP TEMPORARY TABLE IF EXISTS %screw_tmp', $DB->prefix);
    $retval = $DB->exec($sql);
    if ($USER->has_job_permissions(JOB_PERMISSION_ACCOUNTMANAGER)) {
        // Allow $USER to set/edit any user's permission because she is already able
        // to manipulate useraccounts, _all_ useraccounts. We are sure that $USER is a
        // valid user with at least JOB_PERMISSION_STARTCENTER or else we would not be here.
        $sql = sprintf('CREATE TEMPORARY TABLE %screw_tmp ' . 'SELECT u.acl_id, u.username, u.full_name, amn.permissions_modules ' . 'FROM %susers u ' . 'LEFT JOIN %sacls_modules_nodes amn ' . 'ON amn.acl_id = u.acl_id AND amn.module_id = %d AND amn.node_id = %d ' . 'ORDER BY u.full_name', $DB->prefix, $DB->prefix, $DB->prefix, $module_id, $node_id);
    } else {
        // Only allow $USER to set permissions for all her acquaintances, ie. all users
        // that are members of the group(s) that $USER is a also member of.
        $sql = sprintf('CREATE TEMPORARY TABLE %screw_tmp ' . 'SELECT DISTINCT u.acl_id, u.username, u.full_name, amn.permissions_modules ' . 'FROM %susers u ' . 'INNER JOIN %susers_groups_capacities ugc1 USING(user_id) ' . 'INNER JOIN %susers_groups_capacities ugc2 USING(group_id) ' . 'LEFT JOIN %sacls_modules_nodes amn ' . 'ON amn.acl_id = u.acl_id AND amn.module_id = %d AND amn.node_id = %d ' . 'WHERE ugc2.user_id = %d ' . 'ORDER BY u.full_name', $DB->prefix, $DB->prefix, $DB->prefix, $DB->prefix, $DB->prefix, $module_id, $node_id, $user_id);
    }
    $retval = $DB->exec($sql);
    // at this point we have a temporary table with all 'editable' accounts
    // we first add those to the dialogdef.
    $table = 'crew_tmp';
    $fields = '*';
    $where = '';
    $order = array('full_name', 'username');
    if (($records = db_select_all_records($table, $fields, $where, $order)) === FALSE) {
        logger(sprintf('%s(): error retrieving elegible CREW-members: %s', __FUNCTION__, db_errormessage()));
        $output->add_message(t('error_retrieving_data', 'admin'));
    } else {
        foreach ($records as $record) {
            $acl_id = intval($record['acl_id']);
            $name = 'acl_rw_' . $acl_id;
            $dialogdef[$name] = array('type' => F_LISTBOX, 'name' => $name, 'value' => is_null($record['permissions_modules']) ? 0 : $record['permissions_modules'], 'old_value' => $record['permissions_modules'], 'acl_id' => $acl_id, 'options' => $roles, 'viewonly' => $viewonly, 'title' => $record['username'], 'label' => $record['full_name']);
        }
    }
    // the next step is to generate a list of any OTHER accounts that happen to have
    // permissions for this module on this node other than ACL_ROLE_NONE.
    // This list consists of a few UNIONs that effectively yields all accounts that
    // somehow have a non-0 permissions_modules, either global (acls), any node for
    // this module (acls_modules), any node within this area (acls_modules_area),
    // any node that is an ancestor of node_id (acls_modules_nodes) OR this specific
    // node for a user that is NOT an acquaintance (ie. who is not in the temp table).
    // Note that we don't check the ancestors (parents) when node happens to be at
    // the top level within the area, ie. when parent is 0. We also peek inside
    // 'acls_areas' and 'acls_nodes'. Pfew, complicated...
    // All these OTHER accounts cannot be manipulated by $USER because all accounts
    // would then be in the temp table, so there.
    // Since there may be more records for the same user (or rather acl_id), we need
    // to drill down the results. As all permissions are additive we can simply OR
    // these together per acl_id/user which yields a single combined role for that user.
    $tree = tree_build($area_id);
    $ancestors = array();
    for ($next_id = $tree[$node_id]['parent_id']; $next_id; $next_id = $tree[$next_id]['parent_id']) {
        $ancestors[] = $next_id;
    }
    unset($tree);
    $sql = empty($ancestors) ? '' : sprintf('SELECT u.acl_id, u.username, u.full_name, amn.permissions_modules  ' . 'FROM %susers u INNER JOIN %sacls_modules_nodes amn USING (acl_id) ' . 'WHERE amn.permissions_modules <> 0 AND amn.module_id = %d AND amn.node_id IN (%s)', $DB->prefix, $DB->prefix, $module_id, join(',', $ancestors)) . ' UNION ' . sprintf('SELECT u.acl_id, u.username, u.full_name, an.permissions_modules  ' . 'FROM %susers u INNER JOIN %sacls_nodes an USING (acl_id) ' . 'WHERE an.permissions_modules <> 0 AND an.node_id IN (%s)', $DB->prefix, $DB->prefix, join(',', $ancestors)) . ' UNION ';
    $sql .= sprintf('SELECT u.acl_id, u.username, u.full_name, a.permissions_modules ' . 'FROM %susers u INNER JOIN %sacls a USING (acl_id) ' . 'WHERE a.permissions_modules <> 0', $DB->prefix, $DB->prefix) . ' UNION ' . sprintf('SELECT u.acl_id, u.username, u.full_name, am.permissions_modules  ' . 'FROM %susers u INNER JOIN %sacls_modules am USING (acl_id) ' . 'WHERE am.permissions_modules <> 0 AND am.module_id = %d', $DB->prefix, $DB->prefix, $module_id) . ' UNION ' . sprintf('SELECT u.acl_id, u.username, u.full_name, aa.permissions_modules  ' . 'FROM %susers u INNER JOIN %sacls_areas aa USING (acl_id) ' . 'WHERE aa.permissions_modules <> 0 AND aa.area_id = %d', $DB->prefix, $DB->prefix, $area_id) . ' UNION ' . sprintf('SELECT u.acl_id, u.username, u.full_name, ama.permissions_modules  ' . 'FROM %susers u INNER JOIN %sacls_modules_areas ama USING (acl_id) ' . 'WHERE ama.permissions_modules <> 0 AND ama.module_id = %d AND ama.area_id = %d', $DB->prefix, $DB->prefix, $module_id, $area_id) . ' UNION ' . sprintf('SELECT u.acl_id, u.username, u.full_name, an.permissions_modules  ' . 'FROM %susers u INNER JOIN %sacls_nodes an USING (acl_id) ' . 'WHERE an.permissions_modules <> 0 AND an.node_id = %d', $DB->prefix, $DB->prefix, $node_id) . ' UNION ' . sprintf('SELECT u.acl_id, u.username, u.full_name, amn.permissions_modules  ' . 'FROM %susers u INNER JOIN %sacls_modules_nodes amn USING (acl_id) ' . 'LEFT JOIN %screw_tmp tmp USING(acl_id) ' . 'WHERE amn.permissions_modules <> 0 AND amn.module_id = %d AND amn.node_id = %d ' . 'AND tmp.acl_id IS NULL ', $DB->prefix, $DB->prefix, $DB->prefix, $module_id, $node_id) . 'ORDER BY full_name, acl_id';
    if (($result = $DB->query($sql)) === FALSE) {
        logger(sprintf('%s(): error retrieving other account names: %s', __FUNCTION__, db_errormessage()));
        $output->add_message(t('error_retrieving_data', 'admin'));
    } else {
        if ($result->num_rows > 0) {
            $records = array();
            while (($record = $result->fetch_row_assoc()) !== FALSE) {
                $acl_id = intval($record['acl_id']);
                if (isset($records[$acl_id])) {
                    $records[$acl_id]['permissions_modules'] |= intval($record['permissions_modules']);
                } else {
                    $records[$acl_id] = $record;
                }
            }
            $result->close();
            foreach ($records as $acl_id => $record) {
                $name = 'acl_ro_' . $acl_id;
                $dialogdef[$name] = array('type' => F_LISTBOX, 'name' => $name, 'value' => is_null($record['permissions_modules']) ? 0 : $record['permissions_modules'], 'options' => $roles, 'viewonly' => TRUE, 'title' => $record['username'], 'label' => $record['full_name']);
            }
        }
    }
    if (!$viewonly) {
        $dialogdef['button_save'] = dialog_buttondef(BUTTON_SAVE);
    }
    $dialogdef['button_cancel'] = dialog_buttondef(BUTTON_CANCEL);
    return $dialogdef;
}
/** add demonstration data to the system
 *
 * this routine adds demonstration data to the freshly installed system
 *
 * Note
 * If the theme is installed via the Install Wizard, this routine is
 * called. However, if a theme is installed as an additional theme
 * after installation, the {$theme}_demodata() routine is never called.
 * This is because the only time you know that demodata is installed is
 * when the Install Wizard runs. If we're called from admin.php, the
 * webmaster may have already deleted existing (core) demodata so you
 * never can be sure what to expect. To put it another way: it is hard
 * to re-construct $config when we're NOT the Instal Wizard.
 *
 * The array $config contains the following information.
 *
 * <code>
 * $config['language_key']   => install language code (eg. 'en')
 * $config['dir']            => path to CMS Root Directory (eg. /home/httpd/htdocs)
 * $config['www']            => URL of CMS Root Directory (eg. http://exemplum.eu)
 * $config['progdir']        => path to program directory (eg. /home/httpd/htdocs/program)
 * $config['progwww']        => URL of program directory (eg. http://exemplum.eu/program)
 * $config['datadir']        => path to data directory (eg. /home/httpd/wasdata/a1b2c3d4e5f6)
 * $config['user_username']  => userid of webmaster (eg. wblader)
 * $config['user_full_name'] => full name of webmaster (eg. Wilhelmina Bladergroen)
 * $config['user_email']     => email of webmaster (eg. w.bladergroen@exemplum.eu)
 * $config['user_id']        => numerical user_id (usually 1)
 * $config['demo_salt']      => password salt for all demodata accounts
 * $config['demo_password']  => password for all demodata accounts
 * $config['demo_areas']     => array with demo area data
 * $config['demo_groups']    => array with demo group data
 * $config['demo_users']     => array with demo user data
 * $config['demo_nodes']     => array with demo node data
 * </code>
 *
 * With this information, we can add a demonstration configuration for the public area,
 * which shows off the possibilities.
 *
 * @param array &$messages collects the (error) messages
 * @param int $theme_id the key for this theme in the themes table
 * @param array $config pertinent data for the new website + demodata foundation
 * @param array $manifest a copy from the manifest for this theme
 * @return bool TRUE on success + output via $messages, FALSE otherwise
 */
function schoolyard_demodata(&$messages, $theme_id, $config, $manifest)
{
    global $DB;
    $retval = TRUE;
    // assume success
    // 0 -- get hold of our translations in $string[]
    $string = array();
    $language_key = $config['language_key'];
    $filename = dirname(__FILE__) . '/languages/' . $language_key . '/schoolyard.php';
    if (!file_exists($filename)) {
        $filename = dirname(__FILE__) . '/languages/en/schoolyard.php';
    }
    @(include $filename);
    if (empty($string)) {
        $messages[] = 'Internal error: no translations in ' . $filename;
        return FALSE;
    }
    // 1A -- prepare for setting up demo settings
    $quicktop_section_id = intval($config['demo_nodes']['quicktop']['node_id']);
    $quickbottom_section_id = intval($config['demo_nodes']['quickbottom']['node_id']);
    $www = $config['www'];
    $area_id = intval($config['demo_areas']['public']['area_id']);
    $theme_id = intval($theme_id);
    // 1B -- actually setup settings
    $settings = array('quicktop_section_id' => strval($quicktop_section_id), 'quickbottom_section_id' => strval($quickbottom_section_id), 'show_breadcrumb_trail' => '1', 'logo_image' => 'program/themes/schoolyard/waslogo.png', 'logo_width' => '284', 'logo_height' => '71', 'style_usage_static' => '1', 'stylesheet' => 'program/themes/schoolyard/style.css', 'stylesheet_print' => 'program/themes/schoolyard/print.css', 'style_usage_area' => '1', 'style' => '', 'style_usage_node' => '1');
    // 2A -- start with the default settings (copy from theme_properties)
    $sql = sprintf('INSERT INTO %s%s(area_id,theme_id,name,type,value,extra,sort_order,description) ' . 'SELECT %d AS area_id,theme_id,name,type,value,extra,sort_order,description ' . 'FROM %s%s ' . 'WHERE theme_id = %d', $DB->prefix, 'themes_areas_properties', $area_id, $DB->prefix, 'themes_properties', $theme_id);
    if ($DB->exec($sql) === FALSE) {
        $messages[] = __FUNCTION__ . '(): ' . db_errormessage();
        $retval = FALSE;
    }
    // 2B -- update/overwrite the default settings with our own demo-data for area $area_id
    foreach ($settings as $name => $value) {
        $fields = array('value' => strval($value));
        $where = array('area_id' => $area_id, 'theme_id' => $theme_id, 'name' => strval($name));
        if (db_update('themes_areas_properties', $fields, $where) === FALSE) {
            $messages[] = __FUNCTION__ . '(): ' . db_errormessage();
            $retval = FALSE;
        }
    }
    return $retval;
}
Пример #25
0
/** quick and dirty logfile viewer
 *
 * this constructs a table of the HTML-variety with the contents of the logtable.
 * fields displayed are: datim, IP-address, username, logpriority and message
 * we use a LEFT JOIN in order to get to a meaningful username rather than a numeric user_id
 * an attempt is made to start with the last page of the logs because that would probably
 * be the most interesting part. We paginate the log in order to keep it manageable.
 *
 * &lt;Rant&gt;<br>
 * I used to use the built-in constants like LOG_INFO and LOG_DEBUG to allow for different levels
 * of logging (see {@link logger()}). To my complete surprise logging didn't work at all on
 * Windows (it did on Linux). The reason was that LOG_DEBUG and LOG_INFO and LOG_NOTICE are all
 * defined to be the same value. WTF? Any test based on LOG_DEBUG and LOG_INFO being different
 * would fail, hence no logging at all. The mind boggles! So, instead of using built-in constants
 * I had to define my own and do a global search&replace. Aaarghhhhhh!!!!<br>
 * &lt;/Rant&gt;<br>
 *
 * @param object &$output collects output to show to user
 * @return void output displayed via $output
 * @todo should we allow for fancy selection mechanisms on the logfile or is that over the top?
 */
function task_logview(&$output)
{
    global $CFG, $WAS_SCRIPT_NAME, $DB;
    static $priorities = array(WLOG_EMERG => 'LOG_EMERG', WLOG_ALERT => 'LOG_ALERT', WLOG_CRIT => 'LOG_CRIT', WLOG_ERR => 'LOG_ERR', WLOG_WARNING => 'LOG_WARNING', WLOG_NOTICE => 'LOG_NOTICE', WLOG_INFO => 'LOG_INFO', WLOG_DEBUG => 'LOG_DEBUG');
    // 0 -- at least we allow the user to navigate away if something goes wrong
    $output->set_helptopic('logview');
    show_tools_menu($output, TASK_LOGVIEW);
    // 1A -- how many messages are there anyway?
    $table = 'log_messages';
    $where = '';
    // could be used to select per user, per priority, etc. For now: always select everything
    if (($record = db_select_single_record($table, 'COUNT(log_message_id) AS messages', $where)) === FALSE) {
        $output->add_content('<h2>' . t('menu_logview', 'admin') . '</h2>');
        $output->add_content(t('logview_error', 'admin'));
        $output->add_message(t('logview_error', 'admin'));
        logger(sprintf('%s(): cannot retrieve log message count: %s', __FUNCTION__, db_errormessage()));
        return;
    }
    // 1B -- if there are no message we leave
    if (($num_messages = intval($record['messages'])) < 1) {
        $output->add_content('<h2>' . t('menu_logview', 'admin') . '</h2>');
        $output->add_content(t('logview_no_messages', 'admin'));
        $output->add_message(t('logview_no_messages', 'admin'));
        logger(sprintf('%s(): no messages to show', __FUNCTION__), WLOG_DEBUG);
        return;
    }
    // 2 -- which part of the logs do they want to see? (calculate/retrieve offset and limit)
    $limit = get_parameter_int('limit', $CFG->pagination_height);
    $limit = max(1, $limit);
    // make sure 1 <= $limit
    $offset = intval(floor($num_messages / $limit)) * $limit;
    // attempt to start at begin of LAST page
    $offset = get_parameter_int('offset', max($offset, 0));
    $offset = max(min($num_messages - 1, $offset), 0);
    // make sure 0 <= $offset < $num_messages
    // 3 -- show the pagination in the page header (if necessary)
    if ($num_messages <= $limit && $offset == 0) {
        // listing fits on a single screen
        $header = '<h2>' . t('menu_logview', 'admin') . '</h2>';
    } else {
        // pagination necessary, tell user where we are
        $param = array('{FIRST}' => strval($offset + 1), '{LAST}' => strval(min($num_messages, $offset + $limit)), '{TOTAL}' => strval($num_messages));
        $header = '<h2>' . t('menu_logview', 'admin') . ' ' . t('pagination_count_of_total', 'admin', $param) . '</h2>';
        $parameters = array('job' => JOB_TOOLS, 'task' => TASK_LOGVIEW);
        $output->add_pagination($WAS_SCRIPT_NAME, $parameters, $num_messages, $limit, $offset, $CFG->pagination_width);
    }
    // 4 -- retrieve the selected messages (including optional username via LEFT JOIN)
    $sql = sprintf('SELECT l.datim, l.remote_addr, l.priority, l.user_id, u.username, l.message ' . 'FROM %slog_messages l LEFT JOIN %susers u USING (user_id) ' . 'ORDER BY l.datim, l.log_message_id', $DB->prefix, $DB->prefix);
    if (($DBResult = $DB->query($sql, $limit, $offset)) === FALSE) {
        $output->add_message(t('logview_error', 'admin'));
        logger(sprintf('%s(): cannot retrieve log messages: %s', __FUNCTION__, db_errormessage()));
        return;
    }
    $records = $DBResult->fetch_all_assoc();
    $DBResult->close();
    // 5A -- setup a table with a header
    $index = $offset + 1;
    $output->add_content($header);
    $class = 'header';
    $attributes = array('class' => $class, 'align' => 'right');
    $output->add_content('<p>');
    $output->add_content(html_table(array('cellpadding' => '3')));
    $output->add_content('  ' . html_table_row($attributes));
    $output->add_content('    ' . html_table_head($attributes, t('logview_nr', 'admin')));
    $attributes['align'] = 'left';
    $output->add_content('    ' . html_table_head($attributes, t('logview_datim', 'admin')));
    $output->add_content('    ' . html_table_head($attributes, t('logview_remote_addr', 'admin')));
    $output->add_content('    ' . html_table_head($attributes, t('logview_user_id', 'admin')));
    $output->add_content('    ' . html_table_head($attributes, t('logview_priority', 'admin')));
    $output->add_content('    ' . html_table_head($attributes, t('logview_message', 'admin')));
    $output->add_content('  ' . html_table_row_close());
    // 5B -- step through the recordset and dump into the table
    foreach ($records as $record) {
        $class = $class == 'odd' ? 'even' : 'odd';
        $priority = isset($priorities[$record['priority']]) ? $priorities[$record['priority']] : strval(intval($record['priority']));
        $attributes = array('class' => $class);
        $output->add_content('  ' . html_table_row($attributes));
        $attributes['align'] = 'right';
        $output->add_content('    ' . html_table_cell($attributes, strval($index++)));
        $attributes['align'] = 'left';
        $output->add_content('    ' . html_table_cell($attributes, htmlspecialchars($record['datim'])));
        $output->add_content('    ' . html_table_cell($attributes, htmlspecialchars($record['remote_addr'])));
        $output->add_content('    ' . html_table_cell($attributes, htmlspecialchars($record['username'])));
        $output->add_content('    ' . html_table_cell($attributes, $priority));
        $output->add_content('    ' . html_table_cell($attributes, htmlspecialchars($record['message'])));
        $output->add_content('  ' . html_table_row_close());
    }
    // 5C -- all done
    $output->add_content(html_table_close());
    $output->add_content('<p>');
}
 /** retrieve an array with 0, 1 or more records with permissions from table 'acls_nodes'
  *
  * this constructs an array with all permissions from the 'acls_nodes' table for the
  * specified acl $acl_id and optionally for all related acl_id's in $related_acls and optional
  * nodes. The resulting array is keyed by node_id and acl_id.
  *
  * Note that by making the result keyed by node_id first (and then acl_id) it becomes possible
  * to step throug a list of nodes and have 0,1 or more acls for that node in a single array,
  * e.g. $acls = $permissions[16] yields the selected acls that apply to node 16. That is handy
  * when constructing dialogs iterating through nodes such as pagemanager permissions.
  *
  * @param array $area_id the area where the nodes reside
  * @param int $acl_id the primary acl_id (used for both users and groups)
  * @param array|null $related_acls an array with related acls for this user keyed by 'acl_id' or NULL for group acls
  * @return array 0, 1 or more acls-records keyed by node_id and acl_id
  */
 function get_permissions_nodes_in_area($area_id, $acl_id, $related_acls = NULL)
 {
     global $DB;
     $fields = '*';
     // 1A -- selection of acls via '((an.acl_id = 1) OR (an.acl_id = 2) OR (an.acl_id = 3))'
     $where = sprintf("(an.acl_id = %d)", $acl_id);
     if (!empty($related_acls)) {
         foreach ($related_acls as $id => $acl) {
             $where .= sprintf(" OR (an.acl_id = %d)", $id);
         }
         $where = "(" . $where . ")";
     }
     $sql = sprintf("SELECT an.* " . "FROM %sacls_nodes an " . "INNER JOIN %snodes n ON ((an.node_id = n.node_id) AND (n.area_id = %d)) " . "WHERE %s", $DB->prefix, $DB->prefix, $area_id, $where);
     // 2 -- fetch raw data from the database in a single set of database records
     if (($DBResult = $DB->query($sql)) === FALSE) {
         logger('aclmanager(): cannot retrieve nodes permissions in area $area_id: ' . db_errormessage());
         return array();
     }
     $records = $DBResult->fetch_all_assoc();
     $DBResult->close();
     // 3 -- construct a 2D-array keyed with node_id and acl_id (in that order)
     $permissions = array();
     foreach ($records as $record) {
         $node_id = intval($record['node_id']);
         $acl_id = intval($record['acl_id']);
         $permissions[$node_id][$acl_id] = $record;
     }
     unset($records);
     return $permissions;
 }
/** add demonstration data to the system
 *
 * this routine adds demonstration data to the freshly installed system
 *
 * Note
 * If the theme is installed via the Install Wizard, this routine is
 * called. However, if a theme is installed as an additional theme
 * after installation, the {$theme}_demodata() routine is never called.
 * This is because the only time you know that demodata is installed is
 * when the Install Wizard runs. If we're called from admin.php, the
 * webmaster may have already deleted existing (core) demodata so you
 * never can be sure what to expect. To put it another way: it is hard
 * to re-construct $config when we're NOT the Instal Wizard.
 *
 * The array $config contains the following information.
 *
 * <code>
 * $config['language_key']   => install language code (eg. 'en')
 * $config['dir']            => path to CMS Root Directory (eg. /home/httpd/htdocs)
 * $config['www']            => URL of CMS Root Directory (eg. http://exemplum.eu)
 * $config['progdir']        => path to program directory (eg. /home/httpd/htdocs/program)
 * $config['progwww']        => URL of program directory (eg. http://exemplum.eu/program)
 * $config['datadir']        => path to data directory (eg. /home/httpd/wasdata/a1b2c3d4e5f6)
 * $config['user_username']  => userid of webmaster (eg. wblader)
 * $config['user_full_name'] => full name of webmaster (eg. Wilhelmina Bladergroen)
 * $config['user_email']     => email of webmaster (eg. w.bladergroen@exemplum.eu)
 * $config['user_id']        => numerical user_id (usually 1)
 * $config['demo_salt']      => password salt for all demodata accounts
 * $config['demo_password']  => password for all demodata accounts
 * $config['demo_areas']     => array with demo area data
 * $config['demo_groups']    => array with demo group data
 * $config['demo_users']     => array with demo user data
 * $config['demo_nodes']     => array with demo node data
 * </code>
 *
 * With this information, we can add a demonstration configuration for the public area,
 * which shows off the possibilities.
 *
 * @param array &$messages collects the (error) messages
 * @param int $theme_id the key for this theme in the themes table
 * @param array $config pertinent data for the new website + demodata foundation
 * @param array $manifest a copy from the manifest for this theme
 * @return bool TRUE on success + output via $messages, FALSE otherwise
 */
function rosalina_demodata(&$messages, $theme_id, $config, $manifest)
{
    global $DB;
    $retval = TRUE;
    // assume success
    // 0 -- get hold of our translations in $string[]
    $string = array();
    $language_key = $config['language_key'];
    $filename = dirname(__FILE__) . '/languages/' . $language_key . '/rosalina.php';
    if (!file_exists($filename)) {
        $filename = dirname(__FILE__) . '/languages/en/rosalina.php';
    }
    @(include $filename);
    if (empty($string)) {
        $messages[] = 'Internal error: no translations in ' . $filename;
        return FALSE;
    }
    // 1A -- prepare for setting up demo settings
    $quicktop_section_id = intval($config['demo_nodes']['quicktop']['node_id']);
    $quickbottom_section_id = intval($config['demo_nodes']['quickbottom']['node_id']);
    $www = $config['www'];
    $area_id = intval($config['demo_areas']['public']['area_id']);
    $theme_id = intval($theme_id);
    // Hotspot 1 - the blue jigsaw piece leads to admin.php
    $hotspot_1 = implode(';', array('poly', '0,0,37,37,52,22,52,0', $www . '/admin.php', $string['demo_admin_php_title']));
    // Hotspot 2 - the gray jigsaw piece leads to login/logout (index.php)
    $hotspot_2 = implode(';', array('poly', '0,1,37,38,5,70,0,70', $www . '/index.php?login=1', $string['demo_index_php_login_title'], $www . '/index.php?logout=1', $string['demo_index_php_logout_title']));
    // Hotspot 3 - the red jigsaw piece leads to the websiteatschool project website in a new window
    $hotspot_3 = implode(';', array('poly', '6,70,52,24,52,70', 'http://websiteatschool.eu', $string['demo_websiteatschool_eu_title'], '', '', '_blank'));
    // Hotspot 4 - the red word 'Website' leads to the defaul area (via index.php without parameters)
    $hotspot_4 = implode(';', array('rect', '53,17,157,58', $www . '/index.php', $string['demo_index_php_title']));
    // Hotspot 5 - the gray word '@' leads to the demodata contact page
    $hotspot_5 = implode(';', array('circle', '173,36,15', sprintf('%s/index.php?node=%d', $www, $config['demo_nodes']['contact']['node_id']), $config['demo_nodes']['contact']['title']));
    // Hotspot 6 - the blue word 'School' leads explicitly to the public area (via index.php?area=NN)
    $hotspot_6 = implode(';', array('rect', '189,9,279,58', sprintf('%s/index.php?area=%d', $www, $area_id), $config['demo_areas']['public']['title']));
    // 1B -- actually setup settings
    $settings = array('quicktop_section_id' => strval($quicktop_section_id), 'quickbottom_section_id' => strval($quickbottom_section_id), 'show_breadcrumb_trail' => '1', 'logo_image' => 'program/themes/rosalina/waslogo.png', 'logo_width' => '284', 'logo_height' => '71', 'logo_title' => $string['demo_logo_title'], 'logo_alt' => $string['demo_logo_alt'], 'logo_hotspots' => '6', 'logo_hotspot_1' => $hotspot_1, 'logo_hotspot_2' => $hotspot_2, 'logo_hotspot_3' => $hotspot_3, 'logo_hotspot_4' => $hotspot_4, 'logo_hotspot_5' => $hotspot_5, 'logo_hotspot_6' => $hotspot_6, 'logo_hotspot_7' => '', 'logo_hotspot_8' => '', 'style_usage_static' => '1', 'stylesheet' => 'program/themes/rosalina/style.css', 'style_usage_area' => '1', 'style' => '', 'style_usage_node' => '1', 'hvmenu_LowBgColor' => '#FFCCCC', 'hvmenu_LowSubBgColor' => '#FF9999', 'hvmenu_HighBgColor' => '#CCCCFF', 'hvmenu_HighSubBgColor' => '#CCCCFF', 'hvmenu_FontLowColor' => '#000000', 'hvmenu_FontSubLowColor' => '#000000', 'hvmenu_FontHighColor' => '#000000', 'hvmenu_FontSubHighColor' => '#000000', 'hvmenu_BorderColor' => '#666666', 'hvmenu_BorderSubColor' => '#666666', 'hvmenu_BorderWidth' => '1', 'hvmenu_BorderBtwnElmnts' => '1', 'hvmenu_FontFamily' => 'Verdana,sans-serif', 'hvmenu_FontSize' => '9.5', 'hvmenu_FontBold' => '1', 'hvmenu_FontItalic' => '0', 'hvmenu_MenuTextCentered' => 'left', 'hvmenu_MenuCentered' => 'left', 'hvmenu_MenuVerticalCentered' => 'top', 'hvmenu_ChildOverlap' => '0.0', 'hvmenu_ChildVerticalOverlap' => '0.0', 'hvmenu_StartTop' => '0', 'hvmenu_StartLeft' => '0', 'hvmenu_LeftPaddng' => '8', 'hvmenu_TopPaddng' => '2', 'hvmenu_FirstLineHorizontal' => '1', 'hvmenu_DissapearDelay' => '1000', 'hvmenu_MenuWrap' => '1', 'hvmenu_RightToLeft' => '0', 'hvmenu_UnfoldsOnClick' => '0', 'hvmenu_ShowArrow' => '1', 'hvmenu_KeepHilite' => '1', 'hvmenu_Arrws' => 'tri.gif,5,10,tridown.gif,10,5,trileft.gif,5,10', 'menu_top' => '120,10,300,20', 'menu_sub' => '150,10,500,20');
    // 2A -- start with the default settings (copy from theme_properties)
    $sql = sprintf('INSERT INTO %s%s(area_id,theme_id,name,type,value,extra,sort_order,description) ' . 'SELECT %d AS area_id,theme_id,name,type,value,extra,sort_order,description ' . 'FROM %s%s ' . 'WHERE theme_id = %d', $DB->prefix, 'themes_areas_properties', $area_id, $DB->prefix, 'themes_properties', $theme_id);
    if ($DB->exec($sql) === FALSE) {
        $messages[] = __FUNCTION__ . '(): ' . db_errormessage();
        $retval = FALSE;
    }
    // 2B -- update/overwrite the default settings with our own demo-data for area $area_id
    foreach ($settings as $name => $value) {
        $fields = array('value' => strval($value));
        $where = array('area_id' => $area_id, 'theme_id' => $theme_id, 'name' => strval($name));
        if (db_update('themes_areas_properties', $fields, $where) === FALSE) {
            $messages[] = __FUNCTION__ . '(): ' . db_errormessage();
            $retval = FALSE;
        }
    }
    return $retval;
}
 /** save the modified configuration parameters to the database
  *
  * @param object &$output the object that collects the output
  * @result FALSE on error + error messages added to messages part of output or TRUE and data stored to database.
  * @uses dialog_validate()
  */
 function save_data(&$output)
 {
     if (empty($this->dialogdef)) {
         $this->dialogdef = $this->get_dialogdef();
     }
     if (!dialog_validate($this->dialogdef)) {
         foreach ($this->dialogdef as $k => $item) {
             if (isset($item['errors']) && $item['errors'] > 0) {
                 $output->add_message($item['error_messages']);
             }
         }
         return FALSE;
     }
     $errors = 0;
     $records_changed = 0;
     $records_unchanged = 0;
     if (is_array($this->records)) {
         foreach ($this->records as $id => $record) {
             $name = $this->prefix . 'record_' . strval($id);
             if (isset($this->dialogdef[$name])) {
                 if ($this->dialogdef[$name]['value'] != $this->dialogdef[$name]['old_value']) {
                     ++$records_changed;
                     $fields = array('value' => strval($this->dialogdef[$name]['value']));
                     $where = array($this->keyfield => $id);
                     if (db_update($this->table, $fields, $where) === FALSE) {
                         logger('configassistant: error saving config value: ' . db_errormessage());
                         ++$errors;
                     } else {
                         logger(sprintf("configassistant: success updating %s[%s] => '%s'", $this->table, $id, strval($this->dialogdef[$name]['value'])), WLOG_DEBUG);
                     }
                 } else {
                     ++$records_unchanged;
                 }
                 // if (modified)
             }
             // if (data available)
         }
         // foreach
     }
     // if (records)
     logger(sprintf('configassistant: save configuration in table %s: unchanged: %d, changed: %d, errors: %d', $this->table, $records_unchanged, $records_changed, $errors), WLOG_DEBUG);
     if ($errors == 0) {
         $output->add_message(t('success_saving_data', 'admin'));
         $retval = TRUE;
     } else {
         $output->add_message(t('errors_saving_data', 'admin', array('{ERRORS}' => strval($errors))));
         $retval = FALSE;
     }
     return $retval;
 }
/** display the content of the sitemap linked to node $node_id
 *
 * there are three different variations (depends on configuration parameter 'scope'):
 *
 *  - 0 (small): only show a map of the tree in the current area $area_id
 *  - 1 (medium): show a list of available areas followed by the map of the current area $area_id
 *  - 2 (large): show the maps of all available areas
 *
 * The default is 0 (small).
 *
 * @param object &$theme collects the (html) output
 * @param int $area_id identifies the area where $node_id lives
 * @param int $node_id the node to which this module is connected
 * @param array $module the module record straight from the database
 * @return bool TRUE on success + output via $theme, FALSE otherwise
 */
function sitemap_view(&$theme, $area_id, $node_id, $module)
{
    global $USER;
    //
    // 1 -- determine scope of sitemap: 0=small, 1=medium, 2=large
    //
    $table = 'sitemaps';
    $fields = array('header', 'introduction', 'scope');
    $where = array('node_id' => intval($node_id));
    $record = db_select_single_record($table, $fields, $where);
    if ($record === FALSE) {
        logger(sprintf('%s(): error retrieving configuration: %s', __FUNCTION__, db_errormessage()));
        $scope = 0;
        $header = '';
        $introduction = '';
    } else {
        $scope = intval($record['scope']);
        $header = trim($record['header']);
        $introduction = trim($record['introduction']);
    }
    //
    // 2 -- compute a list of areas to process (could be just 1)
    //
    // 2A -- retrieve all areas, including those out of bounds for this user
    if (($all_areas = get_area_records()) === FALSE) {
        logger(sprintf('%s(): huh? cannot get area records: %s', __FUNCTION__, db_errormessage()));
        return FALSE;
        // shouldn't happen
    }
    // 2B -- narrow down the selection (active, (private) access allowed, within scope)
    $areas = array();
    foreach ($all_areas as $id => $area) {
        if (db_bool_is(TRUE, $area['is_active']) && (db_bool_is(FALSE, $area['is_private']) || $USER->has_intranet_permissions(ACL_ROLE_INTRANET_ACCESS, $id))) {
            if ($scope == 2 || $scope == 1 || $scope == 0 && $id == $area_id) {
                $title = $area['title'];
                $params = array('area' => $id);
                $href = was_node_url(NULL, $params, $title, $theme->preview_mode);
                $areas[$id] = html_a($href, NULL, NULL, $title);
            }
        }
    }
    unset($all_areas);
    // $areas now holds all areas that we should to process
    if (sizeof($areas) <= 0) {
        logger(sprintf('%s(): weird, no areas to process; bailing out', __FUNCTION__));
        return FALSE;
        // shouldn't happen
    }
    //
    // 3 -- maybe output a header and an introduction
    //
    if (!empty($header)) {
        $theme->add_content('<h2>' . $header . '</h2>');
    }
    if (!empty($introduction)) {
        $theme->add_content($introduction);
    }
    //
    // 4 - Actually output a sitemap by walking the tree once for every elegible area
    //
    foreach ($areas as $id => $area_anchor) {
        if ($scope == 1 && $area_id != $id) {
            // 1=medium only shows area map of $area_id (and an area list lateron)
            continue;
        }
        // 4A -- output a clickable area title
        $theme->add_content('<h2>' . $area_anchor . '</h2>');
        // 4B -- fetch the tree for this area...
        $tree = tree_build($id);
        tree_visibility($tree[0]['first_child_id'], $tree);
        // 4C -- ...and walk the tree
        sitemap_tree_walk($theme, $tree[0]['first_child_id'], $tree);
        unset($tree);
    }
    if ($scope == 1) {
        $theme->add_content('<h2>' . t('sitemap_available_areas', 'm_sitemap') . '</h2>');
        $theme->add_content('<ul>');
        foreach ($areas as $id => $area_anchor) {
            $theme->add_content('<li>' . $area_anchor);
        }
        $theme->add_content('</ul>');
    }
    return TRUE;
    // indicate success
}
 /** generate a list of (virtual) directories for users this user can access
  *
  * This generates a list of (virtual) user directories for which this
  * user has access permissions. The list is ordered by full name.
  *
  * @return array list of available user directories for this user
  * @uses $USER;
  * @uses $CFG;
  */
 function get_entries_users()
 {
     global $USER, $CFG;
     $entries = array();
     if ($USER->has_job_permissions(JOB_PERMISSION_ACCOUNTMANAGER)) {
         $table = 'users';
         $fields = array('user_id', 'username', 'full_name', 'is_active', 'path');
         $where = '';
         $order = array('full_name', 'username');
         if (($users = db_select_all_records($table, $fields, $where, $order, 'user_id')) === FALSE) {
             logger(sprintf('%s.%s(): cannot retrieve users list: %s', __CLASS__, __FUNCTION__, db_errormessage()));
             $users = array();
         }
     } else {
         $users = array(array('user_id' => $USER->user_id, 'username' => $USER->username, 'full_name' => $USER->full_name, 'is_active' => TRUE, 'path' => $USER->path));
     }
     if (count($users) > 0) {
         foreach ($users as $user_id => $user) {
             $name = $user['path'];
             $path = '/users/' . $name;
             $vname = $user['full_name'];
             $vpath = t('filemanager_users', 'admin') . '/' . $vname;
             $entries[$name] = array('name' => $name, 'path' => $path, 'vname' => $vname, 'vpath' => $vpath, 'mtime' => filemtime($CFG->datadir . $path), 'size' => 0, 'is_file' => FALSE, 'title' => t('filemanager_navigate_to', 'admin', array('{DIRECTORY}' => $vpath)));
         }
     }
     return $entries;
 }