Project

General

Profile

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

    
26
/* Include authentication routines */
27
/* THIS MUST BE ABOVE ALL OTHER CODE */
28
include_once('phpsessionmanager.inc');
29
if (!$nocsrf) {
30
	function csrf_startup() {
31
		global $config;
32
		csrf_conf('rewrite-js', '/csrf/csrf-magic.js');
33
		$timeout_minutes = isset($config['system']['webgui']['session_timeout']) ? $config['system']['webgui']['session_timeout'] : 240;
34
		csrf_conf('expires', $timeout_minutes * 60);
35
	}
36
	require_once("csrf/csrf-magic.php");
37
	if ($_SERVER['REQUEST_METHOD'] == 'POST') {
38
		phpsession_end(true);
39
	}
40
}
41

    
42
/* make sure nothing is cached */
43
if (!$omit_nocacheheaders) {
44
	header("Expires: 0");
45
	header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
46
	header("Cache-Control: no-cache, no-store, must-revalidate");
47
	header("Pragma: no-cache");
48
}
49

    
50
header("X-Frame-Options: SAMEORIGIN");
51
require_once("authgui.inc");
52

    
53
/* parse the configuration and include all configuration functions */
54
require_once("functions.inc");
55

    
56
/* Include the autoloader for all the GUI display classes */
57
require_once("classes/autoload.inc.php");
58

    
59
/* used by progress bar */
60
$lastseen = "-1";
61

    
62
$navlevelsep = ": ";	/* navigation level separator string */
63
$mandfldhtml = "";		/* display this before mandatory input fields */
64
$mandfldhtmlspc = "";	/* same as above, but with spacing */
65

    
66
if (!function_exists('set_language')) {
67
	require_once("pfsense-utils.inc");
68
}
69

    
70
set_language();
71

    
72
/* Some ajax scripts still need access to GUI */
73
if (!$ignorefirmwarelock) {
74
	if (is_subsystem_dirty('firmwarelock')) {
75
		if (!$d_isfwfile) {
76
			header("Location: system_update.php");
77
			exit;
78
		} else {
79
			return;
80
		}
81
	}
82
}
83

    
84
/* Reserved table names to avoid collision */
85
$reserved_table_names = array(
86
	"bogons",
87
	"bogonsv6",
88
	"negate_networks",
89
	"snort2c",
90
	"sshlockout",
91
	"tonatsubnets",
92
	"virusprot",
93
	"vpn_networks",
94
	"webConfiguratorlockout"
95
);
96

    
97
$firewall_rules_dscp_types = array(
98
	"af11",
99
	"af12",
100
	"af13",
101
	"af21",
102
	"af22",
103
	"af23",
104
	"af31",
105
	"af32",
106
	"af33",
107
	"af41",
108
	"af42",
109
	"af43",
110
	"VA",
111
	"EF",
112
	"cs1",
113
	"cs2",
114
	"cs3",
115
	"cs4",
116
	"cs5",
117
	"cs6",
118
	"cs7",
119
	"0x01",
120
	"0x02",
121
	"0x04");
122

    
123
$auth_server_types = array(
124
	'ldap' => "LDAP",
125
	'radius' => "RADIUS");
126

    
127
$ldap_urltypes = array(
128
	'TCP - Standard' => 389,
129
	'TCP - STARTTLS' => 389,
130
	'SSL - Encrypted' => 636);
131

    
132
$ldap_scopes = array(
133
	'one' => gettext("One Level"),
134
	'subtree' => gettext("Entire Subtree"));
135

    
136
$ldap_protvers = array(
137
	2,
138
	3);
139

    
140
$ldap_templates = array(
141

    
142
	'open' => array(
143
		'desc' => "OpenLDAP",
144
		'attr_user' => "cn",
145
		'attr_group' => "cn",
146
		'attr_member' => "member"),
147

    
148
	'msad' => array(
149
		'desc' => "Microsoft AD",
150
		'attr_user' => "samAccountName",
151
		'attr_group' => "cn",
152
		'attr_member' => "memberOf"),
153

    
154
	'edir' => array(
155
		'desc' => "Novell eDirectory",
156
		'attr_user' => "cn",
157
		'attr_group' => "cn",
158
		'attr_member' => "uniqueMember"));
159

    
160
$radius_srvcs = array(
161
	'both' => gettext("Authentication and Accounting"),
162
	'auth' => gettext("Authentication"),
163
	'acct' => gettext("Accounting"));
164

    
165
$radius_protocol = array(
166
	'PAP' => "PAP",
167
	'CHAP_MD5' => "MD5-CHAP",
168
	'MSCHAPv1' => "MS-CHAPv1",
169
	'MSCHAPv2' => "MS-CHAPv2");
170

    
171
$netbios_nodetypes = array(
172
	'0' => "none",
173
	'1' => "b-node",
174
	'2' => "p-node",
175
	'4' => "m-node",
176
	'8' => "h-node");
177

    
178
/* some well known ports */
179
$wkports = array(
180
	5999 => "CVSup",
181
	53 => "DNS",
182
	21 => "FTP",
183
	3000 => "HBCI",
184
	80 => "HTTP",
185
	443 => "HTTPS",
186
	5190 => "ICQ",
187
	113 => "IDENT/AUTH",
188
	143 => "IMAP",
189
	993 => "IMAP/S",
190
	4500 => "IPsec NAT-T",
191
	500 => "ISAKMP",
192
	1701 => "L2TP",
193
	389 => "LDAP",
194
	1755 => "MMS/TCP",
195
	7000 => "MMS/UDP",
196
	445 => "MS DS",
197
	3389 => "MS RDP",
198
	1512 => "MS WINS",
199
	1863 => "MSN",
200
	119 => "NNTP",
201
	123 => "NTP",
202
	138 => "NetBIOS-DGM",
203
	137 => "NetBIOS-NS",
204
	139 => "NetBIOS-SSN",
205
	1194 => "OpenVPN",
206
	110 => "POP3",
207
	995 => "POP3/S",
208
	1723 => "PPTP",
209
	1812 => "RADIUS",
210
	1813 => "RADIUS accounting",
211
	5004 => "RTP",
212
	5060 => "SIP",
213
	25 => "SMTP",
214
	465 => "SMTP/S",
215
	161 => "SNMP",
216
	162 => "SNMP-Trap",
217
	22 => "SSH",
218
	3478 => "STUN",
219
	587 => "SUBMISSION",
220
	3544 => "Teredo",
221
	23 => "Telnet",
222
	69 => "TFTP",
223
	5900 => "VNC");
