1<?php 2 3if (IN_serendipity !== true) { 4 die ('Don\'t hack!'); 5} 6 7if (!serendipity_checkPermission('adminPlugins')) { 8 return; 9} 10 11$data = array(); 12 13include_once S9Y_INCLUDE_PATH . 'include/plugin_api.inc.php'; 14include_once S9Y_INCLUDE_PATH . 'include/functions_entries_admin.inc.php'; 15include_once S9Y_INCLUDE_PATH . 'include/functions_plugins_admin.inc.php'; 16if (!class_exists('Smarty')) { 17 @define('SMARTY_DIR', S9Y_PEAR_PATH . 'Smarty/libs/'); 18 include_once SMARTY_DIR . 'Smarty.class.php'; 19} 20 21if (isset($_GET['serendipity']['plugin_to_move']) && isset($_GET['submit']) && serendipity_checkFormToken()) { 22 23 if (isset($_GET['serendipity']['event_plugin'])) { 24 $plugins = serendipity_plugin_api::enum_plugins('event', false); 25 } else { 26 $plugins = serendipity_plugin_api::enum_plugins('event', true); 27 } 28 29 /* Renumber the sort order to be certain that one actually exists 30 Also look for the one we're going to move */ 31 $idx_to_move = -1; 32 for($idx = 0; $idx < count($plugins); $idx++) { 33 $plugins[$idx]['sort_order'] = $idx; 34 35 if ($plugins[$idx]['name'] == $_GET['serendipity']['plugin_to_move']) { 36 $idx_to_move = $idx; 37 } 38 } 39 40 /* If idx_to_move is still -1 then we never found it (shouldn't happen under normal conditions) 41 Also make sure the swapping idx is around */ 42 if ($idx_to_move >= 0 && (($_GET['submit'] == 'move down' && $idx_to_move < (count($plugins)-1)) || ($_GET['submit'] == 'move up' && $idx_to_move > 0))) { 43 44 /* Swap the one were moving with the one that's in the spot we're moving to */ 45 $tmp = $plugins[$idx_to_move]['sort_order']; 46 47 $plugins[$idx_to_move]['sort_order'] = (int)$plugins[$idx_to_move + ($_GET['submit'] == 'move down' ? 1 : -1)]['sort_order']; 48 $plugins[$idx_to_move + ($_GET['submit'] == 'move down' ? 1 : -1)]['sort_order'] = (int)$tmp; 49 50 /* Update table */ 51 foreach($plugins as $plugin) { 52 $key = serendipity_db_escape_string($plugin['name']); 53 serendipity_db_query("UPDATE {$serendipity['dbPrefix']}plugins SET sort_order = {$plugin['sort_order']} WHERE name='$key'"); 54 } 55 } 56 57 /* TODO: Moving The first Right oriented plugin up, 58 or the last left oriented plugin down 59 should not be displayed to the user as an option. 60 It's a behavior which really has no meaning. */ 61} 62 63if (isset($_GET['serendipity']['plugin_to_conf'])) { 64 65 /* configure a specific instance */ 66 $plugin =& serendipity_plugin_api::load_plugin($_GET['serendipity']['plugin_to_conf']); 67 68 if (!($plugin->protected === FALSE || $plugin->serendipity_owner == '0' || $plugin->serendipity_owner == $serendipity['authorid'] || serendipity_checkPermission('adminPluginsMaintainOthers'))) { 69 return; 70 } 71 $data['plugin_to_conf'] = true; 72 73 $bag = new serendipity_property_bag; 74 $plugin->introspect($bag); 75 76 if (method_exists($plugin, 'performConfig')) { 77 $plugin->performConfig($bag); 78 } 79 80 $name = serendipity_specialchars($bag->get('name')); 81 $desc = serendipity_specialchars($bag->get('description')); 82 $license = serendipity_specialchars($bag->get('license')); 83 84 $documentation = $bag->get('website'); 85 86 $config_names = $bag->get('configuration'); 87 $config_groups = $bag->get('config_groups'); 88 89 if (isset($_POST['SAVECONF']) && serendipity_checkFormToken()) { 90 /* enum properties and set their values */ 91 92 $save_errors = array(); 93 foreach ($config_names as $config_item) { 94 $cbag = new serendipity_property_bag; 95 if ($plugin->introspect_config_item($config_item, $cbag)) { 96 $value = $_POST['serendipity']['plugin'][$config_item]; 97 98 $validate = $plugin->validate($config_item, $cbag, $value); 99 if ($validate === true) { 100 if (!empty($_POST['serendipity']['plugin']['override'][$config_item])) { 101 $value = $_POST['serendipity']['plugin']['override'][$config_item]; 102 } 103 104 if (is_array($_POST['serendipity']['plugin']['activate'][$config_item])) { 105 $active_values = array(); 106 foreach($_POST['serendipity']['plugin']['activate'][$config_item] as $ordered_item_value) { 107 $ordered_item_value; 108 $active_values[] = $ordered_item_value; 109 } 110 $value = implode(',', $active_values); 111 } 112 113 $plugin->set_config($config_item, $value); 114 } else { 115 $save_errors[] = $validate; 116 } 117 } 118 } 119 120 $plugin->cleanup(); 121 } 122 123 if ( isset($save_errors) && is_array($save_errors) && count($save_errors) > 0 ) { 124 $data['save_errors'] = $save_errors; 125 } elseif ( isset($_POST['SAVECONF'])) { 126 $data['saveconf'] = true; 127 $data['timestamp'] = serendipity_strftime('%H:%M:%S'); 128 } 129 $data['formToken'] = serendipity_setFormToken(); 130 $data['name'] = $name; 131 $data['class'] = get_class($plugin); 132 $data['desc'] = $desc; 133 $data['documentation'] = $documentation; 134 $data['plugin'] = $plugin; 135 136 if (@file_exists(dirname($plugin->pluginFile) . '/ChangeLog')) { 137 $data['changelog'] = true; 138 } 139 140 if (@file_exists(dirname($plugin->pluginFile) . '/documentation_' . $serendipity['lang'] . '.html')) { 141 $data['documentation_local'] = '/documentation_' . $serendipity['lang'] . '.html'; 142 } elseif (@file_exists(dirname($plugin->pluginFile) . '/documentation_en.html')) { 143 $data['documentation_local'] = '/documentation_en.html'; 144 } elseif (@file_exists(dirname($plugin->pluginFile) . '/documentation.html')) { 145 $data['documentation_local'] = '/documentation.html'; 146 } elseif (@file_exists(dirname($plugin->pluginFile) . '/README')) { 147 $data['documentation_local'] = '/README'; 148 } 149 150 $data['license'] = $license; 151 $data['config'] = serendipity_plugin_config($plugin, $bag, $name, $desc, $config_names, true, true, true, true, 'plugin', $config_groups); 152 153} elseif ( $serendipity['GET']['adminAction'] == 'addnew' && serendipity_checkFormToken()) { 154 $serendipity['GET']['type'] = $serendipity['GET']['type'] ?: 'sidebar'; 155 $data['adminAction'] = 'addnew'; 156 $data['type'] = $serendipity['GET']['type']; 157 158 # get plugin data from Spartacus 159 $foreignPlugins = $pluginstack = $errorstack = array(); 160 serendipity_plugin_api::hook_event('backend_plugins_fetchlist', $foreignPlugins); 161 $pluginstack = array_merge((array)$foreignPlugins['pluginstack'], $pluginstack); 162 $errorstack = array_merge((array)$foreignPlugins['errorstack'], $errorstack); 163 if ($serendipity['GET']['only_group'] == 'UPGRADE') { 164 // for upgrades, the distinction in sidebar and event-plugins is not useful. We will fetch both and mix the lists 165 if ($serendipity['GET']['type'] == 'event') { 166 $serendipity['GET']['type'] = 'sidebar'; 167 } else { 168 $serendipity['GET']['type'] = 'event'; 169 } 170 $foreignPluginsTemp = array(); 171 serendipity_plugin_api::hook_event('backend_plugins_fetchlist', $foreignPluginsTemp); 172 $pluginstack = array_merge((array)$foreignPluginsTemp['pluginstack'], $pluginstack); 173 $errorstack = array_merge((array)$foreignPluginsTemp['errorstack'], $errorstack); 174 $foreignPlugins = array_merge($foreignPlugins, $foreignPluginsTemp); 175 } 176 177 # load data for installed plugins 178 $plugins = serendipity_plugin_api::get_installed_plugins(); 179 $classes = serendipity_plugin_api::enum_plugin_classes(($serendipity['GET']['type'] === 'event')); 180 if ($serendipity['GET']['only_group'] == 'UPGRADE') { 181 $classes = array_merge($classes, serendipity_plugin_api::enum_plugin_classes(!($serendipity['GET']['type'] === 'event'))); 182 $data['type'] = 'both'; 183 } 184 usort($classes, 'serendipity_pluginListSort'); 185 186 $counter = 0; 187 foreach ($classes as $class_data) { 188 $pluginFile = serendipity_plugin_api::probePlugin($class_data['name'], $class_data['classname'], $class_data['pluginPath']); 189 $plugin =& serendipity_plugin_api::getPluginInfo($pluginFile, $class_data, $serendipity['GET']['type']); 190 191 if (is_object($plugin)) { 192 // Object is returned when a plugin could not be cached. 193 $bag = new serendipity_property_bag; 194 $plugin->introspect($bag); 195 196 // If a foreign plugin is upgradable, keep the new version number. 197 if (isset($foreignPlugins['pluginstack'][$class_data['name']]) && isset($foreignPlugins['pluginstack'][$class_data['name']]['upgrade_version'])) { 198 $class_data['upgrade_version'] = $foreignPlugins['pluginstack'][$class_data['name']]['upgrade_version']; 199 } 200 201 $props = serendipity_plugin_api::setPluginInfo($plugin, $pluginFile, $bag, $class_data, 'local', $foreignPlugins); 202 203 $counter++; 204 } elseif (is_array($plugin)) { 205 // Array is returned if a plugin could be fetched from info cache 206 $props = $plugin; 207 } else { 208 $props = false; 209 } 210 211 if (is_array($props)) { 212 if (version_compare($props['version'], $props['upgrade_version'], '<')) { 213 $props['upgradable'] = true; 214 // since we merged sidebar and event plugins before, we can no longer rely on spartacus' $foreignPlugins['baseURI'] 215 // NOTE: This is not nice and it would be better to move it into the plugins array instead, but that collides with the cache 216 if (strpos($class_data['name'], 'serendipity_plugin') !== false) { 217 $baseURI = "&serendipity[spartacus_fetch]=sidebar"; 218 } else { 219 $baseURI = "&serendipity[spartacus_fetch]=event"; 220 } 221 $props['customURI'] .= $baseURI . $foreignPlugins['upgradeURI']; 222 } 223 224 $props['installable'] = !($props['stackable'] === false && in_array($class_data['true_name'], $plugins)); 225 $props['requirements'] = unserialize($props['requirements']); 226 227 if (empty($props['changelog']) && @file_exists(dirname($props['plugin_file']) . '/ChangeLog')) { 228 $props['changelog'] = 'plugins/' . $props['pluginPath'] . '/ChangeLog'; 229 } 230 231 if (empty($props['local_documentation'])) { 232 if (@file_exists(dirname($props['plugin_file']) . '/documentation_' . $serendipity['lang'] . '.html')) { 233 $props['local_documentation'] = 'plugins/' . $props['pluginPath'] . '/documentation_' . $serendipity['lang'] . '.html'; 234 } elseif (@file_exists(dirname($props['plugin_file']) . '/documentation_en.html')) { 235 $props['local_documentation'] = 'plugins/' . $props['pluginPath'] . '/documentation_en.html'; 236 } elseif (@file_exists(dirname($props['plugin_file']) . '/documentation.html')) { 237 $props['local_documentation'] = 'plugins/' . $props['pluginPath'] . '/documentation.html'; 238 } elseif (@file_exists(dirname($props['plugin_file']) . '/README')) { 239 $props['local_documentation'] = 'plugins/' . $props['pluginPath'] . '/README'; 240 } 241 } 242 $pluginstack[$class_data['true_name']] = $props; 243 } else { 244 // False is returned if a plugin could not be instantiated 245 $errorstack[] = $class_data['true_name']; 246 } 247 } 248 249 usort($pluginstack, 'serendipity_pluginListSort'); 250 $pluggroups = array(); 251 $pluggroups[''] = array(); 252 foreach($pluginstack AS $plugname => $plugdata) { 253 # add pluginsource to pluginstack 254 if (isset($foreignPlugins['pluginstack'][$plugdata['class_name']])) { 255 # remote plugin 256 $plugdata['pluginsource'] = 'Spartacus'; 257 } elseif (serendipity_plugin_api::is_bundled_plugin($plugdata['class_name'])) { 258 # bundled plugin 259 $plugdata['pluginsource'] = PLUGIN_SOURCE_BUNDLED; 260 } else { 261 # everything else must be "local" 262 $plugdata['pluginsource'] = PLUGIN_SOURCE_LOCAL; 263 } 264 # create pluggroups 265 if ($serendipity['GET']['only_group'] == 'ALL') { 266 $pluggroups['ALL'][] = $plugdata; 267 } elseif ($serendipity['GET']['only_group'] == 'UPGRADE' && $plugdata['upgradable']) { 268 $pluggroups['UPGRADE'][] = $plugdata; 269 } elseif (is_array($plugdata['groups'])) { 270 foreach($plugdata['groups'] AS $group) { 271 $pluggroups[$group][] = $plugdata; 272 } 273 } else { 274 $pluggroups[''][] = $plugdata; 275 } 276 } 277 278 ksort($pluggroups); 279 280 $data['count_pluginstack'] = count($pluginstack); 281 $data['errorstack'] = $errorstack; 282 283 if ($serendipity['GET']['only_group'] == 'UPGRADE') { 284 serendipity_plugin_api::hook_event('backend_pluginlisting_header_upgrade', $pluggroups); 285 } 286 287 $available_groups = array_keys($pluggroups); 288 $data['available_groups'] = $available_groups; 289 $groupnames = array(); 290 foreach($available_groups as $available_group) { 291 $groupnames[$available_group] = serendipity_groupname($available_group); 292 } 293 $data['groupnames'] = $groupnames; 294 $data['pluggroups'] = $pluggroups; 295 $data['formToken'] = serendipity_setFormToken(); 296 $data['only_group'] = $serendipity['GET']['only_group']; 297 $data['available_upgrades'] = isset($pluggroups['UPGRADE']); 298 $requirement_failures = array(); 299 300 foreach($pluggroups AS $pluggroup => $groupstack) { 301 foreach ($groupstack as $plug) { 302 if ( !empty($plug['requirements']['serendipity']) && version_compare($plug['requirements']['serendipity'], serendipity_getCoreVersion($serendipity['version']), '>') ) { 303 $requirement_failures[$plug['class_name']] = array("s9y" => true); 304 } 305 306 if ( !empty($plug['requirements']['php']) && version_compare($plug['requirements']['php'], phpversion(), '>') ) { 307 if (isset($requirement_failures[$plug['class_name']])) { 308 $requirement_failures[$plug['class_name']] = array_merge($requirement_failures[$plug['class_name']] , array("php" => true)); 309 } else { 310 $requirement_failures[$plug['class_name']] = array("php" => true); 311 } 312 } 313 314 if ( !empty($plug['requirements']['smarty']) && version_compare($plug['requirements']['smarty'], str_replace('Smarty-', '', Smarty::SMARTY_VERSION), '>') ) { 315 if (isset($requirement_failures[$plug['class_name']])) { 316 $requirement_failures[$plug['class_name']] = array_merge($requirement_failures[$plug['class_name']] , array("smarty" => true)); 317 } else { 318 $requirement_failures[$plug['class_name']] = array("smarty" => true); 319 } 320 } 321 322 } 323 } 324 $data['requirement_failures'] = $requirement_failures; 325} elseif ( $serendipity['GET']['adminAction'] == 'renderOverlay' ) { 326 $data['adminAction'] = 'overlay'; 327} else { 328 /* show general plugin list */ 329 330 /* get sidebar locations */ 331 serendipity_smarty_init(); 332 333 if (is_array($template_config)) { 334 $template_vars =& serendipity_loadThemeOptions($template_config); 335 } 336 337 $col_assoc = array( 338 'event_col' => 'event', 339 'eventh_col' => 'eventh' 340 ); 341 342 if (isset($template_vars['sidebars'])) { 343 $sidebars = explode(',', $template_vars['sidebars']); 344 } elseif (isset($serendipity['sidebars'])) { 345 $sidebars = $serendipity['sidebars']; 346 } else { 347 $sidebars = array('left', 'hide', 'right'); 348 } 349 350 foreach($sidebars AS $sidebar) { 351 $col_assoc[$sidebar . '_col'] = $sidebar; 352 } 353 354 if (isset($_POST['SAVE']) && serendipity_checkFormToken()) { 355 $pos=0; 356 foreach($_POST['serendipity']['plugin'] as $plugin) { 357 serendipity_db_query("UPDATE {$serendipity['dbPrefix']}plugins 358 SET sort_order = ". $pos . " 359 WHERE name='" . serendipity_db_escape_string($plugin['id']) . "'"); 360 361 serendipity_plugin_api::update_plugin_placement( 362 addslashes($plugin['id']), 363 addslashes($plugin['placement']) 364 ); 365 366 serendipity_plugin_api::update_plugin_owner( 367 addslashes($plugin['id']), 368 addslashes($_POST['serendipity']['ownership'][$plugin['name']]) 369 ); 370 $pos++; 371 } 372 } 373 374 if (isset($serendipity['GET']['install_plugin']) && serendipity_checkFormToken()) { 375 $authorid = $serendipity['authorid']; 376 if (serendipity_checkPermission('adminPluginsMaintainOthers')) { 377 $authorid = '0'; 378 } 379 if ($serendipity['ajax']) { 380 // we need to catch the spartacus messages to return only them to the ajax call (used by the update all button) 381 ob_start(); 382 } 383 $fetchplugin_data = array('GET' => &$serendipity['GET'], 384 'install' => true); 385 386 387 serendipity_plugin_api::hook_event('backend_plugins_fetchplugin', $fetchplugin_data); 388 389 // we now have to check that the plugin is not already installed, or stackable, to prevent invalid double instances 390 $new_plugin = true; 391 if ($fetchplugin_data['install']) { 392 // spartacus will set this to false on upgrade, and we want to check this only on install 393 foreach (serendipity_plugin_api::get_installed_plugins() as $pluginName) { 394 if ($serendipity['GET']['install_plugin'] === $pluginName) { 395 $existingPlugin =& serendipity_plugin_api::load_plugin($serendipity['GET']['install_plugin']); 396 if (is_object($existingPlugin)) { 397 $bag = new serendipity_property_bag(); 398 $existingPlugin->introspect($bag); 399 if ($bag->get('stackable') != true) { 400 $new_plugin = false; 401 } 402 } 403 break; 404 } 405 } 406 } 407 408 $data['new_plugin_failed'] = ! $new_plugin; 409 410 if ($fetchplugin_data['install'] && $new_plugin) { 411 $serendipity['debug']['pluginload'] = array(); 412 $inst = serendipity_plugin_api::create_plugin_instance($serendipity['GET']['install_plugin'], null, (serendipity_plugin_api::is_event_plugin($serendipity['GET']['install_plugin']) ? 'event': 'right'), $authorid, serendipity_db_escape_string($serendipity['GET']['pluginPath'])); 413 414 /* Load the new plugin */ 415 $plugin = &serendipity_plugin_api::load_plugin($inst); 416 if (!is_object($plugin)) { 417 echo "DEBUG: Plugin " . serendipity_specialchars($inst) . " not an object: " . serendipity_specialchars(print_r($plugin, true)) 418 . ".<br />Input: " . serendipity_specialchars(print_r($serendipity['GET'], true)) . ".<br /><br />\n\nThis error 419 can happen if a plugin was not properly downloaded (check your plugins directory if the requested plugin 420 was downloaded) or the inclusion of a file failed (permissions?)<br />\n"; 421 echo "Backtrace:<br />\n" . nl2br(serendipity_specialchars(implode("\n", $serendipity['debug']['pluginload']))) . "<br />"; 422 } 423 $bag = new serendipity_property_bag; 424 $plugin->introspect($bag); 425 426 serendipity_plugin_api::hook_event('backend_plugins_install', $serendipity['GET']['install_plugin'], $fetchplugin_data); 427 428 if ($bag->is_set('configuration')) { 429 /* Only play with the plugin if there is something to play with */ 430 echo '<script type="text/javascript">location.href = \'' . $serendipity['baseURL'] . 'serendipity_admin.php?serendipity[adminModule]=plugins&serendipity[plugin_to_conf]=' . $inst . '\';</script>'; 431 die(); 432 } else { 433 /* If no config is available, redirect to plugin overview, because we do not want that a user can install the plugin a second time via accidental browser refresh */ 434 echo '<script type="text/javascript">location.href = \'' . $serendipity['baseURL'] . 'serendipity_admin.php?serendipity[adminModule]=plugins\';</script>'; 435 die(); 436 } 437 } else { 438 serendipity_plugin_api::hook_event('backend_plugins_update', $serendipity['GET']['install_plugin'], $fetchplugin_data); 439 } 440 if ($serendipity['ajax']) { 441 $data['ajax_output'] = ob_get_contents(); 442 ob_end_clean(); 443 } 444 } 445 446 if (isset($_POST['REMOVE']) && serendipity_checkFormToken()) { 447 if (is_array($_POST['serendipity']['plugin_to_remove'])) { 448 foreach ($_POST['serendipity']['plugin_to_remove'] as $key) { 449 $plugin =& serendipity_plugin_api::load_plugin($key); 450 451 if ($plugin->serendipity_owner == '0' || $plugin->serendipity_owner == $serendipity['authorid'] || serendipity_checkPermission('adminPluginsMaintainOthers')) { 452 serendipity_plugin_api::remove_plugin_instance($key); 453 } 454 } 455 } 456 } 457 if (isset($_POST['SAVE'])) { 458 $data['save'] = true; 459 $data['timestamp'] = serendipity_strftime('%H:%M:%S'); 460 } 461 462 ob_start(); 463 serendipity_plugin_api::hook_event('backend_pluginlisting_header', $null); 464 $data['backend_pluginlisting_header'] = ob_get_contents(); 465 ob_end_clean(); 466 467 468 ob_start(); 469 serendipity_plugin_api::hook_event('backend_plugins_sidebar_header', $serendipity); 470 $data['backend_plugins_sidebar_header'] = ob_get_contents(); 471 ob_end_clean(); 472 473 $data['sidebar_plugins'] = show_plugins(false, $sidebars); 474 475 ob_start(); 476 serendipity_plugin_api::hook_event('backend_plugins_event_header', $serendipity); 477 $data['backend_plugins_event_header'] = ob_get_contents(); 478 ob_end_clean(); 479 480 $data['event_plugins'] = show_plugins(true); 481 482 if ($serendipity['memSnaps'] && count($serendipity['memSnaps']) > 0) { 483 $data['$memsnaps'] = $serendipity['memSnaps']; 484 } 485 $data['updateAllMsg'] = isset($serendipity['GET']['updateAllMsg']); 486} 487 488$data['urltoken'] = serendipity_setFormToken('url'); 489echo serendipity_smarty_show('admin/plugins.inc.tpl', $data); 490 491 492/* vim: set sts=4 ts=4 expandtab : */ 493