#include #include #include #include #include #include #include #include #include #include #include "ba2800a.h" /////////////////////////////////////////////////////////// // Utilities /////////////////////////////////////////////////////////// const TString& smart_trim(const TString& str, int len) { TString& tmp = get_tmp_string(); tmp = str; tmp.trim(); if (tmp.len() > len) { TParagraph_string p(tmp, len); tmp = p.get(); } return tmp; } int smart_cmp(const char* s1, const char* s2) { if (s1 == NULL || *s1 <= ' ') s1 = ""; if (s2 == NULL || *s2 <= ' ') s2 = ""; if (isdigit(*s1) && isdigit(*s2)) return atoi(s1) - atoi(s2); return xvt_str_compare_ignoring_case(s1, s2); } ///////////////////////////////////////////////////////////a // TOEM_cache /////////////////////////////////////////////////////////// class TOEM_cache { public: int Agente2OEM(int agente) const; TOEM_cache(); }; // Trasforma un codice OEM del DB in quello di oem.ini int TOEM_cache::Agente2OEM(int agente) const { int oem = -1; switch (agente) { case 1: // Administrator case 2: oem = 0; break; case 3: oem = 1; break; case 4: oem = 3; break; case 5: oem = 6; break; case 6: oem = 5; break; case 7: oem = 7; break; case 8: oem = 8; break; default: break; } return oem; } // Carica la lista di tutti gli OEM dal file setup/oem.ini TOEM_cache::TOEM_cache() { } /////////////////////////////////////////////////////////// // Tdnist_full /////////////////////////////////////////////////////////// class Tdnist_full { TArray _chiavi; public: void set(int key, const char* var, const TString& value); const TString& get(int key, const char* var) const; int last() const { return _chiavi.last(); } bool exists(int key) const { return _chiavi.objptr(key) != NULL; } bool load(); bool save() const; }; const char* const DNINST_ZIP = "setup/dninst.zip"; const char* const DNINST_TXT = "setup/dninst.txt"; void Tdnist_full::set(int key, const char* var, const TString& value) { CHECKD(key > 0, "Invalid key ", key); TAssoc_array* info = (TAssoc_array*)_chiavi.objptr(key); if (info == NULL) { info = new TAssoc_array; _chiavi.add(info, key); } if (value.full()) info->add(var, value, true); else info->remove(var); } const TString& Tdnist_full::get(int key, const char* var) const { TAssoc_array* info = (TAssoc_array*)_chiavi.objptr(key); if (info == NULL) return EMPTY_STRING; const TString* val = (const TString*)info->objptr(var); return val ? *val : EMPTY_STRING; } // Decodifica l'intero dninst.zip in memoria bool Tdnist_full::load() { _chiavi.destroy(); TFilename txt = DNINST_TXT; Tdninst dninst; if (dninst.decode(txt)) { TScanner s(txt); const int anno = atoi(s.line()); int key = 0; TString16 var; TString256 val; while (s.good()) { TString& line = s.line(); if (line[0] == '[') { line.strip("[]"); key = atoi(line); } else { if (key > 0) { const int equal = line.find('='); if (equal > 0) { var = line.left(equal); var.trim(); val = line.mid(equal+1); val.strip("\""); val.trim(); set(key, var, val); } } } } } else cantread_box(DNINST_ZIP); return !_chiavi.empty(); } bool Tdnist_full::save() const { Tdninst dninst; bool done = dninst.ok(); if (done) { ofstream out(DNINST_TXT); out << dninst.assist_year() << endl; FOR_EACH_ARRAY_ITEM(_chiavi, key, obj) { out << '[' << key << ']' << endl; TAssoc_array& info = (TAssoc_array&)*obj; FOR_EACH_ASSOC_OBJECT(info, o, k, i) out << k << '=' << *i << endl; } } if (done) done = dninst.encode(DNINST_TXT); return done; } /////////////////////////////////////////////////////////// // Tdnist_mask /////////////////////////////////////////////////////////// static int _c_key, _c_oem, _c_owner, _c_suspend, _c_killed; static int _c_dboem, _c_dbowner, _c_dbsuspend, _c_dbkilled; static int _c_xmloem, _c_xmlowner, _c_xmlaccess; class Tdnist_mask : public TAutomask { TOEM_cache _oem; Tdnist_full _dninst; private: static int dongle_compare(const TSortable& o1, const TSortable& o2, void* jolly); const TString& remote_dninst() const; TToken_string& find_or_create_line(TString_array& a, int key) const; void load_dninst(TString_array& a); bool load_odbc(TString_array& a) const; bool load_xml(TString_array& a) const; protected: void fill_sheet(); void merge_sheet(); virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); public: Tdnist_mask(); }; int Tdnist_mask::dongle_compare(const TSortable& o1, const TSortable& o2, void* jolly) { TToken_string& d1 = (TToken_string&)o1; TToken_string& d2 = (TToken_string&)o2; const int sort = *(int*)jolly; if (sort == 1) { const char* o1 = d1.get(_c_oem); if (o1 == NULL || *o1 <= ' ') o1 = d1.get(_c_dboem); const char* o2 = d2.get(_c_oem); if (o2 == NULL || *o2 <= ' ') o2 = d2.get(_c_dboem); const int cmp = smart_cmp(o1, o2); if (cmp != 0) return cmp; } if (sort >= 1) { const char* o1 = d1.get(_c_owner); if (o1 == NULL || *o1 <= ' ') o1 = d1.get(_c_dbowner); const char* o2 = d2.get(_c_owner); if (o2 == NULL || *o2 <= ' ') o2 = d2.get(_c_dbowner); const int cmp = smart_cmp(o1, o2); if (cmp != 0) return cmp; } return atoi(d1) - atoi(d2); } const TString& Tdnist_mask::remote_dninst() const { TString& path = get_tmp_string(); if (get_bool(F_DNINST_ON)) { path = get(F_DNINST); path.lower(); if (!path.ends_with(DNINST_ZIP)) path << "/" << DNINST_ZIP; } return path; } void Tdnist_mask::load_dninst(TString_array& a) { _dninst.load(); const int last_key = _dninst.last(); TToken_string str; for (int key = 1; key <= last_key; key++) if (_dninst.exists(key)) { str.cut(0) << key; str.add(_dninst.get(key, "OEM"), _c_oem); str.add(smart_trim(_dninst.get(key, "Owner"), 50), _c_owner); str.add(_dninst.get(key, "MustCall"), _c_suspend); str.add(_dninst.get(key, "*"), _c_killed); a.add(str); } } TToken_string& Tdnist_mask::find_or_create_line(TString_array& a, int key) const { int mi = 0, ma = a.last(); int k = 0; while (mi <= ma) { const int me = (mi+ma)/2; k = a.row(me).get_int(0); if (k == key) return a.row(me); if (k < key) mi = me+1; else ma = me-1; } while (mi < a.items() && key > a.row(mi).get_int(0)) mi++; TToken_string* str = new TToken_string; str->add(key); a.insert(str, mi); return *str; } bool Tdnist_mask::load_odbc(TString_array& a) const { if (!get_bool(F_DSN_ON)) return false; TString query; query << "ODBC(" << get(F_DSN) << ")\n" << "SELECT chiavette.codice AS Chiave, Agente, RagioneSociale, DataDisattivazione\n" << "FROM chiavette,clienti WHERE chiavette.cliente=clienti.codice\n" << "ORDER BY Chiave"; TODBC_recordset att(query); TProgind pi(att.items(), get(F_DSN)); for (bool ok = att.move_first(); ok; ok = att.move_next()) { if (!pi.addstatus(1)) break; const int key = att.get("Chiave").as_int(); if (key > 0) { TToken_string& r = find_or_create_line(a, key); const int agente = att.get("Agente").as_int(); r.add(_oem.Agente2OEM(agente), _c_dboem); r.add(smart_trim(att.get("RagioneSociale").as_string(), 50), _c_dbowner); const TString& kill = att.get("DataDisattivazione").as_string(); if (kill.full() && kill.len() == 10) { const TString& stato = att.get("Stato").as_string(); switch (stato[0]) { case 'D': r.add(kill, _c_dbkilled); break; // Disdetto case 'S': r.add(kill, _c_dbsuspend); break; // Sospeso default: break; } } } } return !att.empty(); } static bool XmlScanner(TXmlItem& item, long jolly) { TToken_string& row = *(TToken_string*)jolly; if (item.GetTag() == "firm") { if (item.GetBoolAttr("Current")) row.add(item.GetAttr("RAGSOC"), _c_xmlowner); } else if (item.GetTag() == "dongle") { row.add(item.GetAttr("OEM"), _c_xmloem); } else if (item.GetTag() == "module") { const TDate date_new = item.GetAttr("Date"); const TDate date_old = row.get(_c_xmlaccess); if (date_new > date_old) row.add(date_new, _c_xmlaccess); } return false; } bool Tdnist_mask::load_xml(TString_array& a) const { if (!get_bool(F_FTP_ON)) return false; TFilename path = get(F_FTP); if (!path.ends_with(".xml")) { if (!path.ends_with("/")) path << '/'; path << "?????.xml"; } TString_array xml; list_files(path, xml); TString msg; msg.format(FR("Scansione cartella %s: %d files"), (const char*)path, xml.items()); TProgind pi(xml.items(), msg); TFilename fname; FOR_EACH_ARRAY_ROW(xml, r, row) { if (!pi.addstatus(1)) break; fname = *row; const TString& n = fname.name_only(); const int sn = atoi(n); if (sn > 0) { TToken_string& r = find_or_create_line(a, sn); TXmlItem i; i.Load(fname); i.ForEach(XmlScanner, (long)&r); } } return !xml.empty(); } void Tdnist_mask::fill_sheet() { TSheet_field& s = sfield(F_DNSHEET); s.destroy(); TString_array& a = s.rows_array(); load_dninst(a); load_odbc(a); load_xml(a); const int sort = get_int(F_SORT); a.TArray::sort(dongle_compare, (void*)&sort); FOR_EACH_ARRAY_ROW(a, r, row) { const char* o1 = row->get(_c_owner); const char* o2 = row->get(_c_dbowner); const char* o3 = row->get(_c_xmlowner); if (o2 && *o2 > ' ') { const double cmp = xvt_str_fuzzy_compare_ignoring_case(o1, o2); if (cmp < 0.7) { if (cmp == 0) s.set_back_and_fore_color(FOCUS_BACK_COLOR, FOCUS_COLOR, r, _c_dbowner); else s.set_back_and_fore_color(REQUIRED_BACK_COLOR, NORMAL_COLOR, r, _c_dbowner); } } if (o3 && *o3 > ' ') { const char* o1 = row->get(2); const double cmp = xvt_str_fuzzy_compare_ignoring_case(o1, o3); if (cmp < 0.7) { if (cmp == 0) s.set_back_and_fore_color(FOCUS_BACK_COLOR, FOCUS_COLOR, r, _c_xmlowner); else s.set_back_and_fore_color(REQUIRED_BACK_COLOR, NORMAL_COLOR, r, _c_xmlowner); } } } s.force_update(); enable(DLG_ELABORA, !s.empty()); } void Tdnist_mask::merge_sheet() { TSheet_field& sheet = sfield(F_DNSHEET); TString16 killed; TString o1, o2, o3; TString c1, c2, c3; int changed = 0; FOR_EACH_SHEET_ROW(sheet, r, row) { const int key = row->get_int(_c_key); c1 = row->get(_c_owner); c2 = row->get(_c_dbowner); c3 = row->get(_c_xmlowner); if (c1.blank()) { if (c2.full()) { c1 = c2; o1 = row->get(_c_dboem); } else if (c3.full()) { c1 = c3; o1 = row->get(_c_xmloem); } if (c1.full()) { row->add(o1, _c_oem); row->add(c1, _c_owner); changed++; } } else { o1 = row->get(_c_oem); if (o1.blank()) { o2 = row->get(_c_dboem); if (o2.full()) { row->add(o2, _c_oem); changed++; } } } killed = row->get(_c_killed); if (killed.blank()) { killed = row->get(_c_dbkilled); if (killed.full()) row->add(killed, _c_killed); } } sheet.force_update(); TString msg; msg.format(FR("Sono state aggiornate %d chiavi"), changed); xvt_dm_popup_message(msg); } bool Tdnist_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case DLG_RECALC: if (e == fe_button && check_fields()) { save_profile(); const TString& n = remote_dninst(); if (n.full()) { TFilename tmp; tmp.tempdir(); tmp.add("dninst.zip"); if (fcopy(n, tmp, false, true) && fsize(tmp) > 0) { fcopy(tmp, DNINST_ZIP); tmp.fremove(); } else cantread_box(n); } fill_sheet(); } break; case DLG_ELABORA: if (e == fe_button && yesno_box(TR("Riporare sul DNINST tutte le chiavi presenti solo su DB?"))) { merge_sheet(); } break; case DLG_SAVEREC: if (e == fe_button) { TSheet_field& sheet = sfield(F_DNSHEET); TString str; FOR_EACH_SHEET_ROW(sheet, r, row) { const int key = row->get_int(0); str = row->get(_c_oem); _dninst.set(key, "OEM", str.trim()); str = row->get(_c_owner); _dninst.set(key, "Owner", str.trim()); str = row->get(_c_suspend); _dninst.set(key, "MustCall", str.trim()); str = row->get(_c_killed); _dninst.set(key, "*", str.trim()); } if (_dninst.save()) { fill_sheet(); const TString& ftp = remote_dninst(); if (ftp != DNINST_ZIP && ftp.starts_with("ftp://") && yesno_box(FR("Copiare il DNINST locale in %s?"), (const char*)ftp)) { if (!xvt_fsys_fcopy(DNINST_ZIP, ftp)) cantwrite_box(ftp); } } } break; case F_DSN: if (e == fe_button && !o.empty()) { TString query; query << "ODBC(" << get(F_DSN) << ")\n" << "SELECT * FROM chiavette,clienti WHERE chiavette.cliente=clienti.codice\n" << "ORDER BY "; switch(get_int(F_SORT)) { case 1: query << "agente,RagioneSociale"; break; case 2: query << "RagioneSociale,chiavette.codice"; break; default: query << "chiavette.codice"; break; } TODBC_recordset att(query); if (att.move_first()) { TRecordset_sheet sheet(att, TR("Chiavi"),0x10); sheet.run(); } } break; case F_SORT: if (e == fe_modify) { TSheet_field& s = sfield(F_DNSHEET); const int sort = get_int(F_SORT); s.rows_array().TArray::sort(dongle_compare, (void*)&sort); s.force_update(); } break; case F_DNSHEET: if (e == se_query_add || e == se_query_del) return false; break; case F_SUSPEND: case F_KILLED: if (e == fe_magic) { const TDate oggi(TODAY); o.set(oggi.string()); } break; default: break; } return true; } Tdnist_mask::Tdnist_mask() : TAutomask("ba2800a") { const TSheet_field& s = sfield(F_DNSHEET); TMask& m = s.sheet_mask(); _c_key = s.cid2index(F_NUMBER); _c_oem = s.cid2index(F_OEM); _c_owner = s.cid2index(F_OWNER); _c_suspend = s.cid2index(F_SUSPEND); _c_killed = s.cid2index(F_KILLED); _c_dboem = s.cid2index(F_DBOEM); _c_dbowner = s.cid2index(F_DBOWNER); _c_dbsuspend= s.cid2index(F_DBSUSPEND); _c_dbkilled = s.cid2index(F_DBKILLED); _c_xmloem = s.cid2index(F_ATOEM); _c_xmlowner = s.cid2index(F_ATOWNER); _c_xmlaccess= s.cid2index(F_ATACCESS); } /////////////////////////////////////////////////////////// // Tdninst_manager /////////////////////////////////////////////////////////// class Tdninst_manager : public TSkeleton_application { protected: virtual bool use_files() const { return false; } virtual bool create(); virtual void main_loop(); }; bool Tdninst_manager::create() { const word n = dongle().number(); if (n != 8453 && !is_power_station()) return error_box(TR("Postazione non abilitata")); if (user() != dongle().administrator()) return error_box(TR("Utente non abilitato")); TSheet_field::set_line_number_width(4); // Numero di chiavette ~ 1000 return TSkeleton_application::create(); } void Tdninst_manager::main_loop() { Tdnist_mask m; m.run(); } int ba2800(int argc, char* argv[]) { Tdninst_manager a; a.run(argc, argv, TR("Gestione attivazioni")); return 0; }