224

    
225
/* TCP flags */
226
$tcpflags = array("fin", "syn", "rst", "psh", "ack", "urg", "ece", "cwr");
227

    
228
$specialnets = array(
229
	"(self)" => gettext("This Firewall"),
230
	"pppoe" => gettext("PPPoE clients"),
231
	"l2tp" => gettext("L2TP clients"));
232

    
233
$spiflist = get_configured_interface_with_descr(true);
234
foreach ($spiflist as $ifgui => $ifdesc) {
235
	$specialnets[$ifgui] = $ifdesc . " net";
236
	$specialnets[$ifgui . 'ip'] = $ifdesc . " address";
237
}
238

    
239
$medias = array(
240
	"auto" => gettext("autoselect"),
241
	"100full" => gettext("100BASE-TX full-duplex"),
242
	"100half" => gettext("100BASE-TX half-duplex"),
243
	"10full" => gettext("10BASE-T full-duplex"),
244
	"10half" => gettext("10BASE-T half-duplex"));
245

    
246
$wlan_modes = array(
247
	"bss" => gettext("Infrastructure (BSS)"),
248
	"adhoc" => gettext("Ad-hoc (IBSS)"),
249
	"hostap" => gettext("Access Point"));
250

    
251
function do_input_validation($postdata, $reqdfields, $reqdfieldsn, &$input_errors) {
252

    
253
	/* check for bad control characters */
254
	foreach ($postdata as $pn => $pd) {
255
		if (is_string($pd) && preg_match("/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f]/", $pd)) {
256
			$input_errors[] = sprintf(gettext("The field %s contains invalid characters."), $pn);
257
		}
258
	}
259

    
260
	for ($i = 0; $i < count($reqdfields); $i++) {
261
		if ($postdata[$reqdfields[$i]] == "") {
262
			$input_errors[] = sprintf(gettext("The field %s is required."), $reqdfieldsn[$i]);
263
		}
264
	}
265
}
266

    
267
function print_input_errors($input_errors) {
268
	echo '<div class="alert alert-danger input-errors">';
269
	echo '<p>' . gettext('The following input errors were detected:') . '</p>';
270
	echo '<ul>';
271

    
272
	foreach ($input_errors as $ierr) {
273
		echo '<li>' . htmlspecialchars($ierr) . '</li>';
274
	}
275

    
276
	echo '</ul>';
277
	echo '</div>';
278
}
279

    
280
function verify_gzip_file($fname) {
281
	$returnvar = mwexec("/usr/bin/gzip -t " . escapeshellarg($fname));
282
	if ($returnvar != 0) {
283
		return 0;
284
	} else {
285
		return 1;
286
	}
287
}
288

    
289
// sprint_info_box() returns a string with a formatted informational box, it does not print the box.
290
// To format and print in one step, call print_info_box() as usual.
291
// Any required button is explicitly created, rather than relying on the detection of certain
292
// strings in the message (such as "apply"). print_info_box_np() has been exterminated.
293
// $class = the bootstrap style class (default, info, warning, success, danger)
294
// $btnname and btntext describe the optional button and its display text, the default is an 'x' Close button.
295
// Note that there is also a shortcut function print_apply_box here that creates a standard "apply" box for you.
296
// In many cases just substitute that for print_info_box_np() to easily get a warning style "Apply changes" box.
297
function sprint_info_box($msg, $class="alert-warning", $btnname = "close", $btntext = "", $btnicon = "", $btnclass = "default") {
298

    
299
	if (strpos($class, "alert-") !== 0) {
300
		$class = 'alert-' . $class;
301
	}
302

    
303
	$msg = '<div class="pull-left">' . $msg . '</div>';
304

    
305
	if ($btnname === "close") {
306
		$msg = '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>' . $msg;
307
	} else if ($btnname != "") {
308
		if (empty($btntext)) {
309
			$btntext = $btnname;
310
		}
311
		if (!empty($btnicon)) {
312
			$btnicon = '<i class="fa ' . $btnicon . ' icon-embed-btn"></i>';
313
		}
314

    
315
		$msg .= '<form method="post" class="pull-right"><button type="submit" class="btn btn-' . $btnclass . '" name="'. $btnname . '" value="' . $btntext . '">' . $btnicon . $btntext . '</button>';
316

    
317
		if ($_POST['if']) {
318
			$msg .= "<input type=\"hidden\" name=\"if\" value=\"" . htmlspecialchars($_POST['if']) . "\" />";
319
		}
320

    
321
		$msg .= '</form>';
322
	}
323

    
324
	return '<div class="alert ' . $class . ' clearfix" role="alert">' . $msg . '</div>';
325
}
326

    
327
// Format and print an info box. See sprint_info_box() for details.
328
function print_info_box($msg, $class="alert-warning", $btnname = "close", $btntext = "", $btnicon = "", $btnclass = "default") {
329
	echo sprint_info_box($msg, $class, $btnname, $btntext, $btnicon, $btnclass);
330
}
331

    
332
function print_apply_box($msg) {
333
	print_info_box($msg, "warning", "apply", gettext("Apply Changes"), 'fa-check', 'success');
334
}
335

    
336
// Format and print a box reporting that changes have been applied
337
// $retval = status value from the functions called to apply the changes
338
// 0 is good
339
// non-zero is a problem
340
// $extra_text = optional extra text to display after the standard message
341
function print_apply_result_box($retval, $extra_text="") {
342
	$result_msg = get_std_save_message($retval);
343
	if ($retval === 0) {
344
		// 0 is success
345
		$severity = "success";
346
	} else {
347
		// non-zero means there was some problem
348
		$severity = "warning";
349
	}
350

    
351
	if (strlen($extra_text) > 0) {
352
		$result_msg .= " " . $extra_text;
353
	}
354
	print_info_box($result_msg, $severity);
355
}
356

    
357
/*
358
 * Print Bootstrap callout
359
 *
360
 * @param string $msg     message to display
361
 * @param string $class   contextual class, defaults to info (default | danger | warning | info)
362
 * @param string $heading optional callout heading
363
 */
