dl-fldigi/src/flarq-src/flarq.cxx

1998 wiersze
44 KiB
C++

// ----------------------------------------------------------------------------
// flarq.cxx - Fast Light ARQ Application
//
// ----------------------------------------------------------------------------
// Copyright (C) 2014
// David Freese, W1HKJ
//
// This file is part of fldigi
//
// fldigi is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// fldigi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#include <config.h>
#include <unistd.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <cstring>
#include <ctime>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <FL/Fl.H>
#include <FL/Fl_Widget.H>
#include <FL/Enumerations.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Group.H>
#include <FL/Fl_Sys_Menu_Bar.H>
#include <FL/x.H>
#include <FL/Fl_Help_Dialog.H>
#include <FL/Fl_Menu_Item.H>
// this tests depends on a modified FL/filename.H in the Fltk-1.3.0
// change
//# if defined(WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
// to
//# if defined(WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__) && !defined(__WOE32__)
#include <FL/filename.H>
#ifdef __MINGW32__
# include "compat.h"
#endif
#include <dirent.h>
#include "fileselect.h"
#include "socket.h"
#include <dirent.h>
#include "threads.h"
#include "flarq.h"
#include "flarqenv.h"
#include "flmisc.h"
#include "stacktrace.h"
#include "icons.h"
#include "arq.h"
#include "arqdialogs.h"
#include "b64.h"
#include "gettext.h"
#include "xml_server.h"
#define FLDIGI_port "7322"
#define MPSK_port "3122"
#define FLARQ_XML_PORT 7422
#define MPSK_TX "TX"
#define MPSK_RX "RX"
#define MPSK_TX2RX "RX_AFTER_TX"
#define MPSK_BYTE 25
#define MPSK_CMD 26
#define MPSK_END 27
#define MPSK_ISTX 28
#define MPSK_ISRX 29
#define MPSK_ISCMD 30
#define MPSK_CMDEND 31
// directory structures for all NBEMS applications
static void checkdirectories(void);
string NBEMS_dir;
string ARQ_dir;
string ARQ_files_dir;
string ARQ_recv_dir;
string ARQ_send_dir;
string ARQ_mail_dir;
string ARQ_mail_in_dir;
string ARQ_mail_out_dir;
string ARQ_mail_sent_dir;
string WRAP_dir;
string WRAP_recv_dir;
string WRAP_send_dir;
string WRAP_auto_dir;
string ICS_dir;
string ICS_msg_dir;
string ICS_tmp_dir;
string MailFileName = "";
string MailSaveFileName = "";
string Logfile;
struct dirent *entry;
DIR *dp;
bool SendingEmail = false;
bool SHOWDEBUG = false;
extern void STATUSprint(string s);
Fl_Text_Buffer *txtbuffARQ;
Fl_Text_Buffer *stylebufARQ;
Fl_Text_Buffer *txtbuffRX;
Fl_Text_Buffer *stylebufRX;
Fl_Text_Buffer *txtbuffComposer;
//Fl_Text_Buffer *styleComposer;
Fl_Text_Display::Style_Table_Entry styletable[] = { // Style table
{ FL_BLACK, FL_SCREEN, FL_NORMAL_SIZE }, // A - RX
{ FL_DARK_RED, FL_SCREEN, FL_NORMAL_SIZE }, // B - TX
{ FL_DARK_GREEN, FL_SCREEN, FL_NORMAL_SIZE }, // C - DEBUG rx text
{ FL_MAGENTA, FL_SCREEN, FL_NORMAL_SIZE } // D - DEBUG tx text
};
Fl_Double_Window *arqwin = 0;
Fl_Double_Window *dlgconfig = 0;
Fl_Double_Window *outdialog = 0;
Fl_Double_Window *composer = 0;
using namespace std;
arq *digi_arq;
bool traffic = false;
bool sendingfile = false;
int arqstate = 0;
bool configured = false;
bool ioMPSK = false;
string arq_address = "127.0.0.1";
string arq_port = FLDIGI_port;
string RX;
string TX;
string teststring;
string statusmsg;
string MyCall;
string beacontext;
#if !defined(__APPLE__) && !defined(__WOE32__) && USE_X
Pixmap flarq_icon_pixmap;
#endif
Socket *tcpip = 0;
string txbuffer;
string cmdbuffer;
string rxbuffer;
size_t bufsize = 0;
size_t bufptr = 0;
bool isRxChar = false;
bool isCmdChar = false;
bool isTxChar = false;
bool inLoop = false;
int exponent = 5;
int txdelay = 500;
int iretries = 5;
long iwaittime = 10000;
long itimeout = 60000;
int bcnInterval = 30;
bool autobeacon = false;
bool beaconrcvd = false;
int blocksSent = 0;
int mainX = 0, mainY = 0, mainW = 600, mainH = 500;
float vers = 0;
float version;
const char *ASCII[32] = {
"<NUL>", "<SOH>", "<STX>", "<ETX>", // 0x00 - 0x03
"<EOT>", "<ENQ>", "<ACK>", "<BEL>", // 0x04 - 0x07
"<BX>", "<TAB>", "<LF>", "<VT>", // 0x08 - 0x0B
"<FF>", "<CR>", "<SO>", "<SI>", // 0x0C - 0x0F
"<DLE>", "<DC1>", "<DC2>", "<DC3>", // 0x10 - 0x13
"<DC4>", "<NAK>", "<SYN>", "<ETB>", // 0x14 - 0x17
"<CAN>", "<EM>", "<SUB>", "<ESC>", // 0x18 - 0x1B
"<FS>", "<GS>", "<RS>", "<US>" // 0x1C - 0x1F
};
string AsciiChars;
string incomingText = "";
string txtarqload = "";
string rxfname = "";
string arqstart = "ARQ::STX\n";
string arqend = "ARQ::ETX\n";
string arqfile = "ARQ:FILE::";
string arqemail = "ARQ:EMAIL::\n";
string arqascii = "ARQ:ENCODING::ASCII\n";
string arqbase64 = "ARQ:ENCODING::BASE64\n";
string arqsizespec = "ARQ:SIZE::";
size_t startpos = string::npos;
size_t endpos = string::npos;
size_t fnamepos = string::npos;
size_t indx = string::npos;
size_t sizepos = string::npos;
size_t lfpos = string::npos;
size_t arqPayloadSize = 0;
bool haveemail = false;
bool rxARQfile = false;
bool rxARQhavesize = false;
bool rxTextReady = false;
time_t StartTime_t;
time_t EndTime_t;
time_t TransferTime_t;
double TransferTime;
//=============================================================================
// email selector
//=============================================================================
int datedir = 1;
int todir = 1;
int subdir = 1;
string sendfilename = "";
void cb_SortByDate()
{
if (datedir == 0) {
tblOutgoing->sort(1, false);
datedir = 1;
} else {
tblOutgoing->sort(1, true);
datedir = 0;
}
tblOutgoing->redraw();
}
void cb_SortByTo()
{
if (todir == 0) {
tblOutgoing->sort(2, false);
todir = 1;
} else {
tblOutgoing->sort(2, true);
todir = 0;
}
tblOutgoing->redraw();
}
void cb_SortBySubj()
{
if (subdir == 0) {
tblOutgoing->sort(3, false);
subdir = 1;
} else {
tblOutgoing->sort(3, true);
subdir = 0;
}
tblOutgoing->redraw();
}
void sendOK()
{
outdialog->hide();
int sel = tblOutgoing->value();
if (sel >= 0)
sendfilename = tblOutgoing->valueAt(sel,0);
else
sendfilename.clear();
}
void sendCancel()
{
outdialog->hide();
sendfilename.clear();
}
void selectTrafficOut(bool ComposerOnly)
{
if (outdialog == 0) {
outdialog = arq_SendSelect();
outdialog->xclass(PACKAGE_TARNAME);
tblOutgoing->addHiddenColumn ("fnbr"); // column #0
tblOutgoing->addColumn ("Date", 180); // column #1
tblOutgoing->addColumn ("To", 120); // column #2
tblOutgoing->addColumn ("Subj", 196); // column #3
tblOutgoing->colcallback (1, cb_SortByDate);
tblOutgoing->columnAlign(1, FL_ALIGN_LEFT);
tblOutgoing->colcallback (2, cb_SortByTo);
tblOutgoing->columnAlign(2, FL_ALIGN_LEFT);
tblOutgoing->colcallback (3, cb_SortBySubj);
tblOutgoing->columnAlign(3, FL_ALIGN_LEFT);
tblOutgoing->allowSort(true);
tblOutgoing->rowSize (14);
tblOutgoing->headerSize (14);
tblOutgoing->allowResize (true);
tblOutgoing->gridEnabled (true);
}
tblOutgoing->clear();
string fline, fname, fdate, fto, fsubj;
char szline[10000];
size_t p;
string folder = ARQ_mail_out_dir;
dp = 0;
dp = opendir(folder.c_str());
if (dp == 0) {
string nfound = folder;
nfound += " not found";
fl_message("%s", nfound.c_str());
return;
}
int nummails = 0;
while ((entry = readdir(dp)) != 0) {
if (entry->d_name[0] == '.')
continue;
fname = folder; fname.append(entry->d_name);
if (fname.find(".eml") == string::npos)
continue;
int validlines = 0;
ifstream emailtxt(fname.c_str());
while (!emailtxt.eof()) {
memset(szline, 0, 10000);
emailtxt.getline(szline,10000);
fline = szline;
if ((p = fline.find("Date: ")) != string::npos) {
fdate = fline.substr(p + 6);
validlines++;
continue;
}
if ((p = fline.find("To: ")) != string::npos) {
fto = fline.substr(p + 4);
p = fto.find('@');
if (p != string::npos) fto.replace(p,1,"@@");
p = fto.find("<");
if (p != string::npos) fto.erase(p,1);
p = fto.find(">");
if (p != string::npos) fto.erase(p,1);
validlines++;
continue;
}
if ((p = fline.find("Subject: ")) != string::npos) {
fsubj = fline.substr(p + 9);
validlines++;
continue;
}
if ((p = fline.find("//FLARQ COMPOSER")) != string::npos)
validlines++;
}
emailtxt.close();
if ((!ComposerOnly && validlines >= 3) || (ComposerOnly && validlines == 4)) {
tblOutgoing->addRow (4, fname.c_str(), fdate.c_str(), fto.c_str(), fsubj.c_str());
nummails++;
}
}
if (nummails) {
tblOutgoing->FirstRow();
outdialog->show();
while (outdialog->shown())
Fl::wait();
} else
fl_message2("No emails for delivery");
}
//======================================================================================
// simple email composer
//======================================================================================
extern bool fileExists(string fname);
void cb_CancelComposeMail()
{
composer->hide();
}
void readComposedFile(string filename)
{
ifstream textfile;
textfile.open(filename.c_str());
if (textfile) {
char szline[10000];
string fline, tempstr;
size_t p;
txtbuffComposer->text("");
while (!textfile.eof()) {
memset(szline,0, 10000);
textfile.getline(szline,10000);
fline = szline;
if ((p = fline.find("//FLARQ COMPOSER")) != string::npos) continue;
if ((p = fline.find("Date: ")) != string::npos) continue;
if ((p = fline.find("From:")) != string::npos) continue;
if ((p = fline.find("To: ")) != string::npos) {
tempstr = fline.substr(p + 4);
p = tempstr.find("<");
if (p != string::npos) tempstr.erase(p,1);
p = tempstr.find(">");
if (p != string::npos) tempstr.erase(p,1);
inpMailTo->value(tempstr.c_str());
continue;
}
if ((p = fline.find("Subject: ")) != string::npos) {
inpMailSubj->value(fline.substr(p + 9).c_str());
continue;
}
if (strlen(szline) == 0 && txtbuffComposer->length() == 0) continue;
txtbuffComposer->append(szline);
txtbuffComposer->append("\n");
}
textfile.close();
}
}
void cb_UseTemplate()
{
string templatename = ARQ_mail_out_dir;
const char *p = FSEL::select("Load Template file", "*.tpl", templatename.c_str());
if (!p) return;
if (!*p) return;
readComposedFile(p);
}
void cb_ClearComposer()
{
sendfilename.clear();
txtbuffComposer->text("");
inpMailTo->value("");
inpMailSubj->value("");
}
string nextEmailFile(string fname)
{
int nbr = 0;
char szNbr[20];
string name;
string ext;
string nuname;
size_t p;
p = fname.find_last_of('.');
if (p != string::npos) {
ext = fname.substr(p);
name = fname.substr(0,p);
} else {
ext = "";
name = fname;
}
do {
nbr++;
nuname = name;
#ifdef __WOE32__
snprintf(szNbr, sizeof(szNbr), "-%-d", nbr);
#else
snprintf(szNbr, sizeof(szNbr), "%-d", nbr);
#endif
nuname.append(szNbr);
nuname.append(ext);
} while (fileExists(nuname));
return nuname;
}
void saveComposedText(string filename)
{
ofstream textfile;
textfile.open(filename.c_str());
textfile << "//FLARQ COMPOSER" << endl;
char szmaildt[100];
time_t maildt = time(NULL);
struct tm *gmt = gmtime(&maildt);
strftime(szmaildt, sizeof(szmaildt), "%x %X", gmt);
textfile << "Date: " << szmaildt << endl;
textfile << "To: " << inpMailTo->value() << endl;
textfile << "From: " << endl;
textfile << "Subject: " << inpMailSubj->value() << endl;
textfile << endl << txtbuffComposer->text() << endl;
textfile.close();
cb_ClearComposer();
}
void SaveComposeMail()
{
if (strlen(inpMailTo->value()) == 0 ||
strlen(inpMailSubj->value()) == 0)
return;
if (sendfilename.empty()) {
sendfilename = ARQ_mail_out_dir;
sendfilename += "flarqmail.eml";
sendfilename = nextEmailFile(sendfilename);
}
saveComposedText(sendfilename);
}
void SaveComposeTemplate()
{
string templatename = ARQ_mail_out_dir;
const char *p = FSEL::saveas("Save Template file", "*.tpl", templatename.c_str());
if (!p) return;
if (!*p) return;
saveComposedText(p);
}
void cb_SaveComposeMail()
{
if (Fl::event_state(FL_SHIFT))
SaveComposeTemplate();
else
SaveComposeMail();
}
void cb_OpenComposeMail()
{
sendfilename.clear();
selectTrafficOut(true);
if (sendfilename.empty())
return;
readComposedFile(sendfilename);
}
void ComposeMail()
{
if (composer == 0) {
composer = arq_composer();
composer->xclass(PACKAGE_TARNAME);
txtbuffComposer = new Fl_Text_Buffer();
txtMailText->buffer(txtbuffComposer);
txtMailText->wrap_mode(1,80);
}
txtbuffComposer->text("");
inpMailTo->value("");
inpMailSubj->value("");
composer->show();
}
//======================================================================================
string noCR(string s)
{
string text = s;
size_t p;
while ((p = text.find('\r')) != string::npos)
text.erase(p,1);
return text;
}
void createAsciiChars()
{
AsciiChars = "";
AsciiChars += 0x09; // tab
AsciiChars += 0x0A; // lf
AsciiChars += 0x0D; // cr
for (int n = 20; n < 128; n++) AsciiChars += n;
}
void initVals()
{
MyCall = "NOCALL";
exponent = digi_arq->getExponent();
iretries = digi_arq->getRetries();
itimeout = digi_arq->getTimeout();
txdelay = digi_arq->getTxDelay();
iwaittime = digi_arq->getWaitTime();
bcnInterval = 30;
beacontext = "";
cbMenuConfig();
digi_arq->myCall(MyCall.c_str());
}
void testDirectory(string dir)
{
string tstdir = ARQ_dir;
tstdir += '/';
tstdir.append(dir);
ifstream test(tstdir.c_str());
if (!test)
mkdir(tstdir.c_str(), 0777);
else
test.close();
}
void readConfig()
{
extern void cbMenuConfig();
string configfname = ARQ_dir;
configfname.append("flarq.config");
ifstream configfile(configfname.c_str());
if (configfile) {
char tempstr[200];
configfile.getline(tempstr,200);
sscanf(tempstr,"%f", &vers);
if (int(vers*10) != int(version*10))
initVals();
else {
configfile >> MyCall;
configfile >> exponent;
configfile >> txdelay;
configfile >> iretries;
configfile >> iwaittime;
configfile >> itimeout;
configfile >> bcnInterval;
configfile >> mainX;
configfile >> mainY;
configfile >> mainW;
configfile >> mainH;
configfile.ignore();
configfile.getline(tempstr, 200);
beacontext = tempstr;
digi_arq->myCall(MyCall.c_str());
digi_arq->setExponent(exponent);
digi_arq->setRetries(iretries);
digi_arq->setTimeout(itimeout);
digi_arq->setTxDelay(txdelay);
digi_arq->setWaitTime(iwaittime);
}
configfile.close();
} else
initVals();
}
void saveConfig()
{
string configfname = ARQ_dir;
configfname.append("flarq.config");
ofstream configfile(configfname.c_str());
if (configfile) {
int mainX = arqwin->x();
int mainY = arqwin->y();
int mainW = arqwin->w();
int mainH = arqwin->h();
configfile << VERSION << endl;
configfile << MyCall << endl;
configfile << exponent << endl;
configfile << txdelay << endl;
configfile << iretries << endl;
configfile << iwaittime << endl;
configfile << itimeout << endl;
configfile << bcnInterval << endl;
configfile << mainX << endl;
configfile << mainY << endl;
configfile << mainW << endl;
configfile << mainH << endl;
configfile << beacontext.c_str() << endl;
configfile.close();
}
}
void cbSetConfig()
{
digi_arq->setExponent(exponent);
digi_arq->setRetries(iretries);
digi_arq->setTimeout(itimeout);
digi_arq->setTxDelay(txdelay);
digi_arq->setWaitTime(iwaittime);
}
void closeConfig()
{
if (dlgconfig)
dlgconfig->hide();
cbSetConfig();
}
void cbMenuConfig()
{
if (!dlgconfig) {
dlgconfig = arq_configure();
dlgconfig->xclass(PACKAGE_TARNAME);
choiceBlockSize->add("16");
choiceBlockSize->add("32");
choiceBlockSize->add("64");
choiceBlockSize->add("128");
choiceBlockSize->add("256");
}
choiceBlockSize->index(exponent - 4);
choiceBlockSize->redraw();
dlgconfig->show();
}
void cbMenuAbout()
{
fl_message2("flarq - ARQ client\nversion: %s\nw1hkj@@w1hkj.com", VERSION);
}
string txhold = "";
//=============================================================================
void mpsk_on()
{
string s;
s.append(1, MPSK_CMD).append(MPSK_TX).append(1, MPSK_END);
try {
tcpip->send(s);
}
catch (const SocketException& e) {
cerr << e.what() << '\n';
}
}
void mpsk_off_after_buffer_sent()
{
string s;
s.append(1, MPSK_CMD).append(MPSK_TX2RX).append(1, MPSK_END);
try {
tcpip->send(s);
}
catch (const SocketException& e) {
cerr << e.what() << '\n';
}
}
void mpsk_off()
{
string s;
s.append(1, MPSK_CMD).append(MPSK_RX).append(1, MPSK_END);
try {
tcpip->send(s);
}
catch (const SocketException& e) {
cerr << e.what() << '\n';
}
}
void MPSK_client_transmit(const string& s)
{
if (s.empty())
return;
string tosend;
tosend.reserve(s.length() * 2);
for (size_t i = 0; i < s.length(); i++)
tosend.append(1, MPSK_BYTE).append(1, s[i]);
try {
mpsk_on();
tcpip->send(tosend);
mpsk_off_after_buffer_sent();
}
catch (const SocketException& e) {
cerr << e.what() << '\n';
}
}
void MPSK_Socket_rcv_loop(void *)
{
if (inLoop) Fl::wait(0.1);
inLoop = true;
char cs;
try {
while (tcpip->wait(0)) {
tcpip->recv(&cs, 1);
if (isRxChar) {
rxbuffer += cs;
isRxChar = false;
continue;
}
if (isTxChar) {
if (cs < 28 || cs > 31)
txbuffer += cs;
isTxChar = false;
continue;
}
if (isCmdChar) {
if (cs == MPSK_CMDEND) {
isCmdChar = false;
if (cmdbuffer.find("RX_AFTER_TX OK") != string::npos) {
rxbuffer += 0x06;
cmdbuffer.clear();
txbuffer.clear();
}
continue;
}
cmdbuffer += cs;
continue;
}
if (cs == MPSK_ISRX) {
isRxChar = true;
continue;
}
if (cs == MPSK_ISCMD) {
isCmdChar = true;
continue;
}
if (cs == MPSK_ISTX) {
isTxChar = true;
continue;
}
}
}
catch (const SocketException& e) {
cerr << e.what() << '\n';
}
inLoop = false;
Fl::add_timeout(0.01, MPSK_Socket_rcv_loop);
}
//=============================================================================
void client_transmit(const string& s )
{
try {
if (!s.empty())
tcpip->send(s);
}
catch (const SocketException& e) {
cerr << e.what() << '\n';
}
}
void Socket_rcv_loop(void *)
{
if (inLoop)
Fl::wait(0.1);
inLoop = true;
try {
tcpip->set_nonblocking(true);
tcpip->recv(rxbuffer);
tcpip->set_nonblocking(false);
}
catch (const SocketException& e) {
cerr << e.what() << '\n';
}
inLoop = false;
Fl::add_timeout(0.01, Socket_rcv_loop);
}
bool client_receive(char &c)
{
if (inLoop) Fl::wait(0.1);
inLoop = true;
bufsize = rxbuffer.length();
if (bufsize) {
if (bufptr < bufsize) {
c = rxbuffer[bufptr++];
inLoop = false;
return true;
}
}
rxbuffer.clear();
bufsize = 0;
bufptr = 0;
inLoop = false;
return false;
}
int autobeaconcounter = 0;
char bcnMsg[40];
void arqAutoBeacon(void *)
{
if (autobeacon == true) {
int currstate = digi_arq->state();
btnCONNECT->deactivate();
btnCONNECT->redraw();
if (currstate > 0x7F) {
txtBeaconing->value("Beaconing");
btnBEACON->deactivate();
btnBEACON->redraw();
Fl::repeat_timeout(1.0, arqAutoBeacon);
return;
} else if (currstate == DOWN || currstate == TIMEDOUT) {
if (autobeaconcounter == 0) {
digi_arq->sendBeacon( beacontext );
autobeaconcounter = bcnInterval;
Fl::repeat_timeout(1.0 + txdelay / 1000.0, arqAutoBeacon);
} else {
snprintf(bcnMsg, sizeof(bcnMsg), "Bcn in: %d sec", autobeaconcounter);
txtBeaconing->value(bcnMsg);
btnBEACON->label("STOP");
btnBEACON->redraw_label();
btnBEACON->activate();
btnBEACON->redraw();
autobeaconcounter--;
Fl::repeat_timeout(1.0, arqAutoBeacon);
}
return;
} else {
autobeaconcounter = 0;
btnBEACON->value(0);
btnBEACON->label("Beacon");
btnBEACON->redraw_label();
btnBEACON->activate();
btnBEACON->redraw();
txtBeaconing->value("Beacon Off");
}
} else {
autobeaconcounter = 0;
btnCONNECT->activate();
btnCONNECT->redraw();
btnBEACON->value(0);
btnBEACON->label("Beacon");
btnBEACON->redraw_label();
btnBEACON->activate();
btnBEACON->redraw();
txtBeaconing->value("Beacon Off");
}
}
void arqBEACON()
{
if (autobeacon == false) {
autobeacon = true;
Fl::add_timeout(0.01, arqAutoBeacon);
} else {
autobeacon = false;
}
}
void printstring(string s)
{
for (size_t n = 0; n < s.length(); n++)
if (s[n] < ' ') printf("<%02d>",(int)s[n]);
else printf("%c", s[n]);
printf("\n");
}
void arqCLOSE()
{
tcpip->close();
saveConfig();
exit_server();
exit(0);
}
void clearText()
{
txtarqload = "";
txtbuffARQ->text("");
txtStatus->value("");
txtStatus2->value("");
}
void restart()
{
TX.clear();
rxfname = "";
rxTextReady = false;
prgStatus->value(0.0);
prgStatus->label("");
prgStatus->redraw();
prgStatus->redraw_label();
rxARQfile = false;
sendingfile = false;
incomingText.clear();
clearText();
}
void arqCONNECT()
{
int state = Fl::event_state();
if ((state & FL_CTRL) == FL_CTRL) {
digi_arq->restart_arq();
txtURCALL->value("");
restart();
return;
}
if (digi_arq->state() < ARQ_CONNECTED) {
if (strlen(txtURCALL->value()) > 0)
digi_arq->connect(txtURCALL->value());
} else {
if (rxARQfile || sendingfile)
abortTransfer();
else {
restart();
digi_arq->disconnect();
txtURCALL->value("");
}
}
}
bool fileExists(string fname)
{
ifstream test(fname.c_str());
if (test) {
test.close();
return true;
}
return false;
}
string nextFileName(string fname)
{
int nbr = 0;
char szNbr[20];
string name;
string ext;
string nuname;
size_t p;
p = fname.find_last_of('.');
if (p != string::npos) {
ext = fname.substr(p);
name = fname.substr(0,p);
} else {
ext = "";
name = fname;
}
do {
nbr++;
nuname = name;
snprintf(szNbr, sizeof(szNbr), ".dup%-d", nbr);
nuname.append(szNbr);
nuname.append(ext);
} while (fileExists(nuname));
return nuname;
}
void saveEmailFile()
{
static char xfrmsg[80];
string tempname;
time(&EndTime_t);
TransferTime = difftime(EndTime_t, StartTime_t);
snprintf(xfrmsg, sizeof(xfrmsg), "Transfer Completed in %4.0f sec's", TransferTime);
string savetoname = ARQ_mail_in_dir;
if (rxfname.find(".eml") == string::npos)
rxfname.append(".eml");
savetoname.append(rxfname);
while (fileExists(savetoname))
savetoname = nextFileName(savetoname);
ofstream tfile(savetoname.c_str(), ios::binary);
if (tfile) {
tfile << txtarqload;
tfile.close();
}
txtStatus->value(xfrmsg);
rxfname = "";
txtarqload = "";
rxTextReady = false;
}
void saveRxFile()
{
static char xfrmsg[80];
time(&EndTime_t);
TransferTime = difftime(EndTime_t, StartTime_t);
snprintf(xfrmsg, sizeof(xfrmsg), "Transfer Completed in %4.0f sec's", TransferTime);
string savetoname = ARQ_recv_dir;
savetoname.append(rxfname);
if (fileExists(savetoname))
savetoname = nextFileName(savetoname);
ofstream tfile(savetoname.c_str(), ios::binary);
if (tfile) {
tfile << txtarqload;
tfile.close();
}
txtStatus->value(xfrmsg);
rxfname = "";
txtarqload = "";
rxTextReady = false;
}
void payloadText(string s)
{
static char szPercent[10];
string text = noCR(s);
string style;
style.append(text.length(), 'A');
stylebufARQ->append(style.c_str());
txtARQ->insert(text.c_str());
txtARQ->show_insert_position();
txtARQ->redraw();
incomingText.append (s);
if (!rxARQfile)
if ((startpos = incomingText.find(arqstart)) != string::npos) {
rxARQfile = true;
startpos += arqstart.length();
time(&StartTime_t);
}
if (rxARQfile) {
if (!rxARQhavesize) {
if ( (sizepos = incomingText.find(arqsizespec)) != string::npos) {
sizepos += arqsizespec.length();
if ((lfpos = incomingText.find('\n', sizepos)) != string::npos) {
string sizechars = incomingText.substr(sizepos, lfpos - sizepos);
sscanf(sizechars.c_str(), "%" PRIuSZ, &arqPayloadSize);
rxARQhavesize = true;
char statusmsg[40];
snprintf(statusmsg, sizeof(statusmsg), "Rcvg: %d",
static_cast<int>(arqPayloadSize));
txtStatus->value(statusmsg);
}
}
} else {
if (startpos != string::npos) {
float partial = incomingText.length() - startpos;
snprintf(szPercent, sizeof(szPercent), "%3.0f %%", 100.0 * partial / arqPayloadSize);
prgStatus->value( partial / arqPayloadSize );
prgStatus->label(szPercent);
} else {
prgStatus->value(0.0);
prgStatus->label("");
}
prgStatus->redraw();
prgStatus->redraw_label();
}
if ((endpos = incomingText.find(arqend)) != string::npos) {
haveemail = false;
fnamepos = incomingText.find(arqfile);
fnamepos += arqfile.length();
indx = incomingText.find('\n', fnamepos);
rxfname = incomingText.substr(fnamepos, indx - fnamepos);
txtarqload = incomingText.substr(startpos, endpos - startpos);
if (incomingText.find(arqbase64) != string::npos) {
base64 b64;
txtarqload = b64.decode(txtarqload);
}
if (incomingText.find(arqemail) != string::npos)
haveemail = true;
startpos = string::npos;
endpos = string::npos;
fnamepos = string::npos;
indx = string::npos;
sizepos = string::npos;
lfpos = string::npos;
arqPayloadSize = 0;
rxARQfile = false;
rxARQhavesize = false;
rxTextReady = true;
if (incomingText.find("FLMSG_XFR") != std::string::npos)
xml_rx_text_ready = true;
incomingText = "";
txtStatus->value("");
prgStatus->value(0.0);
prgStatus->label("");
prgStatus->redraw();
prgStatus->redraw_label();
}
}
}
void cbClearText()
{
txtbuffARQ->text("");
}
void abortedTransfer()
{
restart();
txtARQ->insert("transfer aborted\n");
btnCONNECT->activate();
}
void abortTransfer()
{
sendingfile = false;
SendingEmail = false;
rxARQfile = false;
btnCONNECT->label("ABORTING");
btnCONNECT->redraw_label();
btnCONNECT->deactivate();
digi_arq->abort();
}
void rxBeaconCallsign(string s)
{
txtURCALL->value(s.c_str());
beaconrcvd = true;
}
void moveEmailFile()
{
if (MailFileName.empty()) return;
if (MailSaveFileName.empty()) return;
ifstream infile(MailFileName.c_str(), ios::in | ios::binary);
if (MailSaveFileName.find(".eml") == string::npos)
MailSaveFileName.append(".eml");
while (fileExists(MailSaveFileName))
MailSaveFileName = nextFileName(MailSaveFileName);
ofstream outfile(MailSaveFileName.c_str(), ios::out | ios::binary);
char c;
if (infile && outfile) {
while (!infile.eof()) {
infile.get(c);
outfile.put(c);
}
infile.close();
outfile.close();
unlink(MailFileName.c_str());
}
MailFileName.clear();
MailSaveFileName.clear();
}
void sendEmailFile()
{
if (arqstate < ARQ_CONNECTED) {
fl_alert2("Not connected");
return;
}
sendfilename.clear();
selectTrafficOut(false);
if (sendfilename.empty())
return;
char cin;
size_t txtsize;
string textin = "";
char sizemsg[40];
size_t p;
ifstream textfile;
textfile.open(sendfilename.c_str(), ios::binary);
if (textfile) {
for (size_t i = 0; i < sendfilename.length(); i++)
if (sendfilename[i] == '\\') sendfilename[i] = '/';
MailFileName = sendfilename;
TX.erase();
TX.append(arqfile);
MailSaveFileName = ARQ_mail_sent_dir;
p = sendfilename.find_last_of('/');
if (p != string::npos) p++;
MailSaveFileName.append(sendfilename.substr(p));
TX.append(sendfilename.substr(p));
TX.append("\n");
TX.append(arqemail);
while (textfile.get(cin))
// only allow ASCII printable characters
if ((cin >= ' ' && cin <= '~') ||
(cin == 0x09 || (cin == 0x0a) || cin == 0x0d) )
textin += cin;
textfile.close();
txtsize = textin.length();
arqPayloadSize = txtsize;
blocksSent = 0;
snprintf(sizemsg, sizeof(sizemsg), "ARQ:SIZE::%d\n",
static_cast<int>(txtsize));
TX.append(sizemsg);
TX.append(arqstart);
TX.append(textin);
TX.append(arqend);
traffic = true;
statusmsg = "Sending email: ";
statusmsg.append(sendfilename.substr(p));
txtStatus->value(statusmsg.c_str());
SendingEmail = true;
sendingfile = true;
cbClearText();
return;
}
traffic = false;
sendingfile = false;
SendingEmail = false;
}
void sendAsciiFile()
{
if (arqstate < ARQ_CONNECTED) {
fl_alert2("Not connected");
return;
}
string readfromname = ARQ_send_dir;
readfromname.append(rxfname);
const char *p = FSEL::select("ARQ text file", "*.txt\t*", readfromname.c_str());
char cin;
size_t txtsize;
string textin = "";
char sizemsg[40];
if (p && *p) {
ifstream textfile;
textfile.open(p);
if (textfile) {
TX.erase();
TX.append(arqfile);
p = fl_filename_name(p);
TX.append(p);
TX.append("\n");
TX.append(arqascii);
while (textfile.get(cin))
textin += cin;
textfile.close();
if ( textin.find_first_not_of(AsciiChars) != string::npos) {
fl_alert2("File contains non-ASCII bytes and must be sent as binary.");
return;
}
txtsize = textin.length();
arqPayloadSize = txtsize;
blocksSent = 0;
snprintf(sizemsg, sizeof(sizemsg), "ARQ:SIZE::%d\n",
static_cast<int>(txtsize));
TX.append(sizemsg);
TX.append(arqstart);
TX.append(textin);
TX.append(arqend);
traffic = true;
sendingfile = true;
statusmsg = "Sending ASCII file: ";
statusmsg.append(p);
txtStatus->value(statusmsg.c_str());
cbClearText();
return;
}
}
traffic = false;
sendingfile = false;
}
void sendImageFile()
{
if (arqstate < ARQ_CONNECTED) {
fl_alert2("Not connected");
return;
}
const char *p = FSEL::select("ARQ image file", "*.{png,jpg,bmp}\t*", "");
char cin;
size_t b64size;
string textin = "";
string b64text;
base64 b64(true);
char sizemsg[40];
if (p && *p) {
ifstream textfile;
textfile.open(p, ios::binary);
if (textfile) {
TX.erase();
TX.append(arqfile);
p = fl_filename_name(p);
TX.append(p);
TX.append("\n");
TX.append(arqbase64);
while (textfile.get(cin))
textin += cin;
textfile.close();
b64text = b64.encode(textin);
b64size = b64text.length();
snprintf(sizemsg, sizeof(sizemsg), "ARQ:SIZE::%d\n",
static_cast<int>(b64size));
arqPayloadSize = b64size;
blocksSent = 0;
TX.append(sizemsg);
TX.append(arqstart);
TX.append(b64text);
TX.append(arqend);
traffic = true;
sendingfile = true;
statusmsg = "Sending image: ";
statusmsg.append(p);
txtStatus->value(statusmsg.c_str());
cbClearText();
return;
}
}
traffic = false;
sendingfile = false;
}
void sendBinaryFile()
{
if (arqstate < ARQ_CONNECTED) {
fl_alert2("Not connected");
return;
}
const char *p = FSEL::select("ARQ file", "*", "");
char cin;
size_t b64size;
string textin = "";
string b64text;
base64 b64(true);
char sizemsg[40];
if (p && *p) {
ifstream textfile;
textfile.open(p, ios::binary);
if (textfile) {
TX.erase();
TX.append(arqfile);
p = fl_filename_name(p);
TX.append(p);
TX.append("\n");
TX.append(arqbase64);
while (textfile.get(cin))
textin += cin;
textfile.close();
b64text = b64.encode(textin);
b64size = b64text.length();
snprintf(sizemsg, sizeof(sizemsg), "ARQ:SIZE::%d\n",
static_cast<int>(b64size));
arqPayloadSize = b64size;
blocksSent = 0;
TX.append(sizemsg);
TX.append(arqstart);
TX.append(b64text);
TX.append(arqend);
traffic = true;
sendingfile = true;
statusmsg = "Sending binary: ";
statusmsg.append(p);
txtStatus->value(statusmsg.c_str());
cbClearText();
return;
}
}
traffic = false;
sendingfile = false;
}
void send_xml_text(std::string fname, std::string txt)
{
if (arqstate < ARQ_CONNECTED) {
fl_alert2("Not connected");
return;
}
size_t txtsize;
char sizemsg[40];
if (!txt.empty()) {
TX.erase();
TX.append(arqfile);
TX.append(fname);
TX.append("\n");
TX.append(arqascii);
txtsize = txt.length();
arqPayloadSize = txtsize;
blocksSent = 0;
snprintf(sizemsg, sizeof(sizemsg), "ARQ:SIZE::%d\n",
static_cast<int>(txtsize));
TX.append(sizemsg);
TX.append(arqstart);
TX.append(txt);
TX.append(arqend);
traffic = true;
sendingfile = true;
statusmsg = "Sending XML payload: ";
statusmsg.append(fname);
txtStatus->value(statusmsg.c_str());
cbClearText();
return;
}
traffic = false;
sendingfile = false;
}
char statemsg[80];
void dispState()
{
int currstate = digi_arq->state();
static char xfrmsg[80];
static char szPercent[10];
arqstate = currstate & 0x7F;
if (arqstate == DOWN || arqstate == TIMEDOUT) {
if (btnCONNECT->active())
btnCONNECT->label("Connect");
if (!autobeacon)
btnBEACON->activate();
// mnuSend->deactivate();
mnu->redraw();
}
else if (arqstate == ARQ_CONNECTED || arqstate == WAITING) {
if (btnCONNECT->active())
btnCONNECT->label("Disconnect");
if (!autobeacon)
btnBEACON->deactivate();
mnuSend->activate();
mnu->redraw();
}
if (rxARQfile || sendingfile) {
if (btnCONNECT->active())
btnCONNECT->label("Abort");
}
if (btnCONNECT->active())
btnCONNECT->redraw_label();
if (currstate <= 0x7F) // receiving
switch (currstate) {
case ARQ_CONNECTING :
snprintf(statemsg, sizeof(statemsg), "CONNECTING: %d", digi_arq->getTimeLeft());
txtState->value(statemsg);
txtState->redraw();
autobeacon = false;
break;
case WAITFORACK :
snprintf(statemsg, sizeof(statemsg), "WAITING FOR ACK ");
txtState->value(statemsg);
txtState->redraw();
autobeacon = false;
break;
case ABORT:
case ABORTING :
txtState->value("ABORTING XFR");
txtState->redraw();
autobeacon = false;
break;
case WAITING :
case ARQ_CONNECTED :
char szState[80];
snprintf(szState, sizeof(szState),"CONNECTED - Quality = %4.2f",
digi_arq->quality());
indCONNECT->color(FL_GREEN);
indCONNECT->redraw();
txtState->value(szState);
txtURCALL->value( digi_arq->urCall().c_str() );
autobeacon = false;
break;
case TIMEDOUT :
indCONNECT->color(FL_WHITE);
indCONNECT->redraw();
txtState->value("TIMED OUT");
txtStatus->value("");
autobeacon = false;
beaconrcvd = false;
break;
case DISCONNECT:
case DISCONNECTING:
txtState->value("DISCONNECTING");
break;
case DOWN :
default :
indCONNECT->color(FL_WHITE);
indCONNECT->redraw();
txtState->value("NOT CONNECTED");
txtStatus->value("");
}
if (sendingfile == true) {
if (digi_arq->transferComplete()) {
time(&EndTime_t);
TransferTime = difftime(EndTime_t,StartTime_t);
snprintf(xfrmsg, sizeof(xfrmsg), "Transfer Completed in %4.0f sec's", TransferTime);
txtStatus->value(xfrmsg);
blocksSent = 0;
prgStatus->value(0.0);
prgStatus->label("");
prgStatus->redraw();
prgStatus->redraw_label();
sendingfile = false;
}
else {
prgStatus->value( digi_arq->percentSent());
snprintf(szPercent, sizeof(szPercent), "%3.0f %%", 100.0 * digi_arq->percentSent());
prgStatus->label(szPercent);
prgStatus->redraw();
prgStatus->redraw_label();
}
}
if (SendingEmail == true) {
if (digi_arq->transferComplete()) {
time(&EndTime_t);
TransferTime = difftime(EndTime_t,StartTime_t);
snprintf(xfrmsg, sizeof(xfrmsg), "Transfer Completed in %4.0f sec's", TransferTime);
txtStatus->value(xfrmsg);
moveEmailFile();
blocksSent = 0;
prgStatus->value(0.0);
prgStatus->label("");
prgStatus->redraw();
prgStatus->redraw_label();
SendingEmail = false;
}
else {
prgStatus->value( digi_arq->percentSent());
snprintf(szPercent, sizeof(szPercent), "%3.0f %%", 100.0 * digi_arq->percentSent());
prgStatus->label(szPercent);
prgStatus->redraw();
prgStatus->redraw_label();
}
}
}
void mainloop(void *)
{
if (traffic) {
digi_arq->sendText(TX);
traffic = false;
time(&StartTime_t);
}
dispState();
if (rxTextReady) {
if (haveemail)
saveEmailFile();
else if (!xml_rx_text_ready)
saveRxFile();
}
Fl::repeat_timeout(0.1, mainloop);
}
void changeMyCall(const char *nucall)
{
int currstate = digi_arq->state();
if (currstate != DOWN)
return;
MyCall = nucall;
for (size_t i = 0; i < MyCall.length(); i++)
MyCall[i] = toupper(MyCall[i]);
txtMyCall->value(MyCall.c_str());
digi_arq->myCall(MyCall.c_str());
string title = "flarq ";
title.append(VERSION);
title.append(" - ");
title.append(MyCall);
arqwin->label(title.c_str());
}
void changeBeaconText(const char *txt)
{
beacontext = txt;
}
void TALKprint(string s)
{
string style;
style.append(s.length(), 'A');
stylebufRX->append(style.c_str());
txtRX->insert(s.c_str());
txtRX->show_insert_position();
txtRX->redraw();
}
void clear_STATUS(void* arg)
{
txtStatus2->value("");
}
void STATUSprint(string s, double disptime)
{
txtStatus2->value(s.c_str());
if (disptime > 0.0) {
Fl::remove_timeout( clear_STATUS );
Fl::add_timeout( disptime, clear_STATUS );
}
}
void cbSendTalk()
{
string tosend;
string style;
tosend = txtTX->value();
if (tosend.empty()) return;
tosend += '\n';
digi_arq->sendPlainText(tosend);
txtTX->value("");
style.append(tosend.length(), 'B');
stylebufRX->append(style.c_str());
txtRX->insert(tosend.c_str());
txtRX->show_insert_position();
txtRX->redraw();
}
void arqlog(string nom,string s)
{
static char szGMT[80];
tm *now;
time_t tm;
string strdebug;
time(&tm);
now = localtime( &tm );
strftime(szGMT, sizeof(szGMT), "[%X] ", now);
for (unsigned int i = 0; i < s.length(); i++)
if (s[i] < 32)
strdebug += ASCII[(int)s[i]];
else
strdebug += s[i];
ofstream logfile(Logfile.c_str(), ios::app);
if (logfile)
logfile << nom << szGMT << strdebug << endl;
}
void DEBUGrxprint(string s)
{
string style;
string text = noCR(s);
style.append(text.length(), 'C');
stylebufRX->append(style.c_str());
txtRX->insert(text.c_str());
txtRX->show_insert_position();
txtRX->redraw();
arqlog("<RX>",s);
}
void DEBUGtxprint(string s)
{
string style;
string text = noCR(s);
style.append(text.length(), 'D');
stylebufRX->append(style.c_str());
txtRX->insert(text.c_str());
txtRX->show_insert_position();
txtRX->redraw();
arqlog("<TX>",s);
}
void TXecho(string s)
{
string style;
blocksSent += s.length();
string text = noCR(s);
style.append(text.length(), 'B');
stylebufARQ->append(style.c_str());
txtARQ->insert(text.c_str());
txtARQ->show_insert_position();
txtARQ->redraw();
}
void style_unfinished_cb(int, void*) {
}
void cbClearTalk()
{
txtbuffRX->text("");
stylebufRX->text("");
}
void cb_arqwin(Fl_Widget *, void*)
{
arqCLOSE();
}
int main (int argc, char *argv[] )
{
sscanf(VERSION, "%f", &version);
set_unexpected(handle_unexpected);
set_terminate(diediedie);
setup_signal_handlers();
NBEMS_dir.clear();
{
string appname = argv[0];
string appdir;
char dirbuf[FL_PATH_MAX + 1];
fl_filename_expand(dirbuf, FL_PATH_MAX, appname.c_str());
appdir.assign(dirbuf);
#ifdef __WOE32__
size_t p = appdir.rfind("flarq.exe");
appdir.erase(p);
p = appdir.find("FL_APPS/");
if (p != string::npos) {
NBEMS_dir.assign(appdir.substr(0, p + 8));
} else {
fl_filename_expand(dirbuf, sizeof(dirbuf) -1, "$USERPROFILE/");
NBEMS_dir.assign(dirbuf);
}
NBEMS_dir.append("NBEMS.files/");
#else
fl_filename_absolute(dirbuf, sizeof(dirbuf), argv[0]);
appdir.assign(dirbuf);
size_t p = appdir.rfind("flarq");
if (p != string::npos)
appdir.erase(p);
p = appdir.find("FL_APPS/");
if (p != string::npos)
NBEMS_dir.assign(appdir.substr(0, p + 8));
else {
fl_filename_expand(dirbuf, FL_PATH_MAX, "$HOME/");
NBEMS_dir = dirbuf;
}
DIR *isdir = 0;
string test_dir;
test_dir.assign(NBEMS_dir).append("NBEMS.files/");
isdir = opendir(test_dir.c_str());
if (isdir) {
NBEMS_dir = test_dir;
closedir(isdir);
} else {
NBEMS_dir.append(".nbems/");
}
#endif
}
checkdirectories();
Logfile = ARQ_dir;
Logfile.append("/").append("arqlog.txt");
set_platform_ui();
generate_option_help();
generate_version_text();
int arg_idx;
if (Fl::args(argc, argv, arg_idx, parse_args) != argc) {
cerr << PACKAGE_NAME << ": bad option `" << argv[arg_idx]
<< "'\nTry `" << PACKAGE_NAME
<< " --help' for more information.\n";
exit(EXIT_FAILURE);
}
createAsciiChars(); // allowable ASCII text chars for ".txt" type of files
FSEL::create();
arqwin = arq_dialog();
arqwin->callback(cb_arqwin);
arqwin->xclass(PACKAGE_TARNAME);
// FL_NORMAL_SIZE may have changed; update the menu items
for (int i = 0; i < menu_mnu->size() - 1; i++)
if (menu_mnu[i].text)
menu_mnu[i].labelsize(FL_NORMAL_SIZE);
txtbuffRX = new Fl_Text_Buffer();
txtRX->buffer(txtbuffRX);
txtRX->wrap_mode(1,80);
stylebufRX = new Fl_Text_Buffer();
txtRX->highlight_data(stylebufRX, styletable,
sizeof(styletable) / sizeof(styletable[0]),
'A', style_unfinished_cb, 0);
txtbuffARQ = new Fl_Text_Buffer();
txtARQ->buffer(txtbuffARQ);
txtARQ->wrap_mode(1,80);
stylebufARQ = new Fl_Text_Buffer();
txtARQ->highlight_data(stylebufARQ, styletable,
sizeof(styletable) / sizeof(styletable[0]),
'A', style_unfinished_cb, 0);
digi_arq = new arq();
try {
tcpip = new Socket(Address(arq_address.c_str(), arq_port.c_str()));
tcpip->set_timeout(0.01);
tcpip->connect();
}
catch (const SocketException& e) {
string errmsg;
errmsg.append("Could not connect to modem program.\nPlease start ");
if (ioMPSK)
errmsg.append("MultiPSK");
else
errmsg.append("fldigi");
errmsg.append(" before flarq.");
fl_alert2("%s", errmsg.c_str());
exit(EXIT_FAILURE);
}
if (ioMPSK)
Fl::add_timeout(0.1, MPSK_Socket_rcv_loop);
else
Fl::add_timeout(0.1, Socket_rcv_loop);
// the following sequence of assigning callback functions is mandatory
// for the arq class to function
if (ioMPSK)
digi_arq->setSendFunc (MPSK_client_transmit);
else
digi_arq->setSendFunc (client_transmit);
digi_arq->setGetCFunc (client_receive);
digi_arq->setAbortedTransfer(abortedTransfer);
digi_arq->setDisconnected(restart);
digi_arq->setrxUrCall (rxBeaconCallsign);
digi_arq->setPrintRX (payloadText);
digi_arq->setPrintTX (TXecho);
digi_arq->setPrintTALK (TALKprint);
digi_arq->setPrintSTATUS (STATUSprint);
if (SHOWDEBUG) {
digi_arq->setPrintRX_DEBUG (DEBUGrxprint);
digi_arq->setPrintTX_DEBUG (DEBUGtxprint);
}
digi_arq->start_arq();
readConfig();
string title = "flarq ";
title.append(VERSION);
title.append(" - ");
title.append(MyCall);
arqwin->label(title.c_str());
arqwin->resize(mainX, mainY, mainW, mainH);
txtBeaconing->value("Beacon Off");
Fl::add_timeout(0.1, mainloop);
#ifdef __WOE32__
# ifndef IDI_ICON
# define IDI_ICON 101
# endif
arqwin->icon((char*)LoadIcon(fl_display, MAKEINTRESOURCE(IDI_ICON)));
#elif !defined(__APPLE__) && USE_X
make_pixmap(&flarq_icon_pixmap, flarq_icon, argc, argv);
arqwin->icon((char *)flarq_icon_pixmap);
#endif
start_xml_server(FLARQ_XML_PORT);
arqwin->show(argc, argv);
return Fl::run();
}
static void checkdirectories(void)
{
struct DIRS {
string& dir;
const char* suffix;
void (*new_dir_func)(void);
};
DIRS NBEMS_dirs[] = {
{ NBEMS_dir, 0, 0 },
{ ARQ_dir, "ARQ", 0 },
{ ARQ_files_dir, "ARQ/files", 0 },
{ ARQ_recv_dir, "ARQ/recv", 0 },
{ ARQ_send_dir, "ARQ/send", 0 },
{ ARQ_mail_dir, "ARQ/mail", 0 },
{ ARQ_mail_in_dir, "ARQ/mail/in", 0 },
{ ARQ_mail_out_dir, "ARQ/mail/out", 0 },
{ ARQ_mail_sent_dir, "ARQ/mail/sent", 0 },
{ WRAP_dir, "WRAP", 0 },
{ WRAP_recv_dir, "WRAP/recv", 0 },
{ WRAP_send_dir, "WRAP/send", 0 },
{ WRAP_auto_dir, "WRAP/auto", 0 },
{ ICS_dir, "ICS", 0 },
{ ICS_msg_dir, "ICS/messages", 0 },
{ ICS_tmp_dir, "ICS/templates", 0 },
};
int r;
for (size_t i = 0; i < sizeof(NBEMS_dirs)/sizeof(*NBEMS_dirs); i++) {
if (NBEMS_dirs[i].suffix)
NBEMS_dirs[i].dir.assign(NBEMS_dir).append(NBEMS_dirs[i].suffix).append("/");
if ((r = mkdir(NBEMS_dirs[i].dir.c_str(), 0777)) == -1 && errno != EEXIST) {
cerr << _("Could not make directory") << ' ' << NBEMS_dirs[i].dir
<< ": " << strerror(errno) << '\n';
exit(EXIT_FAILURE);
}
else if (r == 0 && NBEMS_dirs[i].new_dir_func)
NBEMS_dirs[i].new_dir_func();
}
}