1 /*
2 * Tlf - contest logging program for amateur radio operators
3 * Copyright (C) 2013-2015 Ervin Hegedüs - HA2OS <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 * Handle QTC panel, receive and send QTC, write to log
21 *
22 *--------------------------------------------------------------*/
23
24
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include "callinput.h"
31 #include "cw_utils.h"
32 #include "genqtclist.h"
33 #include "get_time.h"
34 #include "ignore_unused.h"
35 #include "keyer.h"
36 #include "keystroke_names.h"
37 #include "lancode.h"
38 #include "nicebox.h" // Includes curses.h
39 #include "qtc_log.h"
40 #include "qtcutil.h"
41 #include "qtcvars.h" // Includes globalvars.h
42 #include "rtty.h"
43 #include "sendbuf.h"
44 #include "speedupndown.h"
45 #include "time_update.h"
46 #include "tlf_panel.h"
47 #include "ui_utils.h"
48 #include "write_keyer.h"
49 /* check direction clause macro
50 * direction should be RECV (1) or SEND (2), see tlf.h
51 */
52 #define DIRCLAUSE (direction == RECV) || (direction == SEND && (activefield == 0 || activefield == 2))
53
54
55 void init_qtc_panel();
56 void draw_qtc_panel();
57 void start_qtc_recording();
58 void stop_qtc_recording();
59 void clear_help_block();
60 void show_help_msg();
61 void showfield(int fidx);
62 void modify_field(int pressed);
63 void delete_from_field(int dir);
64 void shift_left(char *fieldval, int shift);
65 void show_status(int idx);
66 void number_fields();
67 void put_qtc();
68 void replace_spaces(char *src, char *tempc);
69 void show_sendto_lines();
70 void recalc_qtclist();
71 void show_rtty_lines();
72 void fill_qtc_times(char *time);
73
74 extern char hiscall[];
75 extern char lastcall[];
76 extern int trxmode;
77 extern int digikeyer;
78 extern int nr_qsos;
79
80 static int record_run = -1; /* was recording already started? */
81
82 t_qtclist qtclist;
83 t_qtcreclist qtcreclist;
84
85 t_qtc_ry_line qtc_ry_lines[QTC_RY_LINE_NR];
86 int qtc_ry_currline = 0;
87 int qtc_ry_capture;
88 int qtc_ry_copied;
89
90 struct t_qtc_store_obj *qtc_temp_obj; /* temp object to help to maintain
91 the QTC hash */
92
93
94 enum {
95 QTCRECVWINBG = 32,
96 QTCRECVLINE,
97 QTCRECVINVLINE,
98 QTCRECVCURRLINE,
99 QTCRECVBG,
100 };
101
102 #define LINE_INVERTED (COLOR_PAIR(QTCRECVINVLINE) | A_BOLD)
103 #define LINE_CURRINVERTED (COLOR_PAIR(QTCRECVCURRLINE) | A_BOLD)
104 #define LINE_CURRNORMAL (COLOR_PAIR(QTCRECVCURRLINE) | A_NORMAL)
105 #define LINE_NORMAL (COLOR_PAIR(QTCRECVLINE) | A_NORMAL)
106
107 WINDOW *qtcwin;
108 PANEL *qtc_panel;
109 WINDOW *ry_win;
110 PANEL *ry_panel;
111 WINDOW *ry_help_win;
112 PANEL *ry_help_panel;
113
114
115 int activefield;
116 // array values: hor position, cursor position, field len to fill with spaces
117 int pos[6][3] = {{3, 3, 15}, {3, 6, 4}, {8, 8, 2}, {3, 3, 4}, {8, 8, 14}, {24, 24, 4}};
118 int curpos = 0;
119 int curfieldlen = 0;
120 static char prevqtccall[15] = "";
121
122 char help_rec_msgs[7][26] = {
123 "Enter callsign",
124 "Enter the QTC serial",
125 "Enter the QTC number",
126 "Enter the time",
127 "Enter the CALL",
128 "Enter the SERIAL",
129 ""
130 };
131 char help_send_msgs[7][26] = {
132 "Enter callsign",
133 "",
134 "Enter the QTC number",
135 "Press ENTER to send QTC",
136 "",
137 "",
138 "Press CTRL+S to SAVE!"
139 };
140
141 char *qtccallsign;
142 int *qtccount;
143 int qtccurrdirection;
144 char qtchead[32];
145
146
147 /* Init qtc panels and windows if needed, set used colorpairs */
init_qtc_panel()148 void init_qtc_panel() {
149 static int qtcpanel_initialized = 0;
150
151 if (!qtcpanel_initialized) {
152 qtcwin = newwin(14, 75, 9, 2);
153 qtc_panel = new_panel(qtcwin);
154 hide_panel(qtc_panel);
155
156 ry_win = newwin(14, 40, 9, 37);
157 ry_panel = new_panel(ry_win);
158 hide_panel(ry_panel);
159
160 ry_help_win = newwin(5, 75, 4, 2);
161 ry_help_panel = new_panel(ry_help_win);
162 hide_panel(ry_help_panel);
163
164 qtcpanel_initialized = 1;
165 }
166
167 init_pair(QTCRECVWINBG, COLOR_BLUE, COLOR_GREEN);
168 init_pair(QTCRECVLINE, COLOR_WHITE, COLOR_BLUE);
169 init_pair(QTCRECVINVLINE, COLOR_YELLOW, COLOR_CYAN);
170 init_pair(QTCRECVCURRLINE, COLOR_YELLOW, COLOR_MAGENTA);
171 init_pair(QTCRECVBG, COLOR_BLUE, COLOR_CYAN);
172 }
173
174 /* draw the panel content */
draw_qtc_panel(int direction)175 void draw_qtc_panel(int direction) {
176 int i, j;
177
178 show_panel(qtc_panel);
179 top_panel(qtc_panel);
180
181 werase(qtcwin);
182
183 wnicebox(qtcwin, 0, 0, 12, 33, qtchead);
184
185 sprintf(qtchead, "HELP");
186 wnicebox(qtcwin, 0, 35, 12, 38, qtchead);
187
188 wbkgd(qtcwin, (chtype)(A_NORMAL | COLOR_PAIR(QTCRECVWINBG)));
189
190 wattrset(qtcwin, LINE_INVERTED);
191 mvwprintw(qtcwin, 1, 1, " ");
192 /* the first visible and used line is the qtc serial and count
193 * it differs in RECV and SEND direction, these two lines sets them
194 */
195 if (direction == RECV) {
196 mvwprintw(qtcwin, 2, 1, " / ");
197 }
198 if (direction == SEND) {
199 mvwprintw(qtcwin, 2, 1, " %d/%2d ",
200 qtclist.serial, qtclist.count);
201 }
202
203 showfield(0); // QTC CALL
204 if (direction == RECV) {
205 showfield(1); // QTC serial
206 }
207 showfield(2); // QTC nr of row
208
209 clear_help_block();
210
211 /* if the direction is RECV, set the fields on the opened QTC window */
212 if (direction == RECV) {
213 for (i = 0; i < QTC_LINES; i++) {
214 wattrset(qtcwin, LINE_INVERTED);
215 mvwprintw(qtcwin, i + 3, 1, " ");
216 for (j = 0; j < 3; j++) {
217 showfield((i * 3) + j + 3); // QTC fields...
218 }
219 }
220 number_fields();
221 }
222 /* same function, but it's a littlebit more complex, therefore that's in an external function */
223 if (direction == SEND) {
224 show_sendto_lines();
225 }
226
227 /* if the direction is RECV, and mode is DIGIMODE,
228 * show the current CAPTURE MODE
229 */
230 if (qtccurrdirection == RECV) {
231 wattrset(qtcwin, LINE_INVERTED);
232
233 if (trxmode == DIGIMODE) {
234 if (qtc_ry_capture == 0) {
235 mvwprintw(qtcwin, 2, 11, "CAPTURE OFF");
236 } else {
237 mvwprintw(qtcwin, 2, 11, "CAPTURE ON ");
238 show_rtty_lines();
239 }
240 } else {
241 if (qtcrec_record == 1) {
242 mvwprintw(qtcwin, 2, 11, "RECORD OFF ");
243 }
244 }
245 wattrset(qtcwin, LINE_NORMAL);
246 }
247
248 showfield(activefield);
249 curpos = 0;
250
251 refreshp();
252 }
253
254
255 /* start recording */
start_qtc_recording()256 void start_qtc_recording() {
257 char reccommand[100] = "";
258 char tempc[40];
259
260 if (record_run < 0 && qtcrec_record == 1
261 && strlen((char *)qtcrec_record_command) > 0) {
262 strcpy(reccommand, qtcrec_record_command[0]);
263 get_time();
264 strftime(tempc, 60, "%y%m%d%H%M%S.wav", time_ptr);
265 strcat(reccommand, tempc);
266 strcat(reccommand, qtcrec_record_command[1]);
267 record_run = system(reccommand);
268 if (record_run > -1 && qtcrec_record == 1) {
269 mvwprintw(qtcwin, 2, 11, "RECORD ON ");
270 }
271 }
272 }
273
274 /* stop recording */
stop_qtc_recording()275 void stop_qtc_recording() {
276 char reccommand[100] = "";
277
278 if (qtcrec_record == 1 && strlen((char *)qtcrec_record_command_shutdown) > 0) {
279 strcpy(reccommand, "pkill -SIGINT -n ");
280 strcat(reccommand, qtcrec_record_command_shutdown);
281 IGNORE(system(reccommand));;
282 record_run = -1;
283 if (qtcrec_record == 1) {
284 mvwprintw(qtcwin, 2, 11, "RECORD OFF ");
285 }
286 }
287 }
288
fill_qtc_callsign(int direction,char * tcall)289 void fill_qtc_callsign(int direction, char *tcall) {
290 if (direction == RECV) {
291 strcpy(qtcreclist.callsign, tcall);
292 }
293 if (direction == SEND) {
294 strcpy(qtclist.callsign, tcall);
295 }
296 }
297
fill_qtc_times(char * time)298 void fill_qtc_times(char *time) {
299 int i;
300 int len;
301 int afield;
302
303 if (trxmode != DIGIMODE && qtccurrdirection == RECV) {
304 afield = (activefield - 3) / 3;
305 if (strlen(time) >= 2) {
306 len = 2;
307 } else {
308 len = strlen(time);
309 }
310 for (i = afield + 1; i < *qtccount; i++) {
311 strncpy(qtcreclist.qtclines[i].time, time, len);
312 qtcreclist.qtclines[i].time[len] = '\0';
313 showfield(3 + (i * 3));
314 }
315 }
316 }
317
fill_lazy_line(t_qtcrecline * recline)318 void fill_lazy_line(t_qtcrecline *recline) {
319 int i;
320
321 // fill time field
322 for (i = strlen(recline->time); i < 4; i++) {
323 recline->time[i + 1] = '\0';
324 recline->time[i] = '?';
325 }
326
327 // fill callsign field
328 for (i = strlen(recline->callsign); i < 3; i++) {
329 recline->callsign[i + 1] = '\0';
330 recline->callsign[i] = '?';
331 }
332
333 // fill serial field
334 for (i = strlen(recline->serial); i < 1; i++) {
335 recline->serial[i + 1] = '\0';
336 recline->serial[i] = '?';
337 }
338
339 }
340
341 /* prepare data for RECV operation */
prepare_for_recv()342 void prepare_for_recv() {
343 int i;
344
345 /* if the callsign field is empty, or the callsign field has
346 * been changed in main window, then it needs to clean up
347 * all received QTC info
348 */
349 if (strcmp(qtcreclist.callsign, prevqtccall) != 0 ||
350 strlen(qtcreclist.callsign) == 0) {
351 qtcreclist.count = 0;
352 qtcreclist.serial = 0;
353 qtcreclist.confirmed = 0;
354 qtcreclist.sentcfmall = 0;
355 for (i = 0; i < QTC_LINES; i++) {
356 qtcreclist.qtclines[i].status = 0;
357 qtcreclist.qtclines[i].time[0] = '\0';
358 qtcreclist.qtclines[i].callsign[0] = '\0';
359 qtcreclist.qtclines[i].serial[0] = '\0';
360 qtcreclist.qtclines[i].receivedtime[0] = '\0';
361 qtcreclist.qtclines[i].confirmed = 0;
362 }
363 activefield = 0;
364 qtc_ry_copied = 0;
365 stop_qtc_recording();
366 }
367
368 if (qtcreclist.count == 0) {
369 activefield = 0;
370 }
371
372 /* save the previous qtc callsign */
373 g_strlcpy(prevqtccall, qtcreclist.callsign, sizeof(prevqtccall));
374 qtccallsign = qtcreclist.callsign;
375
376 /* save the address of the counter of receive QTC block */
377 qtccount = &qtcreclist.count;
378
379 /* set the QTC win header */
380 sprintf(qtchead, "QTC receive");
381 }
382
383
384 /* prepare data for SEND operation */
prepare_for_send()385 void prepare_for_send() {
386
387 /* if the callsign field in main window had been changed, it needs
388 * to clean up the qtc structure */
389 if (strcmp(qtclist.callsign, prevqtccall) != 0 ||
390 strlen(qtclist.callsign) == 0 || qtclist.count == 0) {
391
392 qtc_temp_obj = qtc_get(qtclist.callsign);
393 genqtclist(qtclist.callsign, (10 - (qtc_temp_obj->total)));
394
395 activefield = 0;
396 }
397
398 /* save the current callsign to previous call variable */
399 g_strlcpy(prevqtccall, qtclist.callsign, sizeof(prevqtccall));
400 qtccallsign = qtclist.callsign;
401
402 /* save the address of the counter of SEND qtc structure */
403 qtccount = &qtclist.count;
404
405 /* set the QTC win header */
406 sprintf(qtchead, "QTC send");
407 }
408
qtc_main_panel(int direction)409 void qtc_main_panel(int direction) {
410 char tempc[40];
411 int i, x;
412 int tfi, tlen = 0;
413 int currqtc = -1;
414 attr_t attributes;
415 short cpair;
416
417
418 /* fill the callsign fields of the current qtc direction structure
419 * with hiscall or the last call if hiscall is empty
420 */
421 if (strlen(hiscall) > 0) {
422 fill_qtc_callsign(direction, hiscall);
423 } else if (strlen(lastcall) > 0) {
424 fill_qtc_callsign(direction, lastcall);
425 }
426
427 /* save the value of the direction variable */
428 qtccurrdirection = direction;
429
430 /* here are the mandatory steps, if the direction is RECV */
431 if (direction == RECV) {
432 prepare_for_recv();
433 }
434
435 /* here are the mandatory steps, if the direction is SEND */
436 if (direction == SEND) {
437 prepare_for_send();
438 }
439
440 init_qtc_panel();
441 draw_qtc_panel(direction);
442
443 i = 1;
444
445 x = -1;
446 /* main loop */
447 while (x != ESCAPE) {
448
449 while (x < 1) {
450
451 usleep(5000);
452 time_update();
453 if (trxmode == DIGIMODE && digikeyer != NO_KEYER) {
454 show_rtty();
455 }
456 x = key_poll();
457
458 }
459
460 switch (x) {
461 // Ctrl-T (^T)
462 case CTRL_T:
463 if (trxmode == DIGIMODE) {
464 show_rtty_lines();
465 }
466
467 // Up Arrow
468 case KEY_UP:
469 if (direction == RECV) {
470 if (activefield > 0) { // nr of QTC record field idx
471 if (activefield == 1 || activefield == 2) {
472 activefield = 0;
473 showfield(1);
474 showfield(2);
475 } else if (activefield == 3 || activefield == 4) {
476 activefield -= 2;
477 showfield(activefield + 2);
478 } else {
479 activefield -= 3;
480 showfield(activefield + 3);
481 }
482 }
483 showfield(activefield);
484 curpos = 0;
485 }
486 if (direction == SEND && ((trxmode != DIGIMODE
487 && qtclist.totalsent < *qtccount) || (trxmode == DIGIMODE
488 && qtclist.totalsent == *qtccount))) {
489 switch (activefield) {
490 case 0:
491 activefield = 12;
492 show_help_msg(activefield);
493 showfield(0);
494 wattrset(qtcwin, LINE_CURRINVERTED);
495 mvwprintw(qtcwin, activefield, 4, "%s", qtclist.qtclines[9].qtc);
496 break;
497 case 2:
498 activefield = 0;
499 showfield(2);
500 showfield(0);
501 break;
502 case 3:
503 activefield = 2;
504 showfield(2);
505 wattrset(qtcwin, LINE_NORMAL);
506 mvwprintw(qtcwin, activefield + 1, 4, "%s", qtclist.qtclines[0].qtc);
507 break;
508 case 4 ... 12:
509 show_help_msg(activefield);
510 wattrset(qtcwin, LINE_NORMAL);
511 mvwprintw(qtcwin, activefield, 4, "%s",
512 qtclist.qtclines[(activefield - 3)].qtc);
513 activefield--;
514 wattrset(qtcwin, LINE_CURRINVERTED);
515 mvwprintw(qtcwin, activefield, 4, "%s",
516 qtclist.qtclines[(activefield - 3)].qtc);
517 break;
518 }
519 }
520 break;
521
522 // Down Arrow
523 case KEY_DOWN:
524 if (direction == RECV) {
525 if (activefield < 30) { // last line serial field idx
526 if (activefield == 0) {
527 activefield = 1;
528 showfield(0);
529 } else if (activefield == 1 || activefield == 2) {
530 activefield += 2;
531 showfield(1);
532 showfield(2);
533 } else {
534 activefield += 3;
535 showfield(activefield - 3);
536 }
537 }
538 showfield(activefield);
539 curpos = 0;
540 }
541 if (direction == SEND && ((trxmode != DIGIMODE
542 && qtclist.totalsent < *qtccount) || (trxmode == DIGIMODE
543 && qtclist.totalsent == *qtccount))) {
544 switch (activefield) {
545 case 0:
546 activefield = 2;
547 showfield(0);
548 showfield(2);
549 break;
550 case 2:
551 activefield = 3;
552 show_help_msg(activefield);
553 showfield(2);
554 wattrset(qtcwin, LINE_CURRINVERTED);
555 mvwprintw(qtcwin, activefield, 4, "%s", qtclist.qtclines[0].qtc);
556 break;
557 case 3 ... 11:
558 show_help_msg(activefield);
559 wattrset(qtcwin, LINE_NORMAL);
560 mvwprintw(qtcwin, activefield, 4, "%s",
561 qtclist.qtclines[(activefield - 3)].qtc);
562 activefield++;
563 wattrset(qtcwin, LINE_CURRINVERTED);
564 mvwprintw(qtcwin, activefield, 4, "%s",
565 qtclist.qtclines[(activefield - 3)].qtc);
566 break;
567 case 12:
568 activefield = 0;
569 wattrset(qtcwin, LINE_NORMAL);
570 mvwprintw(qtcwin, 14, 4, "%s", qtclist.qtclines[9].qtc);
571 showfield(0);
572 break;
573 }
574 }
575 break;
576
577 // Left Arrow
578 case KEY_LEFT:
579 if (DIRCLAUSE) {
580 if (curpos < curfieldlen) { // curpos is a shift, means lenght - position
581 curpos++;
582 showfield(activefield);
583 }
584 }
585 break;
586
587 // Right Arrow
588 case KEY_RIGHT:
589 if (DIRCLAUSE) {
590 if (curpos > 0) {
591 curpos--;
592 showfield(activefield);
593 }
594 }
595 break;
596
597 // <Enter>
598 case '\n':
599 case KEY_ENTER:
600 if (activefield > 2) {
601 if (direction == RECV) {
602 currqtc = ((activefield - 3) / 3);
603 if ((qtcreclist.qtclines[currqtc].status == 0 &&
604 strlen(qtcreclist.qtclines[currqtc].time) == 4 &&
605 strlen(qtcreclist.qtclines[currqtc].callsign) > 0 &&
606 strlen(qtcreclist.qtclines[currqtc].serial) > 0)
607 ||
608 qtc_recv_lazy == 1
609 ) {
610 if (qtc_recv_lazy == 1) {
611 fill_lazy_line(&qtcreclist.qtclines[currqtc]);
612 showfield(3 * (currqtc + 1));
613 showfield((3 * (currqtc + 1)) + 1);
614 showfield((3 * (currqtc + 1)) + 2);
615 }
616
617 get_time();
618 tempc[0] = '\0';
619 strftime(tempc, 40, "%d-%b-%y %H:%M", time_ptr);
620 g_strlcpy(qtcreclist.qtclines[currqtc].receivedtime, tempc, 16);
621 qtcreclist.qtclines[currqtc].status = 2;
622 show_status(currqtc);
623 if (currqtc < *qtccount) {
624 if (trxmode == DIGIMODE) {
625 qtcreclist.qtclines[currqtc].confirmed = 1; // compatibility for other modes
626 qtcreclist.confirmed++;
627 activefield += 3; // go to next line exch field
628 showfield(activefield - 3);
629 } else {
630 if (qtcreclist.qtclines[currqtc].confirmed == 0) {
631 qtcreclist.qtclines[currqtc].confirmed = 1;
632 qtcreclist.confirmed++;
633 if (trxmode == CWMODE) {
634 sendmessage(qtc_recv_msgs[2]);
635 }
636 if (trxmode == SSBMODE) {
637 play_file(qtc_phrecv_message[2]);
638 }
639 }
640 tfi = (activefield - 3) % 3;
641 //activefield++; // go to next line time field
642 activefield += (3 - tfi);
643 showfield(activefield - (3 - tfi));
644 }
645 showfield(activefield);
646 }
647 } else if (qtcreclist.qtclines[currqtc].status == 1 &&
648 qtcreclist.qtclines[currqtc].confirmed != 1) {
649 if (trxmode == CWMODE) {
650 sendmessage(qtc_recv_msgs[7]);
651 }
652 if (trxmode == SSBMODE) {
653 play_file(qtc_phrecv_message[7]);
654 }
655 if (trxmode == DIGIMODE) {
656 char *str = g_strdup_printf("%s %02d %02d\n",
657 g_strchomp(qtc_recv_msgs[7]),
658 currqtc + 1, currqtc + 1);
659 sendmessage(str);
660 g_free(str);
661 }
662 }
663
664 if (*qtccount > 0 && qtcreclist.confirmed == *qtccount) {
665 if (qtcreclist.sentcfmall == 0) {
666 qtcreclist.sentcfmall = 1;
667 log_recv_qtc_to_disk(nr_qsos);
668 if (record_run > -1) {
669 stop_qtc_recording();
670 }
671 if (trxmode == DIGIMODE || trxmode == CWMODE) {
672 sendmessage(qtc_recv_msgs[9]);
673 }
674 if (trxmode == SSBMODE) {
675 play_file(qtc_phrecv_message[9]);
676 }
677 }
678 x = ESCAPE; // <Escape> close the window
679 }
680 }
681 if (direction == SEND && trxmode != DIGIMODE) {
682 if (qtclist.qtclines[activefield - 3].sent == 0) {
683 qtclist.qtclines[activefield - 3].sent = 1;
684 get_time();
685 tempc[0] = '\0';
686 strftime(tempc, 40, "%d-%b-%y %H:%M", time_ptr);
687 g_strlcpy(qtclist.qtclines[activefield - 3].senttime, tempc, 16);
688 qtclist.qtclines[activefield - 3].senttime[15] = '\0';
689 qtclist.totalsent++;
690 }
691 tempc[0] = '\0';
692 replace_spaces(qtclist.qtclines[activefield - 3].qtc, tempc);
693 if (trxmode == CWMODE) {
694 sendmessage(tempc);
695 }
696
697 mvwprintw(qtcwin, activefield, 30, "*");
698 qtclist.qtclines[activefield - 3].flag = 1;
699 // scroll down if not at end of qtclist:
700 if (activefield - 3 < *qtccount - 1) {
701 wattrset(qtcwin, LINE_NORMAL);
702 mvwprintw(qtcwin, activefield, 4, "%s",
703 qtclist.qtclines[(activefield - 3)].qtc);
704 activefield++;
705 wattrset(qtcwin, LINE_CURRINVERTED);
706 mvwprintw(qtcwin, activefield, 4, "%s",
707 qtclist.qtclines[(activefield - 3)].qtc);
708 }
709 if (*qtccount > 0 && qtclist.totalsent == *qtccount) {
710 wattrset(qtcwin, LINE_INVERTED);
711 mvwprintw(qtcwin, 2, 11, "CTRL+S to SAVE!");
712 refreshp();
713 show_help_msg(6);
714 }
715 }
716 }
717 if (activefield == 2) {
718 if (direction == RECV &&
719 strlen(qtcreclist.callsign) > 0 &&
720 qtcreclist.serial > 0 &&
721 qtcreclist.count > 0 &&
722 qtcreclist.confirmed == 0
723 ) {
724 if (trxmode == CWMODE) {
725 sendmessage(qtc_recv_msgs[1]);
726 }
727 if (trxmode == SSBMODE) {
728 play_file(qtc_phrecv_message[1]);
729 }
730 start_qtc_recording();
731 activefield++;
732 showfield(activefield);
733 }
734 }
735 if (trxmode == DIGIMODE) {
736 if (direction == SEND && (activefield == 0 || activefield == 2)
737 && qtclist.totalsent == 0) {
738 if (qtc_send_msgs[1][strlen(qtc_send_msgs[1]) - 1] == 10) {
739 qtc_send_msgs[1][strlen(qtc_send_msgs[1]) - 1] = '\0';
740 }
741 tlen = strlen(qtc_send_msgs[1]) - 5; // len("sr/nr") = 5
742 char tmess[300], timec[40];
743 int ql;
744 tmess[0] = '\0';
745 if (tlen > 0 && strncmp(qtc_send_msgs[1] + tlen, "sr/nr", 5) == 0) {
746 g_strlcpy(tempc, qtc_send_msgs[1], tlen);
747 sprintf(tmess, "%s %d/%d %s %d/%d\n",
748 tempc, qtclist.serial, *qtccount, tempc,
749 qtclist.serial, *qtccount);
750 }
751 timec[0] = '\0';
752 get_time();
753 strftime(timec, 40, "%d-%b-%y %H:%M", time_ptr);
754
755 for (ql = 0; ql < *qtccount; ql++) {
756 qtclist.qtclines[ql].sent = 1;
757 g_strlcpy(qtclist.qtclines[ql].senttime, timec, 16);
758 qtclist.totalsent++;
759
760 tempc[0] = '\0';
761 replace_spaces(qtclist.qtclines[ql].qtc, tempc);
762 strcat(tmess, tempc);
763 mvwprintw(qtcwin, ql + 3, 30, "*");
764 qtclist.qtclines[ql].flag = 1;
765
766 }
767 keyer_append(tmess);
768 write_keyer();
769 wattrset(qtcwin, LINE_INVERTED);
770 mvwprintw(qtcwin, 2, 11, "CTRL+S to SAVE!");
771 refreshp();
772 show_help_msg(6);
773
774 showfield(activefield);
775 } else {
776 if (direction == SEND) {
777 tempc[0] = '\0';
778 replace_spaces(qtclist.qtclines[activefield - 3].qtc, tempc);
779 sendmessage(tempc);
780 }
781 }
782 }
783 if (activefield == 0) {
784 start_qtc_recording();
785 }
786 if (activefield < 2) {
787 if (direction == RECV) {
788 activefield++;
789 showfield(activefield - 1);
790 showfield(activefield);
791 }
792 }
793 break;
794
795 // Ctrl-S (^S), save QTC
796 case CTRL_S:
797 if (qtccurrdirection == SEND && *qtccount > 0
798 && qtclist.totalsent == *qtccount) {
799 log_sent_qtc_to_disk(nr_qsos);
800 wattrset(qtcwin, LINE_INVERTED);
801 mvwprintw(qtcwin, 2, 11, "QTC's have been saved!");
802 prevqtccall[0] = '\0';
803 qtccallsign[0] = '\0';
804 refreshp();
805 sleep(1);
806 x = ESCAPE; // <Escape> close the window
807
808 }
809 if (qtccurrdirection == RECV && trxmode == DIGIMODE) {
810 qtc_ry_capture = 1;
811 wattr_get(qtcwin, &attributes, &cpair, NULL);
812 wattrset(qtcwin, LINE_INVERTED);
813 mvwprintw(qtcwin, 2, 11, "CAPTURE ON ");
814 wattrset(qtcwin, attributes);
815 showfield(activefield);
816 refreshp();
817 show_rtty_lines();
818 }
819 break;
820
821 // Ctrl-E (^E), end capture
822 case CTRL_E:
823 if (qtccurrdirection == RECV && trxmode == DIGIMODE) {
824 qtc_ry_capture = 0;
825 wattr_get(qtcwin, &attributes, &cpair, NULL);
826 wattrset(qtcwin, LINE_INVERTED);
827 mvwprintw(qtcwin, 2, 11, "CAPTURE OFF");
828 wattrset(qtcwin, attributes);
829 showfield(activefield);
830 refreshp();
831 }
832 break;
833
834 // F1...F10
835 case KEY_F(1) ... KEY_F(10):
836 if (trxmode == CWMODE || trxmode == DIGIMODE) {
837 if (direction == RECV) {
838 sendmessage(qtc_recv_msgs[x - KEY_F(1)]); /* 0-9 */
839
840 /* start recording */
841 if (trxmode == CWMODE && strncmp(qtc_recv_msgs[x - KEY_F(1)], "QRV", 3) == 0) {
842 start_qtc_recording();
843 }
844
845 /* stop recording */
846 if (trxmode == CWMODE
847 && strncmp(qtc_recv_msgs[x - KEY_F(1)], "QSL ALL", 7) == 0 && record_run > -1) {
848 stop_qtc_recording();
849 }
850
851 if (trxmode == DIGIMODE
852 && strncmp(qtc_recv_msgs[x - KEY_F(1)], "QRV", 3) == 0) {
853 qtc_ry_capture = 1;
854 wattr_get(qtcwin, &attributes, &cpair, NULL);
855 wattrset(qtcwin, LINE_INVERTED);
856 mvwprintw(qtcwin, 2, 11, "CAPTURE ON ");
857 wattrset(qtcwin, attributes);
858 showfield(activefield);
859 refreshp();
860 show_rtty_lines();
861 }
862 }
863
864 if (direction == SEND && strlen(qtc_send_msgs[x - KEY_F(1)]) > 0) {
865 if (qtc_send_msgs[x - KEY_F(1)][strlen(qtc_send_msgs[x - KEY_F(
866 1)]) - 1] == '\n') {
867 qtc_send_msgs[x - KEY_F(1)][strlen(qtc_send_msgs[x - KEY_F(1)]) - 1] = 0;
868 }
869 tlen = strlen(qtc_send_msgs[x - KEY_F(1)]) - 5; // len("sr/nr") = 5
870 char tmess[60];
871 tmess[0] = '\0';
872 if (tlen > 0 && strncmp(qtc_send_msgs[x - KEY_F(1)] + tlen, "sr/nr", 5) == 0) {
873 g_strlcpy(tempc, qtc_send_msgs[x - KEY_F(1)], tlen);
874 sprintf(tmess, "%s %d/%d ", tempc, qtclist.serial, *qtccount);
875 sendmessage(tmess);
876 } else if ((activefield - 3) >= 0) {
877 if (x - KEY_F(1) == 4) { // F5, TIME
878 strncpy(tmess, qtclist.qtclines[activefield - 3].qtc, 5);
879 tmess[5] = '\0';
880 sendmessage(tmess);
881 }
882 if (x - KEY_F(1) == 5) { // F6, CALLSIGN
883 strncpy(tmess, qtclist.qtclines[activefield - 3].qtc + 5, 13);
884 for (i = 12; tmess[i] == ' '; i--)
885 ;
886 tmess[i + 1] = ' ';
887 tmess[i + 2] = '\0';
888 sendmessage(tmess);
889 }
890 if (x - KEY_F(1) == 6) { // F7, SERIAL
891 strncpy(tmess, qtclist.qtclines[activefield - 3].qtc + 20, 4);
892 tmess[4] = ' ';
893 tmess[5] = '\0';
894 sendmessage(tmess);
895 }
896 } else {
897 sendmessage(qtc_send_msgs[x - KEY_F(1)]);
898 }
899 }
900
901 }
902 if (trxmode == SSBMODE) {
903 if (direction == RECV) {
904 if (x == KEY_F(2)) { // F2, "QRV"
905 start_qtc_recording();
906 }
907 if (x == KEY_F(10) && record_run > -1) { // F10, "QSL ALL"
908 stop_qtc_recording();
909 }
910 play_file(qtc_phrecv_message[x - KEY_F(1)]);
911 }
912 if (direction == SEND) {
913 play_file(qtc_phsend_message[x - KEY_F(1)]);
914 }
915 }
916
917 break;
918
919 // <Delete>, Keypad <Del>
920 case KEY_DC:
921 if (DIRCLAUSE) {
922 delete_from_field(0);
923 }
924 if (direction == SEND && activefield > 2 && trxmode != DIGIMODE) {
925 qtclist.qtclines[activefield - 3].sent = 0;
926 qtclist.qtclines[activefield - 3].flag = 0;
927 wattrset(qtcwin, LINE_CURRNORMAL);
928 mvwprintw(qtcwin, activefield, 30, " ");
929 qtclist.totalsent--;
930 }
931 break;
932
933 // <Tab>
934 case TAB:
935 if (direction == RECV) {
936 if (trxmode == DIGIMODE) {
937 if (activefield == 32) {
938 activefield = 0;
939 showfield(32);
940 } else {
941 activefield++;
942 showfield(activefield - 1);
943 }
944 } else {
945 if ((activefield < 3) || (activefield - 3) % 3 < 2) {
946 activefield++;
947 showfield(activefield - 1);
948 } else { /* (activefield-3)%3 == 2*/
949 activefield -= 2;
950 showfield(activefield + 2);
951 }
952 }
953 showfield(activefield);
954 }
955 if (direction == SEND) {
956 switch (activefield) {
957 case 0:
958 activefield = 2;
959 showfield(0);
960 showfield(2);
961 break;
962 case 2:
963 activefield = 0;
964 showfield(2);
965 showfield(0);
966 break;
967 default:
968 break;
969 }
970 }
971 curpos = 0;
972 break;
973
974 // Shift <Tab>
975 case KEY_BTAB:
976 if (direction == RECV) {
977 if (trxmode == DIGIMODE) {
978 if (activefield == 0) {
979 activefield = 32;
980 showfield(0);
981 } else {
982 activefield--;
983 showfield(activefield + 1);
984 }
985 } else {
986 if ((activefield > 0 && activefield < 3) ||
987 ((activefield - 3) % 3 > 0)) {
988 activefield--;
989 showfield(activefield + 1);
990 } else { /* (activefield-3)%3 == 0) */
991 activefield += 2;
992 showfield(activefield - 2);
993 }
994 }
995 showfield(activefield);
996 }
997 if (direction == SEND) {
998 switch (activefield) {
999 case 0:
1000 activefield = 2;
1001 showfield(0);
1002 showfield(2);
1003 break;
1004 case 2:
1005 activefield = 0;
1006 showfield(2);
1007 showfield(0);
1008 break;
1009 default:
1010 break;
1011 }
1012 }
1013 curpos = 0;
1014 break;
1015
1016 // <Space>
1017 case SPACE:
1018 if (DIRCLAUSE) {
1019 if (direction == RECV) {
1020 if (activefield > 2) {
1021 if (activefield % 3 == 2) {
1022 activefield -= 2;
1023 showfield(activefield + 2);
1024 } else {
1025 activefield++;
1026 showfield(activefield - 1);
1027 }
1028 showfield(activefield);
1029 }
1030 if (activefield == 2) {
1031 if (strlen(qtcreclist.callsign) > 0 &&
1032 qtcreclist.serial > 0 &&
1033 qtcreclist.count > 0 &&
1034 qtcreclist.confirmed == 0
1035 ) {
1036 if (trxmode == CWMODE) {
1037 sendmessage(qtc_recv_msgs[1]);
1038 }
1039 if (trxmode == SSBMODE) {
1040 play_file(qtc_phrecv_message[1]);
1041 }
1042 start_qtc_recording();
1043 activefield++;
1044 showfield(activefield);
1045 }
1046 }
1047 if (activefield < 2) {
1048 if (activefield == 0) {
1049 start_qtc_recording();
1050 }
1051 activefield++;
1052 showfield(activefield - 1);
1053 showfield(activefield);
1054 }
1055 }
1056 }
1057 break;
1058
1059 // Numerals
1060 case '0' ... '9':
1061 if (DIRCLAUSE) {
1062 modify_field(x);
1063 }
1064 break;
1065
1066 /*case 65 ... 90: // letters
1067 modify_field(x);
1068 break;*/
1069
1070 // Convert lower case to upper case
1071 case 'a' ... 'z':
1072 if (DIRCLAUSE) {
1073 modify_field(x - 32);
1074 }
1075 break;
1076
1077 // Slash
1078 case '/':
1079 if (DIRCLAUSE) {
1080 modify_field(x);
1081 }
1082 break;
1083
1084 // Query
1085 case '?':
1086 if (DIRCLAUSE) {
1087 modify_field(x);
1088 }
1089 break;
1090
1091 // <Backspace>
1092 case KEY_BACKSPACE:
1093 if (DIRCLAUSE) {
1094 delete_from_field(1);
1095 }
1096 break;
1097
1098 // <Page-Up>
1099 case KEY_PPAGE:
1100 speedup();
1101 attron(COLOR_PAIR(C_HEADER) | A_STANDOUT);
1102 mvprintw(0, 14, "%2u", GetCWSpeed());
1103 break;
1104
1105 // <Page-Down>
1106 case KEY_NPAGE:
1107 speeddown();
1108 attron(COLOR_PAIR(C_HEADER) | A_STANDOUT);
1109 mvprintw(0, 14, "%2u", GetCWSpeed());
1110 break;
1111
1112 // Comma or Ctrl-K (^K), keyboard window
1113 case ',':
1114 case 11:
1115 mvprintw(5, 0, "");
1116 keyer();
1117 x = 0;
1118 break;
1119
1120 // Ctrl-L (^L), mark callsign for late QTC
1121 case CTRL_L:
1122 if (strlen(g_strstrip(qtccallsign)) > 3) {
1123 qtc_inc(g_strstrip(qtccallsign), QTC_LATER);
1124 sprintf(tempc, "%s;L\n", qtccallsign);
1125 send_lan_message(QTCFLAG, tempc);
1126 }
1127 break;
1128
1129 // Ctrl-N (^N), mark callsign for explicit NO QTC
1130 case CTRL_N:
1131 if (strlen(g_strstrip(qtccallsign)) > 3) {
1132 qtc_inc(g_strstrip(qtccallsign), QTC_NO);
1133 sprintf(tempc, "%s;N\n", qtccallsign);
1134 send_lan_message(QTCFLAG, tempc);
1135 }
1136 break;
1137
1138 // Ctrl-F (^F), fill time fields with first 2 chars
1139 case CTRL_F:
1140 if (activefield > 2) {
1141 fill_qtc_times(qtcreclist.qtclines[(activefield - 3) / 3].time);
1142 showfield(activefield);
1143 }
1144 break;
1145
1146 // Ctrl-R (^R), start/stop recording
1147 case CTRL_R:
1148 if (direction == RECV) {
1149 if (record_run < 0) {
1150 start_qtc_recording();
1151 showfield(activefield);
1152 } else {
1153 stop_qtc_recording();
1154 }
1155 }
1156 }
1157 refreshp();
1158 if (x != ESCAPE) {
1159 x = 0;
1160 }
1161 }
1162 hide_panel(qtc_panel);
1163 }
1164
showfield(int fidx)1165 void showfield(int fidx) {
1166
1167 char fieldval[20], filled[20];
1168 int qtcrow, winrow, fi, posidx, i;
1169
1170 fieldval[0] = '\0';
1171
1172 posidx = 0;
1173 if (fidx == 0) {
1174 sprintf(fieldval, "%s", qtccallsign);
1175 winrow = 1;
1176 posidx = 0;
1177 qtc_temp_obj = qtc_get(qtccallsign);
1178 put_qtc();
1179 } else if (fidx == 1) {
1180 sprintf(fieldval, "%4d", qtcreclist.serial);
1181 winrow = 2;
1182 posidx = 1;
1183 } else if (fidx == 2) {
1184 sprintf(fieldval, "%d", *qtccount);
1185 winrow = 2;
1186 posidx = 2;
1187 } else {
1188 fi = fidx - 3;
1189 winrow = (fi / 3) + 3;
1190 qtcrow = winrow - 3;
1191 switch (fi % 3) {
1192 case 0:
1193 sprintf(fieldval, "%s", qtcreclist.qtclines[qtcrow].time);
1194 posidx = 3;
1195 break;
1196 case 1:
1197 sprintf(fieldval, "%s", qtcreclist.qtclines[qtcrow].callsign);
1198 posidx = 4;
1199 break;
1200 case 2:
1201 sprintf(fieldval, "%s", qtcreclist.qtclines[qtcrow].serial);
1202 posidx = 5;
1203 break;
1204 }
1205 show_status(qtcrow);
1206 }
1207 curfieldlen = strlen(fieldval);
1208
1209 for (i = 0; i < pos[posidx][2]; i++) {
1210 filled[i] = ' ';
1211 }
1212 filled[i] = '\0';
1213 if (fidx == activefield) {
1214 wattrset(qtcwin, LINE_CURRINVERTED);
1215 } else {
1216 wattrset(qtcwin, LINE_NORMAL);
1217 }
1218
1219 mvwprintw(qtcwin, winrow, pos[posidx][0], filled);
1220 mvwprintw(qtcwin, winrow, pos[posidx][0], "%s", fieldval);
1221 if (fidx == activefield) {
1222 show_help_msg(posidx);
1223 if (pos[posidx][0] == pos[posidx][1]) {
1224 wmove(qtcwin, winrow, (pos[posidx][1] + strlen(fieldval)) - curpos);
1225 } else {
1226 wmove(qtcwin, winrow, pos[posidx][1] - curpos);
1227 }
1228 }
1229 }
1230
modify_field(int pressed)1231 void modify_field(int pressed) {
1232 char fieldval[16];
1233 int fi, winrow, qtcrow, posidx, stridx;
1234
1235 memset(fieldval, '\0', 15);
1236
1237 posidx = 0;
1238 if (activefield == 0 && (isalnum(pressed) || pressed == '/')
1239 && strlen(qtccallsign) < pos[0][2] - 1) {
1240 qtccallsign[strlen(qtccallsign) - curpos] = pressed;
1241 if (curpos > 0) {
1242 curpos--;
1243 }
1244 recalc_qtclist();
1245 showfield(0);
1246 } else if (activefield == 1 && isdigit(pressed)) {
1247 sprintf(fieldval, "%d", (qtcreclist.serial) * 10);
1248 fieldval[strlen(fieldval) - (1 + curpos)] = pressed;
1249 if (curpos > 0) {
1250 curpos--;
1251 }
1252 if (strlen(fieldval) <= pos[1][2]) {
1253 qtcreclist.serial = atoi(fieldval);
1254 showfield(1);
1255 }
1256 } else if (activefield == 2 && isdigit(pressed)) {
1257 sprintf(fieldval, "%d", (*qtccount) * 10);
1258 fieldval[strlen(fieldval) - (1 + curpos)] = pressed;
1259 if (curpos > 0) {
1260 curpos--;
1261 }
1262 if (strlen(fieldval) <= pos[2][2] && atoi(fieldval) <= 10) {
1263 qtc_temp_obj = qtc_get(qtccallsign);
1264 if (qtccurrdirection == SEND) {
1265 if (*qtccount != atoi(fieldval)) {
1266 if ((atoi(fieldval) + (qtc_temp_obj->total)) >= 10) {
1267 sprintf(fieldval, "%d", (10 - (qtc_temp_obj->total)));
1268 }
1269 *qtccount = genqtclist(qtccallsign, atoi(fieldval));
1270 show_sendto_lines();
1271 put_qtc();
1272 }
1273 }
1274 if (qtccurrdirection == RECV) {
1275 if ((atoi(fieldval) + (qtc_temp_obj->total)) >= 10) {
1276 sprintf(fieldval, "%d", (10 - (qtc_temp_obj->total)));
1277 }
1278 *qtccount = atoi(fieldval);
1279 }
1280 number_fields();
1281 showfield(2);
1282 }
1283 } else if (activefield >= 3 && activefield <= 32) {
1284 fi = activefield - 3;
1285 winrow = (fi / 3) + 3;
1286 qtcrow = winrow - 3;
1287 stridx = fi % 3;
1288 switch (stridx) {
1289 case 0:
1290 sprintf(fieldval, "%s", qtcreclist.qtclines[qtcrow].time);
1291 posidx = 3;
1292 break;
1293 case 1:
1294 sprintf(fieldval, "%s", qtcreclist.qtclines[qtcrow].callsign);
1295 posidx = 4;
1296 break;
1297 case 2:
1298 sprintf(fieldval, "%s", qtcreclist.qtclines[qtcrow].serial);
1299 posidx = 5;
1300 break;
1301 }
1302 if (pressed == '?') {
1303 qtcreclist.qtclines[qtcrow].status = 1; // set incomplete the qtc status
1304 show_status(qtcrow);
1305 }
1306 if ((((stridx == 0 || stridx == 2) && (isdigit(pressed) || pressed == '?'))
1307 || stridx == 1) && strlen(fieldval) < pos[posidx][2]) {
1308
1309 fieldval[strlen(fieldval) - curpos] = pressed;
1310 switch (stridx) {
1311 case 0:
1312 strcpy(qtcreclist.qtclines[qtcrow].time, fieldval);
1313 if (qtc_auto_filltime == 1) {
1314 fill_qtc_times(fieldval);
1315 }
1316 break;
1317 case 1:
1318 strcpy(qtcreclist.qtclines[qtcrow].callsign, fieldval);
1319 break;
1320 case 2:
1321 strcpy(qtcreclist.qtclines[qtcrow].serial, fieldval);
1322 break;
1323 }
1324 if (curpos > 0) {
1325 curpos--;
1326 }
1327 showfield(activefield);
1328 if (stridx == 0 && strlen(fieldval) == pos[posidx][2]
1329 && activefield <= 32) { // auto TAB if curr field is QTC time, and len is 4
1330 curpos = 0;
1331 activefield++;
1332 showfield(activefield - 1);
1333 showfield(activefield);
1334 }
1335 }
1336 }
1337 }
1338
delete_from_field(int dir)1339 void delete_from_field(int dir) {
1340
1341 char fieldval[16];
1342 int fi, winrow, qtcrow, stridx;
1343
1344 fieldval[0] = '\0';
1345
1346 if (activefield == 0) {
1347 if (strlen(qtccallsign) > 0) {
1348 sprintf(fieldval, "%s", qtccallsign);
1349 shift_left(fieldval, dir);
1350 g_strlcpy(qtccallsign, fieldval, QTC_CALL_SIZE);
1351 qtccallsign[strlen(fieldval)] = '\0';
1352 recalc_qtclist();
1353 showfield(0);
1354 }
1355 } else if (activefield == 1) {
1356 sprintf(fieldval, "%d", qtcreclist.serial);
1357 if (strlen(fieldval) > 0) {
1358 //sprintf(fieldval, "%d", qtcreclist.serial/10);
1359 shift_left(fieldval, dir);
1360 qtcreclist.serial = atoi(fieldval);
1361 showfield(1);
1362 }
1363 } else if (activefield == 2) {
1364 sprintf(fieldval, "%d", *qtccount);
1365 if (strlen(fieldval) > 0) {
1366 //sprintf(fieldval, "%d", *qtccount/10);
1367 shift_left(fieldval, dir);
1368 *qtccount = atoi(fieldval);
1369 showfield(2);
1370 }
1371 } else {
1372 fi = activefield - 3;
1373 winrow = (fi / 3) + 3;
1374 qtcrow = winrow - 3;
1375 stridx = fi % 3;
1376 switch (stridx) {
1377 case 0:
1378 sprintf(fieldval, "%s", qtcreclist.qtclines[qtcrow].time);
1379 break;
1380 case 1:
1381 sprintf(fieldval, "%s", qtcreclist.qtclines[qtcrow].callsign);
1382 break;
1383 case 2:
1384 sprintf(fieldval, "%s", qtcreclist.qtclines[qtcrow].serial);
1385 break;
1386 }
1387
1388 if (strlen(fieldval) > 0) {
1389 shift_left(fieldval, dir);
1390 fieldval[strlen(fieldval)] = '\0';
1391 switch (stridx) {
1392 case 0:
1393 strcpy(qtcreclist.qtclines[qtcrow].time, fieldval);
1394 break;
1395 case 1:
1396 strcpy(qtcreclist.qtclines[qtcrow].callsign, fieldval);
1397 break;
1398 case 2:
1399 strcpy(qtcreclist.qtclines[qtcrow].serial, fieldval);
1400 break;
1401 }
1402 showfield(activefield);
1403 }
1404 }
1405 }
1406
shift_left(char * fieldval,int shift)1407 void shift_left(char *fieldval, int shift) {
1408 int i;
1409
1410 for (i = strlen(fieldval) - (curpos + shift); i < strlen(fieldval); i++) {
1411 fieldval[i] = fieldval[i + 1];
1412 }
1413 if (shift == 0) {
1414 curpos--;
1415 }
1416 }
1417
show_status(int idx)1418 void show_status(int idx) {
1419
1420 char flag = ' ';
1421 int i, status = 0;
1422
1423 status = 0;
1424 if (idx < *qtccount) {
1425 if (strlen(qtcreclist.qtclines[idx].time) != 4) {
1426 status = 1;
1427 } else {
1428 for (i = 0; i < strlen(qtcreclist.qtclines[idx].time); i++) {
1429 if (qtcreclist.qtclines[idx].time[i] == '?'
1430 || ! isdigit(qtcreclist.qtclines[idx].time[i])) {
1431 status = 1;
1432 break;
1433 }
1434 }
1435 }
1436 if (strlen(qtcreclist.qtclines[idx].callsign) < 3) {
1437 status = 1;
1438 } else {
1439 for (i = 0; i < strlen(qtcreclist.qtclines[idx].callsign); i++) {
1440 if (qtcreclist.qtclines[idx].callsign[i] == '?') {
1441 status = 1;
1442 break;
1443 }
1444 }
1445 }
1446 if (strlen(qtcreclist.qtclines[idx].serial) == 0) {
1447 status = 1;
1448 }
1449 for (i = 0; i < strlen(qtcreclist.qtclines[idx].serial); i++) {
1450 if (qtcreclist.qtclines[idx].serial[i] == '?'
1451 || ! isdigit(qtcreclist.qtclines[idx].serial[i])) {
1452 status = 1;
1453 break;
1454 }
1455 }
1456 if (status == 1) {
1457 qtcreclist.qtclines[idx].status = 1;
1458 } else if (qtcreclist.qtclines[idx].status !=
1459 2) { // unset incomplete mark if not marked as complete
1460 qtcreclist.qtclines[idx].status = 0;
1461 }
1462
1463 switch (qtcreclist.qtclines[idx].status) {
1464 case 0:
1465 flag = ' ';
1466 break;
1467 case 1:
1468 flag = '?';
1469 break;
1470 case 2:
1471 flag = '*';
1472 break;
1473 }
1474 if (trxmode == DIGIMODE && qtcreclist.qtclines[idx].status == 0) {
1475 flag = '+';
1476 }
1477 wattrset(qtcwin, (chtype)(A_NORMAL | COLOR_PAIR(QTCRECVBG)));
1478 mvwprintw(qtcwin, idx + 3, 30, "%c", flag);
1479 }
1480 }
1481
number_fields()1482 void number_fields() {
1483 int i;
1484
1485 wattrset(qtcwin, (chtype)(A_NORMAL | COLOR_PAIR(QTCRECVBG)));
1486 for (i = 0; i < QTC_LINES; i++) {
1487 mvwprintw(qtcwin, i + 3, 1, " ");
1488 }
1489 for (i = 0; i < *qtccount; i++) {
1490 mvwprintw(qtcwin, i + 3, 1, "%2d", i + 1);
1491 }
1492 }
1493
clear_help_block()1494 void clear_help_block() {
1495 int i;
1496
1497 wattrset(qtcwin, LINE_INVERTED);
1498 for (i = 1; i < 13; i++) {
1499 mvwprintw(qtcwin, i, 36, " ");
1500 }
1501 }
1502
show_help_msg(int msgidx)1503 void show_help_msg(int msgidx) {
1504 int i = 0, j = 0;
1505 char buff[80];
1506 int currqtc;
1507
1508 clear_help_block();
1509
1510 wattrset(qtcwin, LINE_CURRINVERTED);
1511 if (qtccurrdirection == RECV) {
1512 if (trxmode == DIGIMODE && qtccurrdirection == RECV) {
1513 currqtc = ((activefield - 3) / 3);
1514 if (qtcreclist.qtclines[currqtc].status == 0 &&
1515 strlen(qtcreclist.qtclines[currqtc].time) == 4 &&
1516 strlen(qtcreclist.qtclines[currqtc].callsign) > 0 &&
1517 strlen(qtcreclist.qtclines[currqtc].serial) > 0
1518 ) {
1519 mvwprintw(qtcwin, ++j, 36, "Press ENTER to mark as RCVD");
1520 }
1521 } else {
1522 mvwprintw(qtcwin, ++j, 36, help_rec_msgs[msgidx]);
1523 }
1524 }
1525 if (qtccurrdirection == SEND) {
1526 if (msgidx > 2 && msgidx < 6) {
1527 msgidx = 3;
1528 }
1529 mvwprintw(qtcwin, ++j, 36, help_send_msgs[msgidx]);
1530 }
1531 wattrset(qtcwin, LINE_INVERTED);
1532 mvwprintw(qtcwin, ++j, 36, "PgUP/PgDW: QRQ/QRS CTRL-N: NO QTC");
1533 if (qtccurrdirection == RECV) {
1534 mvwprintw(qtcwin, ++j, 36, "ENTER: R & next OR AGN CTRL-L: LATER ");
1535 }
1536 if (qtccurrdirection == SEND) {
1537 mvwprintw(qtcwin, ++j, 36, "ENTER: send QTC CTRL-L: LATER ");
1538 }
1539 for (i = 0; i < 12 && j < 12; i++) {
1540 if (qtccurrdirection == RECV) {
1541 if (strlen(qtc_recv_msgs[i]) > 0) {
1542 g_strlcpy(buff, qtc_recv_msgs[i], sizeof(buff));
1543 mvwprintw(qtcwin, ++j, 36, "F%-2d: %s", (i + 1), buff);
1544 }
1545 if (i == 1) {
1546 mvwprintw(qtcwin, j - 1, 56, "CTRL-F: FILL TIMES");
1547 }
1548 if (i == 2) {
1549 mvwprintw(qtcwin, j - 1, 56, "CTRL-R: RECORD");
1550 }
1551 }
1552 if (qtccurrdirection == SEND) {
1553 if (strlen(qtc_send_msgs[i]) > 0) {
1554 g_strlcpy(buff, qtc_send_msgs[i], sizeof(buff));
1555 mvwprintw(qtcwin, ++j, 36, "F%-2d: %s", (i + 1), buff);
1556 }
1557 }
1558 }
1559 if (trxmode == DIGIMODE && qtccurrdirection == RECV) {
1560 mvwprintw(qtcwin, ++j, 36, "CTRL-T: Terminal window");
1561 mvwprintw(qtcwin, ++j, 36, "CTRL-S: Start capture");
1562 mvwprintw(qtcwin, ++j, 36, "CTRL-E: End capture");
1563 }
1564 }
1565
parse_ry_line(char * line)1566 int parse_ry_line(char *line) {
1567 int j, i = 0, t = -1, f;
1568 char lline[40], *token, *wtoken, ttoken[50], tokens[5][15] = {"", "", "", "", ""}; // 5 members, cause possible callsign will AB/CD1EF/P, which will use 3
1569 char *saveptr1, *saveptr2;
1570 char sep[6] = "";
1571 int tactivefield;
1572 static int nr_parsed_line = 0;
1573 int serial_nr = 0;
1574 int maxlength[] = {4, 14, 4};
1575
1576 if (*qtccount == 0 || qtcreclist.serial == 0) {
1577 nr_parsed_line = 0;
1578 }
1579 if ((*qtccount > 0 || qtcreclist.serial > 0) && nr_parsed_line == 0) {
1580 nr_parsed_line = 1;
1581 }
1582
1583 g_strlcpy(lline, line, sizeof(lline));
1584 tactivefield = activefield;
1585 if (nr_parsed_line == 0) { // 1st line: SERIAL/NR
1586 wtoken = strtok_r(lline, " ", &saveptr1);
1587 while (wtoken != NULL && nr_parsed_line == 0) {
1588 serial_nr = 0;
1589 strcpy(ttoken, wtoken);
1590 sep[0] = '/';
1591 sep[1] = '\0';
1592 token = strtok_r(ttoken, sep, &saveptr2);
1593 t = -1;
1594 while (token != NULL && t < 2) {
1595 t++;
1596 strcpy(tokens[t], token);
1597 token = strtok_r(NULL, sep, &saveptr2);
1598 }
1599 f = 0;
1600 for (i = 0; i <= t; i++) {
1601 f = 1;
1602 for (j = 0; j < strlen(tokens[i]); j++) {
1603 if (! isdigit(tokens[i][j])) {
1604 f = 0;
1605 }
1606 }
1607 if (f == 1) {
1608 tactivefield = activefield;
1609 activefield = i + 1;
1610 showfield(tactivefield);
1611 for (j = 0; j < strlen(tokens[i]); j++) {
1612 modify_field(tokens[i][j]);
1613 }
1614 showfield(activefield);
1615 serial_nr++;
1616 }
1617 }
1618 if (serial_nr == 2) {
1619 nr_parsed_line++;
1620 }
1621 wtoken = strtok_r(NULL, " ", &saveptr1);
1622 }
1623 } else {
1624 strcpy(sep, "/;-: ");
1625 token = strtok(lline, sep);
1626 while (token != NULL && t < 4) {
1627 t++;
1628 strcpy(tokens[t], token);
1629 token = strtok(NULL, sep);
1630 }
1631
1632 while (t > 2) {
1633 strcat(tokens[1], "/");
1634 strcat(tokens[1], tokens[2]);
1635 strcpy(tokens[t - 1], tokens[t]);
1636 tokens[t][0] = '\0';
1637 t--;
1638 }
1639
1640 for (i = 0; i <= t; i++) {
1641 f = 1;
1642 for (j = 0; j < strlen(tokens[i]); j++) {
1643 if ((i == 0 || i == 2) && ! isdigit(tokens[i][j])) {
1644 tokens[i][j] = '?';
1645 }
1646 if (i == 1 && (!isalnum(tokens[i][j]) && tokens[i][j] != '/')) {
1647 tokens[i][j] = '?';
1648 }
1649 }
1650 if (strlen(tokens[i]) > maxlength[i]) {
1651 tokens[i][maxlength[i]] = '\0';
1652 }
1653 if (f == 1) {
1654 tactivefield = activefield;
1655 activefield = (nr_parsed_line * 3) + i;
1656 showfield(tactivefield);
1657 for (j = 0; j < strlen(tokens[i]); j++) {
1658 modify_field(tokens[i][j]);
1659 }
1660 showfield(activefield);
1661 }
1662 }
1663 for (i = ((t > 0) ? t : 0); i < 2; i++) {
1664 tactivefield = activefield;
1665 activefield = (nr_parsed_line * 3) + i;
1666 showfield(tactivefield);
1667 modify_field('?');
1668 showfield(activefield);
1669 }
1670 nr_parsed_line++;
1671 qtc_ry_copied++;
1672 }
1673 tactivefield = activefield;
1674
1675 return tactivefield;
1676 }
1677
1678 /* print one line with its status */
print_rtty_line(t_qtc_ry_line qtc_ry_line,int row)1679 int print_rtty_line(t_qtc_ry_line qtc_ry_line, int row) {
1680 char currline[50];
1681
1682 sprintf(currline, "%-38s", qtc_ry_line.content);
1683 currline[38] = '\0';
1684 if (qtc_ry_line.attr == 1) {
1685 currline[36] = ' ';
1686 currline[37] = '*';
1687 }
1688 mvwprintw(ry_win, row, 1, "%-38s", currline);
1689 return 0;
1690 }
1691
1692 /* RTTY terminal to helps to capture the RTTY content */
show_rtty_lines()1693 void show_rtty_lines() {
1694 extern int miniterm;
1695
1696 char boxhead[38];
1697 int prevline;
1698 char currline[50] = "", firstline[50] = "";
1699 int x, j;
1700 static int actline = 1;
1701 int oactivefield, tactivefield;
1702
1703 oactivefield = activefield;
1704 tactivefield = activefield;
1705
1706 show_panel(ry_panel);
1707 top_panel(ry_panel);
1708 werase(ry_win);
1709 show_panel(ry_help_panel);
1710 top_panel(ry_help_panel);
1711 werase(ry_help_win);
1712
1713 sprintf(boxhead, "HELP");
1714 wnicebox(ry_help_win, 0, 0, 3, 73, "HELP");
1715 wbkgd(ry_help_win, (chtype)(A_NORMAL | COLOR_PAIR(QTCRECVWINBG)));
1716 wattrset(ry_help_win, LINE_INVERTED);
1717 // "1234567890123456789012345678901234567890123456789012345678901234567890123"
1718 mvwprintw(ry_help_win, 1, 1,
1719 "CTRL-R: Reset lines - CTRL-S: Start capture - CTRL-E: End capture ");
1720 mvwprintw(ry_help_win, 2, 1,
1721 "ENTER: add current line to QTC - Up/Down: move ");
1722 mvwprintw(ry_help_win, 3, 1,
1723 "ESC: hide RTTY window ");
1724
1725 strcpy(boxhead, "RTTY");
1726 wnicebox(ry_win, 0, 0, 12, 38, boxhead);
1727 wattrset(ry_win, LINE_NORMAL);
1728 for (j = 1; j < 13; j++) {
1729 mvwprintw(ry_win, j, 1, " ");
1730 }
1731 refreshp();
1732
1733 if (qtc_ry_capture == 1) {
1734 mvwprintw(qtcwin, 2, 11, "CAPTURE ON ");
1735 } else {
1736 mvwprintw(qtcwin, 2, 11, "CAPTURE OFF");
1737 }
1738
1739 x = -1; j = 1;
1740 prevline = -1;
1741 curs_set(0);
1742 while (x != ESCAPE) {
1743
1744 while (x < 1) {
1745
1746 usleep(1000);
1747 time_update();
1748
1749 if (miniterm == 1 && trxmode == DIGIMODE && digikeyer != NO_KEYER) {
1750 show_rtty();
1751 }
1752
1753 if ((qtc_ry_currline < 11 && prevline != qtc_ry_currline - 1)
1754 || qtc_ry_currline == 11) {
1755 if (actline > 1 && strcmp(firstline, qtc_ry_lines[0].content) != 0) {
1756 actline--;
1757 strcpy(firstline, qtc_ry_lines[0].content);
1758 }
1759 if (actline == 1 && qtc_ry_currline > 0) {
1760 strcpy(firstline, qtc_ry_lines[0].content);
1761 }
1762 for (j = 0; j < qtc_ry_currline; j++) {
1763 if (j + 1 == actline) {
1764 wattrset(ry_win, LINE_CURRNORMAL);
1765 }
1766 print_rtty_line(qtc_ry_lines[j], j + 1);
1767 wattrset(ry_win, LINE_NORMAL);
1768 }
1769 prevline = qtc_ry_currline - 1;
1770 }
1771
1772 strncpy(currline, qtc_ry_lines[qtc_ry_currline].content, 38);
1773 currline[39] = '\0';
1774 mvwprintw(ry_win, qtc_ry_currline + 1, 1, "%-38s", currline);
1775
1776 refreshp();
1777 x = key_poll();
1778 }
1779
1780 switch (x) {
1781
1782 // Up arrow
1783 case KEY_UP:
1784 wattrset(ry_win, LINE_NORMAL);
1785 print_rtty_line(qtc_ry_lines[actline - 1], actline);
1786 if (actline > 1) {
1787 actline--;
1788 } else {
1789 if (qtc_ry_currline > 0) {
1790 actline = qtc_ry_currline;
1791 }
1792 }
1793 wattrset(ry_win, LINE_CURRNORMAL);
1794 print_rtty_line(qtc_ry_lines[actline - 1], actline);
1795 wattrset(ry_win, LINE_NORMAL);
1796 break;
1797
1798 // Down arrow
1799 case KEY_DOWN:
1800 wattrset(ry_win, LINE_NORMAL);
1801 print_rtty_line(qtc_ry_lines[actline - 1], actline);
1802 if (actline < qtc_ry_currline) {
1803 actline++;
1804 } else {
1805 actline = 1;
1806 }
1807 wattrset(ry_win, LINE_CURRNORMAL);
1808 print_rtty_line(qtc_ry_lines[actline - 1], actline);
1809 wattrset(ry_win, LINE_NORMAL);
1810 break;
1811
1812 // Ctrl-R (^R)
1813 case CTRL_R:
1814 for (j = 0; j < 12; j++) {
1815 qtc_ry_lines[j].content[0] = '\0';
1816 qtc_ry_lines[j].attr = 0;
1817 mvwprintw(ry_win, (j + 1), 1, " ");
1818 }
1819 prevline = -1;
1820 actline = 1;
1821 qtc_ry_currline = 0;
1822 qtc_ry_copied = 0;
1823 break;
1824
1825 // Ctrl-S (^S), start capture
1826 case CTRL_S:
1827 qtc_ry_capture = 1;
1828 mvwprintw(qtcwin, 2, 11, "CAPTURE ON ");
1829 break;
1830
1831 // Ctrl-E (^E), end capture
1832 case CTRL_E:
1833 qtc_ry_capture = 0;
1834 mvwprintw(qtcwin, 2, 11, "CAPTURE OFF");
1835 break;
1836
1837 // <Enter>, add to qtc
1838 case LINEFEED:
1839 if (qtc_ry_lines[actline - 1].attr == 0) {
1840 parse_ry_line(qtc_ry_lines[actline - 1].content);
1841 qtc_ry_lines[actline - 1].attr = 1;
1842 }
1843 wattrset(ry_win, LINE_CURRNORMAL);
1844 print_rtty_line(qtc_ry_lines[actline - 1], actline);
1845 wattrset(ry_win, LINE_NORMAL);
1846 break;
1847 }
1848 refreshp();
1849 if (x != ESCAPE) {
1850 x = -1;
1851 }
1852 if (*qtccount > 0 && qtc_ry_copied == qtcreclist.count) {
1853 qtc_ry_capture = 0;
1854 mvwprintw(qtcwin, 2, 11, "CAPTURE OFF");
1855 }
1856 }
1857 hide_panel(ry_panel);
1858 hide_panel(ry_help_panel);
1859
1860 curs_set(1);
1861 tactivefield = activefield;
1862 activefield = oactivefield;
1863 showfield(tactivefield);
1864 showfield(oactivefield);
1865 }
1866
put_qtc()1867 void put_qtc() {
1868
1869 char qtcdirstring[3][10] = {"", "Received", "Sent"};
1870
1871 wattrset(qtcwin, LINE_NORMAL);
1872 if (qtc_temp_obj->capable == -1 && qtc_temp_obj->total == 0) {
1873 mvwprintw(qtcwin, 1, 19, "FLAG: NO QTC");
1874 } else {
1875 mvwprintw(qtcwin, 1, 19, "%s %2d QTC", qtcdirstring[qtccurrdirection],
1876 qtc_temp_obj->total);
1877 }
1878
1879 }
1880
replace_spaces(char * src,char * tempc)1881 void replace_spaces(char *src, char *tempc) {
1882 int tsp, tdp;
1883
1884 tsp = 0;
1885 tdp = 0;
1886 g_strstrip(src);
1887 while (src[tsp] != '\0') {
1888 if (src[tsp] != ' ') {
1889 tempc[tdp] = src[tsp];
1890 tdp++;
1891 } else {
1892 if (trxmode == DIGIMODE) {
1893 tempc[tdp] = '-';
1894 } else {
1895 tempc[tdp] = ' ';
1896 }
1897 tdp++;
1898 while (src[tsp + 1] == ' ' || src[tsp + 1] == '-') {
1899 tsp++;
1900 }
1901 }
1902 tsp++;
1903 }
1904 tempc[tdp] = '\n';
1905 tdp++;
1906 tempc[tdp] = '\0';
1907 }
1908
show_sendto_lines()1909 void show_sendto_lines() {
1910 int i;
1911
1912 wattrset(qtcwin, LINE_INVERTED);
1913 for (i = 0; i < QTC_LINES; i++) {
1914 mvwprintw(qtcwin, i + 3, 1, " ");
1915 }
1916
1917 wattrset(qtcwin, LINE_NORMAL);
1918 for (i = 0; i < qtclist.count; i++) {
1919 mvwprintw(qtcwin, i + 3, 4, "%s", qtclist.qtclines[i].qtc);
1920 if (qtclist.qtclines[i].sent == 1) {
1921 mvwprintw(qtcwin, i + 3, 30, "*");
1922 }
1923 }
1924
1925 wattrset(qtcwin, LINE_NORMAL);
1926 for (i = qtclist.count; i < QTC_LINES; i++) {
1927 mvwprintw(qtcwin, i + 3, 4, " ");
1928 }
1929 number_fields();
1930 }
1931
recalc_qtclist()1932 void recalc_qtclist() {
1933 if (qtccurrdirection == SEND) {
1934 if (strlen(qtccallsign) > 0 && strcmp(qtccallsign, prevqtccall) != 0) {
1935 qtc_temp_obj = qtc_get(qtccallsign);
1936 *qtccount = genqtclist(qtccallsign, (10 - (qtc_temp_obj->total)));
1937 show_sendto_lines();
1938 showfield(2);
1939 put_qtc();
1940 }
1941 }
1942 g_strlcpy(prevqtccall, qtccallsign, sizeof(prevqtccall));
1943 }
1944