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 
60 #ifdef WIN32
61 #  include "flmsgrc.h"
62 #  include "compat.h"
63 #  define dirent fl_dirent_no_thanks
64 #endif
65 
66 #include <FL/filename.H>
67 #include "dirent-check.h"
68 
69 #include <FL/x.H>
70 #include <FL/Fl_Pixmap.H>
71 #include <FL/Fl_Image.H>
72 
73 using namespace std;
74 
75 // ---------------------------------------------------------------------
76 // ics 214 field variables and template variables
77 // ---------------------------------------------------------------------
78 
79 string ics214_incident					= ":inc:";
80 string ics214_date						= ":dat:";
81 string ics214_time						= ":tim:";
82 string ics214_op_period					= ":opp:";
83 string ics214_unit_name					= ":und:";
84 string ics214_unit_leader				= ":unl:";
85 
86 string ics214_roster_name				= ":nam[n]:"; // 14
87 string ics214_roster_position			= ":pos[n]:";
88 string ics214_roster_home_base			= ":hom[n]:";
89 
90 string ics214_activity_time				= ":at[n]:"; // 16
91 string ics214_activity_event			= ":ev[n]:";
92 
93 string ics214_prepared_by				= ":pre:";
94 
95 string s214_incident;
96 string s214_date;
97 string s214_time;
98 string s214_op_period;
99 string s214_unit_name;
100 string s214_unit_leader;
101 
102 string s214_roster_name[16];
103 string s214_roster_position[16];
104 string s214_roster_home_base[16];
105 string s214_activity_time[16];
106 string s214_activity_event[16];
107 
108 string s214_prepared_by;
109 
110 // =====================================================================
111 
112 string buff214;
113 string def_214_filename = "";
114 string base_214_filename = "";
115 string def_214_TemplateName = "";
116 
117 bool using_ics214_template = false;
118 
cb_214_set_date()119 void cb_214_set_date()
120 {
121 	txt_214_date->value(szDate(progStatus.dtformat));
122 }
123 
cb_214_set_time()124 void cb_214_set_time()
125 {
126 	txt_214_time->value(szTime(progStatus.UTC));
127 }
128 
clear_214fields()129 void clear_214fields()
130 {
131 	s214_incident.clear();
132 	s214_date.clear();
133 	s214_time.clear();
134 	s214_op_period.clear();
135 	s214_unit_name.clear();
136 	s214_unit_leader.clear();
137 	s214_prepared_by.clear();
138 
139 	for (int i = 0; i < 16; i++) {
140 		s214_roster_name[i].clear();
141 		s214_roster_position[i].clear();
142 		s214_roster_home_base[i].clear();
143 		s214_activity_time[i].clear();
144 		s214_activity_event[i].clear();
145 	}
146 }
147 
check_214fields()148 bool check_214fields()
149 {
150 	if (s214_incident != txt_214_incident->value())
151 		return true;
152 	if (s214_date != txt_214_date->value())
153 		return true;
154 	if (s214_time != txt_214_time->value())
155 		return true;
156 	if (s214_op_period != txt_214_op_period->value())
157 		return true;
158 	if (s214_unit_name != txt_214_unit_name->value())
159 		return true;
160 	if (s214_unit_leader != txt_214_unit_leader->value())
161 		return true;
162 	if (s214_prepared_by != txt_214_prepared_by->value())
163 		return true;
164 
165 	for (int i = 0; i < 16; i++) {
166 		if (s214_roster_name[i] != txt_214_roster_name[i]->value())
167 			return true;
168 		if (s214_roster_position[i] != txt_214_roster_position[i]->value())
169 			return true;
170 		if (s214_roster_home_base[i] != txt_214_roster_home_base[i]->value())
171 			return true;
172 		if (s214_activity_time[i] != txt_214_activity_time[i]->value())
173 			return true;
174 		if (s214_activity_event[i] != txt_214_activity_event[i]->value())
175 			return true;
176 	}
177 	return false;
178 }
179 
update_214fields()180 void update_214fields()
181 {
182 	s214_incident = txt_214_incident->value();
183 	s214_date = txt_214_date->value();
184 	s214_time = txt_214_time->value();
185 	s214_op_period = txt_214_op_period->value();
186 	s214_unit_name = txt_214_unit_name->value();
187 	s214_unit_leader = txt_214_unit_leader->value();
188 	s214_prepared_by = txt_214_prepared_by->value();
189 
190 	for (int i = 0; i < 16; i++) {
191 		s214_roster_name[i] = txt_214_roster_name[i]->value();
192 		s214_roster_position[i] = txt_214_roster_position[i]->value();
193 		s214_roster_home_base[i] = txt_214_roster_home_base[i]->value();
194 		s214_activity_time[i] = txt_214_activity_time[i]->value();
195 		s214_activity_event[i] = txt_214_activity_event[i]->value();
196 	}
197 }
198 
update_214form()199 void update_214form()
200 {
201 	txt_214_incident->value(s214_incident.c_str());
202 	txt_214_date->value(s214_date.c_str());
203 	txt_214_time->value(s214_time.c_str());
204 	txt_214_op_period->value(s214_op_period.c_str());
205 	txt_214_unit_name->value(s214_unit_name.c_str());
206 	txt_214_unit_leader->value(s214_unit_leader.c_str());
207 	txt_214_prepared_by->value(s214_prepared_by.c_str());
208 
209 	for (int i = 0; i < 16; i++) {
210 		txt_214_roster_name[i]->value(s214_roster_name[i].c_str());
211 		txt_214_roster_position[i]->value(s214_roster_position[i].c_str());
212 		txt_214_roster_home_base[i]->value(s214_roster_home_base[i].c_str());
213 		txt_214_activity_time[i]->value(s214_activity_time[i].c_str());
214 		txt_214_activity_event[i]->value(s214_activity_event[i].c_str());
215 	}
216 }
217 
clear_214_form()218 void clear_214_form()
219 {
220 	clear_214fields();
221 	update_214form();
222 }
223 
ics_nn(string & subst,int n)224 string &ics_nn(string & subst, int n)
225 {
226 	static string garbage = "#$^*!";
227 	static string ics;
228 	ics.clear();
229 	ics = subst;
230 	size_t pos = ics.find("[");
231 	if (pos == string::npos) return garbage;
232 	pos++;
233 	if (n < 10)
234 		ics[pos] = '0' + n;
235 	else {
236 		ics[pos] = '1';
237 		ics[pos+1] = '0' + n % 10;
238 		ics[pos+2] = ']';
239 		ics += ':';
240 	}
241 	return ics;
242 }
243 
make_buff214(bool compress=false)244 void make_buff214(bool compress = false)
245 {
246 	string mbuff;
247 	mbuff.clear();
248 	mbuff.append( lineout( ics214_incident, s214_incident ) );
249 	mbuff.append( lineout( ics214_date, s214_date ) );
250 	mbuff.append( lineout( ics214_time, s214_time ) );
251 	mbuff.append( lineout( ics214_op_period, s214_op_period ) );
252 	mbuff.append( lineout( ics214_unit_name, s214_unit_name) );
253 	mbuff.append( lineout( ics214_unit_leader, s214_unit_leader) );
254 
255 	mbuff.append( lineout( ics214_prepared_by, s214_prepared_by ) );
256 
257 	for (int i = 0; i < 16; i++) {
258 		mbuff.append( lineout( ics_nn( ics214_roster_name, i ), s214_roster_name[i] ) );
259 		mbuff.append( lineout( ics_nn( ics214_roster_position, i ), s214_roster_position[i] ) );
260 		mbuff.append( lineout( ics_nn( ics214_roster_home_base, i ), s214_roster_home_base[i] ) );
261 		mbuff.append( lineout( ics_nn( ics214_activity_time, i ), s214_activity_time[i] ) );
262 		mbuff.append( lineout( ics_nn( ics214_activity_event, i ), s214_activity_event[i] ) );
263 	}
264 	if (compress) compress_maybe(mbuff);
265 	buff214.append(mbuff);
266 }
267 
read_214_buffer(string data)268 void read_214_buffer(string data)
269 {
270 	clear_214fields();
271 	read_header(data);
272 
273 	s214_incident = findstr(data, ics214_incident);
274 	s214_date = findstr(data, ics214_date);
275 	s214_time = findstr(data, ics214_time);
276 	s214_op_period = findstr(data, ics214_op_period);
277 	s214_unit_name = findstr(data, ics214_unit_name);
278 	s214_unit_leader = findstr(data, ics214_unit_leader);
279 	s214_prepared_by = findstr(data, ics214_prepared_by);
280 
281 	for (int i = 0; i < 16; i++) {
282 		s214_roster_name[i]      = findstr(data, ics_nn( ics214_roster_name, i ) );
283 		s214_roster_position[i]  = findstr(data, ics_nn( ics214_roster_position, i ) );
284 		s214_roster_home_base[i] = findstr(data, ics_nn( ics214_roster_home_base, i ) );
285 		s214_activity_time[i]    = findstr(data, ics_nn( ics214_activity_time, i ) );
286 		s214_activity_event[i]   = findstr(data, ics_nn( ics214_activity_event, i ) );
287 	}
288 
289 	update_214form();
290 }
291 
cb_214_new()292 void cb_214_new()
293 {
294 	if (check_214fields()) {
295 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 1) {
296 			update_header(CHANGED);
297 			cb_214_save();
298 		}
299 	}
300 	clear_214_form();
301 	clear_header();
302 	def_214_filename = ICS_msg_dir;
303 	def_214_filename.append("new").append(F214_EXT);
304 	show_filename(def_214_filename);
305 	using_ics214_template = false;
306 }
307 
cb_214_import()308 void cb_214_import()
309 {
310 	fl_alert2("Not implemented");
311 }
312 
cb_214_export()313 void cb_214_export()
314 {
315 	fl_alert2("Not implemented");
316 }
317 
cb_214_wrap_import(string wrapfilename,string inpbuffer)318 void cb_214_wrap_import(string wrapfilename, string inpbuffer)
319 {
320 	clear_214_form();
321 	read_214_buffer(inpbuffer);
322 	def_214_filename = ICS_msg_dir;
323 	def_214_filename.append(wrapfilename);
324 	show_filename(def_214_filename);
325 	using_ics214_template = false;
326 }
327 
eval_214_fsize()328 int eval_214_fsize()
329 {
330 	Ccrc16 chksum;
331 	evalstr.assign("[WRAP:beg][WRAP:lf][WRAP:fn ");
332 	evalstr.append(base_214_filename).append("]");
333 	update_214fields();
334 	update_header(FROM);
335 	evalstr.append(header("<ics214>"));
336 	buff214.clear();
337 	make_buff214(true);
338 	if (buff214.empty()) return 0;
339 	compress_maybe( buff214 );
340 	evalstr.append( buff214 );
341 	evalstr.append("[WRAP:chksum ").append(chksum.scrc16(evalstr)).append("][WRAP:end]");
342 	return evalstr.length();
343 }
344 
cb_214_wrap_export()345 void cb_214_wrap_export()
346 {
347 	if (check_214fields()) {
348 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 0)
349 			return;
350 		update_header(CHANGED);
351 	}
352 	update_214fields();
353 
354 	if (base_214_filename == string("new").append(F214_EXT) ||
355 		base_214_filename == string("default").append(F214_EXT) )
356 		if (!cb_214_save_as()) return;
357 
358 	string wrapfilename = WRAP_send_dir;
359 	wrapfilename.append(base_214_filename);
360 	wrapfilename.append(".wrap");
361 	const char *p = FSEL::saveas(
362 			"Save as wrap file",
363 			"Wrap file\t*.{wrap,WRAP}",
364 			wrapfilename.c_str());
365 	if (p) {
366 		string pext = fl_filename_ext(p);
367 		wrapfilename = p;
368 		update_header(FROM);
369 		buff214.assign(header("<ics214>"));
370 		make_buff214(true);
371 		export_wrapfile(base_214_filename, wrapfilename, buff214, pext != ".wrap");
372 
373 		buff214.assign(header("<ics214>"));
374 		make_buff214(false);
375 		write_214(def_214_filename);
376 	}
377 }
378 
cb_214_wrap_autosend()379 void cb_214_wrap_autosend()
380 {
381 	if (check_214fields()) {
382 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 0)
383 			return;
384 		update_header(CHANGED);
385 	}
386 	update_214fields();
387 
388 	if (base_214_filename == string("new").append(F214_EXT) ||
389 		base_214_filename == string("default").append(F214_EXT) )
390 		if (!cb_214_save_as()) return;
391 
392 	update_header(FROM);
393 	buff214.assign(header("<ics214>"));
394 	make_buff214(true);
395 	xfr_via_socket(base_214_filename, buff214);
396 
397 	buff214.assign(header("<ics214>"));
398 	make_buff214(false);
399 	write_214(def_214_filename);
400 }
401 
cb_214_load_template()402 void cb_214_load_template()
403 {
404 	string def_214_filename = def_214_TemplateName;
405 	const char *p = FSEL::select(
406 			"Open template file",
407 			string("Template file\t*").append(T214_EXT).c_str(),
408 			def_214_filename.c_str());
409 	if (p) {
410 		clear_214_form();
411 		read_data_file(p);
412 		def_214_TemplateName = p;
413 		show_filename(def_214_TemplateName);
414 		using_ics214_template = true;
415 	}
416 }
417 
cb_214_save_template()418 void cb_214_save_template()
419 {
420 	if (!using_ics214_template) {
421 		cb_214_save_as_template();
422 		return;
423 	}
424 	string def_214_filename = def_214_TemplateName;
425 	const char *p = FSEL::saveas(
426 			"Save template file",
427 			string("Template file\t*").append(T214_EXT).c_str(),
428 			def_214_filename.c_str());
429 	if (p) {
430 		update_header(CHANGED);
431 		buff214.assign(header("<ics214>"));
432 		make_buff214();
433 		write_214(p);
434 	}
435 }
436 
cb_214_save_as_template()437 void cb_214_save_as_template()
438 {
439 	string def_214_filename = def_214_TemplateName;
440 	const char *p = FSEL::saveas(
441 			"Save as template file",
442 			string("Template file\t*").append(T214_EXT).c_str(),
443 			def_214_filename.c_str());
444 	if (p) {
445 		const char *pext = fl_filename_ext(p);
446 		def_214_TemplateName = p;
447 		if (strlen(pext) == 0) def_214_TemplateName.append(T214_EXT);
448 		remove_spaces_from_filename(def_214_TemplateName);
449 		clear_header();
450 		update_header(CHANGED);
451 		buff214.assign(header("<ics214>"));
452 		make_buff214();
453 		write_214(def_214_TemplateName);
454 		show_filename(def_214_TemplateName);
455 		using_ics214_template = true;
456 	}
457 }
458 
cb_214_open()459 void cb_214_open()
460 {
461 	const char *p = FSEL::select(
462 			_("Open data file"),
463 			string("ICS-214\t*").append(F214_EXT).c_str(),
464 			def_214_filename.c_str());
465 	if (!p) return;
466 	if (strlen(p) == 0) return;
467 	clear_214_form();
468 	read_data_file(p);
469 	using_ics214_template = false;
470 	def_214_filename = p;
471 	show_filename(def_214_filename);
472 }
473 
write_214(string s)474 void write_214(string s)
475 {
476 	FILE *file214 = fopen(s.c_str(), "w");
477 	if (!file214) return;
478 
479 	fwrite(buff214.c_str(), buff214.length(), 1, file214);
480 	fclose(file214);
481 }
482 
cb_214_save_as()483 bool cb_214_save_as()
484 {
485 	const char *p;
486 	string newfilename;
487 
488 	string name = named_file();
489 	if (!name.empty()) {
490 		name.append(F214_EXT);
491 		newfilename = ICS_msg_dir;
492 		newfilename.append(name);
493 	} else
494 		newfilename = def_214_filename;
495 
496 	p = FSEL::saveas(
497 			_("Save data file"),
498 			string("ICS-214\t*").append(F214_EXT).c_str(),
499 			newfilename.c_str());
500 
501 	if (!p) return false;
502 	if (strlen(p) == 0) return false;
503 
504 	if (progStatus.sernbr_fname) update_sernbr();
505 
506 	const char *pext = fl_filename_ext(p);
507 	def_214_filename = p;
508 	if (strlen(pext) == 0) def_214_filename.append(F214_EXT);
509 
510 	remove_spaces_from_filename(def_214_filename);
511 	update_214fields();
512 	update_header(NEW);
513 	buff214.assign(header("<ics214>"));
514 	make_buff214();
515 	write_214(def_214_filename);
516 
517 	using_ics214_template = false;
518 	show_filename(def_214_filename);
519 	return true;
520 }
521 
cb_214_save()522 void cb_214_save()
523 {
524 	if (base_214_filename == string("new").append(F214_EXT) ||
525 		base_214_filename == string("default").append(F214_EXT) ||
526 		using_ics214_template == true) {
527 		cb_214_save_as();
528 		return;
529 	}
530 	if (check_214fields()) update_header(CHANGED);
531 	update_214fields();
532 	buff214.assign(header("<ics214>"));
533 	make_buff214();
534 	write_214(def_214_filename);
535 	using_ics214_template = false;
536 }
537 
cb_214_html()538 void cb_214_html()
539 {
540 	string fname_name = fl_filename_name(def_214_filename.c_str());
541 	size_t p = fname_name.rfind('.');
542 	if (p != string::npos) fname_name.erase(p);
543 
544 	string ics214_fname = ICS_dir;
545 	ics214_fname.append(fname_name);
546 	ics214_fname.append(".html");
547 
548 	string html_text = "";
549 
550 	update_214fields();
551 	string form214 = ics214_html_template;
552 
553 	replacestr(form214, TITLE, fname_name);
554 	replacestr(form214, ics214_incident, s214_incident );
555 	replacestr(form214, ics214_date, s214_date );
556 	replacestr(form214, ics214_time, s214_time );
557 	replacestr(form214, ics214_op_period, s214_op_period );
558 	replacestr(form214, ics214_unit_name, s214_unit_name );
559 	replacestr(form214, ics214_unit_leader, s214_unit_leader );
560 	replacestr(form214, ics214_prepared_by, s214_prepared_by );
561 
562 	for (int i = 0; i < 16; i++) {
563 		replacestr(form214, ics_nn( ics214_roster_name, i ), s214_roster_name[i] );
564 		replacestr(form214, ics_nn( ics214_roster_position, i ), s214_roster_position[i] );
565 		replacestr(form214, ics_nn( ics214_roster_home_base, i ), s214_roster_home_base[i] );
566 		replacestr(form214, ics_nn( ics214_activity_time, i ), s214_activity_time[i] );
567 		replacestr(form214, ics_nn( ics214_activity_event, i ), s214_activity_event[i] );
568 	}
569 
570 	FILE *file214 = fopen(ics214_fname.c_str(), "w");
571 	fprintf(file214,"%s", form214.c_str());
572 	fclose(file214);
573 
574 	open_url(ics214_fname.c_str());
575 }
576 
cb_214_msg_type()577 void cb_214_msg_type()
578 {
579 	if (tabs_msg_type->value() == tab_ics214 ) {
580 		tab_ics214_type->value(tab_214_1);
581 		show_filename(def_214_filename);
582 	}
583 }
584 
cb_214_textout()585 void cb_214_textout()
586 {
587 	string ics214_fname = ICS_dir;
588 	ics214_fname.append("ics214.txt");
589 
590 	update_214fields();
591 	string form214 = ics214_text_template;
592 
593 	replacestr(form214, ics214_incident, s214_incident );
594 	replacestr(form214, ics214_date, s214_date );
595 	replacestr(form214, ics214_time, s214_time );
596 	replacestr(form214, ics214_op_period, s214_op_period );
597 	replacestr(form214, ics214_unit_name, s214_unit_name );
598 	replacestr(form214, ics214_unit_leader, s214_unit_leader );
599 	replacestr(form214, ics214_prepared_by, s214_prepared_by );
600 
601 	for (int i = 0; i < 16; i++) {
602 		replacestr(form214, ics_nn( ics214_roster_name, i ), s214_roster_name[i] );
603 		replacestr(form214, ics_nn( ics214_roster_position, i ), s214_roster_position[i] );
604 		replacestr(form214, ics_nn( ics214_roster_home_base, i ), s214_roster_home_base[i] );
605 		replacestr(form214, ics_nn( ics214_activity_time, i ), s214_activity_time[i] );
606 		replacestr(form214, ics_nn( ics214_activity_event, i ), s214_activity_event[i] );
607 	}
608 
609 	FILE *file214 = fopen(ics214_fname.c_str(), "w");
610 	fprintf(file214,"%s", form214.c_str());
611 	fclose(file214);
612 
613 	open_url(ics214_fname.c_str());
614 }
615