#include #include #include #define STRICT #define WIN32_LEAN_AND_MEAN #define XVT_INCL_NATIVE #include #include #include #include "faxdll.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bafax.h" /////////////////////////////////////////////////////////// // Finalmente un programma multimediale! /////////////////////////////////////////////////////////// const word SPEAKER_PORT = 0x61; const word PIT_CONTROL = 0x43; const word PIT_CHANNEL_2 = 0x42; const unsigned long PIT_FREQ = 0x1234DD; void sound(word frequency) { const word counter = word(PIT_FREQ / frequency); _outp(PIT_CONTROL, 0xB6); _outp(PIT_CHANNEL_2, counter & 0xFF); _outp(PIT_CHANNEL_2, counter >> 8); // Connect the speaker to the PIT _outp(SPEAKER_PORT, _inp(SPEAKER_PORT) | 3); } void nosound() { // Sconnect the speaker from the PIT _outp(SPEAKER_PORT, _inp(SPEAKER_PORT) & 0xFC); } /////////////////////////////////////////////////////////// // Dati destinatario /////////////////////////////////////////////////////////// class TFax_data : public TAssoc_array { public: void set(const char* key, const char* value); const char* get(const char* key) const; void set_file(const char* file) { set("FILELIST", file); } char* get_char_star(const char* name) const; TFax_data& operator=(const TAssoc_array& a) { copy(a); return *this; } TFax_data& operator=(const TFax_data& d) { copy(d); return *this; } TFax_data(); TFax_data(const TFax_data& d) { copy(d); } virtual ~TFax_data(); }; TFax_data::TFax_data() { } TFax_data::~TFax_data() { } void TFax_data::set(const char* key, const char* value) { add(key, TString(value), TRUE); } const char* TFax_data::get(const char* key) const { const TString* s = (const TString*)((TAssoc_array*)this)->objptr(key); return s ? (const char*)*s : ""; } char* TFax_data::get_char_star(const char* name) const { if (stricmp(name, "FULLDESTFAX") == 0) { TString num(24); num << get("DIALING"); num << get("PREFIX"); num << get("DESTFAX"); ((TFax_data*)this)->set(name, num); } const TString* s = (const TString*)((TAssoc_array*)this)->objptr(name); return s ? (char*)(const char*)*s : ""; } /////////////////////////////////////////////////////////// // Coda fax /////////////////////////////////////////////////////////// class TFax_queue : private TArray { TFax_data _default; public: int push(TFax_data* data); TFax_data& peek_last(); const TFax_data& peek_last() const; const TFax_data& peek_default(); TFax_data& pop(); bool empty() const { return items() == 0; } void on_firm_change(); TFax_queue(); virtual ~TFax_queue(); }; TFax_queue::TFax_queue() { TConfig ini(CONFIG_USER, "Fax"); _default = ini.list_variables(); } TFax_queue::~TFax_queue() { TConfig ini(CONFIG_USER, "Fax"); _default.restart(); for (THash_object* obj = _default.get_hashobj(); obj; obj = _default.get_hashobj()) { const TString& name = obj->key(); const TString& value = (const TString&)obj->obj(); ini.set(name, value); } } TFax_data& TFax_queue::peek_last() { const int l = last(); return l >= 0 ? (TFax_data&)*objptr(l) : _default; } const TFax_data& TFax_queue::peek_last() const { const int l = last(); return l >= 0 ? (TFax_data&)*objptr(l) : _default; } const TFax_data& TFax_queue::peek_default() { on_firm_change(); return _default; } TFax_data& TFax_queue::pop() { TFax_data* d = (TFax_data*)remove(0, TRUE); if (d != NULL) { _default = *d; delete d; } return _default; } int TFax_queue::push(TFax_data* data) { return add(data, -1); } void TFax_queue::on_firm_change() { static long old_firm = 0; TPrefix& pref = prefix(); pref.set("DEF"); const long firm = pref.get_codditta(); if (firm != old_firm) { TLocalisamfile ditte(LF_NDITTE); ditte.put(NDT_CODDITTA, firm); if (ditte.read() == NOERR) { old_firm = firm; TString tmp(80); tmp = ditte.get(NDT_PFAX); if (tmp.not_empty()) tmp << ','; tmp << ditte.get(NDT_FAX); if (tmp.not_empty()) _default.set("FROMFAX", tmp); tmp = ditte.get(NDT_PERRIF); if (tmp.not_empty()) _default.set("FROMNAME", tmp); tmp = ditte.get(NDT_RAGSOC); if (tmp.not_empty()) _default.set("FROMFIRM", tmp); } } } /////////////////////////////////////////////////////////// // TFax_list /////////////////////////////////////////////////////////// class TFax_list : public TToken_string { public: bool is_faxable(const TFilename& name) const; TFax_list(); TFax_list(const char* f); virtual ~TFax_list() { } }; TFax_list::TFax_list() : TToken_string(80, '+') { } TFax_list::TFax_list(const char* name) : TToken_string(name, '+') { } bool TFax_list::is_faxable(const TFilename& name) const { // Lista delle estensioni accettabili const char* known_ext[] = { "BMP", "FMF", "PCX", "PMF", "TIF", "TXT", NULL }; // Estensione del file da controllare const TString16 ext = name.ext(); // Se il file ha un'estensione riconosciuta lo aggiunge alla lista for (int e = 0; known_ext[e]; e++) { if (ext.compare(known_ext[e], -1, TRUE) == 0) return TRUE; } return FALSE; } /////////////////////////////////////////////////////////// // TDDE_fax /////////////////////////////////////////////////////////// class TLog_mask; class TFax_mask; class TDDE_fax : public TDDE { PAPPINFO _pappinfo; SEND_FAX _send_fax; TBit_array _port; TString_array _pending, _sending, _failed, _complete; TFax_queue _queue; TLog_mask* _log_mask; TFax_mask* _fax_mask; bool _close_when_idle; protected: TString_array* log2array(WORD log); const char* error2string(FAXERROR e) const; void add_log(WORD log, PSEND_FAX sf); void remove_log(WORD log, PSEND_FAX sf); void show_status(PSEND_FAX sf); void update_all_logs(); void update_log(WORD log); bool send_next_fax(); void push_fax(const char* fax); TString& ragsoc2name(TString& ragsoc) const; bool ricerca_clifo(char cf, const TString& codice, TFax_data& data) const; bool ricerca_persone(char fg, const TString& codice, TFax_data& data) const; bool ricerca_ditte(const TString& codice, TFax_data& data) const; void choose_temp_name(TFilename& name) const; bool exec_command(const TString& comm, TToken_string& args); void handle_fax_message(word wparam, long lparam); void handle_drop_files(word wparam); // @cmember Ritorna TRUE se il server non e' in attesa di nessun lavoro bool can_close() const; public: // TObject virtual bool ok() const { return _pappinfo != NULL; } public: // TDDE virtual const char* get_app_name() const { return "EASYFAX"; } virtual const char* get_topics() const { return "FAX"; } virtual bool do_initiate(word id, const TString& topic); virtual bool do_custom_message(word msg, word wparam, long lparam); virtual bool do_execute(word id, const TString& cmd); public: bool run_mask(); void log_delete(WORD log, unsigned long id); bool resend_fax(unsigned long id); void on_firm_change(); bool set_destination(const TString& tipo, const TString& codice, TFax_data& data) const; bool push_destination(const TString& tipo, const TString& codice); void auto_configure(); TDDE_fax(); virtual ~TDDE_fax(); }; /////////////////////////////////////////////////////////// // TFax_mask /////////////////////////////////////////////////////////// class TFax_mask : public TMask { TDDE_fax* _fax; TAssoc_array _table; protected: TMask_field* lookup(const char* field); static bool code_handler(TMask_field& f, KEY k); static bool button_handler(TMask_field& f, KEY k); public: void set_field(const char* field, const char* value); const TString& get_field(const char* field); void set_data(const TFax_data& data); void get_data(TFax_data& data) const; TFax_mask(TDDE_fax* fax); virtual ~TFax_mask(); }; TFax_mask::TFax_mask(TDDE_fax* fax) : TMask("bafax01"), _fax(fax) { const char* pippe[] = { "DESTFAX", "FROMFAX", "PREFIX", NULL }; for (int i = fields()-1; i >= 0; i--) { TMask_field& f = fld(i); if (f.in_group(1)) { f.set_handler(code_handler); const TFieldref* c = f.field(); if (c != NULL) { for (int p = 0; pippe[p] != NULL; p++) if (c->name() == pippe[p]) f.allow_pipe(); } } else if (f.in_group(2)) f.set_handler(button_handler); } } TFax_mask::~TFax_mask() { } TMask_field* TFax_mask::lookup(const char* field) { TString* id = (TString*)_table.objptr(field); if (id == NULL) { for (int i = fields()-1; i >= 0; i--) { TMask_field& f = fld(i); const TFieldref* c = f.field(); if (c && c->name() == field) break; } id = new TString; id->format("%d", i); _table.add(field, id); } const int pos = atoi(*id); return pos < 0 ? NULL : &fld(pos); } void TFax_mask::set_field(const char* field, const char* value) { TMask_field* f = lookup(field); if (f) f->set(value); } const TString& TFax_mask::get_field(const char* field) { TMask_field* f = lookup(field); return f ? f->get() : EMPTY_STRING; } bool TFax_mask::code_handler(TMask_field& f, KEY k) { bool ok = TRUE; if (k == K_TAB && f.focusdirty()) { TFax_mask& m = (TFax_mask&)f.mask(); const TString tipo = m.get_field("TIPO"); const TString codice = f.get(); TFax_data data; ok = m._fax->set_destination(tipo, codice, data); if (ok) m.set_data(data); } return ok; } bool TFax_mask::button_handler(TMask_field& f, KEY k) { if (k == K_SPACE) { TFax_mask& m = (TFax_mask&)f.mask(); TMask_field* fax = m.lookup("DESTFAX"); CHECK(fax, "Can't find fax number field"); TString num = fax->get(); const TString& prompt = f.prompt(); if (prompt != "#") { if ((word)num.len() < fax->size()) num << prompt; } else num.rtrim(1); fax->set(num); const TMask_field* dialmode = m.lookup("DIALING"); CHECK(dialmode, "Can't find dial mode field"); const bool tone = dialmode->get()[0] == 'T'; const char* keys[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", ",", "0", "#" }; const word freqs[] = { 1230, 1320, 1460, 1235, 1325, 1465, 1240, 1330, 1470, 1245, 1335, 1475 }; for (int i = 0; i < 12; i++) if (prompt == keys[i]) { if (tone) { sound(freqs[i]); const clock_t end = clock() + CLOCKS_PER_SEC / 5; while (clock() < end); nosound(); } else { if (i >= 9 && i <= 11) i = i == 10 ? 9 : 0; for (int t = 0; t <= i; t++) { sound(50); clock_t end = clock(); while (clock() == end); nosound(); end = clock(); while (clock() == end); } } break; } } return TRUE; } void TFax_mask::set_data(const TFax_data& ass) { TAssoc_array& data = (TAssoc_array&)ass; data.restart(); for (THash_object* obj = data.get_hashobj(); obj; obj = data.get_hashobj()) { const TString& name = obj->key(); const TString& value = (const TString&)obj->obj(); set_field(name, value); } } void TFax_mask::get_data(TFax_data& data) const { for (int i = fields()-1; i >= 0; i--) { const TMask_field& f = fld(i); const TFieldref* fr = f.field(); if (fr) data.set(fr->name(), f.get()); } } /////////////////////////////////////////////////////////// // TQueues_mask /////////////////////////////////////////////////////////// class TLog_mask : public TMask { TDDE_fax* _fax; protected: void update_sheet(short id, const TString_array& a); WORD sheet2log(const TSheet_field& s) const; void set_notify(short id); static bool log_notify(TSheet_field& f, int row, KEY k); static bool delrec_handler(TMask_field& f, KEY k); static bool fax_handler(TMask_field& f, KEY k); public: void update_log(WORD log, const TString_array& a); TLog_mask(TDDE_fax* fax); virtual ~TLog_mask() { } }; TLog_mask::TLog_mask(TDDE_fax* fax) : TMask("bafax02"), _fax(fax) { set_notify(F_PENDING); set_notify(F_SENDING); set_notify(F_FAILED); set_notify(F_COMPLETE); } WORD TLog_mask::sheet2log(const TSheet_field& s) const { WORD log; switch (s.dlg()) { case F_PENDING: log = SUBSCRIBE_LOG_PENDING; break; case F_SENDING: log = SUBSCRIBE_LOG_SENDING; break; case F_COMPLETE: log = SUBSCRIBE_LOG_COMPLETE; break; case F_FAILED: log = SUBSCRIBE_LOG_FAILED; break; default: log = 0; break; } return log; } bool TLog_mask::log_notify(TSheet_field& s, int, KEY k) { if (k == K_INS) return FALSE; /* if (k == K_INS) { const int last = s.items()-1; if (last >= 0 && yesno_box("Si conferma l'eliminazione dei fax?")) { TLog_mask& m = (TLog_mask&)s.mask(); const WORD log = m.sheet2log(s); for (int i = last; i >= 0; i--) { const char* strid = s.row(i).get(0); unsigned long id; sscanf(strid, "%lu", &id); m._fax->log_delete(log, id); do_events(); } } return FALSE; } */ return TRUE; } bool TLog_mask::delrec_handler(TMask_field& f, KEY k) { if (k == K_SPACE) { TMask& m = f.mask(); const char* strid = m.get(101); if (yesno_box("Si conferma l'eliminazione del fax %s?", strid)) { TSheet_field& s = *m.get_sheet(); TLog_mask& l = (TLog_mask&)s.mask(); const WORD log = l.sheet2log(s); CHECK(log, "Invalid Fax log"); unsigned long id; sscanf(strid, "%lu", &id); l._fax->log_delete(log, id); } } return TRUE; } bool TLog_mask::fax_handler(TMask_field& f, KEY k) { if (k == K_SPACE) { TMask& m = f.mask(); TSheet_field& s = *m.get_sheet(); TLog_mask& l = (TLog_mask&)s.mask(); const char* strid = m.get(101); if (f.yesno_box("Si desidera rispedire il fax %s?", strid)) { unsigned long id; sscanf(strid, "%lu", &id); l._fax->resend_fax(id); } } return TRUE; } // @cmember Setta gli handlers dello sheet

