#include #define XVT_INCL_NATIVE #include #include #include #include #include #include #include #include "ba1.h" #include "ba1500.h" #include "ba1600.h" #include "ba1700a.h" HIDDEN int noyes_box(const char* msg) { MessageBeep(MB_ICONQUESTION); int r = MessageBox(GetFocus(), msg, "RICHIESTA", MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2); return r == IDYES; } 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); } /////////////////////////////////////////////////////////// // Maschera principale /////////////////////////////////////////////////////////// class TInstaller_mask : public TArray_sheet { static TInstaller_mask* _curr_mask; word _year_assist; bool _installed; // Flag per verificare se almeno un modulo e' stato installato protected: // TSheet virtual bool on_key(KEY key); static bool tutti_handler(TMask_field& f, KEY k); 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, bool patch); bool add_header(TConfig& ini, const TString& module, bool patch); int sort_modules(); void update_version(); bool move_file(const TFilename& fromdir, 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 installed() { return _installed;} bool autoload(); bool install(const TString& module, int patch); 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) { ini.write_protect(); 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("Patch")); row.add(ini.get("Data")); row.add(patch ? "X" : " ", 9); add(row); } 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; } int TInstaller_mask::sort_modules() { //rows_array().TArray::sort(compare_modules); TString16 dis; const int tot = int(items()); for (int r = 0; r < tot; r++) { const bool patch = row(r).get_char(9) > ' '; const char* mod = row(r).get(2); if (*mod != ' ') // is not an header... { if (patch) { if (dis == mod) disable_row(r); } else dis = mod; } } return tot; } void TInstaller_mask::update_version() { TInstall_ini ini; TString_array& array = rows_array(); FOR_EACH_ARRAY_ROW_BACK(array, m, row) { if (*row->get(2) != ' ') { 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, 6); row->add(ini.get("Patch"), 7); row->add(ini.get("Data"), 8); } } 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[0] == '_' || module.len() == 2) { if (module[0] == '_') add_header(ini, module, FALSE); else add_module(ini, module, FALSE); } } } 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, FALSE); } ininame = path; ininame.add("??0???a.ini"); modules.destroy(); list_files(ininame, modules); 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 module = ininame.mid(pos-6, 2); TConfig ini(ininame, module); add_module(ini, module, TRUE); } } const bool ok = sort_modules() > 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); #ifndef _DEMO_ 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); #endif 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, 0); } } } return ok; } // sposta il file dal direttorio temporaneo a quello passato come destinazione bool TInstaller_mask::move_file(const TFilename& from, const TFilename& file, const char* dir) const { TFilename dest(dir); dest.add(file.mid(from.len())); 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_retry = FALSE; do { write_ok = ::fcopy(file, dest); if (write_ok) ::remove(file); else user_retry = yesno_box("Errore di copia del file %s.\nSi desidera ritentare?", (const char*)file); } while (!write_ok && user_retry); 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(tempdir, 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, int patchlevel) { bool ok = FALSE; const TString& path = get(F_PATH); TFilename ininame = path; ininame.add(module); if (patchlevel > 0) { TString16 name; name.format("%04da.ini", patchlevel); ininame << name; } else ininame << "inst.ini"; if (fexist(ininame)) { TInstall_ini ini(ininame); ini.write_protect(); 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; } TString msg; msg << "Decompressione del modulo '" << module << "' in corso..."; TProgind pi(dischi, msg, FALSE, TRUE); TFilename tempdir; tempdir.tempdir(); TFilename cmdline; for (int d = 1; d <= dischi && ok; d++) { cmdline = path; cmdline.add(module); if (patchlevel > 0) { TString16 name; name.format("%04da", patchlevel); cmdline << name; } else cmdline << "inst"; cmdline << d << ".zip"; ok = cmdline.exist(); 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) { msg.cut(0); msg << "Aggiornamento del modulo '" << module << "' in corso..."; pi.set_text(msg); 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 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 (ok) ok = post_process(ini, module); } else { ininame = path; ininame.add(TInstall_ini::default_name()); ok = fexist(ininame); if (ok) { TInstall_ini ini(ininame); ini.write_protect(); 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()) { TFilename path = fld.get(); if (path.len() == 2 && isalpha(path[0]) && path[1] == ':') { path << SLASH; fld.set(path); } if (path.exist()) _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 newver = row->get(3); if (newver.blank()) { check(r, FALSE); continue; } const TString modulo = row->get(2); const int newpatch = row->get_int(4); const TString oldver = row->get(6); const int oldpatch = row->get_int(7); 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, oldpatch, newver, newpatch); if (cmp == 0) ok = yesno_box("Si desidera reinstallare la versione %s.%d del modulo '%s' ?", (const char*)newver, newpatch, (const char*)modulo); if (cmp > 0) { TString256 msg; msg.format("Si desidera ritornare alla versione %s.%d del modulo '%s' ?\n" "Attenzione: non e' garantito il corretto\n" "funzionamento di tutti i programmi!", (const char*)newver, newpatch, (const char*)modulo); ok = noyes_box(msg); } if (ok) { const bool is_patch = row->get_char(9) > ' '; ok = install(modulo, is_patch ? newpatch : 0); if (ok) _installed = TRUE; // Setta il flag di almeno un modulo installato if (!is_patch) // Se installo un modulo pricipale ... { // ... allora installo tutte le patches for (int p = r+1; ok; p++) { if (row_disabled(p)) { const int patchlevel = arr.row(p).get_int(4); ok = install(modulo, patchlevel); } else break; } } if (ok) check(r, FALSE); } if (ok) check(r,FALSE); // uncheck } } 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::tutti_handler(TMask_field& f, KEY k) { if (k == K_SPACE) { TSheet& s = (TSheet&)f.mask(); if (s.check_enabled()) { if (s.one_checked()) s.uncheck(-1); else { for (long i = s.items()-1; i >=0; i--) { TToken_string r = s.row(i); const TString16 newver = r.get(3); const int newpatch = r.get_int(4); const TString16 curver = r.get(6); const int curpatch = r.get_int(7); s.check(i, compare_version(newver, newpatch, curver, curpatch) > 0); } } } } return TRUE; } bool TInstaller_mask::on_key(KEY key) { bool ok = TRUE; if (key == K_CTRL+'N') autoload(); else if (key == K_F8) { for (long i = items()-1; i >=0; i--) { TToken_string r = row(i); const TString16 newver = r.get(3); const int newpatch = r.get_int(4); const TString16 curver = r.get(6); const int curpatch = r.get_int(7); check(i, compare_version(newver, newpatch, curver, curpatch > 0)); } } 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|Livello\nPatch|Data\nRilascio@10|Versione\nInstallata@10|Livello\nPatch|Data\nInstallazione@13|Aggiornamento", 0x18, 3) { _curr_mask = this; _installed = FALSE; 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); set_handler(DLG_USER, tutti_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(); if (m.installed()) // Almeno 1 modulo installato ? { // Lancia conversione: ba1 -0 -C -uPRASSI TExternal_app conversion("ba1 -0 -C"); conversion.run(); } } int ba1700(int argc, char* argv[]) { TInstaller app; app.run(argc, argv, "Installer"); return 0; }