| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  | #include "adif.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <QFile>
 | 
					
						
							|  |  |  | #include <QTextStream>
 | 
					
						
							|  |  |  | #include <QDateTime>
 | 
					
						
							|  |  |  | #include <QDebug>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | <CALL:4>W1XT<BAND:3>20m<FREQ:6>14.076<GRIDSQUARE:4>DM33<MODE:4>JT65<RST_RCVD:3>-21<RST_SENT:3>-14<QSO_DATE:8>20110422<TIME_ON:6>041712<TIME_OFF:6>042435<TX_PWR:1>4<COMMENT:34>1st JT65A QSO.   Him: mag loop 20W<STATION_CALLSIGN:6>VK3ACF<MY_GRIDSQUARE:6>qf22lb<eor> | 
					
						
							|  |  |  | <CALL:6>IK1SOW<BAND:3>20m<FREQ:6>14.076<GRIDSQUARE:4>JN35<MODE:4>JT65<RST_RCVD:3>-19<RST_SENT:3>-11<QSO_DATE:8>20110422<TIME_ON:6>052501<TIME_OFF:6>053359<TX_PWR:1>3<STATION_CALLSIGN:6>VK3ACF<MY_GRIDSQUARE:6>qf22lb<eor> | 
					
						
							|  |  |  | <CALL:6:S>W4ABC> ... | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ADIF::init(QString const& filename) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _filename = filename; | 
					
						
							| 
									
										
										
										
											2018-03-05 14:49:51 -05:00
										 |  |  |     _data.clear(); | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QString ADIF::extractField(QString const& record, QString const& fieldName) const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-08-05 11:33:30 -04:00
										 |  |  |     int fieldNameIndex = record.indexOf ('<' + fieldName + ':', 0, Qt::CaseInsensitive); | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |     if (fieldNameIndex >=0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int closingBracketIndex = record.indexOf('>',fieldNameIndex); | 
					
						
							|  |  |  |         int fieldLengthIndex = record.indexOf(':',fieldNameIndex);  // find the size delimiter
 | 
					
						
							|  |  |  |         int dataTypeIndex = -1; | 
					
						
							|  |  |  |         if (fieldLengthIndex >= 0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           dataTypeIndex = record.indexOf(':',fieldLengthIndex+1);  // check for a second : indicating there is a data type
 | 
					
						
							|  |  |  |           if (dataTypeIndex > closingBracketIndex) | 
					
						
							|  |  |  |             dataTypeIndex = -1; // second : was found but it was beyond the closing >
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ((closingBracketIndex > fieldNameIndex) && (fieldLengthIndex > fieldNameIndex) && (fieldLengthIndex< closingBracketIndex)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             int fieldLengthCharCount = closingBracketIndex - fieldLengthIndex -1; | 
					
						
							|  |  |  |             if (dataTypeIndex >= 0) | 
					
						
							|  |  |  |               fieldLengthCharCount -= 2; // data type indicator is always a colon followed by a single character
 | 
					
						
							|  |  |  |             QString fieldLengthString = record.mid(fieldLengthIndex+1,fieldLengthCharCount); | 
					
						
							|  |  |  |             int fieldLength = fieldLengthString.toInt(); | 
					
						
							|  |  |  |             if (fieldLength > 0) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               QString field = record.mid(closingBracketIndex+1,fieldLength); | 
					
						
							|  |  |  |               return field; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |        } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return ""; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ADIF::load() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _data.clear(); | 
					
						
							|  |  |  |     QFile inputFile(_filename); | 
					
						
							|  |  |  |     if (inputFile.open(QIODevice::ReadOnly)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       QTextStream in(&inputFile); | 
					
						
							|  |  |  |       QString buffer; | 
					
						
							|  |  |  |       bool pre_read {false}; | 
					
						
							|  |  |  |       int end_position {-1}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // skip optional header record
 | 
					
						
							|  |  |  |       do | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           buffer += in.readLine () + '\n'; | 
					
						
							|  |  |  |           if (buffer.startsWith (QChar {'<'})) // denotes no header
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               pre_read = true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               end_position = buffer.indexOf ("<EOH>", 0, Qt::CaseInsensitive); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       while (!in.atEnd () && !pre_read && end_position < 0); | 
					
						
							|  |  |  |       if (!pre_read)            // found header
 | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           buffer.remove (0, end_position + 5); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       while (buffer.size () || !in.atEnd ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           do | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               end_position = buffer.indexOf ("<EOR>", 0, Qt::CaseInsensitive); | 
					
						
							|  |  |  |               if (!in.atEnd () && end_position < 0) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                   buffer += in.readLine () + '\n'; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           while (!in.atEnd () && end_position < 0); | 
					
						
							|  |  |  |           int record_length {end_position >= 0 ? end_position + 5 : -1}; | 
					
						
							|  |  |  |           auto record = buffer.left (record_length).trimmed (); | 
					
						
							|  |  |  |           auto next_record = buffer.indexOf (QChar {'<'}, record_length); | 
					
						
							|  |  |  |           buffer.remove (0, next_record >=0 ? next_record : buffer.size ()); | 
					
						
							|  |  |  |           record = record.mid (record.indexOf (QChar {'<'})); | 
					
						
							|  |  |  |           add (extractField (record, "CALL") | 
					
						
							|  |  |  |                , extractField (record, "BAND") | 
					
						
							|  |  |  |                , extractField (record, "MODE") | 
					
						
							| 
									
										
										
										
											2018-11-30 17:02:14 -05:00
										 |  |  |                , extractField (record, "SUBMODE") | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |                , extractField (record, "QSO_DATE")); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         inputFile.close (); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-30 17:02:14 -05:00
										 |  |  | void ADIF::add(QString const& call, QString const& band, QString const& mode, QString const& submode, QString const& date) | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     QSO q; | 
					
						
							|  |  |  |     q.call = call; | 
					
						
							|  |  |  |     q.band = band; | 
					
						
							|  |  |  |     q.mode = mode; | 
					
						
							| 
									
										
										
										
											2018-11-30 17:02:14 -05:00
										 |  |  |     q.submode = submode; | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |     q.date = date; | 
					
						
							|  |  |  |     if (q.call.size ()) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         _data.insert(q.call,q); | 
					
						
							|  |  |  |         // qDebug() << "Added as worked:" << call << band << mode << date;
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-30 17:02:14 -05:00
										 |  |  | // return true if in the log same band
 | 
					
						
							|  |  |  | bool ADIF::match(QString const& call, QString const& band) const | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     QList<QSO> qsos = _data.values(call); | 
					
						
							|  |  |  |     if (qsos.size()>0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QSO q; | 
					
						
							|  |  |  |         foreach(q,qsos) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (     (band.compare(q.band,Qt::CaseInsensitive) == 0) | 
					
						
							|  |  |  |                   || (band=="") | 
					
						
							|  |  |  |                   || (q.band=="")) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 return true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | }     | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QList<QString> ADIF::getCallList() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QList<QString> p; | 
					
						
							|  |  |  |     QMultiHash<QString,QSO>::const_iterator i = _data.constBegin(); | 
					
						
							|  |  |  |      while (i != _data.constEnd()) | 
					
						
							|  |  |  |      { | 
					
						
							|  |  |  |          p << i.key(); | 
					
						
							|  |  |  |          ++i; | 
					
						
							|  |  |  |      } | 
					
						
							|  |  |  |     return p; | 
					
						
							| 
									
										
										
										
											2018-03-05 14:49:51 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |      | 
					
						
							|  |  |  | int ADIF::getCount() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return _data.size(); | 
					
						
							|  |  |  | }    | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2018-11-30 17:02:14 -05:00
										 |  |  | QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode, QString const& submode | 
					
						
							| 
									
										
										
										
											2018-03-05 14:49:51 -05:00
										 |  |  |                            , QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn | 
					
						
							|  |  |  |                            , QDateTime const& dateTimeOff, QString const& band, QString const& comments | 
					
						
							|  |  |  |                            , QString const& name, QString const& strDialFreq, QString const& m_myCall | 
					
						
							| 
									
										
										
										
											2019-02-10 09:37:26 -05:00
										 |  |  |                            , QString const& m_myGrid, QString const& operator_call) | 
					
						
							| 
									
										
										
										
											2018-03-05 14:49:51 -05:00
										 |  |  | { | 
					
						
							|  |  |  |   QString t; | 
					
						
							|  |  |  |   t = "<call:" + QString::number(hisCall.length()) + ">" + hisCall; | 
					
						
							|  |  |  |   t += " <gridsquare:" + QString::number(hisGrid.length()) + ">" + hisGrid; | 
					
						
							|  |  |  |   t += " <mode:" + QString::number(mode.length()) + ">" + mode; | 
					
						
							| 
									
										
										
										
											2018-11-30 17:02:14 -05:00
										 |  |  |   if(!submode.isEmpty()){ | 
					
						
							|  |  |  |     t += " <submode:" + QString::number(submode.length()) + ">" + submode; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-03-05 14:49:51 -05:00
										 |  |  |   t += " <rst_sent:" + QString::number(rptSent.length()) + ">" + rptSent; | 
					
						
							|  |  |  |   t += " <rst_rcvd:" + QString::number(rptRcvd.length()) + ">" + rptRcvd; | 
					
						
							|  |  |  |   t += " <qso_date:8>" + dateTimeOn.date().toString("yyyyMMdd"); | 
					
						
							|  |  |  |   t += " <time_on:6>" + dateTimeOn.time().toString("hhmmss"); | 
					
						
							|  |  |  |   t += " <qso_date_off:8>" + dateTimeOff.date().toString("yyyyMMdd"); | 
					
						
							|  |  |  |   t += " <time_off:6>" + dateTimeOff.time().toString("hhmmss"); | 
					
						
							|  |  |  |   t += " <band:" + QString::number(band.length()) + ">" + band; | 
					
						
							|  |  |  |   t += " <freq:" + QString::number(strDialFreq.length()) + ">" + strDialFreq; | 
					
						
							|  |  |  |   t += " <station_callsign:" + QString::number(m_myCall.length()) + ">" + | 
					
						
							|  |  |  |       m_myCall; | 
					
						
							|  |  |  |   t += " <my_gridsquare:" + QString::number(m_myGrid.length()) + ">" + | 
					
						
							|  |  |  |       m_myGrid; | 
					
						
							|  |  |  |   if (comments != "") | 
					
						
							|  |  |  |     t += " <comment:" + QString::number(comments.length()) + | 
					
						
							|  |  |  |         ">" + comments; | 
					
						
							|  |  |  |   if (name != "") | 
					
						
							|  |  |  |     t += " <name:" + QString::number(name.length()) + | 
					
						
							|  |  |  |         ">" + name; | 
					
						
							|  |  |  |   if (operator_call!="") | 
					
						
							|  |  |  |       t+=" <operator:" + QString::number(operator_call.length()) + | 
					
						
							|  |  |  |               ">" + operator_call; | 
					
						
							|  |  |  |   return t.toLatin1 (); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | // open ADIF file and append the QSO details. Return true on success
 | 
					
						
							| 
									
										
										
										
											2018-03-05 14:49:51 -05:00
										 |  |  | bool ADIF::addQSOToFile(QByteArray const& ADIF_record) | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     QFile f2(_filename); | 
					
						
							|  |  |  |     if (!f2.open(QIODevice::Text | QIODevice::Append)) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QTextStream out(&f2); | 
					
						
							|  |  |  |         if (f2.size()==0) | 
					
						
							| 
									
										
										
										
											2018-12-23 08:54:31 -05:00
										 |  |  |             out << "JS8Call ADIF Export<eoh>" << endl;  // new file
 | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-05 14:49:51 -05:00
										 |  |  |         out << ADIF_record << " <eor>" << endl; | 
					
						
							| 
									
										
										
										
											2018-02-08 21:28:33 -05:00
										 |  |  |         f2.close(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } |