Dotclear


Ignore:
Timestamp:
02/14/18 10:14:33 (7 years ago)
Author:
franck <carnet.franck.paul@…>
Branch:
default
Message:

Add autocomplete attribute to form::password where it's relevant, code formatting (PSR-2)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • inc/admin/lib.moduleslist.php

    r3640 r3699  
    1010# 
    1111# -- END LICENSE BLOCK ----------------------------------------- 
    12 if (!defined('DC_ADMIN_CONTEXT')) { return; } 
     12if (!defined('DC_ADMIN_CONTEXT')) {return;} 
    1313 
    1414/** 
     
    2121class adminModulesList 
    2222{ 
    23      public $core;       /**< @var object    dcCore instance */ 
    24      public $modules;    /**< @var object    dcModules instance */ 
    25      public $store;      /**< @var object    dcStore instance */ 
    26  
    27      public static $allow_multi_install = false;       /**< @var boolean   Work with multiple root directories */ 
    28      public static $distributed_modules = array();     /**< @var array     List of modules distributed with Dotclear */ 
    29  
    30      protected $list_id = 'unknow';     /**< @var string    Current list ID */ 
    31      protected $data = array();         /**< @var array     Current modules */ 
    32  
    33      protected $config_module = '';     /**< @var string    Module ID to configure */ 
    34      protected $config_file = '';  /**< @var string    Module path to configure */ 
    35      protected $config_content = '';    /**< @var string    Module configuration page content */ 
    36  
    37      protected $path = false;           /**< @var string    Modules root directory */ 
    38      protected $path_writable = false;  /**< @var boolean   Indicate if modules root directory is writable */ 
    39      protected $path_pattern = false;   /**< @var string    Directory pattern to work on */ 
    40  
    41      protected $page_url = '';                    /**< @var string    Page URL */ 
    42      protected $page_qs = '?';                    /**< @var string    Page query string */ 
    43      protected $page_tab = '';                    /**< @var string    Page tab */ 
    44      protected $page_redir = '';                  /**< @var string    Page redirection */ 
    45  
    46      public static $nav_indexes = 'abcdefghijklmnopqrstuvwxyz0123456789'; /**< @var  string    Index list */ 
    47      protected $nav_list = array();          /**< @var array     Index list with special index */ 
    48      protected $nav_special = 'other';  /**< @var string    Text for other special index */ 
    49  
    50      protected $sort_field = 'sname';   /**< @var string    Field used to sort modules */ 
    51      protected $sort_asc = true;             /**< @var boolean   Sort order asc */ 
    52  
    53      /** 
    54       * Constructor. 
    55       * 
    56       * Note that this creates dcStore instance. 
    57       * 
    58       * @param object    $modules       dcModules instance 
    59       * @param string    $modules_root  Modules root directories 
    60       * @param string    $xml_url       URL of modules feed from repository 
    61       */ 
    62      public function __construct(dcModules $modules, $modules_root, $xml_url) 
    63      { 
    64           $this->core = $modules->core; 
    65           $this->modules = $modules; 
    66           $this->store = new dcStore($modules, $xml_url); 
    67  
    68           $this->page_url = $this->core->adminurl->get('admin.plugins'); 
    69  
    70           $this->setPath($modules_root); 
    71           $this->setIndex(__('other')); 
    72      } 
    73  
    74      /** 
    75       * Begin a new list. 
    76       * 
    77       * @param string    $id       New list ID 
    78       * @return     adminModulesList self instance 
    79       */ 
    80      public function setList($id) 
    81      { 
    82           $this->data = array(); 
    83           $this->page_tab = ''; 
    84           $this->list_id = $id; 
    85  
    86           return $this; 
    87      } 
    88  
    89      /** 
    90       * Get list ID. 
    91       * 
    92       * @return     List ID 
    93       */ 
    94      public function getList() 
    95      { 
    96           return $this->list_id; 
    97      } 
    98  
    99      /// @name Modules root directory methods 
    100      //@{ 
    101      /** 
    102       * Set path info. 
    103       * 
    104       * @param string    $root          Modules root directories 
    105       * @return     adminModulesList self instance 
    106       */ 
    107      protected function setPath($root) 
    108      { 
    109           $paths = explode(PATH_SEPARATOR, $root); 
    110           $path = array_pop($paths); 
    111           unset($paths); 
    112  
    113           $this->path = $path; 
    114           if (is_dir($path) && is_writeable($path)) { 
    115                $this->path_writable = true; 
    116                $this->path_pattern = preg_quote($path,'!'); 
    117           } 
    118  
    119           return $this; 
    120      } 
    121  
    122      /** 
    123       * Get modules root directory. 
    124       * 
    125       * @return     Path to work on 
    126       */ 
    127      public function getPath() 
    128      { 
    129           return $this->path; 
    130      } 
    131  
    132      /** 
    133       * Check if modules root directory is writable. 
    134       * 
    135       * @return     True if directory is writable 
    136       */ 
    137      public function isWritablePath() 
    138      { 
    139           return $this->path_writable; 
    140      } 
    141  
    142      /** 
    143       * Check if root directory of a module is deletable. 
    144       * 
    145       * @param string    $root          Module root directory 
    146       * @return     True if directory is delatable 
    147       */ 
    148      public function isDeletablePath($root) 
    149      { 
    150           return $this->path_writable 
    151                && (preg_match('!^'.$this->path_pattern.'!', $root) || defined('DC_DEV') && DC_DEV) 
    152                && $this->core->auth->isSuperAdmin(); 
    153      } 
    154      //@} 
    155  
    156      /// @name Page methods 
    157      //@{ 
    158      /** 
    159       * Set page base URL. 
    160       * 
    161       * @param string    $url      Page base URL 
    162       * @return     adminModulesList self instance 
    163       */ 
    164      public function setURL($url) 
    165      { 
    166           $this->page_qs = strpos('?', $url) ? '&amp;' : '?'; 
    167           $this->page_url = $url; 
    168  
    169           return $this; 
    170      } 
    171  
    172      /** 
    173       * Get page URL. 
    174       * 
    175       * @param string|array   $queries  Additionnal query string 
    176       * @param booleany  $with_tab      Add current tab to URL end 
    177       * @return     Clean page URL 
    178       */ 
    179      public function getURL($queries='', $with_tab=true) 
    180      { 
    181           return $this->page_url. 
    182                (!empty($queries) ? $this->page_qs : ''). 
    183                (is_array($queries) ? http_build_query($queries) : $queries). 
    184                ($with_tab && !empty($this->page_tab) ? '#'.$this->page_tab : ''); 
    185      } 
    186  
    187      /** 
    188       * Set page tab. 
    189       * 
    190       * @param string    $tab      Page tab 
    191       * @return     adminModulesList self instance 
    192       */ 
    193      public function setTab($tab) 
    194      { 
    195           $this->page_tab = $tab; 
    196  
    197           return $this; 
    198      } 
    199  
    200      /** 
    201       * Get page tab. 
    202       * 
    203       * @return     Page tab 
    204       */ 
    205      public function getTab() 
    206      { 
    207           return $this->page_tab; 
    208      } 
    209  
    210      /** 
    211       * Set page redirection. 
    212       * 
    213       * @param string    $default       Default redirection 
    214       * @return     adminModulesList self instance 
    215       */ 
    216      public function setRedir($default='') 
    217      { 
    218           $this->page_redir = empty($_REQUEST['redir']) ? $default : $_REQUEST['redir']; 
    219  
    220           return $this; 
    221      } 
    222  
    223      /** 
    224       * Get page redirection. 
    225       * 
    226       * @return     Page redirection 
    227       */ 
    228      public function getRedir() 
    229      { 
    230           return empty($this->page_redir) ? $this->getURL() : $this->page_redir; 
    231      } 
    232      //@} 
    233  
    234      /// @name Search methods 
    235      //@{ 
    236      /** 
    237       * Get search query. 
    238       * 
    239       * @return     Search query 
    240       */ 
    241      public function getSearch() 
    242      { 
    243           $query = !empty($_REQUEST['m_search']) ? trim($_REQUEST['m_search']) : null; 
    244           return strlen($query) > 2 ? $query : null; 
    245      } 
    246  
    247      /** 
    248       * Display searh form. 
    249       * 
    250       * @return     adminModulesList self instance 
    251       */ 
    252      public function displaySearch() 
    253      { 
    254           $query = $this->getSearch(); 
    255  
    256           if (empty($this->data) && $query === null) { 
    257                return $this; 
    258           } 
    259  
    260           echo 
    261           '<div class="modules-search">'. 
    262           '<form action="'.$this->getURL().'" method="get">'. 
    263           '<p><label for="m_search" class="classic">'.__('Search in repository:').'&nbsp;</label><br />'. 
    264           form::field(array('m_search','m_search'), 30, 255, html::escapeHTML($query)). 
    265           '<input type="submit" value="'.__('OK').'" /> '; 
    266  
    267           if ($query) { 
    268                echo 
    269                ' <a href="'.$this->getURL().'" class="button">'.__('Reset search').'</a>'; 
    270           } 
    271  
    272           echo 
    273           '</p>'. 
    274           '<p class="form-note">'. 
    275           __('Search is allowed on multiple terms longer than 2 chars, terms must be separated by space.'). 
    276           '</p>'. 
    277           '</form>'; 
    278  
    279           if ($query) { 
    280                echo 
    281                '<p class="message">'.sprintf( 
    282                     __('Found %d result for search "%s":', 'Found %d results for search "%s":', count($this->data)), 
    283                     count($this->data), html::escapeHTML($query) 
    284                     ). 
    285                '</p>'; 
    286           } 
    287           echo '</div>'; 
    288  
    289           return $this; 
    290      } 
    291      //@} 
    292  
    293      /// @name Navigation menu methods 
    294      //@{ 
    295      /** 
    296       * Set navigation special index. 
    297       * 
    298       * @return     adminModulesList self instance 
    299       */ 
    300      public function setIndex($str) 
    301      { 
    302           $this->nav_special = (string) $str; 
    303           $this->nav_list = array_merge(str_split(self::$nav_indexes), array($this->nav_special)); 
    304  
    305           return $this; 
    306      } 
    307  
    308      /** 
    309       * Get index from query. 
    310       * 
    311       * @return     Query index or default one 
    312       */ 
    313      public function getIndex() 
    314      { 
    315           return isset($_REQUEST['m_nav']) && in_array($_REQUEST['m_nav'], $this->nav_list) ? $_REQUEST['m_nav'] : $this->nav_list[0]; 
    316      } 
    317  
    318      /** 
    319       * Display navigation by index menu. 
    320       * 
    321       * @return     adminModulesList self instance 
    322       */ 
    323      public function displayIndex() 
    324      { 
    325           if (empty($this->data) || $this->getSearch() !== null) { 
    326                return $this; 
    327           } 
    328  
    329           # Fetch modules required field 
    330           $indexes = array(); 
    331           foreach ($this->data as $id => $module) { 
    332                if (!isset($module[$this->sort_field])) { 
    333                     continue; 
    334                } 
    335                $char = substr($module[$this->sort_field], 0, 1); 
    336                if (!in_array($char, $this->nav_list)) { 
    337                     $char = $this->nav_special; 
    338                } 
    339                if (!isset($indexes[$char])) { 
    340                     $indexes[$char] = 0; 
    341                } 
    342                $indexes[$char]++; 
    343           } 
    344  
    345           $buttons = array(); 
    346           foreach($this->nav_list as $char) { 
    347                # Selected letter 
    348                if ($this->getIndex() == $char) { 
    349                     $buttons[] = '<li class="active" title="'.__('current selection').'"><strong> '.$char.' </strong></li>'; 
    350                } 
    351                # Letter having modules 
    352                elseif (!empty($indexes[$char])) { 
    353                     $title = sprintf(__('%d result', '%d results', $indexes[$char]), $indexes[$char]); 
    354                     $buttons[] = '<li class="btn" title="'.$title.'"><a href="'.$this->getURL('m_nav='.$char).'" title="'.$title.'"> '.$char.' </a></li>'; 
    355                } 
    356                # Letter without modules 
    357                else { 
    358                     $buttons[] = '<li class="btn no-link" title="'.__('no results').'"> '.$char.' </li>'; 
    359                } 
    360           } 
    361           # Parse navigation menu 
    362           echo '<div class="pager">'.__('Browse index:').' <ul class="index">'.implode('',$buttons).'</ul></div>'; 
    363  
    364           return $this; 
    365      } 
    366      //@} 
    367  
    368      /// @name Sort methods 
    369      //@{ 
    370      /** 
    371       * Set default sort field. 
    372       * 
    373       * @return     adminModulesList self instance 
    374       */ 
    375      public function setSort($field, $asc=true) 
    376      { 
    377           $this->sort_field = $field; 
    378           $this->sort_asc = (boolean) $asc; 
    379  
    380           return $this; 
    381      } 
    382  
    383      /** 
    384       * Get sort field from query. 
    385       * 
    386       * @return     Query sort field or default one 
    387       */ 
    388      public function getSort() 
    389      { 
    390           return !empty($_REQUEST['m_sort']) ? $_REQUEST['m_sort'] : $this->sort_field; 
    391      } 
    392  
    393      /** 
    394       * Display sort field form. 
    395       * 
    396       * @note  This method is not implemented yet 
    397       * @return     adminModulesList self instance 
    398       */ 
    399      public function displaySort() 
    400      { 
    401           // 
    402  
    403           return $this; 
    404      } 
    405      //@} 
    406  
    407      /// @name Modules methods 
    408      //@{ 
    409      /** 
    410       * Set modules and sanitize them. 
    411       * 
    412       * @return     adminModulesList self instance 
    413       */ 
    414      public function setModules($modules) 
    415      { 
    416           $this->data = array(); 
    417           if (!empty($modules) && is_array($modules)) { 
    418                foreach($modules as $id => $module) { 
    419                     $this->data[$id] = self::sanitizeModule($id, $module); 
    420                } 
    421           } 
    422           return $this; 
    423      } 
    424  
    425      /** 
    426       * Get modules currently set. 
    427       * 
    428       * @return     Array of modules 
    429       */ 
    430      public function getModules() 
    431      { 
    432           return $this->data; 
    433      } 
    434  
    435      /** 
    436       * Sanitize a module. 
    437       * 
    438       * This clean infos of a module by adding default keys 
    439       * and clean some of them, sanitize module can safely 
    440       * be used in lists. 
    441       * 
    442       * @return     Array of the module informations 
    443       */ 
    444      public static function sanitizeModule($id, $module) 
    445      { 
    446           $label = empty($module['label']) ? $id : $module['label']; 
    447           $name = __(empty($module['name']) ? $label : $module['name']); 
    448  
    449           return array_merge( 
    450                # Default values 
    451                array( 
    452                     'desc'                   => '', 
    453                     'author'            => '', 
    454                     'version'                => 0, 
    455                     'current_version'   => 0, 
    456                     'root'                   => '', 
    457                     'root_writable'     => false, 
    458                     'permissions'       => null, 
    459                     'parent'            => null, 
    460                     'priority'               => 1000, 
    461                     'standalone_config' => false, 
    462                     'support'                => '', 
    463                     'section'                => '', 
    464                     'tags'                   => '', 
    465                     'details'                => '', 
    466                     'sshot'             => '', 
    467                     'score'                  => 0, 
    468                     'type'                   => null, 
    469                     'require'           => array(), 
    470                     'settings'               => array() 
    471                ), 
    472                # Module's values 
    473                $module, 
    474                # Clean up values 
    475                array( 
    476                     'id'                     => $id, 
    477                     'sid'                    => self::sanitizeString($id), 
    478                     'label'             => $label, 
    479                     'name'                   => $name, 
    480                     'sname'             => self::sanitizeString($name) 
    481                ) 
    482           ); 
    483      } 
    484  
    485      /** 
    486       * Check if a module is part of the distribution. 
    487       * 
    488       * @param string    $id       Module root directory 
    489       * @return     True if module is part of the distribution 
    490       */ 
    491      public static function isDistributedModule($id) 
    492      { 
    493           $distributed_modules = self::$distributed_modules; 
    494  
    495           return is_array($distributed_modules) && in_array($id, $distributed_modules); 
    496      } 
    497  
    498      /** 
    499       * Sort modules list by specific field. 
    500       * 
    501       * @param string    $module        Array of modules 
    502       * @param string    $field         Field to sort from 
    503       * @param bollean   $asc      Sort asc if true, else decs 
    504       * @return     Array of sorted modules 
    505       */ 
    506      public static function sortModules($modules, $field, $asc=true) 
    507      { 
    508           $origin = $sorter = array(); 
    509  
    510           foreach($modules as $id => $module) { 
    511                $origin[] = $module; 
    512                $sorter[] = isset($module[$field]) ? $module[$field] : $field; 
    513           } 
    514  
    515           array_multisort($sorter, $asc ? SORT_ASC : SORT_DESC, $origin); 
    516  
    517           foreach($origin as $module) { 
    518                $final[$module['id']] = $module; 
    519           } 
    520  
    521           return $final; 
    522      } 
    523  
    524      /** 
    525       * Display list of modules. 
    526       * 
    527       * @param array     $cols          List of colones (module field) to display 
    528       * @param array     $actions  List of predefined actions to show on form 
    529       * @param boolean   $nav_limit     Limit list to previously selected index 
    530       * @return     adminModulesList self instance 
    531       */ 
    532      public function displayModules($cols=array('name', 'version', 'desc'), $actions=array(), $nav_limit=false) 
    533      { 
    534           echo 
    535           '<form action="'.$this->getURL().'" method="post" class="modules-form-actions">'. 
    536           '<div class="table-outer">'. 
    537           '<table id="'.html::escapeHTML($this->list_id).'" class="modules'.(in_array('expander', $cols) ? ' expandable' : '').'">'. 
    538           '<caption class="hidden">'.html::escapeHTML(__('Plugins list')).'</caption><tr>'; 
    539  
    540           if (in_array('name', $cols)) { 
    541                $colspan = 1; 
    542                if (in_array('checkbox', $cols)) { 
    543                     $colspan++; 
    544                } 
    545                if (in_array('icon', $cols)) { 
    546                     $colspan++; 
    547                } 
    548                echo 
    549                '<th class="first nowrap"'.($colspan > 1 ? ' colspan="'.$colspan.'"' : '').'>'.__('Name').'</th>'; 
    550           } 
    551  
    552           if (in_array('score', $cols) && $this->getSearch() !== null && defined('DC_DEBUG') && DC_DEBUG) { 
    553                echo 
    554                '<th class="nowrap">'.__('Score').'</th>'; 
    555           } 
    556  
    557           if (in_array('version', $cols)) { 
    558                echo 
    559                '<th class="nowrap count" scope="col">'.__('Version').'</th>'; 
    560           } 
    561  
    562           if (in_array('current_version', $cols)) { 
    563                echo 
    564                '<th class="nowrap count" scope="col">'.__('Current version').'</th>'; 
    565           } 
    566  
    567           if (in_array('desc', $cols)) { 
    568                echo 
    569                '<th class="nowrap" scope="col">'.__('Details').'</th>'; 
    570           } 
    571  
    572           if (in_array('distrib', $cols)) { 
    573                echo 
    574                '<th'.(in_array('desc', $cols) ? '' : ' class="maximal"').'></th>'; 
    575           } 
    576  
    577           if (!empty($actions) && $this->core->auth->isSuperAdmin()) { 
    578                echo 
    579                '<th class="minimal nowrap">'.__('Action').'</th>'; 
    580           } 
    581  
    582           echo 
    583           '</tr>'; 
    584  
    585           $sort_field = $this->getSort(); 
    586  
    587           # Sort modules by $sort_field (default sname) 
    588           $modules = $this->getSearch() === null ? 
    589                self::sortModules($this->data, $sort_field, $this->sort_asc) : 
    590                $this->data; 
    591  
    592           $count = 0; 
    593           foreach ($modules as $id => $module) 
    594           { 
    595                # Show only requested modules 
    596                if ($nav_limit && $this->getSearch() === null) { 
    597                     $char = substr($module[$sort_field], 0, 1); 
    598                     if (!in_array($char, $this->nav_list)) { 
    599                          $char = $this->nav_special; 
    600                     } 
    601                     if ($this->getIndex() != $char) { 
    602                          continue; 
    603                     } 
    604                } 
    605  
    606                echo 
    607                '<tr class="line" id="'.html::escapeHTML($this->list_id).'_m_'.html::escapeHTML($id).'">'; 
    608  
    609                $tds = 0; 
    610  
    611                if (in_array('checkbox', $cols)) { 
    612                     $tds++; 
    613                     echo 
    614                     '<td class="module-icon nowrap">'. 
    615                     form::checkbox(array('modules['.$count.']', html::escapeHTML($this->list_id).'_modules_'.html::escapeHTML($id)), html::escapeHTML($id)). 
    616                     '</td>'; 
    617                } 
    618  
    619                if (in_array('icon', $cols)) { 
    620                     $tds++; 
    621                     echo 
    622                     '<td class="module-icon nowrap">'.sprintf( 
    623                          '<img alt="%1$s" title="%1$s" src="%2$s" />', 
    624                          html::escapeHTML($id), file_exists($module['root'].'/icon.png') ? 
    625                          dcPage::getPF($id.'/icon.png') : 'images/module.png' 
    626                     ).'</td>'; 
    627                } 
    628  
    629                $tds++; 
    630                echo 
    631                '<td class="module-name nowrap" scope="row">'; 
    632                if (in_array('checkbox', $cols)) { 
    633                     if (in_array('expander', $cols)) { 
    634                          echo 
    635                          html::escapeHTML($module['name']).($id != $module['name'] ? sprintf(__(' (%s)'),$id) : ''); 
    636                     } 
    637                     else { 
    638                          echo 
    639                          '<label for="'.html::escapeHTML($this->list_id).'_modules_'.html::escapeHTML($id).'">'. 
    640                          html::escapeHTML($module['name']).($id != $module['name'] ? sprintf(__(' (%s)'),$id) : ''). 
    641                          '</label>'; 
    642                     } 
    643                } 
    644                else { 
    645                     echo 
    646                     html::escapeHTML($module['name']).($id != $module['name'] ? sprintf(__(' (%s)'),$id) : ''). 
    647                     form::hidden(array('modules['.$count.']'), html::escapeHTML($id)); 
    648                } 
    649                echo 
    650                $this->core->formNonce(). 
    651                '</td>'; 
    652  
    653                # Display score only for debug purpose 
    654                if (in_array('score', $cols) && $this->getSearch() !== null && defined('DC_DEBUG') && DC_DEBUG) { 
    655                     $tds++; 
    656                     echo 
    657                     '<td class="module-version nowrap count"><span class="debug">'.$module['score'].'</span></td>'; 
    658                } 
    659  
    660                if (in_array('version', $cols)) { 
    661                     $tds++; 
    662                     echo 
    663                     '<td class="module-version nowrap count">'.html::escapeHTML($module['version']).'</td>'; 
    664                } 
    665  
    666                if (in_array('current_version', $cols)) { 
    667                     $tds++; 
    668                     echo 
    669                     '<td class="module-current-version nowrap count">'.html::escapeHTML($module['current_version']).'</td>'; 
    670                } 
    671  
    672                if (in_array('desc', $cols)) { 
    673                     $tds++; 
    674                     echo 
    675                     '<td class="module-desc maximal">'.html::escapeHTML(__($module['desc'])); 
    676                     if (isset($module['cannot_disable']) && $module['enabled']) { 
    677                          echo 
    678                          '<br/><span class="info">'. 
    679                          sprintf(__('This module cannot be disabled nor deleted, since the following modules are also enabled : %s'), 
    680                                    join(',',$module['cannot_disable'])). 
    681                          '</span>'; 
    682                     } 
    683                     if (isset($module['cannot_enable']) && !$module['enabled']) { 
    684                          echo 
    685                          '<br/><span class="info">'. 
    686                          __('This module cannot be enabled, because of the following reasons :'). 
    687                          '<ul>'; 
    688                          foreach ($module['cannot_enable'] as $m=>$reason) { 
    689                               echo '<li>'.$reason.'</li>'; 
    690                          } 
    691                          echo '</ul>'. 
    692                          '</span>'; 
    693                     } 
    694                     echo '</td>'; 
    695  
    696                } 
    697  
    698                if (in_array('distrib', $cols)) { 
    699                     $tds++; 
    700                     echo 
    701                     '<td class="module-distrib">'.(self::isDistributedModule($id) ? 
    702                          '<img src="images/dotclear_pw.png" alt="'. 
    703                          __('Plugin from official distribution').'" title="'. 
    704                          __('Plugin from official distribution').'" />' 
    705                     : '').'</td>'; 
    706                } 
    707  
    708                if (!empty($actions) && $this->core->auth->isSuperAdmin()) { 
    709                     $buttons = $this->getActions($id, $module, $actions); 
    710  
    711                     $tds++; 
    712                     echo 
    713                     '<td class="module-actions nowrap">'. 
    714  
    715                     '<div>'.implode(' ', $buttons).'</div>'. 
    716  
    717                     '</td>'; 
    718                } 
    719  
    720                echo 
    721                '</tr>'; 
    722  
    723                # Other informations 
    724                if (in_array('expander', $cols)) { 
    725                     echo 
    726                     '<tr class="module-more"><td colspan="'.$tds.'" class="expand">'; 
    727  
    728                     if (!empty($module['author']) || !empty($module['details']) || !empty($module['support'])) { 
    729                          echo 
    730                          '<div><ul class="mod-more">'; 
    731  
    732                          if (!empty($module['author'])) { 
    733                               echo 
    734                               '<li class="module-author">'.__('Author:').' '.html::escapeHTML($module['author']).'</li>'; 
    735                          } 
    736  
    737                          $more = array(); 
    738                          if (!empty($module['details'])) { 
    739                               $more[] = '<a class="module-details" href="'.$module['details'].'">'.__('Details').'</a>'; 
    740                          } 
    741  
    742                          if (!empty($module['support'])) { 
    743                               $more[] = '<a class="module-support" href="'.$module['support'].'">'.__('Support').'</a>'; 
    744                          } 
    745  
    746                          if (!empty($more)) { 
    747                               echo 
    748                               '<li>'.implode(' - ',$more).'</li>'; 
    749                          } 
    750  
    751                          echo 
    752                          '</ul></div>'; 
    753                     } 
    754  
    755                     $config = !empty($module['root']) && file_exists(path::real($module['root'].'/_config.php')); 
    756                     $index = !empty($module['root']) && file_exists(path::real($module['root'].'/index.php')); 
    757  
    758                     if ($config || $index || !empty($module['section']) || !empty($module['tags']) || !empty($module['settings'])) { 
    759                          echo 
    760                          '<div><ul class="mod-more">'; 
    761  
    762                          if ($index && $module['enabled']) { 
    763                               echo '<li><a href="'.$this->core->adminurl->get('admin.plugin.'.$id).'">'.__('Manage plugin').'</a></li>'; 
    764                          } 
    765  
    766                          $settings = $this->getSettingsUrls($this->core,$id); 
    767                          if (!empty($settings) && $module['enabled']) { 
    768                               echo '<li>'.implode(' - ',$settings).'</li>'; 
    769                          } 
    770  
    771                          if (!empty($module['section'])) { 
    772                               echo 
    773                               '<li class="module-section">'.__('Section:').' '.html::escapeHTML($module['section']).'</li>'; 
    774                          } 
    775  
    776                          if (!empty($module['tags'])) { 
    777                               echo 
    778                               '<li class="module-tags">'.__('Tags:').' '.html::escapeHTML($module['tags']).'</li>'; 
    779                          } 
    780  
    781                          echo 
    782                          '</ul></div>'; 
    783                     } 
    784  
    785                     echo 
    786                     '</td></tr>'; 
    787                } 
    788  
    789                $count++; 
    790           } 
    791           echo 
    792           '</table></div>'; 
    793  
    794           if(!$count && $this->getSearch() === null) { 
    795                echo 
    796                '<p class="message">'.__('No plugins matched your search.').'</p>'; 
    797           } 
    798  
    799           elseif ((in_array('checkbox', $cols) || $count > 1) && !empty($actions) && $this->core->auth->isSuperAdmin()) { 
    800                $buttons = $this->getGlobalActions($actions, in_array('checkbox', $cols)); 
    801  
    802                if (!empty($buttons)) { 
    803                     if (in_array('checkbox', $cols)) { 
    804                          echo 
    805                          '<p class="checkboxes-helpers"></p>'; 
    806                     } 
    807                     echo 
    808                     '<div>'.implode(' ', $buttons).'</div>'; 
    809                } 
    810           } 
    811           echo 
    812           '</form>'; 
    813  
    814           return $this; 
    815      } 
    816  
    817      /** 
    818       * Get settings URLs if any 
    819       * 
    820       * @param object $core 
    821       * @param string $id module ID 
    822       * @param boolean $check check permission 
    823       * @param boolean $self include self URL (→ plugin index.php URL) 
    824       * @return Array of settings URLs 
    825       */ 
    826      public static function getSettingsUrls($core,$id,$check=false,$self=true) 
    827      { 
    828           $st = array(); 
    829  
    830           $mr = $core->plugins->moduleRoot($id); 
    831           $config = !empty($mr) && file_exists(path::real($mr.'/_config.php')); 
    832           $settings = $core->plugins->moduleInfo($id,'settings'); 
    833           if ($config || !empty($settings)) { 
    834                if ($config) { 
    835                     if (!$check || 
    836                          $core->auth->isSuperAdmin() || 
    837                          $core->auth->check($core->plugins->moduleInfo($id,'permissions'),$core->blog->id)) 
    838                     { 
    839                          $params = array('module' => $id,'conf' => '1'); 
    840                          if (!$core->plugins->moduleInfo($id,'standalone_config') && !$self) { 
    841                               $params['redir'] = $core->adminurl->get('admin.plugin.'.$id); 
    842                          } 
    843                          $st[] = '<a class="module-config" href="'. 
    844                               $core->adminurl->get('admin.plugins',$params). 
    845                               '">'.__('Configure plugin').'</a>'; 
    846                     } 
    847                } 
    848                if (is_array($settings)) { 
    849                     foreach ($settings as $sk => $sv) { 
    850                          switch ($sk) { 
    851                               case 'blog': 
    852                                    if (!$check || 
    853                                         $core->auth->isSuperAdmin() || 
    854                                         $core->auth->check('admin',$core->blog->id)) 
    855                                    { 
    856                                         $st[] = '<a class="module-config" href="'. 
    857                                              $core->adminurl->get('admin.blog.pref').$sv. 
    858                                              '">'.__('Plugin settings (in blog parameters)').'</a>'; 
    859                                    } 
    860                                    break; 
    861                               case 'pref': 
    862                                    if (!$check || 
    863                                         $core->auth->isSuperAdmin() || 
    864                                         $core->auth->check('usage,contentadmin',$core->blog->id)) 
    865                                    { 
    866                                         $st[] = '<a class="module-config" href="'. 
    867                                              $core->adminurl->get('admin.user.preferences').$sv. 
    868                                              '">'.__('Plugin settings (in user preferences)').'</a>'; 
    869                                    } 
    870                                    break; 
    871                               case 'self': 
    872                                    if ($self) { 
    873                                         if (!$check || 
    874                                              $core->auth->isSuperAdmin() || 
    875                                              $core->auth->check($core->plugins->moduleInfo($id,'permissions'),$core->blog->id)) 
    876                                         { 
    877                                              $st[] = '<a class="module-config" href="'. 
    878                                                   $core->adminurl->get('admin.plugin.'.$id).$sv. 
    879                                                   '">'.__('Plugin settings').'</a>'; 
    880                                         } 
    881                                    } 
    882                                    break; 
    883                          } 
    884                     } 
    885                } 
    886           } 
    887  
    888           return $st; 
    889      } 
    890  
    891      /** 
    892       * Get action buttons to add to modules list. 
    893       * 
    894       * @param string    $id            Module ID 
    895       * @param array     $module        Module info 
    896       * @param array     $actions  Actions keys 
    897       * @return     Array of actions buttons 
    898       */ 
    899      protected function getActions($id, $module, $actions) 
    900      { 
    901           $submits = array(); 
    902  
    903           # Use loop to keep requested order 
    904           foreach($actions as $action) { 
    905                switch($action) { 
    906  
    907                     # Deactivate 
    908                     case 'activate': if ($this->core->auth->isSuperAdmin() && $module['root_writable'] && !isset($module['cannot_enable'])) { 
    909                          $submits[] = 
    910                          '<input type="submit" name="activate['.html::escapeHTML($id).']" value="'.__('Activate').'" />'; 
    911                     } break; 
    912  
    913                     # Activate 
    914                     case 'deactivate': if ($this->core->auth->isSuperAdmin() && $module['root_writable'] && !isset($module['cannot_disable'])) { 
    915                          $submits[] = 
    916                          '<input type="submit" name="deactivate['.html::escapeHTML($id).']" value="'.__('Deactivate').'" class="reset" />'; 
    917                     } break; 
    918  
    919                     # Delete 
    920                     case 'delete': if ($this->core->auth->isSuperAdmin() && $this->isDeletablePath($module['root'])&& !isset($module['cannot_disable'])) { 
    921                          $dev = !preg_match('!^'.$this->path_pattern.'!', $module['root']) && defined('DC_DEV') && DC_DEV ? ' debug' : ''; 
    922                          $submits[] = 
    923                          '<input type="submit" class="delete '.$dev.'" name="delete['.html::escapeHTML($id).']" value="'.__('Delete').'" />'; 
    924                     } break; 
    925  
    926                     # Install (from store) 
    927                     case 'install': if ($this->core->auth->isSuperAdmin() && $this->path_writable) { 
    928                          $submits[] = 
    929                          '<input type="submit" name="install['.html::escapeHTML($id).']" value="'.__('Install').'" />'; 
    930                     } break; 
    931  
    932                     # Update (from store) 
    933                     case 'update': if ($this->core->auth->isSuperAdmin() && $this->path_writable) { 
    934                          $submits[] = 
    935                          '<input type="submit" name="update['.html::escapeHTML($id).']" value="'.__('Update').'" />'; 
    936                     } break; 
    937  
    938                     # Behavior 
    939                     case 'behavior': 
    940  
    941                          # --BEHAVIOR-- adminModulesListGetActions 
    942                          $tmp = $this->core->callBehavior('adminModulesListGetActions', $this, $id, $module); 
    943  
    944                          if (!empty($tmp)) { 
    945                               $submits[] = $tmp; 
    946                          } 
    947                     break; 
    948                } 
    949           } 
    950  
    951           return $submits; 
    952      } 
    953  
    954      /** 
    955       * Get global action buttons to add to modules list. 
    956       * 
    957       * @param array     $actions        Actions keys 
    958       * @param boolean   $with_selection Limit action to selected modules 
    959       * @return     Array of actions buttons 
    960       */ 
    961      protected function getGlobalActions($actions, $with_selection=false) 
    962      { 
    963           $submits = array(); 
    964  
    965           # Use loop to keep requested order 
    966           foreach($actions as $action) { 
    967                switch($action) { 
    968  
    969                     # Deactivate 
    970                     case 'activate': if ($this->core->auth->isSuperAdmin() && $this->path_writable) { 
    971                          $submits[] = 
    972                          '<input type="submit" name="activate" value="'.($with_selection ? 
    973                               __('Activate selected plugins') : 
    974                               __('Activate all plugins from this list') 
    975                          ).'" />'; 
    976                     } break; 
    977  
    978                     # Activate 
    979                     case 'deactivate': if ($this->core->auth->isSuperAdmin() && $this->path_writable) { 
    980                          $submits[] = 
    981                          '<input type="submit" name="deactivate" value="'.($with_selection ? 
    982                               __('Deactivate selected plugins') : 
    983                               __('Deactivate all plugins from this list') 
    984                          ).'" />'; 
    985                     } break; 
    986  
    987                     # Update (from store) 
    988                     case 'update': if ($this->core->auth->isSuperAdmin() && $this->path_writable) { 
    989                          $submits[] = 
    990                          '<input type="submit" name="update" value="'.($with_selection ? 
    991                               __('Update selected plugins') : 
    992                               __('Update all plugins from this list') 
    993                          ).'" />'; 
    994                     } break; 
    995  
    996                     # Behavior 
    997                     case 'behavior': 
    998  
    999                          # --BEHAVIOR-- adminModulesListGetGlobalActions 
    1000                          $tmp = $this->core->callBehavior('adminModulesListGetGlobalActions', $this, $with_selection); 
    1001  
    1002                          if (!empty($tmp)) { 
    1003                               $submits[] = $tmp; 
    1004                          } 
    1005                     break; 
    1006                } 
    1007           } 
    1008  
    1009           return $submits; 
    1010      } 
    1011  
    1012      /** 
    1013       * Execute POST action. 
    1014       * 
    1015       * @note  Set a notice on success through dcPage::addSuccessNotice 
    1016       * @throw Exception Module not find or command failed 
    1017       * @return     Null 
    1018       */ 
    1019      public function doActions() 
    1020      { 
    1021           if (empty($_POST) || !empty($_REQUEST['conf']) 
    1022           || !$this->isWritablePath()) { 
    1023                return null; 
    1024           } 
    1025  
    1026           $modules = !empty($_POST['modules']) && is_array($_POST['modules']) ? array_values($_POST['modules']) : array(); 
    1027  
    1028           if ($this->core->auth->isSuperAdmin() && !empty($_POST['delete'])) { 
    1029  
    1030                if (is_array($_POST['delete'])) { 
    1031                     $modules = array_keys($_POST['delete']); 
    1032                } 
    1033  
    1034                $list = $this->modules->getDisabledModules(); 
    1035  
    1036                $failed = false; 
    1037                $count = 0; 
    1038                foreach($modules as $id) 
    1039                { 
    1040                     if (!isset($list[$id])) { 
    1041  
    1042                          if (!$this->modules->moduleExists($id)) { 
    1043                               throw new Exception(__('No such plugin.')); 
    1044                          } 
    1045  
    1046                          $module = $this->modules->getModules($id); 
    1047                          $module['id'] = $id; 
    1048  
    1049                          if (!$this->isDeletablePath($module['root'])) { 
    1050                               $failed = true; 
    1051                               continue; 
    1052                          } 
    1053  
    1054                          # --BEHAVIOR-- moduleBeforeDelete 
    1055                          $this->core->callBehavior('pluginBeforeDelete', $module); 
    1056  
    1057                          $this->modules->deleteModule($id); 
    1058  
    1059                          # --BEHAVIOR-- moduleAfterDelete 
    1060                          $this->core->callBehavior('pluginAfterDelete', $module); 
    1061                     } 
    1062                     else { 
    1063                          $this->modules->deleteModule($id, true); 
    1064                     } 
    1065  
    1066                     $count++; 
    1067                } 
    1068  
    1069                if (!$count && $failed) { 
    1070                     throw new Exception(__("You don't have permissions to delete this plugin.")); 
    1071                } 
    1072                elseif ($failed) { 
    1073                     dcPage::addWarningNotice(__('Some plugins have not been delete.')); 
    1074                } 
    1075                else { 
    1076                     dcPage::addSuccessNotice( 
    1077                          __('Plugin has been successfully deleted.', 'Plugins have been successuflly deleted.', $count) 
    1078                     ); 
    1079                } 
    1080                http::redirect($this->getURL()); 
    1081           } 
    1082  
    1083           elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['install'])) { 
    1084  
    1085                if (is_array($_POST['install'])) { 
    1086                     $modules = array_keys($_POST['install']); 
    1087                } 
    1088  
    1089                $list = $this->store->get(); 
    1090  
    1091                if (empty($list)) { 
    1092                     throw new Exception(__('No such plugin.')); 
    1093                } 
    1094  
    1095                $count = 0; 
    1096                foreach($list as $id => $module) { 
    1097  
    1098                     if (!in_array($id, $modules)) { 
    1099                          continue; 
    1100                     } 
    1101  
    1102                     $dest = $this->getPath().'/'.basename($module['file']); 
    1103  
    1104                     # --BEHAVIOR-- moduleBeforeAdd 
    1105                     $this->core->callBehavior('pluginBeforeAdd', $module); 
    1106  
    1107                     $this->store->process($module['file'], $dest); 
    1108  
    1109                     # --BEHAVIOR-- moduleAfterAdd 
    1110                     $this->core->callBehavior('pluginAfterAdd', $module); 
    1111  
    1112                     $count++; 
    1113                } 
    1114  
    1115                dcPage::addSuccessNotice( 
    1116                     __('Plugin has been successfully installed.', 'Plugins have been successuflly installed.', $count) 
    1117                ); 
    1118                http::redirect($this->getURL()); 
    1119           } 
    1120  
    1121           elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['activate'])) { 
    1122  
    1123                if (is_array($_POST['activate'])) { 
    1124                     $modules = array_keys($_POST['activate']); 
    1125                } 
    1126  
    1127                $list = $this->modules->getDisabledModules(); 
    1128                if (empty($list)) { 
    1129                     throw new Exception(__('No such plugin.')); 
    1130                } 
    1131  
    1132                $count = 0; 
    1133                foreach($list as $id => $module) { 
    1134  
    1135                     if (!in_array($id, $modules)) { 
    1136                          continue; 
    1137                     } 
    1138  
    1139                     # --BEHAVIOR-- moduleBeforeActivate 
    1140                     $this->core->callBehavior('pluginBeforeActivate', $id); 
    1141  
    1142                     $this->modules->activateModule($id); 
    1143  
    1144                     # --BEHAVIOR-- moduleAfterActivate 
    1145                     $this->core->callBehavior('pluginAfterActivate', $id); 
    1146  
    1147                     $count++; 
    1148                } 
    1149  
    1150                dcPage::addSuccessNotice( 
    1151                     __('Plugin has been successfully activated.', 'Plugins have been successuflly activated.', $count) 
    1152                ); 
    1153                http::redirect($this->getURL()); 
    1154           } 
    1155  
    1156           elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['deactivate'])) { 
    1157  
    1158                if (is_array($_POST['deactivate'])) { 
    1159                     $modules = array_keys($_POST['deactivate']); 
    1160                } 
    1161  
    1162                $list = $this->modules->getModules(); 
    1163                if (empty($list)) { 
    1164                     throw new Exception(__('No such plugin.')); 
    1165                } 
    1166  
    1167                $failed = false; 
    1168                $count = 0; 
    1169                foreach($list as $id => $module) { 
    1170  
    1171                     if (!in_array($id, $modules)) { 
    1172                          continue; 
    1173                     } 
    1174  
    1175                     if (!$module['root_writable']) { 
    1176                          $failed = true; 
    1177                          continue; 
    1178                     } 
    1179  
    1180                     $module[$id] = $id; 
    1181  
    1182                     # --BEHAVIOR-- moduleBeforeDeactivate 
    1183                     $this->core->callBehavior('pluginBeforeDeactivate', $module); 
    1184  
    1185                     $this->modules->deactivateModule($id); 
    1186  
    1187                     # --BEHAVIOR-- moduleAfterDeactivate 
    1188                     $this->core->callBehavior('pluginAfterDeactivate', $module); 
    1189  
    1190                     $count++; 
    1191                } 
    1192  
    1193                if ($failed) { 
    1194                     dcPage::addWarningNotice(__('Some plugins have not been deactivated.')); 
    1195                } 
    1196                else { 
    1197                     dcPage::addSuccessNotice( 
    1198                          __('Plugin has been successfully deactivated.', 'Plugins have been successuflly deactivated.', $count) 
    1199                     ); 
    1200                } 
    1201                http::redirect($this->getURL()); 
    1202           } 
    1203  
    1204           elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['update'])) { 
    1205  
    1206                if (is_array($_POST['update'])) { 
    1207                     $modules = array_keys($_POST['update']); 
    1208                } 
    1209  
    1210                $list = $this->store->get(true); 
    1211                if (empty($list)) { 
    1212                     throw new Exception(__('No such plugin.')); 
    1213                } 
    1214  
    1215                $count = 0; 
    1216                foreach($list as $module) { 
    1217  
    1218                     if (!in_array($module['id'], $modules)) { 
    1219                          continue; 
    1220                     } 
    1221  
    1222                     if (!self::$allow_multi_install) { 
    1223                          $dest = $module['root'].'/../'.basename($module['file']); 
    1224                     } 
    1225                     else { 
    1226                          $dest = $this->getPath().'/'.basename($module['file']); 
    1227                          if ($module['root'] != $dest) { 
    1228                               @file_put_contents($module['root'].'/_disabled', ''); 
    1229                          } 
    1230                     } 
    1231  
    1232                     # --BEHAVIOR-- moduleBeforeUpdate 
    1233                     $this->core->callBehavior('pluginBeforeUpdate', $module); 
    1234  
    1235                     $this->store->process($module['file'], $dest); 
    1236  
    1237                     # --BEHAVIOR-- moduleAfterUpdate 
    1238                     $this->core->callBehavior('pluginAfterUpdate', $module); 
    1239  
    1240                     $count++; 
    1241                } 
    1242  
    1243                $tab = $count && $count == count($list) ? '#plugins' : '#update'; 
    1244  
    1245                dcPage::addSuccessNotice( 
    1246                     __('Plugin has been successfully updated.', 'Plugins have been successuflly updated.', $count) 
    1247                ); 
    1248                http::redirect($this->getURL().$tab); 
    1249           } 
    1250  
    1251           # Manual actions 
    1252           elseif (!empty($_POST['upload_pkg']) && !empty($_FILES['pkg_file']) 
    1253                || !empty($_POST['fetch_pkg']) && !empty($_POST['pkg_url'])) 
    1254           { 
    1255                if (empty($_POST['your_pwd']) || !$this->core->auth->checkPassword($_POST['your_pwd'])) { 
    1256                     throw new Exception(__('Password verification failed')); 
    1257                } 
    1258  
    1259                if (!empty($_POST['upload_pkg'])) { 
    1260                     files::uploadStatus($_FILES['pkg_file']); 
    1261  
    1262                     $dest = $this->getPath().'/'.$_FILES['pkg_file']['name']; 
    1263                     if (!move_uploaded_file($_FILES['pkg_file']['tmp_name'], $dest)) { 
    1264                          throw new Exception(__('Unable to move uploaded file.')); 
    1265                     } 
    1266                } 
    1267                else { 
    1268                     $url = urldecode($_POST['pkg_url']); 
    1269                     $dest = $this->getPath().'/'.basename($url); 
    1270                     $this->store->download($url, $dest); 
    1271                } 
    1272  
    1273                # --BEHAVIOR-- moduleBeforeAdd 
    1274                $this->core->callBehavior('pluginBeforeAdd', null); 
    1275  
    1276                $ret_code = $this->store->install($dest); 
    1277  
    1278                # --BEHAVIOR-- moduleAfterAdd 
    1279                $this->core->callBehavior('pluginAfterAdd', null); 
    1280  
    1281                dcPage::addSuccessNotice($ret_code == 2 ? 
    1282                     __('Plugin has been successfully updated.') : 
    1283                     __('Plugin has been successfully installed.') 
    1284                ); 
    1285                http::redirect($this->getURL().'#plugins'); 
    1286           } 
    1287  
    1288           else { 
    1289  
    1290                # --BEHAVIOR-- adminModulesListDoActions 
    1291                $this->core->callBehavior('adminModulesListDoActions', $this, $modules, 'plugin'); 
    1292  
    1293           } 
    1294  
    1295           return null; 
    1296      } 
    1297  
    1298      /** 
    1299       * Display tab for manual installation. 
    1300       * 
    1301       * @return     adminModulesList self instance 
    1302       */ 
    1303      public function displayManualForm() 
    1304      { 
    1305           if (!$this->core->auth->isSuperAdmin() || !$this->isWritablePath()) { 
    1306                return null; 
    1307           } 
    1308  
    1309           # 'Upload module' form 
    1310           echo 
    1311           '<form method="post" action="'.$this->getURL().'" id="uploadpkg" enctype="multipart/form-data" class="fieldset">'. 
    1312           '<h4>'.__('Upload a zip file').'</h4>'. 
    1313           '<p class="field"><label for="pkg_file" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Zip file path:').'</label> '. 
    1314           '<input type="file" name="pkg_file" id="pkg_file" required /></p>'. 
    1315           '<p class="field"><label for="your_pwd1" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '. 
    1316           form::password(array('your_pwd','your_pwd1'),20,255,'','','',false,'required placeholder="'.__('Password').'"').'</p>'. 
    1317           '<p><input type="submit" name="upload_pkg" value="'.__('Upload').'" />'. 
    1318           $this->core->formNonce().'</p>'. 
    1319           '</form>'; 
    1320  
    1321           # 'Fetch module' form 
    1322           echo 
    1323           '<form method="post" action="'.$this->getURL().'" id="fetchpkg" class="fieldset">'. 
    1324           '<h4>'.__('Download a zip file').'</h4>'. 
    1325           '<p class="field"><label for="pkg_url" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Zip file URL:').'</label> '. 
    1326           form::field(array('pkg_url','pkg_url'),40,255,'','','',false,'required placeholder="'.__('URL').'"').'</p>'. 
    1327           '<p class="field"><label for="your_pwd2" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '. 
    1328           form::password(array('your_pwd','your_pwd2'),20,255,'','','',false,'required placeholder="'.__('Password').'"').'</p>'. 
    1329           '<p><input type="submit" name="fetch_pkg" value="'.__('Download').'" />'. 
    1330           $this->core->formNonce().'</p>'. 
    1331           '</form>'; 
    1332  
    1333           return $this; 
    1334      } 
    1335      //@} 
    1336  
    1337      /// @name Module configuration methods 
    1338      //@{ 
    1339      /** 
    1340       * Prepare module configuration. 
    1341       * 
    1342       * We need to get configuration content in three steps 
    1343       * and out of this class to keep backward compatibility. 
    1344       * 
    1345       * if ($xxx->setConfiguration()) { 
    1346       *   include $xxx->includeConfiguration(); 
    1347       * } 
    1348       * $xxx->getConfiguration(); 
    1349       * ... [put here page headers and other stuff] 
    1350       * $xxx->displayConfiguration(); 
    1351       * 
    1352       * @param string    $id       Module to work on or it gather through REQUEST 
    1353       * @return     True if config set 
    1354       */ 
    1355      public function setConfiguration($id=null) 
    1356      { 
    1357           if (empty($_REQUEST['conf']) || empty($_REQUEST['module']) && !$id) { 
    1358                return false; 
    1359           } 
    1360  
    1361           if (!empty($_REQUEST['module']) && empty($id)) { 
    1362                $id = $_REQUEST['module']; 
    1363           } 
    1364  
    1365           if (!$this->modules->moduleExists($id)) { 
    1366                $this->core->error->add(__('Unknow plugin ID')); 
    1367                return false; 
    1368           } 
    1369  
    1370           $module = $this->modules->getModules($id); 
    1371           $module = self::sanitizeModule($id, $module); 
    1372           $file = path::real($module['root'].'/_config.php'); 
    1373  
    1374           if (!file_exists($file)) { 
    1375                $this->core->error->add(__('This plugin has no configuration file.')); 
    1376                return false; 
    1377           } 
    1378  
    1379           $this->config_module = $module; 
    1380           $this->config_file = $file; 
    1381           $this->config_content = ''; 
    1382  
    1383           if (!defined('DC_CONTEXT_MODULE')) { 
    1384                define('DC_CONTEXT_MODULE', true); 
    1385           } 
    1386  
    1387           return true; 
    1388      } 
    1389  
    1390      /** 
    1391       * Get path of module configuration file. 
    1392       * 
    1393       * @note Required previously set file info 
    1394       * @return Full path of config file or null 
    1395       */ 
    1396      public function includeConfiguration() 
    1397      { 
    1398           if (!$this->config_file) { 
    1399                return null; 
    1400           } 
    1401           $this->setRedir($this->getURL().'#plugins'); 
    1402  
    1403           ob_start(); 
    1404  
    1405           return $this->config_file; 
    1406      } 
    1407  
    1408      /** 
    1409       * Gather module configuration file content. 
    1410       * 
    1411       * @note Required previously file inclusion 
    1412       * @return True if content has been captured 
    1413       */ 
    1414      public function getConfiguration() 
    1415      { 
    1416           if ($this->config_file) { 
    1417                $this->config_content = ob_get_contents(); 
    1418           } 
    1419  
    1420           ob_end_clean(); 
    1421  
    1422           return !empty($this->file_content); 
    1423      } 
    1424  
    1425      /** 
    1426       * Display module configuration form. 
    1427       * 
    1428       * @note Required previously gathered content 
    1429       * @return     adminModulesList self instance 
    1430       */ 
    1431      public function displayConfiguration() 
    1432      { 
    1433           if ($this->config_file) { 
    1434  
    1435                if (!$this->config_module['standalone_config']) { 
    1436                     echo 
    1437                     '<form id="module_config" action="'.$this->getURL('conf=1').'" method="post" enctype="multipart/form-data">'. 
    1438                     '<h3>'.sprintf(__('Configure "%s"'), html::escapeHTML($this->config_module['name'])).'</h3>'. 
    1439                     '<p><a class="back" href="'.$this->getRedir().'">'.__('Back').'</a></p>'; 
    1440                } 
    1441  
    1442                echo $this->config_content; 
    1443  
    1444                if (!$this->config_module['standalone_config']) { 
    1445                     echo 
    1446                     '<p class="clear"><input type="submit" name="save" value="'.__('Save').'" />'. 
    1447                     form::hidden('module', $this->config_module['id']). 
    1448                     form::hidden('redir', $this->getRedir()). 
    1449                     $this->core->formNonce().'</p>'. 
    1450                     '</form>'; 
    1451                } 
    1452           } 
    1453  
    1454           return $this; 
    1455      } 
    1456      //@} 
    1457  
    1458      /** 
    1459       * Helper to sanitize a string. 
    1460       * 
    1461       * Used for search or id. 
    1462       * 
    1463       * @param string    $str      String to sanitize 
    1464       * @return     Sanitized string 
    1465       */ 
    1466      public static function sanitizeString($str) 
    1467      { 
    1468           return preg_replace('/[^A-Za-z0-9\@\#+_-]/', '', strtolower($str)); 
    1469      } 
     23    public $core; /**< @var    object    dcCore instance */ 
     24    public $modules; /**< @var    object    dcModules instance */ 
     25    public $store; /**< @var    object    dcStore instance */ 
     26 
     27    public static $allow_multi_install = false; /**< @var    boolean    Work with multiple root directories */ 
     28    public static $distributed_modules = array(); /**< @var    array    List of modules distributed with Dotclear */ 
     29 
     30    protected $list_id = 'unknow'; /**< @var    string    Current list ID */ 
     31    protected $data    = array(); /**< @var    array    Current modules */ 
     32 
     33    protected $config_module  = ''; /**< @var    string    Module ID to configure */ 
     34    protected $config_file    = ''; /**< @var    string    Module path to configure */ 
     35    protected $config_content = ''; /**< @var    string    Module configuration page content */ 
     36 
     37    protected $path          = false; /**< @var    string    Modules root directory */ 
     38    protected $path_writable = false; /**< @var    boolean    Indicate if modules root directory is writable */ 
     39    protected $path_pattern  = false; /**< @var    string    Directory pattern to work on */ 
     40 
     41    protected $page_url   = ''; /**< @var    string    Page URL */ 
     42    protected $page_qs    = '?'; /**< @var    string    Page query string */ 
     43    protected $page_tab   = ''; /**< @var    string    Page tab */ 
     44    protected $page_redir = ''; /**< @var    string    Page redirection */ 
     45 
     46    public static $nav_indexes = 'abcdefghijklmnopqrstuvwxyz0123456789'; /**< @var    string    Index list */ 
     47    protected $nav_list        = array(); /**< @var    array    Index list with special index */ 
     48    protected $nav_special     = 'other'; /**< @var    string    Text for other special index */ 
     49 
     50    protected $sort_field = 'sname'; /**< @var    string    Field used to sort modules */ 
     51    protected $sort_asc   = true; /**< @var    boolean    Sort order asc */ 
     52 
     53    /** 
     54     * Constructor. 
     55     * 
     56     * Note that this creates dcStore instance. 
     57     * 
     58     * @param    object    $modules        dcModules instance 
     59     * @param    string    $modules_root    Modules root directories 
     60     * @param    string    $xml_url        URL of modules feed from repository 
     61     */ 
     62    public function __construct(dcModules $modules, $modules_root, $xml_url) 
     63    { 
     64        $this->core    = $modules->core; 
     65        $this->modules = $modules; 
     66        $this->store   = new dcStore($modules, $xml_url); 
     67 
     68        $this->page_url = $this->core->adminurl->get('admin.plugins'); 
     69 
     70        $this->setPath($modules_root); 
     71        $this->setIndex(__('other')); 
     72    } 
     73 
     74    /** 
     75     * Begin a new list. 
     76     * 
     77     * @param    string    $id        New list ID 
     78     * @return    adminModulesList self instance 
     79     */ 
     80    public function setList($id) 
     81    { 
     82        $this->data     = array(); 
     83        $this->page_tab = ''; 
     84        $this->list_id  = $id; 
     85 
     86        return $this; 
     87    } 
     88 
     89    /** 
     90     * Get list ID. 
     91     * 
     92     * @return    List ID 
     93     */ 
     94    public function getList() 
     95    { 
     96        return $this->list_id; 
     97    } 
     98 
     99    /// @name Modules root directory methods 
     100    //@{ 
     101    /** 
     102     * Set path info. 
     103     * 
     104     * @param    string    $root        Modules root directories 
     105     * @return    adminModulesList self instance 
     106     */ 
     107    protected function setPath($root) 
     108    { 
     109        $paths = explode(PATH_SEPARATOR, $root); 
     110        $path  = array_pop($paths); 
     111        unset($paths); 
     112 
     113        $this->path = $path; 
     114        if (is_dir($path) && is_writeable($path)) { 
     115            $this->path_writable = true; 
     116            $this->path_pattern  = preg_quote($path, '!'); 
     117        } 
     118 
     119        return $this; 
     120    } 
     121 
     122    /** 
     123     * Get modules root directory. 
     124     * 
     125     * @return    Path to work on 
     126     */ 
     127    public function getPath() 
     128    { 
     129        return $this->path; 
     130    } 
     131 
     132    /** 
     133     * Check if modules root directory is writable. 
     134     * 
     135     * @return    True if directory is writable 
     136     */ 
     137    public function isWritablePath() 
     138    { 
     139        return $this->path_writable; 
     140    } 
     141 
     142    /** 
     143     * Check if root directory of a module is deletable. 
     144     * 
     145     * @param    string    $root        Module root directory 
     146     * @return    True if directory is delatable 
     147     */ 
     148    public function isDeletablePath($root) 
     149    { 
     150        return $this->path_writable 
     151        && (preg_match('!^' . $this->path_pattern . '!', $root) || defined('DC_DEV') && DC_DEV) 
     152        && $this->core->auth->isSuperAdmin(); 
     153    } 
     154    //@} 
     155 
     156    /// @name Page methods 
     157    //@{ 
     158    /** 
     159     * Set page base URL. 
     160     * 
     161     * @param    string    $url        Page base URL 
     162     * @return    adminModulesList self instance 
     163     */ 
     164    public function setURL($url) 
     165    { 
     166        $this->page_qs  = strpos('?', $url) ? '&amp;' : '?'; 
     167        $this->page_url = $url; 
     168 
     169        return $this; 
     170    } 
     171 
     172    /** 
     173     * Get page URL. 
     174     * 
     175     * @param    string|array    $queries    Additionnal query string 
     176     * @param    booleany    $with_tab        Add current tab to URL end 
     177     * @return    Clean page URL 
     178     */ 
     179    public function getURL($queries = '', $with_tab = true) 
     180    { 
     181        return $this->page_url . 
     182            (!empty($queries) ? $this->page_qs : '') . 
     183            (is_array($queries) ? http_build_query($queries) : $queries) . 
     184            ($with_tab && !empty($this->page_tab) ? '#' . $this->page_tab : ''); 
     185    } 
     186 
     187    /** 
     188     * Set page tab. 
     189     * 
     190     * @param    string    $tab        Page tab 
     191     * @return    adminModulesList self instance 
     192     */ 
     193    public function setTab($tab) 
     194    { 
     195        $this->page_tab = $tab; 
     196 
     197        return $this; 
     198    } 
     199 
     200    /** 
     201     * Get page tab. 
     202     * 
     203     * @return    Page tab 
     204     */ 
     205    public function getTab() 
     206    { 
     207        return $this->page_tab; 
     208    } 
     209 
     210    /** 
     211     * Set page redirection. 
     212     * 
     213     * @param    string    $default        Default redirection 
     214     * @return    adminModulesList self instance 
     215     */ 
     216    public function setRedir($default = '') 
     217    { 
     218        $this->page_redir = empty($_REQUEST['redir']) ? $default : $_REQUEST['redir']; 
     219 
     220        return $this; 
     221    } 
     222 
     223    /** 
     224     * Get page redirection. 
     225     * 
     226     * @return    Page redirection 
     227     */ 
     228    public function getRedir() 
     229    { 
     230        return empty($this->page_redir) ? $this->getURL() : $this->page_redir; 
     231    } 
     232    //@} 
     233 
     234    /// @name Search methods 
     235    //@{ 
     236    /** 
     237     * Get search query. 
     238     * 
     239     * @return    Search query 
     240     */ 
     241    public function getSearch() 
     242    { 
     243        $query = !empty($_REQUEST['m_search']) ? trim($_REQUEST['m_search']) : null; 
     244        return strlen($query) > 2 ? $query : null; 
     245    } 
     246 
     247    /** 
     248     * Display searh form. 
     249     * 
     250     * @return    adminModulesList self instance 
     251     */ 
     252    public function displaySearch() 
     253    { 
     254        $query = $this->getSearch(); 
     255 
     256        if (empty($this->data) && $query === null) { 
     257            return $this; 
     258        } 
     259 
     260        echo 
     261        '<div class="modules-search">' . 
     262        '<form action="' . $this->getURL() . '" method="get">' . 
     263        '<p><label for="m_search" class="classic">' . __('Search in repository:') . '&nbsp;</label><br />' . 
     264        form::field(array('m_search', 'm_search'), 30, 255, html::escapeHTML($query)) . 
     265        '<input type="submit" value="' . __('OK') . '" /> '; 
     266 
     267        if ($query) { 
     268            echo 
     269            ' <a href="' . $this->getURL() . '" class="button">' . __('Reset search') . '</a>'; 
     270        } 
     271 
     272        echo 
     273        '</p>' . 
     274        '<p class="form-note">' . 
     275        __('Search is allowed on multiple terms longer than 2 chars, terms must be separated by space.') . 
     276            '</p>' . 
     277            '</form>'; 
     278 
     279        if ($query) { 
     280            echo 
     281            '<p class="message">' . sprintf( 
     282                __('Found %d result for search "%s":', 'Found %d results for search "%s":', count($this->data)), 
     283                count($this->data), html::escapeHTML($query) 
     284            ) . 
     285                '</p>'; 
     286        } 
     287        echo '</div>'; 
     288 
     289        return $this; 
     290    } 
     291    //@} 
     292 
     293    /// @name Navigation menu methods 
     294    //@{ 
     295    /** 
     296     * Set navigation special index. 
     297     * 
     298     * @return    adminModulesList self instance 
     299     */ 
     300    public function setIndex($str) 
     301    { 
     302        $this->nav_special = (string) $str; 
     303        $this->nav_list    = array_merge(str_split(self::$nav_indexes), array($this->nav_special)); 
     304 
     305        return $this; 
     306    } 
     307 
     308    /** 
     309     * Get index from query. 
     310     * 
     311     * @return    Query index or default one 
     312     */ 
     313    public function getIndex() 
     314    { 
     315        return isset($_REQUEST['m_nav']) && in_array($_REQUEST['m_nav'], $this->nav_list) ? $_REQUEST['m_nav'] : $this->nav_list[0]; 
     316    } 
     317 
     318    /** 
     319     * Display navigation by index menu. 
     320     * 
     321     * @return    adminModulesList self instance 
     322     */ 
     323    public function displayIndex() 
     324    { 
     325        if (empty($this->data) || $this->getSearch() !== null) { 
     326            return $this; 
     327        } 
     328 
     329        # Fetch modules required field 
     330        $indexes = array(); 
     331        foreach ($this->data as $id => $module) { 
     332            if (!isset($module[$this->sort_field])) { 
     333                continue; 
     334            } 
     335            $char = substr($module[$this->sort_field], 0, 1); 
     336            if (!in_array($char, $this->nav_list)) { 
     337                $char = $this->nav_special; 
     338            } 
     339            if (!isset($indexes[$char])) { 
     340                $indexes[$char] = 0; 
     341            } 
     342            $indexes[$char]++; 
     343        } 
     344 
     345        $buttons = array(); 
     346        foreach ($this->nav_list as $char) { 
     347            # Selected letter 
     348            if ($this->getIndex() == $char) { 
     349                $buttons[] = '<li class="active" title="' . __('current selection') . '"><strong> ' . $char . ' </strong></li>'; 
     350            } 
     351            # Letter having modules 
     352            elseif (!empty($indexes[$char])) { 
     353                $title     = sprintf(__('%d result', '%d results', $indexes[$char]), $indexes[$char]); 
     354                $buttons[] = '<li class="btn" title="' . $title . '"><a href="' . $this->getURL('m_nav=' . $char) . '" title="' . $title . '"> ' . $char . ' </a></li>'; 
     355            } 
     356            # Letter without modules 
     357            else { 
     358                $buttons[] = '<li class="btn no-link" title="' . __('no results') . '"> ' . $char . ' </li>'; 
     359            } 
     360        } 
     361        # Parse navigation menu 
     362        echo '<div class="pager">' . __('Browse index:') . ' <ul class="index">' . implode('', $buttons) . '</ul></div>'; 
     363 
     364        return $this; 
     365    } 
     366    //@} 
     367 
     368    /// @name Sort methods 
     369    //@{ 
     370    /** 
     371     * Set default sort field. 
     372     * 
     373     * @return    adminModulesList self instance 
     374     */ 
     375    public function setSort($field, $asc = true) 
     376    { 
     377        $this->sort_field = $field; 
     378        $this->sort_asc   = (boolean) $asc; 
     379 
     380        return $this; 
     381    } 
     382 
     383    /** 
     384     * Get sort field from query. 
     385     * 
     386     * @return    Query sort field or default one 
     387     */ 
     388    public function getSort() 
     389    { 
     390        return !empty($_REQUEST['m_sort']) ? $_REQUEST['m_sort'] : $this->sort_field; 
     391    } 
     392 
     393    /** 
     394     * Display sort field form. 
     395     * 
     396     * @note    This method is not implemented yet 
     397     * @return    adminModulesList self instance 
     398     */ 
     399    public function displaySort() 
     400    { 
     401        // 
     402 
     403        return $this; 
     404    } 
     405    //@} 
     406 
     407    /// @name Modules methods 
     408    //@{ 
     409    /** 
     410     * Set modules and sanitize them. 
     411     * 
     412     * @return    adminModulesList self instance 
     413     */ 
     414    public function setModules($modules) 
     415    { 
     416        $this->data = array(); 
     417        if (!empty($modules) && is_array($modules)) { 
     418            foreach ($modules as $id => $module) { 
     419                $this->data[$id] = self::sanitizeModule($id, $module); 
     420            } 
     421        } 
     422        return $this; 
     423    } 
     424 
     425    /** 
     426     * Get modules currently set. 
     427     * 
     428     * @return    Array of modules 
     429     */ 
     430    public function getModules() 
     431    { 
     432        return $this->data; 
     433    } 
     434 
     435    /** 
     436     * Sanitize a module. 
     437     * 
     438     * This clean infos of a module by adding default keys 
     439     * and clean some of them, sanitize module can safely 
     440     * be used in lists. 
     441     * 
     442     * @return    Array of the module informations 
     443     */ 
     444    public static function sanitizeModule($id, $module) 
     445    { 
     446        $label = empty($module['label']) ? $id : $module['label']; 
     447        $name  = __(empty($module['name']) ? $label : $module['name']); 
     448 
     449        return array_merge( 
     450            # Default values 
     451            array( 
     452                'desc'              => '', 
     453                'author'            => '', 
     454                'version'           => 0, 
     455                'current_version'   => 0, 
     456                'root'              => '', 
     457                'root_writable'     => false, 
     458                'permissions'       => null, 
     459                'parent'            => null, 
     460                'priority'          => 1000, 
     461                'standalone_config' => false, 
     462                'support'           => '', 
     463                'section'           => '', 
     464                'tags'              => '', 
     465                'details'           => '', 
     466                'sshot'             => '', 
     467                'score'             => 0, 
     468                'type'              => null, 
     469                'require'           => array(), 
     470                'settings'          => array() 
     471            ), 
     472            # Module's values 
     473            $module, 
     474            # Clean up values 
     475            array( 
     476                'id'    => $id, 
     477                'sid'   => self::sanitizeString($id), 
     478                'label' => $label, 
     479                'name'  => $name, 
     480                'sname' => self::sanitizeString($name) 
     481            ) 
     482        ); 
     483    } 
     484 
     485    /** 
     486     * Check if a module is part of the distribution. 
     487     * 
     488     * @param    string    $id        Module root directory 
     489     * @return    True if module is part of the distribution 
     490     */ 
     491    public static function isDistributedModule($id) 
     492    { 
     493        $distributed_modules = self::$distributed_modules; 
     494 
     495        return is_array($distributed_modules) && in_array($id, $distributed_modules); 
     496    } 
     497 
     498    /** 
     499     * Sort modules list by specific field. 
     500     * 
     501     * @param    string    $module        Array of modules 
     502     * @param    string    $field        Field to sort from 
     503     * @param    bollean    $asc        Sort asc if true, else decs 
     504     * @return    Array of sorted modules 
     505     */ 
     506    public static function sortModules($modules, $field, $asc = true) 
     507    { 
     508        $origin = $sorter = array(); 
     509 
     510        foreach ($modules as $id => $module) { 
     511            $origin[] = $module; 
     512            $sorter[] = isset($module[$field]) ? $module[$field] : $field; 
     513        } 
     514 
     515        array_multisort($sorter, $asc ? SORT_ASC : SORT_DESC, $origin); 
     516 
     517        foreach ($origin as $module) { 
     518            $final[$module['id']] = $module; 
     519        } 
     520 
     521        return $final; 
     522    } 
     523 
     524    /** 
     525     * Display list of modules. 
     526     * 
     527     * @param    array    $cols        List of colones (module field) to display 
     528     * @param    array    $actions    List of predefined actions to show on form 
     529     * @param    boolean    $nav_limit    Limit list to previously selected index 
     530     * @return    adminModulesList self instance 
     531     */ 
     532    public function displayModules($cols = array('name', 'version', 'desc'), $actions = array(), $nav_limit = false) 
     533    { 
     534        echo 
     535        '<form action="' . $this->getURL() . '" method="post" class="modules-form-actions">' . 
     536        '<div class="table-outer">' . 
     537        '<table id="' . html::escapeHTML($this->list_id) . '" class="modules' . (in_array('expander', $cols) ? ' expandable' : '') . '">' . 
     538        '<caption class="hidden">' . html::escapeHTML(__('Plugins list')) . '</caption><tr>'; 
     539 
     540        if (in_array('name', $cols)) { 
     541            $colspan = 1; 
     542            if (in_array('checkbox', $cols)) { 
     543                $colspan++; 
     544            } 
     545            if (in_array('icon', $cols)) { 
     546                $colspan++; 
     547            } 
     548            echo 
     549            '<th class="first nowrap"' . ($colspan > 1 ? ' colspan="' . $colspan . '"' : '') . '>' . __('Name') . '</th>'; 
     550        } 
     551 
     552        if (in_array('score', $cols) && $this->getSearch() !== null && defined('DC_DEBUG') && DC_DEBUG) { 
     553            echo 
     554            '<th class="nowrap">' . __('Score') . '</th>'; 
     555        } 
     556 
     557        if (in_array('version', $cols)) { 
     558            echo 
     559            '<th class="nowrap count" scope="col">' . __('Version') . '</th>'; 
     560        } 
     561 
     562        if (in_array('current_version', $cols)) { 
     563            echo 
     564            '<th class="nowrap count" scope="col">' . __('Current version') . '</th>'; 
     565        } 
     566 
     567        if (in_array('desc', $cols)) { 
     568            echo 
     569            '<th class="nowrap" scope="col">' . __('Details') . '</th>'; 
     570        } 
     571 
     572        if (in_array('distrib', $cols)) { 
     573            echo 
     574                '<th' . (in_array('desc', $cols) ? '' : ' class="maximal"') . '></th>'; 
     575        } 
     576 
     577        if (!empty($actions) && $this->core->auth->isSuperAdmin()) { 
     578            echo 
     579            '<th class="minimal nowrap">' . __('Action') . '</th>'; 
     580        } 
     581 
     582        echo 
     583            '</tr>'; 
     584 
     585        $sort_field = $this->getSort(); 
     586 
     587        # Sort modules by $sort_field (default sname) 
     588        $modules = $this->getSearch() === null ? 
     589        self::sortModules($this->data, $sort_field, $this->sort_asc) : 
     590        $this->data; 
     591 
     592        $count = 0; 
     593        foreach ($modules as $id => $module) { 
     594            # Show only requested modules 
     595            if ($nav_limit && $this->getSearch() === null) { 
     596                $char = substr($module[$sort_field], 0, 1); 
     597                if (!in_array($char, $this->nav_list)) { 
     598                    $char = $this->nav_special; 
     599                } 
     600                if ($this->getIndex() != $char) { 
     601                    continue; 
     602                } 
     603            } 
     604 
     605            echo 
     606            '<tr class="line" id="' . html::escapeHTML($this->list_id) . '_m_' . html::escapeHTML($id) . '">'; 
     607 
     608            $tds = 0; 
     609 
     610            if (in_array('checkbox', $cols)) { 
     611                $tds++; 
     612                echo 
     613                '<td class="module-icon nowrap">' . 
     614                form::checkbox(array('modules[' . $count . ']', html::escapeHTML($this->list_id) . '_modules_' . html::escapeHTML($id)), html::escapeHTML($id)) . 
     615                    '</td>'; 
     616            } 
     617 
     618            if (in_array('icon', $cols)) { 
     619                $tds++; 
     620                echo 
     621                '<td class="module-icon nowrap">' . sprintf( 
     622                    '<img alt="%1$s" title="%1$s" src="%2$s" />', 
     623                    html::escapeHTML($id), file_exists($module['root'] . '/icon.png') ? 
     624                    dcPage::getPF($id . '/icon.png') : 'images/module.png' 
     625                ) . '</td>'; 
     626            } 
     627 
     628            $tds++; 
     629            echo 
     630                '<td class="module-name nowrap" scope="row">'; 
     631            if (in_array('checkbox', $cols)) { 
     632                if (in_array('expander', $cols)) { 
     633                    echo 
     634                    html::escapeHTML($module['name']) . ($id != $module['name'] ? sprintf(__(' (%s)'), $id) : ''); 
     635                } else { 
     636                    echo 
     637                    '<label for="' . html::escapeHTML($this->list_id) . '_modules_' . html::escapeHTML($id) . '">' . 
     638                    html::escapeHTML($module['name']) . ($id != $module['name'] ? sprintf(__(' (%s)'), $id) : '') . 
     639                        '</label>'; 
     640                } 
     641            } else { 
     642                echo 
     643                html::escapeHTML($module['name']) . ($id != $module['name'] ? sprintf(__(' (%s)'), $id) : '') . 
     644                form::hidden(array('modules[' . $count . ']'), html::escapeHTML($id)); 
     645            } 
     646            echo 
     647            $this->core->formNonce() . 
     648                '</td>'; 
     649 
     650            # Display score only for debug purpose 
     651            if (in_array('score', $cols) && $this->getSearch() !== null && defined('DC_DEBUG') && DC_DEBUG) { 
     652                $tds++; 
     653                echo 
     654                    '<td class="module-version nowrap count"><span class="debug">' . $module['score'] . '</span></td>'; 
     655            } 
     656 
     657            if (in_array('version', $cols)) { 
     658                $tds++; 
     659                echo 
     660                '<td class="module-version nowrap count">' . html::escapeHTML($module['version']) . '</td>'; 
     661            } 
     662 
     663            if (in_array('current_version', $cols)) { 
     664                $tds++; 
     665                echo 
     666                '<td class="module-current-version nowrap count">' . html::escapeHTML($module['current_version']) . '</td>'; 
     667            } 
     668 
     669            if (in_array('desc', $cols)) { 
     670                $tds++; 
     671                echo 
     672                '<td class="module-desc maximal">' . html::escapeHTML(__($module['desc'])); 
     673                if (isset($module['cannot_disable']) && $module['enabled']) { 
     674                    echo 
     675                    '<br/><span class="info">' . 
     676                    sprintf(__('This module cannot be disabled nor deleted, since the following modules are also enabled : %s'), 
     677                        join(',', $module['cannot_disable'])) . 
     678                        '</span>'; 
     679                } 
     680                if (isset($module['cannot_enable']) && !$module['enabled']) { 
     681                    echo 
     682                    '<br/><span class="info">' . 
     683                    __('This module cannot be enabled, because of the following reasons :') . 
     684                        '<ul>'; 
     685                    foreach ($module['cannot_enable'] as $m => $reason) { 
     686                        echo '<li>' . $reason . '</li>'; 
     687                    } 
     688                    echo '</ul>' . 
     689                        '</span>'; 
     690                } 
     691                echo '</td>'; 
     692 
     693            } 
     694 
     695            if (in_array('distrib', $cols)) { 
     696                $tds++; 
     697                echo 
     698                    '<td class="module-distrib">' . (self::isDistributedModule($id) ? 
     699                    '<img src="images/dotclear_pw.png" alt="' . 
     700                    __('Plugin from official distribution') . '" title="' . 
     701                    __('Plugin from official distribution') . '" />' 
     702                    : '') . '</td>'; 
     703            } 
     704 
     705            if (!empty($actions) && $this->core->auth->isSuperAdmin()) { 
     706                $buttons = $this->getActions($id, $module, $actions); 
     707 
     708                $tds++; 
     709                echo 
     710                '<td class="module-actions nowrap">' . 
     711 
     712                '<div>' . implode(' ', $buttons) . '</div>' . 
     713 
     714                    '</td>'; 
     715            } 
     716 
     717            echo 
     718                '</tr>'; 
     719 
     720            # Other informations 
     721            if (in_array('expander', $cols)) { 
     722                echo 
     723                    '<tr class="module-more"><td colspan="' . $tds . '" class="expand">'; 
     724 
     725                if (!empty($module['author']) || !empty($module['details']) || !empty($module['support'])) { 
     726                    echo 
     727                        '<div><ul class="mod-more">'; 
     728 
     729                    if (!empty($module['author'])) { 
     730                        echo 
     731                        '<li class="module-author">' . __('Author:') . ' ' . html::escapeHTML($module['author']) . '</li>'; 
     732                    } 
     733 
     734                    $more = array(); 
     735                    if (!empty($module['details'])) { 
     736                        $more[] = '<a class="module-details" href="' . $module['details'] . '">' . __('Details') . '</a>'; 
     737                    } 
     738 
     739                    if (!empty($module['support'])) { 
     740                        $more[] = '<a class="module-support" href="' . $module['support'] . '">' . __('Support') . '</a>'; 
     741                    } 
     742 
     743                    if (!empty($more)) { 
     744                        echo 
     745                        '<li>' . implode(' - ', $more) . '</li>'; 
     746                    } 
     747 
     748                    echo 
     749                        '</ul></div>'; 
     750                } 
     751 
     752                $config = !empty($module['root']) && file_exists(path::real($module['root'] . '/_config.php')); 
     753                $index  = !empty($module['root']) && file_exists(path::real($module['root'] . '/index.php')); 
     754 
     755                if ($config || $index || !empty($module['section']) || !empty($module['tags']) || !empty($module['settings'])) { 
     756                    echo 
     757                        '<div><ul class="mod-more">'; 
     758 
     759                    if ($index && $module['enabled']) { 
     760                        echo '<li><a href="' . $this->core->adminurl->get('admin.plugin.' . $id) . '">' . __('Manage plugin') . '</a></li>'; 
     761                    } 
     762 
     763                    $settings = $this->getSettingsUrls($this->core, $id); 
     764                    if (!empty($settings) && $module['enabled']) { 
     765                        echo '<li>' . implode(' - ', $settings) . '</li>'; 
     766                    } 
     767 
     768                    if (!empty($module['section'])) { 
     769                        echo 
     770                        '<li class="module-section">' . __('Section:') . ' ' . html::escapeHTML($module['section']) . '</li>'; 
     771                    } 
     772 
     773                    if (!empty($module['tags'])) { 
     774                        echo 
     775                        '<li class="module-tags">' . __('Tags:') . ' ' . html::escapeHTML($module['tags']) . '</li>'; 
     776                    } 
     777 
     778                    echo 
     779                        '</ul></div>'; 
     780                } 
     781 
     782                echo 
     783                    '</td></tr>'; 
     784            } 
     785 
     786            $count++; 
     787        } 
     788        echo 
     789            '</table></div>'; 
     790 
     791        if (!$count && $this->getSearch() === null) { 
     792            echo 
     793            '<p class="message">' . __('No plugins matched your search.') . '</p>'; 
     794        } elseif ((in_array('checkbox', $cols) || $count > 1) && !empty($actions) && $this->core->auth->isSuperAdmin()) { 
     795            $buttons = $this->getGlobalActions($actions, in_array('checkbox', $cols)); 
     796 
     797            if (!empty($buttons)) { 
     798                if (in_array('checkbox', $cols)) { 
     799                    echo 
     800                        '<p class="checkboxes-helpers"></p>'; 
     801                } 
     802                echo 
     803                '<div>' . implode(' ', $buttons) . '</div>'; 
     804            } 
     805        } 
     806        echo 
     807            '</form>'; 
     808 
     809        return $this; 
     810    } 
     811 
     812    /** 
     813     * Get settings URLs if any 
     814     * 
     815     * @param object $core 
     816     * @param string $id module ID 
     817     * @param boolean $check check permission 
     818     * @param boolean $self include self URL (→ plugin index.php URL) 
     819     * @return Array of settings URLs 
     820     */ 
     821    public static function getSettingsUrls($core, $id, $check = false, $self = true) 
     822    { 
     823        $st = array(); 
     824 
     825        $mr       = $core->plugins->moduleRoot($id); 
     826        $config   = !empty($mr) && file_exists(path::real($mr . '/_config.php')); 
     827        $settings = $core->plugins->moduleInfo($id, 'settings'); 
     828        if ($config || !empty($settings)) { 
     829            if ($config) { 
     830                if (!$check || 
     831                    $core->auth->isSuperAdmin() || 
     832                    $core->auth->check($core->plugins->moduleInfo($id, 'permissions'), $core->blog->id)) { 
     833                    $params = array('module' => $id, 'conf' => '1'); 
     834                    if (!$core->plugins->moduleInfo($id, 'standalone_config') && !$self) { 
     835                        $params['redir'] = $core->adminurl->get('admin.plugin.' . $id); 
     836                    } 
     837                    $st[] = '<a class="module-config" href="' . 
     838                    $core->adminurl->get('admin.plugins', $params) . 
     839                    '">' . __('Configure plugin') . '</a>'; 
     840                } 
     841            } 
     842            if (is_array($settings)) { 
     843                foreach ($settings as $sk => $sv) { 
     844                    switch ($sk) { 
     845                        case 'blog': 
     846                            if (!$check || 
     847                                $core->auth->isSuperAdmin() || 
     848                                $core->auth->check('admin', $core->blog->id)) { 
     849                                $st[] = '<a class="module-config" href="' . 
     850                                $core->adminurl->get('admin.blog.pref') . $sv . 
     851                                '">' . __('Plugin settings (in blog parameters)') . '</a>'; 
     852                            } 
     853                            break; 
     854                        case 'pref': 
     855                            if (!$check || 
     856                                $core->auth->isSuperAdmin() || 
     857                                $core->auth->check('usage,contentadmin', $core->blog->id)) { 
     858                                $st[] = '<a class="module-config" href="' . 
     859                                $core->adminurl->get('admin.user.preferences') . $sv . 
     860                                '">' . __('Plugin settings (in user preferences)') . '</a>'; 
     861                            } 
     862                            break; 
     863                        case 'self': 
     864                            if ($self) { 
     865                                if (!$check || 
     866                                    $core->auth->isSuperAdmin() || 
     867                                    $core->auth->check($core->plugins->moduleInfo($id, 'permissions'), $core->blog->id)) { 
     868                                    $st[] = '<a class="module-config" href="' . 
     869                                    $core->adminurl->get('admin.plugin.' . $id) . $sv . 
     870                                    '">' . __('Plugin settings') . '</a>'; 
     871                                } 
     872                            } 
     873                            break; 
     874                    } 
     875                } 
     876            } 
     877        } 
     878 
     879        return $st; 
     880    } 
     881 
     882    /** 
     883     * Get action buttons to add to modules list. 
     884     * 
     885     * @param    string    $id            Module ID 
     886     * @param    array    $module        Module info 
     887     * @param    array    $actions    Actions keys 
     888     * @return    Array of actions buttons 
     889     */ 
     890    protected function getActions($id, $module, $actions) 
     891    { 
     892        $submits = array(); 
     893 
     894        # Use loop to keep requested order 
     895        foreach ($actions as $action) { 
     896            switch ($action) { 
     897 
     898                # Deactivate 
     899                case 'activate':if ($this->core->auth->isSuperAdmin() && $module['root_writable'] && !isset($module['cannot_enable'])) { 
     900                        $submits[] = 
     901                        '<input type="submit" name="activate[' . html::escapeHTML($id) . ']" value="' . __('Activate') . '" />'; 
     902                    }break; 
     903 
     904                # Activate 
     905                case 'deactivate':if ($this->core->auth->isSuperAdmin() && $module['root_writable'] && !isset($module['cannot_disable'])) { 
     906                        $submits[] = 
     907                        '<input type="submit" name="deactivate[' . html::escapeHTML($id) . ']" value="' . __('Deactivate') . '" class="reset" />'; 
     908                    }break; 
     909 
     910                # Delete 
     911                case 'delete':if ($this->core->auth->isSuperAdmin() && $this->isDeletablePath($module['root']) && !isset($module['cannot_disable'])) { 
     912                        $dev       = !preg_match('!^' . $this->path_pattern . '!', $module['root']) && defined('DC_DEV') && DC_DEV ? ' debug' : ''; 
     913                        $submits[] = 
     914                        '<input type="submit" class="delete ' . $dev . '" name="delete[' . html::escapeHTML($id) . ']" value="' . __('Delete') . '" />'; 
     915                    }break; 
     916 
     917                # Install (from store) 
     918                case 'install':if ($this->core->auth->isSuperAdmin() && $this->path_writable) { 
     919                        $submits[] = 
     920                        '<input type="submit" name="install[' . html::escapeHTML($id) . ']" value="' . __('Install') . '" />'; 
     921                    }break; 
     922 
     923                # Update (from store) 
     924                case 'update':if ($this->core->auth->isSuperAdmin() && $this->path_writable) { 
     925                        $submits[] = 
     926                        '<input type="submit" name="update[' . html::escapeHTML($id) . ']" value="' . __('Update') . '" />'; 
     927                    }break; 
     928 
     929                # Behavior 
     930                case 'behavior': 
     931 
     932                    # --BEHAVIOR-- adminModulesListGetActions 
     933                    $tmp = $this->core->callBehavior('adminModulesListGetActions', $this, $id, $module); 
     934 
     935                    if (!empty($tmp)) { 
     936                        $submits[] = $tmp; 
     937                    } 
     938                    break; 
     939            } 
     940        } 
     941 
     942        return $submits; 
     943    } 
     944 
     945    /** 
     946     * Get global action buttons to add to modules list. 
     947     * 
     948     * @param    array    $actions          Actions keys 
     949     * @param boolean   $with_selection Limit action to selected modules 
     950     * @return    Array of actions buttons 
     951     */ 
     952    protected function getGlobalActions($actions, $with_selection = false) 
     953    { 
     954        $submits = array(); 
     955 
     956        # Use loop to keep requested order 
     957        foreach ($actions as $action) { 
     958            switch ($action) { 
     959 
     960                # Deactivate 
     961                case 'activate':if ($this->core->auth->isSuperAdmin() && $this->path_writable) { 
     962                        $submits[] = 
     963                            '<input type="submit" name="activate" value="' . ($with_selection ? 
     964                            __('Activate selected plugins') : 
     965                            __('Activate all plugins from this list') 
     966                        ) . '" />'; 
     967                    }break; 
     968 
     969                # Activate 
     970                case 'deactivate':if ($this->core->auth->isSuperAdmin() && $this->path_writable) { 
     971                        $submits[] = 
     972                            '<input type="submit" name="deactivate" value="' . ($with_selection ? 
     973                            __('Deactivate selected plugins') : 
     974                            __('Deactivate all plugins from this list') 
     975                        ) . '" />'; 
     976                    }break; 
     977 
     978                # Update (from store) 
     979                case 'update':if ($this->core->auth->isSuperAdmin() && $this->path_writable) { 
     980                        $submits[] = 
     981                            '<input type="submit" name="update" value="' . ($with_selection ? 
     982                            __('Update selected plugins') : 
     983                            __('Update all plugins from this list') 
     984                        ) . '" />'; 
     985                    }break; 
     986 
     987                # Behavior 
     988                case 'behavior': 
     989 
     990                    # --BEHAVIOR-- adminModulesListGetGlobalActions 
     991                    $tmp = $this->core->callBehavior('adminModulesListGetGlobalActions', $this, $with_selection); 
     992 
     993                    if (!empty($tmp)) { 
     994                        $submits[] = $tmp; 
     995                    } 
     996                    break; 
     997            } 
     998        } 
     999 
     1000        return $submits; 
     1001    } 
     1002 
     1003    /** 
     1004     * Execute POST action. 
     1005     * 
     1006     * @note    Set a notice on success through dcPage::addSuccessNotice 
     1007     * @throw    Exception    Module not find or command failed 
     1008     * @return    Null 
     1009     */ 
     1010    public function doActions() 
     1011    { 
     1012        if (empty($_POST) || !empty($_REQUEST['conf']) 
     1013            || !$this->isWritablePath()) { 
     1014            return; 
     1015        } 
     1016 
     1017        $modules = !empty($_POST['modules']) && is_array($_POST['modules']) ? array_values($_POST['modules']) : array(); 
     1018 
     1019        if ($this->core->auth->isSuperAdmin() && !empty($_POST['delete'])) { 
     1020 
     1021            if (is_array($_POST['delete'])) { 
     1022                $modules = array_keys($_POST['delete']); 
     1023            } 
     1024 
     1025            $list = $this->modules->getDisabledModules(); 
     1026 
     1027            $failed = false; 
     1028            $count  = 0; 
     1029            foreach ($modules as $id) { 
     1030                if (!isset($list[$id])) { 
     1031 
     1032                    if (!$this->modules->moduleExists($id)) { 
     1033                        throw new Exception(__('No such plugin.')); 
     1034                    } 
     1035 
     1036                    $module       = $this->modules->getModules($id); 
     1037                    $module['id'] = $id; 
     1038 
     1039                    if (!$this->isDeletablePath($module['root'])) { 
     1040                        $failed = true; 
     1041                        continue; 
     1042                    } 
     1043 
     1044                    # --BEHAVIOR-- moduleBeforeDelete 
     1045                    $this->core->callBehavior('pluginBeforeDelete', $module); 
     1046 
     1047                    $this->modules->deleteModule($id); 
     1048 
     1049                    # --BEHAVIOR-- moduleAfterDelete 
     1050                    $this->core->callBehavior('pluginAfterDelete', $module); 
     1051                } else { 
     1052                    $this->modules->deleteModule($id, true); 
     1053                } 
     1054 
     1055                $count++; 
     1056            } 
     1057 
     1058            if (!$count && $failed) { 
     1059                throw new Exception(__("You don't have permissions to delete this plugin.")); 
     1060            } elseif ($failed) { 
     1061                dcPage::addWarningNotice(__('Some plugins have not been delete.')); 
     1062            } else { 
     1063                dcPage::addSuccessNotice( 
     1064                    __('Plugin has been successfully deleted.', 'Plugins have been successuflly deleted.', $count) 
     1065                ); 
     1066            } 
     1067            http::redirect($this->getURL()); 
     1068        } elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['install'])) { 
     1069 
     1070            if (is_array($_POST['install'])) { 
     1071                $modules = array_keys($_POST['install']); 
     1072            } 
     1073 
     1074            $list = $this->store->get(); 
     1075 
     1076            if (empty($list)) { 
     1077                throw new Exception(__('No such plugin.')); 
     1078            } 
     1079 
     1080            $count = 0; 
     1081            foreach ($list as $id => $module) { 
     1082 
     1083                if (!in_array($id, $modules)) { 
     1084                    continue; 
     1085                } 
     1086 
     1087                $dest = $this->getPath() . '/' . basename($module['file']); 
     1088 
     1089                # --BEHAVIOR-- moduleBeforeAdd 
     1090                $this->core->callBehavior('pluginBeforeAdd', $module); 
     1091 
     1092                $this->store->process($module['file'], $dest); 
     1093 
     1094                # --BEHAVIOR-- moduleAfterAdd 
     1095                $this->core->callBehavior('pluginAfterAdd', $module); 
     1096 
     1097                $count++; 
     1098            } 
     1099 
     1100            dcPage::addSuccessNotice( 
     1101                __('Plugin has been successfully installed.', 'Plugins have been successuflly installed.', $count) 
     1102            ); 
     1103            http::redirect($this->getURL()); 
     1104        } elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['activate'])) { 
     1105 
     1106            if (is_array($_POST['activate'])) { 
     1107                $modules = array_keys($_POST['activate']); 
     1108            } 
     1109 
     1110            $list = $this->modules->getDisabledModules(); 
     1111            if (empty($list)) { 
     1112                throw new Exception(__('No such plugin.')); 
     1113            } 
     1114 
     1115            $count = 0; 
     1116            foreach ($list as $id => $module) { 
     1117 
     1118                if (!in_array($id, $modules)) { 
     1119                    continue; 
     1120                } 
     1121 
     1122                # --BEHAVIOR-- moduleBeforeActivate 
     1123                $this->core->callBehavior('pluginBeforeActivate', $id); 
     1124 
     1125                $this->modules->activateModule($id); 
     1126 
     1127                # --BEHAVIOR-- moduleAfterActivate 
     1128                $this->core->callBehavior('pluginAfterActivate', $id); 
     1129 
     1130                $count++; 
     1131            } 
     1132 
     1133            dcPage::addSuccessNotice( 
     1134                __('Plugin has been successfully activated.', 'Plugins have been successuflly activated.', $count) 
     1135            ); 
     1136            http::redirect($this->getURL()); 
     1137        } elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['deactivate'])) { 
     1138 
     1139            if (is_array($_POST['deactivate'])) { 
     1140                $modules = array_keys($_POST['deactivate']); 
     1141            } 
     1142 
     1143            $list = $this->modules->getModules(); 
     1144            if (empty($list)) { 
     1145                throw new Exception(__('No such plugin.')); 
     1146            } 
     1147 
     1148            $failed = false; 
     1149            $count  = 0; 
     1150            foreach ($list as $id => $module) { 
     1151 
     1152                if (!in_array($id, $modules)) { 
     1153                    continue; 
     1154                } 
     1155 
     1156                if (!$module['root_writable']) { 
     1157                    $failed = true; 
     1158                    continue; 
     1159                } 
     1160 
     1161                $module[$id] = $id; 
     1162 
     1163                # --BEHAVIOR-- moduleBeforeDeactivate 
     1164                $this->core->callBehavior('pluginBeforeDeactivate', $module); 
     1165 
     1166                $this->modules->deactivateModule($id); 
     1167 
     1168                # --BEHAVIOR-- moduleAfterDeactivate 
     1169                $this->core->callBehavior('pluginAfterDeactivate', $module); 
     1170 
     1171                $count++; 
     1172            } 
     1173 
     1174            if ($failed) { 
     1175                dcPage::addWarningNotice(__('Some plugins have not been deactivated.')); 
     1176            } else { 
     1177                dcPage::addSuccessNotice( 
     1178                    __('Plugin has been successfully deactivated.', 'Plugins have been successuflly deactivated.', $count) 
     1179                ); 
     1180            } 
     1181            http::redirect($this->getURL()); 
     1182        } elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['update'])) { 
     1183 
     1184            if (is_array($_POST['update'])) { 
     1185                $modules = array_keys($_POST['update']); 
     1186            } 
     1187 
     1188            $list = $this->store->get(true); 
     1189            if (empty($list)) { 
     1190                throw new Exception(__('No such plugin.')); 
     1191            } 
     1192 
     1193            $count = 0; 
     1194            foreach ($list as $module) { 
     1195 
     1196                if (!in_array($module['id'], $modules)) { 
     1197                    continue; 
     1198                } 
     1199 
     1200                if (!self::$allow_multi_install) { 
     1201                    $dest = $module['root'] . '/../' . basename($module['file']); 
     1202                } else { 
     1203                    $dest = $this->getPath() . '/' . basename($module['file']); 
     1204                    if ($module['root'] != $dest) { 
     1205                        @file_put_contents($module['root'] . '/_disabled', ''); 
     1206                    } 
     1207                } 
     1208 
     1209                # --BEHAVIOR-- moduleBeforeUpdate 
     1210                $this->core->callBehavior('pluginBeforeUpdate', $module); 
     1211 
     1212                $this->store->process($module['file'], $dest); 
     1213 
     1214                # --BEHAVIOR-- moduleAfterUpdate 
     1215                $this->core->callBehavior('pluginAfterUpdate', $module); 
     1216 
     1217                $count++; 
     1218            } 
     1219 
     1220            $tab = $count && $count == count($list) ? '#plugins' : '#update'; 
     1221 
     1222            dcPage::addSuccessNotice( 
     1223                __('Plugin has been successfully updated.', 'Plugins have been successuflly updated.', $count) 
     1224            ); 
     1225            http::redirect($this->getURL() . $tab); 
     1226        } 
     1227 
     1228        # Manual actions 
     1229        elseif (!empty($_POST['upload_pkg']) && !empty($_FILES['pkg_file']) 
     1230            || !empty($_POST['fetch_pkg']) && !empty($_POST['pkg_url'])) { 
     1231            if (empty($_POST['your_pwd']) || !$this->core->auth->checkPassword($_POST['your_pwd'])) { 
     1232                throw new Exception(__('Password verification failed')); 
     1233            } 
     1234 
     1235            if (!empty($_POST['upload_pkg'])) { 
     1236                files::uploadStatus($_FILES['pkg_file']); 
     1237 
     1238                $dest = $this->getPath() . '/' . $_FILES['pkg_file']['name']; 
     1239                if (!move_uploaded_file($_FILES['pkg_file']['tmp_name'], $dest)) { 
     1240                    throw new Exception(__('Unable to move uploaded file.')); 
     1241                } 
     1242            } else { 
     1243                $url  = urldecode($_POST['pkg_url']); 
     1244                $dest = $this->getPath() . '/' . basename($url); 
     1245                $this->store->download($url, $dest); 
     1246            } 
     1247 
     1248            # --BEHAVIOR-- moduleBeforeAdd 
     1249            $this->core->callBehavior('pluginBeforeAdd', null); 
     1250 
     1251            $ret_code = $this->store->install($dest); 
     1252 
     1253            # --BEHAVIOR-- moduleAfterAdd 
     1254            $this->core->callBehavior('pluginAfterAdd', null); 
     1255 
     1256            dcPage::addSuccessNotice($ret_code == 2 ? 
     1257                __('Plugin has been successfully updated.') : 
     1258                __('Plugin has been successfully installed.') 
     1259            ); 
     1260            http::redirect($this->getURL() . '#plugins'); 
     1261        } else { 
     1262 
     1263            # --BEHAVIOR-- adminModulesListDoActions 
     1264            $this->core->callBehavior('adminModulesListDoActions', $this, $modules, 'plugin'); 
     1265 
     1266        } 
     1267 
     1268        return; 
     1269    } 
     1270 
     1271    /** 
     1272     * Display tab for manual installation. 
     1273     * 
     1274     * @return    adminModulesList self instance 
     1275     */ 
     1276    public function displayManualForm() 
     1277    { 
     1278        if (!$this->core->auth->isSuperAdmin() || !$this->isWritablePath()) { 
     1279            return; 
     1280        } 
     1281 
     1282        # 'Upload module' form 
     1283        echo 
     1284        '<form method="post" action="' . $this->getURL() . '" id="uploadpkg" enctype="multipart/form-data" class="fieldset">' . 
     1285        '<h4>' . __('Upload a zip file') . '</h4>' . 
     1286        '<p class="field"><label for="pkg_file" class="classic required"><abbr title="' . __('Required field') . '">*</abbr> ' . __('Zip file path:') . '</label> ' . 
     1287        '<input type="file" name="pkg_file" id="pkg_file" required /></p>' . 
     1288        '<p class="field"><label for="your_pwd1" class="classic required"><abbr title="' . __('Required field') . '">*</abbr> ' . __('Your password:') . '</label> ' . 
     1289        form::password(array('your_pwd', 'your_pwd1'), 20, 255, 
     1290            array( 
     1291                'extra_html'   => 'required placeholder="' . __('Password') . '"', 
     1292                'autocomplete' => 'current-password' 
     1293            ) 
     1294        ) . '</p>' . 
     1295        '<p><input type="submit" name="upload_pkg" value="' . __('Upload') . '" />' . 
     1296        $this->core->formNonce() . '</p>' . 
     1297            '</form>'; 
     1298 
     1299        # 'Fetch module' form 
     1300        echo 
     1301        '<form method="post" action="' . $this->getURL() . '" id="fetchpkg" class="fieldset">' . 
     1302        '<h4>' . __('Download a zip file') . '</h4>' . 
     1303        '<p class="field"><label for="pkg_url" class="classic required"><abbr title="' . __('Required field') . '">*</abbr> ' . __('Zip file URL:') . '</label> ' . 
     1304        form::field(array('pkg_url', 'pkg_url'), 40, 255, '', '', '', false, 'required placeholder="' . __('URL') . '"') . '</p>' . 
     1305        '<p class="field"><label for="your_pwd2" class="classic required"><abbr title="' . __('Required field') . '">*</abbr> ' . __('Your password:') . '</label> ' . 
     1306        form::password(array('your_pwd', 'your_pwd2'), 20, 255, 
     1307            array( 
     1308                'extra_html'   => 'required placeholder="' . __('Password') . '"', 
     1309                'autocomplete' => 'current-password' 
     1310            ) 
     1311        ) . '</p>' . 
     1312        '<p><input type="submit" name="fetch_pkg" value="' . __('Download') . '" />' . 
     1313        $this->core->formNonce() . '</p>' . 
     1314            '</form>'; 
     1315 
     1316        return $this; 
     1317    } 
     1318    //@} 
     1319 
     1320    /// @name Module configuration methods 
     1321    //@{ 
     1322    /** 
     1323     * Prepare module configuration. 
     1324     * 
     1325     * We need to get configuration content in three steps 
     1326     * and out of this class to keep backward compatibility. 
     1327     * 
     1328     * if ($xxx->setConfiguration()) { 
     1329     *    include $xxx->includeConfiguration(); 
     1330     * } 
     1331     * $xxx->getConfiguration(); 
     1332     * ... [put here page headers and other stuff] 
     1333     * $xxx->displayConfiguration(); 
     1334     * 
     1335     * @param    string    $id        Module to work on or it gather through REQUEST 
     1336     * @return    True if config set 
     1337     */ 
     1338    public function setConfiguration($id = null) 
     1339    { 
     1340        if (empty($_REQUEST['conf']) || empty($_REQUEST['module']) && !$id) { 
     1341            return false; 
     1342        } 
     1343 
     1344        if (!empty($_REQUEST['module']) && empty($id)) { 
     1345            $id = $_REQUEST['module']; 
     1346        } 
     1347 
     1348        if (!$this->modules->moduleExists($id)) { 
     1349            $this->core->error->add(__('Unknow plugin ID')); 
     1350            return false; 
     1351        } 
     1352 
     1353        $module = $this->modules->getModules($id); 
     1354        $module = self::sanitizeModule($id, $module); 
     1355        $file   = path::real($module['root'] . '/_config.php'); 
     1356 
     1357        if (!file_exists($file)) { 
     1358            $this->core->error->add(__('This plugin has no configuration file.')); 
     1359            return false; 
     1360        } 
     1361 
     1362        $this->config_module  = $module; 
     1363        $this->config_file    = $file; 
     1364        $this->config_content = ''; 
     1365 
     1366        if (!defined('DC_CONTEXT_MODULE')) { 
     1367            define('DC_CONTEXT_MODULE', true); 
     1368        } 
     1369 
     1370        return true; 
     1371    } 
     1372 
     1373    /** 
     1374     * Get path of module configuration file. 
     1375     * 
     1376     * @note Required previously set file info 
     1377     * @return Full path of config file or null 
     1378     */ 
     1379    public function includeConfiguration() 
     1380    { 
     1381        if (!$this->config_file) { 
     1382            return; 
     1383        } 
     1384        $this->setRedir($this->getURL() . '#plugins'); 
     1385 
     1386        ob_start(); 
     1387 
     1388        return $this->config_file; 
     1389    } 
     1390 
     1391    /** 
     1392     * Gather module configuration file content. 
     1393     * 
     1394     * @note Required previously file inclusion 
     1395     * @return True if content has been captured 
     1396     */ 
     1397    public function getConfiguration() 
     1398    { 
     1399        if ($this->config_file) { 
     1400            $this->config_content = ob_get_contents(); 
     1401        } 
     1402 
     1403        ob_end_clean(); 
     1404 
     1405        return !empty($this->file_content); 
     1406    } 
     1407 
     1408    /** 
     1409     * Display module configuration form. 
     1410     * 
     1411     * @note Required previously gathered content 
     1412     * @return    adminModulesList self instance 
     1413     */ 
     1414    public function displayConfiguration() 
     1415    { 
     1416        if ($this->config_file) { 
     1417 
     1418            if (!$this->config_module['standalone_config']) { 
     1419                echo 
     1420                '<form id="module_config" action="' . $this->getURL('conf=1') . '" method="post" enctype="multipart/form-data">' . 
     1421                '<h3>' . sprintf(__('Configure "%s"'), html::escapeHTML($this->config_module['name'])) . '</h3>' . 
     1422                '<p><a class="back" href="' . $this->getRedir() . '">' . __('Back') . '</a></p>'; 
     1423            } 
     1424 
     1425            echo $this->config_content; 
     1426 
     1427            if (!$this->config_module['standalone_config']) { 
     1428                echo 
     1429                '<p class="clear"><input type="submit" name="save" value="' . __('Save') . '" />' . 
     1430                form::hidden('module', $this->config_module['id']) . 
     1431                form::hidden('redir', $this->getRedir()) . 
     1432                $this->core->formNonce() . '</p>' . 
     1433                    '</form>'; 
     1434            } 
     1435        } 
     1436 
     1437        return $this; 
     1438    } 
     1439    //@} 
     1440 
     1441    /** 
     1442     * Helper to sanitize a string. 
     1443     * 
     1444     * Used for search or id. 
     1445     * 
     1446     * @param    string    $str        String to sanitize 
     1447     * @return    Sanitized string 
     1448     */ 
     1449    public static function sanitizeString($str) 
     1450    { 
     1451        return preg_replace('/[^A-Za-z0-9\@\#+_-]/', '', strtolower($str)); 
     1452    } 
    14701453} 
    14711454 
     
    14771460class adminThemesList extends adminModulesList 
    14781461{ 
    1479      /** 
    1480       * Constructor. 
    1481       * 
    1482       * Note that this creates dcStore instance. 
    1483       * 
    1484       * @param object    $modules       dcModules instance 
    1485       * @param string    $modules_root  Modules root directories 
    1486       * @param string    $xml_url       URL of modules feed from repository 
    1487       */ 
    1488      public function __construct(dcModules $modules, $modules_root, $xml_url) 
    1489      { 
    1490           parent::__construct($modules, $modules_root, $xml_url); 
    1491           $this->page_url = $this->core->adminurl->get('admin.blog.theme'); 
    1492      } 
    1493  
    1494      public function displayModules($cols=array('name', 'config', 'version', 'desc'), $actions=array(), $nav_limit=false) 
    1495      { 
    1496           echo 
    1497           '<form action="'.$this->getURL().'" method="post" class="modules-form-actions">'. 
    1498           '<div id="'.html::escapeHTML($this->list_id).'" class="modules'.(in_array('expander', $cols) ? ' expandable' : '').' one-box">'; 
    1499  
    1500           $sort_field = $this->getSort(); 
    1501  
    1502           # Sort modules by id 
    1503           $modules = $this->getSearch() === null ? 
    1504                self::sortModules($this->data, $sort_field, $this->sort_asc) : 
    1505                $this->data; 
    1506  
    1507           $res = ''; 
    1508           $count = 0; 
    1509           foreach ($modules as $id => $module) 
    1510           { 
    1511                # Show only requested modules 
    1512                if ($nav_limit && $this->getSearch() === null) { 
    1513                     $char = substr($module[$sort_field], 0, 1); 
    1514                     if (!in_array($char, $this->nav_list)) { 
    1515                          $char = $this->nav_special; 
    1516                     } 
    1517                     if ($this->getIndex() != $char) { 
    1518                          continue; 
    1519                     } 
    1520                } 
    1521  
    1522                $current = $this->core->blog->settings->system->theme == $id && $this->modules->moduleExists($id); 
    1523                $distrib = self::isDistributedModule($id) ? ' dc-box' : ''; 
    1524  
    1525                $line = 
    1526                '<div class="box '.($current ? 'medium current-theme' : 'theme').$distrib.'">'; 
    1527  
    1528                if (in_array('name', $cols) && !$current) { 
    1529                     $line .= 
    1530                     '<h4 class="module-name">'; 
    1531  
    1532                     if (in_array('checkbox', $cols)) { 
    1533                          $line .= 
    1534                          '<label for="'.html::escapeHTML($this->list_id).'_modules_'.html::escapeHTML($id).'">'. 
    1535                          form::checkbox(array('modules['.$count.']', html::escapeHTML($this->list_id).'_modules_'.html::escapeHTML($id)), html::escapeHTML($id)). 
    1536                          html::escapeHTML($module['name']). 
    1537                          '</label>'; 
    1538  
    1539                     } 
    1540                     else { 
    1541                          $line .= 
    1542                          form::hidden(array('modules['.$count.']'), html::escapeHTML($id)). 
    1543                          html::escapeHTML($module['name']); 
    1544                     } 
    1545  
    1546                     $line .= 
    1547                     $this->core->formNonce(). 
    1548                     '</h4>'; 
    1549                } 
    1550  
    1551                # Display score only for debug purpose 
    1552                if (in_array('score', $cols) && $this->getSearch() !== null && defined('DC_DEBUG') && DC_DEBUG) { 
    1553                     $line .= 
    1554                     '<p class="module-score debug">'.sprintf(__('Score: %s'), $module['score']).'</p>'; 
    1555                } 
    1556  
    1557                if (in_array('sshot', $cols)) { 
    1558                     # Screenshot from url 
    1559                     if (preg_match('#^http(s)?://#', $module['sshot'])) { 
    1560                          $sshot = $module['sshot']; 
    1561                     } 
    1562                     # Screenshot from installed module 
    1563                     elseif (file_exists($this->core->blog->themes_path.'/'.$id.'/screenshot.jpg')) { 
    1564                          $sshot = $this->getURL('shot='.rawurlencode($id)); 
    1565                     } 
    1566                     # Default screenshot 
    1567                     else { 
    1568                          $sshot = 'images/noscreenshot.png'; 
    1569                     } 
    1570  
    1571                     $line .= 
    1572                     '<div class="module-sshot"><img src="'.$sshot.'" alt="'. 
    1573                     sprintf(__('%s screenshot.'), html::escapeHTML($module['name'])).'" /></div>'; 
    1574                } 
    1575  
    1576                $line .= 
    1577                '<div class="module-infos toggle-bloc">'; 
    1578  
    1579                if (in_array('name', $cols) && $current) { 
    1580                     $line .= 
    1581                     '<h4 class="module-name">'; 
    1582  
    1583                     if (in_array('checkbox', $cols)) { 
    1584                          $line .= 
    1585                          '<label for="'.html::escapeHTML($this->list_id).'_modules_'.html::escapeHTML($id).'">'. 
    1586                          form::checkbox(array('modules['.$count.']', html::escapeHTML($this->list_id).'_modules_'.html::escapeHTML($id)), html::escapeHTML($id)). 
    1587                          html::escapeHTML($module['name']). 
    1588                          '</label>'; 
    1589                     } 
    1590                     else { 
    1591                          $line .= 
    1592                          form::hidden(array('modules['.$count.']'), html::escapeHTML($id)). 
    1593                          html::escapeHTML($module['name']); 
    1594                     } 
    1595  
    1596                     $line .= 
    1597                     '</h4>'; 
    1598                } 
    1599  
    1600                $line .= 
    1601                '<p>'; 
    1602  
    1603                if (in_array('desc', $cols)) { 
    1604                     $line .= 
    1605                     '<span class="module-desc">'.html::escapeHTML(__($module['desc'])).'</span> '; 
    1606                } 
    1607  
    1608                if (in_array('author', $cols)) { 
    1609                     $line .= 
    1610                     '<span class="module-author">'.sprintf(__('by %s'),html::escapeHTML($module['author'])).'</span> '; 
    1611                } 
    1612  
    1613                if (in_array('version', $cols)) { 
    1614                     $line .= 
    1615                     '<span class="module-version">'.sprintf(__('version %s'),html::escapeHTML($module['version'])).'</span> '; 
    1616                } 
    1617  
    1618                if (in_array('current_version', $cols)) { 
    1619                     $line .= 
    1620                     '<span class="module-current-version">'.sprintf(__('(current version %s)'),html::escapeHTML($module['current_version'])).'</span> '; 
    1621                } 
    1622  
    1623                if (in_array('parent', $cols) && !empty($module['parent'])) { 
    1624                     if ($this->modules->moduleExists($module['parent'])) { 
    1625                          $line .= 
    1626                          '<span class="module-parent-ok">'.sprintf(__('(built on "%s")'),html::escapeHTML($module['parent'])).'</span> '; 
    1627                     } 
    1628                     else { 
    1629                          $line .= 
    1630                          '<span class="module-parent-missing">'.sprintf(__('(requires "%s")'),html::escapeHTML($module['parent'])).'</span> '; 
    1631                     } 
    1632                } 
    1633  
    1634                $has_details = in_array('details', $cols) && !empty($module['details']); 
    1635                $has_support = in_array('support', $cols) && !empty($module['support']); 
    1636                if ($has_details || $has_support) { 
    1637                     $line .= 
    1638                     '<span class="mod-more">'; 
    1639  
    1640                     if ($has_details) { 
    1641                          $line .= 
    1642                          '<a class="module-details" href="'.$module['details'].'">'.__('Details').'</a>'; 
    1643                     } 
    1644  
    1645                     if ($has_support) { 
    1646                          $line .= 
    1647                          ' - <a class="module-support" href="'.$module['support'].'">'.__('Support').'</a>'; 
    1648                     } 
    1649  
    1650                     $line .= 
    1651                     '</span>'; 
    1652                } 
    1653  
    1654                $line .= 
    1655                '</p>'. 
    1656                '</div>'; 
    1657  
    1658                $line .= 
    1659                '<div class="module-actions toggle-bloc">'; 
    1660  
    1661                # Plugins actions 
    1662                if ($current) { 
    1663  
    1664                     # _GET actions 
    1665                     if (file_exists(path::real($this->core->blog->themes_path.'/'.$id).'/style.css')) { 
    1666                          $theme_url = preg_match('#^http(s)?://#', $this->core->blog->settings->system->themes_url) ? 
    1667                               http::concatURL($this->core->blog->settings->system->themes_url, '/'.$id) : 
    1668                               http::concatURL($this->core->blog->url, $this->core->blog->settings->system->themes_url.'/'.$id); 
    1669                          $line .= 
    1670                          '<p><a href="'.$theme_url.'/style.css">'.__('View stylesheet').'</a></p>'; 
    1671                     } 
    1672  
    1673                     $line .= '<div class="current-actions">'; 
    1674  
    1675                     if (file_exists(path::real($this->core->blog->themes_path.'/'.$id).'/_config.php')) { 
    1676                          $line .= 
    1677                          '<p><a href="'.$this->getURL('module='.$id.'&amp;conf=1', false).'" class="button submit">'.__('Configure theme').'</a></p>'; 
    1678                     } 
    1679  
    1680                     # --BEHAVIOR-- adminCurrentThemeDetails 
    1681                     $line .= 
    1682                     $this->core->callBehavior('adminCurrentThemeDetails', $this->core, $id, $module); 
    1683  
    1684                     $line .= '</div>'; 
    1685                } 
    1686  
    1687                # _POST actions 
    1688                if (!empty($actions)) { 
    1689                     $line .= 
    1690                     '<p>'.implode(' ', $this->getActions($id, $module, $actions)).'</p>'; 
    1691                } 
    1692  
    1693                $line .= 
    1694                '</div>'; 
    1695  
    1696                $line .= 
    1697                '</div>'; 
    1698  
    1699                $count++; 
    1700  
    1701                $res = $current ? $line.$res : $res.$line; 
    1702           } 
    1703  
    1704           echo 
    1705           $res. 
    1706           '</div>'; 
    1707  
    1708           if(!$count && $this->getSearch() === null) { 
    1709                echo 
    1710                '<p class="message">'.__('No themes matched your search.').'</p>'; 
    1711           } 
    1712  
    1713           elseif ((in_array('checkbox', $cols) || $count > 1) && !empty($actions) && $this->core->auth->isSuperAdmin()) { 
    1714                $buttons = $this->getGlobalActions($actions, in_array('checkbox', $cols)); 
    1715  
    1716                if (!empty($buttons)) { 
    1717                     if (in_array('checkbox', $cols)) { 
    1718                          echo 
    1719                          '<p class="checkboxes-helpers"></p>'; 
    1720                     } 
    1721                     echo '<div>'.implode(' ', $buttons).'</div>'; 
    1722                } 
    1723           } 
    1724  
    1725           echo 
    1726           '</form>'; 
    1727  
    1728           return $this; 
    1729      } 
    1730  
    1731      protected function getActions($id, $module, $actions) 
    1732      { 
    1733           $submits = array(); 
    1734  
    1735           $this->core->blog->settings->addNamespace('system'); 
    1736           if ($id != $this->core->blog->settings->system->theme) { 
    1737  
    1738                # Select theme to use on curent blog 
    1739                if (in_array('select', $actions)) { 
    1740                     $submits[] = 
    1741                     '<input type="submit" name="select['.html::escapeHTML($id).']" value="'.__('Use this one').'" />'; 
    1742                } 
    1743           } 
    1744  
    1745           return array_merge( 
    1746                $submits, 
    1747                parent::getActions($id, $module, $actions) 
    1748           ); 
    1749      } 
    1750  
    1751      protected function getGlobalActions($actions, $with_selection=false) 
    1752      { 
    1753           $submits = array(); 
    1754  
    1755           foreach($actions as $action) { 
    1756                switch($action) { 
    1757  
    1758                     # Update (from store) 
    1759                     case 'update': if ($this->core->auth->isSuperAdmin() && $this->path_writable) { 
    1760                          $submits[] = 
    1761                          '<input type="submit" name="update" value="'.($with_selection ? 
    1762                               __('Update selected themes') : 
    1763                               __('Update all themes from this list') 
    1764                          ).'" />'.$this->core->formNonce(); 
    1765                     } break; 
    1766  
    1767                     # Behavior 
    1768                     case 'behavior': 
    1769  
    1770                          # --BEHAVIOR-- adminModulesListGetGlobalActions 
    1771                          $tmp = $this->core->callBehavior('adminModulesListGetGlobalActions', $this); 
    1772  
    1773                          if (!empty($tmp)) { 
    1774                               $submits[] = $tmp; 
    1775                          } 
    1776                     break; 
    1777                } 
    1778           } 
    1779  
    1780           return $submits; 
    1781      } 
    1782  
    1783      public function doActions() 
    1784      { 
    1785           if (empty($_POST) || !empty($_REQUEST['conf'])) { 
    1786                return null; 
    1787           } 
    1788  
    1789           $modules = !empty($_POST['modules']) && is_array($_POST['modules']) ? array_values($_POST['modules']) : array(); 
    1790  
    1791           if (!empty($_POST['select'])) { 
    1792  
    1793                # Can select only one theme at a time! 
    1794                if (is_array($_POST['select'])) { 
    1795                     $modules = array_keys($_POST['select']); 
    1796                     $id = $modules[0]; 
    1797  
    1798                     if (!$this->modules->moduleExists($id)) { 
    1799                          throw new Exception(__('No such theme.')); 
    1800                     } 
    1801  
    1802                     $this->core->blog->settings->addNamespace('system'); 
    1803                     $this->core->blog->settings->system->put('theme',$id); 
    1804                     $this->core->blog->triggerBlog(); 
    1805  
    1806                     dcPage::addSuccessNotice(__('Theme has been successfully selected.')); 
    1807                     http::redirect($this->getURL().'#themes'); 
    1808                } 
    1809           } 
    1810  
    1811           else { 
    1812                if (!$this->isWritablePath()) { 
    1813                     return null; 
    1814                } 
    1815  
    1816                if ($this->core->auth->isSuperAdmin() && !empty($_POST['activate'])) { 
    1817  
    1818                     if (is_array($_POST['activate'])) { 
    1819                          $modules = array_keys($_POST['activate']); 
    1820                     } 
    1821  
    1822                     $list = $this->modules->getDisabledModules(); 
    1823                     if (empty($list)) { 
    1824                          throw new Exception(__('No such theme.')); 
    1825                     } 
    1826  
    1827                     $count = 0; 
    1828                     foreach($list as $id => $module) { 
    1829  
    1830                          if (!in_array($id, $modules)) { 
    1831                               continue; 
    1832                          } 
    1833  
    1834                          # --BEHAVIOR-- themeBeforeActivate 
    1835                          $this->core->callBehavior('themeBeforeActivate', $id); 
    1836  
    1837                          $this->modules->activateModule($id); 
    1838  
    1839                          # --BEHAVIOR-- themeAfterActivate 
    1840                          $this->core->callBehavior('themeAfterActivate', $id); 
    1841  
    1842                          $count++; 
    1843                     } 
    1844  
    1845                     dcPage::addSuccessNotice( 
    1846                          __('Theme has been successfully activated.', 'Themes have been successuflly activated.', $count) 
    1847                     ); 
    1848                     http::redirect($this->getURL()); 
    1849                } 
    1850  
    1851                elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['deactivate'])) { 
    1852  
    1853                     if (is_array($_POST['deactivate'])) { 
    1854                          $modules = array_keys($_POST['deactivate']); 
    1855                     } 
    1856  
    1857                     $list = $this->modules->getModules(); 
    1858                     if (empty($list)) { 
    1859                          throw new Exception(__('No such theme.')); 
    1860                     } 
    1861  
    1862                     $failed = false; 
    1863                     $count = 0; 
    1864                     foreach($list as $id => $module) { 
    1865  
    1866                          if (!in_array($id, $modules)) { 
    1867                               continue; 
    1868                          } 
    1869  
    1870                          if (!$module['root_writable']) { 
    1871                               $failed = true; 
    1872                               continue; 
    1873                          } 
    1874  
    1875                          $module[$id] = $id; 
    1876  
    1877                          # --BEHAVIOR-- themeBeforeDeactivate 
    1878                          $this->core->callBehavior('themeBeforeDeactivate', $module); 
    1879  
    1880                          $this->modules->deactivateModule($id); 
    1881  
    1882                          # --BEHAVIOR-- themeAfterDeactivate 
    1883                          $this->core->callBehavior('themeAfterDeactivate', $module); 
    1884  
    1885                          $count++; 
    1886                     } 
    1887  
    1888                     if ($failed) { 
    1889                          dcPage::addWarningNotice(__('Some themes have not been deactivated.')); 
    1890                     } 
    1891                     else { 
    1892                          dcPage::addSuccessNotice( 
    1893                               __('Theme has been successfully deactivated.', 'Themes have been successuflly deactivated.', $count) 
    1894                          ); 
    1895                     } 
    1896                     http::redirect($this->getURL()); 
    1897                } 
    1898  
    1899                elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['delete'])) { 
    1900  
    1901                     if (is_array($_POST['delete'])) { 
    1902                          $modules = array_keys($_POST['delete']); 
    1903                     } 
    1904  
    1905                     $list = $this->modules->getDisabledModules(); 
    1906  
    1907                     $failed = false; 
    1908                     $count = 0; 
    1909                     foreach($modules as $id) 
    1910                     { 
    1911                          if (!isset($list[$id])) { 
    1912  
    1913                               if (!$this->modules->moduleExists($id)) { 
    1914                                    throw new Exception(__('No such theme.')); 
    1915                               } 
    1916  
    1917                               $module = $this->modules->getModules($id); 
    1918                               $module['id'] = $id; 
    1919  
    1920                               if (!$this->isDeletablePath($module['root'])) { 
    1921                                    $failed = true; 
    1922                                    continue; 
    1923                               } 
    1924  
    1925                               # --BEHAVIOR-- themeBeforeDelete 
    1926                               $this->core->callBehavior('themeBeforeDelete', $module); 
    1927  
    1928                               $this->modules->deleteModule($id); 
    1929  
    1930                               # --BEHAVIOR-- themeAfterDelete 
    1931                               $this->core->callBehavior('themeAfterDelete', $module); 
    1932                          } 
    1933                          else { 
    1934                               $this->modules->deleteModule($id, true); 
    1935                          } 
    1936  
    1937                          $count++; 
    1938                     } 
    1939  
    1940                     if (!$count && $failed) { 
    1941                          throw new Exception(__("You don't have permissions to delete this theme.")); 
    1942                     } 
    1943                     elseif ($failed) { 
    1944                          dcPage::addWarningNotice(__('Some themes have not been delete.')); 
    1945                     } 
    1946                     else { 
    1947                          dcPage::addSuccessNotice( 
    1948                               __('Theme has been successfully deleted.', 'Themes have been successuflly deleted.', $count) 
    1949                          ); 
    1950                     } 
    1951                     http::redirect($this->getURL()); 
    1952                } 
    1953  
    1954                elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['install'])) { 
    1955  
    1956                     if (is_array($_POST['install'])) { 
    1957                          $modules = array_keys($_POST['install']); 
    1958                     } 
    1959  
    1960                     $list = $this->store->get(); 
    1961  
    1962                     if (empty($list)) { 
    1963                          throw new Exception(__('No such theme.')); 
    1964                     } 
    1965  
    1966                     $count = 0; 
    1967                     foreach($list as $id => $module) { 
    1968  
    1969                          if (!in_array($id, $modules)) { 
    1970                               continue; 
    1971                          } 
    1972  
    1973                          $dest = $this->getPath().'/'.basename($module['file']); 
    1974  
    1975                          # --BEHAVIOR-- themeBeforeAdd 
    1976                          $this->core->callBehavior('themeBeforeAdd', $module); 
    1977  
    1978                          $this->store->process($module['file'], $dest); 
    1979  
    1980                          # --BEHAVIOR-- themeAfterAdd 
    1981                          $this->core->callBehavior('themeAfterAdd', $module); 
    1982  
    1983                          $count++; 
    1984                     } 
    1985  
    1986                     dcPage::addSuccessNotice( 
    1987                          __('Theme has been successfully installed.', 'Themes have been successuflly installed.', $count) 
    1988                     ); 
    1989                     http::redirect($this->getURL()); 
    1990                } 
    1991  
    1992                elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['update'])) { 
    1993  
    1994                     if (is_array($_POST['update'])) { 
    1995                          $modules = array_keys($_POST['update']); 
    1996                     } 
    1997  
    1998                     $list = $this->store->get(true); 
    1999                     if (empty($list)) { 
    2000                          throw new Exception(__('No such theme.')); 
    2001                     } 
    2002  
    2003                     $count = 0; 
    2004                     foreach($list as $module) { 
    2005  
    2006                          if (!in_array($module['id'], $modules)) { 
    2007                               continue; 
    2008                          } 
    2009  
    2010                          $dest = $module['root'].'/../'.basename($module['file']); 
    2011  
    2012                          # --BEHAVIOR-- themeBeforeUpdate 
    2013                          $this->core->callBehavior('themeBeforeUpdate', $module); 
    2014  
    2015                          $this->store->process($module['file'], $dest); 
    2016  
    2017                          # --BEHAVIOR-- themeAfterUpdate 
    2018                          $this->core->callBehavior('themeAfterUpdate', $module); 
    2019  
    2020                          $count++; 
    2021                     } 
    2022  
    2023                     $tab = $count && $count == count($list) ? '#themes' : '#update'; 
    2024  
    2025                     dcPage::addSuccessNotice( 
    2026                          __('Theme has been successfully updated.', 'Themes have been successuflly updated.', $count) 
    2027                     ); 
    2028                     http::redirect($this->getURL().$tab); 
    2029                } 
    2030  
    2031                # Manual actions 
    2032                elseif (!empty($_POST['upload_pkg']) && !empty($_FILES['pkg_file']) 
    2033                     || !empty($_POST['fetch_pkg']) && !empty($_POST['pkg_url'])) 
    2034                { 
    2035                     if (empty($_POST['your_pwd']) || !$this->core->auth->checkPassword($_POST['your_pwd'])) { 
    2036                          throw new Exception(__('Password verification failed')); 
    2037                     } 
    2038  
    2039                     if (!empty($_POST['upload_pkg'])) { 
    2040                          files::uploadStatus($_FILES['pkg_file']); 
    2041  
    2042                          $dest = $this->getPath().'/'.$_FILES['pkg_file']['name']; 
    2043                          if (!move_uploaded_file($_FILES['pkg_file']['tmp_name'], $dest)) { 
    2044                               throw new Exception(__('Unable to move uploaded file.')); 
    2045                          } 
    2046                     } 
    2047                     else { 
    2048                          $url = urldecode($_POST['pkg_url']); 
    2049                          $dest = $this->getPath().'/'.basename($url); 
    2050                          $this->store->download($url, $dest); 
    2051                     } 
    2052  
    2053                     # --BEHAVIOR-- themeBeforeAdd 
    2054                     $this->core->callBehavior('themeBeforeAdd', null); 
    2055  
    2056                     $ret_code = $this->store->install($dest); 
    2057  
    2058                     # --BEHAVIOR-- themeAfterAdd 
    2059                     $this->core->callBehavior('themeAfterAdd', null); 
    2060  
    2061                     dcPage::addSuccessNotice($ret_code == 2 ? 
    2062                          __('Theme has been successfully updated.') : 
    2063                          __('Theme has been successfully installed.') 
    2064                     ); 
    2065                     http::redirect($this->getURL().'#themes'); 
    2066                } 
    2067  
    2068                else { 
    2069  
    2070                     # --BEHAVIOR-- adminModulesListDoActions 
    2071                     $this->core->callBehavior('adminModulesListDoActions', $this, $modules, 'theme'); 
    2072  
    2073                } 
    2074           } 
    2075  
    2076           return null; 
    2077      } 
     1462    /** 
     1463     * Constructor. 
     1464     * 
     1465     * Note that this creates dcStore instance. 
     1466     * 
     1467     * @param    object    $modules        dcModules instance 
     1468     * @param    string    $modules_root    Modules root directories 
     1469     * @param    string    $xml_url        URL of modules feed from repository 
     1470     */ 
     1471    public function __construct(dcModules $modules, $modules_root, $xml_url) 
     1472    { 
     1473        parent::__construct($modules, $modules_root, $xml_url); 
     1474        $this->page_url = $this->core->adminurl->get('admin.blog.theme'); 
     1475    } 
     1476 
     1477    public function displayModules($cols = array('name', 'config', 'version', 'desc'), $actions = array(), $nav_limit = false) 
     1478    { 
     1479        echo 
     1480        '<form action="' . $this->getURL() . '" method="post" class="modules-form-actions">' . 
     1481        '<div id="' . html::escapeHTML($this->list_id) . '" class="modules' . (in_array('expander', $cols) ? ' expandable' : '') . ' one-box">'; 
     1482 
     1483        $sort_field = $this->getSort(); 
     1484 
     1485        # Sort modules by id 
     1486        $modules = $this->getSearch() === null ? 
     1487        self::sortModules($this->data, $sort_field, $this->sort_asc) : 
     1488        $this->data; 
     1489 
     1490        $res   = ''; 
     1491        $count = 0; 
     1492        foreach ($modules as $id => $module) { 
     1493            # Show only requested modules 
     1494            if ($nav_limit && $this->getSearch() === null) { 
     1495                $char = substr($module[$sort_field], 0, 1); 
     1496                if (!in_array($char, $this->nav_list)) { 
     1497                    $char = $this->nav_special; 
     1498                } 
     1499                if ($this->getIndex() != $char) { 
     1500                    continue; 
     1501                } 
     1502            } 
     1503 
     1504            $current = $this->core->blog->settings->system->theme == $id && $this->modules->moduleExists($id); 
     1505            $distrib = self::isDistributedModule($id) ? ' dc-box' : ''; 
     1506 
     1507            $line = 
     1508                '<div class="box ' . ($current ? 'medium current-theme' : 'theme') . $distrib . '">'; 
     1509 
     1510            if (in_array('name', $cols) && !$current) { 
     1511                $line .= 
     1512                    '<h4 class="module-name">'; 
     1513 
     1514                if (in_array('checkbox', $cols)) { 
     1515                    $line .= 
     1516                    '<label for="' . html::escapeHTML($this->list_id) . '_modules_' . html::escapeHTML($id) . '">' . 
     1517                    form::checkbox(array('modules[' . $count . ']', html::escapeHTML($this->list_id) . '_modules_' . html::escapeHTML($id)), html::escapeHTML($id)) . 
     1518                    html::escapeHTML($module['name']) . 
     1519                        '</label>'; 
     1520 
     1521                } else { 
     1522                    $line .= 
     1523                    form::hidden(array('modules[' . $count . ']'), html::escapeHTML($id)) . 
     1524                    html::escapeHTML($module['name']); 
     1525                } 
     1526 
     1527                $line .= 
     1528                $this->core->formNonce() . 
     1529                    '</h4>'; 
     1530            } 
     1531 
     1532            # Display score only for debug purpose 
     1533            if (in_array('score', $cols) && $this->getSearch() !== null && defined('DC_DEBUG') && DC_DEBUG) { 
     1534                $line .= 
     1535                '<p class="module-score debug">' . sprintf(__('Score: %s'), $module['score']) . '</p>'; 
     1536            } 
     1537 
     1538            if (in_array('sshot', $cols)) { 
     1539                # Screenshot from url 
     1540                if (preg_match('#^http(s)?://#', $module['sshot'])) { 
     1541                    $sshot = $module['sshot']; 
     1542                } 
     1543                # Screenshot from installed module 
     1544                elseif (file_exists($this->core->blog->themes_path . '/' . $id . '/screenshot.jpg')) { 
     1545                    $sshot = $this->getURL('shot=' . rawurlencode($id)); 
     1546                } 
     1547                # Default screenshot 
     1548                else { 
     1549                    $sshot = 'images/noscreenshot.png'; 
     1550                } 
     1551 
     1552                $line .= 
     1553                '<div class="module-sshot"><img src="' . $sshot . '" alt="' . 
     1554                sprintf(__('%s screenshot.'), html::escapeHTML($module['name'])) . '" /></div>'; 
     1555            } 
     1556 
     1557            $line .= 
     1558                '<div class="module-infos toggle-bloc">'; 
     1559 
     1560            if (in_array('name', $cols) && $current) { 
     1561                $line .= 
     1562                    '<h4 class="module-name">'; 
     1563 
     1564                if (in_array('checkbox', $cols)) { 
     1565                    $line .= 
     1566                    '<label for="' . html::escapeHTML($this->list_id) . '_modules_' . html::escapeHTML($id) . '">' . 
     1567                    form::checkbox(array('modules[' . $count . ']', html::escapeHTML($this->list_id) . '_modules_' . html::escapeHTML($id)), html::escapeHTML($id)) . 
     1568                    html::escapeHTML($module['name']) . 
     1569                        '</label>'; 
     1570                } else { 
     1571                    $line .= 
     1572                    form::hidden(array('modules[' . $count . ']'), html::escapeHTML($id)) . 
     1573                    html::escapeHTML($module['name']); 
     1574                } 
     1575 
     1576                $line .= 
     1577                    '</h4>'; 
     1578            } 
     1579 
     1580            $line .= 
     1581                '<p>'; 
     1582 
     1583            if (in_array('desc', $cols)) { 
     1584                $line .= 
     1585                '<span class="module-desc">' . html::escapeHTML(__($module['desc'])) . '</span> '; 
     1586            } 
     1587 
     1588            if (in_array('author', $cols)) { 
     1589                $line .= 
     1590                '<span class="module-author">' . sprintf(__('by %s'), html::escapeHTML($module['author'])) . '</span> '; 
     1591            } 
     1592 
     1593            if (in_array('version', $cols)) { 
     1594                $line .= 
     1595                '<span class="module-version">' . sprintf(__('version %s'), html::escapeHTML($module['version'])) . '</span> '; 
     1596            } 
     1597 
     1598            if (in_array('current_version', $cols)) { 
     1599                $line .= 
     1600                '<span class="module-current-version">' . sprintf(__('(current version %s)'), html::escapeHTML($module['current_version'])) . '</span> '; 
     1601            } 
     1602 
     1603            if (in_array('parent', $cols) && !empty($module['parent'])) { 
     1604                if ($this->modules->moduleExists($module['parent'])) { 
     1605                    $line .= 
     1606                    '<span class="module-parent-ok">' . sprintf(__('(built on "%s")'), html::escapeHTML($module['parent'])) . '</span> '; 
     1607                } else { 
     1608                    $line .= 
     1609                    '<span class="module-parent-missing">' . sprintf(__('(requires "%s")'), html::escapeHTML($module['parent'])) . '</span> '; 
     1610                } 
     1611            } 
     1612 
     1613            $has_details = in_array('details', $cols) && !empty($module['details']); 
     1614            $has_support = in_array('support', $cols) && !empty($module['support']); 
     1615            if ($has_details || $has_support) { 
     1616                $line .= 
     1617                    '<span class="mod-more">'; 
     1618 
     1619                if ($has_details) { 
     1620                    $line .= 
     1621                    '<a class="module-details" href="' . $module['details'] . '">' . __('Details') . '</a>'; 
     1622                } 
     1623 
     1624                if ($has_support) { 
     1625                    $line .= 
     1626                    ' - <a class="module-support" href="' . $module['support'] . '">' . __('Support') . '</a>'; 
     1627                } 
     1628 
     1629                $line .= 
     1630                    '</span>'; 
     1631            } 
     1632 
     1633            $line .= 
     1634                '</p>' . 
     1635                '</div>'; 
     1636 
     1637            $line .= 
     1638                '<div class="module-actions toggle-bloc">'; 
     1639 
     1640            # Plugins actions 
     1641            if ($current) { 
     1642 
     1643                # _GET actions 
     1644                if (file_exists(path::real($this->core->blog->themes_path . '/' . $id) . '/style.css')) { 
     1645                    $theme_url = preg_match('#^http(s)?://#', $this->core->blog->settings->system->themes_url) ? 
     1646                    http::concatURL($this->core->blog->settings->system->themes_url, '/' . $id) : 
     1647                    http::concatURL($this->core->blog->url, $this->core->blog->settings->system->themes_url . '/' . $id); 
     1648                    $line .= 
     1649                    '<p><a href="' . $theme_url . '/style.css">' . __('View stylesheet') . '</a></p>'; 
     1650                } 
     1651 
     1652                $line .= '<div class="current-actions">'; 
     1653 
     1654                if (file_exists(path::real($this->core->blog->themes_path . '/' . $id) . '/_config.php')) { 
     1655                    $line .= 
     1656                    '<p><a href="' . $this->getURL('module=' . $id . '&amp;conf=1', false) . '" class="button submit">' . __('Configure theme') . '</a></p>'; 
     1657                } 
     1658 
     1659                # --BEHAVIOR-- adminCurrentThemeDetails 
     1660                $line .= 
     1661                $this->core->callBehavior('adminCurrentThemeDetails', $this->core, $id, $module); 
     1662 
     1663                $line .= '</div>'; 
     1664            } 
     1665 
     1666            # _POST actions 
     1667            if (!empty($actions)) { 
     1668                $line .= 
     1669                '<p>' . implode(' ', $this->getActions($id, $module, $actions)) . '</p>'; 
     1670            } 
     1671 
     1672            $line .= 
     1673                '</div>'; 
     1674 
     1675            $line .= 
     1676                '</div>'; 
     1677 
     1678            $count++; 
     1679 
     1680            $res = $current ? $line . $res : $res . $line; 
     1681        } 
     1682 
     1683        echo 
     1684            $res . 
     1685            '</div>'; 
     1686 
     1687        if (!$count && $this->getSearch() === null) { 
     1688            echo 
     1689            '<p class="message">' . __('No themes matched your search.') . '</p>'; 
     1690        } elseif ((in_array('checkbox', $cols) || $count > 1) && !empty($actions) && $this->core->auth->isSuperAdmin()) { 
     1691            $buttons = $this->getGlobalActions($actions, in_array('checkbox', $cols)); 
     1692 
     1693            if (!empty($buttons)) { 
     1694                if (in_array('checkbox', $cols)) { 
     1695                    echo 
     1696                        '<p class="checkboxes-helpers"></p>'; 
     1697                } 
     1698                echo '<div>' . implode(' ', $buttons) . '</div>'; 
     1699            } 
     1700        } 
     1701 
     1702        echo 
     1703            '</form>'; 
     1704 
     1705        return $this; 
     1706    } 
     1707 
     1708    protected function getActions($id, $module, $actions) 
     1709    { 
     1710        $submits = array(); 
     1711 
     1712        $this->core->blog->settings->addNamespace('system'); 
     1713        if ($id != $this->core->blog->settings->system->theme) { 
     1714 
     1715            # Select theme to use on curent blog 
     1716            if (in_array('select', $actions)) { 
     1717                $submits[] = 
     1718                '<input type="submit" name="select[' . html::escapeHTML($id) . ']" value="' . __('Use this one') . '" />'; 
     1719            } 
     1720        } 
     1721 
     1722        return array_merge( 
     1723            $submits, 
     1724            parent::getActions($id, $module, $actions) 
     1725        ); 
     1726    } 
     1727 
     1728    protected function getGlobalActions($actions, $with_selection = false) 
     1729    { 
     1730        $submits = array(); 
     1731 
     1732        foreach ($actions as $action) { 
     1733            switch ($action) { 
     1734 
     1735                # Update (from store) 
     1736                case 'update':if ($this->core->auth->isSuperAdmin() && $this->path_writable) { 
     1737                        $submits[] = 
     1738                        '<input type="submit" name="update" value="' . ($with_selection ? 
     1739                            __('Update selected themes') : 
     1740                            __('Update all themes from this list') 
     1741                        ) . '" />' . $this->core->formNonce(); 
     1742                    }break; 
     1743 
     1744                # Behavior 
     1745                case 'behavior': 
     1746 
     1747                    # --BEHAVIOR-- adminModulesListGetGlobalActions 
     1748                    $tmp = $this->core->callBehavior('adminModulesListGetGlobalActions', $this); 
     1749 
     1750                    if (!empty($tmp)) { 
     1751                        $submits[] = $tmp; 
     1752                    } 
     1753                    break; 
     1754            } 
     1755        } 
     1756 
     1757        return $submits; 
     1758    } 
     1759 
     1760    public function doActions() 
     1761    { 
     1762        if (empty($_POST) || !empty($_REQUEST['conf'])) { 
     1763            return; 
     1764        } 
     1765 
     1766        $modules = !empty($_POST['modules']) && is_array($_POST['modules']) ? array_values($_POST['modules']) : array(); 
     1767 
     1768        if (!empty($_POST['select'])) { 
     1769 
     1770            # Can select only one theme at a time! 
     1771            if (is_array($_POST['select'])) { 
     1772                $modules = array_keys($_POST['select']); 
     1773                $id      = $modules[0]; 
     1774 
     1775                if (!$this->modules->moduleExists($id)) { 
     1776                    throw new Exception(__('No such theme.')); 
     1777                } 
     1778 
     1779                $this->core->blog->settings->addNamespace('system'); 
     1780                $this->core->blog->settings->system->put('theme', $id); 
     1781                $this->core->blog->triggerBlog(); 
     1782 
     1783                dcPage::addSuccessNotice(__('Theme has been successfully selected.')); 
     1784                http::redirect($this->getURL() . '#themes'); 
     1785            } 
     1786        } else { 
     1787            if (!$this->isWritablePath()) { 
     1788                return; 
     1789            } 
     1790 
     1791            if ($this->core->auth->isSuperAdmin() && !empty($_POST['activate'])) { 
     1792 
     1793                if (is_array($_POST['activate'])) { 
     1794                    $modules = array_keys($_POST['activate']); 
     1795                } 
     1796 
     1797                $list = $this->modules->getDisabledModules(); 
     1798                if (empty($list)) { 
     1799                    throw new Exception(__('No such theme.')); 
     1800                } 
     1801 
     1802                $count = 0; 
     1803                foreach ($list as $id => $module) { 
     1804 
     1805                    if (!in_array($id, $modules)) { 
     1806                        continue; 
     1807                    } 
     1808 
     1809                    # --BEHAVIOR-- themeBeforeActivate 
     1810                    $this->core->callBehavior('themeBeforeActivate', $id); 
     1811 
     1812                    $this->modules->activateModule($id); 
     1813 
     1814                    # --BEHAVIOR-- themeAfterActivate 
     1815                    $this->core->callBehavior('themeAfterActivate', $id); 
     1816 
     1817                    $count++; 
     1818                } 
     1819 
     1820                dcPage::addSuccessNotice( 
     1821                    __('Theme has been successfully activated.', 'Themes have been successuflly activated.', $count) 
     1822                ); 
     1823                http::redirect($this->getURL()); 
     1824            } elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['deactivate'])) { 
     1825 
     1826                if (is_array($_POST['deactivate'])) { 
     1827                    $modules = array_keys($_POST['deactivate']); 
     1828                } 
     1829 
     1830                $list = $this->modules->getModules(); 
     1831                if (empty($list)) { 
     1832                    throw new Exception(__('No such theme.')); 
     1833                } 
     1834 
     1835                $failed = false; 
     1836                $count  = 0; 
     1837                foreach ($list as $id => $module) { 
     1838 
     1839                    if (!in_array($id, $modules)) { 
     1840                        continue; 
     1841                    } 
     1842 
     1843                    if (!$module['root_writable']) { 
     1844                        $failed = true; 
     1845                        continue; 
     1846                    } 
     1847 
     1848                    $module[$id] = $id; 
     1849 
     1850                    # --BEHAVIOR-- themeBeforeDeactivate 
     1851                    $this->core->callBehavior('themeBeforeDeactivate', $module); 
     1852 
     1853                    $this->modules->deactivateModule($id); 
     1854 
     1855                    # --BEHAVIOR-- themeAfterDeactivate 
     1856                    $this->core->callBehavior('themeAfterDeactivate', $module); 
     1857 
     1858                    $count++; 
     1859                } 
     1860 
     1861                if ($failed) { 
     1862                    dcPage::addWarningNotice(__('Some themes have not been deactivated.')); 
     1863                } else { 
     1864                    dcPage::addSuccessNotice( 
     1865                        __('Theme has been successfully deactivated.', 'Themes have been successuflly deactivated.', $count) 
     1866                    ); 
     1867                } 
     1868                http::redirect($this->getURL()); 
     1869            } elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['delete'])) { 
     1870 
     1871                if (is_array($_POST['delete'])) { 
     1872                    $modules = array_keys($_POST['delete']); 
     1873                } 
     1874 
     1875                $list = $this->modules->getDisabledModules(); 
     1876 
     1877                $failed = false; 
     1878                $count  = 0; 
     1879                foreach ($modules as $id) { 
     1880                    if (!isset($list[$id])) { 
     1881 
     1882                        if (!$this->modules->moduleExists($id)) { 
     1883                            throw new Exception(__('No such theme.')); 
     1884                        } 
     1885 
     1886                        $module       = $this->modules->getModules($id); 
     1887                        $module['id'] = $id; 
     1888 
     1889                        if (!$this->isDeletablePath($module['root'])) { 
     1890                            $failed = true; 
     1891                            continue; 
     1892                        } 
     1893 
     1894                        # --BEHAVIOR-- themeBeforeDelete 
     1895                        $this->core->callBehavior('themeBeforeDelete', $module); 
     1896 
     1897                        $this->modules->deleteModule($id); 
     1898 
     1899                        # --BEHAVIOR-- themeAfterDelete 
     1900                        $this->core->callBehavior('themeAfterDelete', $module); 
     1901                    } else { 
     1902                        $this->modules->deleteModule($id, true); 
     1903                    } 
     1904 
     1905                    $count++; 
     1906                } 
     1907 
     1908                if (!$count && $failed) { 
     1909                    throw new Exception(__("You don't have permissions to delete this theme.")); 
     1910                } elseif ($failed) { 
     1911                    dcPage::addWarningNotice(__('Some themes have not been delete.')); 
     1912                } else { 
     1913                    dcPage::addSuccessNotice( 
     1914                        __('Theme has been successfully deleted.', 'Themes have been successuflly deleted.', $count) 
     1915                    ); 
     1916                } 
     1917                http::redirect($this->getURL()); 
     1918            } elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['install'])) { 
     1919 
     1920                if (is_array($_POST['install'])) { 
     1921                    $modules = array_keys($_POST['install']); 
     1922                } 
     1923 
     1924                $list = $this->store->get(); 
     1925 
     1926                if (empty($list)) { 
     1927                    throw new Exception(__('No such theme.')); 
     1928                } 
     1929 
     1930                $count = 0; 
     1931                foreach ($list as $id => $module) { 
     1932 
     1933                    if (!in_array($id, $modules)) { 
     1934                        continue; 
     1935                    } 
     1936 
     1937                    $dest = $this->getPath() . '/' . basename($module['file']); 
     1938 
     1939                    # --BEHAVIOR-- themeBeforeAdd 
     1940                    $this->core->callBehavior('themeBeforeAdd', $module); 
     1941 
     1942                    $this->store->process($module['file'], $dest); 
     1943 
     1944                    # --BEHAVIOR-- themeAfterAdd 
     1945                    $this->core->callBehavior('themeAfterAdd', $module); 
     1946 
     1947                    $count++; 
     1948                } 
     1949 
     1950                dcPage::addSuccessNotice( 
     1951                    __('Theme has been successfully installed.', 'Themes have been successuflly installed.', $count) 
     1952                ); 
     1953                http::redirect($this->getURL()); 
     1954            } elseif ($this->core->auth->isSuperAdmin() && !empty($_POST['update'])) { 
     1955 
     1956                if (is_array($_POST['update'])) { 
     1957                    $modules = array_keys($_POST['update']); 
     1958                } 
     1959 
     1960                $list = $this->store->get(true); 
     1961                if (empty($list)) { 
     1962                    throw new Exception(__('No such theme.')); 
     1963                } 
     1964 
     1965                $count = 0; 
     1966                foreach ($list as $module) { 
     1967 
     1968                    if (!in_array($module['id'], $modules)) { 
     1969                        continue; 
     1970                    } 
     1971 
     1972                    $dest = $module['root'] . '/../' . basename($module['file']); 
     1973 
     1974                    # --BEHAVIOR-- themeBeforeUpdate 
     1975                    $this->core->callBehavior('themeBeforeUpdate', $module); 
     1976 
     1977                    $this->store->process($module['file'], $dest); 
     1978 
     1979                    # --BEHAVIOR-- themeAfterUpdate 
     1980                    $this->core->callBehavior('themeAfterUpdate', $module); 
     1981 
     1982                    $count++; 
     1983                } 
     1984 
     1985                $tab = $count && $count == count($list) ? '#themes' : '#update'; 
     1986 
     1987                dcPage::addSuccessNotice( 
     1988                    __('Theme has been successfully updated.', 'Themes have been successuflly updated.', $count) 
     1989                ); 
     1990                http::redirect($this->getURL() . $tab); 
     1991            } 
     1992 
     1993            # Manual actions 
     1994            elseif (!empty($_POST['upload_pkg']) && !empty($_FILES['pkg_file']) 
     1995                || !empty($_POST['fetch_pkg']) && !empty($_POST['pkg_url'])) { 
     1996                if (empty($_POST['your_pwd']) || !$this->core->auth->checkPassword($_POST['your_pwd'])) { 
     1997                    throw new Exception(__('Password verification failed')); 
     1998                } 
     1999 
     2000                if (!empty($_POST['upload_pkg'])) { 
     2001                    files::uploadStatus($_FILES['pkg_file']); 
     2002 
     2003                    $dest = $this->getPath() . '/' . $_FILES['pkg_file']['name']; 
     2004                    if (!move_uploaded_file($_FILES['pkg_file']['tmp_name'], $dest)) { 
     2005                        throw new Exception(__('Unable to move uploaded file.')); 
     2006                    } 
     2007                } else { 
     2008                    $url  = urldecode($_POST['pkg_url']); 
     2009                    $dest = $this->getPath() . '/' . basename($url); 
     2010                    $this->store->download($url, $dest); 
     2011                } 
     2012 
     2013                # --BEHAVIOR-- themeBeforeAdd 
     2014                $this->core->callBehavior('themeBeforeAdd', null); 
     2015 
     2016                $ret_code = $this->store->install($dest); 
     2017 
     2018                # --BEHAVIOR-- themeAfterAdd 
     2019                $this->core->callBehavior('themeAfterAdd', null); 
     2020 
     2021                dcPage::addSuccessNotice($ret_code == 2 ? 
     2022                    __('Theme has been successfully updated.') : 
     2023                    __('Theme has been successfully installed.') 
     2024                ); 
     2025                http::redirect($this->getURL() . '#themes'); 
     2026            } else { 
     2027 
     2028                # --BEHAVIOR-- adminModulesListDoActions 
     2029                $this->core->callBehavior('adminModulesListDoActions', $this, $modules, 'theme'); 
     2030 
     2031            } 
     2032        } 
     2033 
     2034        return; 
     2035    } 
    20782036} 
Note: See TracChangeset for help on using the changeset viewer.

Sites map