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 #include "icons.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 using namespace std;
75 
76 // csvform fields
77 
78 string csvbuffer;
79 string def_csv_filename = "";
80 string base_csv_filename = "";
81 string def_csv_TemplateName = "";
82 
83 string csv_title = ":TITLE:";
84 string csv_msg = ":mg:";
85 string csv_field;
86 
87 bool using_csv_template = false;
88 
clear_csvfields()89 void clear_csvfields()
90 {
91 	csv_field.clear();
92 }
93 
check_csvfields()94 bool check_csvfields()
95 {
96 	return (csv_field != txt_csv_msg->buffer()->text());
97 }
98 
update_csvfields()99 void update_csvfields()
100 {
101 	csv_field = txt_csv_msg->buffer()->text();
102 }
103 
clear_csv_form()104 void clear_csv_form()
105 {
106 	clear_csvfields();
107 	txt_csv_msg->clear();
108 }
109 
update_csvform()110 void update_csvform()
111 {
112 	txt_csv_msg->clear();
113 	txt_csv_msg->add(csv_field.c_str());
114 }
115 
read_csvbuffer(string data)116 void read_csvbuffer(string data)
117 {
118 	clear_csvfields();
119 	read_header(data);
120 	csv_field = findstr(data, csv_msg);
121 	update_csvform();
122 }
123 
cb_csv_new()124 void cb_csv_new()
125 {
126 	if (check_csvfields()) {
127 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 1) {
128 			update_header(CHANGED);
129 			cb_csv_save();
130 		}
131 	}
132 	clear_csv_form();
133 	clear_header();
134 	def_csv_filename = ICS_msg_dir;
135 	def_csv_filename.append("new").append(CSVFILE_EXT);
136 	show_filename(def_csv_filename);
137 	using_csv_template = false;
138 }
139 
cb_csv_import()140 void cb_csv_import()
141 {
142 	fl_alert2("Not implemented");
143 }
144 
cb_csv_export()145 void cb_csv_export()
146 {
147 	fl_alert2("Not implemented");
148 }
149 
cb_csv_wrap_import(string wrapfilename,string inpbuffer)150 void cb_csv_wrap_import(string wrapfilename, string inpbuffer)
151 {
152 	clear_csv_form();
153 	read_csvbuffer(inpbuffer);
154 	def_csv_filename = ICS_msg_dir;
155 	def_csv_filename.append(wrapfilename);
156 	show_filename(def_csv_filename);
157 	using_csv_template = false;
158 }
159 
eval_csv_fsize()160 int eval_csv_fsize()
161 {
162 	Ccrc16 chksum;
163 	evalstr.assign("[WRAP:beg][WRAP:lf][WRAP:fn ");
164 	evalstr.append(base_csv_filename).append("]");
165 	update_csvfields();
166 	update_header(FROM);
167 	evalstr.append(header("<csvform>"));
168 	string outbuf = lineout( csv_msg, csv_field );
169 	if (outbuf.empty()) return 0;
170 	compress_maybe( outbuf );
171 	evalstr.append( outbuf );
172 	evalstr.append("[WRAP:chksum ").append(chksum.scrc16(evalstr)).append("][WRAP:end]");
173 	return evalstr.length();
174 }
175 
cb_csv_wrap_export()176 void cb_csv_wrap_export()
177 {
178 	if (check_csvfields()) {
179 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 0)
180 			return;
181 		update_header(CHANGED);
182 	}
183 	update_csvfields();
184 	if (csv_field.empty()) return;
185 
186 	if (base_csv_filename == string("new").append(CSVFILE_EXT) ||
187 		base_csv_filename == string("default").append(CSVFILE_EXT) )
188 		if (!cb_csv_save_as()) return;
189 
190 	string wrapfilename = WRAP_send_dir;
191 	wrapfilename.append(base_csv_filename);
192 	wrapfilename.append(WRAP_EXT);
193 	const char *p = FSEL::saveas(
194 			"Save as wrap file",
195 			"Wrap file\t*.{wrap,WRAP}",
196 			wrapfilename.c_str());
197 	if (p) {
198 		string pext = fl_filename_ext(p);
199 		wrapfilename = p;
200 		update_header(FROM);
201 		csvbuffer.assign(header("<csvform>"));
202 		string outbuf = lineout( csv_msg, csv_field );
203 		compress_maybe(outbuf);
204 		csvbuffer.append(outbuf);
205 		export_wrapfile(base_csv_filename, wrapfilename, csvbuffer, pext != WRAP_EXT);
206 
207 		csvbuffer.assign(header("<csvform>")).append(lineout( csv_msg, csv_field ));
208 		write_csv(def_csv_filename);
209 	}
210 }
211 
cb_csv_wrap_autosend()212 void cb_csv_wrap_autosend()
213 {
214 	if (check_csvfields()) {
215 		if (fl_choice2("Form modified, save?", "No", "Yes", NULL) == 0)
216 			return;
217 		update_header(CHANGED);
218 	}
219 	update_csvfields();
220 	if (csv_field.empty()) return;
221 
222 	if (base_csv_filename == string("new").append(CSVFILE_EXT) ||
223 		base_csv_filename == string("default").append(CSVFILE_EXT) )
224 		if (!cb_csv_save_as()) return;
225 
226 	update_header(FROM);
227 	csvbuffer.assign(header("<csvform>"));
228 	string outbuf = lineout( csv_msg, csv_field );
229 
230 	compress_maybe(outbuf);
231 	csvbuffer.append(outbuf);
232 	xfr_via_socket(base_csv_filename, csvbuffer);
233 
234 	csvbuffer.assign(header("<csvform>")).append(lineout( csv_msg, csv_field ));
235 	write_csv(def_csv_filename);
236 }
237 
cb_csv_load_template()238 void cb_csv_load_template()
239 {
240 	string def_csv_filename = def_csv_TemplateName;
241 	const char *p = FSEL::select(
242 			"Open template file",
243 			string("Template file\t*").append(CSVTEMP_EXT).c_str(),
244 			def_csv_filename.c_str());
245 	if (p) {
246 		clear_csv_form();
247 		read_data_file(p);
248 		def_csv_TemplateName = p;
249 		show_filename(def_csv_TemplateName);
250 		using_csv_template = true;
251 	}
252 }
253 
cb_csv_save_template()254 void cb_csv_save_template()
255 {
256 	if (!using_csv_template) {
257 		cb_csv_save_as_template();
258 		return;
259 	}
260 	string def_csv_filename = def_csv_TemplateName;
261 	const char *p = FSEL::saveas(
262 			"Save template file",
263 			string("Template file\t*").append(CSVTEMP_EXT).c_str(),
264 			def_csv_filename.c_str());
265 	if (p) {
266 		update_header(CHANGED);
267 		update_csvfields();
268 		csvbuffer.assign(header("<csvform>"));
269 		csvbuffer.append( lineout( csv_msg, csv_field ) );
270 		write_csv(p);
271 	}
272 }
273 
cb_csv_save_as_template()274 void cb_csv_save_as_template()
275 {
276 	string def_csv_filename = def_csv_TemplateName;
277 	const char *p = FSEL::saveas(
278 			"Save as template file",
279 			string("Template file\t*").append(CSVTEMP_EXT).c_str(),
280 			def_csv_filename.c_str());
281 	if (p) {
282 		const char *pext = fl_filename_ext(p);
283 		def_csv_TemplateName = p;
284 		if (strlen(pext) == 0) def_csv_TemplateName.append(CSVTEMP_EXT);
285 		remove_spaces_from_filename(def_csv_TemplateName);
286 		clear_header();
287 		update_header(CHANGED);
288 		update_csvfields();
289 		csvbuffer.assign(header("<csvform>"));
290 		csvbuffer.append( lineout( csv_msg, csv_field ) );
291 		write_csv(def_csv_TemplateName);
292 		show_filename(def_csv_TemplateName);
293 		using_csv_template = true;
294 	}
295 }
296 
cb_csv_open()297 void cb_csv_open()
298 {
299 	const char *p = FSEL::select(_("Open data file"), "csv form\t*.c2s",
300 					def_csv_filename.c_str());
301 	if (!p) return;
302 	if (strlen(p) == 0) return;
303 	clear_csv_form();
304 	read_data_file(p);
305 	using_csv_template = false;
306 	def_csv_filename = p;
307 	show_filename(def_csv_filename);
308 }
309 
write_csv(string s)310 void write_csv(string s)
311 {
312 	if (csvbuffer.empty())
313 		return;
314 	FILE *csvfile = fopen(s.c_str(), "w");
315 	if (!csvfile) return;
316 	fwrite(csvbuffer.c_str(), csvbuffer.length(), 1, csvfile);
317 	fclose(csvfile);
318 }
319 
cb_csv_save_as()320 bool cb_csv_save_as()
321 {
322 	const char *p;
323 	string newfilename;
324 
325 	string name = named_file();
326 	if (!name.empty()) {
327 		name.append(".c2s");
328 		newfilename = ICS_msg_dir;
329 		newfilename.append(name);
330 	} else
331 		newfilename = def_csv_filename;
332 
333 	p = FSEL::saveas(_("Save data file"), "csv form\t*.c2s",
334 					newfilename.c_str());
335 
336 	if (!p) return false;
337 	if (strlen(p) == 0) return false;
338 
339 	if (progStatus.sernbr_fname) update_sernbr();
340 
341 	const char *pext = fl_filename_ext(p);
342 	def_csv_filename = p;
343 	if (strlen(pext) == 0) def_csv_filename.append(".c2s");
344 
345 	remove_spaces_from_filename(def_csv_filename);
346 	update_header(NEW);
347 	update_csvfields();
348 	csvbuffer.assign(header("<csvform>"));
349 	csvbuffer.append( lineout( csv_msg, csv_field ) );
350 	write_csv(def_csv_filename);
351 
352 	using_csv_template = false;
353 	show_filename(def_csv_filename);
354 	return true;
355 }
356 
cb_csv_save()357 void cb_csv_save()
358 {
359 	if (base_csv_filename == "new.c2s" ||
360 		base_csv_filename == "default.c2s" ||
361 		using_csv_template == true) {
362 		cb_csv_save_as();
363 		return;
364 	}
365 	if (check_csvfields()) update_header(CHANGED);
366 	update_csvfields();
367 	csvbuffer.assign(header("<csvform>"));
368 	csvbuffer.append( lineout( csv_msg, csv_field ) );
369 	write_csv(def_csv_filename);
370 	using_csv_template = false;
371 }
372 
cb_csv_msg_type()373 void cb_csv_msg_type()
374 {
375 	if (tabs_msg_type->value() == tab_csv ) {
376 		show_filename(def_csv_filename);
377 	} else {
378 		show_filename(def_rg_filename);
379 	}
380 }
381 
cb_csv_import_data()382 void cb_csv_import_data()
383 {
384 	def_csv_filename = CSV_dir;
385 	def_csv_filename.append("default.csv");
386 
387 	const char *p = FSEL::select(
388 						_("Import CSV data"),
389 						"csv file\t*.csv",
390 						def_csv_filename.c_str());
391 	if (!p) return;
392 	if (strlen(p) == 0) return;
393 
394 	clear_csv_form();
395 	clear_estimate();
396 
397 // open the CSV file, read all data
398 	long filesize = 0;
399 	FILE *csv_datafile;
400 
401 	csv_datafile = fopen (p, "rb");
402 	if (!csv_datafile) {
403 		fl_alert2(_("Could not open file"));
404 		return;
405 	}
406 // determine its size for buffer creation
407 	fseek (csv_datafile, 0, SEEK_END);
408 	filesize = ftell (csv_datafile);
409 // test file integrity
410 	if (filesize == 0) {
411 		fl_alert2(_("Empty file"));
412         fclose(csv_datafile);
413 		return;
414 	}
415 
416 	char *buff = new char[filesize + 1];
417 	memset(buff, 0, filesize + 1);
418 // read the entire file into the buffer
419 	fseek (csv_datafile, 0, SEEK_SET);
420 	int retval = fread (buff, 1, filesize, csv_datafile);
421 	fclose (csv_datafile);
422 
423 	if (retval != filesize) {
424 		fl_alert2(_("Error reading file"));
425         delete[] buff;
426 		return;
427 	}
428 
429 	csv_field = buff;
430 // strip any cr-lf pairs if the file was a DOS text file
431 	size_t ptr = csv_field.find("\r\n");
432 	while (ptr != string::npos) {
433 		csv_field.erase(ptr, 1);
434 		ptr = csv_field.find("\r\n");
435 	}
436 	update_csvform();
437 
438 	delete [] buff;
439 
440 	using_csv_template = false;
441 
442 	def_csv_filename = ICS_msg_dir;
443 	def_csv_filename.append(fl_filename_name(p));
444 	size_t pext = def_csv_filename.find(".csv");
445 	if (pext == string::npos) pext = def_csv_filename.find(".CSV");
446 	if (pext != string::npos) def_csv_filename.erase(pext);
447 	def_csv_filename.append(".c2s");
448 	show_filename(def_csv_filename);
449 	estimate();
450 }
451 
cb_csv_export_data(bool open_file)452 void cb_csv_export_data(bool open_file)
453 {
454 	update_csvfields();
455 	if (csv_field.empty()) return;
456 
457 	string fname_name = fl_filename_name(def_csv_filename.c_str());
458 	size_t p = fname_name.rfind('.');
459 	if (p != string::npos) fname_name.erase(p);
460 
461 	string csv_name = CSV_dir;
462 	csv_name.append(fname_name).append(".csv");
463 
464 	const char *pfilename = FSEL::saveas(
465 							_("Export CSV data"),
466 							"csv file\t*.csv",
467 							csv_name.c_str());
468 
469 	if (!pfilename) return;
470 	if (strlen(pfilename) == 0) return;
471 	csv_name = pfilename;
472 	if (csv_name.find(".csv") == string::npos)
473 		csv_name.append(".csv");
474 
475 	FILE *csvfile = fopen(csv_name.c_str(), "w");
476 	fprintf(csvfile,"%s", csv_field.c_str());
477 	fclose(csvfile);
478 
479 	if (open_file) {
480 		fl_alert2("If you modify the data you must save as CSV and\nimport the modified file");
481 		open_url(pfilename);
482 	} else
483 		fl_alert2("Data written to %s", csv_name.c_str());
484 
485 }
486 
csv_set_fname(const char * fn)487 void csv_set_fname(const char *fn)
488 {
489 	string fname = fn;
490 	size_t pext = fname.find(".csv");
491 	if (pext == string::npos) pext = fname.find(".CSV");
492 	if (pext == string::npos) {
493 		txt_csv_msg->clear();
494 		return;
495 	}
496 	using_csv_template = false;
497 	def_csv_filename = ICS_msg_dir;
498 	def_csv_filename.append(fl_filename_name(fn));
499 	def_csv_filename.find(".csv");
500 	if (pext == string::npos) pext = def_csv_filename.find(".CSV");
501 	if (pext != string::npos) def_csv_filename.erase(pext);
502 	def_csv_filename.append(".c2s");
503 	show_filename(def_csv_filename);
504 }
505 
custom_csv_html(string form,string contents)506 void custom_csv_html(string form, string contents)
507 {
508 	string fname_name = fl_filename_name(def_csv_filename.c_str());
509 	size_t p = fname_name.rfind('.');
510 	if (p != string::npos) fname_name.erase(p);
511 
512 	string csv_name = FLMSG_temp_dir;
513 
514 	csv_name.append(fname_name).append(".htm");
515 
516 	string line;
517 	string field;
518 	string data;
519 	while (data[0] == '\n') data.erase(0,1);
520 	size_t comma = contents.find(",");
521 	while (contents[comma+1] == ' ') contents.erase(comma+1,1);
522 	size_t quote = contents.find("\"");
523 	size_t lfptr = contents.find("\n");
524 	size_t tab;
525 	if (quote == comma + 1) {
526 		contents.erase(quote,1);
527 		lfptr = contents.find("\"\n");
528 	}
529 	while (comma != string::npos) {
530 		field = ":"; field.append(contents.substr(0, comma)).append(":");
531 		if (lfptr != string::npos) {
532 			data = contents.substr(comma + 1, lfptr - comma - 1);
533 			tab = data.find("\t");
534 			while (tab != string::npos) {
535 				data.replace(tab, 1, "     ");
536 				tab = data.find("\t");
537 			}
538 			contents.erase(0, lfptr + 1);
539 			while (data[0] == '\n') data.erase(0,1);
540 			while ((quote = data.find("\"")) != string::npos) data.erase(quote,1);
541 		} else {
542 			data = contents.substr(comma + 1);
543 			tab = data.find("\t");
544 			while (tab != string::npos) {
545 				data.replace(tab, 1, "     ");
546 				tab = data.find("\t");
547 			}
548 			while ((quote = data.find("\"")) != string::npos) data.erase(quote,1);
549 			contents.clear();
550 		}
551 		lfptr = data.find("\n");
552 		while (lfptr != string::npos) {
553 			data.replace(lfptr, 1, "<br>");
554 			lfptr = data.find("\n");
555 		}
556 		replacestr(form, field, data);
557 		comma = contents.find(",");
558 		while (contents[comma+1] == ' ') contents.erase(comma+1,1);
559 		quote = contents.find("\"");
560 		if (quote == comma + 1) {
561 			contents.erase(quote,1);
562 			lfptr = contents.find("\"\n");
563 		} else
564 			lfptr = contents.find("\n");
565 	}
566 
567 	FILE *csvfile = fopen(csv_name.c_str(), "w");
568 	fprintf(csvfile,"%s", form.c_str());
569 	fclose(csvfile);
570 
571 	open_url(csv_name.c_str());
572 }
573 
cb_csv_html()574 void cb_csv_html()
575 {
576 	update_csvfields();
577 	if (csv_field.find("CUSTOM_FORM") == 0) {
578 		size_t plf = csv_field.find("\n");
579 		if (plf != string::npos) {
580 			string fname = CUSTOM_dir;
581 			fname.append(csv_field.substr(12, plf - 12));
582 			fname.append(".htm");
583 			FILE *ffile = fopen(fname.c_str(), "r");
584 			if (!ffile) {
585 				fname += 'l';
586 				ffile = fopen(fname.c_str(), "r");
587 			}
588 			if (ffile) {
589 				string form;
590 				char c = fgetc(ffile);
591 				while (!feof(ffile)) {
592 					form += c;
593 					c = fgetc(ffile);
594 				}
595 				fclose(ffile);
596 				custom_csv_html(form, csv_field.substr(plf+1));
597 				return;
598 			}
599 		}
600 	}
601 
602 	csvbuffer.assign(header("<csvform>"));
603 	csvbuffer.append( lineout( csv_msg, csv_field ) );
604 	write_csv(def_csv_filename);
605 
606 	string fname_name = fl_filename_name(def_csv_filename.c_str());
607 	size_t p = fname_name.rfind('.');
608 	if (p != string::npos) fname_name.erase(p);
609 	string csv_name = FLMSG_temp_dir;
610 	string html_text = "";
611 	csv_name.append(fname_name);
612 	csv_name.append(".htm");
613 
614 	string csvform = csv_html_template;
615 	string rows;
616 	string row;
617 	string field;
618 	size_t p_eol = string::npos;
619 	size_t p_eof = string::npos;
620 	char sepchar = ',';
621 
622 	rows.assign(csv_field);
623 	int nrows = 0, ncols = 0;
624 	int cols = 0;
625 	while (!rows.empty()) {
626 		p_eol = rows.find('\n');
627 		nrows++;
628 		cols = 0;
629 		if (p_eol != string::npos)
630 			row.assign(rows.substr(0,p_eol));
631 		else
632 			row.assign(rows);
633 		while(!row.empty()) {
634 			cols++;
635 			p_eof = row.find(sepchar);
636 			if (p_eof != string::npos)
637 				row.erase(0, p_eof + 1);
638 			else
639 				row.clear();
640 		}
641 		if (cols > ncols) ncols = cols;
642 		if (p_eol != string::npos)
643 			rows.erase(0,p_eol+1);
644 		else
645 			rows.clear();
646 	}
647 
648 	char header[200];
649 	snprintf(header, sizeof(header),"<table BORDER=1 CELLPADDING=4 CELLSPACING=0 COLS=%d>\
650 <tbody>\
651 ", ncols);
652 	html_text.append(header);
653 	rows.assign(csv_field);
654 	while (!rows.empty()) {
655 		cols = 0;
656 		html_text.append("<tr>\n");
657 		p_eol = rows.find('\n');
658 		if (p_eol != string::npos)
659 			row.assign(rows.substr(0,p_eol));
660 		else
661 			row.assign(rows);
662 		while(!row.empty()) {
663 			cols++;
664 			if (row[0] == '"') {
665 				p_eof = row.find('"', 1);
666 				field.assign(row.substr(1, p_eof - 1));
667 				p_eof = row.find(sepchar, p_eof);
668 			}
669 			else {
670 				p_eof = row.find(sepchar);
671 				field.assign(row.substr(0, p_eof));
672 			}
673 			if (field.empty()) field.assign("<br>");
674 			p = 0;
675 			while((p = field.find('"', p)) != string::npos)
676 				field.replace(p, 1,"&#34;");
677 			html_text.append("<td VALIGN=top>").append(field).append("</td>\n");
678 			if (p_eof != string::npos)
679 				row.erase(0, p_eof + 1);
680 			else
681 				row.clear();
682 		}
683 		while (cols < ncols) {
684 			html_text.append("<td></td>\n");
685 			cols++;
686 		}
687 		html_text.append("</tr>\n");
688 		if (p_eol != string::npos)
689 			rows.erase(0,p_eol+1);
690 		else
691 			rows.clear();
692 	}
693 	html_text.append("</tbody>\n");
694 
695 	replacestr(csvform, csv_title, fname_name);
696 	replacestr(csvform, csv_msg, html_text);
697 
698 	FILE *csvfile = fopen(csv_name.c_str(), "w");
699 	fprintf(csvfile,"%s", csvform.c_str());
700 	fclose(csvfile);
701 
702 	open_url(csv_name.c_str());
703 }
704 
custom_csv_text(string form,string contents)705 void custom_csv_text(string form, string contents)
706 {
707 	string fname_name = fl_filename_name(def_csv_filename.c_str());
708 	size_t p = fname_name.rfind('.');
709 	if (p != string::npos) fname_name.erase(p);
710 
711 	string csv_name = FLMSG_temp_dir;
712 
713 	csv_name.append(fname_name).append(".txt");
714 
715 	string line;
716 	string field;
717 	string data;
718 	while (data[0] == '\n') data.erase(0,1);
719 	size_t comma = contents.find(",");
720 	while (contents[comma+1] == ' ') contents.erase(comma+1,1);
721 	size_t quote = contents.find("\"");
722 	size_t lfptr = contents.find("\n");
723 	size_t tab;
724 	if (quote == comma + 1) {
725 		contents.erase(quote,1);
726 		lfptr = contents.find("\"\n");
727 	}
728 	while (comma != string::npos) {
729 		field = ":"; field.append(contents.substr(0, comma)).append(":");
730 		if (lfptr != string::npos) {
731 			data = contents.substr(comma + 1, lfptr - comma - 1);
732 			tab = data.find("\t");
733 			while (tab != string::npos) {
734 				data.replace(tab, 1, "     ");
735 				tab = data.find("\t");
736 			}
737 			contents.erase(0, lfptr + 1);
738 			while (data[0] == '\n') data.erase(0,1);
739 			while ((quote = data.find("\"")) != string::npos) data.erase(quote,1);
740 		} else {
741 			data = contents.substr(comma + 1);
742 			tab = data.find("\t");
743 			while (tab != string::npos) {
744 				data.replace(tab, 1, "     ");
745 				tab = data.find("\t");
746 			}
747 			while ((quote = data.find("\"")) != string::npos) data.erase(quote,1);
748 			contents.clear();
749 		}
750 		replacestr(form, field, data);
751 		comma = contents.find(",");
752 		while (contents[comma+1] == ' ') contents.erase(comma+1,1);
753 		quote = contents.find("\"");
754 		if (quote == comma + 1) {
755 			contents.erase(quote,1);
756 			lfptr = contents.find("\"\n");
757 		} else
758 			lfptr = contents.find("\n");
759 	}
760 
761 	FILE *csvfile = fopen(csv_name.c_str(), "w");
762 	fprintf(csvfile,"%s", form.c_str());
763 	fclose(csvfile);
764 
765 	open_url(csv_name.c_str());
766 }
767 
cb_csv_textout()768 void cb_csv_textout()
769 {
770 	update_csvfields();
771 
772 	csvbuffer.assign(header("<csvform>"));
773 	csvbuffer.append( lineout( csv_msg, csv_field ) );
774 	write_csv(def_csv_filename);
775 
776 	if (csv_field.find("CUSTOM_FORM") == 0) {
777 		size_t plf = csv_field.find("\n");
778 		if (plf != string::npos) {
779 			string fname = CUSTOM_dir;
780 			fname.append(csv_field.substr(12, plf - 12));
781 			fname.append(".txt");
782 			FILE *ffile = fopen(fname.c_str(), "r");
783 			if (ffile) {
784 				string form;
785 				char c = fgetc(ffile);
786 				while (!feof(ffile)) {
787 					form += c;
788 					c = fgetc(ffile);
789 				}
790 				fclose(ffile);
791 				custom_csv_text(form, csv_field.substr(plf+1));
792 				return;
793 			}
794 		}
795 	}
796 
797 	string fname_name = fl_filename_name(def_csv_filename.c_str());
798 	size_t p = fname_name.rfind('.');
799 	if (p != string::npos) fname_name.erase(p);
800 
801 	string csv_name = FLMSG_temp_dir;
802 
803 	csv_name.append(fname_name).append(".txt");
804 
805 	string csvform = csv_txt_template;
806 
807 	replacestr(csvform, csv_msg, csv_field);
808 
809 	FILE *csvfile = fopen(csv_name.c_str(), "w");
810 	fprintf(csvfile,"%s", csvform.c_str());
811 	fclose(csvfile);
812 
813 	open_url(csv_name.c_str());
814 }
815