diff --git a/app/access_controls/access_control_export.php b/app/access_controls/access_control_export.php index 32d0ccf48e..093ceec1a3 100644 --- a/app/access_controls/access_control_export.php +++ b/app/access_controls/access_control_export.php @@ -54,6 +54,13 @@ } //define the functions + /** + * Converts an array to a CSV string. + * + * @param array &$array The input array. It should be a multidimensional array where the first level keys are column headers and the second level arrays are rows. + * + * @return string|null The CSV string representation of the input array, or null if the input array is empty. + */ function array2csv(array &$array) { if (count($array) == 0) { return null; @@ -69,7 +76,14 @@ } //send download headers - function download_send_headers($filename) { +/** + * Sends HTTP headers to force a file download. + * + * @param string $filename The name of the file to be downloaded, excluding the path. + * + * @return void + */ +function download_send_headers($filename) { // disable caching $now = gmdate("D, d M Y H:i:s"); header("Expires: Tue, 03 Jul 2001 06:00:00 GMT"); diff --git a/app/access_controls/access_control_import.php b/app/access_controls/access_control_import.php index 83c780e647..c6a603972a 100644 --- a/app/access_controls/access_control_import.php +++ b/app/access_controls/access_control_import.php @@ -40,6 +40,16 @@ //built in str_getcsv requires PHP 5.3 or higher, this function can be used to reproduce the functionality but requires PHP 5.1.0 or higher if (!function_exists('str_getcsv')) { + /** + * Parse a CSV string into an array. + * + * @param string $input The CSV data to parse. + * @param string $delimiter The field delimiter (default: ","). + * @param string $enclosure The field enclosure character (default: """). + * @param string $escape The escape character (default: "\""). + * + * @return array An array containing the parsed CSV fields. + */ function str_getcsv($input, $delimiter = ",", $enclosure = '"', $escape = "\\") { $fp = fopen("php://memory", 'r+'); fputs($fp, $input); @@ -212,6 +222,14 @@ } //get the parent table + /** + * Retrieve the parent table for a given table in a schema. + * + * @param array $schema The database schema to search in. + * @param string $table_name The name of the table for which to find the parent. + * + * @return mixed The name of the parent table, or NULL if not found. + */ function get_parent($schema,$table_name) { foreach ($schema as $row) { if ($row['table'] == $table_name) { diff --git a/app/access_controls/resources/classes/access_controls.php b/app/access_controls/resources/classes/access_controls.php index 5a74b24e10..d3102d608f 100644 --- a/app/access_controls/resources/classes/access_controls.php +++ b/app/access_controls/resources/classes/access_controls.php @@ -3,290 +3,315 @@ /** * access controls class */ - class access_controls { +class access_controls { - /** - * declare constant variables - */ - const app_name = 'access_controls'; - const app_uuid = '1416a250-f6e1-4edc-91a6-5c9b883638fd'; + /** + * declare constant variables + */ + const app_name = 'access_controls'; + const app_uuid = '1416a250-f6e1-4edc-91a6-5c9b883638fd'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * called when the object is created + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $config = $setting_array['config'] ?? config::load(); - $this->database = $setting_array['database'] ?? database::new(['config' => $config]); + //set objects + $config = $setting_array['config'] ?? config::load(); + $this->database = $setting_array['database'] ?? database::new(['config' => $config]); - //assign private variables - $this->list_page = 'access_controls.php'; - } + //assign private variables + $this->list_page = 'access_controls.php'; + } - /** - * delete records - */ - public function delete($records) { + /** + * Deletes one or multiple records from the access controls table. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { - //assign private variables - $this->permission_prefix = 'access_control_'; - $this->table = 'access_controls'; - $this->uuid_prefix = 'access_control_'; + //assign private variables + $this->permission_prefix = 'access_control_'; + $this->table = 'access_controls'; + $this->uuid_prefix = 'access_control_'; - if (permission_exists($this->permission_prefix . 'delete')) { + if (permission_exists($this->permission_prefix . 'delete')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'], 'negative'); - header('Location: ' . $this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //build the delete array - foreach ($records as $x => $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; - $array['access_control_nodes'][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('access_control_node_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('access_control_node_delete', 'temp'); - - //clear the cache - $cache = new cache; - $cache->delete("configuration:acl.conf"); - - //create the event socket connection - event_socket::async("reloadacl"); - - //set message - message::add($text['message-delete']); - } - unset($records); - } + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; } - } - public function delete_nodes($records) { + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { - //assign private variables - $this->permission_prefix = 'access_control_node_'; - $this->table = 'access_control_nodes'; - $this->uuid_prefix = 'access_control_node_'; - - if (permission_exists($this->permission_prefix . 'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate('/app/access_controls/access_control_nodes.php')) { - message::add($text['message-invalid_token'], 'negative'); - header('Location: ' . $this->list_page); - exit; + //build the delete array + foreach ($records as $x => $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array['access_control_nodes'][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + } } - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { - //build the delete array - foreach ($records as $x => $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; - } - } + //grant temporary permissions + $p = permissions::new(); + $p->add('access_control_node_delete', 'temp'); - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); - //execute delete - $this->database->delete($array); - unset($array); + //revoke temporary permissions + $p->delete('access_control_node_delete', 'temp'); - //clear the cache - $cache = new cache; - $cache->delete("configuration:acl.conf"); + //clear the cache + $cache = new cache; + $cache->delete("configuration:acl.conf"); - //create the event socket connection - event_socket::async("reloadacl"); + //create the event socket connection + event_socket::async("reloadacl"); - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * copy records - */ - public function copy($records) { - - //assign private variables - $this->permission_prefix = 'access_control_'; - $this->table = 'access_controls'; - $this->uuid_prefix = 'access_control_'; - - if (permission_exists($this->permission_prefix . 'add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'], 'negative'); - header('Location: ' . $this->list_page); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach ($records as $x => $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'" . $record['uuid'] . "'"; - } - } - - //create insert array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - - //primary table - $sql = "select * from v_" . $this->table . " "; - $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; - $rows = $this->database->select($sql, null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $y = 0; - foreach ($rows as $x => $row) { - $primary_uuid = uuid(); - - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $primary_uuid; - $array[$this->table][$x]['access_control_description'] = trim($row['access_control_description'] . ' (' . $text['label-copy'] . ')'); - - //nodes sub table - $sql_2 = "select * from v_access_control_nodes where access_control_uuid = :access_control_uuid"; - $parameters_2['access_control_uuid'] = $row['access_control_uuid']; - $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); - if (is_array($rows_2) && @sizeof($rows_2) != 0) { - foreach ($rows_2 as $row_2) { - - //copy data - $array['access_control_nodes'][$y] = $row_2; - - //overwrite - $array['access_control_nodes'][$y]['access_control_node_uuid'] = uuid(); - $array['access_control_nodes'][$y]['access_control_uuid'] = $primary_uuid; - - //increment - $y++; - } - } - unset($sql_2, $parameters_2, $rows_2, $row_2); - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('access_control_node_add', 'temp'); - - //save the array - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('access_control_node_add', 'temp'); - - //clear the cache - $cache = new cache; - $cache->delete("configuration:acl.conf"); - - //create the event socket connection - event_socket::async("reloadacl"); - - //set message - message::add($text['message-copy']); - } - unset($records); + //set message + message::add($text['message-delete']); } + unset($records); } } } + + /** + * Deletes one or more access control nodes. + * + * @param array $records Array of records to delete, where each record is an associative array containing the + * 'uuid' and 'checked' keys. + * + * @return void + */ + public function delete_nodes($records) { + + //assign private variables + $this->permission_prefix = 'access_control_node_'; + $this->table = 'access_control_nodes'; + $this->uuid_prefix = 'access_control_node_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate('/app/access_controls/access_control_nodes.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //execute delete + $this->database->delete($array); + unset($array); + + //clear the cache + $cache = new cache; + $cache->delete("configuration:acl.conf"); + + //create the event socket connection + event_socket::async("reloadacl"); + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Copy access controls and their nodes. + * + * @param array $records An array of records to copy. Each record should contain a 'checked' key with value 'true' + * and a 'uuid' key with the UUID of the access control or node to copy. + * + * @return void + */ + public function copy($records) { + + //assign private variables + $this->permission_prefix = 'access_control_'; + $this->table = 'access_controls'; + $this->uuid_prefix = 'access_control_'; + + if (permission_exists($this->permission_prefix . 'add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $x => $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create insert array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + + //primary table + $sql = "select * from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $y = 0; + foreach ($rows as $x => $row) { + $primary_uuid = uuid(); + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; + } + } + + //copy data + $array[$this->table][$x] = $row; + + //overwrite + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $primary_uuid; + $array[$this->table][$x]['access_control_description'] = trim($row['access_control_description'] . ' (' . $text['label-copy'] . ')'); + + //nodes sub table + $sql_2 = "select * from v_access_control_nodes where access_control_uuid = :access_control_uuid"; + $parameters_2['access_control_uuid'] = $row['access_control_uuid']; + $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); + if (is_array($rows_2) && @sizeof($rows_2) != 0) { + foreach ($rows_2 as $row_2) { + + //copy data + $array['access_control_nodes'][$y] = $row_2; + + //overwrite + $array['access_control_nodes'][$y]['access_control_node_uuid'] = uuid(); + $array['access_control_nodes'][$y]['access_control_uuid'] = $primary_uuid; + + //increment + $y++; + } + } + unset($sql_2, $parameters_2, $rows_2, $row_2); + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('access_control_node_add', 'temp'); + + //save the array + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('access_control_node_add', 'temp'); + + //clear the cache + $cache = new cache; + $cache->delete("configuration:acl.conf"); + + //create the event socket connection + event_socket::async("reloadacl"); + + //set message + message::add($text['message-copy']); + } + unset($records); + } + } + } +} diff --git a/app/active_calls/resources/classes/caller_context_filter.php b/app/active_calls/resources/classes/caller_context_filter.php index 1a7af3f0cf..85b7a0eb8c 100644 --- a/app/active_calls/resources/classes/caller_context_filter.php +++ b/app/active_calls/resources/classes/caller_context_filter.php @@ -35,12 +35,29 @@ class caller_context_filter implements filter { private $domains; + /** + * Initializes the object with an array of domain names. + * + * @param array $domain_names Array of domain names to initialize the object with. + * + * @return void + */ public function __construct(array $domain_names) { foreach ($domain_names as $name) { $this->domains[$name] = true; } } + /** + * Invokes this method as a callable. + * + * @param string $key The event key, which is used for validation and filtering. + * @param mixed $value The value associated with the event key, used to determine + * whether the filter chain should drop the payload. + * + * @return bool|null Returns true if the key is not 'caller_context' or the value exists in the domains, + * otherwise returns null to drop the payload. + */ public function __invoke(string $key, $value): ?bool { // return true when not on the event key caller_context to validate if ($key !== 'caller_context') { diff --git a/app/active_calls/resources/classes/event_filter.php b/app/active_calls/resources/classes/event_filter.php index 6a30aa6dbb..5f9233151a 100644 --- a/app/active_calls/resources/classes/event_filter.php +++ b/app/active_calls/resources/classes/event_filter.php @@ -35,10 +35,28 @@ class event_filter implements filter { private $event_names; + /** + * Initializes the object with the event names to filter on. + * + * @param array $event_names Array of event names to initialize the object with + */ public function __construct(array $event_names) { $this->add_event_names($event_names); } + /** + * Invokes this method to filter events. + * + * @param string $key The key name that will be used for filtering, currently only + * supports the "event_name" key. + * @param mixed $value The value associated with the provided key. + * + * @return bool|null Returns true if the invocation is valid and the event name + * filter has not been applied yet. If the invocation has an "event_name" + * key and its corresponding value, this method will return a boolean + * indicating whether the event name already exists in the list of allowed + * names or not. Otherwise returns null. + */ public function __invoke(string $key, $value): ?bool { if ($key !== 'event_name') { return true; @@ -69,17 +87,20 @@ class event_filter implements filter { } } + /** + * Checks if an event with the given name is present in the filters. + * + * @param string $name The name of the event to check for. + * + * @return bool|null True if the event is found, otherwise null. Returns null + * when the event is not allowed due to permissions constraints. + */ public function has_event_name(string $name): ?bool { - if (isset($this->event_names[$name])) + if (isset($this->event_names[$name])) { return true; - // - // If the event name is not allowed by the permissions given in - // this object, then the entire event must be dropped. I could - // not figure out a better way to do this except to throw an - // exception so that the caller can drop the message. - // - // TODO: Find another way not so expensive to reject the payload - // + } + + //reject the payload return null; } } diff --git a/app/active_calls/resources/classes/event_key_filter.php b/app/active_calls/resources/classes/event_key_filter.php index a4c6d4f1c9..a37cb6c77e 100644 --- a/app/active_calls/resources/classes/event_key_filter.php +++ b/app/active_calls/resources/classes/event_key_filter.php @@ -34,10 +34,23 @@ class event_key_filter implements filter { private $filters; + /** + * Initializes a new instance of the object with specified filters. + * + * @param array $filters Optional array of initial filters to be applied. + */ public function __construct(array $filters = []) { $this->add_filters($filters); } + /** + * Invokes a filter check with the given key and value. + * + * @param string $key The key of the filter to check + * @param mixed $value The value associated with the filter key + * + * @return bool|null True if the filter exists, false otherwise + */ public function __invoke(string $key, $value): ?bool { return $this->has_filter_key($key); } @@ -84,6 +97,13 @@ class event_key_filter implements filter { } } + /** + * Checks if a filter key exists. + * + * @param string $key The filter key to check for existence. + * + * @return bool True if the filter key exists, false otherwise. + */ public function has_filter_key(string $key): bool { return isset($this->filters[$key]); } diff --git a/app/active_calls/resources/classes/event_message.php b/app/active_calls/resources/classes/event_message.php index e38261f805..fcd67a30d4 100644 --- a/app/active_calls/resources/classes/event_message.php +++ b/app/active_calls/resources/classes/event_message.php @@ -46,6 +46,11 @@ class event_message implements filterable_payload { * @var array */ private $event; + + /** + * Body of the SIP MESSAGE used in SMS + * @var string + */ private $body; /** @@ -102,6 +107,11 @@ class event_message implements filterable_payload { return $this->event[$name] ?? ''; } + /** + * Return an array representation of this object. + * + * @return array + */ public function __toArray(): array { $array = []; foreach ($this->event as $key => $value) { @@ -110,10 +120,22 @@ class event_message implements filterable_payload { return $array; } + /** + * Convert the current object into an array representation. + * + * @return array + */ public function to_array(): array { return $this->__toArray(); } + /** + * Apply a filter to the event collection. + * + * @param filter $filter The filter function to apply + * + * @return self This object for method chaining + */ public function apply_filter(filter $filter) { foreach ($this->event as $key => $value) { $result = ($filter)($key, $value); @@ -126,6 +148,16 @@ class event_message implements filterable_payload { return $this; } + /** + * Parse an active calls JSON string and return a list of event messages. + * + * This method expects a JSON string where each row represents an active call, and returns + * a list of event_message objects populated with the relevant details for each call. + * + * @param string $json_string The JSON string to parse. + * + * @return array A list of event_message objects. + */ public static function parse_active_calls($json_string): array { $calls = []; $json_array = json_decode($json_string, true); @@ -181,6 +213,15 @@ class event_message implements filterable_payload { return null; } + /** + * Creates a new instance from a switch event. + * + * @param array|string $raw_event The raw event data. + * @param filter|null $filter Optional filter to be applied on the created object. + * @param int $flags Flags controlling the creation process (see EVENT_SWAP_API and EVENT_USE_SUBCLASS). + * + * @return self + */ public static function create_from_switch_event($raw_event, filter $filter = null, $flags = 3): self { // Set the options from the flags passed @@ -264,6 +305,14 @@ class event_message implements filterable_payload { return $this->body; } + /** + * Convert the event object to an array representation. + * + * This method iterates over the event properties and includes them in the returned array. + * If the body is not null, it will be included as a separate key-value pair in the resulting array. + * + * @return array + */ public function event_to_array(): array { $array = []; foreach ($this->event as $key => $value) { @@ -275,15 +324,39 @@ class event_message implements filterable_payload { return $array; } + /** + * Return an iterator for this object. + * + * This method allows iteration over the event data as a Traversable object. + * + * @return \Traversable + */ public function getIterator(): \Traversable { yield from $this->event_to_array(); } + /** + * Check if a specific event key exists in this object. + * + * @param mixed $offset The key of the event to check for existence + * + * @return bool True if the event key exists, false otherwise + */ public function offsetExists(mixed $offset): bool { self::sanitize_event_key($offset); return isset($this->event[$offset]); } + /** + * Return the value associated with the given key from this event object. + * + * If the key is 'body', returns the event body. Otherwise, returns the value + * stored in the 'event' array for the given key. + * + * @param mixed $offset The key to retrieve the value for. + * + * @return mixed The value associated with the given key. + */ public function offsetGet(mixed $offset): mixed { self::sanitize_event_key($offset); if ($offset === self::BODY_ARRAY_KEY) { @@ -292,6 +365,16 @@ class event_message implements filterable_payload { return $this->event[$offset]; } + /** + * Set the value for a given offset in this object. + * + * @param mixed $offset The key or index to set the value for. If it is + * {@link self::BODY_ARRAY_KEY}, this method will replace the + * entire body of the event with the provided value. + * @param mixed $value The new value to be associated with the offset. + * + * @return void + */ public function offsetSet(mixed $offset, mixed $value): void { self::sanitize_event_key($offset); if ($offset === self::BODY_ARRAY_KEY) { @@ -301,6 +384,15 @@ class event_message implements filterable_payload { } } + /** + * Unsets a property from the event array. + * + * This method first sanitizes the provided offset using the sanitize_event_key method to prevent potential security vulnerabilities. + * If the sanitized offset is equal to the BODY_ARRAY_KEY, it sets the body property of this object to null. + * Otherwise, it removes the specified key from the event array. + * + * @param mixed $offset The index or key to be unset from the event array. + */ public function offsetUnset(mixed $offset): void { self::sanitize_event_key($offset); if ($offset === self::BODY_ARRAY_KEY) { diff --git a/app/active_calls/resources/classes/extension_filter.php b/app/active_calls/resources/classes/extension_filter.php index d56f727b75..fcbc7b198e 100644 --- a/app/active_calls/resources/classes/extension_filter.php +++ b/app/active_calls/resources/classes/extension_filter.php @@ -35,6 +35,11 @@ class extension_filter { private $extensions; + /** + * Initializes the class with an array of extensions for fast lookup. + * + * @param array $extensions An optional array of extension configurations. Defaults to []. + */ public function __construct(array $extensions = []) { //organize the extensions in a way we can use isset for fast lookup foreach ($extensions as $extension) { @@ -43,6 +48,14 @@ class extension_filter { } } + /** + * Invokes this instance with a key-value pair for fast lookup. + * + * @param string $key The presence ID key to look up in the extensions array. + * @param mixed $value The value associated with the key, which is used as an index in the extensions array. + * + * @return bool|null True if no match was found or the key is not 'channel_presence_id', null otherwise when dropping a message. + */ public function __invoke(string $key, $value): ?bool { //only match on channel_presence_id key if ($key === 'channel_presence_id' && !isset($this->extensions[$value])) { diff --git a/app/azure/resources/classes/azure.php b/app/azure/resources/classes/azure.php index 8a934120fa..112780920a 100644 --- a/app/azure/resources/classes/azure.php +++ b/app/azure/resources/classes/azure.php @@ -1,209 +1,256 @@ - array ( - 'lang' => 'en-US', - 'gender' => 'Female', - 'name' => 'Microsoft Server Speech Text to Speech Voice (en-US, ZiraRUS)' - ), - 'English-Jessa' => - array ( - 'lang' => 'en-US', - 'gender' => 'Female', - 'name' => 'Microsoft Server Speech Text to Speech Voice (en-US, JessaRUS)' - ), - 'English-Benjamin' => - array ( - 'lang' => 'en-US', - 'gender' => 'Male', - 'name' => 'Microsoft Server Speech Text to Speech Voice (en-US, BenjaminRUS)' - ), - 'British-Susan' => - array ( - 'lang' => 'en-GB', - 'gender' => 'Female', - 'name' => 'Microsoft Server Speech Text to Speech Voice (en-GB, Susan, Apollo)' - ), - 'British-Hazel' => - array ( - 'lang' => 'en-GB', - 'gender' => 'Female', - 'name' => 'Microsoft Server Speech Text to Speech Voice (en-GB, HazelRUS)' - ), - 'British-George' => - array ( - 'lang' => 'en-GB', - 'gender' => 'Male', - 'name' => 'Microsoft Server Speech Text to Speech Voice (en-GB, George, Apollo)' - ), - 'Australian-Catherine' => - array ( - 'lang' => 'en-AU', - 'gender' => 'Female', - 'name' => 'Microsoft Server Speech Text to Speech Voice (en-AU, Catherine)' - ), - 'Spanish-Helena' => - array ( - 'lang' => 'es-ES', - 'gender' => 'Female', - 'name' => 'Microsoft Server Speech Text to Speech Voice (es-ES, HelenaRUS)' - ), - 'Spanish-Laura' => - array ( - 'lang' => 'es-ES', - 'gender' => 'Female', - 'name' => 'Microsoft Server Speech Text to Speech Voice (es-ES, Laura, Apollo)' - ), - 'Spanish-Pablo' => - array ( - 'lang' => 'es-ES', - 'gender' => 'Male', - 'name' => 'Microsoft Server Speech Text to Speech Voice (es-ES, Pablo, Apollo)' - ), - 'French-Julie' => - array ( - 'lang' => 'fr-FR', - 'gender' => 'Female', - 'name' => 'Microsoft Server Speech Text to Speech Voice (fr-FR, Julie, Apollo)' - ), - 'French-Hortense' => - array ( - 'lang' => 'fr-FR', - 'gender' => 'Female', - 'name' => 'Microsoft Server Speech Text to Speech Voice (fr-FR, HortenseRUS)' - ), - 'French-Paul' => - array ( - 'lang' => 'fr-FR', - 'gender' => 'Male', - 'name' => 'Microsoft Server Speech Text to Speech Voice (fr-FR, Paul, Apollo)' - ), - 'German-Hedda' => - array ( - 'lang' => 'de-DE', - 'gender' => 'Female', - 'name' => 'Microsoft Server Speech Text to Speech Voice (de-DE, Hedda)' - ), - 'Russian-Irina' => - array ( - 'lang' => 'ru-RU', - 'gender' => 'Female', - 'name' => 'Microsoft Server Speech Text to Speech Voice (ru-RU, Irina, Apollo)' - ), - 'Russian-Pavel' => - array ( - 'lang' => 'ru-RU', - 'gender' => 'Male', - 'name' => 'Microsoft Server Speech Text to Speech Voice (ru-RU, Pavel, Apollo)' - ), - 'Chinese-Huihui' => - array ( - 'lang' => 'zh-CN', - 'gender' => 'Female', - 'name' => 'Microsoft Server Speech Text to Speech Voice (zh-CN, HuihuiRUS)' - ), - 'Chinese-Yaoyao' => - array ( - 'lang' => 'zh-CN', - 'gender' => 'Female', - 'name' => 'Microsoft Server Speech Text to Speech Voice (zh-CN, Yaoyao, Apollo)' - ), - 'Chinese-Kangkang' => - array ( - 'lang' => 'zh-CN', - 'gender' => 'Male', - 'name' => 'Microsoft Server Speech Text to Speech Voice (zh-CN, Kangkang, Apollo)' - ) - ); + /** + * Array of available speech formats. + * + * This array contains a list of voice names and their corresponding languages + * and genders. The keys are the voice names, and the values are arrays containing + * the language code and gender. + * + * @var array + */ + public static $formats = [ + 'English-Zira' => + [ + 'lang' => 'en-US', + 'gender' => 'Female', + 'name' => 'Microsoft Server Speech Text to Speech Voice (en-US, ZiraRUS)', + ], + 'English-Jessa' => + [ + 'lang' => 'en-US', + 'gender' => 'Female', + 'name' => 'Microsoft Server Speech Text to Speech Voice (en-US, JessaRUS)', + ], + 'English-Benjamin' => + [ + 'lang' => 'en-US', + 'gender' => 'Male', + 'name' => 'Microsoft Server Speech Text to Speech Voice (en-US, BenjaminRUS)', + ], + 'British-Susan' => + [ + 'lang' => 'en-GB', + 'gender' => 'Female', + 'name' => 'Microsoft Server Speech Text to Speech Voice (en-GB, Susan, Apollo)', + ], + 'British-Hazel' => + [ + 'lang' => 'en-GB', + 'gender' => 'Female', + 'name' => 'Microsoft Server Speech Text to Speech Voice (en-GB, HazelRUS)', + ], + 'British-George' => + [ + 'lang' => 'en-GB', + 'gender' => 'Male', + 'name' => 'Microsoft Server Speech Text to Speech Voice (en-GB, George, Apollo)', + ], + 'Australian-Catherine' => + [ + 'lang' => 'en-AU', + 'gender' => 'Female', + 'name' => 'Microsoft Server Speech Text to Speech Voice (en-AU, Catherine)', + ], + 'Spanish-Helena' => + [ + 'lang' => 'es-ES', + 'gender' => 'Female', + 'name' => 'Microsoft Server Speech Text to Speech Voice (es-ES, HelenaRUS)', + ], + 'Spanish-Laura' => + [ + 'lang' => 'es-ES', + 'gender' => 'Female', + 'name' => 'Microsoft Server Speech Text to Speech Voice (es-ES, Laura, Apollo)', + ], + 'Spanish-Pablo' => + [ + 'lang' => 'es-ES', + 'gender' => 'Male', + 'name' => 'Microsoft Server Speech Text to Speech Voice (es-ES, Pablo, Apollo)', + ], + 'French-Julie' => + [ + 'lang' => 'fr-FR', + 'gender' => 'Female', + 'name' => 'Microsoft Server Speech Text to Speech Voice (fr-FR, Julie, Apollo)', + ], + 'French-Hortense' => + [ + 'lang' => 'fr-FR', + 'gender' => 'Female', + 'name' => 'Microsoft Server Speech Text to Speech Voice (fr-FR, HortenseRUS)', + ], + 'French-Paul' => + [ + 'lang' => 'fr-FR', + 'gender' => 'Male', + 'name' => 'Microsoft Server Speech Text to Speech Voice (fr-FR, Paul, Apollo)', + ], + 'German-Hedda' => + [ + 'lang' => 'de-DE', + 'gender' => 'Female', + 'name' => 'Microsoft Server Speech Text to Speech Voice (de-DE, Hedda)', + ], + 'Russian-Irina' => + [ + 'lang' => 'ru-RU', + 'gender' => 'Female', + 'name' => 'Microsoft Server Speech Text to Speech Voice (ru-RU, Irina, Apollo)', + ], + 'Russian-Pavel' => + [ + 'lang' => 'ru-RU', + 'gender' => 'Male', + 'name' => 'Microsoft Server Speech Text to Speech Voice (ru-RU, Pavel, Apollo)', + ], + 'Chinese-Huihui' => + [ + 'lang' => 'zh-CN', + 'gender' => 'Female', + 'name' => 'Microsoft Server Speech Text to Speech Voice (zh-CN, HuihuiRUS)', + ], + 'Chinese-Yaoyao' => + [ + 'lang' => 'zh-CN', + 'gender' => 'Female', + 'name' => 'Microsoft Server Speech Text to Speech Voice (zh-CN, Yaoyao, Apollo)', + ], + 'Chinese-Kangkang' => + [ + 'lang' => 'zh-CN', + 'gender' => 'Male', + 'name' => 'Microsoft Server Speech Text to Speech Voice (zh-CN, Kangkang, Apollo)', + ], + ]; + /** + * Initializes the object with provided setting array. + * + * @param array $setting_array An optional array of setting values. Defaults to an empty array. + */ public function __construct(array $setting_array = []) { //set domain and user UUIDs $domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + $user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; //set objects - $config = $setting_array['config'] ?? config::load(); + $config = $setting_array['config'] ?? config::load(); $this->database = $setting_array['database'] ?? database::new(['config' => $config]); $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $domain_uuid, 'user_uuid' => $user_uuid]); } - private static function getTokenUrl(){ - return "https://api.cognitive.microsoft.com/sts/v1.0/issueToken"; - } + /** + * Returns the URL for obtaining a token from Microsoft Cognitive Services. + * + * @return string The URL for issuing a token + */ + private static function getTokenUrl() { + return "https://api.cognitive.microsoft.com/sts/v1.0/issueToken"; + } - private static function getApiUrl(){ - return "https://speech.platform.bing.com/synthesize"; - } + /** + * Returns the URL for interacting with Microsoft Bing Speech API. + * + * @return string The URL for making requests to the Bing Speech API + */ + private static function getApiUrl() { + return "https://speech.platform.bing.com/synthesize"; + } - private static function getSubscriptionKey(settings $settings){ - return $settings->get('azure', 'key'); - } + /** + * Returns the subscription key from Azure settings. + * + * @param settings $settings The settings object containing Azure configuration + * + * @return string The subscription key for Azure services + */ + private static function getSubscriptionKey(settings $settings) { + return $settings->get('azure', 'key'); + } - private static function _getToken(settings $settings){ - $url = self::getTokenUrl(); - $subscriptionKey = self::getSubscriptionKey($settings); + /** + * Obtains a token from Microsoft Cognitive Services. + * + * @param settings $settings Settings object containing subscription key and other parameters. + * + * @return string The response from the server, which is expected to be an XML token. + */ + private static function _getToken(settings $settings) { + $url = self::getTokenUrl(); + $subscriptionKey = self::getSubscriptionKey($settings); - $headers = array(); - $headers[] = 'Ocp-Apim-Subscription-Key: '. $subscriptionKey; - $headers[] = 'Content-Length: 0'; + $headers = []; + $headers[] = 'Ocp-Apim-Subscription-Key: ' . $subscriptionKey; + $headers[] = 'Content-Length: 0'; - $ch = curl_init(); - curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers); - curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 ); - curl_setopt ( $ch, CURLOPT_URL, $url ); - //curl_setopt($ch, CURLOPT_SSLVERSION, 1); - curl_setopt ( $ch, CURLOPT_CONNECTTIMEOUT, 60 ); - curl_setopt ( $ch, CURLOPT_TIMEOUT, 300 ); - curl_setopt ( $ch, CURLOPT_VERBOSE, false); - curl_setopt($ch, CURLOPT_POST, true); - //curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_post_string); + $ch = curl_init(); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_URL, $url); + //curl_setopt($ch, CURLOPT_SSLVERSION, 1); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60); + curl_setopt($ch, CURLOPT_TIMEOUT, 300); + curl_setopt($ch, CURLOPT_VERBOSE, false); + curl_setopt($ch, CURLOPT_POST, true); + //curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_post_string); - $response = curl_exec($ch); + $response = curl_exec($ch); - curl_close($ch); - return $response; - } + curl_close($ch); + return $response; + } - public static function synthesize(settings $settings, $data, $format_key){ + /** + * Synthesizes the given data into a WAV audio file using Microsoft Cognitive Services. + * + * @param object $settings Settings for the API call + * @param string $data The text to be synthesized + * @param string $format_key The key of the format in self::$formats + * + * @return string The path to the generated WAV file + */ + public static function synthesize(settings $settings, $data, $format_key) { - $lang = self::$formats[$format_key]['lang']; - $gender = self::$formats[$format_key]['gender']; - $name = self::$formats[$format_key]['name']; - $token = self::_getToken($settings); + $lang = self::$formats[$format_key]['lang']; + $gender = self::$formats[$format_key]['gender']; + $name = self::$formats[$format_key]['name']; + $token = self::_getToken($settings); - $url = self::getApiUrl(); + $url = self::getApiUrl(); - $headers = array(); - $headers[] = 'Authorization: Bearer '. $token; - $headers[] = 'Content-Type: application/ssml+xml'; - $headers[] = 'X-Microsoft-OutputFormat: riff-16khz-16bit-mono-pcm'; - $headers[] = 'User-Agent: TTS'; + $headers = []; + $headers[] = 'Authorization: Bearer ' . $token; + $headers[] = 'Content-Type: application/ssml+xml'; + $headers[] = 'X-Microsoft-OutputFormat: riff-16khz-16bit-mono-pcm'; + $headers[] = 'User-Agent: TTS'; - $xml_post_string = " - "; - $xml_post_string .= $data; - $xml_post_string .= " + $xml_post_string = " + "; + $xml_post_string .= $data; + $xml_post_string .= " "; - $ch = curl_init(); - curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers); - curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 ); - curl_setopt ( $ch, CURLOPT_URL, $url ); - //curl_setopt($ch, CURLOPT_SSLVERSION, 1); - curl_setopt ( $ch, CURLOPT_CONNECTTIMEOUT, 60 ); - curl_setopt ( $ch, CURLOPT_TIMEOUT, 300 ); - curl_setopt ( $ch, CURLOPT_VERBOSE, true); - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_post_string); + $ch = curl_init(); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_URL, $url); + //curl_setopt($ch, CURLOPT_SSLVERSION, 1); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60); + curl_setopt($ch, CURLOPT_TIMEOUT, 300); + curl_setopt($ch, CURLOPT_VERBOSE, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_post_string); - $response = curl_exec($ch); - $filename = "tts_".time().".wav"; - file_put_contents("/var/www/html/fusionpbx/app/voiplyrecording/tts_record/".$filename, $response); + $response = curl_exec($ch); + $filename = "tts_" . time() . ".wav"; + file_put_contents("/var/www/html/fusionpbx/app/voiplyrecording/tts_record/" . $filename, $response); - curl_close($ch); - return $filename; - } + curl_close($ch); + return $filename; + } } diff --git a/app/basic_operator_panel/resources/classes/basic_operator_panel.php b/app/basic_operator_panel/resources/classes/basic_operator_panel.php index e3c0fe5430..04f1b6c15b 100644 --- a/app/basic_operator_panel/resources/classes/basic_operator_panel.php +++ b/app/basic_operator_panel/resources/classes/basic_operator_panel.php @@ -66,7 +66,9 @@ private $domain_name; /** - * Called when the object is created + * Initializes the object with domain and user UUIDs, domain name, and database objects. + * + * @param array $setting_array An optional array containing settings for this object. Defaults to an empty array. */ public function __construct(array $setting_array = []) { //set domain and user UUIDs @@ -83,7 +85,10 @@ } /** - * Get the call activity + * Handles the call activity by retrieving extensions and their user status, + * sending a command to retrieve active calls, and building a response array. + * + * @return mixed The response array containing extension details and active call information. */ public function call_activity() { diff --git a/app/bridges/resources/classes/bridges.php b/app/bridges/resources/classes/bridges.php index 8af148f485..ef0e306a48 100644 --- a/app/bridges/resources/classes/bridges.php +++ b/app/bridges/resources/classes/bridges.php @@ -68,7 +68,9 @@ private $toggle_values; /** - * called when the object is created + * Initializes the object with settings and default values. + * + * @param array $setting_array Associative array of setting keys to their respective values (optional) */ public function __construct(array $setting_array = []) { //set domain and user UUIDs @@ -92,7 +94,13 @@ } /** - * delete records + * Deletes one or multiple records from the access controls table. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. */ public function delete($records) { if (permission_exists($this->permission_prefix.'delete')) { @@ -141,7 +149,13 @@ } /** - * toggle records + * Toggles the state of the specified records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. */ public function toggle($records) { if (permission_exists($this->permission_prefix.'edit')) { @@ -212,7 +226,12 @@ } /** - * copy records + * Copies one or more records + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. */ public function copy($records) { if (permission_exists($this->permission_prefix.'add')) { diff --git a/app/call_block/call_block_edit.php b/app/call_block/call_block_edit.php index aa08118048..897c5b68d4 100644 --- a/app/call_block/call_block_edit.php +++ b/app/call_block/call_block_edit.php @@ -456,6 +456,17 @@ if (permission_exists('call_block_all') || permission_exists('call_block_ring_gr echo " ".$text['label-action']."\n"; echo "\n"; echo "\n"; + /** + * Select a call block action. + * + * This function generates an HTML select element for selecting a call block + * action. It includes options for rejecting, busy, holding, and other actions, + * as well as options for extensions, IVRs, ring groups, and voicemail. + * + * @param bool $label Whether to include the label option or not. + * + * @return void The function does not return any value. + */ function call_block_action_select($label = false) { global $select_margin, $text, $call_block_app, $call_block_data, $extensions, $ivrs, $voicemails, $ring_groups; echo "\n"; diff --git a/app/call_forward/resources/classes/call_forward.php b/app/call_forward/resources/classes/call_forward.php index be3ca17664..2ee41e2ff2 100644 --- a/app/call_forward/resources/classes/call_forward.php +++ b/app/call_forward/resources/classes/call_forward.php @@ -1,311 +1,334 @@ - Copyright (C) 2010 - 2025 - All Rights Reserved. + The Initial Developer of the Original Code is + Mark J Crane + Copyright (C) 2010 - 2025 + All Rights Reserved. - Contributor(s): - Mark J Crane - Luis Daniel Lucio Quiroz - Errol Samuels + Contributor(s): + Mark J Crane + Luis Daniel Lucio Quiroz + Errol Samuels - */ + */ //define the call_forward class - class call_forward { +class call_forward { - /** - * declare constant variables - */ - const app_name = 'call_forward'; - const app_uuid = '19806921-e8ed-dcff-b325-dd3e5da4959d'; + /** + * declare constant variables + */ + const app_name = 'call_forward'; + const app_uuid = '19806921-e8ed-dcff-b325-dd3e5da4959d'; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_uuid; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_name; - /** - * declare public variables - */ - public $debug; - public $extension_uuid; - public $forward_all_destination; - public $forward_all_enabled; - public $accountcode; - public $outbound_caller_id_name; - public $outbound_caller_id_number; + /** + * declare public variables + */ + public $debug; + public $extension_uuid; + public $forward_all_destination; + public $forward_all_enabled; + public $accountcode; + public $outbound_caller_id_name; + public $outbound_caller_id_number; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * declare private variables - */ - private $extension; - private $number_alias; - private $toll_allow; - private $toggle_field; - private $toggle_values; + /** + * declare private variables + */ + private $extension; + private $number_alias; + private $toll_allow; + private $toggle_field; + private $toggle_values; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); - - //assign private variables - $this->toggle_field = 'forward_all_enabled'; - $this->toggle_values = ['true', 'false']; - } - - public function set() { - - //determine whether to update the dial string - $sql = "select * from v_extensions "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and extension_uuid = :extension_uuid "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['extension_uuid'] = $this->extension_uuid; - $row = $this->database->select($sql, $parameters, 'row'); - if (is_array($row) && @sizeof($row) != 0) { - $this->extension = $row["extension"]; - $this->number_alias = $row["number_alias"]; - $this->accountcode = $row["accountcode"]; - $this->toll_allow = $row["toll_allow"]; - $this->outbound_caller_id_name = $row["outbound_caller_id_name"]; - $this->outbound_caller_id_number = $row["outbound_caller_id_number"]; - } - unset($sql, $parameters, $row); - - //build extension update array - $array['extensions'][0]['extension_uuid'] = $this->extension_uuid; - $array['extensions'][0]['forward_all_destination'] = strlen($this->forward_all_destination) != 0 ? $this->forward_all_destination : null; - if (empty($this->forward_all_destination) || $this->forward_all_enabled == "false") { - $array['extensions'][0]['forward_all_enabled'] = 'false'; - } else { - $array['extensions'][0]['forward_all_enabled'] = 'true'; - } - - //grant temporary permissions - $p = permissions::new(); - $p->add('extension_add', 'temp'); - - //execute update - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('extension_add', 'temp'); - - //delete extension from the cache - $cache = new cache; - $cache->delete(gethostname().":directory:" . $this->extension . "@" . $this->domain_name); - if (!empty($this->number_alias)) { - $cache->delete(gethostname().":directory:" . $this->number_alias . "@" . $this->domain_name); - } - } - - /** - * Toggle an array of call_forward records - * @param array $records array of records to toggle - */ - public function toggle(array $records) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'], 'negative'); - header('Location: calls.php'); - exit; - } - - //validate there are records to process - if (count($records) < 1) return; - - //check we have permission for this action - if (permission_exists('call_forward')) { - - // initialize an empty array - $uuids = []; - $extensions = []; - - //get current toggle state - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'" . $record['uuid'] . "'"; - } - } - - //toggle the checked records - if (count($uuids) > 0) { - $sql = "select extension_uuid as uuid, extension, number_alias, "; - $sql .= "call_timeout, do_not_disturb, "; - $sql .= "forward_all_enabled, forward_all_destination, "; - $sql .= "forward_busy_enabled, forward_busy_destination, "; - $sql .= "forward_no_answer_enabled, forward_no_answer_destination, "; - $sql .= $this->toggle_field . " as toggle, follow_me_uuid "; - $sql .= "from v_extensions "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and extension_uuid in (" . implode(', ', $uuids) . ") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $extensions[$row['uuid']]['extension'] = $row['extension']; - $extensions[$row['uuid']]['number_alias'] = $row['number_alias']; - $extensions[$row['uuid']]['call_timeout'] = $row['call_timeout']; - $extensions[$row['uuid']]['do_not_disturb'] = $row['do_not_disturb']; - $extensions[$row['uuid']]['forward_all_enabled'] = $row['forward_all_enabled']; - $extensions[$row['uuid']]['forward_all_destination'] = $row['forward_all_destination']; - $extensions[$row['uuid']]['forward_busy_enabled'] = $row['forward_busy_enabled']; - $extensions[$row['uuid']]['forward_busy_destination'] = $row['forward_busy_destination']; - $extensions[$row['uuid']]['forward_no_answer_enabled'] = $row['forward_no_answer_enabled']; - $extensions[$row['uuid']]['forward_no_answer_destination'] = $row['forward_no_answer_destination']; - $extensions[$row['uuid']]['state'] = $row['toggle']; - $extensions[$row['uuid']]['follow_me_uuid'] = $row['follow_me_uuid']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach ($extensions as $uuid => $extension) { - - //check destination - $destination_exists = $extension['forward_all_destination'] != '' ? true : false; - - //determine new state - $new_state = $extension['state'] == $this->toggle_values[1] && $destination_exists ? $this->toggle_values[0] : $this->toggle_values[1]; - - //toggle feature - if ($new_state != $extension['state']) { - $array['extensions'][$x]['extension_uuid'] = $uuid; - $array['extensions'][$x][$this->toggle_field] = $new_state; - } - - //disable other features - if ($new_state == $this->toggle_values[0]) { //true - $array['extensions'][$x]['do_not_disturb'] = $this->toggle_values[1]; //false - $array['extensions'][$x]['follow_me_enabled'] = $this->toggle_values[1]; //false - if (is_uuid($extension['follow_me_uuid'])) { - $array['follow_me'][$x]['follow_me_uuid'] = $extension['follow_me_uuid']; - $array['follow_me'][$x]['follow_me_enabled'] = $this->toggle_values[1]; //false - } - } - - //increment counter - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('extension_edit', 'temp'); - - //save the array - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('extension_edit', 'temp'); - - //send feature event notify to the phone - if ($this->settings->get('device', 'feature_sync', false)) { - foreach ($extensions as $uuid => $extension) { - $feature_event_notify = new feature_event_notify; - $feature_event_notify->domain_name = $this->domain_name; - $feature_event_notify->extension = $extension['extension']; - $feature_event_notify->do_not_disturb = $extension['do_not_disturb']; - $feature_event_notify->ring_count = ceil($extension['call_timeout'] / 6); - $feature_event_notify->forward_all_enabled = $extension['forward_all_enabled']; - $feature_event_notify->forward_busy_enabled = $extension['forward_busy_enabled']; - $feature_event_notify->forward_no_answer_enabled = $extension['forward_no_answer_enabled']; - //workarounds: send 0 as freeswitch doesn't send NOTIFY when destination values are nil - $feature_event_notify->forward_all_destination = $extension['forward_all_destination'] != '' ? $extension['forward_all_destination'] : '0'; - $feature_event_notify->forward_busy_destination = $extension['forward_busy_destination'] != '' ? $extension['forward_busy_destination'] : '0'; - $feature_event_notify->forward_no_answer_destination = $extension['forward_no_answer_destination'] != '' ? $extension['forward_no_answer_destination'] : '0'; - $feature_event_notify->send_notify(); - unset($feature_event_notify); - } - } - - //synchronize configuration - if (!empty($this->settings->get('switch', 'extensions')) && is_readable($this->settings->get('switch', 'extensions'))) { - $ext = new extension; - $ext->xml(); - unset($ext); - } - - //clear the cache - $cache = new cache; - foreach ($extensions as $uuid => $extension) { - $cache->delete(gethostname().":directory:" . $extension['extension'] . "@" . $_SESSION['domain_name']); - if ($extension['number_alias'] != '') { - $cache->delete(gethostname().":directory:" . $extension['number_alias'] . "@" . $_SESSION['domain_name']); - } - } - - //set message - message::add($text['message-toggle']); - } - unset($records, $extensions, $extension); - } - } + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + //assign private variables + $this->toggle_field = 'forward_all_enabled'; + $this->toggle_values = ['true', 'false']; } + /** + * Sets the extension with the provided values. + * + * @return void + */ + public function set() { + + //determine whether to update the dial string + $sql = "select * from v_extensions "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and extension_uuid = :extension_uuid "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['extension_uuid'] = $this->extension_uuid; + $row = $this->database->select($sql, $parameters, 'row'); + if (is_array($row) && @sizeof($row) != 0) { + $this->extension = $row["extension"]; + $this->number_alias = $row["number_alias"]; + $this->accountcode = $row["accountcode"]; + $this->toll_allow = $row["toll_allow"]; + $this->outbound_caller_id_name = $row["outbound_caller_id_name"]; + $this->outbound_caller_id_number = $row["outbound_caller_id_number"]; + } + unset($sql, $parameters, $row); + + //build extension update array + $array['extensions'][0]['extension_uuid'] = $this->extension_uuid; + $array['extensions'][0]['forward_all_destination'] = strlen($this->forward_all_destination) != 0 ? $this->forward_all_destination : null; + if (empty($this->forward_all_destination) || $this->forward_all_enabled == "false") { + $array['extensions'][0]['forward_all_enabled'] = 'false'; + } else { + $array['extensions'][0]['forward_all_enabled'] = 'true'; + } + + //grant temporary permissions + $p = permissions::new(); + $p->add('extension_add', 'temp'); + + //execute update + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('extension_add', 'temp'); + + //delete extension from the cache + $cache = new cache; + $cache->delete(gethostname() . ":directory:" . $this->extension . "@" . $this->domain_name); + if (!empty($this->number_alias)) { + $cache->delete(gethostname() . ":directory:" . $this->number_alias . "@" . $this->domain_name); + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle(array $records) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: calls.php'); + exit; + } + + //validate there are records to process + if (count($records) < 1) return; + + //check we have permission for this action + if (permission_exists('call_forward')) { + + // initialize an empty array + $uuids = []; + $extensions = []; + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //toggle the checked records + if (count($uuids) > 0) { + $sql = "select extension_uuid as uuid, extension, number_alias, "; + $sql .= "call_timeout, do_not_disturb, "; + $sql .= "forward_all_enabled, forward_all_destination, "; + $sql .= "forward_busy_enabled, forward_busy_destination, "; + $sql .= "forward_no_answer_enabled, forward_no_answer_destination, "; + $sql .= $this->toggle_field . " as toggle, follow_me_uuid "; + $sql .= "from v_extensions "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and extension_uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $extensions[$row['uuid']]['extension'] = $row['extension']; + $extensions[$row['uuid']]['number_alias'] = $row['number_alias']; + $extensions[$row['uuid']]['call_timeout'] = $row['call_timeout']; + $extensions[$row['uuid']]['do_not_disturb'] = $row['do_not_disturb']; + $extensions[$row['uuid']]['forward_all_enabled'] = $row['forward_all_enabled']; + $extensions[$row['uuid']]['forward_all_destination'] = $row['forward_all_destination']; + $extensions[$row['uuid']]['forward_busy_enabled'] = $row['forward_busy_enabled']; + $extensions[$row['uuid']]['forward_busy_destination'] = $row['forward_busy_destination']; + $extensions[$row['uuid']]['forward_no_answer_enabled'] = $row['forward_no_answer_enabled']; + $extensions[$row['uuid']]['forward_no_answer_destination'] = $row['forward_no_answer_destination']; + $extensions[$row['uuid']]['state'] = $row['toggle']; + $extensions[$row['uuid']]['follow_me_uuid'] = $row['follow_me_uuid']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($extensions as $uuid => $extension) { + + //check destination + $destination_exists = $extension['forward_all_destination'] != '' ? true : false; + + //determine new state + $new_state = $extension['state'] == $this->toggle_values[1] && $destination_exists ? $this->toggle_values[0] : $this->toggle_values[1]; + + //toggle feature + if ($new_state != $extension['state']) { + $array['extensions'][$x]['extension_uuid'] = $uuid; + $array['extensions'][$x][$this->toggle_field] = $new_state; + } + + //disable other features + if ($new_state == $this->toggle_values[0]) { //true + $array['extensions'][$x]['do_not_disturb'] = $this->toggle_values[1]; //false + $array['extensions'][$x]['follow_me_enabled'] = $this->toggle_values[1]; //false + if (is_uuid($extension['follow_me_uuid'])) { + $array['follow_me'][$x]['follow_me_uuid'] = $extension['follow_me_uuid']; + $array['follow_me'][$x]['follow_me_enabled'] = $this->toggle_values[1]; //false + } + } + + //increment counter + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('extension_edit', 'temp'); + + //save the array + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('extension_edit', 'temp'); + + //send feature event notify to the phone + if ($this->settings->get('device', 'feature_sync', false)) { + foreach ($extensions as $uuid => $extension) { + $feature_event_notify = new feature_event_notify; + $feature_event_notify->domain_name = $this->domain_name; + $feature_event_notify->extension = $extension['extension']; + $feature_event_notify->do_not_disturb = $extension['do_not_disturb']; + $feature_event_notify->ring_count = ceil($extension['call_timeout'] / 6); + $feature_event_notify->forward_all_enabled = $extension['forward_all_enabled']; + $feature_event_notify->forward_busy_enabled = $extension['forward_busy_enabled']; + $feature_event_notify->forward_no_answer_enabled = $extension['forward_no_answer_enabled']; + //workarounds: send 0 as freeswitch doesn't send NOTIFY when destination values are nil + $feature_event_notify->forward_all_destination = $extension['forward_all_destination'] != '' ? $extension['forward_all_destination'] : '0'; + $feature_event_notify->forward_busy_destination = $extension['forward_busy_destination'] != '' ? $extension['forward_busy_destination'] : '0'; + $feature_event_notify->forward_no_answer_destination = $extension['forward_no_answer_destination'] != '' ? $extension['forward_no_answer_destination'] : '0'; + $feature_event_notify->send_notify(); + unset($feature_event_notify); + } + } + + //synchronize configuration + if (!empty($this->settings->get('switch', 'extensions')) && is_readable($this->settings->get('switch', 'extensions'))) { + $ext = new extension; + $ext->xml(); + unset($ext); + } + + //clear the cache + $cache = new cache; + foreach ($extensions as $uuid => $extension) { + $cache->delete(gethostname() . ":directory:" . $extension['extension'] . "@" . $_SESSION['domain_name']); + if ($extension['number_alias'] != '') { + $cache->delete(gethostname() . ":directory:" . $extension['number_alias'] . "@" . $_SESSION['domain_name']); + } + } + + //set message + message::add($text['message-toggle']); + } + unset($records, $extensions, $extension); + } + } + +} + ?> diff --git a/app/call_recordings/resources/classes/call_recordings.php b/app/call_recordings/resources/classes/call_recordings.php index d73dcb4566..bf53eed18b 100644 --- a/app/call_recordings/resources/classes/call_recordings.php +++ b/app/call_recordings/resources/classes/call_recordings.php @@ -27,673 +27,706 @@ /** * call_recordings class */ - class call_recordings { +class call_recordings { - /** - * declare constant variables - */ - const app_name = 'follow_me'; - const app_uuid = 'b1b70f85-6b42-429b-8c5a-60c8b02b7d14'; + /** + * declare constant variables + */ + const app_name = 'follow_me'; + const app_uuid = 'b1b70f85-6b42-429b-8c5a-60c8b02b7d14'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * Username set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $username; + /** + * Username set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $username; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_name; - /** - * declare the variables - */ - private $name; - private $table; - private $description_field; - private $location; - public $recording_uuid; - public $binary; + /** + * declare the variables + */ + private $name; + private $table; + private $description_field; + private $location; + public $recording_uuid; + public $binary; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); - //assign the variables - $this->name = 'call_recording'; - $this->table = 'call_recordings'; - $this->description_field = 'call_recording_description'; - $this->location = 'call_recordings.php'; + //assign the variables + $this->name = 'call_recording'; + $this->table = 'call_recordings'; + $this->description_field = 'call_recording_description'; + $this->location = 'call_recordings.php'; - } + } - /** - * delete rows from the database - */ - public function delete($records) { - if (permission_exists($this->name.'_delete')) { + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->name . '_delete')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - //build the delete array - $x = 0; - foreach ($records as $record) { - //add to the array - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - //get the information to delete - $sql = "select call_recording_name, call_recording_path "; - $sql .= "from view_call_recordings "; - $sql .= "where call_recording_uuid = :call_recording_uuid "; - $parameters['call_recording_uuid'] = $record['uuid']; - $field = $this->database->select($sql, $parameters, 'row'); - if (is_array($field) && @sizeof($field) != 0) { - //delete the file on the file system - if (file_exists($field['call_recording_path'].'/'.$field['call_recording_name'])) { - unlink($field['call_recording_path'].'/'.$field['call_recording_name']); - } - - //build call recording delete array - $array['xml_cdr'][$x]['xml_cdr_uuid'] = $record['uuid']; - $array['xml_cdr'][$x]['record_path'] = null; - $array['xml_cdr'][$x]['record_name'] = null; - $array['xml_cdr'][$x]['record_length'] = null; - - //increment the id - $x++; - } - unset($sql, $parameters, $field); - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //add temporary permissions - $p = permissions::new(); - $p->add('xml_cdr_edit', 'temp'); - - //remove record_path, record_name and record_length - $this->database->app_name = 'xml_cdr'; - $this->database->app_uuid = '4a085c51-7635-ff03-f67b-86e834422848'; - $this->database->save($array, false); - $message = $this->database->message; - unset($array); - - //remove the temporary permissions - $p->delete('xml_cdr_edit', 'temp'); - - //set message - message::add($text['message-delete']); - - } - unset($records); - } + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; } - } - /** - * transcribe call recordings - */ - public function transcribe($records) { - if (permission_exists($this->name.'_view')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //add the settings object - $transcribe_enabled = $this->settings->get('transcribe', 'enabled', false); - $transcribe_engine = $this->settings->get('transcribe', 'engine', ''); - - //transcribe multiple recordings - if ($transcribe_enabled && !empty($transcribe_engine) && is_array($records) && @sizeof($records) != 0) { - //add the transcribe object - $transcribe = new transcribe($this->settings); - - //build the array - $x = 0; - foreach ($records as $record) { - //add to the array - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - - //get the call recording file name and path - $sql = "select call_recording_name, call_recording_path "; - $sql .= "from view_call_recordings "; - $sql .= "where call_recording_uuid = :call_recording_uuid "; - $sql .= "and call_recording_transcription is null "; - $parameters['call_recording_uuid'] = $record['uuid']; - $field = $this->database->select($sql, $parameters, 'row'); - if ( - is_array($field) && - @sizeof($field) != 0 && - file_exists($field['call_recording_path'].'/'.$field['call_recording_name']) - ) { - //audio to text - get the transcription from the audio file - $transcribe->audio_path = $field['call_recording_path']; - $transcribe->audio_filename = $field['call_recording_name']; - $record_transcription = $transcribe->transcribe(); - - //build call recording data array - if (!empty($record_transcription)) { - $array['xml_cdr'][$x]['xml_cdr_uuid'] = $record['uuid']; - $array['xml_cdr'][$x]['record_transcription'] = $record_transcription; - } - - //increment the id - $x++; - } - unset($sql, $parameters, $field); - - } + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + //build the delete array + $x = 0; + foreach ($records as $record) { + //add to the array + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + //get the information to delete + $sql = "select call_recording_name, call_recording_path "; + $sql .= "from view_call_recordings "; + $sql .= "where call_recording_uuid = :call_recording_uuid "; + $parameters['call_recording_uuid'] = $record['uuid']; + $field = $this->database->select($sql, $parameters, 'row'); + if (is_array($field) && @sizeof($field) != 0) { + //delete the file on the file system + if (file_exists($field['call_recording_path'] . '/' . $field['call_recording_name'])) { + unlink($field['call_recording_path'] . '/' . $field['call_recording_name']); } - //update the checked rows - if (is_array($array) && @sizeof($array) != 0) { + //build call recording delete array + $array['xml_cdr'][$x]['xml_cdr_uuid'] = $record['uuid']; + $array['xml_cdr'][$x]['record_path'] = null; + $array['xml_cdr'][$x]['record_name'] = null; + $array['xml_cdr'][$x]['record_length'] = null; - //add temporary permissions - $p = permissions::new(); - $p->add('xml_cdr_edit', 'temp'); - - //remove record_path, record_name and record_length - $this->database->app_name = 'xml_cdr'; - $this->database->app_uuid = '4a085c51-7635-ff03-f67b-86e834422848'; - $this->database->save($array, false); - $message = $this->database->message; - unset($array); - - //remove the temporary permissions - $p->delete('xml_cdr_edit', 'temp'); - - //set message - message::add($text['message-audio_transcribed']); - - } - unset($records); + //increment the id + $x++; + } + unset($sql, $parameters, $field); } - } - } - - /** - * download the recordings - */ - public function download($records = null) { - if (permission_exists('call_recording_play') || permission_exists('call_recording_download')) { - - //get the settings - $record_name = $this->settings->get('call_recordings', 'record_name', ''); - $storage_type = $this->settings->get('call_recordings', 'storage_type', ''); - $time_zone = $this->settings->get('domain', 'time_zone', ''); - - //set the time zone - if (!empty($time_zone)) { - $time_zone = $time_zone; - } - else { - $time_zone = date_default_timezone_get(); } - //single recording - if (empty($records) || !is_array($records) || @sizeof($records) == 0) { + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { - //get call recording from database - if (is_uuid($this->recording_uuid)) { - $sql = "select "; - $sql .= "domain_uuid, "; - $sql .= "call_recording_uuid, "; - $sql .= "caller_id_name, "; - $sql .= "caller_id_number, "; - $sql .= "caller_destination, "; - $sql .= "destination_number, "; - $sql .= "call_recording_name, "; - $sql .= "call_recording_path, "; - $sql .= "call_recording_transcription, "; - $sql .= "call_recording_length, "; - $sql .= "call_recording_date, "; - $sql .= "call_direction, "; - $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'YYYY') AS call_recording_year, "; - $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'Month') AS call_recording_month_name, "; - $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'MM') AS call_recording_month_number, "; - $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'DD') AS call_recording_day, "; - $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'HH24MISS') AS call_recording_time, "; - $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'DD Mon YYYY') as call_recording_date_formatted, "; - $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'HH12:MI:SS am') as call_recording_time_formatted "; - if (!empty($storage_type) && $storage_type == 'base64' && !empty($row['call_recording_base64'])) { - $sql .= ", call_recording_base64 "; + //add temporary permissions + $p = permissions::new(); + $p->add('xml_cdr_edit', 'temp'); + + //remove record_path, record_name and record_length + $this->database->app_name = 'xml_cdr'; + $this->database->app_uuid = '4a085c51-7635-ff03-f67b-86e834422848'; + $this->database->save($array, false); + $message = $this->database->message; + unset($array); + + //remove the temporary permissions + $p->delete('xml_cdr_edit', 'temp'); + + //set message + message::add($text['message-delete']); + + } + unset($records); + } + } + } + + /** + * Transcribes multiple call recordings. + * + * @param array $records An array of records to transcribe. + * + * @return void + */ + public function transcribe($records) { + if (permission_exists($this->name . '_view')) { + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //add the settings object + $transcribe_enabled = $this->settings->get('transcribe', 'enabled', false); + $transcribe_engine = $this->settings->get('transcribe', 'engine', ''); + + //transcribe multiple recordings + if ($transcribe_enabled && !empty($transcribe_engine) && is_array($records) && @sizeof($records) != 0) { + //add the transcribe object + $transcribe = new transcribe($this->settings); + + //build the array + $x = 0; + foreach ($records as $record) { + //add to the array + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + + //get the call recording file name and path + $sql = "select call_recording_name, call_recording_path "; + $sql .= "from view_call_recordings "; + $sql .= "where call_recording_uuid = :call_recording_uuid "; + $sql .= "and call_recording_transcription is null "; + $parameters['call_recording_uuid'] = $record['uuid']; + $field = $this->database->select($sql, $parameters, 'row'); + if ( + is_array($field) && + @sizeof($field) != 0 && + file_exists($field['call_recording_path'] . '/' . $field['call_recording_name']) + ) { + //audio to text - get the transcription from the audio file + $transcribe->audio_path = $field['call_recording_path']; + $transcribe->audio_filename = $field['call_recording_name']; + $record_transcription = $transcribe->transcribe(); + + //build call recording data array + if (!empty($record_transcription)) { + $array['xml_cdr'][$x]['xml_cdr_uuid'] = $record['uuid']; + $array['xml_cdr'][$x]['record_transcription'] = $record_transcription; } - $sql .= "from view_call_recordings "; - $sql .= "where call_recording_uuid = :call_recording_uuid "; - $parameters['call_recording_uuid'] = $this->recording_uuid; - $parameters['time_zone'] = $time_zone; - $row = $this->database->select($sql, $parameters, 'row'); - if (is_array($row) && @sizeof($row) != 0) { - $call_recording_uuid = $row['call_recording_uuid']; - $caller_id_name = $row['caller_id_name']; - $caller_id_number = $row['caller_id_number']; - $caller_destination = $row['caller_destination']; - $destination_number = $row['destination_number']; - $call_recording_name = $row['call_recording_name']; - $call_recording_path = $row['call_recording_path']; - $call_recording_date = $row['call_recording_date']; - $call_direction = $row['call_direction']; - $call_recording_year = $row['call_recording_year']; - $call_recording_month_name = $row['call_recording_month_name']; - $call_recording_month_number = $row['call_recording_month_number']; - $call_recording_day = $row['call_recording_day']; - $call_recording_time = $row['call_recording_time']; - $call_recording_date_formatted = $row['call_recording_date_formatted']; - $call_recording_time_formatted = $row['call_recording_time_formatted']; - $call_recording_base64 = $row['call_recording_base64']; - if (!empty($storage_type) && $storage_type == 'base64' && !empty($row['call_recording_base64'])) { - file_put_contents($call_recording_path.'/'.$call_recording_name, base64_decode($row['call_recording_base64'])); - } - } - unset($sql, $parameters, $row); + + //increment the id + $x++; } + unset($sql, $parameters, $field); - //build full path - $full_recording_path = $call_recording_path.'/'.$call_recording_name; + } + } - //created custom name - $call_recording_name_download = $call_recording_name; - if (!empty($record_name)) { - $call_recording_name_download = str_replace('${uuid}', $call_recording_uuid, $record_name); - $call_recording_name_download = str_replace('${caller_id_name}', $caller_id_name, $call_recording_name_download); - $call_recording_name_download = str_replace('${caller_id_number}', $caller_id_number, $call_recording_name_download); - $call_recording_name_download = str_replace('${caller_destination}', $caller_destination, $call_recording_name_download); - $call_recording_name_download = str_replace('${destination_number}', $destination_number, $call_recording_name_download); - $call_recording_name_download = str_replace('${date}', $call_recording_date, $call_recording_name_download); - $call_recording_name_download = str_replace('${call_direction}', $call_direction, $call_recording_name_download); - $call_recording_name_download = str_replace('${year}', $call_recording_year, $call_recording_name_download); - $call_recording_name_download = str_replace('${month_name}', $call_recording_month_name, $call_recording_name_download); - $call_recording_name_download = str_replace('${month_number}', $call_recording_month_number, $call_recording_name_download); - $call_recording_name_download = str_replace('${day}', $call_recording_day, $call_recording_name_download); - $call_recording_name_download = str_replace('${time}', $call_recording_time, $call_recording_name_download); - } + //update the checked rows + if (is_array($array) && @sizeof($array) != 0) { - //download the file - if ($full_recording_path != '/' && file_exists($full_recording_path)) { - ob_clean(); - $fd = fopen($full_recording_path, "rb"); - if ($this->binary) { - header("Content-Type: application/force-download"); - header("Content-Type: application/octet-stream"); - header("Content-Type: application/download"); - header("Content-Description: File Transfer"); - } - else { - $file_ext = pathinfo($call_recording_name, PATHINFO_EXTENSION); - switch ($file_ext) { - case "wav" : header("Content-Type: audio/x-wav"); break; - case "mp3" : header("Content-Type: audio/mpeg"); break; - case "ogg" : header("Content-Type: audio/ogg"); break; - } - } - $call_recording_name_download = preg_replace('#[^a-zA-Z0-9_\-\.]#', '', $call_recording_name_download); - header('Content-Disposition: attachment; filename="'.$call_recording_name_download.'"'); - header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 - header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past - if ($this->binary) { - header("Content-Length: ".filesize($full_recording_path)); - } - ob_clean(); + //add temporary permissions + $p = permissions::new(); + $p->add('xml_cdr_edit', 'temp'); - //content-range - if (isset($_SERVER['HTTP_RANGE']) && !$this->binary) { - $this->range_download($full_recording_path); - } + //remove record_path, record_name and record_length + $this->database->app_name = 'xml_cdr'; + $this->database->app_uuid = '4a085c51-7635-ff03-f67b-86e834422848'; + $this->database->save($array, false); + $message = $this->database->message; + unset($array); - fpassthru($fd); - } + //remove the temporary permissions + $p->delete('xml_cdr_edit', 'temp'); - //if base64, remove temp recording file - if (!empty($storage_type) && $storage_type == 'base64' && !empty($call_recording_base64)) { - @unlink($full_recording_path); - } + //set message + message::add($text['message-audio_transcribed']); - } else { //multiple recordings + } + unset($records); + } + } + } - //add multi-lingual support - $language = new text; - $text = $language->get(); + /** + * Downloads one or multiple call recordings. + * + * @param array $records An optional array of recording UUIDs to download. If null, the method will attempt to download a single recording based on the current object's recording_uuid property. + * + * @return void + */ + public function download($records = null) { + if (permission_exists('call_recording_play') || permission_exists('call_recording_download')) { - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } + //get the settings + $record_name = $this->settings->get('call_recordings', 'record_name', ''); + $storage_type = $this->settings->get('call_recordings', 'storage_type', ''); + $time_zone = $this->settings->get('domain', 'time_zone', ''); - //drop unchecked records - foreach ($records as $i => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = $record['uuid']; - } - } - unset($records, $record); + //set the time zone + if (!empty($time_zone)) { + $time_zone = $time_zone; + } else { + $time_zone = date_default_timezone_get(); + } - //get data for recordings - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select "; - $sql .= "domain_uuid, "; - $sql .= "call_recording_uuid, "; - $sql .= "caller_id_name, "; - $sql .= "caller_id_number, "; - $sql .= "caller_destination, "; - $sql .= "destination_number, "; - $sql .= "call_recording_name, "; - $sql .= "call_recording_path, "; - $sql .= "call_recording_transcription, "; - $sql .= "call_recording_length, "; - $sql .= "call_recording_date, "; - $sql .= "call_direction, "; - $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'YYYY') AS call_recording_year, "; - $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'Month') AS call_recording_month_name, "; - $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'MM') AS call_recording_month_number, "; - $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'DD') AS call_recording_day, "; - $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'HH24MISS') AS call_recording_time, "; - $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'DD Mon YYYY') as call_recording_date_formatted, "; - $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'HH12:MI:SS am') as call_recording_time_formatted "; - if (!empty($storage_type) && $storage_type == 'base64') { - $sql .= ", call_recording_base64 "; - } - $sql .= "from view_call_recordings "; - $sql .= "where call_recording_uuid in ('".implode("','", $uuids)."') "; - $parameters['time_zone'] = $time_zone; - $rows = $this->database->select($sql, $parameters, 'all'); - if (!empty($rows) && is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $call_recording_uuid = $row['call_recording_uuid']; - $caller_id_name = $row['caller_id_name']; - $caller_id_number = $row['caller_id_number']; - $caller_destination = $row['caller_destination']; - $destination_number = $row['destination_number']; - $call_recording_name = $row['call_recording_name']; - $call_recording_path = $row['call_recording_path']; - $call_recording_date = $row['call_recording_date']; - $call_direction = $row['call_direction']; - $call_recording_year = $row['call_recording_year']; - $call_recording_month_name = $row['call_recording_month_name']; - $call_recording_month_number = $row['call_recording_month_number']; - $call_recording_day = $row['call_recording_day']; - $call_recording_time = $row['call_recording_time']; - $call_recording_date_formatted = $row['call_recording_date_formatted']; - $call_recording_time_formatted = $row['call_recording_time_formatted']; - if (!empty($storage_type) && $storage_type == 'base64' && !empty($row['call_recording_base64'])) { - file_put_contents($call_recording_path.'/'.$call_recording_name, base64_decode($row['call_recording_base64'])); - } + //single recording + if (empty($records) || !is_array($records) || @sizeof($records) == 0) { - if (file_exists($call_recording_path.'/'.$call_recording_name)) { - //add the original file to the array - use original file name - if (empty($record_name)) { - $full_recording_paths[] = $call_recording_path.'/'.$call_recording_name; - } - - //created the custom name using the record_name as a template - if (!empty($record_name)) { - $call_recording_name_download = str_replace('${uuid}', $call_recording_uuid, $record_name); - $call_recording_name_download = str_replace('${caller_id_name}', $caller_id_name, $call_recording_name_download); - $call_recording_name_download = str_replace('${caller_id_number}', $caller_id_number, $call_recording_name_download); - $call_recording_name_download = str_replace('${caller_destination}', $caller_destination, $call_recording_name_download); - $call_recording_name_download = str_replace('${destination_number}', $destination_number, $call_recording_name_download); - $call_recording_name_download = str_replace('${date}', $call_recording_date, $call_recording_name_download); - $call_recording_name_download = str_replace('${call_direction}', $call_direction, $call_recording_name_download); - $call_recording_name_download = str_replace('${year}', $call_recording_year, $call_recording_name_download); - $call_recording_name_download = str_replace('${month_name}', $call_recording_month_name, $call_recording_name_download); - $call_recording_name_download = str_replace('${month_number}', $call_recording_month_number, $call_recording_name_download); - $call_recording_name_download = str_replace('${day}', $call_recording_day, $call_recording_name_download); - $call_recording_name_download = str_replace('${time}', $call_recording_time, $call_recording_name_download); - - //create a symbolic link with custom name - $command = 'ln -s '.$call_recording_path.'/'.$call_recording_name.' '.$call_recording_path.'/'.$call_recording_name_download; - system($command); - - //build the array for all the call recording with the new file name - $full_recording_paths[] = $call_recording_path.'/'.$call_recording_name_download; - } - } - - } - } - unset($sql, $rows, $row); - } - - //compress the recordings - if (!empty($full_recording_paths) && is_array($full_recording_paths) && @sizeof($full_recording_paths) != 0) { - header("Content-Type: application/x-zip"); - header("Content-Description: File Transfer"); - header('Content-Disposition: attachment; filename="call_recordings.zip"'); - header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 - header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past - passthru("zip -qj - ".implode(' ', $full_recording_paths)); - } - - //if base64, remove temp recording file + //get call recording from database + if (is_uuid($this->recording_uuid)) { + $sql = "select "; + $sql .= "domain_uuid, "; + $sql .= "call_recording_uuid, "; + $sql .= "caller_id_name, "; + $sql .= "caller_id_number, "; + $sql .= "caller_destination, "; + $sql .= "destination_number, "; + $sql .= "call_recording_name, "; + $sql .= "call_recording_path, "; + $sql .= "call_recording_transcription, "; + $sql .= "call_recording_length, "; + $sql .= "call_recording_date, "; + $sql .= "call_direction, "; + $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'YYYY') AS call_recording_year, "; + $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'Month') AS call_recording_month_name, "; + $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'MM') AS call_recording_month_number, "; + $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'DD') AS call_recording_day, "; + $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'HH24MISS') AS call_recording_time, "; + $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'DD Mon YYYY') as call_recording_date_formatted, "; + $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'HH12:MI:SS am') as call_recording_time_formatted "; + if (!empty($storage_type) && $storage_type == 'base64' && !empty($row['call_recording_base64'])) { + $sql .= ", call_recording_base64 "; + } + $sql .= "from view_call_recordings "; + $sql .= "where call_recording_uuid = :call_recording_uuid "; + $parameters['call_recording_uuid'] = $this->recording_uuid; + $parameters['time_zone'] = $time_zone; + $row = $this->database->select($sql, $parameters, 'row'); + if (is_array($row) && @sizeof($row) != 0) { + $call_recording_uuid = $row['call_recording_uuid']; + $caller_id_name = $row['caller_id_name']; + $caller_id_number = $row['caller_id_number']; + $caller_destination = $row['caller_destination']; + $destination_number = $row['destination_number']; + $call_recording_name = $row['call_recording_name']; + $call_recording_path = $row['call_recording_path']; + $call_recording_date = $row['call_recording_date']; + $call_direction = $row['call_direction']; + $call_recording_year = $row['call_recording_year']; + $call_recording_month_name = $row['call_recording_month_name']; + $call_recording_month_number = $row['call_recording_month_number']; + $call_recording_day = $row['call_recording_day']; + $call_recording_time = $row['call_recording_time']; + $call_recording_date_formatted = $row['call_recording_date_formatted']; + $call_recording_time_formatted = $row['call_recording_time_formatted']; + $call_recording_base64 = $row['call_recording_base64']; if (!empty($storage_type) && $storage_type == 'base64' && !empty($row['call_recording_base64'])) { - foreach ($full_recording_paths as $full_recording_path) { - @unlink($full_recording_path); - } - } - - //remove the symbolic links to the custom file names - if (!empty($record_name)) { - foreach ($full_recording_paths as $full_recording_path) { - @unlink($full_recording_path); - } - } - - //end the script - exit; - - } - - } - - } //method - - /* - * range download method (helps safari play audio sources) - */ - private function range_download($file) { - $fp = @fopen($file, 'rb'); - - $size = filesize($file); // File size - $length = $size; // Content length - $start = 0; // Start byte - $end = $size - 1; // End byte - // Now that we've gotten so far without errors we send the accept range header - /* At the moment we only support single ranges. - * Multiple ranges requires some more work to ensure it works correctly - * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 - * - * Multirange support annouces itself with: - * header('Accept-Ranges: bytes'); - * - * Multirange content must be sent with multipart/byteranges mediatype, - * (mediatype = mimetype) - * as well as a boundry header to indicate the various chunks of data. - */ - header("Accept-Ranges: 0-".$length); - // header('Accept-Ranges: bytes'); - // multipart/byteranges - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 - if (isset($_SERVER['HTTP_RANGE'])) { - - $c_start = $start; - $c_end = $end; - // Extract the range string - list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2); - // Make sure the client hasn't sent us a multibyte range - if (strpos($range, ',') !== false) { - // (?) Shoud this be issued here, or should the first - // range be used? Or should the header be ignored and - // we output the whole content? - header('HTTP/1.1 416 Requested Range Not Satisfiable'); - header("Content-Range: bytes $start-$end/$size"); - // (?) Echo some info to the client? - exit; - } - // If the range starts with an '-' we start from the beginning - // If not, we forward the file pointer - // And make sure to get the end byte if specified - if ($range[0] == '-') { - // The n-number of the last bytes is requested - $c_start = $size - substr($range, 1); - } - else { - $range = explode('-', $range); - $c_start = $range[0]; - $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size; - } - /* Check the range and make sure it's treated according to the specs. - * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - */ - // End bytes can not be larger than $end. - $c_end = ($c_end > $end) ? $end : $c_end; - // Validate the requested range and return an error if it's not correct. - if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) { - - header('HTTP/1.1 416 Requested Range Not Satisfiable'); - header("Content-Range: bytes $start-$end/$size"); - // (?) Echo some info to the client? - exit; - } - $start = $c_start; - $end = $c_end; - $length = $end - $start + 1; // Calculate new content length - fseek($fp, $start); - header('HTTP/1.1 206 Partial Content'); - } - // Notify the client the byte range we'll be outputting - header("Content-Range: bytes $start-$end/$size"); - header("Content-Length: $length"); - - // Start buffered download - $buffer = 1024 * 8; - while(!feof($fp) && ($p = ftell($fp)) <= $end) { - if ($p + $buffer > $end) { - // In case we're only outputtin a chunk, make sure we don't - // read past the length - $buffer = $end - $p + 1; - } - set_time_limit(0); // Reset time limit for big files - echo fread($fp, $buffer); - flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit. - } - - fclose($fp); - } - - /** - * Called by the maintenance service to clean out old call recordings - * @param settings $settings - * @return void - */ - public static function filesystem_maintenance(settings $settings): void { - //get the database connection object - $database = $settings->database(); - - //get an associative array of domain_uuid => domain_names - $domains = maintenance::get_domains($database); - - //loop over each domain - foreach ($domains as $domain_uuid => $domain_name) { - //get the settings for this domain - $domain_settings = new settings(['database' => $database, 'domain_uuid' => $domain_uuid]); - - //get the recording location for this domain - $call_recording_location = $domain_settings->get('switch', 'recordings', '/var/lib/freeswitch/recordings'); - - //get the retention days for this domain - $retention_days = $domain_settings->get('call_recordings', 'filesystem_retention_days', ''); - - //ensure retention days are not empty - if (!empty($retention_days) && is_numeric($retention_days)) { - $retention_days = intval($retention_days); - - //get list of mp3 and wav files - $mp3_files = glob("$call_recording_location/$domain_name/archive/*/*/*/*.mp3"); - $wav_files = glob("$call_recording_location/$domain_name/archive/*/*/*/*.wav"); - - //combine to single array - $domain_call_recording_files = array_merge($mp3_files, $wav_files); - - //loop over each call recording mp3 or wav file - foreach ($domain_call_recording_files as $file) { - - //use the maintenance service class helper function to get the modified date and see if it is older - if (maintenance_service::days_since_modified($file) > $retention_days) { - //remove the file when it is older - if (unlink($file)) { - //log success - maintenance_service::log_write(self::class, "Removed $file from call_recordings older than $retention_days days", $domain_uuid); - } else { - //log failure - maintenance_service::log_write(self::class, "Unable to remove $file", $domain_uuid, maintenance_service::LOG_ERROR); - } - } else { - //file is not older - do nothing + file_put_contents($call_recording_path . '/' . $call_recording_name, base64_decode($row['call_recording_base64'])); } } + unset($sql, $parameters, $row); } - else { - //report the retention days is not set correctly - maintenance_service::log_write(self::class, "Retention days not set or not a valid number", $domain_uuid, maintenance_service::LOG_ERROR); + + //build full path + $full_recording_path = $call_recording_path . '/' . $call_recording_name; + + //created custom name + $call_recording_name_download = $call_recording_name; + if (!empty($record_name)) { + $call_recording_name_download = str_replace('${uuid}', $call_recording_uuid, $record_name); + $call_recording_name_download = str_replace('${caller_id_name}', $caller_id_name, $call_recording_name_download); + $call_recording_name_download = str_replace('${caller_id_number}', $caller_id_number, $call_recording_name_download); + $call_recording_name_download = str_replace('${caller_destination}', $caller_destination, $call_recording_name_download); + $call_recording_name_download = str_replace('${destination_number}', $destination_number, $call_recording_name_download); + $call_recording_name_download = str_replace('${date}', $call_recording_date, $call_recording_name_download); + $call_recording_name_download = str_replace('${call_direction}', $call_direction, $call_recording_name_download); + $call_recording_name_download = str_replace('${year}', $call_recording_year, $call_recording_name_download); + $call_recording_name_download = str_replace('${month_name}', $call_recording_month_name, $call_recording_name_download); + $call_recording_name_download = str_replace('${month_number}', $call_recording_month_number, $call_recording_name_download); + $call_recording_name_download = str_replace('${day}', $call_recording_day, $call_recording_name_download); + $call_recording_name_download = str_replace('${time}', $call_recording_time, $call_recording_name_download); } + + //download the file + if ($full_recording_path != '/' && file_exists($full_recording_path)) { + ob_clean(); + $fd = fopen($full_recording_path, "rb"); + if ($this->binary) { + header("Content-Type: application/force-download"); + header("Content-Type: application/octet-stream"); + header("Content-Type: application/download"); + header("Content-Description: File Transfer"); + } else { + $file_ext = pathinfo($call_recording_name, PATHINFO_EXTENSION); + switch ($file_ext) { + case "wav" : + header("Content-Type: audio/x-wav"); + break; + case "mp3" : + header("Content-Type: audio/mpeg"); + break; + case "ogg" : + header("Content-Type: audio/ogg"); + break; + } + } + $call_recording_name_download = preg_replace('#[^a-zA-Z0-9_\-\.]#', '', $call_recording_name_download); + header('Content-Disposition: attachment; filename="' . $call_recording_name_download . '"'); + header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 + header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past + if ($this->binary) { + header("Content-Length: " . filesize($full_recording_path)); + } + ob_clean(); + + //content-range + if (isset($_SERVER['HTTP_RANGE']) && !$this->binary) { + $this->range_download($full_recording_path); + } + + fpassthru($fd); + } + + //if base64, remove temp recording file + if (!empty($storage_type) && $storage_type == 'base64' && !empty($call_recording_base64)) { + @unlink($full_recording_path); + } + + } else { //multiple recordings + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //drop unchecked records + foreach ($records as $i => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = $record['uuid']; + } + } + unset($records, $record); + + //get data for recordings + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select "; + $sql .= "domain_uuid, "; + $sql .= "call_recording_uuid, "; + $sql .= "caller_id_name, "; + $sql .= "caller_id_number, "; + $sql .= "caller_destination, "; + $sql .= "destination_number, "; + $sql .= "call_recording_name, "; + $sql .= "call_recording_path, "; + $sql .= "call_recording_transcription, "; + $sql .= "call_recording_length, "; + $sql .= "call_recording_date, "; + $sql .= "call_direction, "; + $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'YYYY') AS call_recording_year, "; + $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'Month') AS call_recording_month_name, "; + $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'MM') AS call_recording_month_number, "; + $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'DD') AS call_recording_day, "; + $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'HH24MISS') AS call_recording_time, "; + $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'DD Mon YYYY') as call_recording_date_formatted, "; + $sql .= "TO_CHAR(timezone(:time_zone, call_recording_date), 'HH12:MI:SS am') as call_recording_time_formatted "; + if (!empty($storage_type) && $storage_type == 'base64') { + $sql .= ", call_recording_base64 "; + } + $sql .= "from view_call_recordings "; + $sql .= "where call_recording_uuid in ('" . implode("','", $uuids) . "') "; + $parameters['time_zone'] = $time_zone; + $rows = $this->database->select($sql, $parameters, 'all'); + if (!empty($rows) && is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $call_recording_uuid = $row['call_recording_uuid']; + $caller_id_name = $row['caller_id_name']; + $caller_id_number = $row['caller_id_number']; + $caller_destination = $row['caller_destination']; + $destination_number = $row['destination_number']; + $call_recording_name = $row['call_recording_name']; + $call_recording_path = $row['call_recording_path']; + $call_recording_date = $row['call_recording_date']; + $call_direction = $row['call_direction']; + $call_recording_year = $row['call_recording_year']; + $call_recording_month_name = $row['call_recording_month_name']; + $call_recording_month_number = $row['call_recording_month_number']; + $call_recording_day = $row['call_recording_day']; + $call_recording_time = $row['call_recording_time']; + $call_recording_date_formatted = $row['call_recording_date_formatted']; + $call_recording_time_formatted = $row['call_recording_time_formatted']; + if (!empty($storage_type) && $storage_type == 'base64' && !empty($row['call_recording_base64'])) { + file_put_contents($call_recording_path . '/' . $call_recording_name, base64_decode($row['call_recording_base64'])); + } + + if (file_exists($call_recording_path . '/' . $call_recording_name)) { + //add the original file to the array - use original file name + if (empty($record_name)) { + $full_recording_paths[] = $call_recording_path . '/' . $call_recording_name; + } + + //created the custom name using the record_name as a template + if (!empty($record_name)) { + $call_recording_name_download = str_replace('${uuid}', $call_recording_uuid, $record_name); + $call_recording_name_download = str_replace('${caller_id_name}', $caller_id_name, $call_recording_name_download); + $call_recording_name_download = str_replace('${caller_id_number}', $caller_id_number, $call_recording_name_download); + $call_recording_name_download = str_replace('${caller_destination}', $caller_destination, $call_recording_name_download); + $call_recording_name_download = str_replace('${destination_number}', $destination_number, $call_recording_name_download); + $call_recording_name_download = str_replace('${date}', $call_recording_date, $call_recording_name_download); + $call_recording_name_download = str_replace('${call_direction}', $call_direction, $call_recording_name_download); + $call_recording_name_download = str_replace('${year}', $call_recording_year, $call_recording_name_download); + $call_recording_name_download = str_replace('${month_name}', $call_recording_month_name, $call_recording_name_download); + $call_recording_name_download = str_replace('${month_number}', $call_recording_month_number, $call_recording_name_download); + $call_recording_name_download = str_replace('${day}', $call_recording_day, $call_recording_name_download); + $call_recording_name_download = str_replace('${time}', $call_recording_time, $call_recording_name_download); + + //create a symbolic link with custom name + $command = 'ln -s ' . $call_recording_path . '/' . $call_recording_name . ' ' . $call_recording_path . '/' . $call_recording_name_download; + system($command); + + //build the array for all the call recording with the new file name + $full_recording_paths[] = $call_recording_path . '/' . $call_recording_name_download; + } + } + + } + } + unset($sql, $rows, $row); + } + + //compress the recordings + if (!empty($full_recording_paths) && is_array($full_recording_paths) && @sizeof($full_recording_paths) != 0) { + header("Content-Type: application/x-zip"); + header("Content-Description: File Transfer"); + header('Content-Disposition: attachment; filename="call_recordings.zip"'); + header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 + header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past + passthru("zip -qj - " . implode(' ', $full_recording_paths)); + } + + //if base64, remove temp recording file + if (!empty($storage_type) && $storage_type == 'base64' && !empty($row['call_recording_base64'])) { + foreach ($full_recording_paths as $full_recording_path) { + @unlink($full_recording_path); + } + } + + //remove the symbolic links to the custom file names + if (!empty($record_name)) { + foreach ($full_recording_paths as $full_recording_path) { + @unlink($full_recording_path); + } + } + + //end the script + exit; + } + } - } //class + } //method + + /* + * range download method (helps safari play audio sources) + */ + private function range_download($file) { + $fp = @fopen($file, 'rb'); + + $size = filesize($file); // File size + $length = $size; // Content length + $start = 0; // Start byte + $end = $size - 1; // End byte + // Now that we've gotten so far without errors we send the accept range header + /* At the moment we only support single ranges. + * Multiple ranges requires some more work to ensure it works correctly + * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 + * + * Multirange support annouces itself with: + * header('Accept-Ranges: bytes'); + * + * Multirange content must be sent with multipart/byteranges mediatype, + * (mediatype = mimetype) + * as well as a boundry header to indicate the various chunks of data. + */ + header("Accept-Ranges: 0-" . $length); + // header('Accept-Ranges: bytes'); + // multipart/byteranges + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 + if (isset($_SERVER['HTTP_RANGE'])) { + + $c_start = $start; + $c_end = $end; + // Extract the range string + [, $range] = explode('=', $_SERVER['HTTP_RANGE'], 2); + // Make sure the client hasn't sent us a multibyte range + if (strpos($range, ',') !== false) { + // (?) Shoud this be issued here, or should the first + // range be used? Or should the header be ignored and + // we output the whole content? + header('HTTP/1.1 416 Requested Range Not Satisfiable'); + header("Content-Range: bytes $start-$end/$size"); + // (?) Echo some info to the client? + exit; + } + // If the range starts with an '-' we start from the beginning + // If not, we forward the file pointer + // And make sure to get the end byte if specified + if ($range[0] == '-') { + // The n-number of the last bytes is requested + $c_start = $size - substr($range, 1); + } else { + $range = explode('-', $range); + $c_start = $range[0]; + $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size; + } + /* Check the range and make sure it's treated according to the specs. + * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + */ + // End bytes can not be larger than $end. + $c_end = ($c_end > $end) ? $end : $c_end; + // Validate the requested range and return an error if it's not correct. + if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) { + + header('HTTP/1.1 416 Requested Range Not Satisfiable'); + header("Content-Range: bytes $start-$end/$size"); + // (?) Echo some info to the client? + exit; + } + $start = $c_start; + $end = $c_end; + $length = $end - $start + 1; // Calculate new content length + fseek($fp, $start); + header('HTTP/1.1 206 Partial Content'); + } + // Notify the client the byte range we'll be outputting + header("Content-Range: bytes $start-$end/$size"); + header("Content-Length: $length"); + + // Start buffered download + $buffer = 1024 * 8; + while (!feof($fp) && ($p = ftell($fp)) <= $end) { + if ($p + $buffer > $end) { + // In case we're only outputtin a chunk, make sure we don't + // read past the length + $buffer = $end - $p + 1; + } + set_time_limit(0); // Reset time limit for big files + echo fread($fp, $buffer); + flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit. + } + + fclose($fp); + } + + /** + * Called by the maintenance service to clean out old call recordings + * + * @param settings $settings + * + * @return void + */ + public static function filesystem_maintenance(settings $settings): void { + //get the database connection object + $database = $settings->database(); + + //get an associative array of domain_uuid => domain_names + $domains = maintenance::get_domains($database); + + //loop over each domain + foreach ($domains as $domain_uuid => $domain_name) { + //get the settings for this domain + $domain_settings = new settings(['database' => $database, 'domain_uuid' => $domain_uuid]); + + //get the recording location for this domain + $call_recording_location = $domain_settings->get('switch', 'recordings', '/var/lib/freeswitch/recordings'); + + //get the retention days for this domain + $retention_days = $domain_settings->get('call_recordings', 'filesystem_retention_days', ''); + + //ensure retention days are not empty + if (!empty($retention_days) && is_numeric($retention_days)) { + $retention_days = intval($retention_days); + + //get list of mp3 and wav files + $mp3_files = glob("$call_recording_location/$domain_name/archive/*/*/*/*.mp3"); + $wav_files = glob("$call_recording_location/$domain_name/archive/*/*/*/*.wav"); + + //combine to single array + $domain_call_recording_files = array_merge($mp3_files, $wav_files); + + //loop over each call recording mp3 or wav file + foreach ($domain_call_recording_files as $file) { + + //use the maintenance service class helper function to get the modified date and see if it is older + if (maintenance_service::days_since_modified($file) > $retention_days) { + //remove the file when it is older + if (unlink($file)) { + //log success + maintenance_service::log_write(self::class, "Removed $file from call_recordings older than $retention_days days", $domain_uuid); + } else { + //log failure + maintenance_service::log_write(self::class, "Unable to remove $file", $domain_uuid, maintenance_service::LOG_ERROR); + } + } else { + //file is not older - do nothing + } + } + } else { + //report the retention days is not set correctly + maintenance_service::log_write(self::class, "Retention days not set or not a valid number", $domain_uuid, maintenance_service::LOG_ERROR); + } + } + } + +} //class diff --git a/app/conference_centers/conference_room_edit.php b/app/conference_centers/conference_room_edit.php index 17b6139021..8f80d6fd06 100644 --- a/app/conference_centers/conference_room_edit.php +++ b/app/conference_centers/conference_room_edit.php @@ -110,7 +110,14 @@ //set the default if (empty($profile)) { $profile = "default"; } -//define fucntion get_conference_pin - used to find a unique pin number + /** + * Generates a unique pin number for a conference room. + * + * @param int $length The length of the pin number to be generated. + * @param string $conference_room_uuid The UUID of the conference room. + * + * @return string A unique pin number if available, or generates another one recursively until an available one is found. + */ function get_conference_pin($length, $conference_room_uuid) { //set the variable as global global $database; diff --git a/app/conference_centers/resources/classes/call_center_notify.php b/app/conference_centers/resources/classes/call_center_notify.php index d871820a31..41e8e9deee 100644 --- a/app/conference_centers/resources/classes/call_center_notify.php +++ b/app/conference_centers/resources/classes/call_center_notify.php @@ -26,35 +26,45 @@ */ //define the blf_notify class - class call_center_notify { +class call_center_notify { - public $debug; - public $domain_name; - public $agent_name; - public $answer_state; - public $agent_uuid; + public $debug; + public $domain_name; + public $agent_name; + public $answer_state; + public $agent_uuid; - //feature_event method - public function send_call_center_notify() { + //feature_event method - $esl = event_socket::create(); - if ($esl->is_connected()) { - //send the event - $event = "sendevent PRESENCE_IN\n"; - $event .= "proto: agent\n"; - $event .= "event_type: presence\n"; - $event .= "alt_event_type: dialog\n"; - $event .= "Presence-Call-Direction: outbound\n"; - $event .= "state: Active (1 waiting)\n"; - $event .= "from: agent+".$this->agent_name."@".$this->domain_name."\n"; - $event .= "login: agent+".$this->agent_name."@".$this->domain_name."\n"; - $event .= "unique-id: ".$this->agent_uuid."\n"; - $event .= "answer-state: ".$this->answer_state."\n"; - $esl->request('api ' . $event); - //echo $event."
"; - } - } //function + /** + * Sends a presence notification to the call center. + * + * This method creates an event socket connection and sends a PRESENCE_IN event + * if the connection is established. The event contains information about the agent's + * presence, including their name, domain, unique ID, and answer state. + * + * @return boolean True if the event was successfully sent, false otherwise. + */ + public function send_call_center_notify() { - } //class + $esl = event_socket::create(); + if ($esl->is_connected()) { + //send the event + $event = "sendevent PRESENCE_IN\n"; + $event .= "proto: agent\n"; + $event .= "event_type: presence\n"; + $event .= "alt_event_type: dialog\n"; + $event .= "Presence-Call-Direction: outbound\n"; + $event .= "state: Active (1 waiting)\n"; + $event .= "from: agent+" . $this->agent_name . "@" . $this->domain_name . "\n"; + $event .= "login: agent+" . $this->agent_name . "@" . $this->domain_name . "\n"; + $event .= "unique-id: " . $this->agent_uuid . "\n"; + $event .= "answer-state: " . $this->answer_state . "\n"; + $esl->request('api ' . $event); + //echo $event."
"; + } + } //function + +} //class ?> diff --git a/app/conference_centers/resources/classes/conference_centers.php b/app/conference_centers/resources/classes/conference_centers.php index 8a5125e31a..443f32bad2 100644 --- a/app/conference_centers/resources/classes/conference_centers.php +++ b/app/conference_centers/resources/classes/conference_centers.php @@ -26,808 +26,859 @@ Luis Daniel Lucio Quiroz */ //define the conference centers class - class conference_centers { +class conference_centers { - /** - * declare constant variables - */ - const app_name = 'conference_centers'; - const app_uuid = '8d083f5a-f726-42a8-9ffa-8d28f848f10e'; + /** + * declare constant variables + */ + const app_name = 'conference_centers'; + const app_uuid = '8d083f5a-f726-42a8-9ffa-8d28f848f10e'; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_uuid; - /** - * declare public variables - */ - public $conference_room_uuid; - public $order_by; - public $order; - public $rows_per_page; - public $offset; - public $search; - public $count; - public $created_by; - public $toggle_field; + /** + * declare public variables + */ + public $conference_room_uuid; + public $order_by; + public $order; + public $rows_per_page; + public $offset; + public $search; + public $count; + public $created_by; + public $toggle_field; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * Username set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $username; + /** + * Username set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $username; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_name; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_values; - private $fields; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_values; + private $fields; - /** - * Called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + } + + /** + * Retrieves the count of conference rooms. + * + * @return array|false An array containing a single column named "column" with the room count. + */ + public function room_count() { + //get the room count + $not_admin = 1; + if (permission_exists("conference_room_view_all")) { + $not_admin = 0; + } + $sql = "select count(*) from v_conference_rooms as r "; + if ($not_admin) { + $sql .= ", v_conference_room_users as u "; + } + $sql .= "where r.domain_uuid = :domain_uuid "; + if ($not_admin) { + $sql .= "and r.conference_room_uuid = u.conference_room_uuid "; + $sql .= "and u.user_uuid = :user_uuid "; + $parameters['user_uuid'] = $this->user_uuid; + } + if (isset($this->conference_room_uuid)) { + $sql .= "and r.conference_room_uuid = :conference_room_uuid "; + $parameters['conference_room_uuid'] = $this->conference_room_uuid; } - /** - * count the conference rooms - */ - public function room_count() { - //get the room count - $not_admin = 1; - if (permission_exists("conference_room_view_all")) { - $not_admin = 0; - } - $sql = "select count(*) from v_conference_rooms as r "; - if ($not_admin) { - $sql .= ", v_conference_room_users as u "; - } - $sql .= "where r.domain_uuid = :domain_uuid "; - if ($not_admin) { - $sql .= "and r.conference_room_uuid = u.conference_room_uuid "; - $sql .= "and u.user_uuid = :user_uuid "; - $parameters['user_uuid'] = $this->user_uuid; - } - if (isset($this->conference_room_uuid)) { - $sql .= "and r.conference_room_uuid = :conference_room_uuid "; - $parameters['conference_room_uuid'] = $this->conference_room_uuid; - } + if (isset($this->created_by)) { + $sql .= "and created_by = :created_by "; + $parameters['created_by'] = $this->created_by; + } + $parameters['domain_uuid'] = $this->domain_uuid; + return $this->database->select($sql, $parameters, 'column'); + } - if (isset($this->created_by)) { - $sql .= "and created_by = :created_by "; - $parameters['created_by'] = $this->created_by; - } - $parameters['domain_uuid'] = $this->domain_uuid; - return $this->database->select($sql, $parameters, 'column'); + /** + * Retrieves a list of conference rooms based on filtering and sorting criteria. + * + * @return array|null A multidimensional array containing information about each room, or null if no rooms are found. + */ + public function rooms() { + //get variables used to control the order + $order_by = $this->order_by; + $order = $this->order; + + //validate order by + if (!empty($order_by)) { + $order_by = preg_replace('#[^a-zA-Z0-9_\-]#', '', $order_by); } - /** - * get the list of conference rooms - */ - public function rooms() { - //get variables used to control the order - $order_by = $this->order_by; - $order = $this->order; + //validate the order + switch ($order) { + case 'asc': + case 'desc': + break; + default: + $order = ''; + } - //validate order by - if (!empty($order_by)) { - $order_by = preg_replace('#[^a-zA-Z0-9_\-]#', '', $order_by); + //get the list of rooms + $not_admin = 1; + if (permission_exists("conference_room_view_all")) { + $not_admin = 0; + } + + $sql = "select "; + $sql .= "r.domain_uuid, r.conference_room_uuid, r.conference_center_uuid, r.conference_room_name, r.max_members, "; + $sql .= "wait_mod, announce_name, announce_count, announce_recording, mute, sounds, created, created_by, r.enabled, r.description, record, "; + $sql .= "profile, r.moderator_pin, r.participant_pin "; + if ($not_admin) { + $sql .= ", u.conference_room_user_uuid, u.user_uuid "; + } + $sql .= "from v_conference_rooms as r "; + if ($not_admin) { + $sql .= ", v_conference_room_users as u "; + } + $sql .= "where r.domain_uuid = :domain_uuid "; + if ($not_admin) { + $sql .= "and r.conference_room_uuid = u.conference_room_uuid "; + $sql .= "and u.user_uuid = :user_uuid "; + $parameters['user_uuid'] = $this->user_uuid; + } + if (!empty($this->search)) { + $sql .= "and ("; + $sql .= "lower(r.conference_room_name) like :search or "; + $sql .= "lower(r.moderator_pin) like :search or "; + $sql .= "lower(r.participant_pin) like :search or "; + $sql .= "lower(r.account_code) like :search or "; + $sql .= "lower(r.description) like :search "; + $sql .= ") "; + $parameters['search'] = '%' . strtolower($this->search) . '%'; + $parameters['domain_uuid'] = $this->domain_uuid; + } + if (isset($this->created_by)) { + $sql .= "and r.created_by = :created_by "; + $parameters['created_by'] = $this->created_by; + } + if (empty($this->order_by)) { + $sql .= "order by r.description, r.conference_room_uuid asc "; + } else { + $sql .= "order by $order_by $order "; + } + $sql .= "limit :rows_per_page offset :offset "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['rows_per_page'] = $this->rows_per_page; + $parameters['offset'] = $this->offset; + $conference_rooms = $this->database->select($sql, $parameters, 'all'); + + if (!empty($conference_rooms)) { + $x = 0; + foreach ($conference_rooms as $row) { + //increment the array index + if (isset($previous) && $row["conference_room_uuid"] != $previous) { + $x++; } + //build the array + $result[$x]["domain_uuid"] = $row["domain_uuid"]; + $result[$x]["conference_room_uuid"] = $row["conference_room_uuid"]; + $result[$x]["conference_center_uuid"] = $row["conference_center_uuid"]; + //$result[$x]["meeting_uuid"] = $row["meeting_uuid"]; + $result[$x]["conference_room_name"] = $row["conference_room_name"]; + $result[$x]["max_members"] = $row["max_members"]; + $result[$x]["wait_mod"] = $row["wait_mod"]; + $result[$x]["announce_name"] = $row["announce_name"]; + $result[$x]["announce_count"] = $row["announce_count"]; + $result[$x]["announce_recording"] = $row["announce_recording"]; + $result[$x]["mute"] = $row["mute"]; + $result[$x]["record"] = $row["record"]; + $result[$x]["sounds"] = $row["sounds"]; + $result[$x]["profile"] = $row["profile"]; + $result[$x]["conference_room_user_uuid"] = $row["conference_room_user_uuid"] ?? null; + $result[$x]["user_uuid"] = $row["user_uuid"] ?? null; + $result[$x]["moderator_pin"] = $row["moderator_pin"]; + $result[$x]["participant_pin"] = $row["participant_pin"]; + $result[$x]["created"] = $row["created"]; + $result[$x]["created_by"] = $row["created_by"]; + $result[$x]["enabled"] = $row["enabled"]; + $result[$x]["description"] = $row["description"]; + //set the previous uuid + $previous = $row["conference_room_uuid"]; + } + } + unset($sql, $parameters, $conference_rooms); + return $result ?? null; + } - //validate the order - switch ($order) { - case 'asc': - case 'desc': + /** + * Downloads a call recording based on the provided ID. + * + * @return void + */ + public function download() { + if (permission_exists('conference_session_play') || permission_exists('call_recording_play') || permission_exists('call_recording_download')) { + + //cache limiter + session_cache_limiter('public'); + + //get call recording from database + if (is_uuid($_GET['id'])) { + $conference_session_uuid = $_GET['id']; + $sql = "select recording from v_conference_sessions "; + $sql .= "where conference_session_uuid = :conference_session_uuid "; + //$sql .= "and domain_uuid = :domain_uuid "; + $parameters['conference_session_uuid'] = $conference_session_uuid; + //$parameters['domain_uuid'] = $domain_uuid; + $conference_sessions = $this->database->select($sql, $parameters, 'all'); + if (is_array($conference_sessions)) { + foreach ($conference_sessions as $row) { + $recording = $row['recording']; break; - default: - $order = ''; + } + } + unset($sql, $parameters, $conference_sessions); + } + + //set the path for the directory + $default_path = $this->settings->get('switch', 'call_recordings') . "/" . $this->domain_name; + + //get the file path and name + $record_path = dirname($recording); + $record_name = basename($recording); + + //download the file + if (file_exists($record_path . '/' . $record_name . '.wav')) { + $record_name = $record_name . '.wav'; + } else { + if (file_exists($record_path . '/' . $record_name . '.mp3')) { + $record_name = $record_name . '.mp3'; + } + } + + //download the file + if (file_exists($record_path . '/' . $record_name)) { + //content-range + //if (isset($_SERVER['HTTP_RANGE'])) { + // range_download($full_recording_path); + //} + ob_clean(); + $fd = fopen($record_path . '/' . $record_name, "rb"); + if ($_GET['t'] == "bin") { + header("Content-Type: application/force-download"); + header("Content-Type: application/octet-stream"); + header("Content-Type: application/download"); + header("Content-Description: File Transfer"); + } else { + $file_ext = substr($record_name, -3); + if ($file_ext == "wav") { + header("Content-Type: audio/x-wav"); + } + if ($file_ext == "mp3") { + header("Content-Type: audio/mpeg"); + } + } + header('Content-Disposition: attachment; filename="' . $record_name . '"'); + header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 + header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past + // header("Content-Length: ".filesize($full_recording_path)); + ob_clean(); + fpassthru($fd); + } + + //if base64, remove temp recording file + //if ($this->settings->get('conference', 'storage_type') == 'base64' && $row['conference_recording_base64'] != '') { + // @unlink($record_path.'/'.$record_name); + //} + } + } //end download method + + /** + * Deletes multiple conference center records. + * + * @param array $records An array of records to delete, where each record is an associative array containing the UUID of + * the conference center and a 'checked' key indicating whether the record should be deleted. + * + * @return void + */ + public function delete_conference_centers($records) { + + //assign private variables + $this->permission_prefix = 'conference_center_'; + $this->list_page = 'conference_centers.php'; + $this->table = 'conference_centers'; + $this->uuid_prefix = 'conference_center_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (!empty($records)) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + + //get the dialplan uuid + $sql = "select dialplan_uuid from v_conference_centers "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and conference_center_uuid = :conference_center_uuid "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['conference_center_uuid'] = $record['uuid']; + $dialplan_uuid = $this->database->select($sql, $parameters, 'column'); + unset($sql, $parameters); + + //create array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + $array['dialplan_details'][$x]['dialplan_uuid'] = $dialplan_uuid; + $array['dialplan_details'][$x]['domain_uuid'] = $this->domain_uuid; + $array['dialplans'][$x]['dialplan_uuid'] = $dialplan_uuid; + $array['dialplans'][$x]['domain_uuid'] = $this->domain_uuid; + } } - //get the list of rooms - $not_admin = 1; - if (permission_exists("conference_room_view_all")) { - $not_admin = 0; + //delete the checked rows + if (!empty($array)) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('dialplan_detail_delete', 'temp'); + $p->add('dialplan_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('dialplan_detail_delete', 'temp'); + $p->delete('dialplan_delete', 'temp'); + + //clear the cache + $cache = new cache; + $cache->delete("dialplan:" . $this->domain_name); + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //apply settings reminder + $_SESSION["reload_xml"] = true; + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Deletes multiple conference rooms. + * + * @param array $records An array containing the IDs of the records to be deleted. The ID is represented as 'uuid'. + * + * @return void + */ + public function delete_conference_rooms($records) { + + //assign private variables + $this->permission_prefix = 'conference_room_'; + $this->list_page = 'conference_rooms.php'; + $this->table = 'conference_rooms'; + $this->uuid_prefix = 'conference_room_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (!empty($records)) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + + //create array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + $array['conference_room_users'][$x]['conference_room_uuid'] = $record['uuid']; + $array['conference_room_users'][$x]['domain_uuid'] = $this->domain_uuid; + } } - $sql = "select "; - $sql .= "r.domain_uuid, r.conference_room_uuid, r.conference_center_uuid, r.conference_room_name, r.max_members, "; - $sql .= "wait_mod, announce_name, announce_count, announce_recording, mute, sounds, created, created_by, r.enabled, r.description, record, "; - $sql .= "profile, r.moderator_pin, r.participant_pin "; - if ($not_admin) { - $sql .= ", u.conference_room_user_uuid, u.user_uuid "; + //delete the checked rows + if (!empty($array)) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('conference_room_user_delete', 'temp'); + $p->add('conference_room_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('conference_room_user_delete', 'temp'); + $p->delete('conference_room_delete', 'temp'); + + //set message + message::add($text['message-delete']); } - $sql .= "from v_conference_rooms as r "; - if ($not_admin) { - $sql .= ", v_conference_room_users as u "; + unset($records); + } + } + } + + /** + * Deletes multiple conference sessions. + * + * @param array $records An array of records to delete, where each record is an associative array with a 'uuid' key and a 'checked' key. + * The 'uuid' value must be a valid UUID, and the 'checked' value should be set to 'true' for the session to be deleted. + * + * @return void + */ + public function delete_conference_sessions($records) { + + //assign private variables + $this->permission_prefix = 'conference_session_'; + $this->list_page = 'conference_sessions.php?id=' . $this->conference_room_uuid; + $this->table = 'conference_sessions'; + $this->uuid_prefix = 'conference_session_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (!empty($records)) { + + //build the delete array + foreach ($records as $x => $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + + //create array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + $array['conference_session_details'][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array['conference_session_details'][$x]['domain_uuid'] = $this->domain_uuid; + } } - $sql .= "where r.domain_uuid = :domain_uuid "; - if ($not_admin) { - $sql .= "and r.conference_room_uuid = u.conference_room_uuid "; - $sql .= "and u.user_uuid = :user_uuid "; - $parameters['user_uuid'] = $this->user_uuid; + + //delete the checked rows + if (!empty($array)) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('conference_session_detail_delete', 'temp'); + $p->add('conference_user_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('conference_session_detail_delete', 'temp'); + $p->delete('conference_user_delete', 'temp'); + + //set message + message::add($text['message-delete']); } - if (!empty($this->search)) { - $sql .= "and ("; - $sql .= "lower(r.conference_room_name) like :search or "; - $sql .= "lower(r.moderator_pin) like :search or "; - $sql .= "lower(r.participant_pin) like :search or "; - $sql .= "lower(r.account_code) like :search or "; - $sql .= "lower(r.description) like :search "; - $sql .= ") "; - $parameters['search'] = '%'.strtolower($this->search).'%'; + unset($records); + } + } + } + + /** + * Toggles the state of multiple conference centers. + * + * @param array $records An array of records to toggle, where each record is an associative array with a 'uuid' key and a 'checked' key. + * The 'uuid' value must be a valid UUID, and the 'checked' value should be set to 'true' for the center to be toggled. + * + * @return void + */ + public function toggle_conference_centers($records) { + + //assign private variables + $this->permission_prefix = 'conference_center_'; + $this->list_page = 'conference_centers.php'; + $this->table = 'conference_centers'; + $this->uuid_prefix = 'conference_center_'; + $this->toggle_field = 'conference_center_enabled'; + $this->toggle_values = ['true', 'false']; + + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (!empty($records)) { + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (!empty($uuids)) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle, dialplan_uuid from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; $parameters['domain_uuid'] = $this->domain_uuid; - } - if (isset($this->created_by)) { - $sql .= "and r.created_by = :created_by "; - $parameters['created_by'] = $this->created_by; - } - if (empty($this->order_by)) { - $sql .= "order by r.description, r.conference_room_uuid asc "; - } - else { - $sql .= "order by $order_by $order "; - } - $sql .= "limit :rows_per_page offset :offset "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['rows_per_page'] = $this->rows_per_page; - $parameters['offset'] = $this->offset; - $conference_rooms = $this->database->select($sql, $parameters, 'all'); - - if (!empty($conference_rooms)) { - $x = 0; - foreach($conference_rooms as $row) { - //increment the array index - if (isset($previous) && $row["conference_room_uuid"] != $previous) { $x++; } - //build the array - $result[$x]["domain_uuid"] = $row["domain_uuid"]; - $result[$x]["conference_room_uuid"] = $row["conference_room_uuid"]; - $result[$x]["conference_center_uuid"] = $row["conference_center_uuid"]; - //$result[$x]["meeting_uuid"] = $row["meeting_uuid"]; - $result[$x]["conference_room_name"] = $row["conference_room_name"]; - $result[$x]["max_members"] = $row["max_members"]; - $result[$x]["wait_mod"] = $row["wait_mod"]; - $result[$x]["announce_name"] = $row["announce_name"]; - $result[$x]["announce_count"] = $row["announce_count"]; - $result[$x]["announce_recording"] = $row["announce_recording"]; - $result[$x]["mute"] = $row["mute"]; - $result[$x]["record"] = $row["record"]; - $result[$x]["sounds"] = $row["sounds"]; - $result[$x]["profile"] = $row["profile"]; - $result[$x]["conference_room_user_uuid"] = $row["conference_room_user_uuid"] ?? null; - $result[$x]["user_uuid"] = $row["user_uuid"] ?? null; - $result[$x]["moderator_pin"] = $row["moderator_pin"]; - $result[$x]["participant_pin"] = $row["participant_pin"]; - $result[$x]["created"] = $row["created"]; - $result[$x]["created_by"] = $row["created_by"]; - $result[$x]["enabled"] = $row["enabled"]; - $result[$x]["description"] = $row["description"]; - //set the previous uuid - $previous = $row["conference_room_uuid"]; - } - } - unset($sql, $parameters, $conference_rooms); - return $result ?? null; - } - - /** - * download the recordings - */ - public function download() { - if (permission_exists('conference_session_play') || permission_exists('call_recording_play') || permission_exists('call_recording_download')) { - - //cache limiter - session_cache_limiter('public'); - - //get call recording from database - if (is_uuid($_GET['id'])) { - $conference_session_uuid = $_GET['id']; - $sql = "select recording from v_conference_sessions "; - $sql .= "where conference_session_uuid = :conference_session_uuid "; - //$sql .= "and domain_uuid = :domain_uuid "; - $parameters['conference_session_uuid'] = $conference_session_uuid; - //$parameters['domain_uuid'] = $domain_uuid; - $conference_sessions = $this->database->select($sql, $parameters, 'all'); - if (is_array($conference_sessions)) { - foreach ($conference_sessions as $row) { - $recording = $row['recording']; - break; - } - } - unset($sql, $parameters, $conference_sessions); - } - - //set the path for the directory - $default_path = $this->settings->get('switch', 'call_recordings')."/".$this->domain_name; - - //get the file path and name - $record_path = dirname($recording); - $record_name = basename($recording); - - //download the file - if (file_exists($record_path.'/'.$record_name.'.wav')) { - $record_name = $record_name.'.wav'; - } - else { - if (file_exists($record_path.'/'.$record_name.'.mp3')) { - $record_name = $record_name.'.mp3'; + $rows = $this->database->select($sql, $parameters, 'all'); + if (!empty($rows)) { + foreach ($rows as $row) { + $conference_centers[$row['uuid']]['state'] = $row['toggle']; + $conference_centers[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; } } + unset($sql, $parameters, $rows, $row); + } - //download the file - if (file_exists($record_path.'/'.$record_name)) { - //content-range - //if (isset($_SERVER['HTTP_RANGE'])) { - // range_download($full_recording_path); - //} - ob_clean(); - $fd = fopen($record_path.'/'.$record_name, "rb"); - if ($_GET['t'] == "bin") { - header("Content-Type: application/force-download"); - header("Content-Type: application/octet-stream"); - header("Content-Type: application/download"); - header("Content-Description: File Transfer"); + //build update array + $x = 0; + foreach ($conference_centers as $uuid => $conference_center) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $conference_center['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $array['dialplans'][$x]['dialplan_uuid'] = $conference_center['dialplan_uuid']; + $array['dialplans'][$x]['dialplan_enabled'] = $conference_center['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + + //save the changes + if (!empty($array)) { + + //grant temporary permissions + $p = permissions::new(); + $p->add("dialplan_edit", "temp"); + + //save the array + + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete("dialplan_edit", "temp"); + + //apply settings reminder + $_SESSION["reload_xml"] = true; + + //clear the cache + $cache = new cache; + $cache->delete("dialplan:" . $this->domain_name); + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //set message + message::add($text['message-toggle']); + + } + unset($records, $conference_centers, $conference_center); + } + + } + } + + /** + * Toggles the state of multiple conference rooms. + * + * @param array $records An array of records to toggle, where each record is an associative array with a 'uuid' key and a 'checked' key. + * The 'uuid' value must be a valid UUID, and the 'checked' value should be set to 'true' for the room to be toggled. + * + * @return void + */ + public function toggle_conference_rooms($records) { + + //assign private variables + $this->permission_prefix = 'conference_room_'; + $this->list_page = 'conference_rooms.php'; + $this->table = 'conference_rooms'; + $this->uuid_prefix = 'conference_room_'; + $this->toggle_values = ['true', 'false']; + + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (!empty($records)) { + + //validate submitted toggle field + if (!in_array($this->toggle_field, ['record', 'wait_mod', 'announce_name', 'announce_count', 'announce_recording', 'mute', 'sounds', 'enabled'])) { + header('Location: ' . $this->list_page); + exit; + } + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[$x] = "'" . $record['uuid'] . "'"; + if (($this->toggle_field == 'record' || $this->toggle_field == 'enabled') && !empty($record['meeting_uuid']) && is_uuid($record['meeting_uuid'])) { + $meeting_uuid[$record['uuid']] = $record['meeting_uuid']; } - else { - $file_ext = substr($record_name, -3); - if ($file_ext == "wav") { - header("Content-Type: audio/x-wav"); - } - if ($file_ext == "mp3") { - header("Content-Type: audio/mpeg"); + } + } + if (!empty($uuids)) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (!empty($rows)) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + + /* + //if toggling to true, start recording + if ($this->toggle_field == 'record' && is_uuid($meeting_uuid[$uuid]) && $state == $this->toggle_values[1]) { + //prepare the values and commands + $default_language = 'en'; + $default_dialect = 'us'; + $default_voice = 'callie'; + // $recording_dir = $this->settings->get('switch', 'recordings').'/'.$this->domain_name.'/archive/'.date("Y").'/'.date("M").'/'.date("d"); + // $switch_cmd_record = "conference ".$meeting_uuid[$uuid]."@".$this->domain_name." record ".$recording_dir.'/'.$meeting_uuid[$uuid].'.wav'; + $switch_cmd_notice = "conference ".$meeting_uuid[$uuid]."@".$this->domain_name." play ".$this->settings->get('switch', 'sounds')."/".$default_language."/".$default_dialect."/".$default_voice."/ivr/ivr-recording_started.wav"; + //execute api commands + // if (!file_exists($recording_dir.'/'.$meeting_uuid[$uuid].'.wav')) { + $esl = event_socket::create(); + if ($esl->is_connected()) { + // $switch_result = event_socket::api($switch_cmd_record); + $switch_result = event_socket::api($switch_cmd_notice); + } + // } + } + */ + $x++; + } + + //save the changes + if (!empty($array)) { + + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + + } + unset($records, $states, $state); + } + + } + } + + /** + * copy records + */ + /* + public function copy_conference_centers($records) { + + //assign private variables + $this->permission_prefix = 'conference_center_'; + $this->list_page = 'conference_centers.php'; + $this->table = 'conference_centers'; + $this->uuid_prefix = 'conference_center_'; + + if (permission_exists($this->permission_prefix.'add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'],'negative'); + header('Location: '.$this->list_page); + exit; + } + + //copy the checked records + if (!empty($records)) { + + //get checked records + foreach($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'".$record['uuid']."'"; } } - header('Content-Disposition: attachment; filename="'.$record_name.'"'); - header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 - header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past - // header("Content-Length: ".filesize($full_recording_path)); - ob_clean(); - fpassthru($fd); - } - //if base64, remove temp recording file - //if ($this->settings->get('conference', 'storage_type') == 'base64' && $row['conference_recording_base64'] != '') { - // @unlink($record_path.'/'.$record_name); - //} - } - } //end download method + //create insert array from existing data + if (!empty($uuids)) { + $sql = "select * from v_".$this->table." "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (!empty($rows)) { + foreach ($rows as $x => $row) { - /** - * delete records - */ - public function delete_conference_centers($records) { + //copy data + $array[$this->table][$x] = $row; - //assign private variables - $this->permission_prefix = 'conference_center_'; - $this->list_page = 'conference_centers.php'; - $this->table = 'conference_centers'; - $this->uuid_prefix = 'conference_center_'; + //overwrite + $array[$this->table][$x][$this->uuid_prefix.'uuid'] = uuid(); + $array[$this->table][$x]['_description'] = trim($row['_description'].' ('.$text['label-copy'].')'); - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (!empty($records)) { - - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - - //get the dialplan uuid - $sql = "select dialplan_uuid from v_conference_centers "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and conference_center_uuid = :conference_center_uuid "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['conference_center_uuid'] = $record['uuid']; - $dialplan_uuid = $this->database->select($sql, $parameters, 'column'); - unset($sql, $parameters); - - //create array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - $array['dialplan_details'][$x]['dialplan_uuid'] = $dialplan_uuid; - $array['dialplan_details'][$x]['domain_uuid'] = $this->domain_uuid; - $array['dialplans'][$x]['dialplan_uuid'] = $dialplan_uuid; - $array['dialplans'][$x]['domain_uuid'] = $this->domain_uuid; } } + unset($sql, $parameters, $rows, $row); + } - //delete the checked rows - if (!empty($array)) { + //save the changes and set the message + if (!empty($array)) { - //grant temporary permissions - $p = permissions::new(); - $p->add('dialplan_detail_delete', 'temp'); - $p->add('dialplan_delete', 'temp'); + //save the array - //execute delete - $this->database->delete($array); - unset($array); + $this->database->save($array); + unset($array); - //revoke temporary permissions - $p->delete('dialplan_detail_delete', 'temp'); - $p->delete('dialplan_delete', 'temp'); + //set message + message::add($text['message-copy']); - //clear the cache - $cache = new cache; - $cache->delete("dialplan:".$this->domain_name); + } + unset($records); + } - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //apply settings reminder - $_SESSION["reload_xml"] = true; - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } } + } + */ - public function delete_conference_rooms($records) { - - //assign private variables - $this->permission_prefix = 'conference_room_'; - $this->list_page = 'conference_rooms.php'; - $this->table = 'conference_rooms'; - $this->uuid_prefix = 'conference_room_'; - - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (!empty($records)) { - - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - - //create array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - $array['conference_room_users'][$x]['conference_room_uuid'] = $record['uuid']; - $array['conference_room_users'][$x]['domain_uuid'] = $this->domain_uuid; - } - } - - //delete the checked rows - if (!empty($array)) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('conference_room_user_delete', 'temp'); - $p->add('conference_room_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('conference_room_user_delete', 'temp'); - $p->delete('conference_room_delete', 'temp'); - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - public function delete_conference_sessions($records) { - - //assign private variables - $this->permission_prefix = 'conference_session_'; - $this->list_page = 'conference_sessions.php?id='.$this->conference_room_uuid; - $this->table = 'conference_sessions'; - $this->uuid_prefix = 'conference_session_'; - - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (!empty($records)) { - - //build the delete array - foreach ($records as $x => $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - - //create array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - $array['conference_session_details'][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array['conference_session_details'][$x]['domain_uuid'] = $this->domain_uuid; - } - } - - //delete the checked rows - if (!empty($array)) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('conference_session_detail_delete', 'temp'); - $p->add('conference_user_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('conference_session_detail_delete', 'temp'); - $p->delete('conference_user_delete', 'temp'); - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * toggle records - */ - public function toggle_conference_centers($records) { - - //assign private variables - $this->permission_prefix = 'conference_center_'; - $this->list_page = 'conference_centers.php'; - $this->table = 'conference_centers'; - $this->uuid_prefix = 'conference_center_'; - $this->toggle_field = 'conference_center_enabled'; - $this->toggle_values = ['true','false']; - - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (!empty($records)) { - - //get current toggle state - foreach($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (!empty($uuids)) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle, dialplan_uuid from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (!empty($rows)) { - foreach ($rows as $row) { - $conference_centers[$row['uuid']]['state'] = $row['toggle']; - $conference_centers[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($conference_centers as $uuid => $conference_center) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $conference_center['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $array['dialplans'][$x]['dialplan_uuid'] = $conference_center['dialplan_uuid']; - $array['dialplans'][$x]['dialplan_enabled'] = $conference_center['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - - //save the changes - if (!empty($array)) { - - //grant temporary permissions - $p = permissions::new(); - $p->add("dialplan_edit", "temp"); - - //save the array - - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete("dialplan_edit", "temp"); - - //apply settings reminder - $_SESSION["reload_xml"] = true; - - //clear the cache - $cache = new cache; - $cache->delete("dialplan:".$this->domain_name); - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-toggle']); - - } - unset($records, $conference_centers, $conference_center); - } - - } - } - - public function toggle_conference_rooms($records) { - - //assign private variables - $this->permission_prefix = 'conference_room_'; - $this->list_page = 'conference_rooms.php'; - $this->table = 'conference_rooms'; - $this->uuid_prefix = 'conference_room_'; - $this->toggle_values = ['true','false']; - - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (!empty($records)) { - - //validate submitted toggle field - if (!in_array($this->toggle_field, ['record','wait_mod','announce_name','announce_count','announce_recording','mute','sounds','enabled'])) { - header('Location: '.$this->list_page); - exit; - } - - //get current toggle state - foreach($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[$x] = "'".$record['uuid']."'"; - if (($this->toggle_field == 'record' || $this->toggle_field == 'enabled') && !empty($record['meeting_uuid']) && is_uuid($record['meeting_uuid'])) { - $meeting_uuid[$record['uuid']] = $record['meeting_uuid']; - } - } - } - if (!empty($uuids)) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (!empty($rows)) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach ($states as $uuid => $state) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - -/* - //if toggling to true, start recording - if ($this->toggle_field == 'record' && is_uuid($meeting_uuid[$uuid]) && $state == $this->toggle_values[1]) { - //prepare the values and commands - $default_language = 'en'; - $default_dialect = 'us'; - $default_voice = 'callie'; -// $recording_dir = $this->settings->get('switch', 'recordings').'/'.$this->domain_name.'/archive/'.date("Y").'/'.date("M").'/'.date("d"); -// $switch_cmd_record = "conference ".$meeting_uuid[$uuid]."@".$this->domain_name." record ".$recording_dir.'/'.$meeting_uuid[$uuid].'.wav'; - $switch_cmd_notice = "conference ".$meeting_uuid[$uuid]."@".$this->domain_name." play ".$this->settings->get('switch', 'sounds')."/".$default_language."/".$default_dialect."/".$default_voice."/ivr/ivr-recording_started.wav"; - //execute api commands -// if (!file_exists($recording_dir.'/'.$meeting_uuid[$uuid].'.wav')) { - $esl = event_socket::create(); - if ($esl->is_connected()) { -// $switch_result = event_socket::api($switch_cmd_record); - $switch_result = event_socket::api($switch_cmd_notice); - } -// } - } -*/ - $x++; - } - - //save the changes - if (!empty($array)) { - - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - - } - unset($records, $states, $state); - } - - } - } - - /** - * copy records - */ - /* - public function copy_conference_centers($records) { - - //assign private variables - $this->permission_prefix = 'conference_center_'; - $this->list_page = 'conference_centers.php'; - $this->table = 'conference_centers'; - $this->uuid_prefix = 'conference_center_'; - - if (permission_exists($this->permission_prefix.'add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //copy the checked records - if (!empty($records)) { - - //get checked records - foreach($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create insert array from existing data - if (!empty($uuids)) { - $sql = "select * from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (!empty($rows)) { - foreach ($rows as $x => $row) { - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = uuid(); - $array[$this->table][$x]['_description'] = trim($row['_description'].' ('.$text['label-copy'].')'); - - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (!empty($array)) { - - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-copy']); - - } - unset($records); - } - - } - } - */ - - - } //class - +} //class //example conference center - /* - $conference_center = new conference_centers; - $conference_center->domain_uuid = $this->domain_uuid; - $conference_center->rows_per_page = 150; - $conference_center->offset = 0; - $conference_center->created_by = uuid; - $conference_center->order_by = $order_by; - $conference_center->order = $order; - $result = $conference_center->rooms(); - print_r($result); - */ +/* +$conference_center = new conference_centers; +$conference_center->domain_uuid = $this->domain_uuid; +$conference_center->rows_per_page = 150; +$conference_center->offset = 0; +$conference_center->created_by = uuid; +$conference_center->order_by = $order_by; +$conference_center->order = $order; +$result = $conference_center->rooms(); +print_r($result); +*/ diff --git a/app/conference_controls/resources/classes/conference_controls.php b/app/conference_controls/resources/classes/conference_controls.php index dfd0be916d..727d6c0832 100644 --- a/app/conference_controls/resources/classes/conference_controls.php +++ b/app/conference_controls/resources/classes/conference_controls.php @@ -27,401 +27,441 @@ /** * conference_controls class */ - class conference_controls { - - /** - * declare constant variables - */ - const app_name = 'conference_controls'; - const app_uuid = 'e1ad84a2-79e1-450c-a5b1-7507a043e048'; - - /** - * declare private variables - */ - - private $database; - private $name; - private $table; - private $toggle_field; - private $toggle_values; - private $description_field; - private $location; - - /** - * declare public variables - */ - public $conference_control_uuid; - - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set objects - $this->database = $setting_array['database'] ?? database::new(); - } - - /** - * delete rows from the database - */ - public function delete($records) { - - //assign the variables - $this->name = 'conference_control'; - $this->table = 'conference_controls'; - $this->location = 'conference_controls.php'; - - if (permission_exists($this->name.'_delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - //build the delete array - $x = 0; - foreach ($records as $record) { - //add to the array - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->name.'_uuid'] = $record['uuid']; - $array['conference_control_details'][$x][$this->name.'_uuid'] = $record['uuid']; - } - - //increment the id - $x++; - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('conference_control_detail_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('conference_control_detail_delete', 'temp'); - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - public function delete_details($records) { - - //assign the variables - $this->name = 'conference_control_detail'; - $this->table = 'conference_control_details'; - $this->location = 'conference_control_edit.php?id='.$this->conference_control_uuid; - - if (permission_exists($this->name.'_delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate('/app/conference_controls/conference_control_details.php')) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //delete multiple records - if (!empty($records) && is_array($records) && @sizeof($records) != 0) { - - //build the delete array - $x = 0; - if (!empty($records) && is_array($records) && @sizeof($records) != 0) { - foreach ($records as $record) { - //add to the array - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->name.'_uuid'] = $record['uuid']; - } - - //increment the id - $x++; - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * toggle a field between two values - */ - public function toggle($records) { - - //assign the variables - $this->name = 'conference_control'; - $this->table = 'conference_controls'; - $this->toggle_field = 'control_enabled'; - $this->toggle_values = ['true','false']; - $this->location = 'conference_controls.php'; - - if (permission_exists($this->name.'_edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - //get current toggle state - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->name."_uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach ($states as $uuid => $state) { - //create the array - $array[$this->table][$x][$this->name.'_uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - - //increment the id - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - } - } - - public function toggle_details($records) { - - //assign the variables - $this->name = 'conference_control_detail'; - $this->table = 'conference_control_details'; - $this->toggle_field = 'control_enabled'; - $this->toggle_values = ['true','false']; - $this->location = 'conference_control_edit.php?id='.$this->conference_control_uuid; - - if (permission_exists($this->name.'_edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate('/app/conference_controls/conference_control_details.php')) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - //get current toggle state - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->name."_uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - if (!empty($states) && is_array($states) && @sizeof($states) != 0) { - foreach ($states as $uuid => $state) { - //create the array - $array[$this->table][$x][$this->name.'_uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - - //increment the id - $x++; - } - } - - //save the changes - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - } - } - - /** - * copy rows from the database - */ - public function copy($records) { - - //assign the variables - $this->name = 'conference_control'; - $this->table = 'conference_controls'; - $this->description_field = 'control_description'; - $this->location = 'conference_controls.php'; - - if (permission_exists($this->name.'_add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create the array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - - //primary table - $sql = "select * from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $y = 0; - foreach ($rows as $x => $row) { - $primary_uuid = uuid(); - - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //add copy to the description - $array[$this->table][$x][$this->name.'_uuid'] = $primary_uuid; - $array[$this->table][$x][$this->description_field] = trim($row[$this->description_field] ?? '').' ('.$text['label-copy'].')'; - - //details sub table - $sql_2 = "select * from v_conference_control_details where conference_control_uuid = :conference_control_uuid"; - $parameters_2['conference_control_uuid'] = $row['conference_control_uuid']; - $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); - if (is_array($rows_2) && @sizeof($rows_2) != 0) { - foreach ($rows_2 as $row_2) { - - //convert boolean values to a string - foreach($row_2 as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row_2[$key] = $value; - } - } - - //copy data - $array['conference_control_details'][$y] = $row_2; - - //overwrite - $array['conference_control_details'][$y]['conference_control_detail_uuid'] = uuid(); - $array['conference_control_details'][$y]['conference_control_uuid'] = $primary_uuid; - - //increment - $y++; - - } - } - unset($sql_2, $parameters_2, $rows_2, $row_2); } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - //save the array - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-copy']); - } - unset($records); - } - } - } - +class conference_controls { + + /** + * declare constant variables + */ + const app_name = 'conference_controls'; + const app_uuid = 'e1ad84a2-79e1-450c-a5b1-7507a043e048'; + + /** + * declare private variables + */ + + private $database; + private $name; + private $table; + private $toggle_field; + private $toggle_values; + private $description_field; + private $location; + + /** + * declare public variables + */ + public $conference_control_uuid; + + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set objects + $this->database = $setting_array['database'] ?? database::new(); } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + + //assign the variables + $this->name = 'conference_control'; + $this->table = 'conference_controls'; + $this->location = 'conference_controls.php'; + + if (permission_exists($this->name . '_delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + //build the delete array + $x = 0; + foreach ($records as $record) { + //add to the array + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->name . '_uuid'] = $record['uuid']; + $array['conference_control_details'][$x][$this->name . '_uuid'] = $record['uuid']; + } + + //increment the id + $x++; + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('conference_control_detail_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('conference_control_detail_delete', 'temp'); + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Deletes conference control details. + * + * @param array $records An array of records to delete, where each record contains a 'checked' key with value 'true'. + * + * @return void + */ + public function delete_details($records) { + + //assign the variables + $this->name = 'conference_control_detail'; + $this->table = 'conference_control_details'; + $this->location = 'conference_control_edit.php?id=' . $this->conference_control_uuid; + + if (permission_exists($this->name . '_delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate('/app/conference_controls/conference_control_details.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //delete multiple records + if (!empty($records) && is_array($records) && @sizeof($records) != 0) { + + //build the delete array + $x = 0; + if (!empty($records) && is_array($records) && @sizeof($records) != 0) { + foreach ($records as $record) { + //add to the array + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->name . '_uuid'] = $record['uuid']; + } + + //increment the id + $x++; + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + + //assign the variables + $this->name = 'conference_control'; + $this->table = 'conference_controls'; + $this->toggle_field = 'control_enabled'; + $this->toggle_values = ['true', 'false']; + $this->location = 'conference_controls.php'; + + if (permission_exists($this->name . '_edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + //get current toggle state + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->name . "_uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + //create the array + $array[$this->table][$x][$this->name . '_uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + + //increment the id + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle_details($records) { + + //assign the variables + $this->name = 'conference_control_detail'; + $this->table = 'conference_control_details'; + $this->toggle_field = 'control_enabled'; + $this->toggle_values = ['true', 'false']; + $this->location = 'conference_control_edit.php?id=' . $this->conference_control_uuid; + + if (permission_exists($this->name . '_edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate('/app/conference_controls/conference_control_details.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + //get current toggle state + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->name . "_uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + if (!empty($states) && is_array($states) && @sizeof($states) != 0) { + foreach ($states as $uuid => $state) { + //create the array + $array[$this->table][$x][$this->name . '_uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + + //increment the id + $x++; + } + } + + //save the changes + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + + //assign the variables + $this->name = 'conference_control'; + $this->table = 'conference_controls'; + $this->description_field = 'control_description'; + $this->location = 'conference_controls.php'; + + if (permission_exists($this->name . '_add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create the array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + + //primary table + $sql = "select * from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $y = 0; + foreach ($rows as $x => $row) { + $primary_uuid = uuid(); + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; + } + } + + //copy data + $array[$this->table][$x] = $row; + + //add copy to the description + $array[$this->table][$x][$this->name . '_uuid'] = $primary_uuid; + $array[$this->table][$x][$this->description_field] = trim($row[$this->description_field] ?? '') . ' (' . $text['label-copy'] . ')'; + + //details sub table + $sql_2 = "select * from v_conference_control_details where conference_control_uuid = :conference_control_uuid"; + $parameters_2['conference_control_uuid'] = $row['conference_control_uuid']; + $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); + if (is_array($rows_2) && @sizeof($rows_2) != 0) { + foreach ($rows_2 as $row_2) { + + //convert boolean values to a string + foreach ($row_2 as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row_2[$key] = $value; + } + } + + //copy data + $array['conference_control_details'][$y] = $row_2; + + //overwrite + $array['conference_control_details'][$y]['conference_control_detail_uuid'] = uuid(); + $array['conference_control_details'][$y]['conference_control_uuid'] = $primary_uuid; + + //increment + $y++; + + } + } + unset($sql_2, $parameters_2, $rows_2, $row_2); + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + //save the array + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-copy']); + } + unset($records); + } + } + } + +} diff --git a/app/conference_profiles/resources/classes/conference_profiles.php b/app/conference_profiles/resources/classes/conference_profiles.php index 6c7748162a..e1d585a967 100644 --- a/app/conference_profiles/resources/classes/conference_profiles.php +++ b/app/conference_profiles/resources/classes/conference_profiles.php @@ -27,405 +27,442 @@ /** * conference_profiles class */ - class conference_profiles { +class conference_profiles { - /** - * declare constant variables - */ - const app_name = 'conference_profiles'; - const app_uuid = 'c33e2c2a-847f-44c1-8c0d-310df5d65ba9'; + /** + * declare constant variables + */ + const app_name = 'conference_profiles'; + const app_uuid = 'c33e2c2a-847f-44c1-8c0d-310df5d65ba9'; - /** - * declare private variables - */ + /** + * declare private variables + */ - private $name; - private $table; - private $toggle_field; - private $toggle_values; - private $description_field; - private $location; - private $database; + private $name; + private $table; + private $toggle_field; + private $toggle_values; + private $description_field; + private $location; + private $database; - /** - * declare public variables - */ - public $conference_profile_uuid; + /** + * declare public variables + */ + public $conference_profile_uuid; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set objects - $this->database = $setting_array['database'] ?? database::new(); - } + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set objects + $this->database = $setting_array['database'] ?? database::new(); + } - /** - * delete rows from the database - */ - public function delete($records) { + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { - //assign the variables - $this->name = 'conference_profile'; - $this->table = 'conference_profiles'; - $this->location = 'conference_profiles.php'; + //assign the variables + $this->name = 'conference_profile'; + $this->table = 'conference_profiles'; + $this->location = 'conference_profiles.php'; - if (permission_exists($this->name.'_delete')) { + if (permission_exists($this->name . '_delete')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + //build the delete array + $x = 0; + foreach ($records as $record) { + //add to the array + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->name . '_uuid'] = $record['uuid']; + $array['conference_profile_params'][$x][$this->name . '_uuid'] = $record['uuid']; } - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - //build the delete array - $x = 0; - foreach ($records as $record) { - //add to the array - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->name.'_uuid'] = $record['uuid']; - $array['conference_profile_params'][$x][$this->name.'_uuid'] = $record['uuid']; - } + //increment the id + $x++; + } - //increment the id - $x++; - } + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { + //grant temporary permissions + $p = permissions::new(); + $p->add('conference_profile_param_delete', 'temp'); - //grant temporary permissions - $p = permissions::new(); - $p->add('conference_profile_param_delete', 'temp'); + //execute delete + $this->database->delete($array); + unset($array); - //execute delete - $this->database->delete($array); - unset($array); + //revoke temporary permissions + $p->delete('conference_profile_param_delete', 'temp'); - //revoke temporary permissions - $p->delete('conference_profile_param_delete', 'temp'); - - //set message - message::add($text['message-delete']); - } - unset($records); - } + //set message + message::add($text['message-delete']); + } + unset($records); } } + } - public function delete_params($records) { + /** + * Deletes multiple parameters from the conference profile. + * + * @param array $records An array of records to delete, where each record contains a 'checked' key with value 'true' and an 'uuid' key containing the UUID of the parameter to be deleted. + * + * @return void + */ + public function delete_params($records) { - //assign the variables - $this->name = 'conference_profile_param'; - $this->table = 'conference_profile_params'; - $this->location = 'conference_profile_edit.php?id='.$this->conference_profile_uuid; + //assign the variables + $this->name = 'conference_profile_param'; + $this->table = 'conference_profile_params'; + $this->location = 'conference_profile_edit.php?id=' . $this->conference_profile_uuid; - if (permission_exists($this->name.'_delete')) { + if (permission_exists($this->name . '_delete')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate('/app/conference_profiles/conference_profile_params.php')) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; + //validate the token + $token = new token; + if (!$token->validate('/app/conference_profiles/conference_profile_params.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //delete multiple records + if (!empty($records) && is_array($records) && @sizeof($records) != 0) { + //build the delete array + $x = 0; + foreach ($records as $record) { + //add to the array + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->name . '_uuid'] = $record['uuid']; } - //delete multiple records - if (!empty($records) && is_array($records) && @sizeof($records) != 0) { - //build the delete array - $x = 0; - foreach ($records as $record) { - //add to the array - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->name.'_uuid'] = $record['uuid']; - } + //increment the id + $x++; + } - //increment the id - $x++; - } + //delete the checked rows + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); - //delete the checked rows - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } + //set message + message::add($text['message-delete']); + } + unset($records); } } + } - /** - * toggle a field between two values - */ - public function toggle($records) { + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { - //assign the variables - $this->name = 'conference_profile'; - $this->table = 'conference_profiles'; - $this->toggle_field = 'profile_enabled'; - $this->toggle_values = ['true','false']; - $this->location = 'conference_profiles.php'; + //assign the variables + $this->name = 'conference_profile'; + $this->table = 'conference_profiles'; + $this->toggle_field = 'profile_enabled'; + $this->toggle_values = ['true', 'false']; + $this->location = 'conference_profiles.php'; - if (permission_exists($this->name.'_edit')) { + if (permission_exists($this->name . '_edit')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + //get current toggle state + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - //get current toggle state - foreach($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->name."_uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($states as $uuid => $state) { - //create the array - $array[$this->table][$x][$this->name.'_uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - - //increment the id - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - //save the array - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->name . "_uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + //create the array + $array[$this->table][$x][$this->name . '_uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + + //increment the id + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + //save the array + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); } } + } - public function toggle_params($records) { + /** + * Toggles the enabled state of multiple parameters in a conference profile. + * + * @param array $records An array of records to toggle, where each record contains a 'checked' key with value 'true' and an 'uuid' key containing the UUID of the parameter to be toggled. + * + * @return void + */ + public function toggle_params($records) { - //assign the variables - $this->name = 'conference_profile_param'; - $this->table = 'conference_profile_params'; - $this->toggle_field = 'profile_param_enabled'; - $this->toggle_values = ['true','false']; - $this->location = 'conference_profile_edit.php?id='.$this->conference_profile_uuid; + //assign the variables + $this->name = 'conference_profile_param'; + $this->table = 'conference_profile_params'; + $this->toggle_field = 'profile_param_enabled'; + $this->toggle_values = ['true', 'false']; + $this->location = 'conference_profile_edit.php?id=' . $this->conference_profile_uuid; - if (permission_exists($this->name.'_edit')) { + if (permission_exists($this->name . '_edit')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate('/app/conference_profiles/conference_profile_params.php')) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; + //validate the token + $token = new token; + if (!$token->validate('/app/conference_profiles/conference_profile_params.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //toggle the checked records + if (!empty($records) && is_array($records) && @sizeof($records) != 0) { + //get current toggle state + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; } - - //toggle the checked records - if (!empty($records) && is_array($records) && @sizeof($records) != 0) { - //get current toggle state - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->name."_uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - if (!empty($states) && is_array($states) && @sizeof($states) != 0) { - foreach ($states as $uuid => $state) { - //create the array - $array[$this->table][$x][$this->name.'_uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - - //increment the id - $x++; - } - } - - //save the changes - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - //save the array - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); + } + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->name . "_uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + if (!empty($states) && is_array($states) && @sizeof($states) != 0) { + foreach ($states as $uuid => $state) { + //create the array + $array[$this->table][$x][$this->name . '_uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + + //increment the id + $x++; + } + } + + //save the changes + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + //save the array + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); } } + } - /** - * copy rows from the database - */ - public function copy($records) { + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { - //assign the variables - $this->name = 'conference_profile'; - $this->table = 'conference_profiles'; - $this->description_field = 'profile_description'; - $this->location = 'conference_profiles.php'; + //assign the variables + $this->name = 'conference_profile'; + $this->table = 'conference_profiles'; + $this->description_field = 'profile_description'; + $this->location = 'conference_profiles.php'; - if (permission_exists($this->name.'_add')) { + if (permission_exists($this->name . '_add')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; } + } - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { + //create the array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { - //get checked records - foreach($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; + //primary table + $sql = "select * from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $y = 0; + foreach ($rows as $x => $row) { + $primary_uuid = uuid(); + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; } } - //create the array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { + //copy data + $array[$this->table][$x] = $row; - //primary table - $sql = "select * from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $y = 0; - foreach ($rows as $x => $row) { - $primary_uuid = uuid(); + //add copy to the description + $array[$this->table][$x][$this->name . '_uuid'] = $primary_uuid; + $array[$this->table][$x][$this->description_field] = trim($row[$this->description_field] ?? '') . ' (' . $text['label-copy'] . ')'; - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } + //params sub table + $sql_2 = "select * from v_conference_profile_params where conference_profile_uuid = :conference_profile_uuid"; + $parameters_2['conference_profile_uuid'] = $row['conference_profile_uuid']; + $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); + if (is_array($rows_2) && @sizeof($rows_2) != 0) { + foreach ($rows_2 as $row_2) { - //copy data - $array[$this->table][$x] = $row; - - //add copy to the description - $array[$this->table][$x][$this->name.'_uuid'] = $primary_uuid; - $array[$this->table][$x][$this->description_field] = trim($row[$this->description_field] ?? '').' ('.$text['label-copy'].')'; - - //params sub table - $sql_2 = "select * from v_conference_profile_params where conference_profile_uuid = :conference_profile_uuid"; - $parameters_2['conference_profile_uuid'] = $row['conference_profile_uuid']; - $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); - if (is_array($rows_2) && @sizeof($rows_2) != 0) { - foreach ($rows_2 as $row_2) { - - //convert boolean values to a string - foreach($row_2 as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row_2[$key] = $value; - } - } - - //copy data - $array['conference_profile_params'][$y] = $row_2; - - //overwrite - $array['conference_profile_params'][$y]['conference_profile_param_uuid'] = uuid(); - $array['conference_profile_params'][$y]['conference_profile_uuid'] = $primary_uuid; - - //increment - $y++; - - } - } - unset($sql_2, $parameters_2, $rows_2, $row_2); + //convert boolean values to a string + foreach ($row_2 as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row_2[$key] = $value; } } - unset($sql, $parameters, $rows, $row); + + //copy data + $array['conference_profile_params'][$y] = $row_2; + + //overwrite + $array['conference_profile_params'][$y]['conference_profile_param_uuid'] = uuid(); + $array['conference_profile_params'][$y]['conference_profile_uuid'] = $primary_uuid; + + //increment + $y++; + + } } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('conference_profile_param_add', 'temp'); - - //save the array - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('conference_profile_param_add', 'temp'); - - //set message - message::add($text['message-copy']); - } - unset($records); + unset($sql_2, $parameters_2, $rows_2, $row_2); + } } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('conference_profile_param_add', 'temp'); + + //save the array + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('conference_profile_param_add', 'temp'); + + //set message + message::add($text['message-copy']); + } + unset($records); } } - } + +} diff --git a/app/conferences/resources/classes/conferences.php b/app/conferences/resources/classes/conferences.php index 8d48fc0ea5..03e11bd72d 100644 --- a/app/conferences/resources/classes/conferences.php +++ b/app/conferences/resources/classes/conferences.php @@ -25,396 +25,426 @@ */ //define the conferences class - class conferences { - - /** - * declare constant variables - */ - const app_name = 'conferences'; - const app_uuid = 'b81412e8-7253-91f4-e48e-42fc2c9a38d9'; - - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; - - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; - - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; - - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_name; - - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; - - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - - //set objects - $this->database = $setting_array['database'] ?? database::new(); - - //assign private variables - $this->permission_prefix = 'conference_'; - $this->list_page = 'conferences.php'; - $this->table = 'conferences'; - $this->uuid_prefix = 'conference_'; - $this->toggle_field = 'conference_enabled'; - $this->toggle_values = ['true','false']; - } - - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - - //get the dialplan uuid - $sql = "select dialplan_uuid from v_conferences "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and conference_uuid = :conference_uuid "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['conference_uuid'] = $record['uuid']; - $dialplan_uuid = $this->database->select($sql, $parameters, 'column'); - unset($sql, $parameters); - - //build array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - $array['conference_users'][$x]['conference_uuid'] = $record['uuid']; - $array['conference_users'][$x]['domain_uuid'] = $this->domain_uuid; - $array['dialplans'][$x]['dialplan_uuid'] = $dialplan_uuid; - $array['dialplans'][$x]['domain_uuid'] = $this->domain_uuid; - $array['dialplan_details'][$x]['dialplan_uuid'] = $dialplan_uuid; - $array['dialplan_details'][$x]['domain_uuid'] = $this->domain_uuid; - - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('conference_user_delete', 'temp'); - $p->add('dialplan_detail_delete', 'temp'); - $p->add('dialplan_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('conference_user_delete', 'temp'); - $p->delete('dialplan_detail_delete', 'temp'); - $p->delete('dialplan_delete', 'temp'); - - //apply settings reminder - $_SESSION["reload_xml"] = true; - - //clear the cache - $cache = new cache; - $cache->delete("dialplan:".$this->domain_name); - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-delete']); - - } - unset($records); - } - } - } - - /** - * toggle records - */ - public function toggle($records) { - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle, dialplan_uuid from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $conferences[$row['uuid']]['state'] = $row['toggle']; - $conferences[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($conferences as $uuid => $conference) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $conference['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $array['dialplans'][$x]['dialplan_uuid'] = $conference['dialplan_uuid']; - $array['dialplans'][$x]['dialplan_enabled'] = $conference['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('dialplan_edit', 'temp'); - - //save the array - - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('dialplan_edit', 'temp'); - - //apply settings reminder - $_SESSION["reload_xml"] = true; - - //clear the cache - $cache = new cache; - $cache->delete("dialplan:".$this->domain_name); - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - - } - } - - /** - * copy records - */ - public function copy($records) { - if (permission_exists($this->permission_prefix.'add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create insert array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select * from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $y = 0; - foreach ($rows as $x => $row) { - $new_conference_uuid = uuid(); - $new_dialplan_uuid = uuid(); - - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $new_conference_uuid; - $array[$this->table][$x]['dialplan_uuid'] = $new_dialplan_uuid; - $array[$this->table][$x]['conference_description'] = trim($row['conference_description'].' ('.$text['label-copy'].')'); - - //conference users sub table - $sql_2 = "select * from v_conference_users "; - $sql_2 .= "where conference_uuid = :conference_uuid "; - $sql_2 .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; - $parameters_2['conference_uuid'] = $row['conference_uuid']; - $parameters_2['domain_uuid'] = $this->domain_uuid; - $conference_users = $this->database->select($sql_2, $parameters_2, 'all'); - if (is_array($conference_users) && @sizeof($conference_users) != 0) { - foreach ($conference_users as $conference_user) { - - //convert boolean values to a string - foreach($conference_user as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $conference_user[$key] = $value; - } - } - - //copy data - $array['conference_users'][$y] = $conference_user; - - //overwrite - $array['conference_users'][$y]['conference_user_uuid'] = uuid(); - $array['conference_users'][$y]['conference_uuid'] = $new_conference_uuid; - - //increment - $y++; - - } - } - unset($sql_2, $parameters_2, $conference_users, $conference_user); - - //conference dialplan record - $sql_3 = "select * from v_dialplans where dialplan_uuid = :dialplan_uuid"; - $parameters_3['dialplan_uuid'] = $row['dialplan_uuid']; - $dialplan = $this->database->select($sql_3, $parameters_3, 'row'); - if (is_array($dialplan) && @sizeof($dialplan) != 0) { - - //convert boolean values to a string - foreach($dialplan as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $dialplan[$key] = $value; - } - } - - //copy data - $array['dialplans'][$x] = $dialplan; - - //overwrite - $array['dialplans'][$x]['dialplan_uuid'] = $new_dialplan_uuid; - $dialplan_xml = $dialplan['dialplan_xml']; - $dialplan_xml = str_replace($row['conference_uuid'], $new_conference_uuid, $dialplan_xml); //replace source conference_uuid with new - $dialplan_xml = str_replace($dialplan['dialplan_uuid'], $new_dialplan_uuid, $dialplan_xml); //replace source dialplan_uuid with new - $array['dialplans'][$x]['dialplan_xml'] = $dialplan_xml; - $array['dialplans'][$x]['dialplan_description'] = trim($dialplan['dialplan_description'].' ('.$text['label-copy'].')'); - - } - unset($sql_3, $parameters_3, $dialplan); - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('conference_user_add', 'temp'); - $p->add('dialplan_add', 'temp'); - - //save the array - - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('conference_user_add', 'temp'); - $p->delete('dialplan_add', 'temp'); - - //apply settings reminder - $_SESSION["reload_xml"] = true; - - //clear the cache - $cache = new cache; - $cache->delete("dialplan:".$this->domain_name); - - //set message - message::add($text['message-copy']); - - } - unset($records); - } - - } - } - +class conferences { + + /** + * declare constant variables + */ + const app_name = 'conferences'; + const app_uuid = 'b81412e8-7253-91f4-e48e-42fc2c9a38d9'; + + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; + + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; + + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; + + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_name; + + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; + + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + + //set objects + $this->database = $setting_array['database'] ?? database::new(); + + //assign private variables + $this->permission_prefix = 'conference_'; + $this->list_page = 'conferences.php'; + $this->table = 'conferences'; + $this->uuid_prefix = 'conference_'; + $this->toggle_field = 'conference_enabled'; + $this->toggle_values = ['true', 'false']; } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + + //get the dialplan uuid + $sql = "select dialplan_uuid from v_conferences "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and conference_uuid = :conference_uuid "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['conference_uuid'] = $record['uuid']; + $dialplan_uuid = $this->database->select($sql, $parameters, 'column'); + unset($sql, $parameters); + + //build array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + $array['conference_users'][$x]['conference_uuid'] = $record['uuid']; + $array['conference_users'][$x]['domain_uuid'] = $this->domain_uuid; + $array['dialplans'][$x]['dialplan_uuid'] = $dialplan_uuid; + $array['dialplans'][$x]['domain_uuid'] = $this->domain_uuid; + $array['dialplan_details'][$x]['dialplan_uuid'] = $dialplan_uuid; + $array['dialplan_details'][$x]['domain_uuid'] = $this->domain_uuid; + + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('conference_user_delete', 'temp'); + $p->add('dialplan_detail_delete', 'temp'); + $p->add('dialplan_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('conference_user_delete', 'temp'); + $p->delete('dialplan_detail_delete', 'temp'); + $p->delete('dialplan_delete', 'temp'); + + //apply settings reminder + $_SESSION["reload_xml"] = true; + + //clear the cache + $cache = new cache; + $cache->delete("dialplan:" . $this->domain_name); + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //set message + message::add($text['message-delete']); + + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle, dialplan_uuid from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $conferences[$row['uuid']]['state'] = $row['toggle']; + $conferences[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($conferences as $uuid => $conference) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $conference['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $array['dialplans'][$x]['dialplan_uuid'] = $conference['dialplan_uuid']; + $array['dialplans'][$x]['dialplan_enabled'] = $conference['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('dialplan_edit', 'temp'); + + //save the array + + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('dialplan_edit', 'temp'); + + //apply settings reminder + $_SESSION["reload_xml"] = true; + + //clear the cache + $cache = new cache; + $cache->delete("dialplan:" . $this->domain_name); + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->permission_prefix . 'add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create insert array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select * from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $y = 0; + foreach ($rows as $x => $row) { + $new_conference_uuid = uuid(); + $new_dialplan_uuid = uuid(); + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; + } + } + + //copy data + $array[$this->table][$x] = $row; + + //overwrite + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $new_conference_uuid; + $array[$this->table][$x]['dialplan_uuid'] = $new_dialplan_uuid; + $array[$this->table][$x]['conference_description'] = trim($row['conference_description'] . ' (' . $text['label-copy'] . ')'); + + //conference users sub table + $sql_2 = "select * from v_conference_users "; + $sql_2 .= "where conference_uuid = :conference_uuid "; + $sql_2 .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; + $parameters_2['conference_uuid'] = $row['conference_uuid']; + $parameters_2['domain_uuid'] = $this->domain_uuid; + $conference_users = $this->database->select($sql_2, $parameters_2, 'all'); + if (is_array($conference_users) && @sizeof($conference_users) != 0) { + foreach ($conference_users as $conference_user) { + + //convert boolean values to a string + foreach ($conference_user as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $conference_user[$key] = $value; + } + } + + //copy data + $array['conference_users'][$y] = $conference_user; + + //overwrite + $array['conference_users'][$y]['conference_user_uuid'] = uuid(); + $array['conference_users'][$y]['conference_uuid'] = $new_conference_uuid; + + //increment + $y++; + + } + } + unset($sql_2, $parameters_2, $conference_users, $conference_user); + + //conference dialplan record + $sql_3 = "select * from v_dialplans where dialplan_uuid = :dialplan_uuid"; + $parameters_3['dialplan_uuid'] = $row['dialplan_uuid']; + $dialplan = $this->database->select($sql_3, $parameters_3, 'row'); + if (is_array($dialplan) && @sizeof($dialplan) != 0) { + + //convert boolean values to a string + foreach ($dialplan as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $dialplan[$key] = $value; + } + } + + //copy data + $array['dialplans'][$x] = $dialplan; + + //overwrite + $array['dialplans'][$x]['dialplan_uuid'] = $new_dialplan_uuid; + $dialplan_xml = $dialplan['dialplan_xml']; + $dialplan_xml = str_replace($row['conference_uuid'], $new_conference_uuid, $dialplan_xml); //replace source conference_uuid with new + $dialplan_xml = str_replace($dialplan['dialplan_uuid'], $new_dialplan_uuid, $dialplan_xml); //replace source dialplan_uuid with new + $array['dialplans'][$x]['dialplan_xml'] = $dialplan_xml; + $array['dialplans'][$x]['dialplan_description'] = trim($dialplan['dialplan_description'] . ' (' . $text['label-copy'] . ')'); + + } + unset($sql_3, $parameters_3, $dialplan); + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('conference_user_add', 'temp'); + $p->add('dialplan_add', 'temp'); + + //save the array + + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('conference_user_add', 'temp'); + $p->delete('dialplan_add', 'temp'); + + //apply settings reminder + $_SESSION["reload_xml"] = true; + + //clear the cache + $cache = new cache; + $cache->delete("dialplan:" . $this->domain_name); + + //set message + message::add($text['message-copy']); + + } + unset($records); + } + + } + } + +} diff --git a/app/conferences_active/conference_exec.php b/app/conferences_active/conference_exec.php index 03d6f395f9..3fa0215a41 100644 --- a/app/conferences_active/conference_exec.php +++ b/app/conferences_active/conference_exec.php @@ -143,6 +143,13 @@ } //define an alternative kick all + /** + * Ends a conference by killing all its members and destroying the session. + * + * @param string $name The name of the conference to end. + * + * @return void + */ function conference_end($name) { $switch_cmd = "conference '".$name."' xml_list"; $xml_str = trim(event_socket::api($switch_cmd)); diff --git a/app/database_transactions/database_transaction_edit.php b/app/database_transactions/database_transaction_edit.php index 8d8e5eb8bb..dd6fac7870 100644 --- a/app/database_transactions/database_transaction_edit.php +++ b/app/database_transactions/database_transaction_edit.php @@ -236,6 +236,20 @@ //define the array _difference function //this adds old and new values to the array + /** + * Calculates the difference between two arrays. + * + * This function recursively iterates through both input arrays, comparing each key-value pair. If a value in $array2 is not present in $array1, + * it is marked as 'new' in the returned array. If a value in $array1 is not present in $array2, it is also included in the returned array with a marker + * indicating its origin. + * + * The function handles nested arrays by recursively calling itself for matching keys. + * + * @param mixed[] $array1 The first input array to compare. + * @param mixed[] $array2 The second input array to compare. + * + * @return mixed[] An array containing the differences between the two input arrays, with added markers indicating origin. + */ function array_difference($array1, $array2) { $array = array(); if (is_array($array1)) { diff --git a/app/database_transactions/resources/classes/database_transactions.php b/app/database_transactions/resources/classes/database_transactions.php index 96b409e819..dfeb9a3468 100644 --- a/app/database_transactions/resources/classes/database_transactions.php +++ b/app/database_transactions/resources/classes/database_transactions.php @@ -36,7 +36,9 @@ class database_transactions { /** * Removes old entries for in the database database_transactions table * see {@link https://github.com/fusionpbx/fusionpbx-app-maintenance/} FusionPBX Maintenance App + * * @param settings $settings Settings object + * * @return void */ public static function database_maintenance(settings $settings): void { diff --git a/app/destinations/destination_download.php b/app/destinations/destination_download.php index 034bd23782..5958784bbc 100644 --- a/app/destinations/destination_download.php +++ b/app/destinations/destination_download.php @@ -73,6 +73,17 @@ $available_columns[] = 'destination_order'; //define the functions + /** + * Converts an associative or numerical array into a CSV string. + * + * This function takes an array and returns its contents as a properly formatted + * CSV string. If the input array is empty, it will return null. + * + * @param array $array The array to be converted into a CSV string. + * It can be either an associative or numerical array. + * + * @return string A CSV string representation of the input array, or null if the array is empty. + */ function array2csv(array &$array) { if (count($array) == 0) { return null; @@ -87,6 +98,17 @@ return ob_get_clean(); } + /** + * Sends HTTP headers for a file download. + * + * This function sends the necessary HTTP headers to force the browser to download + * a file instead of displaying it in the browser. The filename specified should be + * a path to the file on the server, not a URL. + * + * @param string $filename The name and path to the file that will be downloaded by the client. + * + * @return void This function does not return anything. + */ function download_send_headers($filename) { // disable caching $now = gmdate("D, d M Y H:i:s"); diff --git a/app/destinations/destination_imports.php b/app/destinations/destination_imports.php index 9c408c8db7..65784026b7 100644 --- a/app/destinations/destination_imports.php +++ b/app/destinations/destination_imports.php @@ -38,18 +38,6 @@ $language = new text; $text = $language->get(); -//built in str_getcsv requires PHP 5.3 or higher, this function can be used to reproduct the functionality but requirs PHP 5.1.0 or higher - if(!function_exists('str_getcsv')) { - function str_getcsv($input, $delimiter = ",", $enclosure = '"', $escape = "\\") { - $fp = fopen("php://memory", 'r+'); - fputs($fp, $input); - rewind($fp); - $data = fgetcsv($fp, null, $delimiter, $enclosure); // $escape only got added in 5.3.0 - fclose($fp); - return $data; - } - } - //get the http get values and set them as php variables $action = $_POST["action"] ?? null; $from_row = $_POST["from_row"] ?? null; @@ -132,6 +120,14 @@ } //get the parent table + /** + * Retrieves the parent table of a given table in a database schema. + * + * @param array $schema Database schema containing table information + * @param string $table_name Name of the table for which to retrieve the parent + * + * @return mixed Parent table name, or null if no matching table is found + */ function get_parent($schema,$table_name) { foreach ($schema as $row) { if ($row['table'] == $table_name) { diff --git a/app/destinations/destinations.php b/app/destinations/destinations.php index 78047ad224..6f0c6693b9 100644 --- a/app/destinations/destinations.php +++ b/app/destinations/destinations.php @@ -79,6 +79,14 @@ $destination_array = $destination->all('dialplan'); //function to return the action names in the order defined + /** + * Returns a list of actions based on the provided destination array and actions. + * + * @param array $destination_array The array containing the data to process. + * @param array $destination_actions The array of actions to apply to the destination array. + * + * @return array A list of actions resulting from the processing of the destination array and actions. + */ function action_name($destination_array, $destination_actions) { global $settings; $actions = []; @@ -175,8 +183,8 @@ $page = $_GET['page']; } if (!isset($page)) { $page = 0; $_GET['page'] = 0; } - list($paging_controls, $rows_per_page) = paging($num_rows, $param, $rows_per_page); - list($paging_controls_mini, $rows_per_page) = paging($num_rows, $param, $rows_per_page, true); + [$paging_controls, $rows_per_page] = paging($num_rows, $param, $rows_per_page); + [$paging_controls_mini, $rows_per_page] = paging($num_rows, $param, $rows_per_page, true); $offset = $rows_per_page * $page; //get the list diff --git a/app/devices/device_download.php b/app/devices/device_download.php index 5b341772ec..91c898c124 100644 --- a/app/devices/device_download.php +++ b/app/devices/device_download.php @@ -51,6 +51,21 @@ $label_required = $text['label-required']; //define the functions + /** + * Converts a multi-dimensional array to CSV format. + * + * This function assumes that the input array is a collection of devices, + * where each device has an array of columns. The function will take all + * column headers from all devices and use them as the header row in the + * generated CSV file. + * + * If any duplicate column headers are found, they will be removed by + * truncating at the pipe character (|). + * + * @param array &$array A multi-dimensional array of device data. + * + * @return string The CSV formatted data as a string. Returns null if the input array is empty. + */ function array2csv(array &$array) { if (count($array) == 0) { return null; @@ -86,6 +101,15 @@ return ob_get_clean(); } + /** + * Sends HTTP headers to force a file download. + * + * This function sets various HTTP headers to instruct the browser to download the file instead of displaying it in the browser window. + * + * @param string $filename The filename to use for the downloaded file. + * + * @return void No return value. This function only sends HTTP headers and does not generate any output. + */ function download_send_headers($filename) { // disable caching $now = gmdate("D, d M Y H:i:s"); diff --git a/app/devices/device_imports.php b/app/devices/device_imports.php index af50f49496..160a488770 100644 --- a/app/devices/device_imports.php +++ b/app/devices/device_imports.php @@ -38,18 +38,6 @@ $language = new text; $text = $language->get(); -//built in str_getcsv requires PHP 5.3 or higher, this function can be used to reproduct the functionality but requirs PHP 5.1.0 or higher - if (!function_exists('str_getcsv')) { - function str_getcsv($input, $delimiter = ",", $enclosure = '"', $escape = "\\") { - $fp = fopen("php://memory", 'r+'); - fputs($fp, $input); - rewind($fp); - $data = fgetcsv($fp, null, $delimiter, $enclosure, $escape); - fclose($fp); - return $data; - } - } - //set the max php execution time ini_set('max_execution_time',7200); @@ -225,7 +213,15 @@ } //get the parent table - function get_parent($schema,$table_name) { + /** + * Retrieves the parent table name for a given table in the schema. + * + * @param array $schema An associative array of schema definitions + * @param string $table_name The name of the table to retrieve the parent for + * + * @return string|null The parent table name if found, otherwise null + */ + function get_parent($schema, $table_name) { foreach ($schema as $row) { if ($row['table'] == $table_name) { return $row['parent']; diff --git a/app/devices/resources/classes/device.php b/app/devices/resources/classes/device.php index 9e3e940349..32d05393e0 100644 --- a/app/devices/resources/classes/device.php +++ b/app/devices/resources/classes/device.php @@ -25,1423 +25,1557 @@ */ //define the device class - class device { +class device { - /** - * declare constant variables - */ - const app_name = 'devices'; - const app_uuid = '4efa1a1a-32e7-bf83-534b-6c8299958a8e'; + /** + * declare constant variables + */ + const app_name = 'devices'; + const app_uuid = '4efa1a1a-32e7-bf83-534b-6c8299958a8e'; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_uuid; - /** - * declare public variables - */ - public $template_dir; - public $device_uuid; - public $device_vendor_uuid; - public $device_profile_uuid; + /** + * declare public variables + */ + public $template_dir; + public $device_uuid; + public $device_vendor_uuid; + public $device_profile_uuid; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * Username set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $username; + /** + * Username set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $username; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_name; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; - private $tables; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; + private $tables; - /** - * Create a settings object using key/value pairs in the $setting_array. - * - * Valid values are: database. - * @param array setting_array - * @depends database::new() - * @access public - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + } + + /** + * Retrieves the domain UUID. + * + * @return string The domain UUID. + */ + public function get_domain_uuid() { + return $this->domain_uuid; + } + + /** + * Retrieves the device vendor from a given MAC address. + * + * @param string $mac The MAC address to retrieve the vendor for. + * + * @return string The device vendor, or an empty string if the MAC address is invalid. + */ + public static function get_vendor($mac) { + //return if the mac address is empty + if (empty($mac)) { + return ''; } - public function get_domain_uuid() { - return $this->domain_uuid; + //use the mac address to find the vendor + $mac = preg_replace('#[^a-fA-F0-9./]#', '', $mac); + $mac = strtolower($mac); + switch (substr($mac, 0, 6)) { + case "00085d": + $device_vendor = "aastra"; + break; + case "00040d": + $device_vendor = "avaya"; + break; + case "001b4f": + $device_vendor = "avaya"; + break; + case "00549f": + $device_vendor = "avaya"; + break; + case "048a15": + $device_vendor = "avaya"; + break; + case "10cdae": + $device_vendor = "avaya"; + break; + case "14612f": + $device_vendor = "avaya"; + break; + case "24b209": + $device_vendor = "avaya"; + break; + case "24d921": + $device_vendor = "avaya"; + break; + case "2cf4c5": + $device_vendor = "avaya"; + break; + case "3475c7": + $device_vendor = "avaya"; + break; + case "38bb3c": + $device_vendor = "avaya"; + break; + case "3c3a73": + $device_vendor = "avaya"; + break; + case "3cb15b": + $device_vendor = "avaya"; + break; + case "44322a": + $device_vendor = "avaya"; + break; + case "506184": + $device_vendor = "avaya"; + break; + case "50cd22": + $device_vendor = "avaya"; + break; + case "581626": + $device_vendor = "avaya"; + break; + case "6049c1": + $device_vendor = "avaya"; + break; + case "646a52": + $device_vendor = "avaya"; + break; + case "64a7dd": + $device_vendor = "avaya"; + break; + case "64c354": + $device_vendor = "avaya"; + break; + case "6ca849": + $device_vendor = "avaya"; + break; + case "6cfa58": + $device_vendor = "avaya"; + break; + case "703018": + $device_vendor = "avaya"; + break; + case "7038ee": + $device_vendor = "avaya"; + break; + case "7052c5": + $device_vendor = "avaya"; + break; + case "707c69": + $device_vendor = "avaya"; + break; + case "801daa": + $device_vendor = "avaya"; + break; + case "848371": + $device_vendor = "avaya"; + break; + case "90fb5b": + $device_vendor = "avaya"; + break; + case "a009ed": + $device_vendor = "avaya"; + break; + case "a01290": + $device_vendor = "avaya"; + break; + case "a051c6": + $device_vendor = "avaya"; + break; + case "a4251b": + $device_vendor = "avaya"; + break; + case "a47886": + $device_vendor = "avaya"; + break; + case "b0adaa": + $device_vendor = "avaya"; + break; + case "b4475e": + $device_vendor = "avaya"; + break; + case "b4a95a": + $device_vendor = "avaya"; + break; + case "b4b017": + $device_vendor = "avaya"; + break; + case "bcadab": + $device_vendor = "avaya"; + break; + case "c057bc": + $device_vendor = "avaya"; + break; + case "c4bed4": + $device_vendor = "avaya"; + break; + case "c81fea": + $device_vendor = "avaya"; + break; + case "c8f406": + $device_vendor = "avaya"; + break; + case "ccf954": + $device_vendor = "avaya"; + break; + case "d47856": + $device_vendor = "avaya"; + break; + case "d4ea0e": + $device_vendor = "avaya"; + break; + case "e45d52": + $device_vendor = "avaya"; + break; + case "f81547": + $device_vendor = "avaya"; + break; + case "f873a2": + $device_vendor = "avaya"; + break; + case "fc8399": + $device_vendor = "avaya"; + break; + case "fca841": + $device_vendor = "avaya"; + break; + case "001873": + $device_vendor = "cisco"; + break; + case "a44c11": + $device_vendor = "cisco"; + break; + case "0021A0": + $device_vendor = "cisco"; + break; + case "30e4db": + $device_vendor = "cisco"; + break; + case "002155": + $device_vendor = "cisco"; + break; + case "68efbd": + $device_vendor = "cisco"; + break; + case "000b82": + $device_vendor = "grandstream"; + break; + case "00177d": + $device_vendor = "konftel"; + break; + case "00045a": + $device_vendor = "linksys"; + break; + case "000625": + $device_vendor = "linksys"; + break; + case "000e08": + $device_vendor = "linksys"; + break; + case "08000f": + $device_vendor = "mitel"; + break; + case "0080f0": + $device_vendor = "panasonic"; + break; + case "0004f2": + $device_vendor = "polycom"; + break; + case "00907a": + $device_vendor = "polycom"; + break; + case "64167f": + $device_vendor = "polycom"; + break; + case "482567": + $device_vendor = "polycom"; + break; + case "000413": + $device_vendor = "snom"; + break; + case "001565": + $device_vendor = "yealink"; + break; + case "805ec0": + $device_vendor = "yealink"; + break; + case "00268B": + $device_vendor = "escene"; + break; + case "001fc1": + $device_vendor = "htek"; + break; + case "0C383E": + $device_vendor = "fanvil"; + break; + case "7c2f80": + $device_vendor = "gigaset"; + break; + case "14b370": + $device_vendor = "gigaset"; + break; + case "002104": + $device_vendor = "gigaset"; + break; + case "bcc342": + $device_vendor = "panasonic"; + break; + case "080023": + $device_vendor = "panasonic"; + break; + case "0080f0": + $device_vendor = "panasonic"; + break; + case "0021f2": + $device_vendor = "flyingvoice"; + break; + case "f00786": + $device_vendor = "bittel"; + break; + default: + $device_vendor = ""; + } + return $device_vendor; + } + + /** + * Returns the vendor of a given user agent string. + * + * @param string $agent The user agent string to determine the vendor from. + * + * @return string The identified vendor, or an empty string if no match is found. + */ + public static function get_vendor_by_agent($agent) { + if ($agent) { + //set the user agent string to lower case + $agent = strtolower($agent); + //get the vendor + if (preg_replace('/^.*?(aastra).*$/i', '$1', $agent) == "aastra") { + return "aastra"; + } + if (preg_replace('/^.*?(algo).*$/i', '$1', $agent) == "algo") { + return "algo"; + } + if (preg_replace('/^.*?(cisco\/spa).*$/i', '$1', $agent) == "cisco/spa") { + return "cisco-spa"; + } + if (preg_replace('/^.*?(cisco).*$/i', '$1', $agent) == "cisco") { + return "cisco"; + } + if (preg_replace('/^.*?(digium).*$/i', '$1', $agent) == "digium") { + return "digium"; + } + if (preg_replace('/^.*?(grandstream).*$/i', '$1', $agent) == "grandstream") { + return "grandstream"; + } + if (preg_replace('/^.*?(linksys).*$/i', '$1', $agent) == "linksys") { + return "linksys"; + } + if (preg_replace('/^.*?(polycom).*$/i', '$1', $agent) == "polycom") { + return "polycom"; + } + if (preg_replace('/^.*?(poly).*$/i', '$1', $agent) == "poly") { + return "poly"; + } + if (preg_replace('/^.*?(yealink).*$/i', '$1', $agent) == "yealink") { + return "yealink"; + } + if (preg_replace('/^.*?(vp530p).*$/i', '$1', $agent) == "vp530p") { + return "yealink"; + } + if (preg_replace('/^.*?(snom).*$/i', '$1', $agent) == "snom") { + return "snom"; + } + if (preg_match('/^.*?addpac.*$/i', $agent)) { + return "addpac"; + } + /*Escene use User-Agent string like `ES320VN2 v4.0 ... or `ES206 v1.0 ...` */ + if (preg_match('/^es\d\d\d.*$/i', $agent)) { + return "escene"; + } + if (preg_match('/^.*?panasonic.*$/i', $agent)) { + return "panasonic"; + } + if (preg_replace('/^.*?(N510).*$/i', '$1', $agent) == "n510") { + return "gigaset"; + } + if (preg_match('/^.*?htek.*$/i', $agent)) { + return "htek"; + } + if (preg_replace('/^.*?(fanvil).*$/i', '$1', $agent) == "fanvil") { + return "fanvil"; + } + if (preg_replace('/^.*?(flyingvoice).*$/i', '$1', $agent) == "flyingvoice") { + return "flyingvoice"; + } + if (preg_replace('/^.*?(avaya).*$/i', '$1', $agent) == "avaya") { + return "avaya"; + } + if (preg_replace('/^.*?(BITTEL).*$/i', '$1', $agent) == "bittel") { + return "bittel"; + } + // unknown vendor + return ""; + } + } + + /** + * Returns the directory where FusionPBX templates are stored. + * + * This method checks various locations on different operating systems to find the default template directory. + * If a domain name subdirectory exists in the selected template directory, it will be used instead. + * + * @return string The path to the template directory. + */ + public function get_template_dir() { + //set the default template directory + if (PHP_OS == "Linux") { + //set the default template dir + if (empty($this->template_dir)) { + if (file_exists('/usr/share/fusionpbx/templates/provision')) { + $this->template_dir = '/usr/share/fusionpbx/templates/provision'; + } elseif (file_exists('/etc/fusionpbx/resources/templates/provision')) { + $this->template_dir = '/etc/fusionpbx/resources/templates/provision'; + } else { + $this->template_dir = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/resources/templates/provision'; + } + } + } elseif (PHP_OS == "FreeBSD") { + //if the FreeBSD port is installed use the following paths by default. + if (empty($this->template_dir)) { + if (file_exists('/usr/local/share/fusionpbx/templates/provision')) { + $this->template_dir = '/usr/local/share/fusionpbx/templates/provision'; + } elseif (file_exists('/usr/local/etc/fusionpbx/resources/templates/provision')) { + $this->template_dir = '/usr/local/etc/fusionpbx/resources/templates/provision'; + } else { + $this->template_dir = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/resources/templates/provision'; + } + } + } elseif (PHP_OS == "NetBSD") { + //set the default template_dir + if (empty($this->template_dir)) { + $this->template_dir = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/resources/templates/provision'; + } + } elseif (PHP_OS == "OpenBSD") { + //set the default template_dir + if (empty($this->template_dir)) { + $this->template_dir = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/resources/templates/provision'; + } + } else { + //set the default template_dir + if (empty($this->template_dir)) { + $this->template_dir = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/resources/templates/provision'; + } } - public static function get_vendor($mac) { - //return if the mac address is empty - if(empty($mac)) { - return ''; + //check to see if the domain name sub directory exists + if (is_dir($this->template_dir . "/" . $this->domain_name)) { + $this->template_dir = $this->template_dir . "/" . $this->domain_name; + } + + //return the template directory + return $this->template_dir; + } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + + //assign private variables + $this->permission_prefix = 'device_'; + $this->list_page = 'devices.php'; + $this->table = 'devices'; + $this->uuid_prefix = 'device_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $sql = "update v_devices set device_uuid_alternate = null where device_uuid_alternate = :device_uuid_alternate; "; + $parameters['device_uuid_alternate'] = $record['uuid']; + $this->database->execute($sql, $parameters); + unset($sql, $parameters); + + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array['device_settings'][$x]['device_uuid'] = $record['uuid']; + $array['device_lines'][$x]['device_uuid'] = $record['uuid']; + $array['device_keys'][$x]['device_uuid'] = $record['uuid']; + } } - //use the mac address to find the vendor - $mac = preg_replace('#[^a-fA-F0-9./]#', '', $mac); - $mac = strtolower($mac); - switch (substr($mac, 0, 6)) { - case "00085d": - $device_vendor = "aastra"; - break; - case "00040d": - $device_vendor = "avaya"; - break; - case "001b4f": - $device_vendor = "avaya"; - break; - case "00549f": - $device_vendor = "avaya"; - break; - case "048a15": - $device_vendor = "avaya"; - break; - case "10cdae": - $device_vendor = "avaya"; - break; - case "14612f": - $device_vendor = "avaya"; - break; - case "24b209": - $device_vendor = "avaya"; - break; - case "24d921": - $device_vendor = "avaya"; - break; - case "2cf4c5": - $device_vendor = "avaya"; - break; - case "3475c7": - $device_vendor = "avaya"; - break; - case "38bb3c": - $device_vendor = "avaya"; - break; - case "3c3a73": - $device_vendor = "avaya"; - break; - case "3cb15b": - $device_vendor = "avaya"; - break; - case "44322a": - $device_vendor = "avaya"; - break; - case "506184": - $device_vendor = "avaya"; - break; - case "50cd22": - $device_vendor = "avaya"; - break; - case "581626": - $device_vendor = "avaya"; - break; - case "6049c1": - $device_vendor = "avaya"; - break; - case "646a52": - $device_vendor = "avaya"; - break; - case "64a7dd": - $device_vendor = "avaya"; - break; - case "64c354": - $device_vendor = "avaya"; - break; - case "6ca849": - $device_vendor = "avaya"; - break; - case "6cfa58": - $device_vendor = "avaya"; - break; - case "703018": - $device_vendor = "avaya"; - break; - case "7038ee": - $device_vendor = "avaya"; - break; - case "7052c5": - $device_vendor = "avaya"; - break; - case "707c69": - $device_vendor = "avaya"; - break; - case "801daa": - $device_vendor = "avaya"; - break; - case "848371": - $device_vendor = "avaya"; - break; - case "90fb5b": - $device_vendor = "avaya"; - break; - case "a009ed": - $device_vendor = "avaya"; - break; - case "a01290": - $device_vendor = "avaya"; - break; - case "a051c6": - $device_vendor = "avaya"; - break; - case "a4251b": - $device_vendor = "avaya"; - break; - case "a47886": - $device_vendor = "avaya"; - break; - case "b0adaa": - $device_vendor = "avaya"; - break; - case "b4475e": - $device_vendor = "avaya"; - break; - case "b4a95a": - $device_vendor = "avaya"; - break; - case "b4b017": - $device_vendor = "avaya"; - break; - case "bcadab": - $device_vendor = "avaya"; - break; - case "c057bc": - $device_vendor = "avaya"; - break; - case "c4bed4": - $device_vendor = "avaya"; - break; - case "c81fea": - $device_vendor = "avaya"; - break; - case "c8f406": - $device_vendor = "avaya"; - break; - case "ccf954": - $device_vendor = "avaya"; - break; - case "d47856": - $device_vendor = "avaya"; - break; - case "d4ea0e": - $device_vendor = "avaya"; - break; - case "e45d52": - $device_vendor = "avaya"; - break; - case "f81547": - $device_vendor = "avaya"; - break; - case "f873a2": - $device_vendor = "avaya"; - break; - case "fc8399": - $device_vendor = "avaya"; - break; - case "fca841": - $device_vendor = "avaya"; - break; - case "001873": - $device_vendor = "cisco"; - break; - case "a44c11": - $device_vendor = "cisco"; - break; - case "0021A0": - $device_vendor = "cisco"; - break; - case "30e4db": - $device_vendor = "cisco"; - break; - case "002155": - $device_vendor = "cisco"; - break; - case "68efbd": - $device_vendor = "cisco"; - break; - case "000b82": - $device_vendor = "grandstream"; - break; - case "00177d": - $device_vendor = "konftel"; - break; - case "00045a": - $device_vendor = "linksys"; - break; - case "000625": - $device_vendor = "linksys"; - break; - case "000e08": - $device_vendor = "linksys"; - break; - case "08000f": - $device_vendor = "mitel"; - break; - case "0080f0": - $device_vendor = "panasonic"; - break; - case "0004f2": - $device_vendor = "polycom"; - break; - case "00907a": - $device_vendor = "polycom"; - break; - case "64167f": - $device_vendor = "polycom"; - break; - case "482567": - $device_vendor = "polycom"; - break; - case "000413": - $device_vendor = "snom"; - break; - case "001565": - $device_vendor = "yealink"; - break; - case "805ec0": - $device_vendor = "yealink"; - break; - case "00268B": - $device_vendor = "escene"; - break; - case "001fc1": - $device_vendor = "htek"; - break; - case "0C383E": - $device_vendor = "fanvil"; - break; - case "7c2f80": - $device_vendor = "gigaset"; - break; - case "14b370": - $device_vendor = "gigaset"; - break; - case "002104": - $device_vendor = "gigaset"; - break; - case "bcc342": - $device_vendor = "panasonic"; - break; - case "080023": - $device_vendor = "panasonic"; - break; - case "0080f0": - $device_vendor = "panasonic"; - break; - case "0021f2": - $device_vendor = "flyingvoice"; - break; - case "f00786": - $device_vendor = "bittel"; - break; - default: - $device_vendor = ""; - } - return $device_vendor; - } + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { - public static function get_vendor_by_agent($agent){ - if ($agent) { - //set the user agent string to lower case - $agent = strtolower($agent); - //get the vendor - if (preg_replace('/^.*?(aastra).*$/i', '$1', $agent) == "aastra") { - return "aastra"; - } - if (preg_replace('/^.*?(algo).*$/i', '$1', $agent) == "algo") { - return "algo"; - } - if (preg_replace('/^.*?(cisco\/spa).*$/i', '$1', $agent) == "cisco/spa") { - return "cisco-spa"; - } - if (preg_replace('/^.*?(cisco).*$/i', '$1', $agent) == "cisco") { - return "cisco"; - } - if (preg_replace('/^.*?(digium).*$/i', '$1', $agent) == "digium") { - return "digium"; - } - if (preg_replace('/^.*?(grandstream).*$/i', '$1', $agent) == "grandstream") { - return "grandstream"; - } - if (preg_replace('/^.*?(linksys).*$/i', '$1', $agent) == "linksys") { - return "linksys"; - } - if (preg_replace('/^.*?(polycom).*$/i', '$1', $agent) == "polycom") { - return "polycom"; - } - if (preg_replace('/^.*?(poly).*$/i', '$1', $agent) == "poly") { - return "poly"; - } - if (preg_replace('/^.*?(yealink).*$/i', '$1', $agent) == "yealink") { - return "yealink"; - } - if (preg_replace('/^.*?(vp530p).*$/i', '$1', $agent) == "vp530p") { - return "yealink"; - } - if (preg_replace('/^.*?(snom).*$/i', '$1', $agent) == "snom") { - return "snom"; - } - if (preg_match('/^.*?addpac.*$/i', $agent)) { - return "addpac"; - } - /*Escene use User-Agent string like `ES320VN2 v4.0 ... or `ES206 v1.0 ...` */ - if (preg_match('/^es\d\d\d.*$/i', $agent)) { - return "escene"; - } - if (preg_match('/^.*?panasonic.*$/i', $agent)) { - return "panasonic"; - } - if (preg_replace('/^.*?(N510).*$/i', '$1', $agent) == "n510") { - return "gigaset"; - } - if (preg_match('/^.*?htek.*$/i', $agent)) { - return "htek"; - } - if (preg_replace('/^.*?(fanvil).*$/i', '$1', $agent) == "fanvil") { - return "fanvil"; - } - if (preg_replace('/^.*?(flyingvoice).*$/i', '$1', $agent) == "flyingvoice") { - return "flyingvoice"; - } - if (preg_replace('/^.*?(avaya).*$/i', '$1', $agent) == "avaya") { - return "avaya"; - } - if (preg_replace('/^.*?(BITTEL).*$/i', '$1', $agent) == "bittel") { - return "bittel"; - } - // unknown vendor - return ""; - } - } + //grant temporary permissions + $p = permissions::new(); + $p->add('device_setting_delete', 'temp'); + $p->add('device_line_delete', 'temp'); + $p->add('device_key_delete', 'temp'); - public function get_template_dir() { - //set the default template directory - if (PHP_OS == "Linux") { - //set the default template dir - if (empty($this->template_dir)) { - if (file_exists('/usr/share/fusionpbx/templates/provision')) { - $this->template_dir = '/usr/share/fusionpbx/templates/provision'; - } - elseif (file_exists('/etc/fusionpbx/resources/templates/provision')) { - $this->template_dir = '/etc/fusionpbx/resources/templates/provision'; - } - else { - $this->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/resources/templates/provision'; - } + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('device_setting_delete', 'temp'); + $p->delete('device_line_delete', 'temp'); + $p->delete('device_key_delete', 'temp'); + + //write the provision files + if (!empty($this->settings->get('provision', 'path'))) { + $prov = new provision; + $prov->domain_uuid = $this->domain_uuid; + $response = $prov->write(); + } + + //set message + message::add($text['message-delete']); + + } + unset($records); + } + } + } + + /** + * Deletes one or more device lines from the database. + * + * @param array $records A list of records to be deleted, where each record is an associative array containing + * 'uuid' and optionally 'device_uuid'. + * + * @return void + */ + public function delete_lines($records) { + //assign private variables + $this->permission_prefix = 'device_line_'; + $this->table = 'device_lines'; + $this->uuid_prefix = 'device_line_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked device lines, build delete array + $x = 0; + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['device_uuid'] = $this->device_uuid; + $x++; + } + } + + //delete the checked rows + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); + } + unset($records); + } + } + } + + /** + * Deletes multiple device key records. + * + * @param array $records An array of device key records to delete, where each record is an associative array + * containing the uuid and checked status. + * + * @return void + */ + public function delete_keys($records) { + //assign private variables + $this->permission_prefix = 'device_key_'; + $this->table = 'device_keys'; + $this->uuid_prefix = 'device_key_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked device keys, build delete array + $x = 0; + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['device_uuid'] = $this->device_uuid; + $x++; + } + } + + //delete the checked rows + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); + } + unset($records); + } + } + } + + /** + * Deletes multiple device settings records. + * + * This method checks if the user has permission to delete device settings and validates the token. + * It then filters out unchecked device settings, builds a delete array, and executes the deletion. + * + * @param array $records An array of device setting records to be deleted, where each record contains 'uuid' and + * 'checked' keys. + * + * @return void + */ + public function delete_settings($records) { + //assign private variables + $this->permission_prefix = 'device_setting_'; + $this->table = 'device_settings'; + $this->uuid_prefix = 'device_setting_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked device settings, build delete array + $x = 0; + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['device_uuid'] = $this->device_uuid; + $x++; + } + } + + //delete the checked rows + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); + } + unset($records); + } + } + } + + /** + * Deletes the specified vendors. + * + * @param array $records The list of vendor records to delete, where each record is an associative array containing + * the vendor's UUID and a 'checked' flag indicating whether the vendor should be deleted. + * + * @return void + */ + public function delete_vendors($records) { + + //assign private variables + $this->permission_prefix = 'device_vendor_'; + $this->list_page = 'device_vendors.php'; + $this->tables[] = 'device_vendors'; + $this->tables[] = 'device_vendor_functions'; + $this->tables[] = 'device_vendor_function_groups'; + $this->uuid_prefix = 'device_vendor_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + foreach ($this->tables as $table) { + $array[$table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; } + } } - elseif (PHP_OS == "FreeBSD") { - //if the FreeBSD port is installed use the following paths by default. - if (empty($this->template_dir)) { - if (file_exists('/usr/local/share/fusionpbx/templates/provision')) { - $this->template_dir = '/usr/local/share/fusionpbx/templates/provision'; - } - elseif (file_exists('/usr/local/etc/fusionpbx/resources/templates/provision')) { - $this->template_dir = '/usr/local/etc/fusionpbx/resources/templates/provision'; - } - else { - $this->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/resources/templates/provision'; - } + + //delete the checked rows + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('device_vendor_function_delete', 'temp'); + $p->add('device_vendor_function_group_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('device_vendor_function_delete', 'temp'); + $p->delete('device_vendor_function_group_delete', 'temp'); + + //set message + message::add($text['message-delete']); + + } + unset($records); + } + } + } + + /** + * Deletes vendor functions based on the provided records. + * + * @param array $records An array of records containing information about the rows to delete, + * where each record is an associative array with 'checked' and 'uuid' keys. + * + * @return void + */ + public function delete_vendor_functions($records) { + + //assign private variables + $this->permission_prefix = 'device_vendor_function_'; + $this->list_page = 'device_vendor_edit.php'; + $this->tables[] = 'device_vendor_functions'; + $this->tables[] = 'device_vendor_function_groups'; + $this->uuid_prefix = 'device_vendor_function_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate('/app/devices/device_vendor_functions.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page . '?id=' . $this->device_vendor_uuid); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + foreach ($this->tables as $table) { + $array[$table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; } + } } - elseif (PHP_OS == "NetBSD") { - //set the default template_dir - if (empty($this->template_dir)) { - $this->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/resources/templates/provision'; + + //delete the checked rows + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('device_vendor_function_group_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('device_vendor_function_group_delete', 'temp'); + + //set message + message::add($text['message-delete']); + + } + unset($records); + } + } + } + + /** + * Deletes multiple device profiles. + * + * @param array $records The list of records to delete, where each record is an associative array containing the + * UUID and a 'checked' key indicating whether the profile should be deleted. + * + * @return void + */ + public function delete_profiles($records) { + + //assign private variables + $this->permission_prefix = 'device_profile_'; + $this->list_page = 'device_profiles.php'; + $this->tables[] = 'device_profiles'; + $this->tables[] = 'device_profile_keys'; + $this->tables[] = 'device_profile_settings'; + $this->uuid_prefix = 'device_profile_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + foreach ($this->tables as $table) { + $array[$table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; } + } } - elseif (PHP_OS == "OpenBSD") { - //set the default template_dir - if (empty($this->template_dir)) { - $this->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/resources/templates/provision'; + + //delete the checked rows + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('device_profile_key_delete', 'temp'); + $p->add('device_profile_setting_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('device_profile_key_delete', 'temp'); + $p->delete('device_profile_setting_delete', 'temp'); + + //set message + message::add($text['message-delete']); + + } + unset($records); + } + } + } + + /** + * Deletes multiple records from the device profile keys table. + * + * @param array $records The list of records to delete, where each record is an associative array containing 'uuid' + * and/or 'checked' key(s). + * + * @return bool True if all records were successfully deleted, false otherwise. + */ + public function delete_profile_keys($records) { + + //assign private variables + $this->permission_prefix = 'device_profile_key_'; + $this->list_page = 'device_profile_edit.php?id=' . $this->device_profile_uuid; + $this->table = 'device_profile_keys'; + $this->uuid_prefix = 'device_profile_key_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + } + } + + //execute delete + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + $this->database->delete($array); + unset($array); + } + unset($records); + + } + } + } + + /** + * Deletes multiple profile settings. + * + * @param array $records An array of profile settings to delete, with each setting's 'uuid' key as the identifier. + */ + public function delete_profile_settings($records) { + + //assign private variables + $this->permission_prefix = 'device_profile_setting_'; + $this->list_page = 'device_profile_edit.php?id=' . $this->device_profile_uuid; + $this->table = 'device_profile_settings'; + $this->uuid_prefix = 'device_profile_setting_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + } + } + + //execute delete + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + $this->database->delete($array); + unset($array); + } + unset($records); + + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + + //assign private variables + $this->permission_prefix = 'device_'; + $this->list_page = 'devices.php'; + $this->table = 'devices'; + $this->uuid_prefix = 'device_'; + $this->toggle_field = 'device_enabled'; + $this->toggle_values = ['true', 'false']; + + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; } + } + unset($sql, $parameters, $rows, $row); } - else { - //set the default template_dir - if (empty($this->template_dir)) { - $this->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/resources/templates/provision'; + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + + //save the changes + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //write the provision files + if (!empty($this->settings->get('provision', 'path'))) { + $prov = new provision; + $prov->domain_uuid = $this->domain_uuid; + $response = $prov->write(); + } + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + + } + } + + /** + * Toggles the enabled state of one or more vendors. + * + * @param array $records An array of records containing vendor information, where each record + * has a 'checked' property indicating whether to toggle the vendor's state. + * + * @return void + */ + public function toggle_vendors($records) { + + //assign private variables + $this->permission_prefix = 'device_vendor_'; + $this->list_page = 'device_vendors.php'; + $this->table = 'device_vendors'; + $this->uuid_prefix = 'device_vendor_'; + $this->toggle_field = 'enabled'; + $this->toggle_values = ['true', 'false']; + + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; } + } + unset($sql, $parameters, $rows, $row); } - //check to see if the domain name sub directory exists - if (is_dir($this->template_dir."/".$this->domain_name)) { - $this->template_dir = $this->template_dir."/".$this->domain_name; + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; } - //return the template directory - return $this->template_dir; + //save the changes + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + } + } - /** - * delete records - */ - public function delete($records) { + /** + * Toggles the enabled state of one or more vendor functions. + * + * @param array $records An array of records containing vendor function information, where each record has a 'checked' property indicating whether to toggle the function's state. + * + * @return void + */ + public function toggle_vendor_functions($records) { - //assign private variables - $this->permission_prefix = 'device_'; - $this->list_page = 'devices.php'; - $this->table = 'devices'; - $this->uuid_prefix = 'device_'; + //assign private variables + $this->permission_prefix = 'device_vendor_function_'; + $this->list_page = 'device_vendor_edit.php'; + $this->table = 'device_vendor_functions'; + $this->uuid_prefix = 'device_vendor_function_'; + $this->toggle_field = 'enabled'; + $this->toggle_values = ['true', 'false']; - if (permission_exists($this->permission_prefix.'delete')) { + if (permission_exists($this->permission_prefix . 'edit')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; + //validate the token + $token = new token; + if (!$token->validate('/app/devices/device_vendor_functions.php')) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page . '?id=' . $this->device_vendor_uuid); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $sql = "update v_devices set device_uuid_alternate = null where device_uuid_alternate = :device_uuid_alternate; "; - $parameters['device_uuid_alternate'] = $record['uuid']; - $this->database->execute($sql, $parameters); - unset($sql, $parameters); + //save the changes + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array['device_settings'][$x]['device_uuid'] = $record['uuid']; - $array['device_lines'][$x]['device_uuid'] = $record['uuid']; - $array['device_keys'][$x]['device_uuid'] = $record['uuid']; + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + + } + } + + /** + * Toggle the state of checked device profiles. + * + * @param array $records An array containing the records to toggle, where each record is an associative array + * with a 'checked' key indicating whether the profile should be toggled, and a 'uuid' + * key containing the UUID of the profile. + * + * @return void + */ + public function toggle_profiles($records) { + + //assign private variables + $this->permission_prefix = 'device_profile_'; + $this->list_page = 'device_profiles.php'; + $this->table = 'device_profiles'; + $this->uuid_prefix = 'device_profile_'; + $this->toggle_field = 'device_profile_enabled'; + $this->toggle_values = ['true', 'false']; + + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + if (!empty($states) && is_array($states) && @sizeof($states) != 0) { + foreach ($states as $uuid => $state) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + } + + //save the changes + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + + } + } + + /** + * Copy the specified device profiles. + * + * @param array $records An array containing the records to copy, where each record is an associative array + * with a 'checked' key indicating whether the profile should be copied, and a 'uuid' + * key containing the UUID of the profile. + * + * @return void + */ + public function copy_profiles($records) { + + //assign private variables + $this->permission_prefix = 'device_profile_'; + $this->list_page = 'device_profiles.php'; + $this->table = 'device_profiles'; + $this->uuid_prefix = 'device_profile_'; + + if (permission_exists($this->permission_prefix . 'add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create insert array from existing data + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select * from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $y = $z = 0; + foreach ($rows as $x => $row) { + $primary_uuid = uuid(); + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; } } - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { + //copy data + $array[$this->table][$x] = $row; - //grant temporary permissions - $p = permissions::new(); - $p->add('device_setting_delete', 'temp'); - $p->add('device_line_delete', 'temp'); - $p->add('device_key_delete', 'temp'); + //overwrite + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $primary_uuid; + $array[$this->table][$x]['device_profile_description'] = trim($row['device_profile_description'] . ' (' . $text['label-copy'] . ')'); - //execute delete - $this->database->delete($array); - unset($array); + //keys sub table + $sql_2 = "select * from v_device_profile_keys "; + $sql_2 .= "where device_profile_uuid = :device_profile_uuid "; + $sql_2 .= "order by "; + $sql_2 .= "case profile_key_category "; + $sql_2 .= "when 'line' then 1 "; + $sql_2 .= "when 'memort' then 2 "; + $sql_2 .= "when 'programmable' then 3 "; + $sql_2 .= "when 'expansion' then 4 "; + $sql_2 .= "else 100 end, "; + $sql_2 .= "profile_key_id asc "; + $parameters_2['device_profile_uuid'] = $row['device_profile_uuid']; + $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); + if (is_array($rows_2) && @sizeof($rows_2) != 0) { + foreach ($rows_2 as $row_2) { - //revoke temporary permissions - $p->delete('device_setting_delete', 'temp'); - $p->delete('device_line_delete', 'temp'); - $p->delete('device_key_delete', 'temp'); - - //write the provision files - if (!empty($this->settings->get('provision', 'path'))) { - $prov = new provision; - $prov->domain_uuid = $this->domain_uuid; - $response = $prov->write(); + //convert boolean values to a string + foreach ($row_2 as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row_2[$key] = $value; + } } - //set message - message::add($text['message-delete']); + //copy data + $array['device_profile_keys'][$y] = $row_2; - } - unset($records); - } - } - } + //overwrite + $array['device_profile_keys'][$y]['device_profile_key_uuid'] = uuid(); + $array['device_profile_keys'][$y]['device_profile_uuid'] = $primary_uuid; - public function delete_lines($records) { - //assign private variables - $this->permission_prefix = 'device_line_'; - $this->table = 'device_lines'; - $this->uuid_prefix = 'device_line_'; + //increment + $y++; - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked device lines, build delete array - $x = 0; - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['device_uuid'] = $this->device_uuid; - $x++; } } - - //delete the checked rows - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - } - unset($records); - } - } - } - - public function delete_keys($records) { - //assign private variables - $this->permission_prefix = 'device_key_'; - $this->table = 'device_keys'; - $this->uuid_prefix = 'device_key_'; - - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked device keys, build delete array - $x = 0; - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['device_uuid'] = $this->device_uuid; - $x++; - } - } - - //delete the checked rows - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - } - unset($records); - } - } - } - - public function delete_settings($records) { - //assign private variables - $this->permission_prefix = 'device_setting_'; - $this->table = 'device_settings'; - $this->uuid_prefix = 'device_setting_'; - - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked device settings, build delete array - $x = 0; - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['device_uuid'] = $this->device_uuid; - $x++; - } - } - - //delete the checked rows - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - } - unset($records); - } - } - } - - public function delete_vendors($records) { - - //assign private variables - $this->permission_prefix = 'device_vendor_'; - $this->list_page = 'device_vendors.php'; - $this->tables[] = 'device_vendors'; - $this->tables[] = 'device_vendor_functions'; - $this->tables[] = 'device_vendor_function_groups'; - $this->uuid_prefix = 'device_vendor_'; - - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - foreach ($this->tables as $table) { - $array[$table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - } - } - } - - //delete the checked rows - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('device_vendor_function_delete', 'temp'); - $p->add('device_vendor_function_group_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('device_vendor_function_delete', 'temp'); - $p->delete('device_vendor_function_group_delete', 'temp'); - - //set message - message::add($text['message-delete']); - - } - unset($records); - } - } - } - - public function delete_vendor_functions($records) { - - //assign private variables - $this->permission_prefix = 'device_vendor_function_'; - $this->list_page = 'device_vendor_edit.php'; - $this->tables[] = 'device_vendor_functions'; - $this->tables[] = 'device_vendor_function_groups'; - $this->uuid_prefix = 'device_vendor_function_'; - - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate('/app/devices/device_vendor_functions.php')) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page.'?id='.$this->device_vendor_uuid); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - foreach ($this->tables as $table) { - $array[$table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - } - } - } - - //delete the checked rows - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('device_vendor_function_group_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('device_vendor_function_group_delete', 'temp'); - - //set message - message::add($text['message-delete']); - - } - unset($records); - } - } - } - - public function delete_profiles($records) { - - //assign private variables - $this->permission_prefix = 'device_profile_'; - $this->list_page = 'device_profiles.php'; - $this->tables[] = 'device_profiles'; - $this->tables[] = 'device_profile_keys'; - $this->tables[] = 'device_profile_settings'; - $this->uuid_prefix = 'device_profile_'; - - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - foreach ($this->tables as $table) { - $array[$table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - } - } - } - - //delete the checked rows - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('device_profile_key_delete', 'temp'); - $p->add('device_profile_setting_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('device_profile_key_delete', 'temp'); - $p->delete('device_profile_setting_delete', 'temp'); - - //set message - message::add($text['message-delete']); - - } - unset($records); - } - } - } - - public function delete_profile_keys($records) { - - //assign private variables - $this->permission_prefix = 'device_profile_key_'; - $this->list_page = 'device_profile_edit.php?id='.$this->device_profile_uuid; - $this->table = 'device_profile_keys'; - $this->uuid_prefix = 'device_profile_key_'; - - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - } - } - - //execute delete - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - $this->database->delete($array); - unset($array); - } - unset($records); - - } - } - } - - public function delete_profile_settings($records) { - - //assign private variables - $this->permission_prefix = 'device_profile_setting_'; - $this->list_page = 'device_profile_edit.php?id='.$this->device_profile_uuid; - $this->table = 'device_profile_settings'; - $this->uuid_prefix = 'device_profile_setting_'; - - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - } - } - - //execute delete - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - $this->database->delete($array); - unset($array); - } - unset($records); - - } - } - } - - /** - * toggle records - */ - public function toggle($records) { - - //assign private variables - $this->permission_prefix = 'device_'; - $this->list_page = 'devices.php'; - $this->table = 'devices'; - $this->uuid_prefix = 'device_'; - $this->toggle_field = 'device_enabled'; - $this->toggle_values = ['true','false']; - - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach ($states as $uuid => $state) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - - //save the changes - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //write the provision files - if (!empty($this->settings->get('provision', 'path'))) { - $prov = new provision; - $prov->domain_uuid = $this->domain_uuid; - $response = $prov->write(); + unset($sql_2, $parameters_2, $rows_2, $row_2); + + //settings sub table + $sql_3 = "select * from v_device_profile_settings where device_profile_uuid = :device_profile_uuid"; + $parameters_3['device_profile_uuid'] = $row['device_profile_uuid']; + $rows_3 = $this->database->select($sql_3, $parameters_3, 'all'); + if (is_array($rows_3) && @sizeof($rows_3) != 0) { + foreach ($rows_3 as $row_3) { + + //convert boolean values to a string + foreach ($row_3 as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row_3[$key] = $value; + } } - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } + //copy data + $array['device_profile_settings'][$z] = $row_3; + //overwrite + $array['device_profile_settings'][$z]['device_profile_setting_uuid'] = uuid(); + $array['device_profile_settings'][$z]['device_profile_uuid'] = $primary_uuid; + + //increment + $z++; + + } + } + unset($sql_3, $parameters_3, $rows_3, $row_3); + + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('device_profile_key_add', 'temp'); + $p->add('device_profile_setting_add', 'temp'); + + //save the array + + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('device_profile_key_add', 'temp'); + $p->delete('device_profile_setting_add', 'temp'); + + //set message + message::add($text['message-copy']); + + } + unset($records); } + } - public function toggle_vendors($records) { + } //method - //assign private variables - $this->permission_prefix = 'device_vendor_'; - $this->list_page = 'device_vendors.php'; - $this->table = 'device_vendors'; - $this->uuid_prefix = 'device_vendor_'; - $this->toggle_field = 'enabled'; - $this->toggle_values = ['true','false']; +} //class - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach ($states as $uuid => $state) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - - //save the changes - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - - } - } - - public function toggle_vendor_functions($records) { - - //assign private variables - $this->permission_prefix = 'device_vendor_function_'; - $this->list_page = 'device_vendor_edit.php'; - $this->table = 'device_vendor_functions'; - $this->uuid_prefix = 'device_vendor_function_'; - $this->toggle_field = 'enabled'; - $this->toggle_values = ['true','false']; - - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate('/app/devices/device_vendor_functions.php')) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page.'?id='.$this->device_vendor_uuid); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach ($states as $uuid => $state) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - - //save the changes - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - - } - } - - public function toggle_profiles($records) { - - //assign private variables - $this->permission_prefix = 'device_profile_'; - $this->list_page = 'device_profiles.php'; - $this->table = 'device_profiles'; - $this->uuid_prefix = 'device_profile_'; - $this->toggle_field = 'device_profile_enabled'; - $this->toggle_values = ['true','false']; - - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - if (!empty($states) && is_array($states) && @sizeof($states) != 0) { - foreach ($states as $uuid => $state) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - } - - //save the changes - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - - } - } - - /** - * copy records - */ - public function copy_profiles($records) { - - //assign private variables - $this->permission_prefix = 'device_profile_'; - $this->list_page = 'device_profiles.php'; - $this->table = 'device_profiles'; - $this->uuid_prefix = 'device_profile_'; - - if (permission_exists($this->permission_prefix.'add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create insert array from existing data - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select * from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $y = $z = 0; - foreach ($rows as $x => $row) { - $primary_uuid = uuid(); - - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $primary_uuid; - $array[$this->table][$x]['device_profile_description'] = trim($row['device_profile_description'].' ('.$text['label-copy'].')'); - - //keys sub table - $sql_2 = "select * from v_device_profile_keys "; - $sql_2 .= "where device_profile_uuid = :device_profile_uuid "; - $sql_2 .= "order by "; - $sql_2 .= "case profile_key_category "; - $sql_2 .= "when 'line' then 1 "; - $sql_2 .= "when 'memort' then 2 "; - $sql_2 .= "when 'programmable' then 3 "; - $sql_2 .= "when 'expansion' then 4 "; - $sql_2 .= "else 100 end, "; - $sql_2 .= "profile_key_id asc "; - $parameters_2['device_profile_uuid'] = $row['device_profile_uuid']; - $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); - if (is_array($rows_2) && @sizeof($rows_2) != 0) { - foreach ($rows_2 as $row_2) { - - //convert boolean values to a string - foreach($row_2 as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row_2[$key] = $value; - } - } - - //copy data - $array['device_profile_keys'][$y] = $row_2; - - //overwrite - $array['device_profile_keys'][$y]['device_profile_key_uuid'] = uuid(); - $array['device_profile_keys'][$y]['device_profile_uuid'] = $primary_uuid; - - //increment - $y++; - - } - } - unset($sql_2, $parameters_2, $rows_2, $row_2); - - //settings sub table - $sql_3 = "select * from v_device_profile_settings where device_profile_uuid = :device_profile_uuid"; - $parameters_3['device_profile_uuid'] = $row['device_profile_uuid']; - $rows_3 = $this->database->select($sql_3, $parameters_3, 'all'); - if (is_array($rows_3) && @sizeof($rows_3) != 0) { - foreach ($rows_3 as $row_3) { - - //convert boolean values to a string - foreach($row_3 as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row_3[$key] = $value; - } - } - - //copy data - $array['device_profile_settings'][$z] = $row_3; - - //overwrite - $array['device_profile_settings'][$z]['device_profile_setting_uuid'] = uuid(); - $array['device_profile_settings'][$z]['device_profile_uuid'] = $primary_uuid; - - //increment - $z++; - - } - } - unset($sql_3, $parameters_3, $rows_3, $row_3); - - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('device_profile_key_add', 'temp'); - $p->add('device_profile_setting_add', 'temp'); - - //save the array - - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('device_profile_key_add', 'temp'); - $p->delete('device_profile_setting_add', 'temp'); - - //set message - message::add($text['message-copy']); - - } - unset($records); - } - - } - - } //method - - } //class - -?> diff --git a/app/dialplans/dialplan_edit.php b/app/dialplans/dialplan_edit.php index f84adcae4e..973a233407 100644 --- a/app/dialplans/dialplan_edit.php +++ b/app/dialplans/dialplan_edit.php @@ -44,8 +44,10 @@ //declared functions /** * Checks if a dialplan detail record is marked for deletion + * * @param string $uuid UUID of the dialplan detail record - * @param array $deleted_details array of dialplan detail records marked for deletion + * @param array $deleted_details array of dialplan detail records marked for deletion + * * @return bool Returns true if user has permission and dialplan detail is marked for deletion */ function marked_for_deletion(string $uuid, array $deleted_details): bool { diff --git a/app/dialplans/resources/classes/dialplan.php b/app/dialplans/resources/classes/dialplan.php index 34dd6a260d..207fffd6c1 100644 --- a/app/dialplans/resources/classes/dialplan.php +++ b/app/dialplans/resources/classes/dialplan.php @@ -25,1438 +25,1483 @@ */ //define the dialplan class - class dialplan { +class dialplan { - /** - * declare constant variables - */ - const app_name = 'dialplans'; - const app_uuid = '742714e5-8cdf-32fd-462c-cbe7e3d655db'; + /** + * declare constant variables + */ + const app_name = 'dialplans'; + const app_uuid = '742714e5-8cdf-32fd-462c-cbe7e3d655db'; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_uuid; - public $app_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_uuid; + public $app_uuid; - /** - * declare public variables - */ - public $dialplan_uuid; - public $dialplan_detail_uuid; - public $xml; - public $json; - public $display_type; - public $default_context; - public $bridges; - public $variables; + /** + * declare public variables + */ + public $dialplan_uuid; + public $dialplan_detail_uuid; + public $xml; + public $json; + public $display_type; + public $default_context; + public $bridges; + public $variables; - public $dialplan_details; - public $dialplan_name; - public $dialplan_number; - public $dialplan_destination; - public $dialplan_continue; - public $dialplan_order; - public $dialplan_context; - public $dialplan_global; - public $dialplan_enabled; - public $dialplan_description; + public $dialplan_details; + public $dialplan_name; + public $dialplan_number; + public $dialplan_destination; + public $dialplan_continue; + public $dialplan_order; + public $dialplan_context; + public $dialplan_global; + public $dialplan_enabled; + public $dialplan_description; - public $dialplan_detail_tag; - public $dialplan_detail_order; - public $dialplan_detail_type; - public $dialplan_detail_data; - public $dialplan_detail_break; - public $dialplan_detail_inline; - public $dialplan_detail_group; + public $dialplan_detail_tag; + public $dialplan_detail_order; + public $dialplan_detail_type; + public $dialplan_detail_data; + public $dialplan_detail_break; + public $dialplan_detail_inline; + public $dialplan_detail_group; - public $uuid; - public $context; - public $source; - public $destination; - public $is_empty; - public $array; - public $list_page; + public $uuid; + public $context; + public $source; + public $destination; + public $is_empty; + public $array; + public $list_page; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * declare private variables - */ - private $permission_prefix; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; + /** + * declare private variables + */ + private $permission_prefix; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; - //class constructor - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); - //set the default value - $this->dialplan_global = false; + //set the default value + $this->dialplan_global = false; - //assign property defaults - $this->permission_prefix = 'dialplan_'; - $this->list_page = 'dialplans.php'; - $this->table = 'dialplans'; - $this->uuid_prefix = 'dialplan_'; - $this->toggle_field = 'dialplan_enabled'; - $this->toggle_values = ['true','false']; + //assign property defaults + $this->permission_prefix = 'dialplan_'; + $this->list_page = 'dialplans.php'; + $this->table = 'dialplans'; + $this->uuid_prefix = 'dialplan_'; + $this->toggle_field = 'dialplan_enabled'; + $this->toggle_values = ['true', 'false']; + } + + /** + * Checks if a specific dialplan exists in the database. + * + * @return bool True if the dialplan exists, False otherwise + */ + public function dialplan_exists() { + $sql = "select count(*) from v_dialplans "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null)"; + $sql .= "and dialplan_uuid = :dialplan_uuid "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['dialplan_uuid'] = $this->dialplan_uuid; + return $this->database->select($sql, $parameters ?? null, 'column') != 0 ? true : false; + unset($sql, $parameters); + } + + /** + * Imports dialplans from XML files for the specified domains. + * + * @param array $domains An array of domain data, where each domain is an associative array containing 'domain_uuid' and + * other relevant information. + * + * @return void + */ + public function import($domains) { + //set the row id + $x = 0; + + //get the array of xml files + $xml_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/resources/switch/conf/dialplan/*.xml"); + + //add a band-aid for CLI editors with faulty syntax highlighting + /* **/ + + //build the dialplan xml array + /* + foreach ($xml_list as $xml_file) { + $xml_string = file_get_contents($xml_file); + + //prepare the xml + if (!empty($xml_string)) { + //replace the variables + $length = (is_numeric($this->settings->get('security', 'pin_length'))) ? $this->settings->get('security', 'pin_length') : 8; + $xml_string = str_replace("{v_context}", $domain['domain_name'], $xml_string); + $xml_string = str_replace("{v_pin_number}", generate_password($length, 1), $xml_string); + //convert the xml string to an xml object + $xml = simplexml_load_string($xml_string); + //convert to json + $json = json_encode($xml); + //convert to an array + $dialplan = json_decode($json, true); + } + if (!empty($this->json)) { + //convert to an array + $dialplan = json_decode($json, true); + } + $_SESSION['dialplans']['default'][] = $dialplan; } + */ + //loop through each domain + if (!empty($domains) && is_array($domains) && @sizeof($domains) != 0) { + foreach ($domains as $domain) { + //debug info + //echo "domain name ".$domain['domain_name']."\n"; - public function dialplan_exists() { - $sql = "select count(*) from v_dialplans "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null)"; - $sql .= "and dialplan_uuid = :dialplan_uuid "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['dialplan_uuid'] = $this->dialplan_uuid; - return $this->database->select($sql, $parameters ?? null, 'column') != 0 ? true : false; - unset($sql, $parameters); - } + //determine if the dialplan already exists + $sql = "select app_uuid from v_dialplans "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and app_uuid is not null "; + $parameters['domain_uuid'] = $domain['domain_uuid']; + $app_uuids = $this->database->select($sql, $parameters, 'all'); + unset($parameters); - public function import($domains) { - //set the row id - $x = 0; - - //get the array of xml files - $xml_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/resources/switch/conf/dialplan/*.xml"); - - //add a band-aid for CLI editors with faulty syntax highlighting - /* **/ - - //build the dialplan xml array - /* + //process the dialplan xml files + //foreach ($_SESSION['dialplans']['default'] as $dialplan) { foreach ($xml_list as $xml_file) { + //get the xml string $xml_string = file_get_contents($xml_file); //prepare the xml if (!empty($xml_string)) { //replace the variables - $length = (is_numeric($this->settings->get('security', 'pin_length'))) ? $this->settings->get('security', 'pin_length') : 8; - $xml_string = str_replace("{v_context}", $domain['domain_name'], $xml_string); - $xml_string = str_replace("{v_pin_number}", generate_password($length, 1), $xml_string); + $length = (!empty($this->settings->get('security', 'pin_length'))) ? $this->settings->get('security', 'pin_length') : 8; + $xml_string = str_replace("{v_context}", $domain['domain_name'], $xml_string); + $xml_string = str_replace("{v_pin_number}", generate_password($length, 1), $xml_string); + //convert the xml string to an xml object - $xml = simplexml_load_string($xml_string); + $xml = simplexml_load_string($xml_string); + //convert to json - $json = json_encode($xml); + $json = json_encode($xml); + //convert to an array - $dialplan = json_decode($json, true); + $dialplan = json_decode($json, true); + } if (!empty($this->json)) { //convert to an array - $dialplan = json_decode($json, true); + $dialplan = json_decode($json, true); } - $_SESSION['dialplans']['default'][] = $dialplan; - } - */ - //loop through each domain - if (!empty($domains) && is_array($domains) && @sizeof($domains) != 0) { - foreach ($domains as $domain) { - //debug info - //echo "domain name ".$domain['domain_name']."\n"; + //ensure the condition array is uniform + if (!empty($dialplan)) { + if (empty($dialplan['condition'][0])) { + $tmp = $dialplan['condition']; + unset($dialplan['condition']); + $dialplan['condition'][0] = $tmp; + } + } - //determine if the dialplan already exists - $sql = "select app_uuid from v_dialplans "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and app_uuid is not null "; - $parameters['domain_uuid'] = $domain['domain_uuid']; - $app_uuids = $this->database->select($sql, $parameters, 'all'); - unset($parameters); + //determine if the dialplan already exists + $app_uuid_exists = false; + foreach ($app_uuids as $row) { + if ($dialplan['@attributes']['app_uuid'] == $row['app_uuid']) { + $app_uuid_exists = true; + } + } - //process the dialplan xml files - //foreach ($_SESSION['dialplans']['default'] as $dialplan) { - foreach ($xml_list as $xml_file) { - //get the xml string - $xml_string = file_get_contents($xml_file); + //check if the dialplan exists + if (!$app_uuid_exists) { - //prepare the xml - if (!empty($xml_string)) { - //replace the variables - $length = (!empty($this->settings->get('security', 'pin_length'))) ? $this->settings->get('security', 'pin_length') : 8; - $xml_string = str_replace("{v_context}", $domain['domain_name'], $xml_string); - $xml_string = str_replace("{v_pin_number}", generate_password($length, 1), $xml_string); + //dialplan global + if (isset($dialplan['@attributes']['global']) && $dialplan['@attributes']['global'] == "true") { + $dialplan_global = true; + } else { + $dialplan_global = false; + } - //convert the xml string to an xml object - $xml = simplexml_load_string($xml_string); + //get the dialplan context + $dialplan_context = $dialplan['@attributes']['context']; + $dialplan_context = str_replace("\${domain_name}", $domain['domain_name'], $dialplan_context); - //convert to json - $json = json_encode($xml); + //set the domain_uuid + if ($dialplan_global) { + $domain_uuid = null; + } else { + $domain_uuid = $domain['domain_uuid']; + } - //convert to an array - $dialplan = json_decode($json, true); + //get the attributes + $dialplan_uuid = uuid(); - } - if (!empty($this->json)) { - //convert to an array - $dialplan = json_decode($json, true); - } + $array['dialplans'][$x]['dialplan_uuid'] = $dialplan_uuid; + $array['dialplans'][$x]['domain_uuid'] = $domain_uuid; + $array['dialplans'][$x]['app_uuid'] = $dialplan['@attributes']['app_uuid']; + $array['dialplans'][$x]['dialplan_name'] = $dialplan['@attributes']['name']; + $array['dialplans'][$x]['dialplan_number'] = $dialplan['@attributes']['number'] ?? null; + $array['dialplans'][$x]['dialplan_context'] = $dialplan_context; + if (!empty($dialplan['@attributes']['destination'])) { + $array['dialplans'][$x]['dialplan_destination'] = $dialplan['@attributes']['destination']; + } + if (!empty($dialplan['@attributes']['continue'])) { + $array['dialplans'][$x]['dialplan_continue'] = $dialplan['@attributes']['continue']; + } + $array['dialplans'][$x]['dialplan_order'] = $dialplan['@attributes']['order']; + if (!empty($dialplan['@attributes']['enabled'])) { + $array['dialplans'][$x]['dialplan_enabled'] = $dialplan['@attributes']['enabled']; + } else { + $array['dialplans'][$x]['dialplan_enabled'] = true; + } + $array['dialplans'][$x]['dialplan_description'] = $dialplan['@attributes']['description'] ?? null; - //ensure the condition array is uniform - if (!empty($dialplan)) { - if (empty($dialplan['condition'][0])) { - $tmp = $dialplan['condition']; - unset($dialplan['condition']); - $dialplan['condition'][0] = $tmp; + //loop through the condition array + $y = 0; + $group = 0; + $order = 5; + if (isset($dialplan['condition'])) { + foreach ($dialplan['condition'] as $row) { + + $array['dialplans'][$x]['dialplan_details'][$y]['domain_uuid'] = $domain_uuid; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_uuid'] = $dialplan_uuid; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_tag'] = 'condition'; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_order'] = $order; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_type'] = $row['@attributes']['field'] ?? null; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_data'] = $row['@attributes']['expression'] ?? null; + if (!empty($row['@attributes']['break'])) { + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_break'] = $row['@attributes']['break']; + } + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_group'] = $group; + if (isset($row['@attributes']['enabled'])) { + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_enabled'] = $row['@attributes']['enabled']; + } else { + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_enabled'] = true; + } + $y++; + + if (!empty($row['action']) || !empty($row['anti-action'])) { + $condition_self_closing_tag = false; + if (empty($row['action'][0])) { + if ($row['action']['@attributes']['application']) { + $tmp = $row['action']; + unset($row['action']); + $row['action'][0] = $tmp; } } - - //determine if the dialplan already exists - $app_uuid_exists = false; - foreach($app_uuids as $row) { - if ($dialplan['@attributes']['app_uuid'] == $row['app_uuid']) { - $app_uuid_exists = true; + if (empty($row['anti-action'][0])) { + if (!empty($row['anti-action']['@attributes']['application'])) { + $tmp = $row['anti-action']; + unset($row['anti-action']); + $row['anti-action'][0] = $tmp; } } - - //check if the dialplan exists - if (!$app_uuid_exists) { - - //dialplan global - if (isset($dialplan['@attributes']['global']) && $dialplan['@attributes']['global'] == "true") { - $dialplan_global = true; + $order = $order + 5; + if (isset($row['action'])) { + foreach ($row['action'] as $row2) { + $array['dialplans'][$x]['dialplan_details'][$y]['domain_uuid'] = $domain_uuid; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_uuid'] = $dialplan_uuid; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_tag'] = 'action'; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_order'] = $order; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_type'] = $row2['@attributes']['application']; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_data'] = $row2['@attributes']['data'] ?? null; + if (!empty($row2['@attributes']['inline'])) { + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_inline'] = $row2['@attributes']['inline']; + } else { + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_inline'] = null; } - else { - $dialplan_global = false; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_group'] = $group; + if (isset($row2['@attributes']['enabled'])) { + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_enabled'] = $row2['@attributes']['enabled']; + } else { + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_enabled'] = true; } + $y++; - //get the dialplan context - $dialplan_context = $dialplan['@attributes']['context']; - $dialplan_context = str_replace("\${domain_name}", $domain['domain_name'], $dialplan_context); - - //set the domain_uuid - if ($dialplan_global) { - $domain_uuid = null; - } - else { - $domain_uuid = $domain['domain_uuid']; - } - - //get the attributes - $dialplan_uuid = uuid(); - - $array['dialplans'][$x]['dialplan_uuid'] = $dialplan_uuid; - $array['dialplans'][$x]['domain_uuid'] = $domain_uuid; - $array['dialplans'][$x]['app_uuid'] = $dialplan['@attributes']['app_uuid']; - $array['dialplans'][$x]['dialplan_name'] = $dialplan['@attributes']['name']; - $array['dialplans'][$x]['dialplan_number'] = $dialplan['@attributes']['number'] ?? null; - $array['dialplans'][$x]['dialplan_context'] = $dialplan_context; - if (!empty($dialplan['@attributes']['destination'])) { - $array['dialplans'][$x]['dialplan_destination'] = $dialplan['@attributes']['destination']; - } - if (!empty($dialplan['@attributes']['continue'])) { - $array['dialplans'][$x]['dialplan_continue'] = $dialplan['@attributes']['continue']; - } - $array['dialplans'][$x]['dialplan_order'] = $dialplan['@attributes']['order']; - if (!empty($dialplan['@attributes']['enabled'])) { - $array['dialplans'][$x]['dialplan_enabled'] = $dialplan['@attributes']['enabled']; - } - else { - $array['dialplans'][$x]['dialplan_enabled'] = true; - } - $array['dialplans'][$x]['dialplan_description'] = $dialplan['@attributes']['description'] ?? null; - - //loop through the condition array - $y = 0; - $group = 0; - $order = 5; - if (isset($dialplan['condition'])) { - foreach ($dialplan['condition'] as $row) { - - $array['dialplans'][$x]['dialplan_details'][$y]['domain_uuid'] = $domain_uuid; - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_uuid'] = $dialplan_uuid; - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_tag'] = 'condition'; - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_order'] = $order; - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_type'] = $row['@attributes']['field'] ?? null; - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_data'] = $row['@attributes']['expression'] ?? null; - if (!empty($row['@attributes']['break'])) { - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_break'] = $row['@attributes']['break']; - } - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_group'] = $group; - if (isset($row['@attributes']['enabled'])) { - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_enabled'] = $row['@attributes']['enabled']; - } - else { - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_enabled'] = true; - } - $y++; - - if (!empty($row['action']) || !empty($row['anti-action'])) { - $condition_self_closing_tag = false; - if (empty($row['action'][0])) { - if ($row['action']['@attributes']['application']) { - $tmp = $row['action']; - unset($row['action']); - $row['action'][0] = $tmp; - } - } - if (empty($row['anti-action'][0])) { - if (!empty($row['anti-action']['@attributes']['application'])) { - $tmp = $row['anti-action']; - unset($row['anti-action']); - $row['anti-action'][0] = $tmp; - } - } - $order = $order + 5; - if (isset($row['action'])) { - foreach ($row['action'] as $row2) { - $array['dialplans'][$x]['dialplan_details'][$y]['domain_uuid'] = $domain_uuid; - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_uuid'] = $dialplan_uuid; - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_tag'] = 'action'; - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_order'] = $order; - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_type'] = $row2['@attributes']['application']; - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_data'] = $row2['@attributes']['data'] ?? null; - if (!empty($row2['@attributes']['inline'])) { - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_inline'] = $row2['@attributes']['inline']; - } - else { - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_inline'] = null; - } - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_group'] = $group; - if (isset($row2['@attributes']['enabled'])) { - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_enabled'] = $row2['@attributes']['enabled']; - } - else { - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_enabled'] = true; - } - $y++; - - //increase the order number - $order = $order + 5; - } - } - if (isset($row['anti-action'])) { - foreach ($row['anti-action'] as $row2) { - $array['dialplans'][$x]['dialplan_details'][$y]['domain_uuid'] = $domain_uuid; - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_uuid'] = $dialplan_uuid; - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_tag'] = 'anti-action'; - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_order'] = $order; - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_type'] = $row2['@attributes']['application']; - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_data'] = $row2['@attributes']['data']; - if (!empty($row2['@attributes']['inline'])) { - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_inline'] = $row2['@attributes']['inline']; - } - else { - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_inline'] = null; - } - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_group'] = $group; - if (isset($row2['@attributes']['enabled'])) { - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_enabled'] = $row2['@attributes']['enabled']; - } - else { - $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_enabled'] = true; - } - $y++; - - //increase the order number - $order = $order + 5; - } - } - } - else { - $condition_self_closing_tag = true; - } - - //if not a self closing tag then increment the group - if (!$condition_self_closing_tag) { - $group++; - } - - //increment the values - $order = $order + 5; - - //increase the row number - $x++; - } - } - - //update the session array - $_SESSION['upgrade']['app_defaults']['dialplans'][$domain['domain_name']][]['dialplan_name'] = $dialplan_name ?? null; - - } //app_uuid exists - } //end foreach $xml_list - - //grant temporary permissions - $p = permissions::new(); - $p->add('dialplan_add', 'temp'); - $p->add('dialplan_edit', 'temp'); - $p->add('dialplan_detail_add', 'temp'); - $p->add('dialplan_detail_edit', 'temp'); - - //save the data - if (!empty($array)) { - $this->database->save($array); - unset($array); - } - - //revoke temporary permissions - $p->delete('dialplan_add', 'temp'); - $p->delete('dialplan_edit', 'temp'); - $p->delete('dialplan_detail_add', 'temp'); - $p->delete('dialplan_detail_edit', 'temp'); - - //add dialplan xml when the dialplan_xml is null - $this->source = 'details'; - $this->destination = 'database'; - $this->context = $domain['domain_name']; - $this->is_empty = 'dialplan_xml'; - $this->xml(); - - } //foreach domains - } - } - - public function outbound_routes($destination_number) { - - //normalize the destination number - $destination_number = trim($destination_number); - - //check the session array if it doesn't exist then build the array - if (empty($_SESSION[$this->domain_uuid]['outbound_routes'])) { - //get the outbound routes from the database - $sql = "select * "; - $sql .= "from v_dialplans as d, "; - $sql .= "v_dialplan_details as s "; - $sql .= "where "; - $sql .= "( "; - $sql .= "d.domain_uuid = :domain_uuid "; - $sql .= "or d.domain_uuid is null "; - $sql .= ") "; - $sql .= "and d.app_uuid = '8c914ec3-9fc0-8ab5-4cda-6c9288bdc9a3' "; - $sql .= "and d.dialplan_enabled = true "; - $sql .= "and d.dialplan_uuid = s.dialplan_uuid "; - $sql .= "order by "; - $sql .= "d.dialplan_order asc, "; - $sql .= "d.dialplan_name asc, "; - $sql .= "d.dialplan_uuid asc, "; - $sql .= "s.dialplan_detail_group asc, "; - $sql .= "case s.dialplan_detail_tag "; - $sql .= "when 'condition' then 1 "; - $sql .= "when 'action' then 2 "; - $sql .= "when 'anti-action' then 3 "; - $sql .= "else 100 end, "; - $sql .= "s.dialplan_detail_order asc "; - $parameters['domain_uuid'] = $this->domain_uuid; - $dialplans = $this->database->select($sql, $parameters ?? null, 'all'); - unset($sql, $parameters); - $x = 0; $y = 0; - if (!empty($dialplans)) { - foreach ($dialplans as $row) { - //if the previous dialplan uuid has not been set then set it - if (!isset($previous_dialplan_uuid)) { $previous_dialplan_uuid = $row['dialplan_uuid']; } - - //increment dialplan ordinal number - if ($previous_dialplan_uuid != $row['dialplan_uuid']) { - $x++; $y = 0; + //increase the order number + $order = $order + 5; + } } + if (isset($row['anti-action'])) { + foreach ($row['anti-action'] as $row2) { + $array['dialplans'][$x]['dialplan_details'][$y]['domain_uuid'] = $domain_uuid; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_uuid'] = $dialplan_uuid; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_tag'] = 'anti-action'; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_order'] = $order; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_type'] = $row2['@attributes']['application']; + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_data'] = $row2['@attributes']['data']; + if (!empty($row2['@attributes']['inline'])) { + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_inline'] = $row2['@attributes']['inline']; + } else { + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_inline'] = null; + } + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_group'] = $group; + if (isset($row2['@attributes']['enabled'])) { + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_enabled'] = $row2['@attributes']['enabled']; + } else { + $array['dialplans'][$x]['dialplan_details'][$y]['dialplan_detail_enabled'] = true; + } + $y++; - //build the array - $array[$x]['dialplan_uuid'] = $row['dialplan_uuid']; - $array[$x]['dialplan_context'] = $row['dialplan_context']; - $array[$x]['dialplan_name'] = $row['dialplan_name']; - $array[$x]['dialplan_continue'] = $row['dialplan_continue']; - $array[$x]['dialplan_order'] = $row['dialplan_order']; - $array[$x]['dialplan_enabled'] = $row['dialplan_enabled']; - $array[$x]['dialplan_description'] = $row['dialplan_description']; - if (!empty($row['dialplan_detail_uuid'])) { - $array[$x]['dialplan_details'][$y]['dialplan_uuid'] = $row['dialplan_uuid']; - $array[$x]['dialplan_details'][$y]['dialplan_detail_uuid'] = $row['dialplan_detail_uuid']; - $array[$x]['dialplan_details'][$y]['dialplan_detail_tag'] = $row['dialplan_detail_tag']; - $array[$x]['dialplan_details'][$y]['dialplan_detail_type'] = $row['dialplan_detail_type']; - $array[$x]['dialplan_details'][$y]['dialplan_detail_data'] = $row['dialplan_detail_data']; - $y++; + //increase the order number + $order = $order + 5; + } } + } else { + $condition_self_closing_tag = true; + } - //set the previous dialplan_uuid - $previous_dialplan_uuid = $row['dialplan_uuid']; + //if not a self closing tag then increment the group + if (!$condition_self_closing_tag) { + $group++; + } + + //increment the values + $order = $order + 5; + + //increase the row number + $x++; } } - //set the session array - $_SESSION[$this->domain_uuid]['outbound_routes'] = $array; + //update the session array + $_SESSION['upgrade']['app_defaults']['dialplans'][$domain['domain_name']][]['dialplan_name'] = $dialplan_name ?? null; + + } //app_uuid exists + } //end foreach $xml_list + + //grant temporary permissions + $p = permissions::new(); + $p->add('dialplan_add', 'temp'); + $p->add('dialplan_edit', 'temp'); + $p->add('dialplan_detail_add', 'temp'); + $p->add('dialplan_detail_edit', 'temp'); + + //save the data + if (!empty($array)) { + $this->database->save($array); + unset($array); } - //find the matching outbound routes - if (isset($_SESSION[$this->domain_uuid]['outbound_routes'])) { - foreach ($_SESSION[$this->domain_uuid]['outbound_routes'] as $row) { - if (isset($row['dialplan_details'])) { - foreach ($row['dialplan_details'] as $field) { - if ($field['dialplan_detail_tag'] == "condition") { - if ($field['dialplan_detail_type'] == "destination_number") { - $dialplan_detail_data = $field['dialplan_detail_data']; - $pattern = '/'.$dialplan_detail_data.'/'; - preg_match($pattern, $destination_number, $matches, PREG_OFFSET_CAPTURE); - if (count($matches) == 0) { - $regex_match = false; - } - else { - $regex_match = true; - $regex_match_1 = $matches[1][0]; - $regex_match_2 = $matches[2][0]; - $regex_match_3 = $matches[3][0]; - } - } + //revoke temporary permissions + $p->delete('dialplan_add', 'temp'); + $p->delete('dialplan_edit', 'temp'); + $p->delete('dialplan_detail_add', 'temp'); + $p->delete('dialplan_detail_edit', 'temp'); + + //add dialplan xml when the dialplan_xml is null + $this->source = 'details'; + $this->destination = 'database'; + $this->context = $domain['domain_name']; + $this->is_empty = 'dialplan_xml'; + $this->xml(); + + } //foreach domains + } + } + + /** + * Retrieves the outbound routes for a given destination number. + * + * @param string $destination_number The destination number to retrieve the outbound routes for. + * + * @return void + */ + public function outbound_routes($destination_number) { + + //normalize the destination number + $destination_number = trim($destination_number); + + //check the session array if it doesn't exist then build the array + if (empty($_SESSION[$this->domain_uuid]['outbound_routes'])) { + //get the outbound routes from the database + $sql = "select * "; + $sql .= "from v_dialplans as d, "; + $sql .= "v_dialplan_details as s "; + $sql .= "where "; + $sql .= "( "; + $sql .= "d.domain_uuid = :domain_uuid "; + $sql .= "or d.domain_uuid is null "; + $sql .= ") "; + $sql .= "and d.app_uuid = '8c914ec3-9fc0-8ab5-4cda-6c9288bdc9a3' "; + $sql .= "and d.dialplan_enabled = true "; + $sql .= "and d.dialplan_uuid = s.dialplan_uuid "; + $sql .= "order by "; + $sql .= "d.dialplan_order asc, "; + $sql .= "d.dialplan_name asc, "; + $sql .= "d.dialplan_uuid asc, "; + $sql .= "s.dialplan_detail_group asc, "; + $sql .= "case s.dialplan_detail_tag "; + $sql .= "when 'condition' then 1 "; + $sql .= "when 'action' then 2 "; + $sql .= "when 'anti-action' then 3 "; + $sql .= "else 100 end, "; + $sql .= "s.dialplan_detail_order asc "; + $parameters['domain_uuid'] = $this->domain_uuid; + $dialplans = $this->database->select($sql, $parameters ?? null, 'all'); + unset($sql, $parameters); + $x = 0; + $y = 0; + if (!empty($dialplans)) { + foreach ($dialplans as $row) { + //if the previous dialplan uuid has not been set then set it + if (!isset($previous_dialplan_uuid)) { + $previous_dialplan_uuid = $row['dialplan_uuid']; + } + + //increment dialplan ordinal number + if ($previous_dialplan_uuid != $row['dialplan_uuid']) { + $x++; + $y = 0; + } + + //build the array + $array[$x]['dialplan_uuid'] = $row['dialplan_uuid']; + $array[$x]['dialplan_context'] = $row['dialplan_context']; + $array[$x]['dialplan_name'] = $row['dialplan_name']; + $array[$x]['dialplan_continue'] = $row['dialplan_continue']; + $array[$x]['dialplan_order'] = $row['dialplan_order']; + $array[$x]['dialplan_enabled'] = $row['dialplan_enabled']; + $array[$x]['dialplan_description'] = $row['dialplan_description']; + if (!empty($row['dialplan_detail_uuid'])) { + $array[$x]['dialplan_details'][$y]['dialplan_uuid'] = $row['dialplan_uuid']; + $array[$x]['dialplan_details'][$y]['dialplan_detail_uuid'] = $row['dialplan_detail_uuid']; + $array[$x]['dialplan_details'][$y]['dialplan_detail_tag'] = $row['dialplan_detail_tag']; + $array[$x]['dialplan_details'][$y]['dialplan_detail_type'] = $row['dialplan_detail_type']; + $array[$x]['dialplan_details'][$y]['dialplan_detail_data'] = $row['dialplan_detail_data']; + $y++; + } + + //set the previous dialplan_uuid + $previous_dialplan_uuid = $row['dialplan_uuid']; + } + } + + //set the session array + $_SESSION[$this->domain_uuid]['outbound_routes'] = $array; + } + + //find the matching outbound routes + if (isset($_SESSION[$this->domain_uuid]['outbound_routes'])) { + foreach ($_SESSION[$this->domain_uuid]['outbound_routes'] as $row) { + if (isset($row['dialplan_details'])) { + foreach ($row['dialplan_details'] as $field) { + if ($field['dialplan_detail_tag'] == "condition") { + if ($field['dialplan_detail_type'] == "destination_number") { + $dialplan_detail_data = $field['dialplan_detail_data']; + $pattern = '/' . $dialplan_detail_data . '/'; + preg_match($pattern, $destination_number, $matches, PREG_OFFSET_CAPTURE); + if (count($matches) == 0) { + $regex_match = false; + } else { + $regex_match = true; + $regex_match_1 = $matches[1][0]; + $regex_match_2 = $matches[2][0]; + $regex_match_3 = $matches[3][0]; } - if ($regex_match) { - //get the variables - if ($field['dialplan_detail_type'] == "set" && $field['dialplan_detail_tag'] == "action") { - //only set variables with values not variables - if (strpos($field['dialplan_detail_data'], '$') === false) { - $this->variables .= $field['dialplan_detail_data'].","; - } - } - //process the $x detail data variables - if ($field['dialplan_detail_tag'] == "action" && $field['dialplan_detail_type'] == "bridge" && $dialplan_detail_data != "\${enum_auto_route}") { - $dialplan_detail_data = $field['dialplan_detail_data']; - $dialplan_detail_data = str_replace("\$1", $regex_match_1, $dialplan_detail_data); - $dialplan_detail_data = str_replace("\$2", $regex_match_2, $dialplan_detail_data); - $dialplan_detail_data = str_replace("\$3", $regex_match_3, $dialplan_detail_data); - $this->bridges = $dialplan_detail_data; - } - } //if - } //foreach + } + } + if ($regex_match) { + //get the variables + if ($field['dialplan_detail_type'] == "set" && $field['dialplan_detail_tag'] == "action") { + //only set variables with values not variables + if (strpos($field['dialplan_detail_data'], '$') === false) { + $this->variables .= $field['dialplan_detail_data'] . ","; + } + } + //process the $x detail data variables + if ($field['dialplan_detail_tag'] == "action" && $field['dialplan_detail_type'] == "bridge" && $dialplan_detail_data != "\${enum_auto_route}") { + $dialplan_detail_data = $field['dialplan_detail_data']; + $dialplan_detail_data = str_replace("\$1", $regex_match_1, $dialplan_detail_data); + $dialplan_detail_data = str_replace("\$2", $regex_match_2, $dialplan_detail_data); + $dialplan_detail_data = str_replace("\$3", $regex_match_3, $dialplan_detail_data); + $this->bridges = $dialplan_detail_data; + } } //if } //foreach } //if - } //function + } //foreach + } //if + } //function - //combines array dialplans and dialplan details arrays to match results from the database - public function prepare_details($database_array) { - $array = []; - $id = 0; - foreach($database_array['dialplans'] as $row) { - if (!empty($row['dialplan_details'])) { - foreach($row['dialplan_details'] as $detail) { - if ($detail['dialplan_detail_enabled'] == 'true') { - $array[$id]['domain_uuid'] = $row['domain_uuid']; - $array[$id]['dialplan_uuid'] = $row['dialplan_uuid']; - $array[$id]['app_uuid'] = $row['app_uuid'] ?? ''; - $array[$id]['dialplan_context'] = $row['dialplan_context']; - $array[$id]['dialplan_name'] = $row['dialplan_name']; - $array[$id]['dialplan_number'] = $row['dialplan_number']; - $array[$id]['dialplan_continue'] = $row['dialplan_continue']; - $array[$id]['dialplan_order'] = $row['dialplan_order']; - $array[$id]['dialplan_enabled'] = $row['dialplan_enabled']; - $array[$id]['dialplan_description'] = $row['dialplan_description']; - $array[$id]['dialplan_detail_uuid'] = $detail['dialplan_detail_uuid']; - $array[$id]['dialplan_detail_tag'] = $detail['dialplan_detail_tag']; - $array[$id]['dialplan_detail_type'] = $detail['dialplan_detail_type']; - $array[$id]['dialplan_detail_data'] = $detail['dialplan_detail_data']; - $array[$id]['dialplan_detail_break'] = $detail['dialplan_detail_break']; - $array[$id]['dialplan_detail_inline'] = $detail['dialplan_detail_inline']; - $array[$id]['dialplan_detail_group'] = $detail['dialplan_detail_group']; - $array[$id]['dialplan_detail_order'] = $detail['dialplan_detail_order']; - $array[$id]['dialplan_detail_enabled'] = $detail['dialplan_detail_enabled']; - $id++; - } + //combines array dialplans and dialplan details arrays to match results from the database + /** + * Prepares an array of dialplan details from the provided database array. + * + * @param array $database_array An array containing database connections and dialplan data. + * + * @return void + */ + public function prepare_details($database_array) { + $array = []; + $id = 0; + foreach ($database_array['dialplans'] as $row) { + if (!empty($row['dialplan_details'])) { + foreach ($row['dialplan_details'] as $detail) { + if ($detail['dialplan_detail_enabled'] == 'true') { + $array[$id]['domain_uuid'] = $row['domain_uuid']; + $array[$id]['dialplan_uuid'] = $row['dialplan_uuid']; + $array[$id]['app_uuid'] = $row['app_uuid'] ?? ''; + $array[$id]['dialplan_context'] = $row['dialplan_context']; + $array[$id]['dialplan_name'] = $row['dialplan_name']; + $array[$id]['dialplan_number'] = $row['dialplan_number']; + $array[$id]['dialplan_continue'] = $row['dialplan_continue']; + $array[$id]['dialplan_order'] = $row['dialplan_order']; + $array[$id]['dialplan_enabled'] = $row['dialplan_enabled']; + $array[$id]['dialplan_description'] = $row['dialplan_description']; + $array[$id]['dialplan_detail_uuid'] = $detail['dialplan_detail_uuid']; + $array[$id]['dialplan_detail_tag'] = $detail['dialplan_detail_tag']; + $array[$id]['dialplan_detail_type'] = $detail['dialplan_detail_type']; + $array[$id]['dialplan_detail_data'] = $detail['dialplan_detail_data']; + $array[$id]['dialplan_detail_break'] = $detail['dialplan_detail_break']; + $array[$id]['dialplan_detail_inline'] = $detail['dialplan_detail_inline']; + $array[$id]['dialplan_detail_group'] = $detail['dialplan_detail_group']; + $array[$id]['dialplan_detail_order'] = $detail['dialplan_detail_order']; + $array[$id]['dialplan_detail_enabled'] = $detail['dialplan_detail_enabled']; + $id++; } } } - //sort the dataset by group and then by order before returning the values - $dialplan_detail_group = array_column($array, 'dialplan_detail_group'); - $dialplan_detail_order = array_column($array, 'dialplan_detail_order'); - array_multisort($dialplan_detail_group, SORT_ASC, $dialplan_detail_order, SORT_ASC, $array); - $this->dialplan_details = $array; + } + //sort the dataset by group and then by order before returning the values + $dialplan_detail_group = array_column($array, 'dialplan_detail_group'); + $dialplan_detail_order = array_column($array, 'dialplan_detail_order'); + array_multisort($dialplan_detail_group, SORT_ASC, $dialplan_detail_order, SORT_ASC, $array); + $this->dialplan_details = $array; + } + + //reads dialplan details from the database to build the xml + + /** + * Generates XML representation of dialplans. + * + * @return string XML string representing the dialplans. + */ + public function xml() { + + //set the xml array and then concatenate the array to a string + /* $xml = "\n"; */ + //$xml .= "\n"; + //$xml .= "
\n"; + //$xml .= " context . "\">\n"; + + //set defaults + $previous_dialplan_uuid = ""; + $previous_dialplan_detail_group = ""; + $dialplan_tag_status = "closed"; + $condition_tag_status = "closed"; + + //get the dialplans from the dialplan_xml field in the dialplans table + if ($this->source == "dialplans") { + + //get the data using a join between the dialplans and dialplan details tables + $sql = "select dialplan_uuid, dialplan_xml "; + $sql .= "from v_dialplans "; + if (is_uuid($this->uuid)) { + $sql .= "where dialplan_uuid = :dialplan_uuid "; + $parameters['dialplan_uuid'] = $this->uuid; + } else { + if (!empty($this->context)) { + if ($this->context == "public" || substr($this->context, 0, 7) == "public@" || substr($this->context, -7) == ".public") { + $sql .= "where dialplan_context = :dialplan_context "; + } else { + $sql .= "where (dialplan_context = :dialplan_context or dialplan_context = '\${domain_name}' or dialplan_context = 'global') "; + } + $sql .= "and dialplan_enabled = true "; + $parameters['dialplan_context'] = $this->context; + } + } + if ($this->is_empty == "dialplan_xml") { + $sql .= "and p.dialplan_xml is null "; + } + $sql .= "order by "; + $sql .= "dialplan_context asc, "; + $sql .= "dialplan_order asc "; + $results = $this->database->select($sql, $parameters ?? null, 'all'); + if (!empty($results)) { + foreach ($results as $row) { + $dialplans[$row["dialplan_uuid"]] = $row["dialplan_xml"]; + } + } + unset($sql, $parameters, $results, $row); + } - //reads dialplan details from the database to build the xml - public function xml() { + //get the dialplans from the dialplan details + if ($this->source == "details") { + + //get the domains + if (!isset($domains)) { + $sql = "select * from v_domains "; + $result = $this->database->select($sql, null, 'all'); + if (!empty($result)) { + foreach ($result as $row) { + $domains[$row['domain_uuid']] = $row['domain_name']; + } + } + unset($sql, $result, $row); + } + + //get the data using a join between the dialplans and dialplan details tables + if (empty($this->dialplan_details)) { + $sql = "select \n"; + $sql .= "p.domain_uuid, p.dialplan_uuid, p.app_uuid, p.dialplan_context, p.dialplan_name, p.dialplan_number, \n"; + $sql .= "p.dialplan_continue, p.dialplan_order, p.dialplan_enabled, p.dialplan_description, \n"; + $sql .= "s.dialplan_detail_uuid, s.dialplan_detail_tag, s.dialplan_detail_type, s.dialplan_detail_data, \n"; + $sql .= "s.dialplan_detail_break, s.dialplan_detail_inline, s.dialplan_detail_group, s.dialplan_detail_order, s.dialplan_detail_enabled \n"; + $sql .= "from v_dialplans as p, v_dialplan_details as s \n"; + $sql .= "where p.dialplan_uuid = s.dialplan_uuid \n"; + if ($this->is_empty == "dialplan_xml") { + $sql .= "and p.dialplan_xml is null \n"; + } + if (isset($this->context)) { + if ($this->context == "public" || substr($this->context, 0, 7) == "public@" || substr($this->context, -7) == ".public") { + $sql .= "and p.dialplan_context = :dialplan_context \n"; + } else { + $sql .= "and (p.dialplan_context = :dialplan_context or p.dialplan_context = '\${domain_name}' or dialplan_context = 'global') \n"; + } + $parameters['dialplan_context'] = $this->context; + } + if (is_uuid($this->uuid)) { + $sql .= "and p.dialplan_uuid = :dialplan_uuid \n"; + $parameters['dialplan_uuid'] = $this->uuid; + } + $sql .= "and (s.dialplan_detail_enabled = true or s.dialplan_detail_enabled is null) \n"; + $sql .= "order by \n"; + $sql .= "p.dialplan_order asc, \n"; + $sql .= "p.dialplan_name asc, \n"; + $sql .= "p.dialplan_uuid asc, \n"; + $sql .= "s.dialplan_detail_group asc, \n"; + $sql .= "case s.dialplan_detail_tag \n"; + $sql .= "when 'condition' then 0 \n"; + $sql .= "when 'regex' then 1 \n"; + $sql .= "when 'action' then 2 \n"; + $sql .= "when 'anti-action' then 3 \n"; + $sql .= "else 100 end, \n"; + $sql .= "s.dialplan_detail_order asc \n"; + $this->dialplan_details = $this->database->select($sql, $parameters ?? null, 'all'); + unset($sql, $parameters); + + //return if no records were found to update + if (empty($this->dialplan_details)) { + return; + } + } + + //define the values before they are used + $previous_dialplan_uuid = ''; + $previous_dialplan_detail_group = ''; + $dialplan_tag_status = ''; + $condition_attribute = ''; + $condition_break = ''; + $xml = ''; + + //loop through the results to get the xml from the dialplan_xml field or from dialplan details table + $x = 0; + if (!empty($this->dialplan_details)) { + foreach ($this->dialplan_details as $row) { + + //clear flag pass + $pass = false; + + //get the dialplan + $domain_uuid = $row["domain_uuid"]; + $dialplan_uuid = $row["dialplan_uuid"]; + //$app_uuid = $row["app_uuid"]; + $this->context = $row["dialplan_context"]; + $dialplan_name = $row["dialplan_name"]; + //$dialplan_number = $row["dialplan_number"]; + $dialplan_continue = $row["dialplan_continue"]; + //$dialplan_order = $row["dialplan_order"]; + //$dialplan_enabled = $row["dialplan_enabled"]; + //$dialplan_description = $row["dialplan_description"]; + + //$get the dialplan details + //$dialplan_detail_uuid = $row["dialplan_detail_uuid"]; + $dialplan_detail_tag = $row["dialplan_detail_tag"]; + $dialplan_detail_type = $row["dialplan_detail_type"]; + $dialplan_detail_data = $row["dialplan_detail_data"]; + $dialplan_detail_break = $row["dialplan_detail_break"]; + $dialplan_detail_inline = $row["dialplan_detail_inline"]; + $dialplan_detail_group = $row["dialplan_detail_group"]; + //$dialplan_detail_order = $row["dialplan_detail_order; + + //remove $$ and replace with $ + $dialplan_detail_data = str_replace("$$", "$", $dialplan_detail_data ?? ''); + + //get the dialplan detail inline + $detail_inline = ""; + if ($dialplan_detail_inline) { + if (!empty($dialplan_detail_inline)) { + $detail_inline = " inline=\"" . $dialplan_detail_inline . "\""; + } + } + + //close the tags + if ($dialplan_tag_status != "closed") { + if (($previous_dialplan_uuid != $dialplan_uuid) || ($previous_dialplan_detail_group != $dialplan_detail_group)) { + + if ($condition_tag_status != "closed") { + + if ($condition_attribute && (!empty($condition_attribute))) { + $xml .= " \n"; + $condition_attribute = ""; + $condition_tag_status = "closed"; + } elseif (!empty($condition) && substr($condition, -1) == ">") { + $xml .= " " . $condition; + $condition = ""; + $condition_tag_status = "closed"; + } elseif (!empty($condition)) { + $xml .= " " . $condition . "/>"; + $condition = ""; + $condition_tag_status = "closed"; + } elseif ($condition_tag_status != "closed") { + $xml .= " \n"; + $condition_tag_status = "closed"; + } + $condition_tag_status = "closed"; + } + } + if ($previous_dialplan_uuid != $dialplan_uuid) { + //close the extension tag + if (!empty($previous_dialplan_uuid)) { + $xml .= "\n"; + } + + //add to the dialplans + $dialplans[$previous_dialplan_uuid] = $xml ?? ''; + $xml = ''; + + $dialplan_tag_status = "closed"; + } + } + + //open the tags + if ($dialplan_tag_status == "closed") { + + $xml = ''; + $xml .= "\n"; + + $dialplan_tag_status = "open"; + $first_action = true; + $condition = ""; + $condition_attribute = ""; + } + if (isset($dialplan_detail_tag) && $dialplan_detail_tag == "condition" || $dialplan_detail_tag == "regex") { + //determine the type of condition + if ($dialplan_detail_type == "hour") { + $condition_type = 'time'; + } elseif ($dialplan_detail_type == "minute") { + $condition_type = 'time'; + } elseif ($dialplan_detail_type == "minute-of-day") { + $condition_type = 'time'; + } elseif ($dialplan_detail_type == "mday") { + $condition_type = 'time'; + } elseif ($dialplan_detail_type == "mweek") { + $condition_type = 'time'; + } elseif ($dialplan_detail_type == "mon") { + $condition_type = 'time'; + } elseif ($dialplan_detail_type == "time-of-day") { + $condition_type = 'time'; + } elseif ($dialplan_detail_type == "yday") { + $condition_type = 'time'; + } elseif ($dialplan_detail_type == "year") { + $condition_type = 'time'; + } elseif ($dialplan_detail_type == "wday") { + $condition_type = 'time'; + } elseif ($dialplan_detail_type == "week") { + $condition_type = 'time'; + } elseif ($dialplan_detail_type == "date-time") { + $condition_type = 'time'; + } else { + $condition_type = 'default'; + } + + //finalize any previous pending condition statements + if ($condition_tag_status == "open") { + if (!empty($condition) && substr($condition, -1) == ">") { + $xml .= $condition . "\n"; + $condition = ''; + $condition_tag_status = "closed"; + } elseif (!empty($condition)) { + $xml .= $condition . "/>\n"; + $condition = ''; + $condition_tag_status = "closed"; + } elseif (!empty($condition_attribute) && $condition_tag_status == "open") { + // previous condition(s) must have been of type time + // do not finalize if new condition is also of type time + if ($condition_type != 'time') { + // note: condition_break here is value from the previous loop + $xml .= " \n"; + $condition_attribute = ''; + $condition_tag_status = "closed"; + } + //else { + // $xml .= " \n"; + // $condition_tag_status = "closed"; + //} + } + } + + //get the condition break attribute + $condition_break = ''; + if ($dialplan_detail_break) { + if (!empty($dialplan_detail_break)) { + $condition_break = " break=\"" . $dialplan_detail_break . "\""; + } + } + + //condition tag but leave off the ending + if ($condition_type == "default") { + if (isset($dialplan_detail_type) && $dialplan_detail_tag == 'condition' && $dialplan_detail_type == 'regex') { + $condition = " "; + } elseif (isset($dialplan_detail_type) && $dialplan_detail_tag == 'regex') { + $condition = " "; + } else { + $condition = " \n"; + $condition_attribute = ""; + } elseif (!empty($condition) && !empty($condition_tag_status) && substr($condition, -1) == ">") { + $xml .= $condition . "\n"; + $condition = ""; + } elseif (!empty($condition) && !empty($condition_tag_status)) { + $xml .= $condition . ">\n"; + $condition = ""; + } + } + } + + if ($this->context == "public" || substr($this->context, 0, 7) == "public@" || substr($this->context, -7) == ".public") { + if ($dialplan_detail_tag == "action") { + if ($first_action) { + //add the call direction and domain name and uuid + $xml .= " \n"; + if (!empty($domain_uuid)) { + $domain_name = $domains[$domain_uuid]; + $xml .= " \n"; + } + if (!empty($domain_name)) { + $xml .= " \n"; + } + $first_action = false; + } + } + } + if ($dialplan_detail_tag == "action") { + $xml .= " \n"; + } + if ($dialplan_detail_tag == "anti-action") { + $xml .= " \n"; + } + + //reset back to first action if the group has changed + if ($previous_dialplan_detail_group != $dialplan_detail_group) { + $first_action = true; + } + + //save the previous values + $previous_dialplan_uuid = $dialplan_uuid; + $previous_dialplan_detail_group = $dialplan_detail_group; + + //increment the x + $x++; + + //set flag pass + $pass = true; + } + } + unset($row); + + //prevent partial dialplan (pass=nil may be error in sql or empty resultset) + if (isset($pass) && $pass == false) { + if (!empty($this->details)) { + echo 'error while build context: ' . $this->context; + } + } + + //close the extension tag if it was left open + if ($dialplan_tag_status == "open") { + if ($condition_tag_status == "open") { + if ($condition_attribute && (!empty($condition_attribute))) { + $xml .= " \n"; + } elseif (!empty($condition) && substr($condition, -1) == ">") { + $xml .= $condition . "\n"; + } elseif (!empty($condition)) { + $xml .= $condition . "/>\n"; + } else { + $xml .= " \n"; + } + } + $xml .= "\n"; + + //add to the dialplans array + $dialplans[$dialplan_uuid] = $xml; + } //set the xml array and then concatenate the array to a string - /* $xml = "\n"; */ - //$xml .= "\n"; - //$xml .= "
\n"; - //$xml .= " context . "\">\n"; + //$xml .= " \n"; + //$xml .= "
\n"; + //$xml .= "
\n"; - //set defaults - $previous_dialplan_uuid = ""; - $previous_dialplan_detail_group = ""; - $dialplan_tag_status = "closed"; - $condition_tag_status = "closed"; - - //get the dialplans from the dialplan_xml field in the dialplans table - if ($this->source == "dialplans") { - - //get the data using a join between the dialplans and dialplan details tables - $sql = "select dialplan_uuid, dialplan_xml "; - $sql .= "from v_dialplans "; - if (is_uuid($this->uuid)) { - $sql .= "where dialplan_uuid = :dialplan_uuid "; - $parameters['dialplan_uuid'] = $this->uuid; - } - else { - if (!empty($this->context)) { - if ($this->context == "public" || substr($this->context, 0, 7) == "public@" || substr($this->context, -7) == ".public") { - $sql .= "where dialplan_context = :dialplan_context "; - } - else { - $sql .= "where (dialplan_context = :dialplan_context or dialplan_context = '\${domain_name}' or dialplan_context = 'global') "; - } - $sql .= "and dialplan_enabled = true "; - $parameters['dialplan_context'] = $this->context; - } - } - if ($this->is_empty == "dialplan_xml") { - $sql .= "and p.dialplan_xml is null "; - } - $sql .= "order by "; - $sql .= "dialplan_context asc, "; - $sql .= "dialplan_order asc "; - $results = $this->database->select($sql, $parameters ?? null, 'all'); - if (!empty($results)) { - foreach ($results as $row) { - $dialplans[$row["dialplan_uuid"]] = $row["dialplan_xml"]; - } - } - unset($sql, $parameters, $results, $row); - - } - - //get the dialplans from the dialplan details - if ($this->source == "details") { - - //get the domains - if (!isset($domains)) { - $sql = "select * from v_domains "; - $result = $this->database->select($sql, null, 'all'); - if (!empty($result)) { - foreach($result as $row) { - $domains[$row['domain_uuid']] = $row['domain_name']; - } - } - unset($sql, $result, $row); - } - - //get the data using a join between the dialplans and dialplan details tables - if (empty($this->dialplan_details)) { - $sql = "select \n"; - $sql .= "p.domain_uuid, p.dialplan_uuid, p.app_uuid, p.dialplan_context, p.dialplan_name, p.dialplan_number, \n"; - $sql .= "p.dialplan_continue, p.dialplan_order, p.dialplan_enabled, p.dialplan_description, \n"; - $sql .= "s.dialplan_detail_uuid, s.dialplan_detail_tag, s.dialplan_detail_type, s.dialplan_detail_data, \n"; - $sql .= "s.dialplan_detail_break, s.dialplan_detail_inline, s.dialplan_detail_group, s.dialplan_detail_order, s.dialplan_detail_enabled \n"; - $sql .= "from v_dialplans as p, v_dialplan_details as s \n"; - $sql .= "where p.dialplan_uuid = s.dialplan_uuid \n"; - if ($this->is_empty == "dialplan_xml") { - $sql .= "and p.dialplan_xml is null \n"; - } - if (isset($this->context)) { - if ($this->context == "public" || substr($this->context, 0, 7) == "public@" || substr($this->context, -7) == ".public") { - $sql .= "and p.dialplan_context = :dialplan_context \n"; - } - else { - $sql .= "and (p.dialplan_context = :dialplan_context or p.dialplan_context = '\${domain_name}' or dialplan_context = 'global') \n"; - } - $parameters['dialplan_context'] = $this->context; - } - if (is_uuid($this->uuid)) { - $sql .= "and p.dialplan_uuid = :dialplan_uuid \n"; - $parameters['dialplan_uuid'] = $this->uuid; - } - $sql .= "and (s.dialplan_detail_enabled = true or s.dialplan_detail_enabled is null) \n"; - $sql .= "order by \n"; - $sql .= "p.dialplan_order asc, \n"; - $sql .= "p.dialplan_name asc, \n"; - $sql .= "p.dialplan_uuid asc, \n"; - $sql .= "s.dialplan_detail_group asc, \n"; - $sql .= "case s.dialplan_detail_tag \n"; - $sql .= "when 'condition' then 0 \n"; - $sql .= "when 'regex' then 1 \n"; - $sql .= "when 'action' then 2 \n"; - $sql .= "when 'anti-action' then 3 \n"; - $sql .= "else 100 end, \n"; - $sql .= "s.dialplan_detail_order asc \n"; - $this->dialplan_details = $this->database->select($sql, $parameters ?? null, 'all'); - unset($sql, $parameters); - - //return if no records were found to update - if (empty($this->dialplan_details)) { - return; - } - } - - //define the values before they are used - $previous_dialplan_uuid = ''; - $previous_dialplan_detail_group = ''; - $dialplan_tag_status = ''; - $condition_attribute = ''; - $condition_break = ''; - $xml = ''; - - //loop through the results to get the xml from the dialplan_xml field or from dialplan details table - $x = 0; - if (!empty($this->dialplan_details)) { - foreach ($this->dialplan_details as $row) { - - //clear flag pass - $pass = false; - - //get the dialplan - $domain_uuid = $row["domain_uuid"]; - $dialplan_uuid = $row["dialplan_uuid"]; - //$app_uuid = $row["app_uuid"]; - $this->context = $row["dialplan_context"]; - $dialplan_name = $row["dialplan_name"]; - //$dialplan_number = $row["dialplan_number"]; - $dialplan_continue = $row["dialplan_continue"]; - //$dialplan_order = $row["dialplan_order"]; - //$dialplan_enabled = $row["dialplan_enabled"]; - //$dialplan_description = $row["dialplan_description"]; - - //$get the dialplan details - //$dialplan_detail_uuid = $row["dialplan_detail_uuid"]; - $dialplan_detail_tag = $row["dialplan_detail_tag"]; - $dialplan_detail_type = $row["dialplan_detail_type"]; - $dialplan_detail_data = $row["dialplan_detail_data"]; - $dialplan_detail_break = $row["dialplan_detail_break"]; - $dialplan_detail_inline = $row["dialplan_detail_inline"]; - $dialplan_detail_group = $row["dialplan_detail_group"]; - //$dialplan_detail_order = $row["dialplan_detail_order; - - //remove $$ and replace with $ - $dialplan_detail_data = str_replace("$$", "$", $dialplan_detail_data ?? ''); - - //get the dialplan detail inline - $detail_inline = ""; - if ($dialplan_detail_inline) { - if (!empty($dialplan_detail_inline)) { - $detail_inline = " inline=\"" . $dialplan_detail_inline . "\""; - } - } - - //close the tags - if ($dialplan_tag_status != "closed") { - if (($previous_dialplan_uuid != $dialplan_uuid) || ($previous_dialplan_detail_group != $dialplan_detail_group)) { - - if ($condition_tag_status != "closed") { - - if ($condition_attribute && (!empty($condition_attribute))) { - $xml .= " \n"; - $condition_attribute = ""; - $condition_tag_status = "closed"; - } - else if (!empty($condition) && substr($condition, -1) == ">") { - $xml .= " ".$condition; - $condition = ""; - $condition_tag_status = "closed"; - } - else if (!empty($condition)) { - $xml .= " ".$condition . "/>"; - $condition = ""; - $condition_tag_status = "closed"; - } - else if ($condition_tag_status != "closed") { - $xml .= " \n"; - $condition_tag_status = "closed"; - } - $condition_tag_status = "closed"; - } - } - if ($previous_dialplan_uuid != $dialplan_uuid) { - //close the extension tag - if (!empty($previous_dialplan_uuid)) { - $xml .= "\n"; - } - - //add to the dialplans - $dialplans[$previous_dialplan_uuid] = $xml ?? ''; - $xml = ''; - - $dialplan_tag_status = "closed"; - } - } - - //open the tags - if ($dialplan_tag_status == "closed") { - - $xml = ''; - $xml .= "\n"; - - $dialplan_tag_status = "open"; - $first_action = true; - $condition = ""; - $condition_attribute = ""; - } - if (isset($dialplan_detail_tag) && $dialplan_detail_tag == "condition" || $dialplan_detail_tag == "regex") { - //determine the type of condition - if ($dialplan_detail_type == "hour") { - $condition_type = 'time'; - } - else if ($dialplan_detail_type == "minute") { - $condition_type = 'time'; - } - else if ($dialplan_detail_type == "minute-of-day") { - $condition_type = 'time'; - } - else if ($dialplan_detail_type == "mday") { - $condition_type = 'time'; - } - else if ($dialplan_detail_type == "mweek") { - $condition_type = 'time'; - } - else if ($dialplan_detail_type == "mon") { - $condition_type = 'time'; - } - else if ($dialplan_detail_type == "time-of-day") { - $condition_type = 'time'; - } - else if ($dialplan_detail_type == "yday") { - $condition_type = 'time'; - } - else if ($dialplan_detail_type == "year") { - $condition_type = 'time'; - } - else if ($dialplan_detail_type == "wday") { - $condition_type = 'time'; - } - else if ($dialplan_detail_type == "week") { - $condition_type = 'time'; - } - else if ($dialplan_detail_type == "date-time") { - $condition_type = 'time'; - } - else { - $condition_type = 'default'; - } - - //finalize any previous pending condition statements - if ($condition_tag_status == "open") { - if (!empty($condition) && substr($condition, -1) == ">") { - $xml .= $condition . "\n"; - $condition = ''; - $condition_tag_status = "closed"; - } - else if (!empty($condition)) { - $xml .= $condition . "/>\n"; - $condition = ''; - $condition_tag_status = "closed"; - } - else if (!empty($condition_attribute) && $condition_tag_status == "open") { - // previous condition(s) must have been of type time - // do not finalize if new condition is also of type time - if ($condition_type != 'time') { - // note: condition_break here is value from the previous loop - $xml .= " \n"; - $condition_attribute = ''; - $condition_tag_status = "closed"; - } - //else { - // $xml .= " \n"; - // $condition_tag_status = "closed"; - //} - } - } - - //get the condition break attribute - $condition_break = ''; - if ($dialplan_detail_break) { - if (!empty($dialplan_detail_break)) { - $condition_break = " break=\"" . $dialplan_detail_break . "\""; - } - } - - //condition tag but leave off the ending - if ($condition_type == "default") { - if (isset($dialplan_detail_type) && $dialplan_detail_tag == 'condition' && $dialplan_detail_type == 'regex') { - $condition = " "; - } - elseif (isset($dialplan_detail_type) && $dialplan_detail_tag == 'regex') { - $condition = " "; - } - else { - $condition = " \n"; - $condition_attribute = ""; - } - else if (!empty($condition) && !empty($condition_tag_status) && substr($condition, -1) == ">") { - $xml .= $condition . "\n"; - $condition = ""; - } - else if (!empty($condition) && !empty($condition_tag_status)) { - $xml .= $condition . ">\n"; - $condition = ""; - } - } - } - - if ($this->context == "public" || substr($this->context, 0, 7) == "public@" || substr($this->context, -7) == ".public") { - if ($dialplan_detail_tag == "action") { - if ($first_action) { - //add the call direction and domain name and uuid - $xml .= " \n"; - if (!empty($domain_uuid)) { - $domain_name = $domains[$domain_uuid]; - $xml .= " \n"; - } - if (!empty($domain_name)) { - $xml .= " \n"; - } - $first_action = false; - } - } - } - if ($dialplan_detail_tag == "action") { - $xml .= " \n"; - } - if ($dialplan_detail_tag == "anti-action") { - $xml .= " \n"; - } - - //reset back to first action if the group has changed - if ($previous_dialplan_detail_group != $dialplan_detail_group) { - $first_action = true; - } - - //save the previous values - $previous_dialplan_uuid = $dialplan_uuid; - $previous_dialplan_detail_group = $dialplan_detail_group; - - //increment the x - $x++; - - //set flag pass - $pass = true; - } - } - unset($row); - - //prevent partial dialplan (pass=nil may be error in sql or empty resultset) - if (isset($pass) && $pass == false) { - if (!empty($this->details)) { - echo 'error while build context: ' . $this->context; - } - } - - //close the extension tag if it was left open - if ($dialplan_tag_status == "open") { - if ($condition_tag_status == "open") { - if ($condition_attribute && (!empty($condition_attribute))) { - $xml .= " \n"; - } - else if (!empty($condition) && substr($condition, -1) == ">") { - $xml .= $condition . "\n"; - } - else if (!empty($condition)) { - $xml .= $condition . "/>\n"; - } - else { - $xml .= " \n"; - } - } - $xml .= "\n"; - - //add to the dialplans array - $dialplans[$dialplan_uuid] = $xml; - } - - //set the xml array and then concatenate the array to a string - //$xml .= "
\n"; - //$xml .= "
\n"; - //$xml .= "
\n"; - - } //end if source = details - - //return the array - if ($this->destination == "array") { - return $dialplans; - } - - //save the dialplan xml - if ($this->destination == "database") { - if (!empty($dialplans)) { - $x = 0; - foreach ($dialplans as $key => $value) { - if (is_uuid($key) && !empty($value)) { - //build update array - $array['dialplans'][$x]['dialplan_uuid'] = $key; - $array['dialplans'][$x]['dialplan_xml'] = $value; - - //grant temporary permissions - $p = permissions::new(); - $p->add('dialplan_edit', 'temp'); - - //execute update - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('dialplan_edit', 'temp'); - } - } - } - } + } //end if source = details + //return the array + if ($this->destination == "array") { + return $dialplans; } - public function defaults() { - - //get the array of xml files and then process thm - $xml_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/resources/switch/conf/dialplan/*.xml"); - foreach ($xml_list as $xml_file) { - //get and parse the xml - $xml_string = file_get_contents($xml_file); - - //get the order number prefix from the file name - $name_array = explode('_', basename($xml_file)); - if (is_numeric($name_array[0])) { - $dialplan_order = $name_array[0]; - } - else { - $dialplan_order = 0; - } - - //set the xml string - $this->xml = $xml_string; - - //get the domains - $sql = 'select * from v_domains'; - $domains = $this->database->select($sql, null, 'all'); - $this->import($domains); - unset($sql); - } - - //update the dialplan order - $sql_array[] = "update v_dialplans set dialplan_order = '870' where dialplan_order = '980' and dialplan_name = 'cidlookup' "; - $sql_array[] = "update v_dialplans set dialplan_order = '880' where dialplan_order = '990' and dialplan_name = 'call_screen' "; - $sql_array[] = "update v_dialplans set dialplan_order = '890' where dialplan_order = '999' and dialplan_name = 'local_extension' "; - foreach ($sql_array as $query) { - $this->database->execute($query); - } - unset($sql_array, $query); - - //add xml for each dialplan where the dialplan xml is empty - $this->source = "details"; - $this->destination = "database"; - $this->is_empty = "dialplan_xml"; - $array = $this->xml(); - //print_r($array); - unset($this->source, $this->destination, $this->is_empty, $array); - - } - - /** - * delete records - */ - public function delete($records) { - - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (!empty($records)) { - - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - - //build delete array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array['dialplan_details'][$x]['dialplan_uuid'] = $record['uuid']; - - //get the dialplan context - $sql = "select dialplan_context from v_dialplans "; - $sql .= "where dialplan_uuid = :dialplan_uuid "; - $parameters['dialplan_uuid'] = $record['uuid']; - $dialplan_contexts[] = $this->database->select($sql, $parameters ?? null, 'column'); - unset($sql, $parameters); - - } - } - - //delete the checked rows - if (!empty($array)) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('dialplan_delete', 'temp'); - $p->add('dialplan_detail_delete', 'temp'); - - //execute delete - $this->database->delete($array); - - //revoke temporary permissions - $p->delete('dialplan_delete', 'temp'); - $p->delete('dialplan_detail_delete', 'temp'); - - //clear the cache - if (!empty($dialplan_contexts)) { - $dialplan_contexts = array_unique($dialplan_contexts, SORT_STRING); - $cache = new cache; - foreach ($dialplan_contexts as $dialplan_context) { - $cache->delete("dialplan:".$dialplan_context); - } - } - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-delete'].': '.@sizeof($array[$this->table])); - - } - unset($records, $array); - - } - } - } - - public function delete_details($records) { - //set private variables - $this->table = 'dialplan_details'; - $this->uuid_prefix = 'dialplan_detail_'; - - //check the delete permission - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (!empty($records)) { - - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - - //build delete array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['dialplan_uuid'] = $this->dialplan_uuid; - - //get the dialplan context - $sql = "select dialplan_context from v_dialplans "; - $sql .= "where dialplan_uuid = :dialplan_uuid "; - $parameters['dialplan_uuid'] = $this->dialplan_uuid; - $dialplan_contexts[] = $this->database->select($sql, $parameters ?? null, 'column'); - unset($sql, $parameters); - - } - } - - //delete the checked rows - if (!empty($array)) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('dialplan_detail_delete', 'temp'); - - //execute delete - $this->database->delete($array); - - //revoke temporary permissions - $p->delete('dialplan_detail_delete', 'temp'); - - //clear the cache - if (!empty($dialplan_contexts)) { - $dialplan_contexts = array_unique($dialplan_contexts, SORT_STRING); - $cache = new cache; - foreach ($dialplan_contexts as $dialplan_context) { - $cache->delete("dialplan:".$dialplan_context); - } - } - - } - unset($records, $array); - - } - } - } - - /** - * toggle records - */ - public function toggle($records) { - - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (!empty($records)) { - - //get current toggle state - foreach($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (!empty($uuids)) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle, dialplan_context from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - if (!permission_exists('dialplan_all')) { - $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; - $parameters['domain_uuid'] = $this->domain_uuid; - } - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (!empty($rows)) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - $dialplan_contexts[] = $row['dialplan_context']; - } - } - unset($sql, $parameters, $rows, $row); - } - + //save the dialplan xml + if ($this->destination == "database") { + if (!empty($dialplans)) { + $x = 0; + foreach ($dialplans as $key => $value) { + if (is_uuid($key) && !empty($value)) { //build update array - $x = 0; - foreach($states as $uuid => $state) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } + $array['dialplans'][$x]['dialplan_uuid'] = $key; + $array['dialplans'][$x]['dialplan_xml'] = $value; - //save the changes - if (!empty($array)) { + //grant temporary permissions + $p = permissions::new(); + $p->add('dialplan_edit', 'temp'); - //grant temporary permissions - $p = permissions::new(); - $p->add('dialplan_edit', 'temp'); + //execute update + $this->database->save($array); + unset($array); - //save the array - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('dialplan_edit', 'temp'); - - //clear the cache - if (!empty($dialplan_contexts)) { - $dialplan_contexts = array_unique($dialplan_contexts, SORT_STRING); - $cache = new cache; - foreach ($dialplan_contexts as $dialplan_context) { - $cache->delete("dialplan:".$dialplan_context); - } - } - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); + //revoke temporary permissions + $p->delete('dialplan_edit', 'temp'); } - + } } } - /** - * copy records - */ - public function copy($records) { + } - //determine app and permission prefix - if (permission_exists($this->permission_prefix.'add')) { + /** + * Initializes the object with default settings and updates the database. + * + * This method processes XML files, imports domains, and updates dialplan orders in the database. + * It also adds XML for each dialplan where the dialplan XML is empty. + * + * @return void + */ + public function defaults() { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //get the array of xml files and then process thm + $xml_list = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . "/*/*/resources/switch/conf/dialplan/*.xml"); + foreach ($xml_list as $xml_file) { + //get and parse the xml + $xml_string = file_get_contents($xml_file); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; + //get the order number prefix from the file name + $name_array = explode('_', basename($xml_file)); + if (is_numeric($name_array[0])) { + $dialplan_order = $name_array[0]; + } else { + $dialplan_order = 0; + } + + //set the xml string + $this->xml = $xml_string; + + //get the domains + $sql = 'select * from v_domains'; + $domains = $this->database->select($sql, null, 'all'); + $this->import($domains); + unset($sql); + } + + //update the dialplan order + $sql_array[] = "update v_dialplans set dialplan_order = '870' where dialplan_order = '980' and dialplan_name = 'cidlookup' "; + $sql_array[] = "update v_dialplans set dialplan_order = '880' where dialplan_order = '990' and dialplan_name = 'call_screen' "; + $sql_array[] = "update v_dialplans set dialplan_order = '890' where dialplan_order = '999' and dialplan_name = 'local_extension' "; + foreach ($sql_array as $query) { + $this->database->execute($query); + } + unset($sql_array, $query); + + //add xml for each dialplan where the dialplan xml is empty + $this->source = "details"; + $this->destination = "database"; + $this->is_empty = "dialplan_xml"; + $array = $this->xml(); + //print_r($array); + unset($this->source, $this->destination, $this->is_empty, $array); + + } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (!empty($records)) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + + //build delete array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array['dialplan_details'][$x]['dialplan_uuid'] = $record['uuid']; + + //get the dialplan context + $sql = "select dialplan_context from v_dialplans "; + $sql .= "where dialplan_uuid = :dialplan_uuid "; + $parameters['dialplan_uuid'] = $record['uuid']; + $dialplan_contexts[] = $this->database->select($sql, $parameters ?? null, 'column'); + unset($sql, $parameters); + + } + } + + //delete the checked rows + if (!empty($array)) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('dialplan_delete', 'temp'); + $p->add('dialplan_detail_delete', 'temp'); + + //execute delete + $this->database->delete($array); + + //revoke temporary permissions + $p->delete('dialplan_delete', 'temp'); + $p->delete('dialplan_detail_delete', 'temp'); + + //clear the cache + if (!empty($dialplan_contexts)) { + $dialplan_contexts = array_unique($dialplan_contexts, SORT_STRING); + $cache = new cache; + foreach ($dialplan_contexts as $dialplan_context) { + $cache->delete("dialplan:" . $dialplan_context); + } } - //copy the checked records - if (!empty($records)) { + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } - //get checked records - foreach($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; + //set message + message::add($text['message-delete'] . ': ' . @sizeof($array[$this->table])); + + } + unset($records, $array); + + } + } + } + + /** + * Deletes multiple records from the dialplan details table. + * + * @param array $records An array of record IDs to delete, each containing a 'checked' and 'uuid' key + * + * @return void + */ + public function delete_details($records) { + //set private variables + $this->table = 'dialplan_details'; + $this->uuid_prefix = 'dialplan_detail_'; + + //check the delete permission + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (!empty($records)) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + + //build delete array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['dialplan_uuid'] = $this->dialplan_uuid; + + //get the dialplan context + $sql = "select dialplan_context from v_dialplans "; + $sql .= "where dialplan_uuid = :dialplan_uuid "; + $parameters['dialplan_uuid'] = $this->dialplan_uuid; + $dialplan_contexts[] = $this->database->select($sql, $parameters ?? null, 'column'); + unset($sql, $parameters); + + } + } + + //delete the checked rows + if (!empty($array)) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('dialplan_detail_delete', 'temp'); + + //execute delete + $this->database->delete($array); + + //revoke temporary permissions + $p->delete('dialplan_detail_delete', 'temp'); + + //clear the cache + if (!empty($dialplan_contexts)) { + $dialplan_contexts = array_unique($dialplan_contexts, SORT_STRING); + $cache = new cache; + foreach ($dialplan_contexts as $dialplan_context) { + $cache->delete("dialplan:" . $dialplan_context); + } + } + + } + unset($records, $array); + + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (!empty($records)) { + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (!empty($uuids)) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle, dialplan_context from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + if (!permission_exists('dialplan_all')) { + $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; + $parameters['domain_uuid'] = $this->domain_uuid; + } + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (!empty($rows)) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + $dialplan_contexts[] = $row['dialplan_context']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + + //save the changes + if (!empty($array)) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('dialplan_edit', 'temp'); + + //save the array + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('dialplan_edit', 'temp'); + + //clear the cache + if (!empty($dialplan_contexts)) { + $dialplan_contexts = array_unique($dialplan_contexts, SORT_STRING); + $cache = new cache; + foreach ($dialplan_contexts as $dialplan_context) { + $cache->delete("dialplan:" . $dialplan_context); + } + } + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + + //determine app and permission prefix + if (permission_exists($this->permission_prefix . 'add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //copy the checked records + if (!empty($records)) { + + //get checked records + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create insert array from existing data + if (!empty($uuids)) { + + //primary table + $sql = "select * from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (!empty($rows)) { + $y = 0; + foreach ($rows as $x => $row) { + //set a unique uuid + $primary_uuid = uuid(); + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; } } - //create insert array from existing data - if (!empty($uuids)) { + //copy data + $array[$this->table][$x] = $row; - //primary table - $sql = "select * from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (!empty($rows)) { - $y = 0; - foreach ($rows as $x => $row) { - //set a unique uuid - $primary_uuid = uuid(); - - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //app_uuid needs to be unique for copied dialplans - //except for inbound and outbound routes, fifo, time conditions - $app_uuid = $row['app_uuid']; - switch ($app_uuid) { - case "c03b422e-13a8-bd1b-e42b-b6b9b4d27ce4": break; - case "8c914ec3-9fc0-8ab5-4cda-6c9288bdc9a3": break; - case "16589224-c876-aeb3-f59f-523a1c0801f7": break; - case "4b821450-926b-175a-af93-a03c441818b1": break; - default: $app_uuid = uuid(); - } - - //dialplan copy should have a unique app_uuid - $array[$this->table][$x]['app_uuid'] = $app_uuid; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $primary_uuid; - $array[$this->table][$x]['dialplan_description'] = trim($row['dialplan_description'].' ('.$text['label-copy'].')'); - - //details sub table - $sql_2 = "select * from v_dialplan_details where dialplan_uuid = :dialplan_uuid"; - $parameters_2['dialplan_uuid'] = $row['dialplan_uuid']; - $rows_2 = $this->database->select($sql_2, $parameters_2 ?? null, 'all'); - if (!empty($rows_2)) { - foreach ($rows_2 as $row_2) { - - //convert boolean values to a string - foreach($row_2 as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row_2[$key] = $value; - } - } - - //copy data - $array['dialplan_details'][$y] = $row_2; - - //overwrite - $array['dialplan_details'][$y]['dialplan_detail_uuid'] = uuid(); - $array['dialplan_details'][$y]['dialplan_uuid'] = $primary_uuid; - - //increment - $y++; - - } - } - unset($sql_2, $parameters_2, $rows_2, $row_2); - - //get dialplan contexts - $dialplan_contexts[] = $row['dialplan_context']; - } - } - unset($sql, $parameters, $rows, $row); + //app_uuid needs to be unique for copied dialplans + //except for inbound and outbound routes, fifo, time conditions + $app_uuid = $row['app_uuid']; + switch ($app_uuid) { + case "c03b422e-13a8-bd1b-e42b-b6b9b4d27ce4": + break; + case "8c914ec3-9fc0-8ab5-4cda-6c9288bdc9a3": + break; + case "16589224-c876-aeb3-f59f-523a1c0801f7": + break; + case "4b821450-926b-175a-af93-a03c441818b1": + break; + default: + $app_uuid = uuid(); } - //save the changes and set the message - if (!empty($array)) { + //dialplan copy should have a unique app_uuid + $array[$this->table][$x]['app_uuid'] = $app_uuid; - //grant temporary permissions - $p = permissions::new(); - $p->add('dialplan_detail_add', 'temp'); + //overwrite + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $primary_uuid; + $array[$this->table][$x]['dialplan_description'] = trim($row['dialplan_description'] . ' (' . $text['label-copy'] . ')'); - //save the array - $this->database->save($array); - unset($array); + //details sub table + $sql_2 = "select * from v_dialplan_details where dialplan_uuid = :dialplan_uuid"; + $parameters_2['dialplan_uuid'] = $row['dialplan_uuid']; + $rows_2 = $this->database->select($sql_2, $parameters_2 ?? null, 'all'); + if (!empty($rows_2)) { + foreach ($rows_2 as $row_2) { - //revoke temporary permissions - $p->delete('dialplan_detail_add', 'temp'); - - //clear the cache - if (!empty($dialplan_contexts)) { - $dialplan_contexts = array_unique($dialplan_contexts, SORT_STRING); - $cache = new cache; - foreach ($dialplan_contexts as $dialplan_context) { - $cache->delete("dialplan:".$dialplan_context); + //convert boolean values to a string + foreach ($row_2 as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row_2[$key] = $value; } } - //set message - message::add($text['message-copy']); + //copy data + $array['dialplan_details'][$y] = $row_2; + //overwrite + $array['dialplan_details'][$y]['dialplan_detail_uuid'] = uuid(); + $array['dialplan_details'][$y]['dialplan_uuid'] = $primary_uuid; + + //increment + $y++; + + } } - unset($records); + unset($sql_2, $parameters_2, $rows_2, $row_2); + + //get dialplan contexts + $dialplan_contexts[] = $row['dialplan_context']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (!empty($array)) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('dialplan_detail_add', 'temp'); + + //save the array + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('dialplan_detail_add', 'temp'); + + //clear the cache + if (!empty($dialplan_contexts)) { + $dialplan_contexts = array_unique($dialplan_contexts, SORT_STRING); + $cache = new cache; + foreach ($dialplan_contexts as $dialplan_context) { + $cache->delete("dialplan:" . $dialplan_context); + } } + //set message + message::add($text['message-copy']); + + } + unset($records); } - } //method + } + } //method - } //class +} //class diff --git a/app/email_queue/resources/classes/email_queue.php b/app/email_queue/resources/classes/email_queue.php index 9465b1ee81..29181f6708 100644 --- a/app/email_queue/resources/classes/email_queue.php +++ b/app/email_queue/resources/classes/email_queue.php @@ -3,294 +3,332 @@ /** * email_queue class */ - class email_queue { +class email_queue { - /** - * declare constant variables - */ - const app_name = 'email_queue'; - const app_uuid = '5befdf60-a242-445f-91b3-2e9ee3e0ddf7'; + /** + * declare constant variables + */ + const app_name = 'email_queue'; + const app_uuid = '5befdf60-a242-445f-91b3-2e9ee3e0ddf7'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * declare the variables - */ - private $name; - private $table; - private $toggle_field; - private $toggle_values; - private $location; + /** + * declare the variables + */ + private $name; + private $table; + private $toggle_field; + private $toggle_values; + private $location; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); - - //assign the variables - $this->name = 'email_queue'; - $this->table = 'email_queue'; - $this->toggle_field = ''; - $this->toggle_values = ['true','false']; - $this->location = 'email_queue.php'; - } - - /** - * delete rows from the database - */ - public function delete($records) { - if (permission_exists($this->name.'_delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - //build the delete array - $x = 0; - foreach ($records as $record) { - //add to the array - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->name.'_uuid'] = $record['uuid']; - $array['email_queue_attachments'][$x][$this->name.'_uuid'] = $record['uuid']; - //$array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - } - - //increment the id - $x++; - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * resend emails in the queue - */ - public function resend($records) { - if (permission_exists($this->name.'_edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //resend multiple emails - if (is_array($records) && @sizeof($records) != 0) { - //build the message array - $x = 0; - foreach ($records as $record) { - //add to the array - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->name.'_uuid'] = $record['uuid']; - $array[$this->table][$x]['email_status'] = 'waiting'; - $array[$this->table][$x]['email_retry_count'] = null; - } - - //increment the id - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-resending_messages']); - } - unset($records); - } - } - } - - /** - * toggle a field between two values - */ - public function toggle($records) { - if (permission_exists($this->name.'_edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - //get current toggle state - foreach($records as $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->name."_uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($states as $uuid => $state) { - //create the array - $array[$this->table][$x][$this->name.'_uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - - //increment the id - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - } - } - - /** - * copy rows from the database - */ - public function copy($records) { - if (permission_exists($this->name.'_add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach($records as $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create the array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select * from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $x = 0; - foreach ($rows as $row) { - //copy data - $array[$this->table][$x] = $row; - - //add copy to the description - $array[$this->table][$x][$this->name.'_uuid'] = uuid(); - - //increment the id - $x++; - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-copy']); - } - unset($records); - } - } - } + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + //assign the variables + $this->name = 'email_queue'; + $this->table = 'email_queue'; + $this->toggle_field = ''; + $this->toggle_values = ['true', 'false']; + $this->location = 'email_queue.php'; } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->name . '_delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + //build the delete array + $x = 0; + foreach ($records as $record) { + //add to the array + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->name . '_uuid'] = $record['uuid']; + $array['email_queue_attachments'][$x][$this->name . '_uuid'] = $record['uuid']; + //$array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + } + + //increment the id + $x++; + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Resend multiple records. + * + * This method will resend the specified records if the permission to edit exists. + * It first checks if the token is valid, then it iterates over the records and + * updates their status to 'waiting' and resets the retry count. Finally, it saves + * the changes to the database. + * + * @param array $records The records to resend. + * + * @return void + */ + public function resend($records) { + if (permission_exists($this->name . '_edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //resend multiple emails + if (is_array($records) && @sizeof($records) != 0) { + //build the message array + $x = 0; + foreach ($records as $record) { + //add to the array + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->name . '_uuid'] = $record['uuid']; + $array[$this->table][$x]['email_status'] = 'waiting'; + $array[$this->table][$x]['email_retry_count'] = null; + } + + //increment the id + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-resending_messages']); + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->name . '_edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + //get current toggle state + foreach ($records as $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->name . "_uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + //create the array + $array[$this->table][$x][$this->name . '_uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + + //increment the id + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->name . '_add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create the array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select * from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $x = 0; + foreach ($rows as $row) { + //copy data + $array[$this->table][$x] = $row; + + //add copy to the description + $array[$this->table][$x][$this->name . '_uuid'] = uuid(); + + //increment the id + $x++; + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-copy']); + } + unset($records); + } + } + } + +} diff --git a/app/event_guard/resources/classes/event_guard.php b/app/event_guard/resources/classes/event_guard.php index f76fa47bad..08cac587d9 100644 --- a/app/event_guard/resources/classes/event_guard.php +++ b/app/event_guard/resources/classes/event_guard.php @@ -27,303 +27,336 @@ /** * event_guard_logs class */ - class event_guard { +class event_guard { - /** - * declare constant variables - */ - const app_name = 'event_guard'; - const app_uuid = 'c5b86612-1514-40cb-8e2c-3f01a8f6f637'; + /** + * declare constant variables + */ + const app_name = 'event_guard'; + const app_uuid = 'c5b86612-1514-40cb-8e2c-3f01a8f6f637'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * declare the variables - */ - private $name; - private $table; - private $toggle_field; - private $toggle_values; - private $location; + /** + * declare the variables + */ + private $name; + private $table; + private $toggle_field; + private $toggle_values; + private $location; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - - //assign the variables - $this->name = 'event_guard_log'; - $this->table = 'event_guard_logs'; - $this->toggle_field = ''; - $this->toggle_values = ['block','pending']; - $this->location = 'event_guard_logs.php'; - } - - /** - * delete rows from the database - */ - public function delete($records) { - if (permission_exists($this->name.'_delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - //build the delete array - $x = 0; - foreach ($records as $record) { - //add to the array - if ($record['checked'] == 'true' && is_uuid($record['event_guard_log_uuid'])) { - $array[$this->table][$x]['event_guard_log_uuid'] = $record['event_guard_log_uuid']; - } - - //increment the id - $x++; - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * update rows from the database change status to pending - */ - public function unblock($records) { - if (permission_exists($this->name.'_unblock')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - //build the delete array - $x = 0; - foreach ($records as $record) { - //add to the array - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['event_guard_log_uuid'])) { - $array[$this->table][$x]['event_guard_log_uuid'] = $record['event_guard_log_uuid']; - $array[$this->table][$x]['log_status'] = 'pending'; - } - - //increment the id - $x++; - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->save($array); - unset($array); - - //initialize the settings object - $setting = new settings(["category" => 'switch']); - - //send unblock event - $cmd = "sendevent CUSTOM\n"; - $cmd .= "Event-Name: CUSTOM\n"; - $cmd .= "Event-Subclass: event_guard:unblock\n"; - $esl = event_socket::create(); - $switch_result = event_socket::command($cmd); - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * toggle a field between two values - */ - public function toggle($records) { - if (permission_exists($this->name.'_edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - //get current toggle state - foreach($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['event_guard_log_uuid'])) { - $uuids[] = "'".$record['event_guard_log_uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->name."_uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($states as $uuid => $state) { - //create the array - $array[$this->table][$x][$this->name.'_uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - - //increment the id - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - } - } - - /** - * copy rows from the database - */ - public function copy($records) { - if (permission_exists($this->name.'_add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['event_guard_log_uuid'])) { - $uuids[] = "'".$record['event_guard_log_uuid']."'"; - } - } - - //create the array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select * from v_".$this->table." "; - $sql .= "where event_guard_log_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $x = 0; - foreach ($rows as $row) { - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //add copy to the description - $array[$this->table][$x]['event_guard_log_uuid'] = uuid(); - - //increment the id - $x++; - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-copy']); - } - unset($records); - } - } - } + //set objects + $this->database = $setting_array['database'] ?? database::new(); + //assign the variables + $this->name = 'event_guard_log'; + $this->table = 'event_guard_logs'; + $this->toggle_field = ''; + $this->toggle_values = ['block', 'pending']; + $this->location = 'event_guard_logs.php'; } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->name . '_delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + //build the delete array + $x = 0; + foreach ($records as $record) { + //add to the array + if ($record['checked'] == 'true' && is_uuid($record['event_guard_log_uuid'])) { + $array[$this->table][$x]['event_guard_log_uuid'] = $record['event_guard_log_uuid']; + } + + //increment the id + $x++; + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Unblocks multiple records. + * + * @param array $records An array of records to unblock, each containing 'event_guard_log_uuid' and 'checked' keys. + * + * @return void + */ + public function unblock($records) { + if (permission_exists($this->name . '_unblock')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + //build the delete array + $x = 0; + foreach ($records as $record) { + //add to the array + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['event_guard_log_uuid'])) { + $array[$this->table][$x]['event_guard_log_uuid'] = $record['event_guard_log_uuid']; + $array[$this->table][$x]['log_status'] = 'pending'; + } + + //increment the id + $x++; + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->save($array); + unset($array); + + //initialize the settings object + $setting = new settings(["category" => 'switch']); + + //send unblock event + $cmd = "sendevent CUSTOM\n"; + $cmd .= "Event-Name: CUSTOM\n"; + $cmd .= "Event-Subclass: event_guard:unblock\n"; + $esl = event_socket::create(); + $switch_result = event_socket::command($cmd); + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->name . '_edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + //get current toggle state + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['event_guard_log_uuid'])) { + $uuids[] = "'" . $record['event_guard_log_uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->name . "_uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + //create the array + $array[$this->table][$x][$this->name . '_uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + + //increment the id + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->name . '_add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['event_guard_log_uuid'])) { + $uuids[] = "'" . $record['event_guard_log_uuid'] . "'"; + } + } + + //create the array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select * from v_" . $this->table . " "; + $sql .= "where event_guard_log_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $x = 0; + foreach ($rows as $row) { + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; + } + } + + //copy data + $array[$this->table][$x] = $row; + + //add copy to the description + $array[$this->table][$x]['event_guard_log_uuid'] = uuid(); + + //increment the id + $x++; + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-copy']); + } + unset($records); + } + } + } + +} diff --git a/app/event_guard/resources/service/event_guard.php b/app/event_guard/resources/service/event_guard.php index 069e69c5b7..3d75f46467 100644 --- a/app/event_guard/resources/service/event_guard.php +++ b/app/event_guard/resources/service/event_guard.php @@ -115,6 +115,13 @@ echo "pid_file: ".$pid_file."\n"; //function to check if the process exists + /** + * Checks if a process exists. + * + * @param string $file Path to the file containing the process ID (PID) + * + * @return bool True if the process exists, false otherwise + */ function process_exists($file) { //set the default exists to false @@ -373,6 +380,13 @@ } //run command and capture standard output + /** + * Execute a shell command and capture its output. + * + * @param string $command The shell command to execute + * + * @return string The output of the executed command + */ function shell($command) { ob_start(); $result = system($command); @@ -381,6 +395,15 @@ } //block an ip address + /** + * Execute a block command for iptables or pf based on the firewall type. + * + * @param string $ip_address The IP address to block + * @param string $filter The filter name for iptables or pf + * @param array $event The event data containing 'to-user' and 'to-host' + * + * @return boolean True if the block command was executed successfully, false otherwise + */ function block($ip_address, $filter, $event) { //define the global variables global $database, $debug, $firewall_path, $firewall_name; @@ -434,6 +457,14 @@ } //unblock the ip address + /** + * Unblock a specified IP address from a firewall. + * + * @param string $ip_address The IP address to unblock. + * @param string $filter The filter name used in the firewall configuration. + * + * @return bool True if the IP address was successfully unblocked, false otherwise. + */ function unblock($ip_address, $filter) { //define the global variables global $debug, $firewall_path, $firewall_name; @@ -470,6 +501,13 @@ } //is the ip address blocked + /** + * Check if an IP address is blocked in the configured firewall. + * + * @param string $ip_address The IP address to check + * + * @return bool True if the address is blocked, False otherwise + */ function is_blocked($ip_address) { //define the global variables global $firewall_path, $firewall_name; @@ -502,6 +540,17 @@ } //determine if the IP address has been allowed by the access control list node cidr + /** + * Determine if access is allowed for a given IP address. + * + * This method checks the cache, user logs, event guard logs, access controls, + * and registration to determine if access should be granted. If no valid reason + * is found to deny access, it will be automatically allowed. + * + * @param string $ip_address The IP address to check for access. + * + * @return boolean True if access is allowed, false otherwise. + */ function access_allowed($ip_address) { //define global variables global $debug; @@ -586,6 +635,13 @@ } //is the ip address registered + /** + * Checks if the given IP address is registered on the network. + * + * @param string $ip_address The IP address to check for registration. + * + * @return bool True if the IP address is registered, false otherwise. + */ function is_registered($ip_address) { //invalid ip address if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { @@ -609,6 +665,13 @@ } //determine if the IP address has been allowed by the access control list node cidr + /** + * Checks if the given IP address is authorized by any access control node. + * + * @param string $ip_address The IP address to check for authorization. + * + * @return bool True if the IP address is authorized, false otherwise. + */ function access_control_allowed($ip_address) { global $database; @@ -653,6 +716,13 @@ } //determine if the IP address has been allowed by a successful authentication + /** + * Determines if a user's IP address is allowed based on their login history. + * + * @param string $ip_address The IP address to check for access. + * + * @return bool True if the IP address is allowed, false otherwise. + */ function user_log_allowed($ip_address) { global $database, $debug; @@ -689,6 +759,13 @@ } //determine if the IP address has been unblocked in the event guard log + /** + * Determines if an IP address is allowed based on event guard logs. + * + * @param string $ip_address The IP address to check for access. + * + * @return bool True if the IP address is allowed, false otherwise. + */ function event_guard_log_allowed($ip_address) { global $database, $debug; @@ -724,6 +801,13 @@ } //check if the iptables chain exists + /** + * Determines if a pf table exists in the firewall configuration. + * + * @param string $table The name of the pf table to check for existence. + * + * @return bool True if the pf table exists, false otherwise. + */ function pf_table_exists($table) { //define the global variables global $firewall_path, $firewall_name; @@ -741,6 +825,13 @@ } //add IP table chains + /** + * Adds a new IPtables chain and inserts it into the INPUT table. + * + * @param string $chain The name of the IPtables chain to add. + * + * @return bool True if the chain was successfully added, false otherwise. + */ function iptables_chain_add($chain) { //define the global variables global $firewall_path; @@ -769,6 +860,13 @@ } //check if the iptables chain exists + /** + * Determines if a specified iptables chain exists. + * + * @param string $chain The name of the iptables chain to check for existence. + * + * @return bool True if the iptables chain exists, false otherwise. + */ function iptables_chain_exists($chain) { //define the global variables global $firewall_path; @@ -784,5 +882,3 @@ return false; } } - -?> diff --git a/app/extension_settings/resources/classes/extension_settings.php b/app/extension_settings/resources/classes/extension_settings.php index 7892257e75..5f40db66a4 100644 --- a/app/extension_settings/resources/classes/extension_settings.php +++ b/app/extension_settings/resources/classes/extension_settings.php @@ -27,292 +27,321 @@ /** * extension_settings class */ - class extension_settings { +class extension_settings { - /** - * declare constant variables - */ - const app_name = 'extension_settings'; - const app_uuid = '1416a250-f6e1-4edc-91a6-5c9b883638fd'; + /** + * declare constant variables + */ + const app_name = 'extension_settings'; + const app_uuid = '1416a250-f6e1-4edc-91a6-5c9b883638fd'; - /** - * declare the public variables - */ - public $extension_uuid; + /** + * declare the public variables + */ + public $extension_uuid; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * declare the private variables - */ - private $name; - private $table; - private $toggle_field; - private $toggle_values; - private $description_field; - private $location; + /** + * declare the private variables + */ + private $name; + private $table; + private $toggle_field; + private $toggle_values; + private $description_field; + private $location; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); + //set objects + $this->database = $setting_array['database'] ?? database::new(); - //assign the variables - $this->name = 'extension_setting'; - $this->table = 'extension_settings'; - $this->toggle_field = 'extension_setting_enabled'; - $this->toggle_values = ['true','false']; - $this->description_field = 'extension_setting_description'; - $this->location = 'extension_settings.php'; - - } - - /** - * delete rows from the database - */ - public function delete($records) { - if (permission_exists($this->name.'_delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - //build the delete array - $x = 0; - foreach ($records as $record) { - //add to the array - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->name.'_uuid'] = $record['uuid']; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - - if (empty($this->extension_uuid)) { - $sql = "select ".$this->name."_uuid as uuid, ".$this->toggle_field." as toggle, extension_uuid "; - $sql .= "from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in :uuid "; - $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['uuid'] = $record['uuid']; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $this->extension_uuid = $rows[0]['extension_uuid']; - } - unset($sql, $parameters); - } - } - - //increment the id - $x++; - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - - //clear the cache - if (!empty($this->extension_uuid)) { - $sql = "select extension, number_alias, user_context from v_extensions "; - $sql .= "where extension_uuid = :extension_uuid "; - $parameters['extension_uuid'] = $this->extension_uuid; - $extension = $this->database->select($sql, $parameters, 'row'); - $cache = new cache; - $cache->delete(gethostname().":directory:".$extension["extension"]."@".$extension["user_context"]); - $cache->delete(gethostname().":directory:".$extension["number_alias"]."@".$extension["user_context"]); - } - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * toggle a field between two values - */ - public function toggle($records) { - if (permission_exists($this->name.'_edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - //get current toggle state - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->name."_uuid as uuid, ".$this->toggle_field." as toggle, extension_uuid from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $this->extension_uuid = $rows[0]['extension_uuid']; - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($states as $uuid => $state) { - //create the array - $array[$this->table][$x][$this->name.'_uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - - //increment the id - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //clear the cache - $sql = "select extension, number_alias, user_context from v_extensions "; - $sql .= "where extension_uuid = :extension_uuid "; - $parameters['extension_uuid'] = $this->extension_uuid; - $extension = $this->database->select($sql, $parameters, 'row'); - $cache = new cache; - $cache->delete(gethostname().":directory:".$extension["extension"]."@".$extension["user_context"]); - $cache->delete(gethostname().":directory:".$extension["number_alias"]."@".$extension["user_context"]); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - } - } - - /** - * copy rows from the database - */ - public function copy($records) { - if (permission_exists($this->name.'_add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create the array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select * from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $x => $row) { - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->name.'_uuid'] = uuid(); - $array[$this->table][$x][$this->name.'_enabled'] = $row['extension_setting_enabled'] === true ? 'true' : 'false'; - $array[$this->table][$x][$this->description_field] = trim($row[$this->description_field] ?? '').' ('.$text['label-copy'].')'; - - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - //save the array - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-copy']); - } - unset($records); - } - } - } + //assign the variables + $this->name = 'extension_setting'; + $this->table = 'extension_settings'; + $this->toggle_field = 'extension_setting_enabled'; + $this->toggle_values = ['true', 'false']; + $this->description_field = 'extension_setting_description'; + $this->location = 'extension_settings.php'; } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->name . '_delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + //build the delete array + $x = 0; + foreach ($records as $record) { + //add to the array + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->name . '_uuid'] = $record['uuid']; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + + if (empty($this->extension_uuid)) { + $sql = "select " . $this->name . "_uuid as uuid, " . $this->toggle_field . " as toggle, extension_uuid "; + $sql .= "from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in :uuid "; + $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['uuid'] = $record['uuid']; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $this->extension_uuid = $rows[0]['extension_uuid']; + } + unset($sql, $parameters); + } + } + + //increment the id + $x++; + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); + + //clear the cache + if (!empty($this->extension_uuid)) { + $sql = "select extension, number_alias, user_context from v_extensions "; + $sql .= "where extension_uuid = :extension_uuid "; + $parameters['extension_uuid'] = $this->extension_uuid; + $extension = $this->database->select($sql, $parameters, 'row'); + $cache = new cache; + $cache->delete(gethostname() . ":directory:" . $extension["extension"] . "@" . $extension["user_context"]); + $cache->delete(gethostname() . ":directory:" . $extension["number_alias"] . "@" . $extension["user_context"]); + } + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->name . '_edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + //get current toggle state + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->name . "_uuid as uuid, " . $this->toggle_field . " as toggle, extension_uuid from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $this->extension_uuid = $rows[0]['extension_uuid']; + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + //create the array + $array[$this->table][$x][$this->name . '_uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + + //increment the id + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //clear the cache + $sql = "select extension, number_alias, user_context from v_extensions "; + $sql .= "where extension_uuid = :extension_uuid "; + $parameters['extension_uuid'] = $this->extension_uuid; + $extension = $this->database->select($sql, $parameters, 'row'); + $cache = new cache; + $cache->delete(gethostname() . ":directory:" . $extension["extension"] . "@" . $extension["user_context"]); + $cache->delete(gethostname() . ":directory:" . $extension["number_alias"] . "@" . $extension["user_context"]); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->name . '_add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create the array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select * from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $x => $row) { + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; + } + } + + //copy data + $array[$this->table][$x] = $row; + + //overwrite + $array[$this->table][$x][$this->name . '_uuid'] = uuid(); + $array[$this->table][$x][$this->name . '_enabled'] = $row['extension_setting_enabled'] === true ? 'true' : 'false'; + $array[$this->table][$x][$this->description_field] = trim($row[$this->description_field] ?? '') . ' (' . $text['label-copy'] . ')'; + + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + //save the array + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-copy']); + } + unset($records); + } + } + } + +} diff --git a/app/extensions/extension_download.php b/app/extensions/extension_download.php index 9132144d47..efa4717808 100644 --- a/app/extensions/extension_download.php +++ b/app/extensions/extension_download.php @@ -93,6 +93,13 @@ $available_columns[] = 'forward_user_not_registered_enabled'; //define the functions + /** + * Converts a multi-dimensional array into a CSV string. + * + * @param array &$array The input array to be converted. It is expected that all rows of the array have the same number of columns. + * + * @return string|null The CSV string representation of the input array, or null if the input array is empty. + */ function array2csv(array &$array) { if (count($array) == 0) { return null; @@ -107,6 +114,11 @@ return ob_get_clean(); } + /** + * Sets the headers for a file download. + * + * @param string $filename The name of the file to be downloaded. + */ function download_send_headers($filename) { // disable caching $now = gmdate("D, d M Y H:i:s"); diff --git a/app/extensions/extension_edit.php b/app/extensions/extension_edit.php index fc59d13ef3..b9d9bf9c96 100644 --- a/app/extensions/extension_edit.php +++ b/app/extensions/extension_edit.php @@ -50,6 +50,16 @@ $page = isset($_REQUEST['page']) && is_numeric($_REQUEST['page']) ? $_REQUEST['page'] : 0; //return the first item if data type = array, returns value if data type = text + /** + * Returns the first item of a given value. + * + * If the value is an array, returns the first element of the array. + * Otherwise, returns the value as is. + * + * @param mixed $value The value to retrieve the first item from. + * + * @return mixed The first item of the value. + */ function get_first_item($value) { return is_array($value) ? $value[0] : $value; } diff --git a/app/extensions/extension_imports.php b/app/extensions/extension_imports.php index 837dba6550..bdd4ed79f8 100644 --- a/app/extensions/extension_imports.php +++ b/app/extensions/extension_imports.php @@ -38,18 +38,6 @@ $language = new text; $text = $language->get(); -//built in str_getcsv requires PHP 5.3 or higher, this function can be used to reproduct the functionality but requirs PHP 5.1.0 or higher - if (!function_exists('str_getcsv')) { - function str_getcsv($input, $delimiter = ",", $enclosure = '"', $escape = "\\") { - $fp = fopen("php://memory", 'r+'); - fputs($fp, $input); - rewind($fp); - $data = fgetcsv($fp, null, $delimiter, $enclosure, $escape); - fclose($fp); - return $data; - } - } - //get the http get values and set them as php variables $action = $_POST["action"] ?? null; $from_row = $_POST["from_row"] ?? null; @@ -224,6 +212,14 @@ } //get the parent table + /** + * Retrieves the parent table name for a given table in the database schema. + * + * @param array $schema The database schema, where each element is an associative array containing 'table' and 'parent' keys. + * @param string $table_name The name of the table for which to retrieve the parent table name. + * + * @return mixed|null The parent table name if found, otherwise null. + */ function get_parent($schema,$table_name) { foreach ($schema as $row) { if ($row['table'] == $table_name) { diff --git a/app/extensions/resources/classes/extension.php b/app/extensions/resources/classes/extension.php index d18b1ed0f9..6614da2950 100644 --- a/app/extensions/resources/classes/extension.php +++ b/app/extensions/resources/classes/extension.php @@ -25,809 +25,860 @@ */ //define the directory class - class extension { +class extension { - /** - * declare constant variables - */ - const app_name = 'extensions'; - const app_uuid = 'e68d9689-2769-e013-28fa-6214bf47fca3'; + /** + * declare constant variables + */ + const app_name = 'extensions'; + const app_uuid = 'e68d9689-2769-e013-28fa-6214bf47fca3'; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_uuid; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_name; - /** - * declare public variables - */ - public $extension_uuid; - public $extension; - public $voicemail_id; - public $number_alias; - public $password; - public $provisioning_list; - public $voicemail_password; - public $accountcode; - public $effective_caller_id_name; - public $effective_caller_id_number; - public $outbound_caller_id_name; - public $outbound_caller_id_number; - public $emergency_caller_id_name; - public $emergency_caller_id_number; - public $directory_full_name; - public $directory_visible; - public $directory_exten_visible; - public $limit_max; - public $limit_destination; - public $voicemail_enabled; - public $voicemail_mail_to; - public $voicemail_file; - public $voicemail_local_after_email; - public $user_context; - public $toll_allow; - public $call_timeout; - public $call_group; - public $hold_music; - public $auth_acl; - public $cidr; - public $sip_force_contact; - public $sip_force_expires; - public $nibble_account; - public $mwi_account; - public $sip_bypass_media; - public $absolute_codec_string; - public $dial_string; - public $enabled; - public $description; - public $delete_voicemail; + /** + * declare public variables + */ + public $extension_uuid; + public $extension; + public $voicemail_id; + public $number_alias; + public $password; + public $provisioning_list; + public $voicemail_password; + public $accountcode; + public $effective_caller_id_name; + public $effective_caller_id_number; + public $outbound_caller_id_name; + public $outbound_caller_id_number; + public $emergency_caller_id_name; + public $emergency_caller_id_number; + public $directory_full_name; + public $directory_visible; + public $directory_exten_visible; + public $limit_max; + public $limit_destination; + public $voicemail_enabled; + public $voicemail_mail_to; + public $voicemail_file; + public $voicemail_local_after_email; + public $user_context; + public $toll_allow; + public $call_timeout; + public $call_group; + public $hold_music; + public $auth_acl; + public $cidr; + public $sip_force_contact; + public $sip_force_expires; + public $nibble_account; + public $mwi_account; + public $sip_bypass_media; + public $absolute_codec_string; + public $dial_string; + public $enabled; + public $description; + public $delete_voicemail; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); - //assign private variables - $this->permission_prefix = 'extension_'; - $this->list_page = 'extensions.php'; - $this->table = 'extensions'; - $this->uuid_prefix = 'extension_'; - $this->toggle_field = 'enabled'; - $this->toggle_values = ['true','false']; + //assign private variables + $this->permission_prefix = 'extension_'; + $this->list_page = 'extensions.php'; + $this->table = 'extensions'; + $this->uuid_prefix = 'extension_'; + $this->toggle_field = 'enabled'; + $this->toggle_values = ['true', 'false']; + } + + /** + * Checks if an extension exists for a given domain UUID. + * + * @param string $domain_uuid The unique identifier of the domain. + * @param string $extension The name or alias of the extension to check. + * + * @return bool True if the extension exists, false otherwise. + */ + public function exists($domain_uuid, $extension) { + $sql = "select count(*) from v_extensions "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and ( "; + $sql .= "extension = :extension "; + $sql .= "or number_alias = :extension "; + $sql .= ") "; + $sql .= "and enabled = 'true' "; + $parameters['domain_uuid'] = $domain_uuid; + $parameters['extension'] = $extension; + return $this->database->select($sql, $parameters, 'column') != 0 ? true : false; + } + + /** + * Retrieves the domain UUID associated with this object. + * + * @return string The domain UUID as a string. + */ + public function get_domain_uuid() { + return $this->domain_uuid; + } + + /** + * Sets the domain UUID for the current session. + * + * @param string $domain_uuid The UUID of the domain to be set. + * + * @return void + */ + public function set_domain_uuid($domain_uuid) { + $this->domain_uuid = $domain_uuid; + } + + /** + * Updates or inserts the voicemail settings in the database. + * + * @return void + */ + public function voicemail() { + //determine the voicemail_id + if (is_numeric($this->number_alias)) { + $this->voicemail_id = $this->number_alias; + } else { + $this->voicemail_id = $this->extension; } - public function exists($domain_uuid, $extension) { - $sql = "select count(*) from v_extensions "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ( "; - $sql .= "extension = :extension "; - $sql .= "or number_alias = :extension "; - $sql .= ") "; - $sql .= "and enabled = 'true' "; + //insert or update the voicemail settings + $sql = "select voicemail_uuid from v_voicemails "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and voicemail_id = :voicemail_id "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['voicemail_id'] = $this->voicemail_id; + $voicemail_uuid = $this->database->select($sql, $parameters, 'column'); + unset($sql, $parameters); + + if (is_uuid($voicemail_uuid)) { + //build update array + $array['voicemails'][0]['voicemail_uuid'] = $voicemail_uuid; + //grant temporary permissions + $p = permissions::new(); + $p->add('voicemail_edit', 'temp'); + } else { + //build insert array + $array['voicemails'][0]['voicemail_uuid'] = uuid(); + $array['voicemails'][0]['domain_uuid'] = $this->domain_uuid; + //grant temporary permissions + $p = permissions::new(); + $p->add('voicemail_add', 'temp'); + } + if (is_array($array) && @sizeof($array) != 0) { + //include common array fields + $array['voicemails'][0]['voicemail_id'] = $this->voicemail_id; + $array['voicemails'][0]['voicemail_password'] = $this->voicemail_password; + $array['voicemails'][0]['voicemail_mail_to'] = $this->voicemail_mail_to; + $array['voicemails'][0]['voicemail_file'] = $this->voicemail_file; + $array['voicemails'][0]['voicemail_local_after_email'] = $this->voicemail_local_after_email; + $array['voicemails'][0]['voicemail_enabled'] = $this->voicemail_enabled; + $array['voicemails'][0]['voicemail_description'] = $this->description; + //execute insert/update + $this->database->app_name = 'extensions'; + $this->database->app_uuid = 'e68d9689-2769-e013-28fa-6214bf47fca3'; + $this->database->save($array); + unset($array); + //revoke temporary permissions + $p->delete('voicemail_edit', 'temp'); + $p->delete('voicemail_add', 'temp'); + } + + unset($voicemail_uuid); + } + + /** + * Generates XML files for extensions. + * + * @return void + */ + public function xml() { + if (!empty($this->settings->get('switch', 'extensions'))) { + //declare global variables + global $config, $domain_uuid; + + //get the domain_name + $domain_name = $_SESSION['domains'][$domain_uuid]['domain_name']; + $user_context = $domain_name; + + //delete all old extensions to prepare for new ones + $dialplan_list = glob($this->settings->get('switch', 'extensions') . "/" . $user_context . "/v_*.xml"); + foreach ($dialplan_list as $name => $value) { + unlink($value); + } + + //write the xml files + $sql = "select * from v_extensions as e, v_voicemails as v "; + $sql .= "where e.domain_uuid = :domain_uuid "; + $sql .= "and coalesce(nullif(e.number_alias,''),e.extension) = cast(v.voicemail_id as varchar) "; + $sql .= "order by e.call_group asc "; $parameters['domain_uuid'] = $domain_uuid; - $parameters['extension'] = $extension; - return $this->database->select($sql, $parameters, 'column') != 0 ? true : false; + $rows = $this->database->select($sql, $parameters, 'all'); unset($sql, $parameters); - } - public function get_domain_uuid() { - return $this->domain_uuid; - } - - public function set_domain_uuid($domain_uuid){ - $this->domain_uuid = $domain_uuid; - } - - public function voicemail() { - //determine the voicemail_id - if (is_numeric($this->number_alias)) { - $this->voicemail_id = $this->number_alias; - } - else { - $this->voicemail_id = $this->extension; - } - - //insert or update the voicemail settings - $sql = "select voicemail_uuid from v_voicemails "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and voicemail_id = :voicemail_id "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['voicemail_id'] = $this->voicemail_id; - $voicemail_uuid = $this->database->select($sql, $parameters, 'column'); - unset($sql, $parameters); - - if (is_uuid($voicemail_uuid)) { - //build update array - $array['voicemails'][0]['voicemail_uuid'] = $voicemail_uuid; - //grant temporary permissions - $p = permissions::new(); - $p->add('voicemail_edit', 'temp'); - } - else { - //build insert array - $array['voicemails'][0]['voicemail_uuid'] = uuid(); - $array['voicemails'][0]['domain_uuid'] = $this->domain_uuid; - //grant temporary permissions - $p = permissions::new(); - $p->add('voicemail_add', 'temp'); - } - if (is_array($array) && @sizeof($array) != 0) { - //include common array fields - $array['voicemails'][0]['voicemail_id'] = $this->voicemail_id; - $array['voicemails'][0]['voicemail_password'] = $this->voicemail_password; - $array['voicemails'][0]['voicemail_mail_to'] = $this->voicemail_mail_to; - $array['voicemails'][0]['voicemail_file'] = $this->voicemail_file; - $array['voicemails'][0]['voicemail_local_after_email'] = $this->voicemail_local_after_email; - $array['voicemails'][0]['voicemail_enabled'] = $this->voicemail_enabled; - $array['voicemails'][0]['voicemail_description'] = $this->description; - //execute insert/update - $this->database->app_name = 'extensions'; - $this->database->app_uuid = 'e68d9689-2769-e013-28fa-6214bf47fca3'; - $this->database->save($array); - unset($array); - //revoke temporary permissions - $p->delete('voicemail_edit', 'temp'); - $p->delete('voicemail_add', 'temp'); - } - - unset($voicemail_uuid); - } - - public function xml() { - if (!empty($this->settings->get('switch', 'extensions'))) { - //declare global variables - global $config, $domain_uuid; - - //get the domain_name - $domain_name = $_SESSION['domains'][$domain_uuid]['domain_name']; - $user_context = $domain_name; - - //delete all old extensions to prepare for new ones - $dialplan_list = glob($this->settings->get('switch', 'extensions')."/".$user_context."/v_*.xml"); - foreach($dialplan_list as $name => $value) { - unlink($value); - } - - //write the xml files - $sql = "select * from v_extensions as e, v_voicemails as v "; - $sql .= "where e.domain_uuid = :domain_uuid "; - $sql .= "and coalesce(nullif(e.number_alias,''),e.extension) = cast(v.voicemail_id as varchar) "; - $sql .= "order by e.call_group asc "; - $parameters['domain_uuid'] = $domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - unset($sql, $parameters); - - $extension_xml_condensed = false; - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $call_group = $row['call_group'] ?? ''; - $call_group = str_replace(";", ",", $call_group); - $tmp_array = explode(",", $call_group); - $call_group_array = []; - foreach ($tmp_array as $tmp_call_group) { - $tmp_call_group = trim($tmp_call_group); - if (!empty($tmp_call_group)) { - if (empty($call_group_array[$tmp_call_group])) { - $call_group_array[$tmp_call_group] = $row['extension']; - } - else { - $call_group_array[$tmp_call_group] = $call_group_array[$tmp_call_group].','.$row['extension']; - } - } - } - $call_timeout = $row['call_timeout']; - $user_context = $row['user_context']; - $password = $row['password']; - $voicemail_password = $row['voicemail_password']; - //$voicemail_password = str_replace("#", "", $voicemail_password); //preserves leading zeros - - //echo "enabled: ".$row['enabled']; - if ($row['enabled'] != "false") { - $extension_uuid = $row['extension_uuid']; - //remove invalid characters from the file names - $extension = $row['extension']; - $extension = str_replace(" ", "_", $extension); - $extension = preg_replace("/[\*\:\\/\<\>\|\'\"\?]/", "", $extension); - $dial_string = $row['dial_string']; - if (empty($dial_string)) { - if (!empty($this->settings->get('domain', 'dial_string'))) { - $dial_string = $this->settings->get('domain', 'dial_string'); - } - else { - $dial_string = "{sip_invite_domain=\${domain_name},leg_timeout=".$call_timeout.",presence_id=\${dialed_user}@\${dialed_domain}}\${sofia_contact(\${dialed_user}@\${dialed_domain})}"; - } - } - - //set the password hashes - $a1_hash = md5($extension.":".$domain_name.":".$password); - $vm_a1_hash = md5($extension.":".$domain_name.":".$voicemail_password); - - $xml = "\n"; - $cidr = ''; - if (!empty($row['cidr'])) { - $cidr = " cidr=\"" . $row['cidr'] . "\""; - } - $number_alias = ''; - if (!empty($row['number_alias'])) { - $number_alias = " number-alias=\"".$row['number_alias']."\""; - } - $xml .= " \n"; - $xml .= " \n"; - //$xml .= " \n"; - $xml .= " \n"; - $xml .= " \n"; - $xml .= " \n"; - - //voicemail settings - //$xml .= " \n"; - $xml .= " \n"; - switch ($row['voicemail_enabled']) { - case "true": - $xml .= " \n"; - break; - case "false": - $xml .= " \n"; - break; - default: - $xml .= " \n"; - } - if (!empty($row['voicemail_mail_to'])) { - $xml .= " \n"; - switch ($row['voicemail_file']) { - case "attach": - $xml .= " \n"; - break; - default: - $xml .= " \n"; - } - switch ($row['voicemail_local_after_email']) { - case "true": - $xml .= " \n"; - break; - case "false": - $xml .= " \n"; - break; - default: - $xml .= " \n"; - } - $xml .= " \n"; - } - - if (!empty($row['mwi_account'])) { - $xml .= " \n"; - } - if (!empty($row['auth_acl'])) { - $xml .= " \n"; - } - if (!empty($row['directory_exten_visible'])) { - $xml .= " \n"; - } - $xml .= " \n"; - $xml .= " \n"; - $xml .= " \n"; - $xml .= " domain_name . "\"/>\n"; - $xml .= " domain_uuid . "\"/>\n"; - $xml .= " \n"; - if (!empty($row['call_group'])) { - $xml .= " \n"; - } - if (!empty($row['user_record'])) { - $xml .= " \n"; - } - if (!empty($row['hold_music'])) { - $xml .= " \n"; - } - $xml .= " \n"; - if (!empty($row['call_timeout'])) { - $xml .= " \n"; - } - if (!empty($switch_account_code)) { - $xml .= " \n"; - } - else { - $xml .= " \n"; - } - $xml .= " \n"; - if (!empty($row['effective_caller_id_name'])) { - $xml .= " \n"; - } - if (!empty($row['effective_caller_id_number'])) { - $xml .= " \n"; - } - if (!empty($row['outbound_caller_id_name'])) { - $xml .= " \n"; - } - if (!empty($row['outbound_caller_id_number'])) { - $xml .= " \n"; - } - if (!empty($row['emergency_caller_id_name'])) { - $xml .= " \n"; - } - if (!empty($row['emergency_caller_id_number'])) { - $xml .= " \n"; - } - if (!empty($row['directory_full_name'])) { - $xml .= " \n"; - } - if (!empty($row['directory_visible'])) { - $xml .= " \n"; - } - if (!empty($row['limit_max'])) { - $xml .= " \n"; - } - else { - $xml .= " \n"; - } - if (!empty($row['limit_destination'])) { - $xml .= " \n"; - } - if (!empty($row['sip_force_contact'])) { - $xml .= " \n"; - } - if (!empty($row['sip_force_expires'])) { - $xml .= " \n"; - } - if (!empty($row['nibble_account'])) { - $xml .= " \n"; - } - switch ($row['sip_bypass_media']) { - case "bypass-media": - $xml .= " \n"; - break; - case "bypass-media-after-bridge": - $xml .= " \n"; - break; - case "proxy-media": - $xml .= " \n"; - break; - } - if (!empty($row['absolute_codec_string'])) { - $xml .= " \n"; - } - if (!empty($row['forward_all_enabled'])) { - $xml .= " \n"; - } - if (!empty($row['forward_all_destination'])) { - $xml .= " \n"; - } - if (!empty($row['forward_busy_enabled'])) { - $xml .= " \n"; - } - if (!empty($row['forward_busy_destination'])) { - $xml .= " \n"; - } - if (!empty($row['forward_no_answer_enabled'])) { - $xml .= " \n"; - } - if (!empty($row['forward_no_answer_destination'])) { - $xml .= " \n"; - } - if (!empty($row['forward_user_not_registered_enabled'])) { - $xml .= " \n"; - } - if (!empty($row['forward_user_not_registered_destination'])) { - $xml .= " \n"; - } - - if (!empty($row['do_not_disturb'])) { - $xml .= " \n"; - } - $xml .= " \n"; - $xml .= " \n"; - - if (!is_readable($this->settings->get('switch', 'extensions')."/".$row['user_context'])) { - mkdir($this->settings->get('switch', 'extensions')."/".$row['user_context'], 0770, false); - } - if (!empty($extension)) { - $fout = fopen($this->settings->get('switch', 'extensions')."/".$row['user_context']."/v_".$extension.".xml","w"); - } - $xml .= "\n"; - fwrite($fout, $xml); - unset($xml); - fclose($fout); + $extension_xml_condensed = false; + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $call_group = $row['call_group'] ?? ''; + $call_group = str_replace(";", ",", $call_group); + $tmp_array = explode(",", $call_group); + $call_group_array = []; + foreach ($tmp_array as $tmp_call_group) { + $tmp_call_group = trim($tmp_call_group); + if (!empty($tmp_call_group)) { + if (empty($call_group_array[$tmp_call_group])) { + $call_group_array[$tmp_call_group] = $row['extension']; + } else { + $call_group_array[$tmp_call_group] = $call_group_array[$tmp_call_group] . ',' . $row['extension']; } } } - unset($rows, $row); + $call_timeout = $row['call_timeout']; + $user_context = $row['user_context']; + $password = $row['password']; + $voicemail_password = $row['voicemail_password']; + //$voicemail_password = str_replace("#", "", $voicemail_password); //preserves leading zeros - //prepare extension - $extension_dir = realpath($this->settings->get('switch', 'extensions')); - $user_context = str_replace(" ", "_", $user_context); - $user_context = preg_replace("/[\*\:\\/\<\>\|\'\"\?]/", "", $user_context); - - //define the group members - $xml = "\n"; - $xml .= "\n"; - $xml .= "\n"; - $xml .= " \n"; - if ($user_context == "default") { - $xml .= " \n"; - } - else { - $xml .= " \n"; - } - $xml .= " \n"; - //$xml .= " \n"; - $xml .= " \n"; - $xml .= "\n"; - $xml .= " \n"; - $xml .= " \n"; - $xml .= " \n"; - $xml .= " \n"; - $xml .= " \n"; - $xml .= " \n"; - $xml .= " \n"; - $xml .= "\n"; - $xml .= " \n"; - $xml .= " \n"; - $xml .= " \n"; - $xml .= " \n"; - $xml .= " \n"; - $xml .= " \n"; - $xml .= "\n"; - $previous_call_group = ""; - foreach ($call_group_array as $key => $value) { - $call_group = trim($key); - $extension_list = trim($value); - if (!empty($call_group)) { - if ($previous_call_group != $call_group) { - $xml .= " \n"; - $xml .= " \n"; - $xml .= " \n"; - $extension_array = explode(",", $extension_list); - foreach ($extension_array as $tmp_extension) { - $xml .= " \n"; - } - $xml .= " \n"; - $xml .= " \n"; - $xml .= "\n"; + //echo "enabled: ".$row['enabled']; + if ($row['enabled'] != "false") { + $extension_uuid = $row['extension_uuid']; + //remove invalid characters from the file names + $extension = $row['extension']; + $extension = str_replace(" ", "_", $extension); + $extension = preg_replace("/[\*\:\\/\<\>\|\'\"\?]/", "", $extension); + $dial_string = $row['dial_string']; + if (empty($dial_string)) { + if (!empty($this->settings->get('domain', 'dial_string'))) { + $dial_string = $this->settings->get('domain', 'dial_string'); + } else { + $dial_string = "{sip_invite_domain=\${domain_name},leg_timeout=" . $call_timeout . ",presence_id=\${dialed_user}@\${dialed_domain}}\${sofia_contact(\${dialed_user}@\${dialed_domain})}"; } - $previous_call_group = $call_group; } - unset($call_group); - } - $xml .= " \n"; - $xml .= "\n"; - $xml .= " \n"; - $xml .= ""; - //write the xml file - if (is_readable($extension_dir) && !empty($extension_dir)) { - $fout = fopen($extension_dir."/".$user_context.".xml","w"); + //set the password hashes + $a1_hash = md5($extension . ":" . $domain_name . ":" . $password); + $vm_a1_hash = md5($extension . ":" . $domain_name . ":" . $voicemail_password); + + $xml = "\n"; + $cidr = ''; + if (!empty($row['cidr'])) { + $cidr = " cidr=\"" . $row['cidr'] . "\""; + } + $number_alias = ''; + if (!empty($row['number_alias'])) { + $number_alias = " number-alias=\"" . $row['number_alias'] . "\""; + } + $xml .= " \n"; + $xml .= " \n"; + //$xml .= " \n"; + $xml .= " \n"; + $xml .= " \n"; + $xml .= " \n"; + + //voicemail settings + //$xml .= " \n"; + $xml .= " \n"; + switch ($row['voicemail_enabled']) { + case "true": + $xml .= " \n"; + break; + case "false": + $xml .= " \n"; + break; + default: + $xml .= " \n"; + } + if (!empty($row['voicemail_mail_to'])) { + $xml .= " \n"; + switch ($row['voicemail_file']) { + case "attach": + $xml .= " \n"; + break; + default: + $xml .= " \n"; + } + switch ($row['voicemail_local_after_email']) { + case "true": + $xml .= " \n"; + break; + case "false": + $xml .= " \n"; + break; + default: + $xml .= " \n"; + } + $xml .= " \n"; + } + + if (!empty($row['mwi_account'])) { + $xml .= " \n"; + } + if (!empty($row['auth_acl'])) { + $xml .= " \n"; + } + if (!empty($row['directory_exten_visible'])) { + $xml .= " \n"; + } + $xml .= " \n"; + $xml .= " \n"; + $xml .= " \n"; + $xml .= " domain_name . "\"/>\n"; + $xml .= " domain_uuid . "\"/>\n"; + $xml .= " \n"; + if (!empty($row['call_group'])) { + $xml .= " \n"; + } + if (!empty($row['user_record'])) { + $xml .= " \n"; + } + if (!empty($row['hold_music'])) { + $xml .= " \n"; + } + $xml .= " \n"; + if (!empty($row['call_timeout'])) { + $xml .= " \n"; + } + if (!empty($switch_account_code)) { + $xml .= " \n"; + } else { + $xml .= " \n"; + } + $xml .= " \n"; + if (!empty($row['effective_caller_id_name'])) { + $xml .= " \n"; + } + if (!empty($row['effective_caller_id_number'])) { + $xml .= " \n"; + } + if (!empty($row['outbound_caller_id_name'])) { + $xml .= " \n"; + } + if (!empty($row['outbound_caller_id_number'])) { + $xml .= " \n"; + } + if (!empty($row['emergency_caller_id_name'])) { + $xml .= " \n"; + } + if (!empty($row['emergency_caller_id_number'])) { + $xml .= " \n"; + } + if (!empty($row['directory_full_name'])) { + $xml .= " \n"; + } + if (!empty($row['directory_visible'])) { + $xml .= " \n"; + } + if (!empty($row['limit_max'])) { + $xml .= " \n"; + } else { + $xml .= " \n"; + } + if (!empty($row['limit_destination'])) { + $xml .= " \n"; + } + if (!empty($row['sip_force_contact'])) { + $xml .= " \n"; + } + if (!empty($row['sip_force_expires'])) { + $xml .= " \n"; + } + if (!empty($row['nibble_account'])) { + $xml .= " \n"; + } + switch ($row['sip_bypass_media']) { + case "bypass-media": + $xml .= " \n"; + break; + case "bypass-media-after-bridge": + $xml .= " \n"; + break; + case "proxy-media": + $xml .= " \n"; + break; + } + if (!empty($row['absolute_codec_string'])) { + $xml .= " \n"; + } + if (!empty($row['forward_all_enabled'])) { + $xml .= " \n"; + } + if (!empty($row['forward_all_destination'])) { + $xml .= " \n"; + } + if (!empty($row['forward_busy_enabled'])) { + $xml .= " \n"; + } + if (!empty($row['forward_busy_destination'])) { + $xml .= " \n"; + } + if (!empty($row['forward_no_answer_enabled'])) { + $xml .= " \n"; + } + if (!empty($row['forward_no_answer_destination'])) { + $xml .= " \n"; + } + if (!empty($row['forward_user_not_registered_enabled'])) { + $xml .= " \n"; + } + if (!empty($row['forward_user_not_registered_destination'])) { + $xml .= " \n"; + } + + if (!empty($row['do_not_disturb'])) { + $xml .= " \n"; + } + $xml .= " \n"; + $xml .= " \n"; + + if (!is_readable($this->settings->get('switch', 'extensions') . "/" . $row['user_context'])) { + mkdir($this->settings->get('switch', 'extensions') . "/" . $row['user_context'], 0770, false); + } + if (!empty($extension)) { + $fout = fopen($this->settings->get('switch', 'extensions') . "/" . $row['user_context'] . "/v_" . $extension . ".xml", "w"); + } + $xml .= "\n"; fwrite($fout, $xml); unset($xml); fclose($fout); } - - //apply settings - $_SESSION["reload_xml"] = true; + } } - } + unset($rows, $row); - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { + //prepare extension + $extension_dir = realpath($this->settings->get('switch', 'extensions')); + $user_context = str_replace(" ", "_", $user_context); + $user_context = preg_replace("/[\*\:\\/\<\>\|\'\"\?]/", "", $user_context); - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //build the delete array - $y = @sizeof($records) + 1; - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - - //get the extension details - $sql = "select extension, number_alias, user_context, follow_me_uuid from v_extensions "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and extension_uuid = :extension_uuid "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['extension_uuid'] = $record['uuid']; - $row = $this->database->select($sql, $parameters, 'row'); - if (is_array($row) && @sizeof($row) != 0) { - - //for use below and to clear cache (bottom) - $extensions[$x] = $row; - - //build delete array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array['extension_users'][$x]['extension_uuid'] = $record['uuid']; - - //include follow me destinations, if exists - if (is_uuid($extensions[$x]['follow_me_uuid'])) { - $array['follow_me'][$x]['follow_me_uuid'] = $extensions[$x]['follow_me_uuid']; - $array['follow_me_destinations'][$x]['follow_me_uuid'] = $extensions[$x]['follow_me_uuid']; - } - - //include ring group destinations, if exists - if (file_exists($_SERVER["PROJECT_ROOT"]."/app/ring_groups/app_config.php")) { - $array['ring_group_destinations'][$x]['destination_number'] = $extensions[$x]['extension']; - $array['ring_group_destinations'][$x]['domain_uuid'] = $this->domain_uuid; - if (is_numeric($extensions[$x]['number_alias'])) { - $array['ring_group_destinations'][$y]['destination_number'] = $extensions[$x]['number_alias']; - $array['ring_group_destinations'][$y]['domain_uuid'] = $this->domain_uuid; - } - $y++; - } - - //include extension settings, if exists - if (file_exists($_SERVER["PROJECT_ROOT"]."/app/extension_settings/app_config.php")) { - $array['extension_settings'][$x]['extension_uuid'] = $record['uuid']; - $array['extension_settings'][$x]['domain_uuid'] = $this->domain_uuid; - } - - //create array of voicemail ids - if ($this->delete_voicemail && permission_exists('voicemail_delete')) { - if (is_numeric($extensions[$x]['extension'])) { $voicemail_ids[] = $extensions[$x]['extension']; } - if (is_numeric($extensions[$x]['number_alias'])) { $voicemail_ids[] = $extensions[$x]['number_alias']; } - } - - } - unset($sql, $parameters, $row); - - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //delete extension voicemail boxes - if ( - $this->delete_voicemail - && permission_exists('voicemail_delete') - && is_array($voicemail_ids) - && @sizeof($voicemail_ids) != 0 - ) { - //retrieve voicemail uuids - $sql = "select voicemail_uuid as uuid from v_voicemails "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and voicemail_id in ('".implode("','", $voicemail_ids)."') "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $r => $row) { - $voicemails[$r]['checked'] = 'true'; - $voicemails[$r]['uuid'] = $row['uuid']; - } - } - - //delete voicemail boxes - if (!empty($voicemails) && is_array($voicemails)) { - $obj = new voicemail; - $obj->voicemail_delete($voicemails); - } - } - - //grant temporary permissions - $p = permissions::new(); - $p->add('extension_user_delete', 'temp'); - $p->add('follow_me_delete', 'temp'); - $p->add('follow_me_destination_delete', 'temp'); - $p->add('ring_group_destination_delete', 'temp'); - $p->add('extension_setting_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('extension_user_delete', 'temp'); - $p->delete('follow_me_delete', 'temp'); - $p->delete('follow_me_destination_delete', 'temp'); - $p->delete('ring_group_destination_delete', 'temp'); - $p->delete('extension_setting_delete', 'temp'); - - //clear the cache - foreach ($extensions as $x => $extension) { - $cache = new cache; - $cache->delete(gethostname().":directory:".$extension['extension']."@".$extension['user_context']); - if (permission_exists('number_alias') && !empty($extension['number_alias'])) { - $cache->delete(gethostname().":directory:".$extension['number_alias']."@".$extension['user_context']); - } - } - unset($extensions); - - //synchronize configuration - if (!empty($this->settings->get('switch', 'extensions')) && is_writable($this->settings->get('switch', 'extensions'))) { - $this->xml(); - } - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-delete']); - - } - unset($records); - } + //define the group members + $xml = "\n"; + $xml .= "\n"; + $xml .= "\n"; + $xml .= " \n"; + if ($user_context == "default") { + $xml .= " \n"; + } else { + $xml .= " \n"; } - } - - /** - * toggle records - */ - public function toggle($records) { - if (permission_exists($this->permission_prefix.'enabled')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; + $xml .= " \n"; + //$xml .= " \n"; + $xml .= " \n"; + $xml .= "\n"; + $xml .= " \n"; + $xml .= " \n"; + $xml .= " \n"; + $xml .= " \n"; + $xml .= " \n"; + $xml .= " \n"; + $xml .= " \n"; + $xml .= "\n"; + $xml .= " \n"; + $xml .= " \n"; + $xml .= " \n"; + $xml .= " \n"; + $xml .= " \n"; + $xml .= " \n"; + $xml .= "\n"; + $previous_call_group = ""; + foreach ($call_group_array as $key => $value) { + $call_group = trim($key); + $extension_list = trim($value); + if (!empty($call_group)) { + if ($previous_call_group != $call_group) { + $xml .= " \n"; + $xml .= " \n"; + $xml .= " \n"; + $extension_array = explode(",", $extension_list); + foreach ($extension_array as $tmp_extension) { + $xml .= " \n"; + } + $xml .= " \n"; + $xml .= " \n"; + $xml .= "\n"; } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle, extension, number_alias, user_context from v_".$this->table." "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - //for use below and to clear cache (bottom) - $extensions[$row['uuid']]['state'] = $row['toggle']; - $extensions[$row['uuid']]['extension'] = $row['extension']; - $extensions[$row['uuid']]['number_alias'] = $row['number_alias']; - $extensions[$row['uuid']]['user_context'] = $row['user_context']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($extensions as $uuid => $extension) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $extension['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('extension_edit', 'temp'); - - //save the array - - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('extension_edit', 'temp'); - - //synchronize configuration - if (!empty($this->settings->get('switch', 'extensions')) && is_writable($this->settings->get('switch', 'extensions'))) { - $this->xml(); - } - - //write the provision files - if (!empty($this->settings->get('provision', 'path'))) { - if (is_dir($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/app/provision')) { - $prov = new provision; - $prov->domain_uuid = $this->domain_uuid; - $response = $prov->write(); - } - } - - //clear the cache - foreach ($extensions as $uuid => $extension) { - $cache = new cache; - $cache->delete(gethostname().":directory:".$extension['extension']."@".$extension['user_context']); - if (permission_exists('number_alias') && !empty($extension['number_alias'])) { - $cache->delete(gethostname().":directory:".$extension['number_alias']."@".$extension['user_context']); - } - } - unset($extensions); - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-toggle']); - - } - unset($records); - } - + $previous_call_group = $call_group; + } + unset($call_group); } - } + $xml .= " \n"; + $xml .= "\n"; + $xml .= " \n"; + $xml .= ""; + //write the xml file + if (is_readable($extension_dir) && !empty($extension_dir)) { + $fout = fopen($extension_dir . "/" . $user_context . ".xml", "w"); + fwrite($fout, $xml); + unset($xml); + fclose($fout); + } + + //apply settings + $_SESSION["reload_xml"] = true; + } } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + $y = @sizeof($records) + 1; + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + + //get the extension details + $sql = "select extension, number_alias, user_context, follow_me_uuid from v_extensions "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and extension_uuid = :extension_uuid "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['extension_uuid'] = $record['uuid']; + $row = $this->database->select($sql, $parameters, 'row'); + if (is_array($row) && @sizeof($row) != 0) { + + //for use below and to clear cache (bottom) + $extensions[$x] = $row; + + //build delete array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array['extension_users'][$x]['extension_uuid'] = $record['uuid']; + + //include follow me destinations, if exists + if (is_uuid($extensions[$x]['follow_me_uuid'])) { + $array['follow_me'][$x]['follow_me_uuid'] = $extensions[$x]['follow_me_uuid']; + $array['follow_me_destinations'][$x]['follow_me_uuid'] = $extensions[$x]['follow_me_uuid']; + } + + //include ring group destinations, if exists + if (file_exists($_SERVER["PROJECT_ROOT"] . "/app/ring_groups/app_config.php")) { + $array['ring_group_destinations'][$x]['destination_number'] = $extensions[$x]['extension']; + $array['ring_group_destinations'][$x]['domain_uuid'] = $this->domain_uuid; + if (is_numeric($extensions[$x]['number_alias'])) { + $array['ring_group_destinations'][$y]['destination_number'] = $extensions[$x]['number_alias']; + $array['ring_group_destinations'][$y]['domain_uuid'] = $this->domain_uuid; + } + $y++; + } + + //include extension settings, if exists + if (file_exists($_SERVER["PROJECT_ROOT"] . "/app/extension_settings/app_config.php")) { + $array['extension_settings'][$x]['extension_uuid'] = $record['uuid']; + $array['extension_settings'][$x]['domain_uuid'] = $this->domain_uuid; + } + + //create array of voicemail ids + if ($this->delete_voicemail && permission_exists('voicemail_delete')) { + if (is_numeric($extensions[$x]['extension'])) { + $voicemail_ids[] = $extensions[$x]['extension']; + } + if (is_numeric($extensions[$x]['number_alias'])) { + $voicemail_ids[] = $extensions[$x]['number_alias']; + } + } + + } + unset($sql, $parameters, $row); + + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //delete extension voicemail boxes + if ( + $this->delete_voicemail + && permission_exists('voicemail_delete') + && is_array($voicemail_ids) + && @sizeof($voicemail_ids) != 0 + ) { + //retrieve voicemail uuids + $sql = "select voicemail_uuid as uuid from v_voicemails "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and voicemail_id in ('" . implode("','", $voicemail_ids) . "') "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $r => $row) { + $voicemails[$r]['checked'] = 'true'; + $voicemails[$r]['uuid'] = $row['uuid']; + } + } + + //delete voicemail boxes + if (!empty($voicemails) && is_array($voicemails)) { + $obj = new voicemail; + $obj->voicemail_delete($voicemails); + } + } + + //grant temporary permissions + $p = permissions::new(); + $p->add('extension_user_delete', 'temp'); + $p->add('follow_me_delete', 'temp'); + $p->add('follow_me_destination_delete', 'temp'); + $p->add('ring_group_destination_delete', 'temp'); + $p->add('extension_setting_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('extension_user_delete', 'temp'); + $p->delete('follow_me_delete', 'temp'); + $p->delete('follow_me_destination_delete', 'temp'); + $p->delete('ring_group_destination_delete', 'temp'); + $p->delete('extension_setting_delete', 'temp'); + + //clear the cache + foreach ($extensions as $x => $extension) { + $cache = new cache; + $cache->delete(gethostname() . ":directory:" . $extension['extension'] . "@" . $extension['user_context']); + if (permission_exists('number_alias') && !empty($extension['number_alias'])) { + $cache->delete(gethostname() . ":directory:" . $extension['number_alias'] . "@" . $extension['user_context']); + } + } + unset($extensions); + + //synchronize configuration + if (!empty($this->settings->get('switch', 'extensions')) && is_writable($this->settings->get('switch', 'extensions'))) { + $this->xml(); + } + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //set message + message::add($text['message-delete']); + + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->permission_prefix . 'enabled')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle, extension, number_alias, user_context from v_" . $this->table . " "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + //for use below and to clear cache (bottom) + $extensions[$row['uuid']]['state'] = $row['toggle']; + $extensions[$row['uuid']]['extension'] = $row['extension']; + $extensions[$row['uuid']]['number_alias'] = $row['number_alias']; + $extensions[$row['uuid']]['user_context'] = $row['user_context']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($extensions as $uuid => $extension) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $extension['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('extension_edit', 'temp'); + + //save the array + + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('extension_edit', 'temp'); + + //synchronize configuration + if (!empty($this->settings->get('switch', 'extensions')) && is_writable($this->settings->get('switch', 'extensions'))) { + $this->xml(); + } + + //write the provision files + if (!empty($this->settings->get('provision', 'path'))) { + if (is_dir($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/app/provision')) { + $prov = new provision; + $prov->domain_uuid = $this->domain_uuid; + $response = $prov->write(); + } + } + + //clear the cache + foreach ($extensions as $uuid => $extension) { + $cache = new cache; + $cache->delete(gethostname() . ":directory:" . $extension['extension'] . "@" . $extension['user_context']); + if (permission_exists('number_alias') && !empty($extension['number_alias'])) { + $cache->delete(gethostname() . ":directory:" . $extension['number_alias'] . "@" . $extension['user_context']); + } + } + unset($extensions); + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //set message + message::add($text['message-toggle']); + + } + unset($records); + } + + } + } + +} diff --git a/app/fax/fax_emails.php b/app/fax/fax_emails.php index 7b814eb044..843a31ce02 100644 --- a/app/fax/fax_emails.php +++ b/app/fax/fax_emails.php @@ -40,6 +40,13 @@ $sql .= "and fax_email_outbound_subject_tag is not null "; $result = $database->select($sql, null, 'all'); unset($sql); +/** + * Converts an array to a map where each unique value in the array is mapped to true. + * + * @param array &$arr The input array + * + * @return array|false A map where each unique value in the array is mapped to true, or false if the input array is empty. + */ function arr_to_map(&$arr){ if (!empty($arr)){ $map = Array(); diff --git a/app/fax/fax_send.php b/app/fax/fax_send.php index 0260f0ddc7..ca48202f5f 100644 --- a/app/fax/fax_send.php +++ b/app/fax/fax_send.php @@ -127,6 +127,13 @@ //define function correct_path if (!function_exists('correct_path')) { + /** + * Corrects a file path to match the current operating system's conventions. + * + * @param string $p The file path to correct + * + * @return string The corrected file path + */ function correct_path($p) { global $IS_WINDOWS; if ($IS_WINDOWS) { @@ -138,6 +145,17 @@ if (!function_exists('correct_path')) { //define function gs_cmd if (!function_exists('gs_cmd')) { + /** + * Generates a command to execute Ghostscript. + * + * The command is constructed based on the value of $IS_WINDOWS, which indicates + * whether the script is running under Windows. If it is, the command includes + * the 'gswin32c' executable, otherwise it uses 'gs'. + * + * @param string $args Command line arguments to be passed to Ghostscript. + * + * @return string The constructed command as a string. + */ function gs_cmd($args) { global $IS_WINDOWS; if ($IS_WINDOWS) { @@ -149,7 +167,17 @@ if (!function_exists('gs_cmd')) { //define function fax_split dtmf if (!function_exists('fax_split_dtmf')) { - function fax_split_dtmf(&$fax_number, &$fax_dtmf){ + /** + * Splits a fax number string into its numeric and DTMF (Dual-Tone Multi-Frequency) parts. + * + * If the input fax number is in the format '12345678 (DTMF_digits)', this function + * extracts the numeric part and stores it in $fax_number, while storing the DTMF digits + * in $fax_dtmf. + * + * @param string &$fax_number The fax number to be split. Modified to contain only the numeric part. + * @param string &$fax_dtmf The extracted DTMF digits from the input fax number. + */ + function fax_split_dtmf(&$fax_number, &$fax_dtmf) { $tmp = array(); $fax_dtmf = ''; if (preg_match('/^\s*(.*?)\s*\((.*)\)\s*$/', $fax_number, $tmp)){ diff --git a/app/fax/resources/classes/fax.php b/app/fax/resources/classes/fax.php index 3fd9eff015..d5e54b572c 100644 --- a/app/fax/resources/classes/fax.php +++ b/app/fax/resources/classes/fax.php @@ -25,753 +25,808 @@ */ //define the fax class - class fax { +class fax { - /** - * declare constant variables - */ - const app_name = 'fax'; - const app_uuid = '24108154-4ac3-1db6-1551-4731703a4440'; + /** + * declare constant variables + */ + const app_name = 'fax'; + const app_uuid = '24108154-4ac3-1db6-1551-4731703a4440'; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_uuid; - /** - * define the variables - */ - public $fax_uuid; - public $dialplan_uuid; - public $fax_name; - public $fax_description; - public $fax_extension; - public $fax_forward_number; - public $destination_number; - public $box; - public $order_by; - public $order; - public $download; + /** + * define the variables + */ + public $fax_uuid; + public $dialplan_uuid; + public $fax_name; + public $fax_description; + public $fax_extension; + public $fax_forward_number; + public $destination_number; + public $box; + public $order_by; + public $order; + public $download; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_name; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; - private $forward_prefix; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; + private $forward_prefix; - /** - * Called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + } + + /** + * Processes and saves a dial plan for faxing. + * + * This method normalizes fax forward numbers, sets the forward prefix, + * builds an XML dial plan, and saves it to the database. It also clears + * any existing cache and removes temporary permissions after saving. + * + * @return mixed|null The UUID of the saved dialplan or null if not saved. + */ + public function dialplan() { + + //require the fax_extension + if (empty($this->fax_extension)) { + return false; } - /** - * Add a dialplan for call center - * @var string $domain_uuid the multi-tenant id - * @var string $value string to be cached - */ - public function dialplan() { - - //require the fax_extension - if (empty($this->fax_extension)) { - return false; - } - - //require the destination_number - if (empty($this->destination_number)) { - return false; - } - - //normalize the fax forward number - if (strlen($this->fax_forward_number) > 3) { - //$fax_forward_number = preg_replace("~[^0-9]~", "",$fax_forward_number); - $this->fax_forward_number = str_replace(" ", "", $this->fax_forward_number); - $this->fax_forward_number = str_replace("-", "", $this->fax_forward_number); - } - - //set the forward prefix - if (strripos($this->fax_forward_number, '$1') === false) { - $this->forward_prefix = ''; //not found - } else { - $this->forward_prefix = $this->forward_prefix.$this->fax_forward_number.'#'; //found - } - - //set the dialplan_uuid - if (empty($this->dialplan_uuid)) { - $this->dialplan_uuid = uuid(); - } - else { - //build previous details delete array - $array['dialplan_details'][0]['dialplan_uuid'] = $this->dialplan_uuid; - $array['dialplan_details'][0]['domain_uuid'] = $this->domain_uuid; - - //grant temporary permissions - $p = permissions::new(); - $p->add('dialplan_detail_delete', 'temp'); - - //execute delete - $this->database->app_name = 'fax'; - $this->database->app_uuid = '24108154-4ac3-1db6-1551-4731703a4440'; - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('dialplan_detail_delete', 'temp'); - } - - //set the fax name - $fax_name = ($this->fax_name != '') ? $this->fax_name : format_phone($this->destination_number); - - //set the last fax - if (!empty($this->settings->get('fax', 'last_fax'))) { - $last_fax = "last_fax=".xml::sanitize($this->settings->get('fax', 'last_fax')); - } - else { - $last_fax = "last_fax=\${caller_id_number}-\${strftime(%Y-%m-%d-%H-%M-%S)}"; - } - - //set the rx_fax - $rxfax_data = $this->settings->get('switch', 'storage').'/fax/'.$this->domain_name.'/'.xml::sanitize($this->fax_extension).'/inbox/'.xml::sanitize($this->forward_prefix).'${last_fax}.tif'; - - //build the xml dialplan - $dialplan_xml = "dialplan_uuid)."\">\n"; - $dialplan_xml .= " destination_number)."$\">\n"; - $dialplan_xml .= " \n"; - $dialplan_xml .= " fax_uuid)."\"/>\n"; - $dialplan_xml .= " \n"; - foreach($_SESSION['fax']['variable'] as $data) { - if (substr($data,0,8) == "inbound:") { - $dialplan_xml .= " \n"; - } - elseif (substr($data,0,9) == "outbound:") {} - else { - $dialplan_xml .= " \n"; - } - } - $dialplan_xml .= " \n"; - $dialplan_xml .= " \n"; - $dialplan_xml .= " \n"; - $dialplan_xml .= " \n"; - $dialplan_xml .= "\n"; - - //build the dialplan array - $dialplan["app_uuid"] = "24108154-4ac3-1db6-1551-4731703a4440"; - $dialplan["domain_uuid"] = $this->domain_uuid; - $dialplan["dialplan_uuid"] = $this->dialplan_uuid; - $dialplan["dialplan_name"] = ($this->fax_name != '') ? $this->fax_name : format_phone($this->destination_number); - $dialplan["dialplan_number"] = $this->fax_extension; - $dialplan["dialplan_context"] = $this->domain_name; - $dialplan["dialplan_continue"] = false; - $dialplan["dialplan_xml"] = $dialplan_xml; - $dialplan["dialplan_order"] = "40"; - $dialplan["dialplan_enabled"] = true; - $dialplan["dialplan_description"] = $this->fax_description; - $dialplan_detail_order = 10; - - //prepare the array - $array['dialplans'][] = $dialplan; - - //add the dialplan permission - $p = permissions::new(); - $p->add("dialplan_add", 'temp'); - $p->add("dialplan_detail_add", 'temp'); - $p->add("dialplan_edit", 'temp'); - $p->add("dialplan_detail_edit", 'temp'); - - //save the dialplan - $this->database->app_name = 'fax'; - $this->database->app_uuid = '24108154-4ac3-1db6-1551-4731703a4440'; - $this->database->save($array); - //$message = $this->database->message; - - //remove the temporary permission - $p->delete("dialplan_add", 'temp'); - $p->delete("dialplan_detail_add", 'temp'); - $p->delete("dialplan_edit", 'temp'); - $p->delete("dialplan_detail_edit", 'temp'); - - //clear the cache - $cache = new cache; - $cache->delete("dialplan:".$this->domain_name); - - //return the dialplan_uuid - return $dialplan_response ?? null; - + //require the destination_number + if (empty($this->destination_number)) { + return false; } - /** - * delete records - */ - public function delete($records) { + //normalize the fax forward number + if (strlen($this->fax_forward_number) > 3) { + //$fax_forward_number = preg_replace("~[^0-9]~", "",$fax_forward_number); + $this->fax_forward_number = str_replace(" ", "", $this->fax_forward_number); + $this->fax_forward_number = str_replace("-", "", $this->fax_forward_number); + } - //set private variables - $this->permission_prefix = 'fax_extension_'; - $this->list_page = 'fax.php'; - $this->table = 'fax'; - $this->uuid_prefix = 'fax_'; + //set the forward prefix + if (strripos($this->fax_forward_number, '$1') === false) { + $this->forward_prefix = ''; //not found + } else { + $this->forward_prefix = $this->forward_prefix . $this->fax_forward_number . '#'; //found + } - if (permission_exists($this->permission_prefix.'delete')) { + //set the dialplan_uuid + if (empty($this->dialplan_uuid)) { + $this->dialplan_uuid = uuid(); + } else { + //build previous details delete array + $array['dialplan_details'][0]['dialplan_uuid'] = $this->dialplan_uuid; + $array['dialplan_details'][0]['domain_uuid'] = $this->domain_uuid; - //add multi-lingual support - $language = new text; - $text = $language->get(); + //grant temporary permissions + $p = permissions::new(); + $p->add('dialplan_detail_delete', 'temp'); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } + //execute delete + $this->database->app_name = 'fax'; + $this->database->app_uuid = '24108154-4ac3-1db6-1551-4731703a4440'; + $this->database->delete($array); + unset($array); - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { + //revoke temporary permissions + $p->delete('dialplan_detail_delete', 'temp'); + } - //filter out unchecked fax extensions, build where clause for below - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } + //set the fax name + $fax_name = ($this->fax_name != '') ? $this->fax_name : format_phone($this->destination_number); - //get necessary fax details - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, dialplan_uuid from v_".$this->table." "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $faxes[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; - } - } - unset($sql, $parameters, $rows, $row); - } + //set the last fax + if (!empty($this->settings->get('fax', 'last_fax'))) { + $last_fax = "last_fax=" . xml::sanitize($this->settings->get('fax', 'last_fax')); + } else { + $last_fax = "last_fax=\${caller_id_number}-\${strftime(%Y-%m-%d-%H-%M-%S)}"; + } - //get necessary fax file details - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select fax_file_uuid as uuid, fax_mode, fax_file_path, fax_file_type from v_fax_files "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - if ($row['fax_mode'] == 'rx') { $fax_files[$row['uuid']]['folder'] = 'inbox'; } - if ($row['fax_mode'] == 'tx') { $fax_files[$row['uuid']]['folder'] = 'sent'; } - $fax_files[$row['uuid']]['path'] = $row['fax_file_path']; - $fax_files[$row['uuid']]['type'] = $row['fax_file_type']; - } - } - unset($sql, $parameters, $rows, $row); - } + //set the rx_fax + $rxfax_data = $this->settings->get('switch', 'storage') . '/fax/' . $this->domain_name . '/' . xml::sanitize($this->fax_extension) . '/inbox/' . xml::sanitize($this->forward_prefix) . '${last_fax}.tif'; - //delete fax file(s) - if (!empty($fax_files) && is_array($fax_files) && @sizeof($fax_files) != 0) { - foreach ($fax_files as $fax_file_uuid => $fax_file) { - if (substr_count($fax_file['path'], '/temp/') > 0) { - $fax_file['path'] = str_replace('/temp/', '/'.$fax_file['type'].'/', $fax_file['path']); - } - if (file_exists($fax_file['path'])) { - @unlink($fax_file['path']); - } - if ($fax_file['type'] == 'tif') { - $fax_file['path'] = str_replace('.tif', '.pdf', $fax_file['path']); - if (file_exists($fax_file['path'])) { - @unlink($fax_file['path']); - } - } - else if ($fax_file['type'] == 'pdf') { - $fax_file['path'] = str_replace('.pdf', '.tif', $fax_file['path']); - if (file_exists($fax_file['path'])) { - @unlink($fax_file['path']); - } - } - } - } - - //build the delete array - $x = 0; - if (!empty($faxes) && is_array($faxes) && @sizeof($faxes) != 0) { - foreach ($faxes as $fax_uuid => $fax) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $fax_uuid; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - $array['fax_users'][$x][$this->uuid_prefix.'uuid'] = $fax_uuid; - $array['fax_users'][$x]['domain_uuid'] = $this->domain_uuid; - $array['fax_files'][$x][$this->uuid_prefix.'uuid'] = $fax_uuid; - $array['fax_files'][$x]['domain_uuid'] = $this->domain_uuid; - $array['fax_logs'][$x][$this->uuid_prefix.'uuid'] = $fax_uuid; - $array['fax_logs'][$x]['domain_uuid'] = $this->domain_uuid; - $array['dialplans'][$x]['dialplan_uuid'] = $fax['dialplan_uuid']; - $array['dialplans'][$x]['domain_uuid'] = $this->domain_uuid; - $array['dialplan_details'][$x]['dialplan_uuid'] = $fax['dialplan_uuid']; - $array['dialplan_details'][$x]['domain_uuid'] = $this->domain_uuid; - $x++; - } - } - - //delete the checked rows - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('fax_delete', 'temp'); - $p->add('fax_user_delete', 'temp'); - $p->add('fax_file_delete', 'temp'); - $p->add('fax_log_delete', 'temp'); - $p->add('dialplan_delete', 'temp'); - $p->add('dialplan_detail_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('fax_delete', 'temp'); - $p->delete('fax_user_delete', 'temp'); - $p->delete('fax_file_delete', 'temp'); - $p->delete('fax_log_delete', 'temp'); - $p->delete('dialplan_delete', 'temp'); - $p->delete('dialplan_detail_delete', 'temp'); - - //apply settings reminder - $_SESSION["reload_xml"] = true; - - //clear the cache - $cache = new cache; - $cache->delete("dialplan:".$this->domain_name); - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-delete']); - } - unset($records); - } + //build the xml dialplan + $dialplan_xml = "dialplan_uuid) . "\">\n"; + $dialplan_xml .= " destination_number) . "$\">\n"; + $dialplan_xml .= " \n"; + $dialplan_xml .= " fax_uuid) . "\"/>\n"; + $dialplan_xml .= " \n"; + foreach ($_SESSION['fax']['variable'] as $data) { + if (substr($data, 0, 8) == "inbound:") { + $dialplan_xml .= " \n"; + } elseif (substr($data, 0, 9) == "outbound:") { + } else { + $dialplan_xml .= " \n"; } } + $dialplan_xml .= " \n"; + $dialplan_xml .= " \n"; + $dialplan_xml .= " \n"; + $dialplan_xml .= " \n"; + $dialplan_xml .= "\n"; - public function delete_files($records) { + //build the dialplan array + $dialplan["app_uuid"] = "24108154-4ac3-1db6-1551-4731703a4440"; + $dialplan["domain_uuid"] = $this->domain_uuid; + $dialplan["dialplan_uuid"] = $this->dialplan_uuid; + $dialplan["dialplan_name"] = ($this->fax_name != '') ? $this->fax_name : format_phone($this->destination_number); + $dialplan["dialplan_number"] = $this->fax_extension; + $dialplan["dialplan_context"] = $this->domain_name; + $dialplan["dialplan_continue"] = false; + $dialplan["dialplan_xml"] = $dialplan_xml; + $dialplan["dialplan_order"] = "40"; + $dialplan["dialplan_enabled"] = true; + $dialplan["dialplan_description"] = $this->fax_description; + $dialplan_detail_order = 10; - //set private variables - $this->permission_prefix = 'fax_file_'; - $this->list_page = 'fax_files.php?id='.urlencode($this->fax_uuid).'&box='.urlencode($this->box); - $this->table = 'fax_files'; - $this->uuid_prefix = 'fax_file_'; + //prepare the array + $array['dialplans'][] = $dialplan; - if (permission_exists($this->permission_prefix.'delete')) { + //add the dialplan permission + $p = permissions::new(); + $p->add("dialplan_add", 'temp'); + $p->add("dialplan_detail_add", 'temp'); + $p->add("dialplan_edit", 'temp'); + $p->add("dialplan_detail_edit", 'temp'); - //add multi-lingual support - $language = new text; - $text = $language->get(); + //save the dialplan + $this->database->app_name = 'fax'; + $this->database->app_uuid = '24108154-4ac3-1db6-1551-4731703a4440'; + $this->database->save($array); + //$message = $this->database->message; - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } + //remove the temporary permission + $p->delete("dialplan_add", 'temp'); + $p->delete("dialplan_detail_add", 'temp'); + $p->delete("dialplan_edit", 'temp'); + $p->delete("dialplan_detail_edit", 'temp'); - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { + //clear the cache + $cache = new cache; + $cache->delete("dialplan:" . $this->domain_name); - //filter out unchecked fax files, build where clause for below - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } + //return the dialplan_uuid + return $dialplan_response ?? null; - //get necessary fax file details - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, fax_mode, fax_file_path, fax_file_type from v_".$this->table." "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - if ($row['fax_mode'] == 'rx') { $fax_files[$row['uuid']]['folder'] = 'inbox'; } - if ($row['fax_mode'] == 'tx') { $fax_files[$row['uuid']]['folder'] = 'sent'; } - $fax_files[$row['uuid']]['path'] = $row['fax_file_path']; - $fax_files[$row['uuid']]['type'] = $row['fax_file_type']; - } - } - unset($sql, $parameters, $rows, $row); - } + } - //delete fax file(s) - if (is_array($fax_files) && @sizeof($fax_files) != 0) { - foreach ($fax_files as $fax_file_uuid => $fax_file) { - if (substr_count($fax_file['path'], '/temp/') > 0) { - $fax_file['path'] = str_replace('/temp/', '/'.$fax_file['type'].'/', $fax_file['path']); - } - if (file_exists($fax_file['path'])) { - @unlink($fax_file['path']); - } - if ($fax_file['type'] == 'tif') { - $fax_file['path'] = str_replace('.tif', '.pdf', $fax_file['path']); - if (file_exists($fax_file['path'])) { - @unlink($fax_file['path']); - } - } - else if ($fax_file['type'] == 'pdf') { - $fax_file['path'] = str_replace('.pdf', '.tif', $fax_file['path']); - if (file_exists($fax_file['path'])) { - @unlink($fax_file['path']); - } - } - } - } + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { - //build the delete array - $x = 0; - foreach ($fax_files as $fax_file_uuid => $fax_file) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $fax_file_uuid; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - $x++; - } + //set private variables + $this->permission_prefix = 'fax_extension_'; + $this->list_page = 'fax.php'; + $this->table = 'fax'; + $this->uuid_prefix = 'fax_'; - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { + if (permission_exists($this->permission_prefix . 'delete')) { - //execute delete - $this->database->delete($array); - unset($array); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //set message - message::add($text['message-delete']); - } - unset($records); - } + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; } - } - public function delete_logs($records) { + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { - //set private variables - $this->permission_prefix = 'fax_log_'; - $this->list_page = 'fax_logs.php?id='.urlencode($this->fax_uuid); - $this->table = 'fax_logs'; - $this->uuid_prefix = 'fax_log_'; - - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; + //filter out unchecked fax extensions, build where clause for below + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; } + } - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked fax logs, build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * copy records - */ - public function copy($records) { - - //set private variables - $this->permission_prefix = 'fax_extension_'; - $this->list_page = 'fax.php'; - $this->table = 'fax'; - $this->uuid_prefix = 'fax_'; - - if (permission_exists($this->permission_prefix.'copy')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create insert array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - - //primary table - $sql = "select * from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $y = 0; - foreach ($rows as $x => $row) { - $new_fax_uuid = uuid(); - $new_dialplan_uuid = uuid(); - - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $new_fax_uuid; - $array[$this->table][$x]['dialplan_uuid'] = $new_dialplan_uuid; - if ($row['fax_forward_number'] == '') { - unset($array[$this->table][$x]['fax_forward_number']); - } - $array[$this->table][$x]['fax_description'] = trim($row['fax_description'].' ('.$text['label-copy'].')'); - - //fax users sub table - $sql_2 = "select e.* from v_fax_users as e, v_users as u "; - $sql_2 .= "where e.user_uuid = u.user_uuid "; - $sql_2 .= "and e.domain_uuid = :domain_uuid "; - $sql_2 .= "and e.fax_uuid = :fax_uuid "; - $parameters_2['domain_uuid'] = $this->domain_uuid; - $parameters_2['fax_uuid'] = $row['fax_uuid']; - $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); - if (is_array($rows_2) && @sizeof($rows_2) != 0) { - foreach ($rows_2 as $row_2) { - - //convert boolean values to a string - foreach($row_2 as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row_2[$key] = $value; - } - } - - //copy data - $array['fax_users'][$y] = $row_2; - - //overwrite - $array['fax_users'][$y]['fax_user_uuid'] = uuid(); - $array['fax_users'][$y]['fax_uuid'] = $new_fax_uuid; - - //increment - $y++; - - } - } - unset($sql_2, $parameters_2, $rows_2, $row_2); - - //fax dialplan record - $sql_3 = "select * from v_dialplans where dialplan_uuid = :dialplan_uuid"; - $parameters_3['dialplan_uuid'] = $row['dialplan_uuid']; - $dialplan = $this->database->select($sql_3, $parameters_3, 'row'); - if (is_array($dialplan) && @sizeof($dialplan) != 0) { - - //convert boolean values to a string - foreach($dialplan as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $dialplan[$key] = $value; - } - } - - //copy data - $array['dialplans'][$x] = $dialplan; - - //overwrite - $array['dialplans'][$x]['dialplan_uuid'] = $new_dialplan_uuid; - $dialplan_xml = $dialplan['dialplan_xml']; - $dialplan_xml = str_replace($row['fax_uuid'], $new_fax_uuid, $dialplan_xml); //replace source fax_uuid with new - $dialplan_xml = str_replace($dialplan['dialplan_uuid'], $new_dialplan_uuid, $dialplan_xml); //replace source dialplan_uuid with new - $array['dialplans'][$x]['dialplan_xml'] = $dialplan_xml; - $array['dialplans'][$x]['dialplan_description'] = trim($dialplan['dialplan_description'].' ('.$text['label-copy'].')'); - - } - unset($sql_3, $parameters_3, $dialplan); - - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('fax_add', 'temp'); - $p->add('dialplan_add', 'temp'); - - //save the array - - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('fax_add', 'temp'); - $p->delete('dialplan_add', 'temp'); - - //apply settings reminder - $_SESSION["reload_xml"] = true; - - //clear the cache - $cache = new cache; - $cache->delete("dialplan:".$this->domain_name); - - //set message - message::add($text['message-copy']); - - } - unset($records); - } - - } - } //method - - /** - * toggle read/unread - */ - public function fax_file_toggle($records) { - - if (permission_exists('fax_file_edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - if (empty($this->download) || $this->download == false) { - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: fax_files.php?order_by='.urlencode($this->order_by).'&order='.urlencode($this->order).'&id='.urlencode($this->fax_uuid).'&box='.urlencode($this->box)); - exit; + //get necessary fax details + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, dialplan_uuid from v_" . $this->table . " "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $faxes[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; } } + unset($sql, $parameters, $rows, $row); + } - //toggle multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked fax files, build the toggle array - $fax_files_toggled = 0; - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - //get current read state - $sql = "select read_date from v_fax_files where fax_file_uuid = :fax_file_uuid"; - $parameters['fax_file_uuid'] = $record['uuid']; - $read_date = $this->database->select($sql, $parameters, 'column'); - unset($sql, $parameters); - - //toggle read state - $array['fax_files'][$x]['fax_file_uuid'] = $record['uuid']; - $array['fax_files'][$x]['domain_uuid'] = $this->domain_uuid; - $array['fax_files'][$x]['read_date'] = empty($read_date) ? 'now()' : null; - $fax_files_toggled++; - } + //get necessary fax file details + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select fax_file_uuid as uuid, fax_mode, fax_file_path, fax_file_type from v_fax_files "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + if ($row['fax_mode'] == 'rx') { + $fax_files[$row['uuid']]['folder'] = 'inbox'; } - unset($records); - - //update the checked rows - if (!empty($array) && is_array($array)) { - - //execute save - - $this->database->save($array, false); - unset($array); - - //return toggled count - return $fax_files_toggled; - + if ($row['fax_mode'] == 'tx') { + $fax_files[$row['uuid']]['folder'] = 'sent'; } + $fax_files[$row['uuid']]['path'] = $row['fax_file_path']; + $fax_files[$row['uuid']]['type'] = $row['fax_file_type']; + } + } + unset($sql, $parameters, $rows, $row); + } + //delete fax file(s) + if (!empty($fax_files) && is_array($fax_files) && @sizeof($fax_files) != 0) { + foreach ($fax_files as $fax_file_uuid => $fax_file) { + if (substr_count($fax_file['path'], '/temp/') > 0) { + $fax_file['path'] = str_replace('/temp/', '/' . $fax_file['type'] . '/', $fax_file['path']); + } + if (file_exists($fax_file['path'])) { + @unlink($fax_file['path']); + } + if ($fax_file['type'] == 'tif') { + $fax_file['path'] = str_replace('.tif', '.pdf', $fax_file['path']); + if (file_exists($fax_file['path'])) { + @unlink($fax_file['path']); + } + } elseif ($fax_file['type'] == 'pdf') { + $fax_file['path'] = str_replace('.pdf', '.tif', $fax_file['path']); + if (file_exists($fax_file['path'])) { + @unlink($fax_file['path']); + } + } + } + } + + //build the delete array + $x = 0; + if (!empty($faxes) && is_array($faxes) && @sizeof($faxes) != 0) { + foreach ($faxes as $fax_uuid => $fax) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $fax_uuid; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + $array['fax_users'][$x][$this->uuid_prefix . 'uuid'] = $fax_uuid; + $array['fax_users'][$x]['domain_uuid'] = $this->domain_uuid; + $array['fax_files'][$x][$this->uuid_prefix . 'uuid'] = $fax_uuid; + $array['fax_files'][$x]['domain_uuid'] = $this->domain_uuid; + $array['fax_logs'][$x][$this->uuid_prefix . 'uuid'] = $fax_uuid; + $array['fax_logs'][$x]['domain_uuid'] = $this->domain_uuid; + $array['dialplans'][$x]['dialplan_uuid'] = $fax['dialplan_uuid']; + $array['dialplans'][$x]['domain_uuid'] = $this->domain_uuid; + $array['dialplan_details'][$x]['dialplan_uuid'] = $fax['dialplan_uuid']; + $array['dialplan_details'][$x]['domain_uuid'] = $this->domain_uuid; + $x++; + } + } + + //delete the checked rows + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('fax_delete', 'temp'); + $p->add('fax_user_delete', 'temp'); + $p->add('fax_file_delete', 'temp'); + $p->add('fax_log_delete', 'temp'); + $p->add('dialplan_delete', 'temp'); + $p->add('dialplan_detail_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('fax_delete', 'temp'); + $p->delete('fax_user_delete', 'temp'); + $p->delete('fax_file_delete', 'temp'); + $p->delete('fax_log_delete', 'temp'); + $p->delete('dialplan_delete', 'temp'); + $p->delete('dialplan_detail_delete', 'temp'); + + //apply settings reminder + $_SESSION["reload_xml"] = true; + + //clear the cache + $cache = new cache; + $cache->delete("dialplan:" . $this->domain_name); + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); } - //return none - return 0; + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Deletes multiple fax files. + * + * @param array $records An array of records to delete, where each record is an associative array containing the 'checked' and 'uuid' keys. + * + * @return void + */ + public function delete_files($records) { + + //set private variables + $this->permission_prefix = 'fax_file_'; + $this->list_page = 'fax_files.php?id=' . urlencode($this->fax_uuid) . '&box=' . urlencode($this->box); + $this->table = 'fax_files'; + $this->uuid_prefix = 'fax_file_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked fax files, build where clause for below + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //get necessary fax file details + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, fax_mode, fax_file_path, fax_file_type from v_" . $this->table . " "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + if ($row['fax_mode'] == 'rx') { + $fax_files[$row['uuid']]['folder'] = 'inbox'; + } + if ($row['fax_mode'] == 'tx') { + $fax_files[$row['uuid']]['folder'] = 'sent'; + } + $fax_files[$row['uuid']]['path'] = $row['fax_file_path']; + $fax_files[$row['uuid']]['type'] = $row['fax_file_type']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //delete fax file(s) + if (is_array($fax_files) && @sizeof($fax_files) != 0) { + foreach ($fax_files as $fax_file_uuid => $fax_file) { + if (substr_count($fax_file['path'], '/temp/') > 0) { + $fax_file['path'] = str_replace('/temp/', '/' . $fax_file['type'] . '/', $fax_file['path']); + } + if (file_exists($fax_file['path'])) { + @unlink($fax_file['path']); + } + if ($fax_file['type'] == 'tif') { + $fax_file['path'] = str_replace('.tif', '.pdf', $fax_file['path']); + if (file_exists($fax_file['path'])) { + @unlink($fax_file['path']); + } + } elseif ($fax_file['type'] == 'pdf') { + $fax_file['path'] = str_replace('.pdf', '.tif', $fax_file['path']); + if (file_exists($fax_file['path'])) { + @unlink($fax_file['path']); + } + } + } + } + + //build the delete array + $x = 0; + foreach ($fax_files as $fax_file_uuid => $fax_file) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $fax_file_uuid; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + $x++; + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //execute delete + $this->database->delete($array); + unset($array); + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Deletes multiple fax log records based on user input. + * + * @param array $records An array of record data, where each record is an associative array containing + * information about the log entry to delete. Each array should have a 'checked' + * key with a value of either true or false indicating whether the log entry + * should be deleted, and a 'uuid' key containing the UUID of the log entry. + * + * @return void No return value; method only deletes records if permission is granted. + */ + public function delete_logs($records) { + + //set private variables + $this->permission_prefix = 'fax_log_'; + $this->list_page = 'fax_logs.php?id=' . urlencode($this->fax_uuid); + $this->table = 'fax_logs'; + $this->uuid_prefix = 'fax_log_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked fax logs, build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //execute delete + $this->database->delete($array); + unset($array); + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + + //set private variables + $this->permission_prefix = 'fax_extension_'; + $this->list_page = 'fax.php'; + $this->table = 'fax'; + $this->uuid_prefix = 'fax_'; + + if (permission_exists($this->permission_prefix . 'copy')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create insert array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + + //primary table + $sql = "select * from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $y = 0; + foreach ($rows as $x => $row) { + $new_fax_uuid = uuid(); + $new_dialplan_uuid = uuid(); + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; + } + } + + //copy data + $array[$this->table][$x] = $row; + + //overwrite + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $new_fax_uuid; + $array[$this->table][$x]['dialplan_uuid'] = $new_dialplan_uuid; + if ($row['fax_forward_number'] == '') { + unset($array[$this->table][$x]['fax_forward_number']); + } + $array[$this->table][$x]['fax_description'] = trim($row['fax_description'] . ' (' . $text['label-copy'] . ')'); + + //fax users sub table + $sql_2 = "select e.* from v_fax_users as e, v_users as u "; + $sql_2 .= "where e.user_uuid = u.user_uuid "; + $sql_2 .= "and e.domain_uuid = :domain_uuid "; + $sql_2 .= "and e.fax_uuid = :fax_uuid "; + $parameters_2['domain_uuid'] = $this->domain_uuid; + $parameters_2['fax_uuid'] = $row['fax_uuid']; + $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); + if (is_array($rows_2) && @sizeof($rows_2) != 0) { + foreach ($rows_2 as $row_2) { + + //convert boolean values to a string + foreach ($row_2 as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row_2[$key] = $value; + } + } + + //copy data + $array['fax_users'][$y] = $row_2; + + //overwrite + $array['fax_users'][$y]['fax_user_uuid'] = uuid(); + $array['fax_users'][$y]['fax_uuid'] = $new_fax_uuid; + + //increment + $y++; + + } + } + unset($sql_2, $parameters_2, $rows_2, $row_2); + + //fax dialplan record + $sql_3 = "select * from v_dialplans where dialplan_uuid = :dialplan_uuid"; + $parameters_3['dialplan_uuid'] = $row['dialplan_uuid']; + $dialplan = $this->database->select($sql_3, $parameters_3, 'row'); + if (is_array($dialplan) && @sizeof($dialplan) != 0) { + + //convert boolean values to a string + foreach ($dialplan as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $dialplan[$key] = $value; + } + } + + //copy data + $array['dialplans'][$x] = $dialplan; + + //overwrite + $array['dialplans'][$x]['dialplan_uuid'] = $new_dialplan_uuid; + $dialplan_xml = $dialplan['dialplan_xml']; + $dialplan_xml = str_replace($row['fax_uuid'], $new_fax_uuid, $dialplan_xml); //replace source fax_uuid with new + $dialplan_xml = str_replace($dialplan['dialplan_uuid'], $new_dialplan_uuid, $dialplan_xml); //replace source dialplan_uuid with new + $array['dialplans'][$x]['dialplan_xml'] = $dialplan_xml; + $array['dialplans'][$x]['dialplan_description'] = trim($dialplan['dialplan_description'] . ' (' . $text['label-copy'] . ')'); + + } + unset($sql_3, $parameters_3, $dialplan); + + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('fax_add', 'temp'); + $p->add('dialplan_add', 'temp'); + + //save the array + + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('fax_add', 'temp'); + $p->delete('dialplan_add', 'temp'); + + //apply settings reminder + $_SESSION["reload_xml"] = true; + + //clear the cache + $cache = new cache; + $cache->delete("dialplan:" . $this->domain_name); + + //set message + message::add($text['message-copy']); + + } + unset($records); } } + } //method - } //class + /** + * Toggles the read state of multiple fax file records based on user input. + * + * @param array $records An array of record data, where each record is an associative array containing information about the log entry to toggle. + * Each array should have a 'checked' key with a value of either true or false indicating whether the log entry + * should be toggled, and a 'uuid' key containing the UUID of the log entry. + * + * @return int The number of fax files toggled (0 if none were toggled). + */ + public function fax_file_toggle($records) { + + if (permission_exists('fax_file_edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + if (empty($this->download) || $this->download == false) { + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: fax_files.php?order_by=' . urlencode($this->order_by) . '&order=' . urlencode($this->order) . '&id=' . urlencode($this->fax_uuid) . '&box=' . urlencode($this->box)); + exit; + } + } + + //toggle multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked fax files, build the toggle array + $fax_files_toggled = 0; + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + //get current read state + $sql = "select read_date from v_fax_files where fax_file_uuid = :fax_file_uuid"; + $parameters['fax_file_uuid'] = $record['uuid']; + $read_date = $this->database->select($sql, $parameters, 'column'); + unset($sql, $parameters); + + //toggle read state + $array['fax_files'][$x]['fax_file_uuid'] = $record['uuid']; + $array['fax_files'][$x]['domain_uuid'] = $this->domain_uuid; + $array['fax_files'][$x]['read_date'] = empty($read_date) ? 'now()' : null; + $fax_files_toggled++; + } + } + unset($records); + + //update the checked rows + if (!empty($array) && is_array($array)) { + + //execute save + + $this->database->save($array, false); + unset($array); + + //return toggled count + return $fax_files_toggled; + + } + + } + + //return none + return 0; + } + + } + +} //class /* $o = new fax; diff --git a/app/fax/resources/functions/object_to_array.php b/app/fax/resources/functions/object_to_array.php index fe84302e15..5806697345 100644 --- a/app/fax/resources/functions/object_to_array.php +++ b/app/fax/resources/functions/object_to_array.php @@ -1,5 +1,12 @@ Array(),'attachments'=>Array()); $structure = imap_fetchstructure($connection, $message_number, $option); @@ -33,6 +43,18 @@ function parse_message($connection, $message_number, $option = null, $to_charset return $result; } +/** + * Decode the text part of a message from the email connection. + * + * @param resource $connection IMAP connection to the mailbox + * @param array &$part The text part of the message, retrieved using imap_fetchstructure() + * @param int $message_number The message number of the message to parse + * @param int $id Unique identifier for this part of the message + * @param string|null $option Optional argument for imap_fetchbody() + * @param string $to_charset Charset to decode messages into, default is 'UTF-8' + * + * @return array An array containing three keys: 'data', 'type', and 'size'. The 'data' key contains the decoded message text. + */ function parse_message_decode_text($connection, &$part, $message_number, $id, $option, $to_charset){ $msg = parse_message_fetch_body($connection, $part, $message_number, $id, $option); @@ -63,6 +85,17 @@ function parse_message_decode_text($connection, &$part, $message_number, $id, $o ); } +/** + * Parse an attachment from the email connection. + * + * @param resource $connection IMAP connection to the mailbox + * @param object &$part The email part to parse + * @param int $message_number The message number of the message containing the attachment + * @param string $id The internal ID of the attachment in the message + * @param string|null $option Optional argument for imap_fetchbody() + * + * @return array|false An array containing information about the parsed attachment, or false if no valid filename is found. + */ function parse_message_decode_attach($connection, &$part, $message_number, $id, $option){ $filename = false; @@ -99,6 +132,17 @@ function parse_message_decode_attach($connection, &$part, $message_number, $id, ); } +/** + * Retrieves and decodes the body of a message from an email server. + * + * @param resource $connection IMAP connection to the email server + * @param object & $part Part of the email being processed + * @param int $message_number The number of the message to retrieve + * @param string $id Unique identifier for the part + * @param int $option Option flag (default value is not documented) + * + * @return string The decoded body of the message + */ function parse_message_fetch_body($connection, &$part, $message_number, $id, $option){ $body = imap_fetchbody($connection, $message_number, $id, $option); if($part->encoding == ENCBASE64){ @@ -110,6 +154,13 @@ function parse_message_fetch_body($connection, &$part, $message_number, $id, $op return $body; } +/** + * Returns the type and subtype of a message part. + * + * @param object $part Message part object containing type and subtype information. + * + * @return string Type and subtype of the message part, separated by a slash. (e.g., "message/plain") + */ function parse_message_get_type(&$part){ $types = Array( TYPEMESSAGE => 'message', @@ -126,6 +177,17 @@ function parse_message_get_type(&$part){ return $types[$part->type] . '/' . strtolower($part->subtype); } +/** + * Recursively flattens a hierarchical message structure into a single-level array. + * + * @param object $structure Message structure containing nested parts and subparts. + * @param array &$result Resulting flattened array of message parts. + * @param string $prefix Prefix for each part in the result array (optional). + * @param int $index Index of the current part (used for generating prefixes, optional). + * @param bool $fullPrefix Whether to include the index in the prefix or not (optional). + * + * @return array Flattened message structure. + */ function parse_message_flatten(&$structure, &$result = array(), $prefix = '', $index = 1, $fullPrefix = true) { foreach ($structure as $part) { if(isset($part->parts)) { diff --git a/app/fax_queue/resources/classes/fax_queue.php b/app/fax_queue/resources/classes/fax_queue.php index 3ed1506a89..ff557ad85a 100644 --- a/app/fax_queue/resources/classes/fax_queue.php +++ b/app/fax_queue/resources/classes/fax_queue.php @@ -27,316 +27,348 @@ /** * fax_queue class */ - class fax_queue { +class fax_queue { - /** - * declare constant variables - */ - const app_name = 'fax_queue'; - const app_uuid = '3656287f-4b22-4cf1-91f6-00386bf488f4'; + /** + * declare constant variables + */ + const app_name = 'fax_queue'; + const app_uuid = '3656287f-4b22-4cf1-91f6-00386bf488f4'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * declare private variables - */ - private $name; - private $table; - private $toggle_field; - private $toggle_values; - private $location; + /** + * declare private variables + */ + private $name; + private $table; + private $toggle_field; + private $toggle_values; + private $location; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); + //set objects + $this->database = $setting_array['database'] ?? database::new(); - //assign the variables - $this->name = 'fax_queue'; - $this->table = 'fax_queue'; - $this->toggle_field = ''; - $this->toggle_values = ['true','false']; - $this->location = 'fax_queue.php'; - } + //assign the variables + $this->name = 'fax_queue'; + $this->table = 'fax_queue'; + $this->toggle_field = ''; + $this->toggle_values = ['true', 'false']; + $this->location = 'fax_queue.php'; + } - /** - * delete rows from the database - */ - public function delete($records) { - if (permission_exists($this->name.'_delete')) { + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->name . '_delete')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + //build the delete array + $x = 0; + foreach ($records as $record) { + //add to the array + if ($record['checked'] == 'true' && is_uuid($record['fax_queue_uuid'])) { + $array[$this->table][$x]['fax_queue_uuid'] = $record['fax_queue_uuid']; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; } - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - //build the delete array - $x = 0; - foreach ($records as $record) { - //add to the array - if ($record['checked'] == 'true' && is_uuid($record['fax_queue_uuid'])) { - $array[$this->table][$x]['fax_queue_uuid'] = $record['fax_queue_uuid']; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - } + //increment the id + $x++; + } - //increment the id - $x++; - } + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } + //set message + message::add($text['message-delete']); + } + unset($records); } } + } - /** - * resend selected faxes in the fax queue - */ - public function resend($records) { - if (permission_exists($this->name.'_edit')) { + /** + * Resend multiple faxes. + * + * @param array $records Array of records to resend, where each record contains a 'checked' and 'fax_queue_uuid' key. + * + * @return void + */ + public function resend($records) { + if (permission_exists($this->name . '_edit')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //resend multiple faxes + if (is_array($records) && @sizeof($records) != 0) { + //build the fax array + $x = 0; + foreach ($records as $record) { + //add to the array + if ($record['checked'] == 'true' && is_uuid($record['fax_queue_uuid'])) { + $array[$this->table][$x][$this->name . '_uuid'] = $record['fax_queue_uuid']; + $array[$this->table][$x]['fax_status'] = 'waiting'; + $array[$this->table][$x]['fax_retry_date'] = null; + $array[$this->table][$x]['fax_notify_date'] = null; + $array[$this->table][$x]['fax_retry_count'] = '0'; } - //resend multiple faxes - if (is_array($records) && @sizeof($records) != 0) { - //build the fax array - $x = 0; - foreach ($records as $record) { - //add to the array - if ($record['checked'] == 'true' && is_uuid($record['fax_queue_uuid'])) { - $array[$this->table][$x][$this->name.'_uuid'] = $record['fax_queue_uuid']; - $array[$this->table][$x]['fax_status'] = 'waiting'; - $array[$this->table][$x]['fax_retry_date'] = null; - $array[$this->table][$x]['fax_notify_date'] = null; - $array[$this->table][$x]['fax_retry_count'] = '0'; - } + //increment the id + $x++; + } - //increment the id - $x++; - } + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + //save the array - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - //save the array + $this->database->save($array); + unset($array); - $this->database->save($array); - unset($array); + //set message + message::add($text['message-resending_faxes']); + } + unset($records); + } - //set message - message::add($text['message-resending_faxes']); - } - unset($records); + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->name . '_edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + //get current toggle state + foreach ($records as $record) { + if ($record['checked'] == 'true' && is_uuid($record['fax_queue_uuid'])) { + $uuids[] = "'" . $record['fax_queue_uuid'] . "'"; } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->name . "_uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + //create the array + $array[$this->table][$x][$this->name . '_uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + + //increment the id + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); } } + } - /** - * toggle a field between two values - */ - public function toggle($records) { - if (permission_exists($this->name.'_edit')) { + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->name . '_add')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - //get current toggle state - foreach($records as $record) { - if ($record['checked'] == 'true' && is_uuid($record['fax_queue_uuid'])) { - $uuids[] = "'".$record['fax_queue_uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->name."_uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($states as $uuid => $state) { - //create the array - $array[$this->table][$x][$this->name.'_uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - - //increment the id - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; } - } - /** - * copy rows from the database - */ - public function copy($records) { - if (permission_exists($this->name.'_add')) { + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; + //get checked records + foreach ($records as $record) { + if ($record['checked'] == 'true' && is_uuid($record['fax_queue_uuid'])) { + $uuids[] = "'" . $record['fax_queue_uuid'] . "'"; } + } - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach($records as $record) { - if ($record['checked'] == 'true' && is_uuid($record['fax_queue_uuid'])) { - $uuids[] = "'".$record['fax_queue_uuid']."'"; + //create the array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select * from v_" . $this->table . " "; + $sql .= "where fax_queue_uuid in (" . implode(', ', $uuids) . ") "; + $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $x = 0; + foreach ($rows as $row) { + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; } } - //create the array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select * from v_".$this->table." "; - $sql .= "where fax_queue_uuid in (".implode(', ', $uuids).") "; - $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $x = 0; - foreach ($rows as $row) { - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } + //copy data + $array[$this->table][$x] = $row; - //copy data - $array[$this->table][$x] = $row; + //add copy to the description + $array[$this->table][$x][$this->name . '_uuid'] = uuid(); - //add copy to the description - $array[$this->table][$x][$this->name.'_uuid'] = uuid(); - - //increment the id - $x++; - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-copy']); - } - unset($records); + //increment the id + $x++; + } } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-copy']); + } + unset($records); } } + } - /** - * Removes records from the v_fax_files and v_fax_logs tables. Called by the maintenance application. - * @param settings $settings Settings object - * @return void - */ - public static function database_maintenance(settings $settings): void { - $database = $settings->database(); - $domains = maintenance_service::get_domains($database); - foreach ($domains as $domain_uuid => $domain_name) { - $domain_settings = new settings(['database'=>$database, 'domain_uuid'=>$domain_uuid]); - $retention_days = $domain_settings->get('fax_queue', 'database_retention_days', ''); - //delete from v_fax_queue where fax_status = 'sent' and fax_date < NOW() - INTERVAL '$days_keep_fax_queue days' - if (!empty($retention_days) && is_numeric($retention_days)) { - $sql = "delete from v_fax_queue where fax_status = 'sent' and fax_date < NOW() - INTERVAL '$retention_days days'"; - $sql .= " and domain_uuid = '$domain_uuid'"; - $database->execute($sql); - $code = $database->message['code'] ?? 0; - if ($code == 200) { - maintenance_service::log_write(self::class, "Successfully removed entries older than $retention_days", $domain_uuid); - } else { - $message = $database->message['message'] ?? "An unknown error has occurred"; - maintenance_service::log_write(self::class, "Unable to remove old database records. Error message: $message ($code)", $domain_uuid, maintenance_service::LOG_ERROR); - } + /** + * Removes records from the v_fax_files and v_fax_logs tables. Called by the maintenance application. + * + * @param settings $settings Settings object + * + * @return void + */ + public static function database_maintenance(settings $settings): void { + $database = $settings->database(); + $domains = maintenance_service::get_domains($database); + foreach ($domains as $domain_uuid => $domain_name) { + $domain_settings = new settings(['database' => $database, 'domain_uuid' => $domain_uuid]); + $retention_days = $domain_settings->get('fax_queue', 'database_retention_days', ''); + //delete from v_fax_queue where fax_status = 'sent' and fax_date < NOW() - INTERVAL '$days_keep_fax_queue days' + if (!empty($retention_days) && is_numeric($retention_days)) { + $sql = "delete from v_fax_queue where fax_status = 'sent' and fax_date < NOW() - INTERVAL '$retention_days days'"; + $sql .= " and domain_uuid = '$domain_uuid'"; + $database->execute($sql); + $code = $database->message['code'] ?? 0; + if ($code == 200) { + maintenance_service::log_write(self::class, "Successfully removed entries older than $retention_days", $domain_uuid); + } else { + $message = $database->message['message'] ?? "An unknown error has occurred"; + maintenance_service::log_write(self::class, "Unable to remove old database records. Error message: $message ($code)", $domain_uuid, maintenance_service::LOG_ERROR); } } } } +} diff --git a/app/fax_queue/resources/job/fax_queue.php b/app/fax_queue/resources/job/fax_queue.php index 4a797287ee..9c422dc42e 100644 --- a/app/fax_queue/resources/job/fax_queue.php +++ b/app/fax_queue/resources/job/fax_queue.php @@ -34,6 +34,13 @@ //echo "pid_file: ".$pid_file."\n"; //function to check if the process exists + /** + * Checks if a process is running. + * + * @param string $file The path to the file containing the process ID, or false for no check. + * + * @return bool True if the process is running, false otherwise. + */ function process_exists($file = false) { //set the default exists to false diff --git a/app/fax_queue/resources/job/fax_send.php b/app/fax_queue/resources/job/fax_send.php index b733548e0f..657dc70a26 100644 --- a/app/fax_queue/resources/job/fax_send.php +++ b/app/fax_queue/resources/job/fax_send.php @@ -40,7 +40,17 @@ //extract dtmf from the fax number if (!function_exists('fax_split_dtmf')) { - function fax_split_dtmf(&$fax_number, &$fax_dtmf){ + /** + * Splits the fax number and DTMF tone string. + * + * This function takes a fax number with an optional DTMF tone string as input, + * extracts the fax number and the DTMF tone string, and stores them separately in + * the provided references. + * + * @param string &$fax_number The fax number to split. May contain an embedded DTMF tone string. + * @param string &$fax_dtmf The extracted DTMF tone string. + */ + function fax_split_dtmf(&$fax_number, &$fax_dtmf) { $tmp = array(); $fax_dtmf = ''; if (preg_match('/^\s*(.*?)\s*\((.*)\)\s*$/', $fax_number, $tmp)){ @@ -62,6 +72,16 @@ } //shutdown call back function + /** + * Performs a clean shutdown of the system. + * + * This function prepares for graceful termination by updating the fax queue status + * and removing the pid file. It is intended to be called when the application needs + * to shut down cleanly. + * + * @return void + * @see \register_shutdown_function() + */ function shutdown() { //add global variables global $database, $fax_queue_uuid; @@ -89,6 +109,16 @@ //echo "pid_file: ".$pid_file."\n"; //function to check if the process exists + /** + * Checks if a process exists. + * + * This function checks the existence of a file containing a valid process ID, + * then verifies that the corresponding process is running using the `ps` command. + * + * @param string $file The path to the file containing the process ID. Defaults to an empty string, which means the function will return false. + * + * @return bool True if the process exists and is running, false otherwise. + */ function process_exists($file = '') { //check if the file exists return false if not found if (!file_exists($file)) { @@ -112,6 +142,15 @@ } //remove single quote + /** + * Escapes single quotes in a string. + * + * This function removes all occurrences of single quotes from the input value. + * + * @param string $value The value to remove single quotes from. May be empty. + * + * @return boolean|string True if the value was not empty, otherwise false. + */ function escape_quote($value) { if (!empty($value)) { return str_replace("'", "", $value); diff --git a/app/fax_queue/resources/service/fax_queue.php b/app/fax_queue/resources/service/fax_queue.php index 06ffbeed0a..7abf4cf321 100644 --- a/app/fax_queue/resources/service/fax_queue.php +++ b/app/fax_queue/resources/service/fax_queue.php @@ -37,6 +37,16 @@ //echo "pid_file: ".$pid_file."\n"; //function to check if the process exists + /** + * Checks if a process exists. + * + * This function checks if a process with the specified PID file exists, and returns true if it does, + * or false otherwise. If no PID file is provided, the function defaults to returning false. + * + * @param string|false $file The path to the PID file of the process to check for, or false to default to not checking any process. + * + * @return bool True if a process with the specified PID exists, false otherwise. + */ function process_exists($file = false) { //set the default exists to false diff --git a/app/fifo/resources/classes/fifo.php b/app/fifo/resources/classes/fifo.php index 206eb852ca..adc9eff878 100644 --- a/app/fifo/resources/classes/fifo.php +++ b/app/fifo/resources/classes/fifo.php @@ -3,289 +3,305 @@ /** * fifo class */ - class fifo { +class fifo { - /** - * declare constant variables - */ - const app_name = 'fifo'; - const app_uuid = '16589224-c876-aeb3-f59f-523a1c0801f7'; + /** + * declare constant variables + */ + const app_name = 'fifo'; + const app_uuid = '16589224-c876-aeb3-f59f-523a1c0801f7'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * declare the variables - */ - private $name; - private $table; - private $toggle_field; - private $toggle_values; - private $description_field; - private $location; - private $uuid_prefix; + /** + * declare the variables + */ + private $name; + private $table; + private $toggle_field; + private $toggle_values; + private $description_field; + private $location; + private $uuid_prefix; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - - //assign the variables - $this->name = 'fifo'; - $this->table = 'fifo'; - $this->uuid_prefix = 'fifo_'; - $this->toggle_field = 'fifo_enabled'; - $this->toggle_values = ['true','false']; - $this->description_field = 'fifo_description'; - $this->location = 'fifo.php'; - } - - /** - * called when there are no references to a particular object - * unset the variables used in the class - */ - public function __destruct() { - foreach ($this as $key => $value) { - unset($this->$key); - } - } - - /** - * delete rows from the database - */ - public function delete($records) { - if (permission_exists($this->name.'_delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked queues, build where clause for below - $uuids = []; - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && !empty($record['uuid']) && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //get necessary fifo queue details - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, dialplan_uuid from v_".$this->table." "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $fifos[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build the delete array - $x = 0; - foreach ($fifos as $fifo_uuid => $fifo) { - //add to the array - $array[$this->table][$x][$this->name.'_uuid'] = $fifo_uuid; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - $array['fifo_members'][$x]['fifo_uuid'] = $fifo_uuid; - $array['fifo_members'][$x]['domain_uuid'] = $this->domain_uuid; - $array['dialplans'][$x]['dialplan_uuid'] = $fifo['dialplan_uuid']; - $array['dialplans'][$x]['domain_uuid'] = $this->domain_uuid; - - //increment the id - $x++; - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //grant temporary permissions - $p = permissions::new(); - $p->add('fifo_member_delete', 'temp'); - $p->add('dialplan_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('fifo_member_delete', 'temp'); - $p->delete('dialplan_delete', 'temp'); - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * toggle a field between two values - */ - public function toggle($records) { - if (permission_exists($this->name.'_edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - //get current toggle state - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && !empty($record['uuid']) && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->name."_uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach ($states as $uuid => $state) { - //create the array - $array[$this->table][$x][$this->name.'_uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - - //increment the id - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - } - } - - /** - * copy rows from the database - */ - public function copy($records) { - if (permission_exists($this->name.'_add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach($records as $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create the array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select * from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - - if (is_array($rows) && @sizeof($rows) != 0) { - $x = 0; - foreach ($rows as $row) { - //copy data - $array[$this->table][$x] = $row; - - //add copy to the description - $array[$this->table][$x][$this->name.'_uuid'] = uuid(); - $array[$this->table][$x][$this->description_field] = trim($row[$this->description_field]).' ('.$text['label-copy'].')'; - - //increment the id - $x++; - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('fifo_member_add', 'temp'); - - //save the array - - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('fifo_member_add', 'temp'); - - //set message - message::add($text['message-copy']); - } - unset($records); - } - } - } + //set objects + $this->database = $setting_array['database'] ?? database::new(); + //assign the variables + $this->name = 'fifo'; + $this->table = 'fifo'; + $this->uuid_prefix = 'fifo_'; + $this->toggle_field = 'fifo_enabled'; + $this->toggle_values = ['true', 'false']; + $this->description_field = 'fifo_description'; + $this->location = 'fifo.php'; } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->name . '_delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked queues, build where clause for below + $uuids = []; + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && !empty($record['uuid']) && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //get necessary fifo queue details + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, dialplan_uuid from v_" . $this->table . " "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $fifos[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build the delete array + $x = 0; + foreach ($fifos as $fifo_uuid => $fifo) { + //add to the array + $array[$this->table][$x][$this->name . '_uuid'] = $fifo_uuid; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + $array['fifo_members'][$x]['fifo_uuid'] = $fifo_uuid; + $array['fifo_members'][$x]['domain_uuid'] = $this->domain_uuid; + $array['dialplans'][$x]['dialplan_uuid'] = $fifo['dialplan_uuid']; + $array['dialplans'][$x]['domain_uuid'] = $this->domain_uuid; + + //increment the id + $x++; + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //grant temporary permissions + $p = permissions::new(); + $p->add('fifo_member_delete', 'temp'); + $p->add('dialplan_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('fifo_member_delete', 'temp'); + $p->delete('dialplan_delete', 'temp'); + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->name . '_edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + //get current toggle state + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && !empty($record['uuid']) && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->name . "_uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + //create the array + $array[$this->table][$x][$this->name . '_uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + + //increment the id + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->name . '_add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create the array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select * from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + + if (is_array($rows) && @sizeof($rows) != 0) { + $x = 0; + foreach ($rows as $row) { + //copy data + $array[$this->table][$x] = $row; + + //add copy to the description + $array[$this->table][$x][$this->name . '_uuid'] = uuid(); + $array[$this->table][$x][$this->description_field] = trim($row[$this->description_field]) . ' (' . $text['label-copy'] . ')'; + + //increment the id + $x++; + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('fifo_member_add', 'temp'); + + //save the array + + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('fifo_member_add', 'temp'); + + //set message + message::add($text['message-copy']); + } + unset($records); + } + } + } + +} diff --git a/app/gateways/gateways.php b/app/gateways/gateways.php index 23dc00fade..d690892e53 100644 --- a/app/gateways/gateways.php +++ b/app/gateways/gateways.php @@ -91,6 +91,18 @@ //gateway status function if (!function_exists('switch_gateway_status')) { + /** + * Switches the status of a gateway. + * + * This function sends an API request to retrieve the status of a gateway. + * If the first request fails, it attempts to send the same request with the + * gateway UUID in uppercase. + * + * @param string $gateway_uuid The unique identifier of the gateway. + * @param string $result_type The type of response expected (default: 'xml'). + * + * @return string The status of the gateway, or an error message if the request fails. + */ function switch_gateway_status($gateway_uuid, $result_type = 'xml') { global $esl; if ($esl->is_connected()) { diff --git a/app/gateways/resources/classes/gateways.php b/app/gateways/resources/classes/gateways.php index 491842b2d2..475d94bb8a 100644 --- a/app/gateways/resources/classes/gateways.php +++ b/app/gateways/resources/classes/gateways.php @@ -25,581 +25,620 @@ */ //define the gateways class - class gateways { - - /** - * declare constant variables - */ - const app_name = 'gateways'; - const app_uuid = '297ab33e-2c2f-8196-552c-f3567d2caaf8'; - - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; - - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; - - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; - - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; - - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; - - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); - - //assign private variables - $this->permission_prefix = 'gateway_'; - $this->list_page = 'gateways.php'; - $this->table = 'gateways'; - $this->uuid_prefix = 'gateway_'; - $this->toggle_field = 'enabled'; - $this->toggle_values = ['true','false']; - } - - /** - * start gateways - */ - public function start($records) { - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //start the checked gateways - if (!empty($records) && is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked gateways, build where clause for below - foreach($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //get necessary gateway details - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, gateway, profile, enabled from v_".$this->table." "; - if (permission_exists('gateway_all')) { - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - } - else { - $sql .= "where (domain_uuid = :domain_uuid) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - } - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (!empty($rows) && is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $gateways[$row['uuid']]['name'] = $row['gateway']; - $gateways[$row['uuid']]['profile'] = $row['profile']; - $gateways[$row['uuid']]['enabled'] = $row['enabled']; - } - } - unset($sql, $parameters, $rows, $row); - } - - if (!empty($gateways) && is_array($gateways) && @sizeof($gateways) != 0) { - //create the event socket connection - $esl = event_socket::create(); - if ($esl->is_connected()) { - //start gateways - foreach ($gateways as $gateway_uuid => $gateway) { - if ($gateway['enabled'] == 'true') { - //start gateways - foreach ($gateways as $gateway_uuid => $gateway) { - if ($gateway['enabled'] == 'true') { - $cmd = 'sofia profile '.$gateway['profile'].' startgw '.$gateway_uuid; - $responses[$gateway_uuid]['gateway'] = $gateway['name']; - $responses[$gateway_uuid]['message'] = trim(event_socket::api($cmd)); - } - } - //old method used to start gateways - //$cmd = 'sofia profile '.$gateway['profile'].' rescan'; - //$responses[$gateway_uuid]['gateway'] = $gateway['name']; - //$responses[$gateway_uuid]['message'] = trim(event_socket::api($cmd)); - } - } - - //set message - if (!empty($responses) && is_array($responses) && @sizeof($responses) != 0) { - $message = $text['message-gateway_started']; - foreach ($responses as $response) { - $message .= "
".$response['gateway'].": ".$response['message']; - } - message::add($message, 'positive', 7000); - } - } - } - } - - } - } - - /** - * stop gateways - */ - public function stop($records) { - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //stop the checked gateways - if (!empty($records) && is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked gateways, build where clause for below - foreach($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //get necessary gateway details - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, gateway, profile, enabled from v_".$this->table." "; - if (permission_exists('gateway_all')) { - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - } - else { - $sql .= "where (domain_uuid = :domain_uuid) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - } - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $gateways[$row['uuid']]['name'] = $row['gateway']; - $gateways[$row['uuid']]['profile'] = $row['profile']; - $gateways[$row['uuid']]['enabled'] = $row['enabled']; - } - } - unset($sql, $parameters, $rows, $row); - } - - if (!empty($gateways) && is_array($gateways) && @sizeof($gateways) != 0) { - //create the event socket connection - $esl = event_socket::create(); - if ($esl->is_connected()) { - //stop gateways - foreach ($gateways as $gateway_uuid => $gateway) { - if ($gateway['enabled'] == 'true') { - $cmd = 'sofia profile '.$gateway['profile'].' killgw '.$gateway_uuid; - $responses[$gateway_uuid]['gateway'] = $gateway['name']; - $responses[$gateway_uuid]['message'] = trim(event_socket::api($cmd)); - } - } - //set message - if (!empty($responses) && is_array($responses) && @sizeof($responses) != 0) { - $message = $text['message-gateway_stopped']; - foreach ($responses as $response) { - $message .= "
".$response['gateway'].": ".$response['message']; - } - message::add($message, 'positive', 7000); - } - } - } - } - - } - } - - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (!empty($records) && is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked gateways, build where clause for below - foreach ($records as $record) { - if (!empty($record['checked']) == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //get necessary gateway details - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, gateway, profile from v_".$this->table." "; - if (permission_exists('gateway_all')) { - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - } - else { - $sql .= "where (domain_uuid = :domain_uuid) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - } - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (!empty($rows) && is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $gateways[$row['uuid']]['name'] = $row['gateway']; - $gateways[$row['uuid']]['profile'] = $row['profile']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //create the event socket connection - $esl = event_socket::create(); - - //loop through gateways - $x = 0; - foreach ($gateways as $gateway_uuid => $gateway) { - - //remove gateway from session variable - unset($_SESSION['gateways'][$gateway_uuid]); - - //remove the xml file (if any) - if (!empty($this->settings->get('switch', 'sip_profiles'))) { - $gateway_xml_file = $this->settings->get('switch', 'sip_profiles')."/".$gateway['profile']."/v_".$gateway_uuid.".xml"; - if (file_exists($gateway_xml_file)) { - unlink($gateway_xml_file); - } - } - - //send the api command to stop the gateway - if ($esl->is_connected()) { - $cmd = 'sofia profile '.$gateway['profile'].' killgw '.$gateway_uuid; - $response = event_socket::api($cmd); - unset($cmd); - } - - //build delete array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $gateway_uuid; - $x++; - - } - - //delete the checked rows - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - - //execute delete - $this->database->delete($array); - unset($array); - - //synchronize the xml config - save_gateway_xml(); - - //clear the cache - - $cache = new cache; - $cache->delete(gethostname().":configuration:sofia.conf"); - - //rescan the sip profile to look for new or stopped gateways - $esl = event_socket::create(); - if ($esl->is_connected()) { - //get distinct profiles from gateways - foreach ($gateways as $gateway) { - $array[] = $gateway['profile']; - } - $profiles = array_unique($array); - - //send the api command to rescan each profile - foreach ($profiles as $profile) { - $response = event_socket::api("sofia profile $profile rescan"); - } - } - usleep(1000); - - //clear the apply settings reminder - $_SESSION["reload_xml"] = false; - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * toggle records - */ - public function toggle($records) { - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (!empty($records) && is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as state, gateway, profile from v_".$this->table." "; - if (permission_exists('gateway_all')) { - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - } - else { - $sql .= "where (domain_uuid = :domain_uuid) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - } - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (!empty($rows) && is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $gateways[$row['uuid']]['state'] = $row['state']; - $gateways[$row['uuid']]['name'] = $row['gateway']; - $gateways[$row['uuid']]['profile'] = $row['profile']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($gateways as $uuid => $gateway) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $gateway['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - - //save the changes - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //update gateway session variables or remove xml files (if necessary) - foreach ($gateways as $gateway_uuid => $gateway) { - if ($gateway['state'] == 'true') { - $_SESSION['gateways'][$gateway_uuid] = $gateway['name']; - } - else { - unset($_SESSION['gateways'][$gateway_uuid]); - - //remove the xml file (if any) - if (!empty($this->settings->get('switch', 'sip_profiles'))) { - $gateway_xml_file = $this->settings->get('switch', 'sip_profiles')."/".$gateway['profile']."/v_".$gateway_uuid.".xml"; - if (file_exists($gateway_xml_file)) { - unlink($gateway_xml_file); - } - } - } - } - - //synchronize the xml config - save_gateway_xml(); - - //clear the cache - $cache = new cache; - $cache->delete(gethostname().":configuration:sofia.conf"); - - //create the event socket connection - $esl = event_socket::create(); - - //rescan the sip profile to look for new or stopped gateways - if ($esl->is_connected()) { - //get distinct profiles from gateways - foreach ($gateways as $gateway) { - $array[] = $gateway['profile']; - } - $profiles = array_unique($array); - - //send the api command to rescan each profile - foreach ($profiles as $profile) { - event_socket::api("sofia profile $profile rescan"); - } - } - usleep(1000); - - //clear the apply settings reminder - $_SESSION["reload_xml"] = false; - - //set message - message::add($text['message-toggle']); - } - unset($records, $gateways); - } - - } - } - - /** - * copy records - */ - public function copy($records) { - if (permission_exists($this->permission_prefix.'add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //copy the checked records - if (!empty($records) && is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create insert array from existing data - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select * from v_".$this->table." "; - if (permission_exists('gateway_all')) { - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - } - else { - $sql .= "where (domain_uuid = :domain_uuid) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - } - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (!empty($rows) && is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $x => $row) { - $primary_uuid = uuid(); - - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $primary_uuid; - $array[$this->table][$x]['description'] = trim($row['description'].' ('.$text['label-copy'].')'); - unset($array[$this->table][$x]['channels']); - - //defaults - if (empty($row['expire_seconds'])) { - $array[$this->table][$x]['expire_seconds'] = '800'; - } - if (empty($row['retry_seconds'])) { - $array[$this->table][$x]['retry_seconds'] = '30'; - } - - //array of new gateways - if ($row['enabled'] == 'true') { - $gateways[$primary_uuid]['name'] = $row['gateway']; - } - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //add new gateways to session variables - if (!empty($gateways) && is_array($gateways) && @sizeof($gateways) != 0) { - foreach ($gateways as $gateway_uuid => $gateway) { - $_SESSION['gateways'][$gateway_uuid] = $gateway['name']; - } - } - - //synchronize the xml config - save_gateway_xml(); - - //clear the cache - $cache = new cache; - $cache->delete(gethostname().":configuration:sofia.conf"); - - //set message - message::add($text['message-copy']); - - } - unset($records, $gateways); - } - - } - } - +class gateways { + + /** + * declare constant variables + */ + const app_name = 'gateways'; + const app_uuid = '297ab33e-2c2f-8196-552c-f3567d2caaf8'; + + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; + + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; + + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; + + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; + + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; + + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + + //assign private variables + $this->permission_prefix = 'gateway_'; + $this->list_page = 'gateways.php'; + $this->table = 'gateways'; + $this->uuid_prefix = 'gateway_'; + $this->toggle_field = 'enabled'; + $this->toggle_values = ['true', 'false']; } + + /** + * Starts the checked gateways. + * + * This method checks for permission to edit and validates the token. It then + * filters out unchecked gateways and retrieves their details from the database. + * If necessary, it creates an event socket connection and starts the gateways. + * + * @param array $records A list of gateway records. + * + * @return void + */ + public function start($records) { + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //start the checked gateways + if (!empty($records) && is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked gateways, build where clause for below + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //get necessary gateway details + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, gateway, profile, enabled from v_" . $this->table . " "; + if (permission_exists('gateway_all')) { + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + } else { + $sql .= "where (domain_uuid = :domain_uuid) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + } + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (!empty($rows) && is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $gateways[$row['uuid']]['name'] = $row['gateway']; + $gateways[$row['uuid']]['profile'] = $row['profile']; + $gateways[$row['uuid']]['enabled'] = $row['enabled']; + } + } + unset($sql, $parameters, $rows, $row); + } + + if (!empty($gateways) && is_array($gateways) && @sizeof($gateways) != 0) { + //create the event socket connection + $esl = event_socket::create(); + if ($esl->is_connected()) { + //start gateways + foreach ($gateways as $gateway_uuid => $gateway) { + if ($gateway['enabled'] == 'true') { + //start gateways + foreach ($gateways as $gateway_uuid => $gateway) { + if ($gateway['enabled'] == 'true') { + $cmd = 'sofia profile ' . $gateway['profile'] . ' startgw ' . $gateway_uuid; + $responses[$gateway_uuid]['gateway'] = $gateway['name']; + $responses[$gateway_uuid]['message'] = trim(event_socket::api($cmd)); + } + } + //old method used to start gateways + //$cmd = 'sofia profile '.$gateway['profile'].' rescan'; + //$responses[$gateway_uuid]['gateway'] = $gateway['name']; + //$responses[$gateway_uuid]['message'] = trim(event_socket::api($cmd)); + } + } + + //set message + if (!empty($responses) && is_array($responses) && @sizeof($responses) != 0) { + $message = $text['message-gateway_started']; + foreach ($responses as $response) { + $message .= "
" . $response['gateway'] . ": " . $response['message']; + } + message::add($message, 'positive', 7000); + } + } + } + } + + } + } + + /** + * Stops the checked gateways. + * + * This method checks for permission to edit and validates the token. It then + * filters out unchecked gateways and retrieves their details from the database. + * If necessary, it creates an event socket connection and stops the gateways. + * + * @param array $records A list of gateway records. + * + * @return void + */ + public function stop($records) { + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //stop the checked gateways + if (!empty($records) && is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked gateways, build where clause for below + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //get necessary gateway details + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, gateway, profile, enabled from v_" . $this->table . " "; + if (permission_exists('gateway_all')) { + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + } else { + $sql .= "where (domain_uuid = :domain_uuid) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + } + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $gateways[$row['uuid']]['name'] = $row['gateway']; + $gateways[$row['uuid']]['profile'] = $row['profile']; + $gateways[$row['uuid']]['enabled'] = $row['enabled']; + } + } + unset($sql, $parameters, $rows, $row); + } + + if (!empty($gateways) && is_array($gateways) && @sizeof($gateways) != 0) { + //create the event socket connection + $esl = event_socket::create(); + if ($esl->is_connected()) { + //stop gateways + foreach ($gateways as $gateway_uuid => $gateway) { + if ($gateway['enabled'] == 'true') { + $cmd = 'sofia profile ' . $gateway['profile'] . ' killgw ' . $gateway_uuid; + $responses[$gateway_uuid]['gateway'] = $gateway['name']; + $responses[$gateway_uuid]['message'] = trim(event_socket::api($cmd)); + } + } + //set message + if (!empty($responses) && is_array($responses) && @sizeof($responses) != 0) { + $message = $text['message-gateway_stopped']; + foreach ($responses as $response) { + $message .= "
" . $response['gateway'] . ": " . $response['message']; + } + message::add($message, 'positive', 7000); + } + } + } + } + + } + } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (!empty($records) && is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked gateways, build where clause for below + foreach ($records as $record) { + if (!empty($record['checked']) == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //get necessary gateway details + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, gateway, profile from v_" . $this->table . " "; + if (permission_exists('gateway_all')) { + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + } else { + $sql .= "where (domain_uuid = :domain_uuid) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + } + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (!empty($rows) && is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $gateways[$row['uuid']]['name'] = $row['gateway']; + $gateways[$row['uuid']]['profile'] = $row['profile']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //create the event socket connection + $esl = event_socket::create(); + + //loop through gateways + $x = 0; + foreach ($gateways as $gateway_uuid => $gateway) { + + //remove gateway from session variable + unset($_SESSION['gateways'][$gateway_uuid]); + + //remove the xml file (if any) + if (!empty($this->settings->get('switch', 'sip_profiles'))) { + $gateway_xml_file = $this->settings->get('switch', 'sip_profiles') . "/" . $gateway['profile'] . "/v_" . $gateway_uuid . ".xml"; + if (file_exists($gateway_xml_file)) { + unlink($gateway_xml_file); + } + } + + //send the api command to stop the gateway + if ($esl->is_connected()) { + $cmd = 'sofia profile ' . $gateway['profile'] . ' killgw ' . $gateway_uuid; + $response = event_socket::api($cmd); + unset($cmd); + } + + //build delete array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $gateway_uuid; + $x++; + + } + + //delete the checked rows + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + + //execute delete + $this->database->delete($array); + unset($array); + + //synchronize the xml config + save_gateway_xml(); + + //clear the cache + + $cache = new cache; + $cache->delete(gethostname() . ":configuration:sofia.conf"); + + //rescan the sip profile to look for new or stopped gateways + $esl = event_socket::create(); + if ($esl->is_connected()) { + //get distinct profiles from gateways + foreach ($gateways as $gateway) { + $array[] = $gateway['profile']; + } + $profiles = array_unique($array); + + //send the api command to rescan each profile + foreach ($profiles as $profile) { + $response = event_socket::api("sofia profile $profile rescan"); + } + } + usleep(1000); + + //clear the apply settings reminder + $_SESSION["reload_xml"] = false; + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (!empty($records) && is_array($records) && @sizeof($records) != 0) { + + //get current toggle state + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as state, gateway, profile from v_" . $this->table . " "; + if (permission_exists('gateway_all')) { + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + } else { + $sql .= "where (domain_uuid = :domain_uuid) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + } + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (!empty($rows) && is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $gateways[$row['uuid']]['state'] = $row['state']; + $gateways[$row['uuid']]['name'] = $row['gateway']; + $gateways[$row['uuid']]['profile'] = $row['profile']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($gateways as $uuid => $gateway) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $gateway['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + + //save the changes + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //update gateway session variables or remove xml files (if necessary) + foreach ($gateways as $gateway_uuid => $gateway) { + if ($gateway['state'] == 'true') { + $_SESSION['gateways'][$gateway_uuid] = $gateway['name']; + } else { + unset($_SESSION['gateways'][$gateway_uuid]); + + //remove the xml file (if any) + if (!empty($this->settings->get('switch', 'sip_profiles'))) { + $gateway_xml_file = $this->settings->get('switch', 'sip_profiles') . "/" . $gateway['profile'] . "/v_" . $gateway_uuid . ".xml"; + if (file_exists($gateway_xml_file)) { + unlink($gateway_xml_file); + } + } + } + } + + //synchronize the xml config + save_gateway_xml(); + + //clear the cache + $cache = new cache; + $cache->delete(gethostname() . ":configuration:sofia.conf"); + + //create the event socket connection + $esl = event_socket::create(); + + //rescan the sip profile to look for new or stopped gateways + if ($esl->is_connected()) { + //get distinct profiles from gateways + foreach ($gateways as $gateway) { + $array[] = $gateway['profile']; + } + $profiles = array_unique($array); + + //send the api command to rescan each profile + foreach ($profiles as $profile) { + event_socket::api("sofia profile $profile rescan"); + } + } + usleep(1000); + + //clear the apply settings reminder + $_SESSION["reload_xml"] = false; + + //set message + message::add($text['message-toggle']); + } + unset($records, $gateways); + } + + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->permission_prefix . 'add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //copy the checked records + if (!empty($records) && is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create insert array from existing data + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select * from v_" . $this->table . " "; + if (permission_exists('gateway_all')) { + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + } else { + $sql .= "where (domain_uuid = :domain_uuid) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + } + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (!empty($rows) && is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $x => $row) { + $primary_uuid = uuid(); + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; + } + } + + //copy data + $array[$this->table][$x] = $row; + + //overwrite + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $primary_uuid; + $array[$this->table][$x]['description'] = trim($row['description'] . ' (' . $text['label-copy'] . ')'); + unset($array[$this->table][$x]['channels']); + + //defaults + if (empty($row['expire_seconds'])) { + $array[$this->table][$x]['expire_seconds'] = '800'; + } + if (empty($row['retry_seconds'])) { + $array[$this->table][$x]['retry_seconds'] = '30'; + } + + //array of new gateways + if ($row['enabled'] == 'true') { + $gateways[$primary_uuid]['name'] = $row['gateway']; + } + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //add new gateways to session variables + if (!empty($gateways) && is_array($gateways) && @sizeof($gateways) != 0) { + foreach ($gateways as $gateway_uuid => $gateway) { + $_SESSION['gateways'][$gateway_uuid] = $gateway['name']; + } + } + + //synchronize the xml config + save_gateway_xml(); + + //clear the cache + $cache = new cache; + $cache->delete(gethostname() . ":configuration:sofia.conf"); + + //set message + message::add($text['message-copy']); + + } + unset($records, $gateways); + } + + } + } + +} diff --git a/app/ivr_menus/resources/classes/ivr_menu.php b/app/ivr_menus/resources/classes/ivr_menu.php index 6b3167770a..57ea63b050 100644 --- a/app/ivr_menus/resources/classes/ivr_menu.php +++ b/app/ivr_menus/resources/classes/ivr_menu.php @@ -25,506 +25,549 @@ */ //define the ivr_menu class - class ivr_menu { +class ivr_menu { - /** - * declare constant variables - */ - const app_name = 'ivr_menus'; - const app_uuid = 'a5788e9b-58bc-bd1b-df59-fff5d51253ab'; + /** + * declare constant variables + */ + const app_name = 'ivr_menus'; + const app_uuid = 'a5788e9b-58bc-bd1b-df59-fff5d51253ab'; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_uuid; - /** - * declare ivr menu primary uuid key - * @var string - */ - public $ivr_menu_uuid; + /** + * declare ivr menu primary uuid key + * + * @var string + */ + public $ivr_menu_uuid; - /** - * declare order_by variables - * @var string - */ - public $order_by; + /** + * declare order_by variables + * + * @var string + */ + public $order_by; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_name; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); + //set objects + $this->database = $setting_array['database'] ?? database::new(); - //assign private variables - $this->list_page = 'ivr_menus.php'; + //assign private variables + $this->list_page = 'ivr_menus.php'; + } + + /** + * Finds records in the v_ivr_menus table. + * + * @return array An array of menu items or an empty array if no records are found. + */ + public function find() { + $sql = "select * from v_ivr_menus "; + $sql .= "where domain_uuid = :domain_uuid "; + if (isset($this->ivr_menu_uuid)) { + $sql .= "and ivr_menu_uuid = :ivr_menu_uuid "; + $parameters['ivr_menu_uuid'] = $this->ivr_menu_uuid; + } + if (isset($this->order_by)) { + $sql .= $this->order_by; + } + $parameters['domain_uuid'] = $this->domain_uuid; + return $this->database->select($sql, $parameters, 'all'); + } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + //assign private variables + $this->permission_prefix = 'ivr_menu_'; + $this->table = 'ivr_menus'; + $this->uuid_prefix = 'ivr_menu_'; + + //return if permission does not exist + if (!permission_exists($this->permission_prefix . 'delete')) { + return false; } - public function find() { - $sql = "select * from v_ivr_menus "; - $sql .= "where domain_uuid = :domain_uuid "; - if (isset($this->ivr_menu_uuid)) { - $sql .= "and ivr_menu_uuid = :ivr_menu_uuid "; - $parameters['ivr_menu_uuid'] = $this->ivr_menu_uuid; + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (!empty($records)) { + + //filter out unchecked ivr menus, build where clause for below + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } } - if (isset($this->order_by)) { - $sql .= $this->order_by; + + //get necessary ivr menu details + if (!empty($uuids)) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, dialplan_uuid, ivr_menu_context from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $ivr_menus[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; + $ivr_menu_contexts[] = $row['ivr_menu_context']; + } + } + unset($sql, $parameters, $rows, $row); } - $parameters['domain_uuid'] = $this->domain_uuid; - return $this->database->select($sql, $parameters, 'all'); - } - /** - * delete records - */ - public function delete($records) { - //assign private variables - $this->permission_prefix = 'ivr_menu_'; - $this->table = 'ivr_menus'; - $this->uuid_prefix = 'ivr_menu_'; + //build the delete array + $x = 0; + foreach ($ivr_menus as $ivr_menu_uuid => $ivr_menu) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $ivr_menu_uuid; + $array['ivr_menu_options'][$x]['ivr_menu_uuid'] = $ivr_menu_uuid; + $array['dialplans'][$x]['dialplan_uuid'] = $ivr_menu['dialplan_uuid']; + $x++; + } - //return if permission does not exist - if (!permission_exists($this->permission_prefix.'delete')) { - return false; + //delete the checked rows + if (!empty($array)) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('ivr_menu_option_delete', 'temp'); + $p->add('dialplan_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('ivr_menu_option_delete', 'temp'); + $p->delete('dialplan_delete', 'temp'); + + //clear the cache + if (is_array($ivr_menu_contexts) && @sizeof($ivr_menu_contexts) != 0) { + $ivr_menu_contexts = array_unique($ivr_menu_contexts); + $cache = new cache; + foreach ($ivr_menu_contexts as $ivr_menu_context) { + $cache->delete("dialplan:" . $ivr_menu_context); + } } - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (!empty($records)) { - - //filter out unchecked ivr menus, build where clause for below - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //get necessary ivr menu details - if (!empty($uuids)) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, dialplan_uuid, ivr_menu_context from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $ivr_menus[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; - $ivr_menu_contexts[] = $row['ivr_menu_context']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build the delete array - $x = 0; - foreach ($ivr_menus as $ivr_menu_uuid => $ivr_menu) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $ivr_menu_uuid; - $array['ivr_menu_options'][$x]['ivr_menu_uuid'] = $ivr_menu_uuid; - $array['dialplans'][$x]['dialplan_uuid'] = $ivr_menu['dialplan_uuid']; - $x++; - } - - //delete the checked rows - if (!empty($array)) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('ivr_menu_option_delete', 'temp'); - $p->add('dialplan_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('ivr_menu_option_delete', 'temp'); - $p->delete('dialplan_delete', 'temp'); - - //clear the cache - if (is_array($ivr_menu_contexts) && @sizeof($ivr_menu_contexts) != 0) { - $ivr_menu_contexts = array_unique($ivr_menu_contexts); - $cache = new cache; - foreach ($ivr_menu_contexts as $ivr_menu_context) { - $cache->delete("dialplan:".$ivr_menu_context); - } - } - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-delete']); - } - unset($records, $ivr_menus); - } - - } - - public function delete_options($records) { - //assign private variables - $this->permission_prefix = 'ivr_menu_option_'; - $this->table = 'ivr_menu_options'; - $this->uuid_prefix = 'ivr_menu_option_'; - - //return if permission does not exist - if (!permission_exists($this->permission_prefix.'delete')) { - return false; - } - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (!empty($records)) { - - //filter out unchecked ivr menu options, build delete array - $x = 0; - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && !empty($record['uuid']) && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['ivr_menu_uuid'] = $this->ivr_menu_uuid; - $x++; - } - } - - //get ivr menu context - if (!empty($array) && !empty($this->ivr_menu_uuid) && is_uuid($this->ivr_menu_uuid)) { - $sql = "select ivr_menu_context from v_ivr_menus "; - $sql .= "where (domain_uuid = :domain_uuid) "; - $sql .= "and ivr_menu_uuid = :ivr_menu_uuid "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['ivr_menu_uuid'] = $this->ivr_menu_uuid; - $ivr_menu_context = $this->database->select($sql, $parameters, 'column'); - unset($sql, $parameters); - } - - //delete the checked rows - if (!empty($array)) { - - //execute delete - $this->database->delete($array); - unset($array); - - //clear the cache - if (!empty($ivr_menu_context)) { - $cache = new cache; - $cache->delete("dialplan:".$ivr_menu_context); - } - - } - unset($records); - } - } - - /** - * toggle records - */ - public function toggle($records) { - //assign private variables - $this->permission_prefix = 'ivr_menu_'; - $this->table = 'ivr_menus'; - $this->uuid_prefix = 'ivr_menu_'; - $this->toggle_field = 'ivr_menu_enabled'; - $this->toggle_values = ['true','false']; - - //return if permission does not exist - if (!permission_exists($this->permission_prefix.'edit')) { - return false; - } - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (!empty($records)) { - - //get current toggle state - foreach($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && !empty($record['uuid']) && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (!empty($uuids)) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle, dialplan_uuid from v_".$this->table." "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $ivr_menus[$row['uuid']]['state'] = $row['toggle']; - $ivr_menus[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach ($ivr_menus as $uuid => $ivr_menu) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $ivr_menu['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $array['dialplans'][$x]['dialplan_uuid'] = $ivr_menu['dialplan_uuid']; - $array['dialplans'][$x]['dialplan_enabled'] = $ivr_menu['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - - //save the changes - if (!empty($array)) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('dialplan_edit', 'temp'); - - //save the array - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('dialplan_edit', 'temp'); - - //clear the cache - $cache = new cache; - $cache->delete("dialplan:".$this->domain_name); - foreach ($ivr_menus as $ivr_menu_uuid => $ivr_menu) { - $cache->delete("configuration:ivr.conf:".$ivr_menu_uuid); - } - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - - } - - /** - * copy records - */ - public function copy($records) { - //assign private variables - $this->permission_prefix = 'ivr_menu_'; - $this->table = 'ivr_menus'; - $this->uuid_prefix = 'ivr_menu_'; - - //return if permission does not exist - if (!permission_exists($this->permission_prefix.'add')) { - return false; - } - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //copy the checked records - if (!empty($records)) { - - //get checked records - foreach($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && !empty($record['uuid']) && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create insert array from existing data - if (!empty($uuids)) { - - //primary table - $sql = "select * from v_".$this->table." "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (!empty($rows)) { - $y = $z = 0; - foreach ($rows as $x => $row) { - $new_ivr_menu_uuid = uuid(); - $new_dialplan_uuid = uuid(); - - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $new_ivr_menu_uuid; - $array[$this->table][$x]['dialplan_uuid'] = $new_dialplan_uuid; - $array[$this->table][$x]['ivr_menu_description'] = trim($row['ivr_menu_description'].' ('.$text['label-copy'].')'); - - //ivr menu options sub table - $sql_2 = "select * from v_ivr_menu_options where ivr_menu_uuid = :ivr_menu_uuid"; - $parameters_2['ivr_menu_uuid'] = $row['ivr_menu_uuid']; - $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); - if (!empty($rows_2)) { - foreach ($rows_2 as $row_2) { - //convert boolean values to a string - foreach($row_2 as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row_2[$key] = $value; - } - } - - //copy data - $array['ivr_menu_options'][$y] = $row_2; - - //overwrite - $array['ivr_menu_options'][$y]['ivr_menu_option_uuid'] = uuid(); - $array['ivr_menu_options'][$y]['ivr_menu_uuid'] = $new_ivr_menu_uuid; - - //increment - $y++; - - } - } - unset($sql_2, $parameters_2, $rows_2, $row_2); - - //ivr menu dialplan record - $sql_3 = "select * from v_dialplans where dialplan_uuid = :dialplan_uuid"; - $parameters_3['dialplan_uuid'] = $row['dialplan_uuid']; - $dialplan = $this->database->select($sql_3, $parameters_3, 'row'); - if (!empty($dialplan)) { - //convert boolean values to a string - foreach($dialplan as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $dialplan[$key] = $value; - } - } - - //copy data - $array['dialplans'][$z] = $dialplan; - - //overwrite - $array['dialplans'][$z]['dialplan_uuid'] = $new_dialplan_uuid; - $dialplan_xml = $dialplan['dialplan_xml']; - $dialplan_xml = str_replace($row['ivr_menu_uuid'], $new_ivr_menu_uuid, $dialplan_xml); //replace source ivr_menu_uuid with new - $dialplan_xml = str_replace($dialplan['dialplan_uuid'], $new_dialplan_uuid, $dialplan_xml); //replace source dialplan_uuid with new - $array['dialplans'][$z]['dialplan_xml'] = $dialplan_xml; - $array['dialplans'][$z]['dialplan_description'] = trim($dialplan['dialplan_description'].' ('.$text['label-copy'].')'); - - //increment - $z++; - } - unset($sql_3, $parameters_3, $dialplan); - - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (!empty($array)) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('ivr_menu_option_add', 'temp'); - $p->add('dialplan_add', 'temp'); - - //save the array - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p = permissions::new(); - $p->delete('ivr_menu_option_add', 'temp'); - $p->delete('dialplan_add', 'temp'); - - //clear the cache - $cache = new cache; - $cache->delete("dialplan:".$this->domain_name); - - //set message - message::add($text['message-copy']); - - } - unset($records); + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); } + //set message + message::add($text['message-delete']); + } + unset($records, $ivr_menus); } } + + /** + * Deletes one or more ivr menu options. + * + * @param array $records An associative array containing the uuids and checked status of the records to delete. + * + * @return bool True if the operation was successful, false otherwise. + */ + public function delete_options($records) { + //assign private variables + $this->permission_prefix = 'ivr_menu_option_'; + $this->table = 'ivr_menu_options'; + $this->uuid_prefix = 'ivr_menu_option_'; + + //return if permission does not exist + if (!permission_exists($this->permission_prefix . 'delete')) { + return false; + } + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (!empty($records)) { + + //filter out unchecked ivr menu options, build delete array + $x = 0; + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && !empty($record['uuid']) && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['ivr_menu_uuid'] = $this->ivr_menu_uuid; + $x++; + } + } + + //get ivr menu context + if (!empty($array) && !empty($this->ivr_menu_uuid) && is_uuid($this->ivr_menu_uuid)) { + $sql = "select ivr_menu_context from v_ivr_menus "; + $sql .= "where (domain_uuid = :domain_uuid) "; + $sql .= "and ivr_menu_uuid = :ivr_menu_uuid "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['ivr_menu_uuid'] = $this->ivr_menu_uuid; + $ivr_menu_context = $this->database->select($sql, $parameters, 'column'); + unset($sql, $parameters); + } + + //delete the checked rows + if (!empty($array)) { + + //execute delete + $this->database->delete($array); + unset($array); + + //clear the cache + if (!empty($ivr_menu_context)) { + $cache = new cache; + $cache->delete("dialplan:" . $ivr_menu_context); + } + + } + unset($records); + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + //assign private variables + $this->permission_prefix = 'ivr_menu_'; + $this->table = 'ivr_menus'; + $this->uuid_prefix = 'ivr_menu_'; + $this->toggle_field = 'ivr_menu_enabled'; + $this->toggle_values = ['true', 'false']; + + //return if permission does not exist + if (!permission_exists($this->permission_prefix . 'edit')) { + return false; + } + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (!empty($records)) { + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && !empty($record['uuid']) && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (!empty($uuids)) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle, dialplan_uuid from v_" . $this->table . " "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $ivr_menus[$row['uuid']]['state'] = $row['toggle']; + $ivr_menus[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($ivr_menus as $uuid => $ivr_menu) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $ivr_menu['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $array['dialplans'][$x]['dialplan_uuid'] = $ivr_menu['dialplan_uuid']; + $array['dialplans'][$x]['dialplan_enabled'] = $ivr_menu['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + + //save the changes + if (!empty($array)) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('dialplan_edit', 'temp'); + + //save the array + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('dialplan_edit', 'temp'); + + //clear the cache + $cache = new cache; + $cache->delete("dialplan:" . $this->domain_name); + foreach ($ivr_menus as $ivr_menu_uuid => $ivr_menu) { + $cache->delete("configuration:ivr.conf:" . $ivr_menu_uuid); + } + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + //assign private variables + $this->permission_prefix = 'ivr_menu_'; + $this->table = 'ivr_menus'; + $this->uuid_prefix = 'ivr_menu_'; + + //return if permission does not exist + if (!permission_exists($this->permission_prefix . 'add')) { + return false; + } + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //copy the checked records + if (!empty($records)) { + + //get checked records + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && !empty($record['uuid']) && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create insert array from existing data + if (!empty($uuids)) { + + //primary table + $sql = "select * from v_" . $this->table . " "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (!empty($rows)) { + $y = $z = 0; + foreach ($rows as $x => $row) { + $new_ivr_menu_uuid = uuid(); + $new_dialplan_uuid = uuid(); + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; + } + } + + //copy data + $array[$this->table][$x] = $row; + + //overwrite + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $new_ivr_menu_uuid; + $array[$this->table][$x]['dialplan_uuid'] = $new_dialplan_uuid; + $array[$this->table][$x]['ivr_menu_description'] = trim($row['ivr_menu_description'] . ' (' . $text['label-copy'] . ')'); + + //ivr menu options sub table + $sql_2 = "select * from v_ivr_menu_options where ivr_menu_uuid = :ivr_menu_uuid"; + $parameters_2['ivr_menu_uuid'] = $row['ivr_menu_uuid']; + $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); + if (!empty($rows_2)) { + foreach ($rows_2 as $row_2) { + //convert boolean values to a string + foreach ($row_2 as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row_2[$key] = $value; + } + } + + //copy data + $array['ivr_menu_options'][$y] = $row_2; + + //overwrite + $array['ivr_menu_options'][$y]['ivr_menu_option_uuid'] = uuid(); + $array['ivr_menu_options'][$y]['ivr_menu_uuid'] = $new_ivr_menu_uuid; + + //increment + $y++; + + } + } + unset($sql_2, $parameters_2, $rows_2, $row_2); + + //ivr menu dialplan record + $sql_3 = "select * from v_dialplans where dialplan_uuid = :dialplan_uuid"; + $parameters_3['dialplan_uuid'] = $row['dialplan_uuid']; + $dialplan = $this->database->select($sql_3, $parameters_3, 'row'); + if (!empty($dialplan)) { + //convert boolean values to a string + foreach ($dialplan as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $dialplan[$key] = $value; + } + } + + //copy data + $array['dialplans'][$z] = $dialplan; + + //overwrite + $array['dialplans'][$z]['dialplan_uuid'] = $new_dialplan_uuid; + $dialplan_xml = $dialplan['dialplan_xml']; + $dialplan_xml = str_replace($row['ivr_menu_uuid'], $new_ivr_menu_uuid, $dialplan_xml); //replace source ivr_menu_uuid with new + $dialplan_xml = str_replace($dialplan['dialplan_uuid'], $new_dialplan_uuid, $dialplan_xml); //replace source dialplan_uuid with new + $array['dialplans'][$z]['dialplan_xml'] = $dialplan_xml; + $array['dialplans'][$z]['dialplan_description'] = trim($dialplan['dialplan_description'] . ' (' . $text['label-copy'] . ')'); + + //increment + $z++; + } + unset($sql_3, $parameters_3, $dialplan); + + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (!empty($array)) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('ivr_menu_option_add', 'temp'); + $p->add('dialplan_add', 'temp'); + + //save the array + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p = permissions::new(); + $p->delete('ivr_menu_option_add', 'temp'); + $p->delete('dialplan_add', 'temp'); + + //clear the cache + $cache = new cache; + $cache->delete("dialplan:" . $this->domain_name); + + //set message + message::add($text['message-copy']); + + } + unset($records); + } + + } + +} diff --git a/app/ivr_menus/resources/functions/ivr_menu_xml.php b/app/ivr_menus/resources/functions/ivr_menu_xml.php index 5669d46802..05c2284708 100644 --- a/app/ivr_menus/resources/functions/ivr_menu_xml.php +++ b/app/ivr_menus/resources/functions/ivr_menu_xml.php @@ -25,8 +25,16 @@ */ if (!function_exists('save_ivr_menu_xml')) { + /** + * Saves IVR menu XML configuration files. + * + * This function deletes all existing dialplan .xml files in the ivr_menus directory, + * then creates new IVR menu XML files based on the database records for the current domain. + * + * @return void + */ function save_ivr_menu_xml() { - global $domain_uuid; + global $domain_uuid, $settings; //prepare for dialplan .xml files to be written. delete all dialplan files that are prefixed with dialplan_ and have a file extension of .xml if (count($_SESSION["domains"]) > 1) { diff --git a/app/modules/modules.php b/app/modules/modules.php index d0b32fd872..4eacb2e8e4 100644 --- a/app/modules/modules.php +++ b/app/modules/modules.php @@ -167,6 +167,11 @@ echo "
\n"; echo "\n"; + /** + * Writes the header for a list of modules. + * + * @param string $modifier The modifier to use in the checkbox ID and other attributes. + */ function write_header($modifier) { global $text, $modules, $list_row_edit_button; $modifier = str_replace('/', '', $modifier); diff --git a/app/modules/resources/classes/modules.php b/app/modules/resources/classes/modules.php index 11fe06fb10..7bf28bec71 100644 --- a/app/modules/resources/classes/modules.php +++ b/app/modules/resources/classes/modules.php @@ -25,1169 +25,1239 @@ */ //define the modules class - class modules { +class modules { - /** - * declare constant variables - */ - const app_name = 'modules'; - const app_uuid = '5eb9cba1-8cb6-5d21-e36a-775475f16b5e'; + /** + * declare constant variables + */ + const app_name = 'modules'; + const app_uuid = '5eb9cba1-8cb6-5d21-e36a-775475f16b5e'; - /** - * declare public variables - */ - public $dir; - public $esl; - public $modules; - public $msg; + /** + * declare public variables + */ + public $dir; + public $esl; + public $modules; + public $msg; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; - private $active_modules; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; + private $active_modules; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); - $this->esl = event_socket::create(); + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + $this->esl = event_socket::create(); - //assign private variables - $this->permission_prefix = 'module_'; - $this->list_page = 'modules.php'; - $this->table = 'modules'; - $this->uuid_prefix = 'module_'; - $this->toggle_field = 'module_enabled'; - $this->toggle_values = ['true','false']; + //assign private variables + $this->permission_prefix = 'module_'; + $this->list_page = 'modules.php'; + $this->table = 'modules'; + $this->uuid_prefix = 'module_'; + $this->toggle_field = 'module_enabled'; + $this->toggle_values = ['true', 'false']; - //get the list of active modules - $json = $this->esl->request("api show modules as json"); - $this->active_modules = json_decode($json, true); - } - - /** - * get the additional information about a specific module - */ - public function info($name) { - $module_label = substr($name, 4); - $module_label = ucwords(str_replace("_", " ", $module_label)); - $mod['module_label'] = $module_label; - $mod['module_name'] = $name; - $mod['module_order'] = '800'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - $mod['module_description'] = ''; - switch ($name) { - case "mod_amr": - $mod['module_label'] = 'AMR'; - $mod['module_category'] = 'Codecs'; - $mod['module_description'] = 'AMR codec.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_av": - $mod['module_label'] = 'AV'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Supports libav and RTMP streams.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_avmd": - $mod['module_label'] = 'AVMD'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Advanced voicemail beep detection.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_blacklist": - $mod['module_label'] = 'Blacklist'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Blacklist.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_b64": - $mod['module_label'] = 'B64'; - $mod['module_category'] = 'Codecs'; - $mod['module_description'] = 'B64 Codec.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_bcg729": - $mod['module_label'] = 'BCG729'; - $mod['module_category'] = 'Codecs'; - $mod['module_description'] = 'G729 Open Source Codec.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_bv": - $mod['module_label'] = 'BV'; - $mod['module_category'] = 'Codecs'; - $mod['module_description'] = 'BroadVoice16 and BroadVoice32 audio codecs.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_cdr_csv": - $mod['module_label'] = 'CDR CSV'; - $mod['module_category'] = 'Event Handlers'; - $mod['module_description'] = 'CSV call detail record handler.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_cdr_sqlite": - $mod['module_label'] = 'CDR SQLite'; - $mod['module_category'] = 'Event Handlers'; - $mod['module_description'] = 'SQLite call detail record handler.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_callcenter": - $mod['module_label'] = 'Call Center'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Call queuing with agents and tiers for call centers.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_cepstral": - $mod['module_label'] = 'Cepstral'; - $mod['module_category'] = 'Speech Recognition / Text to Speech'; - $mod['module_description'] = 'Text to Speech engine.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_cidlookup": - $mod['module_label'] = 'CID Lookup'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Lookup caller id info.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_cluechoo": - $mod['module_label'] = 'Cluechoo'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'A framework demo module.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_commands": - $mod['module_label'] = 'Commands'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'API interface commands.'; - $mod['module_order'] = 100; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_conference": - $mod['module_label'] = 'Conference'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Conference room module.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_console": - $mod['module_label'] = 'Console'; - $mod['module_category'] = 'Loggers'; - $mod['module_description'] = 'Send logs to the console.'; - $mod['module_order'] = 400; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_curl": - $mod['module_label'] = 'CURL'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Allows scripts to make HTTP requests and return responses in plain text or JSON.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_db": - $mod['module_label'] = 'DB'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Database key / value storage functionality, dialing and limit backend.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_dialplan_asterisk": - $mod['module_label'] = 'Dialplan Asterisk'; - $mod['module_category'] = 'Dialplan Interfaces'; - $mod['module_description'] = 'Allows Asterisk dialplans.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_dialplan_xml": - $mod['module_label'] = 'Dialplan XML'; - $mod['module_category'] = 'Dialplan Interfaces'; - $mod['module_description'] = 'Provides dialplan functionality in XML.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_directory": - $mod['module_label'] = 'Directory'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Dial by name directory.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_distributor": - $mod['module_label'] = 'Distributor'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Round robin call distribution.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_dptools": - $mod['module_label'] = 'Dialplan Plan Tools'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Provides a number of apps and utilities for the dialplan.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_enum": - $mod['module_label'] = 'ENUM'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Route PSTN numbers over internet according to ENUM servers, such as e164.org.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_esf": - $mod['module_label'] = 'ESF'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Holds the multi cast paging application for SIP.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_event_socket": - $mod['module_label'] = 'Event Socket'; - $mod['module_category'] = 'Event Handlers'; - $mod['module_description'] = 'Sends events via a single socket.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_expr": - $mod['module_label'] = 'Expr'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Expression evaluation library.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_fifo": - $mod['module_label'] = 'FIFO'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'FIFO provides custom call queues including call park.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_flite": - $mod['module_label'] = 'Flite'; - $mod['module_category'] = 'Speech Recognition / Text to Speech'; - $mod['module_description'] = 'Text to Speech engine.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_fsv": - $mod['module_label'] = 'FSV'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Video application (Recording and playback).'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_g723_1": - $mod['module_label'] = 'G.723.1'; - $mod['module_category'] = 'Codecs'; - $mod['module_description'] = 'G.723.1 codec.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_g729": - $mod['module_label'] = 'G.729'; - $mod['module_category'] = 'Codecs'; - $mod['module_description'] = 'G729 codec supports passthrough mode'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_h26x": - $mod['module_label'] = 'H26x'; - $mod['module_category'] = 'Codecs'; - $mod['module_description'] = 'Video codecs'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_hash": - $mod['module_label'] = 'Hash'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Resource limitation.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_httapi": - $mod['module_label'] = 'HT-TAPI'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'HT-TAPI Hypertext Telephony API'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_http_cache": - $mod['module_label'] = 'HTTP Cache'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'HTTP GET with caching'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_ilbc": - $mod['module_label'] = 'iLBC'; - $mod['module_category'] = 'Codecs'; - $mod['module_description'] = 'iLBC codec.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_ladspa": - $mod['module_label'] = 'Ladspa'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Auto-tune calls.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_lcr": - $mod['module_label'] = 'LCR'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Least cost routing.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_local_stream": - $mod['module_label'] = 'Local Stream'; - $mod['module_category'] = 'Streams / Files'; - $mod['module_description'] = 'For local streams (play all the files in a directory).'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_logfile": - $mod['module_label'] = 'Log File'; - $mod['module_category'] = 'Loggers'; - $mod['module_description'] = 'Send logs to the local file system.'; - $mod['module_order'] = 400; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_loopback": - $mod['module_label'] = 'Loopback'; - $mod['module_category'] = 'Endpoints'; - $mod['module_description'] = 'A loopback channel driver to make an outbound call as an inbound call.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_lua": - $mod['module_label'] = 'Lua'; - $mod['module_category'] = 'Languages'; - $mod['module_description'] = 'Lua script.'; - $mod['module_order'] = 200; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_memcache": - $mod['module_label'] = 'Memcached'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'API for memcached.'; - $mod['module_enabled'] = false; - $mod['module_order'] = 150; - $mod['module_default_enabled'] = false; - break; - case "mod_native_file": - $mod['module_label'] = 'Native File'; - $mod['module_category'] = 'File Format Interfaces'; - $mod['module_description'] = 'File interface for codec specific file formats.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_nibblebill": - $mod['module_label'] = 'Nibblebill'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Billing module.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_opus": - $mod['module_label'] = 'Opus'; - $mod['module_category'] = 'Codecs'; - $mod['module_description'] = 'OPUS ultra-low delay audio codec'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_park": - $mod['module_label'] = 'Park'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Park Calls.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_pgsql": - $mod['module_label'] = 'PGSQL'; - $mod['module_category'] = 'Databases'; - $mod['module_description'] = 'Client support for PostgreSQL database.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_png": - $mod['module_label'] = 'PNG'; - $mod['module_category'] = 'Formats'; - $mod['module_description'] = 'Image format Portable Network Graphics.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_pocketsphinx": - $mod['module_label'] = 'PocketSphinx'; - $mod['module_category'] = 'Speech Recognition / Text to Speech'; - $mod['module_description'] = 'Speech Recognition.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_rtc": - $mod['module_label'] = 'RTC'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Supports medias streaming for WebRTC and Verto.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_rtmp": - $mod['module_label'] = 'RTMP'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Real Time Media Protocol'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_say_de": - $mod['module_label'] = 'German'; - $mod['module_category'] = 'Say'; - $mod['module_description'] = 'German sound files used for time, date, digits, etc.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_say_en": - $mod['module_label'] = 'English'; - $mod['module_category'] = 'Say'; - $mod['module_description'] = 'English sound files used for time, date, digits, etc.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_say_es": - $mod['module_label'] = 'Spanish'; - $mod['module_category'] = 'Say'; - $mod['module_description'] = 'Spanish sound files used for time, date, digits, etc.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_say_es_ar": - $mod['module_label'] = 'Spanish AR'; - $mod['module_category'] = 'Say'; - $mod['module_description'] = 'Spanish AR sound files used for time, date, digits, etc.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_say_fr": - $mod['module_label'] = 'French'; - $mod['module_category'] = 'Say'; - $mod['module_description'] = 'Play French phrases using sound files for time, date, digits, and more.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_say_he": - $mod['module_label'] = 'Hebrew'; - $mod['module_category'] = 'Say'; - $mod['module_description'] = 'Play Hebrew phrases using sound files for time, date, digits, and more.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_say_hu": - $mod['module_label'] = 'Hungarian'; - $mod['module_category'] = 'Say'; - $mod['module_description'] = 'Play Hungarian phrases using sound files for time, date, digits, and more.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_say_it": - $mod['module_label'] = 'Italian'; - $mod['module_category'] = 'Say'; - $mod['module_description'] = 'Play Italian phrases using sound files for time, date, digits, and more.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_say_nl": - $mod['module_label'] = 'Dutch'; - $mod['module_category'] = 'Say'; - $mod['module_description'] = 'Play Dutch phrases using sound files for time, date, digits, and more.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_say_pt": - $mod['module_label'] = 'Portuguese'; - $mod['module_category'] = 'Say'; - $mod['module_description'] = 'Play Portuguese phrases using sound files for time, date, digits, and more.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_say_ru": - $mod['module_label'] = 'Russian'; - $mod['module_category'] = 'Say'; - $mod['module_description'] = 'Play Russian phrases using sound files for time, date, digits, and more.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_say_th": - $mod['module_label'] = 'Thai'; - $mod['module_category'] = 'Say'; - $mod['module_description'] = 'Play Thai phrases using sound files for time, date, digits, and more.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_say_zh": - $mod['module_label'] = 'Chinese'; - $mod['module_category'] = 'Say'; - $mod['module_description'] = 'Play Chinese phrases using sound files for time, date, digits, and more.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_shout": - $mod['module_label'] = 'Shout'; - $mod['module_category'] = 'Streams / Files'; - $mod['module_description'] = 'MP3 files and shoutcast streams.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_siren": - $mod['module_label'] = 'Siren'; - $mod['module_category'] = 'Codecs'; - $mod['module_description'] = 'Siren codec'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_sms": - $mod['module_label'] = 'SMS'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Chat messages'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_sndfile": - $mod['module_label'] = 'Sound File'; - $mod['module_category'] = 'File Format Interfaces'; - $mod['module_description'] = 'Multi-format file format transcoder (WAV, etc).'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_sofia": - $mod['module_label'] = 'Sofia'; - $mod['module_category'] = 'Endpoints'; - $mod['module_description'] = 'SIP module.'; - $mod['module_order'] = 300; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_spandsp": - $mod['module_label'] = 'SpanDSP'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'FAX provides fax send and receive.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_speex": - $mod['module_label'] = 'Speex'; - $mod['module_category'] = 'Codecs'; - $mod['module_description'] = 'Speex codec.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_spidermonkey": - $mod['module_label'] = 'SpiderMonkey'; - $mod['module_category'] = 'Languages'; - $mod['module_description'] = 'JavaScript support.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_spidermonkey_core_db": - $mod['module_label'] = 'SpiderMonkey Core DB'; - $mod['module_category'] = 'Languages'; - $mod['module_description'] = 'Javascript support for SQLite.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_spidermonkey_curl": - $mod['module_label'] = 'SpiderMonkey Curl'; - $mod['module_category'] = 'Languages'; - $mod['module_description'] = 'Javascript curl support.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_spidermonkey_socket": - $mod['module_label'] = 'SpiderMonkey Socket'; - $mod['module_category'] = 'Languages'; - $mod['module_description'] = 'Javascript socket support.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_spidermonkey_teletone": - $mod['module_label'] = 'SpiderMonkey Teletone'; - $mod['module_category'] = 'Languages'; - $mod['module_description'] = 'Javascript teletone support.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_syslog": - $mod['module_label'] = 'Syslog'; - $mod['module_category'] = 'Loggers'; - $mod['module_description'] = 'Send logs to a remote syslog server.'; - $mod['module_order'] = 400; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_test": - $mod['module_label'] = 'Test'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Test application.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_tone_stream": - $mod['module_label'] = 'Tone Stream'; - $mod['module_category'] = 'Streams / Files'; - $mod['module_description'] = 'Generate tone streams.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_tts_commandline": - $mod['module_label'] = 'TTS Commandline'; - $mod['module_category'] = 'Speech Recognition / Text to Speech'; - $mod['module_description'] = 'Commandline text to speech engine.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_unimrcp": - $mod['module_label'] = 'MRCP'; - $mod['module_category'] = 'Speech Recognition / Text to Speech'; - $mod['module_description'] = 'Media Resource Control Protocol.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_valet_parking": - $mod['module_label'] = 'Valet Parking'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Call parking'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_voicemail": - $mod['module_label'] = 'Voicemail'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Full featured voicemail module.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_voicemail_ivr": - $mod['module_label'] = 'Voicemail IVR'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'Voicemail IVR interface.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_translate": - $mod['module_label'] = 'Translate'; - $mod['module_category'] = 'Applications'; - $mod['module_description'] = 'format numbers into a specified format.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_xml_cdr": - $mod['module_label'] = 'XML CDR'; - $mod['module_category'] = 'XML Interfaces'; - $mod['module_description'] = 'XML based call detail record handler.'; - $mod['module_enabled'] = true; - $mod['module_default_enabled'] = true; - break; - case "mod_xml_curl": - $mod['module_label'] = 'XML Curl'; - $mod['module_category'] = 'XML Interfaces'; - $mod['module_description'] = 'Request XML config files dynamically.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_xml_rpc": - $mod['module_label'] = 'XML RPC'; - $mod['module_category'] = 'XML Interfaces'; - $mod['module_description'] = 'XML Remote Procedure Calls. Issue commands from your web application.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - case "mod_xml_scgi": - $mod['module_label'] = 'XML SCGI'; - $mod['module_category'] = 'XML Interfaces'; - $mod['module_description'] = 'SCGI XML Gateway.'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - break; - default: - $mod['module_category'] = 'Auto'; - $mod['module_enabled'] = false; - $mod['module_default_enabled'] = false; - } - return $mod; + //get the list of active modules + $json = $this->esl->request("api show modules as json"); + $this->active_modules = json_decode($json, true); + } + + /** + * Get additional information about a specific module + * + * Retrieves and formats information about a module. + * + * @param string $name The name of the module to retrieve information for. + * + * @return array An array containing the formatted module information. + */ + public function info($name) { + $module_label = substr($name, 4); + $module_label = ucwords(str_replace("_", " ", $module_label)); + $mod['module_label'] = $module_label; + $mod['module_name'] = $name; + $mod['module_order'] = '800'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + $mod['module_description'] = ''; + switch ($name) { + case "mod_amr": + $mod['module_label'] = 'AMR'; + $mod['module_category'] = 'Codecs'; + $mod['module_description'] = 'AMR codec.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_av": + $mod['module_label'] = 'AV'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Supports libav and RTMP streams.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_avmd": + $mod['module_label'] = 'AVMD'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Advanced voicemail beep detection.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_blacklist": + $mod['module_label'] = 'Blacklist'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Blacklist.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_b64": + $mod['module_label'] = 'B64'; + $mod['module_category'] = 'Codecs'; + $mod['module_description'] = 'B64 Codec.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_bcg729": + $mod['module_label'] = 'BCG729'; + $mod['module_category'] = 'Codecs'; + $mod['module_description'] = 'G729 Open Source Codec.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_bv": + $mod['module_label'] = 'BV'; + $mod['module_category'] = 'Codecs'; + $mod['module_description'] = 'BroadVoice16 and BroadVoice32 audio codecs.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_cdr_csv": + $mod['module_label'] = 'CDR CSV'; + $mod['module_category'] = 'Event Handlers'; + $mod['module_description'] = 'CSV call detail record handler.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_cdr_sqlite": + $mod['module_label'] = 'CDR SQLite'; + $mod['module_category'] = 'Event Handlers'; + $mod['module_description'] = 'SQLite call detail record handler.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_callcenter": + $mod['module_label'] = 'Call Center'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Call queuing with agents and tiers for call centers.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_cepstral": + $mod['module_label'] = 'Cepstral'; + $mod['module_category'] = 'Speech Recognition / Text to Speech'; + $mod['module_description'] = 'Text to Speech engine.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_cidlookup": + $mod['module_label'] = 'CID Lookup'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Lookup caller id info.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_cluechoo": + $mod['module_label'] = 'Cluechoo'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'A framework demo module.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_commands": + $mod['module_label'] = 'Commands'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'API interface commands.'; + $mod['module_order'] = 100; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_conference": + $mod['module_label'] = 'Conference'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Conference room module.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_console": + $mod['module_label'] = 'Console'; + $mod['module_category'] = 'Loggers'; + $mod['module_description'] = 'Send logs to the console.'; + $mod['module_order'] = 400; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_curl": + $mod['module_label'] = 'CURL'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Allows scripts to make HTTP requests and return responses in plain text or JSON.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_db": + $mod['module_label'] = 'DB'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Database key / value storage functionality, dialing and limit backend.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_dialplan_asterisk": + $mod['module_label'] = 'Dialplan Asterisk'; + $mod['module_category'] = 'Dialplan Interfaces'; + $mod['module_description'] = 'Allows Asterisk dialplans.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_dialplan_xml": + $mod['module_label'] = 'Dialplan XML'; + $mod['module_category'] = 'Dialplan Interfaces'; + $mod['module_description'] = 'Provides dialplan functionality in XML.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_directory": + $mod['module_label'] = 'Directory'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Dial by name directory.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_distributor": + $mod['module_label'] = 'Distributor'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Round robin call distribution.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_dptools": + $mod['module_label'] = 'Dialplan Plan Tools'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Provides a number of apps and utilities for the dialplan.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_enum": + $mod['module_label'] = 'ENUM'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Route PSTN numbers over internet according to ENUM servers, such as e164.org.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_esf": + $mod['module_label'] = 'ESF'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Holds the multi cast paging application for SIP.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_event_socket": + $mod['module_label'] = 'Event Socket'; + $mod['module_category'] = 'Event Handlers'; + $mod['module_description'] = 'Sends events via a single socket.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_expr": + $mod['module_label'] = 'Expr'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Expression evaluation library.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_fifo": + $mod['module_label'] = 'FIFO'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'FIFO provides custom call queues including call park.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_flite": + $mod['module_label'] = 'Flite'; + $mod['module_category'] = 'Speech Recognition / Text to Speech'; + $mod['module_description'] = 'Text to Speech engine.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_fsv": + $mod['module_label'] = 'FSV'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Video application (Recording and playback).'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_g723_1": + $mod['module_label'] = 'G.723.1'; + $mod['module_category'] = 'Codecs'; + $mod['module_description'] = 'G.723.1 codec.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_g729": + $mod['module_label'] = 'G.729'; + $mod['module_category'] = 'Codecs'; + $mod['module_description'] = 'G729 codec supports passthrough mode'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_h26x": + $mod['module_label'] = 'H26x'; + $mod['module_category'] = 'Codecs'; + $mod['module_description'] = 'Video codecs'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_hash": + $mod['module_label'] = 'Hash'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Resource limitation.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_httapi": + $mod['module_label'] = 'HT-TAPI'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'HT-TAPI Hypertext Telephony API'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_http_cache": + $mod['module_label'] = 'HTTP Cache'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'HTTP GET with caching'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_ilbc": + $mod['module_label'] = 'iLBC'; + $mod['module_category'] = 'Codecs'; + $mod['module_description'] = 'iLBC codec.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_ladspa": + $mod['module_label'] = 'Ladspa'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Auto-tune calls.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_lcr": + $mod['module_label'] = 'LCR'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Least cost routing.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_local_stream": + $mod['module_label'] = 'Local Stream'; + $mod['module_category'] = 'Streams / Files'; + $mod['module_description'] = 'For local streams (play all the files in a directory).'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_logfile": + $mod['module_label'] = 'Log File'; + $mod['module_category'] = 'Loggers'; + $mod['module_description'] = 'Send logs to the local file system.'; + $mod['module_order'] = 400; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_loopback": + $mod['module_label'] = 'Loopback'; + $mod['module_category'] = 'Endpoints'; + $mod['module_description'] = 'A loopback channel driver to make an outbound call as an inbound call.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_lua": + $mod['module_label'] = 'Lua'; + $mod['module_category'] = 'Languages'; + $mod['module_description'] = 'Lua script.'; + $mod['module_order'] = 200; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_memcache": + $mod['module_label'] = 'Memcached'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'API for memcached.'; + $mod['module_enabled'] = false; + $mod['module_order'] = 150; + $mod['module_default_enabled'] = false; + break; + case "mod_native_file": + $mod['module_label'] = 'Native File'; + $mod['module_category'] = 'File Format Interfaces'; + $mod['module_description'] = 'File interface for codec specific file formats.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_nibblebill": + $mod['module_label'] = 'Nibblebill'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Billing module.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_opus": + $mod['module_label'] = 'Opus'; + $mod['module_category'] = 'Codecs'; + $mod['module_description'] = 'OPUS ultra-low delay audio codec'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_park": + $mod['module_label'] = 'Park'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Park Calls.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_pgsql": + $mod['module_label'] = 'PGSQL'; + $mod['module_category'] = 'Databases'; + $mod['module_description'] = 'Client support for PostgreSQL database.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_png": + $mod['module_label'] = 'PNG'; + $mod['module_category'] = 'Formats'; + $mod['module_description'] = 'Image format Portable Network Graphics.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_pocketsphinx": + $mod['module_label'] = 'PocketSphinx'; + $mod['module_category'] = 'Speech Recognition / Text to Speech'; + $mod['module_description'] = 'Speech Recognition.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_rtc": + $mod['module_label'] = 'RTC'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Supports medias streaming for WebRTC and Verto.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_rtmp": + $mod['module_label'] = 'RTMP'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Real Time Media Protocol'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_say_de": + $mod['module_label'] = 'German'; + $mod['module_category'] = 'Say'; + $mod['module_description'] = 'German sound files used for time, date, digits, etc.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_say_en": + $mod['module_label'] = 'English'; + $mod['module_category'] = 'Say'; + $mod['module_description'] = 'English sound files used for time, date, digits, etc.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_say_es": + $mod['module_label'] = 'Spanish'; + $mod['module_category'] = 'Say'; + $mod['module_description'] = 'Spanish sound files used for time, date, digits, etc.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_say_es_ar": + $mod['module_label'] = 'Spanish AR'; + $mod['module_category'] = 'Say'; + $mod['module_description'] = 'Spanish AR sound files used for time, date, digits, etc.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_say_fr": + $mod['module_label'] = 'French'; + $mod['module_category'] = 'Say'; + $mod['module_description'] = 'Play French phrases using sound files for time, date, digits, and more.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_say_he": + $mod['module_label'] = 'Hebrew'; + $mod['module_category'] = 'Say'; + $mod['module_description'] = 'Play Hebrew phrases using sound files for time, date, digits, and more.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_say_hu": + $mod['module_label'] = 'Hungarian'; + $mod['module_category'] = 'Say'; + $mod['module_description'] = 'Play Hungarian phrases using sound files for time, date, digits, and more.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_say_it": + $mod['module_label'] = 'Italian'; + $mod['module_category'] = 'Say'; + $mod['module_description'] = 'Play Italian phrases using sound files for time, date, digits, and more.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_say_nl": + $mod['module_label'] = 'Dutch'; + $mod['module_category'] = 'Say'; + $mod['module_description'] = 'Play Dutch phrases using sound files for time, date, digits, and more.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_say_pt": + $mod['module_label'] = 'Portuguese'; + $mod['module_category'] = 'Say'; + $mod['module_description'] = 'Play Portuguese phrases using sound files for time, date, digits, and more.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_say_ru": + $mod['module_label'] = 'Russian'; + $mod['module_category'] = 'Say'; + $mod['module_description'] = 'Play Russian phrases using sound files for time, date, digits, and more.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_say_th": + $mod['module_label'] = 'Thai'; + $mod['module_category'] = 'Say'; + $mod['module_description'] = 'Play Thai phrases using sound files for time, date, digits, and more.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_say_zh": + $mod['module_label'] = 'Chinese'; + $mod['module_category'] = 'Say'; + $mod['module_description'] = 'Play Chinese phrases using sound files for time, date, digits, and more.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_shout": + $mod['module_label'] = 'Shout'; + $mod['module_category'] = 'Streams / Files'; + $mod['module_description'] = 'MP3 files and shoutcast streams.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_siren": + $mod['module_label'] = 'Siren'; + $mod['module_category'] = 'Codecs'; + $mod['module_description'] = 'Siren codec'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_sms": + $mod['module_label'] = 'SMS'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Chat messages'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_sndfile": + $mod['module_label'] = 'Sound File'; + $mod['module_category'] = 'File Format Interfaces'; + $mod['module_description'] = 'Multi-format file format transcoder (WAV, etc).'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_sofia": + $mod['module_label'] = 'Sofia'; + $mod['module_category'] = 'Endpoints'; + $mod['module_description'] = 'SIP module.'; + $mod['module_order'] = 300; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_spandsp": + $mod['module_label'] = 'SpanDSP'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'FAX provides fax send and receive.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_speex": + $mod['module_label'] = 'Speex'; + $mod['module_category'] = 'Codecs'; + $mod['module_description'] = 'Speex codec.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_spidermonkey": + $mod['module_label'] = 'SpiderMonkey'; + $mod['module_category'] = 'Languages'; + $mod['module_description'] = 'JavaScript support.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_spidermonkey_core_db": + $mod['module_label'] = 'SpiderMonkey Core DB'; + $mod['module_category'] = 'Languages'; + $mod['module_description'] = 'Javascript support for SQLite.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_spidermonkey_curl": + $mod['module_label'] = 'SpiderMonkey Curl'; + $mod['module_category'] = 'Languages'; + $mod['module_description'] = 'Javascript curl support.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_spidermonkey_socket": + $mod['module_label'] = 'SpiderMonkey Socket'; + $mod['module_category'] = 'Languages'; + $mod['module_description'] = 'Javascript socket support.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_spidermonkey_teletone": + $mod['module_label'] = 'SpiderMonkey Teletone'; + $mod['module_category'] = 'Languages'; + $mod['module_description'] = 'Javascript teletone support.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_syslog": + $mod['module_label'] = 'Syslog'; + $mod['module_category'] = 'Loggers'; + $mod['module_description'] = 'Send logs to a remote syslog server.'; + $mod['module_order'] = 400; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_test": + $mod['module_label'] = 'Test'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Test application.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_tone_stream": + $mod['module_label'] = 'Tone Stream'; + $mod['module_category'] = 'Streams / Files'; + $mod['module_description'] = 'Generate tone streams.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_tts_commandline": + $mod['module_label'] = 'TTS Commandline'; + $mod['module_category'] = 'Speech Recognition / Text to Speech'; + $mod['module_description'] = 'Commandline text to speech engine.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_unimrcp": + $mod['module_label'] = 'MRCP'; + $mod['module_category'] = 'Speech Recognition / Text to Speech'; + $mod['module_description'] = 'Media Resource Control Protocol.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_valet_parking": + $mod['module_label'] = 'Valet Parking'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Call parking'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_voicemail": + $mod['module_label'] = 'Voicemail'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Full featured voicemail module.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_voicemail_ivr": + $mod['module_label'] = 'Voicemail IVR'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'Voicemail IVR interface.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_translate": + $mod['module_label'] = 'Translate'; + $mod['module_category'] = 'Applications'; + $mod['module_description'] = 'format numbers into a specified format.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_xml_cdr": + $mod['module_label'] = 'XML CDR'; + $mod['module_category'] = 'XML Interfaces'; + $mod['module_description'] = 'XML based call detail record handler.'; + $mod['module_enabled'] = true; + $mod['module_default_enabled'] = true; + break; + case "mod_xml_curl": + $mod['module_label'] = 'XML Curl'; + $mod['module_category'] = 'XML Interfaces'; + $mod['module_description'] = 'Request XML config files dynamically.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_xml_rpc": + $mod['module_label'] = 'XML RPC'; + $mod['module_category'] = 'XML Interfaces'; + $mod['module_description'] = 'XML Remote Procedure Calls. Issue commands from your web application.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + case "mod_xml_scgi": + $mod['module_label'] = 'XML SCGI'; + $mod['module_category'] = 'XML Interfaces'; + $mod['module_description'] = 'SCGI XML Gateway.'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; + break; + default: + $mod['module_category'] = 'Auto'; + $mod['module_enabled'] = false; + $mod['module_default_enabled'] = false; } + return $mod; + } //check to see if the module exists in the array - public function exists($name) { - //set the default - $result = false; - //look for the module - foreach ($this->modules as $row) { - if ($row['module_name'] == $name) { - $result = true; - break; - } - } - //return the result - return $result; - } - //check the status of the module - public function active($name) { - foreach ($this->active_modules['rows'] as $row) { - if ($row['ikey'] === $name) { - return true; - } + /** + * Check if a module exists in the collection of modules. + * + * @param string $name The name of the module to check for existence. + * + * @return bool True if the module exists, false otherwise. + */ + public function exists($name) { + //set the default + $result = false; + //look for the module + foreach ($this->modules as $row) { + if ($row['module_name'] == $name) { + $result = true; + break; } - return false; } + //return the result + return $result; + } - //get the list of modules - public function get_modules() { - $sql = "select * from v_modules "; - $sql .= "order by module_category, module_label"; - $this->modules = $this->database->select($sql, null, 'all'); - unset($sql); + /** + * Check the status of the module + * + * @param string $name Module name to check for activity + * + * @return bool True if the module is active, false otherwise + */ + public function active($name) { + foreach ($this->active_modules['rows'] as $row) { + if ($row['ikey'] === $name) { + return true; + } } + return false; + } + + /** + * Sets a list of modules in the object property modules. + * + * @return void + */ + public function get_modules() { + $sql = "select * from v_modules "; + $sql .= "order by module_category, module_label"; + $this->modules = $this->database->select($sql, null, 'all'); + } //add missing modules for more module info see http://wiki.freeswitch.com/wiki/Modules - public function synch() { - if (false !== ($handle = opendir($this->dir ?? ''))) { - $modules_new = ''; - $module_found = false; - $x = 0; - while (false !== ($file = readdir($handle))) { - if ($file != "." && $file != "..") { - if (substr($file, -3) == ".so" || substr($file, -4) == ".dll") { - if (substr($file, -3) == ".so") { - $name = substr($file, 0, -3); - } - if (substr($file, -4) == ".dll") { - $name = substr($file, 0, -4); - } - if (!$this->exists($name)) { - //set module found to true - $module_found = true; - //get the module array - $mod = $this->info($name); - //append the module label - $modules_new .= "
  • ".$mod['module_label']."
  • \n"; - //set the order - $order = $mod['module_order']; - //build insert array - $array['modules'][$x]['module_uuid'] = uuid(); - $array['modules'][$x]['module_label'] = $mod['module_label']; - $array['modules'][$x]['module_name'] = $mod['module_name']; - $array['modules'][$x]['module_description'] = $mod['module_description']; - $array['modules'][$x]['module_category'] = $mod['module_category']; - $array['modules'][$x]['module_order'] = $order; - $array['modules'][$x]['module_enabled'] = $mod['module_enabled']; - $array['modules'][$x]['module_default_enabled'] = $mod['module_default_enabled']; - $x++; - } + + /** + * Synchronize modules with the database. + * + * Scans the module directory for new or updated modules and inserts them into + * the database. If a module is found, it is added to the database with its label, + * name, description, category, order, enabled status, and default enabled status. + * + * @return void + */ + public function synch() { + if (false !== ($handle = opendir($this->dir ?? ''))) { + $modules_new = ''; + $module_found = false; + $x = 0; + while (false !== ($file = readdir($handle))) { + if ($file != "." && $file != "..") { + if (substr($file, -3) == ".so" || substr($file, -4) == ".dll") { + if (substr($file, -3) == ".so") { + $name = substr($file, 0, -3); + } + if (substr($file, -4) == ".dll") { + $name = substr($file, 0, -4); + } + if (!$this->exists($name)) { + //set module found to true + $module_found = true; + //get the module array + $mod = $this->info($name); + //append the module label + $modules_new .= "
  • " . $mod['module_label'] . "
  • \n"; + //set the order + $order = $mod['module_order']; + //build insert array + $array['modules'][$x]['module_uuid'] = uuid(); + $array['modules'][$x]['module_label'] = $mod['module_label']; + $array['modules'][$x]['module_name'] = $mod['module_name']; + $array['modules'][$x]['module_description'] = $mod['module_description']; + $array['modules'][$x]['module_category'] = $mod['module_category']; + $array['modules'][$x]['module_order'] = $order; + $array['modules'][$x]['module_enabled'] = $mod['module_enabled']; + $array['modules'][$x]['module_default_enabled'] = $mod['module_default_enabled']; + $x++; } } } - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - //grant temporary permissions - $p = permissions::new(); - $p->add('module_add', 'temp'); - //execute insert - $this->database->app_name = 'modules'; - $this->database->app_uuid = '5eb9cba1-8cb6-5d21-e36a-775475f16b5e'; + } + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + //grant temporary permissions + $p = permissions::new(); + $p->add('module_add', 'temp'); + //execute insert + $this->database->app_name = 'modules'; + $this->database->app_uuid = '5eb9cba1-8cb6-5d21-e36a-775475f16b5e'; + $this->database->save($array); + unset($array); + //revoke temporary permissions + $p->delete('module_add', 'temp'); + } + closedir($handle); + if ($module_found) { + $msg = "Added New Modules:
    \n"; + $msg .= "
      \n"; + $msg .= $modules_new; + $msg .= "
    \n"; + $this->msg = $msg; + } + } + } + + //save the modules.conf.xml file + + /** + * Composes the XML configuration for modules and saves it to modules.conf.xml file in the switch/autoload_configs + * directory configured in the global default settings. + */ + function xml() { + //set the globals + global $config, $domain_uuid; + + //compose xml + $xml = "\n"; + $xml .= " \n"; + + $sql = "select * from v_modules "; + $sql .= "order by module_order asc, "; + $sql .= "module_category asc "; + $result = $this->database->select($sql, null, 'all'); + unset($sql); + + $prev_module_cat = ''; + if (is_array($result) && @sizeof($result) != 0) { + foreach ($result as $row) { + if ($prev_module_cat != $row['module_category']) { + $xml .= "\n \n"; + } + if ($row['module_enabled']) { + $xml .= " \n"; + } + $prev_module_cat = $row['module_category']; + } + } + unset($result, $row); + + $xml .= "\n"; + $xml .= " \n"; + $xml .= ""; + + if (!empty($this->settings->get('switch', 'conf')) && is_writable($this->settings->get('switch', 'conf') . '/autoload_configs/modules.conf.xml')) { + $fout = fopen($this->settings->get('switch', 'conf') . "/autoload_configs/modules.conf.xml", "w"); + fwrite($fout, $xml); + unset($xml); + fclose($fout); + } + + //apply settings + $_SESSION["reload_xml"] = true; + } + + /** + * Initiates the starting process. + * + * @param mixed[] $records Data required for the starting process + * + * @see modules::control() + */ + public function start($records) { + $this->control('start', $records); + } + + /** + * Stops a module from the switch. + * + * @param mixed[] $records Data required for the termination process + * + * @see modules::control() + */ + public function stop($records) { + $this->control('stop', $records); + } + + /** + * Performs the specified control action on the checked modules. + * + * @param string $action The type of control to be performed ('start' or 'stop') + * @param mixed[] $records An array of records containing information about the modules to be controlled + */ + private function control($action, $records) { + if (permission_exists($this->permission_prefix . 'edit')) { + + //set local variables + switch ($action) { + case 'start': + $action = 'load'; + $response_message = 'message-module_started'; + break; + case 'stop': + $action = 'unload'; + $response_message = 'message-module_stopped'; + break; + default: + exit; + } + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //control the checked modules + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked modules, build where clause for below + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //get module details + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, module_name as module, module_enabled as enabled from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $modules[$row['uuid']]['name'] = $row['module']; + $modules[$row['uuid']]['enabled'] = $row['enabled']; + } + } + unset($sql, $parameters, $rows, $row); + } + + if (is_array($modules) && @sizeof($modules) != 0) { + //create the event socket connection + $esl = event_socket::create(); + + if ($esl->is_connected()) { + //control modules + foreach ($modules as $module_uuid => $module) { + if ($module['enabled'] == 'true') { + $responses[$module_uuid]['module'] = $module['name']; + $responses[$module_uuid]['message'] = trim(event_socket::api($action . ' ' . $module['name'])); + } else { + $responses[$module_uuid]['module'] = $module['name']; + $responses[$module_uuid]['message'] = $text['label-disabled']; + } + } + + //set message + $message = $text[$response_message]; + if (is_array($responses) && @sizeof($responses) != 0) { + foreach ($responses as $response) { + $message .= "
    " . $response['module'] . ": " . $response['message']; + } + } + message::add($message, 'positive', 7000); + } + } + } + + } + } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete the checked modules + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked modules, build where clause for below + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //get module details + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, module_name as module from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $modules[$row['uuid']]['name'] = $row['module']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build the delete array + if (is_array($modules) && @sizeof($modules) != 0) { + $x = 0; + foreach ($modules as $module_uuid => $module) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $module_uuid; + $x++; + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //create the event socket connection + $esl = event_socket::create(); + + //stop modules + if ($esl->is_connected()) { + foreach ($modules as $module_uuid => $module) { + if ($this->active($module['name'])) { + $responses[$module_uuid]['module'] = $module['name']; + $responses[$module_uuid]['message'] = trim(event_socket::api('unload ' . $module['name'])); + } + } + } + + //execute delete + $this->database->delete($array); + unset($array); + + //rewrite mod + $this->xml(); + + //set message + $message = $text['message-delete']; + if (!empty($responses) && is_array($responses) && @sizeof($responses) != 0) { + foreach ($responses as $response) { + $message .= "
    " . $response['module'] . ": " . $response['message']; + } + } + message::add($message, 'positive', 7000); + + } + } + + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as state, module_name as name from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $modules[$row['uuid']]['state'] = $row['state']; + $modules[$row['uuid']]['name'] = $row['name']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + if (is_array($modules) && @sizeof($modules) != 0) { + foreach ($modules as $uuid => $module) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $module['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + + //save the array + $this->database->save($array); unset($array); - //revoke temporary permissions - $p->delete('module_add', 'temp'); - } - closedir($handle); - if ($module_found) { - $msg = "Added New Modules:
    \n"; - $msg .= "
      \n"; - $msg .= $modules_new; - $msg .= "
    \n"; - $this->msg = $msg; - } - } - } - //save the modules.conf.xml file - function xml() { - //set the globals - global $config, $domain_uuid; + //create the event socket connection + $esl = event_socket::create(); - //compose xml - $xml = "\n"; - $xml .= " \n"; - - $sql = "select * from v_modules "; - $sql .= "order by module_order asc, "; - $sql .= "module_category asc "; - $result = $this->database->select($sql, null, 'all'); - unset($sql); - - $prev_module_cat = ''; - if (is_array($result) && @sizeof($result) != 0) { - foreach ($result as $row) { - if ($prev_module_cat != $row['module_category']) { - $xml .= "\n \n"; - } - if ($row['module_enabled']){ - $xml .= " \n"; - } - $prev_module_cat = $row['module_category']; - } - } - unset($result, $row); - - $xml .= "\n"; - $xml .= " \n"; - $xml .= ""; - - if (!empty($this->settings->get('switch', 'conf')) && is_writable($this->settings->get('switch', 'conf').'/autoload_configs/modules.conf.xml')) { - $fout = fopen($this->settings->get('switch', 'conf')."/autoload_configs/modules.conf.xml","w"); - fwrite($fout, $xml); - unset($xml); - fclose($fout); - } - - //apply settings - $_SESSION["reload_xml"] = true; - } - - /** - * start modules - */ - public function start($records) { - $this->control('start', $records); - } - - /** - * stop modules - */ - public function stop($records) { - $this->control('stop', $records); - } - - /** - * control (load/unload) modules - */ - private function control($action, $records) { - if (permission_exists($this->permission_prefix.'edit')) { - - //set local variables - switch ($action) { - case 'start': - $action = 'load'; - $response_message = 'message-module_started'; - break; - case 'stop': - $action = 'unload'; - $response_message = 'message-module_stopped'; - break; - default: - exit; - } - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //control the checked modules - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked modules, build where clause for below - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //get module details - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, module_name as module, module_enabled as enabled from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $modules[$row['uuid']]['name'] = $row['module']; - $modules[$row['uuid']]['enabled'] = $row['enabled']; - } - } - unset($sql, $parameters, $rows, $row); - } - - if (is_array($modules) && @sizeof($modules) != 0) { - //create the event socket connection - $esl = event_socket::create(); - - if ($esl->is_connected()) { - //control modules - foreach ($modules as $module_uuid => $module) { - if ($module['enabled'] == 'true') { - $responses[$module_uuid]['module'] = $module['name']; - $responses[$module_uuid]['message'] = trim(event_socket::api($action.' '.$module['name'])); - } - else { - $responses[$module_uuid]['module'] = $module['name']; - $responses[$module_uuid]['message'] = $text['label-disabled']; - } - } - - //set message - $message = $text[$response_message]; - if (is_array($responses) && @sizeof($responses) != 0) { - foreach ($responses as $response) { - $message .= "
    ".$response['module'].": ".$response['message']; - } - } - message::add($message, 'positive', 7000); + //stop modules if active + if ($esl->is_connected()) { + foreach ($modules as $module_uuid => $module) { + if ($this->active($module['name'])) { + $cmd = 'unload ' . $module['name']; + $responses[$module_uuid]['module'] = $module['name']; + $responses[$module_uuid]['message'] = trim(event_socket::api($cmd)); } } } + //rewrite mod + $this->xml(); + + //set message + $message = $text['message-toggle']; + if (!empty($responses) && is_array($responses) && @sizeof($responses) != 0) { + foreach ($responses as $response) { + $message .= "
    " . $response['module'] . ": " . $response['message']; + } + } + message::add($message, 'positive', 7000); + + } + unset($records, $modules); } + } + } //method - /** - * delete modules - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete the checked modules - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked modules, build where clause for below - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //get module details - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, module_name as module from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $modules[$row['uuid']]['name'] = $row['module']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build the delete array - if (is_array($modules) && @sizeof($modules) != 0) { - $x = 0; - foreach ($modules as $module_uuid => $module) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $module_uuid; - $x++; - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //create the event socket connection - $esl = event_socket::create(); - - //stop modules - if ($esl->is_connected()) { - foreach ($modules as $module_uuid => $module) { - if ($this->active($module['name'])) { - $responses[$module_uuid]['module'] = $module['name']; - $responses[$module_uuid]['message'] = trim(event_socket::api('unload '.$module['name'])); - } - } - } - - //execute delete - $this->database->delete($array); - unset($array); - - //rewrite mod - $this->xml(); - - //set message - $message = $text['message-delete']; - if (!empty($responses) && is_array($responses) && @sizeof($responses) != 0) { - foreach ($responses as $response) { - $message .= "
    ".$response['module'].": ".$response['message']; - } - } - message::add($message, 'positive', 7000); - - } - } - - } - } - - /** - * toggle records - */ - public function toggle($records) { - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as state, module_name as name from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $modules[$row['uuid']]['state'] = $row['state']; - $modules[$row['uuid']]['name'] = $row['name']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - if (is_array($modules) && @sizeof($modules) != 0) { - foreach($modules as $uuid => $module) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $module['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //create the event socket connection - $esl = event_socket::create(); - - //stop modules if active - if ($esl->is_connected()) { - foreach ($modules as $module_uuid => $module) { - if ($this->active($module['name'])) { - $cmd = 'unload '.$module['name']; - $responses[$module_uuid]['module'] = $module['name']; - $responses[$module_uuid]['message'] = trim(event_socket::api($cmd)); - } - } - } - - //rewrite mod - $this->xml(); - - //set message - $message = $text['message-toggle']; - if (!empty($responses) && is_array($responses) && @sizeof($responses) != 0) { - foreach ($responses as $response) { - $message .= "
    ".$response['module'].": ".$response['message']; - } - } - message::add($message, 'positive', 7000); - - } - unset($records, $modules); - } - - } - } //method - - - } //class +} //class /* $mod = new modules; diff --git a/app/music_on_hold/music_on_hold.php b/app/music_on_hold/music_on_hold.php index 91a91478ad..1fac7f418b 100644 --- a/app/music_on_hold/music_on_hold.php +++ b/app/music_on_hold/music_on_hold.php @@ -612,6 +612,16 @@ require_once "resources/footer.php"; //define the download function (helps safari play audio sources) + /** + * Downloads a file in chunks as requested by the client. + * + * This function is used to handle byte-range requests, allowing clients + * to request specific parts of the file. + * + * @param string $file The path to the file being downloaded. + * + * @return void + */ function range_download($file) { $fp = @fopen($file, 'rb'); @@ -640,7 +650,7 @@ $c_start = $start; $c_end = $end; // Extract the range string - list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2); + [, $range] = explode('=', $_SERVER['HTTP_RANGE'], 2); // Make sure the client hasn't sent us a multibyte range if (strpos($range, ',') !== false) { // (?) Shoud this be issued here, or should the first diff --git a/app/music_on_hold/resources/classes/switch_music_on_hold.php b/app/music_on_hold/resources/classes/switch_music_on_hold.php index 2615b9b646..b3175fe1dd 100644 --- a/app/music_on_hold/resources/classes/switch_music_on_hold.php +++ b/app/music_on_hold/resources/classes/switch_music_on_hold.php @@ -27,419 +27,464 @@ */ //define the switch_music_on_hold class - class switch_music_on_hold { +class switch_music_on_hold { - /** - * declare constant variables - */ - const app_name = 'music_on_hold'; - const app_uuid = '1dafe0f8-c08a-289b-0312-15baf4f20f81'; + /** + * declare constant variables + */ + const app_name = 'music_on_hold'; + const app_uuid = '1dafe0f8-c08a-289b-0312-15baf4f20f81'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $this->settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $this->settings_array associative array or + * set in the session global array + * + * @var string + */ + private $user_uuid; - /** - * Username set in the constructor. This can be passed in through the $this->settings_array associative array or set in the session global array - * @var string - */ - private $username; + /** + * Username set in the constructor. This can be passed in through the $this->settings_array associative array or + * set in the session global array + * + * @var string + */ + private $username; - /** - * Domain UUID set in the constructor. This can be passed in through the $this->settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $this->settings_array associative array or + * set in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * Domain name set in the constructor. This can be passed in through the $this->settings_array associative array or set in the session global array - * @var string - */ - private $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $this->settings_array associative array or + * set in the session global array + * + * @var string + */ + private $domain_name; - /** - * declare private variables - */ - private $xml; - private $app_name; - private $app_uuid; - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; + /** + * declare private variables + */ + private $xml; + private $app_name; + private $app_uuid; + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); - //assign private variables - $this->permission_prefix = 'music_on_hold_'; - $this->list_page = 'music_on_hold.php'; - $this->table = 'music_on_hold'; - $this->uuid_prefix = 'music_on_hold_'; + //assign private variables + $this->permission_prefix = 'music_on_hold_'; + $this->list_page = 'music_on_hold.php'; + $this->table = 'music_on_hold'; + $this->uuid_prefix = 'music_on_hold_'; + } + + /** + * Generates a HTML select element. + * + * @param string $name The name of the select field. + * @param string $selected The currently selected value. + * @param array $options Additional options to include in the select. + * + * @return string A HTML select element as a string. + */ + public function select($name, $selected, $options) { + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //start the select + $select = "\n"; - - //music on hold - $music_list = $this->get(); - if (count($music_list) > 0) { - $select .= " \n"; - $previous_name = ''; - foreach($music_list as $row) { - if ($previous_name != $row['music_on_hold_name']) { - $name = ''; - if (!empty($row['domain_uuid'])) { - $name = $row['domain_name'].'/'; - } - $name .= $row['music_on_hold_name']; - $select .= " \n"; - } - $previous_name = $row['music_on_hold_name']; - } - $select .= " \n"; - } - //recordings - if (is_dir($_SERVER["PROJECT_ROOT"].'/app/recordings')) { - $recordings_c = new switch_recordings; - $recordings = $recordings_c->list_recordings(); - if (is_array($recordings) && sizeof($recordings) > 0) { - $select .= " "; - foreach($recordings as $recording_value => $recording_name){ - $select .= " \n"; - } - $select .= " \n"; - } - } - //streams - if (is_dir($_SERVER["PROJECT_ROOT"].'/app/streams')) { - $sql = "select * from v_streams "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and stream_enabled = 'true' "; - $sql .= "order by stream_name asc "; - $parameters['domain_uuid'] = $this->domain_uuid; - $streams = $this->database->select($sql, $parameters, 'all'); - if (is_array($streams) && @sizeof($streams) != 0) { - $select .= " "; - foreach($streams as $row){ - $select .= " \n"; - } - $select .= " \n"; - } - unset($sql, $parameters, $streams, $row); - } - //add additional options - $select .= " "; - $select .= " \n"; - if (is_array($options) && sizeof($options) > 0) { - $select .= $options; + //recordings + if (is_dir($_SERVER["PROJECT_ROOT"] . '/app/recordings')) { + $recordings_c = new switch_recordings; + $recordings = $recordings_c->list_recordings(); + if (is_array($recordings) && sizeof($recordings) > 0) { + $select .= " "; + foreach ($recordings as $recording_value => $recording_name) { + $select .= " \n"; } $select .= " \n"; - //end the select and return it - $select .= "\n"; - return $select; + } } - - public function get() { - //get moh records, build array - $sql = "select "; - $sql .= "d.domain_name, "; - $sql .= "m.* "; - $sql .= "from v_music_on_hold as m "; - $sql .= "left join v_domains as d on d.domain_uuid = m.domain_uuid "; - $sql .= "where (m.domain_uuid = :domain_uuid or m.domain_uuid is null) "; - $sql .= "order by m.domain_uuid desc, music_on_hold_name asc, music_on_hold_rate asc "; + //streams + if (is_dir($_SERVER["PROJECT_ROOT"] . '/app/streams')) { + $sql = "select * from v_streams "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and stream_enabled = 'true' "; + $sql .= "order by stream_name asc "; $parameters['domain_uuid'] = $this->domain_uuid; - return $this->database->select($sql, $parameters, 'all'); + $streams = $this->database->select($sql, $parameters, 'all'); + if (is_array($streams) && @sizeof($streams) != 0) { + $select .= " "; + foreach ($streams as $row) { + $select .= " \n"; + } + $select .= " \n"; + } + unset($sql, $parameters, $streams, $row); + } + //add additional options + $select .= " "; + $select .= " \n"; + if (is_array($options) && sizeof($options) > 0) { + $select .= $options; + } + $select .= " \n"; + //end the select and return it + $select .= "\n"; + return $select; + } + + /** + * Retrieves moh records and builds an array. + * + * @return array|false An array of moh records. + */ + public function get() { + //get moh records, build array + $sql = "select "; + $sql .= "d.domain_name, "; + $sql .= "m.* "; + $sql .= "from v_music_on_hold as m "; + $sql .= "left join v_domains as d on d.domain_uuid = m.domain_uuid "; + $sql .= "where (m.domain_uuid = :domain_uuid or m.domain_uuid is null) "; + $sql .= "order by m.domain_uuid desc, music_on_hold_name asc, music_on_hold_rate asc "; + $parameters['domain_uuid'] = $this->domain_uuid; + return $this->database->select($sql, $parameters, 'all'); + } + + /** + * Reloads the module and establishes a connection to the Event Socket. + */ + public function reload() { + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //if the handle does not exist create it + $esl = event_socket::create(); + + //if the handle still does not exist show an error message + if (!$esl->is_connected()) { + $msg = "
    " . $text['message-event-socket'] . "
    "; } - public function reload() { + //send the api command to check if the module exists + if ($esl->is_connected()) { + $cmd = "reload mod_local_stream"; + $switch_result = event_socket::api($cmd); + unset($cmd); + } + } + + /** + * Saves the music on hold configuration. + * + * This method retrieves the contents of the template, replaces variables, + * and writes the updated XML config file to disk. The XML is then reloaded. + */ + public function save() { + //get the contents of the template + if (file_exists('/usr/share/examples/fusionpbx')) { + $file_contents = file_get_contents("/usr/share/examples/fusionpbx/resources/templates/conf/autoload_configs/local_stream.conf.xml"); + } else { + $file_contents = file_get_contents($_SERVER["PROJECT_ROOT"] . "/app/switch/resources/conf/autoload_configs/local_stream.conf.xml"); + } + //check where the default music is stored + $default_moh_prefix = 'music/default'; + if (file_exists($this->settings->get('switch', 'sounds') . '/music/8000')) { + $default_moh_prefix = 'music'; + } + //replace the variables + $file_contents = preg_replace("/music\/default/", $default_moh_prefix, $file_contents); + $file_contents = preg_replace("/[\t ]*(?:)?/", $this->xml, $file_contents); + + //write the XML config file + $fout = fopen($this->settings->get('switch', 'conf') . "/autoload_configs/local_stream.conf.xml", "w"); + fwrite($fout, $file_contents); + fclose($fout); + + //reload the XML + $this->reload(); + } + + /** + * Imports music on hold records. + * + * Retrieves domain and music on hold data, builds an array of sound files, + * and saves the data to the database. + */ + public function import() { + //get the domains + $sql = "select * from v_domains "; + $domains = $this->database->select($sql, null, 'all'); + unset($sql); + + //get the music_on_hold array + $sql = "select * from v_music_on_hold "; + $sql .= "order by domain_uuid desc, music_on_hold_name asc, music_on_hold_rate asc"; + $music_on_hold = $this->database->select($sql, null, 'all'); + unset($sql); + + //build an array of the sound files + $music_directory = $this->settings->get('switch', 'sounds') . '/music'; + if (file_exists($music_directory)) { + $files = array_merge(glob($music_directory . '/*/*/*.wav'), glob($music_directory . '/*/*/*/*.wav')); + } + + //build a new file array + foreach ($files as $file) { + $path = substr($file, strlen($music_directory . '/')); + $path = str_replace("\\", "/", $path); + $path_array = explode("/", $path); + $file_array[$path_array[0]][$path_array[1]][$path_array[2]] = dirname($file); + //echo "domain_name ".$path_array[0]."
    \n"; + //echo "category_name ".$path_array[1]."
    \n"; + } + //view_array($file_array); + + //prepare the data + $i = 0; + foreach ($file_array as $domain_name => $a1) { + foreach ($a1 as $category_name => $a2) { + foreach ($a2 as $sample_rate => $file_path) { + //echo "domain_name ".$domain_name."
    \n"; + //echo "category_name ".$category_name."
    \n"; + foreach ($domains as $field) { + if ($field['domain_name'] === $domain_name) { + $domain_uuid = $field['domain_uuid']; + //echo "domain_uuid ".$domain_uuid."
    \n"; + } + } + + if ($domain_name == 'global' || $domain_name == 'default') { + $domain_uuid = null; + } + + $array['music_on_hold'][$i]['music_on_hold_uuid'] = uuid(); + $array['music_on_hold'][$i]['domain_uuid'] = $domain_uuid; + $array['music_on_hold'][$i]['music_on_hold_name'] = $category_name; + $array['music_on_hold'][$i]['music_on_hold_path'] = $file_path; + $array['music_on_hold'][$i]['music_on_hold_rate'] = strlen($sample_rate) != 0 ? $sample_rate : null; + $array['music_on_hold'][$i]['music_on_hold_shuffle'] = 'false'; + $array['music_on_hold'][$i]['music_on_hold_channels'] = 1; + $array['music_on_hold'][$i]['music_on_hold_interval'] = 20; + $array['music_on_hold'][$i]['music_on_hold_timer_name'] = 'soft'; + $array['music_on_hold'][$i]['music_on_hold_chime_list'] = null; + $array['music_on_hold'][$i]['music_on_hold_chime_freq'] = null; + $array['music_on_hold'][$i]['music_on_hold_chime_max'] = null; + $i++; + } + } + } + //view_array($array, false); + + //save the data + $p = permissions::new(); + $p->add('music_on_hold_add', 'temp'); + + $this->database->app_name = 'music_on_hold'; + $this->database->app_uuid = '1dafe0f8-c08a-289b-0312-15baf4f20f81'; + $this->database->save($array); + //echo $this->database->message; + unset($array); + + $p->delete('music_on_hold_add', 'temp'); + } + + /** + * Deletes one or more records/files. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { + //add multi-lingual support - $language = new text; - $text = $language->get(); + $language = new text; + $text = $language->get(); - //if the handle does not exist create it - $esl = event_socket::create(); + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } - //if the handle still does not exist show an error message - if (!$esl->is_connected()) { - $msg = "
    ".$text['message-event-socket']."
    "; - } + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { - //send the api command to check if the module exists - if ($esl->is_connected()) { - $cmd = "reload mod_local_stream"; - $switch_result = event_socket::api($cmd); - unset($cmd); - } - } - - public function save() { - //get the contents of the template - if (file_exists('/usr/share/examples/fusionpbx')) { - $file_contents = file_get_contents("/usr/share/examples/fusionpbx/resources/templates/conf/autoload_configs/local_stream.conf.xml"); - } - else { - $file_contents = file_get_contents($_SERVER["PROJECT_ROOT"]."/app/switch/resources/conf/autoload_configs/local_stream.conf.xml"); - } - //check where the default music is stored - $default_moh_prefix = 'music/default'; - if(file_exists($this->settings->get('switch', 'sounds').'/music/8000')) { - $default_moh_prefix = 'music'; - } - //replace the variables - $file_contents = preg_replace("/music\/default/", $default_moh_prefix, $file_contents); - $file_contents = preg_replace("/[\t ]*(?:)?/", $this->xml, $file_contents); - - //write the XML config file - $fout = fopen($this->settings->get('switch', 'conf')."/autoload_configs/local_stream.conf.xml","w"); - fwrite($fout, $file_contents); - fclose($fout); - - //reload the XML - $this->reload(); - } - - /** - * read the music files to add the music on hold into the database - */ - public function import() { - //get the domains - $sql = "select * from v_domains "; - $domains = $this->database->select($sql, null, 'all'); - unset($sql); - - //get the music_on_hold array - $sql = "select * from v_music_on_hold "; - $sql .= "order by domain_uuid desc, music_on_hold_name asc, music_on_hold_rate asc"; - $music_on_hold = $this->database->select($sql, null, 'all'); - unset($sql); - - //build an array of the sound files - $music_directory = $this->settings->get('switch', 'sounds').'/music'; - if (file_exists($music_directory)) { - $files = array_merge(glob($music_directory.'/*/*/*.wav'), glob($music_directory.'/*/*/*/*.wav')); - } - - //build a new file array - foreach($files as $file) { - $path = substr($file, strlen($music_directory.'/')); - $path = str_replace("\\", "/", $path); - $path_array = explode("/", $path); - $file_array[$path_array[0]][$path_array[1]][$path_array[2]] = dirname($file); - //echo "domain_name ".$path_array[0]."
    \n"; - //echo "category_name ".$path_array[1]."
    \n"; - } - //view_array($file_array); - - //prepare the data - $i = 0; - foreach($file_array as $domain_name => $a1) { - foreach($a1 as $category_name => $a2) { - foreach($a2 as $sample_rate => $file_path) { - //echo "domain_name ".$domain_name."
    \n"; - //echo "category_name ".$category_name."
    \n"; - foreach($domains as $field) { - if ($field['domain_name'] === $domain_name) { - $domain_uuid = $field['domain_uuid']; - //echo "domain_uuid ".$domain_uuid."
    \n"; - } + //filter checked records + foreach ($records as $music_on_hold_uuid => $record) { + if (is_uuid($music_on_hold_uuid)) { + if ($record['checked'] == 'true') { + $moh[$music_on_hold_uuid]['delete'] = true; + } + foreach ($record as $key => $array) { + if (is_numeric($key) && is_array($array) && @sizeof($array) != 0 && !empty($array['checked']) && $array['checked'] == 'true') { + $moh[$music_on_hold_uuid][] = $array['file_name']; } - - if ($domain_name == 'global' || $domain_name == 'default') { - $domain_uuid = null; - } - - $array['music_on_hold'][$i]['music_on_hold_uuid'] = uuid(); - $array['music_on_hold'][$i]['domain_uuid'] = $domain_uuid; - $array['music_on_hold'][$i]['music_on_hold_name'] = $category_name; - $array['music_on_hold'][$i]['music_on_hold_path'] = $file_path; - $array['music_on_hold'][$i]['music_on_hold_rate'] = strlen($sample_rate) != 0 ? $sample_rate : null; - $array['music_on_hold'][$i]['music_on_hold_shuffle'] = 'false'; - $array['music_on_hold'][$i]['music_on_hold_channels'] = 1; - $array['music_on_hold'][$i]['music_on_hold_interval'] = 20; - $array['music_on_hold'][$i]['music_on_hold_timer_name'] = 'soft'; - $array['music_on_hold'][$i]['music_on_hold_chime_list'] = null; - $array['music_on_hold'][$i]['music_on_hold_chime_freq'] = null; - $array['music_on_hold'][$i]['music_on_hold_chime_max'] = null; - $i++; } } } - //view_array($array, false); - - //save the data - $p = permissions::new(); - $p->add('music_on_hold_add', 'temp'); - - $this->database->app_name = 'music_on_hold'; - $this->database->app_uuid = '1dafe0f8-c08a-289b-0312-15baf4f20f81'; - $this->database->save($array); - //echo $this->database->message; unset($array); - $p->delete('music_on_hold_add', 'temp'); - } + //loop checked records + $files_deleted = 0; + if (is_array($moh) && @sizeof($moh) != 0) { - /** - * delete records/files - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; + //get music on hold details + $sql = "select * from v_music_on_hold "; + $sql .= "where (domain_uuid = :domain_uuid " . (!permission_exists('music_on_hold_domain') ? "" : "or domain_uuid is null ") . ") "; + $sql .= "and music_on_hold_uuid in ('" . implode("','", array_keys($moh)) . "') "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $streams[$row['music_on_hold_uuid']] = $row; + } } + unset($sql, $parameters, $rows, $row); - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { + //delete files, folders, build delete array + $x = 0; + foreach ($moh as $music_on_hold_uuid => $row) { - //filter checked records - foreach ($records as $music_on_hold_uuid => $record) { - if (is_uuid($music_on_hold_uuid)) { - if ($record['checked'] == 'true') { - $moh[$music_on_hold_uuid]['delete'] = true; - } - foreach ($record as $key => $array) { - if (is_numeric($key) && is_array($array) && @sizeof($array) != 0 && !empty($array['checked']) && $array['checked'] == 'true') { - $moh[$music_on_hold_uuid][] = $array['file_name']; - } - } + //prepare path + $stream_path = $streams[$music_on_hold_uuid]['music_on_hold_path']; + $stream_path = str_replace('$${sounds_dir}', $this->settings->get('switch', 'sounds'), $stream_path); + + //delete checked files + foreach ($row as $key => $stream_file) { + if (is_numeric($key)) { + $stream_file_path = str_replace('../', '', path_join($stream_path, $stream_file)); + if (@unlink($stream_file_path)) { + $files_deleted++; } } - unset($array); + } - //loop checked records - $files_deleted = 0; - if (is_array($moh) && @sizeof($moh) != 0) { - - //get music on hold details - $sql = "select * from v_music_on_hold "; - $sql .= "where (domain_uuid = :domain_uuid ".(!permission_exists('music_on_hold_domain') ? "": "or domain_uuid is null ").") "; - $sql .= "and music_on_hold_uuid in ('".implode("','", array_keys($moh))."') "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $streams[$row['music_on_hold_uuid']] = $row; - } - } - unset($sql, $parameters, $rows, $row); - - //delete files, folders, build delete array - $x = 0; - foreach ($moh as $music_on_hold_uuid => $row) { - - //prepare path - $stream_path = $streams[$music_on_hold_uuid]['music_on_hold_path']; - $stream_path = str_replace('$${sounds_dir}', $this->settings->get('switch', 'sounds'), $stream_path); - - //delete checked files - foreach ($row as $key => $stream_file) { - if (is_numeric($key)) { - $stream_file_path = str_replace('../', '', path_join($stream_path, $stream_file)); - if (@unlink($stream_file_path)) { - $files_deleted++; - } - } - } - - //delete name rate - if (!empty($row['delete']) && $row['delete'] == true) { - - //build delete array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $music_on_hold_uuid; - if (!permission_exists('music_on_hold_domain')) { - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - } - $x++; - - //delete rate folder - @rmdir($stream_path); - - //delete name (category) folder, if empty - $name_path = dirname($stream_path); - if (@sizeof(scandir($name_path)) == 2) { //empty (only /.. and /. remaining) - @rmdir($name_path); - } - } - - } + //delete name rate + if (!empty($row['delete']) && $row['delete'] == true) { + //build delete array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $music_on_hold_uuid; + if (!permission_exists('music_on_hold_domain')) { + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; } + $x++; - //delete the moh records - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - - //execute delete - $this->database->delete($array); - unset($array); - - //set flag - $moh_deleted = true; + //delete rate folder + @rmdir($stream_path); + //delete name (category) folder, if empty + $name_path = dirname($stream_path); + if (@sizeof(scandir($name_path)) == 2) { //empty (only /.. and /. remaining) + @rmdir($name_path); } - unset($records, $moh); - - //post delete - if ((!empty($moh_deleted) && $moh_deleted == true) || $files_deleted != 0) { - //clear the cache - $cache = new cache; - $cache->delete("configuration:local_stream.conf"); - - //reload moh - $this->reload(); - - //set message - message::add($text['message-delete']); - } + } } + } + + //delete the moh records + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + + //execute delete + $this->database->delete($array); + unset($array); + + //set flag + $moh_deleted = true; + + } + unset($records, $moh); + + //post delete + if ((!empty($moh_deleted) && $moh_deleted == true) || $files_deleted != 0) { + //clear the cache + $cache = new cache; + $cache->delete("configuration:local_stream.conf"); + + //reload moh + $this->reload(); + + //set message + message::add($text['message-delete']); + } + } - } //method - } //class + } + } //method +} //class //build and save the XML - //$moh = new switch_music_on_hold; - //$moh->xml(); - //$moh->save(); +//$moh = new switch_music_on_hold; +//$moh->xml(); +//$moh->save(); diff --git a/app/number_translations/resources/classes/number_translations.php b/app/number_translations/resources/classes/number_translations.php index e545adfa79..d1ef8afc69 100644 --- a/app/number_translations/resources/classes/number_translations.php +++ b/app/number_translations/resources/classes/number_translations.php @@ -25,400 +25,434 @@ */ //define the number translations class - class number_translations { +class number_translations { - /** - * declare constant variables - */ - const app_name = 'number_translations'; - const app_uuid = '6ad54de6-4909-11e7-a919-92ebcb67fe33'; + /** + * declare constant variables + */ + const app_name = 'number_translations'; + const app_uuid = '6ad54de6-4909-11e7-a919-92ebcb67fe33'; - /** - * declare public variables - */ - public $number_translation_uuid; + /** + * declare public variables + */ + public $number_translation_uuid; - /** - * declare private variables - */ - private $database; - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; - private $json; - private $xml; - private $display_type; + /** + * declare private variables + */ + private $database; + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; + private $json; + private $xml; + private $display_type; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set objects + $this->database = $setting_array['database'] ?? database::new(); - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set objects - $this->database = $setting_array['database'] ?? database::new(); + //assign private variables + $this->permission_prefix = 'number_translation_'; + $this->list_page = 'number_translations.php'; + $this->table = 'number_translations'; + $this->uuid_prefix = 'number_translation_'; + $this->toggle_field = 'number_translation_enabled'; + $this->toggle_values = ['true', 'false']; + } - //assign private variables - $this->permission_prefix = 'number_translation_'; - $this->list_page = 'number_translations.php'; - $this->table = 'number_translations'; - $this->uuid_prefix = 'number_translation_'; - $this->toggle_field = 'number_translation_enabled'; - $this->toggle_values = ['true','false']; + /** + * Checks if a given name exists as a number translation. + * + * @param string $name The name to check for existence. + * + * @return bool True if the number translation exists, false otherwise. + */ + public function number_translation_exists($name) { + $sql = "select count(*) from v_number_translations "; + $sql .= "where number_translation_name = :number_translation_name "; + $parameters['number_translation_name'] = $name; + return $this->database->select($sql, $parameters, 'column') != 0 ? true : false; + } + + /** + * Imports a number translation from either XML or JSON format. + * + * @return void + */ + public function import() { + //get the xml from the number templates + if (!empty($this->xml)) { + //convert the xml string to an xml object + $xml = simplexml_load_string($this->xml); + //convert to json + $json = json_encode($xml); + //convert to an array + $number_translation = json_decode($json, true); + } elseif (!empty($this->json)) { + //convert to an array + $number_translation = json_decode($this->json, true); + } else { + throw new Exception("require either json or xml to import"); } - - /** - * Check to see if the number translation already exists - */ - public function number_translation_exists($name) { - $sql = "select count(*) from v_number_translations "; - $sql .= "where number_translation_name = :number_translation_name "; - $parameters['number_translation_name'] = $name; - return $this->database->select($sql, $parameters, 'column') != 0 ? true : false; + //check if the number_translation exists + if (!$this->number_translation_exists($number_translation['@attributes']['name'])) { + //begin insert array + $x = 0; + $array['number_translations'][$x]['number_translation_name'] = $number_translation['@attributes']['name']; + $array['number_translations'][$x]['number_translation_enabled'] = "true"; + if (!empty($number_translation['@attributes']['enabled'])) { + $array['number_translations'][$x]['number_translation_enabled'] = $number_translation['@attributes']['enabled']; + } + $array['number_translations'][$x]['number_translation_description'] = $number_translation['@attributes']['description']; + //loop through the condition array + $order = 5; + if (isset($number_translation['rule'])) { + foreach ($number_translation['rule'] as $row) { + if (array_key_exists('@attributes', $row)) { + $row = $row['@attributes']; + } + $array['number_translations'][$x]['number_translation_details'][$order]['number_translation_detail_regex'] = $row['regex']; + $array['number_translations'][$x]['number_translation_details'][$order]['number_translation_detail_replace'] = $row['replace']; + $array['number_translations'][$x]['number_translation_details'][$order]['number_translation_detail_order'] = $order; + $order = $order + 5; + } + } + //grant temporary permissions + $p = permissions::new(); + $p->add('number_translation_add', 'temp'); + $p->add('number_translation_detail_add', 'temp'); + //execute insert + $this->database->app_name = 'number_translations'; + $this->database->app_uuid = '6ad54de6-4909-11e7-a919-92ebcb67fe33'; + $this->database->save($array); + unset($array); + if (!empty($this->display_type) && $this->display_type == "text") { + if ($this->database->message['code'] != '200') { + echo "number_translation:" . $number_translation['@attributes']['name'] . ": failed: " . $this->database->message['message'] . "\n"; + } else { + echo "number_translation:" . $number_translation['@attributes']['name'] . ": added with " . (($order / 5) - 1) . " entries\n"; + } + } + //revoke temporary permissions + $p->delete('number_translation_add', 'temp'); + $p->delete('number_translation_detail_add', 'temp'); } + unset ($this->xml, $this->json); + } - /** - * Import the number translation rules from the resources directory - */ - public function import() { - //get the xml from the number templates - if (!empty($this->xml)) { - //convert the xml string to an xml object - $xml = simplexml_load_string($this->xml); - //convert to json - $json = json_encode($xml); - //convert to an array - $number_translation = json_decode($json, true); + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array['number_translation_details'][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + } } - else if (!empty($this->json)) { - //convert to an array - $number_translation = json_decode($this->json, true); - } - else { - throw new Exception("require either json or xml to import"); - } - //check if the number_translation exists - if (!$this->number_translation_exists($number_translation['@attributes']['name'])) { - //begin insert array - $x = 0; - $array['number_translations'][$x]['number_translation_name'] = $number_translation['@attributes']['name']; - $array['number_translations'][$x]['number_translation_enabled'] = "true"; - if (!empty($number_translation['@attributes']['enabled'])) { - $array['number_translations'][$x]['number_translation_enabled'] = $number_translation['@attributes']['enabled']; - } - $array['number_translations'][$x]['number_translation_description'] = $number_translation['@attributes']['description']; - //loop through the condition array - $order = 5; - if (isset($number_translation['rule'])) { - foreach ($number_translation['rule'] as $row) { - if (array_key_exists('@attributes', $row)) { - $row = $row['@attributes']; - } - $array['number_translations'][$x]['number_translation_details'][$order]['number_translation_detail_regex'] = $row['regex']; - $array['number_translations'][$x]['number_translation_details'][$order]['number_translation_detail_replace'] = $row['replace']; - $array['number_translations'][$x]['number_translation_details'][$order]['number_translation_detail_order'] = $order; - $order = $order + 5; - } - } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //grant temporary permissions - $p = permissions::new(); - $p->add('number_translation_add', 'temp'); - $p->add('number_translation_detail_add', 'temp'); - //execute insert - $this->database->app_name = 'number_translations'; - $this->database->app_uuid = '6ad54de6-4909-11e7-a919-92ebcb67fe33'; - $this->database->save($array); - unset($array); - if (!empty($this->display_type) && $this->display_type == "text") { - if ($this->database->message['code'] != '200') { - echo "number_translation:".$number_translation['@attributes']['name'].": failed: ".$this->database->message['message']."\n"; - } - else { - echo "number_translation:".$number_translation['@attributes']['name'].": added with ".(($order/5)-1)." entries\n"; - } - } + $p = permissions::new(); + $p->add('number_translation_detail_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + //revoke temporary permissions - $p->delete('number_translation_add', 'temp'); - $p->delete('number_translation_detail_add', 'temp'); + $p->delete('number_translation_detail_delete', 'temp'); + + //set message + message::add($text['message-delete']); } - unset ($this->xml, $this->json); - } - - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //build the delete array - foreach ($records as $x => $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array['number_translation_details'][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('number_translation_detail_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('number_translation_detail_delete', 'temp'); - - //set message - message::add($text['message-delete']); - } - unset($records); - } + unset($records); } } + } - public function delete_details($records) { + /** + * Deletes multiple records from the number_translation_details table. + * + * @param array $records An array of records to be deleted, where each record is an associative array containing 'checked' and 'uuid' keys. + * The 'checked' key should contain a boolean value indicating whether the record should be deleted, + * while the 'uuid' key contains the unique identifier of the record. + * + * @return void + */ + public function delete_details($records) { - //assign private variables - $this->permission_prefix = 'number_translation_detail_'; - $this->table = 'number_translation_details'; - $this->uuid_prefix = 'number_translation_detail_'; + //assign private variables + $this->permission_prefix = 'number_translation_detail_'; + $this->table = 'number_translation_details'; + $this->uuid_prefix = 'number_translation_detail_'; - if (permission_exists($this->permission_prefix.'delete')) { + if (permission_exists($this->permission_prefix . 'delete')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['number_translation_uuid'] = $this->number_translation_uuid; } + } - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { - //build the delete array - foreach ($records as $x => $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['number_translation_uuid'] = $this->number_translation_uuid; - } - } + //execute delete + $this->database->delete($array); + unset($array); - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //execute delete - $this->database->delete($array); - unset($array); - - } - unset($records); - } + } + unset($records); } } + } - /** - * toggle records - */ - public function toggle($records) { - if (permission_exists($this->permission_prefix.'edit')) { + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->permission_prefix . 'edit')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach($records as $x => $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($states as $uuid => $state) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } + //add multi-lingual support + $language = new text; + $text = $language->get(); + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; } - } - /** - * copy records - */ - public function copy($records) { - if (permission_exists($this->permission_prefix.'add')) { + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; + //get current toggle state + foreach ($records as $x => $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } - //get checked records - foreach($records as $x => $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->permission_prefix . 'add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $x => $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create insert array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + + //primary table + $sql = "select * from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $y = 0; + foreach ($rows as $x => $row) { + $primary_uuid = uuid(); + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; } } - //create insert array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { + //copy data + $array[$this->table][$x] = $row; - //primary table - $sql = "select * from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $y = 0; - foreach ($rows as $x => $row) { - $primary_uuid = uuid(); + //overwrite + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $primary_uuid; + $array[$this->table][$x]['number_translation_description'] = trim($row['number_translation_description'] . ' (' . $text['label-copy'] . ')'); - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $primary_uuid; - $array[$this->table][$x]['number_translation_description'] = trim($row['number_translation_description'].' ('.$text['label-copy'].')'); - - //nodes sub table - $sql_2 = "select * from v_number_translation_details where number_translation_uuid = :number_translation_uuid"; - $parameters_2['number_translation_uuid'] = $row['number_translation_uuid']; - $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); - if (is_array($rows_2) && @sizeof($rows_2) != 0) { - foreach ($rows_2 as $row_2) { - //convert boolean values to a string - foreach($row_2 as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row_2[$key] = $value; - } - } - - //copy data - $array['number_translation_details'][$y] = $row_2; - - //overwrite - $array['number_translation_details'][$y]['number_translation_detail_uuid'] = uuid(); - $array['number_translation_details'][$y]['number_translation_uuid'] = $primary_uuid; - - //increment - $y++; - - } - } - unset($sql_2, $parameters_2, $rows_2, $row_2); + //nodes sub table + $sql_2 = "select * from v_number_translation_details where number_translation_uuid = :number_translation_uuid"; + $parameters_2['number_translation_uuid'] = $row['number_translation_uuid']; + $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); + if (is_array($rows_2) && @sizeof($rows_2) != 0) { + foreach ($rows_2 as $row_2) { + //convert boolean values to a string + foreach ($row_2 as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row_2[$key] = $value; } } - unset($sql, $parameters, $rows, $row); + + //copy data + $array['number_translation_details'][$y] = $row_2; + + //overwrite + $array['number_translation_details'][$y]['number_translation_detail_uuid'] = uuid(); + $array['number_translation_details'][$y]['number_translation_uuid'] = $primary_uuid; + + //increment + $y++; + + } } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('number_translation_detail_add', 'temp'); - - //save the array - - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('number_translation_detail_add', 'temp'); - - //set message - message::add($text['message-copy']); - - } - unset($records); + unset($sql_2, $parameters_2, $rows_2, $row_2); + } } + unset($sql, $parameters, $rows, $row); + } + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('number_translation_detail_add', 'temp'); + + //save the array + + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('number_translation_detail_add', 'temp'); + + //set message + message::add($text['message-copy']); + + } + unset($records); } - } //method - } //class + } + } //method + +} //class /* $obj = new number_translations; diff --git a/app/phrases/resources/classes/phrases.php b/app/phrases/resources/classes/phrases.php index fad286a666..5f4f4e3c8d 100644 --- a/app/phrases/resources/classes/phrases.php +++ b/app/phrases/resources/classes/phrases.php @@ -25,427 +25,462 @@ */ //define the phrases class - class phrases { +class phrases { - /** - * declare constant variables - */ - const app_name = 'phrases'; - const app_uuid = '5c6f597c-9b78-11e4-89d3-123b93f75cba'; + /** + * declare constant variables + */ + const app_name = 'phrases'; + const app_uuid = '5c6f597c-9b78-11e4-89d3-123b93f75cba'; - /** - * declare public variables - */ - public $phrase_uuid; + /** + * declare public variables + */ + public $phrase_uuid; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); + //set objects + $this->database = $setting_array['database'] ?? database::new(); - //assign private variables - $this->permission_prefix = 'phrase_'; - $this->list_page = 'phrases.php'; - $this->table = 'phrases'; - $this->uuid_prefix = 'phrase_'; - $this->toggle_field = 'phrase_enabled'; - $this->toggle_values = ['true','false']; - } + //assign private variables + $this->permission_prefix = 'phrase_'; + $this->list_page = 'phrases.php'; + $this->table = 'phrases'; + $this->uuid_prefix = 'phrase_'; + $this->toggle_field = 'phrase_enabled'; + $this->toggle_values = ['true', 'false']; + } - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked phrases, build where clause for below + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //get phrase languages + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, phrase_language as lang from v_" . $this->table . " "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $phrase_languages[$row['uuid']] = $row['lang']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build the delete array + if (is_array($phrase_languages) && @sizeof($phrase_languages) != 0) { + $x = 0; + foreach ($phrase_languages as $phrase_uuid => $phrase_language) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $phrase_uuid; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + $array['phrase_details'][$x][$this->uuid_prefix . 'uuid'] = $phrase_uuid; + $array['phrase_details'][$x]['domain_uuid'] = $this->domain_uuid; + $x++; + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('phrase_detail_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('phrase_detail_delete', 'temp'); + + //clear the cache + $phrase_languages = array_unique($phrase_languages); + $cache = new cache; + foreach ($phrase_languages as $phrase_language) { + $cache->delete("languages:" . $phrase_language); } - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked phrases, build where clause for below - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //get phrase languages - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, phrase_language as lang from v_".$this->table." "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $phrase_languages[$row['uuid']] = $row['lang']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build the delete array - if (is_array($phrase_languages) && @sizeof($phrase_languages) != 0) { - $x = 0; - foreach ($phrase_languages as $phrase_uuid => $phrase_language) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $phrase_uuid; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - $array['phrase_details'][$x][$this->uuid_prefix.'uuid'] = $phrase_uuid; - $array['phrase_details'][$x]['domain_uuid'] = $this->domain_uuid; - $x++; - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('phrase_detail_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('phrase_detail_delete', 'temp'); - - //clear the cache - $phrase_languages = array_unique($phrase_languages); - $cache = new cache; - foreach ($phrase_languages as $phrase_language) { - $cache->delete("languages:".$phrase_language); - } - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-delete']); - } - unset($records, $phrase_languages); + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); } + + //set message + message::add($text['message-delete']); + } + unset($records, $phrase_languages); } } + } - public function delete_details($records) { - //assign private variables - $this->permission_prefix = 'phrase_'; - $this->list_page = 'phrase_edit.php?id='.$this->phrase_uuid; - $this->table = 'phrase_details'; - $this->uuid_prefix = 'phrase_detail_'; + /** + * Delete multiple details records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array containing + * the 'uuid' and optionally a 'checked' field. The 'checked' field should be set to true if the record + * should be deleted. + * + * @return void + */ + public function delete_details($records) { + //assign private variables + $this->permission_prefix = 'phrase_'; + $this->list_page = 'phrase_edit.php?id=' . $this->phrase_uuid; + $this->table = 'phrase_details'; + $this->uuid_prefix = 'phrase_detail_'; - if (permission_exists($this->permission_prefix.'edit')) { + if (permission_exists($this->permission_prefix . 'edit')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked phrases, build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['phrase_uuid'] = $this->phrase_uuid; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + } + } + + //get phrase languages + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + $sql = "select phrase_language as lang from v_phrases "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and phrase_uuid = :phrase_uuid "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['phrase_uuid'] = $this->phrase_uuid; + $phrase_language = $this->database->select($sql, $parameters, 'column'); + unset($sql, $parameters, $rows, $row); + } + + //delete the checked rows + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('phrase_detail_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('phrase_detail_delete', 'temp'); + + //clear the cache + if ($phrase_language != '') { + $cache = new cache; + $cache->delete("languages:" . $phrase_language); } - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked phrases, build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['phrase_uuid'] = $this->phrase_uuid; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - } - } - - //get phrase languages - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - $sql = "select phrase_language as lang from v_phrases "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and phrase_uuid = :phrase_uuid "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['phrase_uuid'] = $this->phrase_uuid; - $phrase_language = $this->database->select($sql, $parameters, 'column'); - unset($sql, $parameters, $rows, $row); - } - - //delete the checked rows - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('phrase_detail_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('phrase_detail_delete', 'temp'); - - //clear the cache - if ($phrase_language != '') { - $cache = new cache; - $cache->delete("languages:".$phrase_language); - } - - } - unset($records, $phrase_language); - } + } + unset($records, $phrase_language); } } + } - /** - * toggle records - */ - public function toggle($records) { - if (permission_exists($this->permission_prefix.'edit')) { + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->permission_prefix . 'edit')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get current toggle state and language + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle, phrase_language as lang from v_" . $this->table . " "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + $phrase_languages[] = $row['lang']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //clear the cache + if (!empty($phrase_languages) && is_array($phrase_languages) && @sizeof($phrase_languages) != 0) { + $phrase_languages = array_unique($phrase_languages); + $cache = new cache; + foreach ($phrase_languages as $phrase_language) { + $cache->delete("languages:" . $phrase_language); + } } - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } - //get current toggle state and language - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->permission_prefix . 'add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create insert array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + + //primary table + $sql = "select * from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $y = 0; + foreach ($rows as $x => $row) { + $primary_uuid = uuid(); + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; } } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle, phrase_language as lang from v_".$this->table." "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - $phrase_languages[] = $row['lang']; - } - } - unset($sql, $parameters, $rows, $row); - } - //build update array - $x = 0; - foreach($states as $uuid => $state) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } + //copy data + $array[$this->table][$x] = $row; - //save the changes - if (is_array($array) && @sizeof($array) != 0) { + //overwrite + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $primary_uuid; + $array[$this->table][$x]['phrase_description'] = trim($row['phrase_description'] . ' (' . $text['label-copy'] . ')'); - //save the array + //details sub table + $sql_2 = "select * from v_phrase_details where phrase_uuid = :phrase_uuid"; + $parameters_2['phrase_uuid'] = $row['phrase_uuid']; + $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); + if (is_array($rows_2) && @sizeof($rows_2) != 0) { + foreach ($rows_2 as $row_2) { - $this->database->save($array); - unset($array); - - //clear the cache - if (!empty($phrase_languages) && is_array($phrase_languages) && @sizeof($phrase_languages) != 0) { - $phrase_languages = array_unique($phrase_languages); - $cache = new cache; - foreach ($phrase_languages as $phrase_language) { - $cache->delete("languages:".$phrase_language); + //convert boolean values to a string + foreach ($row_2 as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row_2[$key] = $value; } } - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } + //copy data + $array['phrase_details'][$y] = $row_2; - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } + //overwrite + $array['phrase_details'][$y]['phrase_detail_uuid'] = uuid(); + $array['phrase_details'][$y]['phrase_uuid'] = $primary_uuid; - } - } + //increment + $y++; - /** - * copy records - */ - public function copy($records) { - if (permission_exists($this->permission_prefix.'add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; } } + unset($sql_2, $parameters_2, $rows_2, $row_2); - //create insert array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - - //primary table - $sql = "select * from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $y = 0; - foreach ($rows as $x => $row) { - $primary_uuid = uuid(); - - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $primary_uuid; - $array[$this->table][$x]['phrase_description'] = trim($row['phrase_description'].' ('.$text['label-copy'].')'); - - //details sub table - $sql_2 = "select * from v_phrase_details where phrase_uuid = :phrase_uuid"; - $parameters_2['phrase_uuid'] = $row['phrase_uuid']; - $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); - if (is_array($rows_2) && @sizeof($rows_2) != 0) { - foreach ($rows_2 as $row_2) { - - //convert boolean values to a string - foreach($row_2 as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row_2[$key] = $value; - } - } - - //copy data - $array['phrase_details'][$y] = $row_2; - - //overwrite - $array['phrase_details'][$y]['phrase_detail_uuid'] = uuid(); - $array['phrase_details'][$y]['phrase_uuid'] = $primary_uuid; - - //increment - $y++; - - } - } - unset($sql_2, $parameters_2, $rows_2, $row_2); - - //create array of languages - if (!empty($row['phrase_languages'])) { - $phrase_languages[] = $row['phrase_languages']; - } - } - } - unset($sql, $parameters, $rows, $row); + //create array of languages + if (!empty($row['phrase_languages'])) { + $phrase_languages[] = $row['phrase_languages']; } + } + } + unset($sql, $parameters, $rows, $row); + } - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { - //grant temporary permissions - $p = permissions::new(); - $p->add('phrase_detail_add', 'temp'); + //grant temporary permissions + $p = permissions::new(); + $p->add('phrase_detail_add', 'temp'); - //save the array + //save the array - $this->database->save($array); - unset($array); + $this->database->save($array); + unset($array); - //revoke temporary permissions - $p->delete('phrase_detail_add', 'temp'); + //revoke temporary permissions + $p->delete('phrase_detail_add', 'temp'); - //clear the cache - if (!empty($phrase_languages) && is_array($phrase_languages) && @sizeof($phrase_languages) != 0) { - $phrase_languages = array_unique($phrase_languages); - $cache = new cache; - foreach ($phrase_languages as $phrase_language) { - $cache->delete("languages:".$phrase_language); - } - } - - //set message - message::add($text['message-copy']); - - } - unset($records); + //clear the cache + if (!empty($phrase_languages) && is_array($phrase_languages) && @sizeof($phrase_languages) != 0) { + $phrase_languages = array_unique($phrase_languages); + $cache = new cache; + foreach ($phrase_languages as $phrase_language) { + $cache->delete("languages:" . $phrase_language); + } } - } - } //method + //set message + message::add($text['message-copy']); - } //class + } + unset($records); + } + + } + } //method + +} //class diff --git a/app/pin_numbers/pin_download.php b/app/pin_numbers/pin_download.php index 91e90efe8a..aff105d96e 100644 --- a/app/pin_numbers/pin_download.php +++ b/app/pin_numbers/pin_download.php @@ -51,6 +51,13 @@ $available_columns[] = 'description'; //define the functions + /** + * Converts a multi-dimensional PHP array into a CSV string. + * + * @param array &$array The input data to be converted. It is expected to have at least one row and one column. + * + * @return string|null The CSV representation of the input data, or null if the input array is empty. + */ function array2csv(array &$array) { if (count($array) == 0) { return null; @@ -65,6 +72,13 @@ return ob_get_clean(); } + /** + * Sends HTTP headers for a file download. + * + * @param string $filename The name of the file to be downloaded. + * + * @return void + */ function download_send_headers($filename) { // disable caching $now = gmdate("D, d M Y H:i:s"); diff --git a/app/pin_numbers/resources/classes/pin_numbers.php b/app/pin_numbers/resources/classes/pin_numbers.php index 1a74e65438..9855e358f0 100644 --- a/app/pin_numbers/resources/classes/pin_numbers.php +++ b/app/pin_numbers/resources/classes/pin_numbers.php @@ -25,245 +25,272 @@ */ //define the pin numbers class - class pin_numbers { +class pin_numbers { - /** - * declare constant variables - */ - const app_name = 'pin_numbers'; - const app_uuid = '4b88ccfb-cb98-40e1-a5e5-33389e14a388'; + /** + * declare constant variables + */ + const app_name = 'pin_numbers'; + const app_uuid = '4b88ccfb-cb98-40e1-a5e5-33389e14a388'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - - //assign private variables - $this->permission_prefix = 'pin_number_'; - $this->list_page = 'pin_numbers.php'; - $this->table = 'pin_numbers'; - $this->uuid_prefix = 'pin_number_'; - $this->toggle_field = 'enabled'; - $this->toggle_values = ['true','false']; - } - - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //build the delete array - foreach ($records as $x => $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * toggle records - */ - public function toggle($records) { - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach($records as $x => $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($states as $uuid => $state) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - - } - } - - /** - * copy records - */ - public function copy($records) { - if (permission_exists($this->permission_prefix.'add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach($records as $x => $record) { - if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create insert array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select * from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $x => $row) { - - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = uuid(); - $array[$this->table][$x]['description'] = trim($row['description'].' ('.$text['label-copy'].')'); - - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-copy']); - - } - unset($records); - } - - } - } + //set objects + $this->database = $setting_array['database'] ?? database::new(); + //assign private variables + $this->permission_prefix = 'pin_number_'; + $this->list_page = 'pin_numbers.php'; + $this->table = 'pin_numbers'; + $this->uuid_prefix = 'pin_number_'; + $this->toggle_field = 'enabled'; + $this->toggle_values = ['true', 'false']; } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //execute delete + $this->database->delete($array); + unset($array); + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get current toggle state + foreach ($records as $x => $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->permission_prefix . 'add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $x => $record) { + if ($record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create insert array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select * from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $x => $row) { + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; + } + } + + //copy data + $array[$this->table][$x] = $row; + + //overwrite + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = uuid(); + $array[$this->table][$x]['description'] = trim($row['description'] . ' (' . $text['label-copy'] . ')'); + + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-copy']); + + } + unset($records); + } + + } + } + +} diff --git a/app/provision/index.php b/app/provision/index.php index fd5142f391..b8091c1103 100644 --- a/app/provision/index.php +++ b/app/provision/index.php @@ -72,6 +72,13 @@ } //send http error + /** + * Displays a custom HTTP error page with the specified error code and message. + * + * @param int $error The HTTP error code (e.g., 400, 401, etc.) + * + * @return void The script exits after displaying the error page + */ function http_error($error) { //$error_int_val = intval($error); $http_errors = [ @@ -272,6 +279,13 @@ if (!empty($provision["http_auth_username"]) && empty($provision["http_auth_type"])) { $provision["http_auth_type"] = "digest"; } if (!empty($provision["http_auth_username"]) && $provision["http_auth_type"] === "digest" && !empty($provision["http_auth_enabled"]) && $provision["http_auth_enabled"]) { //function to parse the http auth header + /** + * Parses the specified HTTP Digest authentication text and extracts relevant data. + * + * @param string $txt The HTTP Digest authentication text to parse + * + * @return array|false An array of extracted data if successful, or false if data is incomplete + */ function http_digest_parse($txt) { //protect against missing data $needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1); @@ -286,6 +300,13 @@ } //function to request digest authentication + /** + * Sends an HTTP Digest authentication request with the specified realm. + * + * @param string $realm The name of the protected resource's realm + * + * @return void The script exits after sending the authentication request + */ function http_digest_request($realm) { header('HTTP/1.1 401 Authorization Required'); header('WWW-Authenticate: Digest realm="'.$realm.'", qop="auth", nonce="'.uniqid().'", opaque="'.md5($realm).'"'); @@ -447,8 +468,8 @@ $file_size = strlen($file_contents); if (isset($_SERVER['HTTP_RANGE'])) { $ranges = $_SERVER['HTTP_RANGE']; - list($unit, $range) = explode('=', $ranges, 2); - list($start, $end) = explode('-', $range, 2); + [$unit, $range] = explode('=', $ranges, 2); + [$start, $end] = explode('-', $range, 2); $start = empty($start) ? 0 : (int)$start; $end = empty($end) ? $file_size - 1 : min((int)$end, $file_size - 1); diff --git a/app/provision/resources/classes/provision.php b/app/provision/resources/classes/provision.php index 00c5009572..dce358c415 100644 --- a/app/provision/resources/classes/provision.php +++ b/app/provision/resources/classes/provision.php @@ -26,1463 +26,1576 @@ */ //define the provision class - class provision { +class provision { - /** - * declare constant variables - */ - const app_name = 'provision'; - const app_uuid = 'abf28ead-92ef-3de6-ebbb-023fbc2b6dd3'; + /** + * declare constant variables + */ + const app_name = 'provision'; + const app_uuid = 'abf28ead-92ef-3de6-ebbb-023fbc2b6dd3'; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_uuid; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_name; - /** - * declare public variables - */ - public $template_dir; - public $device_address; - public $device_template; - public $file; + /** + * declare public variables + */ + public $template_dir; + public $device_address; + public $device_template; + public $file; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); - //get the project root - $project_root = dirname(__DIR__, 4); + //get the project root + $project_root = dirname(__DIR__, 4); - //set the default template directory - if (PHP_OS == "Linux") { - //set the default template dir - if (empty($this->template_dir)) { - if (file_exists('/usr/share/fusionpbx/templates/provision')) { - $this->template_dir = '/usr/share/fusionpbx/templates/provision'; - } - elseif (file_exists('/etc/fusionpbx/resources/templates/provision')) { - $this->template_dir = '/etc/fusionpbx/resources/templates/provision'; - } - else { - $this->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/resources/templates/provision'; - } - } - } - elseif (PHP_OS == "FreeBSD") { - //if the FreeBSD port is installed use the following paths by default. - if (empty($this->template_dir)) { - if (file_exists('/usr/local/share/fusionpbx/templates/provision')) { - $this->template_dir = '/usr/local/share/fusionpbx/templates/provision'; - } - elseif (file_exists('/usr/local/etc/fusionpbx/resources/templates/provision')) { - $this->template_dir = '/usr/local/etc/fusionpbx/resources/templates/provision'; - } - else { - $this->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/resources/templates/provision'; - } - } - } - else if (PHP_OS == "NetBSD") { - //set the default template_dir - if (empty($this->template_dir)) { - $this->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/resources/templates/provision'; - } - } - else if (PHP_OS == "OpenBSD") { - //set the default template_dir - if (empty($this->template_dir)) { - $this->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/resources/templates/provision'; - } - } - else { - //set the default template_dir - if (empty($this->template_dir)) { - $this->template_dir = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/resources/templates/provision'; - } - } - - //normalize the device address - if (isset($setting_array['device_address'])) { - $this->device_address = strtolower(preg_replace('#[^a-fA-F0-9./]#', '', $setting_array['device_address'])); - } - } - - /** - * get the domain uuid - */ - public function get_domain_uuid() { - return $this->domain_uuid; - } - - //define the function which checks to see if the device address exists in devices - private function device_exists($device_address) { - //normalize the device address - $device_address = strtolower(preg_replace('#[^a-fA-F0-9./]#', '', $device_address)); - //check in the devices table for a specific device address - $sql = "select count(*) from v_devices "; - $sql .= "where device_address = :device_address "; - $sql .= "and device_address <> '000000000000' "; - $parameters['device_address'] = $device_address; - $num_rows = $this->database->select($sql, $parameters, 'column'); - if ($num_rows > 0) { - return true; + //set the default template directory + if (PHP_OS == "Linux") { + //set the default template dir + if (empty($this->template_dir)) { + if (file_exists('/usr/share/fusionpbx/templates/provision')) { + $this->template_dir = '/usr/share/fusionpbx/templates/provision'; + } elseif (file_exists('/etc/fusionpbx/resources/templates/provision')) { + $this->template_dir = '/etc/fusionpbx/resources/templates/provision'; + } else { + $this->template_dir = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/resources/templates/provision'; } - else { - return false; + } + } elseif (PHP_OS == "FreeBSD") { + //if the FreeBSD port is installed use the following paths by default. + if (empty($this->template_dir)) { + if (file_exists('/usr/local/share/fusionpbx/templates/provision')) { + $this->template_dir = '/usr/local/share/fusionpbx/templates/provision'; + } elseif (file_exists('/usr/local/etc/fusionpbx/resources/templates/provision')) { + $this->template_dir = '/usr/local/etc/fusionpbx/resources/templates/provision'; + } else { + $this->template_dir = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/resources/templates/provision'; } - unset($sql, $parameters, $num_rows); - } - - //set the device address in the correct format for the specific vendor - public function format_address($device_address, $vendor) { - switch (strtolower($vendor)) { - case "algo": - return strtoupper($device_address); - case "aastra": - return strtoupper($device_address); - case "cisco": - return strtoupper($device_address); - case "linksys": - return strtolower($device_address); - case "mitel": - return strtoupper($device_address); - case "polycom": - return strtolower($device_address); - case "snom": - return strtolower($device_address); - case "escene": - return strtolower($device_address); - case "grandstream": - return strtolower($device_address); - case "yealink": - return strtolower($device_address); - case "gigaset": - return strtoupper($device_address); - default: - return strtolower($device_address); + } + } elseif (PHP_OS == "NetBSD") { + //set the default template_dir + if (empty($this->template_dir)) { + $this->template_dir = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/resources/templates/provision'; + } + } elseif (PHP_OS == "OpenBSD") { + //set the default template_dir + if (empty($this->template_dir)) { + $this->template_dir = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/resources/templates/provision'; + } + } else { + //set the default template_dir + if (empty($this->template_dir)) { + $this->template_dir = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/resources/templates/provision'; } } - //send http error - private function http_error($error) { - if ($error === "404") { - header("HTTP/1.0 404 Not Found"); - echo "\n"; - echo "404 Not Found\n"; - echo "\n"; - echo "

    404 Not Found

    \n"; - echo "
    nginx/1.12.1
    \n"; - echo "\n"; - echo "\n"; - } - exit(); + //normalize the device address + if (isset($setting_array['device_address'])) { + $this->device_address = strtolower(preg_replace('#[^a-fA-F0-9./]#', '', $setting_array['device_address'])); } + } - //define a function to check if a contact exists in the contacts array - private function contact_exists($contacts, $uuid) { - if (is_array($contacts[$uuid])) { - return true; - } - else { - return false; - } + /** + * Retrieves the domain UUID associated with the object instance. + * + * @return string The domain UUID of the current domain. + */ + public function get_domain_uuid() { + return $this->domain_uuid; + } + + //define the function which checks to see if the device address exists in devices + + /** + * Checks if a device exists in the database. + * + * @param string $device_address The MAC address of the device to check for existence. + * + * @return bool True if the device is found in the database, false otherwise. + */ + private function device_exists($device_address) { + //normalize the device address + $device_address = strtolower(preg_replace('#[^a-fA-F0-9./]#', '', $device_address)); + //check in the devices table for a specific device address + $sql = "select count(*) from v_devices "; + $sql .= "where device_address = :device_address "; + $sql .= "and device_address <> '000000000000' "; + $parameters['device_address'] = $device_address; + $num_rows = $this->database->select($sql, $parameters, 'column'); + if ($num_rows > 0) { + return true; + } else { + return false; } + } - private function contact_append(&$contacts, &$line, $domain_uuid, $device_user_uuid, $category) { + //set the device address in the correct format for the specific vendor - $sql = "select c.contact_uuid, c.contact_organization, c.contact_name_given, c.contact_name_family, "; - $sql .= "c.contact_type, c.contact_category, p.phone_label,"; - $sql .= "p.phone_number, p.phone_extension, p.phone_primary "; - $sql .= "from v_contacts as c, v_contact_phones as p "; - $sql .= "where c.contact_uuid = p.contact_uuid "; - $sql .= "and p.phone_type_voice = '1' "; - $sql .= "and c.domain_uuid = :domain_uuid "; - if ($category == 'groups') { - $sql .= "and c.contact_uuid in ( "; - $sql .= " select contact_uuid from v_contact_groups "; - $sql .= " where group_uuid in ( "; - $sql .= " select group_uuid from v_user_groups "; - $sql .= " where user_uuid = :device_user_uuid "; - $sql .= " and domain_uuid = :domain_uuid "; - $sql .= " )) "; - $parameters['device_user_uuid'] = $device_user_uuid; - } - if ($category == 'users') { - $sql .= "and c.contact_uuid in ( "; - $sql .= " select contact_uuid from v_contact_users "; - $sql .= " where user_uuid = :device_user_uuid "; - $sql .= " and domain_uuid = :domain_uuid "; - $sql .= ") "; - $parameters['device_user_uuid'] = $device_user_uuid; + /** + * Formats the device address according to the vendor. + * + * @param string $device_address The IP address or hostname of the device. + * @param string $vendor The vendor of the device, e.g. "cisco", "linksys", etc. + * + * @return string The formatted device address. + */ + public function format_address($device_address, $vendor) { + switch (strtolower($vendor)) { + case "algo": + return strtoupper($device_address); + case "aastra": + return strtoupper($device_address); + case "cisco": + return strtoupper($device_address); + case "linksys": + return strtolower($device_address); + case "mitel": + return strtoupper($device_address); + case "polycom": + return strtolower($device_address); + case "snom": + return strtolower($device_address); + case "escene": + return strtolower($device_address); + case "grandstream": + return strtolower($device_address); + case "yealink": + return strtolower($device_address); + case "gigaset": + return strtoupper($device_address); + default: + return strtolower($device_address); + } + } + + //send http error + + /** + * Handles HTTP errors and displays a 404 Not Found page if the error code is '404'. + * + * @param string $error The HTTP error code. + * + * @return void Exits the script with an HTTP status code of 404 if the error code is '404', otherwise continues execution. + */ + private function http_error($error) { + if ($error === "404") { + header("HTTP/1.0 404 Not Found"); + echo "\n"; + echo "404 Not Found\n"; + echo "\n"; + echo "

    404 Not Found

    \n"; + echo "
    nginx/1.12.1
    \n"; + echo "\n"; + echo "\n"; + } + exit(); + } + + //define a function to check if a contact exists in the contacts array + + /** + * Checks if a contact exists in the given array of contacts. + * + * @param array $contacts The array of contacts to search in. + * @param string $uuid The unique identifier (UUID) of the contact to look for. + * + * @return bool True if the contact exists, false otherwise. + */ + private function contact_exists($contacts, $uuid) { + if (is_array($contacts[$uuid])) { + return true; + } else { + return false; + } + } + + /** + * Appends contacts from the database to the given array of contacts. + * + * @param array $contacts The array of contacts to append to. + * @param string $line The current line being processed (used for phone numbers). + * @param string $domain_uuid The UUID of the domain to filter by. + * @param string $device_user_uuid The UUID of the device user to filter by. + * @param string $category The category of contacts to append (one of 'groups', 'users', or 'all'). + * + * @return void + */ + private function contact_append(&$contacts, &$line, $domain_uuid, $device_user_uuid, $category) { + + $sql = "select c.contact_uuid, c.contact_organization, c.contact_name_given, c.contact_name_family, "; + $sql .= "c.contact_type, c.contact_category, p.phone_label,"; + $sql .= "p.phone_number, p.phone_extension, p.phone_primary "; + $sql .= "from v_contacts as c, v_contact_phones as p "; + $sql .= "where c.contact_uuid = p.contact_uuid "; + $sql .= "and p.phone_type_voice = '1' "; + $sql .= "and c.domain_uuid = :domain_uuid "; + if ($category == 'groups') { + $sql .= "and c.contact_uuid in ( "; + $sql .= " select contact_uuid from v_contact_groups "; + $sql .= " where group_uuid in ( "; + $sql .= " select group_uuid from v_user_groups "; + $sql .= " where user_uuid = :device_user_uuid "; + $sql .= " and domain_uuid = :domain_uuid "; + $sql .= " )) "; + $parameters['device_user_uuid'] = $device_user_uuid; + } + if ($category == 'users') { + $sql .= "and c.contact_uuid in ( "; + $sql .= " select contact_uuid from v_contact_users "; + $sql .= " where user_uuid = :device_user_uuid "; + $sql .= " and domain_uuid = :domain_uuid "; + $sql .= ") "; + $parameters['device_user_uuid'] = $device_user_uuid; + } + $parameters['domain_uuid'] = $domain_uuid; + $database_contacts = $this->database->select($sql, $parameters, 'all'); + if (is_array($database_contacts)) { + $x = 0; + foreach ($database_contacts as $row) { + $uuid = $row['contact_uuid']; + $phone_label = strtolower($row['phone_label'] ?? ''); + $contact_category = strtolower($row['contact_category'] ?? ''); + + $contact = []; + $contacts[] = &$contact; + $contact['category'] = ($category == 'all') ? 'groups' : $category; + $contact['contact_uuid'] = $row['contact_uuid']; + $contact['contact_type'] = $row['contact_type']; + $contact['contact_category'] = $row['contact_category']; + $contact['contact_organization'] = $row['contact_organization']; + $contact['contact_name_given'] = $row['contact_name_given']; + $contact['contact_name_family'] = $row['contact_name_family']; + + $contact['numbers'] = []; + $numbers = &$contact['numbers']; + + if (($row['phone_primary'] == '1') || (!isset($contact['phone_number']))) { + $contact['phone_label'] = $phone_label; + $contact['phone_number'] = $row['phone_number']; + $contact['phone_extension'] = $row['phone_extension']; + } + + $numbers[$x]['line_number'] = $line['line_number'] ?? null; + $numbers[$x]['phone_label'] = $phone_label; + $numbers[$x]['phone_number'] = $row['phone_number']; + $numbers[$x]['phone_extension'] = $row['phone_extension']; + $numbers[$x]['phone_primary'] = $row['phone_primary']; + + $contact['phone_number_' . $phone_label] = $row['phone_number']; + unset($contact, $numbers, $uuid, $phone_label); + $x++; } + unset($sql, $parameters); + + } + } + + /** + * Renders the provision page for a device. + * + * This method checks if the device address exists in the database, and if so, + * it retrieves the corresponding device information and template. If not, it + * attempts to assign a default template based on the user agent. + * + * @return void + */ + public function render() { + + //debug + $debug = $_REQUEST['debug'] ?? ''; // array + + //get the variables + $domain_uuid = $this->domain_uuid; + $domain_name = $this->domain_name; + $device_template = $this->device_template; + $template_dir = $this->template_dir; + $device_address = $this->device_address; + $file = $this->file; + + //set the device address to lower case to be consistent with the database + $device_address = strtolower($device_address); + + //get the device template + //if (!empty($_REQUEST['template'])) { + // $device_template = $_REQUEST['template']; + // $search = array('..', '/./'); + // $device_template = str_replace($search, "", $device_template); + // $device_template = str_replace('//', '/', $device_template); + //} + + //remove ../ and slashes in the file name + $search = ['..', '/', '\\', '/./', '//']; + $file = str_replace($search, "", $file); + + //get the domain_name + if (empty($domain_name)) { + $sql = "select domain_name from v_domains "; + $sql .= "where domain_uuid = :domain_uuid "; $parameters['domain_uuid'] = $domain_uuid; - $database_contacts = $this->database->select($sql, $parameters, 'all'); - if (is_array($database_contacts)) { - $x = 0; - foreach ($database_contacts as $row) { - $uuid = $row['contact_uuid']; - $phone_label = strtolower($row['phone_label'] ?? ''); - $contact_category = strtolower($row['contact_category'] ?? ''); + $domain_name = $this->database->select($sql, $parameters, 'column'); + unset($sql, $parameters); + } - $contact = array(); - $contacts[] = &$contact; - $contact['category'] = ($category == 'all') ? 'groups' : $category; - $contact['contact_uuid'] = $row['contact_uuid']; - $contact['contact_type'] = $row['contact_type']; - $contact['contact_category'] = $row['contact_category']; - $contact['contact_organization'] = $row['contact_organization']; - $contact['contact_name_given'] = $row['contact_name_given']; - $contact['contact_name_family'] = $row['contact_name_family']; + //build the provision array + $provision = $this->settings->get('provision', null, []); + foreach ($provision as $key => $value) { + $provision[$key] = $value; + } - $contact['numbers'] = array(); - $numbers = &$contact['numbers']; + //add the http auth password to the array + if (isset($provision["http_auth_password"]) && is_array($provision["http_auth_password"])) { + $provision["http_auth_password"] = $provision["http_auth_password"][0]; + } - if (($row['phone_primary'] == '1') || (!isset($contact['phone_number']))) { - $contact['phone_label'] = $phone_label; - $contact['phone_number'] = $row['phone_number']; - $contact['phone_extension'] = $row['phone_extension']; + //check to see if the device_address exists in devices + //if (empty($_REQUEST['user_id']) || empty($_REQUEST['userid'])) { + if ($this->device_exists($device_address)) { + + //get the device_template + $sql = "select * from v_devices "; + $sql .= "where device_address = :device_address "; + $sql .= "and device_address <> '000000000000' "; + $parameters['device_address'] = $device_address; + $row = $this->database->select($sql, $parameters, 'row'); + unset($sql, $parameters); + if (is_array($row) && sizeof($row) != 0) { + + //checks either device enabled + if ($row['device_enabled'] === false) { + syslog(LOG_WARNING, '[' . $_SERVER['REMOTE_ADDR'] . "] provision attempted but the device is not enabled for " . escape($device_address)); + if ($this->settings->get('provision', 'debug', false)) { + echo "
    device disabled
    "; + } else { + $this->http_error('404'); } - - $numbers[$x]['line_number'] = $line['line_number'] ?? null; - $numbers[$x]['phone_label'] = $phone_label; - $numbers[$x]['phone_number'] = $row['phone_number']; - $numbers[$x]['phone_extension'] = $row['phone_extension']; - $numbers[$x]['phone_primary'] = $row['phone_primary']; - - $contact['phone_number_' . $phone_label] = $row['phone_number']; - unset($contact, $numbers, $uuid, $phone_label); - $x++; + exit; } + + //register that we have seen the device + $sql = "update v_devices "; + $sql .= "set device_provisioned_date = :device_provisioned_date, device_provisioned_method = :device_provisioned_method, device_provisioned_ip = :device_provisioned_ip, device_provisioned_agent = :device_provisioned_agent "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and device_address = :device_address "; + $sql .= "and (device_provisioned_date is null or device_provisioned_date < NOW() - INTERVAL '30 seconds') "; + $parameters['domain_uuid'] = $domain_uuid; + $parameters['device_address'] = strtolower($device_address); + $parameters['device_provisioned_date'] = 'now()'; + $parameters['device_provisioned_method'] = (isset($_SERVER["HTTPS"]) ? 'https' : 'http'); + $parameters['device_provisioned_ip'] = $_SERVER['REMOTE_ADDR']; + $parameters['device_provisioned_agent'] = $_SERVER['HTTP_USER_AGENT']; + $this->database->execute($sql, $parameters); unset($sql, $parameters); + //set the variables from values in the database + $device_uuid = $row["device_uuid"]; + $device_label = $row["device_label"]; + $device_template = $row["device_template"]; + $device_profile_uuid = $row["device_profile_uuid"]; + $device_user_uuid = $row["device_user_uuid"]; + $device_model = $row["device_model"]; + $device_firmware_version = $row["device_firmware_version"]; + if (!empty($row["device_vendor"])) { + $device_vendor = strtolower($row["device_vendor"]); + } + $device_location = $row["device_location"]; + $device_enabled = $row["device_enabled"]; + $device_description = $row["device_description"]; + } + unset($row); + + //find a template that was defined on another phone and use that as the default. + if (empty($device_template)) { + $sql = "select * from v_devices "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and device_enabled = true "; + $sql .= "limit 1 "; + $parameters['domain_uuid'] = $domain_uuid; + $row = $this->database->select($sql, $parameters, 'row'); + if (!empty($row) && is_array($row) && sizeof($row) != 0) { + $device_label = $row["device_label"]; + $device_template = $row["device_template"]; + $device_profile_uuid = $row["device_profile_uuid"]; + $device_model = $row["device_model"]; + $device_firmware_version = $row["device_firmware_version"]; + $device_vendor = strtolower($row["device_vendor"]); + $device_location = strtolower($row["device_location"]); + $device_enabled = $row["device_enabled"]; + $device_description = $row["device_description"]; + } + unset($sql, $row, $parameters); + } + } else { + //use the user_agent to pre-assign a template for 1-hit provisioning. Enter the a unique string to match in the user agent, and the template it should match. + $templates['Linksys/SPA-2102'] = 'linksys/spa2102'; + $templates['Linksys/SPA-3102'] = 'linksys/spa3102'; + $templates['Linksys/SPA-9212'] = 'linksys/spa921'; + + $templates['Cisco/SPA301'] = 'cisco/spa301'; + $templates['Cisco/SPA301D'] = 'cisco/spa302d'; + $templates['Cisco/SPA303'] = 'cisco/spa303'; + $templates['Cisco/SPA501G'] = 'cisco/spa501g'; + $templates['Cisco/SPA502G'] = 'cisco/spa502g'; + $templates['Cisco/SPA504G'] = 'cisco/spa504g'; + $templates['Cisco/SPA508G'] = 'cisco/spa508g'; + $templates['Cisco/SPA509G'] = 'cisco/spa509g'; + $templates['Cisco/SPA512G'] = 'cisco/spa512g'; + $templates['Cisco/SPA514G'] = 'cisco/spa514g'; + $templates['Cisco/SPA525G2'] = 'cisco/spa525g2'; + + $templates['snom300-SIP'] = 'snom/300'; + $templates['snom320-SIP'] = 'snom/320'; + $templates['snom360-SIP'] = 'snom/360'; + $templates['snom370-SIP'] = 'snom/370'; + $templates['snom820-SIP'] = 'snom/820'; + $templates['snom-m3-SIP'] = 'snom/m3'; + + $templates['Fanvil X6'] = 'fanvil/x6'; + $templates['Fanvil i30'] = 'fanvil/i30'; + + $templates['yealink SIP-CP860'] = 'yealink/cp860'; +# $templates['yealink SIP-CP860'] = 'yealink/cp920'; +# $templates['yealink SIP-CP860'] = 'yealink/cp960'; + $templates['yealink SIP-T19P'] = 'yealink/t19p'; + $templates['yealink SIP-T20P'] = 'yealink/t20p'; + $templates['yealink SIP-T21P'] = 'yealink/t21p'; + $templates['yealink SIP-T22P'] = 'yealink/t22p'; + $templates['yealink SIP-T23G'] = 'yealink/t23g'; + $templates['yealink SIP-T23P'] = 'yealink/t23p'; + $templates['yealink SIP-T26P'] = 'yealink/t26p'; + $templates['yealink SIP-T27G'] = 'yealink/t27g'; + $templates['Yealink SIP-T29G'] = 'yealink/t27p'; + $templates['yealink SIP-T28P'] = 'yealink/t28p'; + $templates['Yealink SIP-T29G'] = 'yealink/t29g'; + $templates['yealink SIP-T29P'] = 'yealink/t29p'; + $templates['Yealink SIP-T32G'] = 'yealink/t32g'; + $templates['Yealink SIP-T33G'] = 'yealink/t33g'; + $templates['Yealink SIP-T38G'] = 'yealink/t38g'; + $templates['Yealink SIP-T40P'] = 'yealink/t40p'; + $templates['Yealink SIP-T41G'] = 'yealink/t41g'; + $templates['Yealink SIP-T41P'] = 'yealink/t41p'; + $templates['Yealink SIP-T41S'] = 'yealink/t41s'; + $templates['Yealink SIP-T42G'] = 'yealink/t42g'; + $templates['Yealink SIP-T42S'] = 'yealink/t42s'; + $templates['Yealink SIP-T46G'] = 'yealink/t46g'; + $templates['Yealink SIP-T46S'] = 'yealink/t46s'; + $templates['Yealink SIP-T48G'] = 'yealink/t48g'; + $templates['Yealink SIP-T48S'] = 'yealink/t48s'; + $templates['Yealink SIP-T49G'] = 'yealink/t49g'; + $templates['Yealink SIP-T52S'] = 'yealink/t52s'; + $templates['Yealink SIP-T54S'] = 'yealink/t54s'; + $templates['Yealink SIP-T56A'] = 'yealink/t56a'; + $templates['Yealink SIP-T58'] = 'yealink/t58v'; + $templates['VP530P'] = 'yealink/vp530'; + $templates['Yealink SIP-W52P'] = 'yealink/w52p'; + $templates['Yealink SIP-W56P'] = 'yealink/w56p'; + + $templates['HW DP750'] = 'grandstream/dp750'; + $templates['HW GXP1450'] = 'grandstream/gxp1450'; + $templates['HW GXP1628'] = 'grandstream/gxp16xx'; + $templates['HW GXP1610'] = 'grandstream/gxp16xx'; + $templates['HW GXP1620'] = 'grandstream/gxp16xx'; + $templates['HW GXP1625'] = 'grandstream/gxp16xx'; + $templates['HW GXP1630'] = 'grandstream/gxp16xx'; + $templates['HW GXP1760W'] = 'grandstream/gxp17xx'; + $templates['HW GXP1780'] = 'grandstream/gxp17xx'; + $templates['HW GXP1782'] = 'grandstream/gxp17xx'; + $templates['HW GXP2124'] = 'grandstream/gxp2124'; + $templates['HW GXP2130'] = 'grandstream/gxp2130'; + $templates['HW GXP2135'] = 'grandstream/gxp2135'; + $templates['HW GXP2140'] = 'grandstream/gxp2140'; + $templates['HW GXP2160'] = 'grandstream/gxp2160'; + $templates['HW GXP2170'] = 'grandstream/gxp2170'; + $templates['HW GXV3140'] = 'grandstream/gxv3140'; + $templates['HW GXV3240'] = 'grandstream/gxv3240'; + $templates['HW GXV3175'] = 'grandstream/gxv3175'; + + $templates['PolycomVVX-VVX_101-UA/4'] = 'polycom/4.x'; + $templates['PolycomVVX-VVX_201-UA/4'] = 'polycom/4.x'; + $templates['PolycomVVX-VVX_300-UA/4'] = 'polycom/4.x'; + $templates['PolycomVVX-VVX_301-UA/4'] = 'polycom/4.x'; + $templates['PolycomVVX-VVX_310-UA/4'] = 'polycom/4.x'; + $templates['PolycomVVX-VVX_311-UA/4'] = 'polycom/4.x'; + $templates['PolycomVVX-VVX_400-UA/4'] = 'polycom/4.x'; + $templates['PolycomVVX-VVX_410-UA/4'] = 'polycom/4.x'; + $templates['PolycomVVX-VVX_500-UA/4'] = 'polycom/4.x'; + $templates['PolycomVVX-VVX_501-UA/4'] = 'polycom/4.x'; + $templates['PolycomVVX-VVX_600-UA/4'] = 'polycom/4.x'; + $templates['PolycomVVX-VVX_601-UA/4'] = 'polycom/4.x'; + $templates['PolycomVVX-VVX_101-UA/5'] = 'polycom/5.x'; + $templates['PolycomVVX-VVX_201-UA/5'] = 'polycom/5.x'; + $templates['PolycomVVX-VVX_300-UA/5'] = 'polycom/5.x'; + $templates['PolycomVVX-VVX_301-UA/5'] = 'polycom/5.x'; + $templates['PolycomVVX-VVX_310-UA/5'] = 'polycom/5.x'; + $templates['PolycomVVX-VVX_311-UA/5'] = 'polycom/5.x'; + $templates['PolycomVVX-VVX_400-UA/5'] = 'polycom/5.x'; + $templates['PolycomVVX-VVX_410-UA/5'] = 'polycom/5.x'; + $templates['PolycomVVX-VVX_500-UA/5'] = 'polycom/5.x'; + $templates['PolycomVVX-VVX_501-UA/5'] = 'polycom/5.x'; + $templates['PolycomVVX-VVX_600-UA/5'] = 'polycom/5.x'; + $templates['PolycomVVX-VVX_601-UA/5'] = 'polycom/5.x'; + + $templates['Vesa VCS754'] = 'vtech/vcs754'; + $templates['Wget/1.11.3'] = 'konftel/kt300ip'; + + $templates['Flyingvoice FIP10'] = 'flyingvoice/fip10'; + $templates['Flyingvoice FIP11C'] = 'flyingvoice/fip11c'; + $templates['Flyingvoice FIP12WP'] = 'flyingvoice/fip12wp'; + $templates['Flyingvoice FIP13G'] = 'flyingvoice/fip13g'; + $templates['Flyingvoice FIP14G'] = 'flyingvoice/fip14g'; + $templates['Flyingvoice FIP15G'] = 'flyingvoice/fip15g'; + $templates['Flyingvoice FIP16'] = 'flyingvoice/fip16'; + $templates['Flyingvoice FIP16PLUS'] = 'flyingvoice/fip16plus'; + + foreach ($templates as $key => $value) { + if (stripos($_SERVER['HTTP_USER_AGENT'], $key) !== false) { + $device_template = $value; + break; + } + } + unset($templates); + + //device address does not exist in the table so add it + if ($this->settings->get('provision', 'auto_insert_enabled', false)) { + + //get a new primary key + $device_uuid = uuid(); + + //prepare the auto insert enabled + if (!empty($device_address)) { + $device_vendor = device::get_vendor($device_address); + + //prepare the array + $x = 0; + $array['devices'][$x]['domain_uuid'] = $domain_uuid; + $array['devices'][$x]['device_uuid'] = $device_uuid; + $array['devices'][$x]['device_address'] = $device_address; + $array['devices'][$x]['device_vendor'] = $device_vendor; + $array['devices'][$x]['device_enabled'] = true; + $array['devices'][$x]['device_template'] = $device_template; + $array['devices'][$x]['device_description'] = $_SERVER['HTTP_USER_AGENT']; + + //add the dialplan permission + $p = permissions::new(); + $p->add("device_add", "temp"); + $p->add("device_edit", "temp"); + + //save to the data + $this->database->app_name = 'devices'; + $this->database->app_uuid = '4efa1a1a-32e7-bf83-534b-6c8299958a8e'; + if (!empty($device_uuid)) { + $this->database->uuid($device_uuid); + } + $this->database->save($array); + $message = $this->database->message; + + //remove the temporary permission + $p->delete("device_add", "temp"); + $p->delete("device_edit", "temp"); + } + } + } + //} + + //alternate device_uuid + if (is_uuid($device_uuid)) { + $sql = "select * from v_devices "; + $sql .= "where device_uuid = :device_uuid "; + $sql .= "and device_enabled = true "; + $parameters['device_uuid'] = $device_uuid; + $row = $this->database->select($sql, $parameters, 'row'); + if (is_array($row) && sizeof($row) != 0) { + $device_uuid_alternate = $row["device_uuid_alternate"]; + unset($sql, $row, $parameters); + if (is_uuid($device_uuid_alternate)) { + //override the original device_uuid + $device_uuid = $device_uuid_alternate; + + //get the new devices information + $sql = "select * from v_devices "; + $sql .= "where device_uuid = :device_uuid "; + $parameters['device_uuid'] = $device_uuid; + $row = $this->database->select($sql, $parameters, 'row'); + if (is_array($row) && sizeof($row) != 0) { + if ($row["device_enabled"]) { + $device_label = $row["device_label"]; + + //if the device vendor match then use the alternate device template + if ($device_vendor == $row["device_vendor"]) { + $device_template = $row["device_template"]; + } + + $device_profile_uuid = $row["device_profile_uuid"]; + $device_firmware_version = $row["device_firmware_version"]; + $device_user_uuid = $row["device_user_uuid"]; + $device_location = strtolower($row["device_location"]); + $device_enabled = $row["device_enabled"]; + $device_description = $row["device_description"]; + } + } + unset($sql, $row, $parameters); + } } } - public function render() { - - //debug - $debug = $_REQUEST['debug'] ?? ''; // array - - //get the variables - $domain_uuid = $this->domain_uuid; - $domain_name = $this->domain_name; - $device_template = $this->device_template; - $template_dir = $this->template_dir; - $device_address = $this->device_address; - $file = $this->file; - - //set the device address to lower case to be consistent with the database - $device_address = strtolower($device_address); - - //get the device template - //if (!empty($_REQUEST['template'])) { - // $device_template = $_REQUEST['template']; - // $search = array('..', '/./'); - // $device_template = str_replace($search, "", $device_template); - // $device_template = str_replace('//', '/', $device_template); - //} - - //remove ../ and slashes in the file name - $search = array('..', '/', '\\', '/./', '//'); - $file = str_replace($search, "", $file); - - //get the domain_name - if (empty($domain_name)) { - $sql = "select domain_name from v_domains "; - $sql .= "where domain_uuid = :domain_uuid "; - $parameters['domain_uuid'] = $domain_uuid; - $domain_name = $this->database->select($sql, $parameters, 'column'); - unset($sql, $parameters); - } - - //build the provision array - $provision = $this->settings->get('provision', null, []); - foreach ($provision as $key => $value) { + //get the device settings table in the provision category from the profile and update the provision array + if (is_uuid($device_uuid) && is_uuid($device_profile_uuid)) { + $sql = "select * from v_device_profile_settings "; + $sql .= "where device_profile_uuid = :device_profile_uuid "; + $sql .= "and profile_setting_enabled = true "; + $parameters['device_profile_uuid'] = $device_profile_uuid; + $device_profile_settings = $this->database->select($sql, $parameters, 'all'); + if (is_array($device_profile_settings) && sizeof($device_profile_settings) != 0) { + foreach ($device_profile_settings as $row) { + $key = $row['profile_setting_name']; + $value = $row['profile_setting_value']; $provision[$key] = $value; } + } + unset ($parameters, $device_profile_settings, $sql); + } - //add the http auth password to the array - if (isset($provision["http_auth_password"]) && is_array($provision["http_auth_password"])) { - $provision["http_auth_password"] = $provision["http_auth_password"][0]; + //get the device settings table in the provision category and update the provision array + if (is_uuid($device_uuid)) { + $sql = "select * from v_device_settings "; + $sql .= "where device_uuid = :device_uuid "; + $sql .= "and device_setting_enabled = true "; + $parameters['device_uuid'] = $device_uuid; + $device_settings = $this->database->select($sql, $parameters, 'all'); + if (is_array($device_settings) && sizeof($device_settings) != 0) { + foreach ($device_settings as $row) { + $key = $row['device_setting_subcategory']; + $value = $row['device_setting_value']; + $provision[$key] = $value; } + } + unset ($parameters, $device_settings, $sql); + } - //check to see if the device_address exists in devices - //if (empty($_REQUEST['user_id']) || empty($_REQUEST['userid'])) { - if ($this->device_exists($device_address)) { + //set the template directory + if (!empty($provision["template_dir"])) { + $template_dir = $provision["template_dir"]; + } - //get the device_template - $sql = "select * from v_devices "; - $sql .= "where device_address = :device_address "; - $sql .= "and device_address <> '000000000000' "; - $parameters['device_address'] = $device_address; - $row = $this->database->select($sql, $parameters, 'row'); - unset($sql, $parameters); - if (is_array($row) && sizeof($row) != 0) { + //if the domain name directory exists then only use templates from it + if (is_dir($template_dir . '/' . $domain_name)) { + $device_template = $domain_name . '/' . $device_template; + } - //checks either device enabled - if ($row['device_enabled'] === false) { - syslog(LOG_WARNING, '['.$_SERVER['REMOTE_ADDR']."] provision attempted but the device is not enabled for ".escape($device_address)); - if ($this->settings->get('provision','debug', false)) { - echo "
    device disabled
    "; - } - else { - $this->http_error('404'); - } - exit; - } + //initialize a template object + $view = new template(); + $view->engine = $this->settings->get('provision', 'template_engine', 'smarty'); + $view->template_dir = $template_dir . "/" . $device_template . "/"; + $view->cache_dir = sys_get_temp_dir(); + $view->init(); - //register that we have seen the device - $sql = "update v_devices "; - $sql .= "set device_provisioned_date = :device_provisioned_date, device_provisioned_method = :device_provisioned_method, device_provisioned_ip = :device_provisioned_ip, device_provisioned_agent = :device_provisioned_agent "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and device_address = :device_address "; - $sql .= "and (device_provisioned_date is null or device_provisioned_date < NOW() - INTERVAL '30 seconds') "; - $parameters['domain_uuid'] = $domain_uuid; - $parameters['device_address'] = strtolower($device_address); - $parameters['device_provisioned_date'] = 'now()'; - $parameters['device_provisioned_method'] = (isset($_SERVER["HTTPS"]) ? 'https' : 'http'); - $parameters['device_provisioned_ip'] = $_SERVER['REMOTE_ADDR']; - $parameters['device_provisioned_agent'] = $_SERVER['HTTP_USER_AGENT']; - $this->database->execute($sql, $parameters); - unset($sql, $parameters); + //replace the variables in the template in the future, loop through all the line numbers to do a replace for each possible line number - //set the variables from values in the database - $device_uuid = $row["device_uuid"]; - $device_label = $row["device_label"]; - $device_template = $row["device_template"]; - $device_profile_uuid = $row["device_profile_uuid"]; - $device_user_uuid = $row["device_user_uuid"]; - $device_model = $row["device_model"]; - $device_firmware_version = $row["device_firmware_version"]; - if (!empty($row["device_vendor"])) { - $device_vendor = strtolower($row["device_vendor"]); - } - $device_location = $row["device_location"]; - $device_enabled = $row["device_enabled"]; - $device_description = $row["device_description"]; - } - unset($row); + //create a device address with backslashes for backwards compatibility + //$address_dash = substr($device_address, 0,2).'-'.substr($device_address, 2,2).'-'.substr($device_address, 4,2).'-'.substr($device_address, 6,2).'-'.substr($device_address, 8,2).'-'.substr($device_address, 10,2); - //find a template that was defined on another phone and use that as the default. - if (empty($device_template)) { - $sql = "select * from v_devices "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and device_enabled = true "; - $sql .= "limit 1 "; - $parameters['domain_uuid'] = $domain_uuid; - $row = $this->database->select($sql, $parameters, 'row'); - if (!empty($row) && is_array($row) && sizeof($row) != 0) { - $device_label = $row["device_label"]; - $device_template = $row["device_template"]; - $device_profile_uuid = $row["device_profile_uuid"]; - $device_model = $row["device_model"]; - $device_firmware_version = $row["device_firmware_version"]; - $device_vendor = strtolower($row["device_vendor"]); - $device_location = strtolower($row["device_location"]); - $device_enabled = $row["device_enabled"]; - $device_description = $row["device_description"]; - } - unset($sql, $row, $parameters); - } - } - else { - //use the user_agent to pre-assign a template for 1-hit provisioning. Enter the a unique string to match in the user agent, and the template it should match. - $templates['Linksys/SPA-2102'] = 'linksys/spa2102'; - $templates['Linksys/SPA-3102'] = 'linksys/spa3102'; - $templates['Linksys/SPA-9212'] = 'linksys/spa921'; + //get the provisioning information + if (is_uuid($device_uuid)) { + //get the extensions from the database + $sql = "select extension_uuid as contact_uuid, directory_first_name, directory_last_name, "; + $sql .= "effective_caller_id_name, effective_caller_id_number, "; + $sql .= "number_alias, extension, call_group "; + $sql .= "from v_extensions "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "order by extension asc "; + $parameters['domain_uuid'] = $domain_uuid; + $extensions = $this->database->select($sql, $parameters, 'all'); + foreach ($extensions as $row) { + $extension_labels[$row['extension']]['caller_id_name'] = $row['effective_caller_id_name']; + } + unset($sql, $parameters); - $templates['Cisco/SPA301'] = 'cisco/spa301'; - $templates['Cisco/SPA301D'] = 'cisco/spa302d'; - $templates['Cisco/SPA303'] = 'cisco/spa303'; - $templates['Cisco/SPA501G'] = 'cisco/spa501g'; - $templates['Cisco/SPA502G'] = 'cisco/spa502g'; - $templates['Cisco/SPA504G'] = 'cisco/spa504g'; - $templates['Cisco/SPA508G'] = 'cisco/spa508g'; - $templates['Cisco/SPA509G'] = 'cisco/spa509g'; - $templates['Cisco/SPA512G'] = 'cisco/spa512g'; - $templates['Cisco/SPA514G'] = 'cisco/spa514g'; - $templates['Cisco/SPA525G2'] = 'cisco/spa525g2'; + //get the device lines array + $sql = "select * from v_device_lines "; + $sql .= "where device_uuid = :device_uuid "; + $sql .= "and (enabled = true or enabled is null) "; + $parameters['device_uuid'] = $device_uuid; + //$database_device_lines = $this->database->select($sql, $parameters, 'all'); + foreach ($this->database->select($sql, $parameters, 'all') as $row) { + $id = $row['line_number']; + $device_lines[$id] = $row; + } + unset($sql, $parameters); - $templates['snom300-SIP'] = 'snom/300'; - $templates['snom320-SIP'] = 'snom/320'; - $templates['snom360-SIP'] = 'snom/360'; - $templates['snom370-SIP'] = 'snom/370'; - $templates['snom820-SIP'] = 'snom/820'; - $templates['snom-m3-SIP'] = 'snom/m3'; - - $templates['Fanvil X6'] = 'fanvil/x6'; - $templates['Fanvil i30'] = 'fanvil/i30'; - - $templates['yealink SIP-CP860'] = 'yealink/cp860'; -# $templates['yealink SIP-CP860'] = 'yealink/cp920'; -# $templates['yealink SIP-CP860'] = 'yealink/cp960'; - $templates['yealink SIP-T19P'] = 'yealink/t19p'; - $templates['yealink SIP-T20P'] = 'yealink/t20p'; - $templates['yealink SIP-T21P'] = 'yealink/t21p'; - $templates['yealink SIP-T22P'] = 'yealink/t22p'; - $templates['yealink SIP-T23G'] = 'yealink/t23g'; - $templates['yealink SIP-T23P'] = 'yealink/t23p'; - $templates['yealink SIP-T26P'] = 'yealink/t26p'; - $templates['yealink SIP-T27G'] = 'yealink/t27g'; - $templates['Yealink SIP-T29G'] = 'yealink/t27p'; - $templates['yealink SIP-T28P'] = 'yealink/t28p'; - $templates['Yealink SIP-T29G'] = 'yealink/t29g'; - $templates['yealink SIP-T29P'] = 'yealink/t29p'; - $templates['Yealink SIP-T32G'] = 'yealink/t32g'; - $templates['Yealink SIP-T33G'] = 'yealink/t33g'; - $templates['Yealink SIP-T38G'] = 'yealink/t38g'; - $templates['Yealink SIP-T40P'] = 'yealink/t40p'; - $templates['Yealink SIP-T41G'] = 'yealink/t41g'; - $templates['Yealink SIP-T41P'] = 'yealink/t41p'; - $templates['Yealink SIP-T41S'] = 'yealink/t41s'; - $templates['Yealink SIP-T42G'] = 'yealink/t42g'; - $templates['Yealink SIP-T42S'] = 'yealink/t42s'; - $templates['Yealink SIP-T46G'] = 'yealink/t46g'; - $templates['Yealink SIP-T46S'] = 'yealink/t46s'; - $templates['Yealink SIP-T48G'] = 'yealink/t48g'; - $templates['Yealink SIP-T48S'] = 'yealink/t48s'; - $templates['Yealink SIP-T49G'] = 'yealink/t49g'; - $templates['Yealink SIP-T52S'] = 'yealink/t52s'; - $templates['Yealink SIP-T54S'] = 'yealink/t54s'; - $templates['Yealink SIP-T56A'] = 'yealink/t56a'; - $templates['Yealink SIP-T58'] = 'yealink/t58v'; - $templates['VP530P'] = 'yealink/vp530'; - $templates['Yealink SIP-W52P'] = 'yealink/w52p'; - $templates['Yealink SIP-W56P'] = 'yealink/w56p'; - - $templates['HW DP750'] = 'grandstream/dp750'; - $templates['HW GXP1450'] = 'grandstream/gxp1450'; - $templates['HW GXP1628'] = 'grandstream/gxp16xx'; - $templates['HW GXP1610'] = 'grandstream/gxp16xx'; - $templates['HW GXP1620'] = 'grandstream/gxp16xx'; - $templates['HW GXP1625'] = 'grandstream/gxp16xx'; - $templates['HW GXP1630'] = 'grandstream/gxp16xx'; - $templates['HW GXP1760W'] = 'grandstream/gxp17xx'; - $templates['HW GXP1780'] = 'grandstream/gxp17xx'; - $templates['HW GXP1782'] = 'grandstream/gxp17xx'; - $templates['HW GXP2124'] = 'grandstream/gxp2124'; - $templates['HW GXP2130'] = 'grandstream/gxp2130'; - $templates['HW GXP2135'] = 'grandstream/gxp2135'; - $templates['HW GXP2140'] = 'grandstream/gxp2140'; - $templates['HW GXP2160'] = 'grandstream/gxp2160'; - $templates['HW GXP2170'] = 'grandstream/gxp2170'; - $templates['HW GXV3140'] = 'grandstream/gxv3140'; - $templates['HW GXV3240'] = 'grandstream/gxv3240'; - $templates['HW GXV3175'] = 'grandstream/gxv3175'; - - $templates['PolycomVVX-VVX_101-UA/4'] = 'polycom/4.x'; - $templates['PolycomVVX-VVX_201-UA/4'] = 'polycom/4.x'; - $templates['PolycomVVX-VVX_300-UA/4'] = 'polycom/4.x'; - $templates['PolycomVVX-VVX_301-UA/4'] = 'polycom/4.x'; - $templates['PolycomVVX-VVX_310-UA/4'] = 'polycom/4.x'; - $templates['PolycomVVX-VVX_311-UA/4'] = 'polycom/4.x'; - $templates['PolycomVVX-VVX_400-UA/4'] = 'polycom/4.x'; - $templates['PolycomVVX-VVX_410-UA/4'] = 'polycom/4.x'; - $templates['PolycomVVX-VVX_500-UA/4'] = 'polycom/4.x'; - $templates['PolycomVVX-VVX_501-UA/4'] = 'polycom/4.x'; - $templates['PolycomVVX-VVX_600-UA/4'] = 'polycom/4.x'; - $templates['PolycomVVX-VVX_601-UA/4'] = 'polycom/4.x'; - $templates['PolycomVVX-VVX_101-UA/5'] = 'polycom/5.x'; - $templates['PolycomVVX-VVX_201-UA/5'] = 'polycom/5.x'; - $templates['PolycomVVX-VVX_300-UA/5'] = 'polycom/5.x'; - $templates['PolycomVVX-VVX_301-UA/5'] = 'polycom/5.x'; - $templates['PolycomVVX-VVX_310-UA/5'] = 'polycom/5.x'; - $templates['PolycomVVX-VVX_311-UA/5'] = 'polycom/5.x'; - $templates['PolycomVVX-VVX_400-UA/5'] = 'polycom/5.x'; - $templates['PolycomVVX-VVX_410-UA/5'] = 'polycom/5.x'; - $templates['PolycomVVX-VVX_500-UA/5'] = 'polycom/5.x'; - $templates['PolycomVVX-VVX_501-UA/5'] = 'polycom/5.x'; - $templates['PolycomVVX-VVX_600-UA/5'] = 'polycom/5.x'; - $templates['PolycomVVX-VVX_601-UA/5'] = 'polycom/5.x'; - - $templates['Vesa VCS754'] = 'vtech/vcs754'; - $templates['Wget/1.11.3'] = 'konftel/kt300ip'; - - $templates['Flyingvoice FIP10'] = 'flyingvoice/fip10'; - $templates['Flyingvoice FIP11C'] = 'flyingvoice/fip11c'; - $templates['Flyingvoice FIP12WP'] = 'flyingvoice/fip12wp'; - $templates['Flyingvoice FIP13G'] = 'flyingvoice/fip13g'; - $templates['Flyingvoice FIP14G'] = 'flyingvoice/fip14g'; - $templates['Flyingvoice FIP15G'] = 'flyingvoice/fip15g'; - $templates['Flyingvoice FIP16'] = 'flyingvoice/fip16'; - $templates['Flyingvoice FIP16PLUS'] = 'flyingvoice/fip16plus'; - - foreach ($templates as $key=>$value) { - if(stripos($_SERVER['HTTP_USER_AGENT'],$key)!== false) { - $device_template = $value; - break; - } - } - unset($templates); - - //device address does not exist in the table so add it - if ($this->settings->get('provision','auto_insert_enabled',false)) { - - //get a new primary key - $device_uuid = uuid(); - - //prepare the auto insert enabled - if (!empty($device_address)) { - $device_vendor = device::get_vendor($device_address); - - //prepare the array - $x = 0; - $array['devices'][$x]['domain_uuid'] = $domain_uuid; - $array['devices'][$x]['device_uuid'] = $device_uuid; - $array['devices'][$x]['device_address'] = $device_address; - $array['devices'][$x]['device_vendor'] = $device_vendor; - $array['devices'][$x]['device_enabled'] = true; - $array['devices'][$x]['device_template'] = $device_template; - $array['devices'][$x]['device_description'] = $_SERVER['HTTP_USER_AGENT']; - - //add the dialplan permission - $p = permissions::new(); - $p->add("device_add", "temp"); - $p->add("device_edit", "temp"); - - //save to the data - $this->database->app_name = 'devices'; - $this->database->app_uuid = '4efa1a1a-32e7-bf83-534b-6c8299958a8e'; - if (!empty($device_uuid)) { - $this->database->uuid($device_uuid); - } - $this->database->save($array); - $message = $this->database->message; - - //remove the temporary permission - $p->delete("device_add", "temp"); - $p->delete("device_edit", "temp"); - } - } - } - //} - - //alternate device_uuid - if (is_uuid($device_uuid)) { - $sql = "select * from v_devices "; - $sql .= "where device_uuid = :device_uuid "; - $sql .= "and device_enabled = true "; - $parameters['device_uuid'] = $device_uuid; - $row = $this->database->select($sql, $parameters, 'row'); - if (is_array($row) && sizeof($row) != 0) { - $device_uuid_alternate = $row["device_uuid_alternate"]; - unset($sql, $row, $parameters); - if (is_uuid($device_uuid_alternate)) { - //override the original device_uuid - $device_uuid = $device_uuid_alternate; - - //get the new devices information - $sql = "select * from v_devices "; - $sql .= "where device_uuid = :device_uuid "; - $parameters['device_uuid'] = $device_uuid; - $row = $this->database->select($sql, $parameters, 'row'); - if (is_array($row) && sizeof($row) != 0) { - if ($row["device_enabled"]) { - $device_label = $row["device_label"]; - - //if the device vendor match then use the alternate device template - if ($device_vendor == $row["device_vendor"]) { - $device_template = $row["device_template"]; - } - - $device_profile_uuid = $row["device_profile_uuid"]; - $device_firmware_version = $row["device_firmware_version"]; - $device_user_uuid = $row["device_user_uuid"]; - $device_location = strtolower($row["device_location"]); - $device_enabled = $row["device_enabled"]; - $device_description = $row["device_description"]; - } - } - unset($sql, $row, $parameters); - } - } + //get the device profile keys + if (is_uuid($device_profile_uuid)) { + $sql = "select "; + $sql .= "profile_key_id as device_key_id, "; + $sql .= "profile_key_category as device_key_category, "; + $sql .= "profile_key_vendor as device_key_vendor, "; + $sql .= "profile_key_type as device_key_type, "; + $sql .= "profile_key_subtype as device_key_subtype, "; + $sql .= "profile_key_line as device_key_line, "; + $sql .= "profile_key_value as device_key_value, "; + $sql .= "profile_key_extension as device_key_extension, "; + $sql .= "profile_key_protected as device_key_protected, "; + $sql .= "profile_key_label as device_key_label, "; + $sql .= "profile_key_icon as device_key_icon "; + $sql .= "from v_device_profile_keys "; + $sql .= "where device_profile_uuid = :device_profile_uuid "; + if (strtolower($device_vendor) == 'escene') { + $sql .= "and (lower(profile_key_vendor) = 'escene' or lower(profile_key_vendor) = 'escene programmable' or profile_key_vendor is null) "; + } else { + $sql .= "and (lower(profile_key_vendor) = :device_vendor or profile_key_vendor is null) "; + $parameters['device_vendor'] = $device_vendor; } - - //get the device settings table in the provision category from the profile and update the provision array - if (is_uuid($device_uuid) && is_uuid($device_profile_uuid)) { - $sql = "select * from v_device_profile_settings "; - $sql .= "where device_profile_uuid = :device_profile_uuid "; - $sql .= "and profile_setting_enabled = true "; - $parameters['device_profile_uuid'] = $device_profile_uuid; - $device_profile_settings = $this->database->select($sql, $parameters, 'all'); - if (is_array($device_profile_settings) && sizeof($device_profile_settings) != 0) { - foreach($device_profile_settings as $row) { - $key = $row['profile_setting_name']; - $value = $row['profile_setting_value']; - $provision[$key] = $value; - } - } - unset ($parameters, $device_profile_settings, $sql); + $sql .= "order by "; + $sql .= "profile_key_vendor asc, "; + $sql .= "case profile_key_category "; + $sql .= "when 'line' then 1 "; + $sql .= "when 'memory' then 2 "; + $sql .= "when 'programmable' then 3 "; + $sql .= "when 'expansion' then 4 "; + $sql .= "else 100 end, "; + if ($GLOBALS['db_type'] == "mysql") { + $sql .= "profile_key_id asc "; + } else { + $sql .= "cast(profile_key_id as numeric) asc "; } + $parameters['device_profile_uuid'] = $device_profile_uuid; + $keys = $this->database->select($sql, $parameters, 'all'); - //get the device settings table in the provision category and update the provision array - if (is_uuid($device_uuid)) { - $sql = "select * from v_device_settings "; - $sql .= "where device_uuid = :device_uuid "; - $sql .= "and device_setting_enabled = true "; - $parameters['device_uuid'] = $device_uuid; - $device_settings = $this->database->select($sql, $parameters, 'all'); - if (is_array($device_settings) && sizeof($device_settings) != 0) { - foreach($device_settings as $row) { - $key = $row['device_setting_subcategory']; - $value = $row['device_setting_value']; - $provision[$key] = $value; - } - } - unset ($parameters, $device_settings, $sql); - } - - //set the template directory - if (!empty($provision["template_dir"])) { - $template_dir = $provision["template_dir"]; - } - - //if the domain name directory exists then only use templates from it - if (is_dir($template_dir.'/'.$domain_name)) { - $device_template = $domain_name.'/'.$device_template; - } - - //initialize a template object - $view = new template(); - $view->engine = $this->settings->get('provision', 'template_engine', 'smarty'); - $view->template_dir = $template_dir ."/".$device_template."/"; - $view->cache_dir = sys_get_temp_dir(); - $view->init(); - - //replace the variables in the template in the future, loop through all the line numbers to do a replace for each possible line number - - //create a device address with backslashes for backwards compatibility - //$address_dash = substr($device_address, 0,2).'-'.substr($device_address, 2,2).'-'.substr($device_address, 4,2).'-'.substr($device_address, 6,2).'-'.substr($device_address, 8,2).'-'.substr($device_address, 10,2); - - //get the provisioning information - if (is_uuid($device_uuid)) { - //get the extensions from the database - $sql = "select extension_uuid as contact_uuid, directory_first_name, directory_last_name, "; - $sql .= "effective_caller_id_name, effective_caller_id_number, "; - $sql .= "number_alias, extension, call_group "; - $sql .= "from v_extensions "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "order by extension asc "; - $parameters['domain_uuid'] = $domain_uuid; - $extensions = $this->database->select($sql, $parameters, 'all'); - foreach($extensions as $row) { - $extension_labels[$row['extension']]['caller_id_name'] = $row['effective_caller_id_name']; - } - unset($sql, $parameters); - - //get the device lines array - $sql = "select * from v_device_lines "; - $sql .= "where device_uuid = :device_uuid "; - $sql .= "and (enabled = true or enabled is null) "; - $parameters['device_uuid'] = $device_uuid; - //$database_device_lines = $this->database->select($sql, $parameters, 'all'); - foreach ($this->database->select($sql, $parameters, 'all') as $row) { - $id = $row['line_number']; - $device_lines[$id] = $row; - } - unset($sql, $parameters); - - //get the device profile keys - if (is_uuid($device_profile_uuid)) { - $sql = "select "; - $sql .= "profile_key_id as device_key_id, "; - $sql .= "profile_key_category as device_key_category, "; - $sql .= "profile_key_vendor as device_key_vendor, "; - $sql .= "profile_key_type as device_key_type, "; - $sql .= "profile_key_subtype as device_key_subtype, "; - $sql .= "profile_key_line as device_key_line, "; - $sql .= "profile_key_value as device_key_value, "; - $sql .= "profile_key_extension as device_key_extension, "; - $sql .= "profile_key_protected as device_key_protected, "; - $sql .= "profile_key_label as device_key_label, "; - $sql .= "profile_key_icon as device_key_icon "; - $sql .= "from v_device_profile_keys "; - $sql .= "where device_profile_uuid = :device_profile_uuid "; - if (strtolower($device_vendor) == 'escene'){ - $sql .= "and (lower(profile_key_vendor) = 'escene' or lower(profile_key_vendor) = 'escene programmable' or profile_key_vendor is null) "; - } - else { - $sql .= "and (lower(profile_key_vendor) = :device_vendor or profile_key_vendor is null) "; - $parameters['device_vendor'] = $device_vendor; - } - $sql .= "order by "; - $sql .= "profile_key_vendor asc, "; - $sql .= "case profile_key_category "; - $sql .= "when 'line' then 1 "; - $sql .= "when 'memory' then 2 "; - $sql .= "when 'programmable' then 3 "; - $sql .= "when 'expansion' then 4 "; - $sql .= "else 100 end, "; - if ($GLOBALS['db_type'] == "mysql") { - $sql .= "profile_key_id asc "; - } - else { - $sql .= "cast(profile_key_id as numeric) asc "; - } - $parameters['device_profile_uuid'] = $device_profile_uuid; - $keys = $this->database->select($sql, $parameters, 'all'); - - //add the profile keys to the device keys array - if (is_array($keys) && sizeof($keys) != 0) { - foreach($keys as $row) { - //set the variables - $id = $row['device_key_id']; - $category = $row['device_key_category']; - $device_key_vendor = $row['device_key_vendor']; - $device_key_line = $row['device_key_line']; - - //build the device keys array - $device_keys[$category][$id] = $row; - $device_lines[$device_key_line]['device_key_owner'] = "profile"; - - //add line_keys to the polycom array - if ($row['device_key_vendor'] == 'polycom' && $row['device_key_type'] == 'line') { - $device_lines[$device_key_line]['line_keys'] = $row['device_key_value']; - } - - //kept temporarily for backwards compatibility to allow custom templates to be updated - $device_keys[$id] = $row; - $device_keys[$id]['device_key_owner'] = "profile"; - } - } - unset($sql, $parameters, $keys); - } - - //get the device keys - $sql = "select * from v_device_keys "; - $sql .= "where device_uuid = :device_uuid "; - if (strtolower($device_vendor) == 'escene'){ - $sql .= "and (lower(device_key_vendor) = 'escene' or lower(device_key_vendor) = 'escene programmable' or device_key_vendor is null) "; - } - else { - $sql .= "and (lower(device_key_vendor) = :device_vendor or device_key_vendor is null) "; - $parameters['device_vendor'] = $device_vendor; - } - $sql .= "order by "; - $sql .= "device_key_vendor asc, "; - $sql .= "case device_key_category "; - $sql .= "when 'line' then 1 "; - $sql .= "when 'memory' then 2 "; - $sql .= "when 'programmable' then 3 "; - $sql .= "when 'expansion' then 4 "; - $sql .= "else 100 end, "; - if ($GLOBALS['db_type'] == "mysql") { - $sql .= "device_key_id asc "; - } - else { - $sql .= "cast(device_key_id as numeric) asc "; - } - $parameters['device_uuid'] = $device_uuid; - $keys = $this->database->select($sql, $parameters, 'all'); - - //override profile keys with the device keys - if (is_array($keys)) { - foreach($keys as $row) { - //set the variables - $id = $row['device_key_id']; - $category = $row['device_key_category']; - $device_key_line = $row['device_key_line']; - - //add line_keys to the polycom array - if ($row['device_key_vendor'] == 'polycom' && $row['device_key_type'] == 'line') { - $device_lines[$device_key_line]['line_keys'] = $row['device_key_value']; - } - - //build the device keys array - $device_keys[$category][$id] = $row; - $device_keys[$category][$id]['device_key_owner'] = "device"; - - //kept temporarily for backwards comptability to allow custom templates to be updated - $device_keys[$id] = $row; - $device_keys[$id]['device_key_owner'] = "device"; - } - } - unset($sql, $parameters, $keys); - - //replace the ${caller_id_name} with the extensions caller id name - if (is_array($device_keys)) { - foreach($device_keys as $row) { - //set the variables - $id = $row['device_key_id']; - $category = $row['device_key_category']; - - //build the device keys array - if (in_array($device_key_vendor, ['cisco', 'spa']) && $row['device_key_type'] == 'disabled') { - $device_key_array = explode(';', $row['device_key_value']); - foreach($device_key_array as $sub_row) { - list($key, $value) = explode('=', $sub_row); - if ($key == 'sub') { - $extension = explode('@', $value)[0]; //remove the @PROXY - $caller_id_name = $extension_labels[$extension]['caller_id_name']; - $device_key_label = str_replace('${caller_id_name}', $caller_id_name, $row['device_key_label']); - $device_key_label = str_replace('${extension}', $extension, $device_key_label); - $device_key_label = str_replace('${user}', $extension, $device_key_label); - $device_keys[$category][$id]['device_key_label'] = $device_key_label; - } - } - } elseif (is_numeric($row['device_key_value'])) { - $extension = $row['device_key_value']; - $caller_id_name = $extension_labels[$row['device_key_value']]['caller_id_name']; - $device_key_label = str_replace('${caller_id_name}', $caller_id_name, $row['device_key_label']); - $device_key_label = str_replace('${extension}', $extension, $device_key_label); - $device_key_label = str_replace('${user}', $extension, $device_key_label); - $device_keys[$category][$id]['device_key_label'] = $device_key_label; - } - } - } - + //add the profile keys to the device keys array + if (is_array($keys) && sizeof($keys) != 0) { + foreach ($keys as $row) { //set the variables - if (is_array($device_lines) && sizeof($device_lines) != 0) { - foreach($device_lines as $row) { - //set the variables - $line_number = $row['line_number']; - $register_expires = $row['register_expires']; - $sip_transport = strtolower($row['sip_transport'] ?? 'tcp'); - $sip_port = $row['sip_port'] ?? '5060'; + $id = $row['device_key_id']; + $category = $row['device_key_category']; + $device_key_vendor = $row['device_key_vendor']; + $device_key_line = $row['device_key_line']; - //set defaults - if (empty($register_expires)) { $register_expires = "120"; } + //build the device keys array + $device_keys[$category][$id] = $row; + $device_lines[$device_key_line]['device_key_owner'] = "profile"; - //convert seconds to minutes for grandstream - if ($device_vendor == 'grandstream') { - $register_expires = round($register_expires / 60); - } - - //set a lines array index is the line number - $lines[$line_number] = $row; - $lines[$line_number]['register_expires'] = $register_expires; - $lines[$line_number]['sip_transport'] = strtolower($sip_transport); - $lines[$line_number]['sip_port'] = $sip_port; - $lines[$line_number]['server_address'] = $row["server_address"]; - $lines[$line_number]['outbound_proxy'] = $row["outbound_proxy_primary"]; - $lines[$line_number]['server'][1]['address'] = $row["server_address_primary"]; - $lines[$line_number]['server'][2]['address'] = $row["server_address_secondary"]; - $lines[$line_number]['outbound_proxy_primary'] = $row["outbound_proxy_primary"]; - $lines[$line_number]['outbound_proxy_secondary'] = $row["outbound_proxy_secondary"]; - $lines[$line_number]['display_name'] = $row["display_name"]; - $lines[$line_number]['auth_id'] = $row["auth_id"]; - $lines[$line_number]['user_id'] = $row["user_id"]; - $lines[$line_number]['password'] = $row["password"]; - $lines[$line_number]['user_password'] = $row["password"]; - $lines[$line_number]['shared_line'] = $row["shared_line"]; - - //assign the variables for line one - short name - if ($line_number == "1") { - $view->assign("server_address", $row["server_address"]); - $view->assign("outbound_proxy", $row["outbound_proxy_primary"]); - $view->assign("outbound_proxy_primary", $row["outbound_proxy_primary"]); - $view->assign("outbound_proxy_secondary", $row["outbound_proxy_secondary"]); - $view->assign("display_name", $row["display_name"]); - $view->assign("auth_id", $row["auth_id"]); - $view->assign("user_id", $row["user_id"]); - $view->assign("sip_transport", $sip_transport); - $view->assign("sip_port", $sip_port); - $view->assign("register_expires", $register_expires); - $view->assign("shared_line", $row["shared_line"]); - } - - //assign the variables with the line number as part of the name - $view->assign("server_address_".$line_number, $row["server_address"]); - $view->assign("outbound_proxy_".$line_number, $row["outbound_proxy_primary"]); - $view->assign("outbound_proxy_primary_".$line_number, $row["outbound_proxy_primary"]); - $view->assign("outbound_proxy_secondary_".$line_number, $row["outbound_proxy_secondary"]); - $view->assign("display_name_".$line_number, $row["display_name"]); - $view->assign("auth_id_".$line_number, $row["auth_id"]); - $view->assign("user_id_".$line_number, $row["user_id"]); - $view->assign("user_password_".$line_number, $row["password"]); - $view->assign("sip_transport_".$line_number, $sip_transport); - $view->assign("sip_port_".$line_number, $sip_port); - $view->assign("register_expires_".$line_number, $register_expires); - $view->assign("shared_line_".$line_number, $row["shared_line"]); - } - } - } - - //assign the arrays - $view->assign("lines", $lines); - $view->assign("account", $lines); - $view->assign("user", $lines); - - //get the list of contact directly assigned to the user - if (is_uuid($domain_uuid)) { - if ($this->settings->get('contact','permissions',false)) { - //get the contacts assigned to the groups and add to the contacts array - if (is_uuid($device_user_uuid) && $this->settings->get('contact','contact_groups', false)) { - $this->contact_append($contacts, $line, $domain_uuid, $device_user_uuid, 'groups'); - } - - //get the contacts assigned to the user and add to the contacts array - if (is_uuid($device_user_uuid) && $this->settings->get('contact','contact_users', false)) { - $this->contact_append($contacts, $line, $domain_uuid, $device_user_uuid, 'users'); - } - } - else { - //show all contacts for the domain - $this->contact_append($contacts, $line, $domain_uuid, null, 'all'); + //add line_keys to the polycom array + if ($row['device_key_vendor'] == 'polycom' && $row['device_key_type'] == 'line') { + $device_lines[$device_key_line]['line_keys'] = $row['device_key_value']; } + + //kept temporarily for backwards compatibility to allow custom templates to be updated + $device_keys[$id] = $row; + $device_keys[$id]['device_key_owner'] = "profile"; + } + } + unset($sql, $parameters, $keys); + } + + //get the device keys + $sql = "select * from v_device_keys "; + $sql .= "where device_uuid = :device_uuid "; + if (strtolower($device_vendor) == 'escene') { + $sql .= "and (lower(device_key_vendor) = 'escene' or lower(device_key_vendor) = 'escene programmable' or device_key_vendor is null) "; + } else { + $sql .= "and (lower(device_key_vendor) = :device_vendor or device_key_vendor is null) "; + $parameters['device_vendor'] = $device_vendor; + } + $sql .= "order by "; + $sql .= "device_key_vendor asc, "; + $sql .= "case device_key_category "; + $sql .= "when 'line' then 1 "; + $sql .= "when 'memory' then 2 "; + $sql .= "when 'programmable' then 3 "; + $sql .= "when 'expansion' then 4 "; + $sql .= "else 100 end, "; + if ($GLOBALS['db_type'] == "mysql") { + $sql .= "device_key_id asc "; + } else { + $sql .= "cast(device_key_id as numeric) asc "; + } + $parameters['device_uuid'] = $device_uuid; + $keys = $this->database->select($sql, $parameters, 'all'); + + //override profile keys with the device keys + if (is_array($keys)) { + foreach ($keys as $row) { + //set the variables + $id = $row['device_key_id']; + $category = $row['device_key_category']; + $device_key_line = $row['device_key_line']; + + //add line_keys to the polycom array + if ($row['device_key_vendor'] == 'polycom' && $row['device_key_type'] == 'line') { + $device_lines[$device_key_line]['line_keys'] = $row['device_key_value']; } - //get the extensions and add them to the contacts array - if (is_uuid($device_uuid) && is_uuid($domain_uuid) && $this->settings->get('provision','contact_extensions',false)) { + //build the device keys array + $device_keys[$category][$id] = $row; + $device_keys[$category][$id]['device_key_owner'] = "device"; - //get contacts from the database - $sql = "select extension_uuid as contact_uuid, directory_first_name, directory_last_name, "; - $sql .= "effective_caller_id_name, effective_caller_id_number, "; - $sql .= "number_alias, extension, call_group "; - $sql .= "from v_extensions "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and enabled = true "; - $sql .= "and directory_visible = 'true' "; - $sql .= "order by directory_first_name, effective_caller_id_name asc "; - $parameters['domain_uuid'] = $domain_uuid; - $extensions = $this->database->select($sql, $parameters, 'all'); - if (is_array($extensions) && sizeof($extensions) != 0) { - foreach ($extensions as $row) { - //get the contact_uuid - $uuid = $row['contact_uuid']; - //get the names - if (!empty($row['directory_first_name'])) { - $contact_name_given = $row['directory_first_name']; - $contact_name_family = $row['directory_last_name']; - } else { - $name_array = explode(" ", $row['effective_caller_id_name'] ?? ''); - $contact_name_given = array_shift($name_array); - $contact_name_family = trim(implode(' ', $name_array)); - } - //get the phone_extension - if (is_numeric($row['extension'])) { - $phone_extension = $row['extension']; - } - else { - $phone_extension = $row['number_alias']; - } - //save the contact array values - $contacts[$uuid]['category'] = 'extensions'; - $contacts[$uuid]['contact_uuid'] = $row['contact_uuid']; - $contacts[$uuid]['contact_category'] = 'extensions'; - $contacts[$uuid]['contact_name_given'] = $contact_name_given; - $contacts[$uuid]['contact_name_family'] = $contact_name_family; - $contacts[$uuid]['phone_extension'] = $phone_extension; - $contacts[$uuid]['call_group'] = $row['call_group']; - //unset the variables - unset($name_array, $contact_name_given, $contact_name_family, $phone_extension); - } - } - unset($sql, $parameters); - } + //kept temporarily for backwards comptability to allow custom templates to be updated + $device_keys[$id] = $row; + $device_keys[$id]['device_key_owner'] = "device"; + } + } + unset($sql, $parameters, $keys); - //assign the contacts array to the template - if (is_array($contacts)) { - $view->assign("contacts", $contacts); - unset($contacts); - } + //replace the ${caller_id_name} with the extensions caller id name + if (is_array($device_keys)) { + foreach ($device_keys as $row) { + //set the variables + $id = $row['device_key_id']; + $category = $row['device_key_category']; - //debug information - if ($debug == "array") { - echo "
    \n";
    -						print_r($device_lines);
    -						print_r($device_keys);
    -						echo "
    \n";
    -						exit;
    -					}
    -
    -				//list of variable names
    -					$variable_names = [];
    -					$variable_names[] = 'domain_name';
    -					$variable_names[] = 'user_id';
    -					$variable_names[] = 'auth_id';
    -					$variable_names[] = 'extension';
    -					$variable_names[] = 'register_expires';
    -					$variable_names[] = 'sip_transport';
    -					$variable_names[] = 'sip_port';
    -					$variable_names[] = 'server_address';
    -					$variable_names[] = 'outbound_proxy';
    -					$variable_names[] = 'outbound_proxy_primary';
    -					$variable_names[] = 'outbound_proxy_secondary';
    -					$variable_names[] = 'display_name';
    -					$variable_names[] = 'location';
    -					$variable_names[] = 'description';
    -
    -				//add location and description to the lines array
    -					foreach($lines as $id => $row) {
    -						$lines[$id]['location'] = $device_location;
    -						$lines[$id]['description'] = $device_description;
    -					}
    -
    -				//update the device keys by replacing variables with their values
    -					if (!empty($device_keys['line']) && is_array($device_keys)) {
    -						$types = array("line", "memory", "expansion", "programmable");
    -						foreach ($types as $type) {
    -							if (!empty($device_keys[$type]) && is_array($device_keys[$type])) {
    -								foreach($device_keys[$type] as $row) {
    -									//get the variables
    -									$device_key_line = $row['device_key_line'];
    -									$device_key_id = $row['device_key_id'];
    -									$device_key_value = $row['device_key_value'];
    -									$device_key_extension = $row['device_key_extension'];
    -									$device_key_label = $row['device_key_label'];
    -									$device_key_icon = $row['device_key_icon'];
    -
    -									//replace the variables
    -									foreach($variable_names as $name) {
    -										if (!empty($row['device_key_value'])) {
    -											$device_key_value = str_replace("\${".$name."}", $lines[$device_key_line][$name], $device_key_value);
    -										}
    -										if (!empty($row['device_key_extension'])) {
    -											$device_key_extension = str_replace("\${".$name."}", $lines[$device_key_line][$name], $device_key_extension);
    -										}
    -										if (!empty($row['device_key_label'])) {
    -											$device_key_label = str_replace("\${".$name."}", $lines[$device_key_line][$name], $device_key_label);
    -										}
    -										if (!empty($row['device_key_icon'])) {
    -											$device_key_icon = str_replace("\${".$name."}", $lines[$device_key_line][$name], $device_key_icon);
    -										}
    -									}
    -
    -									//update the device kyes array
    -									$device_keys[$type][$device_key_id]['device_key_value'] = $device_key_value;
    -									$device_keys[$type][$device_key_id]['device_key_extension'] = $device_key_extension;
    -									$device_keys[$type][$device_key_id]['device_key_label'] = $device_key_label;
    -									$device_keys[$type][$device_key_id]['device_key_icon'] = $device_key_icon;
    -								}
    +					//build the device keys array
    +					if (in_array($device_key_vendor, ['cisco', 'spa']) && $row['device_key_type'] == 'disabled') {
    +						$device_key_array = explode(';', $row['device_key_value']);
    +						foreach ($device_key_array as $sub_row) {
    +							[$key, $value] = explode('=', $sub_row);
    +							if ($key == 'sub') {
    +								$extension                                       = explode('@', $value)[0]; //remove the @PROXY
    +								$caller_id_name                                  = $extension_labels[$extension]['caller_id_name'];
    +								$device_key_label                                = str_replace('${caller_id_name}', $caller_id_name, $row['device_key_label']);
    +								$device_key_label                                = str_replace('${extension}', $extension, $device_key_label);
    +								$device_key_label                                = str_replace('${user}', $extension, $device_key_label);
    +								$device_keys[$category][$id]['device_key_label'] = $device_key_label;
     							}
     						}
    +					} elseif (is_numeric($row['device_key_value'])) {
    +						$extension                                       = $row['device_key_value'];
    +						$caller_id_name                                  = $extension_labels[$row['device_key_value']]['caller_id_name'];
    +						$device_key_label                                = str_replace('${caller_id_name}', $caller_id_name, $row['device_key_label']);
    +						$device_key_label                                = str_replace('${extension}', $extension, $device_key_label);
    +						$device_key_label                                = str_replace('${user}', $extension, $device_key_label);
    +						$device_keys[$category][$id]['device_key_label'] = $device_key_label;
    +					}
    +				}
    +			}
    +
    +			//set the variables
    +			if (is_array($device_lines) && sizeof($device_lines) != 0) {
    +				foreach ($device_lines as $row) {
    +					//set the variables
    +					$line_number      = $row['line_number'];
    +					$register_expires = $row['register_expires'];
    +					$sip_transport    = strtolower($row['sip_transport'] ?? 'tcp');
    +					$sip_port         = $row['sip_port'] ?? '5060';
    +
    +					//set defaults
    +					if (empty($register_expires)) {
    +						$register_expires = "120";
     					}
     
    -				//assign the keys array
    -					if (!empty($device_keys)) {
    -						$view->assign("keys", $device_keys);
    +					//convert seconds to minutes for grandstream
    +					if ($device_vendor == 'grandstream') {
    +						$register_expires = round($register_expires / 60);
     					}
     
    -				//set the variables
    -					$types = array("line", "memory", "expansion", "programmable");
    -					foreach ($types as $type) {
    -						if (!empty($device_keys[$type]) && is_array($device_keys[$type])) {
    -							foreach($device_keys[$type] as $row) {
    -								//set the variables
    -									$device_key_category = $row['device_key_category'];
    -									$device_key_id = $row['device_key_id']; //1
    -									$device_key_type = $row['device_key_type']; //line
    -									$device_key_line = $row['device_key_line'];
    -									$device_key_value = $row['device_key_value']; //1
    -									$device_key_extension = $row['device_key_extension'];
    -									$device_key_label = $row['device_key_label']; //label
    -									$device_key_icon = $row['device_key_icon']; //icon
    +					//set a lines array index is the line number
    +					$lines[$line_number]                             = $row;
    +					$lines[$line_number]['register_expires']         = $register_expires;
    +					$lines[$line_number]['sip_transport']            = strtolower($sip_transport);
    +					$lines[$line_number]['sip_port']                 = $sip_port;
    +					$lines[$line_number]['server_address']           = $row["server_address"];
    +					$lines[$line_number]['outbound_proxy']           = $row["outbound_proxy_primary"];
    +					$lines[$line_number]['server'][1]['address']     = $row["server_address_primary"];
    +					$lines[$line_number]['server'][2]['address']     = $row["server_address_secondary"];
    +					$lines[$line_number]['outbound_proxy_primary']   = $row["outbound_proxy_primary"];
    +					$lines[$line_number]['outbound_proxy_secondary'] = $row["outbound_proxy_secondary"];
    +					$lines[$line_number]['display_name']             = $row["display_name"];
    +					$lines[$line_number]['auth_id']                  = $row["auth_id"];
    +					$lines[$line_number]['user_id']                  = $row["user_id"];
    +					$lines[$line_number]['password']                 = $row["password"];
    +					$lines[$line_number]['user_password']            = $row["password"];
    +					$lines[$line_number]['shared_line']              = $row["shared_line"];
     
    -								//add general variables
    -									$device_key_value = str_replace("\${domain_name}", $domain_name, $device_key_value);
    -									$device_key_extension = str_replace("\${domain_name}", $domain_name, $device_key_extension);
    -									$device_key_label = str_replace("\${domain_name}", $domain_name, $device_key_label);
    -									$device_key_icon = str_replace("\${domain_name}", $domain_name, $device_key_icon);
    +					//assign the variables for line one - short name
    +					if ($line_number == "1") {
    +						$view->assign("server_address", $row["server_address"]);
    +						$view->assign("outbound_proxy", $row["outbound_proxy_primary"]);
    +						$view->assign("outbound_proxy_primary", $row["outbound_proxy_primary"]);
    +						$view->assign("outbound_proxy_secondary", $row["outbound_proxy_secondary"]);
    +						$view->assign("display_name", $row["display_name"]);
    +						$view->assign("auth_id", $row["auth_id"]);
    +						$view->assign("user_id", $row["user_id"]);
    +						$view->assign("sip_transport", $sip_transport);
    +						$view->assign("sip_port", $sip_port);
    +						$view->assign("register_expires", $register_expires);
    +						$view->assign("shared_line", $row["shared_line"]);
    +					}
     
    -								//grandstream modes are different based on the category
    -									if ($device_vendor == "grandstream") {
    -										if ($device_key_category == "line") {
    -											switch ($device_key_type) {
    -												case "line": $device_key_type  = "0"; break;
    -												case "shared line": $device_key_type  = "1"; break;
    -												case "speed dial": $device_key_type  = "10"; break;
    -												case "blf": $device_key_type  = "11"; break;
    -												case "presence watcher": $device_key_type  = "12"; break;
    -												case "eventlist blf": $device_key_type  = "13"; break;
    -												case "speed dial active": $device_key_type  = "14"; break;
    -												case "dial dtmf": $device_key_type  = "15"; break;
    -												case "voicemail": $device_key_type  = "16"; break;
    -												case "call return": $device_key_type  = "17"; break;
    -												case "transfer": $device_key_type  = "18"; break;
    -												case "call park": $device_key_type  = "19"; break;
    -												case "monitored call park": $device_key_type  = "26"; break;
    -												case "intercom": $device_key_type  = "20"; break;
    -												case "ldap search": $device_key_type  = "21"; break;
    -												case "phonebook": $device_key_type = "30"; break;
    -											}
    -										}
    -										if ($device_key_category == "memory" || $device_key_category == "expansion") {
    -											switch ($device_key_type) {
    -												case "speed dial": $device_key_type  = "0"; break;
    -												case "blf": $device_key_type  = "1"; break;
    -												case "presence watcher": $device_key_type  = "2"; break;
    -												case "eventlist blf": $device_key_type  = "3"; break;
    -												case "speed dial active": $device_key_type  = "4"; break;
    -												case "dial dtmf": $device_key_type  = "5"; break;
    -												case "voicemail": $device_key_type  = "6"; break;
    -												case "call return": $device_key_type  = "7"; break;
    -												case "transfer": $device_key_type  = "8"; break;
    -												case "call park": $device_key_type  = "9"; break;
    -												case "monitored call park": $device_key_type  = "16"; break;
    -												case "intercom": $device_key_type  = "10"; break;
    -												case "ldap search": $device_key_type  = "11"; break;
    -											}
    -										}
    -									}
    +					//assign the variables with the line number as part of the name
    +					$view->assign("server_address_" . $line_number, $row["server_address"]);
    +					$view->assign("outbound_proxy_" . $line_number, $row["outbound_proxy_primary"]);
    +					$view->assign("outbound_proxy_primary_" . $line_number, $row["outbound_proxy_primary"]);
    +					$view->assign("outbound_proxy_secondary_" . $line_number, $row["outbound_proxy_secondary"]);
    +					$view->assign("display_name_" . $line_number, $row["display_name"]);
    +					$view->assign("auth_id_" . $line_number, $row["auth_id"]);
    +					$view->assign("user_id_" . $line_number, $row["user_id"]);
    +					$view->assign("user_password_" . $line_number, $row["password"]);
    +					$view->assign("sip_transport_" . $line_number, $sip_transport);
    +					$view->assign("sip_port_" . $line_number, $sip_port);
    +					$view->assign("register_expires_" . $line_number, $register_expires);
    +					$view->assign("shared_line_" . $line_number, $row["shared_line"]);
    +				}
    +			}
    +		}
     
    -								//assign the variables
    -									if (empty($device_key_category)) {
    -										$view->assign("key_id_".$device_key_id, $device_key_id);
    -										$view->assign("key_type_".$device_key_id, $device_key_type);
    -										$view->assign("key_line_".$device_key_id, $device_key_line);
    -										$view->assign("key_value_".$device_key_id, $device_key_value);
    -										$view->assign("key_extension_".$device_key_id, $device_key_extension);
    -										$view->assign("key_label_".$device_key_id, $device_key_label);
    -										$view->assign("key_icon_".$device_key_id, $device_key_icon);
    -									}
    -									else {
    -										$view->assign($device_key_category."_key_id_".$device_key_id, $device_key_id);
    -										$view->assign($device_key_category."_key_type_".$device_key_id, $device_key_type);
    -										$view->assign($device_key_category."_key_line_".$device_key_id, $device_key_line);
    -										$view->assign($device_key_category."_key_value_".$device_key_id, $device_key_value);
    -										$view->assign($device_key_category."_key_extension_".$device_key_id, $device_key_extension);
    -										$view->assign($device_key_category."_key_label_".$device_key_id, $device_key_label);
    -										$view->assign($device_key_category."_key_icon_".$device_key_id, $device_key_icon);
    -									}
    +		//assign the arrays
    +		$view->assign("lines", $lines);
    +		$view->assign("account", $lines);
    +		$view->assign("user", $lines);
    +
    +		//get the list of contact directly assigned to the user
    +		if (is_uuid($domain_uuid)) {
    +			if ($this->settings->get('contact', 'permissions', false)) {
    +				//get the contacts assigned to the groups and add to the contacts array
    +				if (is_uuid($device_user_uuid) && $this->settings->get('contact', 'contact_groups', false)) {
    +					$this->contact_append($contacts, $line, $domain_uuid, $device_user_uuid, 'groups');
    +				}
    +
    +				//get the contacts assigned to the user and add to the contacts array
    +				if (is_uuid($device_user_uuid) && $this->settings->get('contact', 'contact_users', false)) {
    +					$this->contact_append($contacts, $line, $domain_uuid, $device_user_uuid, 'users');
    +				}
    +			} else {
    +				//show all contacts for the domain
    +				$this->contact_append($contacts, $line, $domain_uuid, null, 'all');
    +			}
    +		}
    +
    +		//get the extensions and add them to the contacts array
    +		if (is_uuid($device_uuid) && is_uuid($domain_uuid) && $this->settings->get('provision', 'contact_extensions', false)) {
    +
    +			//get contacts from the database
    +			$sql                       = "select extension_uuid as contact_uuid, directory_first_name, directory_last_name, ";
    +			$sql                       .= "effective_caller_id_name, effective_caller_id_number, ";
    +			$sql                       .= "number_alias, extension, call_group ";
    +			$sql                       .= "from v_extensions ";
    +			$sql                       .= "where domain_uuid = :domain_uuid ";
    +			$sql                       .= "and enabled = true ";
    +			$sql                       .= "and directory_visible = 'true' ";
    +			$sql                       .= "order by directory_first_name, effective_caller_id_name asc ";
    +			$parameters['domain_uuid'] = $domain_uuid;
    +			$extensions                = $this->database->select($sql, $parameters, 'all');
    +			if (is_array($extensions) && sizeof($extensions) != 0) {
    +				foreach ($extensions as $row) {
    +					//get the contact_uuid
    +					$uuid = $row['contact_uuid'];
    +					//get the names
    +					if (!empty($row['directory_first_name'])) {
    +						$contact_name_given  = $row['directory_first_name'];
    +						$contact_name_family = $row['directory_last_name'];
    +					} else {
    +						$name_array          = explode(" ", $row['effective_caller_id_name'] ?? '');
    +						$contact_name_given  = array_shift($name_array);
    +						$contact_name_family = trim(implode(' ', $name_array));
    +					}
    +					//get the phone_extension
    +					if (is_numeric($row['extension'])) {
    +						$phone_extension = $row['extension'];
    +					} else {
    +						$phone_extension = $row['number_alias'];
    +					}
    +					//save the contact array values
    +					$contacts[$uuid]['category']            = 'extensions';
    +					$contacts[$uuid]['contact_uuid']        = $row['contact_uuid'];
    +					$contacts[$uuid]['contact_category']    = 'extensions';
    +					$contacts[$uuid]['contact_name_given']  = $contact_name_given;
    +					$contacts[$uuid]['contact_name_family'] = $contact_name_family;
    +					$contacts[$uuid]['phone_extension']     = $phone_extension;
    +					$contacts[$uuid]['call_group']          = $row['call_group'];
    +					//unset the variables
    +					unset($name_array, $contact_name_given, $contact_name_family, $phone_extension);
    +				}
    +			}
    +			unset($sql, $parameters);
    +		}
    +
    +		//assign the contacts array to the template
    +		if (is_array($contacts)) {
    +			$view->assign("contacts", $contacts);
    +			unset($contacts);
    +		}
    +
    +		//debug information
    +		if ($debug == "array") {
    +			echo "
    \n";
    +			print_r($device_lines);
    +			print_r($device_keys);
    +			echo "
    \n";
    +			exit;
    +		}
    +
    +		//list of variable names
    +		$variable_names   = [];
    +		$variable_names[] = 'domain_name';
    +		$variable_names[] = 'user_id';
    +		$variable_names[] = 'auth_id';
    +		$variable_names[] = 'extension';
    +		$variable_names[] = 'register_expires';
    +		$variable_names[] = 'sip_transport';
    +		$variable_names[] = 'sip_port';
    +		$variable_names[] = 'server_address';
    +		$variable_names[] = 'outbound_proxy';
    +		$variable_names[] = 'outbound_proxy_primary';
    +		$variable_names[] = 'outbound_proxy_secondary';
    +		$variable_names[] = 'display_name';
    +		$variable_names[] = 'location';
    +		$variable_names[] = 'description';
    +
    +		//add location and description to the lines array
    +		foreach ($lines as $id => $row) {
    +			$lines[$id]['location']    = $device_location;
    +			$lines[$id]['description'] = $device_description;
    +		}
    +
    +		//update the device keys by replacing variables with their values
    +		if (!empty($device_keys['line']) && is_array($device_keys)) {
    +			$types = ["line", "memory", "expansion", "programmable"];
    +			foreach ($types as $type) {
    +				if (!empty($device_keys[$type]) && is_array($device_keys[$type])) {
    +					foreach ($device_keys[$type] as $row) {
    +						//get the variables
    +						$device_key_line      = $row['device_key_line'];
    +						$device_key_id        = $row['device_key_id'];
    +						$device_key_value     = $row['device_key_value'];
    +						$device_key_extension = $row['device_key_extension'];
    +						$device_key_label     = $row['device_key_label'];
    +						$device_key_icon      = $row['device_key_icon'];
    +
    +						//replace the variables
    +						foreach ($variable_names as $name) {
    +							if (!empty($row['device_key_value'])) {
    +								$device_key_value = str_replace("\${" . $name . "}", $lines[$device_key_line][$name], $device_key_value);
     							}
    -						}
    -					}
    -
    -				//set the device address in the correct format
    -					$device_address = $this->format_address($device_address, $device_vendor);
    -
    -				//set date/time for versioning provisioning templates
    -					$time = date($this->settings->get('provision','version_format', "dmyHi"));
    -
    -				//replace the variables in the template in the future loop through all the line numbers to do a replace for each possible line number
    -					$view->assign("device_address", $device_address);
    -					$view->assign("address", $device_address);
    -					$view->assign("mac", $device_address);
    -					$view->assign("time", $time);
    -					$view->assign("label", $device_label);
    -					$view->assign("device_label", $device_label);
    -					$view->assign("firmware_version", $device_firmware_version);
    -					$view->assign("domain_name", $domain_name);
    -					$view->assign("project_path", PROJECT_PATH);
    -					$view->assign("server1_address", $server1_address ?? '');
    -					$view->assign("proxy1_address", $proxy1_address ?? '');
    -					$view->assign("user_id", $user_id ?? '');
    -					$view->assign("password", $password ?? '');
    -					$view->assign("template", $device_template);
    -					$view->assign("location", $device_location);
    -					$view->assign("device_location", $device_location);
    -					$view->assign("microtime", microtime(true));
    -
    -				//personal ldap password
    -					global $laddr_salt;
    -					if (is_uuid($device_user_uuid)) {
    -						$sql = "select contact_uuid from v_users where user_uuid = :device_user_uuid ";
    -						$parameters['device_user_uuid'] = $device_user_uuid;
    -						$contact_uuid = $this->database->select($sql, $parameters, 'column');
    -						$view->assign("ldap_username", "uid=" . $contact_uuid . "," . $this->settings->get('provision','grandstream_ldap_user_base', ''));
    -						$view->assign("ldap_password",md5($laddr_salt.$device_user_uuid));
    -						unset($sql, $parameters);
    -					}
    -
    -				//get the time zone
    -					$time_zone = $this->settings->get('domain','time_zone', 'UTC');
    -
    -				//auto calculate the daylight savings settings
    -					if ($this->settings->get('provision','daylight_savings_auto', true)) {
    -						//initialize the variables
    -						$daylight_savings_start = null;
    -						$daylight_savings_end = null;
    -
    -						//prepare the daylight saving dates and build the transitions
    -						date_default_timezone_set($time_zone);
    -						$current_year = date('Y');
    -						$tz = new DateTimeZone($time_zone);
    -						$start_of_year = new DateTime($current_year.'-01-01 00:00:00', $tz);
    -						$end_of_year = new DateTime($current_year.'-12-31 23:59:59', $tz);
    -						$transitions = $tz->getTransitions($start_of_year->getTimestamp(), $end_of_year->getTimestamp());
    -
    -						//add the daylight savings to the provision array
    -						foreach ($transitions as $transition) {
    -							if ($transition['isdst']) {
    -								//daylight savings time
    -								if ($daylight_savings_start === null || $transition['ts'] < $daylight_savings_start) {
    -									$daylight_savings_start = $transition['ts'];
    -								}
    -							} else {
    -								//standard time
    -								$standard_offset_seconds = $transition['offset'];
    +							if (!empty($row['device_key_extension'])) {
    +								$device_key_extension = str_replace("\${" . $name . "}", $lines[$device_key_line][$name], $device_key_extension);
    +							}
    +							if (!empty($row['device_key_label'])) {
    +								$device_key_label = str_replace("\${" . $name . "}", $lines[$device_key_line][$name], $device_key_label);
    +							}
    +							if (!empty($row['device_key_icon'])) {
    +								$device_key_icon = str_replace("\${" . $name . "}", $lines[$device_key_line][$name], $device_key_icon);
     							}
     						}
     
    -						//find the end of daylight saving time
    -						foreach ($transitions as $transition) {
    -							if (!$transition['isdst']) {
    -								// daylight saving time end
    -								if ($daylight_savings_start !== null && $transition['ts'] > $daylight_savings_start) {
    -									$daylight_savings_end = $transition['ts'];
    +						//update the device kyes array
    +						$device_keys[$type][$device_key_id]['device_key_value']     = $device_key_value;
    +						$device_keys[$type][$device_key_id]['device_key_extension'] = $device_key_extension;
    +						$device_keys[$type][$device_key_id]['device_key_label']     = $device_key_label;
    +						$device_keys[$type][$device_key_id]['device_key_icon']      = $device_key_icon;
    +					}
    +				}
    +			}
    +		}
    +
    +		//assign the keys array
    +		if (!empty($device_keys)) {
    +			$view->assign("keys", $device_keys);
    +		}
    +
    +		//set the variables
    +		$types = ["line", "memory", "expansion", "programmable"];
    +		foreach ($types as $type) {
    +			if (!empty($device_keys[$type]) && is_array($device_keys[$type])) {
    +				foreach ($device_keys[$type] as $row) {
    +					//set the variables
    +					$device_key_category  = $row['device_key_category'];
    +					$device_key_id        = $row['device_key_id']; //1
    +					$device_key_type      = $row['device_key_type']; //line
    +					$device_key_line      = $row['device_key_line'];
    +					$device_key_value     = $row['device_key_value']; //1
    +					$device_key_extension = $row['device_key_extension'];
    +					$device_key_label     = $row['device_key_label']; //label
    +					$device_key_icon      = $row['device_key_icon']; //icon
    +
    +					//add general variables
    +					$device_key_value     = str_replace("\${domain_name}", $domain_name, $device_key_value);
    +					$device_key_extension = str_replace("\${domain_name}", $domain_name, $device_key_extension);
    +					$device_key_label     = str_replace("\${domain_name}", $domain_name, $device_key_label);
    +					$device_key_icon      = str_replace("\${domain_name}", $domain_name, $device_key_icon);
    +
    +					//grandstream modes are different based on the category
    +					if ($device_vendor == "grandstream") {
    +						if ($device_key_category == "line") {
    +							switch ($device_key_type) {
    +								case "line":
    +									$device_key_type = "0";
    +									break;
    +								case "shared line":
    +									$device_key_type = "1";
    +									break;
    +								case "speed dial":
    +									$device_key_type = "10";
    +									break;
    +								case "blf":
    +									$device_key_type = "11";
    +									break;
    +								case "presence watcher":
    +									$device_key_type = "12";
    +									break;
    +								case "eventlist blf":
    +									$device_key_type = "13";
    +									break;
    +								case "speed dial active":
    +									$device_key_type = "14";
    +									break;
    +								case "dial dtmf":
    +									$device_key_type = "15";
    +									break;
    +								case "voicemail":
    +									$device_key_type = "16";
    +									break;
    +								case "call return":
    +									$device_key_type = "17";
    +									break;
    +								case "transfer":
    +									$device_key_type = "18";
    +									break;
    +								case "call park":
    +									$device_key_type = "19";
    +									break;
    +								case "monitored call park":
    +									$device_key_type = "26";
    +									break;
    +								case "intercom":
    +									$device_key_type = "20";
    +									break;
    +								case "ldap search":
    +									$device_key_type = "21";
    +									break;
    +								case "phonebook":
    +									$device_key_type = "30";
     									break;
    -								}
     							}
     						}
    -
    -						//prepare the provision array
    -						if ($daylight_savings_start !== null) {
    -							$provision["daylight_savings_start"] = date('Y-m-d H:i:s', $daylight_savings_start);
    -							$provision["daylight_savings_start_month"] = date('m', $daylight_savings_start);
    -							$provision["daylight_savings_start_day"] = date('d', $daylight_savings_start);
    -							$provision["daylight_savings_start_time"] = date('H', $daylight_savings_start);
    -						}
    -						if ($daylight_savings_end !== null) {
    -							$provision["daylight_savings_stop"] = date('Y-m-d H:i:s', $daylight_savings_end);
    -							$provision["daylight_savings_stop_month"] = date('m', $daylight_savings_end);
    -							$provision["daylight_savings_stop_day"] = date('d', $daylight_savings_end);
    -							$provision["daylight_savings_stop_time"] = date('H', $daylight_savings_end);
    -						}
    -
    -						//add a generic gmt_offset
    -						$provision["gmt_offset"] = $standard_offset_seconds;
    -
    -						//set daylight savings settings for polycom
    -						$provision["polycom_gmt_offset"] = $standard_offset_seconds;
    -					}
    -
    -				//set daylight savings settings time for yealink
    -					if (!isset($provision["yealink_time_zone_start_time"])) {
    -						$provision["yealink_time_zone_start_time"] = $provision["daylight_savings_start_month"]."/".$provision["daylight_savings_start_day"]."/".$provision["daylight_savings_start_time"];
    -					}
    -					if (!isset($provision["yealink_time_zone_end_time"])) {
    -						$provision["yealink_time_zone_end_time"] = $provision["daylight_savings_stop_month"]."/".$provision["daylight_savings_stop_day"]."/".$provision["daylight_savings_stop_time"];
    -					}
    -
    -				//replace the dynamic provision variables that are defined in default, domain, and device settings
    -					if (is_array($provision)) {
    -						foreach($provision as $key=>$val) {
    -							if (!empty($val) && is_string($val) && strpos($val, '{$domain_name}') !== false) {
    -								$val = str_replace('{$domain_name}', $domain_name, $val);
    +						if ($device_key_category == "memory" || $device_key_category == "expansion") {
    +							switch ($device_key_type) {
    +								case "speed dial":
    +									$device_key_type = "0";
    +									break;
    +								case "blf":
    +									$device_key_type = "1";
    +									break;
    +								case "presence watcher":
    +									$device_key_type = "2";
    +									break;
    +								case "eventlist blf":
    +									$device_key_type = "3";
    +									break;
    +								case "speed dial active":
    +									$device_key_type = "4";
    +									break;
    +								case "dial dtmf":
    +									$device_key_type = "5";
    +									break;
    +								case "voicemail":
    +									$device_key_type = "6";
    +									break;
    +								case "call return":
    +									$device_key_type = "7";
    +									break;
    +								case "transfer":
    +									$device_key_type = "8";
    +									break;
    +								case "call park":
    +									$device_key_type = "9";
    +									break;
    +								case "monitored call park":
    +									$device_key_type = "16";
    +									break;
    +								case "intercom":
    +									$device_key_type = "10";
    +									break;
    +								case "ldap search":
    +									$device_key_type = "11";
    +									break;
     							}
    -							if (!empty($val) && is_string($val) && strpos($val, '${domain_name}') !== false) {
    -								$val = str_replace('${domain_name}', $domain_name, $val);
    +						}
    +					}
    +
    +					//assign the variables
    +					if (empty($device_key_category)) {
    +						$view->assign("key_id_" . $device_key_id, $device_key_id);
    +						$view->assign("key_type_" . $device_key_id, $device_key_type);
    +						$view->assign("key_line_" . $device_key_id, $device_key_line);
    +						$view->assign("key_value_" . $device_key_id, $device_key_value);
    +						$view->assign("key_extension_" . $device_key_id, $device_key_extension);
    +						$view->assign("key_label_" . $device_key_id, $device_key_label);
    +						$view->assign("key_icon_" . $device_key_id, $device_key_icon);
    +					} else {
    +						$view->assign($device_key_category . "_key_id_" . $device_key_id, $device_key_id);
    +						$view->assign($device_key_category . "_key_type_" . $device_key_id, $device_key_type);
    +						$view->assign($device_key_category . "_key_line_" . $device_key_id, $device_key_line);
    +						$view->assign($device_key_category . "_key_value_" . $device_key_id, $device_key_value);
    +						$view->assign($device_key_category . "_key_extension_" . $device_key_id, $device_key_extension);
    +						$view->assign($device_key_category . "_key_label_" . $device_key_id, $device_key_label);
    +						$view->assign($device_key_category . "_key_icon_" . $device_key_id, $device_key_icon);
    +					}
    +				}
    +			}
    +		}
    +
    +		//set the device address in the correct format
    +		$device_address = $this->format_address($device_address, $device_vendor);
    +
    +		//set date/time for versioning provisioning templates
    +		$time = date($this->settings->get('provision', 'version_format', "dmyHi"));
    +
    +		//replace the variables in the template in the future loop through all the line numbers to do a replace for each possible line number
    +		$view->assign("device_address", $device_address);
    +		$view->assign("address", $device_address);
    +		$view->assign("mac", $device_address);
    +		$view->assign("time", $time);
    +		$view->assign("label", $device_label);
    +		$view->assign("device_label", $device_label);
    +		$view->assign("firmware_version", $device_firmware_version);
    +		$view->assign("domain_name", $domain_name);
    +		$view->assign("project_path", PROJECT_PATH);
    +		$view->assign("server1_address", $server1_address ?? '');
    +		$view->assign("proxy1_address", $proxy1_address ?? '');
    +		$view->assign("user_id", $user_id ?? '');
    +		$view->assign("password", $password ?? '');
    +		$view->assign("template", $device_template);
    +		$view->assign("location", $device_location);
    +		$view->assign("device_location", $device_location);
    +		$view->assign("microtime", microtime(true));
    +
    +		//personal ldap password
    +		global $laddr_salt;
    +		if (is_uuid($device_user_uuid)) {
    +			$sql                            = "select contact_uuid from v_users where user_uuid = :device_user_uuid ";
    +			$parameters['device_user_uuid'] = $device_user_uuid;
    +			$contact_uuid                   = $this->database->select($sql, $parameters, 'column');
    +			$view->assign("ldap_username", "uid=" . $contact_uuid . "," . $this->settings->get('provision', 'grandstream_ldap_user_base', ''));
    +			$view->assign("ldap_password", md5($laddr_salt . $device_user_uuid));
    +			unset($sql, $parameters);
    +		}
    +
    +		//get the time zone
    +		$time_zone = $this->settings->get('domain', 'time_zone', 'UTC');
    +
    +		//auto calculate the daylight savings settings
    +		if ($this->settings->get('provision', 'daylight_savings_auto', true)) {
    +			//initialize the variables
    +			$daylight_savings_start = null;
    +			$daylight_savings_end   = null;
    +
    +			//prepare the daylight saving dates and build the transitions
    +			date_default_timezone_set($time_zone);
    +			$current_year  = date('Y');
    +			$tz            = new DateTimeZone($time_zone);
    +			$start_of_year = new DateTime($current_year . '-01-01 00:00:00', $tz);
    +			$end_of_year   = new DateTime($current_year . '-12-31 23:59:59', $tz);
    +			$transitions   = $tz->getTransitions($start_of_year->getTimestamp(), $end_of_year->getTimestamp());
    +
    +			//add the daylight savings to the provision array
    +			foreach ($transitions as $transition) {
    +				if ($transition['isdst']) {
    +					//daylight savings time
    +					if ($daylight_savings_start === null || $transition['ts'] < $daylight_savings_start) {
    +						$daylight_savings_start = $transition['ts'];
    +					}
    +				} else {
    +					//standard time
    +					$standard_offset_seconds = $transition['offset'];
    +				}
    +			}
    +
    +			//find the end of daylight saving time
    +			foreach ($transitions as $transition) {
    +				if (!$transition['isdst']) {
    +					// daylight saving time end
    +					if ($daylight_savings_start !== null && $transition['ts'] > $daylight_savings_start) {
    +						$daylight_savings_end = $transition['ts'];
    +						break;
    +					}
    +				}
    +			}
    +
    +			//prepare the provision array
    +			if ($daylight_savings_start !== null) {
    +				$provision["daylight_savings_start"]       = date('Y-m-d H:i:s', $daylight_savings_start);
    +				$provision["daylight_savings_start_month"] = date('m', $daylight_savings_start);
    +				$provision["daylight_savings_start_day"]   = date('d', $daylight_savings_start);
    +				$provision["daylight_savings_start_time"]  = date('H', $daylight_savings_start);
    +			}
    +			if ($daylight_savings_end !== null) {
    +				$provision["daylight_savings_stop"]       = date('Y-m-d H:i:s', $daylight_savings_end);
    +				$provision["daylight_savings_stop_month"] = date('m', $daylight_savings_end);
    +				$provision["daylight_savings_stop_day"]   = date('d', $daylight_savings_end);
    +				$provision["daylight_savings_stop_time"]  = date('H', $daylight_savings_end);
    +			}
    +
    +			//add a generic gmt_offset
    +			$provision["gmt_offset"] = $standard_offset_seconds;
    +
    +			//set daylight savings settings for polycom
    +			$provision["polycom_gmt_offset"] = $standard_offset_seconds;
    +		}
    +
    +		//set daylight savings settings time for yealink
    +		if (!isset($provision["yealink_time_zone_start_time"])) {
    +			$provision["yealink_time_zone_start_time"] = $provision["daylight_savings_start_month"] . "/" . $provision["daylight_savings_start_day"] . "/" . $provision["daylight_savings_start_time"];
    +		}
    +		if (!isset($provision["yealink_time_zone_end_time"])) {
    +			$provision["yealink_time_zone_end_time"] = $provision["daylight_savings_stop_month"] . "/" . $provision["daylight_savings_stop_day"] . "/" . $provision["daylight_savings_stop_time"];
    +		}
    +
    +		//replace the dynamic provision variables that are defined in default, domain, and device settings
    +		if (is_array($provision)) {
    +			foreach ($provision as $key => $val) {
    +				if (!empty($val) && is_string($val) && strpos($val, '{$domain_name}') !== false) {
    +					$val = str_replace('{$domain_name}', $domain_name, $val);
    +				}
    +				if (!empty($val) && is_string($val) && strpos($val, '${domain_name}') !== false) {
    +					$val = str_replace('${domain_name}', $domain_name, $val);
    +				}
    +				$view->assign($key, $val);
    +			}
    +		}
    +
    +		//if $file is not provided then look for a default file that exists
    +		if (empty($file)) {
    +			if (file_exists($template_dir . "/" . $device_template . "/{\$address}")) {
    +				$file = "{\$address}";
    +			} elseif (file_exists($template_dir . "/" . $device_template . "/{\$address}.xml")) {
    +				$file = "{\$address}.xml";
    +			} elseif (file_exists($template_dir . "/" . $device_template . "/{\$mac}")) {
    +				$file = "{\$mac}";
    +			} elseif (file_exists($template_dir . "/" . $device_template . "/{\$mac}.xml")) {
    +				$file = "{\$mac}.xml";
    +			} elseif (file_exists($template_dir . "/" . $device_template . "/{\$mac}.cfg")) {
    +				$file = "{\$mac}.cfg";
    +			} else {
    +				$this->http_error('404');
    +				exit;
    +			}
    +		} else {
    +			//make sure the file exists
    +			if (!file_exists($template_dir . "/" . $device_template . "/" . $file)) {
    +				$this->http_error('404');
    +				if ($this->settings->get('provision', 'debug', false)) {
    +					echo ":$template_dir/$device_template/$file
    "; + echo "template_dir: $template_dir
    "; + echo "device_template: $device_template
    "; + echo "file: $file"; + } + exit; + } + } + + //output template to string for header processing + $file_contents = $view->render($file); + + //log file for testing + if ($this->settings->get('provision', 'debug', false)) { + $tmp_file = "/tmp/provisioning_log.txt"; + $fh = fopen($tmp_file, 'w') or die("can't open file"); + $tmp_string = $device_address . "\n"; + fwrite($fh, $tmp_string); + fclose($fh); + } + + $this->file = $file; + + //returned the rendered template + return $file_contents; + + } //end render function + + /** + * Writes configuration files for devices based on the provided provision template. + * + * This method iterates over a list of devices in the database, retrieves their configuration + * from the provision array, and writes the corresponding files to disk. If a device is + * disabled, any existing files with a MAC address placeholder are removed. + * + * @return void + */ + function write() { + //build the provision array + $provision = $this->settings->get('provision', null, []); + foreach ($provision as $key => $val) { + if (isset($val['var'])) { + $value = $val['var']; + } elseif (isset($val['text'])) { + $value = $val['text']; + } elseif (isset($val['boolean'])) { + $value = $val['boolean']; + } elseif (isset($val['numeric'])) { + $value = $val['numeric']; + } elseif (is_array($val) && !is_uuid($val['uuid'])) { + $value = $val; + } + if (isset($value)) { + $provision[$key] = $value; + } + unset($value); + } + + //check either we have destination path to write files + if (empty($provision["path"])) { + return; + } + + //get the devices from database + $sql = "select * from v_devices "; + //$sql .= "where domain_uuid = :domain_uuid "; + //$parameters['domain_uuid'] = $this->domain_uuid; + $result = $this->database->select($sql, null, 'all'); + + //process each device + if (is_array($result)) { + foreach ($result as $row) { + //get the values from the database and set as variables + $domain_uuid = $row["domain_uuid"]; + $device_uuid = $row["device_uuid"]; + $device_address = $row["device_address"]; + $device_label = $row["device_label"]; + $device_vendor = strtolower($row["device_vendor"] ?? ''); + $device_model = $row["device_model"]; + $device_firmware_version = $row["device_firmware_version"]; + $device_enabled = $row["device_enabled"]; + $device_template = $row["device_template"]; + $device_username = $row["device_username"]; + $device_password = $row["device_password"]; + $device_description = $row["device_description"]; + + //clear the cache + clearstatcache(); + + //loop through the provision template directory + $dir_array = []; + if (!empty($device_template)) { + $template_path = path_join($this->template_dir, $device_template); + $dir_list = opendir($template_path); + if ($dir_list) { + $x = 0; + while (false !== ($file = readdir($dir_list))) { + $ignore = $file == "." || $file == ".." || substr($file, -3) == ".db" || + substr($file, -4) == ".svn" || substr($file, -4) == ".git"; + if (!$ignore) { + $dir_array[] = path_join($template_path, $file); + if ($x > 1000) { + break; + }; + $x++; } - $view->assign($key, $val); } + closedir($dir_list); + unset($x, $file); } - - //if $file is not provided then look for a default file that exists - if (empty($file)) { - if (file_exists($template_dir."/".$device_template ."/{\$address}")) { - $file = "{\$address}"; - } - elseif (file_exists($template_dir."/".$device_template ."/{\$address}.xml")) { - $file = "{\$address}.xml"; - } - elseif (file_exists($template_dir."/".$device_template ."/{\$mac}")) { - $file = "{\$mac}"; - } - elseif (file_exists($template_dir."/".$device_template ."/{\$mac}.xml")) { - $file = "{\$mac}.xml"; - } - elseif (file_exists($template_dir."/".$device_template ."/{\$mac}.cfg")) { - $file = "{\$mac}.cfg"; - } - else { - $this->http_error('404'); - exit; - } - } - else { - //make sure the file exists - if (!file_exists($template_dir."/".$device_template ."/".$file)) { - $this->http_error('404'); - if ($this->settings->get('provision','debug',false)) { - echo ":$template_dir/$device_template/$file
    "; - echo "template_dir: $template_dir
    "; - echo "device_template: $device_template
    "; - echo "file: $file"; - } - exit; - } - } - - //output template to string for header processing - $file_contents = $view->render($file); - - //log file for testing - if ($this->settings->get('provision','debug',false)) { - $tmp_file = "/tmp/provisioning_log.txt"; - $fh = fopen($tmp_file, 'w') or die("can't open file"); - $tmp_string = $device_address."\n"; - fwrite($fh, $tmp_string); - fclose($fh); - } - - $this->file = $file; - - //returned the rendered template - return $file_contents; - - } //end render function - - function write() { - //build the provision array - $provision = $this->settings->get('provision', null, []); - foreach ($provision as $key => $val) { - if (isset($val['var'])) { - $value = $val['var']; - } elseif (isset($val['text'])) { - $value = $val['text']; - } elseif (isset($val['boolean'])) { - $value = $val['boolean']; - } elseif (isset($val['numeric'])) { - $value = $val['numeric']; - } elseif (is_array($val) && !is_uuid($val['uuid'])) { - $value = $val; - } - if (isset($value)) { - $provision[$key] = $value; - } - unset($value); + unset($dir_list, $template_path); } - //check either we have destination path to write files - if (empty($provision["path"])) { - return; - } + //loop through the provision templates + if (is_array($dir_array)) { + foreach ($dir_array as $template_path) { + if (is_dir($template_path)) continue; + if (!file_exists($template_path)) continue; - //get the devices from database - $sql = "select * from v_devices "; - //$sql .= "where domain_uuid = :domain_uuid "; - //$parameters['domain_uuid'] = $this->domain_uuid; - $result = $this->database->select($sql, null, 'all'); + //template file name + $file_name = basename($template_path); - //process each device - if (is_array($result)) { - foreach ($result as $row) { - //get the values from the database and set as variables - $domain_uuid = $row["domain_uuid"]; - $device_uuid = $row["device_uuid"]; - $device_address = $row["device_address"]; - $device_label = $row["device_label"]; - $device_vendor = strtolower($row["device_vendor"] ?? ''); - $device_model = $row["device_model"]; - $device_firmware_version = $row["device_firmware_version"]; - $device_enabled = $row["device_enabled"]; - $device_template = $row["device_template"]; - $device_username = $row["device_username"]; - $device_password = $row["device_password"]; - $device_description = $row["device_description"]; + //configure device object + $this->domain_uuid = $domain_uuid; + $this->device_address = $device_address; + $this->file = $file_name; - //clear the cache - clearstatcache(); + //format the device address + $address_formatted = $this->format_address($device_address, $device_vendor); - //loop through the provision template directory - $dir_array = array(); - if (!empty($device_template)) { - $template_path = path_join($this->template_dir, $device_template); - $dir_list = opendir($template_path); - if ($dir_list) { - $x = 0; - while (false !== ($file = readdir($dir_list))) { - $ignore = $file == "." || $file == ".." || substr($file, -3) == ".db" || - substr($file, -4) == ".svn" || substr($file, -4) == ".git"; - if (!$ignore) { - $dir_array[] = path_join($template_path, $file); - if ($x > 1000) { break; }; - $x++; - } + //replace {$mac} in the file name + $file_name = str_replace("{\$mac}", $address_formatted, $file_name); + $file_name = str_replace("{\$address}", $address_formatted, $file_name); + + //render and write configuration to file + $provision_dir_array = explode(";", $provision["path"]); + if (is_array($provision_dir_array)) { + foreach ($provision_dir_array as $directory) { + //destination file path + $dest_path = path_join($directory, $file_name); + + if ($device_enabled) { + //output template to string for header processing + $file_contents = $this->render(); + + //write the file + if (!is_dir($directory)) { + mkdir($directory, 0777, true); + } + $fh = fopen($dest_path, "w") or die("Unable to write to $directory for provisioning. Make sure the path exists and permissons are set correctly."); + fwrite($fh, $file_contents); + fclose($fh); + } else { // device disabled + //remove only files with `{$mac}` name + if (strpos($template_path, '{$mac}') !== false) { + unlink($dest_path); } - closedir($dir_list); - unset($x, $file); } - unset($dir_list, $template_path); + + unset($dest_path); } - - //loop through the provision templates - if (is_array($dir_array)) { - foreach ($dir_array as $template_path) { - if (is_dir($template_path)) continue; - if (!file_exists($template_path)) continue; - - //template file name - $file_name = basename($template_path); - - //configure device object - $this->domain_uuid = $domain_uuid; - $this->device_address = $device_address; - $this->file = $file_name; - - //format the device address - $address_formatted = $this->format_address($device_address, $device_vendor); - - //replace {$mac} in the file name - $file_name = str_replace("{\$mac}", $address_formatted, $file_name); - $file_name = str_replace("{\$address}", $address_formatted, $file_name); - - //render and write configuration to file - $provision_dir_array = explode(";", $provision["path"]); - if (is_array($provision_dir_array)) { - foreach ($provision_dir_array as $directory) { - //destination file path - $dest_path = path_join($directory, $file_name); - - if ($device_enabled) { - //output template to string for header processing - $file_contents = $this->render(); - - //write the file - if (!is_dir($directory)) { - mkdir($directory, 0777, true); - } - $fh = fopen($dest_path,"w") or die("Unable to write to $directory for provisioning. Make sure the path exists and permissons are set correctly."); - fwrite($fh, $file_contents); - fclose($fh); - } - else { // device disabled - //remove only files with `{$mac}` name - if (strpos($template_path, '{$mac}') !== false){ - unlink($dest_path); - } - } - - unset($dest_path); - } - } - //unset variables - unset($file_name, $provision_dir_array); - } - } - + } //unset variables - unset($dir_array); + unset($file_name, $provision_dir_array); } } - } //end write function - } //end provision class + //unset variables + unset($dir_array); + } + } + } //end write function + +} //end provision class ?> diff --git a/app/recordings/recordings.php b/app/recordings/recordings.php index 6f70b7fbc2..4ea6de17f9 100644 --- a/app/recordings/recordings.php +++ b/app/recordings/recordings.php @@ -328,8 +328,8 @@ } $param .= "&order_by=".$order_by."&order=".$order; $page = isset($_GET['page']) ? $_GET['page'] : 0; - list($paging_controls, $rows_per_page) = paging($num_rows, $param, $rows_per_page); - list($paging_controls_mini, $rows_per_page) = paging($num_rows, $param, $rows_per_page, true); + [$paging_controls, $rows_per_page] = paging($num_rows, $param, $rows_per_page); + [$paging_controls_mini, $rows_per_page] = paging($num_rows, $param, $rows_per_page, true); $offset = $rows_per_page * $page; //set the time zone @@ -622,6 +622,13 @@ require_once "resources/footer.php"; //define the download function (helps safari play audio sources) + /** + * Downloads a file in range mode, allowing the client to request specific byte ranges. + * + * @param string $file Path to the file being downloaded + * + * @return void + */ function range_download($file) { $fp = @fopen($file, 'rb'); @@ -650,7 +657,7 @@ $c_start = $start; $c_end = $end; // Extract the range string - list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2); + [, $range] = explode('=', $_SERVER['HTTP_RANGE'], 2); // Make sure the client hasn't sent us a multibyte range if (strpos($range, ',') !== false) { // (?) Shoud this be issued here, or should the first diff --git a/app/recordings/resources/classes/switch_recordings.php b/app/recordings/resources/classes/switch_recordings.php index 6e28d97418..a206936cea 100644 --- a/app/recordings/resources/classes/switch_recordings.php +++ b/app/recordings/resources/classes/switch_recordings.php @@ -26,164 +26,189 @@ */ //define the switch_recordings class - class switch_recordings { +class switch_recordings { - /** - * declare constant variables - */ - const app_name = 'recordings'; - const app_uuid = '83913217-c7a2-9e90-925d-a866eb40b60e'; + /** + * declare constant variables + */ + const app_name = 'recordings'; + const app_uuid = '83913217-c7a2-9e90-925d-a866eb40b60e'; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_uuid; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_name; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); - //assign private variables - $this->permission_prefix = 'recording_'; - $this->list_page = 'recordings.php'; - $this->table = 'recordings'; - $this->uuid_prefix = 'recording_'; + //assign private variables + $this->permission_prefix = 'recording_'; + $this->list_page = 'recordings.php'; + $this->table = 'recordings'; + $this->uuid_prefix = 'recording_'; + } + + /** + * Retrieves a list of recordings. + * + * This method queries the database for recordings associated with the current domain UUID + * and populates an array with the recording filenames. The array keys are constructed using + * the directory path specified in the 'switch' settings, relative to the domain name. + * + * @return array|false An array of recording filenames where the keys represent the file paths on disk, + * or false if no recordings were found. + */ + public function list_recordings() { + $sql = "select recording_uuid, recording_filename "; + $sql .= "from v_recordings "; + $sql .= "where domain_uuid = :domain_uuid "; + $parameters['domain_uuid'] = $this->domain_uuid; + $result = $this->database->select($sql, $parameters, 'all'); + if (!empty($result)) { + $switch_recordings_domain_dir = $this->settings->get('switch', 'recordings') . '/' . $this->domain_name; + foreach ($result as $row) { + $recordings[$switch_recordings_domain_dir . "/" . $row['recording_filename']] = $row['recording_filename']; + } + } else { + $recordings = false; } + unset($sql, $parameters, $result, $row); + return $recordings; + } - /** - * list recordings - */ - public function list_recordings() { - $sql = "select recording_uuid, recording_filename "; - $sql .= "from v_recordings "; - $sql .= "where domain_uuid = :domain_uuid "; - $parameters['domain_uuid'] = $this->domain_uuid; - $result = $this->database->select($sql, $parameters, 'all'); - if (!empty($result)) { - $switch_recordings_domain_dir = $this->settings->get('switch', 'recordings').'/'.$this->domain_name; - foreach ($result as $row) { - $recordings[$switch_recordings_domain_dir."/".$row['recording_filename']] = $row['recording_filename']; + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //get recording filename, build delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && !empty($record['uuid'])) { + + //get filename + $sql = "select recording_filename from v_recordings "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and recording_uuid = :recording_uuid "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['recording_uuid'] = $record['uuid']; + $filenames[] = $this->database->select($sql, $parameters, 'column'); + unset($sql, $parameters); + + //build delete array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + } } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //execute delete + $this->database->delete($array); + unset($array); + + //delete recording files + if (is_array($filenames) && @sizeof($filenames) != 0) { + $switch_recordings_domain_dir = $this->settings->get('switch', 'recordings') . "/" . $this->domain_name; + foreach ($filenames as $filename) { + if (!empty($filename) && file_exists($switch_recordings_domain_dir . "/" . $filename)) { + @unlink($switch_recordings_domain_dir . "/" . $filename); + } + } + } + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //set message + message::add($text['message-delete']); + } + unset($records); } - else { - $recordings = false; - } - unset($sql, $parameters, $result, $row); - return $recordings; } - - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { + } //method - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //get recording filename, build delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && !empty($record['uuid'])) { - - //get filename - $sql = "select recording_filename from v_recordings "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and recording_uuid = :recording_uuid "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['recording_uuid'] = $record['uuid']; - $filenames[] = $this->database->select($sql, $parameters, 'column'); - unset($sql, $parameters); - - //build delete array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //execute delete - $this->database->delete($array); - unset($array); - - //delete recording files - if (is_array($filenames) && @sizeof($filenames) != 0) { - $switch_recordings_domain_dir = $this->settings->get('switch', 'recordings')."/".$this->domain_name; - foreach ($filenames as $filename) { - if (!empty($filename) && file_exists($switch_recordings_domain_dir."/".$filename)) { - @unlink($switch_recordings_domain_dir."/".$filename); - } - } - } - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } //method - - } //class +} //class diff --git a/app/registrations/resources/classes/registrations.php b/app/registrations/resources/classes/registrations.php index e9c33ad74a..66e1ea180b 100644 --- a/app/registrations/resources/classes/registrations.php +++ b/app/registrations/resources/classes/registrations.php @@ -24,413 +24,445 @@ Mark J Crane */ - class registrations { +class registrations { - /** - * declare constant variables - */ - const app_name = 'registrations'; - const app_uuid = '5d9e7cd7-629e-3553-4cf5-f26e39fefa39'; + /** + * declare constant variables + */ + const app_name = 'registrations'; + const app_uuid = '5d9e7cd7-629e-3553-4cf5-f26e39fefa39'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_name; - /** - * Set in the constructor. Must be an event_socket object and cannot be null. - * @var event_socket Event Socket Connection Object - */ - private $event_socket; + /** + * Set in the constructor. Must be an event_socket object and cannot be null. + * + * @var event_socket Event Socket Connection Object + */ + private $event_socket; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - public $show; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + public $show; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->event_socket = $setting_array['event_socket'] ?? event_socket::create(); + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->event_socket = $setting_array['event_socket'] ?? event_socket::create(); - //trap passing an invalid connection object for communicating to the switch - if (!($this->event_socket instanceof event_socket)) { - //should never happen but will trap it here just in case - throw new \InvalidArgumentException('Event socket object passed in the constructor is not a valid event_socket object'); + //trap passing an invalid connection object for communicating to the switch + if (!($this->event_socket instanceof event_socket)) { + //should never happen but will trap it here just in case + throw new \InvalidArgumentException('Event socket object passed in the constructor is not a valid event_socket object'); + } + + //assign private variables + $this->permission_prefix = 'registration_'; + $this->list_page = 'registrations.php'; + $this->show = 'local'; + } + + /** + * Retrieves the registration list for a given SIP profile. + * + * @param string|null $profile The name of the SIP profile to retrieve. Defaults to 'all'. + * + * @return array|null The registration list, or null if no profiles are found. + */ + public function get($profile = 'all') { + + //add multi-lingual support + $language = new text; + $text = $language->get(null, '/app/registrations'); + + //initialize the id used in the registrations array + $id = 0; + + //create the event socket connection + $event_socket = $this->event_socket; + + //make sure the event socket is connected + if (!$event_socket->is_connected()) { + //connect to event socket + $event_socket->connect(); + + //check again and throw an error if it can't connect + if (!$event_socket->is_connected()) { + message::add($text['error-event-socket'], 'negative', 5000); + return null; } - - //assign private variables - $this->permission_prefix = 'registration_'; - $this->list_page = 'registrations.php'; - $this->show = 'local'; } - /** - * get the registrations - */ - public function get($profile = 'all') { + //get the default settings + $sql = "select sip_profile_name from v_sip_profiles "; + $sql .= "where true "; + if (!empty($profile) && $profile != 'all') { + $sql .= "and sip_profile_name = :sip_profile_name "; + $parameters['sip_profile_name'] = $profile; + } + $sql .= "and sip_profile_enabled = true "; + $sip_profiles = $this->database->select($sql, $parameters ?? null, 'all'); - //add multi-lingual support - $language = new text; - $text = $language->get(null, '/app/registrations'); + if (!empty($sip_profiles)) { - //initialize the id used in the registrations array - $id = 0; + //use a while loop to ensure the event socket stays connected while communicating + $count = count($sip_profiles); + $i = 0; + while ($event_socket->is_connected() && $i < $count) { + $field = $sip_profiles[$i++]; - //create the event socket connection - $event_socket = $this->event_socket; + //get sofia status profile information including registrations + $cmd = "api sofia xmlstatus profile '" . $field['sip_profile_name'] . "' reg"; + $xml_response = trim($event_socket->request($cmd)); - //make sure the event socket is connected - if (!$event_socket->is_connected()) { - //connect to event socket - $event_socket->connect(); - - //check again and throw an error if it can't connect - if (!$event_socket->is_connected()) { - message::add($text['error-event-socket'], 'negative', 5000); - return null; - } + //show an error message + if ($xml_response == "Invalid Profile!") { + //show the error message + $xml_response = "" . escape($text['label-message']) . ""; } - //get the default settings - $sql = "select sip_profile_name from v_sip_profiles "; - $sql .= "where true "; - if (!empty($profile) && $profile != 'all') { - $sql .= "and sip_profile_name = :sip_profile_name "; - $parameters['sip_profile_name'] = $profile; + //sanitize the XML + if (function_exists('iconv')) { + $xml_response = iconv("utf-8", "utf-8//IGNORE", $xml_response); } - $sql .= "and sip_profile_enabled = true "; - $sip_profiles = $this->database->select($sql, $parameters ?? null, 'all'); - - if (!empty($sip_profiles)) { - - //use a while loop to ensure the event socket stays connected while communicating - $count = count($sip_profiles); - $i = 0; - while ($event_socket->is_connected() && $i < $count) { - $field = $sip_profiles[$i++]; - - //get sofia status profile information including registrations - $cmd = "api sofia xmlstatus profile '".$field['sip_profile_name']."' reg"; - $xml_response = trim($event_socket->request($cmd)); - - //show an error message - if ($xml_response == "Invalid Profile!") { - //show the error message - $xml_response = "".escape($text['label-message']).""; - } - - //sanitize the XML - if (function_exists('iconv')) { $xml_response = iconv("utf-8", "utf-8//IGNORE", $xml_response); } - $xml_response = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $xml_response); - $xml_response = str_replace("", "", $xml_response); - $xml_response = str_replace("", "", $xml_response); - $xml_response = str_replace("<", "", $xml_response); - $xml_response = str_replace(">", "", $xml_response); - if (strlen($xml_response) > 101) { - try { - $xml = new SimpleXMLElement($xml_response); - } - catch(Exception $e) { - echo basename(__FILE__)."
    \n"; - echo "line: ".__line__."
    \n"; - echo "error: ".$e->getMessage()."
    \n"; - //echo $xml_response; - exit; - } - $array = json_decode(json_encode($xml), true); - } - - //normalize the array - if (!empty($array) && is_array($array) && (!isset($array['registrations']['registration'][0]) || !is_array($array['registrations']['registration'][0]))) { - $row = $array['registrations']['registration']; - unset($array['registrations']['registration']); - $array['registrations']['registration'][0] = $row; - } - - //set the registrations array - if (!empty($array) && is_array($array)) { - foreach ($array['registrations']['registration'] as $row) { - - //build the registrations array - //$registrations[0] = $row; - $user_array = explode('@', $row['user'] ?? ''); - $registrations[$id]['user'] = $row['user'] ?? ''; - $registrations[$id]['call-id'] = $row['call-id'] ?? ''; - $registrations[$id]['contact'] = $row['contact'] ?? ''; - $registrations[$id]['sip-auth-user'] = $row['sip-auth-user'] ?? ''; - $registrations[$id]['agent'] = $row['agent'] ?? ''; - $registrations[$id]['host'] = $row['host'] ?? ''; - $registrations[$id]['network-ip'] = $row['network-ip'] ?? ''; - $registrations[$id]['network-port'] = $row['network-port'] ?? ''; - $registrations[$id]['sip-auth-user'] = $row['sip-auth-user'] ?? ''; - $registrations[$id]['sip-auth-realm'] = $row['sip-auth-realm'] ?? ''; - $registrations[$id]['mwi-account'] = $row['mwi-account'] ?? ''; - $registrations[$id]['status'] = $row['status'] ?? ''; - $registrations[$id]['ping-time'] = $row['ping-time'] ?? ''; - $registrations[$id]['ping-status'] = $row['ping-status'] ?? ''; - $registrations[$id]['sip_profile_name'] = $field['sip_profile_name']; - - //get network-ip to url or blank - if (isset($row['network-ip'])) { - $registrations[$id]['network-ip'] = $row['network-ip']; - } - else { - $registrations[$id]['network-ip'] = ''; - } - - //get the LAN IP address if it exists replace the external ip - $call_id_array = explode('@', $row['call-id'] ?? ''); - if (isset($call_id_array[1])) { - $agent = $row['agent']; - $lan_ip = $call_id_array[1]; - if (!empty($agent) && (false !== stripos($agent, 'grandstream') || false !== stripos($agent, 'ooma'))) { - $lan_ip = str_ireplace( - array('A','B','C','D','E','F','G','H','I','J'), - array('0','1','2','3','4','5','6','7','8','9'), - $lan_ip); - } - elseif (!empty($agent) && 1 === preg_match('/\ACL750A/', $agent)) { - //required for GIGASET Sculpture CL750A puts _ in it's lan ip account - $lan_ip = preg_replace('/_/', '.', $lan_ip); - } - $registrations[$id]['lan-ip'] = $lan_ip; - } - else if (preg_match('/real=\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/', $row['contact'] ?? '', $ip_match)) { - //get ip address for snom phones - $lan_ip = str_replace('real=', '', $ip_match[0]); - $registrations[$id]['lan-ip'] = $lan_ip; - } - else if (preg_match('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/', $row['contact'] ?? '', $ip_match)) { - $lan_ip = preg_replace('/_/', '.', $ip_match[0]); - $registrations[$id]['lan-ip'] = $lan_ip; - } - else { - $registrations[$id]['lan-ip'] = ''; - } - - //remove unrelated domains - if (!permission_exists('registration_all') || $this->show != 'all') { - if ($registrations[$id]['sip-auth-realm'] == $this->domain_name) {} - else if ($user_array[1] == $this->domain_name) {} - else { - unset($registrations[$id]); - } - } - - //increment the array id - $id++; - } - unset($array); - } - - } - } - - //return the registrations array - return $registrations ?? null; - } - - /** - * get the registration count - */ - public function count($profile = 'all') { - - //use get the registrations to count - $registrations = $this->get($profile); - - //set the count - $count = !empty($registrations) ? @sizeof($registrations) : 0; - - //return the registrations count - return $count; - - } - - /** - * unregister registrations - */ - public function unregister($registrations) { - $this->switch_api('unregister', $registrations); - } - - /** - * provision registrations - */ - public function provision($registrations) { - $this->switch_api('provision', $registrations); - } - - /** - * reboot registrations - */ - public function reboot($registrations) { - $this->switch_api('reboot', $registrations); - } - - /** - * switch api calls - */ - private function switch_api($action, $records) { - if (permission_exists($this->permission_prefix.'domain') || permission_exists($this->permission_prefix.'all') || if_group('superadmin')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); + $xml_response = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $xml_response); + $xml_response = str_replace("", "", $xml_response); + $xml_response = str_replace("", "", $xml_response); + $xml_response = str_replace("<", "", $xml_response); + $xml_response = str_replace(">", "", $xml_response); + if (strlen($xml_response) > 101) { + try { + $xml = new SimpleXMLElement($xml_response); + } catch (Exception $e) { + echo basename(__FILE__) . "
    \n"; + echo "line: " . __line__ . "
    \n"; + echo "error: " . $e->getMessage() . "
    \n"; + //echo $xml_response; exit; } + $array = json_decode(json_encode($xml), true); + } - //filter out unchecked registrations - if (is_array($records) && @sizeof($records) != 0) { - foreach($records as $record) { - if ($record['checked'] == 'true' && !empty($record['user']) && !empty($record['profile'])) { - $registrations[] = $record; + //normalize the array + if (!empty($array) && is_array($array) && (!isset($array['registrations']['registration'][0]) || !is_array($array['registrations']['registration'][0]))) { + $row = $array['registrations']['registration']; + unset($array['registrations']['registration']); + $array['registrations']['registration'][0] = $row; + } + + //set the registrations array + if (!empty($array) && is_array($array)) { + foreach ($array['registrations']['registration'] as $row) { + + //build the registrations array + //$registrations[0] = $row; + $user_array = explode('@', $row['user'] ?? ''); + $registrations[$id]['user'] = $row['user'] ?? ''; + $registrations[$id]['call-id'] = $row['call-id'] ?? ''; + $registrations[$id]['contact'] = $row['contact'] ?? ''; + $registrations[$id]['sip-auth-user'] = $row['sip-auth-user'] ?? ''; + $registrations[$id]['agent'] = $row['agent'] ?? ''; + $registrations[$id]['host'] = $row['host'] ?? ''; + $registrations[$id]['network-ip'] = $row['network-ip'] ?? ''; + $registrations[$id]['network-port'] = $row['network-port'] ?? ''; + $registrations[$id]['sip-auth-user'] = $row['sip-auth-user'] ?? ''; + $registrations[$id]['sip-auth-realm'] = $row['sip-auth-realm'] ?? ''; + $registrations[$id]['mwi-account'] = $row['mwi-account'] ?? ''; + $registrations[$id]['status'] = $row['status'] ?? ''; + $registrations[$id]['ping-time'] = $row['ping-time'] ?? ''; + $registrations[$id]['ping-status'] = $row['ping-status'] ?? ''; + $registrations[$id]['sip_profile_name'] = $field['sip_profile_name']; + + //get network-ip to url or blank + if (isset($row['network-ip'])) { + $registrations[$id]['network-ip'] = $row['network-ip']; + } else { + $registrations[$id]['network-ip'] = ''; + } + + //get the LAN IP address if it exists replace the external ip + $call_id_array = explode('@', $row['call-id'] ?? ''); + if (isset($call_id_array[1])) { + $agent = $row['agent']; + $lan_ip = $call_id_array[1]; + if (!empty($agent) && (false !== stripos($agent, 'grandstream') || false !== stripos($agent, 'ooma'))) { + $lan_ip = str_ireplace( + ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'], + ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + $lan_ip); + } elseif (!empty($agent) && 1 === preg_match('/\ACL750A/', $agent)) { + //required for GIGASET Sculpture CL750A puts _ in it's lan ip account + $lan_ip = preg_replace('/_/', '.', $lan_ip); + } + $registrations[$id]['lan-ip'] = $lan_ip; + } elseif (preg_match('/real=\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/', $row['contact'] ?? '', $ip_match)) { + //get ip address for snom phones + $lan_ip = str_replace('real=', '', $ip_match[0]); + $registrations[$id]['lan-ip'] = $lan_ip; + } elseif (preg_match('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/', $row['contact'] ?? '', $ip_match)) { + $lan_ip = preg_replace('/_/', '.', $ip_match[0]); + $registrations[$id]['lan-ip'] = $lan_ip; + } else { + $registrations[$id]['lan-ip'] = ''; + } + + //remove unrelated domains + if (!permission_exists('registration_all') || $this->show != 'all') { + if ($registrations[$id]['sip-auth-realm'] == $this->domain_name) { + } elseif ($user_array[1] == $this->domain_name) { + } else { + unset($registrations[$id]); + } + } + + //increment the array id + $id++; + } + unset($array); + } + + } + } + + //return the registrations array + return $registrations ?? null; + } + + /** + * Retrieves the registration count for a given SIP profile. + * + * @param string|null $profile The name of the SIP profile to retrieve. Defaults to 'all'. + * + * @return int The registration count, or 0 if no profiles are found. + */ + public function count($profile = 'all') { + + //use get the registrations to count + $registrations = $this->get($profile); + + //set the count + $count = !empty($registrations) ? @sizeof($registrations) : 0; + + //return the registrations count + return $count; + + } + + /** + * Unregisters a list of registrations from a given SIP profile or all profiles if no profile is specified. + * + * @param array $registrations The list of registrations to unregister, keyed by SIP URI. + * + * @return void This method does not return any value. + */ + public function unregister($registrations) { + $this->switch_api('unregister', $registrations); + } + + /** + * Provision a set of SIP registrations. + * + * @param array $registrations The list of registrations to provision. + * + * @returnvoid This method does not return any value. + */ + public function provision($registrations) { + $this->switch_api('provision', $registrations); + } + + /** + * Initiates a system reboot with the specified registrations. + * + * @param array $registrations The list of registrations to persist before rebooting. + * + * @return void This method does not return any value. + */ + public function reboot($registrations) { + $this->switch_api('reboot', $registrations); + } + + /** + * Processes API commands for a list of registered devices. + * + * This will cause execution to exit. + * + * @param string $action The action to perform (unregister, provision, reboot). + * @param array $records The list of registered devices. + * + * @return void + */ + private function switch_api($action, $records) { + if (permission_exists($this->permission_prefix . 'domain') || permission_exists($this->permission_prefix . 'all') || if_group('superadmin')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //filter out unchecked registrations + if (is_array($records) && @sizeof($records) != 0) { + foreach ($records as $record) { + if ($record['checked'] == 'true' && !empty($record['user']) && !empty($record['profile'])) { + $registrations[] = $record; + } + } + } + + //process checked registrations + if (is_array($registrations) && @sizeof($registrations) != 0) { + + //retrieve sip profiles list + $sql = "select sip_profile_name as name from v_sip_profiles "; + $sip_profiles = $this->database->select($sql, null, 'all'); + unset($sql); + + //create the event socket connection + $event_socket = $this->event_socket; + + //loop through registrations + if ($event_socket->is_connected()) { + //check if registrations exist + if (is_array($registrations)) { + foreach ($registrations as $registration) { + + //validate the submitted profile + if (!empty($registration['profile']) && is_array($sip_profiles) && @sizeof($sip_profiles) != 0) { + foreach ($sip_profiles as $field) { + if ($field['name'] == $registration['profile']) { + $profile = $registration['profile']; + break; + } + } + } else { + header('Location: ' . $this->list_page); + exit; + } + + //validate the submitted user + if (!empty($registration['user'])) { + $user = preg_replace('#[^a-zA-Z0-9_\-\.\@]#', '', $registration['user']); + } + + //validate the submitted host + if (!empty($registration['host'])) { + $host = preg_replace('#[^a-zA-Z0-9_\-\.]#', '', $registration['host']); + } + + //lookup vendor by agent + if (!empty($registration['agent'])) { + $vendor = device::get_vendor_by_agent($registration['agent']); + } + + //prepare the api command + if (!empty($profile) && $user) { + switch ($action) { + case 'unregister': + $command = "sofia profile " . $profile . " flush_inbound_reg " . $user . " reboot"; + $response_message = $text['message-registrations_unregistered']; + break; + case 'provision': + if ($vendor && $host) { + $command = "lua app.lua event_notify " . $profile . " check_sync " . $user . " " . $vendor . " " . $host; + $response_message = $text['message-registrations_provisioned']; + } + break; + case 'reboot': + if ($vendor && $host) { + $command = "lua app.lua event_notify " . $profile . " reboot " . $user . " " . $vendor . " " . $host; + $response_message = $text['message-registrations_rebooted']; + } + break; + default: + header('Location: ' . $this->list_page); + exit; + } + } + + //send the api command + if (!empty($command) && $event_socket->is_connected()) { + $response = $event_socket->request('api ' . $command); + $response_api[$user]['command'] = $command; + $response_api[$user]['log'] = $response; } } } - //process checked registrations - if (is_array($registrations) && @sizeof($registrations) != 0) { - - //retrieve sip profiles list - $sql = "select sip_profile_name as name from v_sip_profiles "; - $sip_profiles = $this->database->select($sql, null, 'all'); - unset($sql); - - //create the event socket connection - $event_socket = $this->event_socket; - - //loop through registrations - if ($event_socket->is_connected()) { - //check if registrations exist - if (is_array($registrations)) { - foreach ($registrations as $registration) { - - //validate the submitted profile - if (!empty($registration['profile']) && is_array($sip_profiles) && @sizeof($sip_profiles) != 0) { - foreach ($sip_profiles as $field) { - if ($field['name'] == $registration['profile']) { - $profile = $registration['profile']; - break; - } - } - } - else { - header('Location: '.$this->list_page); - exit; - } - - //validate the submitted user - if (!empty($registration['user'])) { - $user = preg_replace('#[^a-zA-Z0-9_\-\.\@]#', '', $registration['user']); - } - - //validate the submitted host - if (!empty($registration['host'])) { - $host = preg_replace('#[^a-zA-Z0-9_\-\.]#', '', $registration['host']); - } - - //lookup vendor by agent - if (!empty($registration['agent'])) { - $vendor = device::get_vendor_by_agent($registration['agent']); - } - - //prepare the api command - if (!empty($profile) && $user) { - switch ($action) { - case 'unregister': - $command = "sofia profile ".$profile." flush_inbound_reg ".$user." reboot"; - $response_message = $text['message-registrations_unregistered']; - break; - case 'provision': - if ($vendor && $host) { - $command = "lua app.lua event_notify ".$profile." check_sync ".$user." ".$vendor." ".$host; - $response_message = $text['message-registrations_provisioned']; - } - break; - case 'reboot': - if ($vendor && $host) { - $command = "lua app.lua event_notify ".$profile." reboot ".$user." ".$vendor." ".$host; - $response_message = $text['message-registrations_rebooted']; - } - break; - default: - header('Location: '.$this->list_page); - exit; - } - } - - //send the api command - if (!empty($command) && $event_socket->is_connected()) { - $response = $event_socket->request('api ' . $command); - $response_api[$user]['command'] = $command; - $response_api[$user]['log'] = $response; - } + //set message + if (is_array($response_api)) { + $message = ''; + foreach ($response_api as $registration_user => $response) { + if (is_array($response['command'])) { + foreach ($response['command'] as $command) { + $command = trim($command ?? ''); + if ($command !== '-ERR no reply') { + $message .= "
    \n" . escape($registration_user) . ": " . escape($response_message); } } - - //set message - if (is_array($response_api)) { - $message = ''; - foreach ($response_api as $registration_user => $response) { - if (is_array($response['command'])) { - foreach($response['command'] as $command) { - $command = trim($command ?? ''); - if ($command !== '-ERR no reply') { - $message .= "
    \n".escape($registration_user).": ".escape($response_message); - } - } - } - else { - if (!empty($response['command']) && $response['command'] !== '-ERR no reply') { - $message .= "
    \n".escape($registration_user).": ".escape($response_message); - } - } - } - message::add($message, 'positive', '7000'); - } + } else { + if (!empty($response['command']) && $response['command'] !== '-ERR no reply') { + $message .= "
    \n" . escape($registration_user) . ": " . escape($response_message); + } } - else { - message::add($text['error-event-socket'], 'negative', 5000); - } - + } + message::add($message, 'positive', '7000'); } + } else { + message::add($text['error-event-socket'], 'negative', 5000); + } } - } //method - } //class + } + } //method + +} //class diff --git a/app/ring_groups/resources/classes/ring_groups.php b/app/ring_groups/resources/classes/ring_groups.php index b79269d704..97260c1782 100644 --- a/app/ring_groups/resources/classes/ring_groups.php +++ b/app/ring_groups/resources/classes/ring_groups.php @@ -25,536 +25,573 @@ */ //define the ring groups class - class ring_groups { - - /** - * declare constant variables - */ - const app_name = 'ring_groups'; - const app_uuid = '1d61fb65-1eec-bc73-a6ee-a6203b4fe6f2'; - - /** - * Ring group primary key - * @var uuid - */ - public $ring_group_uuid; - - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; - - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; - - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; - - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; - - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; - - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - - //set objects - $this->database = $setting_array['database'] ?? database::new(); - - //assign private variables - $this->permission_prefix = 'ring_group_'; - $this->list_page = 'ring_groups.php'; - $this->table = 'ring_groups'; - $this->uuid_prefix = 'ring_group_'; - $this->toggle_field = 'ring_group_enabled'; - $this->toggle_values = ['true','false']; - } - - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked ring groups, build where clause for below - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //get necessary ring group details - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, dialplan_uuid, ring_group_context from v_".$this->table." "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $ring_groups[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; - $ring_group_contexts[] = $row['ring_group_context']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build the delete array - $x = 0; - foreach ($ring_groups as $ring_group_uuid => $ring_group) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $ring_group_uuid; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - $array['ring_group_users'][$x][$this->uuid_prefix.'uuid'] = $ring_group_uuid; - $array['ring_group_users'][$x]['domain_uuid'] = $this->domain_uuid; - $array['ring_group_destinations'][$x][$this->uuid_prefix.'uuid'] = $ring_group_uuid; - $array['ring_group_destinations'][$x]['domain_uuid'] = $this->domain_uuid; - $array['dialplans'][$x]['dialplan_uuid'] = $ring_group['dialplan_uuid']; - $array['dialplan_details'][$x]['dialplan_uuid'] = $ring_group['dialplan_uuid']; - $x++; - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('ring_group_user_delete', 'temp'); - $p->add('ring_group_destination_delete', 'temp'); - $p->add('dialplan_delete', 'temp'); - $p->add('dialplan_detail_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('ring_group_user_delete', 'temp'); - $p->delete('ring_group_destination_delete', 'temp'); - $p->delete('dialplan_delete', 'temp'); - $p->delete('dialplan_detail_delete', 'temp'); - - //apply settings reminder - $_SESSION["reload_xml"] = true; - - //clear the cache - if (is_array($ring_group_contexts) && @sizeof($ring_group_contexts) != 0) { - $ring_group_contexts = array_unique($ring_group_contexts); - $cache = new cache; - foreach ($ring_group_contexts as $ring_group_context) { - $cache->delete("dialplan:".$ring_group_context); - } - } - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - public function delete_destinations($records) { - - //assign private variables - $this->permission_prefix = 'ring_group_destination_'; - $this->table = 'ring_group_destinations'; - $this->uuid_prefix = 'ring_group_destination_'; - - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('L$ring_group_uuidocation: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked ring groups, build where clause for below - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = $record['uuid']; - } - } - - //get ring group context - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ring_group_context from v_ring_groups "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ring_group_uuid = :ring_group_uuid "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['ring_group_uuid'] = $this->ring_group_uuid; - $ring_group_context = $this->database->select($sql, $parameters, 'column'); - unset($sql, $parameters); - } - - //build the delete array - if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { - $x = 0; - foreach ($uuids as $uuid) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - $x++; - } - } - - //delete the checked rows - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - - //execute delete - $this->database->delete($array); - unset($array); - - //apply settings reminder - $_SESSION["reload_xml"] = true; - - //clear the cache - if ($ring_group_context) { - $cache = new cache; - $cache->delete("dialplan:".$ring_group_context); - } - - } - unset($records); - } - } - } - - /** - * toggle records - */ - public function toggle($records) { - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle, dialplan_uuid, ring_group_context from v_".$this->table." "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $ring_groups[$row['uuid']]['state'] = $row['toggle']; - $ring_groups[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; - $ring_group_contexts[] = $row['ring_group_context']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach ($ring_groups as $uuid => $ring_group) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $ring_group['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $array['dialplans'][$x]['dialplan_uuid'] = $ring_group['dialplan_uuid']; - $array['dialplans'][$x]['dialplan_enabled'] = $ring_group['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('dialplan_edit', 'temp'); - - //save the array - - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('dialplan_edit', 'temp'); - - //apply settings reminder - $_SESSION["reload_xml"] = true; - - //clear the cache - if (is_array($ring_group_contexts) && @sizeof($ring_group_contexts) != 0) { - $ring_group_contexts = array_unique($ring_group_contexts); - $cache = new cache; - foreach ($ring_group_contexts as $ring_group_context) { - $cache->delete("dialplan:".$ring_group_context); - } - } - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - - } - } - - /** - * copy records - */ - public function copy($records) { - if (permission_exists($this->permission_prefix.'add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach ($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create insert array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - - //primary table - $sql = "select * from v_".$this->table." "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $y = $z = 0; - foreach ($rows as $x => $row) { - $new_ring_group_uuid = uuid(); - $new_dialplan_uuid = uuid(); - - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $new_ring_group_uuid; - $array[$this->table][$x]['dialplan_uuid'] = $new_dialplan_uuid; - $array[$this->table][$x]['ring_group_description'] = trim($row['ring_group_description'].' ('.$text['label-copy'].')'); - - //users sub table - $sql_2 = "select * from v_ring_group_users where ring_group_uuid = :ring_group_uuid"; - $parameters_2['ring_group_uuid'] = $row['ring_group_uuid']; - $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); - if (is_array($rows_2) && @sizeof($rows_2) != 0) { - foreach ($rows_2 as $row_2) { - - //convert boolean values to a string - foreach($row_2 as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row_2[$key] = $value; - } - } - - //copy data - $array['ring_group_users'][$y] = $row_2; - - //overwrite - $array['ring_group_users'][$y]['ring_group_user_uuid'] = uuid(); - $array['ring_group_users'][$y]['ring_group_uuid'] = $new_ring_group_uuid; - - //increment - $y++; - - } - } - unset($sql_2, $parameters_2, $rows_2, $row_2); - - //destinations sub table - $sql_3 = "select * from v_ring_group_destinations where ring_group_uuid = :ring_group_uuid"; - $parameters_3['ring_group_uuid'] = $row['ring_group_uuid']; - $rows_3 = $this->database->select($sql_3, $parameters_3, 'all'); - if (is_array($rows_3) && @sizeof($rows_3) != 0) { - foreach ($rows_3 as $row_3) { - - //convert boolean values to a string - foreach($row_3 as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row_3[$key] = $value; - } - } - - //copy data - $array['ring_group_destinations'][$z] = $row_3; - - //overwrite - $array['ring_group_destinations'][$z]['ring_group_destination_uuid'] = uuid(); - $array['ring_group_destinations'][$z]['ring_group_uuid'] = $new_ring_group_uuid; - - //increment - $z++; - - } - } - unset($sql_3, $parameters_3, $rows_3, $row_3); - - //ring group dialplan record - $sql_4 = "select * from v_dialplans where dialplan_uuid = :dialplan_uuid"; - $parameters_4['dialplan_uuid'] = $row['dialplan_uuid']; - $dialplan = $this->database->select($sql_4, $parameters_4, 'row'); - if (is_array($dialplan) && @sizeof($dialplan) != 0) { - - //convert boolean values to a string - foreach($dialplan as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $dialplan[$key] = $value; - } - } - - //copy data - $array['dialplans'][$x] = $dialplan; - - //overwrite - $array['dialplans'][$x]['dialplan_uuid'] = $new_dialplan_uuid; - $dialplan_xml = $dialplan['dialplan_xml']; - $dialplan_xml = str_replace($row['ring_group_uuid'], $new_ring_group_uuid, $dialplan_xml); //replace source ring_group_uuid with new - $dialplan_xml = str_replace($dialplan['dialplan_uuid'], $new_dialplan_uuid, $dialplan_xml); //replace source dialplan_uuid with new - $array['dialplans'][$x]['dialplan_xml'] = $dialplan_xml; - $array['dialplans'][$x]['dialplan_description'] = trim($dialplan['dialplan_description'].' ('.$text['label-copy'].')'); - - } - unset($sql_4, $parameters_4, $dialplan); - - //create ring group context array - $ring_group_contexts = $row['ring_group_context']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('ring_group_user_add', 'temp'); - $p->add('ring_group_destination_add', 'temp'); - $p->add("dialplan_add", "temp"); - - //save the array - - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('ring_group_user_add', 'temp'); - $p->delete('ring_group_destination_add', 'temp'); - $p->delete("dialplan_add", "temp"); - - //apply settings reminder - $_SESSION["reload_xml"] = true; - - //clear the cache - if (is_array($ring_group_contexts) && @sizeof($ring_group_contexts) != 0) { - $ring_group_contexts = array_unique($ring_group_contexts); - $cache = new cache; - foreach ($ring_group_contexts as $ring_group_context) { - $cache->delete("dialplan:".$ring_group_context); - } - } - - //set message - message::add($text['message-copy']); - - } - unset($records); - } - - } - } - +class ring_groups { + + /** + * declare constant variables + */ + const app_name = 'ring_groups'; + const app_uuid = '1d61fb65-1eec-bc73-a6ee-a6203b4fe6f2'; + + /** + * Ring group primary key + * + * @var uuid + */ + public $ring_group_uuid; + + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; + + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; + + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; + + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; + + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; + + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + + //set objects + $this->database = $setting_array['database'] ?? database::new(); + + //assign private variables + $this->permission_prefix = 'ring_group_'; + $this->list_page = 'ring_groups.php'; + $this->table = 'ring_groups'; + $this->uuid_prefix = 'ring_group_'; + $this->toggle_field = 'ring_group_enabled'; + $this->toggle_values = ['true', 'false']; } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked ring groups, build where clause for below + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //get necessary ring group details + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, dialplan_uuid, ring_group_context from v_" . $this->table . " "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $ring_groups[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; + $ring_group_contexts[] = $row['ring_group_context']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build the delete array + $x = 0; + foreach ($ring_groups as $ring_group_uuid => $ring_group) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $ring_group_uuid; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + $array['ring_group_users'][$x][$this->uuid_prefix . 'uuid'] = $ring_group_uuid; + $array['ring_group_users'][$x]['domain_uuid'] = $this->domain_uuid; + $array['ring_group_destinations'][$x][$this->uuid_prefix . 'uuid'] = $ring_group_uuid; + $array['ring_group_destinations'][$x]['domain_uuid'] = $this->domain_uuid; + $array['dialplans'][$x]['dialplan_uuid'] = $ring_group['dialplan_uuid']; + $array['dialplan_details'][$x]['dialplan_uuid'] = $ring_group['dialplan_uuid']; + $x++; + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('ring_group_user_delete', 'temp'); + $p->add('ring_group_destination_delete', 'temp'); + $p->add('dialplan_delete', 'temp'); + $p->add('dialplan_detail_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('ring_group_user_delete', 'temp'); + $p->delete('ring_group_destination_delete', 'temp'); + $p->delete('dialplan_delete', 'temp'); + $p->delete('dialplan_detail_delete', 'temp'); + + //apply settings reminder + $_SESSION["reload_xml"] = true; + + //clear the cache + if (is_array($ring_group_contexts) && @sizeof($ring_group_contexts) != 0) { + $ring_group_contexts = array_unique($ring_group_contexts); + $cache = new cache; + foreach ($ring_group_contexts as $ring_group_context) { + $cache->delete("dialplan:" . $ring_group_context); + } + } + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Deletes multiple destination records from the database. + * + * @param array $records An array of destination records to delete, where each record contains 'uuid' and 'checked' keys. + * + * @return void + */ + public function delete_destinations($records) { + + //assign private variables + $this->permission_prefix = 'ring_group_destination_'; + $this->table = 'ring_group_destinations'; + $this->uuid_prefix = 'ring_group_destination_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('L$ring_group_uuidocation: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked ring groups, build where clause for below + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = $record['uuid']; + } + } + + //get ring group context + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select ring_group_context from v_ring_groups "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and ring_group_uuid = :ring_group_uuid "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['ring_group_uuid'] = $this->ring_group_uuid; + $ring_group_context = $this->database->select($sql, $parameters, 'column'); + unset($sql, $parameters); + } + + //build the delete array + if (!empty($uuids) && is_array($uuids) && @sizeof($uuids) != 0) { + $x = 0; + foreach ($uuids as $uuid) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + $x++; + } + } + + //delete the checked rows + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + + //execute delete + $this->database->delete($array); + unset($array); + + //apply settings reminder + $_SESSION["reload_xml"] = true; + + //clear the cache + if ($ring_group_context) { + $cache = new cache; + $cache->delete("dialplan:" . $ring_group_context); + } + + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle, dialplan_uuid, ring_group_context from v_" . $this->table . " "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $ring_groups[$row['uuid']]['state'] = $row['toggle']; + $ring_groups[$row['uuid']]['dialplan_uuid'] = $row['dialplan_uuid']; + $ring_group_contexts[] = $row['ring_group_context']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($ring_groups as $uuid => $ring_group) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $ring_group['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $array['dialplans'][$x]['dialplan_uuid'] = $ring_group['dialplan_uuid']; + $array['dialplans'][$x]['dialplan_enabled'] = $ring_group['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('dialplan_edit', 'temp'); + + //save the array + + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('dialplan_edit', 'temp'); + + //apply settings reminder + $_SESSION["reload_xml"] = true; + + //clear the cache + if (is_array($ring_group_contexts) && @sizeof($ring_group_contexts) != 0) { + $ring_group_contexts = array_unique($ring_group_contexts); + $cache = new cache; + foreach ($ring_group_contexts as $ring_group_context) { + $cache->delete("dialplan:" . $ring_group_context); + } + } + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->permission_prefix . 'add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create insert array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + + //primary table + $sql = "select * from v_" . $this->table . " "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $y = $z = 0; + foreach ($rows as $x => $row) { + $new_ring_group_uuid = uuid(); + $new_dialplan_uuid = uuid(); + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; + } + } + + //copy data + $array[$this->table][$x] = $row; + + //overwrite + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $new_ring_group_uuid; + $array[$this->table][$x]['dialplan_uuid'] = $new_dialplan_uuid; + $array[$this->table][$x]['ring_group_description'] = trim($row['ring_group_description'] . ' (' . $text['label-copy'] . ')'); + + //users sub table + $sql_2 = "select * from v_ring_group_users where ring_group_uuid = :ring_group_uuid"; + $parameters_2['ring_group_uuid'] = $row['ring_group_uuid']; + $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); + if (is_array($rows_2) && @sizeof($rows_2) != 0) { + foreach ($rows_2 as $row_2) { + + //convert boolean values to a string + foreach ($row_2 as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row_2[$key] = $value; + } + } + + //copy data + $array['ring_group_users'][$y] = $row_2; + + //overwrite + $array['ring_group_users'][$y]['ring_group_user_uuid'] = uuid(); + $array['ring_group_users'][$y]['ring_group_uuid'] = $new_ring_group_uuid; + + //increment + $y++; + + } + } + unset($sql_2, $parameters_2, $rows_2, $row_2); + + //destinations sub table + $sql_3 = "select * from v_ring_group_destinations where ring_group_uuid = :ring_group_uuid"; + $parameters_3['ring_group_uuid'] = $row['ring_group_uuid']; + $rows_3 = $this->database->select($sql_3, $parameters_3, 'all'); + if (is_array($rows_3) && @sizeof($rows_3) != 0) { + foreach ($rows_3 as $row_3) { + + //convert boolean values to a string + foreach ($row_3 as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row_3[$key] = $value; + } + } + + //copy data + $array['ring_group_destinations'][$z] = $row_3; + + //overwrite + $array['ring_group_destinations'][$z]['ring_group_destination_uuid'] = uuid(); + $array['ring_group_destinations'][$z]['ring_group_uuid'] = $new_ring_group_uuid; + + //increment + $z++; + + } + } + unset($sql_3, $parameters_3, $rows_3, $row_3); + + //ring group dialplan record + $sql_4 = "select * from v_dialplans where dialplan_uuid = :dialplan_uuid"; + $parameters_4['dialplan_uuid'] = $row['dialplan_uuid']; + $dialplan = $this->database->select($sql_4, $parameters_4, 'row'); + if (is_array($dialplan) && @sizeof($dialplan) != 0) { + + //convert boolean values to a string + foreach ($dialplan as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $dialplan[$key] = $value; + } + } + + //copy data + $array['dialplans'][$x] = $dialplan; + + //overwrite + $array['dialplans'][$x]['dialplan_uuid'] = $new_dialplan_uuid; + $dialplan_xml = $dialplan['dialplan_xml']; + $dialplan_xml = str_replace($row['ring_group_uuid'], $new_ring_group_uuid, $dialplan_xml); //replace source ring_group_uuid with new + $dialplan_xml = str_replace($dialplan['dialplan_uuid'], $new_dialplan_uuid, $dialplan_xml); //replace source dialplan_uuid with new + $array['dialplans'][$x]['dialplan_xml'] = $dialplan_xml; + $array['dialplans'][$x]['dialplan_description'] = trim($dialplan['dialplan_description'] . ' (' . $text['label-copy'] . ')'); + + } + unset($sql_4, $parameters_4, $dialplan); + + //create ring group context array + $ring_group_contexts = $row['ring_group_context']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('ring_group_user_add', 'temp'); + $p->add('ring_group_destination_add', 'temp'); + $p->add("dialplan_add", "temp"); + + //save the array + + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('ring_group_user_add', 'temp'); + $p->delete('ring_group_destination_add', 'temp'); + $p->delete("dialplan_add", "temp"); + + //apply settings reminder + $_SESSION["reload_xml"] = true; + + //clear the cache + if (is_array($ring_group_contexts) && @sizeof($ring_group_contexts) != 0) { + $ring_group_contexts = array_unique($ring_group_contexts); + $cache = new cache; + foreach ($ring_group_contexts as $ring_group_context) { + $cache->delete("dialplan:" . $ring_group_context); + } + } + + //set message + message::add($text['message-copy']); + + } + unset($records); + } + + } + } + +} diff --git a/app/sip_profiles/resources/classes/sip_profiles.php b/app/sip_profiles/resources/classes/sip_profiles.php index 557b9cc76f..fb81dbfdea 100644 --- a/app/sip_profiles/resources/classes/sip_profiles.php +++ b/app/sip_profiles/resources/classes/sip_profiles.php @@ -25,420 +25,456 @@ */ //define the sip profiles class - class sip_profiles { - - /** - * declare constant variables - */ - const app_name = 'sip_profiles'; - const app_uuid = 'a6a7c4c5-340a-43ce-bcbc-2ed9bab8659d'; - - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; - - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; - - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; - - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; - - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; - - /** - * declare public variables - */ - public $sip_profile_uuid; - - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); - - //assign private variables - $this->permission_prefix = 'sip_profile_'; - $this->list_page = 'sip_profiles.php'; - $this->table = 'sip_profiles'; - $this->uuid_prefix = 'sip_profile_'; - $this->toggle_field = 'sip_profile_enabled'; - $this->toggle_values = ['true','false']; - } - - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked sip profiles, build where clause for below - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //get necessary sip profile details - $sql = "select ".$this->uuid_prefix."uuid as uuid, sip_profile_name, sip_profile_hostname from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $sip_profiles[$row['uuid']]['name'] = $row['sip_profile_name']; - $sip_profiles[$row['uuid']]['hostname'] = $row['sip_profile_hostname']; - } - } - unset($sql, $parameters, $rows, $row); - - //build the delete array - $x = 0; - foreach ($sip_profiles as $sip_profile_uuid => $sip_profile) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $sip_profile_uuid; - $array['sip_profile_domains'][$x][$this->uuid_prefix.'uuid'] = $sip_profile_uuid; - $array['sip_profile_settings'][$x][$this->uuid_prefix.'uuid'] = $sip_profile_uuid; - $x++; - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('sip_profile_domain_delete', 'temp'); - $p->add('sip_profile_setting_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('sip_profile_domain_delete', 'temp'); - $p->delete('sip_profile_setting_delete', 'temp'); - - //delete the xml sip profile and directory - $switch_conf_dir = $this->settings->get('switch', 'conf'); - foreach ($sip_profiles as $sip_profile_uuid => $sip_profile) { - @unlink($switch_conf_dir."/sip_profiles/".$sip_profile['name'].".xml"); - @unlink($switch_conf_dir."/sip_profiles/".$sip_profile['name']); - } - - //save the sip profile xml - save_sip_profile_xml(); - - //apply settings reminder - $_SESSION["reload_xml"] = true; - - //determine hostnames, get system hostname if necessary - $empty_hostname = false; - foreach ($sip_profiles as $sip_profile_uuid => $sip_profile) { - if ($sip_profile['hostname'] != '') { - $hostnames[] = $sip_profile['hostname']; - } - else { - $empty_hostname = true; - } - } - if ($empty_hostname) { - $hostnames[] = gethostname(); - } - - //clear the cache - if (is_array($hostnames) && @sizeof($hostnames) != 0) { - $hostnames = array_unique($hostnames); - $cache = new cache; - foreach ($hostnames as $hostname) { - $cache->delete($hostname.":configuration:sofia.conf"); - } - } - - //set message - message::add($text['message-delete']); - } - unset($records, $sip_profiles); - } - } - } - - public function delete_domains($records) { - //assign private variables - $this->permission_prefix = 'sip_profile_domain_'; - $this->list_page = 'sip_profile_edit.php?id='.$this->sip_profile_uuid; - $this->table = 'sip_profile_domains'; - $this->uuid_prefix = 'sip_profile_domain_'; - - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked sip profiles, build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['sip_profile_uuid'] = $this->sip_profile_uuid; - } - } - - //get necessary sip profile details - if (!empty($this->sip_profile_uuid) && is_uuid($this->sip_profile_uuid)) { - $sql = "select sip_profile_hostname from v_sip_profiles "; - $sql .= "where sip_profile_uuid = :sip_profile_uuid "; - $parameters['sip_profile_uuid'] = $this->sip_profile_uuid; - $sip_profile_hostname = $this->database->select($sql, $parameters, 'column'); - unset($sql, $parameters); - } - - //delete the checked rows - if (!empty($array) && @sizeof($array) != 0) { - - //execute delete - $this->database->delete($array); - unset($array); - - //save the sip profile xml - save_sip_profile_xml(); - - //apply settings reminder - $_SESSION["reload_xml"] = true; - - //get system hostname if necessary - if (empty($sip_profile_hostname)) { - $sip_profile_hostname = gethostname(); - } - - //clear the cache - if (!empty($sip_profile_hostname)) { - $cache = new cache; - $cache->delete($sip_profile_hostname.":configuration:sofia.conf"); - } - - } - unset($records); - } - } - } - - public function delete_settings($records) { - //assign private variables - $this->permission_prefix = 'sip_profile_setting_'; - $this->list_page = 'sip_profile_edit.php?id='.$this->sip_profile_uuid; - $this->table = 'sip_profile_settings'; - $this->uuid_prefix = 'sip_profile_setting_'; - - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (!empty($records) && @sizeof($records) != 0) { - - //filter out unchecked sip profiles, build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['sip_profile_uuid'] = $this->sip_profile_uuid; - } - } - - //get necessary sip profile details - if (!empty($this->sip_profile_uuid) && is_uuid($this->sip_profile_uuid)) { - $sql = "select sip_profile_hostname from v_sip_profiles "; - $sql .= "where sip_profile_uuid = :sip_profile_uuid "; - $parameters['sip_profile_uuid'] = $this->sip_profile_uuid; - $sip_profile_hostname = $this->database->select($sql, $parameters, 'column'); - unset($sql, $parameters); - } - - //delete the checked rows - if (!empty($array) && @sizeof($array) != 0) { - - //execute delete - $this->database->delete($array); - unset($array); - - //save the sip profile xml - save_sip_profile_xml(); - - //apply settings reminder - $_SESSION["reload_xml"] = true; - - //get system hostname if necessary - if (empty($sip_profile_hostname)) { - $sip_profile_hostname = gethostname(); - } - - //clear the cache - if (!empty($sip_profile_hostname)) { - $cache = new cache; - $cache->delete($sip_profile_hostname.":configuration:sofia.conf"); - } - - } - unset($records); - } - } - } - - /** - * toggle records - */ - public function toggle($records) { - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (!empty($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle, sip_profile_hostname from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $sip_profiles[$row['uuid']]['state'] = $row['toggle']; - $sip_profiles[$row['uuid']]['hostname'] = $row['sip_profile_hostname']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach ($sip_profiles as $uuid => $sip_profile) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $sip_profile['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - - //save the changes - if (!empty($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //determine hostnames, get system hostname if necessary - $empty_hostname = false; - foreach ($sip_profiles as $sip_profile_uuid => $sip_profile) { - if ($sip_profile['hostname'] != '') { - $hostnames[] = $sip_profile['hostname']; - } - else { - $empty_hostname = true; - } - } - if ($empty_hostname) { - $esl = event_socket::create(); - if ($esl->is_connected()) { - $hostnames[] = gethostname(); - } - } - - //clear the cache - if (!empty($hostnames) && @sizeof($hostnames) != 0) { - $hostnames = array_unique($hostnames); - $cache = new cache; - foreach ($hostnames as $hostname) { - $cache->delete($hostname.":configuration:sofia.conf"); - } - } - - //save the sip profile xml - save_sip_profile_xml(); - - //apply settings reminder - $_SESSION["reload_xml"] = true; - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - - } - } - +class sip_profiles { + + /** + * declare constant variables + */ + const app_name = 'sip_profiles'; + const app_uuid = 'a6a7c4c5-340a-43ce-bcbc-2ed9bab8659d'; + + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; + + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; + + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; + + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; + + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; + + /** + * declare public variables + */ + public $sip_profile_uuid; + + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + + //assign private variables + $this->permission_prefix = 'sip_profile_'; + $this->list_page = 'sip_profiles.php'; + $this->table = 'sip_profiles'; + $this->uuid_prefix = 'sip_profile_'; + $this->toggle_field = 'sip_profile_enabled'; + $this->toggle_values = ['true', 'false']; } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked sip profiles, build where clause for below + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //get necessary sip profile details + $sql = "select " . $this->uuid_prefix . "uuid as uuid, sip_profile_name, sip_profile_hostname from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $sip_profiles[$row['uuid']]['name'] = $row['sip_profile_name']; + $sip_profiles[$row['uuid']]['hostname'] = $row['sip_profile_hostname']; + } + } + unset($sql, $parameters, $rows, $row); + + //build the delete array + $x = 0; + foreach ($sip_profiles as $sip_profile_uuid => $sip_profile) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $sip_profile_uuid; + $array['sip_profile_domains'][$x][$this->uuid_prefix . 'uuid'] = $sip_profile_uuid; + $array['sip_profile_settings'][$x][$this->uuid_prefix . 'uuid'] = $sip_profile_uuid; + $x++; + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('sip_profile_domain_delete', 'temp'); + $p->add('sip_profile_setting_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('sip_profile_domain_delete', 'temp'); + $p->delete('sip_profile_setting_delete', 'temp'); + + //delete the xml sip profile and directory + $switch_conf_dir = $this->settings->get('switch', 'conf'); + foreach ($sip_profiles as $sip_profile_uuid => $sip_profile) { + @unlink($switch_conf_dir . "/sip_profiles/" . $sip_profile['name'] . ".xml"); + @unlink($switch_conf_dir . "/sip_profiles/" . $sip_profile['name']); + } + + //save the sip profile xml + save_sip_profile_xml(); + + //apply settings reminder + $_SESSION["reload_xml"] = true; + + //determine hostnames, get system hostname if necessary + $empty_hostname = false; + foreach ($sip_profiles as $sip_profile_uuid => $sip_profile) { + if ($sip_profile['hostname'] != '') { + $hostnames[] = $sip_profile['hostname']; + } else { + $empty_hostname = true; + } + } + if ($empty_hostname) { + $hostnames[] = gethostname(); + } + + //clear the cache + if (is_array($hostnames) && @sizeof($hostnames) != 0) { + $hostnames = array_unique($hostnames); + $cache = new cache; + foreach ($hostnames as $hostname) { + $cache->delete($hostname . ":configuration:sofia.conf"); + } + } + + //set message + message::add($text['message-delete']); + } + unset($records, $sip_profiles); + } + } + } + + /** + * Deletes specified domains from the system. + * + * @param array $records An array of records to be deleted, each containing 'checked' and 'uuid' keys. + * + * @return void + */ + public function delete_domains($records) { + //assign private variables + $this->permission_prefix = 'sip_profile_domain_'; + $this->list_page = 'sip_profile_edit.php?id=' . $this->sip_profile_uuid; + $this->table = 'sip_profile_domains'; + $this->uuid_prefix = 'sip_profile_domain_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked sip profiles, build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['sip_profile_uuid'] = $this->sip_profile_uuid; + } + } + + //get necessary sip profile details + if (!empty($this->sip_profile_uuid) && is_uuid($this->sip_profile_uuid)) { + $sql = "select sip_profile_hostname from v_sip_profiles "; + $sql .= "where sip_profile_uuid = :sip_profile_uuid "; + $parameters['sip_profile_uuid'] = $this->sip_profile_uuid; + $sip_profile_hostname = $this->database->select($sql, $parameters, 'column'); + unset($sql, $parameters); + } + + //delete the checked rows + if (!empty($array) && @sizeof($array) != 0) { + + //execute delete + $this->database->delete($array); + unset($array); + + //save the sip profile xml + save_sip_profile_xml(); + + //apply settings reminder + $_SESSION["reload_xml"] = true; + + //get system hostname if necessary + if (empty($sip_profile_hostname)) { + $sip_profile_hostname = gethostname(); + } + + //clear the cache + if (!empty($sip_profile_hostname)) { + $cache = new cache; + $cache->delete($sip_profile_hostname . ":configuration:sofia.conf"); + } + + } + unset($records); + } + } + } + + /** + * Deletes settings for one or more sip profiles. + * + * @param array $records An associative array containing the records to delete, where each record is an associative array + * with 'uuid' and optionally 'checked' keys. Defaults to an empty array. + * + * @return void + */ + public function delete_settings($records) { + //assign private variables + $this->permission_prefix = 'sip_profile_setting_'; + $this->list_page = 'sip_profile_edit.php?id=' . $this->sip_profile_uuid; + $this->table = 'sip_profile_settings'; + $this->uuid_prefix = 'sip_profile_setting_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (!empty($records) && @sizeof($records) != 0) { + + //filter out unchecked sip profiles, build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['sip_profile_uuid'] = $this->sip_profile_uuid; + } + } + + //get necessary sip profile details + if (!empty($this->sip_profile_uuid) && is_uuid($this->sip_profile_uuid)) { + $sql = "select sip_profile_hostname from v_sip_profiles "; + $sql .= "where sip_profile_uuid = :sip_profile_uuid "; + $parameters['sip_profile_uuid'] = $this->sip_profile_uuid; + $sip_profile_hostname = $this->database->select($sql, $parameters, 'column'); + unset($sql, $parameters); + } + + //delete the checked rows + if (!empty($array) && @sizeof($array) != 0) { + + //execute delete + $this->database->delete($array); + unset($array); + + //save the sip profile xml + save_sip_profile_xml(); + + //apply settings reminder + $_SESSION["reload_xml"] = true; + + //get system hostname if necessary + if (empty($sip_profile_hostname)) { + $sip_profile_hostname = gethostname(); + } + + //clear the cache + if (!empty($sip_profile_hostname)) { + $cache = new cache; + $cache->delete($sip_profile_hostname . ":configuration:sofia.conf"); + } + + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (!empty($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle, sip_profile_hostname from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $sip_profiles[$row['uuid']]['state'] = $row['toggle']; + $sip_profiles[$row['uuid']]['hostname'] = $row['sip_profile_hostname']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($sip_profiles as $uuid => $sip_profile) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $sip_profile['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + + //save the changes + if (!empty($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //determine hostnames, get system hostname if necessary + $empty_hostname = false; + foreach ($sip_profiles as $sip_profile_uuid => $sip_profile) { + if ($sip_profile['hostname'] != '') { + $hostnames[] = $sip_profile['hostname']; + } else { + $empty_hostname = true; + } + } + if ($empty_hostname) { + $esl = event_socket::create(); + if ($esl->is_connected()) { + $hostnames[] = gethostname(); + } + } + + //clear the cache + if (!empty($hostnames) && @sizeof($hostnames) != 0) { + $hostnames = array_unique($hostnames); + $cache = new cache; + foreach ($hostnames as $hostname) { + $cache->delete($hostname . ":configuration:sofia.conf"); + } + } + + //save the sip profile xml + save_sip_profile_xml(); + + //apply settings reminder + $_SESSION["reload_xml"] = true; + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + + } + } + +} diff --git a/app/sip_status/sip_status.php b/app/sip_status/sip_status.php index ef5e866129..1d119270b5 100644 --- a/app/sip_status/sip_status.php +++ b/app/sip_status/sip_status.php @@ -88,6 +88,14 @@ } //sort the array + /** + * Compares two XML elements based on their names and sorts them in a natural order. + * + * @param object $a The first XML element to compare. + * @param object $b The second XML element to compare. + * + * @return int A negative integer, zero, or a positive integer if $a's name is less than, equal to, or greater than $b's name respectively. + */ function sort_xml($a, $b) { return strnatcmp($a->name, $b->name); } diff --git a/app/sofia_global_settings/resources/classes/sofia_global_settings.php b/app/sofia_global_settings/resources/classes/sofia_global_settings.php index 5e5b62743d..859ac5b78f 100644 --- a/app/sofia_global_settings/resources/classes/sofia_global_settings.php +++ b/app/sofia_global_settings/resources/classes/sofia_global_settings.php @@ -27,216 +27,239 @@ /** * sofia_global_settings class */ - class sofia_global_settings { - - /** - * declare constant variables - */ - const app_name = 'sofia_global_settings'; - const app_uuid = '240c25a3-a2cf-44ea-a300-0626eca5b945'; - - /** - * declare the variables - */ - private $database; - - private $name; - private $table; - private $toggle_field; - private $toggle_values; - private $description_field; - private $location; +class sofia_global_settings { /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set objects - $this->database = $setting_array['database'] ?? database::new(); + * declare constant variables + */ + const app_name = 'sofia_global_settings'; + const app_uuid = '240c25a3-a2cf-44ea-a300-0626eca5b945'; - //assign the variables - $this->name = 'sofia_global_setting'; - $this->table = 'sofia_global_settings'; - $this->toggle_field = 'global_setting_enabled'; - $this->toggle_values = ['true','false']; - $this->description_field = 'global_setting_description'; - $this->location = 'sofia_global_settings.php'; - } + /** + * declare the variables + */ + private $database; - /** - * delete rows from the database - */ - public function delete($records) { - if (permission_exists($this->name.'_delete')) { + private $name; + private $table; + private $toggle_field; + private $toggle_values; + private $description_field; + private $location; - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //delete multiple records - if (!empty($records) && @sizeof($records) != 0) { - //build the delete array - $x = 0; - foreach ($records as $record) { - //add to the array - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['sofia_global_setting_uuid'])) { - $array[$this->table][$x]['sofia_global_setting_uuid'] = $record['sofia_global_setting_uuid']; - } - - //increment the id - $x++; - } - - //delete the checked rows - if (!empty($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * toggle a field between two values - */ - public function toggle($records) { - if (permission_exists($this->name.'_edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //toggle the checked records - if (!empty($records) && @sizeof($records) != 0) { - //get current toggle state - foreach($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['sofia_global_setting_uuid'])) { - $uuids[] = "'".$record['sofia_global_setting_uuid']."'"; - } - } - if (!empty($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->name."_uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where ".$this->name."_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, null, 'all'); - if (!empty($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($states as $uuid => $state) { - //create the array - $array[$this->table][$x][$this->name.'_uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - - //increment the id - $x++; - } - - //save the changes - if (!empty($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - } - } - - /** - * copy rows from the database - */ - public function copy($records) { - if (permission_exists($this->name.'_add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->location); - exit; - } - - //copy the checked records - if (!empty($records) && @sizeof($records) != 0) { - - //get checked records - foreach($records as $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['sofia_global_setting_uuid'])) { - $uuids[] = "'".$record['sofia_global_setting_uuid']."'"; - } - } - - //create the array from existing data - if (!empty($uuids) && @sizeof($uuids) != 0) { - $sql = "select * from v_".$this->table." "; - $sql .= "where sofia_global_setting_uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, null, 'all'); - if (!empty($rows) && @sizeof($rows) != 0) { - $x = 0; - foreach ($rows as $row) { - //copy data - $array[$this->table][$x] = $row; - - //add copy to the description - $array[$this->table][$x][$this->name.'_uuid'] = uuid(); - $array[$this->table][$x]['global_setting_enabled'] = $row['global_setting_enabled'] === true ? 'true' : 'false'; - $array[$this->table][$x][$this->description_field] = trim($row[$this->description_field] ?? '').trim(' ('.$text['label-copy'].')'); - - //increment the id - $x++; - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (!empty($array) && @sizeof($array) != 0) { - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-copy']); - } - unset($records); - } - } - } + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set objects + $this->database = $setting_array['database'] ?? database::new(); + //assign the variables + $this->name = 'sofia_global_setting'; + $this->table = 'sofia_global_settings'; + $this->toggle_field = 'global_setting_enabled'; + $this->toggle_values = ['true', 'false']; + $this->description_field = 'global_setting_description'; + $this->location = 'sofia_global_settings.php'; } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->name . '_delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //delete multiple records + if (!empty($records) && @sizeof($records) != 0) { + //build the delete array + $x = 0; + foreach ($records as $record) { + //add to the array + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['sofia_global_setting_uuid'])) { + $array[$this->table][$x]['sofia_global_setting_uuid'] = $record['sofia_global_setting_uuid']; + } + + //increment the id + $x++; + } + + //delete the checked rows + if (!empty($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->name . '_edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //toggle the checked records + if (!empty($records) && @sizeof($records) != 0) { + //get current toggle state + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['sofia_global_setting_uuid'])) { + $uuids[] = "'" . $record['sofia_global_setting_uuid'] . "'"; + } + } + if (!empty($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->name . "_uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where " . $this->name . "_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, null, 'all'); + if (!empty($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + //create the array + $array[$this->table][$x][$this->name . '_uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + + //increment the id + $x++; + } + + //save the changes + if (!empty($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->name . '_add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->location); + exit; + } + + //copy the checked records + if (!empty($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['sofia_global_setting_uuid'])) { + $uuids[] = "'" . $record['sofia_global_setting_uuid'] . "'"; + } + } + + //create the array from existing data + if (!empty($uuids) && @sizeof($uuids) != 0) { + $sql = "select * from v_" . $this->table . " "; + $sql .= "where sofia_global_setting_uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, null, 'all'); + if (!empty($rows) && @sizeof($rows) != 0) { + $x = 0; + foreach ($rows as $row) { + //copy data + $array[$this->table][$x] = $row; + + //add copy to the description + $array[$this->table][$x][$this->name . '_uuid'] = uuid(); + $array[$this->table][$x]['global_setting_enabled'] = $row['global_setting_enabled'] === true ? 'true' : 'false'; + $array[$this->table][$x][$this->description_field] = trim($row[$this->description_field] ?? '') . trim(' (' . $text['label-copy'] . ')'); + + //increment the id + $x++; + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (!empty($array) && @sizeof($array) != 0) { + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-copy']); + } + unset($records); + } + } + } + +} diff --git a/app/streams/resources/classes/streams.php b/app/streams/resources/classes/streams.php index f6c9866c8c..c41e6aa806 100644 --- a/app/streams/resources/classes/streams.php +++ b/app/streams/resources/classes/streams.php @@ -25,262 +25,295 @@ */ //define the streams class - class streams { +class streams { - /** - * declare constant variables - */ - const app_name = 'streams'; - const app_uuid = 'ffde6287-aa18-41fc-9a38-076d292e0a38'; + /** + * declare constant variables + */ + const app_name = 'streams'; + const app_uuid = 'ffde6287-aa18-41fc-9a38-076d292e0a38'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * Username set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $username; + /** + * Username set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $username; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_name; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - - //assign private variables - $this->permission_prefix = 'stream_'; - $this->list_page = 'streams.php'; - $this->table = 'streams'; - $this->uuid_prefix = 'stream_'; - $this->toggle_field = 'stream_enabled'; - $this->toggle_values = ['true','false']; - } - - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //execute delete - $this->database->delete($array); - unset($array); - - //set message - message::add($text['message-delete']); - } - unset($records); - } - } - } - - /** - * toggle records - */ - public function toggle($records) { - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach ($states as $uuid => $state) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } - - } - } - - /** - * copy records - */ - public function copy($records) { - if (permission_exists($this->permission_prefix.'add')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get checked records - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //create insert array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select * from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $x => $row) { - - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = uuid(); - $array[$this->table][$x]['stream_description'] = trim($row['stream_description'].' ('.$text['label-copy'].')'); - - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //set message - message::add($text['message-copy']); - - } - unset($records); - } - - } - } + //set objects + $this->database = $setting_array['database'] ?? database::new(); + //assign private variables + $this->permission_prefix = 'stream_'; + $this->list_page = 'streams.php'; + $this->table = 'streams'; + $this->uuid_prefix = 'stream_'; + $this->toggle_field = 'stream_enabled'; + $this->toggle_values = ['true', 'false']; } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //execute delete + $this->database->delete($array); + unset($array); + + //set message + message::add($text['message-delete']); + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); + } + + } + } + + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->permission_prefix . 'add')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create insert array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select * from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $x => $row) { + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; + } + } + + //copy data + $array[$this->table][$x] = $row; + + //overwrite + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = uuid(); + $array[$this->table][$x]['stream_description'] = trim($row['stream_description'] . ' (' . $text['label-copy'] . ')'); + + } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //set message + message::add($text['message-copy']); + + } + unset($records); + } + + } + } + +} diff --git a/app/switch/resources/classes/presence.php b/app/switch/resources/classes/presence.php index ad0ac4cbbb..d22c98e111 100644 --- a/app/switch/resources/classes/presence.php +++ b/app/switch/resources/classes/presence.php @@ -24,77 +24,87 @@ /** * presence class */ - class presence { +class presence { - /** - * active presence - * @var string $presence_id - */ - public function active($presence_id) { - $json = event_socket::api('show calls as json'); - $call_array = json_decode($json, true); - if (isset($call_array['rows'])) { - $x = 0; - foreach ($call_array['rows'] as $row) { - if ($row['presence_id'] == $presence_id) { + /** + * Check if presence is active + * + * @param string $presence_id Presence ID to check for activity + * + * @return bool True if presence is active, False otherwise + */ + public function active($presence_id) { + $json = event_socket::api('show calls as json'); + $call_array = json_decode($json, true); + if (isset($call_array['rows'])) { + $x = 0; + foreach ($call_array['rows'] as $row) { + if ($row['presence_id'] == $presence_id) { + return true; + } + + if (isset($row['b_presence_id']) && $row['b_presence_id'] != 0) { + if ($row['b_presence_id'] == $presence_id) { return true; } - - if (isset($row['b_presence_id']) && $row['b_presence_id'] != 0) { - if ($row['b_presence_id'] == $presence_id) { - return true; - } - $x++; - } - $x++; } + + $x++; } - return false; - } - - /** - * show presence - */ - public function show() { - $array = []; - $json = event_socket::api('show calls as json'); - $call_array = json_decode($json, true); - if (isset($call_array['rows'])) { - $x = 0; - foreach ($call_array['rows'] as $row) { - $array[$x]['presence_id'] = $row['presence_id']; - $array[$x]['presence_user'] = explode('@', $row['presence_id'])[0]; - $array[$x]['domain_name'] = explode('@', $row['presence_id'])[1]; - - if (isset($row['b_presence_id']) && $row['b_presence_id'] != 0) { - $x++; - $array[$x]['presence_id'] = $row['b_presence_id']; - $array[$x]['presence_user'] = explode('@', $row['b_presence_id'])[0]; - $array[$x]['domain_name'] = explode('@', $row['b_presence_id'])[1]; - } - - $x++; - } - } - return $array; } + return false; } + /** + * Retrieves and processes data from the event socket API. + * + * This method sends a 'show calls as json' request to the event socket API, + * decodes the response, and returns an array containing presence information + * for each user. The array is indexed by the index of the row in the original + * JSON response, with keys for presence_id, presence_user, and domain_name. + * + * @return array An array of arrays containing presence information. + */ + public function show() { + $array = []; + $json = event_socket::api('show calls as json'); + $call_array = json_decode($json, true); + if (isset($call_array['rows'])) { + $x = 0; + foreach ($call_array['rows'] as $row) { + $array[$x]['presence_id'] = $row['presence_id']; + $array[$x]['presence_user'] = explode('@', $row['presence_id'])[0]; + $array[$x]['domain_name'] = explode('@', $row['presence_id'])[1]; + + if (isset($row['b_presence_id']) && $row['b_presence_id'] != 0) { + $x++; + $array[$x]['presence_id'] = $row['b_presence_id']; + $array[$x]['presence_user'] = explode('@', $row['b_presence_id'])[0]; + $array[$x]['domain_name'] = explode('@', $row['b_presence_id'])[1]; + } + + $x++; + } + } + return $array; + } +} + //examples - /* - //check if presence is active - $presence_id = '103@'.$_SESSION['domain_name']; - $presence = new presence; - $result = $presence->active($presence_id); - echo "presence_id $presence_id
    \n"; - if ($result) { - echo "active: true\n"; - } - else { - echo "active: false\n"; - } - //show active the presence - $presence = new presence; - $array = $presence->show(); - */ +/* +//check if presence is active + $presence_id = '103@'.$_SESSION['domain_name']; + $presence = new presence; + $result = $presence->active($presence_id); + echo "presence_id $presence_id
    \n"; + if ($result) { + echo "active: true\n"; + } + else { + echo "active: false\n"; + } +//show active the presence + $presence = new presence; + $array = $presence->show(); +*/ diff --git a/app/switch/resources/classes/ringbacks.php b/app/switch/resources/classes/ringbacks.php index 684ae10eb7..b854c5919d 100644 --- a/app/switch/resources/classes/ringbacks.php +++ b/app/switch/resources/classes/ringbacks.php @@ -25,258 +25,287 @@ Matthew Vale */ - class ringbacks { +class ringbacks { - /** - * declare constant variables - */ - const app_name = 'ringbacks'; - const app_uuid = 'b63db353-e1c6-4401-8f10-101a6ee73b74'; + /** + * declare constant variables + */ + const app_name = 'ringbacks'; + const app_uuid = 'b63db353-e1c6-4401-8f10-101a6ee73b74'; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_uuid; - /** - * declare public variables - */ - public $ringtones_list; + /** + * declare public variables + */ + public $ringtones_list; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * Username set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $username; + /** + * Username set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $username; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_name; - /** - * declare private variables - */ - private $tones_list; - private $music_list; - private $recordings_list; - private $default_ringback_label; - private $streams; + /** + * declare private variables + */ + private $tones_list; + private $music_list; + private $recordings_list; + private $default_ringback_label; + private $streams; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - $this->username = $setting_array['username'] ?? $_SESSION['username'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + $this->username = $setting_array['username'] ?? $_SESSION['username'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); + //set objects + $this->database = $setting_array['database'] ?? database::new(); - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //get the ringtones - $sql = "select * from v_vars "; - $sql .= "where var_category = 'Ringtones' "; - $sql .= "order by var_name asc "; - $ringtones = $this->database->select($sql, null, 'all'); - if (!empty($ringtones)) { - foreach ($ringtones as $ringtone) { - $ringtone = $ringtone['var_name']; - if (isset($text['label-'.$ringtone])) { - $label = $text['label-'.$ringtone]; - } - else { - $label = $ringtone; - } - $ringtones_list[$ringtone] = $label; + //get the ringtones + $sql = "select * from v_vars "; + $sql .= "where var_category = 'Ringtones' "; + $sql .= "order by var_name asc "; + $ringtones = $this->database->select($sql, null, 'all'); + if (!empty($ringtones)) { + foreach ($ringtones as $ringtone) { + $ringtone = $ringtone['var_name']; + if (isset($text['label-' . $ringtone])) { + $label = $text['label-' . $ringtone]; + } else { + $label = $ringtone; } - } - $this->ringtones_list = $ringtones_list ?? ''; - unset($sql, $ringtones, $ringtone, $ringtones_list); - - //get the default_ringback label - /* - $sql = "select * from v_vars where var_name = 'ringback' "; - $row = $this->database->select($sql, null, 'row'); - unset($sql); - $default_ringback = (string) $row['var_value']; - $default_ringback = preg_replace('/\A\$\${/',"",$default_ringback); - $default_ringback = preg_replace('/}\z/',"",$default_ringback); - #$label = $text['label-'.$default_ringback]; - #if($label == "") { - $label = $default_ringback; - #} - $this->default_ringback_label = $label; - unset($results, $default_ringback, $label); - */ - - //get the tones - $tones = new tones; - $this->tones_list = $tones->tones_list(); - - //get music on hold and recordings - if (is_dir($_SERVER["PROJECT_ROOT"].'/app/music_on_hold')) { - $music = new switch_music_on_hold; - $this->music_list = $music->get(); - } - if (is_dir($_SERVER["PROJECT_ROOT"].'/app/recordings')) { - $recordings = new switch_recordings; - $this->recordings_list = $recordings->list_recordings(); - } - - if (is_dir($_SERVER["PROJECT_ROOT"].'/app/streams')) { - $sql = "select * from v_streams "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and stream_enabled = 'true' "; - $sql .= "order by stream_name asc "; - $parameters['domain_uuid'] = $this->domain_uuid; - $streams = $this->database->select($sql, $parameters, 'all'); - $this->streams = $streams; - unset($sql, $parameters, $streams, $row); + $ringtones_list[$ringtone] = $label; } } + $this->ringtones_list = $ringtones_list ?? ''; + unset($sql, $ringtones, $ringtone, $ringtones_list); - public function valid($value) { - foreach($this->ringtones_list as $ringtone_value => $ringtone_name) { - if ($value == "\${".$ringtone_value."}") { - return true; - } - } + //get the default_ringback label + /* + $sql = "select * from v_vars where var_name = 'ringback' "; + $row = $this->database->select($sql, null, 'row'); + unset($sql); + $default_ringback = (string) $row['var_value']; + $default_ringback = preg_replace('/\A\$\${/',"",$default_ringback); + $default_ringback = preg_replace('/}\z/',"",$default_ringback); + #$label = $text['label-'.$default_ringback]; + #if($label == "") { + $label = $default_ringback; + #} + $this->default_ringback_label = $label; + unset($results, $default_ringback, $label); + */ - foreach($this->tones_list as $tone_value => $tone_name) { - if ($value == "\${".$tone_value."}") { - return true; - } - } + //get the tones + $tones = new tones; + $this->tones_list = $tones->tones_list(); - foreach($this->music_list as $row) { - $name = ''; - if (!empty($row['domain_uuid'])) { - $name = $row['domain_name'].'/'; - } - $name .= $row['music_on_hold_name']; - if ($value == "local_stream://".$name) { - return true; - } - } - - foreach($this->recordings_list as $recording_value => $recording_name) { - if ($value == $recording_value) { - return true; - } - } - - foreach($this->streams as $row) { - if ($value == $row['stream_location']) { - return true; - } - } - - return false; + //get music on hold and recordings + if (is_dir($_SERVER["PROJECT_ROOT"] . '/app/music_on_hold')) { + $music = new switch_music_on_hold; + $this->music_list = $music->get(); + } + if (is_dir($_SERVER["PROJECT_ROOT"] . '/app/recordings')) { + $recordings = new switch_recordings; + $this->recordings_list = $recordings->list_recordings(); } - public function select($name, $selected) { - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //start the select - $select = "\n"; - return $select; + if (is_dir($_SERVER["PROJECT_ROOT"] . '/app/streams')) { + $sql = "select * from v_streams "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and stream_enabled = 'true' "; + $sql .= "order by stream_name asc "; + $parameters['domain_uuid'] = $this->domain_uuid; + $streams = $this->database->select($sql, $parameters, 'all'); + $this->streams = $streams; + unset($sql, $parameters, $streams, $row); } } + + /** + * Checks if a given value is valid. + * + * @param mixed $value The value to check for validity + * + * @return bool True if the value is valid, false otherwise + */ + public function valid($value) { + foreach ($this->ringtones_list as $ringtone_value => $ringtone_name) { + if ($value == "\${" . $ringtone_value . "}") { + return true; + } + } + + foreach ($this->tones_list as $tone_value => $tone_name) { + if ($value == "\${" . $tone_value . "}") { + return true; + } + } + + foreach ($this->music_list as $row) { + $name = ''; + if (!empty($row['domain_uuid'])) { + $name = $row['domain_name'] . '/'; + } + $name .= $row['music_on_hold_name']; + if ($value == "local_stream://" . $name) { + return true; + } + } + + foreach ($this->recordings_list as $recording_value => $recording_name) { + if ($value == $recording_value) { + return true; + } + } + + foreach ($this->streams as $row) { + if ($value == $row['stream_location']) { + return true; + } + } + + return false; + } + + /** + * Generates a HTML element with options populated from various lists (music, recordings, streams, ringtones, tones) + */ + public function select($name, $selected) { + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //start the select + $select = "\n"; + return $select; + } +} diff --git a/app/switch/resources/classes/switch_files.php b/app/switch/resources/classes/switch_files.php index ae8416a3a5..2b183e1e2d 100644 --- a/app/switch/resources/classes/switch_files.php +++ b/app/switch/resources/classes/switch_files.php @@ -27,130 +27,137 @@ /** * switch class provides methods for copying switch_files */ - class switch_files { +class switch_files { private $config; /** - * Called when the object is created - */ - public function __construct(array $setting_array = []) { - //set objects - $this->config = $setting_array['config'] ?? config::load(); + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set objects + $this->config = $setting_array['config'] ?? config::load(); + } + + /** + * Converts the given path to a platform-agnostic format. + * + * @param string $path The path to be converted. + * + * @return string The converted path. If running on Windows, backslashes are replaced with forward slashes. + */ + private function correct_path($path) { + global $IS_WINDOWS; + if ($IS_WINDOWS == null) { + if (stristr(PHP_OS, 'WIN')) { + $IS_WINDOWS = true; + } else { + $IS_WINDOWS = false; + } + } + if ($IS_WINDOWS) { + return str_replace('\\', '/', $path); + } + return $path; + } + + /** + * Copy the switch scripts to the switch directory + * + * The function attempts to find the source and destination directories by checking various system locations. If + * neither is found, it throws an exception. + * + * @return void + */ + public function copy_scripts() { + + //get the source directory + if (file_exists('/usr/share/examples/fusionpbx/scripts')) { + $source_directory = '/usr/share/examples/fusionpbx/scripts'; + } elseif (file_exists('/usr/local/www/fusionpbx/app/switch/resources/scripts')) { + $source_directory = '/usr/local/www/fusionpbx/app/switch/resources/scripts'; + } elseif (file_exists('/var/www/fusionpbx/app/switch/resources/scripts')) { + $source_directory = '/var/www/fusionpbx/app/switch/resources/scripts'; + } else { + $source_directory = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/app/switch/resources/scripts'; } - /** - * Corrects the path for specifically for windows - */ - private function correct_path($path) { - global $IS_WINDOWS; - if ($IS_WINDOWS == null) { - if (stristr(PHP_OS, 'WIN')) { $IS_WINDOWS = true; } else { $IS_WINDOWS = false; } - } - if ($IS_WINDOWS) { - return str_replace('\\', '/', $path); - } - return $path; + //get the destination directory + if (file_exists($this->config->get('switch.scripts.dir'))) { + $destination_directory = $this->config->get('switch.scripts.dir'); + } elseif (file_exists('/etc/freeswitch/scripts')) { + $destination_directory = '/etc/freeswitch/scripts'; + } elseif (file_exists('/usr/local/freeswitch/scripts')) { + $destination_directory = '/usr/local/freeswitch/scripts'; } - /** - * Copy the switch scripts to the switch directory - */ - public function copy_scripts() { + //copy the scripts directory + if (!empty($source_directory) && is_readable($source_directory)) { + //copy the main scripts + recursive_copy($source_directory, $destination_directory); + unset($source_directory); - //get the source directory - if (file_exists('/usr/share/examples/fusionpbx/scripts')) { - $source_directory = '/usr/share/examples/fusionpbx/scripts'; + //copy the app/*/resource/install/scripts + $app_scripts = glob($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . 'app/*/resource/scripts'); + foreach ($app_scripts as $app_script) { + recursive_copy($app_script, $destination_directory); } - elseif (file_exists('/usr/local/www/fusionpbx/app/switch/resources/scripts')) { - $source_directory = '/usr/local/www/fusionpbx/app/switch/resources/scripts'; - } - elseif (file_exists('/var/www/fusionpbx/app/switch/resources/scripts')) { - $source_directory = '/var/www/fusionpbx/app/switch/resources/scripts'; - } - else { - $source_directory = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/app/switch/resources/scripts'; - } - - //get the destination directory - if (file_exists($this->config->get('switch.scripts.dir'))) { - $destination_directory = $this->config->get('switch.scripts.dir'); - } - elseif (file_exists('/etc/freeswitch/scripts')) { - $destination_directory = '/etc/freeswitch/scripts'; - } - elseif (file_exists('/usr/local/freeswitch/scripts')) { - $destination_directory = '/usr/local/freeswitch/scripts'; - } - - //copy the scripts directory - if (!empty($source_directory) && is_readable($source_directory)) { - //copy the main scripts - recursive_copy($source_directory, $destination_directory); - unset($source_directory); - - //copy the app/*/resource/install/scripts - $app_scripts = glob($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'app/*/resource/scripts'); - foreach ($app_scripts as $app_script) { - recursive_copy($app_script, $destination_directory); - } - unset($app_scripts); - } - else { - throw new Exception("Cannot read from '$source_directory' to get the scripts"); - } - chmod($destination_directory, 0775); - unset($destination_directory); - - } - - - /** - * Copy the switch languages to the switch directory - */ - public function copy_languages() { - - //get the source directory - if (file_exists('/usr/share/examples/freeswitch/conf/languages')) { - $source_directory = '/usr/share/examples/fusionpbx/conf/languages'; - } - elseif (file_exists('/usr/local/www/fusionpbx/app/switch/resources/conf/languages')) { - $source_directory = '/usr/local/www/fusionpbx/app/switch/resources/conf/languages'; - } - elseif (file_exists('/var/www/fusionpbx/app/switch/resources/conf/languages')) { - $source_directory = '/var/www/fusionpbx/app/switch/resources/conf/languages'; - } - else { - $source_directory = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/app/switch/resources/conf/languages'; - } - - //get the destination directory - if (file_exists($this->config->get('switch.conf.dir').'/languages')) { - $destination_directory = $this->config->get('switch.conf.dir').'/languages'; - } - elseif (file_exists('/etc/freeswitch/languages')) { - $destination_directory = '/usr/local/share/freeswitch/languages'; - } - elseif (file_exists('/usr/local/freeswitch/conf/languages')) { - $destination_directory = '/usr/local/freeswitch/conf/languages'; - } - - //copy the languages directory - if (!empty($source_directory) && is_readable($source_directory)) { - //copy the main languages - recursive_copy($source_directory, $destination_directory); - unset($source_directory); - } - else { - throw new Exception("Cannot read from '$source_directory' to get the scripts"); - } - chmod($destination_directory, 0775); - unset($destination_directory); - + unset($app_scripts); + } else { + throw new Exception("Cannot read from '$source_directory' to get the scripts"); } + chmod($destination_directory, 0775); + unset($destination_directory); } + /** + * Copy the switch languages to the switch directory + * + * @return void + */ + public function copy_languages() { + + //get the source directory + if (file_exists('/usr/share/examples/freeswitch/conf/languages')) { + $source_directory = '/usr/share/examples/fusionpbx/conf/languages'; + } elseif (file_exists('/usr/local/www/fusionpbx/app/switch/resources/conf/languages')) { + $source_directory = '/usr/local/www/fusionpbx/app/switch/resources/conf/languages'; + } elseif (file_exists('/var/www/fusionpbx/app/switch/resources/conf/languages')) { + $source_directory = '/var/www/fusionpbx/app/switch/resources/conf/languages'; + } else { + $source_directory = $_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH . '/app/switch/resources/conf/languages'; + } + + //get the destination directory + if (file_exists($this->config->get('switch.conf.dir') . '/languages')) { + $destination_directory = $this->config->get('switch.conf.dir') . '/languages'; + } elseif (file_exists('/etc/freeswitch/languages')) { + $destination_directory = '/usr/local/share/freeswitch/languages'; + } elseif (file_exists('/usr/local/freeswitch/conf/languages')) { + $destination_directory = '/usr/local/freeswitch/conf/languages'; + } + + //copy the languages directory + if (!empty($source_directory) && is_readable($source_directory)) { + //copy the main languages + recursive_copy($source_directory, $destination_directory); + unset($source_directory); + } else { + throw new Exception("Cannot read from '$source_directory' to get the scripts"); + } + chmod($destination_directory, 0775); + unset($destination_directory); + + } + +} + /* //example use diff --git a/app/switch/sounds.php b/app/switch/sounds.php index 06192236b1..c522ce9afb 100644 --- a/app/switch/sounds.php +++ b/app/switch/sounds.php @@ -95,6 +95,13 @@ } //define the download function (helps safari play audio sources) + /** + * Downloads a specified range of bytes from the given file. + * + * @param string $file The path to the file to download. + * + * @return void + */ function range_download($file) { $fp = @fopen($file, 'rb'); @@ -123,7 +130,7 @@ $c_start = $start; $c_end = $end; // Extract the range string - list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2); + [, $range] = explode('=', $_SERVER['HTTP_RANGE'], 2); // Make sure the client hasn't sent us a multibyte range if (strpos($range, ',') !== false) { // (?) Shoud this be issued here, or should the first diff --git a/app/system/resources/classes/bsd_system_information.php b/app/system/resources/classes/bsd_system_information.php index 5fc91fff39..0d12508fdd 100644 --- a/app/system/resources/classes/bsd_system_information.php +++ b/app/system/resources/classes/bsd_system_information.php @@ -31,6 +31,11 @@ */ class bsd_system_information extends system_information { + /** + * Returns the number of CPU cores available on the system. + * + * @return int The number of CPU cores. + */ public function get_cpu_cores(): int { $result = shell_exec("dmesg | grep -i --max-count 1 CPUs | sed 's/[^0-9]*//g'"); $cpu_cores = trim($result); @@ -38,6 +43,12 @@ class bsd_system_information extends system_information { } //get the CPU details + + /** + * Returns the current CPU usage percentage. + * + * @return float The current CPU usage percentage. + */ public function get_cpu_percent(): float { $result = shell_exec('ps -A -o pcpu'); $percent_cpu = 0; @@ -49,10 +60,20 @@ class bsd_system_information extends system_information { return $percent_cpu; } + /** + * Returns the system uptime in seconds. + * + * @return string The system uptime in seconds. + */ public function get_uptime() { return shell_exec('uptime'); } + /** + * Returns the current CPU usage percentage per core. + * + * @return array An associative array where keys are core indices and values are their respective CPU usage percentages. + */ public function get_cpu_percent_per_core(): array { static $last = []; $results = []; @@ -94,11 +115,11 @@ class bsd_system_information extends system_information { } /** + * Returns the current network speed for a given interface. * - * @staticvar array $last - * @param string $interface - * @return array - * @depends FreeBSD Version 12 + * @param string $interface The network interface to query (default: 'em0') + * + * @return array An array containing the current receive and transmit speeds in bytes per second. */ public function get_network_speed(string $interface = 'em0'): array { static $last = []; diff --git a/app/system/resources/classes/linux_system_information.php b/app/system/resources/classes/linux_system_information.php index bff71c9b9d..c4529102a3 100644 --- a/app/system/resources/classes/linux_system_information.php +++ b/app/system/resources/classes/linux_system_information.php @@ -31,6 +31,13 @@ */ class linux_system_information extends system_information { + /** + * Returns the number of CPU cores available on the system. + * + * This method executes a shell command to parse the /proc/cpuinfo file and counts the number of processor entries found. + * + * @return int The total number of CPU cores + */ public function get_cpu_cores(): int { $result = @trim(shell_exec("grep -P '^processor' /proc/cpuinfo")); $cpu_cores = count(explode("\n", $result)); @@ -38,6 +45,16 @@ class linux_system_information extends system_information { } //get the CPU details + + /** + * Returns the current CPU usage as a percentage. + * + * This method reads the CPU statistics from /proc/stat and calculates + * the CPU usage by comparing the total and idle time of each core. + * The result is rounded to two decimal places. + * + * @return float The current CPU usage in percent. + */ public function get_cpu_percent(): float { $stat1 = file_get_contents('/proc/stat'); usleep(500000); @@ -73,10 +90,27 @@ class linux_system_information extends system_information { return round($percent_cpu / $core_count, 2); } + /** + * Returns the current system uptime as reported by the 'uptime' command. + * + * This method executes the 'uptime' command and returns its output. + * + * @return string The current system uptime. + */ public function get_uptime() { return shell_exec('uptime'); } + /** + * Returns the current CPU usage as a percentage per core. + * + * This method reads the CPU statistics from /proc/stat and calculates + * the CPU usage by comparing the total and idle time of each core. + * The result is rounded to two decimal places. + * + * @return array An array where the keys are the core numbers (starting at 0) + * and the values are the current CPU usage for each core in percent. + */ public function get_cpu_percent_per_core(): array { static $last = []; @@ -107,6 +141,16 @@ class linux_system_information extends system_information { return $results; } + /** + * Returns the current network speed for the specified interface. + * + * This method reads the network statistics from /proc/net/dev and calculates + * the network speed by comparing the received and transmitted bytes between two measurements. + * + * @param string $interface The network interface to read stats from. Defaults to 'eth0'. + * + * @return array An array containing the current receive (rx_bps) and transmit (tx_bps) speeds in bits per second. + */ public function get_network_speed(string $interface = 'eth0'): array { static $last = []; diff --git a/app/system/resources/classes/session.php b/app/system/resources/classes/session.php index d899571c05..2aeb66362b 100644 --- a/app/system/resources/classes/session.php +++ b/app/system/resources/classes/session.php @@ -35,7 +35,9 @@ class session { /** * Removes old php session files. Called by the maintenance application. + * * @param settings $settings A settings object + * * @return void */ public static function filesystem_maintenance(settings $settings): void { diff --git a/app/system/resources/classes/system_dashboard_service.php b/app/system/resources/classes/system_dashboard_service.php index 3722eaf1af..54330c55e1 100644 --- a/app/system/resources/classes/system_dashboard_service.php +++ b/app/system/resources/classes/system_dashboard_service.php @@ -38,6 +38,11 @@ class system_dashboard_service extends base_websocket_system_service { private $network_status_refresh_interval; private $network_interface; + /** + * Reloads settings from database, config file and websocket server. + * + * @return void + */ protected function reload_settings(): void { static::set_system_information(); @@ -64,8 +69,12 @@ class system_dashboard_service extends base_websocket_system_service { } /** - * Executes once - * @return void + * Registers topics for broadcasting system information. + * + * This method is responsible for setting up the system information object, + * registering callback functions for cpu and network status requests, and + * configuring timer callbacks to refresh these statuses at regular intervals. + * It is only called once during initial startup. */ protected function register_topics(): void { @@ -90,6 +99,17 @@ class system_dashboard_service extends base_websocket_system_service { $this->info("Broadcasting Network Status every {$this->network_status_refresh_interval}s"); } + /** + * Handles the network status request. + * + * This method retrieves the current network interface and speeds, constructs a response message, + * logs the request for debugging purposes, and attempts to send the broadcast. If the Websocket server + * is disconnected, it waits until reconnection before attempting to send again. + * + * @param string|null $message The original message that triggered this response (optional). + * + * @return int The refresh interval for network status in seconds. + */ public function on_network_status($message = null): int { // Get RX (receive) and TX (transmit) bps $network_rates = self::$system_information->get_network_speed($this->network_interface); @@ -134,6 +154,15 @@ class system_dashboard_service extends base_websocket_system_service { return $this->network_status_refresh_interval; } + /** + * Handles the selection of a network interface from a message. + * + * This method checks if the message is an instance of WebSocketMessage and if it contains + * a 'network_interface' payload. If both conditions are true, it sets the network interface + * property to the value of the payload. + * + * @param websocket_message|null $message The message containing the selected network interface. + */ public function on_network_interface_select($message = null): void { if ($message !== null && $message instanceof websocket_message) { $payload = $message->payload(); @@ -143,6 +172,17 @@ class system_dashboard_service extends base_websocket_system_service { } } + /** + * Handles cpu status requests. + * + * This method is called to respond to incoming requests for the current CPU usage, + * both total and per-core. It prepares a response message with the requested data + * and sends it to all connected clients. + * + * @param null|websocket_message $message The request message, if responding to a specific request. + * + * @return int The interval at which this method should be called again to refresh the cpu status. + */ public function on_cpu_status($message = null): int { // Get total and per-core CPU usage $cpu_percent_total = self::$system_information->get_cpu_percent(); @@ -192,10 +232,27 @@ class system_dashboard_service extends base_websocket_system_service { return $this->cpu_status_refresh_interval; } + /** + * Returns the service name for system information. + * + * This method provides a unique identifier for the dashboard system information service. + * + * @return string The service name as a string, in this case "dashboard.system.information". + */ public static function get_service_name(): string { return "dashboard.system.information"; } + /** + * Creates a filter chain for broadcasting system information. + * + * This method generates a filter based on the subscriber's permissions, + * allowing them to receive only relevant system view information. + * + * @param subscriber $subscriber The subscriber object with permission data. + * + * @return ?filter A filter chain that matches the subscriber's permissions, or null if no match is found. + */ public static function create_filter_chain_for(subscriber $subscriber): ?filter { // Get the subscriber permissions $permissions = $subscriber->get_permissions(); @@ -216,6 +273,15 @@ class system_dashboard_service extends base_websocket_system_service { return $filter; } + /** + * Sets the system information object. + * + * This method creates a new instance of `SystemInformation` and stores it in + * the class's static property `$system_information`. It is typically called once + * during initial startup to establish the system information source. + * + * @return void + */ public static function set_system_information(): void { self::$system_information = system_information::new(); } diff --git a/app/system/resources/classes/system_information.php b/app/system/resources/classes/system_information.php index 58a3850240..d93ba12513 100644 --- a/app/system/resources/classes/system_information.php +++ b/app/system/resources/classes/system_information.php @@ -37,10 +37,20 @@ abstract class system_information { abstract public function get_cpu_percent_per_core(): array; abstract public function get_network_speed(string $interface = 'eth0'): array; + /** + * Returns the system load average. + * + * @return array Three most recent one-minute load averages. + */ public function get_load_average() { return sys_getloadavg(); } + /** + * Returns a system information object based on the underlying operating system. + * + * @return ?system_information The system information object for the current OS, or null if not supported. + */ public static function new(): ?system_information { if (stristr(PHP_OS, 'BSD')) { return new bsd_system_information(); diff --git a/app/system/resources/dashboard/system_services.php b/app/system/resources/dashboard/system_services.php index b45c28c283..ebbeefc2f3 100644 --- a/app/system/resources/dashboard/system_services.php +++ b/app/system/resources/dashboard/system_services.php @@ -38,6 +38,13 @@ //function to parse a FusionPBX service from a .service file if (!function_exists('get_classname')) { + /** + * Retrieves the name of a PHP class from an ExecStart directive in a service file. + * + * @param string $file Path to the service file. + * + * @return string The name of the PHP class, or empty string if not found. + */ function get_classname(string $file) { if (!file_exists($file)) { return ''; @@ -55,6 +62,14 @@ //function to check for running process: returns [running, pid, etime] if (!function_exists('is_running')) { + /** + * Checks if a process with the given name is currently running. + * + * @param string $name The name of the process to check for. + * + * @return array An array containing information about the process's status, + * including whether it's running, its PID, and how long it's been running. + */ function is_running(string $name) { $name = escapeshellarg($name); $pid = trim(shell_exec("ps -aux | grep $name | grep -v grep | awk '{print \$2}' | head -n 1") ?? ''); @@ -68,6 +83,21 @@ //function to format etime into friendly display if (!function_exists('format_etime')) { + /** + * Formats a time duration string into a human-readable format. + * + * The input string can be in one of the following formats: + * - dd-hh:mm:ss + * - hh:mm:ss + * - mm:ss + * - seconds (no units) + * + * If the input string is empty or invalid, an empty string will be returned. + * + * @param string $etime Time duration string to format. + * + * @return string Formatted time duration string in human-readable format. + */ function format_etime($etime) { // Format: [[dd-]hh:]mm:ss if (empty($etime)) return '-'; diff --git a/app/system/resources/functions/system_information.php b/app/system/resources/functions/system_information.php index b17d89e355..aeb0593fc8 100644 --- a/app/system/resources/functions/system_information.php +++ b/app/system/resources/functions/system_information.php @@ -83,6 +83,14 @@ // //system information + /** + * Retrieves system information. + * + * @return array An array containing various system information such as PHP and switch versions, + * git repository details, operating system name, version, uptime, kernel, and type, + * memory usage, CPU usage, and disk space. The keys of the returned array are + * 'version', 'git', 'path', 'switch', 'php', 'os', 'mem', and 'cpu'. + */ function system_information(): array { global $database, $db_type; $system_information = []; diff --git a/app/time_conditions/resources/classes/time_conditions.php b/app/time_conditions/resources/classes/time_conditions.php index 7f81bc66e9..3248f38ba3 100644 --- a/app/time_conditions/resources/classes/time_conditions.php +++ b/app/time_conditions/resources/classes/time_conditions.php @@ -25,371 +25,406 @@ */ //define the time conditions class - class time_conditions { +class time_conditions { - /** - * declare constant variables - */ - const app_name = 'time_conditions'; - const app_uuid = '4b821450-926b-175a-af93-a03c441818b1'; + /** + * declare constant variables + */ + const app_name = 'time_conditions'; + const app_uuid = '4b821450-926b-175a-af93-a03c441818b1'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * Username set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $username; + /** + * Username set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $username; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_name; - /** - * declare public/private properties - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; - private $dialplan_global; + /** + * declare public/private properties + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; + private $dialplan_global; - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); + //set objects + $this->database = $setting_array['database'] ?? database::new(); - //set the default value - $this->dialplan_global = false; + //set the default value + $this->dialplan_global = false; - //assign property defaults - $this->permission_prefix = 'time_condition_'; - $this->list_page = 'time_conditions.php'; - $this->table = 'dialplans'; - $this->uuid_prefix = 'dialplan_'; - $this->toggle_field = 'dialplan_enabled'; - $this->toggle_values = ['true','false']; + //assign property defaults + $this->permission_prefix = 'time_condition_'; + $this->list_page = 'time_conditions.php'; + $this->table = 'dialplans'; + $this->uuid_prefix = 'dialplan_'; + $this->toggle_field = 'dialplan_enabled'; + $this->toggle_values = ['true', 'false']; + } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; } - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //build the delete array + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } + //build delete array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array['dialplan_details'][$x]['dialplan_uuid'] = $record['uuid']; - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { + //get the dialplan context + $sql = "select dialplan_context from v_dialplans "; + $sql .= "where dialplan_uuid = :dialplan_uuid "; + $parameters['dialplan_uuid'] = $record['uuid']; + $dialplan_contexts[] = $this->database->select($sql, $parameters, 'column'); + unset($sql, $parameters); - //build the delete array - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - - //build delete array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array['dialplan_details'][$x]['dialplan_uuid'] = $record['uuid']; - - //get the dialplan context - $sql = "select dialplan_context from v_dialplans "; - $sql .= "where dialplan_uuid = :dialplan_uuid "; - $parameters['dialplan_uuid'] = $record['uuid']; - $dialplan_contexts[] = $this->database->select($sql, $parameters, 'column'); - unset($sql, $parameters); - - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('dialplan_delete', 'temp'); - $p->add('dialplan_detail_delete', 'temp'); - - //execute delete - $this->database->delete($array); - - //revoke temporary permissions - $p->delete('dialplan_delete', 'temp'); - $p->delete('dialplan_detail_delete', 'temp'); - - //clear the cache - if (is_array($dialplan_contexts) && @sizeof($dialplan_contexts) != 0) { - $dialplan_contexts = array_unique($dialplan_contexts, SORT_STRING); - $cache = new cache; - foreach ($dialplan_contexts as $dialplan_context) { - $cache->delete("dialplan:".$dialplan_context); - } - } - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-delete'].': '.@sizeof($array[$this->table])); - - } - unset($records, $array); - - } + } } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('dialplan_delete', 'temp'); + $p->add('dialplan_detail_delete', 'temp'); + + //execute delete + $this->database->delete($array); + + //revoke temporary permissions + $p->delete('dialplan_delete', 'temp'); + $p->delete('dialplan_detail_delete', 'temp'); + + //clear the cache + if (is_array($dialplan_contexts) && @sizeof($dialplan_contexts) != 0) { + $dialplan_contexts = array_unique($dialplan_contexts, SORT_STRING); + $cache = new cache; + foreach ($dialplan_contexts as $dialplan_context) { + $cache->delete("dialplan:" . $dialplan_context); + } + } + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //set message + message::add($text['message-delete'] . ': ' . @sizeof($array[$this->table])); + + } + unset($records, $array); + + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function toggle($records) { + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; } - /** - * toggle records - */ - public function toggle($records) { - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //get current toggle state - foreach($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, ".$this->toggle_field." as toggle, dialplan_context from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $states[$row['uuid']] = $row['toggle']; - $dialplan_contexts[] = $row['dialplan_context']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //build update array - $x = 0; - foreach($states as $uuid => $state) { - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $uuid; - $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('dialplan_edit', 'temp'); - - //save the array - - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('dialplan_edit', 'temp'); - - //clear the cache - if (is_array($dialplan_contexts) && @sizeof($dialplan_contexts) != 0) { - $dialplan_contexts = array_unique($dialplan_contexts, SORT_STRING); - $cache = new cache; - foreach ($dialplan_contexts as $dialplan_context) { - $cache->delete("dialplan:".$dialplan_context); - } - } - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-toggle']); - } - unset($records, $states); - } + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + //get current toggle state + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } } + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, " . $this->toggle_field . " as toggle, dialplan_context from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $states[$row['uuid']] = $row['toggle']; + $dialplan_contexts[] = $row['dialplan_context']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //build update array + $x = 0; + foreach ($states as $uuid => $state) { + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $uuid; + $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('dialplan_edit', 'temp'); + + //save the array + + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('dialplan_edit', 'temp'); + + //clear the cache + if (is_array($dialplan_contexts) && @sizeof($dialplan_contexts) != 0) { + $dialplan_contexts = array_unique($dialplan_contexts, SORT_STRING); + $cache = new cache; + foreach ($dialplan_contexts as $dialplan_context) { + $cache->delete("dialplan:" . $dialplan_context); + } + } + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //set message + message::add($text['message-toggle']); + } + unset($records, $states); } - /** - * copy records - */ - public function copy($records) { - if (permission_exists($this->permission_prefix.'add')) { + } + } - //add multi-lingual support - $language = new text; - $text = $language->get(); + /** + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function copy($records) { + if (permission_exists($this->permission_prefix . 'add')) { - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } + //add multi-lingual support + $language = new text; + $text = $language->get(); - //copy the checked records - if (is_array($records) && @sizeof($records) != 0) { + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } - //get checked records - foreach($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; + //copy the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //get checked records + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //create insert array from existing data + if (is_array($uuids) && @sizeof($uuids) != 0) { + + //primary table + $sql = "select * from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + $y = 0; + foreach ($rows as $x => $row) { + $primary_uuid = uuid(); + + //convert boolean values to a string + foreach ($row as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row[$key] = $value; + } + } + + //copy data + $array[$this->table][$x] = $row; + + //overwrite + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $primary_uuid; + $array[$this->table][$x]['dialplan_description'] = trim($row['dialplan_description'] . ' (' . $text['label-copy'] . ')'); + + //details sub table + $sql_2 = "select * from v_dialplan_details where dialplan_uuid = :dialplan_uuid"; + $parameters_2['dialplan_uuid'] = $row['dialplan_uuid']; + $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); + if (is_array($rows_2) && @sizeof($rows_2) != 0) { + foreach ($rows_2 as $row_2) { + + //convert boolean values to a string + foreach ($row_2 as $key => $value) { + if (gettype($value) == 'boolean') { + $value = $value ? 'true' : 'false'; + $row_2[$key] = $value; + } } - } - //create insert array from existing data - if (is_array($uuids) && @sizeof($uuids) != 0) { + //copy data + $array['dialplan_details'][$y] = $row_2; - //primary table - $sql = "select * from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - $y = 0; - foreach ($rows as $x => $row) { - $primary_uuid = uuid(); + //overwrite + $array['dialplan_details'][$y]['dialplan_detail_uuid'] = uuid(); + $array['dialplan_details'][$y]['dialplan_uuid'] = $primary_uuid; - //convert boolean values to a string - foreach($row as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row[$key] = $value; - } - } - - //copy data - $array[$this->table][$x] = $row; - - //overwrite - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $primary_uuid; - $array[$this->table][$x]['dialplan_description'] = trim($row['dialplan_description'].' ('.$text['label-copy'].')'); - - //details sub table - $sql_2 = "select * from v_dialplan_details where dialplan_uuid = :dialplan_uuid"; - $parameters_2['dialplan_uuid'] = $row['dialplan_uuid']; - $rows_2 = $this->database->select($sql_2, $parameters_2, 'all'); - if (is_array($rows_2) && @sizeof($rows_2) != 0) { - foreach ($rows_2 as $row_2) { - - //convert boolean values to a string - foreach($row_2 as $key => $value) { - if (gettype($value) == 'boolean') { - $value = $value ? 'true' : 'false'; - $row_2[$key] = $value; - } - } - - //copy data - $array['dialplan_details'][$y] = $row_2; - - //overwrite - $array['dialplan_details'][$y]['dialplan_detail_uuid'] = uuid(); - $array['dialplan_details'][$y]['dialplan_uuid'] = $primary_uuid; - - //increment - $y++; - - } - } - unset($sql_2, $parameters_2, $rows_2, $row_2); - - //get dialplan contexts - $dialplan_contexts[] = $row['dialplan_context']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //save the changes and set the message - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('dialplan_add', 'temp'); - $p->add('dialplan_detail_add', 'temp'); - - //save the array - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('dialplan_add', 'temp'); - $p->delete('dialplan_detail_add', 'temp'); - - //clear the cache - if (is_array($dialplan_contexts) && @sizeof($dialplan_contexts) != 0) { - $dialplan_contexts = array_unique($dialplan_contexts, SORT_STRING); - $cache = new cache; - foreach ($dialplan_contexts as $dialplan_context) { - $cache->delete("dialplan:".$dialplan_context); - } - } - - //set message - message::add($text['message-copy']); + //increment + $y++; } - unset($records); + } + unset($sql_2, $parameters_2, $rows_2, $row_2); + + //get dialplan contexts + $dialplan_contexts[] = $row['dialplan_context']; } + } + unset($sql, $parameters, $rows, $row); + } + + //save the changes and set the message + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('dialplan_add', 'temp'); + $p->add('dialplan_detail_add', 'temp'); + + //save the array + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('dialplan_add', 'temp'); + $p->delete('dialplan_detail_add', 'temp'); + + //clear the cache + if (is_array($dialplan_contexts) && @sizeof($dialplan_contexts) != 0) { + $dialplan_contexts = array_unique($dialplan_contexts, SORT_STRING); + $cache = new cache; + foreach ($dialplan_contexts as $dialplan_context) { + $cache->delete("dialplan:" . $dialplan_context); + } + } + + //set message + message::add($text['message-copy']); } - } //method + unset($records); + } + } + } //method - } //class +} //class diff --git a/app/time_conditions/time_condition_edit.php b/app/time_conditions/time_condition_edit.php index 5dff9f2cbe..cd2d2255c8 100644 --- a/app/time_conditions/time_condition_edit.php +++ b/app/time_conditions/time_condition_edit.php @@ -990,6 +990,13 @@ echo " ".$text['description-extension']."
    \n"; echo "\n"; echo "\n"; +/** + * Adds a custom condition to the given group. + * + * @param object $destination The destination object being processed. + * @param int $group_id The ID of the group to which the condition is being added. + * @param string $dialplan_action The dialplan action for the group (optional). + */ function add_custom_condition($destination, $group_id, $dialplan_action = '') { global $text, $v_link_label_add; echo "
    \n"; diff --git a/app/vars/resources/classes/vars.php b/app/vars/resources/classes/vars.php index f00ce49c3a..786841c85d 100644 --- a/app/vars/resources/classes/vars.php +++ b/app/vars/resources/classes/vars.php @@ -46,7 +46,12 @@ private $toggle_values; /** - * called when the object is created + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void */ public function __construct(array $setting_array = []) { //set objects @@ -62,7 +67,13 @@ } /** - * delete records + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. */ public function delete($records) { if (permission_exists($this->permission_prefix.'delete')) { @@ -111,7 +122,13 @@ } /** - * toggle records + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. */ public function toggle($records) { if (permission_exists($this->permission_prefix.'edit')) { @@ -181,7 +198,13 @@ } /** - * copy records + * Copies one or more records + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. */ public function copy($records) { if (permission_exists($this->permission_prefix.'add')) { diff --git a/app/vars/vars.php b/app/vars/vars.php index 25dfc93ffc..2f5cbce6c1 100644 --- a/app/vars/vars.php +++ b/app/vars/vars.php @@ -105,8 +105,8 @@ $param = $search ? "&search=".$search : null; $param = $order_by ? "&order_by=".$order_by."&order=".$order : null; $page = empty($_GET['page']) ? $page = 0 : $page = $_GET['page']; - list($paging_controls, $rows_per_page) = paging($num_rows, $param, $rows_per_page); - list($paging_controls_mini, $rows_per_page) = paging($num_rows, $param, $rows_per_page, true); + [$paging_controls, $rows_per_page] = paging($num_rows, $param, $rows_per_page); + [$paging_controls_mini, $rows_per_page] = paging($num_rows, $param, $rows_per_page, true); $offset = $rows_per_page * $page; //get the list @@ -191,6 +191,13 @@ echo "
    \n"; echo "
    \n"; + /** + * Writes the header for a list of variables. + * + * @param string $modifier The modifier to be used in the header, with slashes and extra spaces removed. + * + * @return void + */ function write_header($modifier) { global $text, $order_by, $order, $vars, $list_row_edit_button; $modifier = str_replace('/', '', $modifier); diff --git a/app/voicemail_greetings/resources/classes/voicemail_greetings.php b/app/voicemail_greetings/resources/classes/voicemail_greetings.php index e15991e8cc..4c15f5c603 100644 --- a/app/voicemail_greetings/resources/classes/voicemail_greetings.php +++ b/app/voicemail_greetings/resources/classes/voicemail_greetings.php @@ -25,175 +25,193 @@ */ //define the voicemail greetings class - class voicemail_greetings { +class voicemail_greetings { - /** - * declare constant variables - */ - const app_name = 'voicemail_greetings'; - const app_uuid = 'e4b4fbee-9e4d-8e46-3810-91ba663db0c2'; + /** + * declare constant variables + */ + const app_name = 'voicemail_greetings'; + const app_uuid = 'e4b4fbee-9e4d-8e46-3810-91ba663db0c2'; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Settings object set in the constructor. Must be a settings object and cannot be null. - * @var settings Settings Object - */ - private $settings; + /** + * Settings object set in the constructor. Must be a settings object and cannot be null. + * + * @var settings Settings Object + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_uuid; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + private $domain_name; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; - /** - * declare public variables - */ - public $voicemail_id; + /** + * declare public variables + */ + public $voicemail_id; - /** - * called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); - //assign private variables - $this->permission_prefix = 'voicemail_greeting_'; - if (is_numeric($this->voicemail_id)) { - $this->list_page = 'voicemail_greetings.php?id='.urlencode($this->voicemail_id).'&back='.urlencode(PROJECT_PATH.'/app/voicemail/voicemails.php'); - } - else { - $this->list_page = PROJECT_PATH.'/app/voicemails/voicemails.php'; - } - $this->table = 'voicemail_greetings'; - $this->uuid_prefix = 'voicemail_greeting_'; + //assign private variables + $this->permission_prefix = 'voicemail_greeting_'; + if (is_numeric($this->voicemail_id)) { + $this->list_page = 'voicemail_greetings.php?id=' . urlencode($this->voicemail_id) . '&back=' . urlencode(PROJECT_PATH . '/app/voicemail/voicemails.php'); + } else { + $this->list_page = PROJECT_PATH . '/app/voicemails/voicemails.php'; } + $this->table = 'voicemail_greetings'; + $this->uuid_prefix = 'voicemail_greeting_'; + } - /** - * delete records - */ - public function delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //add multi-lingual support + $language = new text; + $text = $language->get(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //check voicemail id - if (!is_numeric($this->voicemail_id)) { - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked records - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //get necessary greeting details - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, greeting_filename, greeting_id from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $greeting_filenames[$row['uuid']] = $row['greeting_filename']; - $greeting_ids[$this->voicemail_id] = $row['greeting_id']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //set the greeting directory - $greeting_directory = $this->settings->get('switch', 'storage').'/voicemail/default/'.$this->domain_name.'/'.$this->voicemail_id; - - //loop through greetings - if (is_array($greeting_filenames) && @sizeof($greeting_filenames) != 0) { - $x = 0; - foreach ($greeting_filenames as $voicemail_greeting_uuid => $greeting_filename) { - //delete the recording file - @unlink($greeting_directory.'/'.$greeting_filename); - //build the delete array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $voicemail_greeting_uuid; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - $x++; - } - } - - //reset voicemail box(es) to default (null) if deleted greeting(s) were assigned - if (is_array($array) && @sizeof($array) != 0 && is_array($greeting_ids) && @sizeof($greeting_ids)) { - foreach ($greeting_ids as $voicemail_id => $greeting_id) { - if (is_numeric($voicemail_id) && is_numeric($greeting_id)) { - $sql = "update v_voicemails set greeting_id = null "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and voicemail_id = :voicemail_id "; - $sql .= "and greeting_id = :greeting_id "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['voicemail_id'] = $voicemail_id; - $parameters['greeting_id'] = $greeting_id; - $this->database->execute($sql, $parameters); - unset($sql, $parameters); - } - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - //set message - message::add($text['message-delete']); - } - unset($records); - - } + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; } - } //method - } //class + //check voicemail id + if (!is_numeric($this->voicemail_id)) { + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked records + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //get necessary greeting details + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, greeting_filename, greeting_id from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $greeting_filenames[$row['uuid']] = $row['greeting_filename']; + $greeting_ids[$this->voicemail_id] = $row['greeting_id']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //set the greeting directory + $greeting_directory = $this->settings->get('switch', 'storage') . '/voicemail/default/' . $this->domain_name . '/' . $this->voicemail_id; + + //loop through greetings + if (is_array($greeting_filenames) && @sizeof($greeting_filenames) != 0) { + $x = 0; + foreach ($greeting_filenames as $voicemail_greeting_uuid => $greeting_filename) { + //delete the recording file + @unlink($greeting_directory . '/' . $greeting_filename); + //build the delete array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $voicemail_greeting_uuid; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + $x++; + } + } + + //reset voicemail box(es) to default (null) if deleted greeting(s) were assigned + if (is_array($array) && @sizeof($array) != 0 && is_array($greeting_ids) && @sizeof($greeting_ids)) { + foreach ($greeting_ids as $voicemail_id => $greeting_id) { + if (is_numeric($voicemail_id) && is_numeric($greeting_id)) { + $sql = "update v_voicemails set greeting_id = null "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and voicemail_id = :voicemail_id "; + $sql .= "and greeting_id = :greeting_id "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['voicemail_id'] = $voicemail_id; + $parameters['greeting_id'] = $greeting_id; + $this->database->execute($sql, $parameters); + unset($sql, $parameters); + } + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); + //set message + message::add($text['message-delete']); + } + unset($records); + + } + } + } //method + +} //class diff --git a/app/voicemail_greetings/voicemail_greetings.php b/app/voicemail_greetings/voicemail_greetings.php index 1534eadfc8..8b0405c188 100644 --- a/app/voicemail_greetings/voicemail_greetings.php +++ b/app/voicemail_greetings/voicemail_greetings.php @@ -62,6 +62,13 @@ } //used (above) to search the array to determine if an extension is assigned to the user + /** + * Checks if the given extension number is assigned to the user. + * + * @param string $number The extension number to check. + * + * @return bool True if the extension number is assigned, False otherwise. + */ function extension_assigned($number) { foreach ($_SESSION['user']['extension'] as $row) { if ((is_numeric($row['number_alias']) && $row['number_alias'] == $number) || $row['user'] == $number) { @@ -506,6 +513,11 @@ require_once "resources/footer.php"; //define the download function (helps safari play audio sources) + /** + * Handles a range download request for the given file. + * + * @param string $file The path to the file being downloaded. + */ function range_download($file) { $fp = @fopen($file, 'rb'); @@ -534,7 +546,7 @@ $c_start = $start; $c_end = $end; // Extract the range string - list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2); + [, $range] = explode('=', $_SERVER['HTTP_RANGE'], 2); // Make sure the client hasn't sent us a multibyte range if (strpos($range, ',') !== false) { // (?) Shoud this be issued here, or should the first diff --git a/app/voicemails/resources/classes/voicemail.php b/app/voicemails/resources/classes/voicemail.php index ac8525817a..b6de9e7328 100644 --- a/app/voicemails/resources/classes/voicemail.php +++ b/app/voicemails/resources/classes/voicemail.php @@ -25,841 +25,1132 @@ */ //define the voicemail class - class voicemail { +class voicemail { - /** - * declare constant variables - */ - const app_name = 'voicemail'; - const app_uuid = 'b523c2d2-64cd-46f1-9520-ca4b4098e044'; + /** + * declare constant variables + */ + const app_name = 'voicemail'; + const app_uuid = 'b523c2d2-64cd-46f1-9520-ca4b4098e044'; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_uuid; - /** - * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_name; + /** + * Domain name set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_name; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + public $user_uuid; - /** - * declare additional public variables - */ - public $voicemail_uuid; - public $voicemail_id; - public $voicemail_message_uuid; - public $order_by; - public $order; - public $offset; - public $type; + /** + * declare additional public variables + */ + public $voicemail_uuid; + public $voicemail_id; + public $voicemail_message_uuid; + public $order_by; + public $order; + public $offset; + public $type; - /** - * Internal array structure that is populated from the database - * @var settings A settings object loaded from Default Settings - */ - private $settings; + /** + * Internal array structure that is populated from the database + * + * @var settings A settings object loaded from Default Settings + */ + private $settings; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Username set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $username; + /** + * Username set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $username; - /** - * declare private variables - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $toggle_field; - private $toggle_values; + /** + * declare private variables + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $toggle_field; + private $toggle_values; - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - $this->username = $setting_array['username'] ?? $_SESSION['username'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->domain_name = $setting_array['domain_name'] ?? $_SESSION['domain_name'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + $this->username = $setting_array['username'] ?? $_SESSION['username'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); - //assign private variables - $this->permission_prefix = 'voicemail_'; - $this->list_page = 'voicemails.php'; - $this->table = 'voicemails'; - $this->uuid_prefix = 'voicemail_'; - $this->toggle_field = 'voicemail_enabled'; - $this->toggle_values = ['true','false']; + //assign private variables + $this->permission_prefix = 'voicemail_'; + $this->list_page = 'voicemails.php'; + $this->table = 'voicemails'; + $this->uuid_prefix = 'voicemail_'; + $this->toggle_field = 'voicemail_enabled'; + $this->toggle_values = ['true', 'false']; + } + + /** + * retrieves the voicemail id + * + * @return int|null the voicemail id if it exists, otherwise null + */ + public function get_voicemail_id() { + + //check if for valid input + if (!is_uuid($this->voicemail_uuid) || !is_uuid($this->domain_uuid)) { + return false; } - public function get_voicemail_id() { + //get the voicemail id if it isn't set already + if (!isset($this->voicemail_id)) { + $sql = "select voicemail_id from v_voicemails "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and voicemail_uuid = :voicemail_uuid "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['voicemail_uuid'] = $this->voicemail_uuid; + $voicemail_id = $this->database->select($sql, $parameters, 'column'); + if (is_numeric($voicemail_id)) { + $this->voicemail_id = $voicemail_id; + } + unset($sql, $parameters, $voicemail_id); + } + } - //check if for valid input - if (!is_uuid($this->voicemail_uuid) || !is_uuid($this->domain_uuid)) { - return false; - } + /** + * retrieves the list of assigned voicemails + * + * @return array|false list of assigned voicemail boxes + */ + public function voicemails() { - //get the voicemail id if it isn't set already - if (!isset($this->voicemail_id)) { - $sql = "select voicemail_id from v_voicemails "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and voicemail_uuid = :voicemail_uuid "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['voicemail_uuid'] = $this->voicemail_uuid; - $voicemail_id = $this->database->select($sql, $parameters, 'column'); - if (is_numeric($voicemail_id)) { - $this->voicemail_id = $voicemail_id; - } - unset($sql, $parameters, $voicemail_id); - } + //check if for valid input + if (!is_uuid($this->domain_uuid)) { + return false; } - public function voicemails() { + //get the assigned extensions + $sql = "select e.extension_uuid, e.extension, e.number_alias, e.enabled, e.description "; + $sql .= "from v_extensions e, v_extension_users eu "; + $sql .= "where e.extension_uuid = eu.extension_uuid "; + $sql .= "and eu.user_uuid = :user_uuid "; + $sql .= "and e.domain_uuid = :domain_uuid "; + $sql .= "order by e.extension asc "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['user_uuid'] = $this->user_uuid; + $assigned_extensions = $this->database->select($sql, $parameters, 'all'); + unset($sql, $parameters); - //check if for valid input - if (!is_uuid($this->domain_uuid)) { - return false; - } - - //get the assigned extensions - $sql = "select e.extension_uuid, e.extension, e.number_alias, e.enabled, e.description "; - $sql .= "from v_extensions e, v_extension_users eu "; - $sql .= "where e.extension_uuid = eu.extension_uuid "; - $sql .= "and eu.user_uuid = :user_uuid "; - $sql .= "and e.domain_uuid = :domain_uuid "; - $sql .= "order by e.extension asc "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['user_uuid'] = $this->user_uuid; - $assigned_extensions = $this->database->select($sql, $parameters, 'all'); - unset($sql, $parameters); - - //set the voicemail id arrays - $voicemail_ids = []; - if (isset($assigned_extensions)) { - foreach ($assigned_extensions as $index => $row) { - $voicemail_ids[] = (is_numeric($row['number_alias'])) ? $row['number_alias'] : $row['extension']; - } - } - - //get the assigned voicemails - $assigned_voicemails = []; - if (!empty($voicemail_ids) && @sizeof($voicemail_ids) != 0) { - $sql = "select * from v_voicemails "; - $sql .= "where voicemail_id in ("; - foreach($voicemail_ids as $i => $voicemail_id) { - if ($i > 0) { $sql .= ","; } - $sql .= ":voicemail_id_".$i; - $parameters['voicemail_id_'.$i] = $voicemail_id; - } - $sql .= ") "; - $sql .= "and domain_uuid = :domain_uuid "; - $parameters['domain_uuid'] = $this->domain_uuid; - $assigned_voicemails = $this->database->select($sql, $parameters, 'all'); - unset($sql, $parameters); - } - - //set the voicemail uuid arrays - $voicemail_uuids = []; - if (isset($assigned_voicemails)) { - foreach ($assigned_voicemails as $row) { - if (!empty($row['voicemail_uuid'])) { - $voicemail_uuids[]['voicemail_uuid'] = $row['voicemail_uuid']; - } - } - } - - //get the uuid and voicemail_id - $sql = "select * from v_voicemails "; - $sql .= "where domain_uuid = :domain_uuid "; - if (is_uuid($this->voicemail_uuid)) { - if (permission_exists('voicemail_delete')) { - //view specific voicemail box usually reserved for an admin or superadmin - $sql .= "and voicemail_uuid = :voicemail_uuid "; - $parameters['voicemail_uuid'] = $this->voicemail_uuid; - } - else { - //ensure that the requested voicemail box is assigned to this user - $found = false; - foreach($voicemail_uuids as $row) { - if ($this->voicemail_uuid == $row['voicemail_uuid']) { - $sql .= "and voicemail_uuid = :voicemail_uuid "; - $parameters['voicemail_uuid'] = $row['voicemail_uuid']; - $found = true; - } - } - //id requested is not owned by the user return no results - if (!$found) { - $sql .= "and voicemail_uuid is null "; - } - } - } - else { - if (!empty($voicemail_ids) && @sizeof($voicemail_ids) != 0) { - //show only the assigned voicemail ids - $sql .= "and "; - if (is_numeric($this->voicemail_id) && in_array($this->voicemail_id, $voicemail_ids)) { - $sql_where = 'voicemail_id = :voicemail_id '; - $parameters['voicemail_id'] = $this->voicemail_id; - } - else { - $x = 0; - $sql_where = ''; - foreach($voicemail_ids as $voicemail_id) { - $sql_where_or[] = "voicemail_id = :voicemail_id_".$x; - $parameters['voicemail_id_'.$x] = $voicemail_id; - $x++; - } - $sql_where .= '('.implode(' or ', $sql_where_or).') '; - } - $sql .= $sql_where; - unset($sql_where_or); - } - else { - //no assigned voicemail ids so return no results - $sql .= "and voicemail_uuid is null "; - } - } - $sql .= "order by voicemail_id asc "; - $parameters['domain_uuid'] = $this->domain_uuid; - $result = $this->database->select($sql, $parameters, 'all'); - unset($sql, $parameters); - return $result; + //set the voicemail id arrays + $voicemail_ids = []; + if (isset($assigned_extensions)) { + foreach ($assigned_extensions as $index => $row) { + $voicemail_ids[] = (is_numeric($row['number_alias'])) ? $row['number_alias'] : $row['extension']; + } } - public function messages() { - - //get the voicemails - $voicemails = $this->voicemails(); - - //add the voicemail messages to the array - if (is_array($voicemails)) { - $i = 0; - foreach ($voicemails as $row) { - //get the voicemail messages - $voicemails[$i]['messages'] = $this->voicemail_messages($row['voicemail_id']); - $i++; - } + //get the assigned voicemails + $assigned_voicemails = []; + if (!empty($voicemail_ids) && @sizeof($voicemail_ids) != 0) { + $sql = "select * from v_voicemails "; + $sql .= "where voicemail_id in ("; + foreach ($voicemail_ids as $i => $voicemail_id) { + if ($i > 0) { + $sql .= ","; } - - //return the array - return $voicemails; + $sql .= ":voicemail_id_" . $i; + $parameters['voicemail_id_' . $i] = $voicemail_id; + } + $sql .= ") "; + $sql .= "and domain_uuid = :domain_uuid "; + $parameters['domain_uuid'] = $this->domain_uuid; + $assigned_voicemails = $this->database->select($sql, $parameters, 'all'); + unset($sql, $parameters); } - private function voicemail_messages($voicemail_id): array { - - //check if for valid input - if (!is_numeric($voicemail_id) || !is_uuid($this->domain_uuid)) { - return []; + //set the voicemail uuid arrays + $voicemail_uuids = []; + if (isset($assigned_voicemails)) { + foreach ($assigned_voicemails as $row) { + if (!empty($row['voicemail_uuid'])) { + $voicemail_uuids[]['voicemail_uuid'] = $row['voicemail_uuid']; } + } + } - //set the time zone - $time_zone = $this->settings->get('domain', 'time_zone', date_default_timezone_get()); - - //get the message from the database - $sql = "select *, "; - $sql .= "to_char(timezone(:time_zone, to_timestamp(m.created_epoch)), 'DD Mon YYYY') as created_date_formatted, \n"; - $sql .= "to_char(timezone(:time_zone, to_timestamp(m.created_epoch)), 'HH12:MI:SS am') as created_time_formatted \n"; - $sql .= "from v_voicemail_messages as m, v_voicemails as v "; - $sql .= "where m.domain_uuid = :domain_uuid "; - $sql .= "and m.voicemail_uuid = v.voicemail_uuid "; - if (is_array($voicemail_id) && @sizeof($voicemail_id) != 0) { - $x = 0; - $sql .= "and ( "; - foreach ($voicemail_id as $row) { - $sql_where_or[] = "v.voicemail_id = :voicemail_id_".$x; - $parameters['voicemail_id_'.$x] = $row['voicemail_id']; + //get the uuid and voicemail_id + $sql = "select * from v_voicemails "; + $sql .= "where domain_uuid = :domain_uuid "; + if (is_uuid($this->voicemail_uuid)) { + if (permission_exists('voicemail_delete')) { + //view specific voicemail box usually reserved for an admin or superadmin + $sql .= "and voicemail_uuid = :voicemail_uuid "; + $parameters['voicemail_uuid'] = $this->voicemail_uuid; + } else { + //ensure that the requested voicemail box is assigned to this user + $found = false; + foreach ($voicemail_uuids as $row) { + if ($this->voicemail_uuid == $row['voicemail_uuid']) { + $sql .= "and voicemail_uuid = :voicemail_uuid "; + $parameters['voicemail_uuid'] = $row['voicemail_uuid']; + $found = true; + } + } + //id requested is not owned by the user return no results + if (!$found) { + $sql .= "and voicemail_uuid is null "; + } + } + } else { + if (!empty($voicemail_ids) && @sizeof($voicemail_ids) != 0) { + //show only the assigned voicemail ids + $sql .= "and "; + if (is_numeric($this->voicemail_id) && in_array($this->voicemail_id, $voicemail_ids)) { + $sql_where = 'voicemail_id = :voicemail_id '; + $parameters['voicemail_id'] = $this->voicemail_id; + } else { + $x = 0; + $sql_where = ''; + foreach ($voicemail_ids as $voicemail_id) { + $sql_where_or[] = "voicemail_id = :voicemail_id_" . $x; + $parameters['voicemail_id_' . $x] = $voicemail_id; $x++; } - $sql .= implode(' or ', $sql_where_or); - $sql .= ") "; - unset($sql_where_or); + $sql_where .= '(' . implode(' or ', $sql_where_or) . ') '; } - else { - $sql .= "and v.voicemail_id = :voicemail_id "; - $parameters['voicemail_id'] = $voicemail_id; - } - if (empty($this->order_by)) { - $sql .= "order by v.voicemail_id, m.created_epoch desc "; - } - else { - $sql .= "order by v.voicemail_id, m.".$this->order_by." ".$this->order." "; - } - //if paging offset defined, apply it along with rows per page - if (isset($this->offset)) { - $rows_per_page = $this->settings->get('domain', 'paging', 50); - $offset = isset($this->offset) && is_numeric($this->offset) ? $this->offset : 0; - $sql .= limit_offset($rows_per_page, $offset); - } - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['time_zone'] = $time_zone; - $result = $this->database->select($sql, $parameters, 'all'); - unset($sql, $parameters); - - //update the array with additional information - if (is_array($result)) { - foreach ($result as $i => $row) { - //set the greeting directory - $path = $this->settings->get('switch', 'voicemail', '/var/lib/freeswitch/storage').'/default/'.$this->domain_name.'/'.$row['voicemail_id']; - if (file_exists($path.'/msg_'.$row['voicemail_message_uuid'].'.wav')) { - $result[$i]['file_path'] = $path.'/msg_'.$row['voicemail_message_uuid'].'.wav'; - } - if (file_exists($path.'/msg_'.$row['voicemail_message_uuid'].'.mp3')) { - $result[$i]['file_path'] = $path.'/msg_'.$row['voicemail_message_uuid'].'.mp3'; - } - $result[$i]['file_size'] = filesize($result[$i]['file_path'] ?? ''); - $result[$i]['file_size_label'] = byte_convert($result[$i]['file_size'] ?? 0); - $result[$i]['file_ext'] = substr($result[$i]['file_path'] ?? '', -3); - - $message_minutes = floor($row['message_length'] / 60); - $message_seconds = $row['message_length'] % 60; - - //use International System of Units (SI) - Source: https://en.wikipedia.org/wiki/International_System_of_Units - $result[$i]['message_length_label'] = ($message_minutes > 0 ? $message_minutes.' min' : '').($message_seconds > 0 ? ' '.$message_seconds.' s' : ''); - $result[$i]['created_date'] = date("j M Y g:i a",$row['created_epoch']); - } - } - else { - $result = []; - } - return $result; + $sql .= $sql_where; + unset($sql_where_or); + } else { + //no assigned voicemail ids so return no results + $sql .= "and voicemail_uuid is null "; + } } + $sql .= "order by voicemail_id asc "; + $parameters['domain_uuid'] = $this->domain_uuid; + $result = $this->database->select($sql, $parameters, 'all'); + unset($sql, $parameters); + return $result; + } - public function voicemail_delete($records) { - if (permission_exists($this->permission_prefix.'delete')) { + /** + * retrieve all voicemail messages for a given list of voicemails + * + * @return array|false an array containing voicemail message data, keyed by voicemail id + */ + public function messages() { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //get the voicemails + $voicemails = $this->voicemails(); - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked sip profiles - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //get necessary voicemail details - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, voicemail_id from v_".$this->table." "; - $sql .= "where ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $rows = $this->database->select($sql, $parameters ?? null, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $voicemail_ids[$row['uuid']] = $row['voicemail_id']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //loop through voicemail ids - if (is_array($voicemail_ids) && @sizeof($voicemail_ids) != 0) { - $x = 0; - foreach ($voicemail_ids as $voicemail_uuid => $voicemail_id) { - - //delete voicemail message recording and greeting files - if (is_numeric($voicemail_id)) { - $file_path = $this->settings->get('switch', 'voicemail')."/default/".$this->domain_name."/".$voicemail_id; - foreach (glob($file_path."/*.*") as $file_name) { - @unlink($file_name); - } - @rmdir($file_path); - } - - //reset message waiting indicator status - $this->voicemail_id = $voicemail_id; - $this->voicemail_uuid = $voicemail_uuid; - $this->domain_uuid = $this->domain_uuid; - $this->message_waiting(); - - //build the delete array - $array[$this->table][$x]['voicemail_uuid'] = $voicemail_uuid; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - $array['voicemail_options'][$x]['voicemail_uuid'] = $voicemail_uuid; - $array['voicemail_options'][$x]['domain_uuid'] = $this->domain_uuid; - $array['voicemail_messages'][$x]['voicemail_uuid'] = $voicemail_uuid; - $array['voicemail_messages'][$x]['domain_uuid'] = $this->domain_uuid; - $array['voicemail_destinations'][$x]['voicemail_uuid'] = $voicemail_uuid; - $array['voicemail_destinations'][$x]['domain_uuid'] = $this->domain_uuid; - if (is_numeric($voicemail_id)) { - $array['voicemail_greetings'][$x]['voicemail_id'] = $voicemail_id; - $array['voicemail_greetings'][$x]['domain_uuid'] = $this->domain_uuid; - } - $x++; - $array['voicemail_destinations'][$x]['voicemail_uuid_copy'] = $voicemail_uuid; - $array['voicemail_destinations'][$x]['domain_uuid'] = $this->domain_uuid; - $x++; - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('voicemail_delete', 'temp'); - $p->add('voicemail_option_delete', 'temp'); - $p->add('voicemail_message_delete', 'temp'); - $p->add('voicemail_destination_delete', 'temp'); - $p->add('voicemail_greeting_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('voicemail_delete', 'temp'); - $p->delete('voicemail_option_delete', 'temp'); - $p->delete('voicemail_message_delete', 'temp'); - $p->delete('voicemail_destination_delete', 'temp'); - $p->delete('voicemail_greeting_delete', 'temp'); - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-delete']); - } - unset($records, $voicemail_ids); - } + //add the voicemail messages to the array + if (is_array($voicemails)) { + $i = 0; + foreach ($voicemails as $row) { + //get the voicemail messages + $voicemails[$i]['messages'] = $this->voicemail_messages($row['voicemail_id']); + $i++; } } - public function voicemail_options_delete($records) { - //assign private variables - $this->permission_prefix = 'voicemail_option_'; - $this->list_page = 'voicemail_edit.php?id='.$this->voicemail_uuid; - $this->table = 'voicemail_options'; - $this->uuid_prefix = 'voicemail_option_'; + //return the array + return $voicemails; + } - if (permission_exists($this->permission_prefix.'delete')) { + /** + * Retrieve voicemail messages. + * + * @param int|string|array $voicemail_id if not array, then will be used as the primary filter for voicemails, + * if array and contains at least one id, then used for filtering + * to retrieve multiple voicemail records with specified ids + * + * @return array list of voicemail messages with additional information such as file path, size and length + */ + private function voicemail_messages($voicemail_id): array { - //add multi-lingual support - $language = new text; - $text = $language->get(); + //check if for valid input + if (!is_numeric($voicemail_id) || !is_uuid($this->domain_uuid)) { + return []; + } - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } + //set the time zone + $time_zone = $this->settings->get('domain', 'time_zone', date_default_timezone_get()); - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked sip profiles - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - //build the delete array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['voicemail_uuid'] = $this->voicemail_uuid; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - } - } - - //delete the checked rows - if (is_array($array) && @sizeof($array) != 0) { - //execute delete - $this->database->delete($array); - unset($array); - } - unset($records); - } + //get the message from the database + $sql = "select *, "; + $sql .= "to_char(timezone(:time_zone, to_timestamp(m.created_epoch)), 'DD Mon YYYY') as created_date_formatted, \n"; + $sql .= "to_char(timezone(:time_zone, to_timestamp(m.created_epoch)), 'HH12:MI:SS am') as created_time_formatted \n"; + $sql .= "from v_voicemail_messages as m, v_voicemails as v "; + $sql .= "where m.domain_uuid = :domain_uuid "; + $sql .= "and m.voicemail_uuid = v.voicemail_uuid "; + if (is_array($voicemail_id) && @sizeof($voicemail_id) != 0) { + $x = 0; + $sql .= "and ( "; + foreach ($voicemail_id as $row) { + $sql_where_or[] = "v.voicemail_id = :voicemail_id_" . $x; + $parameters['voicemail_id_' . $x] = $row['voicemail_id']; + $x++; } + $sql .= implode(' or ', $sql_where_or); + $sql .= ") "; + unset($sql_where_or); + } else { + $sql .= "and v.voicemail_id = :voicemail_id "; + $parameters['voicemail_id'] = $voicemail_id; } + if (empty($this->order_by)) { + $sql .= "order by v.voicemail_id, m.created_epoch desc "; + } else { + $sql .= "order by v.voicemail_id, m." . $this->order_by . " " . $this->order . " "; + } + //if paging offset defined, apply it along with rows per page + if (isset($this->offset)) { + $rows_per_page = $this->settings->get('domain', 'paging', 50); + $offset = isset($this->offset) && is_numeric($this->offset) ? $this->offset : 0; + $sql .= limit_offset($rows_per_page, $offset); + } + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['time_zone'] = $time_zone; + $result = $this->database->select($sql, $parameters, 'all'); + unset($sql, $parameters); - public function voicemail_destinations_delete($records) { - //assign private variables - $this->list_page = 'voicemail_edit.php?id='.$this->voicemail_uuid; - $this->table = 'voicemail_destinations'; - $this->uuid_prefix = 'voicemail_destination_'; + //update the array with additional information + if (is_array($result)) { + foreach ($result as $i => $row) { + //set the greeting directory + $path = $this->settings->get('switch', 'voicemail', '/var/lib/freeswitch/storage') . '/default/' . $this->domain_name . '/' . $row['voicemail_id']; + if (file_exists($path . '/msg_' . $row['voicemail_message_uuid'] . '.wav')) { + $result[$i]['file_path'] = $path . '/msg_' . $row['voicemail_message_uuid'] . '.wav'; + } + if (file_exists($path . '/msg_' . $row['voicemail_message_uuid'] . '.mp3')) { + $result[$i]['file_path'] = $path . '/msg_' . $row['voicemail_message_uuid'] . '.mp3'; + } + $result[$i]['file_size'] = filesize($result[$i]['file_path'] ?? ''); + $result[$i]['file_size_label'] = byte_convert($result[$i]['file_size'] ?? 0); + $result[$i]['file_ext'] = substr($result[$i]['file_path'] ?? '', -3); - if (permission_exists('voicemail_forward')) { + $message_minutes = floor($row['message_length'] / 60); + $message_seconds = $row['message_length'] % 60; - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //delete multiple records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked sip profiles - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - //build the delete array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; - $array[$this->table][$x]['voicemail_uuid'] = $this->voicemail_uuid; - $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; - } - } - - //delete the checked rows - if (!empty($array) && is_array($array) && @sizeof($array) != 0) { - //grant temporary permissions - $p = permissions::new(); - $p->add('voicemail_destination_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('voicemail_destination_delete', 'temp'); - } - unset($records); - } + //use International System of Units (SI) - Source: https://en.wikipedia.org/wiki/International_System_of_Units + $result[$i]['message_length_label'] = ($message_minutes > 0 ? $message_minutes . ' min' : '') . ($message_seconds > 0 ? ' ' . $message_seconds . ' s' : ''); + $result[$i]['created_date'] = date("j M Y g:i a", $row['created_epoch']); } + } else { + $result = []; } + return $result; + } - public function voicemail_toggle($records) { - if (permission_exists($this->permission_prefix.'edit')) { - - //add multi-lingual support - $language = new text; - $text = $language->get(); - - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); - exit; - } - - //toggle the checked records - if (is_array($records) && @sizeof($records) != 0) { - - //filter out unchecked sip profiles - foreach ($records as $x => $record) { - if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { - $uuids[] = "'".$record['uuid']."'"; - } - } - - //get necessary voicemail details - if (is_array($uuids) && @sizeof($uuids) != 0) { - $sql = "select ".$this->uuid_prefix."uuid as uuid, voicemail_id, ".$this->toggle_field." as toggle from v_".$this->table." "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "and ".$this->uuid_prefix."uuid in (".implode(', ', $uuids).") "; - $parameters['domain_uuid'] = $this->domain_uuid; - $rows = $this->database->select($sql, $parameters, 'all'); - if (is_array($rows) && @sizeof($rows) != 0) { - foreach ($rows as $row) { - $voicemails[$row['uuid']]['state'] = $row['toggle']; - $voicemails[$row['uuid']]['id'] = $row['voicemail_id']; - } - } - unset($sql, $parameters, $rows, $row); - } - - //loop through voicemails - if (is_array($voicemails) && @sizeof($voicemails) != 0) { - $x = 0; - foreach ($voicemails as $voicemail_uuid => $voicemail) { - - //reset message waiting indicator status - $this->voicemail_id = $voicemail['id']; - $this->voicemail_uuid = $voicemail_uuid; - $this->domain_uuid = $this->domain_uuid; - $this->message_waiting(); - - //build update array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $voicemail_uuid; - $array[$this->table][$x][$this->toggle_field] = $voicemail['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - $x++; - } - } - - //save the changes - if (is_array($array) && @sizeof($array) != 0) { - - //save the array - - $this->database->save($array); - unset($array); - - //clear the destinations session array - if (isset($_SESSION['destinations']['array'])) { - unset($_SESSION['destinations']['array']); - } - - //set message - message::add($text['message-toggle']); - } - unset($records, $voicemails); - } - - } - } - - public function message_count() { - - //check if for valid input - if (!is_uuid($this->voicemail_uuid) || !is_uuid($this->domain_uuid)) { - return false; - } - - //return the message count - $sql = "select count(*) from v_voicemail_messages "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and voicemail_uuid = :voicemail_uuid "; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['voicemail_uuid'] = $this->voicemail_uuid; - return $this->database->select($sql, $parameters, 'column'); - unset($sql, $parameters); - - } - - public function message_waiting() { - //get the voicemail id - $this->get_voicemail_id(); - - //send the message waiting status - - $esl = event_socket::create(); - if ($esl->is_connected()) { - $switch_cmd = "luarun app.lua voicemail mwi ".$this->voicemail_id."@".$this->domain_name; - $switch_result = event_socket::api($switch_cmd); - } - } - - public function message_delete() { - - //get the voicemail id - $this->get_voicemail_id(); - - //check if for valid input - if (!is_numeric($this->voicemail_id) - || !is_uuid($this->voicemail_uuid) - || !is_uuid($this->domain_uuid) - || !is_uuid($this->voicemail_message_uuid) - ) { - return false; - } - - //delete the recording - $file_path = $this->settings->get('switch', 'voicemail')."/default/".$this->domain_name."/".$this->voicemail_id; - if (is_uuid($this->voicemail_message_uuid)) { - foreach (glob($file_path."/intro_msg_".$this->voicemail_message_uuid.".*") as $file_name) { - unlink($file_name); - } - foreach (glob($file_path."/intro_".$this->voicemail_message_uuid.".*") as $file_name) { - unlink($file_name); - } - foreach (glob($file_path."/msg_".$this->voicemail_message_uuid.".*") as $file_name) { - unlink($file_name); - } - } - else { - foreach (glob($file_path."/msg_*.*") as $file_name) { - unlink($file_name); //remove all recordings - } - } - - //build delete array - $array['voicemail_messages'][0]['domain_uuid'] = $this->domain_uuid; - $array['voicemail_messages'][0]['voicemail_uuid'] = $this->voicemail_uuid; - if (is_uuid($this->voicemail_message_uuid)) { - $array['voicemail_messages'][0]['voicemail_message_uuid'] = $this->voicemail_message_uuid; - } - - //grant temporary permissions - $p = permissions::new(); - $p->add('voicemail_message_delete', 'temp'); - - //execute delete - $this->database->delete($array); - unset($array); - - //revoke temporary permissions - $p->delete('voicemail_message_delete', 'temp'); - - //check the message waiting status - $this->message_waiting(); - } - - public function message_toggle() { - - //check if for valid input - if (!is_uuid($this->voicemail_uuid) - || !is_uuid($this->domain_uuid) - || !is_uuid($this->voicemail_message_uuid) - ) { - return false; - } - - //get message status - $sql = "select message_status from v_voicemail_messages "; - $sql .= "where voicemail_message_uuid = :voicemail_message_uuid "; - $parameters['voicemail_message_uuid'] = $this->voicemail_message_uuid; - $new_status = $this->database->select($sql, $parameters, 'column') != 'saved' ? 'saved' : null; - unset($sql, $parameters); - - //build message status update array - $array['voicemail_messages'][0]['voicemail_message_uuid'] = $this->voicemail_message_uuid; - $array['voicemail_messages'][0]['message_status'] = $new_status; - - //grant temporary permissions - $p = permissions::new(); - $p->add('voicemail_message_edit', 'temp'); - - //execute update - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('voicemail_message_edit', 'temp'); - - //check the message waiting status - $this->message_waiting(); - } - - public function message_resend() { - - //check if for valid input - if (!is_uuid($this->voicemail_uuid) - || !is_uuid($this->domain_uuid) - || !is_uuid($this->voicemail_message_uuid) - ) { - return false; - } + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function voicemail_delete($records) { + if (permission_exists($this->permission_prefix . 'delete')) { //add multi-lingual support $language = new text; - $text = $language->get(); + $text = $language->get(); - //add the settings object - $settings = new settings(["domain_uuid" => $this->domain_uuid, "user_uuid" => $this->user_uuid]); - $email_from = $settings->get('email', 'smtp_from', ''); - $email_from_name = $settings->get('email', 'smtp_from_name', 'PBX'); - $switch_scripts = $settings->get('switch', 'scripts', '/usr/share/freeswitch/scripts'); - $switch_voicemail = $settings->get('switch', 'voicemail', '/var/lib/freeswitch/storage/voicemail'); - $language_dialect = $settings->get('domain', 'language', 'en-us'); - $time_zone = $settings->get('domain', 'time_zone', 'UTC'); - $display_domain_name = $settings->get('voicemail', 'display_domain_name', 'false'); + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } - //get voicemail message details - $sql = "select "; - $sql .= " vm.*, "; - $sql .= " to_char(timezone(:time_zone, to_timestamp(vm.created_epoch)), 'Day DD Mon YYYY HH:MI:SS PM') as message_date, "; - $sql .= " v.voicemail_id, "; - $sql .= " v.voicemail_mail_to, "; - $sql .= " v.voicemail_description, "; - $sql .= " v.voicemail_file, "; - $sql .= " d.domain_name "; - $sql .= "from "; - $sql .= " v_voicemail_messages as vm "; - $sql .= " left join v_voicemails as v on vm.voicemail_uuid = v.voicemail_uuid "; - $sql .= " left join v_domains as d on vm.domain_uuid = d.domain_uuid "; - $sql .= "where "; - $sql .= " vm.voicemail_message_uuid = :voicemail_message_uuid "; - $sql .= "limit 1" ; - $parameters['time_zone'] = $time_zone; + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked sip profiles + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //get necessary voicemail details + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, voicemail_id from v_" . $this->table . " "; + $sql .= "where " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $rows = $this->database->select($sql, $parameters ?? null, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $voicemail_ids[$row['uuid']] = $row['voicemail_id']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //loop through voicemail ids + if (is_array($voicemail_ids) && @sizeof($voicemail_ids) != 0) { + $x = 0; + foreach ($voicemail_ids as $voicemail_uuid => $voicemail_id) { + + //delete voicemail message recording and greeting files + if (is_numeric($voicemail_id)) { + $file_path = $this->settings->get('switch', 'voicemail') . "/default/" . $this->domain_name . "/" . $voicemail_id; + foreach (glob($file_path . "/*.*") as $file_name) { + @unlink($file_name); + } + @rmdir($file_path); + } + + //reset message waiting indicator status + $this->voicemail_id = $voicemail_id; + $this->voicemail_uuid = $voicemail_uuid; + $this->domain_uuid = $this->domain_uuid; + $this->message_waiting(); + + //build the delete array + $array[$this->table][$x]['voicemail_uuid'] = $voicemail_uuid; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + $array['voicemail_options'][$x]['voicemail_uuid'] = $voicemail_uuid; + $array['voicemail_options'][$x]['domain_uuid'] = $this->domain_uuid; + $array['voicemail_messages'][$x]['voicemail_uuid'] = $voicemail_uuid; + $array['voicemail_messages'][$x]['domain_uuid'] = $this->domain_uuid; + $array['voicemail_destinations'][$x]['voicemail_uuid'] = $voicemail_uuid; + $array['voicemail_destinations'][$x]['domain_uuid'] = $this->domain_uuid; + if (is_numeric($voicemail_id)) { + $array['voicemail_greetings'][$x]['voicemail_id'] = $voicemail_id; + $array['voicemail_greetings'][$x]['domain_uuid'] = $this->domain_uuid; + } + $x++; + $array['voicemail_destinations'][$x]['voicemail_uuid_copy'] = $voicemail_uuid; + $array['voicemail_destinations'][$x]['domain_uuid'] = $this->domain_uuid; + $x++; + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions + $p = permissions::new(); + $p->add('voicemail_delete', 'temp'); + $p->add('voicemail_option_delete', 'temp'); + $p->add('voicemail_message_delete', 'temp'); + $p->add('voicemail_destination_delete', 'temp'); + $p->add('voicemail_greeting_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('voicemail_delete', 'temp'); + $p->delete('voicemail_option_delete', 'temp'); + $p->delete('voicemail_message_delete', 'temp'); + $p->delete('voicemail_destination_delete', 'temp'); + $p->delete('voicemail_greeting_delete', 'temp'); + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //set message + message::add($text['message-delete']); + } + unset($records, $voicemail_ids); + } + } + } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function voicemail_options_delete($records) { + //assign private variables + $this->permission_prefix = 'voicemail_option_'; + $this->list_page = 'voicemail_edit.php?id=' . $this->voicemail_uuid; + $this->table = 'voicemail_options'; + $this->uuid_prefix = 'voicemail_option_'; + + if (permission_exists($this->permission_prefix . 'delete')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked sip profiles + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + //build the delete array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['voicemail_uuid'] = $this->voicemail_uuid; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + } + } + + //delete the checked rows + if (is_array($array) && @sizeof($array) != 0) { + //execute delete + $this->database->delete($array); + unset($array); + } + unset($records); + } + } + } + + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function voicemail_destinations_delete($records) { + //assign private variables + $this->list_page = 'voicemail_edit.php?id=' . $this->voicemail_uuid; + $this->table = 'voicemail_destinations'; + $this->uuid_prefix = 'voicemail_destination_'; + + if (permission_exists('voicemail_forward')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked sip profiles + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + //build the delete array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; + $array[$this->table][$x]['voicemail_uuid'] = $this->voicemail_uuid; + $array[$this->table][$x]['domain_uuid'] = $this->domain_uuid; + } + } + + //delete the checked rows + if (!empty($array) && is_array($array) && @sizeof($array) != 0) { + //grant temporary permissions + $p = permissions::new(); + $p->add('voicemail_destination_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('voicemail_destination_delete', 'temp'); + } + unset($records); + } + } + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function voicemail_toggle($records) { + if (permission_exists($this->permission_prefix . 'edit')) { + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //toggle the checked records + if (is_array($records) && @sizeof($records) != 0) { + + //filter out unchecked sip profiles + foreach ($records as $x => $record) { + if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) { + $uuids[] = "'" . $record['uuid'] . "'"; + } + } + + //get necessary voicemail details + if (is_array($uuids) && @sizeof($uuids) != 0) { + $sql = "select " . $this->uuid_prefix . "uuid as uuid, voicemail_id, " . $this->toggle_field . " as toggle from v_" . $this->table . " "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "and " . $this->uuid_prefix . "uuid in (" . implode(', ', $uuids) . ") "; + $parameters['domain_uuid'] = $this->domain_uuid; + $rows = $this->database->select($sql, $parameters, 'all'); + if (is_array($rows) && @sizeof($rows) != 0) { + foreach ($rows as $row) { + $voicemails[$row['uuid']]['state'] = $row['toggle']; + $voicemails[$row['uuid']]['id'] = $row['voicemail_id']; + } + } + unset($sql, $parameters, $rows, $row); + } + + //loop through voicemails + if (is_array($voicemails) && @sizeof($voicemails) != 0) { + $x = 0; + foreach ($voicemails as $voicemail_uuid => $voicemail) { + + //reset message waiting indicator status + $this->voicemail_id = $voicemail['id']; + $this->voicemail_uuid = $voicemail_uuid; + $this->domain_uuid = $this->domain_uuid; + $this->message_waiting(); + + //build update array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $voicemail_uuid; + $array[$this->table][$x][$this->toggle_field] = $voicemail['state'] == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; + $x++; + } + } + + //save the changes + if (is_array($array) && @sizeof($array) != 0) { + + //save the array + + $this->database->save($array); + unset($array); + + //clear the destinations session array + if (isset($_SESSION['destinations']['array'])) { + unset($_SESSION['destinations']['array']); + } + + //set message + message::add($text['message-toggle']); + } + unset($records, $voicemails); + } + + } + } + + /** + * Return the count of messages for a given voicemail and domain + * + * @return int|false|null The message count or null if invalid input is provided + */ + public function message_count() { + + //check if for valid input + if (!is_uuid($this->voicemail_uuid) || !is_uuid($this->domain_uuid)) { + return false; + } + + //return the message count + $sql = "select count(*) from v_voicemail_messages "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and voicemail_uuid = :voicemail_uuid "; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['voicemail_uuid'] = $this->voicemail_uuid; + return $this->database->select($sql, $parameters, 'column'); + } + + /** + * Send the message waiting status using the switch api command + * + * @return void + */ + public function message_waiting() { + //get the voicemail id + $this->get_voicemail_id(); + + //send the message waiting status + + $esl = event_socket::create(); + if ($esl->is_connected()) { + $switch_cmd = "luarun app.lua voicemail mwi " . $this->voicemail_id . "@" . $this->domain_name; + $switch_result = event_socket::api($switch_cmd); + } + } + + /** + * deletes a voicemail message + * + * Object properties voicemail_id, voicemail_uuid, domain_uuid, voicemail_message_uuid must be set. + * + * @return bool True if successful, False otherwise + */ + public function message_delete() { + + //get the voicemail id + $this->get_voicemail_id(); + + //check if for valid input + if (!is_numeric($this->voicemail_id) + || !is_uuid($this->voicemail_uuid) + || !is_uuid($this->domain_uuid) + || !is_uuid($this->voicemail_message_uuid) + ) { + return false; + } + + //delete the recording + $file_path = $this->settings->get('switch', 'voicemail') . "/default/" . $this->domain_name . "/" . $this->voicemail_id; + if (is_uuid($this->voicemail_message_uuid)) { + foreach (glob($file_path . "/intro_msg_" . $this->voicemail_message_uuid . ".*") as $file_name) { + unlink($file_name); + } + foreach (glob($file_path . "/intro_" . $this->voicemail_message_uuid . ".*") as $file_name) { + unlink($file_name); + } + foreach (glob($file_path . "/msg_" . $this->voicemail_message_uuid . ".*") as $file_name) { + unlink($file_name); + } + } else { + foreach (glob($file_path . "/msg_*.*") as $file_name) { + unlink($file_name); //remove all recordings + } + } + + //build delete array + $array['voicemail_messages'][0]['domain_uuid'] = $this->domain_uuid; + $array['voicemail_messages'][0]['voicemail_uuid'] = $this->voicemail_uuid; + if (is_uuid($this->voicemail_message_uuid)) { + $array['voicemail_messages'][0]['voicemail_message_uuid'] = $this->voicemail_message_uuid; + } + + //grant temporary permissions + $p = permissions::new(); + $p->add('voicemail_message_delete', 'temp'); + + //execute delete + $this->database->delete($array); + unset($array); + + //revoke temporary permissions + $p->delete('voicemail_message_delete', 'temp'); + + //check the message waiting status + $this->message_waiting(); + + return true; + } + + /** + * Toggles the state of one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function message_toggle() { + + //check if for valid input + if (!is_uuid($this->voicemail_uuid) + || !is_uuid($this->domain_uuid) + || !is_uuid($this->voicemail_message_uuid) + ) { + return false; + } + + //get message status + $sql = "select message_status from v_voicemail_messages "; + $sql .= "where voicemail_message_uuid = :voicemail_message_uuid "; + $parameters['voicemail_message_uuid'] = $this->voicemail_message_uuid; + $new_status = $this->database->select($sql, $parameters, 'column') != 'saved' ? 'saved' : null; + unset($sql, $parameters); + + //build message status update array + $array['voicemail_messages'][0]['voicemail_message_uuid'] = $this->voicemail_message_uuid; + $array['voicemail_messages'][0]['message_status'] = $new_status; + + //grant temporary permissions + $p = permissions::new(); + $p->add('voicemail_message_edit', 'temp'); + + //execute update + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('voicemail_message_edit', 'temp'); + + //check the message waiting status + $this->message_waiting(); + } + + /** + * Resend a voicemail message + * + * @return boolean true if the voicemail message was resent successfully, false otherwise. + */ + public function message_resend() { + + //check if for valid input + if (!is_uuid($this->voicemail_uuid) + || !is_uuid($this->domain_uuid) + || !is_uuid($this->voicemail_message_uuid) + ) { + return false; + } + + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //add the settings object + $settings = new settings(["domain_uuid" => $this->domain_uuid, "user_uuid" => $this->user_uuid]); + $email_from = $settings->get('email', 'smtp_from', ''); + $email_from_name = $settings->get('email', 'smtp_from_name', 'PBX'); + $switch_scripts = $settings->get('switch', 'scripts', '/usr/share/freeswitch/scripts'); + $switch_voicemail = $settings->get('switch', 'voicemail', '/var/lib/freeswitch/storage/voicemail'); + $language_dialect = $settings->get('domain', 'language', 'en-us'); + $time_zone = $settings->get('domain', 'time_zone', 'UTC'); + $display_domain_name = $settings->get('voicemail', 'display_domain_name', 'false'); + + //get voicemail message details + $sql = "select "; + $sql .= " vm.*, "; + $sql .= " to_char(timezone(:time_zone, to_timestamp(vm.created_epoch)), 'Day DD Mon YYYY HH:MI:SS PM') as message_date, "; + $sql .= " v.voicemail_id, "; + $sql .= " v.voicemail_mail_to, "; + $sql .= " v.voicemail_description, "; + $sql .= " v.voicemail_file, "; + $sql .= " d.domain_name "; + $sql .= "from "; + $sql .= " v_voicemail_messages as vm "; + $sql .= " left join v_voicemails as v on vm.voicemail_uuid = v.voicemail_uuid "; + $sql .= " left join v_domains as d on vm.domain_uuid = d.domain_uuid "; + $sql .= "where "; + $sql .= " vm.voicemail_message_uuid = :voicemail_message_uuid "; + $sql .= "limit 1"; + $parameters['time_zone'] = $time_zone; + $parameters['voicemail_message_uuid'] = $this->voicemail_message_uuid; + $message = $this->database->select($sql, $parameters, 'row'); + unset($sql, $parameters); + + //retrieve appropriate email template + $sql = "select "; + $sql .= " template_subject, "; + $sql .= " template_body "; + $sql .= "from "; + $sql .= " v_email_templates "; + $sql .= "where "; + $sql .= " template_language = :template_language "; + $sql .= " and template_category = 'voicemail' "; + $sql .= " and template_subcategory = '" . (!empty($message['message_transcription']) ? 'transcription' : 'default') . "' "; + $sql .= " and template_type = 'html' "; + $sql .= " and template_enabled = true "; + $sql .= " and (domain_uuid = :domain_uuid or domain_uuid is null) "; + $sql .= "limit 1 "; + $parameters['template_language'] = $language_dialect; + $parameters['domain_uuid'] = $this->domain_uuid; + $template = $this->database->select($sql, $parameters, 'row'); + unset($sql, $parameters); + + //determine formatted voicemail name + $voicemail_name_formatted = $message['voicemail_id']; + if ($display_domain_name == 'true') { + $voicemail_name_formatted = $message['voicemail_id'] . '@' . $message['domain_name']; + } + if (!empty($message['voicemail_description'])) { + $voicemail_name_formatted .= ' (' . $message['voicemail_description'] . ')'; + } + + //replace subject variables + if (!empty($template['template_subject'])) { + $template['template_subject'] = str_replace('${caller_id_name}', $message['caller_id_name'], $template['template_subject']); + $template['template_subject'] = str_replace('${caller_id_number}', $message['caller_id_number'], $template['template_subject']); + $template['template_subject'] = str_replace('${message_date}', $message['message_date'], $template['template_subject']); + $template['template_subject'] = str_replace('${message_duration}', '0' . gmdate("G:i:s", ($message['message_length'] ?? 0)), $template['template_subject']); + $template['template_subject'] = str_replace('${account}', $voicemail_name_formatted, $template['template_subject']); + $template['template_subject'] = str_replace('${voicemail_id}', $message['voicemail_id'], $template['template_subject']); + $template['template_subject'] = str_replace('${voicemail_description}', $message['voicemail_description'], $template['template_subject']); + $template['template_subject'] = str_replace('${voicemail_name_formatted}', $voicemail_name_formatted, $template['template_subject']); + $template['template_subject'] = str_replace('${domain_name}', $message['domain_name'], $template['template_subject']); + } else { + $template['template_subject'] = $text['label-voicemail_from'] . ' ' . $message['caller_id_name'] . ' <' . $message['caller_id_number'] . '> 0' . gmdate("G:i:s", ($message['message_length'] ?? 0)); + } + + //encode subject + $template['template_subject'] = trim(iconv_mime_encode('', $template['template_subject'], ['scheme' => 'B', 'output-charset' => 'utf-8', 'line-break-chars' => "\n"]), ': '); + + //determine voicemail message file path and type + $voicemail_message_path = $switch_voicemail . '/default/' . $message['domain_name'] . '/' . $message['voicemail_id']; + if ( + !empty($message['message_base64']) && + !file_exists($voicemail_message_path . '/msg_' . $message['voicemail_message_uuid'] . '.wav') && + !file_exists($voicemail_message_path . '/msg_' . $message['voicemail_message_uuid'] . '.mp3') + ) { + $voicemail_message_decoded = base64_decode($message['message_base64']); + file_put_contents($voicemail_message_path . '/msg_' . $message['voicemail_message_uuid'] . '.ext', $voicemail_message_decoded); + $finfo = finfo_open(FILEINFO_MIME_TYPE); + $voicemail_message_file_mime = finfo_file($finfo, $voicemail_message_path . '/msg_' . $message['voicemail_message_uuid'] . '.ext'); + finfo_close($finfo); + unset($voicemail_message_decoded); + switch ($voicemail_message_file_mime) { + case 'audio/x-wav': + case 'audio/wav': + $voicemail_message_file_ext = 'wav'; + break; + case 'audio/mpeg': + case 'audio/mp3': + $voicemail_message_file_ext = 'mp3'; + break; + } + rename($voicemail_message_path . '/msg_' . $message['voicemail_message_uuid'] . '.ext', $voicemail_message_path . '/msg_' . $message['voicemail_message_uuid'] . '.' . $voicemail_message_file_ext); + $voicemail_message_file = 'msg_' . $message['voicemail_message_uuid'] . '.' . $voicemail_message_file_ext; + } else { + if (file_exists($voicemail_message_path . '/msg_' . $message['voicemail_message_uuid'] . '.wav')) { + $voicemail_message_file_ext = 'wav'; + } + if (file_exists($voicemail_message_path . '/msg_' . $message['voicemail_message_uuid'] . '.mp3')) { + $voicemail_message_file_ext = 'mp3'; + } + $voicemail_message_file = 'msg_' . $message['voicemail_message_uuid'] . '.' . $voicemail_message_file_ext; + $voicemail_message_file_mime = mime_content_type($voicemail_message_path . '/msg_' . $message['voicemail_message_uuid'] . '.' . $voicemail_message_file_ext); + } + + //determine voicemail intro file path + if ( + !empty($message['message_intro_base64']) && + !file_exists($voicemail_message_path . '/intro_' . $message['voicemail_message_uuid'] . '.wav') && + !file_exists($voicemail_message_path . '/intro_' . $message['voicemail_message_uuid'] . '.mp3') + ) { + $voicemail_intro_decoded = base64_decode($message['message_intro_base64']); + file_put_contents($voicemail_message_path . '/intro_' . $message['voicemail_message_uuid'] . '.' . $voicemail_message_file_ext, $voicemail_intro_decoded); + $voicemail_intro_file = 'intro_' . $message['voicemail_message_uuid'] . '.' . $voicemail_message_file_ext; + } else { + $voicemail_intro_file = 'intro_' . $message['voicemail_message_uuid'] . '.' . $voicemail_message_file_ext; + } + + //combine voicemail intro and message files + $sox = system('which sox'); + if (file_exists($voicemail_message_path . '/' . $voicemail_intro_file) && !empty($sox)) { + $voicemail_combined_file = 'intro_msg_' . $message['voicemail_message_uuid'] . '.' . $voicemail_message_file_ext; + exec($sox . ' ' . $voicemail_message_path . '/' . $voicemail_intro_file . ' ' . $voicemail_message_path . '/' . $voicemail_message_file . ' ' . $voicemail_message_path . '/' . $voicemail_combined_file); + if (file_exists($voicemail_message_path . '/' . $voicemail_combined_file)) { + $message['message_combined_base64'] = base64_encode(file_get_contents($voicemail_message_path . '/' . $voicemail_combined_file)); + } + } + + //replace body variables + if (!empty($template['template_body'])) { + $template['template_body'] = str_replace('${caller_id_name}', $message['caller_id_name'], $template['template_body']); + $template['template_body'] = str_replace('${caller_id_number}', $message['caller_id_number'], $template['template_body']); + $template['template_body'] = str_replace('${message_date}', $message['message_date'], $template['template_body']); + $template['template_body'] = str_replace('${message_text}', $message['message_transcription'], $template['template_body']); + $template['template_body'] = str_replace('${message_duration}', '0' . gmdate("G:i:s", ($message['message_length'] ?? 0)), $template['template_body']); + $template['template_body'] = str_replace('${account}', $voicemail_name_formatted, $template['template_body']); + $template['template_body'] = str_replace('${voicemail_id}', $message['voicemail_id'], $template['template_body']); + $template['template_body'] = str_replace('${voicemail_description}', $message['voicemail_description'], $template['template_body']); + $template['template_body'] = str_replace('${voicemail_name_formatted}', $voicemail_name_formatted, $template['template_body']); + $template['template_body'] = str_replace('${domain_name}', $message['domain_name'], $template['template_body']); + $template['template_body'] = str_replace('${sip_to_user}', $message['voicemail_id'], $template['template_body']); + $template['template_body'] = str_replace('${dialed_user}', $message['voicemail_id'], $template['template_body']); + if (!empty($message['voicemail_file'])) { + if ($message['voicemail_file'] == 'attach' && (file_exists($voicemail_message_path . '/' . $voicemail_combined_file) || file_exists($voicemail_message_path . '/' . $voicemail_message_file))) { + $template['template_body'] = str_replace('${message}', $text['label-attached'], $template['template_body']); + } elseif ($message['voicemail_file'] == 'link') { + $template['template_body'] = str_replace('${message}', "" . $text['label-download'] . "", $template['template_body']); + } else { // listen + $template['template_body'] = str_replace('${message}', "" . $text['label-listen'] . "", $template['template_body']); + } + } + } else { + $template['template_body'] = "\n\n"; + if (!empty($message['caller_id_name']) && $message['caller_id_name'] != $message['caller_id_number']) { + $template['template_body'] .= $message['caller_id_name'] . "
    \n"; + } + $template['template_body'] .= $message['caller_id_number'] . "
    \n"; + $template['template_body'] .= $message['message_date'] . "
    \n"; + if (!empty($message['voicemail_file'])) { + if ($message['voicemail_file'] == 'attach' && (file_exists($voicemail_message_path . '/' . $voicemail_combined_file) || file_exists($voicemail_message_path . '/' . $voicemail_message_file))) { + $template['template_body'] .= "
    \n" . $text['label-attached']; + } elseif ($message['voicemail_file'] == 'link') { + $template['template_body'] .= "
    \n" . $text['label-download'] . ''; + } else { // listen + $template['template_body'] .= "
    \n" . $text['label-listen'] . ''; + } + } + $template['template_body'] .= "\n\n"; + } + + //build message status update array + $array['email_queue'][0]['email_queue_uuid'] = $email_queue_uuid = uuid(); + $array['email_queue'][0]['domain_uuid'] = $this->domain_uuid; + $array['email_queue'][0]['hostname'] = gethostname(); + $array['email_queue'][0]['email_date'] = 'now()'; + $array['email_queue'][0]['email_from'] = $email_from_name . '<' . $email_from . '>'; + $array['email_queue'][0]['email_to'] = $message['voicemail_mail_to']; + $array['email_queue'][0]['email_subject'] = $template['template_subject']; + $array['email_queue'][0]['email_body'] = $template['template_body']; + $array['email_queue'][0]['email_status'] = 'waiting'; + $array['email_queue'][0]['email_uuid'] = $this->voicemail_message_uuid; + $array['email_queue'][0]['email_transcription'] = $message['message_transcription']; + $array['email_queue'][0]['insert_date'] = 'now()'; + $array['email_queue'][0]['insert_user'] = $this->user_uuid; + + //add voicemail file details (and/or base64) to queue attachments + if (!empty($message['voicemail_file']) && $message['voicemail_file'] == 'attach' && (file_exists($voicemail_message_path . '/' . $voicemail_combined_file) || file_exists($voicemail_message_path . '/' . $voicemail_message_file))) { + $array['email_queue_attachments'][0]['email_queue_attachment_uuid'] = uuid(); + $array['email_queue_attachments'][0]['domain_uuid'] = $this->domain_uuid; + $array['email_queue_attachments'][0]['email_queue_uuid'] = $email_queue_uuid; + $array['email_queue_attachments'][0]['email_attachment_type'] = $voicemail_message_file_ext; + $array['email_queue_attachments'][0]['email_attachment_path'] = $voicemail_message_path; + $array['email_queue_attachments'][0]['email_attachment_name'] = $voicemail_combined_file ?? $voicemail_message_file; + $array['email_queue_attachments'][0]['email_attachment_base64'] = $message['message_combined_base64'] ?? $message['message_base64']; + $array['email_queue_attachments'][0]['email_attachment_cid'] = !empty($message['message_combined_base64']) || !empty($message['message_base64']) ? uuid() : null; + $array['email_queue_attachments'][0]['email_attachment_mime_type'] = $voicemail_message_file_mime; + $array['email_queue_attachments'][0]['insert_date'] = 'now()'; + $array['email_queue_attachments'][0]['insert_user'] = $this->user_uuid; + } + + //grant temporary permissions + $p = permissions::new(); + $p->add('email_queue_add', 'temp'); + $p->add('email_queue_attachment_add', 'temp'); + + //execute update + $this->database->save($array); + unset($array); + + //revoke temporary permissions + $p->delete('email_queue_add', 'temp'); + $p->delete('email_queue_attachment_add', 'temp'); + + //remove temp file from base64 output + if (!empty($message['message_base64']) && file_exists($voicemail_message_path . '/' . $voicemail_message_file)) { + @unlink($voicemail_message_path . '/' . $voicemail_message_file); + @unlink($voicemail_message_path . '/' . $voicemail_intro_file); + @unlink($voicemail_message_path . '/' . $voicemail_combined_file); + } + + return true; + } + + /** + * Transcribes a voicemail message + * + * @return bool True if transcription was successful, false otherwise + */ + public function message_transcribe() { + + //get the voicemail id + $this->get_voicemail_id(); + + //check if for valid input + if (!is_numeric($this->voicemail_id) + || !is_uuid($this->voicemail_uuid) + || !is_uuid($this->domain_uuid) + || !is_uuid($this->voicemail_message_uuid) + ) { + return false; + } + + //add the settings object + $settings = new settings(["domain_uuid" => $this->domain_uuid, "user_uuid" => $this->user_uuid]); + $transcribe_enabled = $settings->get('transcribe', 'enabled', false); + $transcribe_engine = $settings->get('transcribe', 'engine', ''); + $switch_voicemail = $settings->get('switch', 'voicemail', '/var/lib/freeswitch/storage/voicemail'); + + //transcribe multiple recordings + if ($transcribe_enabled && !empty($transcribe_engine)) { + + //get voicemail message base64 + $sql = "select message_base64 from v_voicemail_messages where voicemail_message_uuid = :voicemail_message_uuid "; $parameters['voicemail_message_uuid'] = $this->voicemail_message_uuid; - $message = $this->database->select($sql, $parameters, 'row'); + $voicemail_message_base64 = $this->database->select($sql, $parameters, 'column'); unset($sql, $parameters); - //retrieve appropriate email template - $sql = "select "; - $sql .= " template_subject, "; - $sql .= " template_body "; - $sql .= "from "; - $sql .= " v_email_templates "; - $sql .= "where "; - $sql .= " template_language = :template_language "; - $sql .= " and template_category = 'voicemail' "; - $sql .= " and template_subcategory = '".(!empty($message['message_transcription']) ? 'transcription' : 'default')."' "; - $sql .= " and template_type = 'html' "; - $sql .= " and template_enabled = true "; - $sql .= " and (domain_uuid = :domain_uuid or domain_uuid is null) "; - $sql .= "limit 1 "; - $parameters['template_language'] = $language_dialect; - $parameters['domain_uuid'] = $this->domain_uuid; - $template = $this->database->select($sql, $parameters, 'row'); - unset($sql, $parameters); + //define voicemail message file path + $voicemail_message_path = $switch_voicemail . '/default/' . $this->domain_name . '/' . $this->voicemail_id; - //determine formatted voicemail name - $voicemail_name_formatted = $message['voicemail_id']; - if ($display_domain_name == 'true') { - $voicemail_name_formatted = $message['voicemail_id'].'@'.$message['domain_name']; - } - if (!empty($message['voicemail_description'])) { - $voicemail_name_formatted .= ' ('.$message['voicemail_description'].')'; - } - - //replace subject variables - if (!empty($template['template_subject'])) { - $template['template_subject'] = str_replace('${caller_id_name}', $message['caller_id_name'], $template['template_subject']); - $template['template_subject'] = str_replace('${caller_id_number}', $message['caller_id_number'], $template['template_subject']); - $template['template_subject'] = str_replace('${message_date}', $message['message_date'], $template['template_subject']); - $template['template_subject'] = str_replace('${message_duration}', '0'.gmdate("G:i:s", ($message['message_length'] ?? 0)), $template['template_subject']); - $template['template_subject'] = str_replace('${account}', $voicemail_name_formatted, $template['template_subject']); - $template['template_subject'] = str_replace('${voicemail_id}', $message['voicemail_id'], $template['template_subject']); - $template['template_subject'] = str_replace('${voicemail_description}', $message['voicemail_description'], $template['template_subject']); - $template['template_subject'] = str_replace('${voicemail_name_formatted}', $voicemail_name_formatted, $template['template_subject']); - $template['template_subject'] = str_replace('${domain_name}', $message['domain_name'], $template['template_subject']); - } - else { - $template['template_subject'] = $text['label-voicemail_from'].' '.$message['caller_id_name'].' <'.$message['caller_id_number'].'> 0'.gmdate("G:i:s", ($message['message_length'] ?? 0)); - } - - //encode subject - $template['template_subject'] = trim(iconv_mime_encode('', $template['template_subject'], ['scheme'=>'B','output-charset'=>'utf-8', 'line-break-chars'=>"\n"]), ': '); - - //determine voicemail message file path and type - $voicemail_message_path = $switch_voicemail.'/default/'.$message['domain_name'].'/'.$message['voicemail_id']; + //determine voicemail message file properties (decode if base64) if ( - !empty($message['message_base64']) && - !file_exists($voicemail_message_path.'/msg_'.$message['voicemail_message_uuid'].'.wav') && - !file_exists($voicemail_message_path.'/msg_'.$message['voicemail_message_uuid'].'.mp3') - ) { - $voicemail_message_decoded = base64_decode($message['message_base64']); - file_put_contents($voicemail_message_path.'/msg_'.$message['voicemail_message_uuid'].'.ext', $voicemail_message_decoded); - $finfo = finfo_open(FILEINFO_MIME_TYPE); - $voicemail_message_file_mime = finfo_file($finfo, $voicemail_message_path.'/msg_'.$message['voicemail_message_uuid'].'.ext'); + !empty($voicemail_message_base64) && + !file_exists($voicemail_message_path . '/msg_' . $this->voicemail_message_uuid . '.wav') && + !file_exists($voicemail_message_path . '/msg_' . $this->voicemail_message_uuid . '.mp3') + ) { + $voicemail_message_decoded = base64_decode($voicemail_message_base64); + file_put_contents($voicemail_message_path . '/msg_' . $this->voicemail_message_uuid . '.ext', $voicemail_message_decoded); + $finfo = finfo_open(FILEINFO_MIME_TYPE); + $voicemail_message_file_mime = finfo_file($finfo, $voicemail_message_path . '/msg_' . $this->voicemail_message_uuid . '.ext'); finfo_close($finfo); - unset($voicemail_message_decoded); switch ($voicemail_message_file_mime) { case 'audio/x-wav': case 'audio/wav': @@ -870,680 +1161,533 @@ $voicemail_message_file_ext = 'mp3'; break; } - rename($voicemail_message_path.'/msg_'.$message['voicemail_message_uuid'].'.ext', $voicemail_message_path.'/msg_'.$message['voicemail_message_uuid'].'.'.$voicemail_message_file_ext); - $voicemail_message_file = 'msg_'.$message['voicemail_message_uuid'].'.'.$voicemail_message_file_ext; - } - else { - if (file_exists($voicemail_message_path.'/msg_'.$message['voicemail_message_uuid'].'.wav')) { $voicemail_message_file_ext = 'wav'; } - if (file_exists($voicemail_message_path.'/msg_'.$message['voicemail_message_uuid'].'.mp3')) { $voicemail_message_file_ext = 'mp3'; } - $voicemail_message_file = 'msg_'.$message['voicemail_message_uuid'].'.'.$voicemail_message_file_ext; - $voicemail_message_file_mime = mime_content_type($voicemail_message_path.'/msg_'.$message['voicemail_message_uuid'].'.'.$voicemail_message_file_ext); - } - - //determine voicemail intro file path - if ( - !empty($message['message_intro_base64']) && - !file_exists($voicemail_message_path.'/intro_'.$message['voicemail_message_uuid'].'.wav') && - !file_exists($voicemail_message_path.'/intro_'.$message['voicemail_message_uuid'].'.mp3') - ) { - $voicemail_intro_decoded = base64_decode($message['message_intro_base64']); - file_put_contents($voicemail_message_path.'/intro_'.$message['voicemail_message_uuid'].'.'.$voicemail_message_file_ext, $voicemail_intro_decoded); - $voicemail_intro_file = 'intro_'.$message['voicemail_message_uuid'].'.'.$voicemail_message_file_ext; - } - else { - $voicemail_intro_file = 'intro_'.$message['voicemail_message_uuid'].'.'.$voicemail_message_file_ext; - } - - //combine voicemail intro and message files - $sox = system('which sox'); - if (file_exists($voicemail_message_path.'/'.$voicemail_intro_file) && !empty($sox)) { - $voicemail_combined_file = 'intro_msg_'.$message['voicemail_message_uuid'].'.'.$voicemail_message_file_ext; - exec($sox.' '.$voicemail_message_path.'/'.$voicemail_intro_file.' '.$voicemail_message_path.'/'.$voicemail_message_file.' '.$voicemail_message_path.'/'.$voicemail_combined_file); - if (file_exists($voicemail_message_path.'/'.$voicemail_combined_file)) { - $message['message_combined_base64'] = base64_encode(file_get_contents($voicemail_message_path.'/'.$voicemail_combined_file)); + unset($voicemail_message_decoded, $voicemail_message_file_mime); + rename($voicemail_message_path . '/msg_' . $this->voicemail_message_uuid . '.ext', $voicemail_message_path . '/msg_' . $this->voicemail_message_uuid . '.' . $voicemail_message_file_ext); + $voicemail_message_file = 'msg_' . $this->voicemail_message_uuid . '.' . $voicemail_message_file_ext; + } else { + if (file_exists($voicemail_message_path . '/msg_' . $this->voicemail_message_uuid . '.wav')) { + $voicemail_message_file_ext = 'wav'; } + if (file_exists($voicemail_message_path . '/msg_' . $this->voicemail_message_uuid . '.mp3')) { + $voicemail_message_file_ext = 'mp3'; + } + $voicemail_message_file = 'msg_' . $this->voicemail_message_uuid . '.' . $voicemail_message_file_ext; } + unset($voicemail_message_file_ext); - //replace body variables - if (!empty($template['template_body'])) { - $template['template_body'] = str_replace('${caller_id_name}', $message['caller_id_name'], $template['template_body']); - $template['template_body'] = str_replace('${caller_id_number}', $message['caller_id_number'], $template['template_body']); - $template['template_body'] = str_replace('${message_date}', $message['message_date'], $template['template_body']); - $template['template_body'] = str_replace('${message_text}', $message['message_transcription'], $template['template_body']); - $template['template_body'] = str_replace('${message_duration}', '0'.gmdate("G:i:s", ($message['message_length'] ?? 0)), $template['template_body']); - $template['template_body'] = str_replace('${account}', $voicemail_name_formatted, $template['template_body']); - $template['template_body'] = str_replace('${voicemail_id}', $message['voicemail_id'], $template['template_body']); - $template['template_body'] = str_replace('${voicemail_description}', $message['voicemail_description'], $template['template_body']); - $template['template_body'] = str_replace('${voicemail_name_formatted}', $voicemail_name_formatted, $template['template_body']); - $template['template_body'] = str_replace('${domain_name}', $message['domain_name'], $template['template_body']); - $template['template_body'] = str_replace('${sip_to_user}', $message['voicemail_id'], $template['template_body']); - $template['template_body'] = str_replace('${dialed_user}', $message['voicemail_id'], $template['template_body']); - if (!empty($message['voicemail_file'])) { - if ($message['voicemail_file'] == 'attach' && (file_exists($voicemail_message_path.'/'.$voicemail_combined_file) || file_exists($voicemail_message_path.'/'.$voicemail_message_file))) { - $template['template_body'] = str_replace('${message}', $text['label-attached'], $template['template_body']); - } - else if ($message['voicemail_file'] == 'link') { - $template['template_body'] = str_replace('${message}', "".$text['label-download']."", $template['template_body']); - } - else { // listen - $template['template_body'] = str_replace('${message}', "".$text['label-listen']."", $template['template_body']); - } - } - } - else { - $template['template_body'] = "\n\n"; - if (!empty($message['caller_id_name']) && $message['caller_id_name'] != $message['caller_id_number']) { - $template['template_body'] .= $message['caller_id_name']."
    \n"; - } - $template['template_body'] .= $message['caller_id_number']."
    \n"; - $template['template_body'] .= $message['message_date']."
    \n"; - if (!empty($message['voicemail_file'])) { - if ($message['voicemail_file'] == 'attach' && (file_exists($voicemail_message_path.'/'.$voicemail_combined_file) || file_exists($voicemail_message_path.'/'.$voicemail_message_file))) { - $template['template_body'] .= "
    \n".$text['label-attached']; - } - else if ($message['voicemail_file'] == 'link') { - $template['template_body'] .= "
    \n".$text['label-download'].''; - } - else { // listen - $template['template_body'] .= "
    \n".$text['label-listen'].''; - } - } - $template['template_body'] .= "\n\n"; - } + //add the transcribe object + $transcribe = new transcribe($settings); - //build message status update array - $array['email_queue'][0]['email_queue_uuid'] = $email_queue_uuid = uuid(); - $array['email_queue'][0]['domain_uuid'] = $this->domain_uuid; - $array['email_queue'][0]['hostname'] = gethostname(); - $array['email_queue'][0]['email_date'] = 'now()'; - $array['email_queue'][0]['email_from'] = $email_from_name.'<'.$email_from.'>'; - $array['email_queue'][0]['email_to'] = $message['voicemail_mail_to']; - $array['email_queue'][0]['email_subject'] = $template['template_subject']; - $array['email_queue'][0]['email_body'] = $template['template_body']; - $array['email_queue'][0]['email_status'] = 'waiting'; - $array['email_queue'][0]['email_uuid'] = $this->voicemail_message_uuid; - $array['email_queue'][0]['email_transcription'] = $message['message_transcription']; - $array['email_queue'][0]['insert_date'] = 'now()'; - $array['email_queue'][0]['insert_user'] = $this->user_uuid; + //transcribe the voicemail message file + $transcribe->audio_path = $voicemail_message_path; + $transcribe->audio_filename = basename($voicemail_message_file); + $message_transcription = $transcribe->transcribe(); - //add voicemail file details (and/or base64) to queue attachments - if (!empty($message['voicemail_file']) && $message['voicemail_file'] == 'attach' && (file_exists($voicemail_message_path.'/'.$voicemail_combined_file) || file_exists($voicemail_message_path.'/'.$voicemail_message_file))) { - $array['email_queue_attachments'][0]['email_queue_attachment_uuid'] = uuid(); - $array['email_queue_attachments'][0]['domain_uuid'] = $this->domain_uuid; - $array['email_queue_attachments'][0]['email_queue_uuid'] = $email_queue_uuid; - $array['email_queue_attachments'][0]['email_attachment_type'] = $voicemail_message_file_ext; - $array['email_queue_attachments'][0]['email_attachment_path'] = $voicemail_message_path; - $array['email_queue_attachments'][0]['email_attachment_name'] = $voicemail_combined_file ?? $voicemail_message_file; - $array['email_queue_attachments'][0]['email_attachment_base64'] = $message['message_combined_base64'] ?? $message['message_base64']; - $array['email_queue_attachments'][0]['email_attachment_cid'] = !empty($message['message_combined_base64']) || !empty($message['message_base64']) ? uuid() : null; - $array['email_queue_attachments'][0]['email_attachment_mime_type'] = $voicemail_message_file_mime; - $array['email_queue_attachments'][0]['insert_date'] = 'now()'; - $array['email_queue_attachments'][0]['insert_user'] = $this->user_uuid; - } - - //grant temporary permissions - $p = permissions::new(); - $p->add('email_queue_add', 'temp'); - $p->add('email_queue_attachment_add', 'temp'); - - //execute update - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('email_queue_add', 'temp'); - $p->delete('email_queue_attachment_add', 'temp'); - - //remove temp file from base64 output - if (!empty($message['message_base64']) && file_exists($voicemail_message_path.'/'.$voicemail_message_file)) { - @unlink($voicemail_message_path.'/'.$voicemail_message_file); - @unlink($voicemail_message_path.'/'.$voicemail_intro_file); - @unlink($voicemail_message_path.'/'.$voicemail_combined_file); - } - - } - - public function message_transcribe() { - - //get the voicemail id - $this->get_voicemail_id(); - - //check if for valid input - if (!is_numeric($this->voicemail_id) - || !is_uuid($this->voicemail_uuid) - || !is_uuid($this->domain_uuid) - || !is_uuid($this->voicemail_message_uuid) - ) { - return false; - } - - //add the settings object - $settings = new settings(["domain_uuid" => $this->domain_uuid, "user_uuid" => $this->user_uuid]); - $transcribe_enabled = $settings->get('transcribe', 'enabled', false); - $transcribe_engine = $settings->get('transcribe', 'engine', ''); - $switch_voicemail = $settings->get('switch', 'voicemail', '/var/lib/freeswitch/storage/voicemail'); - - //transcribe multiple recordings - if ($transcribe_enabled && !empty($transcribe_engine)) { - - //get voicemail message base64 - $sql = "select message_base64 from v_voicemail_messages where voicemail_message_uuid = :voicemail_message_uuid "; - $parameters['voicemail_message_uuid'] = $this->voicemail_message_uuid; - $voicemail_message_base64 = $this->database->select($sql, $parameters, 'column'); - unset($sql, $parameters); - - //define voicemail message file path - $voicemail_message_path = $switch_voicemail.'/default/'.$this->domain_name.'/'.$this->voicemail_id; - - //determine voicemail message file properties (decode if base64) - if ( - !empty($voicemail_message_base64) && - !file_exists($voicemail_message_path.'/msg_'.$this->voicemail_message_uuid.'.wav') && - !file_exists($voicemail_message_path.'/msg_'.$this->voicemail_message_uuid.'.mp3') - ) { - $voicemail_message_decoded = base64_decode($voicemail_message_base64); - file_put_contents($voicemail_message_path.'/msg_'.$this->voicemail_message_uuid.'.ext', $voicemail_message_decoded); - $finfo = finfo_open(FILEINFO_MIME_TYPE); - $voicemail_message_file_mime = finfo_file($finfo, $voicemail_message_path.'/msg_'.$this->voicemail_message_uuid.'.ext'); - finfo_close($finfo); - switch ($voicemail_message_file_mime) { - case 'audio/x-wav': - case 'audio/wav': - $voicemail_message_file_ext = 'wav'; - break; - case 'audio/mpeg': - case 'audio/mp3': - $voicemail_message_file_ext = 'mp3'; - break; - } - unset($voicemail_message_decoded, $voicemail_message_file_mime); - rename($voicemail_message_path.'/msg_'.$this->voicemail_message_uuid.'.ext', $voicemail_message_path.'/msg_'.$this->voicemail_message_uuid.'.'.$voicemail_message_file_ext); - $voicemail_message_file = 'msg_'.$this->voicemail_message_uuid.'.'.$voicemail_message_file_ext; - } - else { - if (file_exists($voicemail_message_path.'/msg_'.$this->voicemail_message_uuid.'.wav')) { $voicemail_message_file_ext = 'wav'; } - if (file_exists($voicemail_message_path.'/msg_'.$this->voicemail_message_uuid.'.mp3')) { $voicemail_message_file_ext = 'mp3'; } - $voicemail_message_file = 'msg_'.$this->voicemail_message_uuid.'.'.$voicemail_message_file_ext; - } - unset($voicemail_message_file_ext); - - //add the transcribe object - $transcribe = new transcribe($settings); - - //transcribe the voicemail message file - $transcribe->audio_path = $voicemail_message_path; - $transcribe->audio_filename = basename($voicemail_message_file); - $message_transcription = $transcribe->transcribe(); - - //build voicemail message data array - if (!empty($message_transcription)) { - $array['voicemail_messages'][0]['voicemail_message_uuid'] = $this->voicemail_message_uuid; - $array['voicemail_messages'][0]['message_transcription'] = $message_transcription; - } - - //update the checked rows - if (is_array($array) && @sizeof($array) != 0) { - - //grant temporary permissions - $p = permissions::new(); - $p->add('voicemail_message_edit', 'temp'); - - //execute update - $this->database->save($array); - unset($array); - - //revoke temporary permissions - $p->delete('voicemail_message_edit', 'temp'); - - } - - //remove temp file from base64 output - if (!empty($voicemail_message_base64) && file_exists($voicemail_message_path.'/'.$voicemail_message_file)) { - @unlink($voicemail_message_path.'/'.$voicemail_message_file); - } - - return !empty($message_transcription) ? true : false; - - } - - } - - public function message_saved() { - - //check if for valid input - if (!is_uuid($this->voicemail_uuid) - || !is_uuid($this->domain_uuid) - || !is_uuid($this->voicemail_message_uuid) - ) { - return false; - } - - //build message status update array + //build voicemail message data array + if (!empty($message_transcription)) { $array['voicemail_messages'][0]['voicemail_message_uuid'] = $this->voicemail_message_uuid; - $array['voicemail_messages'][0]['message_status'] = 'saved'; + $array['voicemail_messages'][0]['message_transcription'] = $message_transcription; + } - //grant temporary permissions + //update the checked rows + if (is_array($array) && @sizeof($array) != 0) { + + //grant temporary permissions $p = permissions::new(); $p->add('voicemail_message_edit', 'temp'); - //execute update + //execute update $this->database->save($array); unset($array); - //revoke temporary permissions + //revoke temporary permissions $p->delete('voicemail_message_edit', 'temp'); - //check the message waiting status - $this->message_waiting(); - } - - /** - * download the voicemail message intro - * @param string domain_name if domain name is not passed, then will be used from the session variable (if available) to generate the voicemail file path - */ - public function message_intro_download(string $domain_name = '') { - - //check domain name - $domain_name = $this->domain_name; - - //check if for valid input - if (!is_numeric($this->voicemail_id) - || !is_uuid($this->voicemail_uuid) - || !is_uuid($this->domain_uuid) - || !is_uuid($this->voicemail_message_uuid) - ) { - return false; } - //change the message status - $this->message_saved(); - - //set source folder path - $path = realpath($this->settings->get('switch','voicemail','/var/lib/freeswitch/storage/voicemail').'/default/'.$domain_name).'/'.$this->voicemail_id; - - //prepare base64 content from the database, if enabled - if ($this->settings->get('voicemail','storage_type','') == 'base64') { - $sql = "select message_intro_base64 "; - $sql .= "from "; - $sql .= "v_voicemail_messages as m, "; - $sql .= "v_voicemails as v "; - $sql .= "where "; - $sql .= "m.voicemail_uuid = v.voicemail_uuid "; - $sql .= "and v.voicemail_id = :voicemail_id "; - $sql .= "and m.voicemail_uuid = :voicemail_uuid "; - $sql .= "and m.domain_uuid = :domain_uuid "; - $sql .= "and m.voicemail_message_uuid = :voicemail_message_uuid "; - $parameters['voicemail_id'] = $this->voicemail_id; - $parameters['voicemail_uuid'] = $this->voicemail_uuid; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['voicemail_message_uuid'] = $this->voicemail_message_uuid; - $message_intro_base64 = $this->database->select($sql, $parameters, 'column'); - if ($message_intro_base64 != '') { - $message_intro_decoded = base64_decode($message_intro_base64); - $file_ext = $this->settings->get('voicemail','file_ext','mp3'); - file_put_contents($path.'/intro_'.$this->voicemail_message_uuid.'.'.$file_ext, $message_intro_decoded); - } - unset($sql, $parameters, $message_intro_base64, $message_intro_decoded); + //remove temp file from base64 output + if (!empty($voicemail_message_base64) && file_exists($voicemail_message_path . '/' . $voicemail_message_file)) { + @unlink($voicemail_message_path . '/' . $voicemail_message_file); } - //prepare and stream the file - if (file_exists($path.'/intro_'.$this->voicemail_message_uuid.'.wav')) { - $file_path = $path.'/intro_'.$this->voicemail_message_uuid.'.wav'; - } - else if (file_exists($path.'/intro_'.$this->voicemail_message_uuid.'.mp3')) { - $file_path = $path.'/intro_'.$this->voicemail_message_uuid.'.mp3'; - } - else { - return false; - } - - if (empty($file_path)) { - return false; - } - - $fd = fopen($file_path, "rb"); - if ($this->type == 'bin') { - header("Content-Type: application/force-download"); - header("Content-Type: application/octet-stream"); - header("Content-Type: application/download"); - header("Content-Description: File Transfer"); - $file_ext = pathinfo($file_path, PATHINFO_EXTENSION); - switch ($file_ext) { - case "wav": header('Content-Disposition: attachment; filename="intro_'.$this->voicemail_message_uuid.'.wav"'); break; - case "mp3": header('Content-Disposition: attachment; filename="intro_'.$this->voicemail_message_uuid.'.mp3"'); break; - case "ogg": header('Content-Disposition: attachment; filename="intro_'.$this->voicemail_message_uuid.'.ogg"'); break; - } - } - else { - $file_ext = pathinfo($file_path, PATHINFO_EXTENSION); - switch ($file_ext) { - case "wav": header("Content-Type: audio/x-wav"); break; - case "mp3": header("Content-Type: audio/mpeg"); break; - case "ogg": header("Content-Type: audio/ogg"); break; - } - } - header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 - header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // date in the past - if ($this->type == 'bin') { - header("Content-Length: ".filesize($file_path)); - } - ob_end_clean(); - - //content-range - if (isset($_SERVER['HTTP_RANGE']) && $this->type != 'bin') { - $this->range_download($file_path); - } - - fpassthru($fd); - - //if base64, remove temp file - if ($this->settings->get('voicemail','storage_type','') == 'base64') { - @unlink($path.'/intro_'.$this->voicemail_message_uuid.'.'.$file_ext); - } + return !empty($message_transcription) ? true : false; } - /** - * download the voicemail message - * @param string domain_name if domain name is not passed, then will be used from the session variable (if available) to generate the voicemail file path - */ - public function message_download(string $domain_name = '') { + return false; + } - //check domain name - $domain_name = $this->domain_name ?? ''; - - //check if for valid input - if (!is_numeric($this->voicemail_id) - || !is_uuid($this->voicemail_uuid) - || !is_uuid($this->domain_uuid) - || !is_uuid($this->voicemail_message_uuid) - ) { - return false; - } - - //change the message status - $this->message_saved(); - - //set source folder path - $path = realpath($this->settings->get('switch','voicemail','/var/lib/freeswitch/storage/voicemail').'/default/'.$domain_name).'/'.$this->voicemail_id; - - //prepare base64 content from the database, if enabled - if ($this->settings->get('voicemail','storage_type','') == 'base64') { - $sql = "select message_base64 "; - $sql .= "from "; - $sql .= "v_voicemail_messages as m, "; - $sql .= "v_voicemails as v "; - $sql .= "where "; - $sql .= "m.voicemail_uuid = v.voicemail_uuid "; - $sql .= "and v.voicemail_id = :voicemail_id "; - $sql .= "and m.voicemail_uuid = :voicemail_uuid "; - $sql .= "and m.domain_uuid = :domain_uuid "; - $sql .= "and m.voicemail_message_uuid = :voicemail_message_uuid "; - $parameters['voicemail_id'] = $this->voicemail_id; - $parameters['voicemail_uuid'] = $this->voicemail_uuid; - $parameters['domain_uuid'] = $this->domain_uuid; - $parameters['voicemail_message_uuid'] = $this->voicemail_message_uuid; - $message_base64 = $this->database->select($sql, $parameters, 'column'); - if ($message_base64 != '') { - $message_decoded = base64_decode($message_base64); - $file_ext = $this->settings->get('voicemail','file_ext','mp3'); - file_put_contents($path.'/msg_'.$this->voicemail_message_uuid.'.'.$file_ext, $message_decoded); - } - unset($sql, $parameters, $message_base64, $message_decoded); - } - - //prepare and stream the file - if (file_exists($path.'/msg_'.$this->voicemail_message_uuid.'.wav')) { - $file_path = $path.'/msg_'.$this->voicemail_message_uuid.'.wav'; - } - else if (file_exists($path.'/msg_'.$this->voicemail_message_uuid.'.mp3')) { - $file_path = $path.'/msg_'.$this->voicemail_message_uuid.'.mp3'; - } - else { - return false; - } - - if (empty($file_path)) { - return false; - } - - $fd = fopen($file_path, "rb"); - if ($this->type == 'bin') { - header("Content-Type: application/force-download"); - header("Content-Type: application/octet-stream"); - header("Content-Type: application/download"); - header("Content-Description: File Transfer"); - $file_ext = pathinfo($file_path, PATHINFO_EXTENSION); - switch ($file_ext) { - case "wav": header('Content-Disposition: attachment; filename="msg_'.$this->voicemail_message_uuid.'.wav"'); break; - case "mp3": header('Content-Disposition: attachment; filename="msg_'.$this->voicemail_message_uuid.'.mp3"'); break; - case "ogg": header('Content-Disposition: attachment; filename="msg_'.$this->voicemail_message_uuid.'.ogg"'); break; - } - } - else { - $file_ext = pathinfo($file_path, PATHINFO_EXTENSION); - switch ($file_ext) { - case "wav": header("Content-Type: audio/x-wav"); break; - case "mp3": header("Content-Type: audio/mpeg"); break; - case "ogg": header("Content-Type: audio/ogg"); break; - } - } - header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 - header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // date in the past - if ($this->type == 'bin') { - header("Content-Length: ".filesize($file_path)); - } - ob_end_clean(); - - //content-range - if (isset($_SERVER['HTTP_RANGE']) && $this->type != 'bin') { - $this->range_download($file_path); - } - - fpassthru($fd); - - //if base64, remove temp file - if ($this->settings->get('voicemail','storage_type','') == 'base64') { - @unlink($path.'/msg_'.$this->voicemail_message_uuid.'.'.$file_ext); - } + /** + * Update message status to 'saved' in database. + * + * @return bool true if update is successful, false otherwise. + */ + public function message_saved() { + //check if for valid input + if (!is_uuid($this->voicemail_uuid) + || !is_uuid($this->domain_uuid) + || !is_uuid($this->voicemail_message_uuid) + ) { + return false; } - /* - * range download method (helps safari play audio sources) - */ - private function range_download($file) { - $esl = @fopen($file, 'rb'); + //build message status update array + $array['voicemail_messages'][0]['voicemail_message_uuid'] = $this->voicemail_message_uuid; + $array['voicemail_messages'][0]['message_status'] = 'saved'; - $size = filesize($file); // File size - $length = $size; // Content length - $start = 0; // Start byte - $end = $size - 1; // End byte - // Now that we've gotten so far without errors we send the accept range header - /* At the moment we only support single ranges. - * Multiple ranges requires some more work to ensure it works correctly - * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 - * - * Multirange support annouces itself with: - * header('Accept-Ranges: bytes'); - * - * Multirange content must be sent with multipart/byteranges mediatype, - * (mediatype = mimetype) - * as well as a boundry header to indicate the various chunks of data. - */ - header("Accept-Ranges: 0-$length"); - // header('Accept-Ranges: bytes'); - // multipart/byteranges - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 - if (isset($_SERVER['HTTP_RANGE'])) { + //grant temporary permissions + $p = permissions::new(); + $p->add('voicemail_message_edit', 'temp'); - $c_start = $start; - $c_end = $end; - // Extract the range string - list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2); - // Make sure the client hasn't sent us a multibyte range - if (strpos($range, ',') !== false) { - // (?) Shoud this be issued here, or should the first - // range be used? Or should the header be ignored and - // we output the whole content? - header('HTTP/1.1 416 Requested Range Not Satisfiable'); - header("Content-Range: bytes $start-$end/$size"); - // (?) Echo some info to the client? - exit; - } - // If the range starts with an '-' we start from the beginning - // If not, we forward the file pointer - // And make sure to get the end byte if spesified - if (!empty($range0) && $range0 == '-') { - // The n-number of the last bytes is requested - $c_start = $size - substr($range, 1); - } - else { - $range = explode('-', $range); - $c_start = $range[0]; - $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size; - } - /* Check the range and make sure it's treated according to the specs. - * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - */ - // End bytes can not be larger than $end. - $c_end = ($c_end > $end) ? $end : $c_end; - // Validate the requested range and return an error if it's not correct. - if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) { + //execute update + $this->database->save($array); + unset($array); - header('HTTP/1.1 416 Requested Range Not Satisfiable'); - header("Content-Range: bytes $start-$end/$size"); - // (?) Echo some info to the client? - exit; - } - $start = $c_start; - $end = $c_end; - $length = $end - $start + 1; // Calculate new content length - fseek($esl, $start); - header('HTTP/1.1 206 Partial Content'); - } - // Notify the client the byte range we'll be outputting - header("Content-Range: bytes $start-$end/$size"); - header("Content-Length: $length"); + //revoke temporary permissions + $p->delete('voicemail_message_edit', 'temp'); - // Start buffered download - $buffer = 1024 * 8; - while(!feof($esl) && ($p = ftell($esl)) <= $end) { - if ($p + $buffer > $end) { - // In case we're only outputtin a chunk, make sure we don't - // read past the length - $buffer = $end - $p + 1; - } - set_time_limit(0); // Reset time limit for big files - echo fread($esl, $buffer); - flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit. - } + //check the message waiting status + $this->message_waiting(); + } + /** + * download the voicemail message intro + * + * @param string domain_name if domain name is not passed, then will be used from the session variable (if + * available) to generate the voicemail file path + */ + public function message_intro_download(string $domain_name = '') { + + //check domain name + $domain_name = $this->domain_name; + + //check if for valid input + if (!is_numeric($this->voicemail_id) + || !is_uuid($this->voicemail_uuid) + || !is_uuid($this->domain_uuid) + || !is_uuid($this->voicemail_message_uuid) + ) { + return false; } - /** - * Removes old entries for in the database voicemails table - * see {@link https://github.com/fusionpbx/fusionpbx-app-maintenance/} FusionPBX Maintenance App - * @param settings $settings Settings object - * @return void - */ - public static function database_maintenance(settings $settings): void { - //set table name for query - //$table = self::TABLE; - $table = 'voicemail_messages'; - $database = $settings->database(); + //change the message status + $this->message_saved(); - //get a list of domains - $domains = maintenance::get_domains($database); - foreach ($domains as $domain_uuid => $domain_name) { - //get domain settings - $domain_settings = new settings(['database' => $database, 'domain_uuid' => $domain_uuid]); + //set source folder path + $path = realpath($this->settings->get('switch', 'voicemail', '/var/lib/freeswitch/storage/voicemail') . '/default/' . $domain_name) . '/' . $this->voicemail_id; - //ensure we have a retention day - $retention_days = $domain_settings->get('voicemail', maintenance::DATABASE_SUBCATEGORY, ''); - if (!empty($retention_days) && is_numeric($retention_days)) { - //clear out old records - $sql = "delete from v_{$table} WHERE to_timestamp(created_epoch) < NOW() - INTERVAL '{$retention_days} days'" - . " and domain_uuid = '{$domain_uuid}'"; - $database->execute($sql); - $code = $database->message['code'] ?? 0; - if ($database->message['code'] == 200) { - maintenance_service::log_write(self::class, "Successfully removed entries older than $retention_days", $domain_uuid); - } else { - $message = $database->message['message'] ?? "An unknown error has occurred"; - maintenance_service::log_write(self::class, "Unable to remove old database records. Error message: $message ($code)", $domain_uuid, maintenance_service::LOG_ERROR); - } - } + //prepare base64 content from the database, if enabled + if ($this->settings->get('voicemail', 'storage_type', '') == 'base64') { + $sql = "select message_intro_base64 "; + $sql .= "from "; + $sql .= "v_voicemail_messages as m, "; + $sql .= "v_voicemails as v "; + $sql .= "where "; + $sql .= "m.voicemail_uuid = v.voicemail_uuid "; + $sql .= "and v.voicemail_id = :voicemail_id "; + $sql .= "and m.voicemail_uuid = :voicemail_uuid "; + $sql .= "and m.domain_uuid = :domain_uuid "; + $sql .= "and m.voicemail_message_uuid = :voicemail_message_uuid "; + $parameters['voicemail_id'] = $this->voicemail_id; + $parameters['voicemail_uuid'] = $this->voicemail_uuid; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['voicemail_message_uuid'] = $this->voicemail_message_uuid; + $message_intro_base64 = $this->database->select($sql, $parameters, 'column'); + if ($message_intro_base64 != '') { + $message_intro_decoded = base64_decode($message_intro_base64); + $file_ext = $this->settings->get('voicemail', 'file_ext', 'mp3'); + file_put_contents($path . '/intro_' . $this->voicemail_message_uuid . '.' . $file_ext, $message_intro_decoded); } - - //ensure logs are saved - maintenance_service::log_flush(); + unset($sql, $parameters, $message_intro_base64, $message_intro_decoded); } - /** - * Called by the maintenance system to remove old files - * @param settings $settings Settings object - */ - public static function filesystem_maintenance(settings $settings): void { - //get a list of domains - $domains = maintenance::get_domains($settings->database()); + //prepare and stream the file + if (file_exists($path . '/intro_' . $this->voicemail_message_uuid . '.wav')) { + $file_path = $path . '/intro_' . $this->voicemail_message_uuid . '.wav'; + } elseif (file_exists($path . '/intro_' . $this->voicemail_message_uuid . '.mp3')) { + $file_path = $path . '/intro_' . $this->voicemail_message_uuid . '.mp3'; + } else { + return false; + } - //loop through domains to handle domains with different defaults - foreach ($domains as $domain_uuid => $domain_name) { + if (empty($file_path)) { + return false; + } - //get settings for this domain - $domain_settings = new settings(['database' => $settings->database(), 'domain_uuid' => $domain_uuid]); - - //get the switch voicemail location - $voicemail_location = $domain_settings->get('switch', 'voicemail', '/var/lib/freeswitch/storage/voicemail') . '/default'; - - //get the filesystem retention days - $retention_days = $domain_settings->get('voicemail', maintenance::FILESYSTEM_SUBCATEGORY, ''); - if (!empty($retention_days)) { - - //get all wav and mp3 voicemail files - $mp3_files = glob("$voicemail_location/$domain_name/*/msg_*.mp3"); - $wav_files = glob("$voicemail_location/$domain_name/*/msg_*.wav"); - $mp3_intro_files = glob("$voicemail_location/$domain_name/*/intro_*.mp3"); - $wav_intro_files = glob("$voicemail_location/$domain_name/*/intro_*.wav"); - $domain_voicemail_files = array_merge($mp3_files, $wav_files, $mp3_intro_files, $wav_intro_files); - - //delete individually - foreach ($domain_voicemail_files as $file) { - - //check modified date on file - if (maintenance_service::days_since_modified($file) > $retention_days) { - - //date is older so remove - if (unlink($file)) { - //successfully deleted - maintenance_service::log_write(self::class, "Removed $file from voicemails", $domain_uuid); - } else { - //failed to delete file - maintenance_service::log_write(self::class, "Unable to remove $file", $domain_uuid, maintenance_service::LOG_ERROR); - } - } - } - } - else { - //log retention days not valid - maintenance_service::log_write(self::class, "Retention days not set or not a valid number", $domain_uuid, maintenance_service::LOG_ERROR); - } + $fd = fopen($file_path, "rb"); + if ($this->type == 'bin') { + header("Content-Type: application/force-download"); + header("Content-Type: application/octet-stream"); + header("Content-Type: application/download"); + header("Content-Description: File Transfer"); + $file_ext = pathinfo($file_path, PATHINFO_EXTENSION); + switch ($file_ext) { + case "wav": + header('Content-Disposition: attachment; filename="intro_' . $this->voicemail_message_uuid . '.wav"'); + break; + case "mp3": + header('Content-Disposition: attachment; filename="intro_' . $this->voicemail_message_uuid . '.mp3"'); + break; + case "ogg": + header('Content-Disposition: attachment; filename="intro_' . $this->voicemail_message_uuid . '.ogg"'); + break; } + } else { + $file_ext = pathinfo($file_path, PATHINFO_EXTENSION); + switch ($file_ext) { + case "wav": + header("Content-Type: audio/x-wav"); + break; + case "mp3": + header("Content-Type: audio/mpeg"); + break; + case "ogg": + header("Content-Type: audio/ogg"); + break; + } + } + header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 + header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // date in the past + if ($this->type == 'bin') { + header("Content-Length: " . filesize($file_path)); + } + ob_end_clean(); - //ensure logs are saved - maintenance_service::log_flush(); + //content-range + if (isset($_SERVER['HTTP_RANGE']) && $this->type != 'bin') { + $this->range_download($file_path); + } + + fpassthru($fd); + + //if base64, remove temp file + if ($this->settings->get('voicemail', 'storage_type', '') == 'base64') { + @unlink($path . '/intro_' . $this->voicemail_message_uuid . '.' . $file_ext); } } + /** + * download the voicemail message + * + * @param string domain_name if domain name is not passed, then will be used from the session variable (if + * available) to generate the voicemail file path + */ + public function message_download(string $domain_name = '') { + + //check domain name + $domain_name = $this->domain_name ?? ''; + + //check if for valid input + if (!is_numeric($this->voicemail_id) + || !is_uuid($this->voicemail_uuid) + || !is_uuid($this->domain_uuid) + || !is_uuid($this->voicemail_message_uuid) + ) { + return false; + } + + //change the message status + $this->message_saved(); + + //set source folder path + $path = realpath($this->settings->get('switch', 'voicemail', '/var/lib/freeswitch/storage/voicemail') . '/default/' . $domain_name) . '/' . $this->voicemail_id; + + //prepare base64 content from the database, if enabled + if ($this->settings->get('voicemail', 'storage_type', '') == 'base64') { + $sql = "select message_base64 "; + $sql .= "from "; + $sql .= "v_voicemail_messages as m, "; + $sql .= "v_voicemails as v "; + $sql .= "where "; + $sql .= "m.voicemail_uuid = v.voicemail_uuid "; + $sql .= "and v.voicemail_id = :voicemail_id "; + $sql .= "and m.voicemail_uuid = :voicemail_uuid "; + $sql .= "and m.domain_uuid = :domain_uuid "; + $sql .= "and m.voicemail_message_uuid = :voicemail_message_uuid "; + $parameters['voicemail_id'] = $this->voicemail_id; + $parameters['voicemail_uuid'] = $this->voicemail_uuid; + $parameters['domain_uuid'] = $this->domain_uuid; + $parameters['voicemail_message_uuid'] = $this->voicemail_message_uuid; + $message_base64 = $this->database->select($sql, $parameters, 'column'); + if ($message_base64 != '') { + $message_decoded = base64_decode($message_base64); + $file_ext = $this->settings->get('voicemail', 'file_ext', 'mp3'); + file_put_contents($path . '/msg_' . $this->voicemail_message_uuid . '.' . $file_ext, $message_decoded); + } + unset($sql, $parameters, $message_base64, $message_decoded); + } + + //prepare and stream the file + if (file_exists($path . '/msg_' . $this->voicemail_message_uuid . '.wav')) { + $file_path = $path . '/msg_' . $this->voicemail_message_uuid . '.wav'; + } elseif (file_exists($path . '/msg_' . $this->voicemail_message_uuid . '.mp3')) { + $file_path = $path . '/msg_' . $this->voicemail_message_uuid . '.mp3'; + } else { + return false; + } + + if (empty($file_path)) { + return false; + } + + $fd = fopen($file_path, "rb"); + if ($this->type == 'bin') { + header("Content-Type: application/force-download"); + header("Content-Type: application/octet-stream"); + header("Content-Type: application/download"); + header("Content-Description: File Transfer"); + $file_ext = pathinfo($file_path, PATHINFO_EXTENSION); + switch ($file_ext) { + case "wav": + header('Content-Disposition: attachment; filename="msg_' . $this->voicemail_message_uuid . '.wav"'); + break; + case "mp3": + header('Content-Disposition: attachment; filename="msg_' . $this->voicemail_message_uuid . '.mp3"'); + break; + case "ogg": + header('Content-Disposition: attachment; filename="msg_' . $this->voicemail_message_uuid . '.ogg"'); + break; + } + } else { + $file_ext = pathinfo($file_path, PATHINFO_EXTENSION); + switch ($file_ext) { + case "wav": + header("Content-Type: audio/x-wav"); + break; + case "mp3": + header("Content-Type: audio/mpeg"); + break; + case "ogg": + header("Content-Type: audio/ogg"); + break; + } + } + header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 + header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // date in the past + if ($this->type == 'bin') { + header("Content-Length: " . filesize($file_path)); + } + ob_end_clean(); + + //content-range + if (isset($_SERVER['HTTP_RANGE']) && $this->type != 'bin') { + $this->range_download($file_path); + } + + fpassthru($fd); + + //if base64, remove temp file + if ($this->settings->get('voicemail', 'storage_type', '') == 'base64') { + @unlink($path . '/msg_' . $this->voicemail_message_uuid . '.' . $file_ext); + } + + } + + /* + * range download method (helps safari play audio sources) + */ + /** + * Downloads the specified file in range mode. + * + * @param string $file The path to the file to be downloaded. + */ + private function range_download($file) { + $esl = @fopen($file, 'rb'); + + $size = filesize($file); // File size + $length = $size; // Content length + $start = 0; // Start byte + $end = $size - 1; // End byte + // Now that we've gotten so far without errors we send the accept range header + /* At the moment we only support single ranges. + * Multiple ranges requires some more work to ensure it works correctly + * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 + * + * Multirange support annouces itself with: + * header('Accept-Ranges: bytes'); + * + * Multirange content must be sent with multipart/byteranges mediatype, + * (mediatype = mimetype) + * as well as a boundry header to indicate the various chunks of data. + */ + header("Accept-Ranges: 0-$length"); + // header('Accept-Ranges: bytes'); + // multipart/byteranges + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 + if (isset($_SERVER['HTTP_RANGE'])) { + + $c_start = $start; + $c_end = $end; + // Extract the range string + [, $range] = explode('=', $_SERVER['HTTP_RANGE'], 2); + // Make sure the client hasn't sent us a multibyte range + if (strpos($range, ',') !== false) { + // (?) Shoud this be issued here, or should the first + // range be used? Or should the header be ignored and + // we output the whole content? + header('HTTP/1.1 416 Requested Range Not Satisfiable'); + header("Content-Range: bytes $start-$end/$size"); + // (?) Echo some info to the client? + exit; + } + // If the range starts with an '-' we start from the beginning + // If not, we forward the file pointer + // And make sure to get the end byte if spesified + if (!empty($range0) && $range0 == '-') { + // The n-number of the last bytes is requested + $c_start = $size - substr($range, 1); + } else { + $range = explode('-', $range); + $c_start = $range[0]; + $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size; + } + /* Check the range and make sure it's treated according to the specs. + * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + */ + // End bytes can not be larger than $end. + $c_end = ($c_end > $end) ? $end : $c_end; + // Validate the requested range and return an error if it's not correct. + if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) { + + header('HTTP/1.1 416 Requested Range Not Satisfiable'); + header("Content-Range: bytes $start-$end/$size"); + // (?) Echo some info to the client? + exit; + } + $start = $c_start; + $end = $c_end; + $length = $end - $start + 1; // Calculate new content length + fseek($esl, $start); + header('HTTP/1.1 206 Partial Content'); + } + // Notify the client the byte range we'll be outputting + header("Content-Range: bytes $start-$end/$size"); + header("Content-Length: $length"); + + // Start buffered download + $buffer = 1024 * 8; + while (!feof($esl) && ($p = ftell($esl)) <= $end) { + if ($p + $buffer > $end) { + // In case we're only outputtin a chunk, make sure we don't + // read past the length + $buffer = $end - $p + 1; + } + set_time_limit(0); // Reset time limit for big files + echo fread($esl, $buffer); + flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit. + } + + } + + /** + * Removes old entries for in the database voicemails table + * see {@link https://github.com/fusionpbx/fusionpbx-app-maintenance/} FusionPBX Maintenance App + * + * @param settings $settings Settings object + * + * @return void + */ + public static function database_maintenance(settings $settings): void { + //set table name for query + //$table = self::TABLE; + $table = 'voicemail_messages'; + $database = $settings->database(); + + //get a list of domains + $domains = maintenance::get_domains($database); + foreach ($domains as $domain_uuid => $domain_name) { + //get domain settings + $domain_settings = new settings(['database' => $database, 'domain_uuid' => $domain_uuid]); + + //ensure we have a retention day + $retention_days = $domain_settings->get('voicemail', maintenance::DATABASE_SUBCATEGORY, ''); + if (!empty($retention_days) && is_numeric($retention_days)) { + //clear out old records + $sql = "delete from v_{$table} WHERE to_timestamp(created_epoch) < NOW() - INTERVAL '{$retention_days} days'" + . " and domain_uuid = '{$domain_uuid}'"; + $database->execute($sql); + $code = $database->message['code'] ?? 0; + if ($database->message['code'] == 200) { + maintenance_service::log_write(self::class, "Successfully removed entries older than $retention_days", $domain_uuid); + } else { + $message = $database->message['message'] ?? "An unknown error has occurred"; + maintenance_service::log_write(self::class, "Unable to remove old database records. Error message: $message ($code)", $domain_uuid, maintenance_service::LOG_ERROR); + } + } + } + + //ensure logs are saved + maintenance_service::log_flush(); + } + + /** + * Called by the maintenance system to remove old files + * + * @param settings $settings Settings object + * + * @return void + */ + public static function filesystem_maintenance(settings $settings): void { + //get a list of domains + $domains = maintenance::get_domains($settings->database()); + + //loop through domains to handle domains with different defaults + foreach ($domains as $domain_uuid => $domain_name) { + + //get settings for this domain + $domain_settings = new settings(['database' => $settings->database(), 'domain_uuid' => $domain_uuid]); + + //get the switch voicemail location + $voicemail_location = $domain_settings->get('switch', 'voicemail', '/var/lib/freeswitch/storage/voicemail') . '/default'; + + //get the filesystem retention days + $retention_days = $domain_settings->get('voicemail', maintenance::FILESYSTEM_SUBCATEGORY, ''); + if (!empty($retention_days)) { + + //get all wav and mp3 voicemail files + $mp3_files = glob("$voicemail_location/$domain_name/*/msg_*.mp3"); + $wav_files = glob("$voicemail_location/$domain_name/*/msg_*.wav"); + $mp3_intro_files = glob("$voicemail_location/$domain_name/*/intro_*.mp3"); + $wav_intro_files = glob("$voicemail_location/$domain_name/*/intro_*.wav"); + $domain_voicemail_files = array_merge($mp3_files, $wav_files, $mp3_intro_files, $wav_intro_files); + + //delete individually + foreach ($domain_voicemail_files as $file) { + + //check modified date on file + if (maintenance_service::days_since_modified($file) > $retention_days) { + + //date is older so remove + if (unlink($file)) { + //successfully deleted + maintenance_service::log_write(self::class, "Removed $file from voicemails", $domain_uuid); + } else { + //failed to delete file + maintenance_service::log_write(self::class, "Unable to remove $file", $domain_uuid, maintenance_service::LOG_ERROR); + } + } + } + } else { + //log retention days not valid + maintenance_service::log_write(self::class, "Retention days not set or not a valid number", $domain_uuid, maintenance_service::LOG_ERROR); + } + } + + //ensure logs are saved + maintenance_service::log_flush(); + } + +} + //example voicemail messages - //$voicemail = new voicemail; - //$voicemail->voicemail_uuid = $voicemail_uuid; - //$voicemail->order_by = $order_by; - //$voicemail->order = $order; - //$result = $voicemail->messages(); - //$result_count = count($result); +//$voicemail = new voicemail; +//$voicemail->voicemail_uuid = $voicemail_uuid; +//$voicemail->order_by = $order_by; +//$voicemail->order = $order; +//$result = $voicemail->messages(); +//$result_count = count($result); /* Array diff --git a/app/voicemails/voicemail_export.php b/app/voicemails/voicemail_export.php index db0af73f1a..a04993db77 100644 --- a/app/voicemails/voicemail_export.php +++ b/app/voicemails/voicemail_export.php @@ -61,6 +61,13 @@ $available_columns[] = 'voicemail_tutorial'; //define the functions + /** + * Converts a 2D array into a CSV string. + * + * @param array &$array The input array to convert. Each inner array represents a row in the CSV output. + * + * @return string|null The CSV data as a string, or null if the input array is empty. + */ function array2csv(array &$array) { if (count($array) == 0) { return null; @@ -75,6 +82,13 @@ return ob_get_clean(); } + /** + * Sends HTTP headers to initiate a file download. + * + * @param string $filename The name of the file to be downloaded. + * + * @return void + */ function download_send_headers($filename) { // disable caching $now = gmdate("D, d M Y H:i:s"); diff --git a/app/voicemails/voicemail_imports.php b/app/voicemails/voicemail_imports.php index f8c8a28898..38262d6fa3 100644 --- a/app/voicemails/voicemail_imports.php +++ b/app/voicemails/voicemail_imports.php @@ -38,18 +38,6 @@ $language = new text; $text = $language->get(); -//built in str_getcsv requires PHP 5.3 or higher, this function can be used to reproduct the functionality but requirs PHP 5.1.0 or higher - if (!function_exists('str_getcsv')) { - function str_getcsv($input, $delimiter = ",", $enclosure = '"', $escape = "\\") { - $fp = fopen("php://memory", 'r+'); - fputs($fp, $input); - rewind($fp); - $data = fgetcsv($fp, null, $delimiter, $enclosure); // $escape only got added in 5.3.0 - fclose($fp); - return $data; - } - } - //set the max php execution time ini_set('max_execution_time', 7200); @@ -230,7 +218,15 @@ } //get the parent table - function get_parent($schema,$table_name) { + /** + * Retrieves the parent table for a given table name from a schema. + * + * @param array $schema A multidimensional array representing the schema of tables. + * @param string $table_name The name of the table to retrieve the parent for. + * + * @return string|null The name of the parent table, or null if not found in the schema. + */ + function get_parent($schema, $table_name) { foreach ($schema as $row) { if ($row['table'] == $table_name) { return $row['parent']; diff --git a/app/voicemails/voicemail_name.php b/app/voicemails/voicemail_name.php index ee005fd694..c60bcf09fe 100644 --- a/app/voicemails/voicemail_name.php +++ b/app/voicemails/voicemail_name.php @@ -38,6 +38,13 @@ $voicemail_id = trim($_GET['id']); //used (above) to search the array to determine if an extension is assigned to the user + /** + * Checks if a specific extension has been assigned to the current user. + * + * @param string $number The extension number or alias to check for assignment. + * + * @return boolean True if the extension is assigned, false otherwise. + */ function extension_assigned($number) { foreach ($_SESSION['user']['extension'] as $row) { if ((is_numeric($row['number_alias']) && $row['number_alias'] == $number) || $row['user'] == $number) { @@ -75,6 +82,14 @@ } //define the download function (helps safari play audio sources) + /** + * Downloads a file in range mode. + * + * This function sends the file to the client in chunks, allowing for partial downloads + * and resuming from where the download was left off. + * + * @param string $file The path to the file being downloaded. + */ function range_download($file) { $fp = @fopen($file, 'rb'); @@ -103,7 +118,7 @@ $c_start = $start; $c_end = $end; // Extract the range string - list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2); + [, $range] = explode('=', $_SERVER['HTTP_RANGE'], 2); // Make sure the client hasn't sent us a multibyte range if (strpos($range, ',') !== false) { // (?) Shoud this be issued here, or should the first diff --git a/app/voicemails/waveform.php b/app/voicemails/waveform.php index 14131e50ec..a155abdec4 100644 --- a/app/voicemails/waveform.php +++ b/app/voicemails/waveform.php @@ -138,6 +138,14 @@ case 'recorded_name': //used below to search the array to determine if an extension is assigned to the user + + /** + * Checks if an extension has been assigned to the current user. + * + * @param string $number The number of the extension, or the name of a user who is currently assigned this extension + * + * @return bool True if the extension has been assigned, False otherwise + */ function extension_assigned($number) { foreach ($_SESSION['user']['extension'] as $row) { if ((is_numeric($row['number_alias']) && $row['number_alias'] == $number) || $row['user'] == $number) { diff --git a/app/xml_cdr/resources/classes/xml_cdr.php b/app/xml_cdr/resources/classes/xml_cdr.php index b5aac5a753..fd1264eecb 100644 --- a/app/xml_cdr/resources/classes/xml_cdr.php +++ b/app/xml_cdr/resources/classes/xml_cdr.php @@ -27,2366 +27,2432 @@ /** * xml_cdr class provides methods for adding cdr records to the database */ - class xml_cdr { +class xml_cdr { - /** - * declare constant variables - */ - const app_name = 'xml_cdr'; - const app_uuid = '4a085c51-7635-ff03-f67b-86e834422848'; + /** + * declare constant variables + */ + const app_name = 'xml_cdr'; + const app_uuid = '4a085c51-7635-ff03-f67b-86e834422848'; - /** - * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - public $domain_uuid; + /** + * Domain UUID set in the constructor. This can be passed in through the $settings_array associative array or set + * in the session global array + * + * @var string + */ + public $domain_uuid; - /** - * declare public variables - */ - public $array; - public $fields; - public $setting; - public $call_details; - public $call_direction; - public $status; - public $billsec; - public $recording_uuid; - public $binary; + /** + * declare public variables + */ + public $array; + public $fields; + public $setting; + public $call_details; + public $call_direction; + public $status; + public $billsec; + public $recording_uuid; + public $binary; - /** - * user summary - */ - public $quick_select; - public $start_stamp_begin; - public $start_stamp_end; - public $include_internal; - public $extensions; + /** + * user summary + */ + public $quick_select; + public $start_stamp_begin; + public $start_stamp_end; + public $include_internal; + public $extensions; - /** - * Used by read_files, xml_array, and save methods - */ - public $file; + /** + * Used by read_files, xml_array, and save methods + */ + public $file; - /** - * Set in the constructor. Must be a database object and cannot be null. - * @var database Database Object - */ - private $database; + /** + * Set in the constructor. Must be a database object and cannot be null. + * + * @var database Database Object + */ + private $database; - /** - * Internal array structure that is populated from the database - * @var settings A settings object loaded from Default Settings - */ - private $settings; + /** + * Internal array structure that is populated from the database + * + * @var settings A settings object loaded from Default Settings + */ + private $settings; - /** - * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $user_uuid; + /** + * User UUID set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $user_uuid; - /** - * Username set in the constructor. This can be passed in through the $settings_array associative array or set in the session global array - * @var string - */ - private $username; + /** + * Username set in the constructor. This can be passed in through the $settings_array associative array or set in + * the session global array + * + * @var string + */ + private $username; - /** - * Set in the constructor. This can be null. - * @var destinations Object - */ - private $destinations; + /** + * Set in the constructor. This can be null. + * + * @var destinations Object + */ + private $destinations; - /** - * delete method - */ - private $permission_prefix; - private $list_page; - private $table; - private $uuid_prefix; - private $xml_cdr_dir; + /** + * delete method + */ + private $permission_prefix; + private $list_page; + private $table; + private $uuid_prefix; + private $xml_cdr_dir; - /** - * additional private variables - */ - private $password; - private $json; + /** + * additional private variables + */ + private $password; + private $json; - /** - * Called when the object is created - */ - public function __construct(array $setting_array = []) { - //set domain and user UUIDs - $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; - $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; + /** + * Initializes the object with setting array. + * + * @param array $setting_array An array containing settings for domain, user, and database connections. Defaults to + * an empty array. + * + * @return void + */ + public function __construct(array $setting_array = []) { + //set domain and user UUIDs + $this->domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; + $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects - $this->database = $setting_array['database'] ?? database::new(); - $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); + //set objects + $this->database = $setting_array['database'] ?? database::new(); + $this->settings = $setting_array['settings'] ?? new settings(['database' => $this->database, 'domain_uuid' => $this->domain_uuid, 'user_uuid' => $this->user_uuid]); - //set the directory - $this->xml_cdr_dir = $this->settings->get('switch', 'log', '/var/log/freeswitch').'/xml_cdr'; + //set the directory + $this->xml_cdr_dir = $this->settings->get('switch', 'log', '/var/log/freeswitch') . '/xml_cdr'; - //get the destinations object - if (!empty($setting_array['destinations'])) { - $this->destinations = $setting_array['destinations']; - } - - //assign private variables (for delete method) - $this->permission_prefix = 'xml_cdr_'; - $this->list_page = 'xml_cdr.php'; - $this->table = 'xml_cdr'; - $this->uuid_prefix = 'xml_cdr_'; + //get the destinations object + if (!empty($setting_array['destinations'])) { + $this->destinations = $setting_array['destinations']; } - /** - * cdr process logging - */ - public function log($message) { + //assign private variables (for delete method) + $this->permission_prefix = 'xml_cdr_'; + $this->list_page = 'xml_cdr.php'; + $this->table = 'xml_cdr'; + $this->uuid_prefix = 'xml_cdr_'; + } - //save the log if enabled is true - if ($this->settings->get('log', 'enabled', false)) { + /** + * Saves a log message to the configured logging destination. + * + * @param string $message The log message to save + * + * @return void + */ + public function log($message) { - //save the log to the php error log - if ($this->settings->get('log', 'type') == 'error_log') { - error_log($message); + //save the log if enabled is true + if ($this->settings->get('log', 'enabled', false)) { + + //save the log to the php error log + if ($this->settings->get('log', 'type') == 'error_log') { + error_log($message); + } + + //save the log to the syslog server + if ($this->settings->get('log', 'type') == 'syslog') { + openlog("XML CDR", LOG_PID | LOG_PERROR, LOG_LOCAL0); + syslog(LOG_WARNING, $message); + closelog(); + } + + //save the log to the file system + if ($this->settings->get('log', 'text') == 'file') { + $fp = fopen($this->settings->get('server', 'temp') . '/xml_cdr.log', 'a+'); + if (!$fp) { + return; } + fwrite($fp, $message); + fclose($fp); + } - //save the log to the syslog server - if ($this->settings->get('log', 'type') == 'syslog') { - openlog("XML CDR", LOG_PID | LOG_PERROR, LOG_LOCAL0); - syslog(LOG_WARNING, $message); - closelog(); + } + } + + /** + * Defines the fields for the xml_cdr table. + * + * @return void + */ + public function fields() { + + $this->fields[] = "xml_cdr_uuid"; + $this->fields[] = "domain_uuid"; + $this->fields[] = "provider_uuid"; + $this->fields[] = "extension_uuid"; + $this->fields[] = "sip_call_id"; + $this->fields[] = "domain_name"; + $this->fields[] = "accountcode"; + $this->fields[] = "direction"; + $this->fields[] = "default_language"; + $this->fields[] = "context"; + $this->fields[] = "call_flow"; + $this->fields[] = "xml"; + $this->fields[] = "json"; + $this->fields[] = "missed_call"; + $this->fields[] = "caller_id_name"; + $this->fields[] = "caller_id_number"; + $this->fields[] = "caller_destination"; + $this->fields[] = "destination_number"; + $this->fields[] = "source_number"; + $this->fields[] = "start_epoch"; + $this->fields[] = "start_stamp"; + $this->fields[] = "answer_stamp"; + $this->fields[] = "answer_epoch"; + $this->fields[] = "end_epoch"; + $this->fields[] = "end_stamp"; + $this->fields[] = "duration"; + $this->fields[] = "mduration"; + $this->fields[] = "billsec"; + $this->fields[] = "billmsec"; + $this->fields[] = "hold_accum_seconds"; + $this->fields[] = "bridge_uuid"; + $this->fields[] = "read_codec"; + $this->fields[] = "read_rate"; + $this->fields[] = "write_codec"; + $this->fields[] = "write_rate"; + $this->fields[] = "remote_media_ip"; + $this->fields[] = "network_addr"; + $this->fields[] = "record_path"; + $this->fields[] = "record_name"; + $this->fields[] = "record_length"; + $this->fields[] = "leg"; + $this->fields[] = "originating_leg_uuid"; + $this->fields[] = "pdd_ms"; + $this->fields[] = "rtp_audio_in_mos"; + $this->fields[] = "last_app"; + $this->fields[] = "last_arg"; + $this->fields[] = "voicemail_message"; + $this->fields[] = "call_center_queue_uuid"; + $this->fields[] = "cc_side"; + $this->fields[] = "cc_member_uuid"; + $this->fields[] = "cc_queue_joined_epoch"; + $this->fields[] = "cc_queue"; + $this->fields[] = "cc_member_session_uuid"; + $this->fields[] = "cc_agent_uuid"; + $this->fields[] = "cc_agent"; + $this->fields[] = "cc_agent_type"; + $this->fields[] = "cc_agent_bridged"; + $this->fields[] = "cc_queue_answered_epoch"; + $this->fields[] = "cc_queue_terminated_epoch"; + $this->fields[] = "cc_queue_canceled_epoch"; + $this->fields[] = "cc_cancel_reason"; + $this->fields[] = "cc_cause"; + $this->fields[] = "waitsec"; + $this->fields[] = "conference_name"; + $this->fields[] = "conference_uuid"; + $this->fields[] = "conference_member_id"; + $this->fields[] = "digits_dialed"; + $this->fields[] = "pin_number"; + $this->fields[] = "status"; + $this->fields[] = "hangup_cause"; + $this->fields[] = "hangup_cause_q850"; + $this->fields[] = "sip_hangup_disposition"; + $this->fields[] = "ring_group_uuid"; + $this->fields[] = "ivr_menu_uuid"; + + if (!empty($this->settings->get('cdr', 'field'))) { + foreach ($this->settings->get('cdr', 'field') as $field) { + $field_name = end(explode(',', $field)); + $this->fields[] = $field_name; + } + } + $this->fields = array_unique($this->fields); + } + + /** + * Saves the call details record to the database and removes old entries in the xml_cdr, xml_cdr_flow, xml_cdr_json, and xml_cdr_logs tables. + * + * @return void + */ + public function save() { + + $this->fields(); + $field_count = sizeof($this->fields); + //$field_count = sizeof($this->fields); + + if (!empty($this->array)) { + + //add the temporary permission + $p = permissions::new(); + $p->add("xml_cdr_add", "temp"); + $p->add("xml_cdr_json_add", "temp"); + $p->add("xml_cdr_flow_add", "temp"); + $p->add("xml_cdr_log_add", "temp"); + + //save the call details record to the database + $this->database->app_name = 'xml_cdr'; + $this->database->app_uuid = '4a085c51-7635-ff03-f67b-86e834422848'; + //$this->database->domain_uuid = $domain_uuid; + $response = $this->database->save($this->array, false); + if ($response['code'] == '200') { + //delete the file after it is saved to the database + if (file_exists($this->xml_cdr_dir . '/' . $this->file)) { + unlink($this->xml_cdr_dir . '/' . $this->file); } - - //save the log to the file system - if ($this->settings->get('log', 'text') == 'file') { - $fp = fopen($this->settings->get('server', 'temp').'/xml_cdr.log', 'a+'); - if (!$fp) { - return; + } else { + //move the file to a failed directory + if (!$response) { + if (!file_exists($this->xml_cdr_dir . '/failed/sql')) { + mkdir($this->xml_cdr_dir . '/failed/sql', 0770, true); + //echo "Failed to create ".$this->xml_cdr_dir."/failed/sql\n"; } - fwrite($fp, $message); - fclose($fp); + rename($this->xml_cdr_dir . '/' . $this->file, $this->xml_cdr_dir . '/failed/sql/' . $this->file); + } elseif (!file_exists($this->xml_cdr_dir . '/failed')) { + mkdir($this->xml_cdr_dir . '/failed', 0770, true); + //echo "Failed to create ".$this->xml_cdr_dir."/failed\n"; + rename($this->xml_cdr_dir . '/' . $this->file, $this->xml_cdr_dir . '/failed/' . $this->file); } + //send an error message + //echo "failed file moved to ".$this->xml_cdr_dir."/failed/".$this->file."\n"; } + + //clear the array + unset($this->array); + + //debug results + $this->log(print_r($this->database->message, true)); + + //remove the temporary permission + $p->delete("xml_cdr_add", "temp"); + $p->delete("xml_cdr_json_add", "temp"); + $p->delete("xml_cdr_flow_add", "temp"); + $p->delete("xml_cdr_log_add", "temp"); + unset($array); + } - /** - * cdr fields in the database schema - */ - public function fields() { + } - $this->fields[] = "xml_cdr_uuid"; - $this->fields[] = "domain_uuid"; - $this->fields[] = "provider_uuid"; - $this->fields[] = "extension_uuid"; - $this->fields[] = "sip_call_id"; - $this->fields[] = "domain_name"; - $this->fields[] = "accountcode"; - $this->fields[] = "direction"; - $this->fields[] = "default_language"; - $this->fields[] = "context"; - $this->fields[] = "call_flow"; - $this->fields[] = "xml"; - $this->fields[] = "json"; - $this->fields[] = "missed_call"; - $this->fields[] = "caller_id_name"; - $this->fields[] = "caller_id_number"; - $this->fields[] = "caller_destination"; - $this->fields[] = "destination_number"; - $this->fields[] = "source_number"; - $this->fields[] = "start_epoch"; - $this->fields[] = "start_stamp"; - $this->fields[] = "answer_stamp"; - $this->fields[] = "answer_epoch"; - $this->fields[] = "end_epoch"; - $this->fields[] = "end_stamp"; - $this->fields[] = "duration"; - $this->fields[] = "mduration"; - $this->fields[] = "billsec"; - $this->fields[] = "billmsec"; - $this->fields[] = "hold_accum_seconds"; - $this->fields[] = "bridge_uuid"; - $this->fields[] = "read_codec"; - $this->fields[] = "read_rate"; - $this->fields[] = "write_codec"; - $this->fields[] = "write_rate"; - $this->fields[] = "remote_media_ip"; - $this->fields[] = "network_addr"; - $this->fields[] = "record_path"; - $this->fields[] = "record_name"; - $this->fields[] = "record_length"; - $this->fields[] = "leg"; - $this->fields[] = "originating_leg_uuid"; - $this->fields[] = "pdd_ms"; - $this->fields[] = "rtp_audio_in_mos"; - $this->fields[] = "last_app"; - $this->fields[] = "last_arg"; - $this->fields[] = "voicemail_message"; - $this->fields[] = "call_center_queue_uuid"; - $this->fields[] = "cc_side"; - $this->fields[] = "cc_member_uuid"; - $this->fields[] = "cc_queue_joined_epoch"; - $this->fields[] = "cc_queue"; - $this->fields[] = "cc_member_session_uuid"; - $this->fields[] = "cc_agent_uuid"; - $this->fields[] = "cc_agent"; - $this->fields[] = "cc_agent_type"; - $this->fields[] = "cc_agent_bridged"; - $this->fields[] = "cc_queue_answered_epoch"; - $this->fields[] = "cc_queue_terminated_epoch"; - $this->fields[] = "cc_queue_canceled_epoch"; - $this->fields[] = "cc_cancel_reason"; - $this->fields[] = "cc_cause"; - $this->fields[] = "waitsec"; - $this->fields[] = "conference_name"; - $this->fields[] = "conference_uuid"; - $this->fields[] = "conference_member_id"; - $this->fields[] = "digits_dialed"; - $this->fields[] = "pin_number"; - $this->fields[] = "status"; - $this->fields[] = "hangup_cause"; - $this->fields[] = "hangup_cause_q850"; - $this->fields[] = "sip_hangup_disposition"; - $this->fields[] = "ring_group_uuid"; - $this->fields[] = "ivr_menu_uuid"; + /** + * Processes the XML array data and saves it to the database. + * + * @param string $key The key for the XML array. + * @param string $leg The leg of the call. + * @param string $xml_string The XML string to process. + * + * @return mixed + */ + public function xml_array($key, $leg, $xml_string) { + //set the directory + if (!empty($this->settings->get('switch', 'log'))) { + $this->xml_cdr_dir = $this->settings->get('switch', 'log') . '/xml_cdr'; + } + + //xml string is empty + if (empty($xml_string) && !empty($this->file)) { + unlink($this->xml_cdr_dir . '/' . $this->file); + return false; + } + + //fix the xml by escaping the contents of + if (defined('STDIN')) { + $xml_string = preg_replace_callback("/<([^><]+)>(.*?[><].*?)<\/\g1>/", + function ($matches) { + return '<' . $matches[1] . '>' . + str_replace(">", ">", + str_replace("<", "<", $matches[2]) + ) . + ''; + }, + $xml_string + ); + } + + //remove invalid numeric xml tags + $xml_string = preg_replace('/<\/?\d+>/', '', $xml_string); + + //replace xml tag name with + $xml_string = preg_replace('/(<\/?)(set )([^>]*>)/i', '$1$3', $xml_string); + + //replace xml tag name <^^,default_language> with + $xml_string = preg_replace('/(<\/?)(\^\^,)([^>]*>)/', '$1$3', $xml_string); + + //replace xml tag name with + $xml_string = preg_replace('/(<\/?)(nolocal:)([^>]*>)/i', '$1$3', $xml_string); + + //remove spaces in the beginning of the xml open and closing tags + $xml_string = preg_replace('/(<\/?)\s*([\w:-]+)/', '$1$2', $xml_string); + + //disable xml entities + if (PHP_VERSION_ID < 80000) { + libxml_disable_entity_loader(true); + } + + //load the string into an xml object + $xml = simplexml_load_string($xml_string, 'SimpleXMLElement', LIBXML_NOCDATA); + if ($xml === false) { + //failed to load the XML, move the XML file to the failed directory + if (file_exists($this->xml_cdr_dir)) { + rename($this->xml_cdr_dir . '/' . $this->file, $this->xml_cdr_dir . '/failed/xml/' . $this->file); + } + + //return without saving the invalid xml + return false; + } + + //skip call detail records for calls blocked by call block + if (isset($xml->variables->call_block) && $xml->variables->call_block == 'true' && !$this->settings->get('call_block', 'save_call_detail_record', true)) { + //delete the xml cdr file + if (file_exists($this->xml_cdr_dir . '/' . $this->file)) { + unlink($this->xml_cdr_dir . '/' . $this->file); + } + + //return without saving + return false; + } + + //check for duplicate call uuid's + $duplicate_uuid = false; + $uuid = urldecode($xml->variables->uuid); + if (empty($uuid)) { + $uuid = urldecode($xml->variables->call_uuid); + } + if ($uuid != null && is_uuid($uuid)) { + //check for duplicates + $sql = "select count(xml_cdr_uuid) "; + $sql .= "from v_xml_cdr "; + $sql .= "where xml_cdr_uuid = :xml_cdr_uuid "; + $parameters['xml_cdr_uuid'] = $uuid; + $count = $this->database->select($sql, $parameters, 'column'); + if ($count > 0) { + //duplicate uuid detected + $duplicate_uuid = true; + + //remove the file as the record already exists in the database + if (file_exists($this->xml_cdr_dir . '/' . $this->file)) { + unlink($this->xml_cdr_dir . '/' . $this->file); + } + + //return without saving + return false; + } + unset($sql, $parameters); + } + + //set the call_direction + if (isset($xml->variables->call_direction)) { + $call_direction = urldecode($xml->variables->call_direction); + } + + //set the accountcode + if (isset($xml->variables->accountcode)) { + $accountcode = urldecode($xml->variables->accountcode); + } + + //process call detail record data + if ($duplicate_uuid == false && is_uuid($uuid)) { + + //get the caller ID from call flow caller profile + $i = 0; + foreach ($xml->callflow as $row) { + if ($i == 0) { + $caller_id_name = urldecode($row->caller_profile->caller_id_name); + $caller_id_number = urldecode($row->caller_profile->caller_id_number); + } + $i++; + } + unset($i); + + //get the caller ID from variables + if (!isset($caller_id_name) && isset($xml->variables->caller_id_name)) { + $caller_id_name = urldecode($xml->variables->caller_id_name); + } + if (!isset($caller_id_number) && isset($xml->variables->caller_id_number)) { + $caller_id_number = urldecode($xml->variables->caller_id_number); + } + if (!isset($caller_id_number) && isset($xml->variables->sip_from_user)) { + $caller_id_number = urldecode($xml->variables->sip_from_user); + } + + //if the origination caller id name and number are set then use them + if (isset($xml->variables->origination_caller_id_name)) { + $caller_id_name = urldecode($xml->variables->origination_caller_id_name); + } + if (isset($xml->variables->origination_caller_id_number)) { + $caller_id_number = urldecode($xml->variables->origination_caller_id_number); + } + + //if the caller ID was updated then update the caller ID + if (isset($xml->variables->effective_caller_id_name)) { + $caller_id_name = urldecode($xml->variables->effective_caller_id_name); + } + if (isset($xml->variables->effective_caller_id_number)) { + $caller_id_number = urldecode($xml->variables->effective_caller_id_number); + } + + //if intercept is used then update use the last sent callee id name and number + if (isset($xml->variables->last_app) && $xml->variables->last_app == 'intercept' && !empty($xml->variables->last_sent_callee_id_name)) { + $caller_id_name = urldecode($xml->variables->last_sent_callee_id_name); + } + if (isset($xml->variables->last_app) && $xml->variables->last_app == 'intercept' && !empty($xml->variables->last_sent_callee_id_number)) { + $caller_id_number = urldecode($xml->variables->last_sent_callee_id_number); + } + + //if the sip_from_domain and domain_name are not the same then original call direction was inbound + //when an inbound call is forward the call_direction is set to inbound and then updated to outbound + //use sip_from_display and sip_from_user to get the original caller ID instead of the updated caller ID info from the forward + if (isset($xml->variables->sip_from_domain) && urldecode($xml->variables->sip_from_domain) != urldecode($xml->variables->domain_name)) { + if (isset($xml->variables->sip_from_display)) { + $caller_id_name = urldecode($xml->variables->sip_from_display); + } + if (isset($xml->variables->sip_from_user)) { + $caller_id_number = urldecode($xml->variables->sip_from_user); + } + } + + //get the values from the callflow. + $i = 0; + foreach ($xml->callflow as $row) { + if ($i == 0) { + $context = urldecode($row->caller_profile->context); + $destination_number = urldecode($row->caller_profile->destination_number); + $network_addr = urldecode($row->caller_profile->network_addr); + } + $i++; + } + unset($i); + + //remove the provider prefix + if (isset($xml->variables->provider_prefix) && isset($destination_number)) { + $provider_prefix = $xml->variables->provider_prefix; + if ($provider_prefix == substr($destination_number, 0, strlen($provider_prefix))) { + $destination_number = substr($destination_number, strlen($provider_prefix), strlen($destination_number)); + } + } + + //get the caller_destination + if (isset($xml->variables->caller_destination)) { + $caller_destination = urldecode($xml->variables->caller_destination); + } + if (isset($xml->variables->sip_h_caller_destination)) { + $caller_destination = urldecode($xml->variables->sip_h_caller_destination); + } + if (!isset($caller_destination) && isset($xml->variables->dialed_user)) { + $caller_destination = urldecode($xml->variables->dialed_user); + } + + //set missed calls + if (isset($xml->variables->missed_call) && $xml->variables->missed_call == 'true') { + //allow calls marked as missed_call value to be overridden, an alternate destination may have answered the call + $missed_call = 'true'; + } + if (isset($call_direction) && $call_direction == 'inbound' + && isset($xml->variables->hangup_cause) + && $xml->variables->hangup_cause == 'ORIGINATOR_CANCEL') { + $missed_call = 'true'; + } + if (isset($xml->variables->cc_side) && $xml->variables->cc_side == 'agent') { + //call center + $missed_call = 'false'; + } + if (isset($xml->variables->fax_success)) { + //fax server + $missed_call = 'false'; + } + if (isset($xml->variables->hangup_cause) && $xml->variables->hangup_cause == 'LOSE_RACE') { + //ring group or multi destination bridge statement + $missed_call = 'false'; + } + if (isset($xml->variables->hangup_cause) && $xml->variables->hangup_cause == 'NO_ANSWER' && isset($xml->variables->originating_leg_uuid)) { + //ring group or multi destination bridge statement + $missed_call = 'false'; + } + if (isset($xml->variables->bridge_uuid) && !empty($xml->variables->bridge_uuid)) { + //call was bridged + $missed_call = 'false'; + } + if (isset($xml->variables->cc_side) && $xml->variables->cc_side == 'member' + && isset($xml->variables->cc_cause) && $xml->variables->cc_cause == 'cancel') { + //call center + $missed_call = 'true'; + } + if (isset($xml->variables->destination_number) && substr($xml->variables->destination_number, 0, 3) == '*99') { + //voicemail + $missed_call = 'true'; + } + if (isset($xml->variables->voicemail_answer_stamp) && !empty($xml->variables->voicemail_answer_stamp)) { + //voicemail + $missed_call = 'true'; + } + + //read the bridge statement variables + if (isset($xml->variables->last_app)) { + if (urldecode($xml->variables->last_app) == 'bridge') { + //get the variables from inside the { and } brackets + preg_match('/^\{([^}]+)\}/', urldecode($xml->variables->last_arg), $matches); + + //create a variables array from the comma delimitted string + $bridge_variables = explode(",", $matches[1]); + + //set bridge variables as variables + $x = 0; + if (!empty($bridge_variables)) { + foreach ($bridge_variables as $variable) { + $pairs = explode("=", $variable); + $name = $pairs[0]; + $$name = $pairs[1]; + $x++; + } + } + } + } + + //get the last bridge_uuid from the call to preserve previous behavior + foreach ($xml->variables->bridge_uuids as $bridge) { + $last_bridge = urldecode($bridge); + } + + //determine the call status + $failed_array = [ + "CALL_REJECTED", + "CHAN_NOT_IMPLEMENTED", + "DESTINATION_OUT_OF_ORDER", + "EXCHANGE_ROUTING_ERROR", + "INCOMPATIBLE_DESTINATION", + "INVALID_NUMBER_FORMAT", + "MANDATORY_IE_MISSING", + "NETWORK_OUT_OF_ORDER", + "NORMAL_TEMPORARY_FAILURE", + "NORMAL_UNSPECIFIED", + "NO_ROUTE_DESTINATION", + "RECOVERY_ON_TIMER_EXPIRE", + "REQUESTED_CHAN_UNAVAIL", + "SUBSCRIBER_ABSENT", + "SYSTEM_SHUTDOWN", + "UNALLOCATED_NUMBER", + ]; + if ($xml->variables->billsec > 0) { + $status = 'answered'; + } + if ($xml->variables->hangup_cause == 'NO_ANSWER') { + $status = 'no_answer'; + } + if ($xml->variables->hangup_cause == 'ORIGINATOR_CANCEL') { + $status = 'cancelled'; + } + if ($xml->variables->hangup_cause == 'USER_BUSY') { + $status = 'busy'; + } + if (in_array($xml->variables->hangup_cause, $failed_array)) { + $status = 'failed'; + } + if (!isset($status) && in_array($xml->variables->last_bridge_hangup_cause, $failed_array)) { + $status = 'failed'; + } + if ($xml->variables->cc_side == 'agent' && $xml->variables->billsec == 0) { + $status = 'no_answer'; + } + if (!isset($status) && $xml->variables->billsec == 0) { + $status = 'no_answer'; + } + if ($missed_call == 'true') { + $status = 'missed'; + } + if (substr($destination_number, 0, 3) == '*99') { + $status = 'voicemail'; + } + if (!empty($xml->variables->voicemail_message_seconds)) { + $status = 'voicemail'; + } + + //set the key + $key = 'xml_cdr'; + + //get the domain values from the xml + $domain_name = urldecode($xml->variables->domain_name); + $domain_uuid = urldecode($xml->variables->domain_uuid); + + //sanitize the caller ID + $caller_id_name = preg_replace('#[^a-zA-Z0-9\-.\#*@ ]#', '', $caller_id_name); + $caller_id_number = preg_replace('#[^0-9\-\#\*]#', '', $caller_id_number); + + //get the extension_uuid and then add it to the database fields array + if (isset($xml->variables->extension_uuid)) { + $extension_uuid = urldecode($xml->variables->extension_uuid); + $this->array[$key][0]['extension_uuid'] = $extension_uuid; + } else { + if (isset($domain_uuid) && isset($xml->variables->dialed_user)) { + $sql = "select extension_uuid from v_extensions "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and (extension = :dialed_user or number_alias = :dialed_user) "; + $parameters['domain_uuid'] = $domain_uuid; + $parameters['dialed_user'] = $xml->variables->dialed_user; + $extension_uuid = $this->database->select($sql, $parameters, 'column'); + $this->array[$key][0]['extension_uuid'] = $extension_uuid; + unset($parameters); + } + if (isset($domain_uuid) && isset($xml->variables->referred_by_user)) { + $sql = "select extension_uuid from v_extensions "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and (extension = :referred_by_user or number_alias = :referred_by_user) "; + $parameters['domain_uuid'] = $domain_uuid; + $parameters['referred_by_user'] = $xml->variables->referred_by_user; + $extension_uuid = $this->database->select($sql, $parameters, 'column'); + $this->array[$key][0]['extension_uuid'] = $extension_uuid; + unset($parameters); + } + if (isset($domain_uuid) && isset($xml->variables->last_sent_callee_id_number)) { + $sql = "select extension_uuid from v_extensions "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and (extension = :last_sent_callee_id_number or number_alias = :last_sent_callee_id_number) "; + $parameters['domain_uuid'] = $domain_uuid; + $parameters['last_sent_callee_id_number'] = $xml->variables->last_sent_callee_id_number; + $extension_uuid = $this->database->select($sql, $parameters, 'column'); + $this->array[$key][0]['extension_uuid'] = $extension_uuid; + unset($parameters); + } + } + + //misc + $this->array[$key][0]['xml_cdr_uuid'] = $uuid; + $this->array[$key][0]['destination_number'] = $destination_number; + $this->array[$key][0]['sip_call_id'] = urldecode($xml->variables->sip_call_id); + $this->array[$key][0]['source_number'] = urldecode($xml->variables->effective_caller_id_number); + $this->array[$key][0]['network_addr'] = urldecode($xml->variables->sip_network_ip); + $this->array[$key][0]['missed_call'] = $missed_call; + $this->array[$key][0]['caller_id_name'] = $caller_id_name; + $this->array[$key][0]['caller_id_number'] = $caller_id_number; + $this->array[$key][0]['caller_destination'] = $caller_destination; + $this->array[$key][0]['accountcode'] = urldecode($accountcode); + $this->array[$key][0]['default_language'] = urldecode($xml->variables->default_language); + $this->array[$key][0]['bridge_uuid'] = urldecode($xml->variables->bridge_uuid) ?: $last_bridge; + //$this->array[$key][0]['digits_dialed'] = urldecode($xml->variables->digits_dialed); + $this->array[$key][0]['sip_hangup_disposition'] = urldecode($xml->variables->sip_hangup_disposition); + $this->array[$key][0]['pin_number'] = urldecode($xml->variables->pin_number); + $this->array[$key][0]['status'] = $status; + $this->array[$key][0]['ring_group_uuid'] = urldecode($xml->variables->ring_group_uuid); + $this->array[$key][0]['ivr_menu_uuid'] = urldecode($xml->variables->ivr_menu_uuid); + + //time + //catch invalid call detail records + if (empty($xml->variables->start_epoch)) { + //empty the array so it can't save + $this->array = null; + + //move the file to the failed location + $this->move_to_failed($this->file); + + //stop processing + return; + } + $start_epoch = urldecode($xml->variables->start_epoch); + $this->array[$key][0]['start_epoch'] = $start_epoch; + $this->array[$key][0]['start_stamp'] = is_numeric((int)$start_epoch) ? date('c', $start_epoch) : null; + $answer_epoch = urldecode($xml->variables->answer_epoch); + $this->array[$key][0]['answer_epoch'] = $answer_epoch; + $this->array[$key][0]['answer_stamp'] = is_numeric((int)$answer_epoch) ? date('c', $answer_epoch) : null; + $end_epoch = urldecode($xml->variables->end_epoch); + $this->array[$key][0]['end_epoch'] = $end_epoch; + $this->array[$key][0]['end_stamp'] = is_numeric((int)$end_epoch) ? date('c', $end_epoch) : null; + $this->array[$key][0]['duration'] = urldecode($xml->variables->billsec); + $this->array[$key][0]['mduration'] = urldecode($xml->variables->billmsec); + $this->array[$key][0]['billsec'] = urldecode($xml->variables->billsec); + $this->array[$key][0]['billmsec'] = urldecode($xml->variables->billmsec); + $this->array[$key][0]['hold_accum_seconds'] = urldecode($xml->variables->hold_accum_seconds); + + //codecs + $this->array[$key][0]['read_codec'] = urldecode($xml->variables->read_codec); + $this->array[$key][0]['read_rate'] = urldecode($xml->variables->read_rate); + $this->array[$key][0]['write_codec'] = urldecode($xml->variables->write_codec); + $this->array[$key][0]['write_rate'] = urldecode($xml->variables->write_rate); + $this->array[$key][0]['remote_media_ip'] = urldecode($xml->variables->remote_media_ip); + $this->array[$key][0]['hangup_cause'] = urldecode($xml->variables->hangup_cause); + $this->array[$key][0]['hangup_cause_q850'] = urldecode($xml->variables->hangup_cause_q850); + + //store the call direction + $this->array[$key][0]['direction'] = urldecode($call_direction); + + //call center + if ($xml->variables->cc_member_uuid == '_undef_') { + $xml->variables->cc_member_uuid = ''; + } + if ($xml->variables->cc_member_session_uuid == '_undef_') { + $xml->variables->cc_member_session_uuid = ''; + } + if ($xml->variables->cc_agent_uuid == '_undef_') { + $xml->variables->cc_agent_uuid = ''; + } + if ($xml->variables->call_center_queue_uuid == '_undef_') { + $xml->variables->call_center_queue_uuid = ''; + } + if ($xml->variables->cc_queue_joined_epoch == '_undef_') { + $xml->variables->cc_queue_joined_epoch = ''; + } + + $this->array[$key][0]['cc_side'] = urldecode($xml->variables->cc_side); + if (!empty($xml->variables->cc_member_uuid) && is_uuid(urldecode($xml->variables->cc_member_uuid))) { + $this->array[$key][0]['cc_member_uuid'] = urldecode($xml->variables->cc_member_uuid); + } + $this->array[$key][0]['cc_queue'] = urldecode($xml->variables->cc_queue); + if (!empty($xml->variables->call_center_queue_uuid) && is_uuid(urldecode($xml->variables->call_center_queue_uuid))) { + $call_center_queue_uuid = urldecode($xml->variables->call_center_queue_uuid); + } + if (empty($call_center_queue_uuid) && !empty($xml->variables->cc_queue)) { + $sql = "select call_center_queue_uuid from v_call_center_queues "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and queue_extension = :queue_extension "; + $parameters['domain_uuid'] = $domain_uuid; + $parameters['queue_extension'] = explode("@", $xml->variables->cc_queue)[0]; + $call_center_queue_uuid = $this->database->select($sql, $parameters, 'column'); + unset($parameters); + } + if (empty($extension_uuid) && !empty($xml->variables->cc_agent)) { + //use the agent_id as an alternative way to get the extension_uuid + $sql = "select extension_uuid from v_extensions "; + $sql .= "where domain_uuid = :domain_uuid "; + $sql .= "and extension in ( "; + $sql .= " select agent_id from v_call_center_agents where call_center_agent_uuid = :agent_id "; + $sql .= ") "; + $parameters['domain_uuid'] = $domain_uuid; + $parameters['agent_id'] = $xml->variables->cc_agent; + $extension_uuid = $this->database->select($sql, $parameters, 'column'); + $this->array[$key][0]['extension_uuid'] = $extension_uuid; + unset($parameters); + } + if (!empty($call_center_queue_uuid) && is_uuid($call_center_queue_uuid)) { + $this->array[$key][0]['call_center_queue_uuid'] = $call_center_queue_uuid; + } + if (!empty($xml->variables->cc_member_session_uuid) && is_uuid(urldecode($xml->variables->cc_member_session_uuid))) { + $this->array[$key][0]['cc_member_session_uuid'] = urldecode($xml->variables->cc_member_session_uuid); + } + if (!empty($xml->variables->cc_agent_uuid) && is_uuid(urldecode($xml->variables->cc_agent_uuid))) { + $this->array[$key][0]['cc_agent_uuid'] = urldecode($xml->variables->cc_agent_uuid); + } + $this->array[$key][0]['cc_agent'] = urldecode($xml->variables->cc_agent); + $this->array[$key][0]['cc_agent_type'] = urldecode($xml->variables->cc_agent_type); + $this->array[$key][0]['cc_agent_bridged'] = urldecode($xml->variables->cc_agent_bridged); + if (!empty($xml->variables->cc_queue_joined_epoch) && is_numeric((int)$xml->variables->cc_queue_joined_epoch)) { + $this->array[$key][0]['cc_queue_joined_epoch'] = urldecode($xml->variables->cc_queue_joined_epoch); + } + if (!empty($xml->variables->cc_queue_answered_epoch) && is_numeric((int)$xml->variables->cc_queue_answered_epoch)) { + $this->array[$key][0]['cc_queue_answered_epoch'] = urldecode($xml->variables->cc_queue_answered_epoch); + } + if (!empty($xml->variables->cc_queue_terminated_epoch) && is_numeric((int)trim($xml->variables->cc_queue_terminated_epoch))) { + $this->array[$key][0]['cc_queue_terminated_epoch'] = urldecode($xml->variables->cc_queue_terminated_epoch); + } + if (!empty($xml->variables->cc_queue_canceled_epoch) && is_numeric((int)$xml->variables->cc_queue_canceled_epoch)) { + $this->array[$key][0]['cc_queue_canceled_epoch'] = urldecode($xml->variables->cc_queue_canceled_epoch); + } + $this->array[$key][0]['cc_cancel_reason'] = urldecode($xml->variables->cc_cancel_reason); + $this->array[$key][0]['cc_cause'] = urldecode($xml->variables->cc_cause); + $this->array[$key][0]['waitsec'] = urldecode($xml->variables->waitsec); + if (urldecode($xml->variables->cc_side) == 'agent') { + $this->array[$key][0]['direction'] = 'inbound'; + } + + //set the provider id + if (isset($xml->variables->provider_uuid)) { + $this->array[$key][0]['provider_uuid'] = urldecode($xml->variables->provider_uuid); + } + + //app info + $this->array[$key][0]['last_app'] = urldecode($xml->variables->last_app); + $this->array[$key][0]['last_arg'] = urldecode($xml->variables->last_arg); + + //voicemail message success + if (!empty($xml->variables->voicemail_answer_stamp) && $xml->variables->voicemail_message_seconds > 0) { + $this->array[$key][0]['voicemail_message'] = "true"; + } else { //if ($xml->variables->voicemail_action == "save") { + $this->array[$key][0]['voicemail_message'] = "false"; + } + + //conference + $this->array[$key][0]['conference_name'] = urldecode($xml->variables->conference_name); + $this->array[$key][0]['conference_uuid'] = urldecode($xml->variables->conference_uuid); + $this->array[$key][0]['conference_member_id'] = urldecode($xml->variables->conference_member_id); + + //call quality + $rtp_audio_in_mos = urldecode($xml->variables->rtp_audio_in_mos); + if (!empty($rtp_audio_in_mos)) { + $this->array[$key][0]['rtp_audio_in_mos'] = $rtp_audio_in_mos; + } + + //store the call leg + $this->array[$key][0]['leg'] = $leg; + + //store the originating leg uuid + $this->array[$key][0]['originating_leg_uuid'] = urldecode($xml->variables->originating_leg_uuid); + + //store post dial delay, in milliseconds + $this->array[$key][0]['pdd_ms'] = urldecode((int)$xml->variables->progress_mediamsec) + (int)urldecode($xml->variables->progressmsec); + + //get break down the date to year, month and day + $start_stamp = urldecode($xml->variables->start_stamp); + $start_time = strtotime($start_stamp); + $start_year = date("Y", $start_time); + $start_month = date("M", $start_time); + $start_day = date("d", $start_time); + + //get the domain name + if (empty($domain_name)) { + $domain_name = urldecode($xml->variables->dialed_domain); + } + if (empty($domain_name)) { + $domain_name = urldecode($xml->variables->sip_invite_domain); + } + if (empty($domain_name)) { + $domain_name = urldecode($xml->variables->sip_req_host); + } + if (empty($domain_name)) { + $presence_id = urldecode($xml->variables->presence_id); + if (!empty($presence_id)) { + $presence_array = explode($presence_id, '%40'); + $domain_name = $presence_array[1]; + } + } + + //dynamic cdr fields if (!empty($this->settings->get('cdr', 'field'))) { foreach ($this->settings->get('cdr', 'field') as $field) { - $field_name = end(explode(',', $field)); + $fields = explode(",", $field); + $field_name = end($fields); $this->fields[] = $field_name; + if (!isset($this->array[$key][0][$field_name])) { + if (count($fields) == 1) { + $this->array[$key][0][$field_name] = urldecode($xml->variables->{$fields[0]}); + } + if (count($fields) == 2) { + $this->array[$key][0][$field_name] = urldecode($xml->{$fields[0]}->{$fields[1]}); + } + if (count($fields) == 3) { + $this->array[$key][0][$field_name] = urldecode($xml->{$fields[0]}->{$fields[1]}->{$fields[2]}); + } + if (count($fields) == 4) { + $this->array[$key][0][$field_name] = urldecode($xml->{$fields[0]}->{$fields[1]}->{$fields[2]}->{$fields[3]}); + } + if (count($fields) == 5) { + $this->array[$key][0][$field_name] = urldecode($xml->{$fields[0]}->{$fields[1]}->{$fields[2]}->{$fields[3]}->{$fields[4]}); + } + } } } - $this->fields = array_unique($this->fields); - } - /** - * save to the database - */ - public function save() { + //send the domain name to the cdr log + //$this->log("\ndomain_name is `$domain_name`;\ndomain_uuid is '$domain_uuid'\n"); - $this->fields(); - $field_count = sizeof($this->fields); - //$field_count = sizeof($this->fields); - - if (!empty($this->array)) { - - //add the temporary permission - $p = permissions::new(); - $p->add("xml_cdr_add", "temp"); - $p->add("xml_cdr_json_add", "temp"); - $p->add("xml_cdr_flow_add", "temp"); - $p->add("xml_cdr_log_add", "temp"); - - //save the call details record to the database - $this->database->app_name = 'xml_cdr'; - $this->database->app_uuid = '4a085c51-7635-ff03-f67b-86e834422848'; - //$this->database->domain_uuid = $domain_uuid; - $response = $this->database->save($this->array, false); - if ($response['code'] == '200') { - //delete the file after it is saved to the database - if (file_exists($this->xml_cdr_dir.'/'.$this->file)) { - unlink($this->xml_cdr_dir.'/'.$this->file); - } + //get the domain_uuid with the domain_name + if (empty($domain_uuid)) { + $sql = "select domain_uuid from v_domains "; + if (empty($domain_name) && $context != 'public' && $context != 'default') { + $sql .= "where domain_name = :context "; + $parameters['context'] = $context; + } else { + $sql .= "where domain_name = :domain_name "; + $parameters['domain_name'] = $domain_name; } - else { - //move the file to a failed directory - if (!$response) { - if (!file_exists($this->xml_cdr_dir.'/failed/sql')) { - mkdir($this->xml_cdr_dir.'/failed/sql', 0770, true); - //echo "Failed to create ".$this->xml_cdr_dir."/failed/sql\n"; - } - rename($this->xml_cdr_dir.'/'.$this->file, $this->xml_cdr_dir.'/failed/sql/'.$this->file); - } - elseif (!file_exists($this->xml_cdr_dir.'/failed')) { - mkdir($this->xml_cdr_dir.'/failed', 0770, true); - //echo "Failed to create ".$this->xml_cdr_dir."/failed\n"; - rename($this->xml_cdr_dir.'/'.$this->file, $this->xml_cdr_dir.'/failed/'.$this->file); - } - - //send an error message - //echo "failed file moved to ".$this->xml_cdr_dir."/failed/".$this->file."\n"; - } - - //clear the array - unset($this->array); - - //debug results - $this->log(print_r($this->database->message, true)); - - //remove the temporary permission - $p->delete("xml_cdr_add", "temp"); - $p->delete("xml_cdr_json_add", "temp"); - $p->delete("xml_cdr_flow_add", "temp"); - $p->delete("xml_cdr_log_add", "temp"); - unset($array); - + $domain_uuid = $this->database->select($sql, $parameters, 'column'); + unset($parameters); } - } + //set values in the database + if (!empty($domain_uuid)) { + $this->array[$key][0]['domain_uuid'] = $domain_uuid; + } + if (!empty($domain_name)) { + $this->array[$key][0]['domain_name'] = $domain_name; + } - /** - * process method converts the xml cdr and adds it to the database - */ - public function xml_array($key, $leg, $xml_string) { - - //set the directory - if (!empty($this->settings->get('switch', 'log'))) { - $this->xml_cdr_dir = $this->settings->get('switch', 'log').'/xml_cdr'; + //get the recording details + if (isset($xml->variables->record_path) && isset($xml->variables->record_name)) { + $record_path = urldecode($xml->variables->record_path); + $record_name = urldecode($xml->variables->record_name); + if (isset($xml->variables->record_seconds)) { + $record_length = urldecode($xml->variables->record_seconds); + } else { + $record_length = urldecode($xml->variables->duration); } - - //xml string is empty - if (empty($xml_string) && !empty($this->file)) { - unlink($this->xml_cdr_dir.'/'.$this->file); - return false; + } elseif (isset($xml->variables->cc_record_filename)) { + $record_path = dirname(urldecode($xml->variables->cc_record_filename)); + $record_name = basename(urldecode($xml->variables->cc_record_filename)); + $record_length = urldecode($xml->variables->record_seconds); + } elseif (!isset($record_path) && urldecode($xml->variables->last_app) == "record_session") { + $record_path = dirname(urldecode($xml->variables->last_arg)); + $record_name = basename(urldecode($xml->variables->last_arg)); + $record_length = urldecode($xml->variables->record_seconds); + } elseif (!empty($xml->variables->sofia_record_file)) { + $record_path = dirname(urldecode($xml->variables->sofia_record_file)); + $record_name = basename(urldecode($xml->variables->sofia_record_file)); + $record_length = urldecode($xml->variables->record_seconds); + } elseif (!empty($xml->variables->api_on_answer)) { + $command = str_replace("\n", " ", urldecode($xml->variables->api_on_answer)); + $parts = explode(" ", $command); + if ($parts[0] == "uuid_record") { + $recording = $parts[3]; + $record_path = dirname($recording); + $record_name = basename($recording); + $record_length = urldecode($xml->variables->duration); } - - //fix the xml by escaping the contents of - if (defined('STDIN')) { - $xml_string = preg_replace_callback("/<([^><]+)>(.*?[><].*?)<\/\g1>/", - function ($matches) { - return '<' . $matches[1] . '>' . - str_replace(">", ">", - str_replace("<", "<", $matches[2]) - ) . - ''; - }, - $xml_string - ); - } - - //remove invalid numeric xml tags - $xml_string = preg_replace('/<\/?\d+>/', '', $xml_string); - - //replace xml tag name with - $xml_string = preg_replace('/(<\/?)(set )([^>]*>)/i', '$1$3', $xml_string); - - //replace xml tag name <^^,default_language> with - $xml_string = preg_replace('/(<\/?)(\^\^,)([^>]*>)/', '$1$3', $xml_string); - - //replace xml tag name with - $xml_string = preg_replace('/(<\/?)(nolocal:)([^>]*>)/i', '$1$3', $xml_string); - - //remove spaces in the beginning of the xml open and closing tags - $xml_string = preg_replace('/(<\/?)\s*([\w:-]+)/', '$1$2', $xml_string); - - //disable xml entities - if (PHP_VERSION_ID < 80000) { libxml_disable_entity_loader(true); } - - //load the string into an xml object - $xml = simplexml_load_string($xml_string, 'SimpleXMLElement', LIBXML_NOCDATA); - if ($xml === false) { - //failed to load the XML, move the XML file to the failed directory - if (file_exists($this->xml_cdr_dir)) { - rename($this->xml_cdr_dir.'/'.$this->file, $this->xml_cdr_dir.'/failed/xml/'.$this->file); - } - - //return without saving the invalid xml - return false; - } - - //skip call detail records for calls blocked by call block - if (isset($xml->variables->call_block) && $xml->variables->call_block == 'true' && !$this->settings->get('call_block', 'save_call_detail_record', true)) { - //delete the xml cdr file - if (file_exists($this->xml_cdr_dir.'/'.$this->file)) { - unlink($this->xml_cdr_dir.'/'.$this->file); - } - - - //return without saving - return false; - } - - //check for duplicate call uuid's - $duplicate_uuid = false; - $uuid = urldecode($xml->variables->uuid); - if (empty($uuid)) { - $uuid = urldecode($xml->variables->call_uuid); - } - if ($uuid != null && is_uuid($uuid)) { - //check for duplicates - $sql = "select count(xml_cdr_uuid) "; - $sql .= "from v_xml_cdr "; - $sql .= "where xml_cdr_uuid = :xml_cdr_uuid "; - $parameters['xml_cdr_uuid'] = $uuid; - $count = $this->database->select($sql, $parameters, 'column'); - if ($count > 0) { - //duplicate uuid detected - $duplicate_uuid = true; - - //remove the file as the record already exists in the database - if (file_exists($this->xml_cdr_dir.'/'.$this->file)) { - unlink($this->xml_cdr_dir.'/'.$this->file); - } - - - //return without saving - return false; - } - unset($sql, $parameters); - } - - //set the call_direction - if (isset($xml->variables->call_direction)) { - $call_direction = urldecode($xml->variables->call_direction); - } - - //set the accountcode - if (isset($xml->variables->accountcode)) { - $accountcode = urldecode($xml->variables->accountcode); - } - - //process call detail record data - if ($duplicate_uuid == false && is_uuid($uuid)) { - - //get the caller ID from call flow caller profile - $i = 0; - foreach ($xml->callflow as $row) { - if ($i == 0) { - $caller_id_name = urldecode($row->caller_profile->caller_id_name); - $caller_id_number = urldecode($row->caller_profile->caller_id_number); - } - $i++; - } - unset($i); - - //get the caller ID from variables - if (!isset($caller_id_name) && isset($xml->variables->caller_id_name)) { - $caller_id_name = urldecode($xml->variables->caller_id_name); - } - if (!isset($caller_id_number) && isset($xml->variables->caller_id_number)) { - $caller_id_number = urldecode($xml->variables->caller_id_number); - } - if (!isset($caller_id_number) && isset($xml->variables->sip_from_user)) { - $caller_id_number = urldecode($xml->variables->sip_from_user); - } - - //if the origination caller id name and number are set then use them - if (isset($xml->variables->origination_caller_id_name)) { - $caller_id_name = urldecode($xml->variables->origination_caller_id_name); - } - if (isset($xml->variables->origination_caller_id_number)) { - $caller_id_number = urldecode($xml->variables->origination_caller_id_number); - } - - //if the caller ID was updated then update the caller ID - if (isset($xml->variables->effective_caller_id_name)) { - $caller_id_name = urldecode($xml->variables->effective_caller_id_name); - } - if (isset($xml->variables->effective_caller_id_number)) { - $caller_id_number = urldecode($xml->variables->effective_caller_id_number); - } - - //if intercept is used then update use the last sent callee id name and number - if (isset($xml->variables->last_app) && $xml->variables->last_app == 'intercept' && !empty($xml->variables->last_sent_callee_id_name)) { - $caller_id_name = urldecode($xml->variables->last_sent_callee_id_name); - } - if (isset($xml->variables->last_app) && $xml->variables->last_app == 'intercept' && !empty($xml->variables->last_sent_callee_id_number)) { - $caller_id_number = urldecode($xml->variables->last_sent_callee_id_number); - } - - //if the sip_from_domain and domain_name are not the same then original call direction was inbound - //when an inbound call is forward the call_direction is set to inbound and then updated to outbound - //use sip_from_display and sip_from_user to get the original caller ID instead of the updated caller ID info from the forward - if (isset($xml->variables->sip_from_domain) && urldecode($xml->variables->sip_from_domain) != urldecode($xml->variables->domain_name)) { - if (isset($xml->variables->sip_from_display)) { - $caller_id_name = urldecode($xml->variables->sip_from_display); - } - if (isset($xml->variables->sip_from_user)) { - $caller_id_number = urldecode($xml->variables->sip_from_user); - } - } - - //get the values from the callflow. - $i = 0; - foreach ($xml->callflow as $row) { - if ($i == 0) { - $context = urldecode($row->caller_profile->context); - $destination_number = urldecode($row->caller_profile->destination_number); - $network_addr = urldecode($row->caller_profile->network_addr); - } - $i++; - } - unset($i); - - //remove the provider prefix - if (isset($xml->variables->provider_prefix) && isset($destination_number)) { - $provider_prefix = $xml->variables->provider_prefix; - if ($provider_prefix == substr($destination_number, 0, strlen($provider_prefix))) { - $destination_number = substr($destination_number, strlen($provider_prefix), strlen($destination_number)); - } - } - - //get the caller_destination - if (isset($xml->variables->caller_destination) ) { - $caller_destination = urldecode($xml->variables->caller_destination); - } - if (isset($xml->variables->sip_h_caller_destination) ) { - $caller_destination = urldecode($xml->variables->sip_h_caller_destination); - } - if (!isset($caller_destination) && isset($xml->variables->dialed_user)) { - $caller_destination = urldecode($xml->variables->dialed_user); - } - - //set missed calls - if (isset($xml->variables->missed_call) && $xml->variables->missed_call == 'true') { - //allow calls marked as missed_call value to be overridden, an alternate destination may have answered the call - $missed_call = 'true'; - } - if (isset($call_direction) && $call_direction == 'inbound' - && isset($xml->variables->hangup_cause) - && $xml->variables->hangup_cause == 'ORIGINATOR_CANCEL') { - $missed_call = 'true'; - } - if (isset($xml->variables->cc_side) && $xml->variables->cc_side == 'agent') { - //call center - $missed_call = 'false'; - } - if (isset($xml->variables->fax_success)) { - //fax server - $missed_call = 'false'; - } - if (isset($xml->variables->hangup_cause) && $xml->variables->hangup_cause == 'LOSE_RACE') { - //ring group or multi destination bridge statement - $missed_call = 'false'; - } - if (isset($xml->variables->hangup_cause) && $xml->variables->hangup_cause == 'NO_ANSWER' && isset($xml->variables->originating_leg_uuid)) { - //ring group or multi destination bridge statement - $missed_call = 'false'; - } - if (isset($xml->variables->bridge_uuid) && !empty($xml->variables->bridge_uuid)) { - //call was bridged - $missed_call = 'false'; - } - if (isset($xml->variables->cc_side) && $xml->variables->cc_side == 'member' - && isset($xml->variables->cc_cause) && $xml->variables->cc_cause == 'cancel') { - //call center - $missed_call = 'true'; - } - if (isset($xml->variables->destination_number) && substr($xml->variables->destination_number, 0, 3) == '*99') { - //voicemail - $missed_call = 'true'; - } - if (isset($xml->variables->voicemail_answer_stamp) && !empty($xml->variables->voicemail_answer_stamp)) { - //voicemail - $missed_call = 'true'; - } - - //read the bridge statement variables - if (isset($xml->variables->last_app)) { - if (urldecode($xml->variables->last_app) == 'bridge') { - //get the variables from inside the { and } brackets - preg_match('/^\{([^}]+)\}/', urldecode($xml->variables->last_arg), $matches); - - //create a variables array from the comma delimitted string - $bridge_variables = explode(",", $matches[1]); - - //set bridge variables as variables - $x = 0; - if (!empty($bridge_variables)) { - foreach($bridge_variables as $variable) { - $pairs = explode("=", $variable); - $name = $pairs[0]; - $$name = $pairs[1]; - $x++; - } - } - } - } - - //get the last bridge_uuid from the call to preserve previous behavior - foreach ($xml->variables->bridge_uuids as $bridge) { - $last_bridge = urldecode($bridge); - } - - //determine the call status - $failed_array = array( - "CALL_REJECTED", - "CHAN_NOT_IMPLEMENTED", - "DESTINATION_OUT_OF_ORDER", - "EXCHANGE_ROUTING_ERROR", - "INCOMPATIBLE_DESTINATION", - "INVALID_NUMBER_FORMAT", - "MANDATORY_IE_MISSING", - "NETWORK_OUT_OF_ORDER", - "NORMAL_TEMPORARY_FAILURE", - "NORMAL_UNSPECIFIED", - "NO_ROUTE_DESTINATION", - "RECOVERY_ON_TIMER_EXPIRE", - "REQUESTED_CHAN_UNAVAIL", - "SUBSCRIBER_ABSENT", - "SYSTEM_SHUTDOWN", - "UNALLOCATED_NUMBER" - ); - if ($xml->variables->billsec > 0) { - $status = 'answered'; - } - if ($xml->variables->hangup_cause == 'NO_ANSWER') { - $status = 'no_answer'; - } - if ($xml->variables->hangup_cause == 'ORIGINATOR_CANCEL') { - $status = 'cancelled'; - } - if ($xml->variables->hangup_cause == 'USER_BUSY') { - $status = 'busy'; - } - if (in_array($xml->variables->hangup_cause, $failed_array)) { - $status = 'failed'; - } - if (!isset($status) && in_array($xml->variables->last_bridge_hangup_cause, $failed_array)) { - $status = 'failed'; - } - if ($xml->variables->cc_side == 'agent' && $xml->variables->billsec == 0) { - $status = 'no_answer'; - } - if (!isset($status) && $xml->variables->billsec == 0) { - $status = 'no_answer'; - } - if ($missed_call == 'true') { - $status = 'missed'; - } - if (substr($destination_number, 0, 3) == '*99') { - $status = 'voicemail'; - } - if (!empty($xml->variables->voicemail_message_seconds)) { - $status = 'voicemail'; - } - - //set the key - $key = 'xml_cdr'; - - //get the domain values from the xml - $domain_name = urldecode($xml->variables->domain_name); - $domain_uuid = urldecode($xml->variables->domain_uuid); - - //sanitize the caller ID - $caller_id_name = preg_replace('#[^a-zA-Z0-9\-.\#*@ ]#', '', $caller_id_name); - $caller_id_number = preg_replace('#[^0-9\-\#\*]#', '', $caller_id_number); - - //get the extension_uuid and then add it to the database fields array - if (isset($xml->variables->extension_uuid)) { - $extension_uuid = urldecode($xml->variables->extension_uuid); - $this->array[$key][0]['extension_uuid'] = $extension_uuid; - } - else { - if (isset($domain_uuid) && isset($xml->variables->dialed_user)) { - $sql = "select extension_uuid from v_extensions "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and (extension = :dialed_user or number_alias = :dialed_user) "; - $parameters['domain_uuid'] = $domain_uuid; - $parameters['dialed_user'] = $xml->variables->dialed_user; - $extension_uuid = $this->database->select($sql, $parameters, 'column'); - $this->array[$key][0]['extension_uuid'] = $extension_uuid; - unset($parameters); - } - if (isset($domain_uuid) && isset($xml->variables->referred_by_user)) { - $sql = "select extension_uuid from v_extensions "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and (extension = :referred_by_user or number_alias = :referred_by_user) "; - $parameters['domain_uuid'] = $domain_uuid; - $parameters['referred_by_user'] = $xml->variables->referred_by_user; - $extension_uuid = $this->database->select($sql, $parameters, 'column'); - $this->array[$key][0]['extension_uuid'] = $extension_uuid; - unset($parameters); - } - if (isset($domain_uuid) && isset($xml->variables->last_sent_callee_id_number)) { - $sql = "select extension_uuid from v_extensions "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and (extension = :last_sent_callee_id_number or number_alias = :last_sent_callee_id_number) "; - $parameters['domain_uuid'] = $domain_uuid; - $parameters['last_sent_callee_id_number'] = $xml->variables->last_sent_callee_id_number; - $extension_uuid = $this->database->select($sql, $parameters, 'column'); - $this->array[$key][0]['extension_uuid'] = $extension_uuid; - unset($parameters); - } - } - - //misc - $this->array[$key][0]['xml_cdr_uuid'] = $uuid; - $this->array[$key][0]['destination_number'] = $destination_number; - $this->array[$key][0]['sip_call_id'] = urldecode($xml->variables->sip_call_id); - $this->array[$key][0]['source_number'] = urldecode($xml->variables->effective_caller_id_number); - $this->array[$key][0]['network_addr'] = urldecode($xml->variables->sip_network_ip); - $this->array[$key][0]['missed_call'] = $missed_call; - $this->array[$key][0]['caller_id_name'] = $caller_id_name; - $this->array[$key][0]['caller_id_number'] = $caller_id_number; - $this->array[$key][0]['caller_destination'] = $caller_destination; - $this->array[$key][0]['accountcode'] = urldecode($accountcode); - $this->array[$key][0]['default_language'] = urldecode($xml->variables->default_language); - $this->array[$key][0]['bridge_uuid'] = urldecode($xml->variables->bridge_uuid) ?: $last_bridge; - //$this->array[$key][0]['digits_dialed'] = urldecode($xml->variables->digits_dialed); - $this->array[$key][0]['sip_hangup_disposition'] = urldecode($xml->variables->sip_hangup_disposition); - $this->array[$key][0]['pin_number'] = urldecode($xml->variables->pin_number); - $this->array[$key][0]['status'] = $status; - $this->array[$key][0]['ring_group_uuid'] = urldecode($xml->variables->ring_group_uuid); - $this->array[$key][0]['ivr_menu_uuid'] = urldecode($xml->variables->ivr_menu_uuid); - - //time - //catch invalid call detail records - if (empty($xml->variables->start_epoch)) { - //empty the array so it can't save - $this->array = null; - - //move the file to the failed location - $this->move_to_failed($this->file); - - //stop processing - return; - } - $start_epoch = urldecode($xml->variables->start_epoch); - $this->array[$key][0]['start_epoch'] = $start_epoch; - $this->array[$key][0]['start_stamp'] = is_numeric((int)$start_epoch) ? date('c', $start_epoch) : null; - $answer_epoch = urldecode($xml->variables->answer_epoch); - $this->array[$key][0]['answer_epoch'] = $answer_epoch; - $this->array[$key][0]['answer_stamp'] = is_numeric((int)$answer_epoch) ? date('c', $answer_epoch) : null; - $end_epoch = urldecode($xml->variables->end_epoch); - $this->array[$key][0]['end_epoch'] = $end_epoch; - $this->array[$key][0]['end_stamp'] = is_numeric((int)$end_epoch) ? date('c', $end_epoch) : null; - $this->array[$key][0]['duration'] = urldecode($xml->variables->billsec); - $this->array[$key][0]['mduration'] = urldecode($xml->variables->billmsec); - $this->array[$key][0]['billsec'] = urldecode($xml->variables->billsec); - $this->array[$key][0]['billmsec'] = urldecode($xml->variables->billmsec); - $this->array[$key][0]['hold_accum_seconds'] = urldecode($xml->variables->hold_accum_seconds); - - //codecs - $this->array[$key][0]['read_codec'] = urldecode($xml->variables->read_codec); - $this->array[$key][0]['read_rate'] = urldecode($xml->variables->read_rate); - $this->array[$key][0]['write_codec'] = urldecode($xml->variables->write_codec); - $this->array[$key][0]['write_rate'] = urldecode($xml->variables->write_rate); - $this->array[$key][0]['remote_media_ip'] = urldecode($xml->variables->remote_media_ip); - $this->array[$key][0]['hangup_cause'] = urldecode($xml->variables->hangup_cause); - $this->array[$key][0]['hangup_cause_q850'] = urldecode($xml->variables->hangup_cause_q850); - - //store the call direction - $this->array[$key][0]['direction'] = urldecode($call_direction); - - //call center - if ($xml->variables->cc_member_uuid == '_undef_') { $xml->variables->cc_member_uuid = ''; } - if ($xml->variables->cc_member_session_uuid == '_undef_') { $xml->variables->cc_member_session_uuid = ''; } - if ($xml->variables->cc_agent_uuid == '_undef_') { $xml->variables->cc_agent_uuid = ''; } - if ($xml->variables->call_center_queue_uuid == '_undef_') { $xml->variables->call_center_queue_uuid = ''; } - if ($xml->variables->cc_queue_joined_epoch == '_undef_') { $xml->variables->cc_queue_joined_epoch = ''; } - - $this->array[$key][0]['cc_side'] = urldecode($xml->variables->cc_side); - if (!empty($xml->variables->cc_member_uuid) && is_uuid(urldecode($xml->variables->cc_member_uuid))) { - $this->array[$key][0]['cc_member_uuid'] = urldecode($xml->variables->cc_member_uuid); - } - $this->array[$key][0]['cc_queue'] = urldecode($xml->variables->cc_queue); - if (!empty($xml->variables->call_center_queue_uuid) && is_uuid(urldecode($xml->variables->call_center_queue_uuid))) { - $call_center_queue_uuid = urldecode($xml->variables->call_center_queue_uuid); - } - if (empty($call_center_queue_uuid) && !empty($xml->variables->cc_queue)) { - $sql = "select call_center_queue_uuid from v_call_center_queues "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and queue_extension = :queue_extension "; - $parameters['domain_uuid'] = $domain_uuid; - $parameters['queue_extension'] = explode("@", $xml->variables->cc_queue)[0]; - $call_center_queue_uuid = $this->database->select($sql, $parameters, 'column'); - unset($parameters); - } - if (empty($extension_uuid) && !empty($xml->variables->cc_agent)) { - //use the agent_id as an alternative way to get the extension_uuid - $sql = "select extension_uuid from v_extensions "; - $sql .= "where domain_uuid = :domain_uuid "; - $sql .= "and extension in ( "; - $sql .= " select agent_id from v_call_center_agents where call_center_agent_uuid = :agent_id "; - $sql .= ") "; - $parameters['domain_uuid'] = $domain_uuid; - $parameters['agent_id'] = $xml->variables->cc_agent; - $extension_uuid = $this->database->select($sql, $parameters, 'column'); - $this->array[$key][0]['extension_uuid'] = $extension_uuid; - unset($parameters); - } - if (!empty($call_center_queue_uuid) && is_uuid($call_center_queue_uuid)) { - $this->array[$key][0]['call_center_queue_uuid'] = $call_center_queue_uuid; - } - if (!empty($xml->variables->cc_member_session_uuid) && is_uuid(urldecode($xml->variables->cc_member_session_uuid))) { - $this->array[$key][0]['cc_member_session_uuid'] = urldecode($xml->variables->cc_member_session_uuid); - } - if (!empty($xml->variables->cc_agent_uuid) && is_uuid(urldecode($xml->variables->cc_agent_uuid))) { - $this->array[$key][0]['cc_agent_uuid'] = urldecode($xml->variables->cc_agent_uuid); - } - $this->array[$key][0]['cc_agent'] = urldecode($xml->variables->cc_agent); - $this->array[$key][0]['cc_agent_type'] = urldecode($xml->variables->cc_agent_type); - $this->array[$key][0]['cc_agent_bridged'] = urldecode($xml->variables->cc_agent_bridged); - if (!empty($xml->variables->cc_queue_joined_epoch) && is_numeric((int)$xml->variables->cc_queue_joined_epoch)) { - $this->array[$key][0]['cc_queue_joined_epoch'] = urldecode($xml->variables->cc_queue_joined_epoch); - } - if (!empty($xml->variables->cc_queue_answered_epoch) && is_numeric((int)$xml->variables->cc_queue_answered_epoch)) { - $this->array[$key][0]['cc_queue_answered_epoch'] = urldecode($xml->variables->cc_queue_answered_epoch); - } - if (!empty($xml->variables->cc_queue_terminated_epoch) && is_numeric((int)trim($xml->variables->cc_queue_terminated_epoch))) { - $this->array[$key][0]['cc_queue_terminated_epoch'] = urldecode($xml->variables->cc_queue_terminated_epoch); - } - if (!empty($xml->variables->cc_queue_canceled_epoch) && is_numeric((int)$xml->variables->cc_queue_canceled_epoch)) { - $this->array[$key][0]['cc_queue_canceled_epoch'] = urldecode($xml->variables->cc_queue_canceled_epoch); - } - $this->array[$key][0]['cc_cancel_reason'] = urldecode($xml->variables->cc_cancel_reason); - $this->array[$key][0]['cc_cause'] = urldecode($xml->variables->cc_cause); - $this->array[$key][0]['waitsec'] = urldecode($xml->variables->waitsec); - if (urldecode($xml->variables->cc_side) == 'agent') { - $this->array[$key][0]['direction'] = 'inbound'; - } - - //set the provider id - if (isset($xml->variables->provider_uuid)) { - $this->array[$key][0]['provider_uuid'] = urldecode($xml->variables->provider_uuid); - } - - //app info - $this->array[$key][0]['last_app'] = urldecode($xml->variables->last_app); - $this->array[$key][0]['last_arg'] = urldecode($xml->variables->last_arg); - - //voicemail message success - if (!empty($xml->variables->voicemail_answer_stamp) && $xml->variables->voicemail_message_seconds > 0){ - $this->array[$key][0]['voicemail_message'] = "true"; - } - else { //if ($xml->variables->voicemail_action == "save") { - $this->array[$key][0]['voicemail_message'] = "false"; - } - - //conference - $this->array[$key][0]['conference_name'] = urldecode($xml->variables->conference_name); - $this->array[$key][0]['conference_uuid'] = urldecode($xml->variables->conference_uuid); - $this->array[$key][0]['conference_member_id'] = urldecode($xml->variables->conference_member_id); - - //call quality - $rtp_audio_in_mos = urldecode($xml->variables->rtp_audio_in_mos); - if (!empty($rtp_audio_in_mos)) { - $this->array[$key][0]['rtp_audio_in_mos'] = $rtp_audio_in_mos; - } - - //store the call leg - $this->array[$key][0]['leg'] = $leg; - - //store the originating leg uuid - $this->array[$key][0]['originating_leg_uuid'] = urldecode($xml->variables->originating_leg_uuid); - - //store post dial delay, in milliseconds - $this->array[$key][0]['pdd_ms'] = urldecode((int)$xml->variables->progress_mediamsec) + (int)urldecode($xml->variables->progressmsec); - - //get break down the date to year, month and day - $start_stamp = urldecode($xml->variables->start_stamp); - $start_time = strtotime($start_stamp); - $start_year = date("Y", $start_time); - $start_month = date("M", $start_time); - $start_day = date("d", $start_time); - - //get the domain name - if (empty($domain_name)) { - $domain_name = urldecode($xml->variables->dialed_domain); - } - if (empty($domain_name)) { - $domain_name = urldecode($xml->variables->sip_invite_domain); - } - if (empty($domain_name)) { - $domain_name = urldecode($xml->variables->sip_req_host); - } - if (empty($domain_name)) { - $presence_id = urldecode($xml->variables->presence_id); - if (!empty($presence_id)) { - $presence_array = explode($presence_id, '%40'); - $domain_name = $presence_array[1]; - } - } - - //dynamic cdr fields - if (!empty($this->settings->get('cdr', 'field'))) { - foreach ($this->settings->get('cdr', 'field') as $field) { - $fields = explode(",", $field); - $field_name = end($fields); - $this->fields[] = $field_name; - if (!isset($this->array[$key][0][$field_name])) { - if (count($fields) == 1) { - $this->array[$key][0][$field_name] = urldecode($xml->variables->{$fields[0]}); - } - if (count($fields) == 2) { - $this->array[$key][0][$field_name] = urldecode($xml->{$fields[0]}->{$fields[1]}); - } - if (count($fields) == 3) { - $this->array[$key][0][$field_name] = urldecode($xml->{$fields[0]}->{$fields[1]}->{$fields[2]}); - } - if (count($fields) == 4) { - $this->array[$key][0][$field_name] = urldecode($xml->{$fields[0]}->{$fields[1]}->{$fields[2]}->{$fields[3]}); - } - if (count($fields) == 5) { - $this->array[$key][0][$field_name] = urldecode($xml->{$fields[0]}->{$fields[1]}->{$fields[2]}->{$fields[3]}->{$fields[4]}); - } - } - } - } - - //send the domain name to the cdr log - //$this->log("\ndomain_name is `$domain_name`;\ndomain_uuid is '$domain_uuid'\n"); - - //get the domain_uuid with the domain_name - if (empty($domain_uuid)) { - $sql = "select domain_uuid from v_domains "; - if (empty($domain_name) && $context != 'public' && $context != 'default') { - $sql .= "where domain_name = :context "; - $parameters['context'] = $context; - } - else { - $sql .= "where domain_name = :domain_name "; - $parameters['domain_name'] = $domain_name; - } - $domain_uuid = $this->database->select($sql, $parameters, 'column'); - unset($parameters); - } - - //set values in the database - if (!empty($domain_uuid)) { - $this->array[$key][0]['domain_uuid'] = $domain_uuid; - } - if (!empty($domain_name)) { - $this->array[$key][0]['domain_name'] = $domain_name; - } - - //get the recording details - if (isset($xml->variables->record_path) && isset($xml->variables->record_name)) { - $record_path = urldecode($xml->variables->record_path); - $record_name = urldecode($xml->variables->record_name); - if (isset($xml->variables->record_seconds)) { - $record_length = urldecode($xml->variables->record_seconds); - } - else { - $record_length = urldecode($xml->variables->duration); - } - } - elseif (isset($xml->variables->cc_record_filename)) { - $record_path = dirname(urldecode($xml->variables->cc_record_filename)); - $record_name = basename(urldecode($xml->variables->cc_record_filename)); - $record_length = urldecode($xml->variables->record_seconds); - } - elseif (!isset($record_path) && urldecode($xml->variables->last_app) == "record_session") { - $record_path = dirname(urldecode($xml->variables->last_arg)); - $record_name = basename(urldecode($xml->variables->last_arg)); - $record_length = urldecode($xml->variables->record_seconds); - } - elseif (!empty($xml->variables->sofia_record_file)) { - $record_path = dirname(urldecode($xml->variables->sofia_record_file)); - $record_name = basename(urldecode($xml->variables->sofia_record_file)); - $record_length = urldecode($xml->variables->record_seconds); - } - elseif (!empty($xml->variables->api_on_answer)) { - $command = str_replace("\n", " ", urldecode($xml->variables->api_on_answer)); - $parts = explode(" ", $command); - if ($parts[0] == "uuid_record") { - $recording = $parts[3]; - $record_path = dirname($recording); - $record_name = basename($recording); - $record_length = urldecode($xml->variables->duration); - } - } - elseif (!empty($xml->variables->conference_recording)) { - $conference_recording = urldecode($xml->variables->conference_recording); - $record_path = dirname($conference_recording); - $record_name = basename($conference_recording); + } elseif (!empty($xml->variables->conference_recording)) { + $conference_recording = urldecode($xml->variables->conference_recording); + $record_path = dirname($conference_recording); + $record_name = basename($conference_recording); + $record_length = urldecode($xml->variables->duration); + } elseif (!empty($xml->variables->current_application_data)) { + $commands = explode(",", urldecode($xml->variables->current_application_data)); + foreach ($commands as $command) { + $cmd = explode("=", $command); + if ($cmd[0] == "api_on_answer") { + $a = explode("]", $cmd[1]); + $command = str_replace("'", "", $a[0]); + $parts = explode(" ", $command); + if ($parts[0] == "uuid_record") { + $recording = $parts[3]; + $record_path = dirname($recording); + $record_name = basename($recording); $record_length = urldecode($xml->variables->duration); } - elseif (!empty($xml->variables->current_application_data)) { - $commands = explode(",", urldecode($xml->variables->current_application_data)); - foreach ($commands as $command) { - $cmd = explode("=", $command); - if ($cmd[0] == "api_on_answer") { - $a = explode("]", $cmd[1]); - $command = str_replace("'", "", $a[0]); - $parts = explode(" ", $command); - if ($parts[0] == "uuid_record") { - $recording = $parts[3]; - $record_path = dirname($recording); - $record_name = basename($recording); - $record_length = urldecode($xml->variables->duration); - } - } - } - } - - //check to see if file exists with the default file name and path - if (empty($record_name)) { - $path = $this->settings->get('switch', 'recordings').'/'.$domain_name.'/archive/'.$start_year.'/'.$start_month.'/'.$start_day; - if (file_exists($path.'/'.$uuid.'.wav')) { - $record_path = $path; - $record_name = $uuid.'.wav'; - $record_length = urldecode($xml->variables->duration); - } elseif (file_exists($path.'/'.$uuid.'.mp3')) { - $record_path = $path; - $record_name = $uuid.'.mp3'; - $record_length = urldecode($xml->variables->duration); - } - } - - //last check - check to see if file exists with the bridge_uuid for the file name and path - if (empty($record_name)) { - $bridge_uuid = urldecode($xml->variables->bridge_uuid) ?: $last_bridge; - $path = $this->settings->get('switch', 'recordings').'/'.$domain_name.'/archive/'.$start_year.'/'.$start_month.'/'.$start_day; - if (file_exists($path.'/'.$bridge_uuid.'.wav')) { - $record_path = $path; - $record_name = $bridge_uuid.'.wav'; - $record_length = urldecode($xml->variables->duration); - } elseif (file_exists($path.'/'.$bridge_uuid.'.mp3')) { - $record_path = $path; - $record_name = $bridge_uuid.'.mp3'; - $record_length = urldecode($xml->variables->duration); - } - } - - //debug information - //echo "line: ".__line__; - //echo "record_path: ".$record_path."\n"; - //echo "record_name: ".$record_name."\n"; - //echo "record_length: ".$record_length."\n"; - //exit; - - //add the call record path, name and length to the database - if (isset($record_path) && isset($record_name) && file_exists($record_path.'/'.$record_name)) { - $this->array[$key][0]['record_path'] = $record_path; - $this->array[$key][0]['record_name'] = $record_name; - if (isset($record_length)) { - $this->array[$key][0]['record_length'] = $record_length; - } - else { - $this->array[$key][0]['record_length'] = urldecode($xml->variables->duration); - } - } - - //save the xml object to json - $this->json = json_encode($xml); - - //save to the database in xml format - if ($this->settings->get('cdr', 'format') == "xml" && $this->settings->get('cdr', 'storage') == "db") { - $this->array[$key][0]['xml'] = $xml_string; - } - - //build the call detail array with json decode - $this->call_details = json_decode($this->json, true); - - //save the call flow json - $key = 'xml_cdr_flow'; - $this->array[$key][0]['xml_cdr_flow_uuid'] = uuid(); - $this->array[$key][0]['xml_cdr_uuid'] = $uuid; - $this->array[$key][0]['domain_uuid'] = $domain_uuid ?? ''; - $this->array[$key][0]['call_flow'] = json_encode($this->call_flow()); - - //save to the database in json format - if ($this->settings->get('cdr', 'format') == "json" && $this->settings->get('cdr', 'storage') == "db") { - $key = 'xml_cdr_json'; - $this->array[$key][0]['xml_cdr_json_uuid'] = uuid(); - $this->array[$key][0]['xml_cdr_uuid'] = $uuid; - $this->array[$key][0]['domain_uuid'] = $domain_uuid ?? ''; - $this->array[$key][0]['json'] = $this->json; - } - - //save the call log to the database - if ($this->settings->get('cdr', 'call_log_enabled', false) && !empty($this->settings->get('switch', 'log')) && $this->settings->get('cdr', 'storage') == "db") { - //get the log content - $log_content = ''; - $handle = @fopen($this->settings->get('switch', 'log').'/freeswitch.log', "r"); - if ($handle) { - while (!feof($handle)) { - $line = stream_get_line($handle, 0, "\n"); - if (substr($line, 0, 36 ) === $uuid) { - $log_content .= substr($line, 37, strlen($line))."\n"; - } - } - fclose($handle); - } - - //save to the database - if (!empty($log_content)) { - $key = 'xml_cdr_logs'; - $this->array[$key][0]['xml_cdr_log_uuid'] = uuid(); - $this->array[$key][0]['xml_cdr_uuid'] = $uuid; - $this->array[$key][0]['domain_uuid'] = $domain_uuid ?? ''; - $this->array[$key][0]['log_date'] = 'now()'; - $this->array[$key][0]['log_content'] = $log_content; - } - } - - //store xml cdr on the file system as a file - if ($this->settings->get('cdr', 'storage') == "dir" && $error != "true") { - if (!empty($uuid)) { - $tmp_dir = $this->settings->get('switch', 'log').'/xml_cdr/archive/'.$start_year.'/'.$start_month.'/'.$start_day; - if(!file_exists($tmp_dir)) { - mkdir($tmp_dir, 0770, true); - } - if ($this->settings->get('cdr', 'format') == "xml") { - $tmp_file = $uuid.'.xml'; - $fh = fopen($tmp_dir.'/'.$tmp_file, 'w'); - fwrite($fh, $xml_string); - } - else { - $tmp_file = $uuid.'.json'; - $fh = fopen($tmp_dir.'/'.$tmp_file, 'w'); - fwrite($fh, json_encode($xml)); - } - fclose($fh); - } - } - unset($error); - - //save data to the database - $this->save(); - - //debug - //GLOBAL $insert_time,$insert_count; - //$insert_time+=microtime(true)-$time5_insert; //add this current query. - //$insert_count++; - - } //if ($duplicate_uuid == false) - } //function xml_array - - /** - * Build a call flow array based on call details. - * - * This method constructs an array that represents the call flow, utilizing the provided call_details array. Reverses the array to put the events in chronological order and adds profile end times. - * - * @return array The call flow array. - */ - public function call_flow() { - - //save the call flow to the database - if (isset($this->call_details['callflow'])) { - //set the call flow array - $call_flow_array = $this->call_details['callflow']; - - //normalize the array - if (!isset($call_flow_array[0])) { - $tmp = $call_flow_array; - unset($call_flow_array); - $call_flow_array[0] = $tmp; - } - - //reverse the array to put events in chronological order - $call_flow_array = array_reverse($call_flow_array); - - //add the profile end time to the call flow array - $i = 0; - foreach ($call_flow_array as $row) { - //set the profile end time - if (isset($call_flow_array[$i+1]["times"]["profile_created_time"])) { - $call_flow_array[$i]["times"]["profile_end_time"] = $call_flow_array[$i+1]["times"]["profile_created_time"]; } - else { - $call_flow_array[$i]["times"]["profile_end_time"] = urldecode($this->call_details['variables']['end_uepoch']); - } - $i++; - } - - //format the times in the call flow array and add the profile duration - $i = 0; - foreach ($call_flow_array as $row) { - foreach ($row["times"] as $name => $value) { - if ($value > 0) { - $call_flow_array[$i]["times"]["profile_duration_seconds"] = round(((int) $call_flow_array[$i]["times"]["profile_end_time"])/1000000 - ((int) $call_flow_array[$i]["times"]["profile_created_time"])/1000000); - $call_flow_array[$i]["times"]["profile_duration_formatted"] = gmdate("G:i:s", (int) $call_flow_array[$i]["times"]["profile_duration_seconds"]); - } - } - $i++; - } - - //add the call_flow to the array - return $call_flow_array; - } - } - - /** - * Build a call flow summary array based on call summary - * - * This method constructs an array that represents the call flow summary using the call flow array array. The call flow summary array contains a simplified view of the call flow. - * - * @return array The call flow summary array. - */ - public function call_flow_summary($call_flow_array) { - - //set the time zone - $time_zone = $this->settings->get('domain', 'time_zone', date_default_timezone_get()); - - //set the time zone for php - date_default_timezone_set($time_zone); - - //get the destination select list - if ($this->destinations) { - $destination_array = $this->destinations->get('dialplan'); - } - - //add new rows when callee_id_number exists - $new_rows = 0; - foreach ($call_flow_array as $key => $row) { - //for outbound calls update the times if the bridged_time to remove the call setup plus the ring time - if ($this->call_direction === 'outbound') { - if (isset($row["times"]["bridged_time"]) and $row["times"]["bridged_time"] > 0) { - //change the end time for the current row - $call_flow_array[$key]["times"]["profile_created_time"] = $row["times"]["bridged_time"]; - } - } - - //add a new row to the call summary - if (!empty($row["caller_profile"]["destination_number"]) - and !empty($row["caller_profile"]["callee_id_number"]) - and $this->call_direction !== 'outbound' - and $row["caller_profile"]["destination_number"] !== $row["caller_profile"]["callee_id_number"]) { - //build the base of the new_row array - $new_row["caller_profile"]["destination_number"] = $row["caller_profile"]["callee_id_number"]; - $new_row["caller_profile"]["caller_id_name"] = $row["caller_profile"]["callee_id_name"]; - $new_row["caller_profile"]["caller_id_number"] = $row["caller_profile"]["caller_id_number"]; - $new_row['times']["profile_created_time"] = $row["times"]["profile_created_time"]; - $new_row['times']["profile_end_time"] = $row["times"]["profile_end_time"]; - - //update the times if the transfer_time exists. The order of this is important add new row needs to be set before this code - if (isset($row["times"]["transfer_time"]) and $row["times"]["transfer_time"] > 0) { - //change the end time for the current row - $call_flow_array[$key+$new_rows]["times"]["profile_end_time"] = $row["times"]["transfer_time"]; - - //change the created time for the new row - $new_row['times']["profile_created_time"] = $row["times"]["transfer_time"]; - } - - //update the times if the bridged_time exists. The order of this is important add new row needs to be set before this code, and transfer_time needs to be before bridge_time - if (isset($row["times"]["bridged_time"]) and $row["times"]["bridged_time"] > 0) { - //change the end time for the current row - $call_flow_array[$key+$new_rows]["times"]["profile_end_time"] = $row["times"]["bridged_time"]; - - //change the created time for the new row - $new_row['times']["profile_created_time"] = $row["times"]["bridged_time"]; - } - - //increment the new row id - $new_rows++; - - //insert the new row into the array without overwriting an existing row - array_splice($call_flow_array, $key+$new_rows, 0, [$new_row]); - - //clean up - unset($new_row); } } - //format the times in the call flow array + //check to see if file exists with the default file name and path + if (empty($record_name)) { + $path = $this->settings->get('switch', 'recordings') . '/' . $domain_name . '/archive/' . $start_year . '/' . $start_month . '/' . $start_day; + if (file_exists($path . '/' . $uuid . '.wav')) { + $record_path = $path; + $record_name = $uuid . '.wav'; + $record_length = urldecode($xml->variables->duration); + } elseif (file_exists($path . '/' . $uuid . '.mp3')) { + $record_path = $path; + $record_name = $uuid . '.mp3'; + $record_length = urldecode($xml->variables->duration); + } + } + + //last check - check to see if file exists with the bridge_uuid for the file name and path + if (empty($record_name)) { + $bridge_uuid = urldecode($xml->variables->bridge_uuid) ?: $last_bridge; + $path = $this->settings->get('switch', 'recordings') . '/' . $domain_name . '/archive/' . $start_year . '/' . $start_month . '/' . $start_day; + if (file_exists($path . '/' . $bridge_uuid . '.wav')) { + $record_path = $path; + $record_name = $bridge_uuid . '.wav'; + $record_length = urldecode($xml->variables->duration); + } elseif (file_exists($path . '/' . $bridge_uuid . '.mp3')) { + $record_path = $path; + $record_name = $bridge_uuid . '.mp3'; + $record_length = urldecode($xml->variables->duration); + } + } + + //debug information + //echo "line: ".__line__; + //echo "record_path: ".$record_path."\n"; + //echo "record_name: ".$record_name."\n"; + //echo "record_length: ".$record_length."\n"; + //exit; + + //add the call record path, name and length to the database + if (isset($record_path) && isset($record_name) && file_exists($record_path . '/' . $record_name)) { + $this->array[$key][0]['record_path'] = $record_path; + $this->array[$key][0]['record_name'] = $record_name; + if (isset($record_length)) { + $this->array[$key][0]['record_length'] = $record_length; + } else { + $this->array[$key][0]['record_length'] = urldecode($xml->variables->duration); + } + } + + //save the xml object to json + $this->json = json_encode($xml); + + //save to the database in xml format + if ($this->settings->get('cdr', 'format') == "xml" && $this->settings->get('cdr', 'storage') == "db") { + $this->array[$key][0]['xml'] = $xml_string; + } + + //build the call detail array with json decode + $this->call_details = json_decode($this->json, true); + + //save the call flow json + $key = 'xml_cdr_flow'; + $this->array[$key][0]['xml_cdr_flow_uuid'] = uuid(); + $this->array[$key][0]['xml_cdr_uuid'] = $uuid; + $this->array[$key][0]['domain_uuid'] = $domain_uuid ?? ''; + $this->array[$key][0]['call_flow'] = json_encode($this->call_flow()); + + //save to the database in json format + if ($this->settings->get('cdr', 'format') == "json" && $this->settings->get('cdr', 'storage') == "db") { + $key = 'xml_cdr_json'; + $this->array[$key][0]['xml_cdr_json_uuid'] = uuid(); + $this->array[$key][0]['xml_cdr_uuid'] = $uuid; + $this->array[$key][0]['domain_uuid'] = $domain_uuid ?? ''; + $this->array[$key][0]['json'] = $this->json; + } + + //save the call log to the database + if ($this->settings->get('cdr', 'call_log_enabled', false) && !empty($this->settings->get('switch', 'log')) && $this->settings->get('cdr', 'storage') == "db") { + //get the log content + $log_content = ''; + $handle = @fopen($this->settings->get('switch', 'log') . '/freeswitch.log', "r"); + if ($handle) { + while (!feof($handle)) { + $line = stream_get_line($handle, 0, "\n"); + if (substr($line, 0, 36) === $uuid) { + $log_content .= substr($line, 37, strlen($line)) . "\n"; + } + } + fclose($handle); + } + + //save to the database + if (!empty($log_content)) { + $key = 'xml_cdr_logs'; + $this->array[$key][0]['xml_cdr_log_uuid'] = uuid(); + $this->array[$key][0]['xml_cdr_uuid'] = $uuid; + $this->array[$key][0]['domain_uuid'] = $domain_uuid ?? ''; + $this->array[$key][0]['log_date'] = 'now()'; + $this->array[$key][0]['log_content'] = $log_content; + } + } + + //store xml cdr on the file system as a file + if ($this->settings->get('cdr', 'storage') == "dir" && $error != "true") { + if (!empty($uuid)) { + $tmp_dir = $this->settings->get('switch', 'log') . '/xml_cdr/archive/' . $start_year . '/' . $start_month . '/' . $start_day; + if (!file_exists($tmp_dir)) { + mkdir($tmp_dir, 0770, true); + } + if ($this->settings->get('cdr', 'format') == "xml") { + $tmp_file = $uuid . '.xml'; + $fh = fopen($tmp_dir . '/' . $tmp_file, 'w'); + fwrite($fh, $xml_string); + } else { + $tmp_file = $uuid . '.json'; + $fh = fopen($tmp_dir . '/' . $tmp_file, 'w'); + fwrite($fh, json_encode($xml)); + } + fclose($fh); + } + } + unset($error); + + //save data to the database + $this->save(); + + //debug + //GLOBAL $insert_time,$insert_count; + //$insert_time+=microtime(true)-$time5_insert; //add this current query. + //$insert_count++; + + } //if ($duplicate_uuid == false) + } //function xml_array + + /** + * Build a call flow array based on call details. + * + * This method constructs an array that represents the call flow, utilizing the provided call_details array. + * Reverses the array to put the events in chronological order and adds profile end times. + * + * @return array The call flow array. + */ + public function call_flow() { + + //save the call flow to the database + if (isset($this->call_details['callflow'])) { + //set the call flow array + $call_flow_array = $this->call_details['callflow']; + + //normalize the array + if (!isset($call_flow_array[0])) { + $tmp = $call_flow_array; + unset($call_flow_array); + $call_flow_array[0] = $tmp; + } + + //reverse the array to put events in chronological order + $call_flow_array = array_reverse($call_flow_array); + + //add the profile end time to the call flow array $i = 0; - foreach ($call_flow_array as $key => $row) { + foreach ($call_flow_array as $row) { + //set the profile end time + if (isset($call_flow_array[$i + 1]["times"]["profile_created_time"])) { + $call_flow_array[$i]["times"]["profile_end_time"] = $call_flow_array[$i + 1]["times"]["profile_created_time"]; + } else { + $call_flow_array[$i]["times"]["profile_end_time"] = urldecode($this->call_details['variables']['end_uepoch']); + } + $i++; + } + + //format the times in the call flow array and add the profile duration + $i = 0; + foreach ($call_flow_array as $row) { foreach ($row["times"] as $name => $value) { if ($value > 0) { - $call_flow_array[$i]["times"][$name.'stamp'] = date("Y-m-d H:i:s", round((float) $value / 1000000, 0)); + $call_flow_array[$i]["times"]["profile_duration_seconds"] = round(((int)$call_flow_array[$i]["times"]["profile_end_time"]) / 1000000 - ((int)$call_flow_array[$i]["times"]["profile_created_time"]) / 1000000); + $call_flow_array[$i]["times"]["profile_duration_formatted"] = gmdate("G:i:s", (int)$call_flow_array[$i]["times"]["profile_duration_seconds"]); } } $i++; } - //build the call flow summary - $x = 0; $skip_row = false; - if (!empty($call_flow_array)) { - foreach ($call_flow_array as $row) { + //add the call_flow to the array + return $call_flow_array; + } + } - //skip this row - if ($skip_row) { - $skip_row = false; - continue; - } + /** + * Build a call flow summary array based on call summary + * + * This method constructs an array that represents the call flow summary using the call flow array array. The call + * flow summary array contains a simplified view of the call flow. + * + * @return array The call flow summary array. + */ + public function call_flow_summary($call_flow_array) { - //get the application array - if (!empty($destination_array) && !empty($row["caller_profile"]["destination_number"])) { - if ($this->call_direction == 'outbound' && !empty($row["caller_profile"]["username"])) { - $app = $this->find_app($destination_array, urldecode($row["caller_profile"]["username"])); - } - else { - $app = $this->find_app($destination_array, urldecode($row["caller_profile"]["destination_number"])); - } - } + //set the time zone + $time_zone = $this->settings->get('domain', 'time_zone', date_default_timezone_get()); - //call centers - if (!empty($app['application']) && $app['application'] == 'call_centers') { - if (isset($row["caller_profile"]["transfer_source"])) { - $app['status'] = 'answered'; //Out - } - else { - $app['status'] = 'waited'; //In - } - } + //set the time zone for php + date_default_timezone_set($time_zone); - //call flows - if (!empty($app['application']) && $app['application'] == 'call_flows') { - $app['status'] = 'routed'; - } - - //conferences - if (!empty($app['application']) && $app['application'] == 'conferences') { - $app['status'] = 'answered'; - } - - //destinations - if (!empty($app['application']) && $app['application'] == 'destinations') { - $app['status'] = 'routed'; - } - - //extensions - if (!empty($app['application']) && $app['application'] == 'extensions') { - if (!empty($row["times"]["profile_created_time"]) && !empty($row["times"]["profile_end_time"]) && (floor($row["times"]["profile_end_time"] / 1000000) - floor($row["times"]["profile_created_time"] / 1000000)) > 0) { - $app['status'] = 'answered'; - } - else { - $app['status'] = 'missed'; - } - } - - //ivr menus - if (!empty($app['application']) && $app['application'] == 'ivr_menus') { - $app['status'] = 'routed'; - } - - //add the source if there is a value - if (!empty($row["caller_profile"]["username"])) { - $app_source = $this->find_app($destination_array, $row["caller_profile"]["username"]); - $app['source_number'] = $row["caller_profile"]["username"]; - $app['source_uuid'] = $app_source['uuid']; - $app['source_name'] = $app_source['name']; - $app['source_label'] = $app_source['label']; - } - - //outbound routes - if ($this->call_direction == 'outbound') { - $status = 'missed'; - if (!empty($row["times"]["answered_time"])) { - $status = 'answered'; - } - - if (!empty($row["caller_profile"]["username"])) { - //add to the application array - $app['application'] = 'extensions'; - $app['status'] = $status; - $app['name'] = ''; - $app['label'] = 'extensions'; - } - elseif (empty($app['application'])) { - $app['application'] = 'diaplans'; - $app['uuid'] = ''; - $app['status'] = $status; - $app['name'] = 'Outbound'; - $app['label'] = 'Outbound'; - } - } - - //ring groups - if (!empty($app['application']) && $app['application'] == 'ring_groups') { - $app['status'] = 'waited'; - } - - //time conditions - if (!empty($app['application']) && $app['application'] == 'time_conditions') { - $app['status'] = 'routed'; - } - - //valet park - if ( - !empty($row["caller_profile"]["destination_number"]) - && ( - substr($row["caller_profile"]["destination_number"], 0, 4) == 'park' - || ( - substr($row["caller_profile"]["destination_number"], 0, 3) == '*59' - && strlen($row["caller_profile"]["destination_number"]) > 3 - ) - ) - ) { - //add items to the app array - $app['application'] = 'dialplans'; - $app['uuid'] = '46ae6d82-bb83-46a3-901d-33d0724347dd'; - $app['name'] = 'Park'; - $app['label'] = 'Park'; - - //set the call park status - if (strpos($row["caller_profile"]["transfer_source"], 'park+') !== false) { - //$app['status'] = 'In'; - $app['status'] = 'parked'; - - //skip the next row - $skip_row = true; - } - else { - //$app['status'] = 'Out'; - $app['status'] = 'unparked'; - } - } - - //conference - if (!empty($app['application']) && $app['application'] == 'conferences') { - $skip_row = true; - } - - //voicemails - if (!empty($app['application']) && $app['application'] == 'voicemails') { - $app['status'] = 'voicemail'; - } - - //debug - add the callee_id_number to the end of the status - if (isset($_REQUEST['debug']) && $_REQUEST['debug'] == 'true' - && !empty($row["caller_profile"]["destination_number"]) - && !empty($row["caller_profile"]["callee_id_number"]) - && $row["caller_profile"]["destination_number"] !== $row["caller_profile"]["callee_id_number"]) { - $app['status'] .= ' ('.$row["caller_profile"]["callee_id_number"].')'; - } - - //build the application urls - $application_url = ''; - if (!empty($app['application'])) { - //build the source url - $source_url = ''; - if (!empty($app["source_uuid"])) { - $source_url = "/app/".($app['application'] ?? '')."/".$this->singular($app['application'] ?? '')."_edit.php?id=".($app["source_uuid"] ?? ''); - } - - //build the destination url - $destination_url = ''; - $destination_url = "/app/".($app['application'] ?? '')."/".$this->singular($app['application'] ?? '')."_edit.php?id=".($app["uuid"] ?? ''); - $application_url = "/app/".($app['application'] ?? '')."/".($app['application'] ?? '').".php"; - if ($app['application'] == 'call_centers') { - $destination_url = "/app/".($app['application'] ?? '')."/".$this->singular($app['application'] ?? '')."_queue_edit.php?id=".($app["uuid"] ?? ''); - $application_url = "/app/".($app['application'] ?? '')."/".$this->singular($app['application'] ?? '')."_queues.php"; - } - } - - //add the application and destination details - $language2 = new text; - $text2 = $language2->get($this->settings->get('domain', 'language'), 'app/'.($app['application'] ?? '')); - $call_flow_summary[$x]["application_name"] = ($app['application'] ?? ''); - $call_flow_summary[$x]["application_label"] = trim($text2['title-'.($app['application'] ?? '')] ?? ''); - $call_flow_summary[$x]["application_icon"] = array("call_centers" => "fa-headset", "call_flows" => "fa-share-nodes", "conferences" => "fa-comments", "destinations" => "fa-right-to-bracket", "dialplans" => "fa-right-left", "extensions" => "fa-suitcase", "ivr_menus" => "fa-diagram-project", "ring_groups" => "fa-users", "time_conditions" => "fa-clock", "voicemails" => "fa-envelope"); - $call_flow_summary[$x]["call_direction"] = $this->call_direction; - - $call_flow_summary[$x]["application_url"] = $application_url; - if ($this->call_direction == 'outbound') { - $call_flow_summary[$x]["source_uuid"] = ($app['source_uuid'] ?? ''); - $call_flow_summary[$x]["source_number"] = ($app['source_number'] ?? ''); - $call_flow_summary[$x]["source_label"] = ($app['source_label'] ?? ''); - $call_flow_summary[$x]["source_url"] = $destination_url; - $call_flow_summary[$x]["source_name"] = $app['description'] ?? ''; - //$call_flow_summary[$x]["source_description"] = $app['description'] ?? ''; - $call_flow_summary[$x]["destination_uuid"] = ''; - $call_flow_summary[$x]["destination_number"] = ''; - $call_flow_summary[$x]["destination_label"] = ''; - $call_flow_summary[$x]["destination_url"] = ''; - $call_flow_summary[$x]["destination_description"] = ''; - } - else { - $call_flow_summary[$x]["source_uuid"] = ($app['source_uuid'] ?? ''); - $call_flow_summary[$x]["source_number"] = ($app['source_number'] ?? ''); - $call_flow_summary[$x]["source_label"] = ($app['source_label'] ?? ''); - $call_flow_summary[$x]["source_url"] = ($source_url ?? ''); - $call_flow_summary[$x]["destination_name"] = ($app['description'] ?? ''); - $call_flow_summary[$x]["destination_uuid"] = ($app['uuid'] ?? ''); - $call_flow_summary[$x]["destination_label"] = ($app['label'] ?? ''); - $call_flow_summary[$x]["destination_url"] = $destination_url ?? ''; - //$call_flow_summary[$x]["destination_description"] = $app['description'] ?? ''; - } - $call_flow_summary[$x]["destination_number"] = $row["caller_profile"]["destination_number"]; - $call_flow_summary[$x]["destination_status"] = ($app['status'] ?? ''); - $call_flow_summary[$x]["destination_description"] = $app['description'] ?? ''; - //$call_flow_summary[$x]["application"] = $app; - - //set the start and epoch - $profile_created_epoch = $row['times']['profile_created_time'] / 1000000; - $profile_end_epoch = $row['times']['profile_end_time'] / 1000000; - - //add the call flow times - $call_flow_summary[$x]["start_epoch"] = round($profile_created_epoch); - $call_flow_summary[$x]["end_epoch"] = round($profile_end_epoch); - $call_flow_summary[$x]["start_stamp"] = date("Y-m-d H:i:s", (int)$profile_created_epoch); - $call_flow_summary[$x]["end_stamp"] = date("Y-m-d H:i:s", (int)$profile_end_epoch); - $call_flow_summary[$x]["duration_seconds"] = round($profile_end_epoch - $profile_created_epoch); - $call_flow_summary[$x]["duration_formatted"] = gmdate("G:i:s",(int)$call_flow_summary[$x]["duration_seconds"]); - unset($app); - $x++; - } - } - unset($x); - - //set the last status to match the call detail record - $call_flow_summary[count($call_flow_summary ?? [])-1]['destination_status'] = $this->status; - - //return the call flow summary array - return $call_flow_summary; + //get the destination select list + if ($this->destinations) { + $destination_array = $this->destinations->get('dialplan'); } - //add a function to return the find_app - public function find_app($destination_array, $detail_action) { - - //add the destinations to the destination array - $sql = "select * from v_destinations "; - $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; - $parameters['domain_uuid'] = $this->domain_uuid; - $destinations = $this->database->select($sql, $parameters, 'all'); - if (!empty($destinations)) { - $i = 0; - foreach($destinations as $row) { - $destination_array['destinations'][$i]['application'] = 'destinations'; - $destination_array['destinations'][$i]['destination_uuid'] = $row["destination_uuid"]; - $destination_array['destinations'][$i]['uuid'] = $row["destination_uuid"]; - $destination_array['destinations'][$i]['dialplan_uuid'] = $row["dialplan_uuid"]; - $destination_array['destinations'][$i]['destination_type'] = $row["destination_type"]; - $destination_array['destinations'][$i]['destination_prefix'] = $row["destination_prefix"]; - $destination_array['destinations'][$i]['destination_number'] = $row["destination_number"]; - $destination_array['destinations'][$i]['extension'] = $row["destination_prefix"] . $row["destination_number"]; - $destination_array['destinations'][$i]['destination_trunk_prefix'] = $row["destination_trunk_prefix"]; - $destination_array['destinations'][$i]['destination_area_code'] = $row["destination_area_code"]; - $destination_array['destinations'][$i]['context'] = $row["destination_context"]; - $destination_array['destinations'][$i]['label'] = $row["destination_description"]; - $destination_array['destinations'][$i]['destination_enabled'] = $row["destination_enabled"]; - $destination_array['destinations'][$i]['name'] = $row["destination_description"]; - $destination_array['destinations'][$i]['description'] = $row["destination_description"]; - //$destination_array[$i]['destination_caller_id_name'] = $row["destination_caller_id_name"]; - //$destination_array[$i]['destination_caller_id_number'] = $row["destination_caller_id_number"]; - $i++; + //add new rows when callee_id_number exists + $new_rows = 0; + foreach ($call_flow_array as $key => $row) { + //for outbound calls update the times if the bridged_time to remove the call setup plus the ring time + if ($this->call_direction === 'outbound') { + if (isset($row["times"]["bridged_time"]) and $row["times"]["bridged_time"] > 0) { + //change the end time for the current row + $call_flow_array[$key]["times"]["profile_created_time"] = $row["times"]["bridged_time"]; } } - unset($sql, $parameters, $row); - $result = ''; - if (!empty($destination_array)) { - foreach($destination_array as $application => $row) { - if (!empty($row)) { - foreach ($row as $key => $value) { - //find matching destinations - if ($application == 'destinations') { - if ('+'.($value['destination_prefix'] ?? '').$value['destination_number'] == $detail_action - || ($value['destination_prefix'] ?? '').$value['destination_number'] == $detail_action - || $value['destination_number'] == $detail_action - || ($value['destination_trunk_prefix'] ?? '').$value['destination_number'] == $detail_action - || '+'.($value['destination_prefix'] ?? '').($value['destination_area_code'] ?? '').$value['destination_number'] == $detail_action - || ($value['destination_prefix'] ?? '').($value['destination_area_code'] ?? '').$value['destination_number'] == $detail_action - || ($value['destination_area_code'] ?? '').$value['destination_number'] == $detail_action) { - if (file_exists($_SERVER["PROJECT_ROOT"]."/app/".$application."/app_languages.php")) { - $value['application'] = $application; - return $value; - } - } - } + //add a new row to the call summary + if (!empty($row["caller_profile"]["destination_number"]) + and !empty($row["caller_profile"]["callee_id_number"]) + and $this->call_direction !== 'outbound' + and $row["caller_profile"]["destination_number"] !== $row["caller_profile"]["callee_id_number"]) { + //build the base of the new_row array + $new_row["caller_profile"]["destination_number"] = $row["caller_profile"]["callee_id_number"]; + $new_row["caller_profile"]["caller_id_name"] = $row["caller_profile"]["callee_id_name"]; + $new_row["caller_profile"]["caller_id_number"] = $row["caller_profile"]["caller_id_number"]; + $new_row['times']["profile_created_time"] = $row["times"]["profile_created_time"]; + $new_row['times']["profile_end_time"] = $row["times"]["profile_end_time"]; - //find all other matching actions - if (!empty($value['extension']) && $value['extension'] == $detail_action || preg_match('/^'.preg_quote($value['extension'] ?? '').'$/', $detail_action)) { - if (file_exists($_SERVER["PROJECT_ROOT"]."/app/".$application."/app_languages.php")) { + //update the times if the transfer_time exists. The order of this is important add new row needs to be set before this code + if (isset($row["times"]["transfer_time"]) and $row["times"]["transfer_time"] > 0) { + //change the end time for the current row + $call_flow_array[$key + $new_rows]["times"]["profile_end_time"] = $row["times"]["transfer_time"]; + + //change the created time for the new row + $new_row['times']["profile_created_time"] = $row["times"]["transfer_time"]; + } + + //update the times if the bridged_time exists. The order of this is important add new row needs to be set before this code, and transfer_time needs to be before bridge_time + if (isset($row["times"]["bridged_time"]) and $row["times"]["bridged_time"] > 0) { + //change the end time for the current row + $call_flow_array[$key + $new_rows]["times"]["profile_end_time"] = $row["times"]["bridged_time"]; + + //change the created time for the new row + $new_row['times']["profile_created_time"] = $row["times"]["bridged_time"]; + } + + //increment the new row id + $new_rows++; + + //insert the new row into the array without overwriting an existing row + array_splice($call_flow_array, $key + $new_rows, 0, [$new_row]); + + //clean up + unset($new_row); + } + } + + //format the times in the call flow array + $i = 0; + foreach ($call_flow_array as $key => $row) { + foreach ($row["times"] as $name => $value) { + if ($value > 0) { + $call_flow_array[$i]["times"][$name . 'stamp'] = date("Y-m-d H:i:s", round((float)$value / 1000000, 0)); + } + } + $i++; + } + + //build the call flow summary + $x = 0; + $skip_row = false; + if (!empty($call_flow_array)) { + foreach ($call_flow_array as $row) { + + //skip this row + if ($skip_row) { + $skip_row = false; + continue; + } + + //get the application array + if (!empty($destination_array) && !empty($row["caller_profile"]["destination_number"])) { + if ($this->call_direction == 'outbound' && !empty($row["caller_profile"]["username"])) { + $app = $this->find_app($destination_array, urldecode($row["caller_profile"]["username"])); + } else { + $app = $this->find_app($destination_array, urldecode($row["caller_profile"]["destination_number"])); + } + } + + //call centers + if (!empty($app['application']) && $app['application'] == 'call_centers') { + if (isset($row["caller_profile"]["transfer_source"])) { + $app['status'] = 'answered'; //Out + } else { + $app['status'] = 'waited'; //In + } + } + + //call flows + if (!empty($app['application']) && $app['application'] == 'call_flows') { + $app['status'] = 'routed'; + } + + //conferences + if (!empty($app['application']) && $app['application'] == 'conferences') { + $app['status'] = 'answered'; + } + + //destinations + if (!empty($app['application']) && $app['application'] == 'destinations') { + $app['status'] = 'routed'; + } + + //extensions + if (!empty($app['application']) && $app['application'] == 'extensions') { + if (!empty($row["times"]["profile_created_time"]) && !empty($row["times"]["profile_end_time"]) && (floor($row["times"]["profile_end_time"] / 1000000) - floor($row["times"]["profile_created_time"] / 1000000)) > 0) { + $app['status'] = 'answered'; + } else { + $app['status'] = 'missed'; + } + } + + //ivr menus + if (!empty($app['application']) && $app['application'] == 'ivr_menus') { + $app['status'] = 'routed'; + } + + //add the source if there is a value + if (!empty($row["caller_profile"]["username"])) { + $app_source = $this->find_app($destination_array, $row["caller_profile"]["username"]); + $app['source_number'] = $row["caller_profile"]["username"]; + $app['source_uuid'] = $app_source['uuid']; + $app['source_name'] = $app_source['name']; + $app['source_label'] = $app_source['label']; + } + + //outbound routes + if ($this->call_direction == 'outbound') { + $status = 'missed'; + if (!empty($row["times"]["answered_time"])) { + $status = 'answered'; + } + + if (!empty($row["caller_profile"]["username"])) { + //add to the application array + $app['application'] = 'extensions'; + $app['status'] = $status; + $app['name'] = ''; + $app['label'] = 'extensions'; + } elseif (empty($app['application'])) { + $app['application'] = 'diaplans'; + $app['uuid'] = ''; + $app['status'] = $status; + $app['name'] = 'Outbound'; + $app['label'] = 'Outbound'; + } + } + + //ring groups + if (!empty($app['application']) && $app['application'] == 'ring_groups') { + $app['status'] = 'waited'; + } + + //time conditions + if (!empty($app['application']) && $app['application'] == 'time_conditions') { + $app['status'] = 'routed'; + } + + //valet park + if ( + !empty($row["caller_profile"]["destination_number"]) + && ( + substr($row["caller_profile"]["destination_number"], 0, 4) == 'park' + || ( + substr($row["caller_profile"]["destination_number"], 0, 3) == '*59' + && strlen($row["caller_profile"]["destination_number"]) > 3 + ) + ) + ) { + //add items to the app array + $app['application'] = 'dialplans'; + $app['uuid'] = '46ae6d82-bb83-46a3-901d-33d0724347dd'; + $app['name'] = 'Park'; + $app['label'] = 'Park'; + + //set the call park status + if (strpos($row["caller_profile"]["transfer_source"], 'park+') !== false) { + //$app['status'] = 'In'; + $app['status'] = 'parked'; + + //skip the next row + $skip_row = true; + } else { + //$app['status'] = 'Out'; + $app['status'] = 'unparked'; + } + } + + //conference + if (!empty($app['application']) && $app['application'] == 'conferences') { + $skip_row = true; + } + + //voicemails + if (!empty($app['application']) && $app['application'] == 'voicemails') { + $app['status'] = 'voicemail'; + } + + //debug - add the callee_id_number to the end of the status + if (isset($_REQUEST['debug']) && $_REQUEST['debug'] == 'true' + && !empty($row["caller_profile"]["destination_number"]) + && !empty($row["caller_profile"]["callee_id_number"]) + && $row["caller_profile"]["destination_number"] !== $row["caller_profile"]["callee_id_number"]) { + $app['status'] .= ' (' . $row["caller_profile"]["callee_id_number"] . ')'; + } + + //build the application urls + $application_url = ''; + if (!empty($app['application'])) { + //build the source url + $source_url = ''; + if (!empty($app["source_uuid"])) { + $source_url = "/app/" . ($app['application'] ?? '') . "/" . $this->singular($app['application'] ?? '') . "_edit.php?id=" . ($app["source_uuid"] ?? ''); + } + + //build the destination url + $destination_url = ''; + $destination_url = "/app/" . ($app['application'] ?? '') . "/" . $this->singular($app['application'] ?? '') . "_edit.php?id=" . ($app["uuid"] ?? ''); + $application_url = "/app/" . ($app['application'] ?? '') . "/" . ($app['application'] ?? '') . ".php"; + if ($app['application'] == 'call_centers') { + $destination_url = "/app/" . ($app['application'] ?? '') . "/" . $this->singular($app['application'] ?? '') . "_queue_edit.php?id=" . ($app["uuid"] ?? ''); + $application_url = "/app/" . ($app['application'] ?? '') . "/" . $this->singular($app['application'] ?? '') . "_queues.php"; + } + } + + //add the application and destination details + $language2 = new text; + $text2 = $language2->get($this->settings->get('domain', 'language'), 'app/' . ($app['application'] ?? '')); + $call_flow_summary[$x]["application_name"] = ($app['application'] ?? ''); + $call_flow_summary[$x]["application_label"] = trim($text2['title-' . ($app['application'] ?? '')] ?? ''); + $call_flow_summary[$x]["application_icon"] = ["call_centers" => "fa-headset", "call_flows" => "fa-share-nodes", "conferences" => "fa-comments", "destinations" => "fa-right-to-bracket", "dialplans" => "fa-right-left", "extensions" => "fa-suitcase", "ivr_menus" => "fa-diagram-project", "ring_groups" => "fa-users", "time_conditions" => "fa-clock", "voicemails" => "fa-envelope"]; + $call_flow_summary[$x]["call_direction"] = $this->call_direction; + + $call_flow_summary[$x]["application_url"] = $application_url; + if ($this->call_direction == 'outbound') { + $call_flow_summary[$x]["source_uuid"] = ($app['source_uuid'] ?? ''); + $call_flow_summary[$x]["source_number"] = ($app['source_number'] ?? ''); + $call_flow_summary[$x]["source_label"] = ($app['source_label'] ?? ''); + $call_flow_summary[$x]["source_url"] = $destination_url; + $call_flow_summary[$x]["source_name"] = $app['description'] ?? ''; + //$call_flow_summary[$x]["source_description"] = $app['description'] ?? ''; + $call_flow_summary[$x]["destination_uuid"] = ''; + $call_flow_summary[$x]["destination_number"] = ''; + $call_flow_summary[$x]["destination_label"] = ''; + $call_flow_summary[$x]["destination_url"] = ''; + $call_flow_summary[$x]["destination_description"] = ''; + } else { + $call_flow_summary[$x]["source_uuid"] = ($app['source_uuid'] ?? ''); + $call_flow_summary[$x]["source_number"] = ($app['source_number'] ?? ''); + $call_flow_summary[$x]["source_label"] = ($app['source_label'] ?? ''); + $call_flow_summary[$x]["source_url"] = ($source_url ?? ''); + $call_flow_summary[$x]["destination_name"] = ($app['description'] ?? ''); + $call_flow_summary[$x]["destination_uuid"] = ($app['uuid'] ?? ''); + $call_flow_summary[$x]["destination_label"] = ($app['label'] ?? ''); + $call_flow_summary[$x]["destination_url"] = $destination_url ?? ''; + //$call_flow_summary[$x]["destination_description"] = $app['description'] ?? ''; + } + $call_flow_summary[$x]["destination_number"] = $row["caller_profile"]["destination_number"]; + $call_flow_summary[$x]["destination_status"] = ($app['status'] ?? ''); + $call_flow_summary[$x]["destination_description"] = $app['description'] ?? ''; + //$call_flow_summary[$x]["application"] = $app; + + //set the start and epoch + $profile_created_epoch = $row['times']['profile_created_time'] / 1000000; + $profile_end_epoch = $row['times']['profile_end_time'] / 1000000; + + //add the call flow times + $call_flow_summary[$x]["start_epoch"] = round($profile_created_epoch); + $call_flow_summary[$x]["end_epoch"] = round($profile_end_epoch); + $call_flow_summary[$x]["start_stamp"] = date("Y-m-d H:i:s", (int)$profile_created_epoch); + $call_flow_summary[$x]["end_stamp"] = date("Y-m-d H:i:s", (int)$profile_end_epoch); + $call_flow_summary[$x]["duration_seconds"] = round($profile_end_epoch - $profile_created_epoch); + $call_flow_summary[$x]["duration_formatted"] = gmdate("G:i:s", (int)$call_flow_summary[$x]["duration_seconds"]); + unset($app); + $x++; + } + } + unset($x); + + //set the last status to match the call detail record + $call_flow_summary[count($call_flow_summary ?? []) - 1]['destination_status'] = $this->status; + + //return the call flow summary array + return $call_flow_summary; + } + + //add a function to return the find_app + + /** + * Finds an application in the system based on a destination array and detail action. + * + * @param array $destination_array Destination array to search through + * @param string $detail_action Detail action to match against destinations + * + * @return mixed|null Application data if found, or null otherwise + */ + public function find_app($destination_array, $detail_action) { + + //add the destinations to the destination array + $sql = "select * from v_destinations "; + $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) "; + $parameters['domain_uuid'] = $this->domain_uuid; + $destinations = $this->database->select($sql, $parameters, 'all'); + if (!empty($destinations)) { + $i = 0; + foreach ($destinations as $row) { + $destination_array['destinations'][$i]['application'] = 'destinations'; + $destination_array['destinations'][$i]['destination_uuid'] = $row["destination_uuid"]; + $destination_array['destinations'][$i]['uuid'] = $row["destination_uuid"]; + $destination_array['destinations'][$i]['dialplan_uuid'] = $row["dialplan_uuid"]; + $destination_array['destinations'][$i]['destination_type'] = $row["destination_type"]; + $destination_array['destinations'][$i]['destination_prefix'] = $row["destination_prefix"]; + $destination_array['destinations'][$i]['destination_number'] = $row["destination_number"]; + $destination_array['destinations'][$i]['extension'] = $row["destination_prefix"] . $row["destination_number"]; + $destination_array['destinations'][$i]['destination_trunk_prefix'] = $row["destination_trunk_prefix"]; + $destination_array['destinations'][$i]['destination_area_code'] = $row["destination_area_code"]; + $destination_array['destinations'][$i]['context'] = $row["destination_context"]; + $destination_array['destinations'][$i]['label'] = $row["destination_description"]; + $destination_array['destinations'][$i]['destination_enabled'] = $row["destination_enabled"]; + $destination_array['destinations'][$i]['name'] = $row["destination_description"]; + $destination_array['destinations'][$i]['description'] = $row["destination_description"]; + //$destination_array[$i]['destination_caller_id_name'] = $row["destination_caller_id_name"]; + //$destination_array[$i]['destination_caller_id_number'] = $row["destination_caller_id_number"]; + $i++; + } + } + unset($sql, $parameters, $row); + + $result = ''; + if (!empty($destination_array)) { + foreach ($destination_array as $application => $row) { + if (!empty($row)) { + foreach ($row as $key => $value) { + //find matching destinations + if ($application == 'destinations') { + if ('+' . ($value['destination_prefix'] ?? '') . $value['destination_number'] == $detail_action + || ($value['destination_prefix'] ?? '') . $value['destination_number'] == $detail_action + || $value['destination_number'] == $detail_action + || ($value['destination_trunk_prefix'] ?? '') . $value['destination_number'] == $detail_action + || '+' . ($value['destination_prefix'] ?? '') . ($value['destination_area_code'] ?? '') . $value['destination_number'] == $detail_action + || ($value['destination_prefix'] ?? '') . ($value['destination_area_code'] ?? '') . $value['destination_number'] == $detail_action + || ($value['destination_area_code'] ?? '') . $value['destination_number'] == $detail_action) { + if (file_exists($_SERVER["PROJECT_ROOT"] . "/app/" . $application . "/app_languages.php")) { $value['application'] = $application; return $value; } } } - } - } - } - } - public function move_to_failed($failed_file) { - if (!file_exists($this->xml_cdr_dir.'/failed')) { - mkdir($this->xml_cdr_dir.'/failed', 0770, true); - //echo "Failed to create ".$this->xml_cdr_dir."/failed\n"; - } - rename($this->xml_cdr_dir.'/'.$failed_file, $this->xml_cdr_dir.'/failed/'.$failed_file); - } - - /** - * get xml from the filesystem and save it to the database - */ - public function read_files() { - $dir_handle = opendir($this->xml_cdr_dir); - $x = 0; - while($file = readdir($dir_handle)) { - if ($file != '.' && $file != '..') { - //used to test a single file - //$file = 'a_aa76e0af-461e-4d46-be23-433260307ede.cdr.xml'; - - //process the XML files - if (!is_dir($this->xml_cdr_dir . '/' . $file)) { - //get the leg of the call and the file prefix - if (substr($file, 0, 2) == "a_") { - $leg = "a"; - $file_prefix = substr($file, 2, 1); - } - else { - $leg = "b"; - $file_prefix = substr($file, 0, 1); - } - - //set the limit - if (isset($_SERVER["argv"][1]) && is_numeric((int)$_SERVER["argv"][1])) { - $limit = $_SERVER["argv"][1]; - } - else { - $limit = 1; - } - - //filter for specific files based on the file prefix - if (isset($_SERVER["argv"][2])) { - if (strpos($_SERVER["argv"][2], $file_prefix) !== FALSE) { - $import = true; - } - else { - $import = false; - } - } - else { - $import = true; - } - - //move the files that are too large or zero file size to the failed directory - if ($import && (filesize($this->xml_cdr_dir.'/'.$file) >= 3000000 || filesize($this->xml_cdr_dir.'/'.$file) == 0)) { - //echo "WARNING: File too large or zero file size. Moving $file to failed\n"; - if (!file_exists($this->xml_cdr_dir.'/failed')) { - mkdir($this->xml_cdr_dir.'/failed', 0770, true); - //echo "Failed to create ".$this->xml_cdr_dir."/failed\n"; - } - if (rename($this->xml_cdr_dir.'/'.$file, $this->xml_cdr_dir.'/failed/'.$file)) { - //echo "Moved $file successfully\n"; - } - } - - //import the call detail files are less than 3 mb - 3 million bytes - if ($import) { - //get the xml cdr string - $call_details = file_get_contents($this->xml_cdr_dir.'/'.$file); - - //set the file - $this->file = $file; - - //decode the xml string - if (substr($call_details, 0, 1) == '%') { - $call_details = urldecode($call_details); - } - - //parse the xml and insert the data into the db - $this->xml_array($x, $leg, $call_details); - - //increment the value - $x++; - } - - //if limit exceeded exit the loop - if ($limit == $x) { - //echo "limit: $limit count: $x if\n"; - break; - } - } - } - } - //close the directory handle - closedir($dir_handle); - } - //$this->read_files(); - - /** - * read the call detail records from the http post - */ - public function post() { - if (isset($_POST["cdr"])) { - - //debug method - //$this->log($_POST["cdr"]); - - //authentication for xml cdr http post - if (!defined('STDIN')) { - if ($this->settings->get('cdr', 'http_enabled', false)) { - //get the contents of xml_cdr.conf.xml - $conf_xml_string = file_get_contents($this->settings->get('switch', 'conf').'/autoload_configs/xml_cdr.conf.xml'); - - //parse the xml to get the call detail record info - try { - //disable xml entities - libxml_disable_entity_loader(true); - - //load the string into an xml object - $conf_xml = simplexml_load_string($conf_xml_string, 'SimpleXMLElement', LIBXML_NOCDATA); - } - catch(Exception $e) { - echo $e->getMessage(); - } - if (isset($conf_xml->settings->param)) { - foreach ($conf_xml->settings->param as $row) { - if ($row->attributes()->name == "cred") { - $auth_array = explode(":", $row->attributes()->value); - //echo "username: ".$auth_array[0]."
    \n"; - //echo "password: ".$auth_array[1]."
    \n"; - } - if ($row->attributes()->name == "url") { - //check name is equal to url - } - } - } - } - } - - //if http enabled is set to false then deny access - if (!defined('STDIN')) { - if (!$this->settings->get('cdr', 'http_enabled', false)) { - openlog('FusionPBX', LOG_NDELAY, LOG_AUTH); - syslog(LOG_WARNING, '['.$_SERVER['REMOTE_ADDR'].'] XML CDR import default setting http_enabled is not enabled. Line: '.__line__); - closelog(); - - echo "access denied\n"; - return; - } - } - - //check for the correct username and password - if (!defined('STDIN')) { - if ($this->settings->get('cdr', 'http_enabled', false)) { - if ($auth_array[0] == $_SERVER["PHP_AUTH_USER"] && $auth_array[1] == $_SERVER["PHP_AUTH_PW"]) { - //echo "access granted\n"; - $this->username = $auth_array[0]; - $this->password = $auth_array[1]; - } - else { - openlog('FusionPBX', LOG_NDELAY, LOG_AUTH); - syslog(LOG_WARNING, '['.$_SERVER['REMOTE_ADDR'].'] XML CDR import username or password failed. Line: '.__line__); - closelog(); - - echo "access denied\n"; - return; + //find all other matching actions + if (!empty($value['extension']) && $value['extension'] == $detail_action || preg_match('/^' . preg_quote($value['extension'] ?? '') . '$/', $detail_action)) { + if (file_exists($_SERVER["PROJECT_ROOT"] . "/app/" . $application . "/app_languages.php")) { + $value['application'] = $application; + return $value; } } } - - //loop through all attribues - //foreach($xml->settings->param[1]->attributes() as $a => $b) { - // echo $a,'="',$b,"\"\n"; - //} - - //get the http post variable - $xml_string = trim($_POST["cdr"]); - - //get the leg of the call - if (substr($_REQUEST['uuid'], 0, 2) == "a_") { - $leg = "a"; - } - else { - $leg = "b"; - } - - //log the xml cdr - $this->log("HTTP POST\n"); - - //parse the xml and insert the data into the database - $this->xml_array(0, $leg, $xml_string); + } } } - //$this->post(); + return null; + } - /** - * user summary returns an array - */ - public function user_summary() { + /** + * Moves a failed xml_cdr file to the failed directory + * + * @param string $failed_file Path to the failed xml_cdr file + * + * @return void + */ + public function move_to_failed($failed_file) { + if (!file_exists($this->xml_cdr_dir . '/failed')) { + mkdir($this->xml_cdr_dir . '/failed', 0770, true); + //echo "Failed to create ".$this->xml_cdr_dir."/failed\n"; + } + rename($this->xml_cdr_dir . '/' . $failed_file, $this->xml_cdr_dir . '/failed/' . $failed_file); + } - //set the time zone - $time_zone = $this->settings->get('domain', 'time_zone', date_default_timezone_get()); + /** + * Reads XML files from the object property xml_cdr_dir directory and imports call detail records into the database. + * + * @return void + */ + public function read_files() { + $dir_handle = opendir($this->xml_cdr_dir); + $x = 0; + while ($file = readdir($dir_handle)) { + if ($file != '.' && $file != '..') { + //used to test a single file + //$file = 'a_aa76e0af-461e-4d46-be23-433260307ede.cdr.xml'; - //set the time zone for php - date_default_timezone_set($time_zone); - - //build the date range - if ((!empty($this->start_stamp_begin) && strlen($this->start_stamp_begin) > 0) || !empty($this->start_stamp_end)) { - unset($this->quick_select); - if (strlen($this->start_stamp_begin) > 0 && !empty($this->start_stamp_end)) { - $sql_date_range = " and start_stamp between :start_stamp_begin::timestamptz and :start_stamp_end::timestamptz \n"; - $parameters['start_stamp_begin'] = $this->start_stamp_begin.':00.000 '.$time_zone; - $parameters['start_stamp_end'] = $this->start_stamp_end.':59.999 '.$time_zone; + //process the XML files + if (!is_dir($this->xml_cdr_dir . '/' . $file)) { + //get the leg of the call and the file prefix + if (substr($file, 0, 2) == "a_") { + $leg = "a"; + $file_prefix = substr($file, 2, 1); + } else { + $leg = "b"; + $file_prefix = substr($file, 0, 1); } - else { - if (!empty($this->start_stamp_begin)) { - $sql_date_range = "and start_stamp >= :start_stamp_begin::timestamptz \n"; - $parameters['start_stamp_begin'] = $this->start_stamp_begin.':00.000 '.$time_zone; + + //set the limit + if (isset($_SERVER["argv"][1]) && is_numeric((int)$_SERVER["argv"][1])) { + $limit = $_SERVER["argv"][1]; + } else { + $limit = 1; + } + + //filter for specific files based on the file prefix + if (isset($_SERVER["argv"][2])) { + if (strpos($_SERVER["argv"][2], $file_prefix) !== false) { + $import = true; + } else { + $import = false; } - if (!empty($this->start_stamp_end)) { - $sql_date_range .= "and start_stamp <= :start_stamp_end::timestamptz \n"; - $parameters['start_stamp_end'] = $this->start_stamp_end.':59.999 '.$time_zone; + } else { + $import = true; + } + + //move the files that are too large or zero file size to the failed directory + if ($import && (filesize($this->xml_cdr_dir . '/' . $file) >= 3000000 || filesize($this->xml_cdr_dir . '/' . $file) == 0)) { + //echo "WARNING: File too large or zero file size. Moving $file to failed\n"; + if (!file_exists($this->xml_cdr_dir . '/failed')) { + mkdir($this->xml_cdr_dir . '/failed', 0770, true); + //echo "Failed to create ".$this->xml_cdr_dir."/failed\n"; + } + if (rename($this->xml_cdr_dir . '/' . $file, $this->xml_cdr_dir . '/failed/' . $file)) { + //echo "Moved $file successfully\n"; + } + } + + //import the call detail files are less than 3 mb - 3 million bytes + if ($import) { + //get the xml cdr string + $call_details = file_get_contents($this->xml_cdr_dir . '/' . $file); + + //set the file + $this->file = $file; + + //decode the xml string + if (substr($call_details, 0, 1) == '%') { + $call_details = urldecode($call_details); + } + + //parse the xml and insert the data into the db + $this->xml_array($x, $leg, $call_details); + + //increment the value + $x++; + } + + //if limit exceeded exit the loop + if ($limit == $x) { + //echo "limit: $limit count: $x if\n"; + break; + } + } + } + } + //close the directory handle + closedir($dir_handle); + } + //$this->read_files(); + + /** + * Read the call detail records from the http post + * + * @return void + */ + public function post() { + if (isset($_POST["cdr"])) { + + //debug method + //$this->log($_POST["cdr"]); + + //authentication for xml cdr http post + if (!defined('STDIN')) { + if ($this->settings->get('cdr', 'http_enabled', false)) { + //get the contents of xml_cdr.conf.xml + $conf_xml_string = file_get_contents($this->settings->get('switch', 'conf') . '/autoload_configs/xml_cdr.conf.xml'); + + //parse the xml to get the call detail record info + try { + //disable xml entities + libxml_disable_entity_loader(true); + + //load the string into an xml object + $conf_xml = simplexml_load_string($conf_xml_string, 'SimpleXMLElement', LIBXML_NOCDATA); + } catch (Exception $e) { + echo $e->getMessage(); + } + if (isset($conf_xml->settings->param)) { + foreach ($conf_xml->settings->param as $row) { + if ($row->attributes()->name == "cred") { + $auth_array = explode(":", $row->attributes()->value); + //echo "username: ".$auth_array[0]."
    \n"; + //echo "password: ".$auth_array[1]."
    \n"; + } + if ($row->attributes()->name == "url") { + //check name is equal to url + } } } } - else { - switch ($this->quick_select) { - case 1: $sql_date_range = "and start_stamp >= '".date('Y-m-d H:i:s.000', strtotime("-1 week"))." ".$time_zone."'::timestamptz \n"; break; //last 7 days - case 2: $sql_date_range = "and start_stamp >= '".date('Y-m-d H:i:s.000', strtotime("-1 hour"))." ".$time_zone."'::timestamptz \n"; break; //last hour - case 3: $sql_date_range = "and start_stamp >= '".date('Y-m-d')." "."00:00:00.000 ".$time_zone."'::timestamptz \n"; break; //today - case 4: $sql_date_range = "and start_stamp between '".date('Y-m-d',strtotime("-1 day"))." "."00:00:00.000 ".$time_zone."'::timestamptz and '".date('Y-m-d',strtotime("-1 day"))." "."23:59:59.999 ".$time_zone."'::timestamptz \n"; break; //yesterday - case 5: $sql_date_range = "and start_stamp >= '".date('Y-m-d',strtotime("this week"))." "."00:00:00.000 ".$time_zone."' \n"; break; //this week - case 6: $sql_date_range = "and start_stamp >= '".date('Y-m-')."01 "."00:00:00.000 ".$time_zone."'::timestamptz \n"; break; //this month - case 7: $sql_date_range = "and start_stamp >= '".date('Y-')."01-01 "."00:00:00.000 ".$time_zone."'::timestamptz \n"; break; //this year + } + + //if http enabled is set to false then deny access + if (!defined('STDIN')) { + if (!$this->settings->get('cdr', 'http_enabled', false)) { + openlog('FusionPBX', LOG_NDELAY, LOG_AUTH); + syslog(LOG_WARNING, '[' . $_SERVER['REMOTE_ADDR'] . '] XML CDR import default setting http_enabled is not enabled. Line: ' . __line__); + closelog(); + + echo "access denied\n"; + return; + } + } + + //check for the correct username and password + if (!defined('STDIN')) { + if ($this->settings->get('cdr', 'http_enabled', false)) { + if ($auth_array[0] == $_SERVER["PHP_AUTH_USER"] && $auth_array[1] == $_SERVER["PHP_AUTH_PW"]) { + //echo "access granted\n"; + $this->username = $auth_array[0]; + $this->password = $auth_array[1]; + } else { + openlog('FusionPBX', LOG_NDELAY, LOG_AUTH); + syslog(LOG_WARNING, '[' . $_SERVER['REMOTE_ADDR'] . '] XML CDR import username or password failed. Line: ' . __line__); + closelog(); + + echo "access denied\n"; + return; } } + } - //calculate the summary data - $sql = "select \n"; - $sql .= "e.domain_uuid, \n"; - $sql .= "d.domain_name, \n"; - $sql .= "e.extension, \n"; - $sql .= "e.number_alias, \n"; + //loop through all attribues + //foreach($xml->settings->param[1]->attributes() as $a => $b) { + // echo $a,'="',$b,"\"\n"; + //} - //answered - $sql .= "count(*) \n"; - $sql .= "filter ( \n"; - $sql .= " where c.extension_uuid = e.extension_uuid \n"; - $sql .= " and status = 'answered' \n"; - if (!$this->include_internal) { - $sql .= "and (direction = 'inbound' or direction = 'outbound') \n"; - } - $sql .= ") \n"; - $sql .= "as answered, \n"; + //get the http post variable + $xml_string = trim($_POST["cdr"]); - //missed - $sql .= "count(*) \n"; - $sql .= "filter ( \n"; - $sql .= " where c.extension_uuid = e.extension_uuid \n"; - $sql .= " and status = 'missed' \n"; - $sql .= " and (cc_side is null or cc_side != 'agent') \n"; - if (!$this->include_internal) { - $sql .= "and (direction = 'inbound' or direction = 'outbound') \n"; - } - $sql .= ") \n"; - $sql .= "as missed, \n"; + //get the leg of the call + if (substr($_REQUEST['uuid'], 0, 2) == "a_") { + $leg = "a"; + } else { + $leg = "b"; + } - //voicemail - $sql .= "count(*) \n"; - $sql .= "filter ( \n"; - $sql .= " where c.extension_uuid = e.extension_uuid \n"; - $sql .= " and status = 'voicemail' \n"; - if (!$this->include_internal) { - $sql .= "and (direction = 'inbound' or direction = 'outbound') \n"; - } - $sql .= ") \n"; - $sql .= "as voicemail, \n"; + //log the xml cdr + $this->log("HTTP POST\n"); - //no answer - $sql .= "count(*) \n"; - $sql .= "filter ( \n"; - $sql .= " where c.extension_uuid = e.extension_uuid \n"; - $sql .= " and status = 'no_answer'\n"; - $sql .= " and (cc_side IS NOT NULL or cc_side ='agent')"; - if ($this->include_internal) { - $sql .= " and (direction = 'inbound' or direction = 'local') \n"; - } - else { - $sql .= "and direction = 'inbound' \n"; - } - $sql .= ") \n"; - $sql .= "as no_answer, \n"; + //parse the xml and insert the data into the database + $this->xml_array(0, $leg, $xml_string); + } + } + //$this->post(); - //busy - $sql .= "count(*) \n"; - $sql .= "filter ( \n"; - $sql .= " where c.extension_uuid = e.extension_uuid \n"; - $sql .= " and status = 'busy'\n"; - if ($this->include_internal) { - $sql .= " and (direction = 'inbound' or direction = 'local') \n"; - } - else { - $sql .= " and direction = 'inbound' \n"; - } - $sql .= ") \n"; - $sql .= "as busy, \n"; + /** + * Generates a user summary report. + * + * @return array User report summary + */ + public function user_summary() { - //aloc - $sql .= "sum(c.billsec) \n"; - $sql .= "filter ( \n"; - $sql .= " where c.extension_uuid = e.extension_uuid \n"; - if (!$this->include_internal) { - $sql .= " and (direction = 'inbound' or direction = 'outbound') \n"; - } - $sql .= " ) / \n"; - $sql .= "count(*) \n"; - $sql .= "filter ( \n"; - $sql .= " where c.extension_uuid = e.extension_uuid \n"; - if (!$this->include_internal) { - $sql .= " and (direction = 'inbound' or direction = 'outbound') \n"; - } - $sql .= ") \n"; - $sql .= "as aloc, \n"; + //set the time zone + $time_zone = $this->settings->get('domain', 'time_zone', date_default_timezone_get()); - //inbound calls - $sql .= "count(*) \n"; - $sql .= "filter ( \n"; - $sql .= " where c.extension_uuid = e.extension_uuid \n"; - if (!permission_exists('xml_cdr_enterprise_leg')) { - $sql .= " and originating_leg_uuid is null \n"; - } - elseif (!permission_exists('xml_cdr_lose_race')) { - $sql .= " and hangup_cause <> 'LOSE_RACE' \n"; - } - $sql .= " and (cc_side is null or cc_side != 'agent') \n"; - if ($this->include_internal) { - $sql .= " and (direction = 'inbound' or direction = 'local') \n"; - } - else { - $sql .= " and direction = 'inbound' \n"; - } - $sql .= ") \n"; - $sql .= "as inbound_calls, \n"; + //set the time zone for php + date_default_timezone_set($time_zone); - //inbound duration - $sql .= "sum(c.billsec) \n"; - $sql .= "filter ( \n"; - $sql .= " where c.extension_uuid = e.extension_uuid \n"; - if ($this->include_internal) { - $sql .= " and (direction = 'inbound' or direction = 'local')) \n"; + //build the date range + if ((!empty($this->start_stamp_begin) && strlen($this->start_stamp_begin) > 0) || !empty($this->start_stamp_end)) { + unset($this->quick_select); + if (strlen($this->start_stamp_begin) > 0 && !empty($this->start_stamp_end)) { + $sql_date_range = " and start_stamp between :start_stamp_begin::timestamptz and :start_stamp_end::timestamptz \n"; + $parameters['start_stamp_begin'] = $this->start_stamp_begin . ':00.000 ' . $time_zone; + $parameters['start_stamp_end'] = $this->start_stamp_end . ':59.999 ' . $time_zone; + } else { + if (!empty($this->start_stamp_begin)) { + $sql_date_range = "and start_stamp >= :start_stamp_begin::timestamptz \n"; + $parameters['start_stamp_begin'] = $this->start_stamp_begin . ':00.000 ' . $time_zone; } - else { - $sql .= " and direction = 'inbound') \n"; + if (!empty($this->start_stamp_end)) { + $sql_date_range .= "and start_stamp <= :start_stamp_end::timestamptz \n"; + $parameters['start_stamp_end'] = $this->start_stamp_end . ':59.999 ' . $time_zone; } - $sql .= "as inbound_duration, \n"; - - //outbound duration - $sql .= "count(*) \n"; - $sql .= "filter ( \n"; - $sql .= " where c.extension_uuid = e.extension_uuid \n"; - $sql .= " and c.direction = 'outbound' \n"; - $sql .= ") \n"; - $sql .= "as outbound_calls, \n"; - - $sql .= "sum(c.billsec) \n"; - $sql .= "filter ( \n"; - $sql .= " where c.extension_uuid = e.extension_uuid \n"; - $sql .= " and c.direction = 'outbound' \n"; - $sql .= ") \n"; - $sql .= "as outbound_duration, \n"; - - $sql .= "e.description \n"; - - $sql .= "from v_extensions as e, v_domains as d, \n"; - $sql .= "( select \n"; - $sql .= " domain_uuid, \n"; - $sql .= " extension_uuid, \n"; - $sql .= " caller_id_number, \n"; - $sql .= " destination_number, \n"; - $sql .= " missed_call, \n"; - $sql .= " answer_stamp, \n"; - $sql .= " bridge_uuid, \n"; - $sql .= " direction, \n"; - $sql .= " start_stamp, \n"; - $sql .= " hangup_cause, \n"; - $sql .= " originating_leg_uuid, \n"; - $sql .= " billsec, \n"; - $sql .= " cc_side, \n"; - $sql .= " sip_hangup_disposition, \n"; - $sql .= " voicemail_message, \n"; - $sql .= " status \n"; - $sql .= " from v_xml_cdr \n"; - if (!(!empty($_GET['show']) && $_GET['show'] === 'all' && permission_exists('xml_cdr_extension_summary_all'))) { - $sql .= " where domain_uuid = :domain_uuid \n"; - } - else { - $sql .= " where true \n"; - } - $sql .= "and leg = 'a' "; - $sql .= "and extension_uuid is not null "; - $sql .= $sql_date_range; - $sql .= ") as c \n"; - - $sql .= "where \n"; - $sql .= "d.domain_uuid = e.domain_uuid \n"; - if (!(!empty($_GET['show']) && $_GET['show'] === 'all' && permission_exists('xml_cdr_extension_summary_all'))) { - $sql .= "and e.domain_uuid = :domain_uuid \n"; - } - $sql .= "group by e.extension, e.domain_uuid, d.domain_uuid, e.number_alias, e.description \n"; - $sql .= "order by extension asc \n"; - if (!(!empty($_GET['show']) && $_GET['show'] === 'all' && permission_exists('xml_cdr_extension_summary_all'))) { - $parameters['domain_uuid'] = $this->domain_uuid; - } - $summary = $this->database->select($sql, $parameters, 'all'); - unset($parameters); - - //return the array - return $summary; + } + } else { + switch ($this->quick_select) { + case 1: + $sql_date_range = "and start_stamp >= '" . date('Y-m-d H:i:s.000', strtotime("-1 week")) . " " . $time_zone . "'::timestamptz \n"; + break; //last 7 days + case 2: + $sql_date_range = "and start_stamp >= '" . date('Y-m-d H:i:s.000', strtotime("-1 hour")) . " " . $time_zone . "'::timestamptz \n"; + break; //last hour + case 3: + $sql_date_range = "and start_stamp >= '" . date('Y-m-d') . " " . "00:00:00.000 " . $time_zone . "'::timestamptz \n"; + break; //today + case 4: + $sql_date_range = "and start_stamp between '" . date('Y-m-d', strtotime("-1 day")) . " " . "00:00:00.000 " . $time_zone . "'::timestamptz and '" . date('Y-m-d', strtotime("-1 day")) . " " . "23:59:59.999 " . $time_zone . "'::timestamptz \n"; + break; //yesterday + case 5: + $sql_date_range = "and start_stamp >= '" . date('Y-m-d', strtotime("this week")) . " " . "00:00:00.000 " . $time_zone . "' \n"; + break; //this week + case 6: + $sql_date_range = "and start_stamp >= '" . date('Y-m-') . "01 " . "00:00:00.000 " . $time_zone . "'::timestamptz \n"; + break; //this month + case 7: + $sql_date_range = "and start_stamp >= '" . date('Y-') . "01-01 " . "00:00:00.000 " . $time_zone . "'::timestamptz \n"; + break; //this year + } } - /** - * download the recordings - */ - public function download() { + //calculate the summary data + $sql = "select \n"; + $sql .= "e.domain_uuid, \n"; + $sql .= "d.domain_name, \n"; + $sql .= "e.extension, \n"; + $sql .= "e.number_alias, \n"; - //check the permission - if (!permission_exists('xml_cdr_view')) { - //echo "permission denied"; - return; - } + //answered + $sql .= "count(*) \n"; + $sql .= "filter ( \n"; + $sql .= " where c.extension_uuid = e.extension_uuid \n"; + $sql .= " and status = 'answered' \n"; + if (!$this->include_internal) { + $sql .= "and (direction = 'inbound' or direction = 'outbound') \n"; + } + $sql .= ") \n"; + $sql .= "as answered, \n"; - //check for a valid uuid - if (!is_uuid($this->recording_uuid)) { - //echo "invalid uuid"; - return; - } + //missed + $sql .= "count(*) \n"; + $sql .= "filter ( \n"; + $sql .= " where c.extension_uuid = e.extension_uuid \n"; + $sql .= " and status = 'missed' \n"; + $sql .= " and (cc_side is null or cc_side != 'agent') \n"; + if (!$this->include_internal) { + $sql .= "and (direction = 'inbound' or direction = 'outbound') \n"; + } + $sql .= ") \n"; + $sql .= "as missed, \n"; - //get call recording from database - $sql = "select record_name, record_path from v_xml_cdr "; - $sql .= "where xml_cdr_uuid = :xml_cdr_uuid "; - $parameters['xml_cdr_uuid'] = $this->recording_uuid; - $row = $this->database->select($sql, $parameters, 'row'); - if (!empty($row) && is_array($row)) { - $record_name = $row['record_name']; - $record_path = $row['record_path']; - } - unset ($sql, $parameters, $row); + //voicemail + $sql .= "count(*) \n"; + $sql .= "filter ( \n"; + $sql .= " where c.extension_uuid = e.extension_uuid \n"; + $sql .= " and status = 'voicemail' \n"; + if (!$this->include_internal) { + $sql .= "and (direction = 'inbound' or direction = 'outbound') \n"; + } + $sql .= ") \n"; + $sql .= "as voicemail, \n"; - //build full path - $record_file = $record_path.'/'.$record_name; + //no answer + $sql .= "count(*) \n"; + $sql .= "filter ( \n"; + $sql .= " where c.extension_uuid = e.extension_uuid \n"; + $sql .= " and status = 'no_answer'\n"; + $sql .= " and (cc_side IS NOT NULL or cc_side ='agent')"; + if ($this->include_internal) { + $sql .= " and (direction = 'inbound' or direction = 'local') \n"; + } else { + $sql .= "and direction = 'inbound' \n"; + } + $sql .= ") \n"; + $sql .= "as no_answer, \n"; - //download the file - if ($record_file != '/' && file_exists($record_file)) { - ob_clean(); - $fd = fopen($record_file, "rb"); - if ($this->binary) { - header("Content-Type: application/force-download"); - header("Content-Type: application/octet-stream"); - header("Content-Type: application/download"); - header("Content-Description: File Transfer"); - } - else { - $file_ext = pathinfo($record_name, PATHINFO_EXTENSION); - switch ($file_ext) { - case "wav" : header("Content-Type: audio/x-wav"); break; - case "mp3" : header("Content-Type: audio/mpeg"); break; - case "ogg" : header("Content-Type: audio/ogg"); break; - } - } - $record_name = preg_replace('#[^a-zA-Z0-9_\-\.]#', '', $record_name); - header('Content-Disposition: attachment; filename="'.$record_name.'"'); - header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 - header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past - if ($this->binary) { - header("Content-Length: ".filesize($record_file)); - } - ob_clean(); + //busy + $sql .= "count(*) \n"; + $sql .= "filter ( \n"; + $sql .= " where c.extension_uuid = e.extension_uuid \n"; + $sql .= " and status = 'busy'\n"; + if ($this->include_internal) { + $sql .= " and (direction = 'inbound' or direction = 'local') \n"; + } else { + $sql .= " and direction = 'inbound' \n"; + } + $sql .= ") \n"; + $sql .= "as busy, \n"; - //content-range - if (isset($_SERVER['HTTP_RANGE']) && !$this->binary) { - $this->range_download($record_file); - } + //aloc + $sql .= "sum(c.billsec) \n"; + $sql .= "filter ( \n"; + $sql .= " where c.extension_uuid = e.extension_uuid \n"; + if (!$this->include_internal) { + $sql .= " and (direction = 'inbound' or direction = 'outbound') \n"; + } + $sql .= " ) / \n"; + $sql .= "count(*) \n"; + $sql .= "filter ( \n"; + $sql .= " where c.extension_uuid = e.extension_uuid \n"; + if (!$this->include_internal) { + $sql .= " and (direction = 'inbound' or direction = 'outbound') \n"; + } + $sql .= ") \n"; + $sql .= "as aloc, \n"; - fpassthru($fd); - } + //inbound calls + $sql .= "count(*) \n"; + $sql .= "filter ( \n"; + $sql .= " where c.extension_uuid = e.extension_uuid \n"; + if (!permission_exists('xml_cdr_enterprise_leg')) { + $sql .= " and originating_leg_uuid is null \n"; + } elseif (!permission_exists('xml_cdr_lose_race')) { + $sql .= " and hangup_cause <> 'LOSE_RACE' \n"; + } + $sql .= " and (cc_side is null or cc_side != 'agent') \n"; + if ($this->include_internal) { + $sql .= " and (direction = 'inbound' or direction = 'local') \n"; + } else { + $sql .= " and direction = 'inbound' \n"; + } + $sql .= ") \n"; + $sql .= "as inbound_calls, \n"; - } //end download method + //inbound duration + $sql .= "sum(c.billsec) \n"; + $sql .= "filter ( \n"; + $sql .= " where c.extension_uuid = e.extension_uuid \n"; + if ($this->include_internal) { + $sql .= " and (direction = 'inbound' or direction = 'local')) \n"; + } else { + $sql .= " and direction = 'inbound') \n"; + } + $sql .= "as inbound_duration, \n"; - /* - * range download method (helps safari play audio sources) - */ - private function range_download($file) { - $fp = @fopen($file, 'rb'); + //outbound duration + $sql .= "count(*) \n"; + $sql .= "filter ( \n"; + $sql .= " where c.extension_uuid = e.extension_uuid \n"; + $sql .= " and c.direction = 'outbound' \n"; + $sql .= ") \n"; + $sql .= "as outbound_calls, \n"; - $size = filesize($file); // File size - $length = $size; // Content length - $start = 0; // Start byte - $end = $size - 1; // End byte - // Now that we've gotten so far without errors we send the accept range header - /* At the moment we only support single ranges. - * Multiple ranges requires some more work to ensure it works correctly - * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 - * - * Multirange support annouces itself with: - * header('Accept-Ranges: bytes'); - * - * Multirange content must be sent with multipart/byteranges mediatype, - * (mediatype = mimetype) - * as well as a boundry header to indicate the various chunks of data. - */ - header("Accept-Ranges: 0-".$length); - // header('Accept-Ranges: bytes'); - // multipart/byteranges - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 - if (isset($_SERVER['HTTP_RANGE'])) { + $sql .= "sum(c.billsec) \n"; + $sql .= "filter ( \n"; + $sql .= " where c.extension_uuid = e.extension_uuid \n"; + $sql .= " and c.direction = 'outbound' \n"; + $sql .= ") \n"; + $sql .= "as outbound_duration, \n"; - $c_start = $start; - $c_end = $end; - // Extract the range string - list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2); - // Make sure the client hasn't sent us a multibyte range - if (strpos($range, ',') !== false) { - // (?) Shoud this be issued here, or should the first - // range be used? Or should the header be ignored and - // we output the whole content? - header('HTTP/1.1 416 Requested Range Not Satisfiable'); - header("Content-Range: bytes $start-$end/$size"); - // (?) Echo some info to the client? - exit; - } - // If the range starts with an '-' we start from the beginning - // If not, we forward the file pointer - // And make sure to get the end byte if specified - if ($range[0] == '-') { - // The n-number of the last bytes is requested - $c_start = $size - substr($range, 1); - } - else { - $range = explode('-', $range); - $c_start = $range[0]; - $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size; - } - /* Check the range and make sure it's treated according to the specs. - * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - */ - // End bytes can not be larger than $end. - $c_end = ($c_end > $end) ? $end : $c_end; - // Validate the requested range and return an error if it's not correct. - if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) { + $sql .= "e.description \n"; - header('HTTP/1.1 416 Requested Range Not Satisfiable'); - header("Content-Range: bytes $start-$end/$size"); - // (?) Echo some info to the client? - exit; - } - $start = $c_start; - $end = $c_end; - $length = $end - $start + 1; // Calculate new content length - fseek($fp, $start); - header('HTTP/1.1 206 Partial Content'); - } - // Notify the client the byte range we'll be outputting - header("Content-Range: bytes $start-$end/$size"); - header("Content-Length: $length"); + $sql .= "from v_extensions as e, v_domains as d, \n"; + $sql .= "( select \n"; + $sql .= " domain_uuid, \n"; + $sql .= " extension_uuid, \n"; + $sql .= " caller_id_number, \n"; + $sql .= " destination_number, \n"; + $sql .= " missed_call, \n"; + $sql .= " answer_stamp, \n"; + $sql .= " bridge_uuid, \n"; + $sql .= " direction, \n"; + $sql .= " start_stamp, \n"; + $sql .= " hangup_cause, \n"; + $sql .= " originating_leg_uuid, \n"; + $sql .= " billsec, \n"; + $sql .= " cc_side, \n"; + $sql .= " sip_hangup_disposition, \n"; + $sql .= " voicemail_message, \n"; + $sql .= " status \n"; + $sql .= " from v_xml_cdr \n"; + if (!(!empty($_GET['show']) && $_GET['show'] === 'all' && permission_exists('xml_cdr_extension_summary_all'))) { + $sql .= " where domain_uuid = :domain_uuid \n"; + } else { + $sql .= " where true \n"; + } + $sql .= "and leg = 'a' "; + $sql .= "and extension_uuid is not null "; + $sql .= $sql_date_range; + $sql .= ") as c \n"; - // Start buffered download - $buffer = 1024 * 8; - while(!feof($fp) && ($p = ftell($fp)) <= $end) { - if ($p + $buffer > $end) { - // In case we're only outputtin a chunk, make sure we don't - // read past the length - $buffer = $end - $p + 1; - } - set_time_limit(0); // Reset time limit for big files - echo fread($fp, $buffer); - flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit. - } + $sql .= "where \n"; + $sql .= "d.domain_uuid = e.domain_uuid \n"; + if (!(!empty($_GET['show']) && $_GET['show'] === 'all' && permission_exists('xml_cdr_extension_summary_all'))) { + $sql .= "and e.domain_uuid = :domain_uuid \n"; + } + $sql .= "group by e.extension, e.domain_uuid, d.domain_uuid, e.number_alias, e.description \n"; + $sql .= "order by extension asc \n"; + if (!(!empty($_GET['show']) && $_GET['show'] === 'all' && permission_exists('xml_cdr_extension_summary_all'))) { + $parameters['domain_uuid'] = $this->domain_uuid; + } + $summary = $this->database->select($sql, $parameters, 'all'); + unset($parameters); - fclose($fp); + //return the array + return $summary; + } + + /** + * Download a call recording associated with the current recording UUID in the object property recording_uuid. + * + * This method validates permissions, checks for a valid UUID, retrieves the + * recording path and filename from the database, and streams the file to the + * client with appropriate headers. Supports both binary and non-binary + * downloads, including HTTP range requests for non-binary audio files. + * + * @return void + */ + public function download() { + + //check the permission + if (!permission_exists('xml_cdr_view')) { + //echo "permission denied"; + return; } - /** - * delete records - */ - public function delete($records) { - if (!permission_exists($this->permission_prefix.'delete')) { - return false; + //check for a valid uuid + if (!is_uuid($this->recording_uuid)) { + //echo "invalid uuid"; + return; + } + + //get call recording from database + $sql = "select record_name, record_path from v_xml_cdr "; + $sql .= "where xml_cdr_uuid = :xml_cdr_uuid "; + $parameters['xml_cdr_uuid'] = $this->recording_uuid; + $row = $this->database->select($sql, $parameters, 'row'); + if (!empty($row) && is_array($row)) { + $record_name = $row['record_name']; + $record_path = $row['record_path']; + } + unset ($sql, $parameters, $row); + + //build full path + $record_file = $record_path . '/' . $record_name; + + //download the file + if ($record_file != '/' && file_exists($record_file)) { + ob_clean(); + $fd = fopen($record_file, "rb"); + if ($this->binary) { + header("Content-Type: application/force-download"); + header("Content-Type: application/octet-stream"); + header("Content-Type: application/download"); + header("Content-Description: File Transfer"); + } else { + $file_ext = pathinfo($record_name, PATHINFO_EXTENSION); + switch ($file_ext) { + case "wav" : + header("Content-Type: audio/x-wav"); + break; + case "mp3" : + header("Content-Type: audio/mpeg"); + break; + case "ogg" : + header("Content-Type: audio/ogg"); + break; + } + } + $record_name = preg_replace('#[^a-zA-Z0-9_\-\.]#', '', $record_name); + header('Content-Disposition: attachment; filename="' . $record_name . '"'); + header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 + header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past + if ($this->binary) { + header("Content-Length: " . filesize($record_file)); + } + ob_clean(); + + //content-range + if (isset($_SERVER['HTTP_RANGE']) && !$this->binary) { + $this->range_download($record_file); } - //add multi-lingual support - $language = new text; - $text = $language->get(); + fpassthru($fd); + } - //validate the token - $token = new token; - if (!$token->validate($_SERVER['PHP_SELF'])) { - message::add($text['message-invalid_token'],'negative'); - header('Location: '.$this->list_page); + } //end download method + + /* + * range download method (helps safari play audio sources) + */ + /** + * Sends a range of bytes from the specified file to the client. + * + * @param string $file The path to the file to download + * + * @return void + */ + private function range_download($file) { + $fp = @fopen($file, 'rb'); + + $size = filesize($file); // File size + $length = $size; // Content length + $start = 0; // Start byte + $end = $size - 1; // End byte + // Now that we've gotten so far without errors we send the accept range header + /* At the moment we only support single ranges. + * Multiple ranges requires some more work to ensure it works correctly + * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 + * + * Multirange support annouces itself with: + * header('Accept-Ranges: bytes'); + * + * Multirange content must be sent with multipart/byteranges mediatype, + * (mediatype = mimetype) + * as well as a boundry header to indicate the various chunks of data. + */ + header("Accept-Ranges: 0-" . $length); + // header('Accept-Ranges: bytes'); + // multipart/byteranges + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 + if (isset($_SERVER['HTTP_RANGE'])) { + + $c_start = $start; + $c_end = $end; + // Extract the range string + [, $range] = explode('=', $_SERVER['HTTP_RANGE'], 2); + // Make sure the client hasn't sent us a multibyte range + if (strpos($range, ',') !== false) { + // (?) Shoud this be issued here, or should the first + // range be used? Or should the header be ignored and + // we output the whole content? + header('HTTP/1.1 416 Requested Range Not Satisfiable'); + header("Content-Range: bytes $start-$end/$size"); + // (?) Echo some info to the client? exit; } - - //delete multiple records - if (!is_array($records) || @sizeof($records) == 0) { - return; + // If the range starts with an '-' we start from the beginning + // If not, we forward the file pointer + // And make sure to get the end byte if specified + if ($range[0] == '-') { + // The n-number of the last bytes is requested + $c_start = $size - substr($range, 1); + } else { + $range = explode('-', $range); + $c_start = $range[0]; + $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size; } - $records_deleted = 0; + /* Check the range and make sure it's treated according to the specs. + * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + */ + // End bytes can not be larger than $end. + $c_end = ($c_end > $end) ? $end : $c_end; + // Validate the requested range and return an error if it's not correct. + if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) { - //loop through records - foreach($records as $x => $record) { - if (empty($record['checked']) || $record['checked'] != 'true' || !is_uuid($record['uuid'])) { - continue; - } + header('HTTP/1.1 416 Requested Range Not Satisfiable'); + header("Content-Range: bytes $start-$end/$size"); + // (?) Echo some info to the client? + exit; + } + $start = $c_start; + $end = $c_end; + $length = $end - $start + 1; // Calculate new content length + fseek($fp, $start); + header('HTTP/1.1 206 Partial Content'); + } + // Notify the client the byte range we'll be outputting + header("Content-Range: bytes $start-$end/$size"); + header("Content-Length: $length"); - //get the call recordings - $sql = "select xml_cdr_uuid, record_name, record_path from v_xml_cdr "; - $sql .= "where xml_cdr_uuid = :xml_cdr_uuid "; - $sql .= "and record_name is not null"; - $parameters['xml_cdr_uuid'] = $record['uuid']; - $row = $this->database->select($sql, $parameters, 'row'); - unset($sql, $parameters); + // Start buffered download + $buffer = 1024 * 8; + while (!feof($fp) && ($p = ftell($fp)) <= $end) { + if ($p + $buffer > $end) { + // In case we're only outputtin a chunk, make sure we don't + // read past the length + $buffer = $end - $p + 1; + } + set_time_limit(0); // Reset time limit for big files + echo fread($fp, $buffer); + flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit. + } - //delete the call recording (file) - $call_recording_path = realpath($row['record_path']); - $call_recording_name = $row['record_name']; - if (file_exists($call_recording_path.'/'.$call_recording_name)) { - @unlink($call_recording_path.'/'.$call_recording_name); - } + fclose($fp); + } - //build the delete array - $array[$this->table][$x][$this->uuid_prefix.'uuid'] = $record['uuid']; + /** + * Deletes one or more records. + * + * @param array $records An array of record IDs to delete, where each ID is an associative array + * containing 'uuid' and 'checked' keys. The 'checked' value indicates + * whether the corresponding checkbox was checked for deletion. + * + * @return void No return value; this method modifies the database state and sets a message. + */ + public function delete($records) { + if (!permission_exists($this->permission_prefix . 'delete')) { + return false; + } - //increment counter - $records_deleted++; + //add multi-lingual support + $language = new text; + $text = $language->get(); + + //validate the token + $token = new token; + if (!$token->validate($_SERVER['PHP_SELF'])) { + message::add($text['message-invalid_token'], 'negative'); + header('Location: ' . $this->list_page); + exit; + } + + //delete multiple records + if (!is_array($records) || @sizeof($records) == 0) { + return; + } + $records_deleted = 0; + + //loop through records + foreach ($records as $x => $record) { + if (empty($record['checked']) || $record['checked'] != 'true' || !is_uuid($record['uuid'])) { + continue; } - if (!is_array($array) || @sizeof($array) == 0) { - return; + //get the call recordings + $sql = "select xml_cdr_uuid, record_name, record_path from v_xml_cdr "; + $sql .= "where xml_cdr_uuid = :xml_cdr_uuid "; + $sql .= "and record_name is not null"; + $parameters['xml_cdr_uuid'] = $record['uuid']; + $row = $this->database->select($sql, $parameters, 'row'); + unset($sql, $parameters); + + //delete the call recording (file) + $call_recording_path = realpath($row['record_path']); + $call_recording_name = $row['record_name']; + if (file_exists($call_recording_path . '/' . $call_recording_name)) { + @unlink($call_recording_path . '/' . $call_recording_name); } - //grant temporary permissions - $p = permissions::new(); - $p->add('call_recording_delete', 'temp'); + //build the delete array + $array[$this->table][$x][$this->uuid_prefix . 'uuid'] = $record['uuid']; - //execute delete - $this->database->delete($array); - unset($array); + //increment counter + $records_deleted++; + } - //revoke temporary permissions - $p->delete('call_recording_delete', 'temp'); + if (!is_array($array) || @sizeof($array) == 0) { + return; + } - //set message - message::add($text['message-delete'].": ".$records_deleted); + //grant temporary permissions + $p = permissions::new(); + $p->add('call_recording_delete', 'temp'); - unset($records); - } //method + //execute delete + $this->database->delete($array); + unset($array); + //revoke temporary permissions + $p->delete('call_recording_delete', 'temp'); - /** - * define singular function to convert a word in english to singular - */ - public function singular($word) { - //"-es" is used for words that end in "-x", "-s", "-z", "-sh", "-ch" in which case you add - if (substr($word, -2) == "es") { - if (substr($word, -4) == "sses") { // eg. 'addresses' to 'address' - return substr($word,0,-2); - } - elseif (substr($word, -3) == "ses") { // eg. 'databases' to 'database' (necessary!) - return substr($word,0,-1); - } - elseif (substr($word, -3) == "ies") { // eg. 'countries' to 'country' - return substr($word,0,-3)."y"; - } - elseif (substr($word, -3, 1) == "x") { - return substr($word,0,-2); - } - elseif (substr($word, -3, 1) == "s") { - return substr($word,0,-2); - } - elseif (substr($word, -3, 1) == "z") { - return substr($word,0,-2); - } - elseif (substr($word, -4, 2) == "sh") { - return substr($word,0,-2); - } - elseif (substr($word, -4, 2) == "ch") { - return substr($word,0,-2); - } - else { - return rtrim($word, "s"); - } - } - else { + //set message + message::add($text['message-delete'] . ": " . $records_deleted); + + unset($records); + } //method + + /** + * Singularize a word by removing its plural suffix. + * + * This function is based on the English language rules for forming singular nouns from their plural forms. + * It handles various cases such as words ending in "-es", "-s", "-z", "-sh", "-ch" and others. + * + * @param string $word The word to be made singular + * + * @return string The singularized word + */ + public function singular($word) { + //"-es" is used for words that end in "-x", "-s", "-z", "-sh", "-ch" in which case you add + if (substr($word, -2) == "es") { + if (substr($word, -4) == "sses") { // eg. 'addresses' to 'address' + return substr($word, 0, -2); + } elseif (substr($word, -3) == "ses") { // eg. 'databases' to 'database' (necessary!) + return substr($word, 0, -1); + } elseif (substr($word, -3) == "ies") { // eg. 'countries' to 'country' + return substr($word, 0, -3) . "y"; + } elseif (substr($word, -3, 1) == "x") { + return substr($word, 0, -2); + } elseif (substr($word, -3, 1) == "s") { + return substr($word, 0, -2); + } elseif (substr($word, -3, 1) == "z") { + return substr($word, 0, -2); + } elseif (substr($word, -4, 2) == "sh") { + return substr($word, 0, -2); + } elseif (substr($word, -4, 2) == "ch") { + return substr($word, 0, -2); + } else { return rtrim($word, "s"); } - } //method + } else { + return rtrim($word, "s"); + } + } //method - /** - * Removes old entries for in the database xml_cdr, xml_cdr_flow, xml_cdr_json, xml_cdr_logs table - * see {@link https://github.com/fusionpbx/fusionpbx-app-maintenance/} FusionPBX Maintenance App - * @param settings $settings Settings object - * @return void - */ - public static function database_maintenance(settings $settings): void { - //set table name for query - $table = 'xml_cdr'; + /** + * Removes old entries for in the database xml_cdr, xml_cdr_flow, xml_cdr_json, xml_cdr_logs table + * see {@link https://github.com/fusionpbx/fusionpbx-app-maintenance/} FusionPBX Maintenance App + * + * @param settings $settings Settings object + * + * @return void + */ + public static function database_maintenance(settings $settings): void { + //set table name for query + $table = 'xml_cdr'; - //get a database connection - $database = $settings->database(); + //get a database connection + $database = $settings->database(); - //get a list of domains - $domains = maintenance::get_domains($database); - foreach ($domains as $domain_uuid => $domain_name) { + //get a list of domains + $domains = maintenance::get_domains($database); + foreach ($domains as $domain_uuid => $domain_name) { - //get domain settings - $domain_settings = new settings(['database' => $database, 'domain_uuid' => $domain_uuid]); + //get domain settings + $domain_settings = new settings(['database' => $database, 'domain_uuid' => $domain_uuid]); - //get the retention days for xml cdr table using 'cdr' and 'database_retention_days' - $xml_cdr_retention_days = $domain_settings->get('cdr', 'database_retention_days', ''); + //get the retention days for xml cdr table using 'cdr' and 'database_retention_days' + $xml_cdr_retention_days = $domain_settings->get('cdr', 'database_retention_days', ''); - //get the retention days for xml cdr flow table - if ($database->table_exists('xml_cdr_flow')) { - $xml_cdr_flow_retention_days = $domain_settings->get('cdr', 'flow_database_retention_days', $xml_cdr_retention_days); + //get the retention days for xml cdr flow table + if ($database->table_exists('xml_cdr_flow')) { + $xml_cdr_flow_retention_days = $domain_settings->get('cdr', 'flow_database_retention_days', $xml_cdr_retention_days); + } else { + $xml_cdr_flow_retention_days = null; + } + + //get the retention days for xml cdr json table + if ($database->table_exists('xml_cdr_json')) { + $xml_cdr_json_retention_days = $domain_settings->get('cdr', 'json_database_retention_days', $xml_cdr_retention_days); + } else { + $xml_cdr_json_retention_days = null; + } + + //get the retention days for xml cdr logs table + if ($database->table_exists('xml_cdr_logs')) { + $xml_cdr_logs_retention_days = $domain_settings->get('cdr', 'logs_database_retention_days', $xml_cdr_retention_days); + } else { + $xml_cdr_logs_retention_days = null; + } + + //ensure we have retention days + if (!empty($xml_cdr_retention_days) && is_numeric((int)$xml_cdr_retention_days)) { + + //clear out old xml_cdr records + $sql = "delete from v_{$table} WHERE insert_date < NOW() - INTERVAL '{$xml_cdr_retention_days} days'" + . " and domain_uuid = '{$domain_uuid}'"; + $database->execute($sql); + $code = $database->message['code'] ?? 0; + //record result + if ($code == 200) { + maintenance_service::log_write(self::class, "Successfully removed entries older than $xml_cdr_retention_days", $domain_uuid); } else { - $xml_cdr_flow_retention_days = null; + $message = $database->message['message'] ?? "An unknown error has occurred"; + maintenance_service::log_write(self::class, "XML CDR " . "Unable to remove old database records. Error message: $message ($code)", $domain_uuid, maintenance_service::LOG_ERROR); } - //get the retention days for xml cdr json table - if ($database->table_exists('xml_cdr_json')) { - $xml_cdr_json_retention_days = $domain_settings->get('cdr', 'json_database_retention_days', $xml_cdr_retention_days); - } else { - $xml_cdr_json_retention_days = null; + //clear out old xml_cdr_flow records + if (!empty($xml_cdr_flow_retention_days)) { + $sql = "delete from v_xml_cdr_flow WHERE insert_date < NOW() - INTERVAL '{$xml_cdr_flow_retention_days} days'" + . " and domain_uuid = '{$domain_uuid}"; + $database->execute($sql); + $code = $database->message['code'] ?? 0; + //record result + if ($database->message['code'] == 200) { + maintenance_service::log_write(self::class, "Successfully removed XML CDR FLOW entries from $domain_name", $domain_uuid); + } else { + $message = $database->message['message'] ?? "An unknown error has occurred"; + maintenance_service::log_write(self::class, "XML CDR FLOW " . "Unable to remove old database records. Error message: $message ($code)", $domain_uuid, maintenance_service::LOG_ERROR); + } } - //get the retention days for xml cdr logs table - if ($database->table_exists('xml_cdr_logs')) { - $xml_cdr_logs_retention_days = $domain_settings->get('cdr', 'logs_database_retention_days', $xml_cdr_retention_days); - } else { - $xml_cdr_logs_retention_days = null; + //clear out old xml_cdr_json records + if (!empty($xml_cdr_json_retention_days)) { + $sql = "DELETE FROM v_xml_cdr_json WHERE insert_date < NOW() - INTERVAL '{$xml_cdr_json_retention_days} days'" + . " and domain_uuid = '{$domain_uuid}"; + $database->execute($sql); + $code = $database->message['code'] ?? 0; + //record result + if ($database->message['code'] == 200) { + maintenance_service::log_write(self::class, "Successfully removed XML CDR JSON entries from $domain_name", $domain_uuid); + } else { + $message = $database->message['message'] ?? "An unknown error has occurred"; + maintenance_service::log_write(self::class, "XML CDR JSON " . "Unable to remove old database records. Error message: $message ($code)", $domain_uuid, maintenance_service::LOG_ERROR); + } } - //ensure we have retention days - if (!empty($xml_cdr_retention_days) && is_numeric((int)$xml_cdr_retention_days)) { - - //clear out old xml_cdr records - $sql = "delete from v_{$table} WHERE insert_date < NOW() - INTERVAL '{$xml_cdr_retention_days} days'" + //clear out old xml_cdr_logs records + if (!empty($xml_cdr_logs_retention_days)) { + $sql = "DELETE FROM v_xml_cdr_logs WHERE insert_date < NOW() - INTERVAL '{$xml_cdr_logs_retention_days} days'" . " and domain_uuid = '{$domain_uuid}'"; $database->execute($sql); $code = $database->message['code'] ?? 0; //record result - if ($code == 200) { - maintenance_service::log_write(self::class, "Successfully removed entries older than $xml_cdr_retention_days", $domain_uuid); + if ($database->message['code'] === 200) { + maintenance_service::log_write(self::class, "Successfully removed XML CDR LOG entries from $domain_name", $domain_uuid); } else { $message = $database->message['message'] ?? "An unknown error has occurred"; - maintenance_service::log_write(self::class, "XML CDR " . "Unable to remove old database records. Error message: $message ($code)", $domain_uuid, maintenance_service::LOG_ERROR); - } - - //clear out old xml_cdr_flow records - if (!empty($xml_cdr_flow_retention_days)) { - $sql = "delete from v_xml_cdr_flow WHERE insert_date < NOW() - INTERVAL '{$xml_cdr_flow_retention_days} days'" - . " and domain_uuid = '{$domain_uuid}"; - $database->execute($sql); - $code = $database->message['code'] ?? 0; - //record result - if ($database->message['code'] == 200) { - maintenance_service::log_write(self::class, "Successfully removed XML CDR FLOW entries from $domain_name", $domain_uuid); - } else { - $message = $database->message['message'] ?? "An unknown error has occurred"; - maintenance_service::log_write(self::class, "XML CDR FLOW " . "Unable to remove old database records. Error message: $message ($code)", $domain_uuid, maintenance_service::LOG_ERROR); - } - } - - //clear out old xml_cdr_json records - if (!empty($xml_cdr_json_retention_days)) { - $sql = "DELETE FROM v_xml_cdr_json WHERE insert_date < NOW() - INTERVAL '{$xml_cdr_json_retention_days} days'" - . " and domain_uuid = '{$domain_uuid}"; - $database->execute($sql); - $code = $database->message['code'] ?? 0; - //record result - if ($database->message['code'] == 200) { - maintenance_service::log_write(self::class, "Successfully removed XML CDR JSON entries from $domain_name", $domain_uuid); - } else { - $message = $database->message['message'] ?? "An unknown error has occurred"; - maintenance_service::log_write(self::class, "XML CDR JSON " . "Unable to remove old database records. Error message: $message ($code)", $domain_uuid, maintenance_service::LOG_ERROR); - } - } - - //clear out old xml_cdr_logs records - if (!empty($xml_cdr_logs_retention_days)) { - $sql = "DELETE FROM v_xml_cdr_logs WHERE insert_date < NOW() - INTERVAL '{$xml_cdr_logs_retention_days} days'" - . " and domain_uuid = '{$domain_uuid}'"; - $database->execute($sql); - $code = $database->message['code'] ?? 0; - //record result - if ($database->message['code'] === 200) { - maintenance_service::log_write(self::class, "Successfully removed XML CDR LOG entries from $domain_name", $domain_uuid); - } else { - $message = $database->message['message'] ?? "An unknown error has occurred"; - maintenance_service::log_write(self::class, "XML CDR LOG " . "Unable to remove old database records. Error message: $message ($code)", $domain_uuid, maintenance_service::LOG_ERROR); - } + maintenance_service::log_write(self::class, "XML CDR LOG " . "Unable to remove old database records. Error message: $message ($code)", $domain_uuid, maintenance_service::LOG_ERROR); } } } - - //ensure logs are saved - maintenance_service::log_flush(); } - /** - * Return CDR for the default settings category name instead of using the class name xml_cdr - * @return string Returns 'CDR' for the name - */ - public static function database_maintenance_category(): string { - return "cdr"; - } + //ensure logs are saved + maintenance_service::log_flush(); + } - } //class + /** + * Return CDR for the default settings category name instead of using the class name xml_cdr + * + * @return string Returns 'cdr' for the name + */ + public static function database_maintenance_category(): string { + return "cdr"; + } + +} //class diff --git a/app/xml_cdr/resources/service/xml_cdr.php b/app/xml_cdr/resources/service/xml_cdr.php index 89ac4eed40..ac143595af 100644 --- a/app/xml_cdr/resources/service/xml_cdr.php +++ b/app/xml_cdr/resources/service/xml_cdr.php @@ -37,6 +37,13 @@ $pid_file = "/var/run/fusionpbx/".basename( $argv[0], ".php") .".pid"; //function to check if the process exists + /** + * Checks if a process with the specified PID file exists and is currently running. + * + * @param string $file The path to the PID file. Defaults to false, in which case the function will return whether any process exists. + * + * @return bool True if the process is running, false otherwise. + */ function process_exists($file = false) { //set the default exists to false