#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ba7.h" #include "ba7100a.h" #define NOT_TRANS -883 #define NOT_GEST -884 /////////////////////////////////////////////////////////// // TConfig utilities /////////////////////////////////////////////////////////// const TString& set_ini_var(int cfg, const char* para, const char* var, const char* val) { TConfig ini(cfg, para); const TString& prev = ini.get(var); if (val != NULL) ini.set(var, val); if (prev.blank()) return EMPTY_STRING; TString& tmp = get_tmp_string(); tmp = prev; return tmp; } inline const TString& get_ini_var(int cfg, const char* para, const char* var) { return set_ini_var(cfg, para, var, NULL); } /////////////////////////////////////////////////////////// // TMail_box /////////////////////////////////////////////////////////// class TMail_box : public TSocketClient { unsigned long _connection; public: bool default_params(TString& server, TString& user,TString& password); bool logon(const char* server = NULL, const char* usr = NULL, const char* pwd = NULL); virtual bool ok() const { return _connection != NULL; } bool list(TString_array& a); int get(TMail_messages& m); bool remove(const char* id); void logoff(); TMail_box(); ~TMail_box(); }; bool TMail_box::default_params(TString& server, TString& user,TString& password) { bool ok = true; if (server.blank()) { server = get_ini_var(CONFIG_INSTALL, "Server", "POP3"); if (server.empty()) ok = false; } if (user.blank()) user = ::user(); if (password.blank()) { const TString& pwd = cache().get(LF_USER, user).get("PASSWORD"); password = ::decode(pwd); } return ok; } bool TMail_box::logon(const char* ser, const char* usr, const char* pwd) { if (_connection) logoff(); if (!IsOk()) return error_box(TR("Impossibile inizializzare il client POP3")); TString server(ser); TString user(usr); TString password(pwd); if (!default_params(server, user, password)) return error_box(TR("E' necessario specificare un server POP3, un utente ed una password")); _connection = QueryConnection("110", server); if (_connection != 0) { TString buf, req; ReadLine(_connection, buf); if (buf[0] != '+') return error_box(FR("Il server POP3 %s non risponde\nRisultato : %s"), (const char*)server, (const char *)buf); buf = "USER "; buf << user << "\r\n"; WriteLine(_connection, buf); req = buf; ReadLine(_connection, buf); if (buf[0] != '+') return error_box(FR("Il server POP3 %s non accetta l'utente %s\nRichiesta : %sRisultato : %s"), (const char*)server, (const char*)user, (const char *) req, (const char *)buf); buf = "PASS "; buf << password << "\r\n"; WriteLine(_connection, buf); req = buf; ReadLine(_connection, buf); if (buf[0] != '+') return error_box(FR("Il server POP3 %s non accetta la password dell'utente %s\nRichiesta : %sRisultato : %s"), (const char*)server, (const char*)user, (const char *) req, (const char *)buf); } else return error_box(FR("Impossibile contattare il server POP3 %s"), (const char*)server); return true; } void TMail_box::logoff() { if (_connection) { WriteLine(_connection, "QUIT\r\n"); RemoveConnection(_connection); _connection = NULL; } } bool TMail_box::list(TString_array& a) { bool ok = _connection != NULL; if (ok) { TString buf; buf = "LIST\r\n"; WriteLine(_connection, buf); ReadLine(_connection, buf); ok = buf[0] == '+'; while (ok) { if (!ReadLine(_connection, buf)) break; // Unexpected EOF if (buf[0] == '.') break; int pos = buf.find(' '); if (pos > 0) buf.cut(pos); a.add(buf); } } return ok; } HIDDEN int str2month(const char* str) { const char* const mese[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; int m; for (m = 11; m > 0; m--) { if (xvt_str_compare_ignoring_case(str, mese[m]) == 0) break; } return m+1; } enum EncodingType { enc_plain_text, enc_quoted_printable, enc_base64 }; int TMail_box::get(TMail_messages& m) { // Lista dei caratteri validi const char* const Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+*"; // Lista per decodifica dei caratteri validi char Deco64[256]; memset(Deco64, ' ', sizeof(Deco64)); for (int i = 0; Base64[i]; i++) Deco64[Base64[i]] = i; TString_array a; list(a); TString buf, boundary, msg_line; m.destroy(); FOR_EACH_ARRAY_ROW(a, r, row) { TMail_message* msgptr = new TMail_message(user()); m.add(msgptr); TMail_message& msg = *msgptr; buf = "RETR "; buf << *row << "\r\n"; WriteLine(_connection, buf); ReadLine(_connection, buf); bool ok = buf[0] == '+'; EncodingType encoding = enc_plain_text; bool in_body = false; bool in_section = false; bool buf_already_read = false; boundary.cut(0); while (ok) { if (!buf_already_read) { if (!ReadLine(_connection, buf)) { ok = false; break; // Unexpected EOF } } else buf_already_read = false; if (buf[0] == '.') { buf.ltrim(1); if (buf.blank()) break; } if (in_body) { if (buf[0] == '-' && boundary.not_empty() && buf.find(boundary) >= 0) break; // Ignora sezioni di attachment switch (encoding) { case enc_base64: { unsigned val = 0; int bits = 0; msg_line.cut(0); for (const char* s = buf; *s && *s != '='; s++) { if (*s==0x0A || *s==0x0D || *s==0x20 || *s==0x09) continue; // Salta eventuali blanks val <<= 6; val |= Deco64[*s]; bits += 6; if (bits >= 8) { const char c = char((val >> (bits - 8)) & 0xFF); msg_line << c; bits -= 8; } } msg.add_line(msg_line); } break; case enc_quoted_printable: { msg_line.cut(0); for (const char* s = buf; *s; s++) { if (*s == '=') { s++; if (*s >= ' ') { int c; sscanf(s, "%2X", &c); msg_line << char(c); s++; } } else msg_line << *s; } msg.add_line(msg_line); } break; default: buf.rtrim(); msg.add_line(buf); break; } } else { if (boundary.not_empty()) { if (buf.blank()) { in_body = in_section; } else { if (buf.find(boundary) >= 0) in_section = true; } } else { if (buf.blank()) { in_body = true; continue; } } if (buf.compare("From:", 5, true) == 0) { buf.ltrim(6); buf.trim(); msg.set_sender(buf); continue; } if (buf.compare("To:", 3, true) == 0) { buf.ltrim(4); buf.trim(); msg.add_recipient(buf); continue; } if (buf.compare("Cc:", 3, true) == 0) { buf.ltrim(4); buf.trim(); msg.add_copy_recipient(buf); continue; } if (buf.compare("Subject:", 8, true) == 0) { buf.ltrim(9); buf.trim(); msg.set_subject(buf); continue; } if (buf.compare("Date:", 5, true) == 0) { TToken_string d(buf.mid(6), ' '); d.trim(); int giorno = d.get_int(1); int mese = str2month(d.get()); int anno = d.get_int(); if (anno < 100) anno += 2000; TString16 ora = d.get(); buf.cut(0); buf << anno << '/' << mese << '/' << giorno << ' ' << ora; msg.set_date_time(buf); continue; } if (buf.compare("Content-Transfer-Encoding:", 26, true) == 0) { if (buf.find("base64") > 0) encoding = enc_base64; else if (buf.find("quoted-printable") > 0) encoding = enc_quoted_printable; continue; } if (buf.compare("Content-Type:", 13, true) == 0) { int bnd = buf.find("oundary="); // Funziona per Boundary e boundary if (bnd < 0) { ReadLine(_connection, buf); bnd = buf.find("oundary="); if (bnd < 0) buf_already_read = true; } if (bnd > 0) { const int apicia = buf.find('"', bnd); const int apicic = buf.find('"', apicia+1); if (apicia > 0 && apicic > apicia) boundary = buf.sub(apicia+1, apicic); } continue; } } } } return m.items(); } bool TMail_box::remove(const char* id) { bool ok = _connection != NULL; if (ok) { TString buf; buf << "DELE " << id << "\r\n"; WriteLine(_connection, buf); ReadLine(_connection, buf); ok = buf[0] == '+'; } return ok; } TMail_box::TMail_box() : _connection(NULL) { } TMail_box::~TMail_box() { logoff(); } /////////////////////////////////////////////////////////// // TFilter_expr /////////////////////////////////////////////////////////// class TFilter_expr : public TExpression { TAutomask& _mask; protected: virtual bool print_error(const char* msg) const; public: TFilter_expr(TAutomask& m, int logicnum, const char* expr); virtual ~TFilter_expr() { } }; bool TFilter_expr::print_error(const char* msg) const { return _mask.error_box(msg); } TFilter_expr::TFilter_expr(TAutomask& m, int logicnum, const char* expr) : _mask(m) { bool ok = set(expr, _strexpr); if (ok) { if (logicnum < LF_USER || logicnum >= prefix().items()) logicnum = LF_TABCOM; // Niente errori fatali, se possibile const TRectype rec(logicnum); for (int i = 0; i < numvar(); i++) { const TFixed_string name(varname(i)); int num = logicnum; bool ok = rec.exist(name); if (!ok) { const TFieldref f(name, 0); int num = table2logic(f.id()); const TRectype join(num); ok = join.exist(f.name()); } if (!ok) { _error = 883; TString msg; msg.format(FR("Il campo %s non appartiene al file %d"), varname(i), logicnum); print_error(msg); break; } } } } /////////////////////////////////////////////////////////// // TMailer_mask /////////////////////////////////////////////////////////// class TMailer_mask : public TAutomask { long _timer_id; long _secs; long _interval; int _mail_semaphore; TMail_messages _box; bool _sequential; clock_t _last_use; TString_array _key1; // Elenco dei campi della chiave principale dei files TAssoc_array _apps; // Elenco delle applicazioni per processare i files protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); virtual long handler(WINDOW win, EVENT* ep); protected: bool file2app(const TString& file, TString& app) const; void expand_tabs(TMail_message& str, const int tab = 8) const; void save_sheet(TConfig& ini, short dlg, const char* var) const; void load_sheet(TConfig& ini, short dlg, const char* var); TToken_string& get_key1(int lf) const; bool build_key1(int lf, const TString& body, TToken_string& key, TString& action) const; bool build_key1(const TMail_message& msg, TToken_string& key, TString& action) const; void find_redundant_messages(); void track(const TMail_message& msg, const TString& app, const TString& action, int err); bool exec_app(int & err, const TString& appname, TMail_message & msg, TToken_string & sh_row); void scan_dir(const TFilename& dir, TMail_messages& box) const; bool unattended() const; public: void test_delete(); void fill_messages(); bool save_sheet_line(int& err, int line = -1); void save_all_lines(); void auto_save_all(); void save() const; void load(); TMailer_mask(); virtual ~TMailer_mask(); }; void TMailer_mask::test_delete() { if (_mail_semaphore != 0) return; _mail_semaphore = 1; TWait_cursor hourglass; xvtil_statbar_set(TR("Eliminazione messaggi...")); do_events(); TSheet_field& sf = sfield(F_MESSAGES); const int sender_pos = sf.cid2index(F_SENDER); const int mailer_pos = sf.cid2index(F_MAILER); const int msgid_pos = sf.cid2index(F_ID); TString4 mailer; TString id; TMail_messages mapidel; // Lista dei messaggi MAPI da cancellare TMail_box mailbox; FOR_EACH_SHEET_ROW_BACK(sf, nrow, row) if (*row->get(0) == 'X') { row->get(mailer_pos, mailer); row->get(msgid_pos, id); bool deleted = false; if (mailer == "POP3") { if (!mailbox.ok()) { if (!mailbox.logon(get(F_SERVER), get(F_USER), get(F_PASSWORD))) break; } deleted = mailbox.remove(id); } else if (mailer == "CNP") { TFilename file; row->get(sender_pos, file); // Cartella di provenienza file.add(id); file.ext("ini"); file.fremove(); deleted = true; } else if (mailer == "MAPI") { TMail_message* msg = new TMail_message(""); msg->set_id(id); mapidel.add(msg); deleted = true; } if (deleted) { _box.destroy(nrow); sf.destroy(nrow); } else { TString err = TR("Impossibile cancellare il messaggio"); err << ' ' << id; xvtil_statbar_set(err); do_events(); beep(2); // Error sound } } if (mailbox.ok()) mailbox.logoff(); if (mapidel.items() > 0) { xvtil_statbar_set(TR("Eliminazione messaggi MAPI...")); do_events(); mapidel.remove(); } xvtil_statbar_set(TR("Pronto")); do_events(); _mail_semaphore = 0; } void TMailer_mask::expand_tabs(TMail_message& msg, const int tab) const { const int items = msg.items(); for (int n = 0; n < items; n++) { TString & str = msg.row(n); int start = 0; for (int i = 0; str[i]; i++) { switch(str[i]) { case '\n': case '\r': start = i+1; break; case '\t': { const int t = tab - ((i-start) % tab) - 1; str[i] = ' '; if (t > 0) { TString80 spac; spac.spaces(t); str.insert(spac, i+1); i += t; } } break; default: break; } } } } void TMailer_mask::scan_dir(const TFilename& dir, TMail_messages& box) const { TString_array msg; TFilename mask = dir; mask.add("*.ini"); ::list_files(mask, msg); TString subject, text, strdata; TToken_string id(_MAX_FNAME, '_'); FOR_EACH_ARRAY_ROW(msg, r, row) { const int size = fsize(*row); if (size > 64 && size < 48*1024) { char* buffer = text.get_buffer(size); TScanner scanner(*row); memset(buffer, 0 , size); scanner.read(buffer, size); buffer[size] = '\0'; subject.cut(0); int parc = text.find(']'); // fine primo paragrafo if (parc > 0) { int para = text.find('[', parc+1); if (para > 0) { parc = text.find(']', para+1); if (parc > 0) subject = text.sub(para+1, parc); } } if (subject.full()) { xvt_fsys_parse_pathname (*row, NULL, NULL, id.get_buffer(), NULL, NULL); TMail_message* msg = new TMail_message(user(), subject, text, dir); msg->set_id(id); if (id.items() == 3) // Nome file in formato YYMMDD_HHMMSS_NN.ini { strdata = id.get(0); strdata.insert("20"); const TDate data(strdata); const long hhmmss = id.get_long(1); msg->set_date_time(data, hhmmss); } else msg->set_date_time(TDate(TODAY)); box.add(msg); } } } } void TMailer_mask::fill_messages() { if (_mail_semaphore != 0) return; _mail_semaphore = 1; disable(DLG_DELREC); TWait_cursor hourglass; TFilename server(get(F_SERVER)); TString80 user(get(F_USER)); TString80 password(get(F_PASSWORD)); TMail_box mailbox; if (mailbox.default_params(server, user, password)) { set(F_SERVER, server); set(F_USER, user); set(F_PASSWORD, password); } expand_sys_vars(server); int totmapi = 0; if (get_bool(F_MAPI)) { xvtil_statbar_set(TR("Ricezione messaggi MAPI...")); do_events(); totmapi = _box.get(); } TString4 mailer; if (isalpha(server[0]) && server[1] == ':' && is_slash(server[2]) && server.exist()) { mailer = "CNP"; xvtil_statbar_set(TR("Ricezione messaggi CNP ...")); do_events(); scan_dir(server, _box); } else { mailer = "POP3"; xvtil_statbar_set(TR("Ricezione messaggi POP3...")); do_events(); mailbox.logon(server, user, password); mailbox.get(_box); mailbox.logoff(); } TSheet_field& sf = sfield(F_MESSAGES); sf.destroy(); TString mess; for (int m = 0; m < _box.items(); m++) { TMail_message& msg = _box.msg(m); TToken_string& row = sf.row(m); row.add(msg.sender(), sf.cid2index(F_SENDER)); row.add(msg.date(), sf.cid2index(F_DATE)); const real t = msg.time(); row.add(t.string("@@:@@:@@"), sf.cid2index(F_TIME)); row.add(msg.subject(), sf.cid2index(F_SUBJECT)); expand_tabs(msg); mess.cut(0); FOR_EACH_ARRAY_ROW(msg, i, msgrow) { mess << *msgrow; if (mess.len() >= 1024) { mess.cut(1024); break; } } row.add(mess, sf.cid2index(F_BODY)); if (m < totmapi) { row.add("MAPI", sf.cid2index(F_MAILER)); row.add(msg.id(), sf.cid2index(F_ID)); } else { row.add(mailer, sf.cid2index(F_MAILER)); if (mailer == "CNP") row.add(msg.id(), sf.cid2index(F_ID)); else row.add(m-totmapi+1, sf.cid2index(F_ID)); } } sf.force_update(); xvtil_statbar_set(TR("Pronto")); _mail_semaphore = 0; return; } bool TMailer_mask::file2app(const TString& file, TString& app) const { bool ok = false; const TString* run = (const TString*)_apps.objptr(file); if (run == NULL) { TConfig d(CONFIG_DITTA, "ba7"); TString16 appname; appname << "Edit_" << file; app = d.get(appname); if (app.empty()) { if (isdigit(file[0])) { const int filenum = atoi(file); if (filenum >= LF_USER && filenum < prefix().items()) { TLocalisamfile isf(filenum); ok = isf.get_relapp(app); } } else { const int len = file.len(); if (len == 3 || (len == 4 && file[0] == '%')) { TTable table(file); ok = table.get_relapp(app); } } } else ok = true; ((TMailer_mask*)this)->_apps.add(file, app); // Fool const } else { app = *run; ok = app.full(); } return ok; } bool is_incomplete(const TString& l) { if (l[0] == '[') return false; const char a = l.right(1)[0]; if (a == '=') return true; const int eq = l.find("= '"); if (eq > 0 && eq < 20) return a != '\''; return false; } void adjust_long_lines(const TFilename& tmp) { TFilename dst_name; dst_name.temp(); ofstream dst(dst_name); bool adjusted = false; TScanner org(tmp); while (true) { const TString& l = org.line(); if (l.empty()) break; if (is_incomplete(l)) { adjusted = true; dst << l; org.line(); char s = l[0]; if (s == '\'' || s == '"') { char c = l.right(1)[0]; while (c != '\'' && c != '"') { dst << l; org.line(); c = l.right(1)[0]; } } else dst << '\n'; } dst << l << '\n'; } org.close(); dst.close(); if (adjusted) fcopy(dst_name, tmp); dst_name.fremove(); } void TMailer_mask::track(const TMail_message& msg, const TString& app, const TString& action, int err) { const TString& fname = get(F_TRACKING); if (fname.full()) { const char fldsep = '\t'; const char recsep = '\n'; ofstream log(fname, ios::app); log << msg.sender() << fldsep; log << msg.date() << fldsep; const real t = msg.time(); log << t.string("@@:@@:@@") << fldsep; TToken_string k1; TString act; build_key1(msg, k1, act); log << k1.get(0) << fldsep; const int pipe = k1.find(k1.separator()); k1.ltrim(pipe+1); log << k1 << fldsep; log << app << fldsep << action << fldsep << err << fldsep; log << recsep; } } bool TMailer_mask::exec_app(int& err, const TString& appname, TMail_message& msg, TToken_string & sh_row) { err = NOERR; TString action; if (appname.compare("sink", -1, true) == 0) { FOR_EACH_ARRAY_ROW(msg, r, row) { int s = row->find("\nAction"); if (s > 0) { s = row->find('=', s); const int e = row->find('\n', s); action = row->sub(s+1, e); action.trim(); break; } } } else { TFilename tmp; tmp.temp(); { ofstream outf(tmp); const int items = msg.items(); bool long_lines = false; TString message; for (int i = 0; i < items; i++) { message = msg.row(i); message.replace('\r', '\n'); outf << message; } outf.close(); adjust_long_lines(tmp); TConfig ini(tmp, "Transaction"); ini.set("From", msg.sender()); action = ini.get("Action"); } TString command_line(appname); command_line << " /i" << tmp; TExternal_app app(command_line); err = app.run(false, true, false); // Don't iconize (nor restore) the task window! xvt_sys_sleep(1000); if (err == NOERR) { TConfig ini(tmp, "Transaction"); if (ini.get("Result").compare("OK", -1, true) == 0 || ini.get("Action").compare("RUN", -1, true) == 0) err = 0; else if (get_bool(F_DELCANCEL) && ini.get("Result").compare("Cancel", -1, true) == 0) err = 0; else err = ini.get_int("Error"); TFilename backup = get(F_BACKUP); expand_sys_vars(backup); if (backup.exist()) { const TSheet_field& sf = sfield(F_MESSAGES); TString id; TFilename file; sh_row.get(sf.cid2index(F_ID), id); sh_row.get(sf.cid2index(F_SENDER), file); // Cartella di provenienza file.add(id); file.ext("ini"); TFilename dest = backup; dest.add(file.name()); fcopy(tmp, dest); } } tmp.fremove(); } track(msg, appname, action, err); return err == NOERR; } bool TMailer_mask::save_sheet_line(int& err, int nrow) { TSheet_field& sf = sfield(F_MESSAGES); TMask& m = sf.sheet_mask(); if (nrow < 0) nrow = sf.selected(); else sf.update_mask(nrow); TToken_string& row = sf.row(nrow); const TString& msg = m.get(F_BODY); if (msg.find("[Transaction]") < 0) { err = NOT_TRANS; return false; // It's not a transaction } TString subj = m.get(F_SUBJECT); if (isalpha(subj[0])) // Controlla se la tabella in realtà è comune ed aggiunge il simbolino % { TString8 para; para << '[' << LF_TABCOM << ']'; if (msg.find(para) > 0) subj.insert("%"); } TFilename appname; if (!file2app(subj, appname)) // It hasn't a valid application { err = NOT_GEST; return false; } TMail_message& full_msg = _box.msg(nrow); bool ok = exec_app(err, appname, full_msg, row); if (!ok && err == _iskeynotfound) { TString & first_row = full_msg.row(0); int pos = first_row.find("MODIFY"); if (pos > 0) { first_row.overwrite("INSERT", pos); ok = exec_app(err, appname, full_msg, row); } } if (ok) { if (m.is_running()) { m.set(F_CHECKED, "X"); m.stop_run(K_AUTO_ENTER); } else { row.add("X", 0); sf.force_update(nrow); } } // Restore mail recipient // if (old_mailto.full()) // set_ini_var(CONFIG_INSTALL, "Main", "MailTo", old_mailto); return ok; } TToken_string& TMailer_mask::get_key1(int lf) const { TString_array& k = (TString_array&)_key1; // Fool constness TToken_string* key = k.rowptr(lf); if (key == NULL) { key = new TToken_string; // Creo una nuova entry const RecDes& recd = prefix().get_recdes(lf); // Descrizione del record della testata const KeyDes& kd = recd.Ky[0]; // Elenco dei campi della chiave 1 for (int i = 0; i < kd.NkFields; i++) { const int nf = kd.FieldSeq[i] % MaxFields; const RecFieldDes& rf = recd.Fd[nf]; key->add(rf.Name); } k.add(key, lf); } return *key; } bool TMailer_mask::build_key1(int lf, const TString& body, TToken_string& key, TString& action) const { key.format("%d", lf); TString16 field; // Nome del campo chiave TString value; // Valore del campo chiave TToken_string& key1 = get_key1(lf); // Elenco dei campi chiave FOR_EACH_TOKEN(key1, fld) { field = fld; field.insert("\n"); const int start = body.find(field); if (start < 0) return false; const int equal = body.find('=', start); if (equal < 0) return false; const int stop = body.find('\n', equal); if (stop < 0) return false; value = body.sub(equal+1, stop); value.trim(); if (value[0] == '"' && value.right(1) == "\"") // Toglie eventuali virgolette { value.rtrim(1); value.ltrim(1); } key.add(value); } const int act = body.find("\nAction"); const int ugu = body.find('=', act); const int nwl = body.find('\n', ugu); if (act > 0 && ugu > act && ugu < nwl) { action = body.sub(ugu+1,nwl); action.trim(); action.upper(); } return true; } bool TMailer_mask::build_key1(const TMail_message& msg, TToken_string& key, TString& action) const { TString body; FOR_EACH_ARRAY_ROW(msg, r, row) body << *row << '\n'; const TString& subj = msg.subject(); int lfile = LF_TAB; // Numero logico del file if (isalpha(subj[0])) // Controlla se la tabella in realtà è comune ed aggiunge il simbolino % { TString4 para; para << '[' << LF_TABCOM << ']'; if (body.find(para) > 0) lfile = LF_TABCOM; } else lfile = atoi(subj); return build_key1(lfile, body, key, action); } void TMailer_mask::find_redundant_messages() { // Elenco dei records (chiavi primarie) già processati (virtualmente) TAssoc_array andreotti; TSheet_field& sf = sfield(F_MESSAGES); TString subj, body, action; TToken_string key1; // Scorro tutti i messaggi non ancora elaborati FOR_EACH_SHEET_ROW_BACK(sf, nrow, row) if (row->get_char(0) != 'X') { row->get(sf.cid2index(F_BODY), body); if (body.find("[Transaction]") < 0) // Scarto i messaggi che non siano transazioni continue; row->get(sf.cid2index(F_SUBJECT), subj); int lfile = LF_TAB; // Numero logico del file if (isalpha(subj[0])) // Controlla se la tabella in realtà è comune ed aggiunge il simbolino % { TString4 para; para << '[' << LF_TABCOM << ']'; if (body.find(para) > 0) lfile = LF_TABCOM; } else lfile = atoi(subj); if (build_key1(lfile, body, key1, action)) { if (andreotti.is_key(key1) && action != "INSERT") // Non considero ridondanti gli inserimenti! row->add("R", 0); // Messaggio ridondante! else andreotti.add(key1); // Messaggio da processare! } } } void TMailer_mask::save_all_lines() { if (_mail_semaphore != 0) return; _mail_semaphore = 1; TBrowsefile_field& bf = (TBrowsefile_field&)field(F_LOG); TViswin& vv = bf.vis_win(); TString msg; time_t tempo; time(&tempo); const struct tm* d = localtime(&tempo); msg.format(FR("- Inizio elaborazione: %02d-%02d-%04d %02d:%02d:%02d"), d->tm_mday, d->tm_mon+1, 1900+d->tm_year, d->tm_hour, d->tm_min, d->tm_sec); vv.add_line(msg); find_redundant_messages(); bool one_saved = false; TSheet_field& sf = sfield(F_MESSAGES); FOR_EACH_SHEET_ROW(sf, nrow, row) { msg.format("Messaggio %d ", nrow+1); const char mark = *row->get(0); if (mark == 'X') msg << "ignorato in quanto già elaborato"; if (mark == 'R') { msg << "ignorato in quanto ridondante"; row->add("X", 0); // Marcalo come elaborato comunque } if (mark <= ' ') { TString body; row->get(sf.cid2index(F_BODY), body); if (body.find("[Transaction]") >= 0) { int err = 0; const bool yes = save_sheet_line(err, nrow); if (yes) { msg << "elaborato con successo"; one_saved = true; } else if (err == NOT_GEST) { const TMask& m = sf.sheet_mask(); msg << " definire il programma gestore del file " << m.get(F_SUBJECT); } else { msg << "non elaborato a causa di un errore (n.ro " << err << ')'; if (_sequential) break; } } else msg << "ignorato in quanto transazione non riconosciuta"; } vv.add_line(msg); } time(&tempo); d = localtime(&tempo); msg.format("- Fine elaborazione: %02d-%02d-%04d %02d:%02d:%02d", d->tm_mday, d->tm_mon+1, 1900+d->tm_year, d->tm_hour, d->tm_min, d->tm_sec); vv.add_line(msg); vv.add_line(""); vv.goto_end(); sf.force_update(); // Fai apparire tutte le X enable(DLG_DELREC); enable(DLG_DELLOG, bf.lines() > 0); #ifdef DBG one_saved &= yesno_box("Si desidera eliminare i messaggi processati?"); #endif _mail_semaphore = 0; if (one_saved) { test_delete(); fill_messages(); } } bool TMailer_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case F_TIMER: if (e == fe_init || e == fe_modify) { if (_timer_id != XVT_TIMER_ERROR) { xvt_timer_destroy(_timer_id); _timer_id = XVT_TIMER_ERROR; } _interval = atol(o.get()); if (_interval > 0) { _timer_id = xvt_timer_create(win(), 1000L); _secs = 0L; if (_timer_id == XVT_TIMER_ERROR) return error_box("Impossibile impostare il timer"); } } break; case F_MESSAGES: if (e == fe_init) { if (!field(F_SERVER).empty() && !field(F_USER).empty() && !field(F_PASSWORD).empty()) fill_messages(); } else if (e == se_query_add) { auto_save_all(); return false; } break; case DLG_USER: if (e == fe_button) { int err = 0; if (!save_sheet_line(err)) { if (err == NOT_TRANS) message_box(TR("Messaggio ignorato: transazione non riconosciuta")); else if (err == NOT_GEST) { TSheet_field& sf = sfield(F_MESSAGES); TMask& m = sf.sheet_mask(); error_box(FR("Definire il programma gestore del file %s"), (const char*)m.get(F_SUBJECT)); } else message_box(FR("Messaggio non elaborato a causa di un errore (n.ro %d)"), err); } } break; case DLG_SAVEREC: if (e == fe_button && jolly == 0) { if (curr_page() == 0) save_all_lines(); else save(); } break; case DLG_DELREC: if (e == fe_button) { if (jolly == 0) { test_delete(); fill_messages(); return false; } } break; case F_FILE: if (jolly == 3) { if (e == fe_button) { TMask& m = o.mask(); TArray_sheet sht(-1,-1,-4,-4,TR("Selezione archivio"), HR("Codice@6R|Descrizione archivio@70")); const TPrefix& pref = prefix(); const int total = pref.items(); if (total > 0) { TWait_cursor hourglass; for (int i = LF_USER; i < total; i++) { TToken_string* row = new TToken_string; *row << i; row->add(pref.description(*row)); sht.rows_array().add(row); } sht.select(m.get_int(o.dlg()) - LF_USER); } if (sht.run() == K_ENTER) m.set(o.dlg(), sht.selected() + LF_USER); } } break; case F_EXPR: if (jolly == 3) { if (e == fe_modify || e == fe_close) { TAutomask& m = (TAutomask&)o.mask(); const int num = m.get_int(F_FILE); TFilter_expr expr(m, num, o.get()); return expr.error() == 0; } } break; case DLG_DELLOG: if (e == fe_button) { TBrowsefile_field& bf = (TBrowsefile_field&)field(F_LOG); TViswin& vv = bf.vis_win(); vv.destroy_lines(); } break; case DLG_PRINT: if (e == fe_button) { TBrowsefile_field& bf = (TBrowsefile_field&)field(F_LOG); TViswin& vv = bf.vis_win(); vv.text().print(); return false; // Don't close } break; default: break; } _last_use = clock(); return true; } void TMailer_mask::save_sheet(TConfig& ini, short dlg, const char* var) const { TSheet_field& sf = sfield(dlg); FOR_EACH_SHEET_ROW(sf, r, row) ini.set(var, *row, NULL, true, r); } void TMailer_mask::load_sheet(TConfig& ini, short dlg, const char* var) { TSheet_field& sf = sfield(dlg); sf.destroy(); for (int r = 0; ini.exist(var, r); r++) sf.row(r) = ini.get(var, NULL, r); } void TMailer_mask::auto_save_all() { if (_mail_semaphore == 0) { TSheet_field& sf = sfield(F_MESSAGES); test_delete(); if (sf.items() == 0) fill_messages(); if (_interval > 0 && sf.items() > 0) save_all_lines(); } else NFCHECK("Can't save locked mail"); } bool TMailer_mask::unattended() const { if (!xvt_vobj_is_focusable(win())) return true; RCT r; xvt_vobj_get_outer_rect(TASK_WIN, &r); if (r.bottom - r.top < 64) return true; // Finestra principale iconizzata return (clock()-_last_use) > 10*CLOCKS_PER_SEC; } long TMailer_mask::handler(WINDOW win, EVENT* ep) { if (ep->type == E_TIMER && ep->v.timer.id == _timer_id) { _secs++; if (_secs >= _interval) { _secs = 0L; if (_mail_semaphore == 0 && unattended()) auto_save_all(); } return 0L; } return TAutomask::handler(win, ep); } void TMailer_mask::save() const { TConfig ini(CONFIG_DITTA, "MailTransactions"); ini.remove_all(); ini.set("Server", get(F_SERVER)); ini.set("User", get(F_USER)); ini.set("Password", encode(get(F_PASSWORD))); ini.set("Timer", get(F_TIMER)); ini.set("Log", get(F_TRACKING)); ini.set("Backup", get(F_BACKUP)); ini.set("DelCancel", get(F_DELCANCEL)); save_sheet(ini, F_ADDRESSES, "Recipient"); save_sheet(ini, F_PARAMS, "Filter"); } void TMailer_mask::load() { TConfig ini(CONFIG_DITTA, "MailTransactions"); set(F_SERVER, ini.get("Server")); set(F_USER, ini.get("User")); set(F_PASSWORD, decode(ini.get("Password"))); set(F_TIMER, ini.get_int("Timer")); set(F_TRACKING, ini.get("Log")); set(F_BACKUP, ini.get("Backup")); set(F_DELCANCEL, ini.get("DelCancel")); load_sheet(ini, F_ADDRESSES, "Recipient"); load_sheet(ini, F_PARAMS, "Filter"); _sequential = ini.get_bool("StopOnError", "ba7"); } TMailer_mask::TMailer_mask() : TAutomask("ba7100a"), _timer_id(XVT_TIMER_ERROR), _mail_semaphore(0), _last_use(0) { load(); const bool is_super = user() == ::dongle().administrator(); enable(-G_SUPERUSER, is_super); } TMailer_mask::~TMailer_mask() { if (_timer_id != XVT_TIMER_ERROR) { xvt_timer_destroy(_timer_id); _timer_id = XVT_TIMER_ERROR; } save(); } /////////////////////////////////////////////////////////// // TMailer /////////////////////////////////////////////////////////// const char* const appname = TR("Postino"); class TMailer : public TSkeleton_application { public: virtual void main_loop(); }; void TMailer::main_loop() { WINDOW tray = xvt_trayicon_create(TASK_WIN, 0, appname); open_files(LF_USER, 0); TMailer_mask mm; mm.run(); xvt_trayicon_destroy(tray); } int ba7100(int argc, char* argv[]) { #if XVT_OS==XVT_OS_WIN32 long style = xvt_vobj_get_attr(NULL_WIN, ATTR_WIN_PM_TWIN_STARTUP_STYLE); style |= WSF_NO_TASKBAR; xvt_vobj_set_attr(NULL_WIN, ATTR_WIN_PM_TWIN_STARTUP_STYLE, style); #endif TMailer app; app.run(argc, argv, appname); return 0; }