-
dockx thibault authoredVerifiedd93751ba
<?php
/*
This code is part of FusionDirectory (http://www.fusiondirectory.org/)
Copyright (C) 2011-2016 FusionDirectory
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
class ThemeFileParsingException extends Exception
{
}
/*!
* \brief Icon theme directory
*/
class IconThemeDir
{
/* Nominal (unscaled) size of the icons in this directory.
* Required. */
private $Size;
/* Specifies the minimum (unscaled) size that the icons in this directory can be scaled to.
* Defaults to the value of Size if not present. */
private $MinSize;
/* Specifies the maximum (unscaled) size that the icons in this directory can be scaled to.
* Defaults to the value of Size if not present. */
private $MaxSize;
/* The type of icon sizes for the icons in this directory.
* Valid types are Fixed, Scalable and Threshold.
* The type decides what other keys in the section are used.
* If not specified, the default is Threshold. */
private $Type = 'Threshold';
/* The icons in this directory can be used if the size differ at most this much from the desired (unscaled) size.
* Defaults to 2 if not present. */
private $Threshold = 2;
function __construct ($infos)
{
$this->Size = $infos['Size'];
$this->MinSize = $infos['Size'];
$this->MaxSize = $infos['Size'];
foreach (['Type', 'MaxSize', 'MinSize', 'Threshold'] as $key) {
if (isset($infos[$key])) {
$this->$key = $infos[$key];
}
}
/* Thanks to this Threshold and Scaled are the same */
if ($this->Type == 'Threshold') {
$this->MinSize = $this->Size - $this->Threshold;
$this->MaxSize = $this->Size + $this->Threshold;
}
}
function MatchesSize ($size)
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
{
switch ($this->Type) {
case 'Fixed':
return ($this->Size == $size);
case 'Threshold':
case 'Scalable':
default:
return (($this->MinSize <= $size) && ($size <= $this->MaxSize));
}
}
function SizeDistance ($size)
{
switch ($this->Type) {
case 'Fixed':
return abs($this->Size - $size);
case 'Threshold':
case 'Scalable':
default:
if ($size < $this->MinSize) {
return $this->MinSize - $size;
}
if ($size > $this->MaxSize) {
return $size - $this->MaxSize;
}
return 0;
}
}
}
/*!
* \brief Icon theme
*/
class IconTheme
{
private $subdirs = [];
private $path;
private $parent;
function __construct ($folder, $default_parent)
{
$this->path = $folder;
$datas = @parse_ini_file($folder . '/index.theme', TRUE, INI_SCANNER_RAW);
if ($datas === FALSE) {
throw new ThemeFileParsingException('Error while parsing theme file');
}
if (isset($datas['Icon Theme']['Directories']) && !empty($datas['Icon Theme']['Directories'])) {
$dirs = preg_split('/,/', $datas['Icon Theme']['Directories']);
foreach ($dirs as $name) {
if (isset($datas[$name])) {
$this->subdirs[strtolower($datas[$name]['Context'])][$name] = new IconThemeDir($datas[$name]);
}
}
}
if (isset($datas['Icon Theme']['Inherits'])) {
$this->parent = $datas['Icon Theme']['Inherits'];
} else {
$this->parent = $default_parent;
}
}
function FindIcon ($context, $icon, $size)
{
$context = strtolower($context);
return $this->FindIconHelper($context, $icon, $size);
}
function FindIconHelper ($context, $icon, $size)
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
{
$filename = $this->LookupIcon($context, $icon, $size);
if ($filename != NULL) {
return $filename;
}
if (isset(static::$fallbacks[$context . '/' . $icon])) {
foreach (static::$fallbacks[$context . '/' . $icon] as $fallback) {
$filename = $this->LookupIcon($fallback[0], $fallback[1], $size);
if ($filename != NULL) {
return $filename;
}
}
}
if ($this->parent !== NULL) {
$parentTheme = $this->findTheme($this->parent);
if ($parentTheme === NULL) {
$parentTheme = $this->findTheme(static::$default_theme);
}
return $parentTheme->FindIconHelper($context, $icon, $size);
}
return NULL;
}
function LookupIcon ($context, $iconname, $size)
{
if (!isset($this->subdirs[$context])) {
return NULL;
}
foreach ($this->subdirs[$context] as $path => &$subdir) {
if ($subdir->MatchesSize($size)) {
foreach (static::$extensions as $extension) {
$filename = $this->path . '/' . $path . '/' . $iconname . '.' . $extension;
if (file_exists($filename)) {
return $filename;
}
}
}
}
unset($subdir);
if (static::$find_closest) {
$minimal_size = PHP_INT_MAX;
foreach ($this->subdirs[$context] as $path => &$subdir) {
if (($sizedistance = $subdir->SizeDistance($size)) < $minimal_size) {
foreach (static::$extensions as $extension) {
$filename = $this->path . '/' . $path . '/' . $iconname . '.' . $extension;
if (file_exists($filename)) {
$closest_filename = $filename;
$minimal_size = $sizedistance;
}
}
}
}
unset($subdir);
if (isset($closest_filename)) {
return $closest_filename;
}
}
return NULL;
}
static public $default_theme = 'breezy';
static public $extensions = ['png', 'xpm', 'svg'];
static public $find_closest = FALSE;
/* We store themes in the session. To do otherwise, override these methods. */
static public $session_var = 'IconThemes';
static public function loadThemes ($path)
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
{
$themes = [];
if ($dir = opendir("$path")) {
while (($file = readdir($dir)) !== FALSE) {
if (file_exists("$path/$file/index.theme") && !preg_match("/^\./", $file)) {
try {
if ($file == static::$default_theme) {
$themes[$file] = new IconTheme("$path/$file", NULL);
} else {
$themes[$file] = new IconTheme("$path/$file", static::$default_theme);
}
} catch (ThemeFileParsingException $e) {
continue;
}
}
}
}
$_SESSION[static::$session_var] = $themes;
}
static public function findThemeIcon ($theme, $context, $icon, $size)
{
// We have to sanitize the $icon received from $_GET['icon']. Fixing vulnerability : CWE-35
if (!preg_match('/^[a-zA-Z0-9_\-]+$/', $icon)) {
trigger_error('Error: Wrong icon name received');
die('Error: wrong icon name received');
}
if (!isset($_SESSION[static::$session_var])) {
trigger_error('Error: no theme found in session');
die('Error: no theme found in session');
}
if (isset($_SESSION[static::$session_var][$theme])) {
return $_SESSION[static::$session_var][$theme]->FindIcon($context, $icon, $size);
}
return $_SESSION[static::$session_var][static::$default_theme]->FindIcon($context, $icon, $size);
}
public function findTheme ($theme)
{
if (isset($_SESSION[static::$session_var][$theme])) {
return $_SESSION[static::$session_var][$theme];
}
return NULL;
}
/* Fallback system */
static public $fallbacks = [
'types/user-group' => [
['applications', 'system-users']
],
'types/resource-group' => [
['actions', 'resource-group']
],
'types/user' => [
['places', 'user-identity'],
['status', 'avatar-default'],
],
'types/contact' => [
['mimetypes', 'x-office-contact'],
],
'types/certificate' => [
['mimetypes', 'stock_certificate'],
['mimetypes', 'application-certificate'],
['actions', 'view-certificate'],
],
'applications/user-info' => [
['actions', 'user-properties'],
['types', 'contact'],
['mimetypes', 'x-office-contact'],
['types', 'user'],
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
['places', 'user-identity'],
['status', 'avatar-default'],
],
'applications/office-calendar' => [
['mimetypes', 'x-office-calendar'],
],
'applications/os-linux' => [
['applications', 'linux'],
],
'applications/os-windows' => [
['applications', 'windows'],
],
'applications/samba' => [
['applications', 'os-windows'],
['applications', 'windows'],
],
'applications/config-language' => [
['applications', 'locale'],
['applications', 'preferences-desktop-locale'],
],
'mimetypes/text-csv' => [
['mimetypes', 'x-office-spreadsheet'],
['mimetypes', 'text-x-generic'],
],
'mimetypes/application-pdf' => [
['mimetypes', 'x-office-document'],
],
'actions/application-exit' => [
['actions', 'system-log-out'],
],
'actions/archive' => [
['mimetypes', 'application-x-archive'],
],
'actions/document-export' => [
['actions', 'document-send'],
],
'actions/download' => [
['actions', 'document-save'],
],
'actions/document-restore' => [
['actions', 'document-import'],
['actions', 'document-open'],
],
'actions/document-edit' => [
['actions', 'edit'],
['applications', 'text-editor'],
['applications', 'accessories-text-editor'],
['actions', 'document-open'],
],
'actions/snapshot' => [
['actions', 'document-save'],
],
'actions/system-reboot' => [
['actions', 'view-refresh'],
],
'actions/system-update' => [
['applications', 'system-software-update'],
],
'actions/system-reinstall' => [
['applications', 'system-installer'],
],
'actions/task-start' => [
['actions', 'media-playback-start'],
],
'actions/task-stop' => [
['actions', 'media-playback-stop'],
],
'actions/task-schedule' => [
['actions', 'chronometer'],
['actions', 'smallclock'],
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
],
'actions/up' => [
['actions', 'go-up'],
['actions', 'arrow-up'],
],
'actions/upload' => [
['actions', 'document-import'],
['actions', 'up'],
],
'actions/down' => [
['actions', 'go-down'],
['actions', 'arrow-down'],
],
'actions/previous' => [
['actions', 'go-previous'],
['actions', 'arrow-left'],
],
'actions/next' => [
['actions', 'go-next'],
['actions', 'arrow-right'],
],
'actions/submit' => [
['actions', 'go-jump'],
],
'categories/settings' => [
['categories', 'gnome-settings'],
['categories', 'preferences-other'],
['categories', 'preferences-system'],
],
'categories/checks' => [
['actions', 'view-task'],
['actions', 'view-calendar-tasks'],
['actions', 'checkbox'],
['status', 'task-complete'],
],
'devices/server' => [
['places', 'server'],
['places', 'network-server'],
],
'devices/media-cdrom' => [
['devices', 'media-optical'],
],
'devices/terminal' => [
['applications', 'utilities-terminal'],
],
'devices/computer-windows' => [
['applications', 'os-windows'],
['applications', 'windows'],
],
'devices/template' => [
['actions', 'document-new'],
],
'status/object-locked' => [
['status', 'changes-prevent'],
],
'status/object-unlocked' => [
['status', 'changes-allow'],
],
'status/task-waiting' => [
['actions', 'task-schedule'],
],
'places/folder-network' => [
['places', 'folder-remote'],
],
];
}