364
function print_callout($msg, $class = 'info', $heading = '') {
365

    
366
	if ('' == $msg) {
367
		return;
368
	}
369
	$class = strtolower($class);
370
	$callout = '';
371

    
372
	if ($class != 'default' && $class != 'danger' && $class != 'warning' && $class != 'info') {
373
		$class = 'info';
374
	}
375
	$callout .= '<div class="bs-callout bs-callout-' . $class . '">';
376

    
377
	if ('' != $heading) {
378
		$callout .= '<h4>' . $heading . '</h4>';
379
	}
380
	$callout .= $msg . '</div>';
381
	echo $callout;
382
}
383

    
384
function get_std_save_message($retval) {
385
	$filter_related = false;
386
	$filter_pages = array("firewall_aliases", "firewall_nat", "firewall_rules", "status_logs_filter");
387
	if ($retval === 0) {
388
		// 0 is success
389
		$to_return = gettext("The changes have been applied successfully.");
390
	} else {
391
		// non-zero means there was some problem
392
		$to_return = sprintf(gettext('There was a problem applying the changes. See the %1$sSystem Logs%2$s.'), '<a href=\"status_logs.php\">', '</a>');
393
	}
394
	foreach ($filter_pages as $fp) {
395
		if (stristr($_SERVER['SCRIPT_FILENAME'], $fp)) {
396
			$filter_related = true;
397
		}
398
	}
399
	if ($filter_related) {
400
		$to_return .= " " . gettext("The firewall rules are now reloading in the background.") . "<br />" .
401
		    sprintf(gettext('%1$sMonitor%2$s the filter reload progress.'), "<a href='status_filter_reload.php'>", "</a>");
402
	}
403
	return $to_return;
404
}
405

    
406
function pprint_address($adr) {
407
	global $specialnets;
408

    
409
	if (isset($adr['any'])) {
410
		$padr = "*";
411
	} else if ($adr['network']) {
412
		$padr = $specialnets[$adr['network']];
413
	} else {
414
		$padr = $adr['address'];
415
	}
416

    
417
	if (isset($adr['not'])) {
418
		$padr = "! " . $padr;
419
	}
420

    
421
	return $padr;
422
}
423

    
424
function pprint_port($port) {
425
	global $wkports;
426

    
427
	$pport = "";
428

    
429
	if (!$port) {
430
		return "*";
431
	} else {
432
		$srcport = explode("-", $port);
433
		if ((!$srcport[1]) || ($srcport[0] == $srcport[1])) {
434
			$pport = $srcport[0];
435
			if ($wkports[$srcport[0]]) {
436
				$pport .= " (" . $wkports[$srcport[0]] . ")";
437
			}
438
		} else {
439
			$pport .= $srcport[0] . " - " . $srcport[1];
440
		}
441
	}
442

    
443
	return $pport;
444
}
445

    
446
function insert_word_breaks_in_domain_name($domain_name) {
447
	return str_replace('.', '<wbr>.', $domain_name);
448
}
449

    
450
function firewall_check_for_advanced_options(&$item) {
451
	$item_set = "";
452
	if ($item['os']) {
453
			$item_set .= "os {$item['os']} ";
454
	}
455
	if ($item['dscp']) {
456
		$item_set .= "dscp {$item['dscp']} ";
457
	}
458
	if ($item['max']) {
459
		$item_set .= "max {$item['max']} ";
460
	}
461
	if ($item['max-src-nodes']) {
462
		$item_set .= "max-src-nodes {$item['max-src-nodes']} ";
463
	}
464
	if ($item['max-src-conn']) {
465
		$item_set .= "max-src-conn {$item['max-src-conn']} ";
466
	}
467
	if ($item['max-src-states']) {
468
		$item_set .= "max-src-states {$item['max-src-states']} ";
469
	}
470
	if (isset($item['nopfsync'])) {
471
		$item_set .= "nopfsync ";
472
	}
473
	if ($item['statetype'] != "keep state" && $item['statetype'] != "") {
474
		$item_set .= "statetype {$item['statetype']} ";
475
	}
476
	if ($item['statetimeout']) {
477
		$item_set .= "statetimeout {$item['statetimeout']} ";
478
	}
479
	if (isset($item['nosync'])) {
480
		$item_set .= "no XMLRPC Sync ";
481
	}
482
	if ($item['max-src-conn-rate']) {
483
		$item_set .= "max-src-conn-rate {$item['max-src-conn-rate']} ";
484
	}
485
	if ($item['max-src-conn-rates']) {
486
		$item_set .= "max-src-conn-rates {$item['max-src-conn-rates']} ";
487
	}
488
	if ($item['vlanprio']) {
489
		$item_set .= "vlanprio {$item['vlanprio']} ";
490
	}
491
	if ($item['vlanprioset']) {
492
		$item_set .= "vlanprioset {$item['vlanprioset']} ";
493
	}
494
	if ($item['gateway']) {
495
		$item_set .= "gateway {$item['gateway']} ";
496
	}
497
	if ($item['dnpipe']) {
498
		$item_set .= "limiter {$item['dnpipe']} ";
499
	}
500
	if ($item['pdnpipe']) {
501
		$item_set .= "limiter {$item['pdnpipe']} ";
502
	}
503
	if ($item['ackqueue']) {
504
		$item_set .= "ackqueue {$item['ackqueue']} ";
505
	}
506
	if ($item['defaultqueue']) {
507
		$item_set .= "defaultqueue {$item['defaultqueue']} ";
508
	}
509
	if ($item['tag']) {
510
		$item_set .= "tag {$item['tag']} ";
511
	}
512
	if ($item['tagged']) {
513
		$item_set .= "tagged {$item['tagged']} ";
514
	}
515
	if (isset($item['allowopts'])) {
516
		$item_set .= "allowopts ";
517
	}
518
	if (isset($item['disablereplyto'])) {
519
		$item_set .= "disable reply-to ";
520
	}
521
	if ($item['tcpflags_any'] || $item['tcpflags1'] || $item['tcpflags2']) {
522
		$item_set .= "tcpflags set";
523
	}
524

    
525
	return $item_set;
526
}
527

    
528
function gentitle($title) {
529
	global $navlevelsep;
530
	if (!is_array($title)) {
531
		return $title;
532
	} else {
533
		return join($navlevelsep, $title);
534
	}
535
}
536

    
537
function genhtmltitle($title, $links=true) {
538

    
539
	$num_crumbs = count($title);
540

    
541
	// If the array contains only one element, there are no breadcrumbs, so don't
542
	// add anything else
543
	if ($num_crumbs > 1) {
544
		$bc = '<ol class="breadcrumb">';
545

    
546
		if (!is_array($links)) {
547
			$gen_default = ($links === true);
548
			$links = array_fill(0, $num_crumbs, '');
549
			// If no links passed, then default to a link to self on the last entry.
550
			if ($gen_default) {
551
				$links[$num_crumbs-1] = '@self';
552
			}
553
		}
554

    
555
		foreach ($title as $idx => $el) {
556
			$href = $links[$idx];
557
			if (strlen($href) > 0) {
558
				// For convenience, if the caller specifies '@self' then make a link
559
				// to the current page, including any query string.
560
				if ($href == '@self') {
561
					$href = $_SERVER['REQUEST_URI'];
562
				}
563
				if (substr($href, 0, 1) != '/') {
564
					$href = '/' . $href;
565
				}
566
				$bc .= '<li><a href="' . htmlentities($href) . '">' . $el . '</a></li>';
567
			} else {
568
				$bc .= '<li>' . $el . '</li>';
569
			}
570
		}
571

    
572
		$bc .= '</ol>';
573
	} else {
574
		$bc = "";
575
	}
576

    
577
	return $bc;
578
}
579

    
580
function gen_customwidgettitle_div($widgettitle) {
581
	$divstr = '<div class="form-group">';
582
	$divstr .= '  <label for="descr" class="col-sm-4 control-label">' . gettext('Widget title'). '</label>';
583
	$divstr .= '  <div class="col-sm-4">';
584
	$divstr .= '    <input type="text" name="descr" id="descr" value="'. $widgettitle . '" class="form-control" />';
585
	$divstr .= '  </div>';
586
	$divstr .= '</div>';
587

    
588
	return $divstr;
589
}
590

    
591
function set_customwidgettitle(& $user_settings) {
592
	if ($_POST['descr']) {
593
		$user_settings['widgets'][$_POST['widgetkey']]['descr'] = trim($_POST['descr']);
594
	} else {
595
		unset($user_settings['widgets'][$_POST['widgetkey']]['descr']);
596
	}
597
}
598

    
599
/* update the changedesc and changecount(er) variables */
600
function update_changedesc($update) {
601
	global $changedesc;
602
	global $changecount;
603

    
604
	$changedesc .= " {$update}";
605
	$changecount++;
606
}
607

    
608
// This version of dump_clog() does not output <td></td> or any other table elements.
609
function dump_clog_no_table($logfile, $tail, $withorig = true, $grepfor = "", $grepinvert = "") {
610
	global $g, $config;
611
	$sor = isset($config['syslog']['reverse']) ? "-r" : "";
612
	$specific_log = basename($logfile, '.log') . '_settings';
613
	if ($config['syslog'][$specific_log]['cronorder'] == 'forward') $sor = "";
614
	if ($config['syslog'][$specific_log]['cronorder'] == 'reverse') $sor = "-r";
615
	$logarr = array();
616
	$grepline = "  ";
617
	if (is_array($grepfor)) {
618
		$invert = '';
619
		if ((strpos($grepfor[0], '!') === 0)) {
620
			$grepfor[0] = substr($grepfor[0], 1);
621
			$invert = '-v';
622
		}
623
		$grepline .= " | /usr/bin/egrep {$invert} " . escapeshellarg(implode("|", $grepfor));
624
	}
625
	if (is_array($grepinvert)) {
626
		$grepline .= " | /usr/bin/egrep -v " . escapeshellarg(implode("|", $grepinvert));
627
	}
628
	if (is_dir($logfile)) {
629
		$logarr = array(sprintf(gettext("File %s is a directory."), $logfile));
630
	} elseif (file_exists($logfile) && filesize($logfile) == 0) {
631
		$logarr = array(gettext("Log file started."));
632
	} else {
633
		if ($config['system']['disablesyslogclog']) {
634
			exec("cat " . escapeshellarg($logfile) . "{$grepline} | /usr/bin/tail {$sor} -n " . escapeshellarg($tail), $logarr);
635
		} else {
636
			exec("/usr/local/sbin/clog " . escapeshellarg($logfile) . "{$grepline}| grep -v \"CLOG\" | grep -v \"\033\" | /usr/bin/tail {$sor} -n " . escapeshellarg($tail), $logarr);
637
		}
638
	}
639
	echo "\n";
640

    
641
	$rows = 0;
642
	foreach ($logarr as $logent) {
643
		$rows++;
644
		$logent = preg_split("/\s+/", $logent, 6);
645

    
646
		if ($withorig) {
647
				$entry_date_time = htmlspecialchars(join(" ", array_slice($logent, 0, 3)));
648
				$entry_text = ($logent[3] ==  $config['system']['hostname']) ? "" : $logent[3] . " ";
649
				$entry_text .= htmlspecialchars($logent[4] . " " . $logent[5]);
650
				echo "{$entry_date_time}";
651
				echo " " . "{$entry_text}"	. "\n";
652
		} else {
653
				echo htmlspecialchars($logent[5]) . "\n";
654
		}
655

    
656
	}
657
	return($rows);
658
}
659

    
660
function dump_clog($logfile, $tail, $withorig = true, $grepfor = "", $grepinvert = "") {
661
	global $g, $config;
662
	$sor = isset($config['syslog']['reverse']) ? "-r" : "";
663
	$specific_log = basename($logfile, '.log') . '_settings';
664
	if ($config['syslog'][$specific_log]['cronorder'] == 'forward') $sor = "";
665
	if ($config['syslog'][$specific_log]['cronorder'] == 'reverse') $sor = "-r";
666
	$logarr = array();
667
	$grepline = "  ";
668
	if (is_array($grepfor)) {
669
		$invert = '';
670
		if ((strpos($grepfor[0], '!') === 0)) {
671
			$grepfor[0] = substr($grepfor[0], 1);
672
			$invert = '-v';
673
		}
674
		$grepline .= " | /usr/bin/egrep {$invert} " . escapeshellarg(implode("|", $grepfor));
675
	}
676
	if (is_array($grepinvert)) {
677
		$grepline .= " | /usr/bin/egrep -v " . escapeshellarg(implode("|", $grepinvert));
678
	}
679
	if (is_dir($logfile)) {
680
		$logarr = array(sprintf(gettext("File %s is a directory."), $logfile));
681
	} elseif (file_exists($logfile) && filesize($logfile) == 0) {
682
		$logarr = array(gettext("Log file started."));
683
	} else {
684
		if ($config['system']['disablesyslogclog']) {
685
			exec("cat " . escapeshellarg($logfile) . "{$grepline} | /usr/bin/tail {$sor} -n " . escapeshellarg($tail), $logarr);
686
		} else {
687
			exec("/usr/local/sbin/clog " . escapeshellarg($logfile) . "{$grepline}| grep -v \"CLOG\" | grep -v \"\033\" | /usr/bin/tail {$sor} -n " . escapeshellarg($tail), $logarr);
688
		}
689
	}
690

    
691
	$rows = 0;
692
	foreach ($logarr as $logent) {
693
		$rows++;
694
		$logent = preg_split("/\s+/", $logent, 6);
695
		echo "<tr>\n";
696
		if ($withorig) {
697
			$entry_date_time = htmlspecialchars(join(" ", array_slice($logent, 0, 3)));
698
			$entry_text = ($logent[3] == $config['system']['hostname']) ? "" : $logent[3] . " ";
699
			$entry_text .= htmlspecialchars($logent[4] . " " . $logent[5]);
700
			echo "<td class=\"text-nowrap\">{$entry_date_time}</td>\n";
701
			echo "<td style=\"word-wrap:break-word; word-break:break-all; white-space:normal\">{$entry_text}</td>\n";
702
		} else {
703
				echo "<td>" . htmlspecialchars($logent[5]) . "</td>\n";
704
		}
705
		echo "</tr>\n";
706
	}
707
	return($rows);
708
}
709

    
710
function return_clog($logfile, $tail, $withorig = true, $grepfor = "", $grepinvert = "", $grepreverse = false) {
711
	global $g, $config;
712
	$sor = (isset($config['syslog']['reverse']) || $grepreverse) ? "-r" : "";
713
	$specific_log = basename($logfile, '.log') . '_settings';
714
	if (($config['syslog'][$specific_log]['cronorder'] == 'forward') && !$grepreverse) $sor = "";
715
	if (($config['syslog'][$specific_log]['cronorder'] == 'reverse') ||  $grepreverse) $sor = "-r";
716
	$logarr = array();
717
	$grepline = "  ";
718
	if (is_array($grepfor)) {
719
		$grepline .= " | /usr/bin/egrep " . escapeshellarg(implode("|", $grepfor));
720
	}
721
	if (is_array($grepinvert)) {
722
		$grepline .= " | /usr/bin/egrep -v " . escapeshellarg(implode("|", $grepinvert));
723
	}
724
	if ($config['system']['disablesyslogclog']) {
725
		exec("cat " . escapeshellarg($logfile) . "{$grepline} | /usr/bin/tail {$sor} -n " . escapeshellarg($tail), $logarr);
726
	} else {
727
		exec("/usr/local/sbin/clog " . escapeshellarg($logfile) . "{$grepline}| grep -v \"CLOG\" | grep -v \"\033\" | /usr/bin/tail {$sor} -n " . escapeshellarg($tail), $logarr);
728
	}
729
	return($logarr);
730
}
731

    
732
/* Check if variable has changed, update and log if it has
733
 * returns true if var changed
734
 * varname = variable name in plain text
735
 * orig = original value
736
 * new = new value
737
 */
