#include #include #include #include #include #include #include #include #include #include #include #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.compare("www.", 4, true) == 0) return true; if (addr.compare("http:", 5, true) == 0) 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 è 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à"), 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à 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 da manutenzione/installazione moduli! if (modulo == "sy") { 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 = list_files(disk_path, ar); 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!!!! } } //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!!!! } //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) { _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!!!) TRadio_field& rf = add_radio(F_TYPE, 0, "", 1, 0, 21, "0|1", "Installa da disco|Installa da internet"); *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); add_button(F_UPDATE, BR("Rileggi", 9), '\0'); add_button(F_INSTALL, BR("Installa", 9), '\0'); // NON mettere 'I' 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; }