1 /*
2  * Tlf - contest logging program for amateur radio operators
3  * Copyright (C) 2001-2002-2003-2004-2005 Rein Couperus <pa0r@amsat.org>
4  *               2014, 2016               Thomas Beierlein <tb@forth-ev.de>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 /* ------------------------------------------------------------------------
21 *    send the text buffer to the keyer  driver
22 *
23 ---------------------------------------------------------------------------*/
24 
25 
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include <glib.h>
32 
33 #include "callinput.h"
34 #include "displayit.h"
35 #include "globalvars.h"
36 #include "keystroke_names.h"
37 #include "lancode.h"
38 #include "netkeyer.h"
39 #include "tlf.h"
40 #include "tlf_curses.h"
41 #include "write_keyer.h"
42 
43 extern char ph_message[14][80];
44 
45 #define BUFSIZE   81
46 char buffer[BUFSIZE];
47 
48 /** shorten CW numbers */
short_number(char c)49 char short_number(char c) {
50     extern int shortqsonr;
51 
52     if (shortqsonr == SHORTCW) {
53 	if (c == '9')  return 'N';
54 	if (c == '0')  return 'T';
55     }
56     return c;
57 }
58 
59 /*
60  * Replace occurences of 'what' in 'buf' by 'rep'.
61  * The amount of bytes assigned to 'buf' is 'size'.
62  * This includes the terminating \0, i.e. max length of 'buf' is 'size'-1
63  * Replacements are done in-place, no other memory area than 'buf' is used.
64  * Maximum 'count' replacements are done.
65  *
66  */
replace_n(char * buf,int size,const char * what,const char * rep,int count)67 void replace_n(char *buf, int size, const char *what, const char *rep,
68 	       int count) {
69     int len = strlen(buf);
70     if (len > size - 1) {
71 	// input string already too long, don't touch it
72 	return;
73     }
74     int len_what = strlen(what);
75     if (len_what == 0) {
76 	return;
77     }
78 
79     int len_rep = strlen(rep);
80     int len_overlap = (len_rep < len_what ? len_rep : len_what);
81 
82     buf[size - 1] = 0; // ensure proper termination
83 
84     char *p = buf;
85     char *q;
86 
87     while (count-- > 0 && (q = strstr(p, what)) != NULL) {
88 	char *dst;
89 	const char *src;
90 	int n, overflow = 0;
91 
92 	strncpy(q, rep, len_overlap);
93 
94 	if (len_rep < len_what) {
95 	    //
96 	    //   ....WHATabcdef
97 	    //   ....REPTabcdef
98 	    //      q^  ||
99 	    //       dst^|
100 	    //        src^
101 	    //
102 	    //   ....REPabcdef
103 	    //
104 	    // shift rest down
105 	    dst = q + len_overlap;
106 	    src = q + len_what;
107 	    n = buf + len + 1 - src; // include terminating \0
108 	    memmove(dst, src, n);
109 
110 	    // result gets shorter
111 	    len -= len_what - len_rep;
112 	} else if (len_rep > len_what) {
113 	    //
114 	    //   ....Wabcdef
115 	    //   ....Rabcdef
116 	    //      q^| |
117 	    //     src^ |
118 	    //       dst^
119 	    //
120 	    //   ....R__abcdef
121 	    //   ....REPabcdef
122 	    //
123 	    // shift rest up
124 	    dst = q + len_rep;
125 	    src = q + len_overlap;
126 	    n = buf + len + 1 - src; // include terminating \0
127 	    if (dst + n - 1 >= buf + size - 1) {
128 		// would be longer than (size-1), shift only a part
129 		n = buf + size - 1 - dst;
130 		if (n <= 0) {
131 		    // even a part wont fit; no operation
132 		    n = 0;
133 		    overflow = 1;
134 		}
135 	    }
136 	    memmove(dst, src, n);
137 
138 	    // copy tail of rep
139 	    dst = q + len_overlap;
140 	    src = rep + len_overlap;
141 	    n = len_rep - len_what;
142 	    if (dst + n - 1 >= buf + size - 1) {
143 		// only a part of rep fits
144 		n = buf + size - 1 - dst;
145 		overflow = 1;
146 	    }
147 	    memcpy(dst, src, n);
148 
149 	    if (overflow) {
150 		break;
151 	    }
152 
153 	    // result gets longer
154 	    len += len_rep - len_what;
155 	}
156 	p = q + len_rep;
157     }
158 }
159 
replace_1(char * buf,int size,const char * what,const char * rep)160 void replace_1(char *buf, int size, const char *what, const char *rep) {
161     replace_n(buf, size, what, rep, 1);
162 }
163 
replace_all(char * buf,int size,const char * what,const char * rep)164 void replace_all(char *buf, int size, const char *what, const char *rep) {
165     replace_n(buf, size, what, rep, 999);
166 }
167 
ExpandMacro(void)168 void ExpandMacro(void) {
169 
170     extern char call[20];
171     extern char hiscall[20];
172     extern char hiscall_sent[];
173     extern char his_rst[];
174     extern char qsonrstr[5];
175     extern char comment[];
176     extern char lastqsonr[];
177     extern int early_started;
178     extern int noleadingzeros;
179     extern int lan_active;
180     extern int exchange_serial;
181 
182     int i;
183     static char comstr[BUFSIZE] = "";
184     static char qsonroutput[5] = "";
185     static char rst_out[4] = "";
186 
187 
188     strcpy(comstr, call);
189     comstr[strlen(call) - 1] = '\0'; // skip trailing \n
190     replace_all(buffer, BUFSIZE, "%", comstr);   /* mycall */
191 
192 
193     if (NULL != strstr(buffer, "@")) {
194 	char *p = hiscall + strlen(hiscall_sent);
195 	if (strlen(hiscall_sent) != 0) {
196 	    hiscall_sent[0] = '\0';
197 	    early_started = 0;
198 //                              sending_call = 0;
199 	}
200 	replace_1(buffer, BUFSIZE, "@", p);   /* his call, 1st occurence */
201 	replace_all(buffer, BUFSIZE, "@",
202 		    hiscall);   /* his call, further occurrences */
203     }
204 
205 
206     rst_out[0] = his_rst[0];
207     rst_out[1] = short_number(his_rst[1]);
208     rst_out[2] = short_number(his_rst[2]);
209     rst_out[3] = '\0';
210 
211     replace_all(buffer, BUFSIZE, "[", rst_out);   /* his RST */
212 
213 
214     if (NULL != strstr(buffer, "#")) {
215 	int leading_zeros = 0;
216 	int lead = 1;
217 	for (i = 0; i <= 4; i++) {
218 	    if (lead && qsonrstr[i] == '0') {
219 		++leading_zeros;
220 	    } else {
221 		lead = 0;
222 	    }
223 	    qsonroutput[i] = short_number(qsonrstr[i]);
224 	}
225 	qsonroutput[4] = '\0';
226 
227 	if (noleadingzeros != 1 && leading_zeros > 1) {
228 	    leading_zeros = 1;
229 	}
230 
231 	replace_all(buffer, BUFSIZE, "#",
232 		    qsonroutput + leading_zeros);   /* serial nr */
233 
234 	if ((lan_active == 1) && (exchange_serial == 1)) {
235 	    strncpy(lastqsonr, qsonrstr, 5);
236 	    send_lan_message(INCQSONUM, qsonrstr);
237 	}
238     }
239 
240 
241     replace_all(buffer, BUFSIZE, "!", comment);
242     if (trxmode == DIGIMODE)
243 	replace_all(buffer, BUFSIZE, "|", "\r");   /* CR */
244 }
245 
246 
sendbuf(void)247 void sendbuf(void) {
248     extern int trxmode;
249     extern int searchflg;
250     extern char termbuf[];
251     extern int cwkeyer;
252     extern int digikeyer;
253     extern int simulator;
254     extern int simulator_mode;
255     extern int sending_call;
256 
257     static char printlinebuffer[82] = "";
258 
259     printlinebuffer[0] = '\0';
260 
261     if ((trxmode == CWMODE && cwkeyer != NO_KEYER) ||
262 	    (trxmode == DIGIMODE && digikeyer != NO_KEYER)) {
263 
264 	ExpandMacro();
265 
266 	if ((strlen(buffer) + strlen(termbuf)) < 80) {
267 	    if (simulator == 0)
268 		strcat(termbuf, buffer);
269 //              if (sending_call == 1) {
270 //                      strcat (termbuf, " ");
271 //                      sending_call = 0;
272 //              }
273 	}
274 
275 	g_strlcpy(printlinebuffer, termbuf, sizeof(printlinebuffer));
276 
277 	if (searchflg == 0 && simulator == 0)
278 	    strncat(printlinebuffer, backgrnd_str,
279 		    80 - strlen(printlinebuffer));
280 	else {
281 	    int len = 40 - (int)strlen(printlinebuffer);
282 	    if (len > 0) {
283 		strncat(printlinebuffer, backgrnd_str, len);
284 	    }
285 	    if (strlen(printlinebuffer) > 45) {
286 		printlinebuffer[42] = '.';
287 		printlinebuffer[43] = '.';
288 		printlinebuffer[44] = '.';
289 		printlinebuffer[45] = '\0';
290 	    }
291 
292 	}
293 
294 	attron(COLOR_PAIR(C_LOG) | A_STANDOUT);
295 
296 	if (simulator_mode == 0) {
297 	    mvprintw(5, 0, printlinebuffer);
298 	    refreshp();
299 	}
300 	refreshp();
301 
302 	if (trxmode == DIGIMODE) {
303 
304 	    if (digikeyer == MFJ1278_KEYER) {
305 		int i = 0;
306 		for (i = 0; i < strlen(buffer); i++)
307 		    if (buffer[i] == '\n')
308 			buffer[i] = RETURN;
309 		for (i = 0; i < strlen(buffer); i++)
310 		    if (buffer[i] == 123)
311 			buffer[i] = 20;	/* ctrl-t */
312 		for (i = 0; i < strlen(buffer); i++)
313 		    if (buffer[i] == 125)
314 			buffer[i] = CTRL_R;	/* ctrl-r */
315 	    }
316 	    keyer_append(buffer);
317 	}
318 
319 	if (trxmode == CWMODE) {
320 
321 	    if (cwkeyer == MFJ1278_KEYER) {
322 		int i = 0;
323 		for (i = 0; i < strlen(buffer); i++)
324 		    if (buffer[i] == '\n')
325 			buffer[i] = RETURN;
326 	    }
327 	    keyer_append(buffer);
328 	}
329 
330 	if (simulator == 0) {
331 	    if (sending_call == 0)
332 		displayit();
333 	    refreshp();
334 	}
335 
336 	buffer[0] = '\0';
337     }
338 }
339 
340 
341 /** \brief send message
342  *
343  * Send the message via CW or DIGI mode, but only if not empty
344  * \param msg message to send
345  */
sendmessage(const char * msg)346 void sendmessage(const char *msg) {
347     if (strlen(msg) != 0) {
348 	g_strlcpy(buffer, msg, sizeof(buffer));
349 	sendbuf();
350     }
351 }
352 
send_standard_message(int msg)353 void send_standard_message(int msg) {
354     switch (trxmode) {
355 	case CWMODE:
356 	    sendmessage(message[msg]);
357 	    break;
358 	case DIGIMODE:
359 	    sendmessage(digi_message[msg]);
360 	    break;
361 	default:
362 	    if (msg < 14)
363 		play_file(ph_message[msg]);
364 	    break;
365     }
366 }
367 
send_keyer_message(int msg)368 void send_keyer_message(int msg) {
369     switch (trxmode) {
370 	case DIGIMODE:
371 	    sendmessage(digi_message[msg]);
372 	    break;
373 	default:
374 	    sendmessage(message[msg]);
375 	    break;
376     }
377 }
378