Support for new packaged extensions system.
authorJanusz Dobrowolski <janusz@frontaccounting.eu>
Sat, 17 Jul 2010 16:31:47 +0000 (16:31 +0000)
committerJanusz Dobrowolski <janusz@frontaccounting.eu>
Sat, 17 Jul 2010 16:31:47 +0000 (16:31 +0000)
13 files changed:
FA.pem [new file with mode: 0644]
admin/db/maintenance_db.inc
admin/inst_lang.php
admin/inst_module.php
config.default.php
frontaccounting.php
includes/access_levels.inc
includes/archive.inc [new file with mode: 0644]
includes/packages.inc [new file with mode: 0644]
includes/ui/ui_controls.inc
includes/ui/ui_view.inc
includes/ui/view_package.php [new file with mode: 0644]
modules/_cache/index.php [new file with mode: 0644]

diff --git a/FA.pem b/FA.pem
new file mode 100644 (file)
index 0000000..b51aae2
--- /dev/null
+++ b/FA.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICyzCCAjSgAwIBAgIJAPmoLn2B45+EMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNV
+BAYTAlVTMREwDwYDVQQIEwhEZWxhd2FyZTEOMAwGA1UEBxMFRG92ZXIxHDAaBgNV
+BAMTE2Zyb250YWNjb3VudGluZy5uZXQwHhcNMDkxMTE2MTIxNjEwWhcNMTAxMTE2
+MTIxNjEwWjBOMQswCQYDVQQGEwJVUzERMA8GA1UECBMIRGVsYXdhcmUxDjAMBgNV
+BAcTBURvdmVyMRwwGgYDVQQDExNmcm9udGFjY291bnRpbmcubmV0MIGfMA0GCSqG
+SIb3DQEBAQUAA4GNADCBiQKBgQDm9BbI0KCUrzOQPtZkNpI0mBvnSIjgIAIZXPgB
+UQYqRpNihfrA3eIkpH87X6/zPEmoZXIDrzlXFYzLRvlMwHOnPbVeR0Z3HTT4AYYU
++lcL0l4vIJfaNbRjGXSJ8w/FDc4XOMBU5ut5+zPJmwrqmJsyMcIkN0JX8/5g4+lk
+xTnpIQIDAQABo4GwMIGtMB0GA1UdDgQWBBRzT6vxvlhlrXDXTT/WEBZA7k8xMjB+
+BgNVHSMEdzB1gBRzT6vxvlhlrXDXTT/WEBZA7k8xMqFSpFAwTjELMAkGA1UEBhMC
+VVMxETAPBgNVBAgTCERlbGF3YXJlMQ4wDAYDVQQHEwVEb3ZlcjEcMBoGA1UEAxMT
+ZnJvbnRhY2NvdW50aW5nLm5ldIIJAPmoLn2B45+EMAwGA1UdEwQFMAMBAf8wDQYJ
+KoZIhvcNAQEFBQADgYEA4CJMjO0lR5Vsz3N64MBSMpZKw2XgmZDFgMOORiJ9btJA
+EAnc5mYYsCmZFlXVp1XOj3hcoggrMPmgyLLbagAz5NW2wgEg4xzyE9PhWDJptkww
+oW+J9NyESy8pIsZG/FH0FgoFYshrRRGaK0pImNOSj5HUThfBJLJpLbkm2J1aHag=
+-----END CERTIFICATE-----
index 958572c2b5ab0ffb12f5296f1430e8e88ec8f711..11914e02c519e98b69d8de9d46ff6b7a00797545 100644 (file)
@@ -82,25 +82,8 @@ function write_config_db($new = false)
 
        $msg .= "\$def_coy = " . $def_coy . ";\n\n";
        $msg .= "\$tb_pref_counter = " . $tb_pref_counter . ";\n\n";
-       $msg .= "\$db_connections = array (\n";
-       $msg .= "\t0 => ";
-       for ($i = 0; $i < $n; $i++)
-       {
-               if ($i > 0)
-                       $msg .= "\tarray ";
-               else
-                       $msg .= "array ";
-               $msg .= "('name' => '" . $db_connections[$i]['name'] . "',\n";
-               $msg .= "\t\t'host' => '" . $db_connections[$i]['host'] . "',\n";
-               $msg .= "\t\t'dbuser' => '" . $db_connections[$i]['dbuser'] . "',\n";
-               $msg .= "\t\t'dbpassword' => '" . $db_connections[$i]['dbpassword'] . "',\n";
-               $msg .= "\t\t'dbname' => '" . $db_connections[$i]['dbname'] . "',\n";
-               $msg .= "\t\t'tbpref' => '" . $db_connections[$i]['tbpref'] . "')";
-               if ($i != $n - 1)
-                       $msg .= ",";
-               $msg .= "\n\n";
-       }
-       $msg .= "\t);\n?>";
+       $msg .= "\$db_connections = " .var_export($db_connections, true);
+       $msg .= ";\n?>";
 
        $filename = $path_to_root . "/config_db.php";
        // Check if the file exists and is writable first.
@@ -167,20 +150,8 @@ function write_extensions($extensions=null, $company = -1)
        by extensions editor.
 */\n\n";
 
-       $msg .= "\$installed_extensions = array (\n";
-       foreach($extensions as $i => $ext) 
-       {
-               $msg .= "\t$i => ";
-               $msg .= "array ( ";
-               $t = '';
-               foreach($ext as $key => $val) {
-                       $msg .= $t."'$key' => '$val',\n";
-                       $t = "\t\t\t";
-               }
-               $msg .= "\t\t),\n";
-       }
-       $msg .= "\t);\n?>";
-
+       $msg .= "\$installed_extensions = ". var_export($extensions, true);
+       $msg .= ";\n?>";
        $filename = $path_to_root . ($company==-1 ? '' : '/company/'.$company)
                .'/installed_extensions.php';
 
@@ -205,43 +176,57 @@ function write_extensions($extensions=null, $company = -1)
        }
        return true;
 }