e del tasto elimina della sua maschera void TLog_mask::set_notify(short id) { TMask_field& f = field(id); CHECKD(f.is_kind_of(CLASS_SHEET_FIELD), "Not a sheet ", id); TSheet_field& s = (TSheet_field&)f; s.set_notify(log_notify); TMask& sm = s.sheet_mask(); sm.set_handler(DLG_DELREC, delrec_handler); if (id == F_FAILED) sm.set_handler(100, fax_handler); } // @cmember Ricopia l'array

nello sheet

void TLog_mask::update_sheet(short id, const TString_array& a) { TSheet_field& s = (TSheet_field&)field(id); s.rows_array() = a; s.force_update(); } void TLog_mask::update_log(WORD log, const TString_array& a) { // Convere il codice della coda nell'identificatore dello sheet short id; switch(log) { case SUBSCRIBE_LOG_PENDING: id = F_PENDING; break; case SUBSCRIBE_LOG_SENDING: id = F_SENDING; break; case SUBSCRIBE_LOG_COMPLETE: id = F_COMPLETE; break; case SUBSCRIBE_LOG_FAILED: id = F_FAILED; break; default: id = DLG_NULL; break; } // Aggiorna lo sheet, se l'ha trovato if (id != DLG_NULL) update_sheet(id, a); } /////////////////////////////////////////////////////////// // DDE Fax server /////////////////////////////////////////////////////////// TDDE_fax::TDDE_fax() : _pappinfo(NULL), _log_mask(NULL), _fax_mask(NULL), _close_when_idle(FALSE) { _pappinfo = FaxRegisterApp(get_app_name(), hwnd()); if (_pappinfo) { start_server(); // Inizia DDE server FaxSubscribe(_pappinfo, SUBSCRIBE_LOG_ALL); // Connettiti a Faxman update_all_logs(); // Aggiorna tutte le code DragAcceptFiles((HWND)hwnd(), TRUE); // Attiva Drag'n'drop } else { xvt_statbar_set("Impossibile connettersi a FAXMAN"); beep(); } } TDDE_fax::~TDDE_fax() { if (_pappinfo) { DragAcceptFiles((HWND)hwnd(), FALSE); // Non accettare piu' Drag'n'drop FaxUnregisterApp(_pappinfo); // Sconnettiti da Faxman _pappinfo = NULL; } if (_log_mask) { delete _log_mask; _log_mask = NULL; } } bool TDDE_fax::do_initiate(word id, const TString& topic) { return TRUE; } bool TDDE_fax::exec_command(const TString& cmd, TToken_string& arg) { if (cmd.compare("FileClose", -1, TRUE) == 0) { if (can_close()) main_app().stop_run(); else _close_when_idle = TRUE; } if (cmd.compare("SetRecipient", -1, TRUE) == 0) { TString tipo = arg.get(0); tipo.trim(); TString codice = arg.get(); codice.trim(); push_destination(tipo, codice); } return TRUE; } bool TDDE_fax::do_execute(word id, const TString& cmd) { bool ok = TRUE; TToken_string commands(cmd, ']'); TToken_string arguments(80, ','); for (TString command = commands.get(0); command.not_empty(); command = commands.get()) { if (command[0] == '[') command.ltrim(1); const int bracket = command.find('('); if (bracket > 0) { arguments = command.mid(bracket+1, -1); arguments.rtrim(1); arguments.trim(); command.cut(bracket); } else arguments.cut(0); command.trim(); ok = exec_command(command, arguments); if (!ok) break; } return ok; } // Genera il nome di un file temporaneo: se esiste gia' ripete il ciclo. void TDDE_fax::choose_temp_name(TFilename& name) const { static long lastfax = 0; TFilename path; path.tempdir(); // Directory temporanea path.add("FAX"); // Aggiunge la directory FAX if (lastfax == 0 && !fexist(path)) make_dir(path); do { TString16 f; f.format("FAX%05ld.FMF", ++lastfax); name = path; name.add(f); } while (fexist(name)); } void TDDE_fax::on_firm_change() { _queue.on_firm_change(); } void TDDE_fax::handle_fax_message(word wparam, long lparam) { switch(wparam) { case FAXMODEMMSG: if (lparam) { PFAXDEVICE dev = (PFAXDEVICE)lparam; TString msg(24); msg = "E' stata "; if (!dev->wFlags) { _port.reset(dev->nPort); // Removing a port msg << "scollegata"; beep(); } else { _port.set(dev->nPort); // Adding a port msg << "collegata"; } msg << " la porta COM" << dev->nPort; xvt_statbar_set(msg); } break; case FAXGETFILENAME: if (lparam) { TFilename tmp; choose_temp_name(tmp); strcpy((char*)lparam, tmp); } break; case FAXPRINTMSG: if (lparam) { PPRINTSTAT ps = (PPRINTSTAT)lparam; if (ps->pStat == PRN_OK) { TFax_data& data = _queue.peek_last(); data.set_file(ps->FileName); beep(); if (_fax_mask == NULL) send_next_fax(); } GlobalFree((HGLOBAL)lparam); } break; case FAXLOGADD: if (lparam) { PSEND_FAX sf = (PSEND_FAX)lparam; add_log(sf->wLog, sf); } break; case FAXLOGREMOVE: if (lparam) { PSEND_FAX sf = (PSEND_FAX)lparam; remove_log(sf->wLog, sf); } break; case FAXSENDMSG: if (lparam) { PSEND_FAX sf = (PSEND_FAX)lparam; show_status(sf); } break; default: break; } } // Gestione del Drag'n'drop void TDDE_fax::handle_drop_files(word wparam) { TTemp_window tw(TASK_WIN); tw.maximize(); xvt_statbar_set("Creazione fax..."); do_events(); HDROP hdrop = (HDROP)wparam; const int num_files = DragQueryFile(hdrop, -1, NULL, 0); // Numero totale di files TFilename fname; // File corrente TFax_list file_list; for (int i = 0; i < num_files; i++) { DragQueryFile(hdrop, i, (char*)(const char*)fname, fname.size()); if (file_list.is_faxable(fname)) file_list.add(fname); } DragFinish(hdrop); // Spedisce un unico fax con tutti i files droppati if (file_list.items() > 0) { begin_wait(); TFilename fax; choose_temp_name(fax); const word err = FaxCreate(_pappinfo, file_list, fax, 0L); xvt_statbar_set(""); end_wait(); if (err == 0) push_fax(fax); else error_box("Impossibile convertire il file %s", (const char*)file_list.get(err-1)); } else xvt_statbar_set(""); } bool TDDE_fax::do_custom_message(word msg, word wparam, long lparam) { bool ok = TRUE; switch(msg) { case WM_DROPFILES: handle_drop_files(wparam); break; case WM_FAXMSG: handle_fax_message(wparam, lparam); break; default: ok = FALSE; break; } return ok; } bool TDDE_fax::resend_fax(unsigned long id) { PSEND_FAX sf; bool ok = FaxLogFind(_pappinfo, &sf, id) == 1; if (ok) { const TFilename old_name(sf->szFileList); TFilename new_name(old_name); new_name.ext("FMP"); rename(old_name, new_name); // Rinomina file FaxLogDelete(_pappinfo, id, sf->wLog); // Cancella fax do_events(); rename(new_name, old_name); // Ripristina file FaxSchedule(_pappinfo, sf); GlobalFreePtr(sf); } return ok; } bool TDDE_fax::send_next_fax() { static bool no_fax_error = FALSE; TTemp_window tw(TASK_WIN); #if XVT_OS == XVT_OS_WIN HWND hwnd = (HWND)xvt_vobj_get_attr(TASK_WIN, ATTR_NATIVE_WINDOW); SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); #endif tw.maximize(); if (_port.ones() == 0 && !no_fax_error) { no_fax_error = TRUE; error_box("Non c'e nessun Modem/Fax collegato"); } CHECK(_fax_mask == NULL, "Double fax mask"); _fax_mask = new TFax_mask(this); bool sent = FALSE; do { TFax_data& data = _queue.pop(); _fax_mask->set_data(data); if (_fax_mask->run() == K_ENTER) { _fax_mask->get_data(data); PSEND_FAX sf = &_send_fax; FaxInitSendStruct(_pappinfo, sf); sf->szDestFax = data.get_char_star("FULLDESTFAX"); sf->szDestName = data.get_char_star("DESTNAME"); sf->szToCompany = data.get_char_star("DESTFIRM"); sf->szFromFax = data.get_char_star("FROMFAX"); sf->szFromLine = data.get_char_star("FROMNAME"); sf->szFromCompany = data.get_char_star("FROMFIRM"); sf->szFileList = data.get_char_star("FILELIST"); sf->szBanner = "%m %s| |Pagina %c di %p"; sf->szCover = "cover1.pg"; const DWORD id = FaxSchedule(_pappinfo, sf); sent = id > 0; } } while (!_queue.empty()); delete _fax_mask; _fax_mask = NULL; #if XVT_OS == XVT_OS_WIN SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); #endif // Non iconizzare se ho aperta la finestra di stato if (_log_mask == NULL) tw.iconize(); if (_close_when_idle && can_close()) main_app().stop_run(); return sent; } void TDDE_fax::push_fax(const char* fax) { TFax_data* data = new TFax_data(_queue.peek_default()); data->set_file(fax); _queue.push(data); if (_fax_mask == NULL) send_next_fax(); } TString_array* TDDE_fax::log2array(WORD log) { TString_array* array; switch(log) { case SUBSCRIBE_LOG_PENDING : array = &_pending; break; case SUBSCRIBE_LOG_SENDING : array = &_sending; break; case SUBSCRIBE_LOG_COMPLETE: array = &_complete; break; case SUBSCRIBE_LOG_FAILED : array = &_failed; break; default: array = NULL; } return array; } const char* TDDE_fax::error2string(FAXERROR e) const { static const char* msg[] = { "", // FAXERR_OK "Comando non ricosciuto (nessun OK)", // FAXERR_ACK "Modem/Fax non riconosciuto", // FAXERR_BADFAXMODEM "Errore di inizializzazione", // FAXERR_INIT "Errore nei parametri FDIS", // FAXERR_FDIS "Errore nell'identificatore locale", // FAXERR_FLID "Errore di composizione del numero", // FAXERR_DIAL "Errore di connessione al fax remoto", // FAXERR_FCON_ERR "Errore nella stringa FCSI", // FAXERR_FCSI "Errore di ricezione FDIS", // FAXERR_NEG_FDIS "Errore di stato errato", // FAXERR_BADSTATE "Linea occupata", // FAXERR_BUSY "Segnale di libero non rilevato", // FAXERR_NODIALTONE "Messaggio CONNECT non ricevuto", // FAXERR_NOCONNECT "Interrotto dall'utente", // FAXERR_CANCEL "FPTS nullo o errato", // FAXERR_FPTS "FHNG nullo o errato", // FAXERR_FHNG "FDCS nullo o errato", // FAXERR_FDCS "Errore di trasmissione", // FAXERR_ERROR "File in formato errato", // FAXERR_FILE "Fax Server incompatibile", // FAXERR_VERSION "Tempo di trasmissione scaduto", // FAXERR_TIMEOUT "Nessuna risposta a MPS", // FAXERR_NO_MPS_RESP "Nessuna risposta a EOP", // FAXERR_NO_EOP_RESP "Errore di connessione", // FAXERR_NOTRAIN }; if (e < FAXERR_OK || e > FAXERR_NOTRAIN) e = FAXERR_ERROR; return msg[e]; } void TDDE_fax::add_log(WORD log, PSEND_FAX sf) { TString_array* arr = log2array(log); if (arr) { TToken_string* l = new TToken_string(128); l->format("%lu", sf->dwID); // ID l->add(sf->szDestFax); // Dest. fax TString destination(128); destination = sf->szDestName; destination.trim(); if (*sf->szToCompany) { if (destination.not_empty()) destination << ", "; destination << sf->szToCompany; } l->add(destination); // Dest. name l->add(TDate(sf->nDay, sf->nMonth, sf->nYear).string()); // Date and time char ora[16]; sprintf(ora, "%02d:%02d:%02d", sf->nHour, sf->nMin, sf->nSecond); l->add(ora); l->add(sf->szFileList); // Files l->add(error2string(sf->fe)); arr->add(l); // Aggiorna array del log if (_log_mask) // Se aperta, aggiorna anche maschera _log_mask->update_log(log, *arr); } } void TDDE_fax::remove_log(WORD log, PSEND_FAX sf) { TString_array* arr = log2array(log); if (arr) { TString16 id; id.format("%lu", sf->dwID); for (int i = arr->items()-1; i >= 0; i--) { TToken_string& r = arr->row(i); if (id == r.get(0)) break; } if (i >= 0) { arr->destroy(i, TRUE); if (_log_mask) _log_mask->update_log(log, *arr); } } } void TDDE_fax::update_all_logs() { SEND_FAX tmpsf; _pending.destroy(); _sending.destroy(); _failed.destroy(); _complete.destroy(); if (FaxLogInit(_pappinfo, SUBSCRIBE_LOG_PENDING) < MAXITERATORS) { while (FaxLogNext(_pappinfo, &tmpsf) == LOGERR_CONTINUEIT) do_custom_message(WM_FAXMSG, FAXLOGADD, (LPARAM)&tmpsf); } if (FaxLogInit(_pappinfo, SUBSCRIBE_LOG_SENDING) < MAXITERATORS) { while (FaxLogNext(_pappinfo, &tmpsf) == LOGERR_CONTINUEIT) do_custom_message(WM_FAXMSG, FAXLOGADD, (LPARAM)&tmpsf); } if (FaxLogInit(_pappinfo, SUBSCRIBE_LOG_COMPLETE) < MAXITERATORS) { while (FaxLogNext(_pappinfo, &tmpsf) == LOGERR_CONTINUEIT) do_custom_message(WM_FAXMSG, FAXLOGADD, (LPARAM)&tmpsf); } if (FaxLogInit(_pappinfo, SUBSCRIBE_LOG_FAILED) < MAXITERATORS) { while (FaxLogNext(_pappinfo, &tmpsf) == LOGERR_CONTINUEIT) do_custom_message(WM_FAXMSG, FAXLOGADD, (LPARAM)&tmpsf); } _port.reset(); FaxEnumDevices(_pappinfo); } void TDDE_fax::update_log(WORD log) { if (_log_mask) { const TString_array* arr = log2array(log); if (arr) _log_mask->update_log(log, *arr); } } void TDDE_fax::show_status(PSEND_FAX sf) { if (_log_mask) { TString msg(80); switch(sf->fs) { case FAXST_SEND_INIT : msg = "Inizializzazione"; break; case FAXST_SEND_DIALING : msg = "Composizione del numero "; msg << sf->szDestFax; break; case FAXST_SEND_FCSI : msg = "Connessione"; break; case FAXST_SENDING : msg = "Spedizione pagina "; msg << sf->nTotCurPage << " di " << sf->nTotPages << ": " << sf->nPercent << '%'; break; case FAXST_PAGE_END : msg = "Fine pagina "; msg << sf->nTotCurPage; break; case FAXST_COMPLETE : msg = "Fine trasmissione"; break; case FAXST_ABORT : msg = "Operazione abortita"; break; case FAXST_PORTSHUT : msg = "Chiusura COM"; msg << sf->nPort; if (sf->fe != FAXERR_OK) msg << ": " << error2string(sf->fe); break; default : break; } if (msg.not_empty()) _log_mask->set(F_STATUS, msg); } } void TDDE_fax::log_delete(WORD log, unsigned long id) { if (log == SUBSCRIBE_LOG_SENDING) { const bool ok = FaxCancel(_pappinfo, id); if (!ok) FaxLogDelete(_pappinfo, id, log); } else FaxLogDelete(_pappinfo, id, log); } void TDDE_fax::auto_configure() { const int err = FaxAddDevice(_pappinfo, 0); if (err != 0) { const int seconds = 4; TProgind pi(seconds, "Ricerca dei Modem/Fax collegati...", FALSE, TRUE, 48); for (int i = 1; i <= seconds; i++) { pi.setstatus(i); const clock_t end = clock() + CLOCKS_PER_SEC; while (clock() < end) do_events(); } _port.reset(); // Azzera tutti i flag delle porte FaxEnumDevices(_pappinfo); // Richiede la lista delle porte pi.set_text("Controllo dei Modem/Fax trovati ..."); for (i = 1; i <= seconds; i++) { pi.setstatus(i); const clock_t end = clock() + CLOCKS_PER_SEC; while (clock() < end) do_events(); } TString msg(24); msg << "Modem/Fax collegati: "; const long np = _port.ones(); if (np == 0) msg << "NESSUNO"; else msg << np; xvt_statbar_set(msg); } else error_box("Impossibile trovare il server Faxman"); } bool TDDE_fax::run_mask() { const bool ok = _log_mask == NULL; if (ok) { TTemp_window tw(TASK_WIN); tw.maximize(); _log_mask = new TLog_mask(this); update_log(SUBSCRIBE_LOG_PENDING ); update_log(SUBSCRIBE_LOG_SENDING ); update_log(SUBSCRIBE_LOG_FAILED ); update_log(SUBSCRIBE_LOG_COMPLETE); _log_mask->run(); delete _log_mask; _log_mask = NULL; } return ok; } TString& TDDE_fax::ragsoc2name(TString& ragsoc) const { TString first_name = ragsoc.left(30); first_name.trim(); if (first_name.len() < 30) { TString last_name = ragsoc.mid(30); last_name.trim(); ragsoc = first_name; ragsoc << ' ' << last_name; } return ragsoc; } bool TDDE_fax::ricerca_clifo(char cf, const TString& codice, TFax_data& data) const { TLocalisamfile f(LF_CLIFO); f.put(CLI_TIPOCF, cf); f.put(CLI_CODCF, codice); const int err = f.read(); if (err == NOERR) { TToken_string s(80, ','); s = f.get("PFAX"); s.add(f.get("FAX")); data.set("DESTFAX", s); s = f.get("PTEL"); s.add(f.get("TEL")); data.set("DESTTEL", s); data.set("DESTNAME", ""); s = f.get("RAGSOC"); data.set("DESTFIRM", ragsoc2name(s)); data.set("TIPO", cf == 'C' ? "Clienti" : "Fornitori"); data.set(cf == 'C' ? "CLIENTI" : "FORNITORI", codice); } return err == NOERR; } bool TDDE_fax::ricerca_persone(char fg, const TString& codice, TFax_data& data) const { TRelation r(LF_ANAG); if (fg == 'G') r.add(LF_ANAGGIU, "CODANAGR=CODANAGR"); TRectype& c = r.curr(); c.put(ANA_TIPOA, fg); c.put(ANG_CODANAGR, codice); const int err = r.read(); if (err == NOERR) { TToken_string s(80, ','); s = c.get("PFAXRF"); s.add(c.get("FAXRF")); data.set("DESTFAX", s); s = c.get("PTELRF"); s.add(c.get("TELRF")); data.set("DESTTEL", s); if (fg == 'G') { data.set("DESTFIRM", c.get("RAGSOC")); data.set("DESTNAME", r.curr(LF_ANAGGIU).get("PERRIF")); data.set("TIPO", "Giuridiche"); data.set("GIURIDICHE", codice); } else { data.set("DESTFIRM", ""); s = c.get("RAGSOC"); data.set("DESTNAME", ragsoc2name(s)); data.set("TIPO", "Fisiche"); data.set("FISICHE", codice); } } return err == NOERR; } bool TDDE_fax::ricerca_ditte(const TString& codice, TFax_data& data) const { TLocalisamfile f(LF_NDITTE); f.put(NDT_CODDITTA, codice); const int err = f.read(); if (err == NOERR) { TToken_string s(128, ','); s.add(f.get(NDT_PFAX)); s.add(f.get(NDT_FAX)); data.set("DESTFAX", s); data.set("DESTNAME", f.get(NDT_PERRIF)); data.set("DESTFIRM", f.get(NDT_RAGSOC)); data.set("TIPO", "Ditte"); data.set("DITTE", codice); } return err == NOERR; } bool TDDE_fax::set_destination(const TString& tipo, const TString& codice, TFax_data& data) const { const char* tipi[] = { "CLI", "DIT", "FIS", "FOR", "GIU", NULL }; bool ok = TRUE; for (int i = 0; tipi[i]; i++) { if (tipo.compare(tipi[i], 3, TRUE) == 0) break; } data = _queue.peek_last(); // Inizializza valori di default switch(i) { case 0 : ricerca_clifo('C', codice, data); break; case 1 : ricerca_ditte(codice, data); break; case 2 : ricerca_persone('F', codice, data); break; case 3 : ricerca_clifo('F', codice, data); break; case 4 : ricerca_persone('G', codice, data); break; default: ok = FALSE; break; } return ok; } bool TDDE_fax::push_destination(const TString& tipo, const TString& codice) { TFax_data* data = new TFax_data; const bool ok = set_destination(tipo, codice, *data); _queue.push(data); return ok; } bool TDDE_fax::can_close() const { return _log_mask == NULL && _queue.empty() && _pending.items() == 0 && _sending.items() == 0; } /////////////////////////////////////////////////////////// // Fax server application /////////////////////////////////////////////////////////// class TFax_server : public TApplication { TDDE_fax* _fax; protected: virtual bool pre_create(); virtual bool create(); virtual bool destroy(); virtual bool menu(MENU_TAG mt); virtual void on_firm_change(); public: TFax_server() : _fax(NULL) { } virtual ~TFax_server() { } }; bool TFax_server::pre_create() { CHECK(_fax == NULL, "Double fax creation"); _fax = new TDDE_fax; return _fax->ok(); } bool TFax_server::create() { const bool ok = _fax->ok(); if (ok) { bool show_status = FALSE; if (argc() >= 2 && stricmp(argv(1), "-S") == 0) show_status = TRUE; if (argc() > 2) { const TString tipo = argv(1); const TString codice = argv(2); _fax->push_destination(tipo, codice); } TMailbox mb; TToken_string topics = _fax->get_topics(); for (TString topic = topics.get(0); topic.not_empty(); topic = topics.get()) { TMessage* msg = mb.next_s(topic); while (msg) { const TString cmd(msg->body()); if (_fax->do_initiate(0, topic)) _fax->do_execute(0, cmd); msg = mb.next_s(topic); } } if (show_status) { dispatch_e_menu(MENU_ITEM(1)); } else { TTemp_window w(TASK_WIN); w.iconize(); } } else destroy(); // Non verrebbe mai chiamata return ok; } bool TFax_server::destroy() { if (_fax) { delete _fax; _fax = NULL; } return TRUE; } void TFax_server::on_firm_change() { TApplication::on_firm_change(); if (_fax) _fax->on_firm_change(); } bool TFax_server::menu(MENU_TAG mt) { if (_fax) { switch(mt) { case MENU_ITEM(1): _fax->run_mask(); break; case MENU_ITEM(2): _fax->auto_configure(); break; default: break; } } return TRUE; } int main(int argc, char** argv) { TApplication::check_parameters(argc, argv); char drive[_MAX_DRIVE]; char path[_MAX_PATH]; _splitpath(argv[0], drive, path, NULL, NULL); int err = _chdrive(toupper(*drive)-'A'+1); if (err == 0) { const int last = strlen(path)-1; CHECKS(last >= 0, "Invalid directory ", path); if (path[last] == '\\' || path[last] == '/') path[last] = '\0'; err = _chdir(path); } if (err == 0) { TFax_server fs; fs.run(argc, argv, "Fax server"); } else error_box("Impossibile entrare nella directory %s", (const char*)path); return TRUE; }