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 "combo.h"
53 #include "date.h"
54 #include "calendar.h"
55 #include "icons.h"
56 #include "fileselect.h"
57 #include "wrap.h"
58 #include "status.h"
59 #include "parse_xml.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 #include "wx_strings.h"
75 
76 string buffstorm;
77 string def_storm_filename = "";
78 string base_storm_filename = "";
79 string def_storm_TemplateName = "";
80 
81 string	storm_date;
82 string	storm_time;
83 string	storm_zone;
84 string	storm_state;
85 string	storm_county;
86 string	storm_location;
87 bool	storm_tornado;
88 string	storm_tornado_cat;
89 bool	storm_hail;
90 string	storm_hail_size;
91 bool	storm_wind;
92 string	storm_wind_cat;
93 bool	storm_flood;
94 string	storm_flood_cat;
95 bool	storm_damage;
96 string	storm_damage_cat;
97 bool	storm_snow;
98 string	storm_snow_tot;
99 string	storm_snow_dur;
100 bool	storm_f_rain;
101 string	storm_f_rain_tot;
102 string	storm_f_rain_dur;
103 bool	storm_h_rain;
104 string	storm_h_rain_tot;
105 string	storm_h_rain_dur;
106 string	storm_o_name;
107 string	storm_o_email;
108 string	storm_o_tele;
109 string	storm_o_profile;
110 string 	storm_details;
111 
112 // could not use real names ... WIN32 barfs
113 enum STORM_QTYPE { B, D, S, M, T, I, F, C, O, E };
114 // bool, string, multi-line string, text, int, float, character, cOmbo, empty
115 
116 struct STORM_QUAD {
117 	STORM_QTYPE  qtype;  // type of field
118 	string html_fld;
119 	void   *ptr;
120 	Fl_Widget *widget; };
121 
122 STORM_QUAD sQ[] = {
123 { D,	":date:",			&storm_date,			w_storm_date },
124 { S,	":time:",			&storm_time,			w_storm_time },
125 { O,	":zone:",			&storm_zone,			w_storm_zone },
126 { O,	":state:",			&storm_state,			w_storm_state },
127 { O,	":county:",			&storm_county,			w_storm_county },
128 { S,	":location:",		&storm_location,		w_storm_location },
129 { B,	":tornado:",		&storm_tornado,			w_storm_tornado },
130 { O,	":tornado_cat:",	&storm_tornado_cat,		w_storm_tornado_cat },
131 { B,	":hail:",			&storm_hail,			w_storm_hail },
132 { O,	":hail_size:",		&storm_hail_size,		w_storm_hail_size },
133 { B,	":high_wind:",		&storm_wind,			w_storm_wind },
134 { O,	":speed:",			&storm_wind_cat,		w_storm_wind_cat },
135 { B,	":flood:",			&storm_flood,			w_storm_flood },
136 { O,	":flood_cat:",		&storm_flood_cat,		w_storm_flood_cat },
137 { B,	":damage:",			&storm_damage,			w_storm_damage },
138 { O,	":damage_cat:",		&storm_damage_cat,		w_storm_damage_cat },
139 { B,	":snow:",			&storm_snow,			w_storm_snow },
140 { O,	":snow_tot:",		&storm_snow_tot,		w_storm_snow_tot },
141 { O,	":snow_dur:",		&storm_snow_dur,		w_storm_snow_dur },
142 { B,	":f_rain:",			&storm_f_rain,			w_storm_f_rain },
143 { O,	":f_rain_tot:",		&storm_f_rain_tot,		w_storm_f_rain_tot },
144 { O,	":f_rain_dur:",		&storm_f_rain_dur,		w_storm_f_rain_dur },
145 { B,	":h_rain:",			&storm_h_rain,			w_storm_h_rain },
146 { O,	":h_rain_tot:",		&storm_h_rain_tot,		w_storm_h_rain_tot },
147 { O,	":h_rain_dur:",		&storm_h_rain_dur,		w_storm_h_rain_dur },
148 { S,	":o_name:",			&storm_o_name,			w_storm_o_name },
149 { S,	":o_email:",		&storm_o_email,			w_storm_o_email },
150 { S,	":o_tele:",			&storm_o_tele,			w_storm_o_tele },
151 { O,	":o_profile:",		&storm_o_profile,		w_storm_o_profile },
152 { T,	":details:",		&storm_details,			w_storm_details }
153 };
154 
155 int num_quads = (int)(sizeof(sQ) / sizeof(STORM_QUAD));
156 
157 bool using_storm_template = false;
158 
159 //------------------------------------------------------------------------------
160 // required to initialize the control pointers in the QUAD array
161 //------------------------------------------------------------------------------
162 static bool fields_initialized = false;
163 
init_widget(string s,Fl_Widget * w)164 static void init_widget(string s, Fl_Widget * w)
165 {
166 	for (int i = 0; i < num_quads; i++) {
167 		if (sQ[i].html_fld == s) {
168 			sQ[i].widget = w;
169 			break;
170 		}
171 	}
172 }
173 
init_widgets()174 static void init_widgets()
175 {
176 	init_widget(":date:", (Fl_Widget *)w_storm_date);
177 	init_widget(":time:", (Fl_Widget *)w_storm_time);
178 	init_widget(":zone:", (Fl_Widget *)w_storm_zone);
179 	init_widget(":state:", (Fl_Widget *)w_storm_state);
180 	init_widget(":county:", (Fl_Widget *)w_storm_county);
181 	init_widget(":location:", (Fl_Widget *)w_storm_location);
182 	init_widget(":flood:", (Fl_Widget *)w_storm_flood);
183 	init_widget(":flood_cat:", (Fl_Widget *)w_storm_flood_cat);
184 	init_widget(":hail:", (Fl_Widget *)w_storm_hail);
185 	init_widget(":hail_size:", (Fl_Widget *)w_storm_hail_size);
186 	init_widget(":high_wind:", (Fl_Widget *)w_storm_wind);
187 	init_widget(":speed:", (Fl_Widget *)w_storm_wind_cat);
188 	init_widget(":tornado:", (Fl_Widget *)w_storm_tornado);
189 	init_widget(":tornado_cat:", (Fl_Widget *)w_storm_tornado_cat);
190 	init_widget(":damage:", (Fl_Widget *)w_storm_damage);
191 	init_widget(":damage_cat:", (Fl_Widget *)w_storm_damage_cat);
192 	init_widget(":snow:", (Fl_Widget *)w_storm_snow);
193 	init_widget(":snow_tot:", (Fl_Widget *)w_storm_snow_tot);
194 	init_widget(":snow_dur:", (Fl_Widget *)w_storm_snow_dur);
195 	init_widget(":f_rain:", (Fl_Widget *)w_storm_f_rain);
196 	init_widget(":f_rain_tot:", (Fl_Widget *)w_storm_f_rain_tot);
197 	init_widget(":f_rain_dur:", (Fl_Widget *)w_storm_f_rain_dur);
198 	init_widget(":h_rain:", (Fl_Widget *)w_storm_h_rain);
199 	init_widget(":h_rain_tot:", (Fl_Widget *)w_storm_h_rain_tot);
200 	init_widget(":h_rain_dur:", (Fl_Widget *)w_storm_h_rain_dur);
201 	init_widget(":o_name:", (Fl_Widget *)w_storm_o_name);
202 	init_widget(":o_email:", (Fl_Widget *)w_storm_o_email);
203 	init_widget(":o_tele:", (Fl_Widget *)w_storm_o_tele);
204 	init_widget(":o_profile:", (Fl_Widget *)w_storm_o_profile);
205 	init_widget(":details:", (Fl_Widget *)w_storm_details);
206 
207 	fields_initialized = true;
208 }
209 //------------------------------------------------------------------------------
210 
211 // bool, string, multi-line string, text, int, float, character, cOmbo, empty
212 //enum STORM_QTYPE { B, D, S, M, T, I, F, C, O, E };
213 
clearQUAD()214 static void clearQUAD()
215 {
216 	for (int i = 0; i < num_quads; i++) {
217 		switch (sQ[i].qtype) {
218 			case B : (*(bool *)(sQ[i].ptr)) = false; break;
219 			case S :
220 			case D :
221 			case M : ((string *)(sQ[i].ptr))->clear(); break;
222 			case T : ((string *)(sQ[i].ptr))->clear(); break;
223 			case C : (*(char *)(sQ[i].ptr)) = ' ';    break;
224 			case I : (*(int *)(sQ[i].ptr)) = 0;       break;
225 			case F : (*(float *)(sQ[i].ptr)) = 0.0;   break;
226 			case O : ((string *)(sQ[i].ptr))->clear(); break;
227 			case E : return;
228 		}
229 	}
230 }
231 
clear_stormfields()232 void clear_stormfields()
233 {
234 	if (!fields_initialized) init_widgets();
235 	clearQUAD();
236 }
237 
checkQUAD()238 static bool checkQUAD()
239 {
240 	float f = 0;
241 	char c = ' ';
242 	for (int i = 0; i < num_quads; i++) {
243 		switch (sQ[i].qtype) {
244 			case B:
245 				if (*((bool *)(sQ[i].ptr)) != ((Fl_Check_Button *)sQ[i].widget)->value()){
246 					return true;
247 				}
248 				break;
249 			case S:
250 			case M:
251 				if (*((string *)(sQ[i].ptr)) != ((Fl_Input2 *)sQ[i].widget)->value()){
252 					return true;
253 				}
254 				break;
255 			case D:
256 				if (*((string *)(sQ[i].ptr)) != ((Fl_DateInput *)sQ[i].widget)->value()){
257 					return true;
258 				}
259 				break;
260 			case T:
261 				if (*((string *)(sQ[i].ptr)) != ((FTextEdit *)sQ[i].widget)->buffer()->text()){
262 					return true;
263 				}
264 				break;
265 			case C:
266 				c = ' ';
267 				if (((Fl_Input2 *)sQ[i].widget)->value()[0])
268 					c = ((Fl_Input2 *)sQ[i].widget)->value()[0];
269 				if (*((char *)(sQ[i].ptr)) != c){
270 					return true;
271 				}
272 				break;
273 			case I:
274 				i = 0;
275 				if (((Fl_Input2 *)sQ[i].widget)->value()[0])
276 					sscanf( ((Fl_Input2 *)sQ[i].widget)->value(), "%d", &i);
277 				if (*((int *)(sQ[i].ptr)) != i){
278 					return true;
279 				}
280 				break;
281 			case F:
282 				f = 0;
283 				if (((Fl_Input2 *)sQ[i].widget)->value()[0])
284 					sscanf( ((Fl_Input2 *)sQ[i].widget)->value(), "%f", &f);
285 				if (*((float *)(sQ[i].ptr)) != f) {
286 					return true;
287 				}
288 				break;
289 			case O:
290 				if (((Fl_ListBox *)sQ[i].widget)->index() == 0) break;
291 				if (*((string *)(sQ[i].ptr)) != ((Fl_ListBox *)sQ[i].widget)->value()) {
292 					return true;
293 				}
294 				break;
295 			case E:
296 			default: return false;
297 		}
298 	}
299 	return false;
300 }
301 
check_stormfields()302 bool check_stormfields()
303 {
304 	return checkQUAD();
305 }
306 
updateQUAD()307 static void updateQUAD()
308 {
309 	float f = 0;
310 	char c = ' ';
311 	for (int i = 0; i < num_quads; i++) {
312 		switch (sQ[i].qtype) {
313 			case B:
314 				*((bool *)(sQ[i].ptr)) = ((Fl_Check_Button *)sQ[i].widget)->value();
315 				break;
316 			case S:
317 			case M:
318 				*((string *)(sQ[i].ptr)) = ((Fl_Input2 *)sQ[i].widget)->value();
319 				break;
320 			case D:
321 				*((string *)(sQ[i].ptr)) = ((Fl_DateInput *)sQ[i].widget)->value();
322 				break;
323 			case O:
324 				{	string s = ((Fl_ListBox *)sQ[i].widget)->value();
325 					if (s.find("--") == 0)
326 						((string *)(sQ[i].ptr))->clear();
327 					else
328 						*((string *)(sQ[i].ptr)) = ((Fl_ListBox *)sQ[i].widget)->value();
329 				}
330 				break;
331 			case T:
332 				*((string *)(sQ[i].ptr)) = ((FTextEdit *)sQ[i].widget)->buffer()->text();
333 				break;
334 			case C:
335 				c = ' ';
336 				if (((Fl_Input2 *)sQ[i].widget)->value()[0])
337 					c = ((Fl_Input2 *)sQ[i].widget)->value()[0];
338 				*((char *)(sQ[i].ptr)) = c;
339 				break;
340 			case I:
341 				i = 0;
342 				if (((Fl_Input2 *)sQ[i].widget)->value()[0])
343 					sscanf( ((Fl_Input2 *)sQ[i].widget)->value(), "%d", &i);
344 				*((int *)(sQ[i].ptr)) = i;
345 				break;
346 			case F:
347 				f = 0;
348 				if (((Fl_Input2 *)sQ[i].widget)->value()[0])
349 					sscanf( ((Fl_Input2 *)sQ[i].widget)->value(), "%f", &f);
350 				*((float *)(sQ[i].ptr)) = f;
351 				break;
352 			case E:
353 			default: return;
354 		}
355 	}
356 }
357 
update_stormfields()358 void update_stormfields()
359 {
360 	if (!fields_initialized) init_widgets();
361 	updateQUAD();
362 }
363 
activate_listbox()364 static void activate_listbox()
365 {
366 	if (w_storm_flood->value())
367 		w_storm_flood_cat->activate();
368 	else
369 		w_storm_flood_cat->deactivate();
370 	if (w_storm_hail->value())
371 		w_storm_hail_size->activate();
372 	else
373 		w_storm_hail_size->deactivate();
374 	if (w_storm_wind->value())
375 		w_storm_wind_cat->activate();
376 	else
377 		w_storm_wind_cat->deactivate();
378 	if (w_storm_tornado->value())
379 		w_storm_tornado_cat->activate();
380 	else
381 		w_storm_tornado_cat->deactivate();
382 	if (w_storm_damage->value())
383 		w_storm_damage_cat->activate();
384 	else
385 		w_storm_damage_cat->deactivate();
386 	if (w_storm_snow->value()) {
387 		w_storm_snow_tot->activate();
388 		w_storm_snow_dur->activate();
389 	} else {
390 		w_storm_snow_tot->deactivate();
391 		w_storm_snow_dur->deactivate();
392 	}
393 	if (w_storm_f_rain->value()) {
394 		w_storm_f_rain_tot->activate();
395 		w_storm_f_rain_dur->activate();
396 	} else {
397 		w_storm_f_rain_tot->deactivate();
398 		w_storm_f_rain_dur->deactivate();
399 	}
400 	if (w_storm_h_rain->value()) {
401 		w_storm_h_rain_tot->activate();
402 		w_storm_h_rain_dur->activate();
403 	} else {
404 		w_storm_h_rain_tot->deactivate();
405 		w_storm_h_rain_dur->deactivate();
406 	}
407 }
408 
updateFORM()409 static void updateFORM()
410 {
411 	char val[20];
412 	for (int i = 0; i < num_quads; i++ ) {
413 		switch (sQ[i].qtype) {
414 			case B:
415 				((Fl_Check_Button *)sQ[i].widget)->value(*((bool *)(sQ[i].ptr)));
416 				break;
417 			case S:
418 			case M:
419 				((Fl_Input2 *)sQ[i].widget)->value(((string *)(sQ[i].ptr))->c_str());
420 				break;
421 			case D:
422 				((Fl_DateInput *)sQ[i].widget)->value(((string *)(sQ[i].ptr))->c_str());
423 				break;
424 			case O:
425 				if (((string *)(sQ[i].ptr))->empty())
426 					((Fl_ListBox *)sQ[i].widget)->index(0);
427 				else
428 					((Fl_ListBox *)sQ[i].widget)->put_value(((string *)(sQ[i].ptr))->c_str());
429 				break;
430 			case T:
431 				((FTextEdit *)sQ[i].widget)->clear();
432 				((FTextEdit *)sQ[i].widget)->add(((string *)(sQ[i].ptr))->c_str());
433 				break;
434 			case C:
435 				val[0] = *((char *)(sQ[i].ptr));
436 				val[1] = 0;
437 				((Fl_Input2 *)sQ[i].widget)->value(val);
438 				break;
439 			case I:
440 				if (*((int *)(sQ[i].ptr)) == 0)
441 					((Fl_Input2 *)sQ[i].widget)->value("");
442 				else {
443 					snprintf(val, sizeof(val), "%d", *((int *)(sQ[i].ptr)));
444 					((Fl_Input2 *)sQ[i].widget)->value(val);
445 				}
446 				break;
447 			case F:
448 				snprintf(val, sizeof(val), "%f", *((float *)(sQ[i].ptr)));
449 				((Fl_Input2 *)sQ[i].widget)->value(val);
450 				break;
451 			case E:
452 			default: return;
453 		}
454 	}
455 }
456 
update_stormform()457 void update_stormform()
458 {
459 	if (!fields_initialized) init_widgets();
460 	updateFORM();
461 	activate_listbox();
462 }
463 
clear_storm_form()464 void clear_storm_form()
465 {
466 	clear_stormfields();
467 	update_stormform();
468 	w_storm_state->index(0);
469 	set_storm_counties(0);
470 	w_storm_o_profile->index(0);
471 	w_storm_location->index(0);
472 	w_storm_zone->index(0);
473 }
474 
475 static string mbuff;
476 
make_buffQUAD()477 static void make_buffQUAD()
478 {
479 	string one = "1"; string zero = "0";
480 	string sval = " ";
481 	char szval[20];
482 	for (int i = 0; i < num_quads; i++) {
483 		switch (sQ[i].qtype) {
484 			case B:
485 				if (*((bool *)(sQ[i].ptr)) == true)
486 					mbuff.append( lineout( sQ[i].html_fld, *((bool *)(sQ[i].ptr)) ? one : zero));
487 				break;
488 			case O: case S: case D: case M:
489 				if (((string *)(sQ[i].ptr))->length())
490 					mbuff.append( lineout( sQ[i].html_fld, *((string *)(sQ[i].ptr))));
491 				break;
492 			case T:
493 				mbuff.append( lineout( sQ[i].html_fld, *((string *)(sQ[i].ptr))));
494 				break;
495 			case C:
496 				if ((*(char *)(sQ[i].ptr)) != 0 && *((char *)(sQ[i].ptr)) != ' ') {
497 					sval = " ";
498 					sval[0] = *((char *)(sQ[i].ptr));
499 					mbuff.append( lineout( sQ[i].html_fld, sval));
500 				}
501 				break;
502 			case I:
503 				if (*((int*)(sQ[i].ptr)) > 0) {
504 					snprintf(szval, sizeof(szval), "%d", *((int *)(sQ[i].ptr)) );
505 					sval = szval;
506 					mbuff.append( lineout( sQ[i].html_fld, sval) );
507 				}
508 				break;
509 			case F:
510 				if (*((float *)(sQ[i].ptr)) > 0) {
511 					snprintf(szval, sizeof(szval), "%f", *((float *)(sQ[i].ptr)));
512 					sval = szval;
513 					mbuff.append( lineout( sQ[i].html_fld, sval) );
514 				}
515 				break;
516 			case E:
517 			default: return;
518 		}
519 	}
520 }
521 
make_buff_storm(bool compress=false)522 void make_buff_storm(bool compress = false)
523 {
524 	mbuff.clear();
525 	make_buffQUAD();
526 	if (compress) compress_maybe(mbuff);
527 	buffstorm.append(mbuff);
528 }
529 
readQUAD(string data)530 static void readQUAD(string data)
531 {
532 	float f;
533 	for (int i = 0; i < num_quads; i++) {
534 		switch (sQ[i].qtype) {
535 			case B:
536 				*((bool *)(sQ[i].ptr)) = (findstr( data, sQ[i].html_fld ) == "1");
537 				break;
538 			case D: case O: case S: case M:
539 				*((string *)(sQ[i].ptr)) = findstr( data, sQ[i].html_fld );
540 				break;
541 			case T:
542 				*((string *)(sQ[i].ptr)) = findstr( data, sQ[i].html_fld );
543 				break;
544 			case C:
545 				*((char *)(sQ[i].ptr)) = findstr( data, sQ[i].html_fld )[0];
546 				break;
547 			case I:
548 				i = 0;
549 				sscanf( findstr( data, sQ[i].html_fld ).c_str(), "%d", &i);
550 				*((int *)(sQ[i].ptr)) = i;
551 				break;
552 			case F:
553 				f = 0;
554 				sscanf( findstr( data, sQ[i].html_fld ).c_str(), "%f", &f);
555 				*((float *)(sQ[i].ptr)) = f;
556 				break;
557 			case E:
558 			default: return;
559 		}
560 	}
561 }
562 
read_storm_buffer(string data)563 void read_storm_buffer(string data)
564 {
565 	clear_stormfields();
566 	read_header(data);
567 
568 	readQUAD (data);
569 	update_stormform();
570 	int idx = w_storm_state->index();
571 	set_storm_counties(idx);
572 	w_storm_county->value( ((string *)(sQ[4].ptr))->c_str() );
573 }
574 
cb_storm_new()575 void cb_storm_new()
576 {
577 	if (check_stormfields()) {
578 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 1) {
579 			update_header(CHANGED);
580 			cb_storm_save();
581 		}
582 	}
583 	clear_storm_form();
584 	clear_header();
585 	def_storm_filename = ICS_msg_dir;
586 	def_storm_filename.append("new").append(FSTRM_EXT);
587 	show_filename(def_storm_filename);
588 	using_storm_template = false;
589 }
590 
cb_storm_import()591 void cb_storm_import()
592 {
593 	fl_alert2("Not implemented");
594 }
595 
cb_storm_export()596 void cb_storm_export()
597 {
598 	fl_alert2("Not implemented");
599 }
600 
cb_storm_wrap_import(string wrapfilename,string inpbuffer)601 void cb_storm_wrap_import(string wrapfilename, string inpbuffer)
602 {
603 	clear_storm_form();
604 	read_storm_buffer(inpbuffer);
605 	def_storm_filename = ICS_msg_dir;
606 	def_storm_filename.append(wrapfilename);
607 	show_filename(def_storm_filename);
608 	using_storm_template = false;
609 }
610 
eval_storm_fsize()611 int eval_storm_fsize()
612 {
613 	Ccrc16 chksum;
614 	evalstr.assign("[WRAP:beg][WRAP:lf][WRAP:fn ");
615 	evalstr.append(base_storm_filename).append("]");
616 	update_stormfields();
617 	update_header(FROM);
618 	evalstr.append(header("<storm_wx>"));
619 	buffstorm.clear();
620 	make_buff_storm(true);
621 	if (buffstorm.empty()) return 0;
622 	compress_maybe( buffstorm );
623 	evalstr.append( buffstorm );
624 	evalstr.append("[WRAP:chksum ").append(chksum.scrc16(evalstr)).append("][WRAP:end]");
625 	return evalstr.length();
626 }
627 
cb_storm_wrap_export()628 void cb_storm_wrap_export()
629 {
630 	if (check_stormfields()) {
631 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 0)
632 			return;
633 		update_header(CHANGED);
634 	}
635 	update_stormfields();
636 
637 	if (base_storm_filename == string("new").append(FSTRM_EXT) ||
638 		base_storm_filename == string("default").append(FSTRM_EXT) )
639 		if (!cb_storm_save_as()) return;
640 
641 	string wrapfilename = WRAP_send_dir;
642 	wrapfilename.append(base_storm_filename);
643 	wrapfilename.append(".wrap");
644 	const char *p = FSEL::saveas(
645 			"Save as wrap file",
646 			"Wrap file\t*.{wrap,WRAP}",
647 			wrapfilename.c_str());
648 	if (p) {
649 		string pext = fl_filename_ext(p);
650 		wrapfilename = p;
651 
652 		update_header(FROM);
653 		buffstorm.assign(header("<storm_wx>"));
654 		make_buff_storm(true);
655 		export_wrapfile(base_storm_filename, wrapfilename, buffstorm, pext != ".wrap");
656 
657 		buffstorm.assign(header("<storm_wx>"));
658 		make_buff_storm(false);
659 		write_storm(def_storm_filename);
660 	}
661 }
662 
cb_storm_wrap_autosend()663 void cb_storm_wrap_autosend()
664 {
665 	if (check_stormfields()) {
666 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 0)
667 			return;
668 		update_header(CHANGED);
669 	}
670 	update_stormfields();
671 
672 	if (base_storm_filename == string("new").append(FSTRM_EXT) ||
673 		base_storm_filename == string("default").append(FSTRM_EXT) )
674 		if (!cb_storm_save_as()) return;
675 
676 	update_header(FROM);
677 	buffstorm.assign(header("<storm_wx>"));
678 	make_buff_storm(true);
679 	xfr_via_socket(base_storm_filename, buffstorm);
680 
681 	buffstorm.assign(header("<storm_wx>"));
682 	make_buff_storm(false);
683 	write_storm(def_storm_filename);
684 }
685 
cb_storm_load_template()686 void cb_storm_load_template()
687 {
688 	string def_storm_filename = def_storm_TemplateName;
689 	const char *p = FSEL::select(
690 			"Open template file",
691 			string("Template file\t*").append(TSTRM_EXT).c_str(),
692 			def_storm_filename.c_str());
693 	if (p) {
694 		clear_storm_form();
695 		read_data_file(p);
696 		def_storm_TemplateName = p;
697 		show_filename(def_storm_TemplateName);
698 		using_storm_template = true;
699 	}
700 }
701 
cb_storm_save_template()702 void cb_storm_save_template()
703 {
704 	if (!using_storm_template) {
705 		cb_storm_save_as_template();
706 		return;
707 	}
708 	string def_storm_filename = def_storm_TemplateName;
709 	const char *p = FSEL::saveas(
710 			"Save template file",
711 			string("Template file\t*").append(TSTRM_EXT).c_str(),
712 			def_storm_filename.c_str());
713 	if (p) {
714 		update_header(CHANGED);
715 		update_stormfields();
716 		buffstorm.assign(header("<storm_wx>"));
717 		make_buff_storm();
718 		write_storm(p);
719 	}
720 }
721 
cb_storm_save_as_template()722 void cb_storm_save_as_template()
723 {
724 	string def_storm_filename = def_storm_TemplateName;
725 	const char *p = FSEL::saveas(
726 			"Save as template file",
727 			string("Template file\t*").append(TSTRM_EXT).c_str(),
728 			def_storm_filename.c_str());
729 	if (p) {
730 		const char *pext = fl_filename_ext(p);
731 		def_storm_TemplateName = p;
732 		if (strlen(pext) == 0) def_storm_TemplateName.append(TSTRM_EXT);
733 		remove_spaces_from_filename(def_storm_TemplateName);
734 
735 		clear_header();
736 		update_header(CHANGED);
737 		update_stormfields();
738 		buffstorm.assign(header("<storm_wx>"));
739 		make_buff_storm();
740 		write_storm(def_storm_TemplateName);
741 
742 		show_filename(def_storm_TemplateName);
743 		using_storm_template = true;
744 	}
745 }
746 
cb_storm_open()747 void cb_storm_open()
748 {
749 	const char *p = FSEL::select(
750 			_("Open data file"),
751 			string("ICS-storm\t*").append(FSTRM_EXT).c_str(),
752 			def_storm_filename.c_str());
753 	if (!p) return;
754 	if (strlen(p) == 0) return;
755 	clear_storm_form();
756 	read_data_file(p);
757 	using_storm_template = false;
758 	def_storm_filename = p;
759 	show_filename(def_storm_filename);
760 }
761 
write_storm(string s)762 void write_storm(string s)
763 {
764 	FILE *filestorm = fopen(s.c_str(), "w");
765 	if (!filestorm) return;
766 
767 	fwrite(buffstorm.c_str(), buffstorm.length(), 1, filestorm);
768 	fclose(filestorm);
769 }
770 
771 
cb_storm_save_as()772 bool cb_storm_save_as()
773 {
774 	const char *p;
775 	string newfilename;
776 
777 	string name = named_file();
778 	if (!name.empty()) {
779 		name.append(FSTRM_EXT);
780 		newfilename = ICS_msg_dir;
781 		newfilename.append(name);
782 	} else
783 		newfilename = def_storm_filename;
784 
785 	p = FSEL::saveas(
786 			_("Save data file"),
787 			string("ICS-storm\t*").append(FSTRM_EXT).c_str(),
788 			newfilename.c_str());
789 
790 	if (!p) return false;
791 	if (strlen(p) == 0) return false;
792 
793 	if (progStatus.sernbr_fname) update_sernbr();
794 
795 	const char *pext = fl_filename_ext(p);
796 	def_storm_filename = p;
797 	if (strlen(pext) == 0) def_storm_filename.append(FSTRM_EXT);
798 
799 	remove_spaces_from_filename(def_storm_filename);
800 
801 	update_header(NEW);
802 	update_stormfields();
803 	buffstorm.assign(header("<storm_wx>"));
804 	make_buff_storm();
805 	write_storm(def_storm_filename);
806 
807 	using_storm_template = false;
808 	show_filename(def_storm_filename);
809 	return true;
810 }
811 
cb_storm_save()812 void cb_storm_save()
813 {
814 	if (base_storm_filename == string("new").append(FSTRM_EXT) ||
815 		base_storm_filename == string("default").append(FSTRM_EXT) ||
816 		using_storm_template == true) {
817 		cb_storm_save_as();
818 		return;
819 	}
820 
821 	if (check_stormfields()) update_header(CHANGED);
822 	update_stormfields();
823 	buffstorm.assign(header("<storm_wx>"));
824 	make_buff_storm();
825 	write_storm(def_storm_filename);
826 
827 	using_storm_template = false;
828 }
829 
830 static string X = "x"; string SP = "_";
831 static string sval = " ";
832 static string del = "";
833 
quad_to_html(string & target)834 static void quad_to_html(string &target)
835 {
836 	char szval[20];
837 	for (int i = 0; i < num_quads; i++) {
838 		if (sQ[i].qtype == B)
839 			replacestr(target, sQ[i].html_fld, *((bool *)(sQ[i].ptr)) ? X : SP);
840 		else if (sQ[i].qtype == O ) {
841 			string s = *((string *)(sQ[i].ptr));
842 			if (sQ[i].html_fld == ":state:") {
843 				if (s.length() > 1) s.erase(2);
844 				replacestr(target, sQ[i].html_fld, s);
845 			} else if (sQ[i].html_fld == ":zone") {
846 				size_t cp = s.find(',');
847 				s.erase(cp);
848 				replacestr(target, sQ[i].html_fld, s);
849 			} else if (s.find("--") == 0) {
850 				replacestr(target, sQ[i].html_fld, del);
851 			} else {
852 				if (s.length())
853 					replacestr(target, sQ[i].html_fld, s);
854 				else replacestr(target, sQ[i].html_fld, del);
855 			}
856 		} else if (sQ[i].qtype == S || sQ[i].qtype == M || sQ[i].qtype == D) {
857 			if (((string *)(sQ[i].ptr))->length())
858 				replacestr(target, sQ[i].html_fld, *((string *)(sQ[i].ptr)));
859 			else replacestr(target, sQ[i].html_fld, del);
860 		} else if (sQ[i].qtype == M) {
861 			sval = *((string *)(sQ[i].ptr));
862 			size_t np = string::npos;
863 			while ( (np = sval.find("\n")) != string::npos)
864 				sval.replace(np, 1, "<br>");
865 			replacestr(target, sQ[i].html_fld, sval);
866 		} else if (sQ[i].qtype == T)
867 			replacestr(target, sQ[i].html_fld, *((string *)(sQ[i].ptr)));
868 		else if (sQ[i].qtype == C) {
869 			sval = " ";
870 			sval[0] = *((char *)(sQ[i].ptr));
871 			replacestr(target, sQ[i].html_fld, sval);
872 		}
873 		else if (sQ[i].qtype == I) {
874 			if (*((int *)(sQ[i].ptr)) > 0) {
875 				snprintf(szval, sizeof(szval), "%d", *((int *)(sQ[i].ptr)) );
876 				sval = szval;
877 			} else sval.clear();
878 				replacestr(target, sQ[i].html_fld, sval);
879 		}
880 		else if (sQ[i].qtype == F) {
881 			if (*((float *)(sQ[i].ptr)) != 0) {
882 				snprintf(szval, sizeof(szval), "%f", *((float *)(sQ[i].ptr)));
883 				sval = szval;
884 			} else sval.clear();
885 			replacestr(target, sQ[i].html_fld, sval);
886 		}
887 	}
888 }
889 
cb_storm_html()890 void cb_storm_html()
891 {
892 	string name_name = fl_filename_name(def_storm_filename.c_str());
893 	size_t p = name_name.rfind('.');
894 	if (p != string::npos) name_name.erase(p);
895 
896 	string storm_rptsta = ICS_dir;
897 	storm_rptsta.append(name_name);
898 	storm_rptsta.append(".html");
899 
900 	update_stormfields();
901 	string formstorm = storm_html_template;
902 
903 	replacestr(formstorm, TITLE, name_name);
904 
905 	quad_to_html (formstorm);
906 
907 	FILE *filestorm = fopen(storm_rptsta.c_str(), "w");
908 	fprintf(filestorm,"%s", formstorm.c_str());
909 	fclose(filestorm);
910 
911 	open_url(storm_rptsta.c_str());
912 }
913 
quad_to_text(string & target)914 static void quad_to_text( string &target)
915 {
916 	char szval[20];
917 	for (int i = 0; i < num_quads; i++) {
918 		if (sQ[i].qtype == B)
919 			replacestr(target, sQ[i].html_fld, *((bool *)(sQ[i].ptr)) ? X : del);
920 		else if (sQ[i].qtype == O ) {
921 			string s = *((string *)(sQ[i].ptr));
922 			if (sQ[i].html_fld == ":state:") {
923 				if (s.length() > 1) s.erase(2);
924 				replacestr(target, sQ[i].html_fld, s);
925 			} else if (sQ[i].html_fld == ":zone") {
926 				size_t cp = s.find(',');
927 				s.erase(cp);
928 				replacestr(target, sQ[i].html_fld, s);
929 			} else if (s.find("--") == 0) {
930 				replacestr(target, sQ[i].html_fld, del);
931 			} else {
932 				if (s.length())
933 					replacestr(target, sQ[i].html_fld, s);
934 				else replacestr(target, sQ[i].html_fld, del);
935 			}
936 		} else if (sQ[i].qtype == S || sQ[i].qtype == M || sQ[i].qtype == D) {
937 			if (((string *)(sQ[i].ptr))->length())
938 				replacestr(target, sQ[i].html_fld, *((string *)(sQ[i].ptr)));
939 			else replacestr(target, sQ[i].html_fld, del);
940 		} else if (sQ[i].qtype == T) {
941 			if (((string *)(sQ[i].ptr))->length())
942 				replacestr(target, sQ[i].html_fld, *((string *)(sQ[i].ptr)));
943 			else replacestr(target, sQ[i].html_fld, del);
944 		} else if (sQ[i].qtype == C) {
945 			sval = " ";
946 			sval[0] = *((char *)(sQ[i].ptr));
947 			if (sval[0] != 0 && sval[0] != ' ')
948 				replacestr(target, sQ[i].html_fld, sval);
949 			else replacestr(target, sQ[i].html_fld, del);
950 		}
951 		else if (sQ[i].qtype == I) {
952 			if (*((int *)(sQ[i].ptr)) > 0) {
953 				snprintf(szval, sizeof(szval), "%d", *((int *)(sQ[i].ptr)) );
954 				sval = szval;
955 				replacestr(target, sQ[i].html_fld, sval);
956 			} else replacestr(target, sQ[i].html_fld, del);
957 		}
958 		else if (sQ[i].qtype == F) {
959 			if (*((float *)(sQ[i].ptr)) != 0) {
960 				snprintf(szval, sizeof(szval), "%f", *((float *)(sQ[i].ptr)));
961 				sval = szval;
962 				replacestr(target, sQ[i].html_fld, sval);
963 			} else replacestr(target, sQ[i].html_fld, del);
964 		}
965 	}
966 }
967 
cb_storm_textout()968 void cb_storm_textout()
969 {
970 	string storm_rptsta = ICS_dir;
971 	storm_rptsta.append("storm.txt");
972 
973 	update_stormfields();
974 	string formstorm = storm_text_template;
975 
976 	quad_to_text (formstorm);
977 
978 	FILE *filestorm = fopen(storm_rptsta.c_str(), "w");
979 	fprintf(filestorm,"%s", formstorm.c_str());
980 	fclose(filestorm);
981 
982 	open_url(storm_rptsta.c_str());
983 }
984 
985