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