campo-sirio/ba/ba2800.cpp
guy 15b790159f Correzione programma gestione DNINST
Correzione allineamento campi in maschera Banche
Correzione allineamento campi in maschera Contatti

git-svn-id: svn://10.65.10.50/branches/R_10_00@22653 c028cbd2-c16b-5b4b-a496-9718f37d4682
2012-05-23 14:20:02 +00:00

947 lines
23 KiB
C++
Raw Blame History

#include <applicat.h>
#include <assoc.h>
#include <automask.h>
#include <colors.h>
#include <config.h>
#include <dongle.h>
#include <netsock.h>
#include <odbcrset.h>
#include <progind.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 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(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_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 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 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(), 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;
}
}
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);
} 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 cartella %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(10);
if (n.full())
{
if (fcopy(n, DNINST_BAK, false, true) && fsize(DNINST_BAK) > 0)
{
fcopy(DNINST_BAK, DNINST_ZIP);
remove(DNINST_BAK);
return true;
}
}
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);
}
}
}
s.force_update();
enable(DLG_ELABORA, !s.empty());
return true;
}
void Tdninst_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++;
}
}
}
o1 = row->get(_c_suspend); o1.trim();
c1 = row->get(_c_dbsuspend); c1.trim();
if (o1 != c1)
{
row->add(c1, _c_suspend);
changed++;
}
o1 = row->get(_c_killed); o1.trim();
c1 = row->get(_c_dbkilled); c1.trim();
if (o1 != c1)
{
row->add(c1, _c_killed);
changed++;
}
}
sheet.force_update();
TString msg; msg.format(FR("Sono stati aggiornati %d campi"), changed);
xvt_dm_popup_message(msg);
}
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);
}
}
}
}
static word _last_serno;
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 file DNINST in base al DB MySQL?")))
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 && !o.empty())
{
TString query;
query << "ODBC(" << o.get() << ")\n"
<< "SELECT * FROM chiavette,clienti WHERE chiavette.cliente=clienti.codice\n"
<< "ORDER BY ";
switch(get_int(F_SORT))
{
case 1: query << "agente,RagioneSociale,chiavette.codice"; 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_XML_WWW:
if ((e == fe_init || e == fe_modify || e == fe_close) && o.empty())
{
o.set(get(F_XML_WWW));
if (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:
switch (e)
{
case se_query_add: // Lascio aggiungere una riga alla volta
{
TSheet_field& s = (TSheet_field&)o;
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:
{
TSheet_field& s = (TSheet_field&)o;
s.row(jolly).add(_last_serno, 0);
}
break;
case se_notify_modify:
{
TSheet_field& s = (TSheet_field&)o;
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, &o);
_last_serno = 0;
}
}
break;
case se_query_del: return false;
default: break;
}
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_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();
// 8453 = Ilaria; 8517 = Sara; 8578 = Monica
if (n != 8453 && n != 8517 && !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()
{
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;
}