2
0
Эх сурвалжийг харах

Import extensions fix and new Call ACL app (#119)

* Add Bulk Import Extensions app

* Fix Win/Mac browser issue

On Mac, when uploading CSV, filetype is set correctly. On Windows - no

* Fix bugs, added few options

* Restore README.rst

* Call ACL app added
Igor Olhovskiy 6 жил өмнө
parent
commit
c8bdd96cf2

+ 17 - 0
call_acl/README.md

@@ -0,0 +1,17 @@
+# Install HOW TO
+1. ```cd /usr/src/```
+2. ```git clone https://github.com/fusionpbx/fusionpbx-apps```
+3. ```cd fusionpbx-apps/```
+4. ```cp -R call_acl /var/www/fusionpbx/app/```
+5. ```cp -R call_acl/resources/install/scripts/app/call_acl /usr/share/freeswitch/scripts/app/```
+6. ```cp call_acl/templates/conf/dialplan/041_call_acl.xml /var/www/fusionpbx/app/dialplans/resources/switch/conf/dialplan/```
+7. Go to GUI
+8. Upgrades -> SCHEMA; APP DEFAULTS; MENU DEFAULTS; PERMISSION DEFAULTS
+9. Log out and back in
+10. **Dialplan** -> **Dialplan Manager**
+11. You will find new dialplan entry **call_acl**, order **041**, to enable Call ACL need to turn it to Enabled.
+12. **Apps** -> **Call ACL**.
+
+Allow and Reject!
+
+Note, by default call_acl in dialplan is turned off. It's done cause it's used regular expressions and it's not needed on every domain

+ 84 - 0
call_acl/app_config.php

@@ -0,0 +1,84 @@
+<?php
+
+	//application details
+		$apps[$x]['name'] = "Call ACL";
+		$apps[$x]['uuid'] = "32aeff16-c7bf-439b-a54d-2568a7e0cec0";
+		$apps[$x]['category'] = "Switch";
+		$apps[$x]['subcategory'] = "";
+		$apps[$x]['version'] = "1.0";
+		$apps[$x]['license'] = "Mozilla Public License 1.1";
+		$apps[$x]['url'] = "http://www.fusionpbx.com";
+		$apps[$x]['description']['en-us'] = "A tool to make call ACL across domain";
+
+	//permission details
+		$y=0;
+		$apps[$x]['permissions'][$y]['name'] = "call_acl_view";
+		$apps[$x]['permissions'][$y]['menu']['uuid'] = "0674b1b7-e487-4563-bd07-1b1d4dc6e64d";
+		$apps[$x]['permissions'][$y]['groups'][] = "superadmin";
+		$apps[$x]['permissions'][$y]['groups'][] = "admin";
+		$y++;
+		$apps[$x]['permissions'][$y]['name'] = "call_acl_add";
+		$apps[$x]['permissions'][$y]['groups'][] = "superadmin";
+		$apps[$x]['permissions'][$y]['groups'][] = "admin";
+		$y++;
+		$apps[$x]['permissions'][$y]['name'] = "call_acl_edit";
+		$apps[$x]['permissions'][$y]['groups'][] = "superadmin";
+		$apps[$x]['permissions'][$y]['groups'][] = "admin";
+		$y++;
+		$apps[$x]['permissions'][$y]['name'] = "call_acl_delete";
+		$apps[$x]['permissions'][$y]['groups'][] = "superadmin";
+		$apps[$x]['permissions'][$y]['groups'][] = "admin";
+	//default settings
+		$y = 0;
+		$apps[$x]['default_settings'][$y]['default_setting_uuid'] = '3c1b5c71-bd6a-446c-b3a2-b5215c212f28';
+		$apps[$x]['default_settings'][$y]['default_setting_category'] = 'call_acl';
+		$apps[$x]['default_settings'][$y]['default_setting_subcategory'] = 'max_order';
+		$apps[$x]['default_settings'][$y]['default_setting_name'] = 'numeric';
+		$apps[$x]['default_settings'][$y]['default_setting_value'] = '20';
+		$apps[$x]['default_settings'][$y]['default_setting_enabled'] = 'true';
+		$apps[$x]['default_settings'][$y]['default_setting_description'] = 'Maximum order number to select';
+
+	//schema details
+		$y=0;
+		$apps[$x]['db'][$y]['table']['name'] = "v_call_acl";
+		$apps[$x]['db'][$y]['table']['parent'] = "";
+		$z=0;
+		$apps[$x]['db'][$y]['fields'][$z]['name'] = "domain_uuid";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['pgsql'] = "uuid";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['sqlite'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['mysql'] = "char(36)";
+		$apps[$x]['db'][$y]['fields'][$z]['key']['type'] = "foreign";
+		$apps[$x]['db'][$y]['fields'][$z]['key']['reference']['table'] = "v_domains";
+		$apps[$x]['db'][$y]['fields'][$z]['key']['reference']['field'] = "domain_uuid";
+		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
+		$z++;
+		$apps[$x]['db'][$y]['fields'][$z]['name']['text'] = "call_acl_uuid";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['pgsql'] = "uuid";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['sqlite'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['type']['mysql'] = "char(36)";
+		$apps[$x]['db'][$y]['fields'][$z]['key']['type'] = "primary";
+		$z++;
+		$apps[$x]['db'][$y]['fields'][$z]['name']['text'] = "call_acl_order";
+		$apps[$x]['db'][$y]['fields'][$z]['type'] = "numeric";
+		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "Order";
+		$z++;
+		$apps[$x]['db'][$y]['fields'][$z]['name']['text'] = "call_acl_name";
+		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "Enter the name.";
+		$z++;
+		$apps[$x]['db'][$y]['fields'][$z]['name']['text'] = "call_acl_source";
+		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "Call ACL source to be checked against";
+		$z++;
+		$apps[$x]['db'][$y]['fields'][$z]['name']['text'] = "call_acl_destination";
+		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "Call ACL destination to be checked against";
+		$z++;
+		$apps[$x]['db'][$y]['fields'][$z]['name']['text'] = "call_acl_action";
+		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "Action for call.";
+		$z++;
+		$apps[$x]['db'][$y]['fields'][$z]['name']['text'] = "call_acl_enabled";
+		$apps[$x]['db'][$y]['fields'][$z]['type'] = "text";
+		$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "Enable/disable ACL rule";
+?>

+ 62 - 0
call_acl/app_languages.php

@@ -0,0 +1,62 @@
+<?php
+#This file was last reorganized on 19th of September 2017 08:54:24 AM UTC
+
+$text['title-call_acl']['en-us'] = "Call ACL";
+
+$text['label-call_acl_order']['en-us'] = "Order";
+
+$text['label-call_acl_name']['en-us'] = "Name";
+
+$text['label-call_acl_source']['en-us'] = "Source";
+
+$text['label-call_acl_destination']['en-us'] = "Destination";
+
+$text['label-call_acl_action']['en-us'] = "Action";
+
+$text['label-call_acl_enabled']['en-us'] = "Enabled";
+
+
+$text['label-edit-add']['en-us'] = "Add ACL rule";
+
+$text['label-edit-edit']['en-us'] = "Edit ACL rule";
+
+$text['label-add-note']['en-us'] = "Add access control rule. Rules are applied in order. If order for rules are same, they applied in random order. If none of rules are matched - allow call";
+
+$text['label-edit-note']['en-us'] = "Edit access control rule. Rules are applied in order. If order for rules are same, they applied in random order. If none of rules are matched - allow call";
+
+$text['label-add-complete']['en-us'] = "Add Complete";
+
+$text['label-update-complete']['en-us'] = "Update Complete";
+
+$text['label-reject']['en-us'] = "Reject";
+
+$text['label-allow']['en-us'] = "Allow";
+
+$text['description-call_acl']['en-us'] = "Access Control List for calls within domain. Default rule - allow";
+
+$text['description-call_acl_name']['en-us'] = "Enter the name for this rule";
+
+$text['description-call_acl_source']['en-us'] = "Enter the template for source number to match. Refer below for templates description";
+
+$text['description-call_acl_destination']['en-us'] = "Enter the template for destination number to match. Refer below for templates description";
+
+$text['description-call_acl_action']['en-us'] = "Allow or reject(block) this call";
+
+$text['description-call_acl_enabled']['en-us'] = "Enable or disable this rule";
+
+$text['description-call_acl_order']['en-us'] = "Select order number for this rule";
+
+
+
+$text['description-call_acl_templates']['en-us'] = "Templates support ranges and wildcards. Actually it's limited regexes<br>";
+$text['description-call_acl_templates']['en-us'] .= "[A-B] matches any digit within A-B range<br>";
+$text['description-call_acl_templates']['en-us'] .= "'X' matches any digit one time<br>";
+$text['description-call_acl_templates']['en-us'] .= "'*' matches anything<br>";
+$text['description-call_acl_templates']['en-us'] .= "'^'  matches start of the string<br>";
+$text['description-call_acl_templates']['en-us'] .= "'$'  matches end of the string<br>";
+$text['description-call_acl_templates']['en-us'] .= "Examples:<br>";
+$text['description-call_acl_templates']['en-us'] .= "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^[1-2]X matches numbers 10 - 29 <br>";
+$text['description-call_acl_templates']['en-us'] .= "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^XXX or ^XXX*$ matches numbers with 3 digits and more<br>";
+$text['description-call_acl_templates']['en-us'] .= "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^XXX$ matches numbers with exact 3 digits <br>";
+$text['description-call_acl_templates']['en-us'] .= "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^*[45]$ matches numbers that ends with 4 or 5 <br>";
+?>

+ 13 - 0
call_acl/app_menu.php

@@ -0,0 +1,13 @@
+<?php
+
+	$y=0;
+	$apps[$x]['menu'][$y]['title']['en-us'] = "Call ACL";
+
+	$apps[$x]['menu'][$y]['uuid'] = "3f9bcc10-8d16-4619-a8fa-628a3ef6de30";
+	$apps[$x]['menu'][$y]['parent_uuid'] = "fd29e39c-c936-f5fc-8e2b-611681b266b5";
+	$apps[$x]['menu'][$y]['category'] = "internal";
+	$apps[$x]['menu'][$y]['path'] = "/app/call_acl/call_acl.php";
+	$apps[$x]['menu'][$y]['groups'][] = "superadmin";
+	$apps[$x]['menu'][$y]['groups'][] = "admin";
+
+?>

+ 176 - 0
call_acl/call_acl.php

@@ -0,0 +1,176 @@
+<?php
+/*
+	FusionPBX
+	Version: MPL 1.1
+
+	The contents of this file are subject to the Mozilla Public License Version
+	1.1 (the "License"); you may not use this file except in compliance with
+	the License. You may obtain a copy of the License at
+	http://www.mozilla.org/MPL/
+
+	Software distributed under the License is distributed on an "AS IS" basis,
+	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+	for the specific language governing rights and limitations under the
+	License.
+
+	The Original Code is FusionPBX
+
+	The Initial Developer of the Original Code is
+	Mark J Crane <[email protected]>
+	Portions created by the Initial Developer are Copyright (C) 2008-2012
+	the Initial Developer. All Rights Reserved.
+
+	Contributor(s):
+	Mark J Crane <[email protected]>
+	Igor Olhovskiy <[email protected]>
+
+	Call ACL is written on Call Block base by Gerrit Visser <[email protected]>
+*/
+require_once "root.php";
+require_once "resources/require.php";
+
+//check permissions
+	require_once "resources/check_auth.php";
+	if (permission_exists('call_acl_view')) {
+		//access granted
+	} else {
+		echo "access denied";
+		exit;
+	}
+
+//add multi-lingual support
+	$language = new text;
+	$text = $language->get();
+
+//additional includes
+	require_once "resources/header.php";
+	require_once "resources/paging.php";
+
+//get variables used to control the order
+	$order_by = $_GET["order_by"];
+	$order = $_GET["order"];
+
+//show the content
+	echo "<table width='100%' cellpadding='0' cellspacing='0' border='0'>\n";
+	echo "	<tr>\n";
+	echo "		<td width='50%' align='left' nowrap='nowrap'><b>".$text['title-call_acl']."</b></td>\n";
+	echo "		<td width='50%' align='right'>&nbsp;</td>\n";
+	echo "	</tr>\n";
+	echo "	<tr>\n";
+	echo "		<td align='left' colspan='2'>\n";
+	echo "			".$text['description-call_acl']."<br /><br />\n";
+	echo "		</td>\n";
+	echo "	</tr>\n";
+	echo "</table>\n";
+
+//prepare to page the results
+	$sql = "SELECT count(*) AS num_rows FROM v_call_acl";
+	$sql .= " WHERE domain_uuid = '".$_SESSION['domain_uuid']."' ";
+	if (strlen($order_by)> 0) { 
+		$sql .= "ORDER BY $order_by $order "; 
+	}
+	$prep_statement = $db->prepare($sql);
+
+	if ($prep_statement) {
+		$prep_statement->execute();
+		$row = $prep_statement->fetch(PDO::FETCH_ASSOC);
+		$num_rows = $row['num_rows'] > 0 ? $row['num_rows'] : "0";
+	}
+
+//prepare to page the results
+	$rows_per_page = ($_SESSION['domain']['paging']['numeric'] != '') ? $_SESSION['domain']['paging']['numeric'] : 50;
+	$param = "";
+	$page = $_GET['page'];
+	if (strlen($page) == 0) { $page = 0; $_GET['page'] = 0; }
+	list($paging_controls, $rows_per_page, $var3) = paging($num_rows, $param, $rows_per_page);
+	$offset = $rows_per_page * $page;
+
+//get the  list
+	$sql = "SELECT * FROM v_call_acl";
+	$sql .= " WHERE domain_uuid = '".$_SESSION['domain_uuid']."' ";
+	if (strlen($order_by)> 0) { 
+		$sql .= "ORDER BY $order_by $order ";
+	} else {
+		$sql .= "ORDER BY call_acl_order ASC "; 
+	}
+	$sql .= " LIMIT $rows_per_page OFFSET $offset ";
+	$prep_statement = $db->prepare(check_sql($sql));
+	$prep_statement->execute();
+	$result = $prep_statement->fetchAll();
+	$result_count = count($result);
+	unset ($prep_statement, $sql);
+
+//table headers
+	$c = 0;
+	$row_style["0"] = "row_style0";
+	$row_style["1"] = "row_style1";
+	echo "<table class='tr_hover' width='100%' border='0' cellpadding='0' cellspacing='0'>\n";
+	echo "<tr>\n";
+	echo th_order_by('call_acl_order', $text['label-call_acl_order'], $order_by, $order);
+	echo th_order_by('call_acl_name', $text['label-call_acl_name'], $order_by, $order);
+	echo th_order_by('call_acl_source', $text['label-call_acl_source'], $order_by, $order);
+	echo th_order_by('call_acl_destination', $text['label-call_acl_destination'], $order_by, $order);
+	echo th_order_by('call_acl_action', $text['label-call_acl_action'], $order_by, $order);
+	echo th_order_by('call_acl_enabled', $text['label-call_acl_enabled'], $order_by, $order);
+	echo "<td class='list_control_icons'>";
+	if (permission_exists('call_acl_add')) {
+		echo "<a href='call_acl_edit.php' alt='".$text['button-add']."'>$v_link_label_add</a>";
+	}
+	echo "</td>\n";
+	echo "</tr>\n";
+
+//show the results
+	if ($result_count > 0) {
+		foreach($result as $row) {
+			$tr_link = (permission_exists('call_acl_edit')) ? "href='call_acl_edit.php?id=".$row['call_acl_uuid']."'" : null;
+			echo "<tr ".$tr_link.">\n";
+			echo "	<td valign='top' class='".$row_style[$c]."'>";
+			if (permission_exists('call_acl_edit')) {
+				echo "<a href='call_acl_edit.php?id=".escape($row['call_acl_uuid'])."'>".escape($row['call_acl_order'])."</a>";
+			} else {
+				echo escape($row['call_acl_order']);
+			}
+			echo "	</td>\n";
+			echo "	<td valign='top' class='".$row_style[$c]."'>".escape($row['call_acl_name'])."</td>\n";
+			echo "	<td valign='top' class='".$row_style[$c]."'>".escape($row['call_acl_source'])."</td>\n";
+			echo "	<td valign='top' class='".$row_style[$c]."'>".escape($row['call_acl_destination'])."</td>\n";
+			echo "	<td valign='top' class='".$row_style[$c]."'>". (($row['call_acl_action'] == "reject") ? $text['label-reject'] : $text['label-allow']) ."</td>\n";
+			echo "	<td valign='top' class='".$row_style[$c]."'>".$text['label-'.escape($row['call_acl_enabled'])]."</td>\n";
+			echo "	<td class='list_control_icons'>";
+			if (permission_exists('call_acl_edit')) {
+				echo "<a href='call_acl_edit.php?id=".escape($row['call_acl_uuid'])."' alt='".$text['button-edit']."'>$v_link_label_edit</a>";
+			}
+			if (permission_exists('call_acl_delete')) {
+				echo "<a href='call_acl_delete.php?id=".escape($row['call_acl_uuid'])."' alt='".$text['button-delete']."' onclick=\"return confirm('".$text['confirm-delete']."')\">$v_link_label_delete</a>";
+			};
+			echo "  </td>";
+			echo "</tr>\n";
+			$c = 1 - $c;  // Switch $c = 0/1/0...
+		} //end foreach
+		unset($sql, $result, $row_count);
+	} //end if results
+
+//complete the content
+	echo "<tr>\n";
+	echo "<td colspan='11' align='left'>\n";
+	echo "	<table width='100%' cellpadding='0' cellspacing='0'>\n";
+	echo "	<tr>\n";
+	echo "		<td width='33.3%' nowrap>&nbsp;</td>\n";
+	echo "		<td width='33.3%' align='center' nowrap>$paging_controls</td>\n";
+	echo "		<td class='list_control_icons'>";
+	if (permission_exists('call_acl_add')) {
+		echo "<a href='call_acl_edit.php' alt='".$text['button-add']."'>$v_link_label_add</a>";
+	}
+	echo "		</td>\n";
+	echo "	</tr>\n";
+ 	echo "	</table>\n";
+	echo "</td>\n";
+	echo "</tr>\n";
+
+	echo "</table>";
+	echo "<br /><br />";
+
+//include the footer
+	require_once "resources/footer.php";
+
+?>

+ 66 - 0
call_acl/call_acl_delete.php

@@ -0,0 +1,66 @@
+<?php
+/*
+	FusionPBX
+	Version: MPL 1.1
+
+	The contents of this file are subject to the Mozilla Public License Version
+	1.1 (the "License"); you may not use this file except in compliance with
+	the License. You may obtain a copy of the License at
+	http://www.mozilla.org/MPL/
+
+	Software distributed under the License is distributed on an "AS IS" basis,
+	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+	for the specific language governing rights and limitations under the
+	License.
+
+	The Original Code is FusionPBX
+
+	The Initial Developer of the Original Code is
+	Mark J Crane <[email protected]>
+	Portions created by the Initial Developer are Copyright (C) 2008-2012
+	the Initial Developer. All Rights Reserved.
+
+	Contributor(s):
+	Mark J Crane <[email protected]>
+	Igor Olhovskiy <[email protected]>
+
+	Call ACL is written on Call Block base by Gerrit Visser <[email protected]>
+*/
+//includes
+	include "root.php";
+	require_once "resources/require.php";
+	require_once "resources/check_auth.php";
+
+//check permissions
+	if (permission_exists('call_acl_delete')) {
+		//access granted
+	} else {
+		echo "access denied";
+		exit;
+	}
+
+//add multi-lingual support
+	$language = new text;
+	$text = $language->get();
+
+//set the variable
+	if (count($_GET) > 0) {
+		$id = $_GET["id"];
+	}
+
+//delete the extension
+	if (strlen($id) > 0) {
+		//delete the call block
+		$sql = "DELETE FROM v_call_acl";
+		$sql .= " WHERE domain_uuid = '".$_SESSION['domain_uuid']."'";
+		$sql .= " AND call_acl_uuid = '$id' ";
+		$prep_statement = $db->prepare(check_sql($sql));
+		$prep_statement->execute();
+		unset($prep_statement, $sql);
+	}
+
+	//redirect the browser
+		messages::add($text['label-delete-complete']);
+		header("Location: call_acl.php");
+		return;
+?>

+ 330 - 0
call_acl/call_acl_edit.php

@@ -0,0 +1,330 @@
+<?php
+/*
+	FusionPBX
+	Version: MPL 1.1
+
+	The contents of this file are subject to the Mozilla Public License Version
+	1.1 (the "License"); you may not use this file except in compliance with
+	the License. You may obtain a copy of the License at
+	http://www.mozilla.org/MPL/
+
+	Software distributed under the License is distributed on an "AS IS" basis,
+	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+	for the specific language governing rights and limitations under the
+	License.
+
+	The Original Code is FusionPBX
+
+	The Initial Developer of the Original Code is
+	Mark J Crane <[email protected]>
+	Portions created by the Initial Developer are Copyright (C) 2008-2018
+	the Initial Developer. All Rights Reserved.
+
+	Contributor(s):
+	Mark J Crane <[email protected]>
+	Luis Daniel Lucio Quiroz <[email protected]>
+	Igor Olhovskiy <[email protected]>
+
+	Call ACL is written on Call Block base by Gerrit Visser <[email protected]>
+*/
+//includes
+	require_once "root.php";
+	require_once "resources/require.php";
+	require_once "resources/check_auth.php";
+
+//check permissions
+	if (permission_exists('call_acl_edit') || permission_exists('call_acl_add')) {
+		//access granted
+	} else {
+		echo "access denied";
+		exit;
+	}
+
+//add multi-lingual support
+	$language = new text;
+	$text = $language->get();
+
+//action add or update
+	if (isset($_REQUEST["id"])) {
+		$action = "update";
+		$call_acl_uuid = check_str($_REQUEST["id"]);
+	} else {
+		$action = "add";
+	}
+
+//get http post variables and set them to php variables
+	if (count($_POST) > 0) {
+		$call_acl_order = check_str($_POST["call_acl_order"]);
+		$call_acl_name = check_str($_POST["call_acl_name"]);
+		$call_acl_source = check_str($_POST["call_acl_source"]);
+		$call_acl_destination = check_str($_POST["call_acl_destination"]);
+		$call_acl_action = check_str($_POST["call_acl_action"]);
+		$call_acl_enabled = check_str($_POST["call_acl_enabled"]);
+	}
+
+//handle the http post
+	if (count($_POST) > 0 && strlen($_POST["persistformvar"]) == 0) {
+	
+		$msg = '';
+	
+		//check for all required data
+		if (strlen($call_acl_name) == 0) { 
+			$msg .= $text['label-call_acl_name']."<br>\n"; 
+		}
+		if (strlen($call_acl_source) == 0) {
+			$msg .= $text['label-call_acl_source']."<br>\n"; 
+		}
+		if (strlen($call_acl_destination) == 0) { 
+			$msg .= $text['label-call_acl_destination']."<br>\n"; 
+		}
+		if (strlen($call_acl_order) == 0) { 
+			$msg .= $text['label-call_acl_order']."<br>\n"; 
+		}
+
+		if (strlen($msg) > 0 && strlen($_POST["persistformvar"]) == 0) {
+			require_once "resources/header.php";
+			require_once "resources/persist_form_var.php";
+			echo "<div align='center'>\n";
+			echo "<table><tr><td>\n";
+			echo $msg."<br />";
+			echo "</td></tr></table>\n";
+			persistformvar($_POST);
+			echo "</div>\n";
+			require_once "resources/footer.php";
+			return;
+		}
+
+	//add or update the database
+		if (($_POST["persistformvar"] != "true") > 0) {
+
+			if ($action == "add") {
+
+				$call_acl_uuid = uuid();
+
+				$sql = "INSERT INTO v_call_acl";
+				$sql .= " (";
+				$sql .= "domain_uuid, ";
+				$sql .= "call_acl_uuid, ";
+				$sql .= "call_acl_order, ";
+				$sql .= "call_acl_name, ";
+				$sql .= "call_acl_source, ";
+				$sql .= "call_acl_destination, ";
+				$sql .= "call_acl_action, ";
+				$sql .= "call_acl_enabled ";
+				$sql .= ") ";
+				$sql .= "VALUES ";
+				$sql .= "(";
+				$sql .= "'".$_SESSION['domain_uuid']."', ";
+				$sql .= "'$call_acl_uuid', ";
+				$sql .= "'$call_acl_order', ";
+				$sql .= "'$call_acl_name', ";
+				$sql .= "'$call_acl_source', ";
+				$sql .= "'$call_acl_destination', ";
+				$sql .= "'$call_acl_action', ";
+				$sql .= "'$call_acl_enabled'";
+				$sql .= ")";
+				$db->exec(check_sql($sql));
+				unset($sql);
+
+				messages::add($text['label-add-complete']);
+				header("Location: call_acl.php");
+				return;
+			} //if ($action == "add")
+
+			if ($action == "update") {
+
+				$sql = "UPDATE v_call_acl SET ";
+				$sql .= "call_acl_order = '$call_acl_order', ";
+				$sql .= "call_acl_name = '$call_acl_name', ";
+				$sql .= "call_acl_source = '$call_acl_source', ";
+				$sql .= "call_acl_destination = '$call_acl_destination', ";
+				$sql .= "call_acl_action = '$call_acl_action', ";
+				$sql .= "call_acl_enabled = '$call_acl_enabled' ";
+				$sql .= "WHERE domain_uuid = '".$_SESSION['domain_uuid']."' ";
+				$sql .= "AND call_acl_uuid = '$call_acl_uuid'";
+				$db->exec(check_sql($sql));
+				unset($sql);
+
+				messages::add($text['label-update-complete']);
+				header("Location: call_acl.php");
+				return;
+			} //if ($action == "update")
+		} //if ($_POST["persistformvar"] != "true")
+	} //(count($_POST)>0 && strlen($_POST["persistformvar"]) == 0)
+
+//pre-populate the form
+	if (count($_GET)>0 && $_POST["persistformvar"] != "true") {
+		$call_acl_uuid = $_GET["id"];
+		$sql = "SELECT * FROM v_call_acl ";
+		$sql .= "WHERE domain_uuid = '".$_SESSION['domain_uuid']."' ";
+		$sql .= "AND call_acl_uuid = '$call_acl_uuid' ";
+		$prep_statement = $db->prepare(check_sql($sql));
+		$prep_statement->execute();
+		$result = $prep_statement->fetchAll();
+
+		foreach ($result as &$row) {
+			$call_acl_order = $row["call_acl_order"];
+			$call_acl_name = $row["call_acl_name"];
+			$call_acl_source = $row["call_acl_source"];
+			$call_acl_destination = $row["call_acl_destination"];
+			$call_acl_action = $row["call_acl_action"];
+			$call_acl_enabled = $row["call_acl_enabled"];
+			break; //limit to 1 row ? Should be only 1 result at all
+		}
+		unset ($prep_statement, $sql);
+	}
+
+// Get maximum order number
+
+	$call_acl_order_max = isset($_SESSION['call_acl']['max_order']['numeric']) ? (int)$_SESSION['call_acl']['max_order']['numeric'] : 20;
+	if (!$call_acl_order_max) {
+		$call_acl_order_max = 20;
+	}
+
+//show the header
+	require_once "resources/header.php";
+
+//show the content
+
+	echo "<form method='post' name='frm' action=''>\n";
+	echo "<table width='100%' border='0' cellpadding='0' cellspacing='0'>\n";
+	echo "<tr>\n";
+	if ($action == "add") {
+		echo "<td align='left' width='30%' nowrap='nowrap'><b>".$text['label-edit-add']."</b></td>\n";
+	}
+	if ($action == "update") {
+		echo "<td align='left' width='30%' nowrap='nowrap'><b>".$text['label-edit-edit']."</b></td>\n";
+	}
+	echo "<td width='70%' align='right'>";
+	echo "	<input type='button' class='btn' name='' alt='".$text['button-back']."' onclick=\"window.location='call_acl.php'\" value='".$text['button-back']."'>";
+	echo "	<input type='submit' name='submit' class='btn' value='".$text['button-save']."'>\n";
+	echo "</td>\n";
+	echo "</tr>\n";
+	echo "<tr>\n";
+	echo "<td align='left' colspan='2'>\n";
+	if ($action == "add") {
+		echo $text['label-add-note']."<br /><br />\n";
+	}
+	if ($action == "update") {
+		echo $text['label-edit-note']."<br /><br />\n";
+	}
+	echo "</td>\n";
+	echo "</tr>\n";
+
+	// Show order TODO
+	echo "<tr>\n";
+	echo "<td class='vncellreq' valign='top' align='left' nowrap='nowrap'>\n";
+	echo "	".$text['label-call_acl_order']."\n";
+	echo "</td>\n";
+	echo "<td class='vtable' align='left'>\n";
+	echo "<select name='call_acl_order' class='formfld'>\n";
+	for ($i = 0; $i <= $call_acl_order_max; $i++) {
+		$selected = ($i == $call_acl_order) ? "selected" : "";
+		echo "<option value='$i' ".$selected.">$i</option>\n";
+	}
+	echo "		</select>\n";
+	echo "<br />\n";
+	echo $text['description-call_acl_order']."\n";
+	echo "<br />\n";
+	echo "</td>\n";
+	echo "</tr>\n";
+
+	// Show name
+	echo "<tr>\n";
+	echo "<td class='vncellreq' valign='top' align='left' nowrap='nowrap'>\n";
+	echo "	".$text['label-call_acl_name']."\n";
+	echo "</td>\n";
+	echo "<td class='vtable' align='left'>\n";
+	echo "	<input class='formfld' type='text' name='call_acl_name' maxlength='255' value=\"".escape($call_acl_name)."\" required='required'>\n";
+	echo "<br />\n";
+	echo $text['description-call_acl_name']."\n";
+	echo "</td>\n";
+	echo "</tr>\n";
+
+	// Show source
+	echo "<tr>\n";
+	echo "<td class='vncellreq' valign='top' align='left' nowrap='nowrap'>\n";
+	echo "	".$text['label-call_acl_source']."\n";
+	echo "</td>\n";
+	echo "<td class='vtable' align='left'>\n";
+	echo "	<input class='formfld' type='text' name='call_acl_source' maxlength='255' value=\"".escape($call_acl_source)."\" required='required'>\n";
+	echo "<br />\n";
+	echo $text['description-call_acl_source']."\n";
+	echo "</td>\n";
+	echo "</tr>\n";
+
+	// Show destination
+	echo "<tr>\n";
+	echo "<td class='vncellreq' valign='top' align='left' nowrap='nowrap'>\n";
+	echo "	".$text['label-call_acl_destination']."\n";
+	echo "</td>\n";
+	echo "<td class='vtable' align='left'>\n";
+	echo "	<input class='formfld' type='text' name='call_acl_destination' maxlength='255' value=\"".escape($call_acl_destination)."\" required='required'>\n";
+	echo "<br />\n";
+	echo $text['description-call_acl_destination']."\n";
+	echo "</td>\n";
+	echo "</tr>\n";
+
+
+
+	// Show action
+	echo "<tr>\n";
+	echo "<td class='vncell' valign='top' align='left' nowrap='nowrap'>\n";
+	echo "	".$text['label-call_acl_action']."\n";
+	echo "</td>\n";
+	echo "<td class='vtable' align='left'>\n";
+	echo "	<select class='formfld' name='call_acl_action'>\n";
+	if ($call_acl_action == "reject") {
+		echo "	<option value='allow'>".$text['label-allow']."</option>\n";
+		echo "	<option value='reject' selected='selected'>".$text['label-reject']."</option>\n";
+	} else {
+		echo "	<option value='allow' selected='selected'>".$text['label-allow']."</option>\n";
+		echo "	<option value='reject'>".$text['label-reject']."</option>\n";
+	}
+	echo "	</select>\n";
+	echo "<br />\n";
+	echo $text['description-call_acl_action']."\n";
+	echo "\n";
+	echo "</td>\n";
+	echo "</tr>\n";
+
+	// Show enabled
+	echo "<tr>\n";
+	echo "<td class='vncell' valign='top' align='left' nowrap='nowrap'>\n";
+	echo "	".$text['label-call_acl_enabled']."\n";
+	echo "</td>\n";
+	echo "<td class='vtable' align='left'>\n";
+	echo "	<select class='formfld' name='call_acl_enabled'>\n";
+	echo "		<option value='true' ".(($call_acl_enabled == "true") ? "selected" : null).">".$text['label-true']."</option>\n";
+	echo "		<option value='false' ".(($call_acl_enabled == "false") ? "selected" : null).">".$text['label-false']."</option>\n";
+	echo "	</select>\n";
+	echo "<br />\n";
+	echo $text['description-call_acl_enabled']."\n";
+	echo "\n";
+	echo "</td>\n";
+	echo "</tr>\n";
+
+	echo "	<tr>\n";
+	echo "		<td colspan='2' align='right'>\n";
+	if ($action == "update") {
+		echo "		<input type='hidden' name='id' value='".escape($call_acl_uuid)."'>\n";
+	}
+	echo "			<br>";
+	echo "			<input type='submit' name='submit' class='btn' value='".$text['button-save']."'>\n";
+	echo "		</td>\n";
+	echo "	</tr>";
+	echo "</table>";
+	echo "<br><br>";
+	echo "</form>";
+
+	echo "<table>";
+	echo "<tr>";
+	echo "<td>";
+	echo $text['description-call_acl_templates'];
+	echo "</td>";
+	echo "</tr>";
+	echo "</table>";
+
+//include the footer
+	require_once "resources/footer.php";
+?>

+ 111 - 0
call_acl/resources/install/scripts/app/call_acl/index.lua

@@ -0,0 +1,111 @@
+-- Check both clid and destination number against ACL
+
+-- connect to the database
+require "resources.functions.database_handle"
+
+local dbh = database_handle('system')
+
+local function log(message)
+    freeswitch.consoleLog("NOTICE", "[call_acl] "..message.."\n");
+end
+
+local function convert_pattern(pattern)
+    
+    -- Cleanup pattern-related magical characters
+    converted_pattern = pattern:gsub("%(", "%%(")
+    converted_pattern = converted_pattern:gsub("%)", "%%)")
+    converted_pattern = converted_pattern:gsub("%%", "%%%%")
+    converted_pattern = converted_pattern:gsub("%.", "%%.")
+    converted_pattern = converted_pattern:gsub("%[", "%%[")
+    converted_pattern = converted_pattern:gsub("%]", "%%]")
+    converted_pattern = converted_pattern:gsub("%+", "%%+")
+    converted_pattern = converted_pattern:gsub("%-", "%%-")
+    converted_pattern = converted_pattern:gsub("%?", "%%?")
+
+    -- Internal convention x - any digit, * - any number of digits
+    converted_pattern = converted_pattern:gsub("x", "%%d")
+    converted_pattern = converted_pattern:gsub("%*", ".*")
+
+    return converted_pattern
+
+end
+
+if (session:ready()) then
+
+    local sql = ""
+
+    local source = session:getVariable("caller_id_number")
+    local destination = session:getVariable("destination_number")
+
+    if (source == nil or destination == nil) then
+        log("Cannot get callerid or destination number")
+        return
+    end
+
+
+    if (domain_id == nil) then
+        domain_id = session:getVariable("domain_name") or session:getVariable("sip_invite_domain")
+    else
+        sql = "SELECT call_acl_name, "
+        sql = sql .. "call_acl_source, "
+        sql = sql .. "call_acl_destination, "
+        sql = sql .. "call_acl_action "
+        sql = sql .. "FROM v_call_acl "
+        sql = sql .. "WHERE domain_uuid = '" .. domain_id .. "' "
+        sql = sql .. "AND call_acl_enabled = 'true' "
+        sql = sql .. "ORDER BY call_acl_order"
+    end
+
+    if (domain_id ~= nil) then
+        if (sql == "") then
+            sql = "SELECT call_acl_name, "
+            sql = sql .. "call_acl_source, "
+            sql = sql .. "call_acl_destination, "
+            sql = sql .. "call_acl_action "
+            sql = sql .. "FROM v_call_acl "
+            sql = sql .. "WHERE domain_uuid ="
+            sql = sql .. " (SELECT domain_uuid FROM v_domains"
+            sql = sql .. " WHERE domain_name = '" .. domain_id .. "'"
+            sql = sql .. " AND domain_enabled = 'true') "
+            sql = sql .. "AND call_acl_enabled = 'true' "
+            sql = sql .. "ORDER BY call_acl_order"
+        end
+
+        -- Get all patterns in list. Mainly cause we can't get 
+        local patterns = {}
+        local pattern_index = 1
+        dbh:query(sql, function(row)
+            patterns[pattern_index] = row
+            pattern_index = pattern_index + 1
+        end);
+
+        dbh:release()
+
+        -- Adjust pattern_index as it's 1 more than actual data
+        pattern_index = pattern_index - 1
+
+        for i = 1, pattern_index do
+            call_acl_name = patterns[i]['call_acl_name']
+            call_acl_source = patterns[i]['call_acl_source']
+            call_acl_destination = patterns[i]['call_acl_destination']
+            call_acl_action = patterns[i]['call_acl_action']
+
+            call_acl_source = convert_pattern(call_acl_source:lower())
+            call_acl_destination = convert_pattern(call_acl_destination:lower())
+
+            if (source:find(call_acl_source) and destination:find(call_acl_destination)) then
+                log("[" ..source.. "/" .. call_acl_source.. "][" ..destination.. "/" .. call_acl_destination.. "] ACL " .. call_acl_name .. " matched")
+                if call_acl_action == 'reject' then
+                    log("ACL is reject. Stop process call")
+                    session:execute('hangup', "BEARERCAPABILITY_NOTAUTH")
+                else 
+                    -- We found pattern match and this is allow (means not reject)
+                    log("ACL is allow. Stop process ACLs")
+                end
+                return
+            end
+        end
+    end
+
+    log("ACL processing end. Contunue call")
+end

+ 7 - 0
call_acl/resources/templates/conf/dialplan/041_call_acl.xml

@@ -0,0 +1,7 @@
+<context name="{v_context}">
+	<extension name="call_acl" number="" continue="true" app_uuid="32aeff16-c7bf-439b-a54d-2568a7e0cec0" enabled="false">
+		<condition field="" expression="" break="">
+			<action application="lua" data="app.lua call_acl"/>
+		</condition>
+	</extension>
+</context>

+ 90 - 0
call_acl/root.php

@@ -0,0 +1,90 @@
+<?php
+/*
+	FusionPBX
+	Version: MPL 1.1
+
+	The contents of this file are subject to the Mozilla Public License Version
+	1.1 (the "License"); you may not use this file except in compliance with
+	the License. You may obtain a copy of the License at
+	http://www.mozilla.org/MPL/
+
+	Software distributed under the License is distributed on an "AS IS" basis,
+	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+	for the specific language governing rights and limitations under the
+	License.
+
+	The Original Code is FusionPBX
+
+	The Initial Developer of the Original Code is
+	Mark J Crane <[email protected]>
+	Portions created by the Initial Developer are Copyright (C) 2008-2012
+	the Initial Developer. All Rights Reserved.
+
+	Contributor(s):
+	Mark J Crane <[email protected]>
+*/
+
+// make sure the PATH_SEPARATOR is defined
+	umask(2);
+	if (!defined("PATH_SEPARATOR")) {
+		if (strpos($_ENV["OS"], "Win") !== false) {
+			define("PATH_SEPARATOR", ";");
+		} else {
+			define("PATH_SEPARATOR", ":");
+		}
+	}
+
+	if (!isset($output_format)) $output_format = (PHP_SAPI == 'cli') ? 'text' : 'html';
+
+	// make sure the document_root is set
+	$_SERVER["SCRIPT_FILENAME"] = str_replace("\\", '/', $_SERVER["SCRIPT_FILENAME"]);
+	if(PHP_SAPI == 'cli'){
+		chdir(pathinfo(realpath($_SERVER["PHP_SELF"]), PATHINFO_DIRNAME));
+		$script_full_path = str_replace("\\", '/', getcwd() . '/' . $_SERVER["SCRIPT_FILENAME"]);
+		$dirs = explode('/', pathinfo($script_full_path, PATHINFO_DIRNAME));
+		if (file_exists('/project_root.php')) {
+			$path = '/';
+		} else {
+			$i    = 1;
+			$path = '';
+			while ($i < count($dirs)) {
+				$path .= '/' . $dirs[$i];
+				if (file_exists($path. '/project_root.php')) {
+					break;
+				}
+				$i++;
+			}
+		}
+		$_SERVER["DOCUMENT_ROOT"] = $path;
+	}else{
+		$_SERVER["DOCUMENT_ROOT"]   = str_replace($_SERVER["PHP_SELF"], "", $_SERVER["SCRIPT_FILENAME"]);
+	}
+	$_SERVER["DOCUMENT_ROOT"]   = realpath($_SERVER["DOCUMENT_ROOT"]);
+// try to detect if a project path is being used
+	if (!defined('PROJECT_PATH')) {
+		if (is_dir($_SERVER["DOCUMENT_ROOT"]. '/fusionpbx')) {
+			define('PROJECT_PATH', '/fusionpbx');
+		} elseif (file_exists($_SERVER["DOCUMENT_ROOT"]. '/project_root.php')) {
+			define('PROJECT_PATH', '');
+		} else {
+			$dirs = explode('/', str_replace('\\', '/', pathinfo($_SERVER["PHP_SELF"], PATHINFO_DIRNAME)));
+			$i    = 1;
+			$path = $_SERVER["DOCUMENT_ROOT"];
+			while ($i < count($dirs)) {
+				$path .= '/' . $dirs[$i];
+				if (file_exists($path. '/project_root.php')) {
+					break;
+				}
+				$i++;
+			}
+			if(!file_exists($path. '/project_root.php')){
+				die("Failed to locate the Project Root by searching for project_root.php please contact support for assistance");
+			}
+			$project_path = str_replace($_SERVER["DOCUMENT_ROOT"], "", $path);
+			define('PROJECT_PATH', $project_path);
+		}
+		$_SERVER["PROJECT_ROOT"] = realpath($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH);
+		set_include_path(get_include_path() . PATH_SEPARATOR . $_SERVER["PROJECT_ROOT"]);
+	}
+
+?>