1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2014
3 //              David Freese, W1HKJ
4 //
5 // This file is part of flmsg
6 //
7 // flrig 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 3 of the License, or
10 // (at your option) any later version.
11 //
12 // flrig 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, see <http://www.gnu.org/licenses/>.
19 // ----------------------------------------------------------------------------
20 
21 #include <stdlib.h>
22 #include <iostream>
23 #include <fstream>
24 #include <cstring>
25 #include <ctime>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <stdio.h>
29 #include <errno.h>
30 
31 #include <FL/Fl.H>
32 #include <FL/Enumerations.H>
33 #include <FL/Fl_Window.H>
34 #include <FL/Fl_Button.H>
35 #include <FL/Fl_Group.H>
36 #include <FL/Fl_Sys_Menu_Bar.H>
37 #include <FL/x.H>
38 #include <FL/Fl_Help_Dialog.H>
39 #include <FL/Fl_Menu_Item.H>
40 #include <FL/Fl_File_Icon.H>
41 
42 #include "config.h"
43 #include "flmsg_config.h"
44 
45 #include "flmsg.h"
46 #include "templates.h"
47 #include "debug.h"
48 #include "util.h"
49 #include "gettext.h"
50 #include "flmsg_dialog.h"
51 #include "flinput2.h"
52 #include "date.h"
53 #include "calendar.h"
54 #include "icons.h"
55 #include "fileselect.h"
56 #include "wrap.h"
57 #include "status.h"
58 #include "parse_xml.h"
59 #include "arl_msgs.h"
60 
61 #ifdef WIN32
62 #  include "flmsgrc.h"
63 #  include "compat.h"
64 #  define dirent fl_dirent_no_thanks
65 #endif
66 
67 #include <FL/filename.H>
68 #include "dirent-check.h"
69 
70 #include <FL/x.H>
71 #include <FL/Fl_Pixmap.H>
72 #include <FL/Fl_Image.H>
73 
74 using namespace std;
75 
76 string base_rg_filename = "";
77 string def_rg_filename = "";
78 string def_rg_TemplateName = "";
79 
80 // Radiogram rgfields
81 
82 const char *s_prec[] = {
83 "ROUTINE", "WELFARE", "PRIORITY", "EMERGENCY",
84 "TEST ROUTINE", "TEST WELFARE", "TEST PRIORITY", "TEST EMERGENCY"};
85 const char precitems[] =
86 "ROUTINE|WELFARE|PRIORITY|EMERGENCY|\
87 TEST ROUTINE|TEST WELFARE|TEST PRIORITY|TEST EMERGENCY";
88 
89 const char *s_hx[] = {"", "HXA", "HXB", "HXC", "HXD", "HXE", "HXF", "HXG"};
90 const char hxitems[] = " |HXA|HXB|HXC|HXD|HXE|HXF|HXG";
91 
92 // compatibility fields required to read older data files
93 
94 string a_rg_nbr		= "<nbr:";		// 0.
95 string a_rg_prec	= "<prec:";		// 1.
96 string a_rg_hx		= "<hx:";		// 2.
97 string a_rg_d1		= "<d1:";		// 3.
98 string a_rg_t1		= "<t1:";		// 4.
99 string a_rg_dt2		= "<dt2:";		// 5.
100 string a_rg_dt3		= "<dt3:";		// 6.
101 string a_rg_to		= "<to:";		// 7.
102 string a_rg_phone	= "<tel:";		// 8.
103 string a_rg_opnote	= "<opn:";		// 9
104 string a_rg_msg		= "<msg:";		// 10.
105 string a_rg_sig		= "<sig:";		// 11.
106 string a_rg_opnote2	= "<op2:";		// 12
107 string a_rg_check	= "<ck:";		// 13.
108 string a_rg_station	= "<sta:";		// 14.
109 string a_rg_place	= "<org:";		// 15
110 string a_rg_orig	= "<ori:";		// 16
111 string a_rg_dlvd_to	= "<dlv:";		// 17
112 string a_rg_sent_to	= "<sto:";		// 18
113 string a_rg_snt_net	= "<snt:";		// 19
114 string a_rg_dt4		= "<dt4:";		// 20
115 string a_rg_rcv_fm	= "<rfm:";		// 21
116 string a_rg_rcv_net	= "<rnt:";		// 22
117 string a_rg_dt5		= "<dt5:";		// 23
118 string a_rg_svc		= "<svc:";		// 24
119 
120 FIELD argfields[] = {
121 { a_rg_nbr,		"", (void **)&txt_rg_nbr,	't' },	// 0
122 { a_rg_prec,	"0", (void **)&sel_rg_prec,	's' },	// 1
123 { a_rg_hx,		"", (void **)&txt_rg_hx,		't' },	// 2
124 { a_rg_d1,		"", (void **)&txt_rg_d1,		't' },	// 3
125 { a_rg_t1,		"", (void **)&txt_rg_t1,		't' },	// 4
126 { a_rg_dt2,		"", (void **)&txt_rg_dt2,	't' },	// 5
127 { a_rg_dt3,		"", (void **)&txt_rg_dt3,	't' },	// 6
128 { a_rg_to,		"", (void **)&txt_rg_to,		't' },	// 7
129 { a_rg_phone,	"", (void **)&txt_rg_phone,	't' },	// 8
130 { a_rg_opnote,	"", (void **)&txt_rg_opnote,	't' },	// 9
131 { a_rg_msg,		"", (void **)&txt_rg_msg,	'e' },	// 10
132 { a_rg_sig,		"", (void **)&txt_rg_sig,	't' },	// 11
133 { a_rg_opnote2,	"", (void **)&txt_rg_opnote2,'t' },	// 12
134 { a_rg_check,	"", (void **)&txt_rg_check,	't' },	// 13
135 { a_rg_station,	"", (void **)&txt_rg_station,'t' },	// 14
136 { a_rg_place,	"", (void **)&txt_rg_place,	't' },	// 15
137 { a_rg_orig,	"", (void **)&txt_rg_orig,	't' },	// 16
138 { a_rg_dlvd_to,	"", (void **)&txt_rg_dlvd_to,'t' },	// 17
139 { a_rg_sent_to,	"", (void **)&txt_rg_sent_to,'t' },	// 18
140 { a_rg_snt_net,	"", (void **)&txt_rg_snt_net,'t' },	// 19
141 { a_rg_dt4,		"", (void **)&txt_rg_dt4,	't' },	// 20
142 { a_rg_rcv_fm,	"", (void **)&txt_rg_rcv_fm,	't' },	// 21
143 { a_rg_rcv_net,	"", (void **)&txt_rg_rcv_net,'t' },	// 22
144 { a_rg_dt5,		"", (void **)&txt_rg_dt5,	't' },	// 23
145 { a_rg_svc,		"", (void **)&btn_rg_svc,	'b' }	// 24
146 };
147 
148 // new tag strings
149 
150 string _rg_nbr		= ":nbr:";		// 0.
151 string _rg_prec		= ":prec:";		// 1.
152 string _rg_hx		= ":hx:";		// 2.
153 string _rg_d1		= ":d1:";		// 3.
154 string _rg_t1		= ":t1:";		// 4.
155 string _rg_dt2		= ":dt2:";		// 5.
156 string _rg_dt3		= ":dt3:";		// 6.
157 string _rg_to		= ":to:";		// 7.
158 string _rg_phone	= ":tel:";		// 8.
159 string _rg_opnote	= ":opn:";		// 9
160 string _rg_msg		= ":msg:";		// 10.
161 string _rg_sig		= ":sig:";		// 11.
162 string _rg_opnote2	= ":op2:";		// 12
163 string _rg_check	= ":ck:";		// 13.
164 string _rg_station	= ":sta:";		// 14.
165 string _rg_place	= ":org:";		// 15
166 string _rg_orig		= ":ori:";		// 16
167 string _rg_dlvd_to	= ":dlv:";		// 17
168 string _rg_sent_to	= ":sto:";		// 18
169 string _rg_snt_net	= ":snt:";		// 19
170 string _rg_dt4		= ":dt4:";		// 20
171 string _rg_rcv_fm	= ":rfm:";		// 21
172 string _rg_rcv_net	= ":rnt:";		// 22
173 string _rg_dt5		= ":dt5:";		// 23
174 string _rg_svc		= ":svc:";		// 24
175 string _rg_standard	= ":std:";		// 25
176 
177 FIELD rgfields[] = {
178 { _rg_nbr,		"", (void **)&txt_rg_nbr,		't' },	// 0
179 { _rg_prec,		"0", (void **)&sel_rg_prec,		's' },	// 1
180 { _rg_hx,		"", (void **)&txt_rg_hx,		't' },	// 2
181 { _rg_d1,		"", (void **)&txt_rg_d1,		't' },	// 3
182 { _rg_t1,		"", (void **)&txt_rg_t1,		't' },	// 4
183 { _rg_dt2,		"", (void **)&txt_rg_dt2,		't' },	// 5
184 { _rg_dt3,		"", (void **)&txt_rg_dt3,		't' },	// 6
185 { _rg_to,		"", (void **)&txt_rg_to,		't' },	// 7
186 { _rg_phone,	"", (void **)&txt_rg_phone,		't' },	// 8
187 { _rg_opnote,	"", (void **)&txt_rg_opnote,	't' },	// 9
188 { _rg_msg,		"", (void **)&txt_rg_msg,		'e' },	// 10
189 { _rg_sig,		"", (void **)&txt_rg_sig,		't' },	// 11
190 { _rg_opnote2,	"", (void **)&txt_rg_opnote2,	't' },	// 12
191 { _rg_check,	"", (void **)&txt_rg_check,		't' },	// 13
192 { _rg_station,	"", (void **)&txt_rg_station,	't' },	// 14
193 { _rg_place,	"", (void **)&txt_rg_place,		't' },	// 15
194 { _rg_orig,		"", (void **)&txt_rg_orig,		't' },	// 16
195 { _rg_dlvd_to,	"", (void **)&txt_rg_dlvd_to,	't' },	// 17
196 { _rg_sent_to,	"", (void **)&txt_rg_sent_to,	't' },	// 18
197 { _rg_snt_net,	"", (void **)&txt_rg_snt_net,	't' },	// 19
198 { _rg_dt4,		"", (void **)&txt_rg_dt4,		't' },	// 20
199 { _rg_rcv_fm,	"", (void **)&txt_rg_rcv_fm,	't' },	// 21
200 { _rg_rcv_net,	"", (void **)&txt_rg_rcv_net,	't' },	// 22
201 { _rg_dt5,		"", (void **)&txt_rg_dt5,		't' },	// 23
202 { _rg_svc,		"F", (void **)&btn_rg_svc,		'b' },	// 24
203 { _rg_standard,	"T", (void **)&btn_rg_standard,	'B' }	// 25
204 };
205 
206 bool using_rg_template = false;
207 
208 int num_rgfields = sizeof(rgfields) / sizeof(FIELD);
209 
fld_nbr(string & fld)210 int fld_nbr(string &fld)
211 {
212 	for (int i = 0; i < num_rgfields; i++)
213 		if (fld == rgfields[i].f_type)
214 			return i;
215 	printf("err %s\n", fld.c_str());
216 	exit(1);
217 }
218 
219 //======================================================================
220 
cb_rgSetDate1()221 void cb_rgSetDate1()
222 {
223 	txt_rg_d1->value(szAbbrevDate());
224 }
225 
cb_rgSetTime1()226 void cb_rgSetTime1()
227 {
228 	txt_rg_t1->value(szTime(progStatus.UTC <= 1 ? 0 : 2));
229 }
230 
cb_rgSetDateTime2()231 void cb_rgSetDateTime2()
232 {
233 	txt_rg_dt2->value(szDateTime());
234 }
235 
cb_rgSetDateTime3()236 void cb_rgSetDateTime3()
237 {
238 	txt_rg_dt3->value(szDateTime());
239 }
240 
cb_rgSetDateTime4()241 void cb_rgSetDateTime4()
242 {
243 	txt_rg_dt4->value(szDateTime());
244 }
245 
cb_rgSetDateTime5()246 void cb_rgSetDateTime5()
247 {
248 	txt_rg_dt5->value(szDateTime());
249 }
250 
cb_rg_nbr(Fl_Widget * wdg)251 void cb_rg_nbr(Fl_Widget *wdg)
252 {
253 	Fl_Input2 *inp = (Fl_Input2 *)wdg;
254 	string s = inp->value();
255 	for (size_t n = 0; n < s.length(); n++)
256 		if (!isdigit(s[n])) s.erase(n,1);
257 	strip_leading_zeros(s);
258 	inp->value(s.c_str());
259 }
260 
261 static char valid_input[] = "0123456789/ ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
262 
cb_rg_filter_input(Fl_Widget * wdg)263 void cb_rg_filter_input(Fl_Widget *wdg)
264 {
265 	Fl_Input2 *inp = (Fl_Input2 *)wdg;
266 	int p = inp->position();
267 	string s = inp->value();
268 	ucase(s);
269 	for (size_t n = 0; n < s.length(); n++)
270 		if (strchr(valid_input, s[n]) == NULL)
271 			s.erase(n,1);
272 	inp->value(s.c_str());
273 	inp->position(p);
274 }
275 
clear_rgfields()276 void clear_rgfields()
277 {
278 	for (int i = 0; i < num_rgfields; i++) {
279 		switch (rgfields[i].w_type) {
280 			case 's':
281 				rgfields[i].f_data = "0";
282 				break;
283 			case 'b':
284 				rgfields[i].f_data = "F";
285 				break;
286 			case 'B':
287 				rgfields[i].f_data = "T";
288 				break;
289 			default:
290 				rgfields[i].f_data.clear();
291 		}
292 	}
293 }
294 
numeric(int n)295 string numeric(int n)
296 {
297 	static char snum[12];
298 	snprintf(snum, sizeof(snum), "%d", n);
299 	return snum;
300 }
301 
set_rg_choices()302 void set_rg_choices() {
303 	sel_rg_prec->clear();
304 	sel_rg_prec->add(precitems);
305 	sel_rg_prec->index(0);
306 }
307 
check_rgfields()308 bool check_rgfields()
309 {
310 	string temp;
311 	for (int i = 0; i < num_rgfields; i++) {
312 		if (rgfields[i].w == NULL) return false;
313 		if (rgfields[i].w_type == 'd') {
314 			if (rgfields[i].f_data != ((Fl_DateInput *)(*rgfields[i].w))->value())
315 				return true;
316 		} else if (rgfields[i].w_type == 't') {
317 			if (rgfields[i].f_data != ((Fl_Input2 *)(*rgfields[i].w))->value())
318 				return true;
319 		} else if (rgfields[i].w_type == 's') {
320 			int choice = ((Fl_ListBox *)(*rgfields[i].w))->index();
321 			if (rgfields[i].f_data != numeric(choice))
322 				return true;
323 		} else if (rgfields[i].w_type == 'e') {
324 			if (rgfields[i].f_data != ((FTextEdit *)(*rgfields[i].w))->buffer()->text())
325 				return true;
326 		} else if (rgfields[i].w_type == 'b') {
327 			temp = ((Fl_Button *)(*rgfields[i].w))->value() ? "T" : "F";
328 			if (rgfields[i].f_data != temp)
329 				return true;
330 		} else if (rgfields[i].w_type == 'B'){
331 			temp = ((Fl_Button *)(*rgfields[i].w))->value() ? "T" : "F";
332 			if (rgfields[i].f_data != temp)
333 				return true;
334 		}
335 	}
336 	return false;
337 }
338 
update_rgfields()339 void update_rgfields()
340 {
341 	for (int i = 0; i < num_rgfields; i++) {
342 		if (rgfields[i].w_type == 'd')
343 			rgfields[i].f_data = ((Fl_DateInput *)(*rgfields[i].w))->value();
344 		else if (rgfields[i].w_type == 't')
345 			rgfields[i].f_data = ((Fl_Input2 *)(*rgfields[i].w))->value();
346 		else if (rgfields[i].w_type == 's') {
347 			int choice = ((Fl_ListBox *)(*rgfields[i].w))->index();
348 			if (choice >= 0)
349 				rgfields[i].f_data = numeric(choice);
350 		} else if (rgfields[i].w_type == 'e')
351 			rgfields[i].f_data = ((FTextEdit *)(*rgfields[i].w))->buffer()->text();
352 		else if (rgfields[i].w_type == 'b')
353 			rgfields[i].f_data = ((Fl_Button *)(*rgfields[i].w))->value() ? "T" : "F";
354 		else if (rgfields[i].w_type == 'B')
355 			rgfields[i].f_data = ((Fl_Button *)(*rgfields[i].w))->value() ? "T" : "F";
356 	}
357 }
358 
clear_rg_form()359 void clear_rg_form()
360 {
361 	clear_rgfields();
362 
363 	if (progStatus.rgnbr_fname)
364 		txt_rg_nbr->value(progStatus.rgnbr.c_str());
365 	else
366 		txt_rg_nbr->value("");
367 
368 	for (int i = 1; i < num_rgfields; i++)
369 		if (rgfields[i].w_type == 'd')
370 			((Fl_DateInput *)(*rgfields[i].w))->value("");
371 		else if (rgfields[i].w_type == 't')
372 			((Fl_Input2 *)(*rgfields[i].w))->value("");
373 		else if (rgfields[i].w_type == 's')
374 			((Fl_ListBox *)(*rgfields[i].w))->index(0);
375 		else if (rgfields[i].w_type == 'e')
376 			((FTextEdit *)(*rgfields[i].w))->clear();
377 		else if (rgfields[i].w_type == 'b')
378 			((Fl_Button *)(*rgfields[i].w))->value(0);
379 		else if (rgfields[i].w_type == 'B')
380 			((Fl_Button *)(*rgfields[i].w))->value(1);
381 	update_rgfields();
382 }
383 
update_rg_form()384 void update_rg_form()
385 {
386 	for (int i = 0; i < num_rgfields; i++) {
387 		if (rgfields[i].w_type == 'd')
388 			((Fl_DateInput *)(*rgfields[i].w))->value(rgfields[i].f_data.c_str());
389 		else if (rgfields[i].w_type == 't')
390 			((Fl_Input2 *)(*rgfields[i].w))->value(rgfields[i].f_data.c_str());
391 		else if (rgfields[i].w_type == 's')
392 			((Fl_ListBox *)(*rgfields[i].w))->index(atoi(rgfields[i].f_data.c_str()));
393 		else if (rgfields[i].w_type == 'e') {
394 			((FTextEdit *)(*rgfields[i].w))->clear();
395 			((FTextEdit *)(*rgfields[i].w))->add(rgfields[i].f_data.c_str());
396 		} else if (rgfields[i].w_type == 'b')
397 			((Fl_Button *)(*rgfields[i].w))->value(rgfields[i].f_data == "T" ? 1 : 0);
398 		else if (rgfields[i].w_type == 'B')
399 			((Fl_Button *)(*rgfields[i].w))->value(rgfields[i].f_data == "T" ? 1 : 0);
400 	}
401 }
402 
make_rg_buffer(bool compress=false)403 void make_rg_buffer(bool compress = false)
404 {
405 	string mbuff;
406 	mbuff.clear();
407 	for (int i = 0; i < num_rgfields; i++)
408 		mbuff.append( lineout( rgfields[i].f_type, rgfields[i].f_data ) );
409 	if (compress) compress_maybe(mbuff);
410 	buffer.append(mbuff);
411 }
412 
read_rg_buffer(string data)413 void read_rg_buffer(string data)
414 {
415 	bool data_ok = false;
416 	clear_fields();
417 	read_header(data);
418 
419 	string temp;
420 	for (int i = 0; i < num_rgfields; i++) {
421 		temp = findstr(data, rgfields[i].f_type);
422 		if (!temp.empty()) rgfields[i].f_data = temp;
423 		if (!rgfields[i].f_data.empty()) data_ok = true;
424 	}
425 	if (!data_ok)
426 		for (int i = 0; i < num_rgfields; i++)
427 			rgfields[i].f_data = findstr(data, argfields[i].f_type);
428 
429 	update_rg_form();
430 }
431 
cb_rg_new()432 void cb_rg_new()
433 {
434 	if (check_rgfields()) {
435 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 1) {
436 			update_header(CHANGED);
437 			cb_rg_save();
438 		}
439 	}
440 	clear_rg_form();
441 	clear_header();
442 	def_rg_filename = ICS_msg_dir;
443 	def_rg_filename.append("new").append(RGFILE_EXT);
444 	using_rg_template = false;
445 	show_filename(def_rg_filename);
446 }
447 
cb_rg_import()448 void cb_rg_import()
449 {
450 	string def_rg_filename = ICS_dir;
451 	def_rg_filename.append("DEFAULT.XML");
452 	const char *p = FSEL::select(
453 		"Open Qforms xml file",
454 		"Qforms xml\t*.{xml,XML}",
455 		def_rg_filename.c_str());
456 	if (p){
457 		clear_rg_form();
458 		qform_rg_import(p);
459 		using_rg_template = false;
460 	}
461 }
462 
cb_rg_export()463 void cb_rg_export()
464 {
465 	string exp_rgFileName = ICS_dir;
466 	exp_rgFileName.append(base_rg_filename);
467 	exp_rgFileName.append(".XML");
468 	const char *p = FSEL::saveas(
469 			"Open Qforms xml file",
470 			"Qforms xml\t*.{xml,XML}",
471 			exp_rgFileName.c_str());
472 	if (p) {
473 		const char *pext = fl_filename_ext(p);
474 		exp_rgFileName = p;
475 		if (strlen(pext) == 0) exp_rgFileName.append(".XML");
476 		qform_rg_export(exp_rgFileName);
477 	}
478 }
479 
cb_rg_wrap_import(string wrapfilename,string inpbuffer)480 void cb_rg_wrap_import(string wrapfilename, string inpbuffer)
481 {
482 	clear_rg_form();
483 	read_rg_buffer(inpbuffer);
484 	def_rg_filename = ICS_msg_dir;
485 	def_rg_filename.append(wrapfilename);
486 	show_filename(def_rg_filename);
487 	using_rg_template = false;
488 }
489 
eval_rg_fsize()490 int eval_rg_fsize()
491 {
492 	Ccrc16 chksum;
493 	evalstr.assign("[WRAP:beg][WRAP:lf][WRAP:fn ");
494 	evalstr.append(base_rg_filename).append("]");
495 	update_rgfields();
496 	update_header(FROM);
497 	evalstr.append(header("<radiogram>"));
498 	buffer.clear();
499 	make_rg_buffer(true);
500 	if (buffer.empty()) return 0;
501 	evalstr.append( buffer );
502 	evalstr.append("[WRAP:chksum ").append(chksum.scrc16(evalstr)).append("][WRAP:end]");
503 	return evalstr.length();
504 }
505 
cb_rg_wrap_export()506 void cb_rg_wrap_export()
507 {
508 	if (btn_rg_check->labelcolor() == FL_RED)
509 		cb_rg_check();
510 
511 	if (check_rgfields()) {
512 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 0)
513 			return;
514 		update_header(CHANGED);
515 	}
516 	update_rgfields();
517 
518 	if (base_rg_filename == string("new").append(RGFILE_EXT) ||
519 		base_rg_filename == string("default").append(RGFILE_EXT) )
520 		if (!cb_rg_save_as()) return;
521 
522 	string wrapfilename = WRAP_send_dir;
523 	wrapfilename.append(base_rg_filename);
524 	wrapfilename.append(WRAP_EXT);
525 	const char *p = FSEL::saveas(
526 			"Save as wrapped radiogram file",
527 			"Wrap file\t*.{wrap,WRAP}",
528 			wrapfilename.c_str());
529 	if (p) {
530 		if (btn_rg_check->labelcolor() == FL_RED)
531 			cb_rg_check();
532 		string pext = fl_filename_ext(p);
533 		wrapfilename = p;
534 
535 		update_header(FROM);
536 		buffer.assign(header("<radiogram>"));
537 		make_rg_buffer(true);
538 		export_wrapfile(base_rg_filename, wrapfilename, buffer, pext != WRAP_EXT);
539 
540 		buffer.assign(header("<radiogram>"));
541 		make_rg_buffer(false);
542 		write_rg(def_rg_filename);
543 	}
544 }
545 
cb_rg_wrap_autosend()546 void cb_rg_wrap_autosend()
547 {
548 	if (btn_rg_check->labelcolor() == FL_RED)
549 		cb_rg_check();
550 
551 	if (check_rgfields()) {
552 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 0)
553 			return;
554 		update_header(CHANGED);
555 	}
556 	update_rgfields();
557 
558 	if (base_rg_filename == string("new").append(RGFILE_EXT) ||
559 		base_rg_filename == string("default").append(RGFILE_EXT) )
560 		if (!cb_rg_save_as()) return;
561 
562 	update_header(FROM);
563 	buffer.assign(header("<radiogram>"));
564 	make_rg_buffer(true);
565 	xfr_via_socket(base_rg_filename, buffer);
566 
567 	buffer.assign(header("<radiogram>"));
568 	make_rg_buffer(false);
569 	write_rg(def_rg_filename);
570 }
571 
cb_rg_load_template()572 void cb_rg_load_template()
573 {
574 	string def_rg_filename = def_rg_TemplateName;
575 	const char *p = FSEL::select(
576 			"Open template file",
577 			string("Template file\t*").append(RGTEMP_EXT).c_str(),
578 			def_rg_filename.c_str());
579 	if (p) {
580 		clear_rg_form();
581 		read_data_file(p);
582 		def_rg_TemplateName = p;
583 		show_filename(def_rg_TemplateName);
584 		using_rg_template = true;
585 	}
586 }
587 
cb_rg_save_template()588 void cb_rg_save_template()
589 {
590 	if (!using_rg_template) {
591 		cb_rg_save_as_template();
592 		return;
593 	}
594 	string def_rg_filename = def_rg_TemplateName;
595 	const char *p = FSEL::saveas(
596 			"Save template file",
597 			string("Template file\t*").append(RGTEMP_EXT).c_str(),
598 			def_rg_filename.c_str());
599 	if (p) {
600 		update_header(CHANGED);
601 		update_rgfields();
602 		buffer.assign(header("<radiogram>"));
603 		make_rg_buffer();
604 		write_rg(p);
605 	}
606 }
607 
cb_rg_save_as_template()608 void cb_rg_save_as_template()
609 {
610 	string def_rg_filename = def_rg_TemplateName;
611 	const char *p = FSEL::saveas(
612 			"Save as template file",
613 			string("Template file\t*").append(RGTEMP_EXT).c_str(),
614 			def_rg_filename.c_str());
615 	if (p) {
616 		const char *pext = fl_filename_ext(p);
617 		def_rg_TemplateName = p;
618 		if (strlen(pext) == 0) def_rg_TemplateName.append(RGTEMP_EXT);
619 		remove_spaces_from_filename(def_rg_TemplateName);
620 
621 		clear_header();
622 		update_header(CHANGED);
623 		buffer.assign(header("<radiogram>"));
624 		make_rg_buffer();
625 		write_rg(def_rg_TemplateName);
626 
627 		show_filename(def_rg_TemplateName);
628 		using_rg_template = true;
629 	}
630 }
631 
cb_rg_open()632 void cb_rg_open()
633 {
634 	const char *p = FSEL::select(
635 			_("Open data file"),
636 			string("radiogram\t*").append(RGFILE_EXT).c_str(),
637 			def_rg_filename.c_str());
638 	if (!p) return;
639 	if (strlen(p) == 0) return;
640 	clear_rg_form();
641 	read_data_file(p);
642 	using_rg_template = false;
643 	def_rg_filename = p;
644 	show_filename(def_rg_filename);
645 }
646 
write_rg(string s)647 void write_rg(string s)
648 {
649 	FILE *rgfile = fopen(s.c_str(), "w");
650 	if (!rgfile) return;
651 
652 	fwrite(buffer.c_str(), buffer.length(), 1, rgfile);
653 	fclose(rgfile);
654 }
655 
cb_rg_save_as()656 bool cb_rg_save_as()
657 {
658 	const char *p;
659 	string newfilename;
660 	string name = named_file();
661 
662 	if (!name.empty()) {
663 		name.append(RGFILE_EXT);
664 		newfilename = ICS_msg_dir;
665 		newfilename.append(name);
666 	} else
667 		newfilename = def_rg_filename;
668 	p = FSEL::saveas(
669 			_("Save data file"),
670 			string("radiogram\t*").append(RGFILE_EXT).c_str(),
671 			newfilename.c_str());
672 
673 	if (!p) return false;
674 	if (strlen(p) == 0) return false;
675 
676 	if (progStatus.rgnbr_fname) {
677 		int n = atoi(progStatus.rgnbr.c_str());
678 		n++;
679 		char szn[12];
680 		snprintf(szn, sizeof(szn), "%d", n);
681 		progStatus.rgnbr = szn;
682 		txt_rgnbr->value(szn);
683 		txt_rgnbr->redraw();
684 	} else if (progStatus.sernbr_fname)
685 		update_sernbr();
686 
687 	const char *pext = fl_filename_ext(p);
688 	def_rg_filename = p;
689 	if (strlen(pext) == 0) def_rg_filename.append(RGFILE_EXT);
690 
691 	remove_spaces_from_filename(def_rg_filename);
692 
693 	update_header(NEW);
694 	update_rgfields();
695 	buffer.assign(header("<radiogram>"));
696 	make_rg_buffer();
697 	write_rg(def_rg_filename);
698 
699 	using_rg_template = false;
700 	show_filename(def_rg_filename);
701 	return true;
702 }
703 
cb_rg_save()704 void cb_rg_save()
705 {
706 	if (base_rg_filename == string("new").append(RGFILE_EXT) ||
707 		base_rg_filename == string("default").append(RGFILE_EXT) ||
708 		using_rg_template == true) {
709 		cb_rg_save_as();
710 		return;
711 	}
712 
713 	if (check_rgfields()) update_header(CHANGED);
714 	update_rgfields();
715 	buffer.assign(header("<radiogram>"));
716 	make_rg_buffer();
717 	write_rg(def_rg_filename);
718 	using_rg_template = false;
719 }
720 
721 const char *punctuation[] = {
722 ". ", " X ",
723 ",", " COMMA ",
724 "?", " QUERY ",
725 "\\", " BACKSLASH ",
726 "://", " COLON SLASH SLASH ",
727 "~", " TILDE ",
728 "_", " UNDERSCORE ",
729 "@", " AT ",
730 "#", " POUNDSIGN ",
731 "\"", " QUOTE ",
732 "\'", "",
733  0, 0 };
734 
cb_rg_check()735 void cb_rg_check()
736 {
737 	string temp = txt_rg_msg->buffer()->text();
738 	if (temp.empty()) {
739 		txt_rg_check->value("");
740 		btn_rg_check->labelcolor(FL_BLACK);
741 		btn_rg_check->redraw_label();
742 		return;
743 	}
744 
745 	size_t pos = string::npos;
746 
747 	if (btn_rg_standard->value()) {
748 // convert to uppercase
749 		for (size_t n = 0; n < temp.length(); n++)
750 			temp[n] = toupper(temp[n]);
751 
752 		strip_lfs(temp);
753 // remove trailing period
754 		if (temp[temp.length()-1] == '.') temp.erase(temp.length()-1,1);
755 		// convert punctuation
756 		for (int n = 0; punctuation[n]; n += 2)
757 			while ((pos = temp.find(punctuation[n])) != string::npos)
758 				temp.replace(pos, strlen(punctuation[n]), punctuation[n+1]);
759 //convert embedded periods
760 		while ((pos = temp.find(".")) != string::npos)
761 			if (isdigit(temp[pos-1]) || isdigit(temp[pos+1]))
762 				temp[pos] = 'R';
763 			else
764 				temp.replace(pos, 1, " DOT ");
765 	}
766 
767 // remove any user inserted end-of-lines
768 	while ((pos = temp.find('\n')) != string::npos) temp[pos] = ' ';
769 
770 // only single spaces no trailing spaces, no leading spaces
771 	while ((pos = temp.find("  ")) != string::npos) temp.erase(pos,1);
772 	while (temp[temp.length() -1] == ' ') temp.erase(temp.length()-1, 1);
773 	if (temp[0] == ' ') temp.erase(0,1);
774 
775 // count number of words in textdef_rg_filename
776 	int numwords = 1;
777 	if (temp.length()) {
778 		pos = 0;
779 		while ((pos = temp.find(" ", pos + 1)) != string::npos) numwords++;
780 	}
781 
782 // no more than specified # words to a line
783 	if (numwords > progStatus.wpl) {
784 		int wc = numwords;
785 		size_t pos = 0;
786 		while (wc > progStatus.wpl) {
787 			for (int i = 0; i < progStatus.wpl; i++) pos = temp.find(' ', pos + 1);
788 			temp[pos] = '\n';
789 			wc -= progStatus.wpl;
790 		}
791 	}
792 	// insert trailing end-of-line
793 	temp += '\n';
794 
795 	// return converted text to editor
796 	txt_rg_msg->clear();
797 	txt_rg_msg->addstr(temp.c_str());
798 
799 	char snum[15];
800 	snprintf(snum, sizeof(snum), "%s%d",
801 		temp.find("ARL") != string::npos ? "ARL " : "",
802 		numwords);
803 	txt_rg_check->value(snum);
804 	update_rgfields();
805 	btn_rg_check->labelcolor(FL_BLACK);
806 	btn_rg_check->redraw_label();
807 }
808 
cb_rg_html()809 void cb_rg_html()
810 {
811 	string rgname;
812 	string html_text;
813 	unsigned int nbr;
814 	rgname = ICS_dir;
815 	rgname.append("radiogram.html");
816 
817 	update_rgfields();
818 	cb_rg_check();
819 	string form;
820 	if (progStatus.rri) form = rri_html_template;
821 	else form = rg_html_template;
822 
823 	for (int i = 0; i < num_rgfields; i++) {
824 		if (rgfields[i].f_type == _rg_prec) {
825 			sscanf(rgfields[i].f_data.c_str(), "%u", &nbr);
826 			if (nbr >= 0 && nbr < (sizeof(s_prec) / sizeof(*s_prec)))
827 				html_text = s_prec[nbr];
828 			else
829 				html_text = s_prec[0];
830 			replacestr( form, rgfields[i].f_type, html_text );
831 		} else if (rgfields[i].w_type == 'b') {
832 			replacestr( form, rgfields[i].f_type, rgfields[i].f_data == "T" ? yes : no);
833 		} else
834 			replacestr( form, rgfields[i].f_type, rgfields[i].f_data );
835 	}
836 
837 	string rxstr = "";
838 	rxstr.append(progStatus.my_call).append(" ").append(progStatus.my_tel);
839 	rxstr.append("\n").append(progStatus.my_name);
840 	rxstr.append("\n").append(progStatus.my_addr);
841 	rxstr.append("\n").append(progStatus.my_city);
842 	html_text = ":rx:";
843 	replacestr( form, html_text, rxstr);
844 
845 	html_text = ":exp:";
846 	string arlmsgs = "";
847 	if (progStatus.arl_desc)
848 		arlmsgs = expand_arl(rgfields[10].f_data);
849 	replacestr( form, html_text, arlmsgs);
850 
851 	FILE *rgfile = fopen(rgname.c_str(), "w");
852 	fprintf(rgfile,"%s", form.c_str());
853 	fclose(rgfile);
854 
855 	open_url(rgname.c_str());
856 }
857 
cb_rg_html_fcopy()858 void cb_rg_html_fcopy()
859 {
860 	string rgname;
861 	string MSG = "";
862 	string html_text;
863 	unsigned int nbr;
864 	rgname = ICS_dir;
865 	rgname.append("rg_file_copy.html");
866 
867 	update_rgfields();
868 	cb_rg_check();
869 	string form;
870 	if (progStatus.rri) form = rri_html_fcopy_template;
871 	else form = rg_html_fcopy_template;
872 
873 	for (int i = 0; i < num_rgfields; i++) {
874 		if (rgfields[i].f_type == _rg_prec) {
875 			sscanf(rgfields[i].f_data.c_str(), "%u", &nbr);
876 			if (nbr >= 0 && nbr < (sizeof(s_prec) / sizeof(*s_prec)))
877 				html_text = s_prec[nbr];
878 			else
879 				html_text = s_prec[0];
880 			replacestr( form, rgfields[i].f_type, html_text);
881 		} else if (rgfields[i].w_type == 'b') {
882 			replacestr( form, rgfields[i].f_type, rgfields[i].f_data == "T" ? yes : no);
883 		} else
884 			replacestr( form, rgfields[i].f_type, rgfields[i].f_data );
885 	}
886 
887 	string rxstr = "";
888 	rxstr.append(progStatus.my_call).append(" ").append(progStatus.my_tel);
889 	rxstr.append("\n").append(progStatus.my_name);
890 	rxstr.append("\n").append(progStatus.my_addr);
891 	rxstr.append("\n").append(progStatus.my_city);
892 	html_text = ":rx:";
893 	replacestr( form, html_text, rxstr);
894 
895 	FILE *rgfile = fopen(rgname.c_str(), "w");
896 	fprintf(rgfile,"%s", form.c_str());
897 	fclose(rgfile);
898 
899 	open_url(rgname.c_str());
900 }
901 
cb_rg_textout()902 void cb_rg_textout()
903 {
904 	string rgname;
905 	string lines;
906 	string str;
907 	unsigned int nbr = 0;
908 	rgname = ICS_dir;
909 	rgname.append("radiogram.txt");
910 
911 	update_rgfields();
912 	cb_rg_check();
913 
914 	string form;
915 	if (progStatus.rri) form = rri_txt_template;
916 	else form = rg_txt_template;
917 
918 	for (int i = 0; i < num_rgfields; i++) {
919 		str.clear();
920 		if (rgfields[i].f_type == _rg_prec) {
921 			sscanf(rgfields[i].f_data.c_str(), "%u", &nbr);
922 			if (nbr < 0) nbr = 0;
923 			if (nbr >= sizeof(s_prec)/sizeof(*s_prec)) nbr = 0;
924 			str = s_prec[nbr];
925 			if (str.find("TEST") != string::npos) {				// test message
926 				if (str.find("EMERGENCY") == string::npos)
927 					str = str.substr(0, 6);
928 			} else {
929 				if (str.find("EMERGENCY") == string::npos)
930 					str = str[0];
931 			}
932 			replacestr( form, rgfields[i].f_type, str);
933 		} else if (rgfields[i].w_type == 'e' || rgfields[i].w_type == 't') {
934 			if (rgfields[i].f_type == _rg_opnote || rgfields[i].f_type == _rg_opnote2) {
935 			    if (!rgfields[i].f_data.empty())
936 					str.append("\nOPNOTE ").append(rgfields[i].f_data);
937 			} else if (rgfields[i].f_type == _rg_hx && !rgfields[i].f_data.empty()) {
938 				str = " ";
939 				str.append(rgfields[i].f_data);
940 			} else {
941 				str = rgfields[i].f_data;
942 				strip_lfs(str);
943 			}
944 			replacestr( form, rgfields[i].f_type, str );
945 		} else
946 			replacestr( form, rgfields[i].f_type, rgfields[i].f_data );
947 	}
948 
949 	FILE *rgfile = fopen(rgname.c_str(), "w");
950 	fprintf(rgfile,"%s", form.c_str());
951 	fclose(rgfile);
952 	open_url(rgname.c_str());
953 }
954 
955