#include #define XVT_INCL_NATIVE #include #include #include #include #include #include #include "ba1.h" #include "ba1500.h" #include "ba1600.h" #include "ba1700a.h" HIDDEN int compare_version(const char* v1, const char* v2) { 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); return ver1.compare(ver2, -1, TRUE); } 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); } /////////////////////////////////////////////////////////// // Maschera principale /////////////////////////////////////////////////////////// class TInstaller_mask : public TArray_sheet { static TInstaller_mask* _curr_mask; word _year_assist; protected: // TSheet virtual bool on_key(KEY key); 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); bool add_module(TConfig& ini, const TString& module); void update_version(); bool move_file(const TFilename& file, const char* dir) 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 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; public: bool autoload(); bool install(const TString& module); 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 ok = ini.set_paragraph(module); if (ok) { TToken_string row; row = " "; // Not selected row.add(ini.get("Descrizione")); row.add(module); row.add(ini.get("Versione")); row.add(ini.get("Data")); add(row); } return ok; } void TInstaller_mask::update_version() { TInstall_ini ini; TString_array& array = rows_array(); FOR_EACH_ARRAY_ROW_BACK(array, m, row) { const TString16 module = row->get(2); ini.set_paragraph(module); const TString16 newver = row->get(3); const TString16 oldver = ini.get("Versione"); row->add(oldver, 5); row->add(ini.get("Data"), 6); } 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() { const TString& path = get(F_PATH); if (!fexist(path)) return error_box("Specificare un percorso valido"); TWait_cursor hourglass; destroy(); TFilename ininame; ininame = path; ininame.add(TInstall_ini::default_name()); TString_array modules; if (fexist(ininame)) { TInstall_ini ini(ininame); ini.list_paragraphs(modules); FOR_EACH_ARRAY_ROW(modules, i, row) { const TString& module = *row; if (module.len() == 2) add_module(ini, module); } } else { ininame = path; ininame.add("??inst.ini"); list_files(ininame, modules); 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); } } rows_array().sort(); const bool ok = items() > 0; if (ok) update_version(); else error_box("Non e' stato trovato nessun modulo da installare\n" "in %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() == 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 << "Attenzione: Non e' possibile installare la versione "; msg << (ini.demo() ? "dimostrativa" : "normale"); msg << " nella cartella della versione "; msg << (curini.demo() ? "dimostrativa" : "normale"); return error_box(msg); } const TString& version = ini.version(module); const word year = version2year(version); if (year < 1997) return error_box("Il modulo '%s' non ha una versione valida.", module); if (year > _year_assist) return error_box("Per installare la versione %s del modulo '%s'\n" "occorre il contratto di assistenza per l'anno %d.", (const char*)version, module, year); TAuto_token_string altri(ini.get("Moduli", module)); if (stricmp(module, "ba") != 0 && altri.get_pos("ba") < 0) altri.add("ba"); // La base e' obbligatoria per tutti 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 << "L'installazione del modulo '" << module << "'\nrichiede la presenza del modulo '" << submodule << "':\nSi desidera procedere alla sua installazione?"; ok = yesno_box(msg); if (ok) ok = install(submodule); } } } return ok; } bool TInstaller_mask::move_file(const TFilename& file, const char* dir) const { TFilename dest(dir); dest.add(file.name()); const long filesize = fsize(file); bool space_ok = FALSE; while (!space_ok) { int disk = 0; if (dest[1] == ':') { const char letter = toupper(dest[0]); disk = 'A' - letter + 1; } struct _diskfree_t drive; _dos_getdiskfree(disk, &drive); const unsigned requested_clusters = unsigned(filesize / drive.sectors_per_cluster / drive.bytes_per_sector) + 1; space_ok = requested_clusters <= drive.avail_clusters; if (!space_ok) { TString msg; msg << "Lo spazio sull'unita' e' insufficiente"; if (GetDriveType(disk-1) == DRIVE_REMOVABLE) { msg << ":\nInserire un nuovo disco e ritentare?"; if (!yesno_box(msg)) return FALSE; } else return error_box(msg); } } bool write_ok = TRUE; bool user_abort = FALSE; do { write_ok = ::fcopy(file, dest); if (write_ok) ::remove(file); else { if (!yesno_box("Errore di copia del file %s.\nSi desidera riprovare?", (const char*)file)); user_abort = TRUE; } } while (!write_ok && !user_abort); return write_ok; } bool TInstaller_mask::move_module(const TString& module, TInstall_ini& ini, bool update) const { bool ok = TRUE; TFilename src; src.tempdir(); const TFilename tempdir(src); TString_array list; ini.build_list(module, list); FOR_EACH_ARRAY_ROW(list, f, file) { src = tempdir; src.add(file->get(0)); if (update) { const bool move_ok = move_file(src, "."); if (!move_ok) ok = update = FALSE; } if (!update) ::remove(src); } if (update) ini.export_paragraph(module, ini.default_name()); return ok; } bool TInstaller_mask::install(const TString& module) { bool ok = FALSE; const TString& path = get(F_PATH); TFilename ininame = path; ininame.add(module); ininame << "inst.ini"; if (fexist(ininame)) { TInstall_ini ini(ininame); if (!can_install(module, ini)) return FALSE; const int dischi = ini.get_int("Dischi", module); ok = dischi > 0; if (!ok) { return error_box("Impossibile determinare il numero dei dischetti"); } else { ok = pre_process(ini, module); if (!ok) return FALSE; } TProgind pi(dischi, "Decompressione in corso...", FALSE, TRUE); TFilename tempdir; tempdir.tempdir(); TFilename cmdline; for (int d = 1; d <= dischi && ok; d++) { cmdline = path; cmdline.add(module); cmdline << "inst" << d; cmdline.ext("zip"); ok = fexist(cmdline); while (!ok) { message_box("Inserire il disco %d di %d del modulo\n%s", d, dischi, (const char*)ini.get("Descrizione")); ok = fexist(cmdline); if (!ok) { if (!yesno_box("Impossibile trovare %s\nSi desidera riprovare?", (const char*)cmdline)) break; } } if (ok) { struct _diskfree_t drive; _dos_getdiskfree(0, &drive); const long required = fsize(cmdline) * (dischi-d+1) * 4; const unsigned requested_clusters = unsigned(required / drive.sectors_per_cluster / drive.bytes_per_sector) + 1; if (requested_clusters >= drive.avail_clusters) { ok = yesno_box("Lo spazio su disco potrebbe essere insufficiente:\n" "Si desidera continuare ugualmente?"); } } if (ok) { TWait_cursor hourglass; cmdline.insert("unzip.pif -o ", 0); cmdline << " -d " << tempdir; TExternal_app app(cmdline); ok = app.run(FALSE, FALSE, FALSE, FALSE) == 0; pi.addstatus(1); } } if (ok) { pi.set_text("Aggiornamento in corso..."); ok = move_module(module, ini, TRUE); 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 TString16 reqver = ini.version(submod); upd = compare_version(reqver, curver) > 0; if (!upd) { warning_box("Il sottomodulo '%s' e' aggiornato alla versione %s:\n" "l'installazione della versione %s non vera' effettuata.", (const char*)submod, (const char*)curver, (const char*)reqver); } } ok &= move_module(submod, ini, upd); } } } if (ok) ok = post_process(ini, module); } else { ininame = path; ininame.add(TInstall_ini::default_name()); ok = fexist(ininame); if (ok) { TInstall_ini ini(ininame); if (!can_install(module, ini)) return FALSE; TString_array list; const int files = ini.build_complete_list(module, list); if (files > 0) { ok = pre_process(ini, module); if (ok) { TProgind pi(files, "Copia in corso...", FALSE, TRUE); TFilename src, dst; for (int f = 0; f < files && ok; f++) { pi.addstatus(1); dst = list.row(f).get(0); src = path; src.add(dst); ok = fcopy(src, dst); } } if (ok) { ini.export_module_paragraphs(module, ini.default_name()); ok = post_process(ini, module); } } } } if (ok) { TInstall_ini ini; ini.set("DiskPath", path); ini.set("Data", TDate(TODAY), module); ini.update_prices(ininame); } // Non spostare nell'if precedente: permettere l'aggiornamento del .ini if (ok) update_version(); return ok; } bool TInstaller_mask::path_handler(TMask_field& fld, KEY key) { bool ok = TRUE; if (key == K_TAB && fld.focusdirty()) { TString path = fld.get(); if (path.len() == 2 && isalpha(path[0]) && path[1] == ':') { path << SLASH; fld.set(path); } if (fexist(path)) _curr_mask->autoload(); else ok = fld.error_box("Specificare un percorso valido"); } return ok; } void TInstaller_mask::install_selection() { TString_array& arr = rows_array(); FOR_EACH_ARRAY_ROW(arr, r, row) if (checked(r)) { const TString modulo = row->get(2); const TString newver = row->get(3); const TString oldver = row->get(5); if (version2year(newver) < 1997) { error_box("Il modulo '%s' non ha una versione valida.", (const char*)modulo); continue; } bool ok = TRUE; const int cmp = compare_version(oldver, newver); if (cmp < 0) ok = yesno_box("Si desidera installare la versione %s?", (const char*)newver); if (cmp == 0) ok = yesno_box("Si desidera reinstallare la versione %s?", (const char*)newver); if (cmp > 0) ok = yesno_box("Si desidera ritornare alla versione %s?\n" "Attenzione: non e' garantito il corretto\n" "funzionamento di tutti i programmi!", (const char*)oldver); if (ok) install(modulo); } } bool TInstaller_mask::install_handler(TMask_field& fld, KEY key) { if (key == K_SPACE) { if (_curr_mask->items() == 1) _curr_mask->check(0); if (_curr_mask->one_checked()) _curr_mask->install_selection(); else error_box("Selezionare uno piu' moduli da installare."); } return TRUE; } bool TInstaller_mask::on_key(KEY key) { bool ok = TRUE; if (key == K_CTRL+'N') autoload(); else ok = TArray_sheet::on_key(key); return ok; } TInstaller_mask::TInstaller_mask() : TArray_sheet(0, 0, 0, 0, "Installazione", "@1|Modulo@30|Cod.|Versione\nda installare@13|Data\nRilascio@10|Versione\nInstallata@10|Data\nInstallazione@13", 0x18, 3) { _curr_mask = this; add_string(F_PATH, 0, "Percorso da cui installare ", 1, 1, 50); add_string(F_CURPATH, 0, "Percorso in cui installare ", 1, 2, 50, "D"); add_button(F_INSTALL, "Installa", '\0'); // NON mettere 'I' set_handler(F_PATH, path_handler); set_handler(F_INSTALL, install_handler); TDongle dongle; dongle.login(); dongle.logout(); _year_assist = dongle.year_assist(); TInstall_ini ini; TFilename path = ini.get("DiskPath"); set(F_PATH, path); const char lettera = toupper(path[0]); const bool floppy = (path.len() > 1) && path[1] == ':' && GetDriveType(lettera - 'A') == DRIVE_REMOVABLE; if (path.not_empty() && !floppy) 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; } /////////////////////////////////////////////////////////// // Programma principale /////////////////////////////////////////////////////////// class TInstaller : public TSkeleton_application { protected: virtual bool use_files() const { return FALSE; } virtual void main_loop(); }; void TInstaller::main_loop() { TInstaller_mask m; m.load(); m.run(); } int ba1700(int argc, char* argv[]) { TInstaller app; app.run(argc, argv, "Installer"); return 0; }