Project

General

Profile

Download (42.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * pkg_edit.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8
 * Copyright (c) 2014-2024 Rubicon Communications, LLC (Netgate)
9
 * All rights reserved.
10
 *
11
 * Licensed under the Apache License, Version 2.0 (the "License");
12
 * you may not use this file except in compliance with the License.
13
 * You may obtain a copy of the License at
14
 *
15
 * http://www.apache.org/licenses/LICENSE-2.0
16
 *
17
 * Unless required by applicable law or agreed to in writing, software
18
 * distributed under the License is distributed on an "AS IS" BASIS,
19
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
 * See the License for the specific language governing permissions and
21
 * limitations under the License.
22
 */
23

    
24
##|+PRIV
25
##|*IDENT=page-package-edit
26
##|*NAME=Package: Edit
27
##|*DESCR=Allow access to the 'Package: Edit' page.
28
##|*MATCH=pkg_edit.php*
29
##|-PRIV
30

    
31
ini_set('max_execution_time', '0');
32

    
33
require_once("filter.inc");
34
require_once("functions.inc");
35
require_once("guiconfig.inc");
36
require_once("shaper.inc");
37
require_once("pkg-utils.inc");
38
require_once("pfsense-utils.inc");
39
require_once("util.inc");
40

    
41
$xml = htmlspecialchars($_REQUEST['xml']);
42

    
43
$xml_fullpath = realpath('/usr/local/pkg/' . $xml);
44

    
45
if ($xml == "" || $xml_fullpath === false || substr($xml_fullpath, 0, strlen('/usr/local/pkg/')) != '/usr/local/pkg/') {
46
	$pgtitle = array(gettext("Package"), gettext("Editor"));
47
	$pglinks = array("", "@self");
48
	include("head.inc");
49
	print_info_box(gettext("No valid package defined."), 'danger', false);
50
	include("foot.inc");
51
	die;
52
} else {
53
	$pkg = parse_xml_config_pkg($xml_fullpath, "packagegui");
54
}
55

    
56
if ($pkg['include_file'] != "") {
57
	require_once($pkg['include_file']);
58
}
59

    
60
if (!isset($pkg['adddeleteeditpagefields'])) {
61
	$only_edit = true;
62
} else {
63
	$only_edit = false;
64
}
65

    
66
$id = $_REQUEST['id'];
67
if (isset($_POST['id'])) {
68
	$id = htmlspecialchars($_POST['id']);
69
}
70

    
71
// Not posting?	 Then user is editing a record. There must be a valid id
72
// when editing a record.
73
if (!$id && !$_POST) {
74
	$id = "0";
75
}
76

    
77
if (!is_numeric($id)) {
78
	header("Location: /");
79
	exit;
80
}
81

    
82
if ($pkg['custom_php_global_functions'] != "") {
83
	eval($pkg['custom_php_global_functions']);
84
}
85

    
86
/* If the first entry in the array is an empty <config/> tag, kill it.
87
 * See the following tickets for more:
88
 *  https://redmine.pfsense.org/issues/7624
89
 *  https://redmine.pfsense.org/issues/476
90
 */
91

    
92
$pkg_config_path = 'installedpackages/' . xml_safe_fieldname($pkg['name']) . '/config';
93
config_init_path($pkg_config_path);
94
$pkg_config = config_get_path($pkg_config_path);
95
if ((count($pkg_config) > 0) && (empty($pkg_config[0]))) {
96
	array_shift($pkg_config);
97
	config_set_path($pkg_config_path, $pkg_config);
98
}
99

    
100
if ($_REQUEST['savemsg'] != "") {
101
	$savemsg = htmlspecialchars($_REQUEST['savemsg']);
102
}
103

    
104
if ($pkg['custom_php_command_before_form'] != "") {
105
	eval($pkg['custom_php_command_before_form']);
106
}
107

    
108
if ($_POST) {
109
	$rows = 0;
110

    
111
	$input_errors = array();
112
	$reqfields = array();
113
	$reqfieldsn = array();
114
	foreach ($pkg['fields']['field'] as $field) {
115
		if (isset($field['required'])) {
116
			if ($field['fieldname']) {
117
				$reqfields[] = $field['fieldname'];
118
			}
119
			if ($field['fielddescr']) {
120
				$reqfieldsn[] = $field['fielddescr'];
121
			}
122
		}
123
	}
124
	do_input_validation($_POST, $reqfields, $reqfieldsn, $input_errors);
125

    
126
	if ($pkg['custom_php_validation_command']) {
127
		eval($pkg['custom_php_validation_command']);
128
	}
129

    
130
	if ($_POST['act'] == "del") {
131
		if ($pkg['custom_delete_php_command']) {
132
			if ($pkg['custom_php_command_before_form'] != "") {
133
				eval($pkg['custom_php_command_before_form']);
134
			}
135
			eval($pkg['custom_delete_php_command']);
136
		}
137
		write_config($pkg['delete_string']);
138
		// resync the configuration file code if defined.
139
		if ($pkg['custom_php_resync_config_command'] != "") {
140
			if ($pkg['custom_php_command_before_form'] != "") {
141
				eval($pkg['custom_php_command_before_form']);
142
			}
143
			eval($pkg['custom_php_resync_config_command']);
144
		}
145
	} else {
146
		if (!$input_errors && $pkg['custom_add_php_command']) {
147
			if ($pkg['donotsave'] != "" or $pkg['preoutput'] != "") {
148
				include("head.inc");
149
			}
150

    
151
			if ($pkg['preoutput']) {
152
				echo "<pre>";
153
			}
154
			eval($pkg['custom_add_php_command']);
155
			if ($pkg['preoutput']) {
156
				echo "</pre>";
157
			}
158
		}
159
	}
160

    
161
	if (empty($pkg['donotsave'])) {
162

    
163
		// store values in xml configuration file.
164
		if (!$input_errors) {
165
			$pkgarr = array();
166
			foreach ($pkg['fields']['field'] as $fields) {
167
				switch ($fields['type']) {
168
					case "rowhelper":
169
						// save rowhelper items.
170
						#$rowhelpername=($fields['fieldname'] ? $fields['fieldname'] : "row");
171
						$rowhelpername="row";
172
						foreach ($fields['rowhelper']['rowhelperfield'] as $rowhelperfield) {
173
							foreach ($_POST as $key => $value) {
174
								$matches = array();
175
								if (preg_match("/^{$rowhelperfield['fieldname']}(\d+)$/", $key, $matches)) {
176
									if ($rowhelperfield['type'] == "textarea") {
177
										$pkgarr[$rowhelpername][$matches[1]][$rowhelperfield['fieldname']] = unixnewlines($value);
178
									} else {
179
										$pkgarr[$rowhelpername][$matches[1]][$rowhelperfield['fieldname']] = $value;
180
									}
181
								}
182
							}
183
						}
184
						break;
185
					case "textarea":
186
						$fieldname = $fields['fieldname'];
187
						$fieldvalue = unixnewlines(trim($_POST[$fieldname]));
188
						if ($fields['encoding'] == 'base64') {
189
							$fieldvalue = base64_encode($fieldvalue);
190
						}
191
						if ($fieldname) {
192
							$pkgarr[$fieldname] = $fieldvalue;
193
						}
194
					default:
195
						$fieldname = $fields['fieldname'];
196
						if ($fieldname == "interface_array") {
197
							$fieldvalue = $_POST[$fieldname];
198
						} elseif (is_array($_POST[$fieldname])) {
199
							$fieldvalue = implode(',', $_POST[$fieldname]);
200
						} else {
201
							$fieldvalue = trim($_POST[$fieldname]);
202
							if ($fields['encoding'] == 'base64') {
203
								$fieldvalue = base64_encode($fieldvalue);
204
							}
205
						}
206
						if ($fieldname) {
207
							$pkgarr[$fieldname] = $fieldvalue;
208
						}
209
					}
210
			}
211

    
212
			/* If the user supplied an ID and it exists, or if id=0
213
			 * and the settings are invalid, overwrite.
214
			 * See https://redmine.pfsense.org/issues/7624
215
			 */
216
			if (isset($id) && (config_get_path("{$pkg_config_path}/{$id}") ||
217
			   (($id == 0) && !is_array(config_get_path("{$pkg_config_path}/{$id}"))) )) {
218
				config_set_path("{$pkg_config_path}/{$id}", $pkgarr);
219
			} else {
220
				config_set_path("{$pkg_config_path}/", $pkgarr);
221
			}
222

    
223
			write_config($pkg['addedit_string']);
224
			// late running code
225
			if ($pkg['custom_add_php_command_late'] != "") {
226
				eval($pkg['custom_add_php_command_late']);
227
			}
228

    
229
			if (isset($pkg['filter_rules_needed'])) {
230
				filter_configure();
231
			}
232

    
233
			// resync the configuration file code if defined.
234
			if ($pkg['custom_php_resync_config_command'] != "") {
235
				eval($pkg['custom_php_resync_config_command']);
236
			}
237

    
238
			parse_package_templates();
239

    
240
			/* if start_command is defined, restart w/ this */
241
			if ($pkg['start_command'] != "") {
242
				exec($pkg['start_command'] . ">/dev/null 2&>1");
243
			}
244

    
245
			/* if restart_command is defined, restart w/ this */
246
			if ($pkg['restart_command'] != "") {
247
				exec($pkg['restart_command'] . ">/dev/null 2&>1");
248
			}
249

    
250
			if ($pkg['aftersaveredirect'] != "") {
251
				pfSenseHeader($pkg['aftersaveredirect']);
252
			} elseif (!$pkg['adddeleteeditpagefields']) {
253
				pfSenseHeader("pkg_edit.php?xml={$xml}&id=0");
254
			} elseif (!$pkg['preoutput']) {
255
				pfSenseHeader("pkg.php?xml=" . $xml);
256
			}
257
			exit;
258
		} else {
259
			$get_from_post = true;
260
		}
261
	} elseif (!$input_errors) {
262
		// donotsave is enabled.  lets simply exit.
263
		exit;
264
	}
265
}
266

    
267

    
268
// Turn an embedded table into a bootstrap class table. This is for backward compatibility.
269
// We remove any table attributes in the XML and replace them with Bootstrap table classes
270
function bootstrapTable($text) {
271
	$t = strpos($text, '<table') + strlen('<table');	// Find the <table tag
272
	$c = strpos($text, '>', $t);						// And its closing bracket
273

    
274
	// Substitute everything inbetween with our new classes
275
	if ($t && $c && (($c - $t) < 200)) {
276
		return(substr_replace($text, ' class="table table-striped table-hover table-condensed"', $t, ($c - $t)));
277
	}
278
}
279

    
280
/*
281
 * ROW helper function. Creates one element in the row from a PHP table by adding
282
 * the specified element to $group
283
 */
284
function display_row($trc, $value, $fieldname, $type, $rowhelper, $description, $ewidth = null) {
285
	global $text, $group;
286

    
287
	switch ($type) {
288
		case "input":
289
			$inpt = new Form_Input(
290
				$fieldname . $trc,
291
				null,
292
				'text',
293
				$value
294
			);
295

    
296
			$inpt->setHelp($description);
297

    
298
			if ($ewidth) {
299
				$inpt->setWidth($ewidth);
300
			}
301

    
302
			$group->add($inpt);
303
			break;
304
		case "checkbox":
305
			$group->add(new Form_Checkbox(
306
				$fieldname . $trc,
307
				null,
308
				null,
309
				$value,
310
				'ON'
311
			))->setHelp($description);
312

    
313
			break;
314
		case "password":
315
			$group->add(new Form_Input(
316
				$fieldname . $trc,
317
				null,
318
				'password',
319
				$value
320
			))->setHelp($description)->setAttribute('autocomplete', 'new-password');
321
			break;
322
		case "textarea":
323
			$group->add(new Form_Textarea(
324
				$fieldname . $trc,
325
				null,
326
				$value
327
			))->setHelp($description);
328

    
329
			break;
330
		case "select":
331
			$options = array();
332
			foreach ($rowhelper['options']['option'] as $rowopt) {
333
				$options[$rowopt['value']] = $rowopt['name'];
334
			}
335

    
336
			$grp = new Form_Select(
337
				$fieldname . $trc,
338
				null,
339
				$value,
340
				$options
341
			);
342

    
343
			$grp->setHelp($description);
344

    
345
			if ($ewidth) {
346
				$grp->setWidth($ewidth);
347
			}
348

    
349
			$group->add($grp);
350

    
351
			break;
352
		case "interfaces_selection":
353
			$size = ($rowhelper['size'] ? "size=\"{$rowhelper['size']}\"" : '');
354
			$multiple = '';
355
			if (isset($rowhelper['multiple'])) {
356
				$multiple = "multiple";
357
			}
358
			echo "<select style='height:22px;' id='{$fieldname}{$trc}' name='{$fieldname}{$trc}' {$size} {$multiple}>\n";
359
			$ifaces = get_configured_interface_with_descr();
360
			$additional_ifaces = $rowhelper['add_to_interfaces_selection'];
361
			if (!empty($additional_ifaces)) {
362
				$ifaces = array_merge($ifaces, explode(',', $additional_ifaces));
363
			}
364

    
365
			if (is_array($value)) {
366
				$values = $value;
367
			} else {
368
				$values = explode(',', $value);
369
			}
370

    
371
			$ifaces["lo0"] = "loopback";
372
			$options = array();
373
			$selected = array();
374

    
375
			foreach ($ifaces as $ifname => $iface) {
376
				$options[$ifname] = $iface;
377

    
378
				if (in_array($ifname, $values)) {
379
					array_push($selected, $ifname);
380
				}
381
			}
382

    
383
			$group->add(new Form_Select(
384
				$fieldname . $trc,
385
				null,
386
				($multiple) ? $selected:$selected[0],
387
				$options,
388
				$multiple
389
			))->setHelp($description);
390

    
391
			//echo "</select>\n";
392
			break;
393
		case "select_source":
394
			$options = array();
395
			$selected = array();
396

    
397
			$multiple = '';
398
			if (isset($rowhelper['multiple'])) {
399
				$multiple = "multiple";
400
			}
401

    
402
			if (isset($rowhelper['show_disable_value'])) {
403
				$options[$rowhelper['show_disable_value']] = $rowhelper['show_disable_value'];
404
			}
405

    
406
			$source_url = $rowhelper['source'];
407
			try{
408
				@eval("\$pkg_source_txt = $source_url;");
409
			} catch (\Throwable | \Error | \Exception $e) {
410
				log_error(sprintf(gettext("Error in '{$source_url}': %s"), $e->getMessage()));
411
			}
412

    
413
			foreach ($pkg_source_txt as $opt) {
414
				$source_name = ($rowhelper['source_name'] ? $opt[$rowhelper['source_name']] : $opt[$rowhelper['name']]);
415
				$source_value = ($rowhelper['source_value'] ? $opt[$rowhelper['source_value']] : $opt[$rowhelper['value']]);
416
				$options[$source_value] = $source_name;
417

    
418
				if ($source_value == $value) {
419
					array_push($selected, $value);
420
				}
421
			}
422

    
423
			$group->add(new Form_Select(
424
				$fieldname . $trc,
425
				null,
426
				($multiple) ? $selected:$selected[0],
427
				$options,
428
				$multiple
429
			))->setHelp($description);
430

    
431
			break;
432
	}
433
}
434

    
435
function fixup_string($string) {
436
	// fixup #1: $myurl -> http[s]://ip_address:port/
437
	$https = "";
438
	$port = config_get_path('system/webguiport');
439
	if ($port != "443" and $port != "80") {
440
		$urlport = ":" . $port;
441
	} else {
442
		$urlport = "";
443
	}
444

    
445
	if (config_get_path('system/webgui/protocol') == "https") {
446
		$https = "s";
447
	}
448
	$myurl = "http" . $https . "://" . getenv("HTTP_HOST") . $urlport;
449
	$newstring = str_replace("\$myurl", $myurl, $string);
450
	$string = $newstring;
451
	// fixup #2: $wanip
452
	$curwanip = get_interface_ip();
453
	$newstring = str_replace("\$wanip", $curwanip, $string);
454
	$string = $newstring;
455
	// fixup #3: $lanip
456
	$lancfg = config_get_path('interfaces/lan');
457
	$lanip = $lancfg['ipaddr'];
458
	$newstring = str_replace("\$lanip", $lanip, $string);
459
	$string = $newstring;
460
	// fixup #4: fix'r'up here.
461
	return $newstring;
462
}
463

    
464
/*
465
 *	Parse templates if they are defined
466
 */
467
function parse_package_templates() {
468
	global $pkg;
469
	if ($pkg['templates']['template'] != "") {
470
		foreach ($pkg['templates']['template'] as $pkg_template_row) {
471
			$filename = $pkg_template_row['filename'];
472
			$template_text = $pkg_template_row['templatecontents'];
473
			/* calculate total row helpers count and */
474
			/* change fields defined as fieldname_fieldvalue to their value */
475
			foreach ($pkg['fields']['field'] as $fields) {
476
				switch ($fields['type']) {
477
					case "rowhelper":
478
						// save rowhelper items.
479
						$row_helper_total_rows = 0;
480
						$row_helper_data = "";
481
						foreach ($fields['rowhelper']['rowhelperfield'] as $rowhelperfield) {
482
							foreach ($_POST as $key => $value) {
483
								if (preg_match("/^{$rowhelperfield['fieldname']}(\d+)$/", $key, $matches)) {
484
									$row_helper_total_rows++;
485
									$row_helper_data .= $value;
486
									$sep = "";
487
									preg_match($rowhelperfield['fieldname'] . "_fieldvalue\[(.*)\]", $template_text, $sep);
488
									foreach ($sep as $se) {
489
										$separator = $se;
490
									}
491
									if ($separator != "") {
492
										$row_helper_data = str_replace("  ", $separator, $row_helper_data);
493
										$template_text = str_replace("\[{$separator}\]", "", $template_text);
494
									}
495
									$template_text = str_replace($rowhelperfield['fieldname'] . "_fieldvalue", $row_helper_data, $template_text);
496
								}
497
							}
498
						}
499
						break;
500
					default:
501
						$fieldname = $fields['fieldname'];
502
						$fieldvalue = $_POST[$fieldname];
503
						$template_text = str_replace($fieldname . "_fieldvalue", $fieldvalue, $template_text);
504
				}
505
			}
506
			/* replace $domain_total_rows with total rows */
507
			$template_text = str_replace("$domain_total_rows", $row_helper_total_rows, $template_text);
508

    
509
			/* replace cr's */
510
			$template_text = str_replace("\\n", "\n", $template_text);
511

    
512
			/* write out new template file */
513
			$fout = fopen($filename, "w");
514
			fwrite($fout, $template_text);
515
			fclose($fout);
516
		}
517
	}
518
}
519

    
520
//breadcrumb
521
if ($pkg['title'] != "") {
522
	if (!$only_edit) {
523
		$pkg['title'] = $pkg['title'] . '/Edit';
524
	}
525

    
526
	if (strpos($pkg['title'], '/')) {
527
		$title = explode('/', $pkg['title']);
528

    
529
		foreach ($title as $subtitle) {
530
			$pgtitle[] = gettext($subtitle);
531
			$pglinks[] = ((($subtitle == "Edit") || (strlen($pkg['menu'][0]['url']) == 0)) ? "@self" : $pkg['menu'][0]['url']);
532
		}
533
	} else {
534
		$pgtitle = array(gettext("Package"), gettext($pkg['title']));
535
		$pglinks = array("", ((($subtitle == "Edit") || (strlen($pkg['menu'][0]['url']) == 0)) ? "@self" : $pkg['menu'][0]['url']));
536
	}
537
} else {
538
	$pgtitle = array(gettext("Package"), gettext("Editor"));
539
	$pglinks = array("", "@self");
540
}
541

    
542
// Create any required tabs
543
if ($pkg['tabs'] != "") {
544
	$tab_array = array();
545
	foreach ($pkg['tabs']['tab'] as $tab) {
546
		if ($tab['tab_level']) {
547
			$tab_level = $tab['tab_level'];
548
		} else {
549
			$tab_level = 1;
550
		}
551

    
552
		if (isset($tab['active'])) {
553
			$active = true;
554
			$pgtitle[] = $tab['text'] ;
555
			$pglinks[] = ((strlen($tab['url']) > 0) ? $tab['url'] : "@self");
556
		} else {
557
			$active = false;
558
		}
559

    
560
		$urltmp = "";
561
		if ($tab['url'] != "") {
562
			$urltmp = $tab['url'];
563
		}
564

    
565
		if ($tab['xml'] != "") {
566
			$urltmp = "pkg_edit.php?xml=" . $tab['xml'];
567
		}
568

    
569
		$addresswithport = getenv("HTTP_HOST");
570
		$colonpos = strpos($addresswithport, ":");
571

    
572
		if ($colonpos !== False) {
573
			//my url is actually just the IP address of the pfsense box
574
			$myurl = substr($addresswithport, 0, $colonpos);
575
		} else {
576
			$myurl = $addresswithport;
577
		}
578

    
579
		// eval url so that above $myurl item can be processed if need be.
580
		$url = str_replace('$myurl', $myurl, $urltmp);
581

    
582
		$tab_array[$tab_level][] = array(
583
			$tab['text'],
584
			$active,
585
			$url
586
		);
587
	}
588

    
589
	ksort($tab_array);
590
}
591
if (!empty($pkg['tabs'])) {
592
	$shortcut_section = $pkg['shortcut_section'];
593
}
594

    
595
include("head.inc");
596
if ($pkg['custom_php_after_head_command']) {
597
	eval($pkg['custom_php_after_head_command']);
598
}
599
if (isset($tab_array)) {
600
	foreach ($tab_array as $tab) {
601
		display_top_tabs($tab);
602
	}
603
}
604

    
605
// Start of page display
606
if ($input_errors) {
607
	print_input_errors($input_errors);
608
}
609

    
610
if ($savemsg) {
611
	print_info_box($savemsg, 'success');
612
}
613

    
614
$cols = 0;
615
$savevalue = gettext("Save");
616
if ($pkg['savetext'] != "") {
617
	$savevalue = $pkg['savetext'];
618
}
619

    
620
$savehelp = "";
621
if ($pkg['savehelp'] != "") {
622
	$savehelp = $pkg['savehelp'];
623
}
624

    
625
$saveicon = "fa-solid fa-save";
626
if ($pkg['saveicon'] != "") {
627
	$saveicon = $pkg['saveicon'];
628
}
629

    
630
$savebtnclass = "btn-primary";
631
if ($pkg['savebtnclass'] != "") {
632
	$savebtnclass = $pkg['savebtnclass'];
633
}
634

    
635
$grouping = false; // Indicates the elements we are composing are part of a combined group
636

    
637
$savebutton = new Form_Button(
638
	'submit',
639
	$savevalue,
640
	null,
641
	$saveicon
642
);
643
$savebutton->addClass($savebtnclass);
644

    
645
if ($savehelp) {
646
	$savebutton->setHelp($savehelp);
647
}
648

    
649
$form = new Form($savebutton);
650

    
651
$form->addGlobal(new Form_Input(
652
	'xml',
653
	null,
654
	'hidden',
655
	$xml
656
));
657

    
658
/* If a package's XML has <advanced_options/> configured, then setup
659
 * the section for the fields that have <advancedfield/> set.
660
 * These fields will be placed below other fields in a separate area titled 'Advanced Features'.
661
 * These advanced fields are not normally configured and generally left to default to 'default settings'.
662
 */
663

    
664
if ($pkg['advanced_options'] == "enabled") {
665
	$advfield_count = 0;
666
	$advanced = new Form_Section("Advanced Features");
667
	$advanced->addClass('advancedoptions');
668
}
669

    
670
$js_array = array();
671

    
672
// Now loop through all of the fields defined in the XML
673
if (!is_array($pkg['fields']['field'])) {
674
	$pkg['fields']['field'] = array();
675
}
676
foreach ($pkg['fields']['field'] as $pkga) {
677

    
678
	$action = "";
679
	$uid = "";
680

    
681
	if ($pkga['type'] == "sorting") {
682
		continue;
683
	}
684

    
685
	// Generate a new section
686
	if ($pkga['type'] == "listtopic") {
687
		if (isset($pkga['advancedfield']) && isset($advfield_count)) {
688
			$advanced->addInput(new Form_StaticText(
689
				strip_tags($pkga['name']),
690
				null
691
			));
692

    
693
			$advfield_count++;
694
		} else {
695
			if (isset($section)) {
696
				$form->add($section);
697
			}
698

    
699
			if (isset($pkga['collapse'])) {
700
				$uid = uniqid("section");
701

    
702
				$action = COLLAPSIBLE;
703

    
704
				if ($pkga['collapse'] == "open") {
705
					$action |= SEC_OPEN;
706
				} else {
707
					$action |= SEC_CLOSED;
708
				}
709
			}
710

    
711
			$section = new Form_Section(strip_tags($pkga['name']), $uid, $action);
712
		}
713

    
714
		continue;
715
	}
716

    
717
	// 'begin' starts a form group. ('end' ends it)
718
	if ($pkga['combinefields'] == "begin") {
719
		$group = new Form_Group(strip_tags($pkga['fielddescr']));
720
		$grouping = true;
721
	}
722

    
723
	$size = "";
724
	$colspan="";
725

    
726
	// if user is editing a record, load in the data.
727
	$fieldname = $pkga['fieldname'];
728
	unset($value);
729
	if ($get_from_post) {
730
		$value = $_POST[$fieldname];
731
		if (is_array($value)) {
732
			$value = implode(',', $value);
733
		}
734
	} else {
735
		$this_pkg_config = isset($id) ? config_get_path("{$pkg_config_path}/{$id}") : null;
736
		if (is_array($this_pkg_config) && isset($this_pkg_config[$fieldname])) {
737
			$value = $this_pkg_config[$fieldname];
738
		} else {
739
			if (isset($pkga['default_value'])) {
740
				$value = $pkga['default_value'];
741
			}
742
		}
743
	}
744

    
745
	// If we get here but have no $section, the package config file probably had no listtopic field
746
	// We can create a section with a generic name to fix that
747
	if (!$section) {
748
		$section = new Form_Section('General Options');
749
	}
750

    
751
	// If this is a required field, pre-pend a "*" to the field description
752
	// This tells the system to add "element-required" class text decoration to the field label
753
	if (isset($pkga['required'])) {
754
		$pkga['fielddescr'] = "*" . $pkga['fielddescr'];
755
	}
756

    
757
	switch ($pkga['type']) {
758
		// Create an input element. The format is slightly different depending on whether we are composing a group,
759
		// section, or advanced section. This is true for every element type
760
		case "input":
761
			if (($pkga['encoding'] == 'base64') && !$get_from_post && !empty($value)) {
762
				$value = base64_decode($value);
763
			}
764

    
765
			$grp = new Form_Input(
766
					$pkga['fieldname'],
767
					$pkga['fielddescr'],
768
					'text',
769
					$value
770
				);
771

    
772
			$grp->setHelp($pkga['description']);
773

    
774
			foreach (array_get_path($pkga, 'class', []) as $class) {
775
				$grp->addClass($class);
776
			}
777

    
778
			if ($pkga['width']) {
779
				$grp->setWidth($pkga['width']);
780
			}
781

    
782
			if ($grouping) {
783
				$group->add($grp);
784
			} else {
785
				if (isset($pkga['advancedfield']) && isset($advfield_count)) {
786
					$advanced->addInput($grp);
787
				} else {
788
					$section->addInput($grp);
789
				}
790
			}
791

    
792
			break;
793

    
794
		case "password":
795
			if (($pkga['encoding'] == 'base64') && !$get_from_post && !empty($value)) {
796
				$value = base64_decode($value);
797
			}
798

    
799
			// Create a password element
800
			if ($grouping) {
801
				$group->add(new Form_Input(
802
					$pkga['fieldname'],
803
					$pkga['fielddescr'],
804
					'password',
805
					$value
806
				))->setHelp($pkga['description'])->setAttribute('autocomplete', 'new-password');
807
			} else {
808
				if (isset($pkga['advancedfield']) && isset($advfield_count)) {
809
					$advanced->addInput(new Form_Input(
810
						$pkga['fieldname'],
811
						$pkga['fielddescr'],
812
						'password',
813
						$value
814
					))->setHelp($pkga['description'])->setAttribute('autocomplete', 'new-password');
815
				} else {
816
					$section->addInput(new Form_Input(
817
						$pkga['fieldname'],
818
						$pkga['fielddescr'],
819
						'password',
820
						$value
821
					))->setHelp($pkga['description'])->setAttribute('autocomplete', 'new-password');
822
				}
823
			}
824

    
825
			break;
826

    
827
		case "info":
828
			// If the info contains a table we should detect and Bootstrap it
829

    
830
			if (strpos($pkga['description'], '<table') !== FALSE) {
831
				$info = bootstrapTable($pkga['description']);
832
			} else {
833
				$info = $pkga['description'];
834
			}
835

    
836
			if (isset($pkga['advancedfield']) && isset($advfield_count)) {
837
				$advanced->addInput(new Form_StaticText(
838
					strip_tags($pkga['fielddescr']),
839
					$info
840
				));
841
			} else {
842
				$section->addInput(new Form_StaticText(
843
					strip_tags($pkga['fielddescr']),
844
					$info
845
				));
846
			}
847

    
848
			break;
849

    
850
		case "select":
851
			// Create a select element
852
			$optionlist = array();
853
			$selectedlist = array();
854

    
855
			$fieldname = $pkga['fieldname'];
856

    
857
			if (isset($pkga['multiple'])) {
858
				$multiple = 'multiple';
859
				$items = explode(',', $value);
860
				$fieldname .= "[]";
861
			} else {
862
				$multiple = '';
863
				$items = array($value);
864
			}
865

    
866
			$onchange = (isset($pkga['onchange']) ? "{$pkga['onchange']}" : '');
867

    
868
			foreach ($pkga['options']['option'] as $opt) {
869
				$optionlist[$opt['value']] = $opt['name'];
870

    
871
				if (in_array($opt['value'], $items)) {
872
					array_push($selectedlist, $opt['value']);
873
				}
874
			}
875

    
876
			if (isset($pkga['advancedfield']) && isset($advfield_count)) {
877
				$function = $grouping ? $advanced->add:$advanced->addInput;
878
			} else {
879
				$function = ($grouping) ? $section->add:$section->addInput;
880
			}
881

    
882
			$grp = new Form_Select(
883
						$pkga['fieldname'],
884
						strip_tags($pkga['fielddescr']),
885
						isset($pkga['multiple']) ? $selectedlist:$selectedlist[0],
886
						$optionlist,
887
						isset($pkga['multiple'])
888
					);
889

    
890
			$grp ->setHelp($pkga['description'])->setOnchange($onchange)->setAttribute('size', $pkga['size']);
891

    
892
			if ($pkga['width']) {
893
				$grp->setWidth($pkga['width']);
894
			}
895

    
896
			if ($grouping) {
897
				$group->add($grp);
898
			} else {
899
				if (isset($pkga['advancedfield']) && isset($advfield_count)) {
900
					$advanced->addInput($grp);
901
				} else {
902
					$section->addInput($grp);
903
				}
904
			}
905

    
906
			break;
907

    
908
		case "select_source":
909

    
910
			if (isset($pkga['multiple'])) {
911
				$items = explode(',', $value);
912
				$fieldname .= "[]";
913
			} else {
914
				$items = array($value);
915
			}
916

    
917
			$onchange = (isset($pkga['onchange']) ? "{$pkga['onchange']}" : '');
918

    
919
			$source_url = $pkga['source'];
920
			try{
921
				@eval("\$pkg_source_txt = $source_url;");
922
			} catch (\Throwable | \Error | \Exception $e) {
923
				log_error(sprintf(gettext("Error in '{$source_url}': %s"), $e->getMessage()));
924
			}
925
			#check if show disable option is present on xml
926
			if (!is_array($pkg_source_txt)) {
927
				$pkg_source_txt = array();
928
			}
929
			if (isset($pkga['show_disable_value'])) {
930
				array_push($pkg_source_txt,
931
					array(($pkga['source_name']? $pkga['source_name'] : $pkga['name'])=> $pkga['show_disable_value'], ($pkga['source_value']? $pkga['source_value'] : $pkga['value'])=> $pkga['show_disable_value']));
932
			}
933

    
934
			$srcoptions = array();
935
			$srcselected = array();
936

    
937
			foreach ($pkg_source_txt as $opt) {
938
				$source_name =($pkga['source_name']? $opt[$pkga['source_name']] : $opt[$pkga['name']]);
939
				$source_value =($pkga['source_value'] ? $opt[$pkga['source_value']] : $opt[$pkga['value']]);
940
				$srcoptions[$source_value] = $source_name;
941

    
942
				if (in_array($source_value, $items)) {
943
					array_push($srcselected, $source_value);
944
				}
945
			}
946

    
947
			$descr = (isset($pkga['description'])) ? $pkga['description'] : "";
948
			if ($grouping) {
949
				$group->add(new Form_Select(
950
					$pkga['fieldname'],
951
					strip_tags($pkga['fielddescr']),
952
					isset($pkga['multiple']) ? $srcselected:$srcselected[0],
953
					$srcoptions,
954
					isset($pkga['multiple'])
955
				))->setHelp($descr)->setOnchange($onchange);
956
			} else {
957
				if (isset($pkga['advancedfield']) && isset($advfield_count)) {
958
					$advanced->addInput(new Form_Select(
959
						$pkga['fieldname'],
960
						strip_tags($pkga['fielddescr']),
961
						isset($pkga['multiple']) ? $srcselected:$srcselected[0],
962
						$srcoptions,
963
						isset($pkga['multiple'])
964
					))->setHelp($descr)->setOnchange($onchange);
965
				} else {
966
					$section->addInput(new Form_Select(
967
						$pkga['fieldname'],
968
						strip_tags($pkga['fielddescr']),
969
						isset($pkga['multiple']) ? $srcselected:$srcselected[0],
970
						$srcoptions,
971
						isset($pkga['multiple'])
972
					))->setHelp($descr)->setOnchange($onchange);
973
				}
974
			}
975

    
976
			break;
977

    
978
		case "vpn_selection" :
979
			$vpnlist = array();
980

    
981
			foreach (config_get_path('ipsec/phase1', []) as $vpn) {
982
				$vpnlist[$vpn['descr']] = $vpn['descr'];
983

    
984
			}
985

    
986
			if ($grouping) {
987
				$group->add(new Form_Select(
988
					$pkga['fieldname'],
989
					null,
990
					false,
991
					$vpnlist
992
				))->setHelp(fixup_string($pkga['description']));
993
			} else {
994
				if (isset($pkga['advancedfield']) && isset($advfield_count)) {
995
					$advanced->addInput(new Form_Select(
996
						$pkga['fieldname'],
997
						null,
998
						false,
999
						$vpnlist
1000
					))->setHelp(fixup_string($pkga['description']));
1001
				} else {
1002
					$section->addInput(new Form_Select(
1003
						$pkga['fieldname'],
1004
						null,
1005
						false,
1006
						$vpnlist
1007
					))->setHelp(fixup_string($pkga['description']));
1008
				}
1009
			}
1010

    
1011
			break;
1012

    
1013
		// Create a checkbox element
1014
		case "checkbox":
1015
			$onchange = (isset($pkga['onchange']) ? "{$pkga['onchange']}" : '');
1016
			if (isset($pkga['enablefields']) || isset($pkga['checkenablefields'])) {
1017
				$onclick = 'javascript:enablechange();';
1018
			} else {
1019
				$onclick = '';
1020
			}
1021

    
1022
			if ($grouping) {
1023
				$group->add(new Form_Checkbox(
1024
					$pkga['fieldname'],
1025
					$pkga['fielddescr'],
1026
					fixup_string($pkga['description']),
1027
					($value == "on"),
1028
					'on'
1029
				))->setOnclick($onclick)
1030
				  ->setOnchange($onchange)
1031
				  ->setHelp($pkga['sethelp']);
1032
			} else {
1033
				if (isset($pkga['advancedfield']) && isset($advfield_count)) {
1034
					$advanced->addInput(new Form_Checkbox(
1035
						$pkga['fieldname'],
1036
						$pkga['fielddescr'],
1037
						fixup_string($pkga['description']),
1038
						($value == "on"),
1039
						'on'
1040
					))->setOnclick($onclick)
1041
					  ->setOnchange($onchange)
1042
					  ->setHelp($pkga['sethelp']);
1043
				} else {
1044
					$section->addInput(new Form_Checkbox(
1045
						$pkga['fieldname'],
1046
						$pkga['fielddescr'],
1047
						fixup_string($pkga['description']),
1048
						($value == "on"),
1049
						'on'
1050
					))->setOnclick($onclick)
1051
					  ->setOnchange($onchange)
1052
					  ->setHelp($pkga['sethelp']);
1053
				}
1054
			}
1055

    
1056
			break;
1057

    
1058
		// Create a textarea element
1059
		case "textarea":
1060
			$rows = $cols = 0;
1061

    
1062
			if ($pkga['rows']) {
1063
				$rows = $pkga['rows'];
1064
			}
1065
			if ($pkga['cols']) {
1066
				$cols = $pkga['cols'];
1067
			}
1068

    
1069
			if (($pkga['encoding'] == 'base64') && !$get_from_post && !empty($value)) {
1070
				$value = base64_decode($value);
1071
			}
1072

    
1073
			$grp = new Form_Textarea(
1074
					$pkga['fieldname'],
1075
					$pkga['fielddescr'],
1076
					$value
1077
			);
1078

    
1079
			$grp->setHelp(fixup_string($pkga['description']));
1080

    
1081
			if ($rows > 0) {
1082
				$grp->setRows($rows);
1083
			}
1084

    
1085
			if ($cols > 0) {
1086
				$grp->setCols($cols);
1087
			}
1088

    
1089
			if ($pkga['wrap'] == "off") {
1090
				$grp->setAttribute("wrap", "off");
1091
				$grp->setAttribute("style", "white-space:nowrap; width: auto;");
1092
			} else {
1093
				$grp->setAttribute("style", "width: auto;");
1094
			}
1095

    
1096
			if ($grouping) {
1097
				$group->add($grp);
1098
			} else {
1099
				if (isset($pkga['advancedfield']) && isset($advfield_count)) {
1100
					$advanced->addInput($grp);
1101
				} else {
1102
					$section->addInput($grp);
1103
				}
1104
			}
1105

    
1106
			break;
1107

    
1108
		case "aliases":
1109

    
1110
			// Use xml tag <typealiases> to filter type aliases
1111
			$size = ($pkga['size'] ? "size=\"{$pkga['size']}\"" : '');
1112
			$fieldname = $pkga['fieldname'];
1113

    
1114
			config_init_path('aliases/alias');
1115
			$a_aliases = config_get_path('aliases/alias');
1116
			$addrisfirst = 0;
1117
			$aliasesaddr = "";
1118

    
1119
			if (isset($a_aliases)) {
1120
				if (!empty($pkga['typealiases'])) {
1121
					foreach ($a_aliases as $alias) {
1122
						if ($alias['type'] == $pkga['typealiases']) {
1123
							if ($addrisfirst == 1) {
1124
								$aliasesaddr .= ",";
1125
							}
1126
							$aliasesaddr .= "'" . $alias['name'] . "'";
1127
							$addrisfirst = 1;
1128
						}
1129
					}
1130
				} else {
1131
					foreach ($a_aliases as $alias) {
1132
						if ($addrisfirst == 1) {
1133
							$aliasesaddr .= ",";
1134
						}
1135
						$aliasesaddr .= "'" . $alias['name'] . "'";
1136
						$addrisfirst = 1;
1137
					}
1138
				}
1139
			}
1140

    
1141
			$grp = new Form_Input(
1142
					$pkga['fieldname'],
1143
					$pkga['fielddescr'],
1144
					'text',
1145
					$value
1146
				);
1147

    
1148
			$grp->setHelp($pkga['description']);
1149

    
1150
			if ($pkga['width']) {
1151
				$grp->setWidth($pkga['width']);
1152
			}
1153

    
1154
			if ($grouping) {
1155
				$group->add($grp);
1156
			} else {
1157
				if (isset($pkga['advancedfield']) && isset($advfield_count)) {
1158
					$advanced->addInput($grp);
1159
				} else {
1160
					$section->addInput($grp);
1161
				}
1162
			}
1163

    
1164
			$script = "<script type='text/javascript'>\n";
1165
			$script .= "//<![CDATA[\n";
1166
			$script .= "events.push(function(){\n";
1167
			$script .= "	var aliasarray = new Array({$aliasesaddr})\n";
1168
			$script .= "	$('#' + '{$fieldname}').autocomplete({\n";
1169
			$script .= "		source: aliasarray\n";
1170
			$script .= "	})\n";
1171
			$script .= "});\n";
1172
			$script .= "//]]>\n";
1173
			$script .= "</script>";
1174

    
1175
			echo $script;
1176

    
1177
			break;
1178

    
1179
		case "interfaces_selection":
1180
			$ips = array();
1181
			$interface_regex=(isset($pkga['hideinterfaceregex']) ? $pkga['hideinterfaceregex'] : "nointerfacestohide");
1182
			foreach (config_get_path('interfaces', []) as $iface_key=>$iface_value) {
1183
				if (isset($iface_value['enable']) && !preg_match("/{$interface_regex}/", $iface_key)) {
1184
					$iface_description=($iface_value['descr'] !="" ? strtoupper($iface_value['descr']) : strtoupper($iface_key));
1185
					if (isset($pkga['showips'])) {
1186
						$iface_description .= " address";
1187
					}
1188
					$ips[] = array('ip'=> $iface_key, 'description'=> $iface_description);
1189
				}
1190
			}
1191

    
1192
			if (isset($pkga['showvirtualips'])) {
1193
				foreach (config_get_path('virtualip/vip', []) as $vip) {
1194
					if (!preg_match("/{$interface_regex}/", $vip['interface'])) {
1195
						$vip_description=($vip['descr'] !="" ? " ({$vip['descr']}) " : " ");
1196
					}
1197
					switch ($vip['mode']) {
1198
						case "ipalias":
1199
						case "carp":
1200
							$ips[] = array('ip' => $vip['subnet'], 'description' => "{$vip['subnet']} $vip_description");
1201
							break;
1202
						case "proxyarp":
1203
							if ($vip['type'] == "network") {
1204
								$start = ip2long32(gen_subnet($vip['subnet'], $vip['subnet_bits']));
1205
								$end = ip2long32(gen_subnet_max($vip['subnet'], $vip['subnet_bits']));
1206
								$len = $end - $start;
1207
								for ($i = 0; $i <= $len; $i++) {
1208
									$ips[]= array('ip' => long2ip32($start+$i), 'description' => long2ip32($start+$i)." from {$vip['subnet']}/{$vip['subnet_bits']} {$vip_description}");
1209
								}
1210
							} else {
1211
								$ips[]= array('ip' => $vip['subnet'], 'description' => "{$vip['subnet']} $vip_description");
1212
							}
1213
							break;
1214
					}
1215
				}
1216
			}
1217

    
1218
			sort($ips);
1219
			if (isset($pkga['showlistenall'])) {
1220
				array_unshift($ips, array('ip' => gettext('All'), 'description' => gettext('Listen on All interfaces/ip addresses ')));
1221
			}
1222

    
1223
			if (!preg_match("/{$interface_regex}/", "loopback")) {
1224
				$loopback_text = gettext("loopback");
1225
				$iface_description=(isset($pkga['showips']) ? "127.0.0.1 (" . $loopback_text . ")" : $loopback_text);
1226
				array_push($ips, array('ip' => 'lo0', 'description' => $iface_description));
1227
			}
1228

    
1229
			#show interfaces array on gui
1230
			$size = ($pkga['size'] ? "size=\"{$pkga['size']}\"" : '');
1231
			$multiple = '';
1232
			$fieldname = $pkga['fieldname'];
1233
			if (isset($pkga['multiple'])) {
1234
				$fieldname .= '[]';
1235
				$multiple = 'multiple';
1236
			}
1237

    
1238
			$selectedlist = array();
1239
			$optionlist = array();
1240

    
1241
			if (is_array($value)) {
1242
				$values = $value;
1243
			} else {
1244
				$values = explode(',', $value);
1245
			}
1246

    
1247
			foreach ($ips as $iface) {
1248
				if (in_array($iface['ip'], $values)) {
1249
					array_push($selectedlist, $iface['ip']);
1250
				}
1251

    
1252
				$optionlist[$iface['ip']] = $iface['description'];
1253
			}
1254

    
1255
			if ($grouping) {
1256
				$group->add(new Form_Select(
1257
					$pkga['fieldname'],
1258
					$pkga['fielddescr'],
1259
					isset($pkga['multiple']) ? $selectedlist:$selectedlist[0],
1260
					$optionlist,
1261
					isset($pkga['multiple'])
1262
				))->setHelp($pkga['description']);
1263
			} else {
1264
				if (isset($pkga['advancedfield']) && isset($advfield_count)) {
1265
					$advanced->addInput(new Form_Select(
1266
						$pkga['fieldname'],
1267
						$pkga['fielddescr'],
1268
						isset($pkga['multiple']) ? $selectedlist:$selectedlist[0],
1269
						$optionlist,
1270
						isset($pkga['multiple'])
1271
					))->setHelp($pkga['description']);
1272
				} else {
1273
					$section->addInput(new Form_Select(
1274
						$pkga['fieldname'],
1275
						$pkga['fielddescr'],
1276
						isset($pkga['multiple']) ? $selectedlist:$selectedlist[0],
1277
						$optionlist,
1278
						isset($pkga['multiple'])
1279
					))->setHelp($pkga['description']);
1280
				}
1281
			}
1282

    
1283
			break;
1284

    
1285
		// Create radio button
1286
		case "radio":
1287
			if ($grouping) {
1288
				$group->add(new Form_Checkbox(
1289
					$pkga['fieldname'],
1290
					$pkga['fielddescr'],
1291
					fixup_string($pkga['description']),
1292
					($value == "on"),
1293
					'on'
1294
				))->displayAsRadio();
1295
			} else {
1296
				if (isset($pkga['advancedfield']) && isset($advfield_count)) {
1297
					$advanced->addInput(new Form_Checkbox(
1298
						$pkga['fieldname'],
1299
						$pkga['fielddescr'],
1300
						fixup_string($pkga['description']),
1301
						($value == "on"),
1302
						'on'
1303
					))->displayAsRadio();
1304
				} else {
1305
					$section->addInput(new Form_Checkbox(
1306
						$pkga['fieldname'],
1307
						$pkga['fielddescr'],
1308
						fixup_string($pkga['description']),
1309
						($value == "on"),
1310
						'on'
1311
					))->displayAsRadio();
1312
				}
1313
			}
1314

    
1315
			break;
1316

    
1317
		// Create form button
1318
		case "button":
1319
			$newbtnicon = "fa-solid fa-save";
1320
			if ($pkga['buttonicon'] != "") {
1321
				$newbtnicon = $pkga['buttonicon'];
1322
			}
1323
			$newbtnclass = "btn-primary";
1324
			if ($pkga['buttonclass'] != "") {
1325
				$newbtnclass = $pkga['buttonclass'];
1326
			}
1327

    
1328
			$newbtn = new Form_Button(
1329
				$pkga['fieldname'],
1330
				$pkga['fielddescr'],
1331
				null,
1332
				$newbtnicon
1333
			);
1334
			$newbtn->addClass($newbtnclass);
1335

    
1336
			if ($grouping) {
1337
				$group->add(new Form_StaticText(
1338
					null,
1339
					$newbtn . '<br />' . '<div class="help-block">' . fixup_string($pkga['description']) . '</div>'
1340
				));
1341
			} else {
1342
				if (isset($pkga['advancedfield']) && isset($advfield_count)) {
1343
					$advanced->addInput(new Form_StaticText(
1344
						null,
1345
						$newbtn . '<br />' . '<div class="help-block">' . fixup_string($pkga['description']) . '</div>'
1346
					));
1347
				} else {
1348
					$section->addInput(new Form_StaticText(
1349
						null,
1350
						$newbtn . '<br />' . '<div class="help-block">' . fixup_string($pkga['description']) . '</div>'
1351
					));
1352
				}
1353
			}
1354

    
1355
			break;
1356

    
1357
		case "schedule_selection":
1358

    
1359
			$input = "<select id='{$pkga['fieldname']}' name='{$pkga['fieldname']}'>\n";
1360
			$schedules = array();
1361
			$schedules[] = "none";
1362
			foreach (config_get_path('schedules/schedule', []) as $schedule) {
1363
				if ($schedule['name'] != "") {
1364
					$schedules[] = $schedule['name'];
1365
				}
1366
			}
1367

    
1368
			foreach ($schedules as $schedule) {
1369
				if ($schedule == "none") {
1370
					$schedlist[""] = $schedule;
1371
				} else {
1372
					$schedlist[$schedule] = $schedule;
1373
				}
1374
			}
1375

    
1376
			if ($grouping) {
1377
				$group->add(new Form_Select(
1378
					$pkga['fieldname'],
1379
					$pkga['fielddescr'],
1380
					$value,
1381
					$schedlist
1382
				))->setHelp(fixup_string($pkga['description']));
1383
			} else {
1384
				if (isset($pkga['advancedfield']) && isset($advfield_count)) {
1385
					$advanced->addInput(new Form_Select(
1386
						$pkga['fieldname'],
1387
						$pkga['fielddescr'],
1388
						$value,
1389
						$schedlist
1390
					))->setHelp(fixup_string($pkga['description']));
1391
				} else {
1392
					$section->addInput(new Form_Select(
1393
						$pkga['fieldname'],
1394
						$pkga['fielddescr'],
1395
						$value,
1396
						$schedlist
1397
					))->setHelp(fixup_string($pkga['description']));
1398
				}
1399
			}
1400

    
1401
			break;
1402

    
1403
		case "rowhelper":
1404

    
1405
			$rowhelpername="row";
1406

    
1407
				$rowcounter = 0;
1408
				$trc = 0;
1409
				$this_pkg_config = isset($id) ? config_get_path("{$pkg_config_path}/{$id}") : null;
1410

    
1411
				//Use assigned $this_pkg_config or create an empty array to enter loop
1412
				if (is_array($this_pkg_config) && isset($this_pkg_config[$rowhelpername])) {
1413
					$saved_rows=$this_pkg_config[$rowhelpername];
1414
				} else {
1415
					$saved_rows[] = array();
1416
				}
1417

    
1418
				$numrows = count($saved_rows) - 1;
1419

    
1420
				foreach ($saved_rows as $row) {
1421
					$group = new Form_Group(($rowcounter == 0) ? $pkga['fielddescr']:null);
1422
					$group->addClass('repeatable');
1423

    
1424
					foreach ($pkga['rowhelper']['rowhelperfield'] as $rowhelper) {
1425
						unset($value);
1426
						$width = null;
1427

    
1428
						$fieldname = $rowhelper['fieldname'];
1429
						$fielddescr = $rowhelper['fielddescr'];
1430

    
1431
						// If input validation failed, read the value from the POST data so that the user's input is not lost
1432
						if ($get_from_post && isset($_POST[$fieldname.$rowcounter])) {
1433
							$value = $_POST[$fieldname.$rowcounter];
1434
						} elseif (isset($id) && $this_pkg_config) {
1435
							$value = $row[$fieldname];
1436
						} elseif ($rowhelper['value'] != "") {
1437
							$value = $rowhelper['value'];
1438
						}
1439

    
1440
						$type = $rowhelper['type'];
1441
						if ($type == "input" || $type == "password" || $type == "textarea") {
1442
							if (($rowhelper['encoding'] == 'base64') && !$get_from_post && !empty($value)) {
1443
								$value = base64_decode($value);
1444
							}
1445
						}
1446

    
1447

    
1448
						if ($rowhelper['size']) {
1449
							$size = $rowhelper['size'];
1450
						} else if ($pkga['size']) {
1451
							$size = $pkga['size'];
1452
						} else {
1453
							$size = "8";
1454
						}
1455

    
1456
						if ($rowhelper['width']) {
1457
							$width = $rowhelper['width'];
1458
						}
1459

    
1460
						display_row($rowcounter, $value, $fieldname, $type, $rowhelper, ($numrows == $rowcounter) ? $fielddescr:null, $width);
1461

    
1462
						$text = "";
1463
						$trc++;
1464
					}
1465

    
1466
					// Delete row button
1467
					$group->add(new Form_Button(
1468
						'deleterow' . $rowcounter,
1469
						'Delete',
1470
						null,
1471
						'fa-solid fa-trash-can'
1472
					))->removeClass('btn-primary')->addClass('btn-warning btn-sm');
1473

    
1474
					$rowcounter++;
1475
					$section->add($group);
1476
				}
1477

    
1478
			// Add row button
1479
			$section->addInput(new Form_Button(
1480
				'addrow',
1481
				'Add',
1482
				null,
1483
				'fa-solid fa-plus'
1484
			))->addClass('btn-success');
1485

    
1486
			break;
1487

    
1488
	}
1489

    
1490
		if ($pkga['combinefields'] == "end") {
1491
			$group->add(new Form_StaticText(
1492
				null,
1493
				null
1494
			));
1495

    
1496
			if ($advanced) {
1497
				$advanced->add($group);
1498
			} else {
1499
				$section->add($group);
1500
			}
1501

    
1502
			$grouping = false;
1503
		}
1504

    
1505
	#increment counter
1506
	$i++;
1507
} // e-o-foreach field described in the XML
1508

    
1509
if ($section) {
1510
	$form->add($section);
1511
}
1512

    
1513
$form->addGlobal(new Form_Input(
1514
	'id',
1515
	null,
1516
	'hidden',
1517
	$id
1518
));
1519

    
1520
// If we created an advanced section, add it (and a button) to the form here
1521
if (!empty($advanced)) {
1522
	$form->addGlobal(new Form_Button(
1523
		'showadv',
1524
		'Show Advanced Options',
1525
		null,
1526
		'fa-solid fa-cog'
1527
	))->setAttribute('type','button')->addClass('btn-info');
1528

    
1529
	$form->add($advanced);
1530
}
1531

    
1532
print($form);
1533

    
1534
if ($pkg['note'] != "") {
1535
	print_info_box($pkg['note'], 'info');
1536
}
1537

    
1538
if ($pkg['custom_php_after_form_command']) {
1539
	eval($pkg['custom_php_after_form_command']);
1540
}
1541

    
1542

    
1543
$hidemsg = gettext("Show Advanced Options");
1544
$showmsg = gettext("Hide Advanced Options");
1545

    
1546
if ($pkg['fields']['field'] != "") { ?>
1547
<script type="text/javascript">
1548
//<![CDATA[
1549
	events.push(function() {
1550

    
1551
	// Hide the advanced section
1552
	var advanced_visible = false;
1553

    
1554
	// Hide on page load
1555
	$('.advancedoptions').hide();
1556

    
1557
	// Suppress "Delete row" button if there are fewer than two rows
1558
	checkLastRow();
1559

    
1560
	// Show advanced section if you click the showadv button
1561
	$("#showadv").click(function() {
1562
		advanced_visible = !advanced_visible;
1563

    
1564
		if (advanced_visible) {
1565
			$('.advancedoptions').show();
1566
			$("#showadv").html('<i class="fa-solid fa-cog icon-embed-btn"></i>' + "<?=$showmsg?>");
1567
		} else {
1568
			$('.advancedoptions').hide();
1569
			$("#showadv").html('<i class="fa-solid fa-cog icon-embed-btn"></i>' + "<?=$hidemsg?>");
1570
		}
1571
	});
1572

    
1573
	// Call enablechange function
1574
	enablechange();
1575
});
1576

    
1577
	function enablechange() {
1578
<?php
1579
	foreach ($pkg['fields']['field'] as $field) {
1580
		if (isset($field['enablefields']) or isset($field['checkenablefields'])) {
1581
			echo "\tif ($('input[name=\"{$field['fieldname']}\"]').prop('checked') == false) {\n";
1582

    
1583
			if (isset($field['enablefields'])) {
1584
				foreach (explode(',', $field['enablefields']) as $enablefield) {
1585
					echo "\t\tif ($('input[name=\"{$enablefield}\"]').length > 0) {\n";
1586
					echo "\t\t\t$('input[name=\"{$enablefield}\"]').prop('disabled',true);\n";
1587
					echo "\t\t}\n";
1588
				}
1589
			}
1590

    
1591
			if (isset($field['checkenablefields'])) {
1592
				foreach (explode(',', $field['checkenablefields']) as $checkenablefield) {
1593
					echo "\t\tif ($('input[name=\"{$checkenablefield}\"]').length > 0) {\n";
1594
					echo "\t\t\t$('input[name=\"{$checkenablefield}\"]').prop('checked',true);\n";
1595
					echo "\t\t}\n";
1596
				}
1597
			}
1598

    
1599
			echo "\t}\n\telse {\n";
1600

    
1601
			if (isset($field['enablefields'])) {
1602
				foreach (explode(',', $field['enablefields']) as $enablefield) {
1603
					echo "\t\tif ($('input[name=\"{$enablefield}\"]').length > 0) {\n";
1604
					echo "\t\t\t$('input[name=\"{$enablefield}\"]').prop('disabled',false);\n";
1605
					echo "\t\t}\n";
1606
				}
1607
			}
1608

    
1609
			if (isset($field['checkenablefields'])) {
1610
				foreach (explode(',', $field['checkenablefields']) as $checkenablefield) {
1611
					echo "\t\tif ($('input[name=\"{$checkenablefield}\"]').length > 0) {\n";
1612
					echo "\t\t\t$('input[name=\"{$checkenablefield}\"]').prop('checked',false);\n";
1613
					echo "\t\t}\n";
1614
				}
1615
			}
1616

    
1617
			echo "\t}\n";
1618
		}
1619
	}
1620
	?>
1621
	}
1622
//]]>
1623
</script>
1624

    
1625
<?php
1626
}
1627

    
1628
include("foot.inc");
(97-97/232)