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 216 field variables and template variables
77 // ---------------------------------------------------------------------
78
79 string ics216_incident = ":inc:";
80 string ics216_date = ":dat:";
81 string ics216_time = ":tim:";
82 string ics216_branch = ":br:";
83 string ics216_agc = ":agc:";
84 string ics216_op_period = ":opp:";
85 string ics216_tac_freq = ":tfr:";
86
87 string ics216_div_grp = ":div[n]:";
88 string ics216_agency = ":agy[n]:";
89
90 string ics216_ag = ":ag[n]:";
91 string ics216_id = ":id[n]:";
92 string ics216_rr = ":rr[n]:";
93
94 string ics216_prepared_by = ":pre:";
95
96 string s216_incident;
97 string s216_date;
98 string s216_time;
99 string s216_branch;
100 string s216_agc;
101 string s216_op_period;
102 string s216_tac_freq;
103
104 string s216_div_grp[4];
105 string s216_agency[4];
106 string s216_ag[36];
107 string s216_id[36];
108 string s216_rr[36];
109
110 string s216_prepared_by;
111
112 // =====================================================================
113
114 string buff216;
115 string def_216_filename = "";
116 string base_216_filename = "";
117 string def_216_TemplateName = "";
118 bool using_ics216_template = false;
119
cb_216_set_date()120 void cb_216_set_date()
121 {
122 txt_216_date->value(szDate(progStatus.dtformat));
123 }
124
cb_216_set_time()125 void cb_216_set_time()
126 {
127 txt_216_time->value(szTime(progStatus.UTC));
128 }
129
clear_216fields()130 void clear_216fields()
131 {
132 s216_incident.clear();
133 s216_date.clear();
134 s216_time.clear();
135 s216_branch.clear();
136 s216_agc.clear();
137 s216_op_period.clear();
138 s216_tac_freq.clear();
139 s216_prepared_by.clear();
140
141 for (int i = 0; i < 4; i++) {
142 s216_div_grp[i].clear();
143 s216_agency[i].clear();
144 }
145 for (int i = 0; i < 36; i++) {
146 s216_ag[i].clear();
147 s216_id[i].clear();
148 s216_rr[i].clear();
149 }
150 }
151
check_216fields()152 bool check_216fields()
153 {
154 if (s216_incident != txt_216_incident->value())
155 return true;
156 if (s216_date != txt_216_date->value())
157 return true;
158 if (s216_time != txt_216_time->value())
159 return true;
160 if (s216_branch != txt_216_branch->value())
161 return true;
162 if (s216_agc != txt_216_agc->value())
163 return true;
164 if (s216_op_period != txt_216_op_period->value())
165 return true;
166 if (s216_tac_freq != txt_216_tac_freq->value())
167 return true;
168 if (s216_prepared_by != txt_216_prepared_by->value())
169 return true;
170
171 for (int i = 0; i < 4; i++) {
172 if (s216_div_grp[i] != txt_216_div_grp[i]->value())
173 return true;
174 if (s216_agency[i] != txt_216_agency[i]->value())
175 return true;
176 }
177
178 for (int i = 0; i < 36; i++) {
179 if (s216_ag[i] != txt_216_ag[i]->value())
180 return true;
181 if (s216_id[i] != txt_216_id[i]->value())
182 return true;
183 if (s216_rr[i] != txt_216_rr[i]->value())
184 return true;
185 }
186 return false;
187 }
188
update_216fields()189 void update_216fields()
190 {
191 s216_incident = txt_216_incident->value();
192 s216_date = txt_216_date->value();
193 s216_time = txt_216_time->value();
194 s216_branch = txt_216_branch->value();
195 s216_agc = txt_216_agc->value();
196 s216_op_period = txt_216_op_period->value();
197 s216_tac_freq = txt_216_tac_freq->value();
198 s216_prepared_by = txt_216_prepared_by->value();
199
200 for (int i = 0; i < 4; i++) {
201 s216_div_grp[i] = txt_216_div_grp[i]->value();
202 s216_agency[i] = txt_216_agency[i]->value();
203 }
204
205 for (int i = 0; i < 36; i++) {
206 s216_ag[i] = txt_216_ag[i]->value();
207 s216_id[i] = txt_216_id[i]->value();
208 s216_rr[i] = txt_216_rr[i]->value();
209 }
210 }
211
update_216form()212 void update_216form()
213 {
214 txt_216_incident->value(s216_incident.c_str());
215 txt_216_date->value(s216_date.c_str());
216 txt_216_time->value(s216_time.c_str());
217 txt_216_branch->value(s216_branch.c_str());
218 txt_216_agc->value(s216_agc.c_str());
219 txt_216_op_period->value(s216_op_period.c_str());
220 txt_216_tac_freq->value(s216_tac_freq.c_str());
221 txt_216_prepared_by->value(s216_prepared_by.c_str());
222
223 for (int i = 0; i < 4; i++) {
224 txt_216_div_grp[i]->value(s216_div_grp[i].c_str());
225 txt_216_agency[i]->value(s216_agency[i].c_str());
226 }
227 for (int i = 0; i < 36; i++) {
228 txt_216_ag[i]->value(s216_ag[i].c_str());
229 txt_216_id[i]->value(s216_id[i].c_str());
230 txt_216_rr[i]->value(s216_rr[i].c_str());
231 }
232 }
233
clear_216_form()234 void clear_216_form()
235 {
236 clear_216fields();
237 update_216form();
238 }
239
ics_216_nn(string & subst,int n)240 string &ics_216_nn(string & subst, int n)
241 {
242 static string garbage = "#$^*!";
243 static string ics;
244 ics.clear();
245 ics = subst;
246 size_t pos = ics.find("[");
247 if (pos == string::npos) return garbage;
248 pos++;
249 if (n < 10)
250 ics[pos] = '0' + n;
251 else {
252 if (n < 20)
253 ics[pos] = '1';
254 else if ( n < 30)
255 ics[pos] = '2';
256 else if (n < 40)
257 ics[pos] = '3';
258 ics[pos+1] = '0' + n % 10;
259 ics[pos+2] = ']';
260 ics += ':';
261 }
262 return ics;
263 }
264
make_buff216(bool compress=false)265 void make_buff216(bool compress = false)
266 {
267 string mbuff;
268 mbuff.clear();
269 mbuff.append( lineout( ics216_incident, s216_incident ) );
270 mbuff.append( lineout( ics216_date, s216_date ) );
271 mbuff.append( lineout( ics216_time, s216_time ) );
272 mbuff.append( lineout( ics216_branch, s216_branch ) );
273 mbuff.append( lineout( ics216_agc, s216_agc ) );
274 mbuff.append( lineout( ics216_op_period, s216_op_period ) );
275 mbuff.append( lineout( ics216_tac_freq, s216_tac_freq ) );
276 mbuff.append( lineout( ics216_prepared_by, s216_prepared_by ) );
277
278 for (int i = 0; i < 4; i++) {
279 mbuff.append( lineout( ics_216_nn( ics216_div_grp, i), s216_div_grp[i] ) );
280 mbuff.append( lineout( ics_216_nn( ics216_agency, i), s216_agency[i] ) );
281 }
282 for (int i = 0; i < 36; i++) {
283 mbuff.append( lineout( ics_216_nn( ics216_ag, i), s216_ag[i] ) );
284 mbuff.append( lineout( ics_216_nn( ics216_id, i), s216_id[i] ) );
285 mbuff.append( lineout( ics_216_nn( ics216_rr, i), s216_rr[i] ) );
286 }
287 if (compress) compress_maybe(mbuff);
288 buff216.append(mbuff);
289 }
290
read_216_buffer(string data)291 void read_216_buffer(string data)
292 {
293 clear_216fields();
294 read_header(data);
295
296 s216_incident = findstr( data, ics216_incident );
297 s216_date = findstr( data, ics216_date );
298 s216_time = findstr( data, ics216_time );
299 s216_branch = findstr( data, ics216_branch );
300 s216_agc = findstr( data, ics216_agc );
301 s216_op_period = findstr( data, ics216_op_period );
302 s216_tac_freq = findstr( data, ics216_tac_freq );
303 s216_prepared_by = findstr( data, ics216_prepared_by );
304
305 for (int i = 0; i < 4; i++) {
306 s216_div_grp[i] = findstr( data, ics_216_nn( ics216_div_grp, i ) );
307 s216_agency[i] = findstr( data, ics_216_nn( ics216_agency, i ) );
308 }
309 for (int i = 0; i < 36; i++) {
310 s216_ag[i] = findstr( data, ics_216_nn( ics216_ag, i ) );
311 s216_id[i] = findstr( data, ics_216_nn( ics216_id, i ) );
312 s216_rr[i] = findstr( data, ics_216_nn( ics216_rr, i ) );
313 }
314
315 update_216form();
316 }
317
cb_216_new()318 void cb_216_new()
319 {
320 if (check_216fields()) {
321 if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 1) {
322 update_header(CHANGED);
323 cb_216_save();
324 }
325 }
326 clear_216_form();
327 clear_header();
328 def_216_filename = ICS_msg_dir;
329 def_216_filename.append("new").append(F216_EXT);
330 show_filename(def_216_filename);
331 using_ics216_template = false;
332 }
333
cb_216_import()334 void cb_216_import()
335 {
336 fl_alert2("Not implemented");
337 }
338
cb_216_export()339 void cb_216_export()
340 {
341 fl_alert2("Not implemented");
342 }
343
cb_216_wrap_import(string wrapfilename,string inpbuffer)344 void cb_216_wrap_import(string wrapfilename, string inpbuffer)
345 {
346 clear_216_form();
347 read_216_buffer(inpbuffer);
348 def_216_filename = ICS_msg_dir;
349 def_216_filename.append(wrapfilename);
350 show_filename(def_216_filename);
351 using_ics216_template = false;
352 }
353
eval_216_fsize()354 int eval_216_fsize()
355 {
356 Ccrc16 chksum;
357 evalstr.assign("[WRAP:beg][WRAP:lf][WRAP:fn ");
358 evalstr.append(base_216_filename).append("]");
359 update_216fields();
360 update_header(FROM);
361 evalstr.append(header("<ics216>"));
362 buff216.clear();
363 make_buff216(true);
364 if (buff216.empty()) return 0;
365 compress_maybe( buff216 );
366 evalstr.append( buff216 );
367 evalstr.append("[WRAP:chksum ").append(chksum.scrc16(evalstr)).append("][WRAP:end]");
368 return evalstr.length();
369 }
370
cb_216_wrap_export()371 void cb_216_wrap_export()
372 {
373 if (check_216fields()) {
374 if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 0)
375 return;
376 update_header(CHANGED);
377 }
378 update_216fields();
379
380 if (base_216_filename == string("new").append(F216_EXT) ||
381 base_216_filename == string("default").append(F216_EXT) )
382 if (!cb_216_save_as()) return;
383
384 string wrapfilename = WRAP_send_dir;
385 wrapfilename.append(base_216_filename);
386 wrapfilename.append(".wrap");
387 const char *p = FSEL::saveas(
388 "Save as wrap file",
389 "Wrap file\t*.{wrap,WRAP}",
390 wrapfilename.c_str());
391 if (p) {
392 string pext = fl_filename_ext(p);
393 wrapfilename = p;
394 update_header(FROM);
395 buff216.assign(header("<ics216>"));
396 make_buff216(true);
397 export_wrapfile(base_216_filename, wrapfilename, buff216, pext != ".wrap");
398
399 buff216.assign(header("<ics216>"));
400 make_buff216(false);
401 write_216(def_216_filename);
402 }
403 }
404
cb_216_wrap_autosend()405 void cb_216_wrap_autosend()
406 {
407 if (check_216fields()) {
408 if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 0)
409 return;
410 update_header(CHANGED);
411 }
412 update_216fields();
413
414 if (base_216_filename == string("new").append(F216_EXT) ||
415 base_216_filename == string("default").append(F216_EXT) )
416 if (!cb_216_save_as()) return;
417
418 update_header(FROM);
419 buff216.assign(header("<ics216>"));
420 make_buff216(true);
421 xfr_via_socket(base_216_filename, buff216);
422
423 buff216.assign(header("<ics216>"));
424 make_buff216(false);
425 write_216(def_216_filename);
426 }
427
cb_216_load_template()428 void cb_216_load_template()
429 {
430 string def_216_filename = def_216_TemplateName;
431 const char *p = FSEL::select(
432 "Open template file",
433 string("Template file\t*").append(T216_EXT).c_str(),
434 def_216_filename.c_str());
435 if (p) {
436 clear_216_form();
437 read_data_file(p);
438 def_216_TemplateName = p;
439 show_filename(def_216_TemplateName);
440 using_ics216_template = true;
441 }
442 }
443
cb_216_save_template()444 void cb_216_save_template()
445 {
446 if (!using_ics216_template) {
447 cb_216_save_as_template();
448 return;
449 }
450 string def_216_filename = def_216_TemplateName;
451 const char *p = FSEL::saveas(
452 "Save template file",
453 string("Template file\t*").append(T216_EXT).c_str(),
454 def_216_filename.c_str());
455 if (p) {
456 update_header(CHANGED);
457 buff216.assign(header("<ics216>"));
458 make_buff216();
459 write_216(p);
460 }
461 }
462
cb_216_save_as_template()463 void cb_216_save_as_template()
464 {
465 string def_216_filename = def_216_TemplateName;
466 const char *p = FSEL::saveas(
467 "Save as template file",
468 string("Template file\t*").append(T216_EXT).c_str(),
469 def_216_filename.c_str());
470 if (p) {
471 const char *pext = fl_filename_ext(p);
472 def_216_TemplateName = p;
473 if (strlen(pext) == 0) def_216_TemplateName.append(T216_EXT);
474 remove_spaces_from_filename(def_216_TemplateName);
475 clear_header();
476 update_header(CHANGED);
477 buff216.assign(header("<ics216>"));
478 make_buff216();
479 write_216(def_216_TemplateName);
480 show_filename(def_216_TemplateName);
481 using_ics216_template = true;
482 }
483 }
484
cb_216_open()485 void cb_216_open()
486 {
487 const char *p = FSEL::select(
488 _("Open data file"),
489 string("ICS-216\t*").append(F216_EXT).c_str(),
490 def_216_filename.c_str());
491 if (!p) return;
492 if (strlen(p) == 0) return;
493 clear_216_form();
494 read_data_file(p);
495 using_ics216_template = false;
496 def_216_filename = p;
497 show_filename(def_216_filename);
498 }
499
write_216(string s)500 void write_216(string s)
501 {
502 FILE *file216 = fopen(s.c_str(), "w");
503 if (!file216) return;
504
505 fwrite(buff216.c_str(), buff216.length(), 1, file216);
506 fclose(file216);
507 }
508
cb_216_save_as()509 bool cb_216_save_as()
510 {
511 const char *p;
512 string newfilename;
513
514 string name = named_file();
515 if (!name.empty()) {
516 name.append(F216_EXT);
517 newfilename = ICS_msg_dir;
518 newfilename.append(name);
519 } else
520 newfilename = def_216_filename;
521
522 p = FSEL::saveas(
523 _("Save data file"),
524 string("ICS-216\t*").append(F216_EXT).c_str(),
525 newfilename.c_str());
526
527 if (!p) return false;
528 if (strlen(p) == 0) return false;
529
530 if (progStatus.sernbr_fname) update_sernbr();
531
532 const char *pext = fl_filename_ext(p);
533 def_216_filename = p;
534 if (strlen(pext) == 0) def_216_filename.append(F216_EXT);
535
536 remove_spaces_from_filename(def_216_filename);
537 update_216fields();
538 update_header(NEW);
539 buff216.assign(header("<ics216>"));
540 make_buff216();
541 write_216(def_216_filename);
542
543 using_ics216_template = false;
544 show_filename(def_216_filename);
545 return true;
546 }
547
cb_216_save()548 void cb_216_save()
549 {
550 if (base_216_filename == string("new").append(F216_EXT) ||
551 base_216_filename == string("default").append(F216_EXT) ||
552 using_ics216_template == true) {
553 cb_216_save_as();
554 return;
555 }
556 if (check_216fields()) update_header(CHANGED);
557 update_216fields();
558 buff216.assign(header("<ics216>"));
559 make_buff216();
560 write_216(def_216_filename);
561 using_ics216_template = false;
562 }
563
cb_216_html()564 void cb_216_html()
565 {
566 string fname_name = fl_filename_name(def_216_filename.c_str());
567 size_t p = fname_name.rfind('.');
568 if (p != string::npos) fname_name.erase(p);
569
570 string ics216_fname = ICS_dir;
571 ics216_fname.append(fname_name);
572 ics216_fname.append(".html");
573
574 string html_text = "";
575
576 update_216fields();
577 string form216 = ics216_html_template;
578
579 replacestr(form216, TITLE, fname_name);
580 replacestr(form216, ics216_incident, s216_incident );
581 replacestr(form216, ics216_date, s216_date );
582 replacestr(form216, ics216_time, s216_time );
583 replacestr(form216, ics216_branch, s216_branch );
584 replacestr(form216, ics216_agc, s216_agc );
585 replacestr(form216, ics216_op_period, s216_op_period );
586 replacestr(form216, ics216_tac_freq, s216_tac_freq );
587 replacestr(form216, ics216_prepared_by, s216_prepared_by );
588
589 for (int i = 0; i < 4; i++) {
590 replacestr(form216, ics_216_nn( ics216_div_grp, i), s216_div_grp[i] );
591 replacestr(form216, ics_216_nn( ics216_agency, i), s216_agency[i] );
592 }
593 for (int i = 0; i < 36; i++) {
594 replacestr(form216, ics_216_nn( ics216_ag, i), s216_ag[i] );
595 replacestr(form216, ics_216_nn( ics216_id, i), s216_id[i] );
596 replacestr(form216, ics_216_nn( ics216_rr, i), s216_rr[i] );
597 }
598
599 FILE *file216 = fopen(ics216_fname.c_str(), "w");
600 fprintf(file216,"%s", form216.c_str());
601 fclose(file216);
602
603 open_url(ics216_fname.c_str());
604 }
605
cb_216_msg_type()606 void cb_216_msg_type()
607 {
608 if (tabs_msg_type->value() == tab_ics216 ) {
609 tab_ics216_type->value(tab_216_1);
610 show_filename(def_216_filename);
611 }
612 }
613
cb_216_textout()614 void cb_216_textout()
615 {
616 string ics216_fname = ICS_dir;
617 ics216_fname.append("ics216.txt");
618
619 update_216fields();
620 string form216 = ics216_text_template;
621
622 replacestr(form216, ics216_incident, s216_incident );
623 replacestr(form216, ics216_date, s216_date );
624 replacestr(form216, ics216_time, s216_time );
625 replacestr(form216, ics216_branch, s216_branch );
626 replacestr(form216, ics216_agc, s216_agc );
627 replacestr(form216, ics216_op_period, s216_op_period );
628 replacestr(form216, ics216_tac_freq, s216_tac_freq );
629 replacestr(form216, ics216_prepared_by, s216_prepared_by );
630
631 for (int i = 0; i < 4; i++) {
632 replacestr(form216, ics_216_nn( ics216_div_grp, i), s216_div_grp[i] );
633 replacestr(form216, ics_216_nn( ics216_agency, i), s216_agency[i] );
634 }
635 for (int i = 0; i < 36; i++) {
636 replacestr(form216, ics_216_nn( ics216_ag, i), s216_ag[i] );
637 replacestr(form216, ics_216_nn( ics216_id, i), s216_id[i] );
638 replacestr(form216, ics_216_nn( ics216_rr, i), s216_rr[i] );
639 }
640
641 FILE *file216 = fopen(ics216_fname.c_str(), "w");
642 fprintf(file216,"%s", form216.c_str());
643 fclose(file216);
644
645 open_url(ics216_fname.c_str());
646 }
647