git-svn-id: svn://10.65.10.50/branches/R_10_00@22899 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			1104 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1104 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include <applicat.h>
 | ||
| #include <automask.h>
 | ||
| #include <colors.h>
 | ||
| #include <config.h>
 | ||
| #include <dongle.h>
 | ||
| #include <netsock.h>
 | ||
| #include <odbcrset.h>
 | ||
| #include <progind.h>
 | ||
| #include <reputils.h>
 | ||
| #include <utility.h>
 | ||
| #include <xml.h>
 | ||
| 
 | ||
| #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 TObject
 | ||
| {
 | ||
| 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  2: oem = 0; break; // Aga
 | ||
|   case  3: oem = 3; break; // Geisoft
 | ||
|   case  5: oem = 6; break; // Sipag -> Sicuri
 | ||
|   case  7: oem = 7; break; // Prassi Roma -> Itertec
 | ||
|   case  8:                 // Prassi Calabria
 | ||
|   case  9: oem = 8; break; // Metacalabria
 | ||
|   case 10: oem = 6; break; // Socogem -> Sicuri
 | ||
|   case 11: oem = 7; break; // Itertec
 | ||
|   case 13: oem = 2; break; // Tetractis
 | ||
|   case 14: oem = 9; break; // San Zeno informatica
 | ||
|   default: oem = 1; break; // Sirio
 | ||
|   }
 | ||
|   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(int version) const;
 | ||
| };
 | ||
| 
 | ||
| #define DNINST "setup/dninst."
 | ||
| const char* const DNINST_ZIP = DNINST"zip";
 | ||
| const char* const DNINST_TXT = DNINST"txt";
 | ||
| const char* const DNINST_BAK = DNINST"bak";
 | ||
| 
 | ||
| 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(int version) const
 | ||
| {
 | ||
|   Tdninst dninst;
 | ||
|   bool done = dninst.ok();
 | ||
| 
 | ||
|   if (done)
 | ||
|   {
 | ||
|     const int ass_year = version < 11 ? 2101 : 2121;
 | ||
|     ofstream out(DNINST_TXT);
 | ||
|     out << ass_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);
 | ||
| #ifdef DBG
 | ||
|     if (version == 11)
 | ||
|       fcopy(DNINST_TXT, "../src/setup/dninst.txt");
 | ||
| #endif
 | ||
|   }
 | ||
| 
 | ||
|   return done;
 | ||
| }
 | ||
| 
 | ||
| ///////////////////////////////////////////////////////////
 | ||
| // Tdninst_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_xmlyear, _c_xmlaccess;
 | ||
| 
 | ||
| class Tdninst_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(int version) const;
 | ||
| 
 | ||
|   void load_dninst(TString_array& a);
 | ||
|   bool load_odbc(TString_array& a) const;
 | ||
|   bool load_xml(TString_array& a) const;
 | ||
|   TToken_string& find_or_create_line(TString_array& a, int key) const;
 | ||
| 
 | ||
| protected:
 | ||
|   virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
 | ||
|   bool on_sheet_event(TSheet_field& s, TField_event e, long jolly);
 | ||
|   bool fill_sheet();
 | ||
|   void merge_sheet();
 | ||
|   void save_sheet();
 | ||
|   void log(int severity, const char* msg) const;
 | ||
|   bool get_remote_dninst();
 | ||
|   bool send_remote_dninst(const TString& ftp) const;
 | ||
| 
 | ||
| public:
 | ||
|   void overnight_batch();
 | ||
| 
 | ||
|   Tdninst_mask();
 | ||
| };
 | ||
| 
 | ||
| void Tdninst_mask::log(int severity, const char* msg) const 
 | ||
