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