campo-sirio/ba/bafax.cpp
alex 203164b1a5 numerati i file a partire da 1
git-svn-id: svn://10.65.10.50/trunk@3702 c028cbd2-c16b-5b4b-a496-9718f37d4682
1996-10-03 10:07:27 +00:00

1561 lines
38 KiB
C++
Executable File

#include <conio.h>
#include <direct.h>
#include <stdlib.h>
#include <time.h>
#include <xvt.h>
#include <applicat.h>
#include <assoc.h>
#include <golem.h>
#include <mailbox.h>
#include <msksheet.h>
#include <prefix.h>
#include <progind.h>
#include <relation.h>
#include <urldefid.h>
#include <utility.h>
#include <xvtility.h>
#include <anagiu.h>
#include <clifo.h>
#include <nditte.h>
#include "bafax.h"
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <shellapi.h>
#include "faxdll.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() : "";
}
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 <p id> 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 <p a> nello sheet <p id>
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(ANG_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;
}