+ */
+ function catalog_template_files($template_set_id, $file_list=array(), $directory='') {
+
+ $template_base_dir = SM_PATH
+ . Template::calculate_template_file_directory($template_set_id);
+
+ if (empty($directory)) {
+ $directory = $template_base_dir;
+ }
+
+
+ // bail if we have been asked to traverse a Subversion directory
+ //
+ if (strpos($directory, '/.svn') === strlen($directory) - 5) return $file_list;
+
+
+ $files_and_dirs = list_files($directory, '', FALSE, TRUE, FALSE, TRUE);
+
+ // recurse for all the subdirectories in the template set
+ //
+ foreach ($files_and_dirs['DIRECTORIES'] as $dir) {
+ $file_list = Template::catalog_template_files($template_set_id, $file_list, $dir);
+ }
+
+ // place all found files in the cache
+ // FIXME: assuming PHP template engine may not necessarily be a good thing
+ //
+ $engine = Template::get_template_config($template_set_id,
+ 'template_engine', SQ_PHP_TEMPLATE);
+ foreach ($files_and_dirs['FILES'] as $file) {
+
+ // remove the part of the file path corresponding to the
+ // template set's base directory
+ //
+ $relative_file = substr($file, strlen($template_base_dir));
+
+ /**
+ * only put file in cache if not already found in earlier template
+ * PATH should be relative to SquirrelMail top directory
+ */
+ if (!isset($file_list[$relative_file])) {
+ $file_list[$relative_file] = array(
+ 'PATH' => substr($file,strlen(SM_PATH)),
+ 'SET_ID' => $template_set_id,
+ 'ENGINE' => $engine,
+ );
+ }
+
+ }
+
+
+ // now if we are currently at the top-level of the template
+ // set base directory, we need to move on to the parent
+ // template set, if any
+ //
+ if ($directory == $template_base_dir) {
+
+ // use fallback when we run out of parents
+ //
+ $fallback_id = Template::get_fallback_template_set();
+ $parent_id = Template::get_template_config($template_set_id,
+ 'parent_template_set',
+ $fallback_id);
+
+ // were we already all the way to the last level? just exit
+ //
+ // note that this code allows the fallback set to have
+ // a parent, too, but can result in endless loops
+ // if ($parent_id == $template_set_id) {
+ //
+ if ($fallback_id == $template_set_id) {
+ return $file_list;
+ }
+
+ $file_list = Template::catalog_template_files($parent_id, $file_list);
+
+ }
+
+ return $file_list;
+
+ }
+
+ /**
+ * Look for a template file in a plugin; add to template
+ * file cache if found.
+ *
+ * The file is searched for in the following order:
+ *
+ * - A directory for the current template set within the plugin:
+ * SM_PATH/plugins/<plugin name>/templates/<template name>/
+ * - In a directory for one of the current template set's ancestor
+ * (inherited) template sets within the plugin:
+ * SM_PATH/plugins/<plugin name>/templates/<parent template name>/
+ * - In a directory for the fallback template set within the plugin:
+ * SM_PATH/plugins/<plugin name>/templates/<fallback template name>/
+ *
+ * @param string $plugin The name of the plugin
+ * @param string $file The name of the template file
+ * @param string $template_set_id The ID of the template for which
+ * to start looking for the file
+ * (optional; default is current
+ * template set ID).
+ *
+ * @return boolean TRUE if the template file was found, FALSE otherwise.
+ *
+ */
+ function find_and_cache_plugin_template_file($plugin, $file, $template_set_id='') {
+
+ if (empty($template_set_id))
+ $template_set_id = $this->template_set_id;
+
+ $file_path = SM_PATH . 'plugins/' . $plugin . '/'
+ . $this->calculate_template_file_directory($template_set_id)
+ . $file;
+
+ if (file_exists($file_path)) {
+ // FIXME: assuming PHP template engine may not necessarily be a good thing
+ $engine = $this->get_template_config($template_set_id,
+ 'template_engine', SQ_PHP_TEMPLATE);
+ $file_list = array('plugins/' . $plugin . '/' . $file => array(
+ 'PATH' => substr($file_path, strlen(SM_PATH)),
+ 'SET_ID' => $template_set_id,
+ 'ENGINE' => $engine,
+ )
+ );
+ $this->template_file_cache
+ = $this->cache_template_file_hierarchy(FALSE, $file_list);
+ return TRUE;
+ }
+
+
+ // not found yet, try parent template set
+ // (use fallback when we run out of parents)
+ //
+ $fallback_id = $this->get_fallback_template_set();
+ $parent_id = $this->get_template_config($template_set_id,
+ 'parent_template_set',
+ $fallback_id);
+
+ // were we already all the way to the last level? just exit
+ //
+ // note that this code allows the fallback set to have
+ // a parent, too, but can result in endless loops
+ // if ($parent_id == $template_set_id) {
+ //
+ if ($fallback_id == $template_set_id) {
+ return FALSE;
+ }
+
+ return $this->find_and_cache_plugin_template_file($plugin, $file, $parent_id);
+
+ }
+
+ /**
+ * Find the right template file.
+ *
+ * The template file is taken from the template file cache, thus
+ * the file is taken from the current template, one of its
+ * ancestors or the fallback template.