738
function update_if_changed($varname, & $orig, $new) {
739
	if (is_array($orig) && is_array($new)) {
740
		$a_diff = array_diff($orig, $new);
741
		foreach ($a_diff as $diff) {
742
			update_changedesc("removed {$varname}: \"{$diff}\"");
743
		}
744
		$a_diff = array_diff($new, $orig);
745
		foreach ($a_diff as $diff) {
746
			update_changedesc("added {$varname}: \"{$diff}\"");
747
		}
748
		$orig = $new;
749
		return true;
750

    
751
	} else {
752
		if ($orig != $new) {
753
			update_changedesc("{$varname}: \"{$orig}\" -> \"{$new}\"");
754
			$orig = $new;
755
			return true;
756
		}
757
	}
758
	return false;
759
}
760

    
761
function address_to_pconfig($adr, &$padr, &$pmask, &$pnot, &$pbeginport, &$pendport) {
762
	if (isset($adr['any'])) {
763
		$padr = "any";
764
	} else if ($adr['network']) {
765
		$padr = $adr['network'];
766
	} else if ($adr['address']) {
767
		list($padr, $pmask) = explode("/", $adr['address']);
768
		if (!$pmask) {
769
			if (is_ipaddrv6($padr)) {
770
				$pmask = 128;
771
			} else {
772
				$pmask = 32;
773
			}
774
		}
775
	}
776

    
777
	if (isset($adr['not'])) {
778
		$pnot = 1;
779
	} else {
780
		$pnot = 0;
781
	}
782

    
783
	if ($adr['port']) {
784
		list($pbeginport, $pendport) = explode("-", $adr['port']);
785
		if (!$pendport) {
786
			$pendport = $pbeginport;
787
		}
788
	} else if (!is_alias($pbeginport) && !is_alias($pendport)) {
789
		$pbeginport = "any";
790
		$pendport = "any";
791
	}
792
}
793

    
794
function pconfig_to_address(&$adr, $padr, $pmask, $pnot = false, $pbeginport = 0, $pendport = 0) {
795
	$adr = array();
796

    
797
	if ($padr == "any") {
798
		$adr['any'] = true;
799
	} else if (is_specialnet($padr)) {
800
		$adr['network'] = $padr;
801
	} else {
802
		$adr['address'] = $padr;
803
		if (is_ipaddrv6($padr)) {
804
			if ($pmask != 128) {
805
				$adr['address'] .= "/" . $pmask;
806
			}
807
		} else {
808
			if ($pmask != 32) {
809
				$adr['address'] .= "/" . $pmask;
810
			}
811
		}
812
	}
813

    
814
	if ($pnot) {
815
		$adr['not'] = true;
816
	} else {
817
		unset($adr['not']);
818
	}
819

    
820
	if (($pbeginport != 0) && ($pbeginport != "any")) {
821
		if ($pbeginport != $pendport) {
822
			$adr['port'] = $pbeginport . "-" . $pendport;
823
		} else {
824
			$adr['port'] = $pbeginport;
825
		}
826
	}
827

    
828
	if (is_alias($pbeginport)) {
829
		$adr['port'] = $pbeginport;
830
	}
831
}
832

    
833
function is_specialnet($net) {
834
	global $specialsrcdst;
835

    
836
	if (!$net) {
837
		return false;
838
	}
839
	if (in_array($net, $specialsrcdst)) {
840
		return true;
841
	} else {
842
		return false;
843
	}
844
}
845

    
846
//function to create widget tabs when called
847
function display_widget_tabs(& $tab_array) {
848
	echo "<div id=\"tabs\">";
849
	$tabscounter = 0;
850
	foreach ($tab_array as $ta) {
851
		$dashpos = strpos($ta[2], '-');
852
		$tabname = $ta[2] . "-tab";
853
		$tabclass = substr($ta[2], 0, $dashpos);
854
		$tabclass = $tabclass . "-class";
855
		if ($ta[1] == true) {
856
			$tabActive = "table-cell";
857
			$tabNonActive = "none";
858
		} else {
859
			$tabActive = "none";
860
			$tabNonActive = "table-cell";
861
		}
862
		echo "<div id=\"{$ta[2]}-active\" class=\"{$tabclass}-tabactive\" style=\"display:{$tabActive}; background-color:#EEEEEE; color:black;\">";
863
		echo "<b>&nbsp;&nbsp;&nbsp;{$ta[0]}";
864
		echo "&nbsp;&nbsp;&nbsp;</b>";
865
		echo "</div>";
866

    
867
		echo "<div id=\"{$ta[2]}-deactive\" class=\"{$tabclass}-tabdeactive\" style=\"display:{$tabNonActive}; background-color:#777777; color:white; cursor: pointer;\" onclick=\"return changeTabDIV('{$ta[2]}')\">";
868
		echo "<b>&nbsp;&nbsp;&nbsp;{$ta[0]}";
869
		echo "&nbsp;&nbsp;&nbsp;</b>";
870
		echo "</div>";
871
	}
872
	echo "</div>";
873
}
874

    
875

    
876
// Return inline javascript file or CSS to minimize
877
// request count going back to server.
878
function outputJavaScriptFileInline($javascript) {
879
	if (file_exists($javascript)) {
880
		echo "\n<script type=\"text/javascript\">\n";
881
		include_once($javascript);
882
		echo "\n</script>\n";
883
	} else {
884
		echo "\n\n<!-- Could not locate file:  {$javascript} -->\n\n";
885
	}
886
}
887

    
888

    
889

    
890
function outputCSSPrintFileInline($css) {
891
	if (file_exists($css)) {
892
		echo "\n<style media=\"print\" type=\"text/css\">\n";
893
		include_once($css);
894
		echo "\n</style>\n";
895
	} else {
896
		echo "\n\n<!-- Could not locate file:  {$css} -->\n\n";
897
	}
898
}
899

    
900

    
901
function outputCSSFileInline($css) {
902
	if (file_exists($css)) {
903
		echo "\n<style type=\"text/css\">\n";
904
		include_once($css);
905
		echo "\n</style>\n";
906
	} else {
907
		echo "\n\n<!-- Could not locate file:  {$css} -->\n\n";
908
	}
909
}
910

    
911
$rfc2616 = array(
912
	100 => "100 Continue",
913
	101 => "101 Switching Protocols",
914
	200 => "200 OK",
915
	201 => "201 Created",
916
	202 => "202 Accepted",
917
	203 => "203 Non-Authoritative Information",
918
	204 => "204 No Content",
919
	205 => "205 Reset Content",
920
	206 => "206 Partial Content",
921
	300 => "300 Multiple Choices",
922
	301 => "301 Moved Permanently",
923
	302 => "302 Found",
924
	303 => "303 See Other",
925
	304 => "304 Not Modified",
926
	305 => "305 Use Proxy",
927
	306 => "306 (Unused)",
928
	307 => "307 Temporary Redirect",
929
	400 => "400 Bad Request",
930
	401 => "401 Unauthorized",
931
	402 => "402 Payment Required",
932
	403 => "403 Forbidden",
933
	404 => "404 Not Found",
934
	405 => "405 Method Not Allowed",
935
	406 => "406 Not Acceptable",
936
	407 => "407 Proxy Authentication Required",
937
	408 => "408 Request Timeout",
938
	409 => "409 Conflict",
939
	410 => "410 Gone",
940
	411 => "411 Length Required",
941
	412 => "412 Precondition Failed",
942
	413 => "413 Request Entity Too Large",
943
	414 => "414 Request-URI Too Long",
944
	415 => "415 Unsupported Media Type",
945
	416 => "416 Requested Range Not Satisfiable",
946
	417 => "417 Expectation Failed",
947
	500 => "500 Internal Server Error",
948
	501 => "501 Not Implemented",
949
	502 => "502 Bad Gateway",
950
	503 => "503 Service Unavailable",
951
	504 => "504 Gateway Timeout",
952
	505 => "505 HTTP Version Not Supported"
953
);
954

    
955
function is_rfc2616_code($code) {
956
	global $rfc2616;
957
	if (isset($rfc2616[$code])) {
958
		return true;
959
	} else {
960
		return false;
961
	}
962
}
963

    
964
function print_rfc2616_select($tag, $current) {
965
	global $rfc2616;
966

    
967
	/* Default to 200 OK if not set */
968
	if ($current == "") {
969
		$current = 200;
970
	}
971

    
972
	echo "<select id=\"{$tag}\" name=\"{$tag}\">\n";
973
	foreach ($rfc2616 as $code => $message) {
974
		if ($code == $current) {
975
			$sel = " selected";
976
		} else {
977
			$sel = "";
978
		}
979
		echo "<option value=\"{$code}\"{$sel}>{$message}</option>\n";
980
	}
981
	echo "</select>\n";
982
}
983

    
984
// Useful debugging function, much cleaner than print_r
985
function echo_array($array, $return_me = false) {
986
	if (is_array($array) == false) {
987
		$return = "The provided variable is not an array.";
988
	} else {
989
		foreach ($array as $name=>$value) {
990
			if (is_array($value)) {
991
				$return .= "";
992
				$return .= "['<b>$name</b>'] {<div style=\"margin-left:10px;\">\n";
993
				$return .= echo_array($value, true);
994
				$return .= "</div>}";
995
				$return .= "\n\n";
996
			} else {
997
				if (is_string($value)) {
998
					$value = "\"$value\"";
999
				}
1000
				$return .= "['<b>$name</b>'] = $value\n\n";
1001
			}
1002
		}
1003
	}
1004
	if ($return_me == true) {
1005
		return $return;
1006
	} else {
1007
		echo "<pre>".$return."</pre>";
1008
	}
1009
}
1010

    
1011
/****f* pfsense-utils/display_top_tabs
1012
 * NAME
1013
 *	 display_top_tabs - display tabs with rounded edges
1014
 * INPUTS
1015
 *	 $text	  - array of tabs
1016
 * RESULT
1017
 *	 null
1018
 ******/