+//---------------------------------------------------------------------------------------------
+//
+// Update per-company list of installed extensions
+//
+function update_extensions($extensions) {
+       global $db_connections;
+       
+       if (!write_extensions($extensions)) {
+               display_notification(_("Cannot update system extensions list."));
+               return false;
+       }
+
+       // update per company files
+       $cnt = count($db_connections);
+       for($i = 0; $i < $cnt; $i++) 
+       {
+               $newexts = $extensions;
+               // update 'active' status 
+               $exts = get_company_extensions($i);
+               foreach ($exts as $key => $ext) 
+               {
+                       if (isset($newexts[$key]))
+                               $newexts[$key]['active'] = $exts[$key]['active'];
+               }
+               if(!write_extensions($newexts, $i)) 
+               {
+                       display_notification(sprintf(_("Cannot update extensions list for company '%s'."),
+                               $db_connections[$i]['name']));
+                return false;
+               }
+       }
+       return true;
+}
+
 
 function write_lang()
 {
        global $path_to_root, $installed_languages, $dflt_lang;
 
-       $conn = array_natsort($installed_languages, 'code', 'code');
-       $installed_languages = $conn;
-       //reset($installed_languages);
+       $installed_languages = array_natsort($installed_languages, 'code', 'code');
        $n = count($installed_languages);
        $msg = "<?php\n\n";
 
        $msg .= "/* How to make new entries here\n\n";
-       $msg .= "-- if adding languages at the beginning of the list, make sure it's index is set to 0 (it has ' 0 => ')\n";
        $msg .= "-- 'code' should match the name of the directory for the language under \\lang\n";
        $msg .= "-- 'name' is the name that will be displayed in the language selection list (in Users and Display Setup)\n";
        $msg .= "-- 'rtl' only needs to be set for right-to-left languages like Arabic and Hebrew\n\n";
        $msg .= "*/\n\n\n";
 
-       $msg .= "\$installed_languages = array (\n";
-       if ($n > 0)
-           $msg .= "\t0 => ";
-       for ($i = 0; $i < $n; $i++)
-       {
-               if ($i > 0)
-                       $msg .= "\t\tarray ";
-               else
-                       $msg .= "array ";
-               $msg .= "('code' => '" . $installed_languages[$i]['code'] . "', ";
-               $msg .= "'name' => '" . $installed_languages[$i]['name'] . "', ";
-               $msg .= "'encoding' => '" . $installed_languages[$i]['encoding'] . "'";
-               if (isset($installed_languages[$i]['rtl']) && $installed_languages[$i]['rtl'])
-                       $msg .= ", 'rtl' => true),\n";
-               else
-                       $msg .= "),\n";
-       }
-
-       $msg .= "\t);\n";
+       $msg .= "\$installed_languages = " . var_export($installed_languages, true);
+       $msg .= ";\n";
        $msg .= "\n\$dflt_lang = '$dflt_lang';\n?>\n";
 
        $path = $path_to_root . "/lang";
@@ -316,7 +301,7 @@ function db_drop_db($connection)
 function db_import($filename, $connection, $force=true)
 {
        global $db, $go_debug;
-       
+
        $allowed_commands = array(
                "create"  => 'table_queries', 
                "alter table" => 'table_queries', 
@@ -338,7 +323,6 @@ function db_import($filename, $connection, $force=true)
 
        ini_set("max_execution_time", "180");
        db_query("SET foreign_key_checks=0");
-
        // uncrompress gziped backup files
        if (strpos($filename, ".gz") || strpos($filename, ".GZ"))
                $lines = db_ungzip("lines", $filename);
@@ -604,8 +588,8 @@ function db_export($conn, $filename, $zip='no', $comment='', $tbpref = TB_PREF)
                        $out.=$table_sql[$tablename];
 
                        // add auto_increment value
-                       if ($auto_incr[$tablename])
-                               $out.=" AUTO_INCREMENT=".$auto_incr[$tablename];
+//                     if ($auto_incr[$tablename])
+//                             $out.=" AUTO_INCREMENT=".$auto_incr[$tablename];
                        $out.=" ;";
                        $out.="\n\n\n";
 
index 858e13a6afcaea83872d7eda9965adf1fabb722e..54183e090dae1a694ad2c9eccd5ddafeb860a70c 100644 (file)
@@ -13,47 +13,138 @@ $page_security = 'SA_CREATELANGUAGE';
 $path_to_root="..";
 include_once($path_to_root . "/includes/session.inc");
 
-page(_($help_context = "Install/Update Languages"));
-
-include_once($path_to_root . "/includes/date_functions.inc");
-include_once($path_to_root . "/admin/db/company_db.inc");
+include_once($path_to_root."/includes/packages.inc");
 include_once($path_to_root . "/admin/db/maintenance_db.inc");
 include_once($path_to_root . "/includes/ui.inc");
 
-//---------------------------------------------------------------------------------------------
+if ($use_popup_windows)
+       $js = get_js_open_window(900, 500);
 
-if (isset($_GET['selected_id']))
-{
-       $selected_id = $_GET['selected_id'];
-}
-elseif (isset($_POST['selected_id']))
-{
-       $selected_id = $_POST['selected_id'];
-}
-else
-       $selected_id = -1;
+page(_($help_context = "Install/Update Languages"), false, false, "", $js);
+
+simple_page_mode(true);
 
 //---------------------------------------------------------------------------------------------
+//
+// Display all packages - both already installed and available from repository
+//
+function display_languages()
+{
+       global $table_style, $installed_languages, $dflt_lang;
+       global $repository, $FA_repo_version;
+       
+       $th = array(_("Language"), _("Name"), _("Encoding"), _("Right To Left"),
+               _("Installed"), _("Available"), _("Default"), "", "");
+       $currlang = $_SESSION["language"]->code;
+
+       div_start('lang_tbl');
+       start_form();
+       //
+       // select/display system locales support for sites using native gettext
+       //
+       if (function_exists('gettext'))
+       {
+               if (check_value('DisplayAll'))
+                        array_insert($th, 7, _("Supported"));
+               start_table();
+               check_row(_('Display also languages not supported by server locales'), 'DisplayAll', null, true);
+               end_table();
+       }
 
+       start_table(TABLESTYLE);
+       table_header($th);
+
+       $k = 0;
+
+       // get list of all (available and installed) langauges
+       $langs = get_languages_list();
+       foreach ($langs as $pkg_name => $lng)
+       {
+               $lang = $lng['code'];
+               $lang_name = $lng['name'];
+               $charset = $lng['encoding'];
+               $rtl = @$lng['rtl'] == 'yes' || @$lng['rtl'] === true;
+               $available = @$lng['available'];
+               $installed = @$lng['version'];
+               $id = @$lng['local_id'];
+               
+               if ($lang == $currlang)
+                       start_row("class='stockmankobg'");
+               else
+                       alt_table_row_color($k);
+
+               $support = ($lang == 'en_GB') ||
+                       $_SESSION['get_text']->check_support($lang, $charset);
+
+               if (function_exists('gettext') && !$support && !get_post('DisplayAll')) continue;
+
+               label_cell($lang);
+               label_cell($available ? get_package_view_str($lang, $lang_name) : $lang_name);
+               label_cell($charset);
+               label_cell($rtl ? _("Yes") : _("No"));
+               
+               label_cell($id === null ? _("None") :
+                       ($available && $installed ? $installed : _("Unknown")));
+
+               label_cell($available ? $available : _("None"));
+
+               label_cell($id === null ? '' :
+                       radio(null, 'CurDflt', $id, $dflt_lang == $lang, true),
+                       "align='center'");
+               
+               if (function_exists('gettext') && check_value('DisplayAll'))
+                       label_cell($support ? _("Yes") :_("No"));
+
+               if (!$available && ($lang != 'en_GB'))  // manually installed language
+                       button_cell('Edit'.$id, _("Edit"), _('Edit non standard language configuration'), 
+                               ICON_EDIT);
+               elseif (check_pkg_upgrade($installed, $available)) // outdated or not installed language in repo
+                       button_cell('Update'.$pkg_name, $installed ? _("Update") : _("Install"),
+                               _('Upload and install latest language package'), ICON_DOWN);
+               else
+                       label_cell('');
+
+               if (($id !== null) && ($lang != $currlang) && ($lang != 'en_GB')) {
+                       delete_button_cell('Delete'.$id, _('Delete'));
+                       submit_js_confirm('Delete'.$id, 
+                               sprintf(_("You are about to remove language \'%s\'.\nDo you want to continue ?"), 
+                                       $lang_name));
+               } else
+                       label_cell('');
+               end_row();
+       }
+       end_table();
+       display_note(_("The marked language is the current language which cannot be deleted."), 0, 0, "class='currentfg'");
+       br();
+       submit_center_first('Refresh', _("Update default"), '', null);
+
+       submit_center_last('Add', _("Add new language manually"), '', false);
+
+       end_form();
+       div_end();
+}
+//---------------------------------------------------------------------------------------------
+// Non standard (manually entered) languages support.
+//
 function check_data()
 {
-       if ($_POST['code'] == "" || $_POST['name'] == "" || $_POST['encoding'] == "") {
+       global $installed_languages;
+
+       if (get_post('code') == '' || get_post('name') == '' || get_post('encoding') == '') {
                display_error(_("Language name, code nor encoding cannot be empty"));
                return false;
        }
+       $id = array_search_value($_POST['code'], $installed_languages, 'code');
+       if ($id !== null && $installed_languages[$id]['package'] != null) {
+               display_error(_('Standard package for this language is already installed. If you want to install this language manually, uninstall standard language package first.'));
+               return false;
+       }
        return true;
 }
 
-//---------------------------------------------------------------------------------------------
-
-function handle_submit()
+function handle_submit($id)
 {
-       global $path_to_root, $installed_languages, $dflt_lang;
-
-       if (!check_data())
-               return false;
-
-       $id = $_GET['id'];
+       global $path_to_root, $installed_languages, $dflt_lang, $Mode;
 
        if ($_POST['dflt']) {
                        $dflt_lang = $_POST['code'];
@@ -61,8 +152,11 @@ function handle_submit()
        
        $installed_languages[$id]['code'] = $_POST['code'];
        $installed_languages[$id]['name'] = $_POST['name'];
+       $installed_languages[$id]['path'] = 'lang/' . $_POST['code'];
        $installed_languages[$id]['encoding'] = $_POST['encoding'];
        $installed_languages[$id]['rtl'] = (bool)$_POST['rtl'];
+       $installed_languages[$id]['package'] = '';
+       $installed_languages[$id]['version'] = '';
        if (!write_lang())
                return false;
        $directory = $path_to_root . "/lang/" . $_POST['code'];
@@ -92,123 +186,30 @@ function handle_submit()
 
 //---------------------------------------------------------------------------------------------
 
-function handle_delete()
-{
-       global  $path_to_root, $installed_languages, $dflt_lang;
-
-       $id = $_GET['id'];
-
-       $lang = $installed_languages[$id]['code'];
-       $filename = "$path_to_root/lang/$lang/LC_MESSAGES";
-
-       if ($lang == $dflt_lang ) { 
-               // on delete set default to current.
-               $dflt_lang = $_SESSION['language']->code;
-       }
-       
-       unset($installed_languages[$id]);
-       $installed_languages = array_values($installed_languages);
-
-       if (!write_lang())
-               return;
-
-       $filename = "$path_to_root/lang/$lang";
-       flush_dir($filename);
-       rmdir($filename);
-
-       meta_forward($_SERVER['PHP_SELF']);
-}
-
-//---------------------------------------------------------------------------------------------
-
-function display_languages()
-{
-       global $installed_languages, $dflt_lang;
-
-       $lang = $_SESSION["language"]->code;
-
-       echo "
-               <script language='javascript'>
-               function deleteLanguage(id) {
-                       if (!confirm('" . _("Are you sure you want to delete language no. ") . "'+id))
-                               return
-                       document.location.replace('inst_lang.php?c=df&id='+id)
-               }
-               </script>";
-       start_table(TABLESTYLE);
-       $th = array(_("Language"), _("Name"), _("Encoding"), _("Right To Left"), _("Default"), "", "");
-       table_header($th);
-
-       $k = 0;
-       $conn = $installed_languages;
-       $n = count($conn);
-       for ($i = 0; $i < $n; $i++)
-       {
-               if ($conn[$i]['code'] == $lang)
-               start_row("class='stockmankobg'");
-       else
-               alt_table_row_color($k);
-
-               label_cell($conn[$i]['code']);
-               label_cell($conn[$i]['name']);
-               label_cell($conn[$i]['encoding']);
-               if (isset($conn[$i]['rtl']) && $conn[$i]['rtl'])
-                       $rtl = _("Yes");
-               else
-                       $rtl = _("No");
-               label_cell($rtl);
-               label_cell($dflt_lang == $conn[$i]['code'] ? _("Yes") :_("No"));
-               $edit = _("Edit");
-               $delete = _("Delete");
-               if (user_graphic_links())
-               {
-                       $edit = set_icon(ICON_EDIT, $edit);
-                       $delete = set_icon(ICON_DELETE, $delete);
-               }
-       label_cell("<a href='" . $_SERVER['PHP_SELF']. "?selected_id=$i'>$edit</a>");
-               label_cell($conn[$i]['code'] == $lang ? '' :
-                       "<a href='javascript:deleteLanguage(" . $i . ")'>$delete</a>");
-               end_row();
-       }
-
-       end_table();
-    display_note(_("The marked language is the current language which cannot be deleted."), 0, 0, "class='currentfg'");
-}
-
-//---------------------------------------------------------------------------------------------
-
 function display_language_edit($selected_id)
 {
        global $installed_languages, $dflt_lang;
 
-       if ($selected_id != -1)
-               $n = $selected_id;
-       else
+       if ($selected_id == -1)
                $n = count($installed_languages);
-
+       else
+               $n = $selected_id;
+       
        start_form(true);
 
-       echo "
-               <script language='javascript'>
-               function updateLanguage() {
-                       document.forms[0].action='inst_lang.php?c=u&id=" . $n . "'
-                       document.forms[0].submit()
-               }
-               </script>";
-
        start_table(TABLESTYLE2);
 
        if ($selected_id != -1)
        {
-               $conn = $installed_languages[$selected_id];
-               $_POST['code'] = $conn['code'];
-               $_POST['name']  = $conn['name'];
-               $_POST['encoding']  = $conn['encoding'];
+               $lang = $installed_languages[$n];
+               $_POST['code'] = $lang['code'];
+               $_POST['name']  = $lang['name'];
+               $_POST['encoding']  = $lang['encoding'];
                if (isset($conn['rtl']))
-                       $_POST['rtl']  = $conn['rtl'];
+                       $_POST['rtl']  = $lang['rtl'];
                else
                        $_POST['rtl'] = false;
-               $_POST['dflt'] = $dflt_lang == $conn['code'];
+               $_POST['dflt'] = $dflt_lang == $lang['code'];
                hidden('selected_id', $selected_id);
        }
        text_row_ex(_("Language Code"), 'code', 20);
@@ -223,41 +224,71 @@ function display_language_edit($selected_id)
 
        end_table(0);
        display_note(_("Select your language files from your local harddisk."), 0, 1);
-       echo "<center><input onclick='javascript:updateLanguage()' type='button' style='width:150px' value='". _("Save"). "'></center>";
 
+       submit_add_or_update_center(false, '', 'both');
 
        end_form();
 }
 
-
-//---------------------------------------------------------------------------------------------
-
-if (isset($_GET['c']))
+function handle_delete($id)
 {
-       if ($_GET['c'] == 'df')
-       {
-               handle_delete();
+       global  $path_to_root, $installed_languages, $dflt_lang;
+
+       $lang = $installed_languages[$id]['code'];
+       if ($installed_languages[$id]['package'])
+               if (!uninstall_package($installed_languages[$id]['package']))
+                       return;
+                       
+       if ($lang == $dflt_lang ) { 
+               // on delete set default to current.
+               $dflt_lang = $_SESSION['language']->code;
        }
+       
+       unset($installed_languages[$id]);
+       $installed_languages = array_values($installed_languages);
 
-       if ($_GET['c'] == 'u')
-       {
-               if (handle_submit())
-               {
-                       //meta_forward($_SERVER['PHP_SELF']);
-               }
+       if (!write_lang())
+               return;
+
+       $dirname = "$path_to_root/lang/$lang";
+       if ($lang && is_dir($dirname)) {        // remove nonstadard language dir
+               flush_dir($dirname, true);
+               rmdir($dirname);
        }
 }
 
 //---------------------------------------------------------------------------------------------
 
-display_languages();
+if ($Mode == 'Delete')
+       handle_delete($selected_id);
 
-hyperlink_no_params($_SERVER['PHP_SELF'], _("Create a new language"));
+if ($Mode == 'ADD_ITEM' || $Mode == 'UPDATE_ITEM')
+       if (check_data() && handle_submit($selected_id))
+               $Mode = 'RESET';
 
-display_language_edit($selected_id);
+if ($id = find_submit('Update', false))
+       install_language($id);
 
+if (get_post('_CurDflt_update') || (get_post('Refresh') && get_post('CurDflt', -1) != -1)) {
+       $new_lang = $installed_languages[get_post('CurDflt', 0)]['code'];
+       if ($new_lang != $dflt_lang) {
+               $dflt_lang = $new_lang;
+               write_lang();
+               $Ajax->activate('lang_tbl');
+       }
+}
+if (get_post('_DisplayAll_update')) {
+       $Ajax->activate('lang_tbl');
+}
+       
 //---------------------------------------------------------------------------------------------
 
+if (isset($_GET['popup']) || get_post('Add') || $Mode == 'Edit' || $Mode == 'ADD_ITEM' || $Mode == 'UPDATE_ITEM') {
+       display_language_edit($selected_id);
+} else
+       display_languages();
+
+//---------------------------------------------------------------------------------------------
 end_page();
 
 ?>
\ No newline at end of file
index 844244b737099e1abc3b46c925a1860f9c9b4be4..52190ca7eabe2fe968df80479462ce59eb36f2d8 100644 (file)
@@ -12,6 +12,7 @@
 $page_security = 'SA_CREATEMODULES';
 $path_to_root="..";
 include_once($path_to_root . "/includes/session.inc");
+include_once($path_to_root."/includes/packages.inc");
 
 page(_($help_context = "Install/Activate extensions"));
 
@@ -21,38 +22,9 @@ include_once($path_to_root . "/admin/db/maintenance_db.inc");
 include_once($path_to_root . "/includes/ui.inc");
 
 simple_page_mode(true);
-
 //---------------------------------------------------------------------------------------------
-function update_extensions($extensions) {
-       global $db_connections;
-       
-       if (!write_extensions($extensions)) {
-               display_notification(_("Cannot update system extensions list."));
-               return false;
-       }
-
-       // update per company files
-       $cnt = count($db_connections);
-       for($i = 0; $i < $cnt; $i++) 
-       {
-               $newexts = $extensions;
-               // update 'active' status 
-               $exts = get_company_extensions($i);
-               foreach ($exts as $key => $ext) 
-               {
-                       if (isset($newexts[$key]))
-                               $newexts[$key]['active'] = $exts[$key]['active'];
-               }
-               if(!write_extensions($newexts, $i)) 
-               {
-                       display_notification(sprintf(_("Cannot update extensions list for company '%s'."),
-                               $db_connections[$i]['name']));
-                return false;
-               }
-       }
-       return true;
-}
-
+// Check third-party extension parameters
+//
 function check_data($id, $exts)
 {
        if ($_POST['name'] == "") {
@@ -93,17 +65,21 @@ function handle_submit()
        $id = $selected_id==-1 ? $next_extension_id : $selected_id;
 
        if ($selected_id != -1 && $extensions[$id]['type'] != 'plugin') {
-               display_error(_('Module installation support is not implemented yet. You have to do it manually.'));
+               display_error(_('Module installation support is not implemented.'));
                return;
        }
 
-       $extensions[$id]['tab'] = $_POST['tab'];
        $extensions[$id]['name'] = $_POST['name'];
-       $extensions[$id]['path'] = $_POST['path'];
-       $extensions[$id]['title'] = $_POST['title'];
+       $extensions[$id]['package'] = '';
+       $extensions[$id]['version'] = '';
        $extensions[$id]['active'] = check_value('active');
+       $entry = $selected_id == -1 ? array() : $extensions[$id]['entries'][0];
+       
+       $entry['tab_id'] = $_POST['tab'];
+       $entry['title'] = $_POST['title'];
+       $entry['section'] = 2; // menu section aka module
 
-       // Currently we support only plugin extensions here.
+       // Only plugin extensions can be installed manually.
        $extensions[$id]['type'] = 'plugin';
        $directory = $path_to_root . "/modules/" . $_POST['path'];
        if (!file_exists($directory))
@@ -112,7 +88,7 @@ function handle_submit()
        }
        if (is_uploaded_file($_FILES['uploadfile']['tmp_name']))
        {
-               $extensions[$id]['filename'] = $_FILES['uploadfile']['name'];
+               $entry['url'] = '/modules/'.$_POST['path'].'/'.$_FILES['uploadfile']['name'];
                $file1 = $_FILES['uploadfile']['tmp_name'];
                $file2 = $directory . "/".$_FILES['uploadfile']['name'];
                if (file_exists($file2))
@@ -120,21 +96,18 @@ function handle_submit()
                move_uploaded_file($file1, $file2);
        }
        else
-               $extensions[$id]['filename'] = get_post('filename');
+               $entry['url'] = '/modules/'.$_POST['path'].'/'.get_post('filename');
+
        if (is_uploaded_file($_FILES['uploadfile2']['tmp_name']))
        {
                $file1 = $_FILES['uploadfile2']['tmp_name'];
-               $file2 = $directory . "/".$_FILES['uploadfile2']['name'];
-               if (file_exists($file2))
-                       unlink($file2);
-               move_uploaded_file($file1, $file2);
                $db_name = $_SESSION["wa_current_user"]->company;
-               db_import($file2, $db_connections[$db_name]);
+               db_import($file1, $db_connections[$db_name]);
        }
        
        if (is_uploaded_file($_FILES['uploadfile3']['tmp_name']))
        {
-               $extensions[$id]['acc_file'] = $_FILES['uploadfile3']['name'];
+               $extensions[$id]['acc_file'] = '/modules/'.$_POST['path'].'/'.$_FILES['uploadfile3']['name'];
                $file1 = $_FILES['uploadfile3']['tmp_name'];
                $file2 = $directory . "/".$_FILES['uploadfile3']['name'];
                if (file_exists($file2))
@@ -142,19 +115,18 @@ function handle_submit()
                move_uploaded_file($file1, $file2);
        }
        else
-               $extensions[$id]['acc_file'] = get_post('acc_file');
+               $extensions[$id]['acc_file'] = '/modules/'.$_POST['path'].'/'.get_post('acc_file');
 
        // security area guess for plugins
-       if ($extensions[$id]['type'] == 'plugin'){
-               $exttext = file_get_contents($path_to_root.'/modules/'
-                       .$extensions[$id]['path'].'/'.$extensions[$id]['filename']);
-               $area = 'SA_OPEN';
-               if (preg_match('/.*\$page_security\s*=\s*[\'"]([^\'"]*)/', $exttext, $match)) {
-                       $area = trim($match[1]);
-               } 
-               $extensions[$id]['access'] = $area;
+       $exttext = file_get_contents($path_to_root.$entry['url']);
+       $area = 'SA_OPEN';
+       if (preg_match('/.*\$page_security\s*=\s*[\'"]([^\'"]*)/', $exttext, $match)) {
+               $area = trim($match[1]);
        }
+       $entry['access'] = $area;
 
+       $extensions[$id]['entries'] = array($entry);
+       
        if ($selected_id == -1) 
        {
                $next_extension_id++;
@@ -164,76 +136,116 @@ function handle_submit()
        return true;
 }
 
-function handle_delete()
+function handle_delete($id)
 {
-       global  $path_to_root, $db_connections, $selected_id;
+       global $path_to_root;
        
        $extensions = get_company_extensions();
 
-       $id = $selected_id;
-
-       $filename = $path_to_root
-               . ($extensions[$id]['type']=='plugin' ? "/modules/": '/')
-               . $extensions[$id]['path'];
+       if ($extensions[$id]['package'] != '') {
+               if (!uninstall_package($extensions[$id]['package']))
+                       return false;
+       } else {
 
-       flush_dir($filename);
-       rmdir($filename);
+               $dirname = dirname(@$extensions[$id]['entries'][0]['url']);
+               if ($dirname) {
+                       $dirname = $path_to_root.$dirname;
+                       flush_dir($dirname, true);
+                       rmdir($dirname);
+               }
+       }
        unset($extensions[$id]);
-       if (update_extensions($extensions))
+       if (update_extensions($extensions)) {
                display_notification(_("Selected extension has been successfully deleted"));
+       }
        return true;
 }
-
+//
+// Helper for formating menu tabs/entries to be displayed in extension table
+//
+function fmt_titles($defs)
+{
+               if (!$defs) return '';
+               foreach($defs as $def) {
+                       $str[] = access_string($def['title'], true);
+               }
+               return implode('<br>', array_values($str));
+}
 //---------------------------------------------------------------------------------------------
-
+//
+// Display list of all extensions - installed and available from repository
+//
 function display_extensions()
 {
+
+       div_start('ext_tbl');
        start_table(TABLESTYLE);
-       $th = array(_("Name"),_("Tab"), _("Link text"), _("Folder"), _("Filename"), 
-               _("Access extensions"),"", "");
+
+       $th = array(_("Extension"),_("Modules provided"), _("Options provided"),
+                _("Installed"), _("Available"),  "", "");
        table_header($th);
 
        $k = 0;
-       $mods = get_company_extensions();
-       $mods = array_natsort($mods, null, 'name');
+       $mods = get_extensions_list();
 
-       foreach($mods as $i => $mod)
+       foreach($mods as $pkg_name => $ext)
        {
-               $is_mod = $mod['type'] == 'module';
-               alt_table_row_color($k);
-               label_cell($mod['name']);
-               label_cell( $is_mod ? 
-                       $mod['title'] : access_string($_SESSION['App']->applications[$mod['tab']]->name, true));
-               $ttl = access_string($mod['title']);
-               label_cell($ttl[0]);
-               label_cell($mod['path']);
-               label_cell($mod['filename']);
-               label_cell(@$mod['acc_file']);
-               if ($is_mod)
-               {
-                       label_cell(''); // not implemented (yet)
-               }
+               $available = @$ext['available'];
+               $installed = @$ext['version'];
+               $id = @$ext['local_id'];
+               $is_mod = $ext['type'] == 'module';
+
+               $entries = fmt_titles(@$ext['entries']);
+               $tabs = fmt_titles(@$ext['tabs']);
+
+               alt_table_row_color($k);
+//             label_cell(is_array($ext['Descr']) ? $ext['Descr'][0] : $ext['Descr']);
+               label_cell($available ? get_package_view_str($pkg_name, $ext['name']) : $ext['name']);
+               label_cell($tabs);
+               label_cell($entries);
+
+               label_cell($id === null ? _("None") :
+                       ($available && $installed ? $installed : _("Unknown")));
+               label_cell($available ? $available : _("None"));
+
+               if (!$available && $ext['type'] == 'plugin')    // third-party plugin
+                       button_cell('Edit'.$id, _("Edit"), _('Edit third-party extension parameters.'), 
+                               ICON_EDIT);
+               elseif (check_pkg_upgrade($installed, $available)) // outdated or not installed extension in repo
+                       button_cell('Update'.$pkg_name, $installed ? _("Update") : _("Install"),
+                               _('Upload and install latest extension package'), ICON_DOWN);
                else
-               {
-                       edit_button_cell("Edit".$i, _("Edit"));
-               }
-                       delete_button_cell("Delete".$i, _("Delete"));
-               submit_js_confirm('Delete'.$i, _('You are about to delete this extension\nDo you want to continue?'));
+                       label_cell('');
+
+               if ($id !== null) {
+                       delete_button_cell('Delete'.$id, _('Delete'));
+                       submit_js_confirm('Delete'.$id, 
+                               sprintf(_("You are about to remove package \'%s\'.\nDo you want to continue ?"), 
+                                       $ext['name']));
+               } else
+                       label_cell('');
+
                end_row();
        }
 
        end_table(1);
-}
 
+       submit_center_first('Refresh', _("Update"), '', null);
+       submit_center_last('Add', _("Add third-party plugin"), '', false);
+
+       div_end();
+}
+//---------------------------------------------------------------------------------
+//
+// Get all installed extensions and display
+// with current status stored in company directory.
+//
 function company_extensions($id)
 {
        start_table(TABLESTYLE);
        
-       $th = array(_("Name"),_("Tab"), _("Link text"), _("Active"));
+       $th = array(_("Extension"),_("Modules provided"), _("Options provided"), _("Active"));
        
-       // get all available extensions and display
-       // with current status stored in company directory.
-
        $mods = get_company_extensions();
        $exts = get_company_extensions($id);
        foreach($mods as $key => $ins) {
@@ -250,26 +262,28 @@ function company_extensions($id)
        {
                alt_table_row_color($k);
                label_cell($mod['name']);
-               label_cell( $mod['type'] == 'module' ? 
-                       $mod['title'] : access_string($_SESSION['App']->applications[$mod['tab']]->name, true));
-               $ttl = access_string($mod['title']);
-               label_cell($ttl[0]);
+               $entries = fmt_titles(@$mod['entries']);
+               $tabs = fmt_titles(@$mod['tabs']);
+               label_cell($tabs);
+               label_cell($entries);
+
                check_cells(null, 'Active'.$i, @$mod['active'] ? 1:0, 
                        false, false, "align='center'");
                end_row();
        }
 
        end_table(1);
-       submit_center('Update', _('Update'), true, false, 'default');
+       submit_center('Refresh', _('Update'), true, false, 'default');
 }
 
 //---------------------------------------------------------------------------------------------
-
+//
+// Third-party plugin installation
+//
 function display_ext_edit($selected_id)
 {
        global $Mode;
 
-
        $extensions = get_company_extensions();
 
        start_table(TABLESTYLE2);
@@ -278,12 +292,14 @@ function display_ext_edit($selected_id)
        {
                if ($Mode == 'Edit') {
                        $mod = $extensions[$selected_id];
-                       $_POST['tab']  = $mod['tab'];
+                       $entry = $mod['entries'][0];
+
                        $_POST['name'] = $mod['name'];
-                       $_POST['title'] = $mod['title'];
-                       $_POST['path'] = $mod['path'];
-                       $_POST['filename'] = $mod['filename'];
-                       $_POST['acc_file'] = @$mod['acc_file'];
+                       $_POST['tab']  = $entry['tab_id'];
+                       $_POST['title'] = $entry['title'];
+                       $_POST['path'] = substr(dirname($entry['url']), 9); //strip '/modules/'
+                       $_POST['filename'] = basename($entry['url']);
+                       $_POST['acc_file'] = @$mod['acc_file'] ? basename($mod['acc_file']) : null;
                        hidden('filename', $_POST['filename']);
                        hidden('acc_file', $_POST['acc_file']);
                }
@@ -318,12 +334,18 @@ if ($Mode=='ADD_ITEM' || $Mode == 'UPDATE_ITEM') {
 }
 if ($Mode == 'Delete')
 {
-       handle_delete();
+       handle_delete($selected_id);
        $Mode = 'RESET';
 }
-if (get_post('Update')) {
-       $exts = get_company_extensions();
+if (get_post('Refresh')) {
+       $exts = get_company_extensions(get_post('extset')); //
+       $comp = get_post('extset');
+       
        foreach($exts as $i => $ext) {
+               if ($ext['package'] && ($ext['active'] ^ check_value('Active'.$i))) {
+                       $pkg = new package($ext['package'].'-'.$ext['version'].'.pkg');
+                       $pkg->support(check_value('Active'.$i) ? 'activate':'deactivate', $comp);
+               }
                $exts[$i]['active'] = check_value('Active'.$i);
        }
        write_extensions($exts, get_post('extset'));
@@ -332,6 +354,9 @@ if (get_post('Update')) {
        display_notification(_('Current active extensions set has been saved.'));
 }
 
+if ($id = find_submit('Update', false))
+       install_extension($id);
+
 if ($Mode == 'RESET')
 {
        $selected_id = -1;
@@ -343,21 +368,26 @@ start_form(true);
 if (list_updated('extset'))
        $Ajax->activate('_page_body');
 
-echo "<center>" . _('Extensions:') . "&nbsp;&nbsp;";
-echo extset_list('extset', null, true);
-echo "</center><br>";
-
 $set = get_post('extset', -1);
-if ($set == -1) {
-       display_extensions();
 
+if (isset($_GET['popup']) || get_post('Add') || $Mode == 'Edit' 
+               || $Mode == 'ADD_ITEM' || $Mode == 'UPDATE_ITEM') 
+{
        display_ext_edit($selected_id);
-} else {
-       company_extensions($set);
 }
+else { 
+       echo "<center>" . _('Extensions:') . "&nbsp;&nbsp;";
+       echo extset_list('extset', null, true);
+       echo "</center><br>";
+
+       if ($set == -1) 
+               display_extensions();
+       else 
+               company_extensions($set);
+}
+
 //---------------------------------------------------------------------------------------------
 end_form();
 
 end_page();
-
 ?>
\ No newline at end of file
index 60205becd5a74c6aad6b5d539f6036ea418fcc70..34b86733130fcfec5f344d53ea1781051cce6d07 100644 (file)
@@ -61,6 +61,16 @@ if (!isset($path_to_root) || isset($_GET['path_to_root']) || isset($_POST['path_
         // src-data compatibility check. Do not change.
        $core_version = "2.3";
 
+       // Extension packages repository
+       $FA_repo_version = '2.3'; // this should be get from database FA version?
+       $repo_auth = array(
+                'login' => 'anonymous',
+                'pass' => 'password',
+       );
+       
+       $repository = 'http://'.$repo_auth['login'].':'.$repo_auth['pass'].'@'.'localhost/Repo'
+               .'/index.php?path=';
+               
        // Build for development purposes
        $build_version  = date("d.m.Y", filemtime("$path_to_root/CHANGELOG.txt"));
 
index 4ae88cbb1f6f5c681576b116dbded1075cd3b057..3324d6bb4bdcd14b978305979626d659b296863c 100644 (file)
@@ -20,14 +20,14 @@ if (!isset($path_to_root) || isset($_GET['path_to_root']) || isset($_POST['path_
        include_once($path_to_root . '/applications/generalledger.php');
        include_once($path_to_root . '/applications/setup.php');
        include_once($path_to_root . '/installed_extensions.php');
-       if (count($installed_extensions) > 0)
+
+       foreach ($installed_extensions as $ext)
        {
-               foreach ($installed_extensions as $ext)
-               {
-                       if ($ext['type'] == 'module')
-                               include_once($path_to_root."/".$ext['path']."/".$ext['filename']);
-               }
-       }       
+               if (@($ext['active'] && isset($ext['tabs']))) // supressed warnings before 2.2 upgrade
+                       foreach($ext['tabs'] as $tab) {
+                               include_once($path_to_root.'/'.$ext['path'].'/'.$tab['url']);
+                       }
+       }
 
        class front_accounting
                {
@@ -38,6 +38,7 @@ if (!isset($path_to_root) || isset($_GET['path_to_root']) || isset($_POST['path_
                // GUI
                var $menu;
                //var $renderer;
+
                function front_accounting()
                {
                        //$this->renderer =& new renderer();
@@ -64,7 +65,9 @@ if (!isset($path_to_root) || isset($_GET['path_to_root']) || isset($_POST['path_
                function display()
                {
                        global $path_to_root;
-                       include($path_to_root . "/themes/".user_theme()."/renderer.php");
+                       
+                       include_once($path_to_root . "/themes/".user_theme()."/renderer.php");
+
                        $this->init();
                        $rend = new renderer();
                        $rend->wa_header();
@@ -72,6 +75,7 @@ if (!isset($path_to_root) || isset($_GET['path_to_root']) || isset($_POST['path_
                        $rend->display_applications($this);
                        //$rend->menu_footer($this->menu);
                        $rend->wa_footer();
+                       $this->renderer =& $rend;
                }
                function init()
                {
@@ -87,27 +91,25 @@ if (!isset($path_to_root) || isset($_GET['path_to_root']) || isset($_POST['path_
                        $this->add_application(new manufacturing_app());
                        $this->add_application(new dimensions_app());
                        $this->add_application(new general_ledger_app());
-                       if (count($installed_extensions) > 0)
+
+                       // Do not use global array directly here, or you suffer 
+                       // from buggy php behaviour (unexpected loop break 
+                       // because of same var usage in class constructor).
+                       $extensions = $installed_extensions;
+                       foreach ($extensions as $ext)
                        {
-                               // Do not use global array directly here, or you suffer 
-                               // from buggy php behaviour (unexpected loop break 
-                               // because of same var usage in class constructor).
-                               $extensions = $installed_extensions;
-                               foreach ($extensions as $ext)
-                               {
-                                       if (@($ext['active'] && $ext['type'] == 'module')) // supressed warnings before 2.2 upgrade
-                                       { 
-                                               $_SESSION['get_text']->add_domain($_SESSION['language']->code, 
-                                                       $ext['path']."/lang");
-                                               $class = $ext['tab']."_app";
+                               if (@($ext['active'] && isset($ext['tabs']))) { // supressed warnings before 2.2 upgrade
+                                       $_SESSION['get_text']->add_domain($_SESSION['language']->code, 
+                                               $ext['path']."/lang");
+                                       foreach($ext['tabs'] as $tab) {
+                                               $class = $tab['tab_id']."_app";
                                                if (class_exists($class))
                                                        $this->add_application(new $class());
-                                               $_SESSION['get_text']->add_domain($_SESSION['language']->code, 
-                                                       $path_to_root."/lang");
                                        }
                                }
-                       }       
-                       
+                       }
+                       $_SESSION['get_text']->add_domain($_SESSION['language']->code, 
+                               $path_to_root."/lang", $_SESSION['language']->version);
                        $this->add_application(new setup_app());
                }
 }
index 77dcae9afc1f6ccf489945e2e76f957224b07131..bb84a10a7c66f76ede184deb1b5b00b3d67446c3 100644 (file)
@@ -300,7 +300,7 @@ function get_access_extensions($id) {
        $security_sections = $security_areas = array();
        
        if (isset($ext['acc_file']))
-               include($path_to_root.($ext['type'] == 'plugin' ? '/modules/':'/').$ext['path'].'/'.$ext['acc_file']);
+               include($path_to_root.'/'.$ext['path'].'/'.$ext['acc_file']);
 
        return array($security_areas, $security_sections);
 }
diff --git a/includes/archive.inc b/includes/archive.inc
new file mode 100644 (file)
index 0000000..d8316d3
--- /dev/null
@@ -0,0 +1,466 @@
+<?php
+/*--------------------------------------------------
+ | TAR/GZIP/BZIP2/ZIP ARCHIVE CLASSES 2.1
+ | By Devin Doucette
+ | Copyright (c) 2005 Devin Doucette
+ | Email: darksnoopy@shaw.ca
+ +--------------------------------------------------
+ | Email bugs/suggestions to darksnoopy@shaw.ca
+ +--------------------------------------------------
+ | This script has been created and released under
+ | the GNU GPL and is free to use and redistribute
+ | only if this copyright statement is not removed
+ +--------------------------------------------------
+ | FrontAccounting bugfixes/changes added.
+ +--------------------------------------------------*/
+
+class archive
+{
+       function archive($name)
+       {
+               $this->options = array (
+                       'basedir' => ".",
+                       'name' => $name,
+                       'prepend' => "",
+                       'inmemory' => 0,
+                       'overwrite' => 0,
+                       'recurse' => 1,
+                       'storepaths' => 1,
+                       'followlinks' => 0,
+                       'level' => 3,
+                       'method' => 1,
+                       'sfx' => "",
+                       'type' => "",
+                       'comment' => ""
+               );
+               $this->files = array ();
+               $this->exclude = array ();
+               $this->storeonly = array ();
+               $this->error = array ();
+       }
+
+       function set_options($options)
+       {
+               foreach ($options as $key => $value)
+                       $this->options[$key] = $value;
+               if (!empty ($this->options['basedir']))
+               {
+                       $this->options['basedir'] = str_replace("\\", "/", $this->options['basedir']);
+                       $this->options['basedir'] = preg_replace("/\/+/", "/", $this->options['basedir']);
+                       $this->options['basedir'] = preg_replace("/\/$/", "", $this->options['basedir']);
+               }
+               if (!empty ($this->options['name']))
+               {
+                       $this->options['name'] = str_replace("\\", "/", $this->options['name']);
+//                     $this->options['name'] = preg_replace("/\/+/", "/", $this->options['name']);
+               }
+               if (!empty ($this->options['prepend']))
+               {
+                       $this->options['prepend'] = str_replace("\\", "/", $this->options['prepend']);
+                       $this->options['prepend'] = preg_replace("/^(\.*\/+)+/", "", $this->options['prepend']);
+                       $this->options['prepend'] = preg_replace("/\/+/", "/", $this->options['prepend']);
+                       $this->options['prepend'] = preg_replace("/\/$/", "", $this->options['prepend']) . "/";
+               }
+       }
+
+       function create_archive()
+       {
+               $this->make_list();
+
+               if ($this->options['inmemory'] == 0)
+               {
+                       if ($this->options['overwrite'] == 0 && 
+                               file_exists($this->options['name'] 
+                               . ($this->options['type'] == "pkg" || $this->options['type'] == "gzip" ||$this->options['type'] == "bzip" ? ".tmp" : "")))
+                       {
+                               $this->error[] = "File {$this->options['name']} already exists.";
+                               return 0;
+                       }
+                       else if (!($this->archive = @fopen($this->options['name'].".tmp", "wb+")))
+                       {
+                               $this->error[] = "Could not open {$this->options['name']} for writing.".':'.getcwd();
+                               return 0;
+                       }
+               }
+               else
+                       $this->archive = "";
+
+               if (!$this->create_tar())
+               {
+                       $this->error[] = "Could not create package file.";
+                       return 0;
+               }
+               if (!$this->create_pkg())
+               {
+                       $this->error[] = "Could not compress package file.";
+                       return 0;
+               }
+
+               if ($this->options['inmemory'] == 0)
+               {
+                       fclose($this->archive);
+                       unlink($this->options['name'] . ".tmp");
+               }
+       }
+
+       function add_data($data)
+       {
+               if ($this->options['inmemory'] == 0)
+                       fwrite($this->archive, $data);
+               else
+                       $this->archive .= $data;
+       }
+
+       function make_list()
+       {
+               if (!empty ($this->exclude)) {
+                       foreach ($this->files as $key => $value)
+                               foreach ($this->exclude as $current)
+                                       if ($value['name'] == $current['name']) 
+                                               unset ($this->files[$key]);
+               }
+               if (!empty ($this->storeonly))
+                       foreach ($this->files as $key => $value)
+                               foreach ($this->storeonly as $current)
+                                       if ($value['name'] == $current['name'])
+                                               $this->files[$key]['method'] = 0;
+               unset ($this->exclude, $this->storeonly);
+       }
+
+       function add_files($list)
+       {
+               $temp = $this->list_files($list);
+               foreach ($temp as $current)
+                       $this->files[] = $current;
+       }
+
+       function exclude_files($list)
+       {
+               $temp = $this->list_files($list);
+               foreach ($temp as $current)
+                       $this->exclude[] = $current;
+       }
+
+       function store_files($list)
+       {
+               $temp = $this->list_files($list);
+               foreach ($temp as $current)
+                       $this->storeonly[] = $current;
+       }
+
+       function list_files($list)
+       {
+               if (!is_array ($list))
+               {
+                       $temp = $list;
+                       $list = array ($temp);
+                       unset ($temp);
+               }
+
+               $files = array ();
+
+               $pwd = getcwd();
+               chdir($this->options['basedir']);
+
+               foreach ($list as $current)
+               {
+                       $current = str_replace("\\", "/", $current);
+                       $current = preg_replace("/\/+/", "/", $current);
+                       $current = preg_replace("/\/$/", "", $current);
+                       if (strstr($current, "*"))
+                       {
+                               $regex = preg_replace("/([\\\^\$\.\[\]\|\(\)\?\+\{\}\/])/", "\\\\\\1", $current);
+                               $regex = str_replace("*", ".*", $regex);
+                               $dir = strstr($current, "/") ? substr($current, 0, strrpos($current, "/")) : ".";
+                               $temp = $this->parse_dir($dir);
+                               foreach ($temp as $current2)
+                                       if (preg_match("/^{$regex}$/i", $current2['name']))
+                                               $files[] = $current2;
+                               unset ($regex, $dir, $temp, $current);
+                       }
+                       else if (@is_dir($current))
+                       {
+                               $temp = $this->parse_dir($current);
+                               foreach ($temp as $file)
+                                       $files[] = $file;
+                               unset ($temp, $file);
+                       }
+                       else if (@file_exists($current))
+                               $files[] = array ('name' => $current, 'name2' => $this->options['prepend'] .
+                                       preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($current, "/")) ?
+                                       substr($current, strrpos($current, "/") + 1) : $current),
+                                       'type' => @is_link($current) && $this->options['followlinks'] == 0 ? 2 : 0,
+                                       'ext' => substr($current, strrpos($current, ".")), 'stat' => stat($current));
+               }
+
+               chdir($pwd);
+
+               unset ($current, $pwd);
+               return $files;
+       }
+
+       function parse_dir($dirname)
+       {
+               if ($this->options['storepaths'] == 1 && !preg_match("/^(\.+\/*)+$/", $dirname))
+                       $files = array (array ('name' => $dirname, 'name2' => $this->options['prepend'] .
+                               preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($dirname, "/")) ?
+                               substr($dirname, strrpos($dirname, "/") + 1) : $dirname), 'type' => 5, 'stat' => stat($dirname)));
+               else
+                       $files = array ();
+               $dir = @opendir($dirname);
+
+               while ($file = @readdir($dir))
+               {
+                       $fullname = $dirname . "/" . $file;
+                       if ($file == "." || $file == "..")
+                               continue;
+                       else if (@is_dir($fullname))
+                       {
+                               if (empty ($this->options['recurse']))
+                                       continue;
+                               $temp = $this->parse_dir($fullname);
+                               foreach ($temp as $file2)
+                                       $files[] = $file2;
+                       }
+                       else if (@file_exists($fullname))
+                               $files[] = array ('name' => $fullname, 'name2' => $this->options['prepend'] .
+                                       preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($fullname, "/")) ?
+                                       substr($fullname, strrpos($fullname, "/") + 1) : $fullname),
+                                       'type' => @is_link($fullname) && $this->options['followlinks'] == 0 ? 2 : 0,
+                                       'ext' => substr($file, strrpos($file, ".")), 'stat' => stat($fullname));
+               }
+
+               @closedir($dir);
+
+               return $files;
+       }
+}
+
+class tar_file extends archive
+{
+       function tar_file($name)
+       {
+               $this->archive($name);
+               $this->options['type'] = "tar";
+       }
+
+       function create_tar()
+       {
+               $pwd = getcwd();
+               chdir($this->options['basedir']);
+               $files = $this->files;
+               foreach ($files as $current)
+               {
+                       if ($current['name'] == $this->options['name'])
+                               continue;
+                       if (strlen($current['name2']) > 99)
+                       {
+                               $path = substr($current['name2'], 0, strpos($current['name2'], "/", strlen($current['name2']) - 100) + 1);
+                               $current['name2'] = substr($current['name2'], strlen($path));
+                               if (strlen($path) > 154 || strlen($current['name2']) > 99)
+                               {
+                                       $this->error[] = "Could not add {$path}{$current['name2']} to archive because the filename is too long.";
+                                       continue;
+                               }
+                       }
+                       $block = pack("a100a8a8a8a12a12a8a1a100a6a2a32a32a8a8a155a12", $current['name2'], sprintf("%07o", 
+                               $current['stat'][2]), sprintf("%07o", $current['stat'][4]), sprintf("%07o", $current['stat'][5]), 
+                               sprintf("%011o", $current['type'] == 2 ? 0 : $current['stat'][7]), sprintf("%011o", $current['stat'][9]), 
+                               "        ", $current['type'], $current['type'] == 2 ? @readlink($current['name']) : "", "ustar ", " ", 
+                               "Unknown", "Unknown", "", "", !empty ($path) ? $path : "", "");
+
+                       $checksum = 0;
+                       for ($i = 0; $i < 512; $i++)
+                               $checksum += ord(substr($block, $i, 1));
+                       $checksum = pack("a8", sprintf("%07o", $checksum));
+                       $block = substr_replace($block, $checksum, 148, 8);
+
+                       if ($current['type'] == 2 || $current['stat'][7] == 0)
+                               { $this->add_data($block); 
+                               }
+                       else if ($fp = @fopen($current['name'], "rb"))
+                       {
+                               $this->add_data($block);
+
+                               while ($temp = fread($fp, 1048576)) {
+                                       $this->add_data($temp);
+                               }
+                               if ($current['stat'][7] % 512 > 0)
+                               {
+                                       $temp = "";
+                                       for ($i = 0; $i < 512 - $current['stat'][7] % 512; $i++)
+                                               $temp .= "\0";
+                                       $this->add_data($temp);
+                               }
+                               fclose($fp);
+                       }
+                       else
+                               $this->error[] = "Could not open file {$current['name']} for reading. It was not added.";
+               }
+
+               $this->add_data(pack("a1024", ""));
+
+               chdir($pwd);
+
+               return 1;
+       }
+       /*
+               Extract files to base directory.
+               When $dry_run!=0 no file is written,
+               but list of existing files to be written is returned.
+       */
+       function extract_files($dry_run = false)
+       {
+       $flist = array();
+               if ($fp = $this->open_archive())
+               {
+                       $pwd = getcwd();
+                       // display_error($pwd.':'.$this->options['basedir']);
+                       chdir($this->options['basedir']);
+                       if ($this->options['inmemory'] == 1)
+                               $this->files = array();
+
+                       while ($block = fread($fp, 512))
+                       {
+                               $temp = unpack("a100name/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1type/a100symlink/a6magic/a2temp/a32temp/a32temp/a8temp/a8temp/a155prefix/a12temp", $block);
+                               $file = array (
+                                       'name' => $temp['prefix'] . $temp['name'],
+                                       'stat' => array (
+                                               2 => octdec($temp['mode']),
+                                               4 => octdec($temp['uid']),
+                                               5 => octdec($temp['gid']),
+                                               7 => octdec($temp['size']),
+                                               9 => octdec($temp['mtime']),
+                                       ),
+                                       'checksum' => octdec($temp['checksum']),
+                                       'type' => $temp['type'],
+                                       'magic' => $temp['magic'],
+                               );
+                               if ($file['checksum'] == 0x00000000)
+                                       break;
+                               else if (substr($file['magic'], 0, 5) != "ustar")
+                               {
+                                       $this->error[] = "This script does not support extracting this type of tar file.";
+                                       break;
+                               }
+                               $block = substr_replace($block, "        ", 148, 8);
+                               $checksum = 0;
+                               for ($i = 0; $i < 512; $i++)
+                                       $checksum += ord(substr($block, $i, 1));
+                               if ($file['checksum'] != $checksum) {
+                                       $this->error[] = "Could not extract from {$this->options['name']}, it is corrupt.";
+                                       break;
+                               }
+                               if ($dry_run || $this->options['inmemory'] == 1)
+                               {
+                                       if ($file['type'] == 0) {
+                                               if($dry_run) {
+                                                       $tst = check_write($file['name']);
+                                                       if (!$tst) {
+                                                               $this->error[] = "Could not open {$this->options['basedir']}/{$file['name']} for writing.";
+                                                               break;
+                                                       } else {
+                                                               $flist[] = $file['name'];
+                                                               if ( $tst < 0 && $this->options['overwrite'] == 0)
+                                                                       $this->error[] = "{$file['name']} already exists.";
+                                                       }
+                                                       fseek($fp, ($file['stat'][7] + 511) & ~511, SEEK_CUR); // skip data
+                                               } else {
+                                                       $dat = fread($fp, $file['stat'][7]);
+                                                       $tail = $file['stat'][7] % 512;
+                                                       if ($tail)
+                                                               fread($fp, 512 - $tail);
+                                                       $file['data'] = $dat;
+                                               }
+                                       }
+                                       unset ($file['checksum'], $file['magic']);
+                                       $this->files[] = $file; 
+                               }
+                               else if ($file['type'] == 5)
+                               {
+                                       if (!is_dir($file['name'])) {
+                                               mkdir($file['name'], $file['stat'][2]);
+                                       }
+                               }
+                               else if ($this->options['overwrite'] == 0 && file_exists($file['name']))
+                               {
+                                       $this->error[] = "{$file['name']} already exists.";
+                                       continue;
+                               }
+                               else if ($file['type'] == 2)
+                               {
+                                       symlink($temp['symlink'], $file['name']);
+                                       @chmod($file['name'], $file['stat'][2]);
+                               }
+                               else if ($new = @fopen($file['name'], "wb"))
+                               {
+                                       fwrite($new, fread($fp, $file['stat'][7]));
+                                       fread($fp, (512 - $file['stat'][7] % 512) == 512 ? 0 : (512 - $file['stat'][7] % 512));
+                                       fclose($new);
+                                       @chmod($file['name'], $file['stat'][2]);
+                               }
+                               else
+                               {
+                                       $this->error[] = "Could not open {$file['name']} for writing.";
+                                       continue;
+                               }
+//                             @chown($file['name'], $file['stat'][4]);
+//                             @chgrp($file['name'], $file['stat'][5]);
+                               if (!$dry_run) {
+                                       @touch($file['name'], $file['stat'][9]);
+                               }
+                               unset ($file);
+                       }
+                       chdir($pwd);
+               }
+               else
+                       $this->error[] = "Could not open file {$this->options['name']}";
+               error_log('3');
+
+               return $flist;
+       }
+
+       function open_archive()
+       {
+               return @fopen($this->options['name'], "rb");
+       }
+}
+
+class gzip_file extends tar_file
+{
+       function gzip_file($name)
+       {
+               $this->tar_file($name);
+               $this->options['type'] = "gzip";
+       }
+
+       function create_gzip()
+       {
+               if ($this->options['inmemory'] == 0)
+               {
+                       if ($fp = gzopen($this->options['name'], "wb{$this->options['level']}"))
+                       {
+                               fseek($this->archive, 0);
+                               while ($temp = fread($this->archive, 1048576))
+                                       gzwrite($fp, $temp);
+                               gzclose($fp);
+                       }
+                       else
+                       {
+                               $this->error[] = "Could not open {$this->options['name']} for writing.";
+                               return 0;
+                       }
+               }
+               else
+                       $this->archive = gzencode($this->archive, $this->options['level']);
+
+               return 1;
+       }
+
+       function open_archive()
+       {
+               return @gzopen($this->options['name'], "rb");
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/includes/packages.inc b/includes/packages.inc
new file mode 100644 (file)
index 0000000..70b11c1
--- /dev/null
@@ -0,0 +1,647 @@
+<?php
+/**********************************************************************
+    Copyright (C) FrontAccounting, LLC.
+       Released under the terms of the GNU General Public License, GPL, 
+       as published by the Free Software Foundation, either version 3 
+       of the License, or (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+    See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
+***********************************************************************/
+include_once($path_to_root. "/includes/archive.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       
+//
+class package extends gzip_file {
+       function package($filename, $basedir=null)
+       {
+               global $path_to_root;
+
+               if (!$basedir) {
+                       $basedir = PKG_CACHE_PATH.'/'.substr(basename($filename), 0, -4);
+                       if (file_exists($basedir)) {
+//                             flush_dir($basedir, true); 
+                       } else
+                       mkdir($basedir);
+               }
+               $this->archive($filename);
+               $this->set_options(array('basedir'=> $basedir));
+               $this->options['type'] = "pkg";
+       }
+       //
+       //      Used by archive class. Use create_archive() instead.
+       //      
+       function create_pkg() 
+       {
+               return $this->create_gzip();
+       }
+       //
+       //      Install package and clean temp directory.
+       //
+       function install()
+       {
+               global $path_to_root;
+               
+               $success = true;
+
+               $this->set_options(array('overwrite' => 1));
+               $this->extract_files(); // extract package in cache directory
+               $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))
+                       mkdir($targetdir);
+
+               $dpackage = new package("$cachepath/_data", $targetdir);
+               $dpackage->set_options(array('overwrite' => 1));
+
+               $flist = $dpackage->extract_files(true);
+               if (count($dpackage->error)) {
+                       $this->error = array_merge($this->error, $dpackage->error);
+                       return false;
+               }
+               copy_files($flist, $targetdir, "$cachepath/_back");
+       
+               $dpackage->extract_files(); //install package in target directory
+
+               $success &= $this->support('install');
+               $success &= count($dpackage->error) == 0;
+               $this->error = array_merge($this->error, $dpackage->error);
+               return $success;
+       }
+       //
+       //      Removing package related sources
+       //
+       function uninstall()
+       {
+               global $path_to_root;
+
+               $success = true;
+
+               $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);
+
+               $flist = $dpackage->extract_files(true);
+
+               $success &= copy_files($flist, "$cachepath/_back", $targetdir, true);
+
+               $success &= $this->support('uninstall');
+
+               return $success;
+       }
+       //
+       //      Purge all package related configuration and data.
+       //
+       function purge()
+       {
+               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 
+// arrays of subfields if needed.
+//
+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'),
+       );
+       if (!isset($sub_fields[$key]))
+               return $value==='' ? null : $value;
+
+       $prop = array();
+
+       if (!is_array($value))
+               $value = array($value);
+       foreach($value as $line) {
+               $indexes = $sub_fields[$key];
+               $ret = array();
+               preg_match_all('/(["])(?:\\\\?+.)*?\1|[^"\s][\S]*/', $line, $match);
+               foreach($match[0] as $n => $subf) {
+                       if ($match[1][$n])
+                               $val = strtr(substr($subf, 1, -1),
+                                       array('\\"'=>'"'));
+               else
+                               $val = $subf;
+                       if (count($indexes))
+                               $ret[array_shift($indexes)] = $val;
+                       else
+                               $ret[] = $val;
+               }
+               if (count($ret))
+                       $prop[] = $ret;
+       }
+       return $prop;
+}
+//=============================================================================
+//
+// Retrieve control file and return as associative array
+//     $index is name of field used as key in result array, or null for numeric keys
+//
+function get_control_file($file, $index = false) {
+
+       $list = gzopen($file, 'rb');
+       if (!$list) return null;
+
+       $repo = $pkg = array();
+       $key = false; $value = '';
+       $line = '';
+       do {
+               $line = rtrim($line);
+               if (@ctype_space($line[0])) { // continuation of multiline property
+                       if (strlen(ltrim($line))) {
+                               if ($value !== '' && !is_array($value))
+                                       $value = array($value);
+                               $value[] = ltrim($line);
+                               continue;
+                       }
+               }
+               if ($key) { // save previous property if any
+                       $pkg[$key] = ufmt_property($key, $value);
+               }
+               if (!strlen($line)) { // end of section
+                       if (count($pkg)) {
+                               if ($index !== true) {
+                                       if ($index === false) break;
+                                       if (!isset($pkg[$index])) {
+                                               display_error(_("No key field '$index' in file '$file'"));
+                                               return null;
+                                       }
+                                       $repo[$pkg[$index]] = $pkg;
+                               } else
+                                       $repo[] = $pkg;
+                       }
+                       $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)) {
+                               display_error("Empty key in line $line");
+                               return null;
+                       }
+               } else {
+                       display_error("File parse error in line $line");
+                       return null;
+               }
+               
+       } while ((($line = fgets($list))!==false) || $key);
+       fclose($list);
+
+       return $index === false ? $pkg : $repo;
+}
+//
+//     Save configuration data to control file.
+//
+function save_control_file($fname, $list, $zip=false) 
+{
+       $file = $zip ?  gzopen($fname, 'wb') : fopen($fname, 'wb');
+       foreach($list as $section) {
+               foreach($section as $key => $value) {
+                       if (is_array($value)) { // multiline value
+                               if (is_array(reset($value))) { // lines have subfields
+                                       foreach($value as $i => $line) {
+               // Subfields containing white spaces or double quotes are doublequoted 
+               // with " escaped with backslash.
+                                               foreach($line as $n => $subfield)
+                                                       if (preg_match('/[\s"]/', $subfield)) {
+                                                               $value[$i][$n] = 
+                                                                       '"'.strtr($subfield, array('"'=>'\\"')).'"';
+                                                       }
+                                               // Subfields are separated by white space.
+                                               $value[$i] = implode(' ', $value[$i]);
+                                       }
+                               }
+                               // array elements on subsequent lines starting with white space
+                               $value = //(count($value) ? "\n " :'').
+                                       implode("\n ", $value);
+                       }
+                       $zip ? gzwrite($file, "$key: $value\n") : fwrite($file, "$key: $value\n");
+               }
+               $zip ? gzwrite($file, "\n"): fwrite($file, "\n");
+       }
+       $zip ? gzclose($file) : fclose($file);
+}
+//
+//     Retrieve text field in localized version or default one 
+//     when the localized is not avaialable.
+//
+function pkg_prop($pkg, $property, $lang=false) 
+{
+       
+       if ($lang && isset($pkg[$property.'-'.user_language()]))
+               $prop = @$pkg[$pname];
+       else
+               $prop = @$pkg[$property];
+
+       return is_array($prop) ? implode("\n ",$prop): $prop;
+}
+//
+//     Retrieve list of packages from repository and return as table ($pkgname==null),
+//     or find $pkgname package in repository and optionaly download
+//
+//     $type is type/s of package
+//  $filter is optional field selection array in form field=>newkey
+//             or (0=>field1, 1=>field2...)
+//  $outkey - field used as a key in package list. If null 'Package' field is used.
+//
+function get_pkg_or_list($type = null, $pkgname = null, $filter=array(), $outkey=null, $download=true) {
+
+       global $path_to_root, $repository, $FA_repo_version;
+
+       // 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)) {
+               $type = array($type);
+       }
+       $refresh = true;
+       do{
+               if (!file_exists($loclist)) {
+                       copy(REPO_URL.'/Release.gz', $loclist);
+                       $refresh = false;
+               }
+               $sig = file_get_contents(REPO_URL.'/Release.sig', 'rb');
+               $data = file_get_contents($loclist);
+               $cert = file_get_contents(PUBKEY_PATH.'/FA.pem');
+               if (!openssl_verify($data, $sig, $cert)) {
+                       if ($refresh)
+                               @unlink($loclist);
+                       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();
+       foreach($Release as $fname => $parms) {
+               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) {
+                       display_warning(_('Repository version does not match application version.')); // ?
+               }
+               $remoteindex = REPO_URL.'/'.$fname;
+               $locindex = PKG_CACHE_PATH.'/'.$fname;
+               $refresh = true;
+               do{
+                       if (!file_exists($locindex)) { 
+                               copy($remoteindex, $locindex);
+                               $refresh = false;
+                       }
+                       if ($parms['SHA1sum'] != sha1_file($locindex)) {        // check subdir index consistency
+                               if ($refresh)
+                                       @unlink($locindex);
+                               else {
+                                       display_error(sprintf( _("Security alert: broken index file in repository '%s'. Please inform repository administrator about this issue."),
+                                               $fname));
+                                       return null;
+                               }
+                       } else
+                               $refresh = false;
+               } while($refresh);
+               
+                // 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)) {
+                               if (empty($filter))
+                                       $p = $pkg;
+                               else {
+                                       foreach($filter as $field => $key) {
+                                               if (is_numeric($field))
+                                                       $p[$field] = @$pkg[$field];
+                                               else
+                                                       $p[$key] = @$pkg[$field];
+                                       }
+                               }
+                               if ($pkgname == null) {
+                                       $Packages[$outkey ? $outkey : $name] = $p;
+                               } elseif ($pkgname == $pkg['Package']) {
+                                       //download package to temp directory
+                                       if ($download) {
+                                               $locname = "$path_to_root/tmp/".$pkg['Filename'].'.pkg';
+                                               copy($pkgfullname, $locname);
+                                                // checking sha1 hash is expensive proces, so chekc the package
+                                                // consistency just before downloading
+                                               if ($pkg['SHA1sum'] != sha1_file($locname)) {
+                                                       display_error(sprintf( _("Security alert: broken package '%s' in repository. Please inform repository administrator about this issue."),
+                                                               $pkgfullname));
+                                                       return null;
+                                               }
+                                       }
+                                       return $p;
+                               }
+                       }
+               }
+       }
+       
+       return $Packages;
+}
+
+function get_package($pkgname, $type = null)
+{
+       $all = get_pkg_or_list($type, $pkgname);
+       $pkg = array_search_value($all, $pkgname, 'Package');
+}
+/*
+       Returns full name of installed package, or null if package is not installed.
+*/
+function installed_package($package)
+{
+       $cache = opendir(PKG_CACHE_PATH);
+
+       while ($file = @readdir($cache)) {
+               if (!is_dir(PKG_CACHE_PATH.'/'.$file))
+                       continue;
+               if (strpos($file, $package.'-') === 0)
+                       return $file;
+       }
+       @closedir($cache);
+
+       return null;
+}
+/*
+       Remove package from system
+*/
+function uninstall_package($name)
+{
+       $name = installed_package($name);
+       if (!$name) return true; // not installed
+       $pkg = new package($name.'.pkg');
+       $pkg->uninstall();
+       if($name) {
+               flush_dir(PKG_CACHE_PATH.'/'.$name, true);
+               rmdir(PKG_CACHE_PATH.'/'.$name);
+       }
+       return count($pkg->error)==0;
+}
+
+//---------------------------------------------------------------------------------------
+//
+//     Return merged list of available and installed languages in inform of local 
+// configuration array supplemented with installed versions information.
+//
+function get_languages_list()
+{
+       global $installed_languages;
+       
+       $pkgs = get_pkg_or_list('language', null, array(
+                               'Package' => 'package',
+                               'Version' => 'available',
+                               'Name' => 'name',
+                               'Language' => 'code',
+                               'Encoding' => 'encoding',
+                               'RTLDir' => 'rtl',
+                               'Description' => 'Descr',
+                               'InstallPath' => 'path'
+                       ));
+
+       // add/update languages already installed
+       // 
+       foreach($installed_languages as $id => $l) {
+               $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]['local_id'] = $id;         // index in installed_languages
+                               continue 2;
+                       }
+               }
+               $l['local_id'] = $id;
+               if (!isset($pkgs[$l['package']]) || $l['package'] == '')
+                       $pkgs[] = $l;
+               else
+                       $pkgs[$l['package']] = array_merge($pkgs[$l['package']], $l);
+       }
+       ksort($pkgs);
+       return $pkgs;
+}
+//---------------------------------------------------------------------------------------
+//
+//     Return merged list of available and installed extensions in inform of local 
+// configuration array supplemented with installed versions information.
+//
+function get_extensions_list()
+{
+       $pkgs = get_pkg_or_list('extension', null, array(
+                               'Package' => 'package',
+                               'Version' => 'available',
+                               'Name' => 'name',
+                               'Description' => 'Descr',
+                               'Type' => 'type',
+                               'DefaultStatus'=> 'active',
+                               'MenuTabs' => 'tabs',
+                               'MenuEntries' => 'entries',
+                               'AccessExtensions' => 'acc_file',
+                               'InstallPath' => 'path'
+                       ));
+
+       // add/update extensions already installed
+       // 
+       $local = get_company_extensions();
+       foreach($local as $extno => $ext) {
+               if ($ext['type'] == 'theme') continue;
+               $ext['local_id'] = $extno;
+               if (!isset($pkgs[$ext['package']]) || $ext['package'] == '')
+                       $pkgs[] = $ext;
+               else
+                       $pkgs[$ext['package']] = array_merge($pkgs[$ext['package']], $ext);
+       }
+       ksort($pkgs);
+       return $pkgs;
+}
+//
+// Return merged list of available and installed extensions in inform of local
+// configuration array supplemented with installed versions information.
+//
+function get_themes_list()
+{
+       $pkgs = get_pkg_or_list('theme', null, array(
+                               'Package' => 'package',
+                               'Version' => 'available',
+                               'Name' => 'name',
+                               'Description' => 'Descr'
+                       ));
+
+       // add/update extensions already installed
+       // 
+       $local = get_company_extensions();
+       
+       foreach($local as $extno => $ext) {
+               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);
+       return $pkgs;
+}
+//---------------------------------------------------------------------------------------------
+//     Install/update package from repository
+//
+function install_language($pkg_name)
+{
+       global $path_to_root, $installed_languages, $Ajax;
+       
+       $pkg = get_pkg_or_list('language', $pkg_name);
+
+       if ($pkg) {
+               $i = array_search_key($pkg['Language'], $installed_languages, 'code');
+               if ($i === null)
+                       $i = count($installed_languages);
+               else {  // remove another already installed package for this language 
+                       $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');
+               if ($package->install()) {
+                       $lang = array(
+                               'name' => $pkg['Name'],
+                               'package' => $pkg['Package'],
+                               'code' => $pkg['Language'],
+                               'encoding' => $pkg['Encoding'],
+                               'version' => $pkg['Version'],
+                               'path' => $pkg['InstallPath']
+                       );
+                       if ($pkg['RTLDir']=='yes')
+                               $lang['rtl'] = true;
+                       $installed_languages[$i] = $lang;
+                       write_lang($installed_languages);
+                       unlink("$path_to_root/tmp/".$pkg['Filename'].'.pkg');
+                       $Ajax->activate('lang_tbl');
+               }
+
+       }
+
+}
+//---------------------------------------------------------------------------------------------
+//     Install/update extension or theme package from repository
+//
+function install_extension($pkg_name)
+{
+       global $path_to_root, $next_extension_id, $Ajax;
+       
+       $pkg = get_pkg_or_list(array('extension', 'theme'), $pkg_name);
+       if ($pkg) {
+               $package = new package("$path_to_root/tmp/".$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++;
+                       $ext = array(
+                               'name' => $pkg['Name'],
+                               'package' => $pkg['Package'],
+                               'version' => $pkg['Version'],
+                               'type' => $pkg['Type'],
+                               'active' => true,
+                               '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'];
+                       $local_exts[$ext_id] = $ext;
+                       update_extensions($local_exts);
+                       unlink("$path_to_root/tmp/".$pkg['Filename'].'.pkg');
+                       $Ajax->activate('ext_tbl');
+               } else {
+                       display_error(implode('<br>', $package->error));
+               }
+       }
+}
+/*
+       Returns true if newer package version is available
+*/
+function check_pkg_upgrade($current, $available)
+{
+       preg_match_all('/[\d]+/', $available, $aver);
+       if (!count($aver[0]))
+               return false;
+       preg_match_all('/[\d]+/', $current, $cver);
+       if (!count($cver[0]))
+               return true;
+       foreach($aver[0] as $n => $ver)
+               if ($ver>@$cver[0][$n]) 
+                       return true;
+       return false;
+}
+
+//
+//     Returns package info from index file
+//
+function get_package_info($pkg, $type=null, $filter=array(), $outkey=null, $download=true) {
+       return get_pkg_or_list($type, $pkg, $filter, null, false);
+}
+
+?>
\ No newline at end of file
index 54315e2cb306fe53f8c283955e7ca77092679e15..43b7fd8146230ac77e6e2c8ba9ba6b68932bc2f1 100644 (file)
@@ -217,7 +217,6 @@ function viewer_link($label, $url='', $class='', $id='',  $icon=null)
        }
        else
                $preview_str = $label;
-
  return $preview_str;
 }
 
index cce5b51d7cfd4c2119517cce3e2d4592a3e2f677..69a4e556b2ab700e503f7b5e273dfd14b8569e58 100644 (file)
@@ -201,6 +201,19 @@ function get_journal_trans_view_str($type, $trans_no, $label="", $icon=false,
        return viewer_link($label, $viewer, $class, $id,  $icon);
 }
 
+//--------------------------------------------------------------------------------------
+
+function get_package_view_str($pkg, $label="", $icon=false, $class='', $id='')
+{
+       if ($label == "")
+       {
+               $label = _("Info");
+//             $icon = ICON_GL;
+       }
+       return viewer_link($label, "includes/ui/view_package.php?id=$pkg", $class, $id, $icon);
+}
+
+
 //--------------------------------------------------------------------------------------
 
 function get_trans_view_str($type, $trans_no, $label="", $icon=false, 
diff --git a/includes/ui/view_package.php b/includes/ui/view_package.php
new file mode 100644 (file)
index 0000000..9c8022c
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+$page_security = 'SA_OPEN';
+$path_to_root = "../..";
+include_once($path_to_root . "/includes/session.inc");
+include_once($path_to_root . "/includes/packages.inc");
+
+page(_($help_context = "Package Details"), true);
+
+include_once($path_to_root . "/includes/ui.inc");
+
+if (!isset($_GET['id'])) 
+{
+       /*Script was not passed the correct parameters */
+       display_note(_("The script must be called with a valid package id to review the info for."));
+       end_page();
+}
+
+$filter = array(
+       'Version' => _('Available version'), 
+       'Type' => _('Package type'), 
+       'Name' => _('Package content'),
+       'Description' => _('Description'), 
+       'Author' => _('Author'), 
+       'Homepage' => _('Home page'),
+       'Maintenance' => _('Package maintainer'),
+       'InstallPath' => _('Installation path'),
+       'Depends' => _('Minimal software versions'),
+       'RTLDir' => _('Right to left'),
+       'Encoding' => _('Charset encoding')
+);
+
+$pkg = get_package_info($_GET['id'], null, $filter);
+
+display_heading(sprintf(_("Content information for package '%s'"), $_GET['id']));
+br();
+start_table(TABLESTYLE2, "width=80%");
+$th = array(_("Property"), _("Value"));
+table_header($th);
+
+foreach ($pkg as $field => $value) {
+       if ($value == '')
+               continue;
+       start_row();
+       label_cells($field, htmlentities(is_array($value) ? implode('<br>', $value) :$value),
+                "class='tableheader2'");
+       end_row();
+}
+end_table();
+
+end_page();
diff --git a/modules/_cache/index.php b/modules/_cache/index.php
new file mode 100644 (file)
index 0000000..763940a
--- /dev/null
@@ -0,0 +1,3 @@
+<?php
+header("Location: ../index.php");
+?>