1 /*
2 * Tlf - contest logging program for amateur radio operators
3 * Copyright (C) 2017 Ervin Hegedus <airween@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #ifndef _XOPEN_SOURCE
21 #define _XOPEN_SOURCE
22 #endif
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <time.h>
28
29 #include "addcall.h"
30 #include "addmult.h"
31 #include "bands.h"
32 #include "cabrillo_utils.h"
33 #include "cleanup.h"
34 #include "getexchange.h"
35 #include "globalvars.h"
36 #include "makelogline.h"
37 #include "qtc_log.h"
38 #include "readcabrillo.h"
39 #include "startmsg.h"
40 #include "store_qso.h"
41 #include "tlf_curses.h"
42
43 #define MAX_CABRILLO_LEN 255
44
45 enum {
46 LOGPREF_NONE,
47 LOGPREF_QSO,
48 LOGPREF_XQSO,
49 LOGPREF_QTC
50 };
51
52 static int cablinecnt = 0;
53 char qtcsend_logfile_import[] = "IMPORT_QTC_sent.log";
54 char qtcrecv_logfile_import[] = "IMPORT_QTC_recv.log";
55 extern char qsos[MAX_QSOS][LOGLINELEN +
56 1]; // array of log lines of QSOs so far;
57 extern int qsoflags_for_qtc[MAX_QSOS]; // array of flag to log lines of QSOs
58 extern int nr_qsos;
59
60
concat_comment(char * exchstr)61 void concat_comment(char *exchstr) {
62 if (strlen(comment) > 0) {
63 strcat(comment, " ");
64 }
65 strcat(comment, exchstr);
66 }
67
qtcs_allowed(struct cabrillo_desc * cabdesc)68 int qtcs_allowed(struct cabrillo_desc *cabdesc) {
69 return ((qtcdirection > 0) && (cabdesc->qtc_item_count > 0));
70 }
71
72 /* check if line starts with 'start' */
starts_with(char * line,char * start)73 int starts_with(char *line, char *start) {
74 return (strncmp(line, start, strlen(start)) == 0);
75 }
76
77 /* write a new line to the qso log */
write_log_fm_cabr()78 void write_log_fm_cabr() {
79 qsonum = cablinecnt;
80 sprintf(qsonrstr, "%04d", cablinecnt);
81
82 if (serial_grid4_mult == 1) {
83 strcpy(section, getgrid(comment));
84 }
85
86 checkexchange(0);
87 addcall(); /* add call to dupe list */
88 makelogline(); /* format logline */
89 store_qso(logline4);
90 cleanup_qso();
91 qsoflags_for_qtc[nr_qsos - 1] = 0;
92 }
93
94 /* write a new line to the qtc log */
write_qtclog_fm_cabr(char * qtcrcall,struct read_qtc_t qtc_line)95 void write_qtclog_fm_cabr(char *qtcrcall, struct read_qtc_t qtc_line) {
96 extern char call[];
97
98 static int qtc_curr_call_nr = 0;
99 static int qtc_last_call_nr = 0;
100 static int qtc_last_qtc_serial = 0;
101 static int qtc_last_qtc_count = 0;
102 static char qtc_last_qtc_rcall[15] = "";
103
104 char thiscall[15] = "", ttime[5] = "";
105 int found_call = 0, found_empty = 0;
106
107 if (strcmp(qtcrcall, call) == 0) { // RECV
108 qtc_line.direction = RECV;
109 qtc_line.qsonr = cablinecnt;
110 make_qtc_logline(qtc_line, qtcrecv_logfile_import);
111 } else { // SENT
112
113 qtc_line.direction = SEND;
114 // search the sent callsign in list of QSO's
115
116 found_call = 0; // indicates that the callsign found
117 found_empty = 0;// indicates that there is the "hole" in the list
118 // some reason, eg. own call
119 // if new qtc block comes, go back to last empty
120 if (qtc_last_qtc_count != qtc_line.qtchead_count &&
121 qtc_last_qtc_serial != qtc_line.qtchead_serial &&
122 strcmp(qtc_last_qtc_rcall, qtcrcall) != 0) {
123 // current nr last stored nr - empty (see above) or after last
124 qtc_curr_call_nr = qtc_last_call_nr;
125 strcpy(qtc_last_qtc_rcall, qtcrcall);
126 qtc_last_qtc_serial = qtc_line.qtchead_serial;
127 qtc_last_qtc_count = qtc_line.qtchead_count;
128 }
129
130 // look until not found and we're in list
131 while (found_call == 0 && qtc_curr_call_nr < nr_qsos) {
132 strncpy(thiscall, qsos[qtc_curr_call_nr] + 29, 14);
133 g_strchomp(thiscall);
134 strncpy(ttime, qsos[qtc_curr_call_nr] + 17, 2);
135 strncpy(ttime + 2, qsos[qtc_curr_call_nr] + 20, 2);
136 ttime[4] = '\0';
137 // check the call was't sent, and call and time are equals
138 if (qsoflags_for_qtc[qtc_curr_call_nr] == 0 &&
139 (strcmp(thiscall, qtc_line.qtc_call) == 0) &&
140 (strcmp(ttime, qtc_line.qtc_time)) == 0) {
141 found_call = qtc_curr_call_nr + 1;
142 qsoflags_for_qtc[qtc_curr_call_nr] = 1;
143 } else {
144 if (found_empty == 0) {
145 found_empty = 1;
146 qtc_last_call_nr = qtc_curr_call_nr;
147 }
148 }
149
150 // increment list pos.
151 qtc_curr_call_nr++;
152
153 }
154 // end search
155 if (found_empty == 0 && found_call > 0) {
156 qtc_last_call_nr = qtc_curr_call_nr;
157 } else {
158 // TODO
159 // handling this issue
160 //if (found_call == 0) {
161 //syslog(LOG_DEBUG, "Found invalid QTC time / QTC call: '%s' '%s' - '%s' '%s' at QTC with %s [%d] (%d - %d)", qtc_line.qtc_time, qtc_line.qtc_call, ttime, thiscall, qtcrcall, qtc_curr_call_nr, found_empty, found_call);
162 //}
163 qtc_curr_call_nr = qtc_last_call_nr;
164 }
165 strcpy(qtc_line.call, qtcrcall);
166 qtc_line.callpos = found_call;
167 qtc_line.qsonr = cablinecnt;
168 make_qtc_logline(qtc_line, qtcsend_logfile_import);
169 }
170 }
171
172 /* cabrillo QSO to Tlf format
173 *
174 * walk through the lines which starts with QSO/X-QSO, and
175 * build a virtual QSO; then it calls the existing functions
176 * to add to the real log, used by the Cabrillo datas (eg. freq,
177 * date, time, band, ...) instead of the real
178 */
179
180 struct read_qtc_t qtc_line; /* make global for testability */
181
cab_qso_to_tlf(char * line,struct cabrillo_desc * cabdesc)182 void cab_qso_to_tlf(char *line, struct cabrillo_desc *cabdesc) {
183
184 extern freq_t freq;
185 extern struct tm time_ptr_cabrillo;
186 extern char call[];
187
188
189 int item_count;
190 GPtrArray *item_array;
191 struct line_item *item;
192
193 int i;
194 int pos = 0;
195 char tempstr[80], *tempstrp, timestr[3];
196 int linetype = LOGPREF_NONE;
197 char qtcrcall[15], qtcscall[15];
198
199 // [UNIVERSAL]
200 // QSO=FREQ,5;MODE,2;DATE,10;TIME,4;MYCALL,13;RST_S,3;EXC_S,6;HISCALL,13;RST_R,3;EXCH,6
201
202 // [WAEDC]
203 // QSO=FREQ,5;MODE,2;DATE,10;TIME,4;MYCALL,13;RST_S,3;EXC_S,6;HISCALL,13;RST_R,3;EXCH,6
204 // QTC=FREQ,5;MODE,2;DATE,10;TIME,4;QTCRCALL,13;QTCHEAD,10;QTCSCALL,13;QTC,23
205 // QSO: 14043 CW 2016-08-13 0022 HA2OS 599 0004 KL7SB/VY2 599 025
206 // QSO: 7002 CW 2016-08-13 0033 HA2OS 599 0008 K6ND 599 044
207 //
208 // Tlf log:
209 // 20CW 13-Aug-16 00:22 0004 KL7SB/VY2 599 599 025 KL7 1 14043.5
210 // 40CW 13-Aug-16 00:33 0008 K6ND 599 599 044 K6 1 7002.8
211
212 // QSO: 14084 RY 2016-11-12 1210 HA2OS 599 0013 K4GM 599 156
213 // QTC: 14084 RY 2016-11-12 1214 HA2OS 13/10 K4GM 0230 DL6UHD 074
214 //
215 // 20DIG 0013 12-Nov-16 12:14 K4GM 0013 0010 0230 DL6UHD 074 14084.0
216 // BANDM QSO DATE TIME CALL SERIAL/NR TIME QTCCALL QTCSER FREQ
217 //
218 // QSO: 3593 RY 2016-11-12 2020 HA2OS 599 0110 RG9A 599 959
219 // QTC: 3593 RY 2016-11-12 2021 RG9A 2/10 HA2OS 1208 2M0WEV 018
220 //
221 // 80DIG 0110 0011 12-Nov-16 20:21 RG9A 0002 0010 1208 2M0WEV 018 3593.8
222 // BANDM QSO POS DATE TIME CALL SERIAL/NR TIME QTCCALL QTCSER FREQ
223
224
225 memset(&time_ptr_cabrillo, 0, sizeof(struct tm));
226 memset(&qtc_line, 0, sizeof(struct read_qtc_t));
227
228 if (starts_with(line, "QSO")) {
229 pos = 5;
230 cablinecnt++;
231 linetype = LOGPREF_QSO;
232 item_count = cabdesc->item_count;
233 item_array = cabdesc->item_array;
234 } else if (starts_with(line, "X-QSO")) {
235 pos = 7;
236 cablinecnt++;
237 linetype = LOGPREF_XQSO;
238 item_count = cabdesc->item_count;
239 item_array = cabdesc->item_array;
240 } else if (qtcs_allowed(cabdesc) && (starts_with(line, "QTC"))) {
241 pos = 5;
242 linetype = LOGPREF_QTC;
243 item_count = cabdesc->qtc_item_count;
244 item_array = cabdesc->qtc_item_array;
245 } else {
246 return;
247 }
248
249 qtcrcall[0] = '\0';
250 qtcscall[0] = '\0';
251 for (i = 0; i < item_count; i++) {
252 item = g_ptr_array_index(item_array, i);
253 g_strlcpy(tempstr, line + pos, item->len + 1);
254 g_strchomp(tempstr);
255 pos += item->len;
256 pos++; // space between fields
257 switch (item->tag) {
258 case FREQ:
259 freq = atof(tempstr) * 1000.0;
260 bandinx = freq2band(freq);
261 strcpy(qtc_line.band, band[bandinx]);
262 qtc_line.freq = freq;
263 break;
264 case MODE:
265 if (strcmp(tempstr, "CW") == 0) {
266 trxmode = CWMODE;
267 strcpy(qtc_line.mode, "CW ");
268 } else if (strcmp(tempstr, "PH") == 0) {
269 trxmode = SSBMODE;
270 strcpy(qtc_line.mode, "PH ");
271 } else {
272 trxmode = DIGIMODE;
273 strcpy(qtc_line.mode, "DIG");
274 }
275 break;
276 case DATE:
277 strptime(tempstr, "%Y-%m-%d", &time_ptr_cabrillo);
278 strftime(qtc_line.date, 60, "%d-%b-%y", &time_ptr_cabrillo);
279 break;
280 case TIME:
281 timestr[0] = tempstr[0];
282 timestr[1] = tempstr[1];
283 timestr[2] = '\0';
284 time_ptr_cabrillo.tm_hour = atoi(timestr);
285 timestr[0] = tempstr[2];
286 timestr[1] = tempstr[3];
287 timestr[2] = '\0';
288 time_ptr_cabrillo.tm_min = atoi(timestr);
289 sprintf(qtc_line.time, "%02d:%02d", time_ptr_cabrillo.tm_hour,
290 time_ptr_cabrillo.tm_min);
291 break;
292 case MYCALL:
293 break;
294 case HISCALL:
295 strcpy(hiscall, tempstr);
296 break;
297 case RST_S:
298 strcpy(my_rst, tempstr);
299 break;
300 case RST_R:
301 strcpy(his_rst, tempstr);
302 break;
303 case EXCH:
304 strcpy(comment, tempstr);
305 break;
306 case EXC1:
307 strcpy(comment, tempstr);
308 break;
309 case EXC2:
310 concat_comment(tempstr);
311 break;
312 case EXC3:
313 concat_comment(tempstr);
314 break;
315 case EXC4:
316 concat_comment(tempstr);
317 break;
318 case EXC_S:
319 case TX:
320 case QTCRCALL:
321 strcpy(qtcrcall, tempstr);
322 strcpy(qtc_line.call, tempstr);
323 break;
324 case QTCHEAD:
325 strcpy(qtc_line.qtchead, tempstr);
326 qtc_line.qtchead_serial = 0;
327 if ((tempstrp = strtok(qtc_line.qtchead, "/")) != NULL)
328 qtc_line.qtchead_serial = atoi(tempstrp);
329
330 qtc_line.qtchead_count = 0;
331 if ((tempstrp = strtok(NULL, " ")) != NULL)
332 qtc_line.qtchead_count = atoi(tempstrp);
333
334 break;
335 case QTCSCALL:
336 strcpy(qtcscall, tempstr);
337 strcpy(qtc_line.call, tempstr);
338 break;
339 case QTC:
340 strcpy(qtc_line.qtcstr, tempstr);
341 if ((tempstrp = strtok(qtc_line.qtcstr, " ")) != NULL)
342 strcpy(qtc_line.qtc_time, tempstrp);
343
344 if ((tempstrp = strtok(NULL, " ")) != NULL) {
345 g_strchomp(tempstrp);
346 strcpy(qtc_line.qtc_call, tempstrp);
347 }
348
349 qtc_line.qtc_serial = 0;
350 if ((tempstrp = strtok(NULL, " ")) != NULL) {
351 g_strchomp(tempstrp);
352 qtc_line.qtc_serial = atoi(tempstrp);
353 }
354 case NO_ITEM:
355 default:
356 break;
357 }
358
359 }
360
361
362 if ((linetype == LOGPREF_QSO) || (linetype == LOGPREF_XQSO)) {
363 write_log_fm_cabr();
364 } else if (linetype == LOGPREF_QTC) {
365 write_qtclog_fm_cabr(qtcrcall, qtc_line);
366 }
367
368 }
369
show_readcab_msg(int mode,char * msg)370 void show_readcab_msg(int mode, char *msg) {
371
372 if (mode == READCAB_MODE_CLI) {
373 showmsg(msg);
374 refreshp();
375 }
376 }
377
378 /** readcabrillo
379 *
380 * Main routine to read the cabrillo lines, parses them, and
381 * creates a new Tlf compatible log.
382 *
383 */
384
readcabrillo(int mode)385 int readcabrillo(int mode) {
386
387 extern char *cabrillo;
388 extern char call[];
389
390 char *cab_dfltfile;
391 struct cabrillo_desc *cabdesc;
392 char input_logfile[24];
393 char output_logfile[80], temp_logfile[80];
394 char logline[MAX_CABRILLO_LEN];
395 char *tempstrp;
396
397 char t_qsonrstr[5];
398 int t_qsonum;
399 int t_bandinx;
400
401 FILE *fp1, *fp2, *fpqtc;
402
403 do_cabrillo = 1;
404
405 if (cabrillo == NULL) {
406 show_readcab_msg(mode, "Missing CABRILLO= keyword (see man page)");
407 sleep(2);
408 do_cabrillo = 0;
409 return (1);
410 }
411
412 /* Try to read cabrillo format first from local directory.
413 * Try also in default data dir if not found.
414 */
415 cabdesc = read_cabrillo_format("cabrillo.fmt", cabrillo);
416 if (!cabdesc) {
417 cab_dfltfile = g_strconcat(PACKAGE_DATA_DIR, G_DIR_SEPARATOR_S,
418 "cabrillo.fmt", NULL);
419 cabdesc = read_cabrillo_format(cab_dfltfile, cabrillo);
420 g_free(cab_dfltfile);
421 }
422
423 if (!cabdesc) {
424 show_readcab_msg(mode, "Cabrillo format specification not found!");
425 sleep(2);
426 do_cabrillo = 0;
427 return (2);
428 } else {
429 tempstrp = g_strdup_printf("CABRILLO format: %s", cabrillo);
430 show_readcab_msg(mode, tempstrp);
431 g_free (tempstrp);
432 sleep(1);
433 }
434
435 strcpy(temp_logfile, logfile);
436
437 strcpy(input_logfile, call);
438 g_strchomp(input_logfile); /* drop \n */
439 strcat(input_logfile, ".cbr");
440
441 strcpy(output_logfile, "IMPORT_");
442 strcat(output_logfile, logfile);
443 strcpy(logfile, output_logfile);
444
445 if ((fp2 = fopen(output_logfile, "w")) == NULL) {
446 tempstrp = g_strdup_printf("Can't open output logfile: %s.",
447 output_logfile);
448 show_readcab_msg(mode, tempstrp);
449 g_free (tempstrp);
450 sleep(2);
451 do_cabrillo = 0;
452 free_cabfmt(cabdesc);
453 return (1);
454 }
455 fclose(fp2);
456
457 if ((fp1 = fopen(input_logfile, "r")) == NULL) {
458 tempstrp = g_strdup_printf("Can't open input logfile: %s.",
459 input_logfile);
460 show_readcab_msg(mode, tempstrp);
461 g_free (tempstrp);
462 sleep(2);
463 do_cabrillo = 0;
464 free_cabfmt(cabdesc);
465 return (1);
466 }
467
468 if (cabdesc->qtc_item_count > 0) {
469 if (qtcdirection & SEND) {
470 fpqtc = fopen(qtcsend_logfile_import, "w");
471 if (fpqtc) fclose(fpqtc);
472 }
473
474 if (qtcdirection & RECV) {
475 fpqtc = fopen(qtcrecv_logfile_import, "w");
476 if (fpqtc) fclose(fpqtc);
477 }
478 }
479
480 strcpy(t_qsonrstr, qsonrstr);
481 t_qsonum = qsonum;
482 t_bandinx = bandinx;
483
484 while (fgets(logline, MAX_CABRILLO_LEN, fp1) != NULL) {
485 cab_qso_to_tlf(logline, cabdesc);
486 }
487
488 strcpy(qsonrstr, t_qsonrstr);
489 qsonum = t_qsonum;
490 bandinx = t_bandinx;
491
492 fclose(fp1);
493
494 free_cabfmt(cabdesc);
495
496 strcpy(logfile, temp_logfile);
497 do_cabrillo = 0;
498
499 return 0;
500 }
501