#include #include #include #include #include #include #include #include #include #include #include #include #include #define NO_MFC #include #include "ba7.h" #include "ba7100a.h" /////////////////////////////////////////////////////////// // TConfig utilities /////////////////////////////////////////////////////////// TString& set_ini_var(int cfg, const char* para, const char* var, const char* val) { static TString80 prev; TConfig ini(cfg, para); prev = ini.get(var); if (val != NULL) ini.set(var, val); return prev; } inline 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.empty()) { server = get_ini_var(CONFIG_INSTALL, "Server", "POP3"); if (server.empty()) ok = FALSE; } if (user.empty()) user = ::user(); if (password.empty()) { 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("Impossibile inizializzare il client POP3"); TString server(ser); TString user(usr); TString password(pwd); if (!default_params(server, user, password)) return error_box("E' necessario specificare un server POP3, un utente ed una password"); _connection = QueryConnection("110", server); if (_connection != 0) { TString buf; ReadLine(_connection, buf); if (buf[0] != '+') return error_box("Il server POP3 %s non risponde", (const char*)server); buf = "USER "; buf << user << '\n'; WriteLine(_connection, buf); ReadLine(_connection, buf); if (buf[0] != '+') return error_box("Il server POP3 %s non accetta l'utente %s", (const char*)server, (const char*)user); buf = "PASS "; buf << password << '\n'; WriteLine(_connection, buf); ReadLine(_connection, buf); if (buf[0] != '+') return error_box("Il server POP3 %s non accetta l'utente %s", (const char*)server, (const char*)user); } else return error_box("Impossibile contattare il server POP3 %s", (const char*)server); return TRUE; } void TMail_box::logoff() { if (_connection) { WriteLine(_connection, "QUIT\n"); RemoveConnection(_connection); _connection = NULL; } } bool TMail_box::list(TString_array& a) { bool ok = _connection != NULL; if (ok) { TString buf; buf = "LIST\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 (stricmp(str, mese[m]) == 0) break; } return m+1; } int TMail_box::get(TMail_messages& m) { // Lista dei caratteri validi const char 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; 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 << '\n'; WriteLine(_connection, buf); ReadLine(_connection, buf); bool ok = buf[0] == '+'; bool base64 = FALSE; bool in_body = FALSE; while (ok) { if (!ReadLine(_connection, buf)) { ok = FALSE; break; // Unexpected EOF } if (buf[0] == '.') { buf.ltrim(1); if (buf.blank()) break; } if (in_body) { if (base64) { unsigned val = 0; int bits = 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 << c; bits -= 8; } } } else { const char last = buf.right(1)[0]; if (last > '\0' && last < ' ') buf.rtrim(1); msg << buf << '\n'; } } else { if (buf.blank()) in_body = TRUE; else if (buf.compare("From:", 5, TRUE) == 0) { buf.ltrim(6); msg.set_sender(buf); } else if (buf.compare("To:", 3, TRUE) == 0) { buf.ltrim(4); msg.add_recipient(buf); } else if (buf.compare("Cc:", 3, TRUE) == 0) { buf.ltrim(4); msg.add_copy_recipient(buf); } else if (buf.compare("Subject:", 8, TRUE) == 0) { buf.ltrim(9); msg.set_subject(buf); } else if (buf.compare("Date:", 5, TRUE) == 0) { TToken_string d(buf.mid(6), ' '); int giorno = d.get_int(1); int mese = str2month(d.get()); int anno = d.get_int(); if (anno < 1000) anno += anno >= 98 ? 1900 : 2000; TString16 ora = d.get(); buf.cut(0); buf << anno << '/' << mese << '/' << giorno << ' ' << ora; msg.set_date_time(buf); } else if (buf.compare("Content-Transfer-Encoding:", 26, TRUE) == 0) { base64 = buf.find("base64") > 0; } } } } return m.items(); } bool TMail_box::remove(const char* id) { bool ok = _connection != NULL; if (ok) { TString buf; buf << "DELE " << id << '\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; TLocalisamfile isf(logicnum); TRectype& rec = isf.curr(); for (int i = 0; i < numvar(); i++) if (rec.exist(varname(i))) { _error = 883; TString msg; msg << "Il campo " << varname(i) << " non appartiene al file " << logicnum; print_error(msg); break; } } } /////////////////////////////////////////////////////////// // TMailer_mask /////////////////////////////////////////////////////////// class TMailer_mask : public TAutomask { int _timer_id; int _mail_semaphore; protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); virtual void handler(WINDOW win, EVENT* ep); protected: bool file2app(const TString& file, TString& app) const; void expand_tabs(TString& 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); public: void test_delete(); int fill_messages(); bool save_curr_line(); void save_all_lines(); void auto_save_all(); void save() const; void load(); void mail_lock() { _mail_semaphore++; } void mail_unlock() { CHECK(_mail_semaphore > 0, "Bad timer unlock"); _mail_semaphore--; } TMailer_mask(); virtual ~TMailer_mask(); }; class TMail_lock { TMailer_mask* _mm; public: TMail_lock(TMailer_mask* mm) : _mm(mm) { _mm->mail_lock(); } ~TMail_lock() { _mm->mail_unlock(); } }; void TMailer_mask::test_delete() { TMail_lock ml(this); TWait_cursor hourglass; xvt_statbar_set("Eliminazione messaggi POP3..."); do_events(); TSheet_field& sf = sfield(F_MESSAGES); TString16 mailer, 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(sf.cid2index(F_MAILER), mailer); row->get(sf.cid2index(F_ID), id); if (mailer == "POP3") { if (!mailbox.ok()) { if (!mailbox.logon(get(F_SERVER), get(F_USER), get(F_PASSWORD))) break; } if (!mailbox.remove(id)) error_box("Impossibile cancellare il messagio POP3 %s", (const char*)id); } else { TMail_message* msg = new TMail_message(""); msg->set_id(id); mapidel.add(msg); } sf.destroy(nrow); } mailbox.logoff(); if (mapidel.items() > 0) { xvt_statbar_set("Eliminazione messaggi MAPI..."); do_events(); mapidel.remove(); } xvt_statbar_set("Pronto"); do_events(); } void TMailer_mask::expand_tabs(TString& str, const int tab) const { 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; } } } int TMailer_mask::fill_messages() { TMail_lock ml(this); TWait_cursor hourglass; TMail_messages box; TString server(get(F_SERVER)); TString user(get(F_USER)); TString 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); } int totmapi = 0; if (get_bool(F_MAPI)) { xvt_statbar_set("Ricezione messaggi MAPI..."); do_events(); totmapi = box.get(); } xvt_statbar_set("Ricezione messaggi POP3..."); do_events(); mailbox.logon(server, user, password); mailbox.get(box); mailbox.logoff(); TSheet_field& sf = sfield(F_MESSAGES); sf.destroy(); 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); row.add(msg, sf.cid2index(F_BODY)); row.add(m= 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); } } return ok; } bool TMailer_mask::save_curr_line() { TMail_lock ml(this); TSheet_field& sf = sfield(F_MESSAGES); TMask& m = sf.sheet_mask(); const int nrow = sf.selected(); TToken_string& row = sf.row(nrow); const TString& msg = m.get(F_BODY); if (msg.find("[Transaction]") < 0) return FALSE; // It's not a transaction TFilename appname; if (!file2app(m.get(F_SUBJECT), appname)) return FALSE; // It hasn't a valid application TFilename tmp; tmp.temp(); ofstream outf(tmp); outf << msg; outf.close(); const TString old_mailto = set_ini_var(CONFIG_INSTALL, "Main", "MailTo", ""); appname << " /i" << tmp; TExternal_app app(appname); bool ok = app.run() == NOERR; if (ok) { TConfig ini(tmp, "Transaction"); ok = ini.get("Result") == "OK"; } ::remove(tmp); 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.not_empty()) set_ini_var(CONFIG_INSTALL, "Main", "MailTo", old_mailto); return TRUE; } void TMailer_mask::save_all_lines() { TMail_lock ml(this); TWait_cursor hourglass; TSheet_field& sf = sfield(F_MESSAGES); TString body; bool one_saved = FALSE; FOR_EACH_SHEET_ROW(sf, nrow, row) if (*row->get(0) != 'X') { row->get(sf.cid2index(F_BODY), body); if (body.find("[Transaction]") >= 0) { sf.select(nrow); one_saved |= save_curr_line(); } } if (one_saved && yesno_box("Si desidera eliminare i messaggi processati?")) { 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_destroy(_timer_id); _timer_id = XVT_TIMER_ERROR; } const long minutes = atol(o.get()); if (minutes > 0) { _timer_id = xvt_timer_create(win(), minutes * 60000L); 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()) { auto_save_all(); } } else if (e == se_query_add) { auto_save_all(); return FALSE; } break; case DLG_USER: if (e == fe_button) save_curr_line(); break; case DLG_SAVEREC: if (e == fe_button) save_all_lines(); break; case DLG_DELREC: if (e == fe_button) { 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,"Selezione archivio", "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; default: break; } 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) { TMail_lock ml(this); test_delete(); fill_messages(); if (!field(F_TIMER).empty()) save_all_lines(); } else NFCHECK("Can't save locked mail"); } void TMailer_mask::handler(WINDOW win, EVENT* ep) { if (ep->type == E_TIMER) { if (ep->v.timer.id == _timer_id && _mail_semaphore == 0) auto_save_all(); } 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)); 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")); load_sheet(ini, F_ADDRESSES, "Recipient"); load_sheet(ini, F_PARAMS, "Filter"); } TMailer_mask::TMailer_mask() : TAutomask("ba7100a"), _timer_id(XVT_TIMER_ERROR), _mail_semaphore(0) { load(); } TMailer_mask::~TMailer_mask() { if (_timer_id != XVT_TIMER_ERROR) { xvt_timer_destroy(_timer_id); _timer_id = XVT_TIMER_ERROR; } save(); } /////////////////////////////////////////////////////////// // TMailer /////////////////////////////////////////////////////////// class TMailer : public TSkeleton_application { public: virtual void main_loop(); }; void TMailer::main_loop() { open_files(LF_USER, 0); TMailer_mask mm; mm.run(); } int ba7100(int argc, char* argv[]) { TMailer app; app.run(argc, argv, "Postino"); return 0; }