1 /***************************************************************************
2                           utilities.cpp  -  description
3                              -------------------
4     begin                : jun 2015
5     copyright            : (C) 2015 by Jaime Robles
6     email                : jaime@robles.es
7  ***************************************************************************/
8 
9 /*****************************************************************************
10  * This file is part of KLog.                                                *
11  *                                                                           *
12  *    KLog is free software: you can redistribute it and/or modify           *
13  *    it under the terms of the GNU General Public License as published by   *
14  *    the Free Software Foundation, either version 3 of the License, or      *
15  *    (at your option) any later version.                                    *
16  *                                                                           *
17  *    KLog is distributed in the hope that it will be useful,                *
18  *    but WITHOUT ANY WARRANTY; without even the implied warranty of         *
19  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
20  *    GNU General Public License for more details.                           *
21  *                                                                           *
22  *    You should have received a copy of the GNU General Public License      *
23  *    along with KLog.  If not, see <https://www.gnu.org/licenses/>.         *
24  *                                                                           *
25  *****************************************************************************/
26 #include "global.h"
27 #include "utilities.h"
28 
29 bool g_callsignCheck;
Utilities()30 Utilities::Utilities()
31 {
32     //qDebug() << "Utilities::Utilities"  ;
33     init();
34 
35     //palRed.setColor(QPalette::Text, Qt::red);
36     //palBlack.setColor(QPalette::Text, Qt::black);
37     //qDebug() << "Utilities::Utilities - END"  ;
38 }
39 
~Utilities()40 Utilities::~Utilities()
41 {
42 }
43 
init()44 void Utilities::init()
45 {
46     softwareVersion = "0.0";
47     darkMode = false;
48     callValidation = true;
49 }
50 
setVersion(const QString & _v)51 void Utilities::setVersion(const QString &_v)
52 {
53        //qDebug() << "Utilities::setVersion: " << _v ;
54     softwareVersion = _v;
55 }
56 
getVersion()57 QString Utilities::getVersion()
58 {
59     return softwareVersion;
60 }
61 
getVersionDouble()62 double Utilities::getVersionDouble()
63 {
64        //qDebug() << "Utilities::getVersionDouble: " << softwareVersion ;
65     if (softwareVersion.count('.')>1)
66     {
67         QString first = softwareVersion.section('.', 0, 0);
68         int pos = softwareVersion.indexOf('.');
69 
70         QString decimals = softwareVersion.section('.', pos, -1);
71         decimals.remove('.');
72         first = first + "." + decimals;
73            //qDebug() << "Utilities::getVersionDouble - returning: "  << first ;
74         return first.toDouble();
75     }
76        //qDebug() << "Utilities::getVersionDouble: no points detected" ;
77     return softwareVersion.toDouble();
78 }
79 
getProgresStepForDialog(int totalSteps)80 int Utilities::getProgresStepForDialog(int totalSteps)
81 {
82        //qDebug() << "Utilities::getProgresStepForDialog";
83     if (totalSteps <=100)
84         return 1;
85     else if (totalSteps <=1000)
86         return 5;
87     else if (totalSteps <=4000)
88         return 10;
89     else if (totalSteps <=5000)
90         return 15;
91     else if (totalSteps <=7000)
92         return 20;
93     else if (totalSteps <=9999)
94         return 25;
95     else if (totalSteps <=20000)
96         return 100;
97     else
98         return 250;
99 }
100 
trueOrFalse(const QString & _s)101 bool Utilities::trueOrFalse(const QString &_s)
102 {// reads a String and return true if s.upper()== TRUE :-)
103          //qDebug() << "Utilities::trueOrFalse: " << _s ;
104 
105     if ( (_s.toUpper()) == "TRUE")
106     {
107         return true;
108     }
109     else
110     {
111         return false;
112     }
113     //return false;
114 }
115 
boolToCharToSQLite(const bool _b)116 QChar Utilities::boolToCharToSQLite(const bool _b)
117 {
118     if (_b)
119     {
120         return 'Y';
121     }
122     else
123     {
124         return 'N';
125     }
126 }
127 
boolToQString(const bool _b)128 QString Utilities::boolToQString(const bool _b)
129 {
130     if (_b)
131     {
132         return "True";
133     }
134     else
135     {
136         return "False";
137     }
138 }
139 
checkAndFixASCIIinADIF(const QString & _data)140 QString Utilities::checkAndFixASCIIinADIF(const QString &_data)
141 {
142     //qDebug() << "SetupDialog::checkAndFixASCIIinADIF " << _data ;
143 // This function is not really working with ASCII but with Unicode
144 //TODO: this function is also in the FileManager class. Maybe I should call that one and keep just one copy
145     ushort unicodeVal;
146     QString st = _data;
147     QString newString;
148     newString.clear();
149     for(int i=0; i < st.length(); i++)
150     {
151     // Get unicode VALUE into unicodeVal
152         unicodeVal = (st.at(i)).unicode();
153         if ((20 <= unicodeVal ) && (unicodeVal <= 126))
154         {
155             newString.append(st.at(i));
156         }
157              //qDebug() << "SetupDialog::checkAndFixunicodeinADIF: " << st.at(i) <<" = " << QString::number(unicodeVal) ;
158     }
159     // Show into another lineEdit
160     return newString;
161 }
162 
printQString(const QStringList & _qs)163 void Utilities::printQString(const QStringList &_qs)
164 {
165         //qDebug() << "Utilities::printQString: COMMENT THIS CALL BEFORE RELEASING" ;
166     if (_qs.length()<1)
167     {
168             //qDebug() << "Utilities::printQString: EMPTY QStringList received!!" ;
169         return;
170     }
171     for (int i=0; i<_qs.length()-1;i++)
172     {
173             //qDebug() << _qs.at(i) << "/" ;
174     }
175         //qDebug() << _qs.at(_qs.length()-1) ;
176 }
177 
getGlobalAgent(const QString & _klogversion)178 QString Utilities::getGlobalAgent(const QString &_klogversion)
179 {
180     return QString("KLog-%1").arg(_klogversion);
181 }
182 
getAgent(const QString & _klogversion)183 QString Utilities::getAgent(const QString &_klogversion)
184 {
185     QString version;
186     QString ops;
187     version = _klogversion;
188 
189 #if defined(Q_OS_WIN32)
190     ops = "KLog-Win32-";
191 #elif defined(Q_OS_WIN64)
192     ops = "KLog-Win64-";
193 #elif defined(Q_OS_LINUX)
194     ops = "KLog-Linux-";
195 #elif defined(Q_OS_WIN)
196     ops = "KLog-Win-"+ version;
197 #elif defined(Q_OS_MACOS)
198     ops = "KLog-macOS-";
199 #elif defined(Q_OS_OSX)
200     ops = "KLog-OSX-";
201 #elif defined(Q_OS_MAC)
202     ops = "KLog-MAC-";
203 #elif defined(Q_OS_DARWIN)
204     ops = "KLog-DARWIN-";
205 #elif defined(Q_OS_AIX)
206     ops = "KLog-aix-";
207 #elif defined(Q_OS_ANDROID)
208     ops = "KLog-android-";
209 //#elif defined(Q_OS_BSD4)
210 //    ops = "KLog-bsd4-";
211 #elif defined(Q_OS_BSDI)
212     ops = "KLog-bsdi-";
213 #elif defined(Q_OS_CYGWIN)
214     ops = "KLog-cygwin-";
215 #elif defined(Q_OS_DARWIN)
216     ops = "KLog-darwin-";
217 #elif defined(Q_OS_DGUX)
218     ops = "KLog-dgux-";
219 #elif defined(Q_OS_DYNIX)
220     ops = "KLog-dynix-";
221 #elif defined(Q_OS_FREEBSD)
222     ops = "KLog-freebsd-";
223 #elif defined(Q_OS_HPUX)
224     ops = "KLog-hpux-";
225 #elif defined(Q_OS_IOS)
226     ops = "KLog-ios-";
227 #elif defined(Q_OS_IRIX)
228     ops = "KLog-irix-";
229 #elif defined(Q_OS_LYNX)
230     ops = "KLog-lynx-";
231 #elif defined(Q_OS_NETBSD)
232     ops = "KLog-netbsd-";
233 #elif defined(Q_OS_OPENBSD)
234     ops = "KLog-openbsd-";
235 #elif defined(Q_OS_OSF)
236     ops = "KLog-osf-";
237 #elif defined(Q_OS_QNX)
238     ops = "KLog-qnx-";
239 #elif defined(Q_OS_SCO)
240     ops = "KLog-sco-";
241 #elif defined(Q_OS_SOLARIS)
242     ops = "KLog-solaris-";
243 #elif defined(Q_OS_TVOS)
244     ops = "KLog-tvos-";
245 #elif defined(Q_OS_UNIX)
246     ops = "KLog-unix-";
247 #elif defined(Q_OS_UNIXWARE)
248     ops = "KLog-unixware-";
249 #elif defined(Q_OS_WHATCHOS)
250     ops = "KLog-whatchos-";
251 #elif defined(Q_OS_WINRT)
252     ops = "KLog-winrt-";
253 #else
254     ops = "KLog-Other-";
255 #endif
256 
257     return ops+version;
258 
259     //return "KLog-Unknown-" + version;
260 }
261 
getHomeDir()262 QString Utilities::getHomeDir()
263 {
264 //TODO: To be removed when the defaultDir is saved in the config file
265 #if defined(Q_OS_WIN)
266          //qDebug() << "WINDOWS DETECTED!: "  << QDir::homePath() + "/klog" ;
267     return QDir::homePath()+"/klog";  // We create the \klog for the logs and data
268 
269 #else
270          //qDebug() << "NO WINDOWS DETECTED!"  ;
271     return QDir::homePath()+"/.klog";  // We create the ~/.klog for the logs and data
272 #endif
273 }
274 
getDefaultRST(const QString & _m)275 QString Utilities::getDefaultRST(const QString &_m)
276 {
277    //qDebug() << "Utilities::getDefaultRST: " << _m ;
278 
279    if ((_m == "SSB") || (_m== "LSB") || (_m=="USB") )
280    {
281         //qDebug() << "MainWindow::setRSTToMode: Detected SSB/LSB/USB"  ;
282        return "59";
283    }
284    else if ((_m == "CW") || (_m == "RTTY"))
285    {
286        return "599";
287    }
288    else if (_m == "PSK31")
289    {
290        return "599";
291    }
292    else if ( (_m.contains("FT", Qt::CaseInsensitive)) || (_m.contains("JT", Qt::CaseInsensitive)) || (_m.contains("QRA64", Qt::CaseInsensitive)) || (_m.contains("JS", Qt::CaseInsensitive)))
293    {
294         return "0";
295    }
296    else
297    { // By default SSB RST is configured but anything could be added
298         return "59";
299    }
300 }
301 
getDefaultLogFields()302 QStringList Utilities::getDefaultLogFields()
303 {
304     QStringList fields;
305     fields.clear();
306     fields << "qso_date" << "call" << "rst_sent" << "rst_rcvd" << "bandid" << "modeid" << "comment";
307     return fields;
308 }
309 
getKLogDefaultDatabaseFile()310 QString Utilities::getKLogDefaultDatabaseFile()
311 {
312 //TODO: To be removed when the defaultDir is saved in the config file
313     return getHomeDir() ;
314 }
315 
getKLogDBFile()316 QString Utilities::getKLogDBFile()
317 {
318         //qDebug() << "Utilities::getKLogDBFile: start " ;
319 
320     dbPath = getKLogDefaultDatabaseFile();
321     QFile file(getCfgFile());
322 
323     if (!file.open(QIODevice::ReadOnly | QIODevice::Text))  /* Flawfinder: ignore */
324     {
325         //return dbPath;
326         //return getKLogDatabaseFile(dbPath);
327     }
328     else
329     {
330         while (!file.atEnd()) {
331             QByteArray line = file.readLine();
332             processConfigLine(line);
333         }
334 
335         if (dbPath.length()<1)
336         {
337             dbPath = getKLogDefaultDatabaseFile();
338         }
339     }
340        //qDebug() << "Utilities::getKLogDBFile: path to use: " << dbPath ;
341     return dbPath + "/logbook.dat";
342 }
343 
getKLogDBBackupFile()344 QString Utilities::getKLogDBBackupFile()
345 {
346         //qDebug() << "Utilities::getKLogDBFile: start " ;
347 
348     dbPath = getKLogDefaultDatabaseFile();
349     QFile file(getCfgFile());
350 
351     if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) /* Flawfinder: ignore */
352     {
353         //return dbPath;
354         //return getKLogDatabaseFile(dbPath);
355     }
356     else
357     {
358         while (!file.atEnd()) {
359             QByteArray line = file.readLine();
360             processConfigLine(line);
361         }
362         if (dbPath.length()<1)
363         {
364             dbPath = getKLogDefaultDatabaseFile();
365         }
366     }
367        //qDebug() << "Utilities::getKLogDBFile: path to use: " << dbPath ;
368     return dbPath + "/" + QDateTime::currentDateTime().toString("yyyyMMdd-hhmmss") + "-backup-logbook.dat" ;
369 }
370 
processConfigLine(const QString & _line)371 bool Utilities::processConfigLine(const QString &_line)
372 {
373              //qDebug() << "Utilities::processConfigLine: " << _line ;
374 
375         QString line = _line.simplified();
376         //line.simplified();
377         //QString aux;
378         QStringList values = line.split("=", QT_SKIP);
379 
380         if (line.startsWith('#')){
381                  //qDebug() << "Utilities::processConfigLine: notes Line!" ;
382             return true;
383         }
384         if (!( (line.contains('=')) && (line.contains(';')))){
385                  //qDebug() << "Utilities::processConfigLine: Wrong Line!" ;
386             return false;
387         }
388         QString field = (values.at(0)).toUpper();
389         QString value = values.at(1);
390 
391         int endValue = value.indexOf(';');
392         if (endValue>-1){
393             value = value.left(value.length() - (value.length() - endValue));
394         }
395 
396         if (field == "DBPATH")
397         {
398                   //qDebug() << "Utilities::processConfigLine: dbPATH found: " << value ;
399             dbPath = value;
400         }
401         return true;
402 }
403 
404 /*
405 QString Utilities::getKLogDatabaseFile(const QString &_file)
406 {
407        //qDebug() << "Utilities::getKLogDatabaseFile:" << _file ;
408     if ( QFile::exists(_file + "/logbook.dat") )
409     {
410            //qDebug() << "Utilities::getKLogDatabaseFile:returning: " <<  _file + "/logbook.dat" ;
411         return _file + "/logbook.dat";
412     }
413          //qDebug() << "Utilities::getKLogDatabaseFile: Does not exist so default: " <<  getKLogDefaultDatabaseFile() ;
414         return getKLogDefaultDatabaseFile();
415 }
416 */
417 
getCfgFile()418 QString Utilities::getCfgFile()
419 {
420 //TODO: To be removed when the defaultDir is saved in the config file
421 #if defined(Q_OS_WIN)
422          //qDebug() << "WINDOWS DETECTED!: " << getHomeDir() + "/klogrc.cfg"  ;
423     return getHomeDir() + "/klogrc.cfg";
424 
425 #else
426          //qDebug() << "NO WINDOWS DETECTED!: " << getHomeDir() + "/klogrc.cfg"  ;
427     return getHomeDir() + "/klogrc";
428 
429 #endif
430 }
431 
getDebugLogFile()432 QString Utilities::getDebugLogFile()
433 {
434 #if defined(Q_OS_WIN)
435          //qDebug() << "WINDOWS DETECTED!: " << getHomeDir() + "/klogrc.cfg"  ;
436     return getHomeDir() + "/klogdebug.log";
437 
438 #else
439          //qDebug() << "NO WINDOWS DETECTED!: " << getHomeDir() + "/klogrc.cfg"  ;
440     return getHomeDir() + "/klogdebug.log";
441 
442 #endif
443 }
444 
getSaveSpotsLogFile()445 QString Utilities::getSaveSpotsLogFile()
446 {
447     QString filename = "/" + (QDateTime::currentDateTime()).toString("yyyyMMdd") + "-klogdxcluster.txt";
448     return getHomeDir() + filename;
449 }
450 
getBackupADIFile()451 QString Utilities::getBackupADIFile()
452 {
453    return getHomeDir() + "/" + (QDateTime::currentDateTime()).toString("yyyyMMdd-hhmm") + "-klogbackup.adi";
454 }
455 
getClubLogFile()456 QString Utilities::getClubLogFile()
457 {
458     return getHomeDir() + "/klog-clublog-upload.adi";
459 }
460 
getEQSLFile()461 QString Utilities::getEQSLFile()
462 {
463     return getHomeDir() + "/klog-eqsl-upload.adi";
464 }
465 
getLoTWAdifFile()466 QString Utilities::getLoTWAdifFile()
467 {
468     return getHomeDir() + "/klog-lotw-upload.adi";
469 }
470 
getTQSLsFileName()471 QString Utilities::getTQSLsFileName()
472 {
473       //qDebug() << "Utilities::getTQSLsFileName: "   ;
474 
475 #if defined(Q_OS_WIN)
476          //qDebug() << "WINDOWS DETECTED!: "   ;
477     return "tqsl.exe";
478 #elif   defined(Q_OS_MACOS)
479       //qDebug() << "macOS DETECTED!: "   ;
480     return "tqsl.app";
481 #else
482          //qDebug() << "NO WINDOWS/macOS DETECTED!: "   ;
483     return "tqsl";
484 #endif
485 }
486 
getTQSLsPath()487 QString Utilities::getTQSLsPath()
488 {
489       //qDebug() << "Utilities::getDefaultProgramsPath " ;
490 
491 #if defined(Q_OS_WIN64)
492          //qDebug() << "WINDOWS DETECTED!: "   ;
493     return "C:/Program Files/TrustedQSL/";
494 #elif defined(Q_OS_WIN32)
495     return "C:/Program Files (x86)/TrustedQSL/";
496 #elif defined(Q_OS_MACOS)
497       //qDebug() << "macOS DETECTED!: "   ;
498     return "/Applications/TrustedQSL/";
499 #else
500          //qDebug() << "NO WINDOWS/macOS DETECTED!: "   ;
501     return "/usr/bin/";
502 #endif
503 }
504 
getCTYFile()505 QString Utilities::getCTYFile()
506 {
507     return getHomeDir() + "/cty.csv";
508 }
509 
getNormalizedDXCCValue(const int _dxcc)510 int Utilities::getNormalizedDXCCValue(const int _dxcc)
511 {
512     if (_dxcc >1000)
513     {
514         return ((QString::number(_dxcc)).rightRef(3)).toInt();
515     }
516     else
517     {
518         return _dxcc;
519     }
520 }
521 
getDefaultDate()522 QDate Utilities::getDefaultDate()
523 {
524     //return QDate::fromString("18000101", "yyyyMMdd");
525     return QDate::currentDate();
526 }
527 
isValidDate(const QDate _d)528 bool Utilities::isValidDate(const QDate _d)
529 {
530       //qDebug() << "Utilities::isValidDate: " << _d.toString("yyyyMMdd") ;
531     if (_d.isValid())
532     {
533         if ( _d > QDate::fromString("18000101", "yyyyMMdd") )
534         {
535               //qDebug() << "Utilities::isValidDate: OK" ;
536             return true;
537         }
538     }
539       //qDebug() << "Utilities::isValidDate: Error" ;
540     return false;
541 }
542 
isValidDateTime(const QString & _d)543 bool Utilities::isValidDateTime(const QString &_d)
544 {
545        //qDebug() << "Utilities::isValidDateTime: " << _d ;
546     QDateTime _dateTime = QDateTime::fromString(_d, "yyyyMMddhhmmss");
547     if ( _dateTime.isValid()  )
548     {
549            //qDebug() << "Utilities::isValidDateTime: 1"  ;
550         return isValidDate(_dateTime.date());
551     }
552        //qDebug() << "Utilities::isValidDateTime: Error" ;
553     return false;
554 }
555 
isValidSubCall(const QString & _c)556 bool Utilities::isValidSubCall(const QString &_c)
557 {
558     //qDebug() << "Utilities::isValidSubCall: " << _c ;
559     // This functions only checks simple calls like EA4K, not composed like EA4K/F of F/EA4K/QRP
560     //Rules: http://life.itu.int/radioclub/rr/art19.pdf
561     if (_c.contains ('/'))
562     {
563         return false;
564     }
565     if (_c.length()<3)
566     {
567         //qDebug() << "Utilities::isValidSubCall: FALSE-1: " << _c ;
568         return false;
569     }
570     if (!(_c.at(_c.length ()-1).isLetter ()))
571     {
572         //qDebug() << "Utilities::isValidSubCall: FALSE-1.1: " << _c ;
573         return false;
574     }
575     for (int i = 0; i<_c.length ();i++)
576     {
577         if (!_c.at(i).isLetterOrNumber ())
578         {
579             // Non valid chars
580             return false;
581         }
582     }
583 
584     int prefixLength = isAPrefix (_c);
585     if (prefixLength<1)
586     {
587         //qDebug() << "Utilities::isValidSubCall: FALSE-1.2: " << _c ;
588         return false;
589     }
590 
591     int i = prefixLength;
592     //qDebug() << "Utilities::isValidSubCall: prefixLength" << QString::number(prefixLength) ;
593     //qDebug() << "Utilities::isValidSubCall: call" << _c ;
594     while(i<_c.length ()-1)
595     {
596         if (!((_c.at(i).isLetter()) ))
597         {
598             //qDebug() << "Utilities::isValidSubCall: FALSE-1.3: " << _c ;
599             return false;
600         }
601         i++;
602     }
603     //qDebug() << "Utilities::isValidSubCall: true" ;
604     return true;
605 }
606 
isAPrefix(const QString & _c)607 int Utilities::isAPrefix (const QString &_c)
608 {
609     // Returns -1 if it is not a prefix or valid call.
610     // Returns an int with the lenght of the prefix:
611     // The length would be including the number, if possible EA4 or;
612     // including just the country prefix: EA if the number is not included.
613 
614     //qDebug() << "Utilities::isAPrefix: " << _c ;
615     // Prefixes are at least 1 chars (like in K1K)
616     int length = _c.length ();
617 
618     if (length < 1)
619     {
620         //qDebug() << "Utilities::isAPrefix: TOO short prefix - false - END \n";
621         return -1;
622     }
623 
624     QString call = _c;
625     //qDebug() << "Utilities::isAPrefix: -10: " << call.at(0) ;
626     QChar firstChar = call.at(0);
627     QList<QChar> validFirstLettersOnly = {'B', 'F', 'G', 'I', 'K', 'M', 'N', 'R', 'W'};
628 
629     if (length == 1)
630     {
631         if (validFirstLettersOnly.contains (firstChar))
632         {
633             //qDebug() << "Utilities::isAPrefix: VALID 1 letter" ;
634             return 1;
635         }
636         else
637         {
638             //qDebug() << "Utilities::isAPrefix: NOT VALID 1 letter" ;
639             return -1;
640         }
641     }
642 
643     QChar secondChar = call.at(1);
644     //qDebug() << "Utilities::isAPrefix: SecondChar: " << secondChar ;
645     int pref = -1;
646     if (call.count(QRegularExpression("\\d")) >0) // Does it has any digit?
647     {
648         //qDebug() << "Utilities::isAPrefix: It has digits: " << call ;
649         bool done = false;
650         int i = -1;
651         while ((i < length-1) && !done)
652         {
653             //qDebug() << "Utilities::isAPrefix: in the while: " << QString::number(i) ;
654             i++;
655             if (call.at(i).isLetter ())
656             {
657                 //qDebug() << "Utilities::isAPrefix: in the while: is a Letter: " << call.at(i) ;
658                 if (pref>0)
659                 {
660                     pref = i;
661                     done = true;
662                 }
663             }
664             else
665             {
666                 //qDebug() << "Utilities::isAPrefix: in the while: is NOT a Letter: " << call.at(i) ;
667                 if (i > 0)
668                 {
669                     pref = i;
670                 }
671             }
672         } // end of while
673     }
674 
675     //qDebug() << "Utilities::isAPrefix: After the while: " << QString::number(pref) ;
676 
677     QString prefix;
678     if (pref>0)
679     {
680          //qDebug() << "Utilities::isAPrefix: pref>0 =>: " << call.left (pref) ;
681         prefix = call.left (pref);
682     }
683     else
684     {
685         prefix = call;
686         //qDebug() << "Utilities::isAPrefix: pref<=0 =>: " << call ;
687     }
688 
689     length = prefix.length();
690 
691     QChar thirdChar = QChar();
692     if (length>2)
693     {
694         thirdChar = prefix.at(2);
695     }
696 
697     //qDebug() << "Utilities::isAPrefix: -50 "  ;
698     // The first two characters shall be two letters or a letter followed
699     // by a digit or a digit followed by a letter. The first two characters or in certain cases
700     // the first character of a call sign constitute the nationality identification
701 
702     if (firstChar.isDigit() && secondChar.isDigit())
703     {
704         //qDebug() << "Utilities::isAPrefix: FALSE-6: " << prefix ;
705         return -1;
706     }
707 
708     //qDebug() << "Utilities::isAPrefix: -60 "  ;
709     if (firstChar.isLetter() && secondChar.isLetter() && thirdChar.isLetter())
710     {
711         //qDebug() << "Utilities::isAPrefix: FALSE-6: " << prefix ;
712         return -1;
713     }
714 
715     //qDebug() << "Utilities::isAPrefix: -70 "  ;
716 
717     QList<QChar> validFirstLetters = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T' ,'U', 'V', 'W', 'Z'};
718 
719     if (secondChar.isDigit ())
720     {
721         if (!validFirstLetters.contains (firstChar))
722         {
723             //qDebug() << "Utilities::isAPrefix: NOT VALID 1 letter not valid" ;
724             return -1;
725         }
726     }
727     /*
728      // The following if is to manage not format but specific IARU callsign assignments
729      // defined here: http://life.itu.int/radioclub/rr/ap42.pdf
730      // For the time being, KLog will not check that
731     if ( (firstChar.isLetter ()) && (secondChar.isDigit ()) && (validFirstLetters.contains(firstChar)))
732     {
733         //qDebug() << "Utilities::isAPrefix validFirstLetters contains the first one!" ;
734         if (firstChar == 'C')
735         {
736             if ((secondChar == '1') || (secondChar == '7'))
737             {
738                 //qDebug() << "Utilities::isAPrefix: FALSE-7.1: " << prefix ;
739                 return false;
740             }
741         }
742         if (firstChar == 'D')
743         {
744             //((secondChar == '1') || (secondChar == '8'))
745             if (false)
746             {
747                 //qDebug() << "Utilities::isAPrefix: FALSE-7.2: " << prefix ;
748                 return false;
749             }
750         }
751         if (firstChar == 'E')
752         {
753             if (!(secondChar == '2') && !(secondChar == '3') && !(secondChar == '4') && !(secondChar == '7')
754             {
755                 //qDebug() << "Utilities::isAPrefix: FALSE-7.3: " << prefix ;
756                 return false;
757             }
758         }
759         if (firstChar == 'H')
760         {
761             if ((secondChar == '1') )
762             {
763                 //qDebug() << "Utilities::isAPrefix: FALSE-7.4: " << prefix ;
764                 return false;
765             }
766         }
767         if (firstChar == 'J')
768         {
769             if ((secondChar == '1') || (secondChar == '9'))
770             {
771                 //qDebug() << "Utilities::isAPrefix: FALSE-7.5: " << prefix ;
772                 return false;
773             }
774         }
775         if (firstChar == 'P')
776         {
777             if (secondChar == '1')
778             {
779                 //qDebug() << "Utilities::isAPrefix: FALSE-7.6: " << prefix ;
780                 return false;
781             }
782         }
783         if (firstChar == 'S')
784         {
785             if ((secondChar == '1') || (secondChar == '6'))
786             {
787                 //qDebug() << "Utilities::isAPrefix: FALSE-7.7: " << prefix ;
788                 return false;
789             }
790         }
791         if (firstChar == 'T')
792         {
793             if (secondChar == '0')
794             {
795                 //qDebug() << "Utilities::isAPrefix: FALSE-7.8: " << prefix ;
796                 return false;
797             }
798         }
799         if (firstChar == 'V')
800         {
801             if ((secondChar == '1') || (secondChar == '9'))
802             {
803                 //qDebug() << "Utilities::isAPrefix: FALSE-7.9: " << prefix ;
804                 return false;
805             }
806         }
807         if (firstChar == 'Z')
808         {
809             if (!((secondChar == '2') || (secondChar == '3')))
810             {
811                 //qDebug() << "Utilities::isAPrefix: FALSE-7.10: " << prefix ;
812                 return false;
813             }
814         }
815         //qDebug() << "Utilities::isAPrefix: 1-Letter + number prefix valid: " << prefix ;
816     }
817     */
818     //qDebug() << "Utilities::isAPrefix: After the if's"  ;
819     // It seems to be a valid prefix, let's count how many chars belong to the prefix, first letter after the digit
820     // should be the suffix starting point
821 
822     //qDebug() << "Utilities::isAPrefix: Prefix length: " << QString::number(pref) << "/" << prefix ;
823     if (pref>0)
824     {
825         return pref;
826     }
827     else
828     {
829         return prefix.length ();
830     }
831 }
832 
setCallValidation(const bool _b)833 void Utilities::setCallValidation(const bool _b)
834 {
835     callValidation = _b;
836 }
837 
isValidCall(const QString & _c)838 bool Utilities::isValidCall(const QString &_c)
839 {
840      //qDebug() << "Utilities::isValidCall: " << _c ;
841     // Prefixes are at least 2 chars
842     if (!g_callsignCheck)
843     {
844          //qDebug() << "Utilities::isValidCall - 009" ;
845         return true;
846     }
847      //qDebug() << "Utilities::isValidCall - 010" ;
848     QString call = _c;
849     if (_c.length()<3)
850     {
851          //qDebug() << "Utilities::isValidCall: FALSE-1: " << _c ;
852         return false;
853     }
854      //qDebug() << "Utilities::isValidCall - 015" ;
855     call.replace('\\', '/');
856 
857     if (call.count('/')>2)
858     {
859         //qDebug() << "Utilities::isValidCall: FALSE-3: " << call;
860         return false;
861     }
862      //qDebug() << "Utilities::isValidCall - 020" ;
863     if (call.count('/') == 2)
864     { //Things like F/EA4K/P will become F/EA4K
865         //qDebug() << "Utilities::isValidCall: Two /; Ignoring the last part: " << call ;
866         QStringList parts;
867         parts.clear();
868         parts << call.split('/');
869         call = parts.at(0) + "/" + parts.at(1);
870     }
871      //qDebug() << "Utilities::isValidCall - 025" ;
872     //qDebug() << "Utilities::isValidCall: Call: " << call ;
873 
874     if (call.count('/') == 1)
875     { // Complex calls (like F/EA4K or EA4K/F OR /p OR /qrp
876       // We are just checking the call format not if it belongs to a country or whatever.
877       // It may return true for wrong calls like "ABC/EA4K"
878       // TODO: Add a check just for prefixes to fix the previous
879          //qDebug() << "Utilities::isValidCall: Call with one /: " << call ;
880         QStringList parts;
881         parts.clear();
882         parts << call.split ('/');
883 
884         //return ( ((isAPrefix (parts.at (0)))>0) || ((isAPrefix (parts.at (1)))>0) || (isValidSubCall (parts.at(0)) ) || (isValidSubCall (parts.at(1)) ));
885 
886 
887         if (parts.at(0).length ()<parts.at(1).length ())
888         {
889             return ( ((isAPrefix (parts.at (0)))>0) && (isValidSubCall (parts.at(1)) ) );
890         }
891         else
892         { //Both lenght are just the same or the second is showter, we need to check both parts and return true if one is valid
893           // It may happen that we have a EA4K/QRP or EA4K/F or EA4K/TTT
894             return isValidSubCall (parts.at(0));
895         }
896     }
897     return isValidSubCall (call);
898 }
899 
getPrefixFromCall(const QString & _c)900 QString Utilities::getPrefixFromCall(const QString &_c)
901 {
902     //qDebug() << "Utilities::getPrefixFromCall: " << _c ;
903     QString call = _c;
904     call.replace('\\', '/');
905 
906     if (call.count('/') == 2)
907     { //Things like F/EA4K/P will become F/EA4K
908         QStringList parts;
909         parts.clear();
910         parts << call.split('/');
911         call = parts.at(0) + "/" + parts.at(1);
912     }
913 
914     //QString prefix = QString();
915     int pref = -1;
916     if (call.count('/') == 1)
917     { // Complex calls (like F/EA4K or EA4K/F OR /p OR /qrp
918         QStringList parts;
919         parts.clear();
920         parts << call.split ('/');
921         if (parts.at(0).length ()<parts.at(1).length ())
922         { // First one is shorter
923             //qDebug() << "Utilities::getPrefixFromCall: First one is shorter: " ;
924             int pref = isAPrefix (parts.at(0));
925             if (pref>0)
926             {
927                 //qDebug() << "Utilities::getPrefixFromCall: R1=" << call.left (pref) ;
928                 return parts.at(0);
929             }
930             else
931             {
932                 //qDebug() << "Utilities::getPrefixFromCall: EMPTY-2"  ;
933                 return QString();
934             }
935         }
936         else if(parts.at(0).length ()>parts.at(1).length ())
937         { // Second one is shorter
938             //qDebug() << "Utilities::getPrefixFromCall: Second one is shorter: " ;
939             pref = isAPrefix (parts.at(1));
940             if (pref>0)
941             {
942                 //qDebug() << "Utilities::getPrefixFromCall: R2=" << parts.at(1) ;
943 
944                 return parts.at(1);
945             }
946             else
947             {
948                 pref = isAPrefix (parts.at(0));
949                 if (pref>0)
950                 {
951                     //qDebug() << "Utilities::getPrefixFromCall: R3=" << parts.at(0).left (pref) ;
952                     return parts.at(0).left (pref);
953                 }
954                 else
955                 {
956                     //qDebug() << "Utilities::getPrefixFromCall: EMPTY-3"  ;
957                     return QString();
958                 }
959             }
960         }
961         else
962         { //Both lenght are just the same, we need to check both parts and return true if one is valid
963             //qDebug() << "Utilities::getPrefixFromCall: Same length, we shoudl consider the first one if valid, if not the second one " ;
964         }
965     }
966 
967     pref = isAPrefix (call);
968     if (pref>0)
969     {
970         //qDebug() << "Utilities::getPrefixFromCall: R4=" << call.left (pref) ;
971         return call.left (pref);
972     }
973     //qDebug() << "Utilities::getPrefixFromCall: EMPTY-4"  ;
974     return QString();
975 }
976 
977 /*
978 QPair<QString, QString> Utilities::getCallParts(const QString &_c)
979 { // DXCC prefix, if different from original, full call
980 
981     QString call = _c;
982     QPair<QString, QString> pair;
983     pair.first = QString();
984     pair.second = QString();
985 
986     if (_c.length()<3)
987     {
988         //qDebug() << "Utilities::isValidCall: FALSE-1: " << _c ;
989         return pair;
990     }
991 
992     call.replace('\\', '/');
993 
994     if (call.count('/')>2)
995     {
996         //qDebug() << "Utilities::isValidCall: FALSE-3: " << call ;
997         return pair;
998     }
999     if (call.count('/') == 2)
1000     { //Things like F/EA4K/P will become F/EA4K
1001         QStringList parts;
1002         parts.clear();
1003         parts << call.split('/');
1004         call = parts.at(0)+parts.at(1);
1005     }
1006     QString prefix = QString();
1007 
1008     if (call.count('/') == 1)
1009     { // Complex calls (like F/EA4K or EA4K/F OR /p OR /qrp
1010         QStringList parts;
1011         parts.clear();
1012         parts << call.split('/');
1013         //qDebug() << "Utilities::isValidCall: first: " << parts.at(0) ;
1014         //qDebug() << "Utilities::isValidCall: second: " << parts.at(1) ;
1015 
1016         QStringList validSuffixes = {"P", "M", "MM", "QRP", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"};
1017         if (validSuffixes.contains (parts.at(1)))
1018         {
1019             //qDebug() << "Utilities::isValidCall: returning a result just with: " << parts.at(1) ;
1020             pair.second = parts.at(1);
1021             return pair;
1022         }
1023 
1024         if (parts.at(0).length ()<=parts.at(1).length ())
1025         {
1026             if (isAPrefix (parts.at(0))>0)
1027             //if (isAPrefix (parts.at(0)))
1028             {
1029                 //qDebug() << "Utilities::isValidCall: first is shorter " ;
1030                 pair.first = parts.at(0);
1031                 pair.second = parts.at(1);
1032             }
1033             else
1034             {
1035                 //qDebug() << "Utilities::isValidCall: first is shorter but not a prefix" ;
1036                 return pair;
1037             }
1038         }
1039         else
1040         {
1041              //qDebug() << "Utilities::isValidCall: second is shorter " ;
1042              if (isAPrefix (parts.at(1))>0)
1043              {
1044 
1045                  pair.first = parts.at(1);
1046                  pair.second = parts.at(0);
1047              }
1048              else
1049              {
1050                  //qDebug() << "Utilities::isValidCall: second is shorter but not a prefix" ;
1051                  return pair;
1052              }
1053         }
1054     }
1055     return pair;
1056 }
1057 */
1058 
isSameFreq(const double fr1,const double fr2)1059 bool Utilities::isSameFreq(const double fr1, const double fr2)
1060 {
1061     //qDebug() << Q_FUNC_INFO << ": " << QString::number(fr1) << "/" << QString::number(fr2) << " = " << QString::number(fabs(fr1 - fr2)) ;
1062 
1063     if (fabs(fr1 - fr2) < 0.001)
1064     {
1065         //qDebug() << Q_FUNC_INFO << " - true" ;
1066         return true;
1067     }
1068     else
1069     {
1070         //qDebug() << Q_FUNC_INFO << " - false" ;
1071         return false;
1072     }
1073     //return fabs(fr1 - fr2) < 0.001;
1074 }
1075 
isValidBandId(const int _b)1076 bool Utilities::isValidBandId(const int _b)
1077 {
1078     if (_b>0)
1079     {
1080         return true;
1081     }
1082     else
1083     {
1084         return false;
1085     }
1086     //return false;
1087 }
1088 
isValidModeId(const int _m)1089 bool Utilities::isValidModeId(const int _m)
1090 {
1091     if (_m>0)
1092     {
1093         return true;
1094     }
1095     else
1096     {
1097         return false;
1098     }
1099     //return false;
1100 }
1101 
isValidFreq(const QString & _b)1102 bool Utilities::isValidFreq(const QString &_b)
1103 {
1104     if (_b.toDouble()>0)
1105     {
1106         return true;
1107     }
1108     else
1109     {
1110         return false;
1111     }
1112     //return false;
1113 }
1114 
isValidGrid(const QString & _b)1115 bool Utilities::isValidGrid(const QString &_b)
1116 {
1117     Locator locator;
1118     return locator.isValidLocator(_b);
1119 }
1120 
isValidVUCCGrids(const QString & _b)1121 bool Utilities::isValidVUCCGrids(const QString &_b)
1122 {
1123     //qDebug() << Q_FUNC_INFO << ": " << _b;
1124     QStringList tmp;
1125 
1126     //QString a = _b;
1127     tmp.clear ();
1128     tmp << _b.split (',', QT_SKIP);
1129 
1130     if ((tmp.length ()!=2) && (tmp.length ()!=4))
1131     {
1132         //qDebug() << Q_FUNC_INFO << ": NON VALID LENGTH";
1133         return false;
1134     }
1135 
1136     //qDebug() << Q_FUNC_INFO << ": tmp: " << tmp;
1137     QString aux;
1138     foreach (aux, tmp) {
1139         aux = aux.trimmed ();
1140 
1141         if ((!isValidGrid (aux)) || (aux.length ()!=4))
1142         {
1143             //qDebug() << Q_FUNC_INFO << ": NON VALID";
1144             return false;
1145         }
1146         else
1147         {
1148             //qDebug() << Q_FUNC_INFO << ": VALID: " << aux;
1149         }
1150     }
1151     //qDebug() << Q_FUNC_INFO << ": VALID-END";
1152     return true;
1153 }
1154 
isValidRST(const QString & _b)1155 bool Utilities::isValidRST(const QString &_b)
1156 {
1157     if (_b.length()>0)
1158     {
1159         return true;
1160     }
1161     return false;
1162 }
1163 
isValidPower(const QString & _b)1164 bool Utilities::isValidPower(const QString &_b)
1165 {
1166     if (_b.toDouble()>0)
1167     {
1168         return true;
1169     }
1170     return false;
1171 }
1172 
isValidComment(const QString & _b)1173 bool Utilities::isValidComment(const QString &_b)
1174 {
1175     if (_b.length()>0)
1176     {
1177         return true;
1178     }
1179     return false;
1180 }
1181 
isValidName(const QString & _b)1182 bool Utilities::isValidName(const QString &_b)
1183 {
1184     if (_b.length()>0)
1185     {
1186         return true;
1187     }
1188     return false;
1189 }
1190 
isDBFileExisting()1191 bool Utilities::isDBFileExisting()
1192 {
1193     //qDebug() << "Utilities::isDBFileExisting: " << getKLogDBFile() ;
1194     if (QFile::exists(getKLogDBFile()))
1195     {
1196              //qDebug() << "Utilities::isDBFileExisting - true" ;
1197         return true;
1198     }
1199     else
1200     {
1201              //qDebug() << "Utilities::isDBFileExisting - false" ;
1202         return false;
1203     }
1204     //return false;
1205 }
1206 
isDBFileExisting(const QString & _file)1207 bool Utilities::isDBFileExisting(const QString &_file)
1208 {
1209          //qDebug() << "Utilities::isDBFileExisting2: " << _file ;
1210 
1211     if (QFile::exists(_file))
1212     {
1213              //qDebug() << "Utilities::isDBFileExisting2 - true" ;
1214         return true;
1215     }
1216     else
1217     {
1218              //qDebug() << "Utilities::isDBFileExisting2 - false" ;
1219         return false;
1220     }
1221     //return false;
1222 }
1223 
isValidADIFField(const QString & _b)1224 bool Utilities::isValidADIFField(const QString &_b)
1225 {
1226        //qDebug() << "Utilities::isValidADIFField: " << _b ;
1227     /*
1228         This functions checks if the ADIF field has the proper format.
1229         <Field:length:Data type>Data
1230     */
1231 
1232     if (!((_b.startsWith('<')) &&  (_b.count('>')) == 1 ))
1233     {
1234            //qDebug() << "Utilities::isValidADIFField: BAD FORMAT: No < or > delimiters: " << _b ;
1235         return false;
1236     }
1237     if (_b.simplified() == "<EOR>")
1238     {
1239         return true;
1240     }
1241 
1242     QStringList validDataTypes = {"B", "N", "D", "T", "S", "I", "M", "G", "E", "L"};
1243     QStringList qs;
1244     qs.clear();
1245     qs.append(_b.split('>'));
1246 
1247     if (qs.size()!= 2)
1248     {
1249            //qDebug() << "Utilities::isValidADIFField-0 (not two): " << QString::number(qs.size()) ;
1250         return false;
1251     }
1252 
1253     QString field = (qs.at(0)).right((qs.at(0)).length() - 1);
1254     QString data = (qs.at(1)).simplified();
1255     //data = data.simplified();
1256     QString dataType = QString();
1257 
1258       //qDebug() << "Utilities::isValidADIFField-Field: " << field ;
1259       //qDebug() << "Utilities::isValidADIFField_Data: " << data ;
1260 
1261     int length = data.length();
1262     int separatorPosition = 0;
1263     int i = (field).count(":"); //Check how many ":" do we have, to see if we have a data type or not
1264 
1265     if (i == 2) // We have data type
1266     { // DATE:8:D / 20141020
1267         separatorPosition = (field.section(':', 1, 1)).toInt();
1268         dataType = field.section(':', 2, 2);
1269         if (!validDataTypes.contains(dataType.toUpper()))
1270         {
1271                //qDebug() << "Utilities::isValidADIFField - FORMAT ERROR: Wrong data type: " << dataType ;
1272             return false;
1273         }
1274     }
1275     else if (i == 1)
1276     { // DATE:8 / 20141020
1277         separatorPosition = (field.section(':', 1, 1)).toInt();
1278     }
1279     else
1280     {
1281            //qDebug() << "Utilities::isValidADIFField - FORMAT ERROR, more than 2 \":\" - " << field ;
1282         return false;
1283     }
1284 
1285     if ( length != separatorPosition)
1286     {
1287            //qDebug() << "Utilities::isValidADIFField: Data Length problem: " << (field) << "/" << data << " - " << QString::number(length) << "/" << QString::number(separatorPosition) ;
1288         return false;
1289     }
1290 
1291     if (separatorPosition <= 0)
1292     {
1293         //qDebug() << "Utilities::isValidADIFField: Length problem <= 0" ;
1294         return false;
1295     }
1296 
1297        //qDebug() << "FileManager::checkADIFValidFormat: Return true" ;
1298     return true;
1299 }
1300 
isValidQSL_Rcvd(const QString & c)1301 bool Utilities::isValidQSL_Rcvd(const QString &c)
1302 {
1303     if ((c == "Y") || (c == "N") || (c == "R") || (c == "I") || (c == "V"))
1304     {
1305         return true;
1306     }
1307     else {
1308         return false;
1309     }
1310 }
1311 
isValidQSL_Sent(const QString & c)1312 bool Utilities::isValidQSL_Sent(const QString &c)
1313 {
1314     if ((c == "Y") || (c == "N") || (c == "R") || (c == "Q") || (c == "I"))
1315     {
1316         return true;
1317     }
1318     else
1319     {
1320         return false;
1321     }
1322 }
1323 
isValidUpload_Status(const QString & c)1324 bool Utilities::isValidUpload_Status(const QString &c)
1325 {
1326     if ((c == "Y") || (c == "N") || (c == "M"))
1327     {
1328         return true;
1329     }
1330     else {
1331         return false;
1332     }
1333 }
1334 
getValidADIFFieldAndData(const QString & _b)1335 QStringList Utilities::getValidADIFFieldAndData(const QString &_b)
1336 {
1337    //qDebug() << "Utilities::getValidADIFFieldAndData: " << _b ;
1338     /*
1339         This functions checks if the ADIF field has the proper format.
1340         <Field:length:Data type>Data
1341     */
1342     QStringList result;
1343     result.clear();
1344 
1345     if (!(_b.startsWith('<')))
1346     {
1347         //qDebug() << "Utilities::getValidADIFFieldAndData: BAD FORMAT: No < or > delimiters: " << _b ;
1348         return QStringList();
1349     }
1350     if (_b.simplified() == "<EOR>")
1351     {
1352         //qDebug() << "Utilities::getValidADIFFieldAndData: EOR" ;
1353         result << "EOR" << "EOR";
1354         return result;
1355     }
1356     QString aux = _b;
1357     QStringList qs;
1358     qs.clear();
1359 
1360     if ((aux.contains("APP_LOTW_")) && aux.contains("//"))
1361     { // Trying to fix a LoTW ADIF bug
1362         qs.append(aux.split("//"));
1363         aux = qs.at(0);
1364     }
1365 
1366     //qDebug() << "Utilities::getValidADIFFieldAndData: -20" ;
1367     QStringList validDataTypes = {"B", "N", "D", "T", "S", "I", "M", "G", "E", "L"};
1368 
1369     qs.clear();
1370     qs.append(aux.split('>'));
1371 
1372     if (qs.size()!= 2)
1373     {
1374         //qDebug() << "Utilities::getValidADIFFieldAndData-0 (not two): " << QString::number(qs.size()) ;
1375         return result;
1376     }
1377     //qDebug() << "Utilities::getValidADIFFieldAndData: -30" ;
1378     //QString field = (qs.at(0)).right((qs.at(0)).length() - 1);
1379     QString field = (qs.at(0)).right((qs.at(0)).length() - 1);
1380     QString data = (qs.at(1)).simplified();
1381     //data = data.simplified();
1382     QString dataType = QString();
1383 
1384     //qDebug() << "Utilities::getValidADIFFieldAndData-Field: " << field ;
1385     //qDebug() << "Utilities::getValidADIFFieldAndData_Data: " << data ;
1386 
1387     int length = data.length();
1388     int separatorPosition = 0;
1389     int i = (field).count(":"); //Check how many ":" do we have, to see if we have a data type or not
1390 
1391     if (i == 2) // We have data type
1392     { // DATE:8:D / 20141020
1393         separatorPosition = (field.section(':', 1, 1)).toInt();
1394         dataType = field.section(':', 2, 2);
1395           //qDebug() << "Utilities::getValidADIFFieldAndData - DataType: -" << dataType << "-" ;
1396         if (!validDataTypes.contains(dataType.toUpper()))
1397         {
1398               //qDebug() << "Utilities::getValidADIFFieldAndData - FORMAT ERROR: Wrong data type: " << dataType ;
1399             return result;
1400         }
1401     }
1402     else if (i == 1)
1403     { // DATE:8 / 20141020
1404         separatorPosition = (field.section(':', 1, 1)).toInt();
1405     }
1406     else
1407     {
1408         //qDebug() << "Utilities::getValidADIFFieldAndData - FORMAT ERROR, more than 2 \":\" - " << field ;
1409         return result;
1410     }
1411     //qDebug() << "Utilities::getValidADIFFieldAndData: -60" ;
1412     if ( length != separatorPosition)
1413     {
1414         //qDebug() << "Utilities::getValidADIFFieldAndData: Data Length problem: " << (field) << "/" << data << " - " << QString::number(length) << "/" << QString::number(separatorPosition) ;
1415         return result;
1416     }
1417 
1418     if (separatorPosition <= 0)
1419     {
1420         //qDebug() << "Utilities::getValidADIFFieldAndData: Length problem <= 0" ;
1421         return result;
1422     }
1423      //qDebug() << "Utilities::getValidADIFFieldAndData: -90: f: " << field ;
1424       //qDebug() << "Utilities::getValidADIFFieldAndData: -90: d: " << data<< endl;
1425     //field = field.section(':', 0, 0);
1426     result.clear();
1427     result << field.section(':', 0, 0) << data;
1428      //qDebug() << "Utilities::checkADIFValidFormat: Return true: " << result.at(0) << "/" << result.at(1) ;
1429     return result;
1430 }
1431 
getAValidCall(const QString & _wrongCall)1432 QString Utilities::getAValidCall (const QString &_wrongCall)
1433 {
1434     //qDebug() << "Utilities::getAValidCall: " << _wrongCall ;
1435     QString _confirmedCall;
1436     _confirmedCall.clear();
1437 
1438     bool ok;
1439     if (_wrongCall.length() > 0)
1440     {
1441         //qDebug() << "Utilities::getAValidCall (Don't have VALID CALL): " << _wrongCall ;
1442         _confirmedCall = QString(QObject::tr("A wrong callsign has been found: %1. Please enter a new callsign or confirm that the current one is a good callsign.")).arg(_wrongCall);
1443     }
1444     else
1445     {
1446         //qDebug() << "Utilities::getAValidCall (Don't have ANY CALL): " << _wrongCall ;
1447         _confirmedCall = QString(QObject::tr("An empty callsign has been detected. If it is possible, please enter the right call."));
1448     }
1449 
1450     QString text = QInputDialog::getText(nullptr, QObject::tr("KLog - Not valid callsign found"),
1451                                                _confirmedCall, QLineEdit::Normal, _wrongCall, &ok);
1452     if (!(ok && isValidCall(text)))
1453     {
1454         _confirmedCall = text;
1455     }
1456     else
1457     {
1458         _confirmedCall = QString();
1459     }
1460     //qDebug() << "Utilities::getAValidCall: " << _confirmedCall ;
1461     return _confirmedCall;
1462 }
1463 
getDateTimeSQLiteStringFromDateTime(const QDateTime & _d)1464 QString Utilities::getDateTimeSQLiteStringFromDateTime(const QDateTime &_d)
1465 {
1466     return QString(_d.toString("yyyy-MM-dd hh:mm:ss"));
1467 }
1468 
getDateSQLiteStringFromDate(const QDate & _d)1469 QString Utilities::getDateSQLiteStringFromDate(const QDate &_d)
1470 {
1471     return QString(_d.toString("yyyy-MM-dd"));
1472 }
1473 
isValidDateFromString(const QString & _s)1474 bool Utilities::isValidDateFromString(const QString &_s)
1475 {
1476     return getDateFromSQliteString(_s).isValid();
1477 }
1478 
isValidTimeFromString(const QString & _s)1479 bool Utilities::isValidTimeFromString(const QString &_s)
1480 {
1481     return getDateTimeFromSQLiteString(_s).time().isValid();
1482 }
1483 
isValidDateTimeFromString(const QString & _s)1484 bool Utilities::isValidDateTimeFromString(const QString &_s)
1485 {
1486     return getDateTimeFromSQLiteString(_s).isValid();
1487 }
1488 
isValidDXCC(const int _d)1489 bool Utilities::isValidDXCC(const int _d)
1490 {//TODO: Look for a better way to check, taking into account how KLog is identifiying the DXCC
1491     if (((_d > 0) && (_d < 523))  || (_d == 1206) || (_d == 1279) || (_d == 1248) || (_d == 2248) || (_d == 1259) || (_d == 1390))
1492     {
1493         return true;
1494     }
1495     else
1496     {
1497         return false;
1498     }
1499 }
1500 
getDateTimeFromSQLiteString(const QString & _s)1501 QDateTime Utilities::getDateTimeFromSQLiteString(const QString &_s)
1502 {
1503     return QDateTime::fromString(_s, "yyyy-MM-dd hh:mm:ss");
1504 }
1505 
getTimeFromSQLiteString(const QString & _s)1506 QTime Utilities::getTimeFromSQLiteString(const QString &_s)
1507 {
1508     if (_s.length()==5)
1509     {
1510         return QTime::fromString(_s, "hh:mm");
1511     }
1512     else
1513     {
1514         return QTime::fromString(_s, "hh:mm:ss");
1515     }
1516 }
1517 
getDateFromSQliteString(const QString & _s)1518 QDate Utilities::getDateFromSQliteString(const QString &_s)
1519 {
1520     //It may receive "just" a date or a "date time".
1521 
1522     if (getDateTimeFromSQLiteString(_s).isValid()) // if we have received a full date time
1523     {
1524         return (getDateTimeFromSQLiteString(_s)).date();
1525     }
1526     else // If we have received "just a date" or an error
1527     {
1528         return  QDate::fromString(_s, "yyyy-MM-dd");
1529     }
1530 }
1531 
getDateFromADIFDateString(const QString & _s)1532 QDate Utilities::getDateFromADIFDateString(const QString &_s)
1533 {// Expects an ADIF DATE format string: "YYYYMMDD"
1534    //qDebug() << "Utilities::getDateFromADIFDateString: " << _s ;
1535     return QDate::fromString(_s, "yyyyMMdd");
1536 }
1537 
getTimeFromADIFTimeString(const QString & _s)1538 QTime Utilities::getTimeFromADIFTimeString(const QString &_s)
1539 {// Expects and ADIF TIME format String "HHMMSS" or "HHMM"
1540     //qDebug() << "Utilities::getTimeFromADIFTimeString: " << _s ;
1541     if (_s.length()==4)
1542     {
1543         return QTime::fromString(_s, "hhmm");
1544     }
1545     else
1546     {
1547         return QTime::fromString(_s, "hhmmss");
1548     }
1549 }
1550 
getDateFromLoTWQSLDateString(const QString & _s)1551 QDate Utilities::getDateFromLoTWQSLDateString(const QString &_s)
1552 {
1553     //qDebug() << "Utilities::getDateFromLoTWQSLDateString: " << _s ;
1554     QStringList datet;
1555     datet.clear();
1556     if (_s.endsWith ('Z'))
1557     {
1558         datet << _s.split("T");
1559     }
1560     else
1561     {
1562         datet << _s.split(" ");
1563     }
1564     //qDebug() << "Utilities::getDateFromLoTWQSLDateString: " << datet.at(0) ;
1565     return QDate::fromString(datet.at(0), "yyyy-MM-dd");
1566 }
1567 
1568 
getADIFDateFromQDateTime(const QDateTime & _d)1569 QString Utilities::getADIFDateFromQDateTime(const QDateTime &_d)
1570 {
1571     if (!_d.isValid())
1572     {
1573         return QString();
1574     }
1575     else
1576     {
1577         return _d.date().toString("yyyyMMdd");
1578     }
1579 }
1580 
getADIFDateFromQDate(const QDate & _d)1581 QString Utilities::getADIFDateFromQDate(const QDate &_d)
1582 {
1583     if (!_d.isValid())
1584     {
1585         return QString();
1586     }
1587     else
1588     {
1589         return _d.toString("yyyyMMdd");
1590     }
1591 }
1592 
getADIFTimeFromQDateTime(const QDateTime & _d)1593 QString Utilities::getADIFTimeFromQDateTime(const QDateTime &_d)
1594 {
1595     if (!_d.isValid())
1596     {
1597         return QString();
1598     }
1599     else
1600     {
1601         return _d.time().toString("hhmmss");
1602     }
1603 }
1604 
1605 
getCabrilloDateFromQDate(const QDate & _d)1606 QString Utilities::getCabrilloDateFromQDate(const QDate &_d)
1607 {// Will produce the Cabrillo DATE format: "YYYY-MM-DD"
1608     if (!_d.isValid())
1609     {
1610         return QString("0000-00-00");
1611     }
1612     else
1613     {
1614         return _d.toString("yyyy-MM-dd");
1615     }
1616 }
1617 
getCabrilloTimeFromQDateTime(const QDateTime & _d)1618 QString Utilities::getCabrilloTimeFromQDateTime(const QDateTime &_d)
1619 {// Will produce the Cabrillo TIME format: "HHMM"
1620     if (!_d.isValid())
1621     {
1622         return QString("0000");
1623     }
1624     else
1625     {
1626         return _d.time().toString("hhmm");
1627     }
1628 }
1629 
getOnlineServiceName(OnLineProvider _service)1630 QString Utilities::getOnlineServiceName(OnLineProvider _service)
1631 {//enum OnLineProvider {ClubLog, LoTW, eQSL, QRZ}; //, HamQTH, HRDLog
1632     switch (_service)
1633     {
1634         case LoTW:
1635         {
1636             return "LoTW";
1637         }
1638     case ClubLog:
1639     {
1640         return "ClubLog";
1641     }
1642     case QRZ:
1643     {
1644         return "QRZ.com";
1645     }
1646     case eQSL:
1647     {
1648         return "eQSL.cc";
1649     }
1650     }
1651     return QString();
1652 }
1653 
getClearSQLi(QString _s)1654 QString Utilities::getClearSQLi(QString _s)
1655 {
1656     return _s.remove ('\'');
1657 }
1658 
1659 /*
1660 QPalette Utilities::getPalete(bool _ok)
1661 {
1662    //qDebug() << "Utilities::getPalete"  ;
1663     if (_ok)
1664     {
1665        //qDebug() << "Utilities::getPalete - true"  ;
1666         return palRed;
1667         //return QPalette::setColor(QPalette::Text, Qt::red);
1668     }
1669     else
1670     {
1671        //qDebug() << "Utilities::getPalete - false"  ;
1672         return palBlack;
1673     }
1674 }
1675 */
1676 
setDarkMode(const QString & _dm)1677 void Utilities::setDarkMode(const QString &_dm)
1678 {
1679     darkMode = trueOrFalse(_dm);
1680 }
1681 
isDarkMode()1682 bool Utilities::isDarkMode()
1683 {
1684     if (darkMode)
1685     {
1686         return true;
1687     }
1688     else
1689     {
1690         return false;
1691     }
1692 }
1693 
getLogColumnName(const QString & _column)1694 QString Utilities::getLogColumnName(const QString &_column)
1695 {
1696     //qDebug() << Q_FUNC_INFO << ": " << _column;
1697     if (_column == "qso_date")
1698         return QObject::tr("Date");
1699     else if (_column == "call")
1700         return QObject::tr("Call");
1701     else if (_column == "rst_sent")
1702         return QObject::tr("RSTtx");
1703     else if (_column == "rst_rcvd")
1704         return QObject::tr("RSTrx");
1705     else if (_column == "bandid")
1706         return QObject::tr("Band");
1707     else if (_column == "comment")
1708         return QObject::tr("Comment");
1709     else if (_column == "modeid")
1710         return QObject::tr("Mode");
1711     else if (_column == "cqz")
1712         return QObject::tr("CQz");
1713     else if (_column == "ituz")
1714         return QObject::tr("ITUz");
1715     else if (_column == "dxcc")
1716         return QObject::tr("DXCC");
1717     else if (_column == "address")
1718         return QObject::tr("Address");
1719     else if (_column == "age")
1720         return QObject::tr("Age");
1721     else if (_column == "cnty")
1722         return QObject::tr("County");
1723     else if (_column == "a_index")
1724         return QObject::tr("A_Index");
1725     else if (_column == "ant_az")
1726         return QObject::tr("Ant_Az");
1727     else if (_column == "ant_el")
1728         return QObject::tr("Ant_El");
1729     else if (_column == "ant_path")
1730         return QObject::tr("Ant_Path");
1731     else if (_column == "arrl_sect")
1732         return QObject::tr("ARRL_SECT");
1733     else if (_column == "award_submitted")
1734         return QObject::tr("Award_Submitted");
1735     else if (_column == "award_granted")
1736         return QObject::tr("Award_granted");
1737     else if (_column == "band_rx")
1738         return QObject::tr("Band_RX");
1739     else if (_column == "checkcontest")
1740         return QObject::tr("CheckContest");
1741     else if (_column == "class")
1742         return QObject::tr("Class");
1743     else if (_column == "clublog_qso_upload_date")
1744         return QObject::tr("ClubLog SDate");
1745     else if (_column == "clublog_qso_upload_staus")
1746         return QObject::tr("ClubLog status");
1747     else if (_column == "cont")
1748         return QObject::tr("Continent");
1749     else if (_column == "contacted_op")
1750         return QObject::tr("Contacted Op");
1751     else if (_column == "contest_id")
1752         return QObject::tr("Contest Id");
1753     else if (_column == "country")
1754         return QObject::tr("Country");
1755     else if (_column == "credit_submitted")
1756         return QObject::tr("Credit Submitted");
1757     else if (_column == "credit_granted")
1758         return QObject::tr("Credit granted");
1759     else if (_column == "dark_dok")
1760         return QObject::tr("Dark Dok", "Do not translate if unsure, common hamradio term.");
1761     else if (_column == "distance")
1762         return QObject::tr("Distance");
1763     else if (_column == "email")
1764         return QObject::tr("Email");
1765     else if (_column == "eq_call")
1766         return QObject::tr("EQ_Call");
1767     else if (_column == "eqsl_qslrdate")
1768         return QObject::tr("eQSL RDate");
1769     else if (_column == "eqsl_qslsdate")
1770         return QObject::tr("eQSL SDate");
1771     else if (_column == "eqsl_qsl_rcvd")
1772         return QObject::tr("eQSL Rcvd");
1773     else if (_column == "eqsl_qsl_sent")
1774         return QObject::tr("eQSL Sent");
1775     else if (_column == "fists")
1776         return QObject::tr("Fists", "Do not translate if unsure, common hamradio term.");
1777     else if (_column == "fists_cc")
1778         return QObject::tr("Fists CC", "Do not translate if unsure, common hamradio term.");
1779     else if (_column == "force_init")
1780         return QObject::tr("Force Init");
1781     else if (_column == "freq")
1782         return QObject::tr("Freq");
1783     else if (_column == "freq_rx")
1784         return QObject::tr("Freq RX");
1785     else if (_column == "gridsquare")
1786         return QObject::tr("Gridsquare");
1787     else if (_column == "guest_op")
1788         return QObject::tr("Guest OP");
1789     else if (_column == "hrdlog_qso_upload_date")
1790         return QObject::tr("HRDLog SDate");
1791     else if (_column == "hrdlog_qso_upload_status")
1792         return QObject::tr("HRDLog status");
1793     else if (_column == "iota")
1794         return QObject::tr("IOTA");
1795     else if (_column == "iota_island_id")
1796         return QObject::tr("IOTA Island id");
1797     else if (_column == "k_index")
1798         return QObject::tr("K Index");
1799     else if (_column == "lat")
1800         return QObject::tr("Lat");
1801     else if (_column == "lon")
1802         return QObject::tr("Lon");
1803     else if (_column == "lotw_qslrdate")
1804         return QObject::tr("LoTW RDate");
1805     else if (_column == "lotw_qslsdate")
1806         return QObject::tr("LoTW SDate");
1807     else if (_column == "lotw_qsl_rcvd")
1808         return QObject::tr("LoTW Rcvd");
1809     else if (_column == "lotw_qsl_sent")
1810         return QObject::tr("LoTW Sent");
1811     else if (_column == "max_bursts")
1812         return QObject::tr("Max Bursts");
1813     else if (_column == "multiplier")
1814         return QObject::tr("Multiplier");
1815     else if (_column == "ms_shower")
1816         return QObject::tr("MS Shower");
1817     else if (_column == "my_antenna")
1818         return QObject::tr("My Antenna");
1819     else if (_column == "my_city")
1820         return QObject::tr("My City");
1821     else if (_column == "my_cnty")
1822         return QObject::tr("My Cnty");
1823     else if (_column == "my_country")
1824         return QObject::tr("My Country");
1825     else if (_column == "my_cq_zone")
1826         return QObject::tr("My CQz");
1827     else if (_column == "my_dxcc")
1828         return QObject::tr("My DXCC");
1829     else if (_column == "my_fists")
1830         return QObject::tr("My Fists", "Do not translate if unsure, common hamradio term.");
1831     else if (_column == "my_gridsquare")
1832         return QObject::tr("My Gridsquare");
1833     else if (_column == "my_iota")
1834         return QObject::tr("My IOTA");
1835     else if (_column == "my_iota_island_id")
1836         return QObject::tr("My IOTA island id");
1837     else if (_column == "my_itu_zone")
1838         return QObject::tr("My ITUz");
1839     else if (_column == "my_lat")
1840         return QObject::tr("My Lat");
1841     else if (_column == "my_lon")
1842         return QObject::tr("My Lon");
1843     else if (_column == "my_name")
1844         return QObject::tr("My Name");
1845     else if (_column == "my_postal_code")
1846         return QObject::tr("My Postal code");
1847     else if (_column == "my_rig")
1848         return QObject::tr("My Rig");
1849     else if (_column == "my_sig")
1850         return QObject::tr("My Sig");
1851     else if (_column == "my_sig_info")
1852         return QObject::tr("My Sig Info");
1853     else if (_column == "my_sota_ref")
1854         return QObject::tr("My SOTA ref");
1855     else if (_column == "my_state")
1856         return QObject::tr("My State");
1857     else if (_column == "my_street")
1858         return QObject::tr("My Street");
1859     else if (_column == "my_usaca_counties")
1860         return QObject::tr("My USACA counties");
1861     else if (_column == "my_vucc_grids")
1862         return QObject::tr("My VUCC grids");
1863     else if (_column == "name")
1864         return QObject::tr("Name");
1865     else if (_column == "notes")
1866         return QObject::tr("Notes");
1867     else if (_column == "nr_bursts")
1868         return QObject::tr("Nr bursts", "Do not translate if unsure, common hamradio term.");
1869     else if (_column == "nr_pings")
1870         return QObject::tr("Nr pings", "Do not translate if unsure, common hamradio term.");
1871     else if (_column == "operator")
1872         return QObject::tr("Operator");
1873     else if (_column == "owner_callsign")
1874         return QObject::tr("Owner Callsign");
1875     else if (_column == "pfx")
1876         return QObject::tr("Pfx");
1877     else if (_column == "points")
1878         return QObject::tr("Points");
1879     else if (_column == "precedence")
1880         return QObject::tr("Precedence");
1881     else if (_column == "prop_mode")
1882         return QObject::tr("Prop Mode");
1883     else if (_column == "public_key")
1884         return QObject::tr("Public Key");
1885     else if (_column == "qrzcom_qso_upload_date")
1886         return QObject::tr("QRZcom SDate");
1887     else if (_column == "qrzcom_qso_upload_status")
1888         return QObject::tr("QRZcom status");
1889     else if (_column == "qslmsg")
1890         return QObject::tr("QSL msg");
1891     else if (_column == "qslrdate")
1892         return QObject::tr("QSL RDate");
1893     else if (_column == "qslsdate")
1894         return QObject::tr("QSL SDate");
1895     else if (_column == "qsl_rcvd")
1896         return QObject::tr("QSL Rcvd");
1897     else if (_column == "qsl_sent")
1898         return QObject::tr("QSL Sent");
1899     else if (_column == "qsl_rcvd_via")
1900         return QObject::tr("QSL rcvd via");
1901     else if (_column == "qsl_sent_via")
1902         return QObject::tr("QSL sent via");
1903     else if (_column == "qsl_via")
1904         return QObject::tr("QSL via");
1905     else if (_column == "qso_complete")
1906         return QObject::tr("QSO complete");
1907     else if (_column == "qso_random")
1908         return QObject::tr("QSO random");
1909     else if (_column == "qth")
1910         return QObject::tr("QTH");
1911     else if (_column == "region")
1912         return QObject::tr("Region");
1913     else if (_column == "rig")
1914         return QObject::tr("Rig");
1915     else if (_column == "rx_pwr")
1916         return QObject::tr("RX Pwr");
1917     else if (_column == "sat_mode")
1918         return QObject::tr("Sat mode");
1919     else if (_column == "sat_name")
1920         return QObject::tr("Sat name");
1921     else if (_column == "sfi")
1922         return QObject::tr("SFI");
1923     else if (_column == "sig")
1924         return QObject::tr("Sig");
1925     else if (_column == "sig_info")
1926         return QObject::tr("Sig Info");
1927     else if (_column == "silent_key")
1928         return QObject::tr("Silent key", "Do not translate if unsure, common hamradio term.");
1929     else if (_column == "skcc")
1930         return QObject::tr("SKCC");
1931     else if (_column == "sota_ref")
1932         return QObject::tr("SOTA Ref");
1933     else if (_column == "srx_string")
1934         return QObject::tr("SRX String");
1935     else if (_column == "srx")
1936         return QObject::tr("SRX");
1937     else if (_column == "stx_string")
1938         return QObject::tr("STX String");
1939     else if (_column == "state")
1940         return QObject::tr("State");
1941     else if (_column == "station_callsign")
1942         return QObject::tr("Station Callsign");
1943     else if (_column == "submode")
1944         return QObject::tr("Submode");
1945     else if (_column == "swl")
1946         return QObject::tr("SWL", "Do not translate if unsure, common hamradio term.");
1947     else if (_column == "uksmg")
1948         return QObject::tr("UKSMG");
1949     else if (_column == "usaca_counties")
1950         return QObject::tr("USACA counties");
1951     else if (_column == "ve_prov")
1952         return QObject::tr("VE prov");
1953     else if (_column == "vucc_grids")
1954         return QObject::tr("VUCC grids");
1955     else if (_column == "ten_ten")
1956         return QObject::tr("Ten-Ten", "Do not translate, it is a hamradio group name.");
1957     else if (_column == "tx_pwr")
1958         return QObject::tr("TX Pwr");
1959     else if (_column == "web")
1960         return QObject::tr("Web");
1961     else if (_column == "qso_date_off")
1962         return QObject::tr("QSO Date off");
1963     else if (_column == "transmiterid")
1964         return QObject::tr("Transmitter id");
1965     else if (_column == "lognumber")
1966         return QObject::tr("Log number");
1967     else
1968     {
1969         return _column;
1970     }
1971 }
1972