campo-sirio/ba/ba1700.cpp
luca ea9a22d88c Patch level :10.0 68
Files correlati     :
Ricompilazione Demo : [ ]
Commento            :sistemato il problema del rilancio di setup.exe quando si aggiornava via web da un'area test in cui non trovava la cartella setup


git-svn-id: svn://10.65.10.50/trunk@16783 c028cbd2-c16b-5b4b-a496-9718f37d4682
2008-06-19 10:00:05 +00:00

1707 lines
49 KiB
C++
Executable File
Raw Blame History

#include <agasys.h>
#include <applicat.h>
#include <dongle.h>
#include <execp.h>
#include <isamrpc.h>
#include <modaut.h>
#include <prefix.h>
#include <progind.h>
#include <sheet.h>
#include <statbar.h>
#include <urldefid.h>
#include <utility.h>
#include "ba1.h"
#include "ba1500.h"
#include "ba1600.h"
#include "ba1700a.h"
// definizioni delle colonne dello sheet
#define C_MODULE 1
#define C_CODE 2
#define C_RELEASE 3
#define C_PATCH 4
#define C_DATAREL 5
#define C_CURRRELEASE 6
#define C_CURRPATCH 7
#define C_CURRDATAREL 8
#define C_ISPATCH 9
#define C_BASEPATCH 10
///////////////////////////////////////////////////////
// Metodi di utility
///////////////////////////////////////////////////////
HIDDEN const char* http_default_path()
{
//da compilare in base al producer!
return "www.aga.it/agarel100/";
}
HIDDEN int compare_version(const char* v1, int p1, const char* v2, int p2)
{
TString16 ver1(v1), ver2(v2);
ver1.trim();
ver1.ltrim(ver1.len() == 4 ? 2 : 4);
ver2.trim();
ver2.ltrim(ver2.len() == 4 ? 2 : 4);
int res = ver1.compare(ver2, -1, TRUE);
if (res == 0)
res = p1 - p2;
return res;
}
HIDDEN word version2year(const char* v)
{
TString16 ver(v);
if (ver.len() == 4)
ver.insert((v[0] == '9') ? "19" : "20", 0);
ver.cut(4);
return atoi(ver);
}
static int compare_modules(const TObject** o1, const TObject** o2)
{
TToken_string& ts1 = *(TToken_string*)(*o1);
TToken_string& ts2 = *(TToken_string*)(*o2);
int res = 0;
for (int i = 2; i < 5 && res == 0; i++)
{
TString16 s1 = ts1.get(i);
const char* s2 = ts2.get(i);
res = s1.compare(s2);
}
return res;
}
bool is_internet_path(const TString& addr)
{
if (addr.starts_with("www.", true) || addr.starts_with("http:", true))
return true;
int a1, a2, a3, a4;
if (sscanf(addr, "%d.%d.%d.%d", &a1, &a2, &a3, &a4) == 4)
return true;
return false;
}
///////////////////////////////////////////////////////////
// Maschera principale
///////////////////////////////////////////////////////////
class TInstaller_mask : public TArray_sheet
{
static TInstaller_mask* _curr_mask;
int _station_type; //intero che definisce il tipo di installazione (1=std,2=server,3=client)
bool _installed; // Flag per verificare se almeno un modulo e' stato installato
bool _setup_run; //Flag che indica se e' stato lanciato il programma setup.exe
enum { NONE=0, NEW_MENU=1,
NEW_MENUPRG=2, NEW_INSTALLER=4, NEW_DLL=8, NEW_SYS=14,
NEW_TRR=16 };
int _reboot_program;
protected: // TSheet
virtual bool on_key(KEY key);
static bool tutti_handler(TMask_field& f, KEY k);
int get_module_number(const TString& module) const;
bool has_module(int modnumber) const;
bool is_zip_file(const TFilename& n) const;
void create_dirs(const char* path) const;
bool copy_tree(const char* src_study, const char* dst_study) const;
int test_station_type() const;
protected:
static bool path_handler(TMask_field& fld, KEY key);
static bool web_handler(TMask_field& fld, KEY key);
static bool sheet_notify(TSheet_field& s, int r, KEY k);
static bool install_handler(TMask_field& fld, KEY key);
static bool update_handler(TMask_field& f, KEY k);
bool add_module(TConfig& ini, const TString& module, bool patch, int pos=-1);
bool add_header(TConfig& ini, const TString& module);
int precheck_modules(bool only_newer=true);
void update_version();
int needs_reboot(const TFilename& file) const;
bool move_file(const TFilename& src, const TFilename& dst) const;
bool move_module(const TString& module, TInstall_ini& ini, bool update) const;
bool can_install(const char* module, TInstall_ini& ini);
void install_selection();
bool install_patches(const TString& module, const TString& lastrelease, int lastpatch , bool onlynew=true);
KEY askdisk(TString & path, TFilename & cmdline, int d, int dischi, const char * modulo);
bool do_process(TToken_string& commands) const;
bool pre_process(TInstall_ini& ini, const char* module) const;
bool post_process(TInstall_ini& ini, const char* module) const;
bool get_patches_path(TFilename& path) const;
void parse_internet_path(TString& http_server, TFilename& http_path) const;
public:
bool installed() const { return _installed;}
bool setup_run() const { return _setup_run; }
int station_type() const {return _station_type;}
bool autoload();
bool install(const TString& module, int patch);
void backup() const;
bool run_conversion() const
{ return installed() && (_reboot_program & NEW_TRR) != 0; }
TInstaller_mask();
virtual ~TInstaller_mask();
};
TInstaller_mask* TInstaller_mask::_curr_mask = NULL;
// Copia nello sheet i dati di un modulo prendendoli da un .ini
bool TInstaller_mask::add_module(TConfig& ini, const TString& module, bool patch, int pos)
{
ini.write_protect();
if (!ini.set_paragraph(module))
return false;
// Nasconde i moduli Enterprise Edition ad occhi indiscreti
const bool ee = ini.get_bool("Ee");
if (ee && !dongle().active(EEAUT))
return false;
const int numpatch = ini.get_int("Patch");
TString4 strpatch;
if (numpatch > 0)
strpatch.format("%04d", numpatch);
TToken_string row;
row = " "; // Not selected
row.add(ini.get("Descrizione"));
row.add(module);
row.add(ini.get("Versione"));
row.add(strpatch);
row.add(ini.get("Data"));
row.add(patch ? "X" : " ", C_ISPATCH);
if (pos==-1)
add(row);
else
insert(row,pos);
return true;
}
// Copia nello sheet l'intestazione di un modulo prendendola da un .ini
bool TInstaller_mask::add_header(TConfig& ini, const TString& module)
{
ini.write_protect();
bool ok = ini.set_paragraph(module);
if (ok)
{
TToken_string row;
row = " "; // Not selected
row.add(ini.get("Descrizione"));
row.add(ini.get(" "));
enable_row(add(row),false);
}
return ok;
}
bool TInstaller_mask::has_module(int modnumber) const
{
//se sei un server hai tutti i moduli da installare
if (station_type() == 2)
return true;
//senno' sei sfigato e ti installa solo i moduli sulla chiave
return main_app().has_module(modnumber, CHK_DONGLE);
}
//che tipo di installazione e'?
int TInstaller_mask::test_station_type() const
{
TConfig ini(CONFIG_INSTALL, "Main");
int type = ini.get_int("Type");
//se type non e' definito nei valori giusti (1=standard,2=server,3=client)
if (type < 1 || type > 3)
{
const bool testdb = ini.get_bool("TestDatabase");
const bool testprg = ini.get_bool("TestPrograms");
if (testdb)
{
if (dongle().hardware() == _dongle_network) //se usa un server di chiavi->server
type = 2;
else
type = 1;
}
else
type = 3;
ini.set("Type", type); //cosi' lo definisce se non c'e'
}
return type;
}
int TInstaller_mask::precheck_modules(bool only_newer)
{
TString16 release,currrelease;
TString4 cod_module;
int patchlevel,modnumber,currpatch;
bool check_enabled = true;
_setup_run = false; //inizializzazione del flag di controllo di lancio di setup.exe
TString_array& array = rows_array();
FOR_EACH_ARRAY_ROW(array, r, row)
{
TToken_string& rigar = *row;
cod_module = rigar.get(C_CODE);
release = rigar.get(C_RELEASE);
patchlevel = rigar.get_int(C_PATCH);
currrelease = rigar.get(C_CURRRELEASE);
currpatch = rigar.get_int(C_CURRPATCH);
modnumber = get_module_number(cod_module);
if (modnumber >= 0 && has_module(modnumber) &&
!release.blank() &&
((release > currrelease) ||
(release == currrelease && (only_newer ? patchlevel > currpatch : patchlevel >= currpatch) ))
)
{
// checca il modulo o la patch se ho installata la stessa versione
const bool chk = rigar.get_char(C_ISPATCH) != 'X' || release == currrelease;
if (check_enabled)
check(r, chk);
if (chk && only_newer && cod_module == "sy") //se viene checkato il modulo sy (sistema) deve togliere..
{ //..la possibilita' di installare altri moduli..
for (int i = 0; i < array.items(); i++)
disable_row(i); //disabilita tutte le righe dello sheet
disable(DLG_USER);
check_enabled = false; //..ed uscire
}
} //if(modnumber>=0...
} //FOR_EACH_ARRAY_ROW...
force_update(); // Indispensabile per vedere le righe aggiornate sullo sheet
return items();
}
int TInstaller_mask::get_module_number(const TString& module) const
{
int aut = -1;
bool ok = false;
if (module.full())
{
if (module == "ba" || module == "sy") //moduli base e sistema: deve ritornare 0;
return 0;
aut = dongle().module_name2code(module);
ok = aut < ENDAUT;
}
return ok ? aut : -1;
}
void TInstaller_mask::update_version()
{
TInstall_ini ini;
TString_array& array = rows_array();
FOR_EACH_ARRAY_ROW_BACK(array, m, row)
{
if (*row->get(C_CODE) != ' ')
{
const TString16 module = row->get(C_CODE);
ini.set_paragraph(module);
const TString16 newver = row->get(C_RELEASE);
const TString16 oldver = ini.get("Versione");
const int numpatch = ini.get_int("Patch");
TString16 strpatch;
if (numpatch > 0) strpatch.format("%04d", numpatch);
row->add(oldver, C_CURRRELEASE);
row->add(strpatch, C_CURRPATCH);
row->add(ini.get("Data"), C_CURRDATAREL);
}
}
force_update();
}
// Cerca nel percorso specificato sulla maschera tutti i possibili files .ini
// utilizzabili per un'installazione e li inserisce nello spreadsheet
bool TInstaller_mask::autoload()
{
TString_array& mask_rows = rows_array();
TString http_server;
TFilename http_path;
TFilename path;
TFilename ininame;
//controla se si e' scelto un path di installazione internet o da disco
const bool internet = get_patches_path(path);
//se e' un aggiornamento via internet...
if (internet)
{
parse_internet_path(http_server, http_path); //controlla il path internet scritto nel campo sulla maschera
make_dir(path); //crea la directory temporanaea di installazione dove depositare e scompattare gli zip
ininame = path;
ininame.add(TInstall_ini::default_name());
//se si ritrova dei vecchi .ini nella directory temporanea->pulisce la directory temporanea x evitare casini
if (ininame.exist()) //&& yesno_box(TR("Si desidera svuotare la cache dei files scaricati dal sito?"))) domanda del cazzo!
{
TString_array list;
TFilename name = path; name.add("*.*");
::list_files(name, list);
FOR_EACH_ARRAY_ROW(list, i, row)
::remove(*row);
}
if (!ininame.exist())
{
TFilename remote_ini = http_path;
remote_ini << TInstall_ini::default_name();
{
TIndwin contacting(60,TR("Connessione al server HTTP..."), false, false);
http_get(http_server, remote_ini, ininame);
}
}
} //if(internet...
if (path.exist())
{
ininame = path;
ininame.add(TInstall_ini::default_name());
}
else
return error_box(TR("Specificare un percorso valido"));
TWait_cursor hourglass;
destroy();
force_update();
TString_array modules;
TString producer;
//cerca sull'install.ini di origine se lo trova (ininame e' il path dell'install.ini remoto)
if (ininame.exist())
{
// Presente il file ini generale "install.ini" (moduli;immagine cd)
TInstall_ini ini(ininame);
//prende il producer dall'install.ini di origine installazione...non si sa mai che sia cambiato..
producer = ini.get("Producer", "Main");
ini.list_paragraphs(modules); //riempie modules con la lista dei paragrafi sul .ini ***
FOR_EACH_ARRAY_ROW(modules, i, row)
{
const TString& module = *row;
if (module[0] == '_' || module.len() == 2)
{
if (module[0] == '_')
add_header(ini, module);
else
{
TFilename mod_ini = ininame.path();
mod_ini.add(module);
mod_ini << "inst.ini";
//controlla se esiste il pacco zippato del modulo attraverso l'esistenza del file..
//..XXinst.ini
if (mod_ini.exist())
{
TInstall_ini moduleini(mod_ini);
add_module(moduleini, module, false);
}
else
add_module(ini, module, false);
}
} //if(module[0]...
} //FOR_EACH_ARRAY_ROW(...
}
else
{
// Presenti i singoli file .ini dei moduli (pacchi ma non patches!)
ininame = path;
ininame.add("??inst.ini");
list_files(ininame, modules); //ritorna la lista dei files presenti nel .ini della patch ***
FOR_EACH_ARRAY_ROW(modules, m, row)
{
TString& ininame = *row;
ininame.lower();
const int pos = ininame.find("inst.ini");
CHECKS(pos >= 2, "Invalid installation configuration: ", (const char*)ininame);
const TString4 module = ininame.mid(pos-2, 2);
TConfig ini(ininame, module);
add_module(ini, module, false);
}
}
modules.destroy();
if (internet) //internet patches
{
http_dir(http_server, http_path, modules);
for (int i = modules.last(); i >= 0; i--)
{
TString& str = modules.row(i);
if (str.match("??????A.INI") || str.match("??????a.ini"))
{
TFilename remote = http_path;
remote << str;
ininame = path;
ininame.add(str);
if (!ininame.exist() && !http_get(http_server, remote, ininame))
{
error_box(FR("Errore di trasferimento del file %s"), (const char*)remote);
modules.destroy(i);
}
str = ininame;
}
else
modules.destroy(i);
}
modules.pack();
}
else //normal patches
{
ininame = path;
ininame.add("??????a.ini");
list_files(ininame, modules);
}
if (modules.items() > 0) //ordina i moduli come sull'install.ini locale (per avere SY come primo
{ //modulo e via via gli altri)
TInstall_ini installini;
TString_array paragrafi;
TFilename file;
installini.list_paragraphs(paragrafi);
//settaggio del produttore sull'install.ini locale nel caso sia cambiato..
//..ovvero ad ogni nuova versione prassi..no partners..cioe' doubleone..volevo dire sirio..
if (producer.full())
installini.set("Producer", (const char*)producer, "Main");
FOR_EACH_ARRAY_ROW(modules, am, arow)
{
file = *arow;
file = file.name();
int pos = paragrafi.find(file.left(2));
if (pos <= 0)
pos = 10000+am;
TString8 str;
str.format("%05d", pos); //aggiunge un numero d'ordine sulla sinistra del nome del file..
arow->insert(str);
}
modules.sort(); //..cosi' che la sort (che ordina alfabeticamente) sistemi la lista moduli
FOR_EACH_ARRAY_ROW(modules, bm, brow) //rimette i nomi dei moduli a posto (toglie il numero d'ordine)
brow->ltrim(5);
}
//genera le righe dello sheet di installazione
FOR_EACH_ARRAY_ROW(modules, am, arow)
{
TString& ininame = *arow;
ininame.lower();
const int pos = ininame.find("a.ini");
CHECKS(pos >= 6, TR("Configurazione di installazione non valida: "), (const char*)ininame);
const TString16 module = ininame.mid(pos-6, 2);
TConfig ini(ininame, module);
ini.write_protect();
int r;
for (r = int(items()-1); r >=0; r--)
if (module == row(r).get(C_CODE))
break;
if (r >= 0)
{
const TString16 patchversion = ini.get("Versione");
const int patchlevel = ini.get_int("Patch");
TToken_string& row = mask_rows.row(r);
const TString16 release(row.get(C_RELEASE));
if (patchversion.mid(4) == release.mid(4) // se le versioni corrispondono ...
&& patchlevel > row.get_int(C_PATCH)) // ..e il patchlevel <20> superiore
{
TString16 patch; patch.format("%04d", patchlevel); //aggiunge zeri per avere 3 cifre sempre
if (*row.get(C_ISPATCH)<=' ') // se era un modulo ...
{
row.add("+", C_ISPATCH); // .....setta la presenza di patches
row.add(row.get(C_PATCH), C_BASEPATCH); // memorizza patch del modulo
}
row.add(patch, C_PATCH); // aggiorna il patchlevel mostrato per il modulo
if (release < patchversion)
row.add(patchversion, C_RELEASE);
}
}
else
add_module(ini, module, true);
}
update_version();
const bool ok = precheck_modules() > 0;
if (!ok)
error_box(FR("Non e' stato trovato nessun modulo da installare\nin %s"), (const char*)path);
return ok;
}
bool TInstaller_mask::do_process(TToken_string& commands) const
{
bool ok = true;
TFilename cmd;
for (const char* c = commands.get(0); c && ok; c = commands.get())
{
cmd = c;
if (!cmd.blank())
{
TWait_cursor hourglass;
TExternal_app app(cmd);
ok = app.run(false,3,true) == 0;
}
}
return ok;
}
bool TInstaller_mask::pre_process(TInstall_ini& ini, const char* module) const
{
TAuto_token_string commands(ini.get("PreProcess", module));
bool ok = do_process(commands);
return ok;
}
bool TInstaller_mask::post_process(TInstall_ini& ini, const char* module) const
{
TAuto_token_string commands(ini.get("PostProcess", module));
return do_process(commands);
}
bool TInstaller_mask::can_install(const char* module, TInstall_ini& ini)
{
TInstall_ini curini;
if (curini.demo() != ini.demo())
{
TString msg;
msg << TR("Attenzione: Non e' possibile installare la versione ");
msg << (ini.demo() ? TR("dimostrativa") : TR("normale"));
msg << TR(" nella cartella della versione ");
msg << (curini.demo() ? TR("dimostrativa") : TR("normale"));
return error_box(msg);
}
const TString& version = ini.version(module);
const word year = version2year(version);
if (year < 2007)
return error_box(FR("Il modulo '%s' non ha una versione valida."), module);
#ifndef _DEMO_
if (year > dongle().year_assist())
{
if (!update_assistance_year())
return false;
}
#endif
TAuto_token_string altri(ini.get("Moduli", module));
if (xvt_str_compare_ignoring_case(module, "sy") != 0) //SY e' indipendente dagli altri moduli
{
if (xvt_str_compare_ignoring_case(module, "ba") != 0 && altri.get_pos("ba") < 0)
altri.add("ba");
}
bool ok = true;
TString submodule;
for (const char* mod = altri.get(0); mod && ok; mod = altri.get())
{
submodule = mod;
if (submodule.len() == 2)
{
if (curini.get("Versione", submodule).empty())
{
TString msg;
msg.format(FR("L'installazione del modulo %s richiede la presenza del modulo %s."),
(const char*)module, (const char*)submodule);
msg << '\n' << TR("Si desidera procedere alla sua installazione?");
ok = yesno_box(msg);
if (ok)
ok = install(submodule, 0);
}
}
}
return ok;
}
int TInstaller_mask::needs_reboot(const TFilename& file) const
{
char fname[_MAX_FNAME], ext[_MAX_EXT];
xvt_fsys_parse_pathname(file, NULL, NULL, fname, ext, NULL);
int underscore = NONE;
if (xvt_str_compare_ignoring_case(ext, "exe") == 0)
{
if (xvt_str_compare_ignoring_case(fname, "ba0") == 0)
underscore = NEW_MENUPRG; else
if (xvt_str_compare_ignoring_case(fname, "ba1") == 0)
underscore = NEW_INSTALLER;
} else
if (xvt_str_compare_ignoring_case(ext, "dll") == 0)
underscore = NEW_DLL; else
if (xvt_str_compare_ignoring_case(ext, "men") == 0)
underscore = NEW_MENU; else
if (xvt_str_compare_ignoring_case(ext, "trr") == 0 || xvt_str_compare_ignoring_case(ext, "dir") == 0)
underscore = NEW_TRR;
return underscore;
}
// Controlla se un file puo' essere scompattato.
// Attenzione: dninst.zip e' un falso zip
bool TInstaller_mask::is_zip_file(const TFilename& n) const
{
bool yes = xvt_str_compare_ignoring_case(n.ext(), "zip") == 0 &&
xvt_str_compare_ignoring_case(n.name(), "dninst.zip") != 0;
return yes;
}
void TInstaller_mask::create_dirs(const char* path) const
{
TToken_string dirs(path, SLASH);
if (SLASH == '\\')
dirs.replace('/', SLASH);
else
dirs.replace('\\', SLASH);
// file contains non existent subdir specification ?
TFilename subdir;
for (int c=0; c < dirs.items()-1; c++)
{
subdir.add(dirs.get(c));
if (subdir.right(1) == ":" )
subdir << SLASH;
if (!subdir.exist() )
// build destination directory
make_dir(subdir);
}
}
// sposta il file dal direttorio temporaneo a quello passato come destinazione
bool TInstaller_mask::move_file(const TFilename& src, const TFilename& dst) const
{
TFilename dest = dst;
const int reboot = needs_reboot(dest);
if ((reboot & NEW_SYS)!=0 && dst.exist())
{
dest.rtrim(1);
dest << '_';
}
if (!dest.exist())
create_dirs(dest.path());
const bool is_zip = is_zip_file(src);
const long filesize = fsize(src) * (is_zip ? 4 : 1);
if (xvt_fsys_test_disk_free_space(dest.path(), filesize) == 0)
return error_box(TR("Lo spazio disponibile e' insufficiente!"));
const bool write_ok = ::fcopy(src, dest);
if (write_ok && is_zip)
aga_unzip(src, dest.path());
if (write_ok)
::remove(src);
if (write_ok)
{
(int&)_reboot_program |= reboot; // Skip const!
}
return write_ok;
}
bool TInstaller_mask::move_module(const TString& module, TInstall_ini& ini, bool update) const
{
bool ok = true;
TFilename tempdir; tempdir.tempdir();
const TString& destdir = get(F_CURPATH);
TString_array list;
ini.build_list(module, list);
FOR_EACH_ARRAY_ROW(list, f, file)
{
TFilename src = tempdir;
src.add(file->get(0));
if (update)
{
TFilename dst = destdir;
dst.add(file->get(0));
const bool move_ok = move_file(src, dst);
if (!move_ok)
ok = update = false;
}
if (!update)
::remove(src);
}
return ok;
}
bool TInstaller_mask::copy_tree(const char* src_study, const char* dst_study) const
{
xvt_fsys_save_dir();
TFilename mask(src_study); mask.add("*.");
SLIST dlist = xvt_fsys_list_files(DIR_TYPE, mask, TRUE);
xvt_fsys_restore_dir();
TProgind pd(xvt_slist_count(dlist), TR("Copia cartelle"), true, true);
TString msg; // Messaggio di progresso
bool go_on = true;
for (SLIST_ELT d = xvt_slist_get_first(dlist); d && go_on; d = xvt_slist_get_next(dlist, d))
{
if (!pd.addstatus(1))
{
go_on = false;
break;
}
const TFilename dir = xvt_slist_get(dlist, d, NULL);
TString name = dir.name(); name.lower();
if (name == "cesp")
continue;
msg.cut(0) << TR("Copia di ") << name;
pd.set_text(msg);
mask = dir; mask.add("*.*");
TString_array files; list_files(mask, files);
TProgind pi(files.items(), "Copia file", true, true);
TFilename dst;
FOR_EACH_ARRAY_ROW(files, i, f)
{
if (!pi.addstatus(1))
{
go_on = false;
break;
}
TFilename src(*f);
TString16 ext(src.ext()); ext.lower();
if (ext != "zip" && ext != "rar" && ext != "mdb" && ext != "inf")
{
msg.cut(0) << TR("Copia di ") << src;
pi.set_text(msg);
dst = dst_study;
dst.add(name);
dst.add(src.name());
create_dirs(dst);
fcopy(src, dst);
}
}
}
xvt_slist_destroy(dlist);
return go_on;
}
void TInstaller_mask::backup() const
{
TFilename src = firm2dir(-1);
if (!isalnum(src.right(1)[0]))
src.rtrim(1);
TFilename dst(src);
dst << ' ' << TDate(TODAY).date2ansi(); // Lo spazio rende inutilizzabile lo studio
TToken_string msg(256, '\n');
msg.add(TR("Si consiglia creare una copia dello studio ")); msg << src.name();
msg.add(TR("nella cartella ")); msg << dst;
msg.add(TR("L'operazione potrebbe richiedere alcuni minuti."));
msg.add("");
msg.add(TR("Si desidera effetture la copia?"));
if (yesno_box(msg))
copy_tree(src, dst);
}
KEY TInstaller_mask::askdisk(TString & path, TFilename & cmdline, int d, int dischi, const char * modulo)
{
TMask retry_mask(TR("Inserimento disco"),1,80,10);
retry_mask.add_static((F_PATH==101 ? 102:101),0,
format(FR("Inserire il disco %d di %d del modulo '%s' nell'unit<69>"), d, dischi, modulo)
,2,2);
retry_mask.add_static(F_PATH+3,0,TR("oppure indicare un percorso diverso"),2,3);
retry_mask.add_string(F_PATH,0,"",2,5,48);
retry_mask.add_button(DLG_OK,0,TR("Riprova"),-12,7,9,2);
retry_mask.add_button(DLG_QUIT,0,"",-22,7,9,2);
retry_mask.set(F_PATH,path);
KEY k;
do {
if ((k=retry_mask.run())==K_QUIT )
break;
if (!retry_mask.get(F_PATH).blank())
{
if (fexist(retry_mask.get(F_PATH)))
{
TString16 tmpname(cmdline.name() );
cmdline= path = retry_mask.get(F_PATH);
cmdline.add(tmpname);
break;
}
else
error_box(TR("Il percorso indicato non e' valido"));
}
} while (true);
return k;
}
bool TInstaller_mask::install(const TString& module, int patchlevel)
{
bool cancelled = false;
bool ok = false;
TString msg; // stringa per i messaggi
TString16 lastrelease; // release che sto installando
int lastpatch=patchlevel; // patchlevel che sto installando
TFilename path ;
TString http_server;
TFilename http_path;
const bool internet = get_patches_path(path);
if (internet)
parse_internet_path(http_server,http_path );
const bool is_a_patch = (patchlevel > 0);
TFilename ininame = path;
ininame.add(module);
if (is_a_patch)
{
TString16 name;
name.format("%04da.ini", patchlevel);
ininame << name;
}
else
ininame << "inst.ini";
if (internet && !ininame.exist())
{
TFilename remote = ininame.name();
remote.insert(http_path, 0);
http_get(http_server, remote, ininame);
}
if (ininame.exist())
{
// esiste un particolare .ini con formato XXinst.ini (moduli) o con XX9999a.ini (patch)
// (installazione da directory con .zip)
TInstall_ini* ini = new TInstall_ini(ininame);
ini->write_protect();
lastpatch=ini->get_int("Patch",module);
lastrelease=ini->get("Versione",module);
if (!can_install(module, *ini))
{
delete ini;
return false;
}
const int dischi = ini->get_int("Dischi", module);
ok = dischi > 0;
if (!ok)
return error_box(FR("Impossibile determinare il numero dei dischetti in %s"),ininame.name());
else
{
if (patchlevel==0)
ok = pre_process(*ini, module);
if (!ok)
{
delete ini;
return false;
}
}
// ==============
// decompressione
msg = TR("Decompressione");
if (is_a_patch)
msg << TR(" della patch ") << patchlevel ;
msg << TR(" del modulo '") << module << TR("' in corso...");
TProgind pi(dischi, msg, false, true);
TFilename tempdir; tempdir.tempdir();
// File tottale dei vari sotto-zip
TFilename totti = tempdir; totti.add(module); totti.ext("zip");
for (int d = 1; d <= dischi && ok; d++)
{
TFilename chunk = path;
chunk.add(module);
if (patchlevel > 0)
{
TString16 name;
name.format("%04da", patchlevel);
chunk << name;
}
else
chunk << "inst";
chunk << d << ".zip";
if (internet && !chunk.exist())
{
TFilename remote = chunk.name();
remote.insert(http_path, 0);
if (!http_get(http_server, remote, chunk))
error_box(FR("Errore di trasferimento del file '%s'"), (const char*)remote);
}
ok = chunk.exist();
if (!ok && !internet) // Chiedi cambio disco (solo se non sta scaricando da internet)
{
while (!ok)
{
if (askdisk(path,chunk,d,dischi,(const char*)ini->get("Descrizione"))==K_QUIT)
break;
ok = chunk.exist();
if (!ok)
message_box(FR("Impossibile trovare il file '%s'"),(const char*)chunk);
}
}
if (ok)
{
const long required = fsize(chunk) * (dischi-d+1) * 4;
if (!xvt_fsys_test_disk_free_space(tempdir, required))
{
ok = yesno_box(TR("Lo spazio su disco potrebbe essere insufficiente:\nSi desidera continuare ugualmente?"));
}
}
if (ok)
::fcopy(chunk, totti, d > 1); // Somma il chunk al totale
}
aga_unzip(totti, tempdir); // Scompatta il file totale
::remove(totti);
// =============
// trasferimento
if (ok)
{
// si assicura che sia leggibile il .ini del primo disco
do
{
TFilename cmdline = path;
cmdline.add(ininame.name());
ok = cmdline.exist();
if (!ok)
{
if (askdisk(path,cmdline,1,dischi,(const char*)ini->get("Descrizione"))==K_QUIT)
break;
ok = fexist(cmdline);
if (!ok)
message_box(FR("Impossibile trovare %s\n"),(const char*)cmdline);
else
{
delete ini;
ini = new TInstall_ini (cmdline);
}
}
} while (!ok);
if (ok)
{
msg.cut(0);
msg << TR("Aggiornamento del modulo '") << module << TR("' in corso...");
pi.set_text(msg);
ok = move_module(module, *ini, true);
if (ok)
{
TAuto_token_string altri(ini->get("Moduli", module));
FOR_EACH_TOKEN(altri, mod)
{
const TString16 submod = mod;
if (submod.len() > 2) // sposta sottomoduli esterni
{
bool upd = ok;
if (ok)
{
TInstall_ini curini;
const TString16 curver = curini.version(submod);
const int curpatch = curini.patch(submod);
const TString16 reqver = ini->version(submod);
const int reqpatch = ini->patch(submod);
int distance = compare_version(reqver, reqpatch, curver, curpatch);
upd = distance > 0;
}
ok &= move_module(submod, *ini, upd);
if (upd && ok) // marca sull'install.ini di destinazione l'avvenuta installazione del sottomodulo "esterno"
ini->export_paragraph(submod, ini->default_name(), !is_a_patch);
}
}
}
if (ok) //rimozione files da eliminare indicati nel .ini
{
TString killmod;
killmod << module << 99;
if (ini->set_paragraph(killmod))
{
TToken_string rigaini;
TFilename filetokill;
for (int k=0; ;k++)
{
rigaini = ini->get("Kill", NULL, k, "");
if (rigaini.empty())
break;
filetokill = rigaini.get(0);
if (filetokill.find('*') >= 0 || filetokill.find('?') >=0)
{
TString_array filelist;
list_files (filetokill, filelist);
FOR_EACH_ARRAY_ROW(filelist, r, file)
{
::remove_file((const char *)file);
}
}
else
::remove_file(filetokill);
}
}
}
}
}
if (ok) // marca sull'install.ini di destinazione l'avvenuta installazione del modulo
ini->export_module_paragraphs(module, ini->default_name(),!is_a_patch);
} // installazione da directory con zip
else
if (!is_a_patch)
{
//
// non c'e' il .ini del modulo ma un unico "install.ini"
// (installazione da directory con eseguibili)
ininame = path;
ininame.add(TInstall_ini::default_name());
ok = fexist(ininame);
if (ok)
{
TInstall_ini ini(ininame);
ini.write_protect();
lastpatch=ini.get_int("Patch",module);
lastrelease=ini.get("Versione",module);
if (!can_install(module, ini))
return false;
TString_array list;
const int files = ini.build_complete_list(module, list);
if (files > 0)
{
if (patchlevel==0)
ok = pre_process(ini, module);
if (ok)
{
msg.cut(0) << TR("Copia del modulo ") << module;
TProgind pi(files, msg, true, true);
TFilename src, dst;
for (int f = 0; f < files && ok; f++)
{
pi.addstatus(1);
dst = list.row(f).get(0);
dst.lower();
src = path;
src.add(dst);
const int reboot = needs_reboot(dst);
if ((reboot & NEW_SYS)!=0 && dst.exist())
{
dst.rtrim(1);
dst << '_';
}
if (!dst.exist())
create_dirs(dst.path());
ok = ::fcopy(src, dst);
if (ok && is_zip_file(src))
aga_unzip(src, dst.path());
if (ok && reboot != NONE)
_reboot_program |= reboot;
cancelled = pi.iscancelled();
}
ok &= !cancelled;
}
if (ok) // marca sull'install.ini di destinazione l'avvenuta installazione del modulo
ini.export_module_paragraphs(module, ini.default_name(),true);
} // controllo esistenza lista di file non vuota per questo modulo
} // controllo esistenza install.ini
} // fine installazione da directory con eseguibili
if (ok)
{
{
TInstall_ini ini;
ini.set("DiskPath", get(F_PATH));
ini.set("WebPath", get(F_WEB));
ini.set("Data", TDate(TODAY), module);
ini.update_prices(ininame);
}
// Non togliere le parentesi graffe soprastanti per permettere l'aggiornamento fisico del .ini (CON LA CHIAMATA DEL DISTRUTTORE)
update_version();
}
if (ok && patchlevel == 0) // Se installo un modulo pricipale ...
{
// ... installo DOPO tutte le patches successive
install_patches(module, lastrelease, lastpatch);
TInstall_ini ini;
ok &= post_process(ini, module);
}
return ok;
}
bool TInstaller_mask::get_patches_path(TFilename& path) const
{
const TEdit_field& www = efield(F_WEB);
path = get(F_WEB);
if (www.active() && path.full() && is_internet_path(path))
{
path.tempdir();
path.add("www");
return true;
}
else
path = get(F_PATH);
return false;
}
void TInstaller_mask::parse_internet_path(TString & http_server, TFilename &http_path) const
{
http_server = get(F_WEB);
if (http_server.blank())
{
http_server = http_default_path();
((TMask*)this)->set(F_WEB, http_server);
}
if (http_server.compare("http://", 7, true) == 0)
http_server.ltrim(7);
const int slash = http_server.find('/');
if (slash > 0)
{
http_path = http_server.mid(slash);
http_server.cut(slash);
}
//aggiunge lo slash finale se l'utonto l'ha omesso
if (!http_path.ends_with("/"))
http_path << '/';
//e' un server redirezionato?
http_isredirected_server(http_server, http_path);
}
bool TInstaller_mask::install_patches(const TString& module, const TString& lastrelease, int lastpatch, bool only_newer)
{
bool ok = true;
TString_array modules;
TFilename ininame;
get_patches_path(ininame);
ininame.add(module);
ininame << "????a.ini";
modules.destroy();
list_files(ininame, modules);
modules.sort();
FOR_EACH_ARRAY_ROW(modules, am, arow)
{
TString& ininame = *arow;
ininame.lower();
const int pos = ininame.find("a.ini");
CHECKS(pos >= 6, "Invalid installation configuration: ", (const char*)ininame);
const TString16 patchmodule = ininame.mid(pos-6, 2);
TConfig ini(ininame, patchmodule);
const int patchlevel = ini.get_int("Patch");
const TString16 patchversion = ini.get("Versione");
if (ok && lastrelease.mid(4) == patchversion.mid(4) // installa solo le patch della stessa ver..
&& (only_newer ? lastpatch < patchlevel : lastpatch <= patchlevel)) // ... e patch superiore o uguale (reinstalla l'ultima patch)
ok = install(module, patchlevel);
}
return ok;
}
bool TInstaller_mask::update_handler(TMask_field& f, KEY k)
{
if (k == K_SPACE)
{
TInstaller_mask& m = (TInstaller_mask&)f.mask();
m.autoload();
}
return true;
}
bool TInstaller_mask::path_handler(TMask_field& fld, KEY key)
{
bool ok = true;
if (key == K_TAB && fld.focusdirty())
{
TFilename path = fld.get();
if (path.not_empty())
{
if (path.len() == 2 && isalpha(path[0]) && path[1] == ':')
{
path << SLASH;
fld.set(path);
}
if (path.exist() || ::is_internet_path(path))
_curr_mask->autoload();
else
ok = fld.error_box(TR("Specificare un percorso valido"));
}
}
return ok;
}
bool TInstaller_mask::web_handler(TMask_field& fld, KEY key)
{
bool ok = true;
if (key == K_TAB && fld.focusdirty())
{
TFilename path = fld.get();
if (path.not_empty())
{
if (!path.ends_with("/"))
{
path << '/';
fld.set(path);
}
ok = ::is_internet_path(path);
if (!ok)
ok = fld.error_box(TR("Specificare un indirizzo valido"));
}
}
return ok;
}
void TInstaller_mask::install_selection()
{
TString_array& arr = rows_array();
int nModules = 0;
{
FOR_EACH_ARRAY_ROW(arr, r, row)
{
if (checked(r))
nModules++;
}
}
TProgind pi(nModules, "Installazione", true, true);
FOR_EACH_ARRAY_ROW(arr, r, row) if (checked(r))
{
if (!pi.addstatus(1))
break;
const TString newver = row->get(C_RELEASE);
if (newver.blank())
{
check(r, false);
continue;
}
const TString4 modulo = row->get(C_CODE);
const int newpatch = row->get_int(C_PATCH);
const TString oldver = row->get(C_CURRRELEASE);
const int oldpatch = row->get_int(C_CURRPATCH);
pi.set_text(format(FR("Installazione modulo '%s'"), (const char*)modulo));
if (version2year(newver) < 2006)
{
error_box(FR("Il modulo '%s' non ha una versione valida."), (const char*)modulo);
continue;
}
bool ok = true;
bool is_patch = row->get_char(C_ISPATCH) == 'X';
bool has_patch = row->get_char(C_ISPATCH) == '+';
const int cmp = compare_version(oldver, oldpatch, newver, newpatch);
//versione e patch coincidono
if (cmp == 0)
ok = noyes_box(FR("Si desidera reinstallare la versione %s.%d del modulo '%s' ?"), (const char*)newver, newpatch, (const char*)modulo);
//ci sono ANCHE i pacchi
if (!is_patch && cmp > 0)
{
TString256 msg;
msg.format(FR("Si desidera ritornare alla versione %s.%d del modulo '%s' ?\nAttenzione: non e' garantito il corretto\nfunzionamento di tutti i programmi!"), (const char*)newver, newpatch, (const char*)modulo);
ok = noyes_box(msg);
}
//ci sono SOLO patch da installare
if (ok && is_patch)
{
// installo le patch solo se esiste gi<67> un modulo installato della stessa versione
if (!oldver.blank() )
{
if (compare_version(oldver, 0, newver, 0)) //controlla SOLO la versione indipendentemente dall'anno!
ok = error_box(FR("Il modulo '%s' installato ha versione %s:\nimpossibile installare le patch della versione %s"),(const char *)modulo,(const char *)oldver,(const char *)newver);
} else
if (newpatch < oldpatch)
{
TString256 msg;
msg.format(FR("Si desidera ritornare alla patch %s.%d del modulo '%s' ?\nAttenzione: non e' garantito il corretto\nfunzionamento di tutti i programmi!"), (const char*)newver, newpatch, (const char*)modulo);
ok = noyes_box(msg);
}
} //if(ok&&is_patch...
if (ok)
{
if (has_patch)
{
if (newver == oldver && newpatch >= oldpatch)
{
const int basepatch = row->get_int(C_BASEPATCH);
if (oldpatch >= basepatch)
is_patch = !noyes_box(FR("Si desidera reinstallare l'intero modulo '%s'?"
"\nRispondendo NO verranno installate le sole patch"),
(const char *)modulo);
else
is_patch = false; // Quando la versione installata precede la patch base devo reinstallare il modulo!
}
}
TFilename path;
const bool internet = get_patches_path(path);
//richiesto aggiornamento da disco del modulo SY o del modulo SR da manutenzione/installazione moduli!
if (modulo == "sy" || modulo == "sr")
{
if (!internet)
{
bool file_copied = false;
//trova il path della directory setup che e' nell'area con gli zip del cd
TFilename disk_path = path;
disk_path.add("setup/");
TString_array ar;
const int items = disk_path.exist() ? list_files(disk_path, ar) : 0;
if (items > 0)
{
//copia la dir setup dal disco sovrascrivendo eventuali files gia' presenti
make_dir("setup");
TFilename local_file, remote_file;
FOR_EACH_ARRAY_ROW(ar, r, row)
{
local_file = row->mid(path.len() + 1);
remote_file = *row;
file_copied = fcopy(remote_file, local_file); //occhio alle maiuscole!!!!
}
}
//aggiorna l'install.ini con eventuali modifiche dell'utente (decisivo in caso di cambio path..
//..di installazione)
{
TInstall_ini ini;
ini.set("DiskPath", get(F_PATH));
ini.set("WebPath", get(F_WEB));
}
//lancia setup in modalita' aggiornamento da disco
_setup_run = xvt_sys_execute("setup\\setup.exe -ud", false, false) !=0;
}
//richiesto aggiornamento via web del modulo SY da manutenzione/installazione moduli!
else
{
bool file_copied = false;
//trova l'indirizzo web completo
TString http_server;
TFilename http_path;
parse_internet_path(http_server, http_path);
//copia la dir setup dalla remote dir sovrascrivendo eventuali files gia' presenti
http_path.add("setup/");
TString_array ar;
http_dir(http_server, http_path, ar);
if (ar.items() > 0)
{
make_dir("setup");
TFilename local_file, remote_file;
FOR_EACH_ARRAY_ROW(ar, r, row)
{
local_file = "setup";
local_file.add(*row);
remote_file = http_path;
remote_file.add(*row);
file_copied = http_get(http_server, remote_file, local_file); //occhio alle maiuscole!!!!
}
//aggiorna l'install.ini con eventuali modifiche dell'utente (decisivo in caso di cambio path..
//..di installazione)
{
TInstall_ini ini;
ini.set("DiskPath", get(F_PATH));
ini.set("WebPath", get(F_WEB));
}
}
//lancia setup in modalita' aggiornamento web
_setup_run = xvt_sys_execute("setup\\setup.exe -uw", false, false) != 0;
}
if (_setup_run) //se riesce a lanciare setup.exe...
{
//si suicida...Banzai!
uncheck(r);
send_key(K_SPACE, DLG_QUIT);
return;
}
}
//installa solo le patch del modulo...
if (is_patch)
{
ok = install_patches(modulo, oldver, oldpatch, false) ; // installa l'ultima patch
if (!ok)
message_box(TR("Impossibile installare le patch del modulo '%s'"),(const char *)modulo);
}
else //..installa anche il pacco del modulo
{
ok = install(modulo, 0); // installa il modulo
}
if (ok)
{
_installed = true; // Setta il flag di almeno un modulo installato
uncheck(r); //finalmente unchecka i moduli installati
}
} //if(ok)...
else
uncheck(r); // se non ci sono patch o moduli -> uncheck
} //FOR_EACH_ARRAY_ROW(arr...
force_update(); //serve per togliere il check al modulo 'sy' quando viene installato
}
bool TInstaller_mask::install_handler(TMask_field& fld, KEY key)
{
if (key == K_SPACE)
{
if (_curr_mask->items() == 1)
_curr_mask->check(0);
const bool check_on = _curr_mask->check_enabled();
_curr_mask->enable_check(true);
const bool some = _curr_mask->one_checked();
_curr_mask->enable_check(check_on);
if (some)
_curr_mask->install_selection();
else
error_box(TR("Selezionare uno o piu' moduli da installare."));
}
return true;
}
bool TInstaller_mask::tutti_handler(TMask_field& f, KEY k)
{
if (k == K_SPACE)
{
TInstaller_mask & m=(TInstaller_mask &) f.mask();
if (m.check_enabled())
{
if (m.one_checked())
m.uncheck(-1);
else
m.precheck_modules(false);
}
}
return true;
}
bool TInstaller_mask::on_key(KEY key)
{
bool ok = true;
switch (key)
{
case K_F7: autoload(); break;
case K_F8: field(DLG_USER).on_hit(); break;
default : ok = TArray_sheet::on_key(key); break;
}
return ok;
}
TInstaller_mask::TInstaller_mask()
: TArray_sheet(0, 0, 0, 0, TR("Installazione"),
HR("@1|Modulo@32|Cod.@3|Versione da\ninstallare@11|Liv.\nPatch@6|Data\nRilascio@10|Versione\nInstallata@10|Liv.\nPatch@6|Data\nInstallazione@13|Aggiornamento|Patch Base"),
0x18, 4)
{
add_button(F_UPDATE, BR("Rileggi", 9), '\0', TOOL_CONVERT);
add_button(F_INSTALL, BR("Installa", 9), '\0', TOOL_ELABORA); // NON mettere 'I'
xvt_toolbar_set_last_tool(toolbar(), DLG_QUIT);
_station_type = test_station_type();
_curr_mask = this;
_installed = false;
_reboot_program= NONE;
//in base al tipo di installazione che rileva decide se puo' effettuare aggiornamenti via web (un client..
//..non puo' fare aggiornamenti da web!!!)
TToken_string installada;
installada.add(TR("Installa da disco"));
installada.add(TR("Installa da internet"));
TRadio_field& rf = add_radio(F_TYPE, 0, "", 1, 0, 21, "0|1", installada);
*rf.message(0, true) = "DISABLE,207|ENABLE,201";
*rf.message(1, true) = "DISABLE,201|ENABLE,207";
add_string(F_PATH, 0, "", 22, 1, 256, "", 58);
add_string(F_WEB, 0, "", 22, 2, 256, "", 58);
set(F_TYPE, "0", 0x1);
//un client non puo' scegliere a caso da dove aggiornarsi!Solo dal suo server!
if (_station_type == 3)
rf.disable();
add_string(F_CURPATH, 0, PR("Installa in "), 1, 3, 80, "D", 58);
set_handler(F_PATH, path_handler);
set_handler(F_WEB, web_handler);
set_handler(F_INSTALL, install_handler);
set_handler(F_UPDATE, update_handler);
set_handler(DLG_USER, tutti_handler);
TInstall_ini ini;
TFilename path = ini.get("DiskPath");
TFilename webpath = ini.get("WebPath");
set(F_PATH, path);
set(F_WEB, webpath);
//..fine costruzione maschera di installazione
//decide quale e' il percorso di installazione
//ha un cd o un disco di rete -> si aggiorna da questo...
if (path.exist())
autoload();
else //senno' cerca su internet se trova un path internet completo e la connessione funzionante
{
if (_station_type != 3 && webpath.full())
{
set(F_TYPE, "1", 0x1);
if (xvt_net_get_status() & 0x2) //la connessione web funziona?...
//if (yesno_box(TR("E' possibile l'aggiornamento via internet. Si desidera connettersi ora?")))
autoload(); //...quindi scarica l'elenco dei moduli da aggiornare!
}
}
DIRECTORY dir;
xvt_fsys_get_dir(&dir);
xvt_fsys_convert_dir_to_str(&dir, path.get_buffer(), path.size());
set(F_CURPATH, path);
}
TInstaller_mask::~TInstaller_mask()
{
_curr_mask = NULL;
}
///////////////////////////////////////////////////////////
// Programma principale
///////////////////////////////////////////////////////////
class TInstaller : public TSkeleton_application
{
protected:
TInstaller_mask* _m;
protected:
virtual bool create();
virtual bool use_files() const { return false; }
virtual bool test_assistance_year() const;
virtual void main_loop();
void convert_archives();
};
bool TInstaller::test_assistance_year() const
{
// Per il momento lascia continuare: ci pensa poi la create
return true;
}
bool TInstaller::create()
{
if (!TApplication::test_assistance_year())
{
TExternal_app attivazione("ba1 -4");
attivazione.run();
dongle().login(); // Rilegge anno assistenza
}
else
update_dninst(false); // Aggiorna se necessario
//crea la maschera di installazione
_m = new TInstaller_mask();
//se e' un client
if (_m->station_type() == 3)
{
_m->disable_check();
_m->disable(F_UPDATE);
_m->disable(DLG_USER);
}
else //se e' standalone o server...
{
if (user() != ::dongle().administrator())
return error_box(TR("Solo l'utente amministratore puo' aggiornare questa postazione!"));
}
return TSkeleton_application::create();
}
void TInstaller::convert_archives()
{
bool conv = true;
if (is_power_station())
conv = yesno_box(TR("Si desidera convertire gli archivi ora?"));
if (conv)
{
_m->backup();
// Lancia conversione: ba1 -0 -C -uADMIN
TExternal_app conversion("ba1 -0 -C");
conversion.run();
}
}
void TInstaller::main_loop()
{
_m->run();
if (_m->run_conversion() && _m->station_type() < 3) // Almeno un trr installato e non e' client->conversione ammessa
{
convert_archives();
}
//controlla se ha lanciato setup.exe prima di chiudersi; se non lo ha fatto -> e' a fine installazione..
//..normale (moduli non SY) e quindi lancia ba0.exe
const bool setup_launched = _m->setup_run();
delete _m; _m = NULL;
if (!setup_launched)
{
TExternal_app ba0("ba0.exe");
ba0.run(true, true, false); // run asynchronous and not iconized!
}
}
int ba1700(int argc, char* argv[])
{
TInstaller app;
app.run(argc, argv, TR("Installazione moduli"));
return 0;
}