X-Git-Url: https://delta.frontaccounting.com/gitweb/?a=blobdiff_plain;f=includes%2Fpackages.inc;h=54d16abf5b4bf31cd15ff29f8b048a6acd0b9c94;hb=5a3cbfe6d2df1c8c32edcab8bf93e8a8432a15fc;hp=70b11c15f61e6fd8042c21ba057961755ca0b8d6;hpb=cef4b4de401511a4195b7b8ad04b47bec1895b20;p=fa-stable.git diff --git a/includes/packages.inc b/includes/packages.inc index 70b11c15..54d16abf 100644 --- a/includes/packages.inc +++ b/includes/packages.inc @@ -10,23 +10,17 @@ See the License here . ***********************************************************************/ include_once($path_to_root. "/includes/archive.inc"); +include_once($path_to_root. "/includes/remote_url.inc"); +include_once($path_to_root. "/includes/hooks.inc"); define('PKG_CACHE_PATH', $path_to_root.'/modules/_cache'); define('PUBKEY_PATH', $path_to_root); -define('REPO_URL', "$repository/$FA_repo_version"); -/* -$pkg_data_basedir = array( - 'language' => '/lang/', -// 'module' => '/', - 'extension' => '/modules/', -// 'plugin' => '/modules/', - 'theme' => '/themes/'); -*/ // -// FrontAccounting package class +// FrontAccounting package class // class package extends gzip_file { - function package($filename, $basedir=null) + + function __construct($filename, $basedir=null) { global $path_to_root; @@ -37,7 +31,7 @@ class package extends gzip_file { } else mkdir($basedir); } - $this->archive($filename); + parent::__construct($filename); $this->set_options(array('basedir'=> $basedir)); $this->options['type'] = "pkg"; } @@ -62,11 +56,6 @@ class package extends gzip_file { $cachepath = $this->options['basedir']; $ctrl = get_control_file("$cachepath/_init/config"); -// $targetdir = $pkg_data_basedir[$ctrl['Type']]; -// if ($targetdir) -// $targetdir = $path_to_root.$targetdir.$ctrl['Package']; -// else -// $targetdir = $path_to_root; $targetdir = $path_to_root.'/'.$ctrl['InstallPath']; if (!is_dir($targetdir)) @@ -84,7 +73,8 @@ class package extends gzip_file { $dpackage->extract_files(); //install package in target directory - $success &= $this->support('install'); + $install = hook_invoke($ctrl['Package'], 'install_extension', $dummy); + $success &= $install===null || $install; $success &= count($dpackage->error) == 0; $this->error = array_merge($this->error, $dpackage->error); return $success; @@ -100,11 +90,7 @@ class package extends gzip_file { $cachepath = $this->options['basedir']; $ctrl = get_control_file("$cachepath/_init/config"); -// $targetdir = $pkg_data_basedir[$ctrl['Type']]; -// if ($targetdir) -// $targetdir = $path_to_root.$targetdir.$ctrl['Package']; -// else -// $targetdir = $path_to_root; + $targetdir = $path_to_root.'/'.$ctrl['InstallPath']; $dpackage = new package("$cachepath/_data", $targetdir); @@ -113,7 +99,13 @@ class package extends gzip_file { $success &= copy_files($flist, "$cachepath/_back", $targetdir, true); - $success &= $this->support('uninstall'); + if (strpos($ctrl['InstallPath'], 'modules/') === 0) { // flush module directory + flush_dir($targetdir, true); + rmdir($targetdir); + } + + $uninstall = hook_invoke($ctrl['Package'], 'uninstall_extension', $dummy); + $success &= $uninstall===null || $uninstall; return $success; } @@ -125,25 +117,6 @@ class package extends gzip_file { return true; } - // - // Call special function defined in package install class - // - function support($name, $params = null) - { - $cachepath = $this->options['basedir']; - if (file_exists("$cachepath/_init/init.php")) { - include("$cachepath/_init/init.php"); - if (method_exists($installer, $name)) { - set_include_path("$cachepath/_init".PATH_SEPARATOR.get_include_path()); -// $old = getcwd(); -// chdir("$cachepath/_init"); - $ret = $installer->$name($params); -// chdir($old); - return $ret; - } - } - return true; - } } // // Changes field value read from control file (single, or multiline) into @@ -153,8 +126,8 @@ function ufmt_property($key, $value) { // indexes used in output arrays $sub_fields = array( - 'MenuTabs' => array('url', 'access', 'tab_id', 'title', 'section'), - 'MenuEntries' => array('url', 'access', 'tab_id', 'title'), +// 'MenuTabs' => array('url', 'access', 'tab_id', 'title', 'section'), +// 'MenuEntries' => array('url', 'access', 'tab_id', 'title'), ); if (!isset($sub_fields[$key])) return $value==='' ? null : $value; @@ -198,7 +171,7 @@ function get_control_file($file, $index = false) { $line = ''; do { $line = rtrim($line); - if (@ctype_space($line[0])) { // continuation of multiline property + if ($line && ctype_space($line[0])) { // continuation of multiline property if (strlen(ltrim($line))) { if ($value !== '' && !is_array($value)) $value = array($value); @@ -214,7 +187,7 @@ function get_control_file($file, $index = false) { if ($index !== true) { if ($index === false) break; if (!isset($pkg[$index])) { - display_error(_("No key field '$index' in file '$file'")); + display_error(sprintf(_("No key field '%s' in file '%s'"), $index, $file)); return null; } $repo[$pkg[$index]] = $pkg; @@ -224,7 +197,6 @@ function get_control_file($file, $index = false) { $pkg = array(); $key = null; $value = ''; continue; -// } elseif (preg_match('/([\w-]*):\s*(.*)/', $line, $m)) { } elseif (preg_match('/([^:]*):\s*(.*)/', $line, $m)) { $key = $m[1]; $value = $m[2]; if (!strlen($key)) { @@ -264,8 +236,7 @@ function save_control_file($fname, $list, $zip=false) } } // array elements on subsequent lines starting with white space - $value = //(count($value) ? "\n " :''). - implode("\n ", $value); + $value = implode("\n ", $value); } $zip ? gzwrite($file, "$key: $value\n") : fwrite($file, "$key: $value\n"); } @@ -298,38 +269,58 @@ function pkg_prop($pkg, $property, $lang=false) // function get_pkg_or_list($type = null, $pkgname = null, $filter=array(), $outkey=null, $download=true) { - global $path_to_root, $repository, $FA_repo_version; + global $path_to_root, $repo_auth; + + $repo = (isset($repo_auth['scheme']) ? $repo_auth['scheme'] : 'http://') + .(isset($repo_auth['login']) ? $repo_auth['login'].':' : '') + .(isset($repo_auth['pass']) ? $repo_auth['pass'].'@' : '') + .(isset($repo_auth['host']) ? $repo_auth['host'].'/' : '') + .(isset($repo_auth['path']) ? $repo_auth['path'].'/' : '') + .$repo_auth['branch']; // first download local copy of repo release file // and check remote signature with local copy of public key // $loclist = PKG_CACHE_PATH.'/Release.gz'; - - if ($type!=null && !is_array($type)) { + $target_dir = $download==true ? VARLIB_PATH."/" : $download; + + if (isset($type) && !is_array($type)) { $type = array($type); } $refresh = true; do{ if (!file_exists($loclist)) { - copy(REPO_URL.'/Release.gz', $loclist); + if (!url_copy($repo.'/Release.gz', $loclist)) + { + display_error(_("Cannot download repo index file." )); + return null; + } $refresh = false; } - $sig = file_get_contents(REPO_URL.'/Release.sig', 'rb'); + $sig = url_get_contents($repo.'/Release.sig'); $data = file_get_contents($loclist); $cert = file_get_contents(PUBKEY_PATH.'/FA.pem'); - if (!openssl_verify($data, $sig, $cert)) { - if ($refresh) - @unlink($loclist); - else { + if (!function_exists('openssl_verify')) { + display_error(_("OpenSSL have to be available on your server to use extension repository system.")); + return null; + } + if (openssl_verify($data, $sig, $cert) <= 0) { + if ($refresh) { + if (!@unlink($loclist)) + { + display_error(sprintf(_("Cannot delete outdated '%s' file."), $loclist)); + return null; + } + } else { display_error(_('Release file in repository is invalid, or public key is outdated.')); return null; } } else $refresh = false; + } while($refresh); $Release = get_control_file($loclist, 'Filename'); - // download and check all indexes containing given package types // then complete package list or seek for pkg $Packages = array(); @@ -337,21 +328,27 @@ function get_pkg_or_list($type = null, $pkgname = null, $filter=array(), $outkey if ($type && !count(array_intersect(explode(' ', $parms['Type']), $type))) { unset($Release[$fname]); continue; // no packages of selected type in this index } - if ($Release[$fname]['Version'] != $FA_repo_version) { + if ($Release[$fname]['Version'] != $repo_auth['branch']) { display_warning(_('Repository version does not match application version.')); // ? } - $remoteindex = REPO_URL.'/'.$fname; + $remoteindex = $repo.'/'.$fname; $locindex = PKG_CACHE_PATH.'/'.$fname; $refresh = true; do{ if (!file_exists($locindex)) { - copy($remoteindex, $locindex); + if (!url_copy($remoteindex, $locindex)) { + display_error(sprintf(_("Cannot download '%s' file." ), $fname)); + return null; + } $refresh = false; } if ($parms['SHA1sum'] != sha1_file($locindex)) { // check subdir index consistency - if ($refresh) - @unlink($locindex); - else { + if ($refresh) { + if (!@unlink($locindex)) { + display_error(sprintf(_("Cannot delete outdated '%s' file."), $locindex)); + return null; + } + } else { display_error(sprintf( _("Security alert: broken index file in repository '%s'. Please inform repository administrator about this issue."), $fname)); return null; @@ -363,8 +360,8 @@ function get_pkg_or_list($type = null, $pkgname = null, $filter=array(), $outkey // scan subdir list and select packages of given type $pkglist = get_control_file($locindex, 'Package'); foreach($pkglist as $name => $pkg) { - $pkgfullname = REPO_URL.'/'.$parms['Path']."/".$pkg['Filename'].'.pkg'; - if ($type==null || in_array($pkg['Type'], $type)) { + $pkgfullname = $repo.'/'.$parms['Path']."/".$pkg['Filename'].'.pkg'; + if (!isset($type) || in_array($pkg['Type'], $type)) { if (empty($filter)) $p = $pkg; else { @@ -380,8 +377,11 @@ function get_pkg_or_list($type = null, $pkgname = null, $filter=array(), $outkey } elseif ($pkgname == $pkg['Package']) { //download package to temp directory if ($download) { - $locname = "$path_to_root/tmp/".$pkg['Filename'].'.pkg'; - copy($pkgfullname, $locname); + $locname = $target_dir.$pkg['Filename'].'.pkg'; + if (!url_copy($pkgfullname, $locname)) { + display_error(sprintf(_("Cannot download '%s' file." ), $pkgfullname)); + return null; + } // checking sha1 hash is expensive proces, so chekc the package // consistency just before downloading if ($pkg['SHA1sum'] != sha1_file($locname)) { @@ -395,14 +395,13 @@ function get_pkg_or_list($type = null, $pkgname = null, $filter=array(), $outkey } } } - + return $Packages; } function get_package($pkgname, $type = null) { - $all = get_pkg_or_list($type, $pkgname); - $pkg = array_search_value($all, $pkgname, 'Package'); + return get_pkg_or_list($type, $pkgname); } /* Returns full name of installed package, or null if package is not installed. @@ -463,56 +462,87 @@ function get_languages_list() $list = array_search_keys($l['code'], $pkgs, 'code'); // get all packages with this code foreach ($list as $name) { if ($l['encoding'] == $pkgs[$name]['encoding']) { // if the same encoding - $pkgs[$name]['version'] = $l['version']; // set installed version + $pkgs[$name]['version'] = @$l['version']; // set installed version $pkgs[$name]['local_id'] = $id; // index in installed_languages continue 2; } } $l['local_id'] = $id; - if (!isset($pkgs[$l['package']]) || $l['package'] == '') + if (!isset($l['package']) || $l['package'] == '' || !isset($pkgs[$l['package']])) $pkgs[] = $l; else $pkgs[$l['package']] = array_merge($pkgs[$l['package']], $l); } - ksort($pkgs); + if ($pkgs) + ksort($pkgs); return $pkgs; } //--------------------------------------------------------------------------------------- // -// Return merged list of available and installed extensions in inform of local +// Return merged list of available and installed extensions as a local // configuration array supplemented with installed versions information. // -function get_extensions_list() +function get_extensions_list($type = null) { - $pkgs = get_pkg_or_list('extension', null, array( + global $path_to_root; + + if (isset($type) || !is_array($type)) { + $type = array($type); + } + + $pkgs = get_pkg_or_list($type, null, array( 'Package' => 'package', 'Version' => 'available', 'Name' => 'name', 'Description' => 'Descr', 'Type' => 'type', - 'DefaultStatus'=> 'active', - 'MenuTabs' => 'tabs', - 'MenuEntries' => 'entries', - 'AccessExtensions' => 'acc_file', + 'DefaultStatus' => 'active', +// 'MenuTabs' => 'tabs', +// 'MenuEntries' => 'entries', + 'Encoding' => 'encoding', +// 'AccessExtensions' => 'acc_file', 'InstallPath' => 'path' )); + // lookup for local extensions + $path = $path_to_root.'/modules/'; + $loc = array(); + $moddir = opendir($path); + + while(false != ($fname = readdir($moddir))) + { + if(!in_array($fname, array('.','..','CVS','_cache')) && is_dir($path.$fname)) + { + if (!isset($pkgs[$fname])) + $pkgs[$fname] = array( + 'package' => $fname, + 'name' => $fname, + 'version' => '', + 'available' => '', + 'type' => 'extension', + 'path' => 'modules/'.$fname, + 'active' => false + ); + } + } + // add/update extensions already installed // - $local = get_company_extensions(); - foreach($local as $extno => $ext) { - if ($ext['type'] == 'theme') continue; + $installed = get_company_extensions(); + foreach($installed as $extno => $ext) { + if (!in_array($ext['type'], $type)) continue; $ext['local_id'] = $extno; - if (!isset($pkgs[$ext['package']]) || $ext['package'] == '') - $pkgs[] = $ext; - else +// if (!isset($pkgs[$ext['package']]) || $ext['package'] == '') +// $pkgs[] = $ext; +// else $pkgs[$ext['package']] = array_merge($pkgs[$ext['package']], $ext); } - ksort($pkgs); + if ($pkgs) + ksort($pkgs); return $pkgs; } // -// Return merged list of available and installed extensions in inform of local +// Return merged list of available and installed extensions as a local // configuration array supplemented with installed versions information. // function get_themes_list() @@ -529,14 +559,48 @@ function get_themes_list() $local = get_company_extensions(); foreach($local as $extno => $ext) { - if (isset($pkgs[$ext['package']])) { + if (isset($pkgs[@$ext['package']])) { $ext['local_id'] = $extno; $pkgs[$ext['package']] = array_merge($pkgs[$ext['package']], $ext); } } // TODO: Add other themes from themes directory - - ksort($pkgs); + if ($pkgs) + ksort($pkgs); + return $pkgs; +} +//--------------------------------------------------------------------------------------- +// +// Return merged list of available and installed COAs as a local +// configuration array supplemented with installed versions information. +// +function get_charts_list() +{ + $pkgs = get_pkg_or_list('chart', null, array( + 'Package' => 'package', + 'Version' => 'available', + 'Name' => 'name', + 'Description' => 'Descr', + 'Type' => 'type', + 'InstallPath' => 'path', + 'Encoding' => 'encoding', + 'SqlScript' => 'sql' + )); + + // add/update default charts + // + $local = get_company_extensions(); + + foreach($local as $extno => $ext) { + if ($ext['type'] != 'chart') continue; + $ext['local_id'] = $extno; + if (!isset($pkgs[$ext['package']]) || $ext['package'] == '') + $pkgs[] = $ext; + else + $pkgs[$ext['package']] = array_merge($pkgs[$ext['package']], $ext); + } + if ($pkgs) + ksort($pkgs); return $pkgs; } //--------------------------------------------------------------------------------------------- @@ -553,12 +617,12 @@ function install_language($pkg_name) if ($i === null) $i = count($installed_languages); else { // remove another already installed package for this language - $old_pkg = $installed_languages[$i]['package']; + $old_pkg = @$installed_languages[$i]['package']; if ($old_pkg && ($pkg['Package'] != $old_pkg)) uninstall_package($old_pkg); } - $package = new package("$path_to_root/tmp/".$pkg['Filename'].'.pkg'); + $package = new package(VARLIB_PATH."/".$pkg['Filename'].'.pkg'); if ($package->install()) { $lang = array( 'name' => $pkg['Name'], @@ -572,53 +636,72 @@ function install_language($pkg_name) $lang['rtl'] = true; $installed_languages[$i] = $lang; write_lang($installed_languages); - unlink("$path_to_root/tmp/".$pkg['Filename'].'.pkg'); + unlink(VARLIB_PATH."/".$pkg['Filename'].'.pkg'); $Ajax->activate('lang_tbl'); + } else { + display_error(implode('
', $package->error)); + return false; } - + } else { + display_error(sprintf(_("Package '%s' not found."), $pkg_name)); + return false; } - + return true; } //--------------------------------------------------------------------------------------------- // Install/update extension or theme package from repository // function install_extension($pkg_name) { - global $path_to_root, $next_extension_id, $Ajax; + global $path_to_root, $installed_extensions, $next_extension_id, $Ajax, $db_connections; - $pkg = get_pkg_or_list(array('extension', 'theme'), $pkg_name); + $pkg = get_pkg_or_list(array('extension', 'theme', 'chart'), $pkg_name); if ($pkg) { - $package = new package("$path_to_root/tmp/".$pkg['Filename'].'.pkg'); + $package = new package(VARLIB_PATH."/".$pkg['Filename'].'.pkg'); $local_exts = get_company_extensions(); if ($package->install()) { $ext_id = array_search_key($pkg['Package'], $local_exts, 'package'); if ($ext_id === null) $ext_id = $next_extension_id++; + else { // remove another already installed package for this language + $old_pkg = $installed_extensions[$ext_id]['package']; + if ($old_pkg) + uninstall_package($old_pkg); + } $ext = array( 'name' => $pkg['Name'], 'package' => $pkg['Package'], 'version' => $pkg['Version'], 'type' => $pkg['Type'], - 'active' => true, + 'active' => @$pkg['DefaultStatus'] == 'active' ? true : false, 'path' => $pkg['InstallPath'], -// 'tabs' => $pkg['MenuTabs'], -// 'entries' => $pkg['MenuEntries'], -// 'acc_file' => @$pkg['AccessExtensions'], ); - if (isset($pkg['MenuTabs'])) - $ext['tabs'] = $pkg['MenuTabs']; - if (isset($pkg['MenuEntries'])) - $ext['entries'] = $pkg['MenuEntries']; - if (isset($pkg['AccessExtensions'])) - $ext['acc_file'] = $pkg['AccessExtensions']; + if (isset($pkg['SqlScript'])) + $ext['sql'] = $pkg['SqlScript']; + $local_exts[$ext_id] = $ext; - update_extensions($local_exts); - unlink("$path_to_root/tmp/".$pkg['Filename'].'.pkg'); + $ret = update_extensions($local_exts); + + if (($ext['active'] == true) && file_exists($path_to_root.'/'.$ext['path'].'/hooks.php')) + { + // we need to include the new hooks file to activate extension + include_once($path_to_root.'/'.$ext['path'].'/hooks.php'); + foreach($db_connections as $comp => $db) + activate_hooks($ext['package'], $comp); + } + + unlink(VARLIB_PATH."/".$pkg['Filename'].'.pkg'); $Ajax->activate('ext_tbl'); + return $ret; } else { display_error(implode('
', $package->error)); + return false; } + } else { + display_error(sprintf(_("Package '%s' not found."), $pkg_name)); + return false; } + return true; } /* Returns true if newer package version is available @@ -644,4 +727,20 @@ function get_package_info($pkg, $type=null, $filter=array(), $outkey=null, $down return get_pkg_or_list($type, $pkg, $filter, null, false); } -?> \ No newline at end of file +/* + Check basic extension source compatibility. +*/ +function check_src_ext_version($ext_v) +{ + global $src_version; + if ($ext_v != '-') { + $compat_levels = 2; // current policy is keeping compatibility on major version level. + $app = explode('.', substr($src_version, 0, strspn($src_version, "0123456789."))); + $pkg = explode('.', substr($ext_v, 0, strspn($ext_v, "0123456789."))); + + for ($i=0; $i < min($compat_levels, count($app)); $i++) + if ($pkg[$i] < $app[$i]) + return false; + } + return true; +}