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 <string>
26 #include <ctime>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <stdio.h>
30 #include <errno.h>
31 
32 #include <FL/Fl.H>
33 #include <FL/Enumerations.H>
34 #include <FL/Fl_Window.H>
35 #include <FL/Fl_Button.H>
36 #include <FL/Fl_Group.H>
37 #include <FL/Fl_Sys_Menu_Bar.H>
38 #include <FL/x.H>
39 #include <FL/Fl_Help_Dialog.H>
40 #include <FL/Fl_Menu_Item.H>
41 #include <FL/Fl_File_Icon.H>
42 #include <FL/Fl_Input.H>
43 #include <FL/Fl_Check_Button.H>
44 #include <FL/fl_draw.H>
45 #include <FL/fl_ask.H>
46 #include <FL/Fl_Table_Row.H>
47 #include <FL/Fl_Browser.H>
48 
49 #include <vector>
50 
51 #include "mongoose.h"
52 
53 #include "config.h"
54 #include "flmsg.h"
55 #include "templates.h"
56 #include "debug.h"
57 #include "util.h"
58 #include "gettext.h"
59 #include "flmsg_dialog.h"
60 #include "flmsg_config.h"
61 #include "flinput2.h"
62 #include "date.h"
63 #include "calendar.h"
64 #include "icons.h"
65 #include "fileselect.h"
66 #include "wrap.h"
67 #include "status.h"
68 #include "parse_xml.h"
69 #include "icons.h"
70 #include "threads.h"
71 
72 #include "ext_string.h"
73 
74 #ifdef WIN32
75 #  include "flmsgrc.h"
76 #  include "compat.h"
77 #  define dirent fl_dirent_no_thanks
78 #endif
79 
80 #include <FL/filename.H>
81 #include "dirent-check.h"
82 
83 #include <FL/x.H>
84 #include <FL/Fl_Pixmap.H>
85 #include <FL/Fl_Image.H>
86 
87 using namespace std;
88 
89 extern int custom_select;
90 
91 extern struct mg_server *server;
92 
93 static string action_str   = "\n<FORM ACTION=\"/handle_post_request\" METHOD=\"post\" \n";
94 static string submit_str   = "\n<INPUT TYPE=\"submit\" VALUE=\"Submit Form\">\n</form ";
95 static string input_str    = "<INPUT";
96 static string select_str   = "<SELECT";
97 static string end_sel_str  = "</SELECT";
98 static string textarea_str = "<TEXTAREA";
99 static string textend_str  = "</TEXTAREA";
100 static string checked      = "CHECKED";
101 static string checkedeq    = "CHECKED=\"CHECKED\"";
102 static string selected     = "SELECTED";
103 
104 static string value_str    = "VALUE=\"";
105 static string name_str     = "NAME=\"";
106 
107 static string text_type_str =      "TYPE=\"TEXT\"";
108 static string radio_type_str =     "TYPE=\"RADIO\"";
109 static string checkbox_type_str =  "TYPE=\"CHECKBOX\"";
110 static string password_type_str =  "TYPE=\"PASSWORD\"";
111 static string number_str =         "TYPE=\"NUMBER\"";
112 static string date_str =           "TYPE=\"DATE\"";
113 static string datetime_str =       "TYPE=\"DATETIME\"";
114 static string datetime_local_str = "TYPE=\"DATETIME-LOCAL\"";
115 static string time_str =           "TYPE=\"TIME\"";
116 static string week_str =           "TYPE=\"WEEK\"";
117 static string month_str =          "TYPE=\"MONTH\"";
118 static string tel_str =            "TYPE=\"TEL\"";
119 static string email_str =          "TYPE=\"EMAIL\"";
120 
121 enum {
122 	T_TEXT, T_RADIO, T_CHECKBOX, T_AREA, T_SELECT, T_PASSWORD,
123 	T_NUMBER, T_DATE, T_DTIME, T_DTIME_LOCAL, T_TIME, T_WEEK, T_MONTH, T_TEL, T_EMAIL };
124 
125 struct INPUT_TYPE {
126 	int id;
127 	string txt;
INPUT_TYPEINPUT_TYPE128 	INPUT_TYPE(int i, string s) {
129 		id = i;
130 		txt = s;
131 	}
132 };
133 
134 static INPUT_TYPE input_types[] = {
135 	INPUT_TYPE(T_TEXT, text_type_str),
136 	INPUT_TYPE(T_PASSWORD, password_type_str),
137 	INPUT_TYPE(T_AREA, textarea_str),
138 	INPUT_TYPE(T_RADIO, radio_type_str),
139 	INPUT_TYPE(T_CHECKBOX, checkbox_type_str),
140 	INPUT_TYPE(T_SELECT, select_str),
141 	INPUT_TYPE(T_NUMBER, number_str),
142 	INPUT_TYPE(T_DATE, date_str),
143 	INPUT_TYPE(T_DTIME, datetime_str),
144 	INPUT_TYPE(T_DTIME_LOCAL, datetime_local_str),
145 	INPUT_TYPE(T_TIME, time_str),
146 	INPUT_TYPE(T_WEEK, week_str),
147 	INPUT_TYPE(T_MONTH, month_str),
148 	INPUT_TYPE(T_TEL, tel_str),
149 	INPUT_TYPE(T_EMAIL, email_str)
150 };
151 
152 struct NAME_VALUE {
153 	int    id;
154 	string name;
155 	string value;
NAME_VALUENAME_VALUE156 	NAME_VALUE(int ID, string S1, string S2) {id = ID; name = S1; value = S2;}
157 };
158 
159 // customform fields
160 
161 string custombuffer;
162 string def_custom_filename = "";
163 string base_custom_filename = "";
164 string def_custom_TemplateName = "";
165 
166 string custom_title = ":TITLE:";
167 string custom_msg = ":mg:";
168 string custom_field;
169 
170 std::vector<NAME_VALUE> name_values;
171 
172 string html_form;
173 string edit_txt;
174 
escape(string & s)175 void escape(string &s)
176 {
177 	size_t p;
178 	p = 0;
179 	while ((p = s.find("\r", p)) != string::npos)
180 		s.erase(p,1);
181 	p = 0;
182 	while ((p = s.find("\n", p)) != string::npos) {
183 		s.replace(p, 1, "\\n");
184 		p += 2;
185 	}
186 	p = 0;
187 	while ((p = s.find("\"", p)) != string::npos) {
188 		if (p == 0 || s[p-1] != '\\') {
189 			s.replace(p, 1, "\\\"");
190 			p += 2;
191 		} else p++;
192 	}
193 }
194 
unescape(string & s)195 void unescape(string &s)
196 {
197 	size_t p;
198 	p = 0;
199 	while ((p = s.find("\\n", p)) != string::npos) {
200 		s.replace(p,2,"\n");
201 		p++;
202 	}
203 	p = 0;
204 	while ((p = s.find("\\\"", p)) != string::npos) {
205 		s.replace(p,2,"\"");
206 		p++;
207 	}
208 }
209 
convert_case(string & s)210 int convert_case(string &s)
211 {
212 	std::string s1, s3;
213 	extstring s2;//s1;
214 	s2.assign(s);
215 
216 	size_t p1 = s2.ufind("<body", 0);
217 	if (p1 == std::string::npos)
218 		return 1;
219 	s1 = s2.substr(0, p1);
220 	s2.erase(0, p1);
221 	p1 = s2.ufind("</body", 0);
222 	if (p1 == std::string::npos)
223 		return 1;
224 	s3 = s2.substr(p1);
225 	s2.erase(p1);
226 
227 	if (s2.ufind("<FORM", 0) == string::npos ||
228 		s2.ufind("</FORM", 0) == string::npos )
229 		return 1;
230 	s2.ureplace("<FORM");
231 	s2.ureplace("</FORM");
232 	s2.ureplace("<INPUT");
233 	s2.ureplace("<TEXTAREA");
234 	s2.ureplace("</TEXTAREA");
235 	s2.ureplace("VALUE=\"");
236 	s2.ureplace("NAME=\"");
237 	s2.ureplace("TYPE=\"");
238 	s2.ureplace("=\"TEXT\"");
239 	s2.ureplace("=\"RADIO\"");
240 	s2.ureplace("=\"CHECKBOX\"");
241 	s2.ureplace("=\"PASSWORD\"");
242 
243 	s2.ureplace("=\"NUMBER\"");
244 	s2.ureplace("=\"DATE\"");
245 	s2.ureplace("=\"DATETIME\"");
246 	s2.ureplace("=\"DATETIME-LOCAL\"");
247 	s2.ureplace("=\"TIME\"");
248 	s2.ureplace("=\"WEEK\"");
249 	s2.ureplace("=\"MONTH\"");
250 	s2.ureplace("=\"TEL\"");
251 	s2.ureplace("=\"EMAIL\"");
252 
253 	s2.ureplace("SELECTED");
254 	s2.ureplace("CHECKED");
255 	s2.ureplace("<SELECT");
256 	s2.ureplace("</SELECT");
257 //	s2.ureplace("<OPTION");
258 	s.assign(s1).append(s2).append(s3);
259 //	s.assign(s1);
260 	return 0;
261 }
262 
263 // this function may be called by the main or the web_server thread
264 // reads the values associated with each form type and
265 // clears the html form of those value.
extract_fields()266 void extract_fields()
267 {
268 	if (custom_select < 0) return;
269 	string fname = CUSTOM_dir;
270 	{
271 		guard_lock web_lock(&mutex_web_server);
272 		fname.append(custom_pairs[custom_select].file_name);
273 		edit_txt.assign("CUSTOM_FORM,")
274 				.append(custom_pairs[custom_select].file_name)
275 				.append("\n");
276 	}
277 	FILE *html_file = fopen(fname.c_str(), "r");
278 	char c = fgetc(html_file);
279 	html_form.clear();
280 
281 	while (!feof(html_file)) {
282 		html_form += c;
283 		c = fgetc(html_file);
284 	}
285 
286 	fclose(html_file);
287 
288 	if (convert_case(html_form)) {
289 		html_form.clear();
290 		custom_select = 0;
291 		edit_txt.assign("INVALID HTML FORM DOCUMENT");
292 		return;
293 	}
294 
295 	size_t ptype, pstart, pend, pname, pvalue, p1, p2, p3;
296 	string field_name;
297 	string field_value;
298 	string val;
299 
300 	name_values.clear();
301 
302 	for (size_t i = 0; i < sizeof(input_types) / sizeof(INPUT_TYPE); i++) {
303 		ptype = html_form.find(input_types[i].txt);
304 		while (ptype != string::npos) {
305 			field_name.clear();
306 			field_value.clear();
307 			pstart = html_form.rfind("<", ptype);
308 			pend = html_form.find(">", ptype);
309 			pname = html_form.find(name_str, pstart);
310 
311 			if (pname == string::npos || pname > pend) {
312 				ptype = html_form.find(input_types[i].txt, ptype + 1);
313 				continue;
314 			}
315 
316 			pname += name_str.length();
317 			p1 = html_form.find("\"", pname);
318 			field_name = html_form.substr(pname, p1 - pname);
319 
320 			switch (input_types[i].id) {
321 				case T_TEXT: case T_PASSWORD: case T_NUMBER:
322 				case T_DATE: case T_DTIME: case T_DTIME_LOCAL:
323 				case T_TIME: case T_WEEK:  case T_MONTH: case T_TEL: case T_EMAIL:
324 					pvalue = html_form.find(value_str, pstart);
325 					if (pvalue == string::npos || pvalue > pend) break;
326 					pvalue += value_str.length();
327 					p2 = html_form.find("\"", pvalue);
328 					val = html_form.substr(pvalue, p2 - pvalue);
329 					p3 = val.find("&quot;");
330 					while (p3 != string::npos)
331 						val.replace(p3, 6, "\"");
332 					escape(val);
333 					field_value = val;
334 					break;
335 				case T_RADIO:
336 					pvalue = html_form.find(value_str, pstart);
337 					if (pvalue == string::npos || pvalue > pend) break;
338 					pvalue += value_str.length();
339 					p1 = html_form.find("\"", pvalue);
340 					if (p1 < pend) {
341 						field_name.append(".")
342 								  .append(html_form.substr(pvalue, p1 - pvalue));
343 						field_value.clear();
344 						p2 = html_form.find(checkedeq, pstart);
345 						if (p2 < pend) {
346 							field_value = "Y";//checked;
347 							html_form.erase(p2 - 1, checkedeq.length() + 1);
348 							pend = html_form.find(">", pstart);
349 						} else {
350 							p2 = html_form.find(checked, pstart);
351 							if (p2 < pend) {
352 								field_value = "Y";//checked;
353 								html_form.erase(p2 - 1, checked.length() + 1);
354 								pend = html_form.find(">", pstart);
355 							}
356 						}
357 					}
358 					break;
359 				case T_CHECKBOX:
360 					pvalue = html_form.find(value_str, pstart);
361 					if (pvalue != string::npos && pvalue < pend) {
362 						pvalue += value_str.length();
363 						p1 = html_form.find("\"", pvalue);
364 						if (p1 < pend) {
365 							field_name.append(".")
366 									  .append(html_form.substr(pvalue, p1 - pvalue));
367 						}
368 					}
369 					field_value.clear();
370 					p2 = html_form.find(checkedeq, pstart);
371 					if (p2 < pend) {
372 						field_value = "Y";//"ON";
373 						html_form.erase(p2 - 1, checkedeq.length() + 1);
374 						pend = html_form.find(">", pstart);
375 					} else {
376 						p2 = html_form.find(checked, pstart);
377 						if (p2 < pend) {
378 							field_value = "Y";//"ON";
379 							html_form.erase(p2 - 1, checked.length() + 1);
380 							pend = html_form.find(">", pstart);
381 						} else {
382 							p2 = html_form.find(" ON", pstart);
383 							if (p2 < pend) {
384 								field_value = "Y";//"ON";
385 								html_form.erase(p2, 3);
386 								pend = html_form.find(">", pstart);
387 							}
388 						}
389 					}
390 					break;
391 				case T_AREA: //extract
392 					pvalue = pend + 1;
393 					p1 = html_form.find(textend_str, pvalue);
394 					if (p1 == string::npos) break;
395 					if (p1 > pvalue)
396 						val = html_form.substr(pvalue, p1 - pvalue);
397 					else
398 						val.clear();
399 					html_form.erase(pvalue, val.length());
400 					escape(val);
401 					field_value.assign(val);
402 					break;
403 				case T_SELECT:
404 					p3 = html_form.find(end_sel_str, pstart);
405 					if (p3 == string::npos) break;
406 					p2 = html_form.find(selected, pstart);
407 					if (p2 != string::npos && p2 < p3) {
408 						pvalue = html_form.rfind(value_str, p2);
409 						if (pvalue != string::npos) {
410 							pvalue += value_str.length();
411 							p1 = html_form.find("\"", pvalue);
412 							if (p1 < p2)
413 								field_value = html_form.substr(pvalue, p1 - pvalue);
414 						}
415 					}
416 					break;
417 				default:
418 					break;
419 			}
420 
421 			edit_txt.append(field_name).append(",");
422 			edit_txt.append(field_value).append("\n");
423 			name_values.push_back(NAME_VALUE(input_types[i].id, field_name, field_value));
424 
425 			ptype = html_form.find(input_types[i].txt, ptype+1);
426 		}
427 	}
428 }
429 
refresh_txt_custom_msg(void *)430 void refresh_txt_custom_msg(void *)
431 {
432 	txt_custom_msg->clear();
433 	txt_custom_msg->add(edit_txt.c_str());
434 }
435 
436 // called by web server thread
get_html_vars(struct mg_connection * conn)437 void get_html_vars(struct mg_connection *conn)
438 {
439 	size_t p;
440 	if (custom_select < 0) return;
441 
442 	edit_txt.assign("CUSTOM_FORM,")
443 			.append(custom_pairs[custom_select].file_name)
444 			.append("\n");
445 
446 	string field, line, val;
447 	for (size_t n = 0; n < name_values.size(); n++)
448 		name_values[n].value.clear();
449 
450 	for (size_t n = 0; n < name_values.size(); n++) {
451 		field = name_values[n].name;
452 		if (name_values[n].id == T_CHECKBOX ||
453 			name_values[n].id == T_RADIO) {
454 			if ((p = field.find(".")) != string::npos)
455 				field.erase(p);
456 		}
457 
458 		int fld_len = mg_get_var_len(conn, field.c_str());
459 		char buff[fld_len + 1];
460 		memset(buff, 0, sizeof(buff));
461 
462 		mg_get_var(conn, field.c_str(), buff, sizeof(buff));
463 
464 		switch (name_values[n].id) {
465 			case T_RADIO :
466 				p = name_values[n].name.find(".");
467 				if (name_values[n].name.substr(p+1) == buff)
468 					name_values[n].value = "Y";//checked;
469 				line.assign(name_values[n].name)
470 					.append(",")
471 					.append(name_values[n].value);
472 				break;
473 			case T_CHECKBOX :
474 				if (strstr(buff, "on") == buff || strstr(buff, "ON") == buff)
475 					name_values[n].value = "Y";//"ON";
476 				line.assign(name_values[n].name)
477 					.append(",")
478 					.append(name_values[n].value);
479 				break;
480 			case T_AREA://get html vars
481 				val = buff;
482 				escape(val);
483 				name_values[n].value = val;
484 				line.assign(name_values[n].name).append(",").append(val);
485 				break;
486 			// T_TEXT, T_PASSWORD, T_SELECT, T_DATE, T_DATETIME ...
487   			default :
488 				name_values[n].value = buff;
489 				line.assign(name_values[n].name)
490 					.append(",")
491 					.append(name_values[n].value);
492 		}
493 		edit_txt.append(line).append("\n");
494 	}
495 	Fl::awake(refresh_txt_custom_msg);
496 }
497 
498 // modify the html form with the value strings
499 
assign_values(string & html)500 void assign_values(string &html)
501 {
502 	string nm, val, s1, s2, temp;
503 	size_t p, p0, p1, p2, p3, pbeg, pend, pval, pnm;
504 
505 	for (size_t n = 0; n < name_values.size(); n++) {
506 		switch (name_values[n].id) {
507 			case T_TEXT : case T_PASSWORD : case T_NUMBER :
508 			case T_DATE : case T_DTIME : case T_DTIME_LOCAL :
509 			case T_TIME : case T_WEEK :  case T_MONTH : case T_TEL : case T_EMAIL:
510 				nm.assign("NAME=\"").append(name_values[n].name).append("\"");
511 				pnm = html.find(nm);
512 				if (pnm != string::npos) {
513 					pnm += nm.length();
514 					p1 = html.find(value_str, pnm);
515 					p2 = html.find(">", pnm);
516 					val = name_values[n].value;
517 					unescape(val);
518 					p3 = val.find("\"");
519 					while (p3 != string::npos) {
520 						val.replace(p3,1, "&quot;");
521 						p3 = val.find("\"");
522 					}
523 					if (p1 < p2) {
524 						p1 += value_str.length();
525 						p2 = html.find("\"", p1);
526 						html.replace(p1, p2 - p1, val);
527 					} else {
528 						temp.assign(" VALUE=\"").append(val).append("\"");
529 						html.insert(p2, temp);
530 					}
531 				}
532 				break;
533 			case T_RADIO :
534 				temp = name_values[n].name;
535 				p = temp.find(".");
536 				s1.assign(temp.substr(0, p));
537 				s2.assign(temp.substr(p+1));
538 				nm.assign(name_str).append(s1).append("\"");
539 				val.assign(value_str).append(s2).append("\"");
540 				pnm = html.find(nm);
541 				while (pnm != string::npos) {
542 					pbeg = html.rfind("<", pnm); // beginning of tag specifier
543 					pend = html.find(">", pbeg); // end of tag specifier
544 					pval = html.find(val, pbeg);
545 					if (pval == string::npos || pval > pend) {
546 						pnm = html.find(nm, pend);
547 						continue;
548 					}
549 				// found name and value pair
550 					if (name_values[n].value == checked ||
551 						name_values[n].value == "Y")
552 						html.insert(pend, string(" ").append(checked));
553 					pend = html.find(">", pbeg);
554 					pnm = html.find(nm, pend);
555 				}
556 				break;
557 			case T_CHECKBOX :
558 				nm.assign("NAME=\"").append(name_values[n].name).append("\"");
559 				pnm = html.find(nm);
560 				if (pnm != string::npos) {
561 					pbeg = html.rfind("<", pnm);
562 					pend = html.find(">", pbeg);
563 					if (name_values[n].value == "ON" ||
564 						name_values[n].value == "Y") {
565 						html.insert(pend, string(" ").append(checked));
566 						pend = html.find(">", pbeg);
567 					}
568 				}
569 				break;
570 			case T_AREA : //assign values
571 				nm.assign("NAME=\"").append(name_values[n].name).append("\"");
572 				pnm = html.find(nm);
573 				if (pnm != string::npos) {
574 					p1 = html.find(textend_str, pnm);
575 					if (p1 == string::npos)
576 						break;
577 					p0 = html.rfind(">", p1) + 1;
578 					val = name_values[n].value;
579 					unescape(val);
580 					if (p0 < p1) {
581 						html.replace(p0, p1 - p0, val);
582 					} else {
583 						html.insert(p1, val);
584 					}
585 				}
586 				break;
587 			case T_SELECT :
588 				nm.assign("NAME=\"").append(name_values[n].name).append("\"");
589 				pnm = html.find(nm);
590 				if (pnm != string::npos) {
591 					p2 = html.find("</SELECT", pnm);
592 					p0 = html.find(value_str, pnm);
593 					while(p0 != string::npos && p0 < p2) {
594 						p0 += value_str.length();
595 						p1 = html.find("\"", p0);
596 						if (p1 != string::npos && p1 < p2) {
597 							p3 = html.find(">", p1);
598 							if (html.substr(p0, p1 - p0) == name_values[n].value) {
599 								html.replace(p1+1, p3 - p1 - 1, " SELECTED");
600 							} else
601 								html.replace(p1+1, p3 - p1 - 1, "");
602 						}
603 						p0 = html.find(value_str, p0);
604 					}
605 				}
606 				break;
607 			default :
608 				break;
609 		}
610 	}
611 }
612 
custom_editor(struct mg_connection * conn)613 void custom_editor(struct mg_connection *conn)
614 {
615 	string html_edit = html_form;
616 	size_t p = html_edit.find("<FORM");
617 	if (p == string::npos) return;
618 
619 	html_edit.replace(p, 5, action_str);
620 	p = html_edit.find("</FORM");
621 	html_edit.replace(p, 6, submit_str);
622 	assign_values(html_edit);
623 	mg_send_data(conn, html_edit.c_str(), html_edit.length());
624 }
625 
custom_viewer(struct mg_connection * conn)626 void custom_viewer(struct mg_connection *conn)
627 {
628 	string html_view = html_form;
629 
630 	assign_values(html_view);
631 
632 // add readonly attribute to all input controls
633 	size_t pstart, ptext, pradio, pcheckbox, ppassword, pnumber,
634 		   pdate, pdtime, pdtime_local, pweek, pmonth,
635 		   ptel, pemail, pend;
636 
637 	pstart = html_view.find("<INPUT");
638 	while (pstart != string::npos) {
639 		pend = html_view.find(">", pstart);
640 		ptext = html_view.find(text_type_str, pstart);
641 		ppassword = html_view.find(password_type_str, pstart);
642 		pnumber = html_view.find(number_str, pstart);
643 		pradio = html_view.find(radio_type_str, pstart );
644 		pcheckbox = html_view.find(checkbox_type_str, pstart);
645 		pdate = html_view.find(date_str, pstart);
646 		pdtime = html_view.find(datetime_str, pstart);
647 		pdtime_local = html_view.find(datetime_local_str, pstart);
648 		pweek = html_view.find(week_str, pstart);
649 		pmonth = html_view.find(month_str, pstart);
650 		ptel = html_view.find(tel_str, pstart);
651 		pemail = html_view.find(email_str, pstart);
652 
653 		if (ppassword < pend) {
654 			size_t pvalue = html_view.find("VALUE=\"", pstart);
655 			if (pvalue < pend) {
656 				pvalue += 7;
657 				while (html_view[pvalue] != '\"') {
658 					html_view[pvalue] = '*';
659 					pvalue++;
660 				}
661 			}
662 			html_view.replace(ppassword, password_type_str.length(), text_type_str);
663 			html_view.insert(pstart + 6, " READONLY");
664 		} else if (ptext < pend || pnumber < pend ||
665 				  pdate < pend || pdtime < pend || pdtime_local < pend ||
666 				  pweek < pend || pmonth < pend || ptel < pend || pemail < pend)
667 			html_view.insert(pstart + 6, " READONLY");
668 		else if (pradio < pend || pcheckbox < pend)
669 			html_view.insert(pstart + 6, " DISABLED");
670 		pstart = html_view.find("<INPUT", pend + 1);
671 	}
672 
673 	pstart = html_view.find("<TEXTAREA");
674 	while (pstart != string::npos) {
675 		pend = html_view.find(">", pstart);
676 		html_view.insert(pstart + 9, " READONLY");
677 		pstart = html_view.find("<TEXTAREA", pend + 1);
678 	}
679 
680 	pstart = html_view.find("<SELECT");
681 	while (pstart != string::npos) {
682 		pend = html_view.find(">", pstart);
683 		html_view.insert(pstart + 7, " DISABLED");
684 		pstart = html_view.find("<SELECT", pend + 1);
685 	}
686 
687 	string fname = "";
688 	size_t plc = custom_field.find(",");
689 	size_t plf = custom_field.find("\n");
690 	if ((plc != string::npos) && (plf != string::npos) && (plc < plf))
691 		fname.append(custom_field.substr(plc+1, plf - plc - 1));
692 	else
693 		fname.append("RX_doc.html");
694 	plc = fname.find(".");
695 	if (plc != string::npos) fname.erase(plc);
696 	fname.append(".htm");
697 	fname.insert(0, FLMSG_temp_dir);
698 
699 	FILE *tempfile = fopen(fname.c_str(), "w");
700 	fprintf(tempfile,"%s", html_view.c_str());
701 	fclose(tempfile);
702 
703 	if (conn == (struct mg_connection *)0) {
704 		open_url(fname.c_str());
705 		return;
706 	}
707 
708 	mg_send_data(conn, html_view.c_str(), html_view.length());
709 }
710 
711 bool using_custom_template = false;
712 
clear_customfields()713 void clear_customfields()
714 {
715 	custom_field.clear();
716 	extract_fields();
717 }
718 
check_customfields()719 bool check_customfields()
720 {
721 	return (custom_field != txt_custom_msg->buffer()->text());
722 }
723 
update_customfields()724 void update_customfields()
725 {
726 	custom_field = txt_custom_msg->buffer()->text();
727 }
728 
clear_custom_form()729 void clear_custom_form()
730 {
731 	clear_customfields();
732 	txt_custom_msg->clear();
733 	txt_custom_msg->add(edit_txt.c_str());
734 }
735 
text_to_pairs()736 void text_to_pairs()
737 {
738 	string val;
739 	size_t p, p1;
740 	int offset;
741 	for (size_t n = 0; n < name_values.size(); n++) {
742 // look for LF+Field+COMMA
743 		p = edit_txt.find("\n" + name_values[n].name + ",");
744 		offset = 2; //Skip 2 characters (LF and COMMA)
745 // Not found, check if it is first field in the data string (not preceeded by LF).
746 		if (p == string::npos) {
747 			if (edit_txt.find(name_values[n].name + ",") == 0) {
748 				p = 0;
749 				offset = 1; //Skip 1 character (COMMA)
750 			}
751 		}
752 		if (p != string::npos) {
753 			p += name_values[n].name.length() + offset;
754 			p1 = edit_txt.find("\n", p);
755 			val = edit_txt.substr(p, p1 - p);
756 			if (!val.empty() &&
757 				(name_values[n].id == T_AREA || name_values[n].id == T_TEXT))
758 				escape(val);
759 			name_values[n].value = val;
760 		}
761 	}
762 }
763 
pairs_to_text()764 void pairs_to_text()
765 {
766 	edit_txt.clear();
767 	edit_txt.assign("CUSTOM_FORM,")
768 			.append(custom_pairs[custom_select].file_name)
769 			.append("\n");
770 	for (size_t n = 0; n < name_values.size(); n++) {
771 		edit_txt.append(name_values[n].name)
772 				.append(",")
773 				.append(name_values[n].value)
774 				.append("\n");
775 	}
776 }
777 
min_pairs_to_text()778 std::string min_pairs_to_text()
779 {
780 	if (custom_select == -1) return "";
781 	static std::string mintext;
782 	mintext.clear();
783 	mintext.assign("CUSTOM_FORM,")
784 			.append(custom_pairs[custom_select].file_name)
785 			.append("\n");
786 	for (size_t n = 0; n < name_values.size(); n++) {
787 		if (!name_values[n].value.empty())
788 			mintext.append(name_values[n].name)
789 				.append(",")
790 				.append(name_values[n].value)
791 				.append("\n");
792 	}
793 	return mintext;
794 }
795 
update_customform()796 void update_customform()
797 {
798 	extract_fields();
799 	edit_txt = custom_field;
800 	text_to_pairs();
801 	pairs_to_text();
802 	txt_custom_msg->clear();
803 	txt_custom_msg->add(edit_txt.c_str());
804 }
805 
read_custombuffer(string data)806 void read_custombuffer(string data)
807 {
808 	size_t p0, p1;
809 
810 	clear_customfields();
811 	read_header(data);
812 	custom_field = findstr(data, custom_msg);
813 
814 	custom_select = -1;
815 
816 	p0 = custom_field.find("CUSTOM_FORM,");
817 	if (p0 == string::npos) return;
818 	p0 += 12;//strlen("CUSTOM_FORM,");
819 	p1 = custom_field.find("\n", p0);
820 	if (p1 == string::npos) return;
821 	string fname = custom_field.substr(p0, p1-p0);
822 	string html_fname = CUSTOM_dir;
823 	html_fname.append(fname);
824 
825 	{ // treat this block as a critical section
826 		guard_lock web_lock(&mutex_web_server);
827 		for (int i = 0; i < num_custom_entries; i++) {
828 			if (fname == custom_pairs[i].file_name) {
829 				custom_select = i;
830 				break;
831 			}
832 		}
833 	}
834 	if (custom_select == -1) {
835 		fl_alert2("Custom form %s not found!", fname.c_str());
836 		return;
837 	}
838 	update_customform();
839 }
840 
cb_custom_new()841 void cb_custom_new()
842 {
843 	if (check_customfields()) {
844 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 1) {
845 			update_header(CHANGED);
846 			cb_custom_save_as();
847 		}
848 	}
849 	clear_custom_form();
850 	clear_header();
851 	def_custom_filename = ICS_msg_dir;
852 	def_custom_filename.append("new").append(CUSTOMFILE_EXT);
853 	show_filename(def_custom_filename);
854 	using_custom_template = false;
855 }
856 
cb_custom_import()857 void cb_custom_import()
858 {
859 	fl_alert2("Not implemented");
860 }
861 
cb_custom_export()862 void cb_custom_export()
863 {
864 	fl_alert2("Not implemented");
865 }
866 
cb_custom_wrap_import(string wrapfilename,string inpbuffer)867 void cb_custom_wrap_import(string wrapfilename, string inpbuffer)
868 {
869 	clear_custom_form();
870 	read_custombuffer(inpbuffer);
871 	def_custom_filename = ICS_msg_dir;
872 	def_custom_filename.append(wrapfilename);
873 	show_filename(def_custom_filename);
874 	using_custom_template = false;
875 }
876 
eval_custom_fsize()877 int eval_custom_fsize()
878 {
879 	Ccrc16 chksum;
880 	evalstr.assign("[WRAP:beg][WRAP:lf][WRAP:fn ");
881 	evalstr.append(base_custom_filename).append("]");
882 	update_customfields();
883 	update_header(FROM);
884 	evalstr.append(header("<customform>"));
885 	string outbuf = lineout( custom_msg, custom_field );
886 	if (outbuf.empty()) return 0;
887 	compress_maybe( outbuf );
888 	evalstr.append( outbuf );
889 	evalstr.append("[WRAP:chksum ").append(chksum.scrc16(evalstr)).append("][WRAP:end]");
890 	return evalstr.length();
891 }
892 
cb_custom_wrap_export()893 void cb_custom_wrap_export()
894 {
895 	if (check_customfields()) {
896 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 0)
897 			return;
898 		update_header(CHANGED);
899 	}
900 	string wfields = min_pairs_to_text();
901 	if (wfields.empty()) return;
902 
903 	if (base_custom_filename == string("new").append(CUSTOMFILE_EXT) ||
904 		base_custom_filename == string("default").append(CUSTOMFILE_EXT) )
905 		if (!cb_custom_save_as()) return;
906 
907 	string wrapfilename = WRAP_send_dir;
908 	wrapfilename.append(base_custom_filename);
909 	wrapfilename.append(WRAP_EXT);
910 	const char *p = FSEL::saveas(
911 			"Save as wrap file",
912 			"Wrap file\t*.{wrap,WRAP}",
913 			wrapfilename.c_str());
914 	if (p) {
915 		string pext = fl_filename_ext(p);
916 		wrapfilename = p;
917 		update_header(FROM);
918 		custombuffer.assign(header("<customform>"));
919 		string outbuf = lineout( custom_msg, wfields);
920 		compress_maybe(outbuf);
921 		custombuffer.append(outbuf);
922 		export_wrapfile(base_custom_filename, wrapfilename, custombuffer, pext != WRAP_EXT);
923 
924 		custombuffer.assign(header("<customform>")).append(lineout( custom_msg, custom_field ));
925 		write_custom(def_custom_filename);
926 	}
927 }
928 
cb_custom_wrap_autosend()929 void cb_custom_wrap_autosend()
930 {
931 	if (check_customfields()) {
932 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 0)
933 			return;
934 		update_header(CHANGED);
935 	}
936 	string wfields = min_pairs_to_text();
937 	if (wfields.empty()) return;
938 
939 	if (base_custom_filename == string("new").append(CUSTOMFILE_EXT) ||
940 		base_custom_filename == string("default").append(CUSTOMFILE_EXT) )
941 		if (!cb_custom_save_as()) return;
942 
943 	update_header(FROM);
944 	custombuffer.assign(header("<customform>"));
945 	string outbuf = lineout( custom_msg, wfields);
946 
947 	compress_maybe(outbuf);
948 	custombuffer.append(outbuf);
949 	xfr_via_socket(base_custom_filename, custombuffer);
950 
951 	custombuffer.assign(header("<customform>")).append(lineout( custom_msg, custom_field ));
952 	write_custom(def_custom_filename);
953 }
954 
cb_custom_load_template()955 void cb_custom_load_template()
956 {
957 	return;
958 }
959 
cb_custom_save_template()960 void cb_custom_save_template()
961 {
962 	if (!using_custom_template) {
963 		cb_custom_save_as_template();
964 		return;
965 	}
966 	string def_custom_filename = def_custom_TemplateName;
967 	const char *p = FSEL::saveas(
968 			"Save template file",
969 			string("Template file\t*").append(CUSTOMTEMP_EXT).c_str(),
970 			def_custom_filename.c_str());
971 	if (p) {
972 		update_header(CHANGED);
973 		update_customfields();
974 		custombuffer.assign(header("<customform>"));
975 		custombuffer.append( lineout( custom_msg, custom_field ) );
976 		write_custom(p);
977 	}
978 }
979 
cb_custom_save_as_template()980 void cb_custom_save_as_template()
981 {
982 	string def_custom_filename = def_custom_TemplateName;
983 	const char *p = FSEL::saveas(
984 			"Save as template file",
985 			string("Template file\t*").append(CUSTOMTEMP_EXT).c_str(),
986 			def_custom_filename.c_str());
987 	if (p) {
988 		const char *pext = fl_filename_ext(p);
989 		def_custom_TemplateName = p;
990 		if (strlen(pext) == 0) def_custom_TemplateName.append(CUSTOMTEMP_EXT);
991 		remove_spaces_from_filename(def_custom_TemplateName);
992 		clear_header();
993 		update_header(CHANGED);
994 		update_customfields();
995 		custombuffer.assign(header("<customform>"));
996 		custombuffer.append( lineout( custom_msg, custom_field ) );
997 		write_custom(def_custom_TemplateName);
998 		show_filename(def_custom_TemplateName);
999 		using_custom_template = true;
1000 	}
1001 }
1002 
cb_custom_open()1003 void cb_custom_open()
1004 {
1005 	const char *p = FSEL::select(_("Open data file"), "custom form\t*.k2s",
1006 					def_custom_filename.c_str());
1007 	if (!p) return;
1008 	if (strlen(p) == 0) return;
1009 	if ((strstr(p, ".k2s") == NULL) && update_custom) {
1010 		fl_alert2("Not a custom form");
1011 		return;
1012 	}
1013 	clear_custom_form();
1014 	read_data_file(p);
1015 	using_custom_template = false;
1016 	def_custom_filename = p;
1017 	show_filename(def_custom_filename);
1018 }
1019 
write_custom(string s)1020 void write_custom(string s)
1021 {
1022 	if (custombuffer.empty())
1023 		return;
1024 	FILE *customfile = fopen(s.c_str(), "w");
1025 	if (!customfile) return;
1026 	fwrite(custombuffer.c_str(), custombuffer.length(), 1, customfile);
1027 	fclose(customfile);
1028 }
1029 
cb_custom_save_as()1030 bool cb_custom_save_as()
1031 {
1032 	const char *p;
1033 	string newfilename;
1034 
1035 	string name = named_file();
1036 	if (!name.empty()) {
1037 		name.append(".k2s");
1038 		newfilename = ICS_msg_dir;
1039 		newfilename.append(name);
1040 	} else
1041 		newfilename = def_custom_filename;
1042 
1043 	p = FSEL::saveas(_("Save data file"), "custom form\t*.k2s",
1044 					newfilename.c_str());
1045 
1046 	if (!p) return false;
1047 	if (strlen(p) == 0) return false;
1048 
1049 	if (progStatus.sernbr_fname) update_sernbr();
1050 
1051 	const char *pext = fl_filename_ext(p);
1052 	def_custom_filename = p;
1053 	if (strlen(pext) == 0) def_custom_filename.append(".k2s");
1054 
1055 	remove_spaces_from_filename(def_custom_filename);
1056 	update_header(NEW);
1057 	update_customfields();
1058 	custombuffer.assign(header("<customform>"));
1059 	custombuffer.append( lineout( custom_msg, custom_field ) );
1060 	write_custom(def_custom_filename);
1061 
1062 	using_custom_template = false;
1063 	show_filename(def_custom_filename);
1064 	return true;
1065 }
1066 
cb_custom_save()1067 void cb_custom_save()
1068 {
1069 	if (base_custom_filename == "new.k2s" ||
1070 		base_custom_filename == "default.k2s" ||
1071 		using_custom_template == true) {
1072 		cb_custom_save_as();
1073 		return;
1074 	}
1075 	if (check_customfields()) update_header(CHANGED);
1076 	update_customfields();
1077 	custombuffer.assign(header("<customform>"));
1078 	custombuffer.append( lineout( custom_msg, custom_field ) );
1079 	write_custom(def_custom_filename);
1080 	using_custom_template = false;
1081 }
1082 
cb_custom_msg_type()1083 void cb_custom_msg_type()
1084 {
1085 	if (tabs_msg_type->value() == tab_custom ) {
1086 		show_filename(def_custom_filename);
1087 	} else {
1088 		show_filename(def_rg_filename);
1089 	}
1090 }
1091 
cb_custom_import_data()1092 void cb_custom_import_data()
1093 {
1094 	def_custom_filename = CUSTOM_dir;
1095 	def_custom_filename.append("default.custom");
1096 
1097 	const char *p = FSEL::select(
1098 						_("Import custom data"),
1099 						"custom file\t*.custom",
1100 						def_custom_filename.c_str());
1101 	if (!p) return;
1102 	if (strlen(p) == 0) return;\
1103 
1104 	clear_custom_form();
1105 	clear_estimate();
1106 
1107 // open the custom file, read all data
1108 	long filesize = 0;
1109 	char *buff;
1110 	FILE *custom_datafile;
1111 
1112 	custom_datafile = fopen (p, "r");
1113 	if (!custom_datafile)
1114 		return;
1115 // determine its size for buffer creation
1116 	fseek (custom_datafile, 0, SEEK_END);
1117 	filesize = ftell (custom_datafile);
1118 // test file integrity
1119 	if (filesize == 0) {
1120 		fl_alert2(_("Empty file"));
1121         fclose (custom_datafile);
1122 		return;
1123 	}
1124 
1125 	buff = new char[filesize + 1];
1126 	memset(buff, 0, filesize + 1);
1127 // read the entire file into the buffer
1128 	fseek (custom_datafile, 0, SEEK_SET);
1129 	int retval = fread (buff, filesize, 1, custom_datafile);
1130 	fclose (custom_datafile);
1131 	if (retval != 1) {
1132         delete[] buff;
1133         return;
1134     }
1135 
1136 	custom_field = buff;
1137 // strip any cr-lf pairs if the file was a DOS text file
1138 	size_t ptr = custom_field.find("\r\n");
1139 	while (ptr != string::npos) {
1140 		custom_field.erase(ptr, 1);
1141 		ptr = custom_field.find("\r\n");
1142 	}
1143 	update_customform();
1144 
1145 	delete [] buff;
1146 
1147 	using_custom_template = false;
1148 
1149 	def_custom_filename = ICS_msg_dir;
1150 	def_custom_filename.append(fl_filename_name(p));
1151 	size_t pext = def_custom_filename.find(".custom");
1152 	if (pext == string::npos) pext = def_custom_filename.find(".custom");
1153 	if (pext != string::npos) def_custom_filename.erase(pext);
1154 	def_custom_filename.append(".k2s");
1155 	show_filename(def_custom_filename);
1156 	estimate();
1157 }
1158 
cb_custom_export_data(bool open_file)1159 void cb_custom_export_data(bool open_file)
1160 {
1161 	update_customfields();
1162 	if (custom_field.empty()) return;
1163 
1164 	string fname_name = fl_filename_name(def_custom_filename.c_str());
1165 	size_t p = fname_name.rfind('.');
1166 	if (p != string::npos) fname_name.erase(p);
1167 
1168 	string custom_name = CUSTOM_dir;
1169 	custom_name.append(fname_name).append(".custom");
1170 
1171 	const char *pfilename = FSEL::saveas(
1172 							_("Export custom data"),
1173 							"custom file\t*.custom",
1174 							custom_name.c_str());
1175 
1176 	if (!pfilename) return;
1177 	if (strlen(pfilename) == 0) return;
1178 	custom_name = pfilename;
1179 	if (custom_name.find(".custom") == string::npos)
1180 		custom_name.append(".custom");
1181 
1182 	FILE *customfile = fopen(custom_name.c_str(), "w");
1183 	fprintf(customfile,"%s", custom_field.c_str());
1184 	fclose(customfile);
1185 
1186 	if (open_file) {
1187 		fl_alert2("If you modify the data you must save as custom and\nimport the modified file");
1188 		open_url(pfilename);
1189 	} else
1190 		fl_alert2("Data written to %s", custom_name.c_str());
1191 
1192 }
1193 
custom_set_fname(const char * fn)1194 void custom_set_fname(const char *fn)
1195 {
1196 	string fname = fn;
1197 	size_t pext = fname.find(".custom");
1198 	if (pext == string::npos) pext = fname.find(".custom");
1199 	if (pext == string::npos) {
1200 		txt_custom_msg->clear();
1201 		return;
1202 	}
1203 	using_custom_template = false;
1204 	def_custom_filename = ICS_msg_dir;
1205 	def_custom_filename.append(fl_filename_name(fn));
1206 	def_custom_filename.find(".custom");
1207 	if (pext == string::npos) pext = def_custom_filename.find(".custom");
1208 	if (pext != string::npos) def_custom_filename.erase(pext);
1209 	def_custom_filename.append(".k2s");
1210 	show_filename(def_custom_filename);
1211 }
1212 
cb_custom_html(bool exit_after_print)1213 void cb_custom_html(bool exit_after_print)
1214 {
1215 	if (custom_field.find("CUSTOM_FORM") == 0) {
1216 		size_t plf = custom_field.find("\n");
1217 		if (plf != string::npos) {
1218 			string fname = CUSTOM_dir;
1219 			fname.append(custom_field.substr(12, plf - 12));
1220 			FILE *html_file = fopen(fname.c_str(), "r");
1221 			char c;
1222 
1223 			html_form.clear();
1224 			c = fgetc(html_file);
1225 			while (!feof(html_file)) {
1226 				html_form += c;
1227 				c = fgetc(html_file);
1228 			}
1229 			fclose(html_file);
1230 
1231 			convert_case(html_form);
1232 			if (exit_after_print) {
1233 				custom_viewer((struct mg_connection *)0);
1234 				return;
1235 			}
1236 
1237 			handle_type = HANDLE_VIEW;
1238 			string url = "http://127.0.0.1:";
1239 			url.append(sz_srvr_portnbr);
1240 			open_url(url.c_str());
1241 		}
1242 	}
1243 }
1244 
cb_custom_textout()1245 void cb_custom_textout()
1246 {
1247 	return;
1248 	if (custom_field.find("CUSTOM_FORM") == 0) {
1249 		size_t plf = custom_field.find("\n");
1250 		if (plf != string::npos) {
1251 			string tempfile = FLMSG_temp_dir;
1252 			tempfile.append(custom_field.substr(12, plf - 12));
1253 			tempfile.append(".txt");
1254 			FILE *textfile = fopen(tempfile.c_str(), "w");
1255 			fprintf(textfile,"%s", edit_txt.c_str());
1256 			fclose(textfile);
1257 			open_url(tempfile.c_str());
1258 		}
1259 	}
1260 }
1261 
1262 //==============================================================================
1263 // Support for transfering / receiving custom FORM, html files
1264 //==============================================================================
1265 
1266 string transfer_custom_buffer;
1267 string def_custom_transfer_filename;
1268 
1269 string def_custom_rx_filename;
1270 string receive_custom_buffer;
1271 
read_custom_transfer_buffer(string data)1272 void read_custom_transfer_buffer(string data)
1273 {
1274 	const char *xfrstr = "<html_form>\n";
1275 	size_t p1 = data.find(xfrstr);
1276 	if (p1 != string::npos) p1 += strlen(xfrstr);
1277 	data.erase(0, p1);
1278 	receive_custom_buffer = data;
1279 	read_header(data);
1280 }
1281 
cb_custom_form_wrap_import(string wrapfilename,string inpbuffer)1282 void cb_custom_form_wrap_import(string wrapfilename, string inpbuffer)
1283 {
1284 	read_custom_transfer_buffer(inpbuffer);
1285 
1286 	def_custom_rx_filename = CUSTOM_dir;
1287 	def_custom_rx_filename.append(wrapfilename);
1288 	txt_rcvd_custom_html_filename->value(def_custom_rx_filename.c_str());
1289 	btn_save_custom_html_file->color(FL_RED);
1290 }
1291 
eval_transfer_custom_form_fsize()1292 int eval_transfer_custom_form_fsize()
1293 {
1294 	if (transfer_custom_buffer.empty()) return 0;
1295 
1296 	Ccrc16 chksum;
1297 
1298 	evalstr.assign("[WRAP:beg][WRAP:lf][WRAP:fn ");
1299 	evalstr.append(fl_filename_name(def_custom_transfer_filename.c_str())).append("]");
1300 	evalstr.append(header("<html_form>"));
1301 
1302 	string outbuf(transfer_custom_buffer);
1303 	if (outbuf.empty()) return 0;
1304 
1305 	compress_maybe( outbuf, false );
1306 
1307 	evalstr.append( outbuf );
1308 	string ck = chksum.scrc16(evalstr);
1309 
1310 	evalstr.append("[WRAP:chksum ").append(ck).append("][WRAP:end]");
1311 
1312 	return evalstr.length();
1313 }
1314 
load_custom_html_file()1315 void load_custom_html_file()
1316 {
1317 	if (def_custom_filename.empty()) return;
1318 	string fname = CUSTOM_dir;
1319 	fname.append(def_custom_transfer_filename);
1320 	transfer_custom_buffer.clear();
1321 
1322 	FILE *dfile = fopen(fname.c_str(), "rb");
1323 	if (!dfile) {
1324 		show_filename("ERROR");
1325 		transfer_custom_buffer.clear();
1326 		return;
1327 	}
1328 	fseek(dfile, 0, SEEK_END);
1329 	size_t fsize = ftell(dfile);
1330 	if (fsize <= 0) {
1331         fclose (dfile);
1332         return;
1333     }
1334 	fseek(dfile, 0, SEEK_SET);
1335 	transfer_custom_buffer.resize(fsize);
1336 	size_t r = fread((void *)transfer_custom_buffer.c_str(), 1, fsize, dfile);
1337 	fclose(dfile);
1338 	if (r != fsize) {
1339 		show_filename("ERROR");
1340 		transfer_custom_buffer.clear();
1341 		return;
1342 	}
1343 	estimate();
1344 }
1345 
cb_transfer_custom_html()1346 void cb_transfer_custom_html()
1347 {
1348 	if (transfer_custom_buffer.empty()) return;
1349 
1350 	update_header(FROM);
1351 	string fbuff(header("<html_form>"));
1352 	string outbuf(transfer_custom_buffer);
1353 	compress_maybe(outbuf, false);
1354 	fbuff.append(outbuf);
1355 	xfr_via_socket(fl_filename_name(def_custom_transfer_filename.c_str()), fbuff);
1356 }
1357 
cb_save_custom_html(Fl_Widget * w,void * d)1358 void cb_save_custom_html(Fl_Widget *w, void *d)
1359 {
1360 	btn_save_custom_html_file->color(FL_BACKGROUND_COLOR);
1361 
1362 	if (receive_custom_buffer.empty()) return;
1363 
1364 	FILE *binfile = fopen(def_custom_rx_filename.c_str(), "wb");
1365 	if (binfile) {
1366 		fwrite(receive_custom_buffer.c_str(), receive_custom_buffer.length(), 1, binfile);
1367 		fclose(binfile);
1368 	}
1369 	txt_rcvd_custom_html_filename->value("");
1370 	update_custom_transfer();
1371 }
1372 
cb_btn_select_custom_html(Fl_Widget * w,void * d)1373 void cb_btn_select_custom_html(Fl_Widget *w, void *d)
1374 {
1375 	def_custom_transfer_filename = custom_files[custom_selector->index()];
1376 	show_filename(def_custom_transfer_filename);
1377 	load_custom_html_file();
1378 }
1379 
custom_edit()1380 void custom_edit() {
1381 
1382 	handle_type = HANDLE_EDIT;
1383 	string url = "http://127.0.0.1:";
1384 	url.append(sz_srvr_portnbr);
1385 	open_url(url.c_str());
1386 }
1387