1019
function display_top_tabs(& $tab_array, $no_drop_down = false, $type = 'pills', $usepost = "") {
1020
	global $config;
1021
	global $g;
1022
	global $tab_array_indent;
1023
	global $tab_array_space;
1024
	global $tab_array_char_limit;
1025

    
1026
	/*	does the user have access to this tab?
1027
	 *	master user has access to everything.
1028
	 *	if the user does not have access, simply
1029
	 *	unset the tab item.
1030
	 */
1031

    
1032
	/* empty string code */
1033
	if ($tab_array_indent == '') {
1034
		$tab_array_indent = 0;
1035
	}
1036

    
1037
	if ($tab_array_space == '') {
1038
		$tab_array_space = 1;
1039
	}
1040

    
1041
	if ($tab_array_char_limit == '') {
1042
		$tab_array_char_limit = 256;
1043
	}
1044

    
1045
	foreach ($tab_array as $tab_id => $ta) {
1046
		if (!isAllowedPage($ta[2])) {
1047
			unset ($tab_array[$tab_id]);
1048
		}
1049
	}
1050

    
1051
	$tab_active_bg	 = "#EEEEEE";
1052
	$tab_inactive_bg = "#777777";
1053
	$nifty_tabs_corners = "#FFF";
1054
	$font_color = "white";
1055

    
1056
	$tabcharcount = 0;
1057
	foreach ($tab_array as $ta) {
1058
		$tabcharcount = $tabcharcount + strlen($ta[0]);
1059
	}
1060

    
1061
	if ($no_drop_down == true) {
1062
		$tabcharcount = 0;
1063
		unset($tab_array_char_limit);
1064
	}
1065

    
1066
	// If the character count of the tab names is > 670
1067
	// then show a select item dropdown menubox.
1068
	if ($tabcharcount > $tab_array_char_limit) {
1069
		echo gettext("Currently viewing: ");
1070
		echo "<select name=\"TabSelect\" onchange=\"tabs_will_go(this)\">\n";
1071

    
1072
		foreach ($tab_array as $ta) {
1073
			if ($ta[1] == "true") {
1074
				$selected = " selected";
1075
			} else {
1076
				$selected = "";
1077
			}
1078
			// Onclick in option will not work in some browser
1079
			// echo "<option onclick=\"document.location='{$ta[2]}';\"{$selected}>{$ta['0']}</option>\n";
1080
			echo "<option value=\"{$ta[2]}\"{$selected}>{$ta['0']}</option>\n";
1081
		}
1082

    
1083
		echo "</select>\n<p>&nbsp;</p>";
1084
		echo "<script type=\"text/javascript\">";
1085
		echo "\n//<![CDATA[\n";
1086
		if ($usepost == 'usepost') {
1087
			echo " function tabs_will_go(obj){ var target = obj.value.split(\"?\"); postSubmit(get2post(target[1]),target[0]); }\n";
1088
		} else {
1089
			echo " function tabs_will_go(obj){ document.location = obj.value; }\n";
1090
		}
1091
		echo "//]]>\n";
1092
		echo "</script>";
1093
	} else {
1094
		echo '<ul class="nav nav-' . $type . '">';
1095

    
1096
		foreach ($tab_array as $ta) {
1097
			echo '<li role="presentation"';
1098
			if ($ta[1]) {
1099
				echo ' class="active"';
1100
			}
1101

    
1102
			echo '><a href="' . $ta[2] . '" ' . $usepost . '>' . $ta[0] . '</a></li>';
1103
		}
1104

    
1105
		echo '</ul>';
1106
	}
1107
}
1108

    
1109
function add_package_tabs($tabgroup, &$tab_array) {
1110
	global $config, $g;
1111

    
1112
	if (!isset($config['installedpackages']['package'])) {
1113
		return;
1114
	}
1115

    
1116
	foreach ($config['installedpackages']['package'] as $pkg) {
1117
		if (!is_array($pkg['tabs']['tab'])) {
1118
			continue;
1119
		}
1120

    
1121
		foreach ($pkg['tabs']['tab'] as $tab) {
1122
			if ($tab['tabgroup'] != $tabgroup) {
1123
				continue;
1124
			}
1125
			$tab_entry = array();
1126
			if ($tab['name']) {
1127
				$tab_entry[] = $tab['name'];
1128
				$tab_entry[] = false;
1129
				$tab_entry[] = $tab['url'];
1130
				$tab_array[] = $tab_entry;
1131
			}
1132
		}
1133
	}
1134
}
1135

    
1136
function alias_info_popup($alias_id) {
1137
	global $config, $user_settings;
1138

    
1139
	if (!is_array($config['aliases']['alias'][$alias_id])) {
1140
		return;
1141
	}
1142

    
1143
	$maxlength = 60;
1144
	$alias = $config['aliases']['alias'][$alias_id];
1145
	$content = "";
1146

    
1147
	if ($user_settings['webgui']['disablealiaspopupdetail']) {
1148
		if (strlen($alias['descr']) >= $maxlength) {
1149
			$alias['descr'] = substr($alias['descr'], 0, $maxlength) . '&hellip;';
1150
		}
1151

    
1152
		$content .= $alias['descr'];
1153
	} else if ($alias['url']) {
1154
		// TODO: Change it when pf supports tables with ports
1155
		if ($alias['type'] == "urltable") {
1156
			exec("/sbin/pfctl -t {$alias['name']} -T show | wc -l", $total_entries);
1157
			$counter=preg_replace("/\D/", "", $total_entries[0]);
1158
			exec("/sbin/pfctl -t {$alias['name']} -T show | head -10002", $alias_addresses);
1159
		} else {
1160
			$urlfn = alias_expand_urltable($alias['name']);
1161
			$alias_addresses = explode("\n", file_get_contents($urlfn));
1162
			$counter = count($alias_addresses);
1163
		}
1164

    
1165
		$content .= '<h5>'. $alias['url'] .'</h5><ul><li>'. implode('</li><li>', $alias_addresses) .'</li></ul>';
1166
		if ($counter > 10002) {
1167
			$content .= '<i>'. gettext("listing only first 10k items") .'</i>';
1168
		}
1169
	} else {
1170
		$alias_addresses = explode (" ", $alias['address']);
1171
		$alias_details = explode ("||", $alias['detail']);
1172
		$idx = 0;
1173

    
1174
		$content .= "<table>\n";
1175
		$content .= "<thead>\n";
1176
		$content .= "<tr>\n";
1177
		$content .= "<th>" . gettext("Value") . "</th><th  style='padding-left: 10px;'>" . gettext("Description") . "</th></tr>\n";
1178
		$content .= "</thead>\n";
1179
		$content .= "<tbody>\n";
1180

    
1181
		foreach ($alias_addresses as $ap) {
1182
			$content .= "	<tr>\n";
1183
			$content .= "		<td>\n";
1184
			$content .= 			$ap;
1185
			$content .=	"		</td>\n";
1186
			$content .= "		<td style='padding-left: 10px;'>\n";
1187
			$content .= 			htmlspecialchars($alias_details[$idx]);
1188
			$content .=	"		</td>\n";
1189
			$content .= "	</tr>\n";
1190
			$idx++;
1191
		}
1192

    
1193
		$content .= "</tbody>\n";
1194
		$content .= "<table>\n";
1195
	}
1196

    
1197
	return $content;
1198
}
1199

    
1200
function rule_columns_with_alias($src, $srcport, $dst, $dstport, $target="", $targetport="") {
1201
	global $config;
1202

    
1203
	if ($config['aliases']['alias'] == "" || !is_array($config['aliases']['alias'])) {
1204
		return;
1205
	}
1206

    
1207
	$columns = array();
1208
	foreach ($config['aliases']['alias'] as $alias_id => $alias_name) {
1209
		if ($alias_name['name'] == $src) {
1210
			$columns['src'] = $alias_id;
1211
		}
1212
		if ($alias_name['name'] == $srcport) {
1213
			$columns['srcport'] = $alias_id;
1214
		}
1215
		if ($alias_name['name'] == $dst) {
1216
			$columns['dst'] = $alias_id;
1217
		}
1218
		if ($alias_name['name'] == $dstport) {
1219
			$columns['dstport'] = $alias_id;
1220
		}
1221
		if ($alias_name['name'] == $target) {
1222
			$columns['target'] = $alias_id;
1223
		}
1224
		if ($alias_name['name'] == $targetport) {
1225
			$columns['targetport'] = $alias_id;
1226
		}
1227
	}
1228

    
1229
	return $columns;
1230
}
1231

    
1232
function form_output_row($name, $label, $content) {
1233
var_dump($content);die;
1234
?>
1235
<div class="form-group">
1236
	<label for="<?=$name?>" class="col-sm-2 control-label"><?=gettext($label); ?></label>
1237
	<div class="col-sm-10">
1238
		<?=$content?>
1239
	</div>
1240
</div>
1241
<?php
1242
}
1243

    
1244
function set_flash_message($class, $msg) {
1245
	@phpsession_begin();
1246
	$_SESSION['flash_messages'][$class][] = $msg;
1247
	@phpsession_end(true);
1248
}
1249

    
1250
function get_flash_message() {
1251
	@phpsession_begin();
1252
	if (isset($_SESSION['flash_messages']) && !empty($_SESSION['flash_messages'])) {
1253
		foreach ($_SESSION['flash_messages'] as $class => $flash_message) {
1254
			print_info_box(implode("<br />", $flash_message), $class);
1255
		}
1256
		unset($_SESSION['flash_messages']);
1257
	}
1258
	@phpsession_end(true);
1259
}
1260

    
1261
/* Retrieve GET or POST Value/State
1262
 * Eample Usage:
1263
 * $value = getGETPOSTsettingvalue('get/post parameter name', "");
1264
 * $value = getGETPOSTsettingvalue('get/post parameter name', null);
1265
 * $state = getGETPOSTsettingvalue('get/post parameter name', null);
1266
 * $state = getGETPOSTsettingvalue('get/post parameter name', false);
1267
 */
1268
function getGETPOSTsettingvalue($settingname, $default) {
1269
	$settingvalue = $default;
1270
	if ($_GET[$settingname]) {
1271
		$settingvalue = $_GET[$settingname];
1272
	}
1273
	if ($_POST[$settingname]) {
1274
		$settingvalue = $_POST[$settingname];
1275
	}
1276
	return $settingvalue;
1277
}
1278

    
1279
/* set timezone */
1280
if (isset($config['system']['timezone']) &&
1281
    !empty($config['system']['timezone'])) {
1282
	$timezone = $config['system']['timezone'];
1283
} elseif (isset($g['default_timezone']) && !empty($g['default_timezone'])) {
1284
	$timezone = $g['default_timezone'];
1285
} else {
1286
	$timezone = "Etc/UTC";
1287
}
1288

    
1289
date_default_timezone_set($timezone);
1290

    
1291
?>
(66-66/230)