#include #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 #ifdef _DEMO_ const char* const http_default_path = "/aga/demo/zip/"; #else const char* const http_default_path = "/aga/program/zip/"; #endif HIDDEN int compare_version(const char* v1, int p1, const char* v2, int p2) { TString16 ver1(v1), ver2(v2); ver1.trim(); if (ver1.len() == 4) ver1.insert((v1[0] == '9') ? "19" : "20", 0); ver2.trim(); if (ver2.len() == 4) ver2.insert((v2[0] == '9') ? "19" : "20", 0); 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); } 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; bool _installed; // Flag per verificare se almeno un modulo e' stato installato bool _sys_installed; //Flag per controllare l'installazione del modulo di sistema SY enum { NONE = 0, NEW_MENU = 1, NEW_MENUPRG = 2, NEW_INSTALLER = 4, NEW_DLL = 8 }; int _reboot_program; protected: // TSheet virtual bool on_key(KEY key); static bool quit_handler(TMask_field& f, KEY k); 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; protected: static bool path_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, bool patch); 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_internet_path(TFilename& ininame) const; void parse_internet_path(TString& http_server, TFilename& http_path) const; public: bool installed() const { return _installed;} bool sys_installed() const { return _sys_installed;} bool autoload(); bool install(const TString& module, int patch); bool run_ba0close() const { return _reboot_program >= NEW_MENUPRG; } 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(); bool ok = ini.set_paragraph(module); if (ok) { const int numpatch = ini.get_int("Patch"); TString16 strpatch; if (numpatch > 0) strpatch.format("%03d", 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 ok; } // Copia nello sheet i dati di un modulo prendendoli da un .ini bool TInstaller_mask::add_header(TConfig& ini, const TString& module, bool patch) { 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; } 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 TInstaller_mask::has_module(int modnumber) const { if (modnumber == SRAUT) { char s[16]; if (xvt_fsys_get_campo_stp_value("Servers", s, sizeof(s)) || xvt_fsys_get_campo_stp_value("Sy", s, sizeof(s))) //***aggiunto il modulo sy return atoi(s) > 0; } return main_app().has_module(modnumber, CHK_DONGLE); } int TInstaller_mask::precheck_modules(bool only_newer) { TString16 release,currrelease; TString4 cod_module; int patchlevel,modnumber,currpatch; 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; 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); break; //..ed uscire } } } force_update(); // Indispensabile per vedere le righe aggiornate return items(); } int TInstaller_mask::get_module_number(const TString& module) const { int aut = -1; bool ok = FALSE; if (module.not_empty()) { if (module == "ba" || module == "sy") //moduli base e sistema: deve ritornare 0; return 0; TScanner scanner(AUT_FILE); for (aut = 0; scanner.line() != ""; aut++) if (scanner.token().starts_with(module)) { ok = TRUE; break; } } 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("%03d", 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; const bool internet = get_internet_path(path); if (internet) { parse_internet_path(http_server,http_path); make_dir(path); ininame = path; ininame.add(TInstall_ini::default_name()); if (ininame.exist() && yesno_box(TR("Si desidera svuotare la cache dei files scaricati dal sito?"))) { TString_array list; TFilename name = path; name.add("*.*"); ::list_files(name, list); FOR_EACH_ARRAY_ROW(list, i, row) ::remove(*row); } if (!ininame.exist()) { bool httpresult; TFilename remote_ini = http_path; remote_ini << TInstall_ini::default_name(); { TIndwin contacting(60,TR("Connessione al server HTTP..."),FALSE,FALSE); httpresult=http_get(http_server, remote_ini, ininame); } } } 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; if (ininame.exist()) { // Presente il file ini generale "install.ini" (moduli;immagine cd) TInstall_ini ini(ininame); 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, FALSE); else { TFilename mod_ini = ininame.path(); mod_ini.add(module); mod_ini << "inst.ini"; if (mod_ini.exist()) { TInstall_ini moduleini(mod_ini); add_module(moduleini, module, FALSE); } else add_module(ini, module, FALSE); } } } } 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 TString16 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("??0???A.INI") || str.match("??0???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("??0???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; installini.list_paragraphs(paragrafi); TFilename file; 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(); for (int 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); if (patchversion == row.get(C_RELEASE) // se le versioni corrispondono ... && patchlevel > row.get_int(C_PATCH)) // ..e il patchlevel è superiore { TString16 patch; patch.format("%03d", 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 } } 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 < 1997) return error_box(FR("Il modulo '%s' non ha una versione valida."), module); #ifndef _DEMO_ if (year > dongle().year_assist()) return error_box(FR("Per installare la versione %s del modulo '%s'\noccorre il contratto di assistenza per l'anno %d."), (const char*)version, module, year); #endif TAuto_token_string altri(ini.get("Moduli", module)); if (stricmp(module, "sy") != 0) //SY e' indipendente dagli altri moduli { if (stricmp(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; return underscore; } bool TInstaller_mask::is_zip_file(const TFilename& n) const { const char* ext = n.ext(); return xvt_str_compare_ignoring_case(ext, "zip") == 0; } 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_MENU && 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, filesize) == 0) return error_box(TR("Lo spazio sull'unita' di destinazione 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; } 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_internet_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 pi.addstatus(1); } } 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); ::remove(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_MENU && 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("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_internet_path(TFilename &ininame) const { ininame = get(F_PATH); if (is_internet_path(ininame)) { ininame.tempdir(); ininame.add("www"); return TRUE; } return FALSE; } void TInstaller_mask::parse_internet_path(TString & http_server, TFilename &http_path) const { http_server = get(F_PATH); 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); if (http_path.right(1) != "/") http_path << '/'; http_server.cut(slash); } else http_path = http_default_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_internet_path(ininame); ininame.add(module); ininame << "0???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 char * patchversion = ini.get("Versione"); if (ok && lastrelease == patchversion // 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; } void TInstaller_mask::install_selection() { TString_array& arr = rows_array(); _sys_installed = false; FOR_EACH_ARRAY_ROW(arr, r, row) if (checked(r)) { const TString newver = row->get(C_RELEASE); if (newver.blank()) { check(r, FALSE); continue; } const TString 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); if (version2year(newver) < 1998) { 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); if (cmp == 0) ok = noyes_box(FR("Si desidera reinstallare la versione %s.%d del modulo '%s' ?"), (const char*)newver, newpatch, (const char*)modulo); 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); } if (ok && is_patch) { // installo le patch solo se esiste già un modulo installato della stessa versione if (!oldver.blank() ) { if (oldver != newver) 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 ok =FALSE;//error_box("Impossibile installare le patch perche' il modulo '%s' non e' installato",(const char *)modulo); } 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! } } 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 { ok = install(modulo, 0); // installa il modulo } if (ok) { _installed = true; // Setta il flag di almeno un modulo installato if (modulo == "sy") //se ha installato il modulo 'sy' esce { _sys_installed = true; enable_row(r); //deve abilitare la riga di system senno' non la puo' uncheckare dopo uncheck(-1); //uncheck di tutti i moduli break; } uncheck(r); //finalmente unchecka i moduli installati } } else uncheck(r); // se non ci sono patch o moduli -> uncheck } force_update(); //serve per togliere il check al modulo 'sy' quando viene installato if (installed()) { if (_sys_installed) { warning_box("Modulo SY installato: altri moduli presenti dovranno essere installati successivamente"); send_key(K_SPACE, DLG_QUIT); } else message_box(TR("Installazione conclusa")); } } 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::quit_handler(TMask_field& f, KEY k) { if (k == K_SPACE) { TInstaller_mask & m=(TInstaller_mask &) f.mask(); 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) return noyes_box(TR("Alcuni moduli sono selezionati per l'installazione.\nConfermare l'uscita")); } 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, 3) { _curr_mask = this; _installed = FALSE; _reboot_program= NONE; add_string(F_PATH, 0, PR("Installa da "), 1, 1, 80, "", 60); add_string(F_CURPATH, 0, PR("Installa in "), 1, 2, 80, "D", 60); 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_INSTALL, install_handler); set_handler(F_UPDATE, update_handler); set_handler(DLG_QUIT, quit_handler); set_handler(DLG_USER, tutti_handler); TInstall_ini ini; TFilename path = ini.get("DiskPath"); set(F_PATH, path); const bool floppy = xvt_fsys_is_removable_drive(path) != 0; if (path.not_empty() && !floppy && !is_internet_path(path)) autoload(); 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; if (_reboot_program != NONE) { TString msg; msg << TR("Sono stati aggiornati i seguenti elementi:") < '\n'; if (_reboot_program & NEW_MENU) msg << TR("voci di menu;"); if (_reboot_program & NEW_MENUPRG) msg << TR("navigatore dei menu;"); if (_reboot_program & NEW_INSTALLER) msg << TR("installatore;"); if (_reboot_program & NEW_DLL) msg << TR("librerie di base;"); msg.rtrim(1); msg << '\n' << TR("E' necessario uscire e rientrare dal programma."); warning_box(msg); } } /////////////////////////////////////////////////////////// // 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(); bool testdatabase() const; bool testprograms() const; }; bool TInstaller::testdatabase() const { TConfig ini(CONFIG_INSTALL, "Main"); return ini.get("TestDatabase","Main",-1,"Y") != "N"; } bool TInstaller::testprograms() const { TConfig ini(CONFIG_INSTALL, "Main"); char c = ini.get("TestPrograms","Main",-1,"N")[0]; return c == 'X' || c == 'Y'; } 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 if (testprograms()) { _m = new TInstaller_mask() ; _m->disable_check(); _m->disable(F_PATH); _m->disable(F_UPDATE); _m->disable(DLG_USER); return TSkeleton_application::create(); } return error_box(FR("L'utente %s non è abilitato all'uso di questo programma"), (const char *)user()); } void TInstaller::main_loop() { _m->run(); if (_m->installed() && !_m->sys_installed() && testdatabase()) // Almeno 1 modulo installato ? { // Lancia conversione: ba1 -0 -C -uADMIN TExternal_app conversion("ba1 -0 -C"); conversion.run(); } delete _m; _m = NULL; } class TExtendedInstaller : public TInstaller { protected: virtual bool create(); virtual void main_loop(); }; bool TExtendedInstaller::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 _m = new TInstaller_mask() ; return TSkeleton_application::create(); } void TExtendedInstaller::main_loop() { _m->run(); if (_m->installed() && !_m->sys_installed() && testdatabase()) // Almeno 1 modulo installato ? { // Lancia conversione: ba1 -0 -C -uADMIN TExternal_app conversion("ba1 -0 -C"); conversion.run(); } const bool reboot = _m->run_ba0close(); delete _m; _m = NULL; if (reboot && !fexist("ba3.exe")) //e' una prima installazione (non ha ancora installato la base) { TExternal_app ba0close("ba0close.exe"); ba0close.run(TRUE,TRUE,TRUE); // run asynchronous... } } int ba1700(int argc, char* argv[]) { const char* const PROGNAME = "Installazione moduli"; if (user() != ::dongle().administrator()) { TInstaller app; app.run(argc, argv, PROGNAME); } else { TExtendedInstaller app; app.run(argc, argv, PROGNAME); } return 0; }