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 309 field variables and template variables
77 // ---------------------------------------------------------------------
78 
79 string ics309_incident				= ":inc:";
80 string ics309_date_fm				= ":dfm:";
81 string ics309_time_fm				= ":tfm:";
82 string ics309_date_to				= ":dto:";
83 string ics309_time_to				= ":tto:";
84 string ics309_prepared_by			= ":pre:";
85 string ics309_preparer_date_time	= ":dtm:";
86 string ics309_radio_net				= ":net:";
87 string ics309_radio_operator		= ":opr:";
88 
89 string ics309_comm_msg				= ":msg[n]:"; // 34
90 string ics309_comm_to				= ":to[n]:"; // 34
91 string ics309_comm_from				= ":fm[n]:"; // 34
92 string ics309_comm_time				= ":tm[n]:"; // 34
93 
94 string s309_incident;
95 string s309_date_fm;
96 string s309_time_fm;
97 string s309_date_to;
98 string s309_time_to;
99 string s309_prepared_by;
100 string s309_preparer_date_time;
101 string s309_radio_net;
102 string s309_radio_operator;
103 
104 string s309_comm_time[34];
105 string s309_comm_from[34];
106 string s309_comm_msg[34];
107 string s309_comm_to[34];
108 
109 // =====================================================================
110 
111 string buff309;
112 string def_309_filename = "";
113 string base_309_filename = "";
114 string def_309_TemplateName = "";
115 bool using_ics309_template = false;
116 
cb_309_set_date_fm()117 void cb_309_set_date_fm()
118 {
119 	txt_309_date_fm->value(szDate(progStatus.dtformat));
120 }
121 
cb_309_set_time_fm()122 void cb_309_set_time_fm()
123 {
124 	txt_309_time_fm->value(szTime(progStatus.UTC));
125 }
126 
cb_309_set_date_to()127 void cb_309_set_date_to()
128 {
129 	txt_309_date_to->value(szDate(progStatus.dtformat));
130 }
131 
cb_309_set_time_to()132 void cb_309_set_time_to()
133 {
134 	txt_309_time_to->value(szTime(progStatus.UTC));
135 }
136 
cb_309_set_date_time()137 void cb_309_set_date_time()
138 {
139 	string dt = szDate(progStatus.dtformat);
140 	dt.append(", ").append(szTime(progStatus.UTC));
141 	txt_309_preparer_date_time->value(dt.c_str());
142 }
143 
clear_309fields()144 void clear_309fields()
145 {
146 	s309_incident.clear();
147 	s309_date_fm.clear();
148 	s309_time_fm.clear();
149 	s309_date_to.clear();
150 	s309_time_to.clear();
151 	s309_prepared_by.clear();
152 	s309_preparer_date_time.clear();
153 	s309_radio_net.clear();
154 	s309_radio_operator.clear();
155 
156 	for (int i = 0; i < 34; i++) {
157 		s309_comm_msg[i].clear();
158 		s309_comm_to[i].clear();
159 		s309_comm_from[i].clear();
160 	}
161 }
162 
check_309fields()163 bool check_309fields()
164 {
165 	if (s309_incident != txt_309_incident->value())
166 		return true;
167 	if (s309_date_fm != txt_309_date_fm->value())
168 		return true;
169 	if (s309_time_fm != txt_309_time_fm->value())
170 		return true;
171 	if (s309_date_to != txt_309_date_to->value())
172 		return true;
173 	if (s309_time_to != txt_309_time_to->value())
174 		return true;
175 	if (s309_prepared_by != txt_309_prepared_by->value())
176 		return true;
177 	if (s309_radio_net != txt_309_radio_net->value())
178 		return true;
179 	if (s309_radio_operator != txt_309_radio_operator->value())
180 		return true;
181 	if (s309_preparer_date_time != txt_309_preparer_date_time->value())
182 		return true;
183 	for (int i = 0; i < 34; i++) {
184 		if (s309_comm_time[i] != txt_309_comm_time[i]->value())
185 			return true;
186 		if (s309_comm_msg[i] != txt_309_comm_msg[i]->value())
187 			return true;
188 		if (s309_comm_to[i] != txt_309_comm_to[i]->value())
189 			return true;
190 		if (s309_comm_from[i] != txt_309_comm_from[i]->value())
191 			return true;
192 	}
193 	return false;
194 }
195 
update_309fields()196 void update_309fields()
197 {
198 	s309_incident = txt_309_incident->value();
199 	s309_date_fm = txt_309_date_fm->value();
200 	s309_time_fm = txt_309_time_fm->value();
201 	s309_date_to = txt_309_date_to->value();
202 	s309_time_to = txt_309_time_to->value();
203 	s309_prepared_by = txt_309_prepared_by->value();
204 	s309_radio_net = txt_309_radio_net->value();
205 	s309_radio_operator = txt_309_radio_operator->value();
206 	s309_preparer_date_time = txt_309_preparer_date_time->value();
207 	for (int i = 0; i < 34; i++) {
208 		s309_comm_time[i] = txt_309_comm_time[i]->value();
209 		s309_comm_from[i] = txt_309_comm_from[i]->value();
210 		s309_comm_to[i] = txt_309_comm_to[i]->value();
211 		s309_comm_msg[i] = txt_309_comm_msg[i]->value();
212 	}
213 }
214 
update_309form()215 void update_309form()
216 {
217 	txt_309_incident->value(s309_incident.c_str());
218 	txt_309_date_fm->value(s309_date_fm.c_str());
219 	txt_309_time_fm->value(s309_time_fm.c_str());
220 	txt_309_date_to->value(s309_date_to.c_str());
221 	txt_309_time_to->value(s309_time_to.c_str());
222 	txt_309_prepared_by->value(s309_prepared_by.c_str());
223 	txt_309_radio_net->value(s309_radio_net.c_str());
224 	txt_309_radio_operator->value(s309_radio_operator.c_str());
225 	txt_309_preparer_date_time->value(s309_preparer_date_time.c_str());
226 
227 	for (int i = 0; i < 34; i++) {
228 		txt_309_comm_time[i]->value(s309_comm_time[i].c_str());
229 		txt_309_comm_to[i]->value(s309_comm_to[i].c_str());
230 		txt_309_comm_from[i]->value(s309_comm_from[i].c_str());
231 		txt_309_comm_msg[i]->value(s309_comm_msg[i].c_str());
232 	}
233 }
234 
clear_309_form()235 void clear_309_form()
236 {
237 	clear_309fields();
238 	update_309form();
239 }
240 
ics309_nn(string & subst,int n)241 string &ics309_nn(string & subst, int n)
242 {
243 	static string garbage = "#$^*!";
244 	static string ics;
245 	ics.clear();
246 	ics = subst;
247 	size_t pos = ics.find("[");
248 	if (pos == string::npos) return garbage;
249 	pos++;
250 	if (n < 10)
251 		ics[pos] = '0' + n;
252 	else {
253 		ics[pos] = n > 29 ? '3' : n > 19 ? '2' : '1';
254 		ics[pos+1] = '0' + n % 10;
255 		ics[pos+2] = ']';
256 		ics += ':';
257 	}
258 	return ics;
259 }
260 
make_buff309(bool compress=false)261 void make_buff309(bool compress = false)
262 {
263 	string mbuff;
264 	mbuff.clear();
265 	mbuff.append( lineout( ics309_incident, s309_incident ) );
266 	mbuff.append( lineout( ics309_date_fm, s309_date_fm ) );
267 	mbuff.append( lineout( ics309_time_fm, s309_time_fm ) );
268 	mbuff.append( lineout( ics309_date_to, s309_date_to ) );
269 	mbuff.append( lineout( ics309_time_to, s309_time_to ) );
270 	mbuff.append( lineout( ics309_prepared_by, s309_prepared_by ) );
271 	mbuff.append( lineout( ics309_preparer_date_time, s309_preparer_date_time ) );
272 	mbuff.append( lineout( ics309_radio_net, s309_radio_net ) );
273 	mbuff.append( lineout( ics309_radio_operator, s309_radio_operator ) );
274 
275 	for (int i = 0; i < 34; i++) {
276 		mbuff.append( lineout( ics309_nn( ics309_comm_time, i ), s309_comm_time[i] ) );
277 		mbuff.append( lineout( ics309_nn( ics309_comm_to, i ),     s309_comm_to[i] ) );
278 		mbuff.append( lineout( ics309_nn( ics309_comm_from, i ),     s309_comm_from[i] ) );
279 		mbuff.append( lineout( ics309_nn( ics309_comm_msg, i ), s309_comm_msg[i] ) );
280 	}
281 	if (compress) compress_maybe(mbuff);
282 	buff309.append(mbuff);
283 }
284 
read_309_buffer(string data)285 void read_309_buffer(string data)
286 {
287 	clear_309fields();
288 	read_header(data);
289 
290 	s309_incident = findstr( data, ics309_incident );
291 	s309_date_fm = findstr( data, ics309_date_fm );
292 	s309_time_fm  = findstr( data, ics309_time_fm );
293 	s309_date_to = findstr( data, ics309_date_to );
294 	s309_time_to  = findstr( data, ics309_time_to );
295 	s309_prepared_by = findstr( data, ics309_prepared_by );
296 	s309_preparer_date_time = findstr( data, ics309_preparer_date_time );
297 	s309_radio_net = findstr( data, ics309_radio_net );
298 	s309_radio_operator  = findstr( data, ics309_radio_operator );
299 
300 	for (int i = 0; i < 34; i++) {
301 		s309_comm_time[i]    = findstr( data, ics309_nn( ics309_comm_time, i ) );
302 		s309_comm_to[i]      = findstr( data, ics309_nn( ics309_comm_to, i ) );
303 		s309_comm_from[i]    = findstr( data, ics309_nn( ics309_comm_from, i ) );
304 		s309_comm_msg[i] = findstr( data, ics309_nn( ics309_comm_msg, i ) );
305 	}
306 
307 	update_309form();
308 }
309 
cb_309_new()310 void cb_309_new()
311 {
312 	if (check_309fields()) {
313 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 1) {
314 			update_header(CHANGED);
315 			cb_309_save();
316 		}
317 	}
318 	clear_309_form();
319 	clear_header();
320 	def_309_filename = ICS_msg_dir;
321 	def_309_filename.append("new").append(F309_EXT);
322 	show_filename(def_309_filename);
323 	using_ics309_template = false;
324 }
325 
cb_309_import()326 void cb_309_import()
327 {
328 	fl_alert2("Not implemented");
329 }
330 
cb_309_export()331 void cb_309_export()
332 {
333 	fl_alert2("Not implemented");
334 }
335 
cb_309_wrap_import(string wrapfilename,string inpbuffer)336 void cb_309_wrap_import(string wrapfilename, string inpbuffer)
337 {
338 	clear_309_form();
339 	read_309_buffer(inpbuffer);
340 	def_309_filename = ICS_msg_dir;
341 	def_309_filename.append(wrapfilename);
342 	show_filename(def_309_filename);
343 	using_ics309_template = false;
344 }
345 
eval_309_fsize()346 int eval_309_fsize()
347 {
348 	Ccrc16 chksum;
349 	evalstr.assign("[WRAP:beg][WRAP:lf][WRAP:fn ");
350 	evalstr.append(base_309_filename).append("]");
351 	update_309fields();
352 	update_header(FROM);
353 	evalstr.append(header("<ics309>"));
354 	buff309.clear();
355 	make_buff309(true);
356 	if (buff309.empty()) return 0;
357 	compress_maybe( buff309 );
358 	evalstr.append( buff309 );
359 	evalstr.append("[WRAP:chksum ").append(chksum.scrc16(evalstr)).append("][WRAP:end]");
360 	return evalstr.length();
361 }
362 
cb_309_wrap_export()363 void cb_309_wrap_export()
364 {
365 	if (check_309fields()) {
366 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 0)
367 			return;
368 		update_header(CHANGED);
369 	}
370 	update_309fields();
371 
372 	if (base_309_filename == string("new").append(F309_EXT) ||
373 		base_309_filename == string("default").append(F309_EXT) )
374 		if (!cb_309_save_as()) return;
375 
376 	string wrapfilename = WRAP_send_dir;
377 	wrapfilename.append(base_309_filename);
378 	wrapfilename.append(".wrap");
379 	const char *p = FSEL::saveas(
380 			"Save as wrap file",
381 			"Wrap file\t*.{wrap,WRAP}",
382 			wrapfilename.c_str());
383 	if (p) {
384 		string pext = fl_filename_ext(p);
385 		wrapfilename = p;
386 		update_header(FROM);
387 		buff309.assign(header("<ics309>"));
388 		make_buff309(true);
389 		export_wrapfile(base_309_filename, wrapfilename, buff309, pext != ".wrap");
390 		write_309(def_309_filename);
391 	}
392 }
393 
cb_309_wrap_autosend()394 void cb_309_wrap_autosend()
395 {
396 	if (check_309fields()) {
397 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 0)
398 			return;
399 		update_header(CHANGED);
400 	}
401 	update_309fields();
402 
403 	if (base_309_filename == string("new").append(F309_EXT) ||
404 		base_309_filename == string("default").append(F309_EXT) )
405 		cb_309_save_as();
406 
407 	update_header(FROM);
408 	buff309.assign(header("<ics309>"));
409 	make_buff309(true);
410 
411 	xfr_via_socket(base_309_filename, buff309);
412 	write_309(def_309_filename);
413 }
414 
cb_309_load_template()415 void cb_309_load_template()
416 {
417 	string def_309_filename = def_309_TemplateName;
418 	const char *p = FSEL::select(
419 			"Open template file",
420 			string("Template file\t*").append(T309_EXT).c_str(),
421 			def_309_filename.c_str());
422 	if (p) {
423 		clear_309_form();
424 		read_data_file(p);
425 		def_309_TemplateName = p;
426 		show_filename(def_309_TemplateName);
427 		using_ics309_template = true;
428 	}
429 }
430 
cb_309_save_template()431 void cb_309_save_template()
432 {
433 	if (!using_ics309_template) {
434 		cb_309_save_as_template();
435 		return;
436 	}
437 	string def_309_filename = def_309_TemplateName;
438 	const char *p = FSEL::saveas(
439 			"Save template file",
440 			string("Template file\t*").append(T309_EXT).c_str(),
441 			def_309_filename.c_str());
442 	if (p) {
443 		update_header(CHANGED);
444 		buff309.assign(header("<ics309>"));
445 		make_buff309();
446 		write_309(p);
447 	}
448 }
449 
cb_309_save_as_template()450 void cb_309_save_as_template()
451 {
452 	string def_309_filename = def_309_TemplateName;
453 	const char *p = FSEL::saveas(
454 			"Save as template file",
455 			string("Template file\t*").append(T309_EXT).c_str(),
456 			def_309_filename.c_str());
457 	if (p) {
458 		const char *pext = fl_filename_ext(p);
459 		def_309_TemplateName = p;
460 		if (strlen(pext) == 0) def_309_TemplateName.append(T309_EXT);
461 		remove_spaces_from_filename(def_309_TemplateName);
462 		clear_header();
463 		update_header(CHANGED);
464 		buff309.assign(header("<ics309>"));
465 		make_buff309();
466 		write_309(def_309_TemplateName);
467 		show_filename(def_309_TemplateName);
468 		using_ics309_template = true;
469 	}
470 }
471 
cb_309_open()472 void cb_309_open()
473 {
474 	const char *p = FSEL::select(
475 			_("Open data file"),
476 			string("ICS-309\t*").append(F309_EXT).c_str(),
477 			def_309_filename.c_str());
478 	if (!p) return;
479 	if (strlen(p) == 0) return;
480 	clear_309_form();
481 	read_data_file(p);
482 	using_ics309_template = false;
483 	def_309_filename = p;
484 	show_filename(def_309_filename);
485 }
486 
write_309(string s)487 void write_309(string s)
488 {
489 	FILE *file309 = fopen(s.c_str(), "w");
490 	if (!file309) return;
491 
492 	fwrite(buff309.c_str(), buff309.length(), 1, file309);
493 	fclose(file309);
494 }
495 
cb_309_save_as()496 bool cb_309_save_as()
497 {
498 	const char *p;
499 	string newfilename;
500 
501 	string name = named_file();
502 	if (!name.empty()) {
503 		name.append(F309_EXT);
504 		newfilename = ICS_msg_dir;
505 		newfilename.append(name);
506 	} else
507 		newfilename = def_309_filename;
508 
509 	p = FSEL::saveas(
510 			_("Save data file"),
511 			string("ICS-309\t*").append(F309_EXT).c_str(),
512 			newfilename.c_str());
513 
514 	if (!p) return false;
515 	if (strlen(p) == 0) return false;
516 
517 	if (progStatus.sernbr_fname) update_sernbr();
518 
519 	const char *pext = fl_filename_ext(p);
520 	def_309_filename = p;
521 	if (strlen(pext) == 0) def_309_filename.append(F309_EXT);
522 
523 	remove_spaces_from_filename(def_309_filename);
524 	update_309fields();
525 	update_header(NEW);
526 	buff309.assign(header("<ics309>"));
527 	make_buff309();
528 	write_309(def_309_filename);
529 
530 	using_ics309_template = false;
531 	show_filename(def_309_filename);
532 	return true;
533 }
534 
cb_309_save()535 void cb_309_save()
536 {
537 	if (base_309_filename == string("new").append(F309_EXT) ||
538 		base_309_filename == string("default").append(F309_EXT) ||
539 		using_ics309_template == true) {
540 		cb_309_save_as();
541 		return;
542 	}
543 	if (check_309fields()) update_header(CHANGED);
544 	update_309fields();
545 	buff309.assign(header("<ics309>"));
546 	make_buff309();
547 	write_309(def_309_filename);
548 	using_ics309_template = false;
549 }
550 
cb_309_html()551 void cb_309_html()
552 {
553 	string fname_name = fl_filename_name(def_309_filename.c_str());
554 	size_t p = fname_name.rfind('.');
555 	if (p != string::npos) fname_name.erase(p);
556 
557 	string ics309_fname = ICS_dir;
558 	ics309_fname.append(fname_name);
559 	ics309_fname.append(".html");
560 
561 	string html_text = "";
562 	string empty = "<br>";
563 
564 	update_309fields();
565 	string form309 = ics309_html_template;
566 
567 	replacestr(form309, TITLE, fname_name);
568 	replacestr(form309, ics309_incident, s309_incident );
569 	replacestr(form309, ics309_date_fm, s309_date_fm );
570 	replacestr(form309, ics309_time_fm, s309_time_fm );
571 	replacestr(form309, ics309_date_to, s309_date_to );
572 	replacestr(form309, ics309_time_to, s309_time_to );
573 	replacestr(form309, ics309_prepared_by, s309_prepared_by );
574 	replacestr(form309, ics309_preparer_date_time, s309_preparer_date_time );
575 	replacestr(form309, ics309_radio_net, s309_radio_net );
576 	replacestr(form309, ics309_radio_operator, s309_radio_operator );
577 
578 	for (int i = 0; i < 34; i++) {
579 		replacestr(form309, ics309_nn( ics309_comm_time, i ),
580 			s309_comm_time[i].empty() ? empty : s309_comm_time[i] );
581 		replacestr(form309, ics309_nn( ics309_comm_to, i ),
582 			s309_comm_to[i].empty() ? empty : s309_comm_to[i] );
583 		replacestr(form309, ics309_nn( ics309_comm_from, i ),
584 			s309_comm_from[i].empty() ? empty : s309_comm_from[i] );
585 		replacestr(form309, ics309_nn( ics309_comm_msg, i ),
586 			s309_comm_msg[i].empty() ? empty : s309_comm_msg[i] );
587 	}
588 
589 	FILE *file309 = fopen(ics309_fname.c_str(), "w");
590 	fprintf(file309,"%s", form309.c_str());
591 	fclose(file309);
592 
593 	open_url(ics309_fname.c_str());
594 }
595 
cb_309_msg_type()596 void cb_309_msg_type()
597 {
598 	if (tabs_msg_type->value() == tab_ics309 ) {
599 		tab_ics309_type->value(tab_309_1);
600 		show_filename(def_309_filename);
601 	}
602 }
603 
cb_309_textout()604 void cb_309_textout()
605 {
606 	string ics309_fname = ICS_dir;
607 	ics309_fname.append("ics309.txt");
608 
609 	update_309fields();
610 	string form309 = ics309_text_template;
611 
612 	replacestr(form309, ics309_incident, s309_incident );
613 	replacestr(form309, ics309_date_fm, s309_date_fm );
614 	replacestr(form309, ics309_time_fm, s309_time_fm );
615 	replacestr(form309, ics309_date_to, s309_date_to );
616 	replacestr(form309, ics309_time_to, s309_time_to );
617 	replacestr(form309, ics309_prepared_by, s309_prepared_by );
618 	replacestr(form309, ics309_preparer_date_time, s309_preparer_date_time );
619 	replacestr(form309, ics309_radio_net, s309_radio_net );
620 	replacestr(form309, ics309_radio_operator, s309_radio_operator );
621 
622 	for (int i = 0; i < 34; i++) {
623 		replacestr(form309, ics309_nn( ics309_comm_time, i ), s309_comm_time[i] );
624 		replacestr(form309, ics309_nn( ics309_comm_msg, i ), s309_comm_msg[i] );
625 		replacestr(form309, ics309_nn( ics309_comm_to, i ), s309_comm_to[i] );
626 		replacestr(form309, ics309_nn( ics309_comm_from, i ), s309_comm_from[i] );
627 	}
628 
629 	FILE *file309 = fopen(ics309_fname.c_str(), "w");
630 	fprintf(file309,"%s", form309.c_str());
631 	fclose(file309);
632 
633 	open_url(ics309_fname.c_str());
634 }
635 
ics309_csv(Fl_Widget * w,void * d)636 void ics309_csv(Fl_Widget *w, void *d)
637 {
638 	string csv_fname = ICS_dir;
639 	csv_fname.append("ics309.csv");
640 
641 	const char *p;
642 
643 	p = FSEL::saveas(_("Save csv file"), "ICS-309\t*.csv",
644 					csv_fname.c_str());
645 
646 	if (!p) return;
647 	if (strlen(p) == 0) return;
648 
649 	csv_fname = p;
650 
651 	update_309fields();
652 
653 	string cvs_text;
654 	cvs_text.assign("Incident,Start_Date,Start_Time,End_Date,End_Time,Preparer,Prepared_Date,Radio_Net,Radio_operator\n");
655 	cvs_text.append("\"").append(s309_incident).append("\",");
656 	cvs_text.append("\"").append(s309_date_fm).append("\",");
657 	cvs_text.append("\"").append(s309_time_fm).append("\",");
658 	cvs_text.append("\"").append(s309_date_to).append("\",");
659 	cvs_text.append("\"").append(s309_time_to).append("\",");
660 	cvs_text.append("\"").append(s309_prepared_by).append("\",");
661 	cvs_text.append("\"").append(s309_preparer_date_time).append("\",");
662 	cvs_text.append("\"").append(s309_radio_net).append("\",");
663 	cvs_text.append("\"").append(s309_radio_operator).append("\"\n");
664 	cvs_text.append("\n");
665 	cvs_text.append("COMM_TIME,COMM_TO,COMM_FM,COMM_MSG\n");
666 
667 	for (int i = 0; i < 34; i++) {
668 		cvs_text.append("\"").append(s309_comm_time[i]).append("\",");
669 		cvs_text.append("\"").append(s309_comm_to[i]).append("\",");
670 		cvs_text.append("\"").append(s309_comm_from[i]).append("\",");
671 		cvs_text.append("\"").append(s309_comm_msg[i]).append("\"\n");
672 	}
673 
674 	FILE *csv_file = fopen(csv_fname.c_str(), "w");
675 	if (!csv_file) return;
676 	fprintf(csv_file,"%s", cvs_text.c_str());
677 	fclose(csv_file);
678 }
679