| {
 | ||
|   FILE* f = fopen("DNINST.log", "a");
 | ||
|   if (f != NULL)
 | ||
|   {
 | ||
|     if (msg && *msg > ' ')
 | ||
|     {
 | ||
|       char sev = ' ';
 | ||
|       switch (severity)
 | ||
|       {
 | ||
|       case  0: sev = ' '; break;
 | ||
|       case  1: sev = '-'; break;
 | ||
|       default: sev = '!'; break;
 | ||
|       }
 | ||
|       time_t rawtime; time(&rawtime);
 | ||
|       struct tm * timeinfo = localtime (&rawtime);
 | ||
|       fprintf(f, "%c %02d-%02d-%04d %02d:%02d:%02d %s\n", sev, 
 | ||
|               timeinfo->tm_mday, timeinfo->tm_mon, timeinfo->tm_year+1900,
 | ||
|               timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, 
 | ||
|               msg);
 | ||
|     }
 | ||
|     else
 | ||
|       fputc('\n', f);
 | ||
|     fclose(f);
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| void Tdninst_mask::overnight_batch()
 | ||
| {
 | ||
|   log(0, TR("Inizio procedura aggiornamento DNINST"));
 | ||
| 
 | ||
|   set(F_ZIP_ON, "X");
 | ||
|   set(F_DSN_ON, "X");
 | ||
|   set(F_XML_ON, "");
 | ||
|   on_field_event(efield(F_ZIP_WWW), fe_init, 0); 
 | ||
|   on_field_event(efield(F_DSN_WWW), fe_init, 0); 
 | ||
| 
 | ||
|   log(0, TR("Caricamento dati da DSN"));
 | ||
|   if (get_remote_dninst())
 | ||
|   {
 | ||
|     fill_sheet();
 | ||
|     log(0, TR("Elaborazione abilitazioni"));
 | ||
|     merge_sheet();
 | ||
| 
 | ||
|     log(0, TR("Salvataggio dati"));
 | ||
|     save_sheet();
 | ||
|   }
 | ||
| 
 | ||
|   log(0, TR("Fine procedura aggiornamento DNINST"));
 | ||
|   log(0, "\n");
 | ||
| }
 | ||
| 
 | ||
| int Tdninst_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;
 | ||
|   } else
 | ||
|   if (sort == 3)
 | ||
|   {
 | ||
|     const TDate a1 = d1.get(_c_xmlaccess); 
 | ||
|     const TDate a2 = d2.get(_c_xmlaccess); 
 | ||
|     int cmp = a2.date2ansi() - a1.date2ansi();
 | ||
|     if (cmp == 0)
 | ||
|       cmp = atoi(d1) - atoi(d2);
 | ||
|     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& Tdninst_mask::remote_dninst(int version) const
 | ||
| {
 | ||
|   if (!get_bool(F_ZIP_ON) || field(F_ZIP_WWW).empty())
 | ||
|     return EMPTY_STRING;
 | ||
| 
 | ||
|   if (version < 10)
 | ||
|   {
 | ||
|     int year, tag, patch;
 | ||
|     main_app().get_version_info(year, version, tag, patch);
 | ||
|   }
 | ||
| 
 | ||
|   TString& path = get_tmp_string();
 | ||
|   path << "ftp://" << get(F_ZIP_USR)
 | ||
|        << ':' << get(F_ZIP_PWD)
 | ||
|        << '@' << get(F_ZIP_WWW)
 | ||
|        << '/' << get(F_ZIP_USR)
 | ||
|        << "/release/v_" << version 
 | ||
|        << ".0/program/" << DNINST_ZIP;
 | ||
| 
 | ||
|   return path;
 | ||
| }
 | ||
| 
 | ||
| void Tdninst_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& Tdninst_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 Tdninst_mask::load_odbc(TString_array& a) const
 | ||
| {
 | ||
|   const TString& dsn = get(F_DSN_WWW);
 | ||
|   bool done = false;
 | ||
|   
 | ||
|   if (dsn.full())
 | ||
|   {
 | ||
|     TString query;
 | ||
|     query << "ODBC(" << dsn << ")\n"
 | ||
|           << "SELECT chiavette.Codice, chiavette.Cliente, clienti.RagioneSociale, clienti.Agente, clienti.DataDisattivazione, clienti.Stato"
 | ||
|           << "\nFROM chiavette JOIN clienti ON chiavette.cliente=clienti.codice" 
 | ||
|           << "\nORDER BY Codice";
 | ||
| 
 | ||
|     TODBC_recordset att(query);
 | ||
|     TProgind pi(att.items(), dsn);
 | ||
|     for (bool ok = att.move_first(); ok; ok = att.move_next())
 | ||
|     {
 | ||
|       if (!pi.addstatus(1)) break;
 | ||
|       const int key = att.get("Codice").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);
 | ||
| 
 | ||
|         TString16 kill;
 | ||
|         TString16 stato = att.get("Stato").as_string();
 | ||
|         if (stato[0] > 'A') // Non Attivo
 | ||
|           kill = att.get("DataDisattivazione").as_string();
 | ||
|         if (kill.blank())
 | ||
|         {
 | ||
|           query.cut(0);
 | ||
|           query << "ODBC(" << dsn << ")\n"
 | ||
|                 << "SELECT Chiave,DataAttivazione,DataScadenza\n"
 | ||
|                 << "FROM attivazioni WHERE Modulo IS NULL AND Chiave=" << r.get(0);
 | ||
|           TODBC_recordset ad(query);
 | ||
|           for (bool ok = ad.move_first(); ok; ok = ad.move_next())
 | ||
|           {
 | ||
|             const TString& attivaz = ad.get("DataAttivazione").as_string();
 | ||
|             const TString& disatt  = ad.get("DataScadenza").as_string();
 | ||
|             if (disatt > kill)
 | ||
|               kill = disatt; else
 | ||
|             if (attivaz > kill)
 | ||
|               kill.cut(0);
 | ||
|           }
 | ||
|           if (kill.full())
 | ||
|             stato = "Disdetto";
 | ||
|         }
 | ||
| 
 | ||
|         if (kill.full() && kill.len() == 10)
 | ||
|         {
 | ||
|           TDate d;
 | ||
|           if (kill[2] == '-')
 | ||
|             d = TDate(kill); else
 | ||
|           if (kill[4] == '-')
 | ||
|             d = TDate(atol(kill.strip("-")));
 | ||
|           if (d.year() >= 1990)
 | ||
|           {
 | ||
|             switch (stato[0])
 | ||
|             {
 | ||
|             case 'D': r.add(d.string(), _c_dbkilled); break;  // Disdetto
 | ||
|             case 'S': r.add(d.string(), _c_dbsuspend); break; // Sospeso
 | ||
|             default: break;                                   // Attivo
 | ||
|             }
 | ||
|           }
 | ||
|         }
 | ||
|   
 | ||
|         done = true;
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   if (!done)
 | ||
|   {
 | ||
|     if (is_running())
 | ||
|       cantread_box(dsn);
 | ||
|     else
 | ||
|     {
 | ||
|       TString msg; 
 | ||
|       msg << TR("Impossibile leggere i dati da ") << dsn;
 | ||
|       log(2, msg);
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   return done;
 | ||
| }
 | ||
| 
 | ||
| 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);
 | ||
| 
 | ||
|     const int year_new = item.GetIntAttr("Year");
 | ||
|     const int year_old = row.get_int(_c_xmlyear);
 | ||
|     if (year_new > year_old)
 | ||
|       row.add(year_new, _c_xmlyear);
 | ||
| 
 | ||
|   } 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 Tdninst_mask::load_xml(TString_array& a) const
 | ||
| {
 | ||
|   TFilename path;
 | ||
|   path << "ftp://" << get(F_XML_USR) 
 | ||
|        << ':' << get(F_XML_PWD) 
 | ||
|        << '@' << get(F_XML_WWW)
 | ||
|        << "/attivazioni/?????.xml";
 | ||
| 
 | ||
|   TString_array xml;
 | ||
|   list_files(path, xml);
 | ||
| 
 | ||
|   TString msg; msg.format(FR("Scansione %s: %d files"), (const char*)path, xml.items());
 | ||
|   TProgind pi(xml.items(), msg);
 | ||
|   TFilename fname, tmpname;
 | ||
|   TFilename tmpdir; tmpdir.tempdir(); tmpdir.add("www");
 | ||
|   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);
 | ||
|       tmpname = tmpdir; tmpname.add(fname.name());
 | ||
| 
 | ||
|       TXmlItem i;
 | ||
|       bool scan = false;
 | ||
|       if (!tmpname.exist())
 | ||
|       {
 | ||
|         scan = i.Load(fname);
 | ||
|         i.Save(tmpname);
 | ||
|       }
 | ||
|       else
 | ||
|         scan = i.Load(tmpname);
 | ||
|       if (scan)
 | ||
|         i.ForEach(XmlScanner, (long)&r);
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   return !xml.empty();
 | ||
| }
 | ||
| 
 | ||
| bool Tdninst_mask::get_remote_dninst()
 | ||
| {
 | ||
|   const TString& n = remote_dninst(11);
 | ||
|   if (n.full())
 | ||
|   {
 | ||
|     const int minsize = 46*1024;
 | ||
|     if (fcopy(n, DNINST_BAK, false, true))
 | ||
|     {
 | ||
|       const int size = fsize(DNINST_BAK);
 | ||
|       if (size > minsize)
 | ||
|       {
 | ||
|         fcopy(DNINST_BAK, DNINST_ZIP);
 | ||
|         remove(DNINST_BAK);
 | ||
|         return true;
 | ||
|       }
 | ||
|       else
 | ||
|       {
 | ||
|         TString msg; msg << TR("Il file dninst.zip remoto pesa solo ") << size << " bytes";
 | ||
|         if (is_running())
 | ||
|           error_box(msg);
 | ||
|         else
 | ||
|           log(2, msg);
 | ||
|         return false;
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
|   if (is_running())
 | ||
|     cantread_box(n);
 | ||
|   else
 | ||
|   {
 | ||
|     TString msg; msg << TR("Impossibile leggere ") << n;
 | ||
|     log(2, msg);
 | ||
|   }
 | ||
|   return false;
 | ||
| }
 | ||
| 
 | ||
| bool Tdninst_mask::fill_sheet()
 | ||
| {
 | ||
|   TSheet_field& s = sfield(F_DNSHEET);
 | ||
|   s.destroy();
 | ||
| 
 | ||
|   TString_array& a = s.rows_array();
 | ||
|   load_dninst(a);
 | ||
|   if (a.empty())
 | ||
|     return false;
 | ||
| 
 | ||
|   if (get_bool(F_DSN_ON) && !field(F_DSN_WWW).empty())
 | ||
|   {
 | ||
|     if (!load_odbc(a))
 | ||
|       return false;
 | ||
|   }
 | ||
| 
 | ||
|   if (get_bool(F_XML_ON) && !field(F_XML_WWW).empty())
 | ||
|     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);
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|     TDate ds = row->get(_c_suspend);
 | ||
|     TDate dk = row->get(_c_killed);
 | ||
|     if (dk > ds) ds = dk;
 | ||
| 
 | ||
|     TDate dbs = row->get(_c_dbsuspend);
 | ||
|     TDate dbk = row->get(_c_dbkilled);
 | ||
|     if (dbk > dbs) dbs = dbk;
 | ||
| 
 | ||
|     if (ds != dbs)
 | ||
|     {
 | ||
|       if (dbs.ok())
 | ||
|         s.set_back_and_fore_color(FOCUS_BACK_COLOR, FOCUS_COLOR, r, _c_suspend);
 | ||
|       else
 | ||
|         s.set_back_and_fore_color(FOCUS_BACK_COLOR, FOCUS_COLOR, r, _c_dbsuspend);
 | ||
|     }
 | ||
|     if (dk != dbk)
 | ||
|     {
 | ||
|       if (dbk.ok())
 | ||
|         s.set_back_and_fore_color(FOCUS_BACK_COLOR, FOCUS_COLOR, r, _c_killed);
 | ||
|       else
 | ||
|         s.set_back_and_fore_color(FOCUS_BACK_COLOR, FOCUS_COLOR, r, _c_dbkilled);
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   s.force_update();
 | ||
| 
 | ||
|   const bool on = !s.empty();
 | ||
|   enable(DLG_ELABORA, on);
 | ||
|   enable(DLG_SAVEREC, on);
 | ||
|   return true;
 | ||
| }
 | ||
| 
 | ||
| void Tdninst_mask::merge_sheet()
 | ||
| {
 | ||
|   TLog_report log;
 | ||
|   TString msg;
 | ||
| 
 | ||
|   TSheet_field& sheet = sfield(F_DNSHEET);
 | ||
| 
 | ||
|   TString16 killed;
 | ||
|   TString o1, o2, o3;
 | ||
|   TString c1, c2, c3;
 | ||
|   TString d1, d2;
 | ||
| 
 | ||
|   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);
 | ||
|       }
 | ||
|       if (c3.full())
 | ||
|       {
 | ||
|         c1 = c3;
 | ||
|         o1 = row->get(_c_xmloem);
 | ||
|       }
 | ||
|       if (c1.full())
 | ||
|       {
 | ||
|         row->add(o1, _c_oem);
 | ||
|         row->add(c1, _c_owner);
 | ||
|         changed++;
 | ||
| 
 | ||
|         msg.cut(0) << key << " : ";
 | ||
|         msg << TR("Inserito cliente ") << c1;
 | ||
|         log.log(0, msg); 
 | ||
|       }
 | ||
|     } 
 | ||
|     else
 | ||
|     {
 | ||
|       o1 = row->get(_c_oem);
 | ||
|       if (o1.blank())
 | ||
|       {
 | ||
|         o2 = row->get(_c_dboem);
 | ||
|         if (o2.full())
 | ||
|         {
 | ||
|           row->add(o2, _c_oem);
 | ||
|           changed++;
 | ||
| 
 | ||
|           msg.cut(0) << key << " : ";
 | ||
|           msg << TR("Aggiornato agente del cliente ") << c1;
 | ||
|           log.log(0, msg); 
 | ||
|         }
 | ||
|       }
 | ||
| 
 | ||
|       c2 = row->get(_c_dbowner);
 | ||
|       if (c2.full() && c1 != c2)
 | ||
|       {
 | ||
|         row->add(c2, _c_owner);
 | ||
|         changed++;
 | ||
| 
 | ||
|         if (xvt_str_fuzzy_compare_ignoring_case(c1, c2) < 0.7)
 | ||
|         {
 | ||
|           msg.cut(0) << key << " : ";
 | ||
|           msg << TR("Aggiornata ragione sociale da '")
 | ||
|               << c1 << "' a '" << c2 << "'";
 | ||
|           log.log(0, msg); 
 | ||
|         }
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|     d1 = row->get(_c_suspend);   d1.trim();
 | ||
|     d2 = row->get(_c_dbsuspend); d2.trim();
 | ||
|     if (d2.full() && d1 != d2)
 | ||
|     {
 | ||
|       row->add(d2, _c_suspend);
 | ||
|       changed++;
 | ||
|       msg.cut(0) << key << " : ";
 | ||
|       msg << TR("Sospensione del cliente ")
 | ||
|           << c1 << TR(" dal ") << d2;
 | ||
|       log.log(1, msg); 
 | ||
|     }
 | ||
| 
 | ||
|     d1 = row->get(_c_killed);   d1.trim();
 | ||
|     d2 = row->get(_c_dbkilled); d2.trim();
 | ||
|     if (d2.full() && d1 != d2)
 | ||
|     {
 | ||
|       row->add(d2, _c_killed);
 | ||
|       changed++;
 | ||
|       msg.cut(0) << key << " : ";
 | ||
|       msg << TR("Disattivazione del cliente ")
 | ||
|           << c1 << TR(" dal ") << d2;
 | ||
|       log.log(2, msg); 
 | ||
|     }
 | ||
|   }
 | ||
|   sheet.force_update();
 | ||
| 
 | ||
|   log.preview();
 | ||
| }
 | ||
| 
 | ||
| bool Tdninst_mask::send_remote_dninst(const TString& ftp) const
 | ||
| {
 | ||
|   int at = ftp.find('@', 6); if (at < 0) at = 5;
 | ||
|   int slash = ftp.find('/', at+1);
 | ||
|   const TString& server = ftp.sub(at+1, slash);
 | ||
| 
 | ||
|   bool sent = false;
 | ||
|   TSocketClient aga;
 | ||
|   CONNID id = aga.QueryConnection("21", server);
 | ||
|   if (id > 0)
 | ||
|   {
 | ||
|     TString16 user = "guastalla", password = "tk0nmo4q3";
 | ||
|     const int colon = ftp.find(':', 6);
 | ||
|     if (colon > 6 && colon < at)
 | ||
|     {
 | ||
|       user = ftp.sub(6, colon);
 | ||
|       password = ftp.sub(colon+1, at);
 | ||
|     }
 | ||
|     sent = aga.FtpSendFile(id, ftp.mid(slash), DNINST_ZIP, user, password);
 | ||
|     aga.RemoveConnection(id);
 | ||
|   }
 | ||
|   if (!sent)
 | ||
|   {
 | ||
|     if (is_running())
 | ||
|       cantwrite_box(ftp);
 | ||
|     else
 | ||
|     {
 | ||
|       TString msg;
 | ||
|       msg << TR("Impossibile aggiornare il file ") << ftp;
 | ||
|       log(2, msg);
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   return sent;
 | ||
| }
 | ||
| 
 | ||
| void Tdninst_mask::save_sheet()
 | ||
| {
 | ||
|   TSheet_field& sheet = sfield(F_DNSHEET);
 | ||
|   TString str;
 | ||
|   FOR_EACH_SHEET_ROW(sheet, r, row)
 | ||
|   {
 | ||
|     const int key = row->get_int(0);
 | ||
|     if (key > 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(10))
 | ||
|   {
 | ||
|     fill_sheet();
 | ||
|     const TFilename ftp10 = remote_dninst(10);
 | ||
|     if (ftp10 != DNINST_ZIP && ftp10.starts_with("ftp://"))
 | ||
|     if (!is_running() || yesno_box(FR("Copiare il DNINST locale in %s?"), (const char*)ftp10))
 | ||
|     {
 | ||
|       send_remote_dninst(ftp10);
 | ||
| 
 | ||
|       if (fcopy(DNINST_ZIP, DNINST_BAK))
 | ||
|       {
 | ||
|         _dninst.save(11);
 | ||
|         const TFilename ftp11 = remote_dninst(11);
 | ||
|         send_remote_dninst(ftp11);
 | ||
|         fcopy(DNINST_BAK, DNINST_ZIP);
 | ||
|         remove(DNINST_BAK);
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| bool Tdninst_mask::on_sheet_event(TSheet_field& s, TField_event e, long jolly)
 | ||
| {
 | ||
|   static word _last_serno = 0;
 | ||
| 
 | ||
|   switch (e)
 | ||
|   {
 | ||
|   case se_query_add: // Lascio aggiungere una riga alla volta
 | ||
|     {
 | ||
|       TToken_string& r = s.row(s.items()-1);
 | ||
|       _last_serno = r.get_int(0);
 | ||
|       if (_last_serno > 0)
 | ||
|       {
 | ||
|         char str[8] = "";
 | ||
|         xvt_dm_post_string_prompt(TR("Inserire il numero di serie"), str, sizeof(str));
 | ||
|         _last_serno = atoi(str);
 | ||
|         if (_last_serno > 0)
 | ||
|         {
 | ||
|           FOR_EACH_SHEET_ROW(s, r, row)
 | ||
|           {
 | ||
|             if (row->get_int(0) == _last_serno)
 | ||
|             {
 | ||
|               error_box(TR("Chiave gi<67> inserita"));
 | ||
|               s.post_select(r);
 | ||
|               _last_serno = 0;
 | ||
|               break;
 | ||
|             }
 | ||
|           }
 | ||
|         }
 | ||
|       }
 | ||
|       return _last_serno > 0; 
 | ||
|     }
 | ||
|   case se_notify_add:
 | ||
|     s.row(jolly).add(_last_serno, 0);
 | ||
|     break;
 | ||
|   case se_notify_modify:
 | ||
|     {
 | ||
|       TToken_string& r = s.row(jolly);
 | ||
|       const int serno = r.get_int(0);
 | ||
|       if (serno == _last_serno)
 | ||
|       {
 | ||
|         if (yesno_box(FR("Si desidera salvare la nuova chiave %d?"), serno))
 | ||
|           send_key(K_SPACE, DLG_SAVEREC, &s);
 | ||
|         _last_serno = 0;
 | ||
|       }
 | ||
|     }
 | ||
|     break;
 | ||
|   case se_query_del: 
 | ||
|     {
 | ||
|       TToken_string& r = s.row(jolly);
 | ||
|       const int serno = r.get_int(0);    
 | ||
|       return delete_box("Si desidera eliminare la chiave %d", serno);
 | ||
|     }
 | ||
|     break;
 | ||
|   default: break;
 | ||
|   }
 | ||
|   return true;
 | ||
| }
 | ||
| 
 | ||
| bool Tdninst_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
 | ||
| { 
 | ||
|   switch (o.dlg())
 | ||
|   {
 | ||
|   case DLG_RECALC:
 | ||
|     if (e == fe_button && check_fields())
 | ||
|     {
 | ||
|       get_remote_dninst();
 | ||
|       fill_sheet();
 | ||
|     }
 | ||
|     break;
 | ||
|   case DLG_ELABORA:
 | ||
|     if (e == fe_button && yesno_box(TR("Aggiornare il DNINST in base al DB")))
 | ||
|        merge_sheet();
 | ||
|     break;
 | ||
|   case DLG_SAVEREC:
 | ||
|     if (e == fe_button)
 | ||
|       save_sheet();
 | ||
|     break;
 | ||
|   case F_ZIP_ON:
 | ||
|     if (e == fe_init && o.get().empty())
 | ||
|       set(F_ZIP_ON, "X", 0x1);
 | ||
|     break;
 | ||
|   case F_ZIP_WWW:
 | ||
|     if ((e == fe_init || e == fe_modify || e == fe_close) && o.empty())
 | ||
|     {
 | ||
|       set(F_ZIP_WWW, "85.18.53.183");
 | ||
|       set(F_ZIP_USR, "guastalla");
 | ||
|       set(F_ZIP_PWD, "tk0nmo4q3");
 | ||
|     }
 | ||
|     break;
 | ||
|   case F_DSN_WWW:
 | ||
|     if (e == fe_button)
 | ||
|     {
 | ||
|       if (o.empty())
 | ||
|       {
 | ||
|         TConfig odbc("c:/windows/odbc.ini", "ODBC 32 bit Data Sources");
 | ||
|         TAssoc_array& var = odbc.list_variables();
 | ||
|         if (!var.empty())
 | ||
|         {
 | ||
|           TArray_sheet dsn(-1, -1, 78, 20, TR("Sorgenti dati ODBC"), HR("Nome@25|Driver@50"));
 | ||
|           TToken_string row;
 | ||
|           FOR_EACH_ASSOC_OBJECT(var, obj, key, itm)
 | ||
|           {
 | ||
|             row = key;
 | ||
|             row.add(*(TString*)itm);
 | ||
|             dsn.add(row);
 | ||
|           }
 | ||
|           if (dsn.run() == K_ENTER)
 | ||
|             o.set(dsn.row(-1).get(0));
 | ||
|         }
 | ||
|       }
 | ||
|       else
 | ||
|       {
 | ||
|         TString query;
 | ||
|         query << "ODBC(" << o.get() << ")\n"
 | ||
|               << "SELECT chiavette.Codice AS Chiave, chiavette.Cliente, clienti.RagioneSociale AS 'Ragione Sociale', "
 | ||
|               << "clienti.Stato, clienti.DataDisattivazione AS Data, "
 | ||
|               << "agenti.Codice AS Agente, agenti.RagioneSociale AS Rivenditore"
 | ||
|               << "\nFROM (chiavette JOIN clienti ON chiavette.cliente=clienti.codice) JOIN agenti ON clienti.Agente=agenti.Codice" 
 | ||
|               << "\nORDER BY ";
 | ||
|         switch (get_int(F_SORT))
 | ||
|         {
 | ||
|         case  1: query << "Agente,clienti.RagioneSociale,Chiave"; break;
 | ||
|         case  2: query << "clienti.RagioneSociale,Chiave"; break;
 | ||
|         default: query << "Chiave"; break;
 | ||
|         }
 | ||
| 
 | ||
|         TODBC_recordset att(query);
 | ||
| 
 | ||
|         bool connected = false;
 | ||
|         if (!connected) // Dummy test
 | ||
|         {
 | ||
|           TWait_cursor hourglass;
 | ||
|           connected = att.move_first();
 | ||
|         }
 | ||
| 
 | ||
|         if (connected)
 | ||
|         {
 | ||
|           TRecordset_sheet sheet(att, TR("Chiavi"),0x10);
 | ||
|           sheet.run();
 | ||
|         }
 | ||
|       }
 | ||
|     }
 | ||
|     break;
 | ||
|   case F_XML_WWW:
 | ||
|     if ((e == fe_init || e == fe_modify || e == fe_close) && o.empty())
 | ||
|     {
 | ||
|       o.set("85.18.53.183");
 | ||
|       set(F_XML_USR, "attivazioni");
 | ||
|       set(F_XML_PWD, "viagra");
 | ||
|     }
 | ||
|     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 (o.is_sheet())
 | ||
|       return on_sheet_event((TSheet_field&)o, e, jolly);
 | ||
|     break;
 | ||
|   case F_SUSPEND:
 | ||
|   case F_KILLED:
 | ||
|     if (e == fe_magic)
 | ||
|     {
 | ||
|       const TDate oggi(TODAY);
 | ||
|       o.set(oggi.string());
 | ||
|     }
 | ||
|     break;
 | ||
|   default: break;
 | ||
|   }
 | ||
|   return true;
 | ||
| }
 | ||
| 
 | ||
| Tdninst_mask::Tdninst_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_xmlyear  = s.cid2index(F_ATYEAR);
 | ||
|   _c_xmlaccess= s.cid2index(F_ATACCESS);
 | ||
| 
 | ||
|   disable(DLG_ELABORA);
 | ||
|   disable(DLG_SAVEREC);
 | ||
| }
 | ||
| 
 | ||
| ///////////////////////////////////////////////////////////
 | ||
| // 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()
 | ||
| {
 | ||
|   if (user() != dongle().administrator())
 | ||
|     return error_box(TR("Utente non abilitato"));
 | ||
| 
 | ||
|   const word n = dongle().number();
 | ||
|   // 8453 = Ilaria; 8517 = Sara
 | ||
|   if (n != 8453 && n != 8517 && !is_power_station() && 
 | ||
|       get_hostname().compare("nbkgiardini", -1, true) != 0 && 
 | ||
|       get_hostname().compare("pcpiccolow7", -1, true) != 0)
 | ||
|     return error_box(TR("Postazione non abilitata"));
 | ||
| 
 | ||
|   TSheet_field::set_line_number_width(4); // Numero di chiavette ~ 1000
 | ||
| 
 | ||
|   return TSkeleton_application::create();
 | ||
| }
 | ||
| 
 | ||
| void Tdninst_manager::main_loop()
 | ||
| {
 | ||
|   Tdninst_mask m;
 | ||
| 
 | ||
|   const TFixed_string a(argv(1));
 | ||
|   if (a == "-A" || a == "/A")
 | ||
|     m.overnight_batch();
 | ||
|   else
 | ||
|     m.run();
 | ||
| }
 | ||
| 
 | ||
| int ba2800(int argc, char* argv[])
 | ||
| {                                             
 | ||
|   Tdninst_manager a;
 | ||
|   a.run(argc, argv, TR("Gestione attivazioni"));
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 |