diff options
| -rw-r--r-- | composer.json-dist | 25 | ||||
| -rw-r--r-- | program/include/iniset.php | 5 | ||||
| -rw-r--r-- | program/lib/Roundcube/rcube_plugin.php | 10 | ||||
| -rw-r--r-- | program/lib/Roundcube/rcube_plugin_api.php | 114 | ||||
| -rw-r--r-- | program/steps/settings/about.inc | 67 | 
5 files changed, 150 insertions, 71 deletions
diff --git a/composer.json-dist b/composer.json-dist index 846f742eb..1c2ac80bd 100644 --- a/composer.json-dist +++ b/composer.json-dist @@ -1,35 +1,16 @@  {      "name": "roundcube/roundcubemail",      "description": "The Roundcube Webmail suite", -    "license": "GPL-3.0", +    "license": "GPL-3.0+",      "repositories": [          {              "type": "composer",              "url": "http://plugins.roundcube.net/" -        }, -        { -            "type": "pear", -            "url": "http://pear.php.net/" -        }, -        { -            "type": "package", -            "package": { -                "name": "Net_SMTP", -                "version": "dev-master", -                "source": { -                    "url": "http://github.com/pear/Net_SMTP", -                    "type": "git", -                    "reference": "master" -                } -            }          }      ],      "require": { -        "pear-pear/Mail_Mime": ">=1.8.1", -        "pear-pear/Mail_mimeDecode": ">=1.5.5", -        "Net_SMTP": "dev-master", -        "pear-pear/Net_IDNA2": ">=0.1.1", -        "pear-pear/Auth_SASL": ">=1.0.6" +        "php": ">=5.3.0", +        "roundcube/plugin-installer": ">=0.1.2"      },      "minimum-stability": "dev"  } diff --git a/program/include/iniset.php b/program/include/iniset.php index 913d3d7f6..919cc7682 100644 --- a/program/include/iniset.php +++ b/program/include/iniset.php @@ -60,6 +60,11 @@ require_once 'Roundcube/bootstrap.php';  // register autoloader for rcmail app classes  spl_autoload_register('rcmail_autoload'); +// include composer autoloader (if available) +if (file_exists('vendor/autoload.php')) { +    require 'vendor/autoload.php'; +} +  // backward compatybility (to be removed)  require_once INSTALL_PATH . 'program/include/bc.php'; diff --git a/program/lib/Roundcube/rcube_plugin.php b/program/lib/Roundcube/rcube_plugin.php index 167a9eb4f..d24a2693c 100644 --- a/program/lib/Roundcube/rcube_plugin.php +++ b/program/lib/Roundcube/rcube_plugin.php @@ -92,6 +92,16 @@ abstract class rcube_plugin      abstract function init();      /** +     * Provide information about this +     * +     * @return array Meta information about a plugin or false if not implemented +     */ +    public static function info() +    { +        return false; +    } + +    /**       * Attempt to load the given plugin which is required for the current plugin       *       * @param string Plugin name diff --git a/program/lib/Roundcube/rcube_plugin_api.php b/program/lib/Roundcube/rcube_plugin_api.php index a89f14712..4bb6c6677 100644 --- a/program/lib/Roundcube/rcube_plugin_api.php +++ b/program/lib/Roundcube/rcube_plugin_api.php @@ -228,6 +228,120 @@ class rcube_plugin_api      }      /** +     * Get information about a specific plugin. +     * This is either provided my a plugin's info() method or extracted from a package.xml or a composer.json file +     * +     * @param string Plugin name +     * @return array Meta information about a plugin or False if plugin was not found +     */ +    public function get_info($plugin_name) +    { +      static $composer_lock, $license_uris = array( +        'Apache'     => 'http://www.apache.org/licenses/LICENSE-2.0.html', +        'Apache-2'   => 'http://www.apache.org/licenses/LICENSE-2.0.html', +        'Apache-1'   => 'http://www.apache.org/licenses/LICENSE-1.0', +        'Apache-1.1' => 'http://www.apache.org/licenses/LICENSE-1.1', +        'GPL'        => 'http://www.gnu.org/licenses/gpl.html', +        'GPLv2'      => 'http://www.gnu.org/licenses/gpl-2.0.html', +        'GPL-2.0'    => 'http://www.gnu.org/licenses/gpl-2.0.html', +        'GPLv3'      => 'http://www.gnu.org/licenses/gpl-3.0.html', +        'GPL-3.0'    => 'http://www.gnu.org/licenses/gpl-3.0.html', +        'GPL-3.0+'   => 'http://www.gnu.org/licenses/gpl.html', +        'GPL-2.0+'   => 'http://www.gnu.org/licenses/gpl.html', +        'LGPL'       => 'http://www.gnu.org/licenses/lgpl.html', +        'LGPLv2'     => 'http://www.gnu.org/licenses/lgpl-2.0.html', +        'LGPLv2.1'   => 'http://www.gnu.org/licenses/lgpl-2.1.html', +        'LGPLv3'     => 'http://www.gnu.org/licenses/lgpl.html', +        'LGPL-2.0'   => 'http://www.gnu.org/licenses/lgpl-2.0.html', +        'LGPL-2.1'   => 'http://www.gnu.org/licenses/lgpl-2.1.html', +        'LGPL-3.0'   => 'http://www.gnu.org/licenses/lgpl.html', +        'LGPL-3.0+'  => 'http://www.gnu.org/licenses/lgpl.html', +        'BSD'          => 'http://opensource.org/licenses/bsd-license.html', +        'BSD-2-Clause' => 'http://opensource.org/licenses/BSD-2-Clause', +        'BSD-3-Clause' => 'http://opensource.org/licenses/BSD-3-Clause', +        'FreeBSD'      => 'http://opensource.org/licenses/BSD-2-Clause', +        'MIT'          => 'http://www.opensource.org/licenses/mit-license.php', +        'PHP'          => 'http://opensource.org/licenses/PHP-3.0', +        'PHP-3'        => 'http://www.php.net/license/3_01.txt', +        'PHP-3.0'      => 'http://www.php.net/license/3_0.txt', +        'PHP-3.01'     => 'http://www.php.net/license/3_01.txt', +      ); + +      $dir = dir($this->dir); +      $fn = unslashify($dir->path) . DIRECTORY_SEPARATOR . $plugin_name . DIRECTORY_SEPARATOR . $plugin_name . '.php'; +      $info = false; + +      if (!class_exists($plugin_name)) +        include($fn); + +      if (class_exists($plugin_name)) +        $info = $plugin_name::info(); + +      // fall back to composer.json file +      if (!$info) { +        $composer = INSTALL_PATH . "/plugins/$plugin_name/composer.json"; +        if (file_exists($composer) && ($json = @json_decode(file_get_contents($composer), true))) { +          list($info['vendor'], $info['name']) = explode('/', $json['name']); +          $info['license'] = $json['license']; +          if ($license_uri = $license_uris[$info['license']]) +            $info['license_uri'] = $license_uri; +        } + +        // read local composer.lock file (once) +        if (!isset($composer_lock)) { +          $composer_lock = @json_decode(@file_get_contents(INSTALL_PATH . "/composer.lock"), true); +          if ($composer_lock['packages']) { +            foreach ($composer_lock['packages'] as $i => $package) { +              $composer_lock['installed'][$package['name']] = $package; +            } +          } +        } + +        // load additional information from local composer.lock file +        if ($lock = $composer_lock['installed'][$json['name']]) { +          $info['version'] = $lock['version']; +          $info['uri']     = $lock['homepage'] ? $lock['homepage'] : $lock['source']['uri']; +          $info['src_uri'] = $lock['dist']['uri'] ? $lock['dist']['uri'] : $lock['source']['uri']; +        } +      } + +      // fall back to package.xml file +      if (!$info) { +        $package = INSTALL_PATH . "/plugins/$plugin_name/package.xml"; +        if (file_exists($package) && ($file = file_get_contents($package))) { +          $doc = new DOMDocument(); +          $doc->loadXML($file); +          $xpath = new DOMXPath($doc); +          $xpath->registerNamespace('rc', "http://pear.php.net/dtd/package-2.0"); +          $data = array(); + +          // XPaths of plugin metadata elements +          $metadata = array( +            'name'    => 'string(//rc:package/rc:name)', +            'version' => 'string(//rc:package/rc:version/rc:release)', +            'license' => 'string(//rc:package/rc:license)', +            'license_uri' => 'string(//rc:package/rc:license/@uri)', +            'src_uri' => 'string(//rc:package/rc:srcuri)', +            'uri' => 'string(//rc:package/rc:uri)', +          ); + +          foreach ($metadata as $key => $path) { +            $info[$key] = $xpath->evaluate($path); +          } + +          // dependent required plugins (can be used, but not included in config) +          $deps = $xpath->evaluate('//rc:package/rc:dependencies/rc:required/rc:package/rc:name'); +          for ($i = 0; $i < $deps->length; $i++) { +            $dn = $deps->item($i)->nodeValue; +            $info['requires'][] = $dn; +          } +        } +      } + +      return $info; +    } + +    /**       * Allows a plugin object to register a callback for a certain hook       *       * @param string $hook Hook name diff --git a/program/steps/settings/about.inc b/program/steps/settings/about.inc index 9b13402f1..0fdefddda 100644 --- a/program/steps/settings/about.inc +++ b/program/steps/settings/about.inc @@ -40,17 +40,28 @@ function rcmail_plugins_list($attrib)      $attrib['id'] = 'rcmpluginlist';    $plugins = array_filter((array) $RCMAIL->config->get('plugins')); -  $plugins = array_flip($plugins); +  $plugin_info = array(); -  foreach ($plugins as $name => $plugin) { -    rcube_plugin_data($name, $plugins); +  foreach ($plugins as $name) { +    if ($info = $RCMAIL->plugins->get_info($name)) +      $plugin_info[$name] = $info;    } -  if (empty($plugins)) { +  // load info from required plugins, too +  foreach ($plugin_info as $name => $info) { +    if (is_array($info['required']) && !empty($info['required'])) { +      foreach ($info['required'] as $req_name) { +        if (!isset($plugin_info[$req_name]) && ($req_info = $RCMAIL->plugins->get_info($req_name))) +          $plugin_info[$req_name] = $req_info; +      } +    } +  } + +  if (empty($plugin_info)) {      return '';    } -  ksort($plugins, SORT_LOCALE_STRING); +  ksort($plugin_info, SORT_LOCALE_STRING);    $table = new html_table($attrib); @@ -60,8 +71,8 @@ function rcmail_plugins_list($attrib)    $table->add_header('license', rcube_label('license'));    $table->add_header('source', rcube_label('source')); -  foreach ($plugins as $name => $data) { -    $uri = $data['srcuri'] ? $data['srcuri'] : $data['uri']; +  foreach ($plugin_info as $name => $data) { +    $uri = $data['src_uri'] ? $data['src_uri'] : $data['uri'];      if ($uri && stripos($uri, 'http') !== 0) {        $uri = 'http://' . $uri;      } @@ -78,48 +89,6 @@ function rcmail_plugins_list($attrib)    return $table->show();  } -function rcube_plugin_data($name, &$plugins = array()) -{ -  // XPaths of plugin metadata elements -  $metadata = array( -    'name'    => 'string(//rc:package/rc:name)', -    'version' => 'string(//rc:package/rc:version/rc:release)', -    'license' => 'string(//rc:package/rc:license)', -    'license_uri' => 'string(//rc:package/rc:license/@uri)', -    'srcuri' => 'string(//rc:package/rc:srcuri)', -    'uri' => 'string(//rc:package/rc:uri)', -  ); - -  $package = INSTALL_PATH . "/plugins/$name/package.xml"; -  if (file_exists($package) && ($file = file_get_contents($package))) { -    $doc = new DOMDocument(); -    $doc->loadXML($file); -    $xpath = new DOMXPath($doc); -    $xpath->registerNamespace('rc', "http://pear.php.net/dtd/package-2.0"); -    $data = array(); - -    foreach ($metadata as $key => $path) { -      $data[$key] = $xpath->evaluate($path); -    } - -    $plugins[$name] = $data; - -    // dependent required plugins (can be used, but not included in config) -    $deps = $xpath->evaluate('//rc:package/rc:dependencies/rc:required/rc:package/rc:name'); -    $cnt  = $deps->length; - -    for ($i=0; $i<$cnt; $i++) { -      $dn = $deps->item($i)->nodeValue; -      if (!array_key_exists($dn, $plugins)) { -        rcube_plugin_data($dn, $plugins); -      } -    } -  } -  else { -    unset($plugins[$name]); -  } -} -  $OUTPUT->set_pagetitle(rcube_label('about'));  | 
