1 /*
2  * Tlf - contest logging program for amateur radio operators
3  * Copyright (C) 2001-2002-2003-2004-2005 Rein Couperus <pa0r@eudx.org>
4  *               2011-2012                Thomas Beierlein <tb@forth-ev.de>
5  *               2013-2014                Ervin Hegedus - HA2OS <airween@gmail.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 
22 /* ------------------------------------------------------------
23  *        Getexchange handles  the  comment field
24  *
25  *--------------------------------------------------------------*/
26 
27 
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 
32 #include "addspot.h"
33 #include "cw_utils.h"
34 #include "keyer.h"
35 #include "keystroke_names.h"
36 #include "lancode.h"
37 #include "locator2longlat.h"
38 #include "logit.h"
39 #include "qtcvars.h"		// Includes globalvars.h
40 #include "qtcwin.h"
41 #include "recall_exchange.h"
42 #include "rtty.h"
43 #include "score.h"
44 #include "searchlog.h"		// Includes glib.h
45 #include "sendbuf.h"
46 #include "speedupndown.h"
47 #include "stoptx.h"
48 #include "time_update.h"
49 #include "tlf_curses.h"
50 #include "ui_utils.h"
51 #include "addmult.h"
52 
53 #include "getexchange.h"
54 
55 #define LEN(array) (sizeof(array) / sizeof(array[0]))
56 
57 
58 int play_file(char *audiofile);
59 
60 
61 int getlastpattern(char *checkstring);
62 void exchange_edit(void);
63 
getexchange(void)64 int getexchange(void) {
65 
66     extern int contest;
67     extern char comment[];
68     extern char cqzone[];
69     extern char ituzone[];
70     extern char my_rst[];
71     extern int change_rst;
72     extern char ph_message[14][80];
73     extern char hiscall[];
74     extern char qsonrstr[];
75     extern int cqww;
76     extern int wpx;
77     extern int pacc_pa_flg;
78     extern int stewperry_flg;
79     extern int arrldx_usa;
80     extern int arrl_fd;
81     extern int exchange_serial;
82     extern int countrynr;
83     extern int mycountrynr;
84     extern int sprint;
85     extern int trxmode;
86     extern int recall_mult;
87     extern int arrlss;
88     extern int lan_active;
89     extern char lastqsonr[];
90     extern char qsonrstr[];
91     extern char call[];
92     extern char section[];
93     extern int serial_section_mult;
94     extern int serial_grid4_mult;
95     extern int sectn_mult;
96     extern int dx_arrlsections;
97     extern int ctcomp;
98     extern int wazmult;
99     extern int itumult;
100     extern int pfxmult;
101     extern int exc_cont;
102     extern char continent[];
103     extern int commentfield;
104     extern int no_rst;
105     extern int serial_or_section;
106     extern int ve_cty;
107     extern int w_cty;
108 
109     int i;
110     int x = 0;
111     char instring[2];
112     char commentbuf[40] = "";
113     char *gridmult = "";
114 
115     instring[1] = '\0';
116 
117     if ((lan_active == 1) && (exchange_serial == 1)) {
118 	strncpy(lastqsonr, qsonrstr, 5);
119 	send_lan_message(INCQSONUM, qsonrstr);
120     }
121 
122     if (recall_mult == 1)
123 	recall_exchange();
124 
125     if ((arrldx_usa == 1) && (trxmode != CWMODE))
126 	recall_exchange();
127 
128     if (arrl_fd == 1)
129 	recall_exchange();
130 
131     if (((cqww == 1) || (wazmult == 1) || (itumult == 1))
132 	    && (*comment == '\0') && (strlen(hiscall) != 0)) {
133 	if (itumult == 1)
134 	    strcpy(comment, ituzone);
135 	else
136 	    strcpy(comment, cqzone);
137     }
138     if ((exc_cont == 1) && (*comment == '\0')
139 	    && (strlen(hiscall) != 0)) {
140 	strcpy(comment, continent);
141     }
142 
143     if (stewperry_flg == 1) {
144 	recall_exchange();
145     }
146 
147     /* parse input and modify exchange field accordingly */
148 
149     commentfield = 1;
150 
151     i = strlen(comment);
152 
153     while (1) {
154 
155 	refresh_comment();
156 
157 	/* wait for next char pressed, but update time, cluster and TRX qrg */
158 	/* main loop waiting for input */
159 	x = -1;
160 	while (x < 1) {
161 
162 	    usleep(10000);
163 
164 	    time_update();
165 
166 	    if (trxmode == DIGIMODE) {
167 		show_rtty();
168 	    }
169 
170 	    /* make sure that the wrefresh() inside getch() shows the cursor
171 	     * in the input field */
172 	    wmove(stdscr, 12, 54 + strlen(comment));
173 	    x = key_poll();
174 	}
175 
176 	switch (x) {
177 
178 	    case CTRL_Q: {	// Ctl-q (^Q)--Open QTC panel for receiving or sending QTCs
179 		if (qtcdirection == 1 || qtcdirection == 3) {	// in case of QTC=RECV or QTC=BOTH
180 		    qtc_main_panel(RECV);
181 		}
182 		if (qtcdirection == 2) {			// in case of QTC=SEND
183 		    qtc_main_panel(SEND);
184 		}
185 		x = KEY_LEFT;
186 		continue;
187 	    }
188 	    case 19: {	// Ctl+s (^S)--Open QTC panel for sending QTCs
189 		if (qtcdirection == 2 || qtcdirection == 3) {	// in case of QTC=SEND ot QTC=BOTH
190 		    qtc_main_panel(SEND);
191 		}
192 		x = KEY_LEFT;
193 		continue;
194 	    }
195 	    case CTRL_A: {	// Ctrl-A (^A)
196 		addspot();
197 		*comment = '\0';
198 		x = TAB;	// <Tab>
199 		break;
200 	    }
201 
202 	    case KEY_BACKSPACE: {	// Erase (^H or <Backspace>)
203 		if (i >= 1) {
204 		    comment[strlen(comment) - 1] = '\0';
205 		    i -= 1;
206 		}
207 		break;
208 	    }
209 
210 	    case ESCAPE: {                // <Escape>
211 		stoptx();			/* stop sending CW */
212 		if (comment[0] != '\0') {	/* if comment not empty */
213 		    /* drop exchange so far */
214 		    comment[0] = '\0';
215 		    i = 0;
216 		} else {
217 		    /* back to callinput */
218 		    x = TAB;	// <Tab>
219 		}
220 		break;
221 	    }
222 
223 	    /* I cannot find any reference for this key combination in my
224 	     * CT ver 9 documentation.  As it is, most X window managers
225 	     * will trap this combination for the window menu so would
226 	     * only be useful on the console.
227 	     *
228 	     * - N0NB
229 	     */
230 	    /* case 160: {	// For CT compatibility Meta-<Space> (M- ) */
231 	    /*     if (ctcomp != 0) { */
232 	    /*         send_standard_message(1);		// F2 */
233 
234 	    /*     } */
235 	    /*     break; */
236 	    /* } */
237 
238 	    /* '+', send TU and log in CT mode */
239 	    case '+': {
240 		if ((ctcomp != 0) && (strlen(hiscall) > 2)) {
241 		    if (comment[0] == '\0') {
242 			x = -1;
243 		    } else {
244 			/* F4 (TU macro) */
245 			send_standard_message(3);
246 
247 			/* log without additional message */
248 			x = BACKSLASH;
249 		    }
250 		}
251 		break;
252 	    }
253 
254 	    /* <Insert>, send exchange in CT mode */
255 	    case KEY_IC: {
256 		if (ctcomp != 0) {
257 		    /* F3 (RST macro) */
258 		    send_standard_message(2);
259 
260 		}
261 		break;
262 	    }
263 
264 	    case KEY_F(1): {
265 		if (trxmode == CWMODE || trxmode == DIGIMODE) {
266 		    sendmessage(call);		/* F1 */
267 		} else
268 		    play_file(ph_message[5]);	// call
269 
270 		break;
271 	    }
272 
273 	    case KEY_F(2) ... KEY_F(11): {
274 		/* F2...F11 - F1 = 1...10 */
275 		send_standard_message(x - KEY_F(1));
276 
277 		break;
278 	    }
279 
280 	    case 176 ... 185: {	/* Alt-0 to Alt-9 */
281 		send_standard_message(x - 162);	/* Messages 15-24 */
282 
283 		break;
284 	    }
285 
286 	    /* <Home>--edit exchange field, position cursor to left end of field.
287 	     * Fall through to KEY_LEFT stanza if ungetch() is successful.
288 	     */
289 	    case KEY_HOME: {
290 		if (ungetch(x) != OK)
291 		    break;
292 	    }
293 
294 	    case KEY_LEFT: {	/* Left Arrow--edit exchange field */
295 		if (*comment != '\0')
296 		    exchange_edit();
297 		break;
298 	    }
299 
300 	    case KEY_PPAGE: {	/* Page-Up--change MY RST */
301 		if (change_rst == 1) {
302 		    if (my_rst[1] <= 56) {
303 			my_rst[1]++;
304 
305 			if (!no_rst)
306 			    mvprintw(12, 49, my_rst);
307 		    }
308 		} else {	/* speed up */
309 		    speedup();
310 
311 		    attron(COLOR_PAIR(C_HEADER) | A_STANDOUT);
312 		    mvprintw(0, 14, "%2u", GetCWSpeed());
313 		}
314 		break;
315 
316 	    }
317 	    case KEY_NPAGE: {	/* Page-Down--change MY RST */
318 		if (change_rst == 1) {
319 
320 		    if (my_rst[1] > 49) {
321 			my_rst[1]--;
322 
323 			if (!no_rst)
324 			    mvprintw(12, 49, my_rst);
325 		    }
326 		} else {	/* speed down */
327 		    speeddown();
328 
329 		    attron(COLOR_PAIR(C_HEADER) | A_STANDOUT);
330 		    mvprintw(0, 14, "%2u", GetCWSpeed());
331 		}
332 		break;
333 
334 	    }
335 	    case ',':		// Keyboard Morse
336 	    case CTRL_K: {	// Ctrl-K
337 		mvprintw(5, 0, "");
338 		keyer();
339 		x = 0;
340 		break;
341 	    }
342 	    case '\n':
343 	    case KEY_ENTER: {
344 		/* log QSO immediately if CT compatible
345 		 * or not in contest */
346 		if ((ctcomp == 1) || (contest != 1)) {
347 		    /* Don't log if exchange field is empty. */
348 		    if (comment[0] == '\0') {
349 			x = -1;
350 		    } else {
351 			/* Log without sending a message. */
352 			x = BACKSLASH;
353 		    }
354 		}
355 		break;
356 	    }
357 	}	// End switch
358 
359 	if (x >= 'a' && x <= 'z')
360 	    x = x - 32;		// Promote to upper case
361 
362 	if (i < 25) {		/* normal character -> insert if space left */
363 	    if (x >= ' ' && x <= 'Z') {
364 		instring[0] = x;
365 		addch(x);
366 		strcat(comment, instring);
367 		i++;
368 		refreshp();
369 	    }
370 	}
371 
372 	if ((serial_section_mult == 1) ||
373 		(dx_arrlsections == 1) ||
374 		(sectn_mult == 1) ||
375 		(arrlss == 1) ||
376 		(cqww == 1) ||
377 		(stewperry_flg == 1)) {
378 
379 	    x = checkexchange(x);
380 	}
381 
382 	/* <Enter>, <Tab>, Ctl-K, '\' */
383 	if (x == '\n' || x == KEY_ENTER || x == TAB
384 		|| x == CTRL_K || x == BACKSLASH) {
385 
386 	    if ((exchange_serial == 1 && comment[0] >= '0'
387 		    && comment[0] <= '9')) {	/* align serial nr. */
388 		if (strlen(comment) == 1) {
389 		    strcpy(commentbuf, comment);
390 		    comment[0] = '\0';
391 		    strcat(comment, "00");
392 		    strcat(comment, commentbuf);
393 		}
394 
395 		if (strlen(comment) == 2) {
396 		    strcpy(commentbuf, comment);
397 		    comment[0] = '\0';
398 		    strcat(comment, "0");
399 		    strcat(comment, commentbuf);
400 		}
401 
402 	    }
403 
404 	    if (wpx == 1 && pfxmult == 0) {	/* align serial nr. */
405 
406 		if ((strlen(comment) == 1) || (comment[1] == ' ')) {
407 		    strcpy(commentbuf, comment);
408 		    comment[0] = '\0';
409 		    strcat(comment, "00");
410 		    strcat(comment, commentbuf);
411 		}
412 
413 		if ((strlen(comment) == 2) || (comment[2] == ' ')) {
414 		    strcpy(commentbuf, comment);
415 		    comment[0] = '\0';
416 		    strcat(comment, "0");
417 		    strcat(comment, commentbuf);
418 		}
419 
420 	    }
421 
422 	    if (sprint == 1) {
423 
424 		if ((comment[1] == ' ') && (comment[0] != ' ')) {
425 
426 		    strcpy(commentbuf, "00");
427 		    commentbuf[2] = comment[0];
428 		    commentbuf[3] = '\0';
429 		    strcat(commentbuf, comment + 1);
430 		    strcpy(comment, commentbuf);
431 		}
432 		if ((comment[2] == ' ') && (comment[1] != ' ')) {
433 
434 		    strcpy(commentbuf, "0");
435 		    commentbuf[1] = comment[0];
436 		    commentbuf[2] = comment[1];
437 		    commentbuf[3] = '\0';
438 		    strcat(commentbuf, comment + 2);
439 		    strcpy(comment, commentbuf);
440 		}
441 
442 	    }
443 
444 	    if ((pacc_pa_flg == 1) && (countrynr != mycountrynr)) {
445 		if (strlen(comment) == 1) {
446 		    strcpy(commentbuf, comment);
447 		    comment[0] = '\0';
448 		    strcat(comment, "00");
449 		    strcat(comment, commentbuf);
450 		}
451 
452 		if (strlen(comment) == 2) {
453 		    strcpy(commentbuf, comment);
454 		    comment[0] = '\0';
455 		    strcat(comment, "0");
456 		    strcat(comment, commentbuf);
457 		}
458 
459 	    }
460 
461 	    if ((arrlss == 1) && (x != TAB) && (strlen(section) < 2)) {
462 		mvprintw(13, 54, "section?");
463 		mvprintw(12, 54, comment);
464 		x = 0;
465 	    } else if (((serial_section_mult == 1) || (sectn_mult == 1))
466 		       && ((x != TAB) && (strlen(section) < 1))) {
467 		if (serial_or_section == 0 || (serial_or_section == 1
468 					       && country_found(hiscall))) {
469 		    mvprintw(13, 54, "section?", section);
470 		    mvprintw(12, 54, comment);
471 		    refreshp();
472 		}
473 		break;
474 
475 	    } else if (serial_grid4_mult == 1) {
476 		//      mvprintw(13,54, "section?");
477 		mvprintw(12, 54, comment);
478 		refreshp();
479 		gridmult = getgrid(comment);
480 		strcpy(section, gridmult);
481 		section[4] = '\0';
482 
483 		break;
484 //                              x = 0; //##debug
485 
486 	    } else if (stewperry_flg == 1) {
487 		if (check_qra(comment) == 0) {
488 		    mvprintw(13, 54, "locator?");
489 		    mvprintw(12, 54, comment);
490 		    break;
491 		}
492 		refreshp();
493 		break;
494 	    } else if (cqww == 1 && trxmode == DIGIMODE && ((countrynr == w_cty)
495 		       || (countrynr == ve_cty))) {
496 		if (strlen(comment) < 5) {
497 		    mvprintw(13, 54, "state/prov?");
498 		    mvprintw(12, 54, comment);
499 		    if (x == '\n' || x == KEY_ENTER || x == BACKSLASH) {
500 			x = 0;
501 		    } else {
502 			refreshp();
503 			break;
504 		    }
505 		    x = 0;
506 		} else {
507 		    refreshp();
508 		    break;
509 		}
510 	    } else
511 		break;
512 	}
513 
514     }
515     refresh_comment();
516 
517     commentfield = 0;
518 
519     return (x);
520 }
521 
522 
523 /* ------------------------------------------------------------------------ */
524 
525 char cmpattern[32] = "                               ";	// global
526 char ssexchange[30] = "";
527 char section[8] = "";
528 char callupdate[7];
529 int call_update = 0;
530 char zone_export[3] = "  ";
531 char zone_fix[3] = "";
532 
533 /* ------------------------------------------------------------------------ */
534 
checkexchange(int x)535 int checkexchange(int x) {
536 
537     extern char comment[];
538     extern char ssexchange[];
539     extern int cqww;
540     extern int arrlss;
541     extern int stewperry_flg;
542     extern char section[];
543     extern char callupdate[];
544     extern char hiscall[];
545     extern int call_update;
546     extern char zone_export[];
547     extern char zone_fix[];
548     extern int serial_section_mult;
549     extern int sectn_mult;
550     extern int dx_arrlsections;
551 
552     char precedent[] = " ";
553     char serial[5] = "    ";
554     char check[3] = "  ";
555     char checksection[30];
556     char zone[4] = "";
557 
558     /* field of allowed pattern sequences
559      *
560      * The characters have the following meaning:
561      * u - undefined (left or right delimiter)
562      * b - blank character
563      * a - ascii character
564      * f - a figure / digit
565      *
566      * e.g. faf means a character between two digits
567      */
568     char serpats[8][8] = {
569 	"bfb",
570 	"afb",
571 	"bfa",
572 	"bffab",
573 	"affab",
574 	"bffbffb",
575 	"fff",
576 	"ffff"
577     };
578     char precpats[8][4] = {
579 	"faf",
580 	"fab",
581 	"bab",
582 	"baf",
583 	"fau",
584 	"bau",
585 	"uaf",
586 	"uab"
587     };
588     char checkpats[6][5] = {
589 	"bffb",
590 	"bffu",
591 	"affu",
592 	"affb",
593 	"affa",
594 	"bffa"
595     };
596     char secpats[10][6] = {
597 	"fab",
598 	"faab",
599 	"faaab",
600 	"bab",
601 	"baab",
602 	"baaab",
603 	"bau",
604 	"baau",
605 	"baaau",
606 	"baafb"
607     };
608     char callpats[5][9] = {
609 	"bafaab",
610 	"baafab",
611 	"baafaab",
612 	"bafaaab",
613 	"baafaaab"
614     };
615     char zonepats[6][6] = {
616 	"ufb",
617 	"uffb",
618 	"bfb",
619 	"bffb",
620 	"bffu",
621 	"bfu"
622     };
623     char sectionpats[9][6] = {
624 	"uab",
625 	"uaab",
626 	"uaaab",
627 	"uau",
628 	"uaau",
629 	"uaaau",
630 	"bab",
631 	"baab",
632 	"baaab"
633     };
634 
635     int i, s, hr, ii, pr, jj;
636 
637     /* get the pattern sequence from comment string */
638     strcpy(cmpattern, "u                    ");
639 
640     if (strlen(comment) > 0) {
641 
642 	for (i = 0; i < strlen(comment); i++) {
643 
644 	    switch ((int) comment[i]) {
645 
646 		case 'A'...'Z': {
647 		    cmpattern[i + 1] = 'a';
648 		    cmpattern[i + 2] = 'u';
649 		    break;
650 		}
651 
652 		case '0'...'9': {
653 		    cmpattern[i + 1] = 'f';
654 		    cmpattern[i + 2] = 'u';
655 		    break;
656 		}
657 
658 		case ' ': {
659 		    cmpattern[i + 1] = 'b';
660 		    break;
661 		}
662 
663 		default:
664 		    cmpattern[i + 1] = 'u';
665 	    }
666 	}
667     }
668 
669     // -----------------------------------cqww-----------------------
670     if (cqww == 1) {
671 
672 	s = atoi(comment);
673 	snprintf(zone, sizeof(zone), "%02d", s);
674 
675 	for (ii = 0; ii < LEN(zonepats); ii++) {
676 
677 	    hr = getlastpattern(zonepats[ii]);
678 
679 //! \todo  logik und Verwendung zone_fix vs zone_export unklar
680 //! Was passiert, falls zonenummer in comment zu groess ist?
681 	    if ((hr > 1) && (atoi(comment + hr - 1) != 0)) {
682 		sprintf(zone, "%02d", atoi(comment + hr - 1));
683 		strncpy(zone_fix, zone, 2);
684 		zone_fix[2] = '\0';
685 	    } else {
686 		strncpy(zone_export, zone, 2);
687 		zone_export[2] = '\0';
688 	    }
689 	}
690 
691 	if (strlen(hiscall) >= 2)
692 	    OnLowerSearchPanel(32, zone_export);
693 
694 
695 	for (ii = 0; ii < LEN(callpats); ii++) {
696 
697 	    hr = getlastpattern(callpats[ii]);	// call update ?
698 
699 	    if (hr > 0) {
700 
701 		switch (ii) {
702 
703 		    case 0 ... 1:
704 			strncpy(callupdate, comment + hr, 4);
705 			callupdate[4] = '\0';
706 			break;
707 		    case 2 ... 3:
708 			strncpy(callupdate, comment + hr, 5);
709 			callupdate[5] = '\0';
710 			break;
711 		    case 4:
712 			strncpy(callupdate, comment + hr, 6);
713 			callupdate[6] = '\0';
714 		}
715 
716 		if (strlen(callupdate) > 3) {
717 
718 		    if (call_update == 1)
719 			strcpy(hiscall, callupdate);
720 
721 		    mvprintw(12, 29, "       ");
722 		    mvprintw(12, 29, "%s", hiscall);
723 		    mvprintw(12, 54, "%s", comment);
724 		}
725 	    }
726 	}
727 
728 	return (x);
729     }
730 
731     // ---------------------------arrls------------------------------
732     if (arrlss == 1) {
733 
734 	// get serial nr.
735 
736 	s = atoi(comment);
737 
738 	if (s != 0)
739 	    snprintf(serial, sizeof(serial), "%4d", s);
740 
741 	for (ii = 0; ii < LEN(serpats); ii++) {
742 
743 	    hr = getlastpattern(serpats[ii]);
744 
745 	    if (hr > 0)
746 		snprintf(serial, sizeof(serial), "%4d",
747 			 atoi(comment + hr - 1));
748 
749 	    if (ii == 5 && hr > 0) {
750 		snprintf(serial, sizeof(serial), "%4d", atoi(comment + hr - 1));
751 		snprintf(check, sizeof(check), "%2d", atoi(comment + hr + 2));
752 	    }
753 
754 	}
755 
756 	// get precedent
757 
758 	if (((comment[0] == 'A')
759 		|| (comment[0] == 'B')
760 		|| (comment[0] == 'M')
761 		|| (comment[0] == 'Q')
762 		|| (comment[0] == 'S')
763 		|| (comment[0] == 'U'))
764 		&& ((comment[1] == ' ') || (cmpattern[2] == 'f'))) {
765 
766 	    precedent[0] = comment[0];
767 	}
768 
769 
770 	/* look for a single letter */
771 	for (ii = 0; ii < LEN(precpats); ii++) {
772 
773 	    hr = getlastpattern(precpats[ii]);
774 
775 	    if (hr > 0) {
776 		pr = comment[hr];
777 		if ((pr == 'Q') || (pr == 'A') || (pr == 'B')
778 			|| (pr == 'U') || (pr == 'M') || (pr == 'S')) {
779 		    precedent[0] = pr;
780 		    precedent[1] = '\0';
781 		}
782 	    }
783 	}
784 
785 	// get call update
786 
787 	for (ii = 0; ii < LEN(callpats); ii++) {
788 
789 	    hr = getlastpattern(callpats[ii]);
790 
791 	    if (hr > 0) {
792 		if (((comment[hr] == 'A') && (comment[hr + 1] > 59))
793 			|| (comment[hr] == 'K') || (comment[hr] == 'N')
794 			|| (comment[hr] == 'W')
795 			|| (comment[hr] == 'V') || (comment[hr] == 'C')) {
796 
797 		    switch (ii) {
798 
799 			case 0 ... 1:
800 			    strncpy(callupdate, comment + hr, 4);
801 			    callupdate[4] = '\0';
802 			    break;
803 			case 2 ... 3:
804 			    strncpy(callupdate, comment + hr, 5);
805 			    callupdate[5] = '\0';
806 			    break;
807 			case 4:
808 			    strncpy(callupdate, comment + hr, 6);
809 			    callupdate[6] = '\0';
810 
811 		    }
812 		    if (strlen(callupdate) > 3) {
813 
814 			if (call_update == 1)
815 			    strcpy(hiscall, callupdate);
816 
817 			mvprintw(12, 29, "       ");
818 			mvprintw(12, 29, "%s", hiscall);
819 			mvprintw(12, 54, "%s", comment);
820 		    }
821 
822 		}
823 	    }
824 
825 	}
826 
827 	// get check
828 
829 	for (ii = 0; ii < LEN(checkpats); ii++) {
830 
831 	    hr = getlastpattern(checkpats[ii]);
832 	    if (hr > 0) {
833 		check[0] = comment[hr];
834 		check[1] = comment[hr + 1];
835 		check[2] = '\0';
836 	    }
837 	}
838 
839 	// get section
840 	*section = '\0';
841 
842 	for (ii = 0; ii < LEN(secpats); ii++) {
843 
844 	    hr = getlastpattern(secpats[ii]);
845 
846 	    if (hr > 0) {
847 
848 		g_strlcpy(checksection, comment + hr, 4);
849 		g_strchomp(checksection);
850 
851 		for (jj = 0; jj < get_mult_count(); jj++) {
852 
853 		    char *multi = g_strdup(get_mult(jj));
854 		    g_strchomp(multi);
855 
856 		    if ((strlen(multi) >= 1) &&
857 			    (strcmp(checksection, multi) == 0)) {
858 
859 			strcpy(section, multi);
860 			break;
861 		    }
862 		    g_free(multi);
863 		}
864 	    }
865 	}
866 
867 	{
868 	    char buf[40];
869 	    sprintf(buf, " %4s %1s %2s %2s ", serial, precedent,
870 		    check, section);
871 	    OnLowerSearchPanel(8, buf);
872 	}
873 
874 	/* \todo use sprintf */
875 	ssexchange[0] = '\0';
876 
877 	strcat(ssexchange, serial);
878 	strcat(ssexchange, " ");
879 	strcat(ssexchange, precedent);
880 	strcat(ssexchange, " ");
881 	strcat(ssexchange, check);
882 	strcat(ssexchange, " ");
883 	strcat(ssexchange, section);
884 
885 	mvprintw(12, 54, comment);
886 	refreshp();
887 
888 	return (x);		// end arrlss
889     }
890 
891     // ----------------------serial+section--------------------------
892     if ((serial_section_mult == 1) || (sectn_mult == 1)
893 	    || (dx_arrlsections == 1)) {
894 
895 	if (serial_section_mult == 1) {
896 
897 	    // get serial nr.
898 
899 	    s = atoi(comment);
900 
901 	    if (s != 0)
902 		snprintf(serial, sizeof(serial), "%4d", atoi(comment));
903 
904 	    for (ii = 0; ii < LEN(serpats); ii++) {
905 
906 		hr = getlastpattern(serpats[ii]);
907 
908 		if (hr > 0)
909 		    snprintf(serial, sizeof(serial), "%4d",
910 			     atoi(comment + hr - 1));
911 
912 		if (ii == 5 && hr > 0) {
913 		    snprintf(serial, sizeof(serial), "%4d",
914 			     atoi(comment + hr - 1));
915 		    snprintf(check, sizeof(check), "%2d",
916 			     atoi(comment + hr + 2));
917 		}
918 
919 	    }
920 
921 	    // get section
922 
923 	    for (ii = 0; ii < LEN(secpats); ii++) {
924 
925 		hr = getlastpattern(secpats[ii]);
926 
927 		if (hr > 0) {
928 
929 		    memset(checksection, 0, 29);
930 		    strncpy(checksection, comment + (hr), 3);
931 		    if (checksection[strlen(checksection) - 1] == ' ') {
932 			checksection[strlen(checksection) - 1] = '\0';
933 		    }
934 
935 		    for (jj = 0; jj < get_mult_count(); jj++) {
936 			if (get_matching_length(checksection, jj) ==
937 				strlen(checksection)) {
938 			    strcpy(section, get_mult(jj));
939 			    break;
940 			}
941 		    }
942 		}
943 	    }
944 	}			// end serial_section_mult
945 	if (sectn_mult == 1) {
946 
947 	    for (ii = 0; ii < LEN(sectionpats); ii++) {
948 
949 		hr = getlastpattern(sectionpats[ii]);
950 
951 		strncpy(checksection, comment, 3);
952 		checksection[3] = '\0';
953 
954 		int best_len = 0;
955 		int idx = -1;
956 		for (jj = 0; jj < get_mult_count(); jj++) {
957 		    int len = get_matching_length(checksection, jj);
958 		    if (len > best_len) {
959 			best_len = len;
960 			idx = jj;
961 		    }
962 		}
963 
964 		if (idx >= 0) {
965 		    strcpy(section, get_mult(idx));
966 		}
967 	    }
968 
969 	}			//  end sectn_mult
970 	if (dx_arrlsections == 1) {
971 
972 	    for (ii = 0; ii < LEN(sectionpats); ii++) {
973 
974 		hr = getlastpattern(sectionpats[ii]);
975 
976 		strncpy(checksection, comment, 3);
977 		checksection[3] = '\0';
978 
979 		for (jj = 0; jj < get_mult_count(); jj++) {
980 		    if (get_matching_length(checksection, jj) == strlen(checksection)) {
981 			strcpy(section, get_mult(jj));
982 
983 			// if (strlen(section) == strlen(mults_possible[jj])) break;
984 		    }
985 		}
986 
987 	    }
988 
989 	}			// end dx_arrlsections
990 
991 	callupdate[0] = '\0';
992 
993     }
994 
995 
996     // get call update
997 
998     for (ii = 0; ii < LEN(callpats); ii++) {
999 
1000 	hr = getlastpattern(callpats[ii]);
1001 
1002 	if (hr > 0) {
1003 	    if (((comment[hr] == 'A') && (comment[hr + 1] > 59))
1004 		    || (comment[hr] == 'K') || (comment[hr] == 'N')
1005 		    || (comment[hr] == 'W')
1006 		    || (comment[hr] == 'V') || (comment[hr] == 'C')) {
1007 
1008 		switch (ii) {
1009 
1010 		    case 0 ... 1:
1011 			strncpy(callupdate, comment + hr, 4);
1012 			callupdate[4] = '\0';
1013 			break;
1014 		    case 2 ... 3:
1015 			strncpy(callupdate, comment + hr, 5);
1016 			callupdate[5] = '\0';
1017 			break;
1018 		    case 4:
1019 			strncpy(callupdate, comment + hr, 6);
1020 			callupdate[6] = '\0';
1021 
1022 		}
1023 
1024 		if (strlen(callupdate) > 3) {
1025 
1026 		    if (call_update == 1)
1027 			strcpy(hiscall, callupdate);
1028 
1029 		    mvprintw(12, 29, "       ");
1030 		    mvprintw(12, 29, "%s", hiscall);
1031 		    mvprintw(12, 54, "%s", comment);
1032 		}
1033 
1034 	    }
1035 	}
1036 
1037     }
1038     OnLowerSearchPanel(32, "   ");
1039     OnLowerSearchPanel(32, section);	/* show section on lower frame of
1040 					   Worked window */
1041     ssexchange[0] = '\0';
1042 
1043     /*	if (serial_section_mult == 1) {
1044     		strcat (ssexchange,serial);
1045     		strcat (ssexchange, " ");
1046     	}
1047     */
1048     strcat(ssexchange, section);
1049 
1050     // ---------------------------end mults --------------------------
1051     mvprintw(12, 54, comment);
1052     refreshp();
1053 
1054     return (x);
1055 }
1056 
1057 
1058 /* ------------------------------------------------------------------------ */
1059 
1060 /** search checkstring in cmpattern
1061  *
1062  * find first occurence of checkstring in cmpattern
1063  * \parm checkstring - the pattern to be found
1064  * \return offset of checkstring in cmpattern (or 0 if not found)
1065  */
getlastpattern(char * checkstring)1066 int getlastpattern(char *checkstring) {
1067 
1068     extern char comment[];
1069     char newpat[80];
1070     int i, x = 0;
1071 
1072     if ((strlen(cmpattern) - strlen(checkstring)) > 0) {
1073 	for (i = 0; i < (strlen(cmpattern) - strlen(checkstring)) - 1; i++) {
1074 
1075 	    newpat[0] = '\0';
1076 	    strncat(newpat, cmpattern + i, strlen(comment));
1077 
1078 	    if (strncmp(newpat, checkstring, strlen(checkstring)) == 0) {
1079 		x = i;
1080 	    }
1081 	}
1082 	if (x > strlen(comment))
1083 	    x = 0;
1084     }
1085     return (x);
1086 
1087 }
1088 
1089 /* ------------------------------------------------------------------------
1090  * return a pointer to the start of grid locator
1091  */
1092 
getgrid(char * comment)1093 char *getgrid(char *comment) {
1094 
1095     char *gridmult = "";
1096     int multposition = 0;
1097     int i = 0;
1098 
1099     /* search for first letter, that should be the start of the Grid locator*/
1100     for (i = 0; i < strlen(comment); i++) {
1101 	if (comment[i] > 64 && comment[i] < 91) {
1102 	    multposition = i;
1103 	    break;
1104 	}
1105     }
1106     gridmult = comment + multposition;
1107 
1108     return (gridmult);
1109 }
1110 
1111 /* ------------------------------------------------------------------------ */
1112 /** Edit exchange field
1113  */
1114 
exchange_edit(void)1115 void exchange_edit(void) {
1116     extern char comment[];
1117 
1118     int l, b;
1119     int i = 0, j;
1120     char comment2[27];
1121 
1122     l = strlen(comment);
1123     b = l - 1;
1124 
1125     while ((i != ESCAPE) && (b <= strlen(comment))) {
1126 	attroff(A_STANDOUT);
1127 	attron(COLOR_PAIR(C_HEADER));
1128 
1129 	mvprintw(12, 54, spaces(80 - 54));
1130 	mvprintw(12, 54, comment);
1131 	mvprintw(12, 54 + b, "");
1132 
1133 	i = key_get();
1134 
1135 	// Ctrl-A (^A) or <Home>, move to beginning of comment field.
1136 	if (i == CTRL_A || i == KEY_HOME) {
1137 
1138 	    b = 0;
1139 
1140 	    // Ctrl-E (^E) or <End>, move to end of comment field, exit edit mode.
1141 	} else if (i == CTRL_E || i == KEY_END) {
1142 
1143 	    b = strlen(comment);
1144 	    break;
1145 
1146 	    // Left arrow, move cursor left one position.
1147 	} else if (i == KEY_LEFT) {
1148 
1149 	    if (b > 0)
1150 		b--;
1151 
1152 	    // Right arrow, move cursor right one position.
1153 	} else if (i == KEY_RIGHT) {
1154 
1155 	    if (b < strlen(comment) - 1) {
1156 		b++;
1157 	    } else
1158 		break;		/* stop edit */
1159 
1160 	    // <Delete>, erase character under the cursor,
1161 	    // shift all characters to the right of the cursor left one position.
1162 	} else if (i == KEY_DC) {
1163 
1164 	    l = strlen(comment);
1165 
1166 	    for (j = b; j <= l; j++) {
1167 		comment[j] = comment[j + 1];	/* move to left incl.\0 */
1168 	    }
1169 
1170 	    // <Backspace>, erase character to the left of the cursor,
1171 	    // shift all characters to the right of the cursor left one position.
1172 	} else if (i == KEY_BACKSPACE) {
1173 
1174 	    if (b > 0) {
1175 		b--;
1176 
1177 		l = strlen(comment);
1178 
1179 		for (j = b; j <= l; j++) {
1180 		    comment[j] = comment[j + 1];
1181 		}
1182 	    }
1183 
1184 	    // <Escape> not received.
1185 	} else if (i != ESCAPE) {
1186 
1187 	    // Promote lower case to upper case.
1188 	    if ((i >= 'a') && (i <= 'z'))
1189 		i = i - 32;
1190 
1191 	    // Accept printable characters.
1192 	    if ((i >= ' ') && (i <= 'Z')) {
1193 
1194 		if (strlen(comment) <= 24) {
1195 		    /* copy including trailing \0 */
1196 		    strncpy(comment2, comment + b, strlen(comment) - (b - 1));
1197 
1198 		    comment[b] = i;
1199 		    comment[b + 1] = '\0';
1200 		    strcat(comment, comment2);
1201 
1202 		    b++;
1203 		}
1204 
1205 	    } else if (i != 0)
1206 		i = ESCAPE;
1207 	}
1208     }
1209 
1210     attron(A_STANDOUT);
1211     refresh_comment();
1212 }
1213