dl-fldigi/src/logbook/logsupport.cxx

1676 wiersze
42 KiB
C++

// ----------------------------------------------------------------------------
// logsupport.cxx
//
// Copyright (C) 2006-2010
// Dave Freese, W1HKJ
// Copyright (C) 2008-2009
// Stelios Bounanos, M0GLD
//
// 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 fldigi. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#include <config.h>
#include <string>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include "main.h"
#include "trx.h"
#include "debug.h"
#include "macros.h"
#include "status.h"
#include "date.h"
#include "logger.h"
#include "adif_io.h"
#include "textio.h"
#include "logbook.h"
#include "rigsupport.h"
#include "fl_digi.h"
#include "fileselect.h"
#include "configuration.h"
#include "main.h"
#include "locator.h"
#include "icons.h"
#include "gettext.h"
#include "qrunner.h"
#include "flmisc.h"
#include <FL/filename.H>
#include <FL/fl_ask.H>
using namespace std;
cQsoDb qsodb;
cAdifIO adifFile;
cTextFile txtFile;
string logbook_filename;
enum sorttype {NONE, SORTCALL, SORTDATE, SORTFREQ, SORTMODE};
sorttype lastsort = SORTDATE;
bool callfwd = true;
bool modefwd = true;
bool freqfwd = true;
void restore_sort();
// convert to and from "00:00:00" <=> "000000"
const char *timeview(const char *s)
{
static char ds[9];
int len = strlen(s);
strcpy(ds, "00:00:00");
if (len < 4)
return ds;
ds[0] = s[0]; ds[1] = s[1];
ds[3] = s[2]; ds[4] = s[3];
if (len < 6)
return ds;
ds[6] = s[4];
ds[7] = s[5];
return ds;
}
const char *timestring(const char *s)
{
static char ds[7];
int len = strlen(s);
if (len <= 4) return s;
ds[0] = s[0]; ds[1] = s[1];
ds[2] = s[3]; ds[3] = s[4];
if (len < 8) {
ds[4] = ds[5] = '0';
ds[6] = 0;
return ds;
}
ds[4] = s[6];
ds[5] = s[7];
ds[6] = 0;
return ds;
}
const char *timeview4(const char *s)
{
static char ds[6];
int len = strlen(s);
strcpy(ds, "00:00");
if (len < 5)
return ds;
ds[0] = s[0]; ds[1] = s[1];
ds[3] = s[2]; ds[4] = s[3];
return ds;
}
const char *time4(const char *s)
{
static char ds[5];
int len = strlen(s);
if (len <= 4)
return ds;
memset(ds, 0, 5);
strncpy(ds, s, 4);
return ds;
}
void Export_CSV()
{
if (chkExportBrowser->nchecked() == 0) return;
cQsoRec *rec;
string title = _("Export to CSV file");
string filters = "CSV\t*.csv";
#ifdef __APPLE__
filters.append("\n");
#endif
const char* p = FSEL::saveas( title.c_str(), filters.c_str(), "export.csv");
if (!p) return;
if (!*p) return;
for (int i = 0; i < chkExportBrowser->FLTK_nitems(); i++) {
if (chkExportBrowser->checked(i + 1)) {
rec = qsodb.getRec(i);
rec->putField(EXPORT, "E");
qsodb.qsoUpdRec (i, rec);
}
}
string sp = p;
if (sp.find(".csv") == string::npos) sp.append(".csv");
txtFile.writeCSVFile(sp.c_str(), &qsodb);
}
void Export_TXT()
{
if (chkExportBrowser->nchecked() == 0) return;
cQsoRec *rec;
string title = _("Export to fixed field text file");
string filters = "TEXT\t*.txt";
#ifdef __APPLE__
filters.append("\n");
#endif
const char* p = FSEL::saveas( title.c_str(), filters.c_str(), "export.txt");
if (!p) return;
if (!*p) return;
for (int i = 0; i < chkExportBrowser->FLTK_nitems(); i++) {
if (chkExportBrowser->checked(i + 1)) {
rec = qsodb.getRec(i);
rec->putField(EXPORT, "E");
qsodb.qsoUpdRec (i, rec);
}
}
string sp = p;
if (sp.find(".txt") == string::npos) sp.append(".txt");
txtFile.writeTXTFile(p, &qsodb);
}
void Export_ADIF()
{
if (chkExportBrowser->nchecked() == 0) return;
cQsoRec *rec;
string title = _("Export to ADIF file");
string filters;
string defname;
filters.assign("ADIF\t*.").append(ADIF_SUFFIX);
#ifdef __APPLE__
filters.append("\n");
#endif
defname.assign("export.").append(ADIF_SUFFIX);
const char* p = FSEL::saveas( title.c_str(), filters.c_str(), defname.c_str());
if (!p) return;
if (!*p) return;
for (int i = 0; i < chkExportBrowser->FLTK_nitems(); i++) {
if (chkExportBrowser->checked(i + 1)) {
rec = qsodb.getRec(i);
rec->putField(EXPORT, "E");
qsodb.qsoUpdRec (i, rec);
}
}
string sp = p;
if (sp.find("." ADIF_SUFFIX) == string::npos) sp.append("." ADIF_SUFFIX);
adifFile.writeFile (sp.c_str(), &qsodb);
}
static savetype export_to = ADIF;
void Export_log()
{
if (export_to == ADIF) Export_ADIF();
else if (export_to == CSV) Export_CSV();
else Export_TXT();
}
void saveLogbook()
{
if (!qsodb.isdirty()) return;
if (progdefaults.NagMe)
if (!fl_choice2(_("Save changed Logbook?"), _("No"), _("Yes"), NULL))
return;
cQsoDb::reverse = false;
qsodb.SortByDate(progdefaults.sort_date_time_off);
qsodb.isdirty(0);
restore_sort();
adifFile.writeLog (logbook_filename.c_str(), &qsodb);
}
static void dxcc_entity_cache_clear(void);
static void dxcc_entity_cache_add(cQsoRec* r);
static void dxcc_entity_cache_rm(cQsoRec* r);
static void dxcc_entity_cache_add(cQsoDb& db);
void cb_mnuNewLogbook(Fl_Menu_* m, void* d){
saveLogbook();
logbook_filename = LogsDir;
logbook_filename.append("newlog." ADIF_SUFFIX);
progdefaults.logbookfilename = logbook_filename;
dlgLogbook->label(fl_filename_name(logbook_filename.c_str()));
progdefaults.changed = true;
qsodb.deleteRecs();
dxcc_entity_cache_clear();
wBrowser->clear();
clearRecord();
}
void adif_read_OK()
{
if (qsodb.nbrRecs() == 0)
adifFile.writeFile(logbook_filename.c_str(), &qsodb);
dxcc_entity_cache_clear();
dxcc_entity_cache_add(qsodb);
restore_sort();
activateButtons();
loadBrowser();
}
void cb_mnuOpenLogbook(Fl_Menu_* m, void* d)
{
string title = _("Open logbook file");
string filter;
filter.assign("ADIF file\t*.{adi,adif}");
#ifdef __APPLE__
filter.append("\n");
#endif
std::string deffilename = LogsDir;
deffilename.append(fl_filename_name(logbook_filename.c_str()));
const char* p = FSEL::select( title.c_str(), filter.c_str(), deffilename.c_str());
if (!p) return;
if (!*p) return;
saveLogbook();
qsodb.deleteRecs();
logbook_filename = p;
progdefaults.logbookfilename = logbook_filename;
progdefaults.changed = true;
adifFile.readFile (logbook_filename.c_str(), &qsodb);
dlgLogbook->label(fl_filename_name(logbook_filename.c_str()));
qsodb.isdirty(0);
}
void cb_mnuSaveLogbook(Fl_Menu_*m, void* d) {
string title = _("Save logbook file");
string filter;
filter.assign("ADIF\t*.").append(ADIF_SUFFIX);
#ifdef __APPLE__
filter.append("\n");
#endif
std::string deffilename = LogsDir;
deffilename.append(fl_filename_name(logbook_filename.c_str()));
const char* p = FSEL::saveas( title.c_str(), filter.c_str(), deffilename.c_str());
if (!p) return;
if (!*p) return;
logbook_filename = p;
if (logbook_filename.find("." ADIF_SUFFIX) == string::npos)
logbook_filename.append("." ADIF_SUFFIX);
progdefaults.logbookfilename = logbook_filename;
progdefaults.changed = true;
dlgLogbook->label(fl_filename_name(logbook_filename.c_str()));
cQsoDb::reverse = false;
qsodb.SortByDate(progdefaults.sort_date_time_off);
qsodb.isdirty(0);
restore_sort();
adifFile.writeLog (logbook_filename.c_str(), &qsodb);
}
int comparerecs (const void *rp1, const void *rp2) { // rp1 needle, rp2 haystack
cQsoRec *r1 = (cQsoRec *)rp1;
cQsoRec *r2 = (cQsoRec *)rp2;
int cmp = 0;
// compare by call
const char * s1 = r1->getField(CALL);
const char * s2 = r2->getField(CALL);
const char *p1 = strpbrk (s1+1, "0123456789");
const char *p2 = strpbrk (s2+1, "0123456789");
if (p1 && p2) {
cmp = (*p1 < *p2) ? -1 : (*p1 > *p2) ? 1 : 0;
if (cmp == 0) {
cmp = strncmp (s1, s2, max(p1 - s1, p2 - s2));
if (cmp == 0)
cmp = strcmp(p1+1, p2+1);
}
} else // not a normal call, do a simple string comparison
cmp = strcmp(s1, s2);
if (cmp != 0)
return cmp;
// compare by date
cmp = strcmp( r1->getField(QSO_DATE), r2->getField(QSO_DATE));
if (cmp != 0) return cmp;
// compare by time
int t1 = atoi(r1->getField(TIME_ON));
int t2 = atoi(r2->getField(TIME_ON));
if (abs(t1 - t2) > 200) { // changed from 2 to accommodate seconds
if (t1 < t2)
return -1;
if (t1 > t2)
return 1;
} // matched with +/- 2 minutes
// compare by mode
const char *m1 = r1->getField(MODE); // needle
const char *m2 = r2->getField(MODE); // haystack
if (strcasestr(m1, "DOM"))
cmp = strncasecmp("DOM", m2, 3);
else if (strcasestr(m2, m1)) // eQSL, LoTW use sparse MODE designators
cmp = 0;
else
cmp = strcasecmp(m1, m2);
if (cmp != 0) return cmp;
// compare by band
cmp = strcasecmp( r1->getField(BAND), r2->getField(BAND));
if (cmp == 0) printf("r1: %s, %s, %s, %s, %s\nr2: %s, %s, %s, %s, %s\n",
r1->getField(CALL), r1->getField(QSO_DATE), r1->getField(TIME_ON), r1->getField(MODE), r1->getField(BAND),
r2->getField(CALL), r2->getField(QSO_DATE), r2->getField(TIME_ON), r2->getField(MODE), r2->getField(BAND));
return cmp;
}
static void rxtext(const char *s)
{
ReceiveText->addstr(s);
}
void merge_recs( cQsoDb *db, cQsoDb *mrgdb ) // (haystack, needle)
{
static char msg1[100];
static char msg2[100];
static char msg3[100];
sorttype origsort = lastsort;
cQsoDb::reverse = false;
cQsoDb *reject = new cQsoDb;
cQsoDb *copy = new cQsoDb(db);
cQsoDb *merged = new cQsoDb;
snprintf(msg1, sizeof(msg1), "Read %d records", mrgdb->nbrRecs());
LOG_INFO("%s", msg1);
REQ(rxtext, "\n*** ");
REQ(rxtext, msg1);
db->clearDatabase();
copy->SortByCall();
mrgdb->SortByCall();
int n = 0; // copy
int m = 0; // merge
int N = copy->nbrRecs();
int M = mrgdb->nbrRecs();
int cmp;
for (;;) {
if (n == N && m == M) break;
if (n < N && m < M) {
if ((cmp = comparerecs(copy->getRec(n), mrgdb->getRec(m))) <= 0) {
db->qsoNewRec(copy->getRec(n));
n++;
if (cmp == 0) {
reject->qsoNewRec(mrgdb->getRec(m));
m++;
}
} else {
if (db->nbrRecs() == 0) {
db->qsoNewRec(mrgdb->getRec(m));
merged->qsoNewRec(mrgdb->getRec(m));
} else if (comparerecs(db->getRec(db->nbrRecs()-1), mrgdb->getRec(m)) != 0) {
db->qsoNewRec(mrgdb->getRec(m));
merged->qsoNewRec(mrgdb->getRec(m));
} else {
reject->qsoNewRec(mrgdb->getRec(m));
}
m++;
}
} else if (n == N) {
if (db->nbrRecs() == 0) {
db->qsoNewRec(mrgdb->getRec(m));
merged->qsoNewRec(mrgdb->getRec(m));
} else if (comparerecs(db->getRec(db->nbrRecs()-1), mrgdb->getRec(m)) != 0) {
db->qsoNewRec(mrgdb->getRec(m));
merged->qsoNewRec(mrgdb->getRec(m));
} else {
reject->qsoNewRec(mrgdb->getRec(m));
}
m++;
} else {
db->qsoNewRec(copy->getRec(n));
n++;
}
}
if (merged->nbrRecs()) {
string mergedname = LogsDir;
mergedname.append("merged_recs");
#ifdef __WIN32__
mergedname.append(".adi");
#else
mergedname.append(".adif");
#endif
adifFile.writeLog (mergedname.c_str(), merged, true);
snprintf(msg2, sizeof(msg2), "%d merged records saved in\n*** %s",
merged->nbrRecs(), mergedname.c_str());
REQ(rxtext, "\n*** ");
REQ(rxtext, msg2);
LOG_INFO("%s", msg2);
db->isdirty(1);
}
if (reject->nbrRecs()) {
string rejname = LogsDir;
rejname.append("duplicate_recs");
#ifdef __WIN32__
rejname.append(".adi");
#else
rejname.append(".adif");
#endif
adifFile.writeLog (rejname.c_str(), reject, true);
snprintf(msg3, sizeof(msg3), "%d duplicates's saved in\n %s",
reject->nbrRecs(), rejname.c_str());
REQ(rxtext, "\n*** ");
REQ(rxtext, msg3);
LOG_INFO("%s", msg3);
}
delete reject;
delete copy;
delete merged;
lastsort = origsort;
restore_sort();
loadBrowser();
}
void cb_mnuMergeADIF_log(Fl_Menu_* m, void* d) {
const char* p = FSEL::select(_("Merge ADIF file"), "ADIF\t*.{adi,adif}", LogsDir.c_str());
Fl::wait();
fl_digi_main->redraw();
Fl::awake();
if (!p) return;
if (!*p) return;
cQsoDb *mrgdb = new cQsoDb;
adifFile.do_readfile (p, mrgdb);
merge_recs(&qsodb, mrgdb);
delete mrgdb;
}
void cb_export_date_select() {
if (qsodb.nbrRecs() == 0) return;
int start = atoi(inp_export_start_date->value());
int stop = atoi(inp_export_stop_date->value());
if (!start || !stop) return;
int chkdate;
chkExportBrowser->check_none();
if (!btn_export_by_date->value()) return;
cQsoRec *rec;
for (int i = 0; i < qsodb.nbrRecs(); i++) {
rec = qsodb.getRec (i);
chkdate = atoi(rec->getField(progdefaults.sort_date_time_off ? QSO_DATE_OFF : QSO_DATE));
if (chkdate >= start && chkdate <= stop)
chkExportBrowser->checked(i+1, 1);
}
chkExportBrowser->redraw();
}
inline const char *szfreq(const char *freq)
{
static char szf[11];
float f = atof(freq);
snprintf(szf, sizeof(szf), "%10.6f", f);
return szf;
}
void cb_Export_log() {
if (qsodb.nbrRecs() == 0) return;
cQsoRec *rec;
char line[80];
chkExportBrowser->clear();
#ifdef __APPLE__
chkExportBrowser->textfont(FL_SCREEN_BOLD);
chkExportBrowser->textsize(12);
#else
chkExportBrowser->textfont(FL_COURIER);
chkExportBrowser->textsize(12);
#endif
for( int i = 0; i < qsodb.nbrRecs(); i++ ) {
rec = qsodb.getRec (i);
snprintf(line,sizeof(line),"%8s %4s %-10s %-10s %-s",
rec->getField(QSO_DATE),
rec->getField(TIME_OFF),
rec->getField(CALL),
szfreq(rec->getField(FREQ)),
rec->getField(MODE) );
chkExportBrowser->add(line);
}
cb_export_date_select();
wExport->show();
}
void cb_mnuExportADIF_log(Fl_Menu_* m, void* d) {
export_to = ADIF;
cb_Export_log();
}
void cb_mnuExportCSV_log(Fl_Menu_* m, void* d) {
export_to = CSV;
cb_Export_log();
}
void cb_mnuExportTEXT_log(Fl_Menu_* m, void *d) {
export_to = TEXT;
cb_Export_log();
}
void cb_mnuShowLogbook(Fl_Menu_* m, void* d)
{
dlgLogbook->show();
}
enum State {VIEWREC, NEWREC};
static State logState = VIEWREC;
void activateButtons()
{
if (logState == NEWREC) {
bNewSave->label(_("Save"));
bUpdateCancel->label(_("Cancel"));
bUpdateCancel->activate();
bDelete->deactivate ();
bSearchNext->deactivate ();
bSearchPrev->deactivate ();
inpDate_log->take_focus();
return;
}
bNewSave->label(_("New"));
bUpdateCancel->label(_("Update"));
if (qsodb.nbrRecs() > 0) {
bDelete->activate();
bUpdateCancel->activate();
bSearchNext->activate ();
bSearchPrev->activate ();
wBrowser->take_focus();
} else {
bDelete->deactivate();
bUpdateCancel->deactivate();
bSearchNext->deactivate();
bSearchPrev->deactivate();
}
}
void cb_btnNewSave(Fl_Button* b, void* d) {
if (logState == VIEWREC) {
logState = NEWREC;
clearRecord();
activateButtons();
} else {
saveRecord();
qsodb.SortByDate(progdefaults.sort_date_time_off);
loadBrowser();
logState = VIEWREC;
activateButtons();
}
}
void cb_btnUpdateCancel(Fl_Button* b, void* d) {
if (logState == NEWREC) {
logState = VIEWREC;
activateButtons ();
} else {
updateRecord();
wBrowser->take_focus();
}
}
void cb_btnDelete(Fl_Button* b, void* d) {
deleteRecord();
wBrowser->take_focus();
}
void restore_sort()
{
switch (lastsort) {
case SORTCALL :
cQsoDb::reverse = callfwd;
qsodb.SortByCall();
break;
case SORTDATE :
cQsoDb::reverse = progStatus.logbook_reverse;
qsodb.SortByDate(progdefaults.sort_date_time_off);
break;
case SORTFREQ :
cQsoDb::reverse = freqfwd;
qsodb.SortByFreq();
break;
case SORTMODE :
cQsoDb::reverse = modefwd;
qsodb.SortByMode();
break;
default: break;
}
}
void cb_SortByCall (void) {
if (lastsort == SORTCALL)
callfwd = !callfwd;
else {
callfwd = false;
lastsort = SORTCALL;
}
cQsoDb::reverse = callfwd;
qsodb.SortByCall();
loadBrowser();
}
void cb_SortByDate (void) {
if (lastsort == SORTDATE)
progStatus.logbook_reverse = !progStatus.logbook_reverse;
else {
lastsort = SORTDATE;
}
cQsoDb::reverse = progStatus.logbook_reverse;
qsodb.SortByDate(progdefaults.sort_date_time_off);
loadBrowser();
}
void reload_browser()
{
qsodb.SortByDate(progdefaults.sort_date_time_off);
loadBrowser();
}
void cb_SortByMode (void) {
if (lastsort == SORTMODE)
modefwd = !modefwd;
else {
modefwd = false;
lastsort = SORTMODE;
}
cQsoDb::reverse = modefwd;
qsodb.SortByMode();
loadBrowser();
}
void cb_SortByFreq (void) {
if (lastsort == SORTFREQ)
freqfwd = !freqfwd;
else {
freqfwd = false;
lastsort = SORTFREQ;
}
cQsoDb::reverse = freqfwd;
qsodb.SortByFreq();
loadBrowser();
}
void DupCheck()
{
Fl_Color call_clr = progdefaults.LOGGINGcolor;
if (progdefaults.xml_logbook)
if (xml_check_dup())
call_clr = fl_rgb_color(
progdefaults.dup_color.R,
progdefaults.dup_color.G,
progdefaults.dup_color.B);
if (!progdefaults.xml_logbook && qsodb.duplicate(
inpCall->value(),
zdate(), ztime(), progdefaults.timespan, progdefaults.duptimespan,
inpFreq->value(), progdefaults.dupband,
inpState->value(), progdefaults.dupstate,
mode_info[active_modem->get_mode()].adif_name, progdefaults.dupmode,
inpXchgIn->value(), progdefaults.dupxchg1 ) ) {
call_clr = fl_rgb_color(
progdefaults.dup_color.R,
progdefaults.dup_color.G,
progdefaults.dup_color.B);
}
inpCall1->color(call_clr);
inpCall2->color(call_clr);
inpCall3->color(call_clr);
inpCall4->color(call_clr);
inpCall1->redraw();
inpCall2->redraw();
inpCall3->redraw();
inpCall4->redraw();
}
cQsoRec* SearchLog(const char *callsign)
{
size_t len = strlen(callsign);
char* re = new char[len + 3];
snprintf(re, len + 3, "^%s$", callsign);
int row = 0, col = 2;
return wBrowser->search(row, col, !cQsoDb::reverse, re) ? qsodb.getRec(row) : 0;
}
void SearchLastQSO(const char *callsign)
{
size_t len = strlen(callsign);
if (len < 3)
return;
if (progdefaults.xml_logbook) {
if(xml_get_record(callsign))
return;
}
Fl::focus(inpCall);
char* re = new char[len + 3];
snprintf(re, len + 3, "^%s$", callsign);
int row = 0, col = 2;
if (wBrowser->search(row, col, !cQsoDb::reverse, re)) {
wBrowser->GotoRow(row);
inpName->value(inpName_log->value());
inpQth->value(inpQth_log->value());
inpLoc->value(inpLoc_log->value());
inpState->value(inpState_log->value());
inpVEprov->value(inpVE_Prov_log->value ());
inpCountry->value(inpCountry_log->value ());
inpSearchString->value(callsign);
if (inpLoc->value()[0]) {
double lon1, lat1, lon2, lat2;
double azimuth, distance;
char szAZ[4];
if ( QRB::locator2longlat(&lon1, &lat1, progdefaults.myLocator.c_str()) == QRB::QRB_OK &&
QRB::locator2longlat(&lon2, &lat2, inpLoc->value()) == QRB::QRB_OK &&
QRB::qrb(lon1, lat1, lon2, lat2, &distance, &azimuth) == QRB::QRB_OK ) {
snprintf(szAZ,sizeof(szAZ),"%0.f", azimuth);
inpAZ->value(szAZ);
} else
inpAZ->value("");
} else
inpAZ->value("");
} else {
inpName->value("");
inpQth->value("");
inpLoc->value("");
inpState->value("");
inpVEprov->value("");
inpCountry->value("");
inpAZ->value("");
inpSearchString->value("");
}
delete [] re;
}
void cb_search(Fl_Widget* w, void*)
{
const char* str = inpSearchString->value();
if (!*str)
return;
bool rev = w == bSearchPrev;
int col = 2, row = wBrowser->value() + (rev ? -1 : 1);
row = WCLAMP(row, 0, wBrowser->rows() - 1);
if (wBrowser->search(row, col, rev, str))
wBrowser->GotoRow(row);
wBrowser->take_focus();
}
int log_search_handler(int)
{
if (!(Fl::event_state() & FL_CTRL))
return 0;
switch (Fl::event_key()) {
case 's':
bSearchNext->do_callback();
break;
case 'r':
bSearchPrev->do_callback();
break;
default:
return 0;
}
return 1;
}
static int editNbr = 0;
void cb_btnDialFreq(Fl_Button* b, void* d)
{
double drf = atof(inpFreq_log->value());
if (!drf) return;
int rf1, rf, audio;
rf1 = drf * 1e6;
rf = rf1 / 10000;
rf *= 10000;
audio = rf1 - rf;
// try to keep within normal xcvr bw, 500 - 3000 Hz
while (audio > 3000) {
audio -= 3000;
rf += 3000;
}
if (audio < 500) {
audio += 500;
rf -= 500;
}
qsy(rf, audio);
std::string mode_name = inpMode_log->value();
trx_mode m;
for (m = 0; m < NUM_MODES; m++)
if (mode_name == mode_info[m].adif_name)
break;
// do we have a valid modem?
if (m < NUM_MODES && active_modem->get_mode() != mode_info[m].mode)
init_modem(mode_info[m].mode);
const cQsoRec *qsoPtr = qsodb.getRec(editNbr);
inpCall->value(qsoPtr->getField(CALL));
inpName->value (qsoPtr->getField(NAME));
inpTimeOn->value (inpTimeOff->value());
inpState->value (qsoPtr->getField(STATE));
inpCountry->value (qsoPtr->getField(COUNTRY));
inpXchgIn->value(qsoPtr->getField(XCHG1));
inpQth->value (qsoPtr->getField(QTH));
inpLoc->value (qsoPtr->getField(GRIDSQUARE));
inpNotes->value (qsoPtr->getField(NOTES));
wBrowser->take_focus();
}
void clearRecord() {
Date tdy;
inpCall_log->value ("");
inpName_log->value ("");
inpDate_log->value (tdy.szDate(2));
inpDateOff_log->value (tdy.szDate(2));
inpTimeOn_log->value ("");
inpTimeOff_log->value ("");
inpRstR_log->value ("");
inpRstS_log->value ("");
inpFreq_log->value ("");
inpMode_log->value ("");
inpQth_log->value ("");
inpState_log->value ("");
inpVE_Prov_log->value ("");
inpCountry_log->value ("");
inpLoc_log->value ("");
inpQSLrcvddate_log->value ("");
inpQSLsentdate_log->value ("");
inpSerNoOut_log->value ("");
inpSerNoIn_log->value ("");
inpXchgIn_log->value("");
inpMyXchg_log->value(progdefaults.myXchg.c_str());
inpNotes_log->value ("");
inpIOTA_log->value("");
inpDXCC_log->value("");
inpQSL_VIA_log->value("");
inpCONT_log->value("");
inpCNTY_log->value("");
inpCQZ_log->value("");
inpITUZ_log->value("");
inpTX_pwr_log->value("");
inpSearchString->value ("");
}
void saveRecord() {
cQsoRec rec;
rec.putField(CALL, inpCall_log->value());
rec.putField(NAME, inpName_log->value());
rec.putField(QSO_DATE, inpDate_log->value());
rec.putField(QSO_DATE_OFF, inpDateOff_log->value());
string tm = timestring(inpTimeOn_log->value());
rec.putField(TIME_ON, tm.c_str());
inpTimeOn_log->value(timeview(tm.c_str()));
tm = timestring(inpTimeOff_log->value());
rec.putField(TIME_OFF, tm.c_str());
inpTimeOff_log->value(timeview(tm.c_str()));
rec.putField(FREQ, inpFreq_log->value());
rec.putField(MODE, inpMode_log->value());
rec.putField(QTH, inpQth_log->value());
rec.putField(STATE, inpState_log->value());
rec.putField(VE_PROV, inpVE_Prov_log->value());
rec.putField(COUNTRY, inpCountry_log->value());
rec.putField(GRIDSQUARE, inpLoc_log->value());
rec.putField(NOTES, inpNotes_log->value());
rec.putField(QSLRDATE, inpQSLrcvddate_log->value());
rec.putField(QSLSDATE, inpQSLsentdate_log->value());
rec.putField(RST_RCVD, inpRstR_log->value ());
rec.putField(RST_SENT, inpRstS_log->value ());
rec.putField(SRX, inpSerNoIn_log->value());
rec.putField(STX, inpSerNoOut_log->value());
rec.putField(XCHG1, inpXchgIn_log->value());
if (!qso_exchange.empty()) {
rec.putField(MYXCHG, qso_exchange.c_str());
qso_exchange.clear();
qso_time.clear();
} else if (!qso_time.empty()) {
string myexch = inpMyXchg_log->value();
myexch.append(" ").append(qso_time);
rec.putField(MYXCHG, myexch.c_str());
qso_time.clear();
} else {
rec.putField(MYXCHG, inpMyXchg_log->value());
}
rec.putField(CNTY, inpCNTY_log->value());
rec.putField(IOTA, inpIOTA_log->value());
rec.putField(DXCC, inpDXCC_log->value());
rec.putField(DXCC, inpQSL_VIA_log->value());
rec.putField(CONT, inpCONT_log->value());
rec.putField(CQZ, inpCQZ_log->value());
rec.putField(ITUZ, inpITUZ_log->value());
rec.putField(TX_PWR, inpTX_pwr_log->value());
qsodb.qsoNewRec (&rec);
dxcc_entity_cache_add(&rec);
submit_record(rec);
cQsoDb::reverse = false;
qsodb.SortByDate(progdefaults.sort_date_time_off);
qsodb.isdirty(0);
loadBrowser();
adifFile.writeLog (logbook_filename.c_str(), &qsodb);
}
void updateRecord() {
cQsoRec rec;
if (qsodb.nbrRecs() == 0) return;
rec.putField(CALL, inpCall_log->value());
rec.putField(NAME, inpName_log->value());
rec.putField(QSO_DATE, inpDate_log->value());
rec.putField(QSO_DATE_OFF, inpDateOff_log->value());
string tm = timestring(inpTimeOn_log->value());
rec.putField(TIME_ON, tm.c_str());
inpTimeOn_log->value(timeview(tm.c_str()));
tm = timestring(inpTimeOff_log->value());
rec.putField(TIME_OFF, tm.c_str());
inpTimeOff_log->value(timeview(tm.c_str()));
rec.putField(FREQ, inpFreq_log->value());
rec.putField(MODE, inpMode_log->value());
rec.putField(QTH, inpQth_log->value());
rec.putField(STATE, inpState_log->value());
rec.putField(VE_PROV, inpVE_Prov_log->value());
rec.putField(COUNTRY, inpCountry_log->value());
rec.putField(GRIDSQUARE, inpLoc_log->value());
rec.putField(NOTES, inpNotes_log->value());
rec.putField(QSLRDATE, inpQSLrcvddate_log->value());
rec.putField(QSLSDATE, inpQSLsentdate_log->value());
rec.putField(RST_RCVD, inpRstR_log->value ());
rec.putField(RST_SENT, inpRstS_log->value ());
rec.putField(SRX, inpSerNoIn_log->value());
rec.putField(STX, inpSerNoOut_log->value());
rec.putField(XCHG1, inpXchgIn_log->value());
rec.putField(MYXCHG, inpMyXchg_log->value());
rec.putField(CNTY, inpCNTY_log->value());
rec.putField(IOTA, inpIOTA_log->value());
rec.putField(DXCC, inpDXCC_log->value());
rec.putField(QSL_VIA, inpQSL_VIA_log->value());
rec.putField(CONT, inpCONT_log->value());
rec.putField(CQZ, inpCQZ_log->value());
rec.putField(ITUZ, inpITUZ_log->value());
rec.putField(TX_PWR, inpTX_pwr_log->value());
dxcc_entity_cache_rm(qsodb.getRec(editNbr));
qsodb.qsoUpdRec (editNbr, &rec);
dxcc_entity_cache_add(&rec);
cQsoDb::reverse = false;
qsodb.SortByDate(progdefaults.sort_date_time_off);
qsodb.isdirty(0);
restore_sort();
loadBrowser(true);
adifFile.writeLog (logbook_filename.c_str(), &qsodb);
}
void deleteRecord () {
if (qsodb.nbrRecs() == 0 || fl_choice2(_("Really delete record for \"%s\"?"),
_("Yes"), _("No"), NULL, wBrowser->valueAt(-1, 2)))
return;
dxcc_entity_cache_rm(qsodb.getRec(editNbr));
qsodb.qsoDelRec(editNbr);
cQsoDb::reverse = false;
qsodb.SortByDate(progdefaults.sort_date_time_off);
qsodb.isdirty(0);
restore_sort();
loadBrowser(true);
adifFile.writeLog (logbook_filename.c_str(), &qsodb);
}
void EditRecord( int i )
{
cQsoRec *editQSO = qsodb.getRec (i);
if( !editQSO )
return;
inpCall_log->value (editQSO->getField(CALL));
inpName_log->value (editQSO->getField(NAME));
inpDate_log->value (editQSO->getField(QSO_DATE));
inpDateOff_log->value (editQSO->getField(QSO_DATE_OFF));
inpTimeOn_log->value (timeview(editQSO->getField(TIME_ON)));
inpTimeOff_log->value (timeview(editQSO->getField(TIME_OFF)));
inpRstR_log->value (editQSO->getField(RST_RCVD));
inpRstS_log->value (editQSO->getField(RST_SENT));
inpFreq_log->value (editQSO->getField(FREQ));
inpMode_log->value (editQSO->getField(MODE));
inpState_log->value (editQSO->getField(STATE));
inpVE_Prov_log->value (editQSO->getField(VE_PROV));
inpCountry_log->value (editQSO->getField(COUNTRY));
inpQth_log->value (editQSO->getField(QTH));
inpLoc_log->value (editQSO->getField(GRIDSQUARE));
inpQSLrcvddate_log->value (editQSO->getField(QSLRDATE));
inpQSLsentdate_log->value (editQSO->getField(QSLSDATE));
inpNotes_log->value (editQSO->getField(NOTES));
inpSerNoIn_log->value(editQSO->getField(SRX));
inpSerNoOut_log->value(editQSO->getField(STX));
inpXchgIn_log->value(editQSO->getField(XCHG1));
inpMyXchg_log->value(editQSO->getField(MYXCHG));
inpCNTY_log->value(editQSO->getField(CNTY));
inpIOTA_log->value(editQSO->getField(IOTA));
inpDXCC_log->value(editQSO->getField(DXCC));
inpQSL_VIA_log->value(editQSO->getField(QSL_VIA));
inpCONT_log->value(editQSO->getField(CONT));
inpCQZ_log->value(editQSO->getField(CQZ));
inpITUZ_log->value(editQSO->getField(ITUZ));
inpTX_pwr_log->value(editQSO->getField(TX_PWR));
}
std::string sDate_on = "";
std::string sTime_on = "";
std::string sDate_off = "";
std::string sTime_off = "";
void AddRecord ()
{
inpCall_log->value(inpCall->value());
inpName_log->value (inpName->value());
if (progdefaults.force_date_time) {
inpDate_log->value(sDate_off.c_str());
inpTimeOn_log->value (timeview(sTime_off.c_str()));
} else {
inpDate_log->value(sDate_on.c_str());
inpTimeOn_log->value (timeview(sTime_on.c_str()));
}
inpDateOff_log->value(sDate_off.c_str());
inpTimeOff_log->value (timeview(sTime_off.c_str()));
inpRstR_log->value (inpRstIn->value());
inpRstS_log->value (inpRstOut->value());
{
char Mhz[30];
snprintf(Mhz, sizeof(Mhz), "%-f", atof(inpFreq->value()) / 1000.0);
inpFreq_log->value(Mhz);
}
inpMode_log->value (logmode);
inpState_log->value (inpState->value());
inpVE_Prov_log->value (inpVEprov->value());
inpCountry_log->value (inpCountry->value());
inpSerNoIn_log->value(inpSerNo->value());
inpSerNoOut_log->value(outSerNo->value());
inpXchgIn_log->value(inpXchgIn->value());
inpMyXchg_log->value(progdefaults.myXchg.c_str());
inpQth_log->value (inpQth->value());
inpLoc_log->value (inpLoc->value());
inpQSLrcvddate_log->value ("");
inpQSLsentdate_log->value ("");
inpNotes_log->value (inpNotes->value());
inpTX_pwr_log->value (progdefaults.mytxpower.c_str());
inpCNTY_log->value("");
inpIOTA_log->value("");
inpDXCC_log->value("");
inpQSL_VIA_log->value("");
inpCONT_log->value("");
inpCQZ_log->value("");
inpITUZ_log->value("");
saveRecord();
restore_sort();
loadBrowser();
logState = VIEWREC;
activateButtons();
}
void cb_browser (Fl_Widget *w, void *data )
{
Table *table = (Table *)w;
editNbr = atoi(table->valueAt(-1,6));
EditRecord (editNbr);
}
void loadBrowser(bool keep_pos)
{
cQsoRec *rec;
char sNbr[6];
int row = wBrowser->value(), pos = wBrowser->scrollPos();
if (row >= qsodb.nbrRecs()) row = qsodb.nbrRecs() - 1;
wBrowser->clear();
if (qsodb.nbrRecs() == 0)
return;
for( int i = 0; i < qsodb.nbrRecs(); i++ ) {
rec = qsodb.getRec (i);
snprintf(sNbr,sizeof(sNbr),"%d",i);
wBrowser->addRow (7,
rec->getField(progdefaults.sort_date_time_off ? QSO_DATE_OFF : QSO_DATE),
timeview4(rec->getField(progdefaults.sort_date_time_off ? TIME_OFF : TIME_ON)),
rec->getField(CALL),
rec->getField(NAME),
rec->getField(FREQ),
rec->getField(MODE),
sNbr);
}
if (keep_pos && row >= 0) {
wBrowser->value(row);
wBrowser->scrollTo(pos);
}
else {
if (cQsoDb::reverse == true)
wBrowser->FirstRow ();
else
wBrowser->LastRow ();
}
char szRecs[6];
snprintf(szRecs, sizeof(szRecs), "%5d", qsodb.nbrRecs());
txtNbrRecs_log->value(szRecs);
}
//=============================================================================
// Cabrillo reporter
//=============================================================================
const char *contests[] =
{ "AP-SPRINT",
"ARRL-10", "ARRL-160", "ARRL-DX-CW", "ARRL-DX-SSB", "ARRL-SS-CW",
"ARRL-SS-SSB", "ARRL-UHF-AUG", "ARRL-VHF-JAN", "ARRL-VHF-JUN", "ARRL-VHF-SEP",
"ARRL-RTTY",
"BARTG-RTTY", "BARTG-SPRINT",
"CQ-160-CW", "CQ-160-SSB", "CQ-WPX-CW", "CQ-WPX-RTTY", "CQ-WPX-SSB", "CQ-VHF",
"CQ-WW-CW", "CQ-WW-RTTY", "CQ-WW-SSB",
"DARC-WAEDC-CW", "DARC-WAEDC-RTTY", "DARC-WAEDC-SSB",
"FCG-FQP", "IARU-HF", "JIDX-CW", "JIDX-SSB",
"NAQP-CW", "NAQP-RTTY", "NAQP-SSB", "NA-SPRINT-CW", "NA-SPRINT-SSB", "NCCC-CQP",
"NEQP", "OCEANIA-DX-CW", "OCEANIA-DX-SSB", "RDXC", "RSGB-IOTA",
"SAC-CW", "SAC-SSB", "STEW-PERRY", "TARA-RTTY", 0 };
enum icontest {
AP_SPRINT,
ARRL_10, ARRL_160, ARRL_DX_CW, ARRL_DX_SSB, ARRL_SS_CW,
ARRL_SS_SSB, ARRL_UHF_AUG, ARRL_VHF_JAN, ARRL_VHF_JUN, ARRL_VHF_SEP,
ARRL_RTTY,
BARTG_RTTY, BARTG_SPRINT,
CQ_160_CW, CQ_160_SSB, CQ_WPX_CW, CQ_WPX_RTTY, CQ_WPX_SSB, CQ_VHF,
CQ_WW_CW, CQ_WW_RTTY, CQ_WW_SSB,
DARC_WAEDC_CW, DARC_WAEDC_RTTY, DARC_WAEDC_SSB,
FCG_FQP, IARU_HF, JIDX_CW, JIDX_SSB,
NAQP_CW, NAQP_RTTY, NAQP_SSB, NA_SPRINT_CW, NA_SPRINT_SSB, NCCC_CQP,
NEQP, OCEANIA_DX_CW, OCEANIA_DX_SSB, RDXC, RSGB_IOTA,
SAC_CW, SAC_SSB, STEW_PERRY, TARA_RTTY
};
bool bInitCombo = true;
icontest contestnbr;
void setContestType()
{
contestnbr = (icontest)cboContest->index();
btnCabCall->value(true); btnCabFreq->value(true); btnCabMode->value(true);
btnCabQSOdate->value(true); btnCabTimeOFF->value(true); btnCabRSTsent->value(true);
btnCabRSTrcvd->value(true); btnCabSerialIN->value(true);btnCabSerialOUT->value(true);
btnCabXchgIn->value(true); btnCabMyXchg->value(true);
switch (contestnbr) {
case ARRL_SS_CW :
case ARRL_SS_SSB :
btnCabRSTrcvd->value(false);
break;
case BARTG_RTTY :
case BARTG_SPRINT :
break;
case ARRL_UHF_AUG :
case ARRL_VHF_JAN :
case ARRL_VHF_JUN :
case ARRL_VHF_SEP :
case CQ_VHF :
btnCabRSTrcvd->value(false);
btnCabSerialIN->value(false);
btnCabSerialOUT->value(false);
break;
case AP_SPRINT :
case ARRL_10 :
case ARRL_160 :
case ARRL_DX_CW :
case ARRL_DX_SSB :
case CQ_160_CW :
case CQ_160_SSB :
case CQ_WPX_CW :
case CQ_WPX_RTTY :
case CQ_WPX_SSB :
case RDXC :
case OCEANIA_DX_CW :
case OCEANIA_DX_SSB :
break;
case DARC_WAEDC_CW :
case DARC_WAEDC_RTTY :
case DARC_WAEDC_SSB :
break;
case NAQP_CW :
case NAQP_RTTY :
case NAQP_SSB :
case NA_SPRINT_CW :
case NA_SPRINT_SSB :
break;
case RSGB_IOTA :
break;
default :
break;
}
}
void cb_Export_Cabrillo(Fl_Menu_* m, void* d) {
if (qsodb.nbrRecs() == 0) return;
cQsoRec *rec;
char line[80];
int indx = 0;
if (bInitCombo) {
bInitCombo = false;
while (contests[indx]) {
cboContest->add(contests[indx]);
indx++;
}
}
cboContest->index(0);
chkCabBrowser->clear();
#ifdef __APPLE__
chkCabBrowser->textfont(FL_SCREEN_BOLD);
chkCabBrowser->textsize(12);
#else
chkCabBrowser->textfont(FL_COURIER);
chkCabBrowser->textsize(12);
#endif
for( int i = 0; i < qsodb.nbrRecs(); i++ ) {
rec = qsodb.getRec (i);
memset(line, 0, sizeof(line));
snprintf(line,sizeof(line),"%8s %4s %-10s %-10s %-s",
rec->getField(QSO_DATE),
time4(rec->getField(TIME_OFF)),
rec->getField(CALL),
szfreq(rec->getField(FREQ)),
rec->getField(MODE) );
std::cout << line << "\n";
chkCabBrowser->add(line);
}
wCabrillo->show();
}
void cabrillo_append_qso (FILE *fp, cQsoRec *rec)
{
char freq[16] = "";
string rst_in, rst_out, exch_in, exch_out, date, time, mode, mycall, call, exch;
string qsoline = "QSO: ";
int ifreq = 0;
size_t len = 0;
size_t p = 0;
exch_out.clear();
exch_in.clear();
exch.clear();
if (btnCabFreq->value()) {
ifreq = (int)(1000.0 * atof(rec->getField(FREQ)));
snprintf(freq, sizeof(freq), "%7d", ifreq);
qsoline.append(freq); qsoline.append(" ");
}
if (btnCabMode->value()) {
mode = rec->getField(MODE);
if (mode.compare("USB") == 0 || mode.compare("LSB") == 0 ||
mode.compare("SSB") == 0 || mode.compare("PH") == 0 ) mode = "PH";
else if (mode.compare("FM") == 0 || mode.compare("CW") == 0 ) ;
else mode = "RY";
qsoline.append(mode); qsoline.append(" ");
}
if (btnCabQSOdate->value()) {
date = rec->getField(progdefaults.sort_date_time_off ? QSO_DATE_OFF : QSO_DATE);
date.insert(4,"-");
date.insert(7,"-");
qsoline.append(date); qsoline.append(" ");
}
if (btnCabTimeOFF->value()) {
time = rec->getField(progdefaults.sort_date_time_off ? TIME_OFF : TIME_ON);
qsoline.append(time4(time.c_str())); qsoline.append(" ");
}
mycall = progdefaults.myCall;
if (mycall.length() > 13) mycall = mycall.substr(0,13);
len = mycall.length();
if (len < 13) mycall.append(13 - len, ' ');
qsoline.append(mycall); qsoline.append(" ");
if (btnCabRSTsent->value() || contestnbr == BARTG_RTTY) {
rst_out = rec->getField(RST_SENT);
if (rst_out.length() > 3) rst_out = rst_out.substr(0, 3);
len = rst_out.length();
if (len < 3) rst_out.append(3 - len, ' ');
exch_out.append(rst_out).append(" ");
}
if (btnCabSerialOUT->value() || contestnbr == BARTG_RTTY) {
exch_out.append(rec->getField(STX)).append(" ");
}
if (btnCabMyXchg->value()) {
exch = rec->getField(MYXCHG);
if (!exch.empty())
exch_out.append(rec->getField(MYXCHG)).append(" ");
}
if (contestnbr == BARTG_RTTY) {
string toff = rec->getField(TIME_OFF);
if (toff.length() > 4) toff = toff.substr(0,4);
toff = toff.append(" ");
exch_out.append(toff);
}
if (exch_out.length() > 20) exch_out = exch_out.substr(0,20);
len = exch_out.length();
if (len < 20) exch_out.append(20 - len, ' ');
qsoline.append(exch_out);
if (btnCabCall->value()) {
call = rec->getField(CALL);
if (call.length() > 13) call = call.substr(0,13);
len = call.length();
if (len < 13) call.append(13 - len, ' ');
qsoline.append(call); qsoline.append(" ");
}
if (btnCabRSTrcvd->value()) {
rst_in = rec->getField(RST_RCVD);
if (rst_in.length() > 3) rst_in = rst_in.substr(0,3);
len = rst_in.length();
if (len < 3) rst_in.append(3 - len, ' ');
qsoline.append(rst_in); qsoline.append(" ");
}
if (btnCabSerialIN->value()) {
exch_in = exch_in.append(rec->getField(SRX));
if (exch_in.length())
exch_in += ' ';
}
if (btnCabXchgIn->value()) {
exch = rec->getField(XCHG1);
while ((p = exch.find(":")) != string::npos) exch.erase(p,1);
while ((p = exch.find(" ")) != string::npos) exch.erase(p,1);
if (exch[0] == ' ') exch.erase(0,1);
exch_in.append(exch);
}
if (exch_in.length() > 14) exch_in = exch_in.substr(0,14);
len = exch_in.length();
if (len < 14) exch_in.append(14 - len, ' ');
qsoline.append(exch_in);
fprintf (fp, "%s\n", qsoline.c_str());
return;
}
void WriteCabrillo()
{
if (chkCabBrowser->nchecked() == 0) return;
cQsoRec *rec;
string title = _("Create cabrillo report");
string filters = "TEXT\t*.txt";
#ifdef __APPLE__
filters.append("\n");
#endif
string strContest = "";
const char* p = FSEL::saveas( title.c_str(), filters.c_str(), "contest.txt");
if (!p) return;
if (!*p) return;
for (int i = 0; i < chkCabBrowser->FLTK_nitems(); i++) {
if (chkCabBrowser->checked(i + 1)) {
rec = qsodb.getRec(i);
rec->putField(EXPORT, "E");
qsodb.qsoUpdRec (i, rec);
}
}
string sp = p;
if (sp.find(".txt") == string::npos) sp.append(".txt");
FILE *cabFile = fopen (p, "w");
if (!cabFile)
return;
strContest = cboContest->value();
contestnbr = (icontest)cboContest->index();
fprintf (cabFile,
"START-OF-LOG: 3.0\n\
CREATED-BY: %s %s\n\
\n\
# The callsign used during the contest.\n\
CALLSIGN: %s\n\
\n\
# ASSISTED or NON-ASSISTED\n\
CATEGORY-ASSISTED: \n\
\n\
# Band: ALL, 160M, 80M, 40M, 20M, 15M, 10M, 6M, 2M, 222, 432, 902, 1.2G\n\
CATEGORY-BAND: \n\
\n\
# Mode: SSB, CW, RTTY, MIXED \n\
CATEGORY-MODE: \n\
\n\
# Operator: SINGLE-OP, MULTI-OP, CHECKLOG \n\
CATEGORY-OPERATOR: \n\
\n\
# Power: HIGH, LOW, QRP \n\
CATEGORY-POWER: \n\
\n\
# Station: FIXED, MOBILE, PORTABLE, ROVER, EXPEDITION, HQ, SCHOOL \n\
CATEGORY-STATION: \n\
\n\
# Time: 6-HOURS, 12-HOURS, 24-HOURS \n\
CATEGORY-TIME: \n\
\n\
# Transmitter: ONE, TWO, LIMITED, UNLIMITED, SWL \n\
CATEGORY-TRANSMITTER: \n\
\n\
# Overlay: ROOKIE, TB-WIRES, NOVICE-TECH, OVER-50 \n\
CATEGORY-OVERLAY: \n\
\n\
# Integer number\n\
CLAIMED-SCORE: \n\
\n\
# Name of the radio club with which the score should be aggregated.\n\
CLUB: \n\
\n\
# Contest: AP-SPRINT, ARRL-10, ARRL-160, ARRL-DX-CW, ARRL-DX-SSB, ARRL-SS-CW,\n\
# ARRL-SS-SSB, ARRL-UHF-AUG, ARRL-VHF-JAN, ARRL-VHF-JUN, ARRL-VHF-SEP,\n\
# ARRL-RTTY, BARTG-RTTY, CQ-160-CW, CQ-160-SSB, CQ-WPX-CW, CQ-WPX-RTTY,\n\
# CQ-WPX-SSB, CQ-VHF, CQ-WW-CW, CQ-WW-RTTY, CQ-WW-SSB, DARC-WAEDC-CW,\n\
# DARC-WAEDC-RTTY, DARC-WAEDC-SSB, FCG-FQP, IARU-HF, JIDX-CW, JIDX-SSB,\n\
# NAQP-CW, NAQP-RTTY, NAQP-SSB, NA-SPRINT-CW, NA-SPRINT-SSB, NCCC-CQP,\n\
# NEQP, OCEANIA-DX-CW, OCEANIA-DX-SSB, RDXC, RSGB-IOTA, SAC-CW, SAC-SSB,\n\
# STEW-PERRY, TARA-RTTY \n\
CONTEST: %s\n\
\n\
# Optional email address\n\
EMAIL: \n\
\n\
LOCATION: \n\
\n\
# Operator name\n\
NAME: \n\
\n\
# Maximum 4 address lines.\n\
ADDRESS: \n\
ADDRESS: \n\
ADDRESS: \n\
ADDRESS: \n\
\n\
# A space-delimited list of operator callsign(s). \n\
OPERATORS: \n\
\n\
# Offtime yyyy-mm-dd nnnn yyyy-mm-dd nnnn \n\
# OFFTIME: \n\
\n\
# Soapbox comments.\n\
SOAPBOX: \n\
SOAPBOX: \n\
SOAPBOX: \n\n",
PACKAGE_NAME, PACKAGE_VERSION,
progdefaults.myCall.c_str(),
strContest.c_str() );
qsodb.SortByDate(progdefaults.sort_date_time_off);
for (int i = 0; i < qsodb.nbrRecs(); i++) {
rec = qsodb.getRec(i);
if (rec->getField(EXPORT)[0] == 'E') {
cabrillo_append_qso(cabFile, rec);
rec->putField(EXPORT,"");
qsodb.qsoUpdRec(i, rec);
}
}
fprintf(cabFile, "END-OF-LOG:\n");
fclose (cabFile);
return;
}
#if HAVE_STD_HASH
# include <unordered_map>
typedef std::unordered_map<string, unsigned> dxcc_entity_cache_t;
#elif HAVE_STD_TR1_HASH
# include <tr1/unordered_map>
typedef tr1::unordered_map<string, unsigned> dxcc_entity_cache_t;
#else
# error "No std::hash or std::tr1::hash support"
#endif
static dxcc_entity_cache_t dxcc_entity_cache;
static bool dxcc_entity_cache_enabled = false;
#include "dxcc.h"
static void dxcc_entity_cache_clear(void)
{
if (dxcc_entity_cache_enabled)
dxcc_entity_cache.clear();
}
static void dxcc_entity_cache_add(cQsoRec* r)
{
if (!dxcc_entity_cache_enabled | !r)
return;
const dxcc* e = dxcc_lookup(r->getField(CALL));
if (e)
dxcc_entity_cache[e->country]++;
}
static void dxcc_entity_cache_add(cQsoDb& db)
{
if (!dxcc_entity_cache_enabled)
return;
int n = db.nbrRecs();
for (int i = 0; i < n; i++)
dxcc_entity_cache_add(db.getRec(i));
if (!dxcc_entity_cache.empty())
LOG_INFO("Found %" PRIuSZ " countries in %d QSO records",
dxcc_entity_cache.size(), n);
}
static void dxcc_entity_cache_rm(cQsoRec* r)
{
if (!dxcc_entity_cache_enabled || !r)
return;
const dxcc* e = dxcc_lookup(r->getField(CALL));
if (!e)
return;
dxcc_entity_cache_t::iterator i = dxcc_entity_cache.find(e->country);
if (i != dxcc_entity_cache.end()) {
if (i->second)
i->second--;
else
dxcc_entity_cache.erase(i);
}
}
void dxcc_entity_cache_enable(bool v)
{
if (dxcc_entity_cache_enabled == v)
return;
dxcc_entity_cache_clear();
if ((dxcc_entity_cache_enabled = v))
dxcc_entity_cache_add(qsodb);
}
bool qsodb_dxcc_entity_find(const char* country)
{
return dxcc_entity_cache.find(country) != dxcc_entity_cache.end();
}