| 1 |
<?php /* $id$ */ |
|---|
| 2 |
//Copyright (C) 2004 Coalescent Systems Inc. (info@coalescentsystems.ca) |
|---|
| 3 |
// |
|---|
| 4 |
//This program is free software; you can redistribute it and/or |
|---|
| 5 |
//modify it under the terms of the GNU General Public License |
|---|
| 6 |
//as published by the Free Software Foundation; either version 2 |
|---|
| 7 |
//of the License, or (at your option) any later version. |
|---|
| 8 |
// |
|---|
| 9 |
//This program is distributed in the hope that it will be useful, |
|---|
| 10 |
//but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 11 |
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 12 |
//GNU General Public License for more details. |
|---|
| 13 |
|
|---|
| 14 |
require_once( (defined('AMP_BASE_INCLUDE_PATH') ? AMP_BASE_INCLUDE_PATH.'/' : '').'featurecodes.class.php'); |
|---|
| 15 |
require_once( (defined('AMP_BASE_INCLUDE_PATH') ? AMP_BASE_INCLUDE_PATH.'/' : '').'components.class.php'); |
|---|
| 16 |
|
|---|
| 17 |
define('MODULE_STATUS_NOTINSTALLED', 0); |
|---|
| 18 |
define('MODULE_STATUS_DISABLED', 1); |
|---|
| 19 |
define('MODULE_STATUS_ENABLED', 2); |
|---|
| 20 |
define('MODULE_STATUS_NEEDUPGRADE', 3); |
|---|
| 21 |
define('MODULE_STATUS_BROKEN', -1); |
|---|
| 22 |
|
|---|
| 23 |
class modulelist { |
|---|
| 24 |
var $_loaded = false; |
|---|
| 25 |
var $module_array = array(); |
|---|
| 26 |
var $_db; |
|---|
| 27 |
|
|---|
| 28 |
function &create(&$db) { |
|---|
| 29 |
static $obj; |
|---|
| 30 |
if (!isset($obj)) { |
|---|
| 31 |
$obj = new modulelist($db); |
|---|
| 32 |
} |
|---|
| 33 |
return $obj; |
|---|
| 34 |
} |
|---|
| 35 |
function modulelist(&$db) { |
|---|
| 36 |
$this->_db =& $db; |
|---|
| 37 |
$module_serialized = sql("SELECT `data` FROM `module_xml` WHERE `id` = 'mod_serialized'","getOne"); |
|---|
| 38 |
if (isset($module_serialized) && $module_serialized) { |
|---|
| 39 |
$this->module_array = (unserialize($module_serialized)); |
|---|
| 40 |
$this->_loaded = true; |
|---|
| 41 |
} |
|---|
| 42 |
} |
|---|
| 43 |
function is_loaded() { |
|---|
| 44 |
return $this->_loaded; |
|---|
| 45 |
} |
|---|
| 46 |
function initialize(&$module_list) { |
|---|
| 47 |
$this->module_array = $module_list; |
|---|
| 48 |
$module_serialized = $this->_db->escapeSimple(serialize($this->module_array)); |
|---|
| 49 |
sql("DELETE FROM `module_xml` WHERE `id` = 'mod_serialized'"); |
|---|
| 50 |
sql("INSERT INTO `module_xml` (`id`, `time`, `data`) VALUES ('mod_serialized', '".time()."','".$module_serialized."')"); |
|---|
| 51 |
$this->_loaded = true; |
|---|
| 52 |
} |
|---|
| 53 |
function invalidate() { |
|---|
| 54 |
unset($this->module_array); |
|---|
| 55 |
sql("DELETE FROM `module_xml` WHERE `id` = 'mod_serialized'"); |
|---|
| 56 |
$this->_loaded = false; |
|---|
| 57 |
} |
|---|
| 58 |
} |
|---|
| 59 |
|
|---|
| 60 |
define("NOTIFICATION_TYPE_CRITICAL", 100); |
|---|
| 61 |
define("NOTIFICATION_TYPE_SECURITY", 200); |
|---|
| 62 |
define("NOTIFICATION_TYPE_UPDATE", 300); |
|---|
| 63 |
define("NOTIFICATION_TYPE_ERROR", 400); |
|---|
| 64 |
define("NOTIFICATION_TYPE_WARNING" , 500); |
|---|
| 65 |
define("NOTIFICATION_TYPE_NOTICE", 600); |
|---|
| 66 |
|
|---|
| 67 |
class notifications { |
|---|
| 68 |
|
|---|
| 69 |
var $not_loaded = true; |
|---|
| 70 |
var $notification_table = array(); |
|---|
| 71 |
var $_db; |
|---|
| 72 |
|
|---|
| 73 |
function &create(&$db) { |
|---|
| 74 |
static $obj; |
|---|
| 75 |
if (!isset($obj)) { |
|---|
| 76 |
$obj = new notifications($db); |
|---|
| 77 |
} |
|---|
| 78 |
return $obj; |
|---|
| 79 |
} |
|---|
| 80 |
|
|---|
| 81 |
function notifications(&$db) { |
|---|
| 82 |
$this->_db =& $db; |
|---|
| 83 |
} |
|---|
| 84 |
|
|---|
| 85 |
|
|---|
| 86 |
function add_critical($module, $id, $display_text, $extended_text="", $link="", $reset=true, $candelete=false) { |
|---|
| 87 |
$this->_add_type(NOTIFICATION_TYPE_CRITICAL, $module, $id, $display_text, $extended_text, $link, $reset, $candelete); |
|---|
| 88 |
} |
|---|
| 89 |
function add_security($module, $id, $display_text, $extended_text="", $link="", $reset=true, $candelete=false) { |
|---|
| 90 |
$this->_add_type(NOTIFICATION_TYPE_SECURITY, $module, $id, $display_text, $extended_text, $link, $reset, $candelete); |
|---|
| 91 |
} |
|---|
| 92 |
function add_update($module, $id, $display_text, $extended_text="", $link="", $reset=false, $candelete=false) { |
|---|
| 93 |
$this->_add_type(NOTIFICATION_TYPE_UPDATE, $module, $id, $display_text, $extended_text, $link, $reset, $candelete); |
|---|
| 94 |
} |
|---|
| 95 |
function add_error($module, $id, $display_text, $extended_text="", $link="", $reset=false, $candelete=false) { |
|---|
| 96 |
$this->_add_type(NOTIFICATION_TYPE_ERROR, $module, $id, $display_text, $extended_text, $link, $reset, $candelete); |
|---|
| 97 |
} |
|---|
| 98 |
function add_warning($module, $id, $display_text, $extended_text="", $link="", $reset=false, $candelete=false) { |
|---|
| 99 |
$this->_add_type(NOTIFICATION_TYPE_WARNING, $module, $id, $display_text, $extended_text, $link, $reset, $candelete); |
|---|
| 100 |
} |
|---|
| 101 |
function add_notice($module, $id, $display_text, $extended_text="", $link="", $reset=false, $candelete=true) { |
|---|
| 102 |
$this->_add_type(NOTIFICATION_TYPE_NOTICE, $module, $id, $display_text, $extended_text, $link, $reset, $candelete); |
|---|
| 103 |
} |
|---|
| 104 |
|
|---|
| 105 |
|
|---|
| 106 |
function list_critical($show_reset=false) { |
|---|
| 107 |
return $this->_list(NOTIFICATION_TYPE_CRITICAL, $show_reset); |
|---|
| 108 |
} |
|---|
| 109 |
function list_security($show_reset=false) { |
|---|
| 110 |
return $this->_list(NOTIFICATION_TYPE_SECURITY, $show_reset); |
|---|
| 111 |
} |
|---|
| 112 |
function list_update($show_reset=false) { |
|---|
| 113 |
return $this->_list(NOTIFICATION_TYPE_UPDATE, $show_reset); |
|---|
| 114 |
} |
|---|
| 115 |
function list_error($show_reset=false) { |
|---|
| 116 |
return $this->_list(NOTIFICATION_TYPE_ERROR, $show_reset); |
|---|
| 117 |
} |
|---|
| 118 |
function list_warning($show_reset=false) { |
|---|
| 119 |
return $this->_list(NOTIFICATION_TYPE_WARNING, $show_reset); |
|---|
| 120 |
} |
|---|
| 121 |
function list_notice($show_reset=false) { |
|---|
| 122 |
return $this->_list(NOTIFICATION_TYPE_NOTICE, $show_reset); |
|---|
| 123 |
} |
|---|
| 124 |
function list_all($show_reset=false) { |
|---|
| 125 |
return $this->_list("", $show_reset); |
|---|
| 126 |
} |
|---|
| 127 |
|
|---|
| 128 |
|
|---|
| 129 |
function reset($module, $id) { |
|---|
| 130 |
$module = q($module); |
|---|
| 131 |
$id = q($id); |
|---|
| 132 |
|
|---|
| 133 |
$sql = "UPDATE notifications SET reset = 1 WHERE module = $module AND id = $id"; |
|---|
| 134 |
sql($sql); |
|---|
| 135 |
} |
|---|
| 136 |
|
|---|
| 137 |
function delete($module, $id) { |
|---|
| 138 |
$module = q($module); |
|---|
| 139 |
$id = q($id); |
|---|
| 140 |
|
|---|
| 141 |
$sql = "DELETE FROM notifications WHERE module = $module AND id = $id"; |
|---|
| 142 |
sql($sql); |
|---|
| 143 |
} |
|---|
| 144 |
|
|---|
| 145 |
function safe_delete($module, $id) { |
|---|
| 146 |
$module = q($module); |
|---|
| 147 |
$id = q($id); |
|---|
| 148 |
|
|---|
| 149 |
$sql = "DELETE FROM notifications WHERE module = $module AND id = $id AND candelete = 1"; |
|---|
| 150 |
sql($sql); |
|---|
| 151 |
} |
|---|
| 152 |
|
|---|
| 153 |
/* Internal functions |
|---|
| 154 |
*/ |
|---|
| 155 |
|
|---|
| 156 |
function _add_type($level, $module, $id, $display_text, $extended_text="", $link="", $reset=false, $candelete=false) { |
|---|
| 157 |
if ($this->not_loaded) { |
|---|
| 158 |
$this->notification_table = $this->_list("",true); |
|---|
| 159 |
$this->not_loaded = false; |
|---|
| 160 |
} |
|---|
| 161 |
|
|---|
| 162 |
$existing_row = false; |
|---|
| 163 |
foreach ($this->notification_table as $row) { |
|---|
| 164 |
if ($row['module'] == $module && $row['id'] == $id ) { |
|---|
| 165 |
$existing_row = $row; |
|---|
| 166 |
break; |
|---|
| 167 |
} |
|---|
| 168 |
} |
|---|
| 169 |
// Found an existing row - check if anything changed or if we are suppose to reset it |
|---|
| 170 |
// |
|---|
| 171 |
$candelete = $candelete ? 1 : 0; |
|---|
| 172 |
if ($existing_row) { |
|---|
| 173 |
|
|---|
| 174 |
if (($reset && $existing_row['reset'] == 1) || $existing_row['level'] != $level || $existing_row['display_text'] != $display_text || $existing_row['extended_text'] != $extended_text || $existing_row['link'] != $link || $existing_row['candelete'] == $candelete) { |
|---|
| 175 |
|
|---|
| 176 |
// If $reset is set to the special case of PASSIVE then the updates will not change it's value in an update |
|---|
| 177 |
// |
|---|
| 178 |
$reset_value = ($reset == 'PASSIVE') ? $existing_row['reset'] : 0; |
|---|
| 179 |
|
|---|
| 180 |
$module = q($module); |
|---|
| 181 |
$id = q($id); |
|---|
| 182 |
$level = q($level); |
|---|
| 183 |
$display_text = q($display_text); |
|---|
| 184 |
$extended_text = q($extended_text); |
|---|
| 185 |
$link = q($link); |
|---|
| 186 |
$now = time(); |
|---|
| 187 |
$sql = "UPDATE notifications SET |
|---|
| 188 |
level = $level, |
|---|
| 189 |
display_text = $display_text, |
|---|
| 190 |
extended_text = $extended_text, |
|---|
| 191 |
link = $link, |
|---|
| 192 |
reset = $reset_value, |
|---|
| 193 |
candelete = $candelete, |
|---|
| 194 |
timestamp = $now |
|---|
| 195 |
WHERE module = $module AND id = $id |
|---|
| 196 |
"; |
|---|
| 197 |
sql($sql); |
|---|
| 198 |
|
|---|
| 199 |
// TODO: I should really just add this to the internal cache, but really |
|---|
| 200 |
// how often does this get called that if is a big deal. |
|---|
| 201 |
$this->not_loaded = true; |
|---|
| 202 |
} |
|---|
| 203 |
} else { |
|---|
| 204 |
// No existing row so insert this new one |
|---|
| 205 |
// |
|---|
| 206 |
$now = time(); |
|---|
| 207 |
$module = q($module); |
|---|
| 208 |
$id = q($id); |
|---|
| 209 |
$level = q($level); |
|---|
| 210 |
$display_text = q($display_text); |
|---|
| 211 |
$extended_text = q($extended_text); |
|---|
| 212 |
$link = q($link); |
|---|
| 213 |
$sql = "INSERT INTO notifications |
|---|
| 214 |
(module, id, level, display_text, extended_text, link, reset, candelete, timestamp) |
|---|
| 215 |
VALUES |
|---|
| 216 |
($module, $id, $level, $display_text, $extended_text, $link, 0, $candelete, $now) |
|---|
| 217 |
"; |
|---|
| 218 |
sql($sql); |
|---|
| 219 |
|
|---|
| 220 |
// TODO: I should really just add this to the internal cache, but really |
|---|
| 221 |
// how often does this get called that if is a big deal. |
|---|
| 222 |
$this->not_loaded = true; |
|---|
| 223 |
} |
|---|
| 224 |
} |
|---|
| 225 |
|
|---|
| 226 |
function _list($level, $show_reset=false) { |
|---|
| 227 |
|
|---|
| 228 |
$level = q($level); |
|---|
| 229 |
$where = array(); |
|---|
| 230 |
|
|---|
| 231 |
if (!$show_reset) { |
|---|
| 232 |
$where[] = "reset = 0"; |
|---|
| 233 |
} |
|---|
| 234 |
|
|---|
| 235 |
switch ($level) { |
|---|
| 236 |
case NOTIFICATION_TYPE_CRITICAL: |
|---|
| 237 |
case NOTIFICATION_TYPE_SECURITY: |
|---|
| 238 |
case NOTIFICATION_TYPE_UPDATE: |
|---|
| 239 |
case NOTIFICATION_TYPE_ERROR: |
|---|
| 240 |
case NOTIFICATION_TYPE_WARNING: |
|---|
| 241 |
case NOTIFICATION_TYPE_NOTICE: |
|---|
| 242 |
$where[] = "level = $level "; |
|---|
| 243 |
break; |
|---|
| 244 |
default: |
|---|
| 245 |
} |
|---|
| 246 |
$sql = "SELECT * FROM notifications "; |
|---|
| 247 |
if (count($where)) { |
|---|
| 248 |
$sql .= " WHERE ".implode(" AND ", $where); |
|---|
| 249 |
} |
|---|
| 250 |
$sql .= " ORDER BY level, module"; |
|---|
| 251 |
|
|---|
| 252 |
$list = sql($sql,"getAll",DB_FETCHMODE_ASSOC); |
|---|
| 253 |
return $list; |
|---|
| 254 |
} |
|---|
| 255 |
/* Returns the number of active notifications |
|---|
| 256 |
*/ |
|---|
| 257 |
function get_num_active() { |
|---|
| 258 |
$sql = "SELECT COUNT(id) FROM notifications WHERE reset = 0"; |
|---|
| 259 |
return sql($sql,'getOne'); |
|---|
| 260 |
} |
|---|
| 261 |
} |
|---|
| 262 |
|
|---|
| 263 |
class cronmanager { |
|---|
| 264 |
/** |
|---|
| 265 |
* note: time is the hour time of day a job should run, -1 indicates don't care |
|---|
| 266 |
*/ |
|---|
| 267 |
|
|---|
| 268 |
function &create(&$db) { |
|---|
| 269 |
static $obj; |
|---|
| 270 |
if (!isset($obj)) { |
|---|
| 271 |
$obj = new cronmanager($db); |
|---|
| 272 |
} |
|---|
| 273 |
return $obj; |
|---|
| 274 |
} |
|---|
| 275 |
|
|---|
| 276 |
function cronmanager(&$db) { |
|---|
| 277 |
$this->_db =& $db; |
|---|
| 278 |
} |
|---|
| 279 |
|
|---|
| 280 |
function save_email($address) { |
|---|
| 281 |
$address = q($address); |
|---|
| 282 |
sql("DELETE FROM admin WHERE variable = 'email'"); |
|---|
| 283 |
sql("INSERT INTO admin (variable, value) VALUES ('email', $address)"); |
|---|
| 284 |
} |
|---|
| 285 |
|
|---|
| 286 |
function get_email() { |
|---|
| 287 |
$sql = "SELECT value FROM admin WHERE variable = 'email'"; |
|---|
| 288 |
return sql($sql, 'getOne'); |
|---|
| 289 |
} |
|---|
| 290 |
|
|---|
| 291 |
function save_hash($id, &$string) { |
|---|
| 292 |
$hash = md5($string); |
|---|
| 293 |
$id = q($id); |
|---|
| 294 |
sql("DELETE FROM admin WHERE variable = $id"); |
|---|
| 295 |
sql("INSERT INTO admin (variable, value) VALUE ($id, '$hash')"); |
|---|
| 296 |
} |
|---|
| 297 |
|
|---|
| 298 |
function check_hash($id, &$string) { |
|---|
| 299 |
$id = q($id); |
|---|
| 300 |
$sql = "SELECT value FROM admin WHERE variable = $id LIMIT 1"; |
|---|
| 301 |
$hash = sql($sql, "getOne"); |
|---|
| 302 |
return ($hash == md5($string)); |
|---|
| 303 |
} |
|---|
| 304 |
|
|---|
| 305 |
function enable_updates($freq=24) { |
|---|
| 306 |
global $amp_conf; |
|---|
| 307 |
|
|---|
| 308 |
$night_time = array(19,20,21,22,23,0,1,2,3,4,5); |
|---|
| 309 |
$run_time = $night_time[rand(0,10)]; |
|---|
| 310 |
$command = $amp_conf['AMPBIN']."/module_admin listonline"; |
|---|
| 311 |
$lasttime = 0; |
|---|
| 312 |
|
|---|
| 313 |
$sql = "SELECT * FROM cronmanager WHERE module = 'module_admin' AND id = 'UPDATES'"; |
|---|
| 314 |
$result = sql($sql, "getAll",DB_FETCHMODE_ASSOC); |
|---|
| 315 |
if (count($result)) { |
|---|
| 316 |
$sql = "UPDATE cronmanager SET |
|---|
| 317 |
freq = '$freq', |
|---|
| 318 |
command = '$command' |
|---|
| 319 |
WHERE |
|---|
| 320 |
module = 'module_admin' AND id = 'UPDATES' |
|---|
| 321 |
"; |
|---|
| 322 |
} else { |
|---|
| 323 |
$sql = "INSERT INTO cronmanager |
|---|
| 324 |
(module, id, time, freq, lasttime, command) |
|---|
| 325 |
VALUES |
|---|
| 326 |
('module_admin', 'UPDATES', '$run_time', $freq, 0, '$command') |
|---|
| 327 |
"; |
|---|
| 328 |
} |
|---|
| 329 |
sql($sql); |
|---|
| 330 |
} |
|---|
| 331 |
|
|---|
| 332 |
function disable_updates() { |
|---|
| 333 |
sql("DELETE FROM cronmanager WHERE module = 'module_admin' AND id = 'UPDATES'"); |
|---|
| 334 |
} |
|---|
| 335 |
|
|---|
| 336 |
function updates_enabled() { |
|---|
| 337 |
$results = sql("SELECT module, id FROM cronmanager WHERE module = 'module_admin' AND id = 'UPDATES'",'getAll'); |
|---|
| 338 |
return count($results); |
|---|
| 339 |
} |
|---|
| 340 |
|
|---|
| 341 |
/** run_jobs() |
|---|
| 342 |
* select all entries that need to be run now and run them, then update the times. |
|---|
| 343 |
* |
|---|
| 344 |
* 1. select all entries |
|---|
| 345 |
* 2. foreach entry, if its paramters indicate it should be run, then run it and |
|---|
| 346 |
* update it was run in the time stamp. |
|---|
| 347 |
*/ |
|---|
| 348 |
function run_jobs() { |
|---|
| 349 |
|
|---|
| 350 |
$errors = 0; |
|---|
| 351 |
$error_arr = array(); |
|---|
| 352 |
|
|---|
| 353 |
$now = time(); |
|---|
| 354 |
$jobs = sql("SELECT * FROM cronmanager","getAll", DB_FETCHMODE_ASSOC); |
|---|
| 355 |
foreach ($jobs as $job) { |
|---|
| 356 |
$nexttime = $job['lasttime'] + $job['freq']*3600; |
|---|
| 357 |
if ($nexttime <= $now) { |
|---|
| 358 |
if ($job['time'] >= 0 && $job['time'] < 24) { |
|---|
| 359 |
$date_arr = getdate($now); |
|---|
| 360 |
// Now if lasttime is 0, then we want this kicked off at the proper hour |
|---|
| 361 |
// after wich the frequencey will set the pace for same time each night |
|---|
| 362 |
// |
|---|
| 363 |
if (($date_arr['hours'] != $job['time']) && !$job['lasttime']) { |
|---|
| 364 |
continue; |
|---|
| 365 |
} |
|---|
| 366 |
} |
|---|
| 367 |
} else { |
|---|
| 368 |
// no need to run job, time is not up yet |
|---|
| 369 |
continue; |
|---|
| 370 |
} |
|---|
| 371 |
// run the job |
|---|
| 372 |
exec($job['command'],$job_out,$ret); |
|---|
| 373 |
if ($ret) { |
|---|
| 374 |
$errors++; |
|---|
| 375 |
$error_arr[] = array($job['command'],$ret); |
|---|
| 376 |
|
|---|
| 377 |
// If there where errors, let's print them out in case the script is being debugged or running |
|---|
| 378 |
// from cron which will then put the errors out through the cron system. |
|---|
| 379 |
// |
|---|
| 380 |
foreach ($job_out as $line) { |
|---|
| 381 |
echo $line."\n"; |
|---|
| 382 |
} |
|---|
| 383 |
} else { |
|---|
| 384 |
$module = $job['module']; |
|---|
| 385 |
$id = $job['id']; |
|---|
| 386 |
$sql = "UPDATE cronmanager SET lasttime = $now WHERE module = '$module' AND id = '$id'"; |
|---|
| 387 |
sql($sql); |
|---|
| 388 |
} |
|---|
| 389 |
} |
|---|
| 390 |
if ($errors) { |
|---|
| 391 |
$nt =& notifications::create($db); |
|---|
| 392 |
$text = sprintf(_("Cronmanager encountered %s Errors"),$errors); |
|---|
| 393 |
$extext = _("The following commands failed with the listed error"); |
|---|
| 394 |
foreach ($error_arr as $item) { |
|---|
| 395 |
$extext .= "<br />".$item[0]." (".$item[1].")"; |
|---|
| 396 |
} |
|---|
| 397 |
$nt->add_error('cron_manager', 'EXECFAIL', $text, $extext, '', true, true); |
|---|
| 398 |
} |
|---|
| 399 |
} |
|---|
| 400 |
} |
|---|
| 401 |
|
|---|
| 402 |
class ampuser { |
|---|
| 403 |
var $username; |
|---|
| 404 |
var $_password; |
|---|
| 405 |
var $_extension_high; |
|---|
| 406 |
var $_extension_low; |
|---|
| 407 |
var $_deptname; |
|---|
| 408 |
var $_sections; |
|---|
| 409 |
|
|---|
| 410 |
function ampuser($username) { |
|---|
| 411 |
$this->username = $username; |
|---|
| 412 |
if ($user = getAmpUser($username)) { |
|---|
| 413 |
$this->_password = $user["password_sha1"]; |
|---|
| 414 |
$this->_extension_high = $user["extension_high"]; |
|---|
| 415 |
$this->_extension_low = $user["extension_low"]; |
|---|
| 416 |
$this->_deptname = $user["deptname"]; |
|---|
| 417 |
$this->_sections = $user["sections"]; |
|---|
| 418 |
} else { |
|---|
| 419 |
// user doesn't exist |
|---|
| 420 |
$this->_password = false; |
|---|
| 421 |
$this->_extension_high = ""; |
|---|
| 422 |
$this->_extension_low = ""; |
|---|
| 423 |
$this->_deptname = ""; |
|---|
| 424 |
$this->_sections = array(); |
|---|
| 425 |
} |
|---|
| 426 |
} |
|---|
| 427 |
|
|---|
| 428 |
/** Give this user full admin access |
|---|
| 429 |
*/ |
|---|
| 430 |
function setAdmin() { |
|---|
| 431 |
$this->_extension_high = ""; |
|---|
| 432 |
$this->_extension_low = ""; |
|---|
| 433 |
$this->_deptname = ""; |
|---|
| 434 |
$this->_sections = array("*"); |
|---|
| 435 |
} |
|---|
| 436 |
|
|---|
| 437 |
function checkPassword($password) { |
|---|
| 438 |
// strict checking so false will never match |
|---|
| 439 |
return ($this->_password === $password); |
|---|
| 440 |
} |
|---|
| 441 |
|
|---|
| 442 |
function checkSection($section) { |
|---|
| 443 |
// if they have * then it means all sections |
|---|
| 444 |
return in_array("*", $this->_sections) || in_array($section, $this->_sections); |
|---|
| 445 |
} |
|---|
| 446 |
} |
|---|
| 447 |
|
|---|
| 448 |
/* Usage |
|---|
| 449 |
Grab some XML data, either from a file, URL, etc. however you want. Assume storage in $strYourXML; |
|---|
| 450 |
|
|---|
| 451 |
$xml = new xml2Array($strYourXML); |
|---|
| 452 |
xml array is in $xml->data; |
|---|
| 453 |
This is basically an array version of the XML data (no attributes), striaght-up. If there are |
|---|
| 454 |
multiple items with the same name, they are split into a numeric sub-array, |
|---|
| 455 |
eg, <items><item test="123">foo</item><item>bar</item></items> |
|---|
| 456 |
becomes: array('item' => array(0=>array('item'=>'foo'), 1=>array('item'=>'foo')) |
|---|
| 457 |
attributes are in $xml->attributes; |
|---|
| 458 |
These are stored with xpath type paths, as $xml->attributes['/items/item/0']["test"] == "123" |
|---|
| 459 |
|
|---|
| 460 |
|
|---|
| 461 |
Other way (still works, but not as nice): |
|---|
| 462 |
|
|---|
| 463 |
$objXML = new xml2Array(); |
|---|
| 464 |
$arrOutput = $objXML->parse($strYourXML); |
|---|
| 465 |
print_r($arrOutput); //print it out, or do whatever! |
|---|
| 466 |
|
|---|
| 467 |
*/ |
|---|
| 468 |
|
|---|
| 469 |
class xml2Array { |
|---|
| 470 |
var $arrOutput = array(); |
|---|
| 471 |
var $resParser; |
|---|
| 472 |
var $strXmlData; |
|---|
| 473 |
|
|---|
| 474 |
var $attributes; |
|---|
| 475 |
var $data; |
|---|
| 476 |
|
|---|
| 477 |
function xml2Array($strInputXML = false) { |
|---|
| 478 |
if (!empty($strInputXML)) { |
|---|
| 479 |
$this->data = $this->parseAdvanced($strInputXML); |
|---|
| 480 |
} |
|---|
| 481 |
} |
|---|
| 482 |
|
|---|
| 483 |
function parse($strInputXML) { |
|---|
| 484 |
|
|---|
| 485 |
$this->resParser = xml_parser_create (); |
|---|
| 486 |
xml_set_object($this->resParser,$this); |
|---|
| 487 |
xml_set_element_handler($this->resParser, "tagOpen", "tagClosed"); |
|---|
| 488 |
|
|---|
| 489 |
xml_set_character_data_handler($this->resParser, "tagData"); |
|---|
| 490 |
|
|---|
| 491 |
$this->strXmlData = xml_parse($this->resParser,$strInputXML ); |
|---|
| 492 |
if(!$this->strXmlData) { |
|---|
| 493 |
die_freepbx(sprintf("XML error: %s at line %d", |
|---|
| 494 |
xml_error_string(xml_get_error_code($this->resParser)), |
|---|
| 495 |
xml_get_current_line_number($this->resParser))); |
|---|
| 496 |
} |
|---|
| 497 |
|
|---|
| 498 |
xml_parser_free($this->resParser); |
|---|
| 499 |
|
|---|
| 500 |
return $this->arrOutput; |
|---|
| 501 |
} |
|---|
| 502 |
function tagOpen($parser, $name, $attrs) { |
|---|
| 503 |
$tag=array("name"=>$name,"attrs"=>$attrs); |
|---|
| 504 |
@array_push($this->arrOutput,$tag); |
|---|
| 505 |
} |
|---|
| 506 |
|
|---|
| 507 |
function tagData($parser, $tagData) { |
|---|
| 508 |
if(trim($tagData)) { |
|---|
| 509 |
if(isset($this->arrOutput[count($this->arrOutput)-1]['tagData'])) { |
|---|
| 510 |
$this->arrOutput[count($this->arrOutput)-1]['tagData'] .= "\n".$tagData; |
|---|
| 511 |
} |
|---|
| 512 |
else { |
|---|
| 513 |
$this->arrOutput[count($this->arrOutput)-1]['tagData'] = $tagData; |
|---|
| 514 |
} |
|---|
| 515 |
} |
|---|
| 516 |
} |
|---|
| 517 |
|
|---|
| 518 |
function tagClosed($parser, $name) { |
|---|
| 519 |
@$this->arrOutput[count($this->arrOutput)-2]['children'][] = $this->arrOutput[count($this->arrOutput)-1]; |
|---|
| 520 |
array_pop($this->arrOutput); |
|---|
| 521 |
} |
|---|
| 522 |
|
|---|
| 523 |
function recursive_parseLevel($items, &$attrs, $path = "") { |
|---|
| 524 |
$array = array(); |
|---|
| 525 |
foreach (array_keys($items) as $idx) { |
|---|
| 526 |
@$items[$idx]['name'] = strtolower($items[$idx]['name']); |
|---|
| 527 |
|
|---|
| 528 |
$multi = false; |
|---|
| 529 |
if (isset($array[ $items[$idx]['name'] ])) { |
|---|
| 530 |
// this child is already set, so we're adding multiple items to an array |
|---|
| 531 |
|
|---|
| 532 |
if (!is_array($array[ $items[$idx]['name'] ]) || !isset($array[ $items[$idx]['name'] ][0])) { |
|---|
| 533 |
// hasn't already been made into a numerically-indexed array, so do that now |
|---|
| 534 |
// we're basically moving the current contents of this item into a 1-item array (at the |
|---|
| 535 |
// original location) so that we can add a second item in the code below |
|---|
| 536 |
$array[ $items[$idx]['name'] ] = array( $array[ $items[$idx]['name'] ] ); |
|---|
| 537 |
|
|---|
| 538 |
if (isset($attrs[ $path.'/'.$items[$idx]['name'] ])) { |
|---|
| 539 |
// move the attributes to /0 |
|---|
| 540 |
$attrs[ $path.'/'.$items[$idx]['name'].'/0' ] = $attrs[ $path.'/'.$items[$idx]['name'] ]; |
|---|
| 541 |
unset($attrs[ $path.'/'.$items[$idx]['name'] ]); |
|---|
| 542 |
} |
|---|
| 543 |
} |
|---|
| 544 |
$multi = true; |
|---|
| 545 |
} |
|---|
| 546 |
|
|---|
| 547 |
if ($multi) { |
|---|
| 548 |
$newitem = &$array[ $items[$idx]['name'] ][]; |
|---|
| 549 |
} else { |
|---|
| 550 |
$newitem = &$array[ $items[$idx]['name'] ]; |
|---|
| 551 |
} |
|---|
| 552 |
|
|---|
| 553 |
|
|---|
| 554 |
if (isset($items[$idx]['children']) && is_array($items[$idx]['children'])) { |
|---|
| 555 |
$newitem = $this->recursive_parseLevel($items[$idx]['children'], $attrs, $path.'/'.$items[$idx]['name']); |
|---|
| 556 |
} else if (isset($items[$idx]['tagData'])) { |
|---|
| 557 |
$newitem = $items[$idx]['tagData']; |
|---|
| 558 |
} else { |
|---|
| 559 |
$newitem = false; |
|---|
| 560 |
} |
|---|
| 561 |
|
|---|
| 562 |
if (isset($items[$idx]['attrs']) && is_array($items[$idx]['attrs']) && count($items[$idx]['attrs'])) { |
|---|
| 563 |
$attrpath = $path.'/'.$items[$idx]['name']; |
|---|
| 564 |
if ($multi) { |
|---|
| 565 |
$attrpath .= '/'.(count($array[ $items[$idx]['name'] ])-1); |
|---|
| 566 |
} |
|---|
| 567 |
foreach ($items[$idx]['attrs'] as $name=>$value) { |
|---|
| 568 |
$attrs[ $attrpath ][ strtolower($name) ] = $value; |
|---|
| 569 |
} |
|---|
| 570 |
} |
|---|
| 571 |
} |
|---|
| 572 |
return $array; |
|---|
| 573 |
} |
|---|
| 574 |
|
|---|
| 575 |
function parseAdvanced($strInputXML) { |
|---|
| 576 |
$array = $this->parse($strInputXML); |
|---|
| 577 |
$this->attributes = array(); |
|---|
| 578 |
return $this->data = $this->recursive_parseLevel($array, $this->attributes); |
|---|
| 579 |
} |
|---|
| 580 |
} |
|---|
| 581 |
|
|---|
| 582 |
/* |
|---|
| 583 |
Return a much more manageable assoc array with module data. |
|---|
| 584 |
*/ |
|---|
| 585 |
class xml2ModuleArray extends xml2Array { |
|---|
| 586 |
function parseModulesXML($strInputXML) { |
|---|
| 587 |
$array = $this->parseAdvanced($strInputXML); |
|---|
| 588 |
if (isset($array['xml'])) { |
|---|
| 589 |
foreach ($array['xml'] as $key=>$module) { |
|---|
| 590 |
if ($key == 'module') { |
|---|
| 591 |
// copy the structure verbatim |
|---|
| 592 |
$modules[ $module['name'] ] = $module; |
|---|
| 593 |
} |
|---|
| 594 |
} |
|---|
| 595 |
} |
|---|
| 596 |
|
|---|
| 597 |
// if you are confused about what's happening below, uncomment this why we do it |
|---|
| 598 |
// echo "<pre>"; print_r($arrOutput); echo "</pre>"; |
|---|
| 599 |
|
|---|
| 600 |
// ignore the regular xml garbage ([0]['children']) & loop through each module |
|---|
| 601 |
if(!is_array($arrOutput[0]['children'])) return false; |
|---|
| 602 |
foreach($arrOutput[0]['children'] as $module) { |
|---|
| 603 |
if(!is_array($module['children'])) return false; |
|---|
| 604 |
// loop through each modules's tags |
|---|
| 605 |
foreach($module['children'] as $modTags) { |
|---|
| 606 |
if(isset($modTags['children']) && is_array($modTags['children'])) { |
|---|
| 607 |
$$modTags['name'] = $modTags['children']; |
|---|
| 608 |
// loop if there are children (menuitems and requirements) |
|---|
| 609 |
foreach($modTags['children'] as $subTag) { |
|---|
| 610 |
$subTags[strtolower($subTag['name'])] = $subTag['tagData']; |
|---|
| 611 |
} |
|---|
| 612 |
$$modTags['name'] = $subTags; |
|---|
| 613 |
unset($subTags); |
|---|
| 614 |
} else { |
|---|
| 615 |
// create a variable for each tag we find |
|---|
| 616 |
$$modTags['name'] = $modTags['tagData']; |
|---|
| 617 |
} |
|---|
| 618 |
|
|---|
| 619 |
} |
|---|
| 620 |
// now build our return array |
|---|
| 621 |
$arrModules[$RAWNAME]['rawname'] = $RAWNAME; // This has to be set |
|---|
| 622 |
$arrModules[$RAWNAME]['displayName'] = $NAME; // This has to be set |
|---|
| 623 |
$arrModules[$RAWNAME]['version'] = $VERSION; // This has to be set |
|---|
| 624 |
$arrModules[$RAWNAME]['type'] = isset($TYPE)?$TYPE:'setup'; |
|---|
| 625 |
$arrModules[$RAWNAME]['category'] = isset($CATEGORY)?$CATEGORY:'Unknown'; |
|---|
| 626 |
$arrModules[$RAWNAME]['info'] = isset($INFO)?$INFO:'http://www.freepbx.org/wiki/'.$RAWNAME; |
|---|
| 627 |
$arrModules[$RAWNAME]['location'] = isset($LOCATION)?$LOCATION:'local'; |
|---|
| 628 |
$arrModules[$RAWNAME]['items'] = isset($MENUITEMS)?$MENUITEMS:null; |
|---|
| 629 |
$arrModules[$RAWNAME]['requirements'] = isset($REQUIREMENTS)?$REQUIREMENTS:null; |
|---|
| 630 |
$arrModules[$RAWNAME]['md5sum'] = isset($MD5SUM)?$MD5SUM:null; |
|---|
| 631 |
//print_r($arrModules); |
|---|
| 632 |
//unset our variables |
|---|
| 633 |
unset($NAME); |
|---|
| 634 |
unset($VERSION); |
|---|
| 635 |
unset($TYPE); |
|---|
| 636 |
unset($CATEGORY); |
|---|
| 637 |
unset($AUTHOR); |
|---|
| 638 |
unset($EMAIL); |
|---|
| 639 |
unset($LOCATION); |
|---|
| 640 |
unset($MENUITEMS); |
|---|
| 641 |
unset($REQUIREMENTS); |
|---|
| 642 |
unset($MD5SUM); |
|---|
| 643 |
} |
|---|
| 644 |
//echo "<pre>"; print_r($arrModules); echo "</pre>"; |
|---|
| 645 |
|
|---|
| 646 |
return $arrModules; |
|---|
| 647 |
} |
|---|
| 648 |
} |
|---|
| 649 |
|
|---|
| 650 |
class moduleHook { |
|---|
| 651 |
var $hookHtml = ''; |
|---|
| 652 |
var $arrHooks = array(); |
|---|
| 653 |
|
|---|
| 654 |
function install_hooks($viewing_itemid,$target_module,$target_menuid = '') { |
|---|
| 655 |
global $active_modules; |
|---|
| 656 |
// loop through all active modules |
|---|
| 657 |
foreach($active_modules as $this_module) { |
|---|
| 658 |
// look for requested hooks for $module |
|---|
| 659 |
// ie: findme_hook_extensions() |
|---|
| 660 |
$funct = $this_module['rawname'] . '_hook_' . $target_module; |
|---|
| 661 |
if( function_exists( $funct ) ) { |
|---|
| 662 |
// execute the function, appending the |
|---|
| 663 |
// html output to that of other hooking modules |
|---|
| 664 |
|
|---|
| 665 |
$thismod = $this_module['rawname']; |
|---|
| 666 |
if (isset($_COOKIE['lang']) && is_dir("./modules/$thismod/i18n/".$_COOKIE['lang'])) { |
|---|
| 667 |
bindtextdomain($thismod,"./modules/$thismod/i18n"); |
|---|
| 668 |
bind_textdomain_codeset($thismod, 'utf8'); |
|---|
| 669 |
textdomain($thismod); |
|---|
| 670 |
|
|---|
| 671 |
if ($hookReturn = $funct($target_menuid, $viewing_itemid)) { |
|---|
| 672 |
$this->hookHtml .= $hookReturn; |
|---|
| 673 |
} |
|---|
| 674 |
|
|---|
| 675 |
textdomain('amp'); |
|---|
| 676 |
} else { |
|---|
| 677 |
if ($hookReturn = $funct($target_menuid, $viewing_itemid)) { |
|---|
| 678 |
$this->hookHtml .= $hookReturn; |
|---|
| 679 |
} |
|---|
| 680 |
} |
|---|
| 681 |
// remember who installed hooks |
|---|
| 682 |
// we need to know this for processing form vars |
|---|
| 683 |
$this->arrHooks[] = $this_module['rawname']; |
|---|
| 684 |
} |
|---|
| 685 |
} |
|---|
| 686 |
} |
|---|
| 687 |
|
|---|
| 688 |
// process the request from the module we hooked |
|---|
| 689 |
function process_hooks($viewing_itemid, $target_module, $target_menuid, $request) { |
|---|
| 690 |
if(is_array($this->arrHooks)) { |
|---|
| 691 |
foreach($this->arrHooks as $hookingMod) { |
|---|
| 692 |
// check if there is a processing function |
|---|
| 693 |
$funct = $hookingMod . '_hookProcess_' . $target_module; |
|---|
| 694 |
if( function_exists( $funct ) ) { |
|---|
| 695 |
$funct($viewing_itemid, $request); |
|---|
| 696 |
} |
|---|
| 697 |
} |
|---|
| 698 |
} |
|---|
| 699 |
} |
|---|
| 700 |
} |
|---|
| 701 |
|
|---|
| 702 |
$amp_conf_defaults = array( |
|---|
| 703 |
'AMPDBENGINE' => array('std' , 'mysql'), |
|---|
| 704 |
'AMPDBNAME' => array('std' , 'asterisk'), |
|---|
| 705 |
'AMPENGINE' => array('std' , 'asterisk'), |
|---|
| 706 |
'ASTMANAGERPORT' => array('std' , '5038'), |
|---|
| 707 |
'AMPDBHOST' => array('std' , 'localhost'), |
|---|
| 708 |
'AMPDBUSER' => array('std' , 'asteriskuser'), |
|---|
| 709 |
'AMPDBPASS' => array('std' , 'amp109'), |
|---|
| 710 |
'AMPMGRUSER' => array('std' , 'admin'), |
|---|
| 711 |
'AMPMGRPASS' => array('std' , 'amp111'), |
|---|
| 712 |
'FOPPASSWORD' => array('std' , 'passw0rd'), |
|---|
| 713 |
'FOPSORT' => array('std' , 'extension'), |
|---|
| 714 |
'AMPSYSLOGLEVEL '=> array('std' , 'LOG_ERR'), |
|---|
| 715 |
|
|---|
| 716 |
'ASTETCDIR' => array('dir' , '/etc/asterisk'), |
|---|
| 717 |
'ASTMODDIR' => array('dir' , '/usr/lib/asterisk/modules'), |
|---|
| 718 |
'ASTVARLIBDIR' => array('dir' , '/var/lib/asterisk'), |
|---|
| 719 |
'ASTAGIDIR' => array('dir' , '/var/lib/asterisk/agi-bin'), |
|---|
| 720 |
'ASTSPOOLDIR' => array('dir' , '/var/spool/asterisk/'), |
|---|
| 721 |
'ASTRUNDIR' => array('dir' , '/var/run/asterisk'), |
|---|
| 722 |
'ASTLOGDIR' => array('dir' , '/var/log/asterisk'), |
|---|
| 723 |
'AMPBIN' => array('dir' , '/var/lib/asterisk/bin'), |
|---|
| 724 |
'AMPSBIN' => array('dir' , '/usr/sbin'), |
|---|
| 725 |
'AMPWEBROOT' => array('dir' , '/var/www/html'), |
|---|
| 726 |
'FOPWEBROOT' => array('dir' , '/var/www/html/panel'), |
|---|
| 727 |
|
|---|
| 728 |
'USECATEGORIES' => array('bool' , true), |
|---|
| 729 |
'ENABLECW' => array('bool' , true), |
|---|
| 730 |
'CWINUSEBUSY' => array('bool' , true), |
|---|
| 731 |
'FOPRUN' => array('bool' , true), |
|---|
| 732 |
'AMPBADNUMBER' => array('bool' , true), |
|---|
| 733 |
'DEVEL' => array('bool' , false), |
|---|
| 734 |
'DEVELRELOAD' => array('bool' , false), |
|---|
| 735 |
'CUSTOMASERROR' => array('bool' , true), |
|---|
| 736 |
'DYNAMICHINTS' => array('bool' , false), |
|---|
| 737 |
'BADDESTABORT' => array('bool' , false), |
|---|
| 738 |
'SERVERINTITLE' => array('bool' , false), |
|---|
| 739 |
'XTNCONFLICTABORT' => array('bool' , false), |
|---|
| 740 |
'USEDEVSTATE' => array('bool' , false), |
|---|
| 741 |
'MODULEADMINWGET'=> array('bool' , false), |
|---|
| 742 |
'AMPDISABLELOG' => array('bool' , true), |
|---|
| 743 |
'AMPENABLEDEVELDEBUG'=> array('bool' , false), |
|---|
| 744 |
'AMPMPG123' => array('bool' , true), |
|---|
| 745 |
'FOPDISABLE' => array('bool' , false), |
|---|
| 746 |
'ZAP2DAHDICOMPAT' => array('bool' , false), |
|---|
| 747 |
'CHECKREFERER' => array('bool' , true), |
|---|
| 748 |
); |
|---|
| 749 |
|
|---|
| 750 |
function parse_amportal_conf($filename) { |
|---|
| 751 |
global $amp_conf_defaults; |
|---|
| 752 |
|
|---|
| 753 |
/* defaults |
|---|
| 754 |
* This defines defaults and formating to assure consistency across the system so that |
|---|
| 755 |
* components don't have to keep being 'gun shy' about these variables. |
|---|
| 756 |
* |
|---|
| 757 |
*/ |
|---|
| 758 |
$file = file($filename); |
|---|
| 759 |
if (is_array($file)) { |
|---|
| 760 |
foreach ($file as $line) { |
|---|
| 761 |
if (preg_match("/^\s*([a-zA-Z0-9_]+)=([a-zA-Z0-9 .&-@=_!<>\"\']+)\s*$/",$line,$matches)) { |
|---|
| 762 |
$conf[ $matches[1] ] = $matches[2]; |
|---|
| 763 |
} |
|---|
| 764 |
} |
|---|
| 765 |
} else { |
|---|
| 766 |
die_freepbx("<h1>".sprintf(_("Missing or unreadable config file (%s)...cannot continue"), $filename)."</h1>"); |
|---|
| 767 |
} |
|---|
| 768 |
|
|---|
| 769 |
// set defaults |
|---|
| 770 |
foreach ($amp_conf_defaults as $key=>$arr) { |
|---|
| 771 |
|
|---|
| 772 |
switch ($arr[0]) { |
|---|
| 773 |
// for type dir, make sure there is no trailing '/' to keep consistent everwhere |
|---|
| 774 |
// |
|---|
| 775 |
case 'dir': |
|---|
| 776 |
if (!isset($conf[$key]) || trim($conf[$key]) == '') { |
|---|
| 777 |
$conf[$key] = $arr[1]; |
|---|
| 778 |
} else { |
|---|
| 779 |
$conf[$key] = rtrim($conf[$key],'/'); |
|---|
| 780 |
} |
|---|
| 781 |
break; |
|---|
| 782 |
// booleans: |
|---|
| 783 |
// "yes", "true", "on", true, 1 (case-insensitive) will be treated as true, everything else is false |
|---|
| 784 |
// |
|---|
| 785 |
case 'bool': |
|---|
| 786 |
if (!isset($conf[$key])) { |
|---|
| 787 |
$conf[$key] = $arr[1]; |
|---|
| 788 |
} else { |
|---|
| 789 |
$conf[$key] = ($conf[$key] === true || strtolower($conf[$key]) == 'true' || $conf[$key] === 1 || $conf[$key] == '1' |
|---|
| 790 |
|| strtolower($conf[$key]) == 'yes' || strtolower($conf[$key]) == 'on'); |
|---|
| 791 |
} |
|---|
| 792 |
break; |
|---|
| 793 |
default: |
|---|
| 794 |
if (!isset($conf[$key])) { |
|---|
| 795 |
$conf[$key] = $arr[1]; |
|---|
| 796 |
} else { |
|---|
| 797 |
$conf[$key] = trim($conf[$key]); |
|---|
| 798 |
} |
|---|
| 799 |
} |
|---|
| 800 |
} |
|---|
| 801 |
return $conf; |
|---|
| 802 |
} |
|---|
| 803 |
|
|---|
| 804 |
function parse_asterisk_conf($filename) { |
|---|
| 805 |
//TODO: Should the correction of $amp_conf be passed by refernce and optional? |
|---|
| 806 |
// |
|---|
| 807 |
global $amp_conf; |
|---|
| 808 |
$conf = array(); |
|---|
| 809 |
|
|---|
| 810 |
$convert = array( |
|---|
| 811 |
'astetcdir' => 'ASTETCDIR', |
|---|
| 812 |
'astmoddir' => 'ASTMODDIR', |
|---|
| 813 |
'astvarlibdir' => 'ASTVARLIBDIR', |
|---|
| 814 |
'astagidir' => 'ASTAGIDIR', |
|---|
| 815 |
'astspooldir' => 'ASTSPOOLDIR', |
|---|
| 816 |
'astrundir' => 'ASTRUNDIR', |
|---|
| 817 |
'astlogdir' => 'ASTLOGDIR' |
|---|
| 818 |
); |
|---|
| 819 |
|
|---|
| 820 |
$file = file($filename); |
|---|
| 821 |
foreach ($file as $line) { |
|---|
| 822 |
if (preg_match("/^\s*([a-zA-Z0-9]+)\s* => \s*(.*)\s*([;#].*)?/",$line,$matches)) { |
|---|
| 823 |
$conf[ $matches[1] ] = rtrim($matches[2],"/ \t"); |
|---|
| 824 |
} |
|---|
| 825 |
} |
|---|
| 826 |
|
|---|
| 827 |
// Now that we parsed asterisk.conf, we need to make sure $amp_conf is consistent |
|---|
| 828 |
// so just set it to what we found, since this is what asterisk will use anyhow. |
|---|
| 829 |
// |
|---|
| 830 |
foreach ($convert as $ast_conf_key => $amp_conf_key) { |
|---|
| 831 |
if (isset($conf[$ast_conf_key])) { |
|---|
| 832 |
$amp_conf[$amp_conf_key] = $conf[$ast_conf_key]; |
|---|
| 833 |
} |
|---|
| 834 |
} |
|---|
| 835 |
return $conf; |
|---|
| 836 |
} |
|---|
| 837 |
|
|---|
| 838 |
/** check if a specific extension is being used, or get a list of all extensions that are being used |
|---|
| 839 |
* @param mixed an array of extension numbers to check against, or if boolean true then return list of all extensions |
|---|
| 840 |
* @param array a hash of module names to search for callbacks, otherwise global $active_modules is used |
|---|
| 841 |
* @return array returns an empty array if exten not in use, or any array with usage info, or of all usage |
|---|
| 842 |
* if exten is boolean true |
|---|
| 843 |
* @description Upon passing in an array of extension numbers, this api will query all modules to determine if any |
|---|
| 844 |
* are using those extension numbers. If so, it will return an array with the usage information |
|---|
| 845 |
* as described below, otherwise an empty array. If passed boolean true, it will return an array |
|---|
| 846 |
* of the same format with all extensions on the system that are being used. |
|---|
| 847 |
* |
|---|
| 848 |
* $exten_usage[$module][$exten]['description'] // description of the extension |
|---|
| 849 |
* ['edit_url'] // a url that could be invoked to edit extension |
|---|
| 850 |
* ['status'] // Status: INUSE, RESERVED, RESTRICTED |
|---|
| 851 |
*/ |
|---|
| 852 |
function framework_check_extension_usage($exten=true, $module_hash=false) { |
|---|
| 853 |
global $active_modules; |
|---|
| 854 |
$exten_usage = array(); |
|---|
| 855 |
|
|---|
| 856 |
if (!is_array($module_hash)) { |
|---|
| 857 |
$module_hash = $active_modules; |
|---|
| 858 |
} |
|---|
| 859 |
|
|---|
| 860 |
if (!is_array($exten) && $exten !== true) { |
|---|
| 861 |
$exten = array($exten); |
|---|
| 862 |
} |
|---|
| 863 |
|
|---|
| 864 |
foreach(array_keys($module_hash) as $mod) { |
|---|
| 865 |
$function = $mod."_check_extensions"; |
|---|
| 866 |
if (function_exists($function)) { |
|---|
| 867 |
$prev_domain = textdomain(NULL); |
|---|
| 868 |
if (isset($_COOKIE['lang']) && is_dir("./modules/$mod/i18n/".$_COOKIE['lang'])) { |
|---|
| 869 |
bindtextdomain($mod,"./modules/$mod/i18n"); |
|---|
| 870 |
bind_textdomain_codeset($mod, 'utf8'); |
|---|
| 871 |
textdomain($mod); |
|---|
| 872 |
$module_usage = $function($exten); |
|---|
| 873 |
} else { |
|---|
| 874 |
textdomain('amp'); |
|---|
| 875 |
$module_usage = $function($exten); |
|---|
| 876 |
} |
|---|
| 877 |
if (!empty($module_usage)) { |
|---|
| 878 |
$exten_usage[$mod] = $module_usage; |
|---|
| 879 |
} |
|---|
| 880 |
textdomain($prev_domain); |
|---|
| 881 |
} |
|---|
| 882 |
} |
|---|
| 883 |
if ($exten === true) { |
|---|
| 884 |
return $exten_usage; |
|---|
| 885 |
} else { |
|---|
| 886 |
foreach (array_keys($exten_usage) as $mod) { |
|---|
| 887 |
foreach ($exten as $test_exten) { |
|---|
| 888 |
if (isset($exten_usage[$mod][$test_exten])) { |
|---|
| 889 |
$exten_matches[$mod][$test_exten] = $exten_usage[$mod][$test_exten]; |
|---|
| 890 |
} |
|---|
| 891 |
} |
|---|
| 892 |
} |
|---|
| 893 |
} |
|---|
| 894 |
return $exten_matches; |
|---|
| 895 |
} |
|---|
| 896 |
|
|---|
| 897 |
/** check if a specific destination is being used, or get a list of all destinations that are being used |
|---|
| 898 |
* @param mixed an array of destinations to check against, or if boolean true then return list of all destinations in use |
|---|
| 899 |
* @param array a hash of module names to search for callbacks, otherwise global $active_modules is used |
|---|
| 900 |
* @return array returns an empty array if destination not in use, or any array with usage info, or of all usage |
|---|
| 901 |
* if dest is boolean true |
|---|
| 902 |
* @description Upon passing in an array of destinations, this api will query all modules to determine if any |
|---|
| 903 |
* are using that destination. If so, it will return an array with the usage information |
|---|
| 904 |
* as described below, otherwise an empty array. If passed boolean true, it will return an array |
|---|
| 905 |
* of the same format with all destinations on the system that are being used. |
|---|
| 906 |
* |
|---|
| 907 |
* $dest_usage[$module][]['dest'] // The destination being used |
|---|
| 908 |
* ['description'] // Description of who is using it |
|---|
| 909 |
* ['edit_url'] // a url that could be invoked to edit the using entity |
|---|
| 910 |
* |
|---|
| 911 |
*/ |
|---|
| 912 |
function framework_check_destination_usage($dest=true, $module_hash=false) { |
|---|
| 913 |
global $active_modules; |
|---|
| 914 |
|
|---|
| 915 |
$dest_usage = array(); |
|---|
| 916 |
$dest_matches = array(); |
|---|
| 917 |
|
|---|
| 918 |
if (!is_array($module_hash)) { |
|---|
| 919 |
$module_hash = $active_modules; |
|---|
| 920 |
} |
|---|
| 921 |
|
|---|
| 922 |
if (!is_array($dest) && $dest !== true) { |
|---|
| 923 |
$dest = array($dest); |
|---|
| 924 |
} |
|---|
| 925 |
|
|---|
| 926 |
foreach(array_keys($module_hash) as $mod) { |
|---|
| 927 |
$function = $mod."_check_destinations"; |
|---|
| 928 |
if (function_exists($function)) { |
|---|
| 929 |
$prev_domain = textdomain(NULL); |
|---|
| 930 |
if (isset($_COOKIE['lang']) && is_dir("./modules/$mod/i18n/".$_COOKIE['lang'])) { |
|---|
| 931 |
bindtextdomain($mod,"./modules/$mod/i18n"); |
|---|
| 932 |
bind_textdomain_codeset($mod, 'utf8'); |
|---|
| 933 |
textdomain($mod); |
|---|
| 934 |
$module_usage = $function($dest); |
|---|
| 935 |
} else { |
|---|
| 936 |
textdomain('amp'); |
|---|
| 937 |
$module_usage = $function($dest); |
|---|
| 938 |
} |
|---|
| 939 |
if (!empty($module_usage)) { |
|---|
| 940 |
$dest_usage[$mod] = $module_usage; |
|---|
| 941 |
} |
|---|
| 942 |
textdomain($prev_domain); |
|---|
| 943 |
} |
|---|
| 944 |
} |
|---|
| 945 |
if ($dest === true) { |
|---|
| 946 |
return $dest_usage; |
|---|
| 947 |
} else { |
|---|
| 948 |
/* |
|---|
| 949 |
$destlist[] = array( |
|---|
| 950 |
'dest' => $thisdest, |
|---|
| 951 |
'description' => 'Annoucement: '.$result['description'], |
|---|
| 952 |
'edit_url' => 'config.php?display=announcement&type='.$type.'&extdisplay='.urlencode($thisid), |
|---|
| 953 |
); |
|---|
| 954 |
*/ |
|---|
| 955 |
foreach (array_keys($dest_usage) as $mod) { |
|---|
| 956 |
foreach ($dest as $test_dest) { |
|---|
| 957 |
foreach ($dest_usage[$mod] as $dest_item) { |
|---|
| 958 |
if ($dest_item['dest'] == $test_dest) { |
|---|
| 959 |
$dest_matches[$mod][] = $dest_item; |
|---|
| 960 |
} |
|---|
| 961 |
} |
|---|
| 962 |
} |
|---|
| 963 |
} |
|---|
| 964 |
} |
|---|
| 965 |
return $dest_matches; |
|---|
| 966 |
} |
|---|
| 967 |
|
|---|
| 968 |
/** provide optional alert() box and formatted url info for extension conflicts |
|---|
| 969 |
* @param array an array of extensions that are in conflict obtained from framework_check_extension_usage |
|---|
| 970 |
* @param boolean default false. True if url and descriptions should be split, false to combine (see return) |
|---|
| 971 |
* @param boolean default true. True to echo an alert() box, false to bypass the alert box |
|---|
| 972 |
* @return array returns an array of formatted URLs with descriptions. If $split is true, retuns an array |
|---|
| 973 |
* of the URLs with each element an array in the format of array('label' => 'description, 'url' => 'a url') |
|---|
| 974 |
* @description This is used upon detecting conflicting extension numbers to provide an optional alert box of the issue |
|---|
| 975 |
* by a module which should abort the attempt to create the extension. It also returns an array of |
|---|
| 976 |
* URLs that can be displayed by the module to show the conflicting extension(s) and links to edit |
|---|
| 977 |
* them or further interogate. The resulting URLs are returned in an array either formatted for immediate |
|---|
| 978 |
* display or split into a description and the raw URL to provide more fine grained control (or use with guielements). |
|---|
| 979 |
*/ |
|---|
| 980 |
function framework_display_extension_usage_alert($usage_arr=array(),$split=false,$alert=true) { |
|---|
| 981 |
$url = array(); |
|---|
| 982 |
if (!empty($usage_arr)) { |
|---|
| 983 |
$conflicts=0; |
|---|
| 984 |
foreach($usage_arr as $rawmodule => $properties) { |
|---|
| 985 |
foreach($properties as $exten => $details) { |
|---|
| 986 |
$conflicts++; |
|---|
| 987 |
if ($conflicts == 1) { |
|---|
| 988 |
switch ($details['status']) { |
|---|
| 989 |
case 'INUSE': |
|---|
| 990 |
$str = "Extension $exten not available, it is currently used by ".htmlspecialchars($details['description'])."."; |
|---|
| 991 |
if ($split) { |
|---|
| 992 |
$url[] = array('label' => "Edit: ".htmlspecialchars($details['description']), |
|---|
| 993 |
'url' => $details['edit_url'], |
|---|
| 994 |
); |
|---|
| 995 |
} else { |
|---|
| 996 |
$url[] = "<a href='".$details['edit_url']."'>Edit: ".htmlspecialchars($details['description'])."</a>"; |
|---|
| 997 |
} |
|---|
| 998 |
break; |
|---|
| 999 |
default: |
|---|
| 1000 |
$str = "This extension is not available: ".htmlspecialchars($details['description'])."."; |
|---|
| 1001 |
} |
|---|
| 1002 |
} else { |
|---|
| 1003 |
if ($split) { |
|---|
| 1004 |
$url[] = array('label' => "Edit: ".htmlspecialchars($details['description']), |
|---|
| 1005 |
'url' => $details['edit_url'], |
|---|
| 1006 |
); |
|---|
| 1007 |
} else { |
|---|
| 1008 |
$url[] = "<a href='".$details['edit_url']."'>Edit: ".htmlspecialchars($details['description'])."</a>"; |
|---|
| 1009 |
} |
|---|
| 1010 |
} |
|---|
| 1011 |
} |
|---|
| 1012 |
} |
|---|
| 1013 |
if ($conflicts > 1) { |
|---|
| 1014 |
$str .= sprintf(" There are %s additonal conflicts not listed",$conflicts-1); |
|---|
| 1015 |
} |
|---|
| 1016 |
} |
|---|
| 1017 |
if ($alert) { |
|---|
| 1018 |
echo "<script>javascript:alert('$str')</script>"; |
|---|
| 1019 |
} |
|---|
| 1020 |
return($url); |
|---|
| 1021 |
} |
|---|
| 1022 |
|
|---|
| 1023 |
/** check if a specific destination is being used, or get a list of all destinations that are being used |
|---|
| 1024 |
* @param mixed an array of destinations to check against |
|---|
| 1025 |
* @param array a hash of module names to search for callbacks, otherwise global $active_modules is used |
|---|
| 1026 |
* @return array array with a message and tooltip to display usage of this destination |
|---|
| 1027 |
* @description This is called to generate a label and tooltip which summarized the usage of this |
|---|
| 1028 |
* destination and a tooltip listing all the places that use it |
|---|
| 1029 |
* |
|---|
| 1030 |
*/ |
|---|
| 1031 |
function framework_display_destination_usage($dest, $module_hash=false) { |
|---|
| 1032 |
|
|---|
| 1033 |
if (!is_array($dest)) { |
|---|
| 1034 |
$dest = array($dest); |
|---|
| 1035 |
} |
|---|
| 1036 |
$usage_list = framework_check_destination_usage($dest, $module_hash); |
|---|
| 1037 |
if (!empty($usage_list)) { |
|---|
| 1038 |
$usage_count = 0; |
|---|
| 1039 |
$str = null; |
|---|
| 1040 |
foreach ($usage_list as $mod_list) { |
|---|
| 1041 |
foreach ($mod_list as $details) { |
|---|
| 1042 |
$usage_count++; |
|---|
| 1043 |
$str .= $details['description']."<br />"; |
|---|
| 1044 |
} |
|---|
| 1045 |
} |
|---|
| 1046 |
$object = $usage_count > 1 ? _("Objects"):_("Object"); |
|---|
| 1047 |
return array('text' => ' '.sprintf(dgettext('amp',"Used as Destination by %s %s"),$usage_count, dgettext('amp',$object)), |
|---|
| 1048 |
'tooltip' => $str, |
|---|
| 1049 |
); |
|---|
| 1050 |
} else { |
|---|
| 1051 |
return array(); |
|---|
| 1052 |
} |
|---|
| 1053 |
} |
|---|
| 1054 |
|
|---|
| 1055 |
/** determines which module a list of destinations belongs to, and if the destination object exists |
|---|
| 1056 |
* @param mixed an array of destinations to check against |
|---|
| 1057 |
* @param array a hash of module names to search for callbacks, otherwise global $active_modules is used |
|---|
| 1058 |
* @return array an array structure with informaiton about the destinations (see code) |
|---|
| 1059 |
* @description Mainly used by framework_list_problem_destinations. This function will find the module |
|---|
| 1060 |
* that a destination belongs to and determine if the object still exits. This allow it to |
|---|
| 1061 |
* either obtain the identify, identify it as an object that has been deleted, or identify |
|---|
| 1062 |
* it as an unknown destination, usually a custom destination. |
|---|
| 1063 |
* |
|---|
| 1064 |
*/ |
|---|
| 1065 |
function framework_identify_destinations($dest, $module_hash=false) { |
|---|
| 1066 |
global $active_modules; |
|---|
| 1067 |
static $dest_cache = array(); |
|---|
| 1068 |
|
|---|
| 1069 |
$dest_results = array(); |
|---|
| 1070 |
|
|---|
| 1071 |
$dest_usage = array(); |
|---|
| 1072 |
$dest_matches = array(); |
|---|
| 1073 |
|
|---|
| 1074 |
if (!is_array($module_hash)) { |
|---|
| 1075 |
$module_hash = $active_modules; |
|---|
| 1076 |
} |
|---|
| 1077 |
|
|---|
| 1078 |
if (!is_array($dest)) { |
|---|
| 1079 |
$dest = array($dest); |
|---|
| 1080 |
} |
|---|
| 1081 |
|
|---|
| 1082 |
foreach ($dest as $target) { |
|---|
| 1083 |
if (isset($dest_cache[$target])) { |
|---|
| 1084 |
$dest_results[$target] = $dest_cache[$target]; |
|---|
| 1085 |
} else { |
|---|
| 1086 |
$found_owner = false; |
|---|
| 1087 |
foreach(array_keys($module_hash) as $mod) { |
|---|
| 1088 |
$function = $mod."_getdestinfo"; |
|---|
| 1089 |
if (function_exists($function)) { |
|---|
| 1090 |
$prev_domain = textdomain(NULL); |
|---|
| 1091 |
if (isset($_COOKIE['lang']) && is_dir("./modules/$mod/i18n/".$_COOKIE['lang'])) { |
|---|
| 1092 |
bindtextdomain($mod,"./modules/$mod/i18n"); |
|---|
| 1093 |
bind_textdomain_codeset($mod, 'utf8'); |
|---|
| 1094 |
textdomain($mod); |
|---|
| 1095 |
$check_module = $function($target); |
|---|
| 1096 |
} else { |
|---|
| 1097 |
textdomain('amp'); |
|---|
| 1098 |
$check_module = $function($target); |
|---|
| 1099 |
} |
|---|
| 1100 |
textdomain($prev_domain); |
|---|
| 1101 |
if ($check_module !== false) { |
|---|
| 1102 |
$found_owner = true; |
|---|
| 1103 |
$dest_cache[$target] = array($mod => $check_module); |
|---|
| 1104 |
$dest_results[$target] = $dest_cache[$target]; |
|---|
| 1105 |
break; |
|---|
| 1106 |
} |
|---|
| 1107 |
} |
|---|
| 1108 |
} |
|---|
| 1109 |
if (! $found_owner) { |
|---|
| 1110 |
//echo "Not Found: $target\n"; |
|---|
| 1111 |
$dest_cache[$target] = false; |
|---|
| 1112 |
$dest_results[$target] = $dest_cache[$target]; |
|---|
| 1113 |
} |
|---|
| 1114 |
} |
|---|
| 1115 |
} |
|---|
| 1116 |
return $dest_results; |
|---|
| 1117 |
} |
|---|
| 1118 |
|
|---|
| 1119 |
/** create a comprehensive list of all destinations that are problematic |
|---|
| 1120 |
* @param array an array of destinations to check against |
|---|
| 1121 |
* @param bool set to true if custome (unknown) destinations should be reported |
|---|
| 1122 |
* @return array an array of the destinations that are empty, orphaned or custom |
|---|
| 1123 |
* @description This function will scan the entire system and identify destinations |
|---|
| 1124 |
* that are problematic. Either empty, orphaned or an unknow custom |
|---|
| 1125 |
* destinations. An orphaned destination is one that should belong |
|---|
| 1126 |
* to a module but the object it would have pointed to does not exist |
|---|
| 1127 |
* because it was probably deleted. |
|---|
| 1128 |
*/ |
|---|
| 1129 |
function framework_list_problem_destinations($module_hash=false, $ignore_custom=false) { |
|---|
| 1130 |
global $active_modules; |
|---|
| 1131 |
|
|---|
| 1132 |
if (!is_array($module_hash)) { |
|---|
| 1133 |
$module_hash = $active_modules; |
|---|
| 1134 |
} |
|---|
| 1135 |
|
|---|
| 1136 |
$my_dest_arr = array(); |
|---|
| 1137 |
$problem_dests = array(); |
|---|
| 1138 |
|
|---|
| 1139 |
$all_dests = framework_check_destination_usage(true, $module_hash); |
|---|
| 1140 |
|
|---|
| 1141 |
foreach ($all_dests as $dests) { |
|---|
| 1142 |
foreach ($dests as $adest) { |
|---|
| 1143 |
if (!empty($adest['dest'])) { |
|---|
| 1144 |
$my_dest_arr[] = $adest['dest']; |
|---|
| 1145 |
} |
|---|
| 1146 |
} |
|---|
| 1147 |
} |
|---|
| 1148 |
$my_dest_arr = array_unique($my_dest_arr); |
|---|
| 1149 |
|
|---|
| 1150 |
$identities = framework_identify_destinations($my_dest_arr, $module_hash); |
|---|
| 1151 |
|
|---|
| 1152 |
foreach ($all_dests as $dests) { |
|---|
| 1153 |
foreach ($dests as $adest) { |
|---|
| 1154 |
if (empty($adest['dest'])) { |
|---|
| 1155 |
$problem_dests[] = array('status' => 'EMPTY', |
|---|
| 1156 |
'dest' => $adest['dest'], |
|---|
| 1157 |
'description' => $adest['description'], |
|---|
| 1158 |
'edit_url' => $adest['edit_url'], |
|---|
| 1159 |
); |
|---|
| 1160 |
} else if ($identities[$adest['dest']] === false){ |
|---|
| 1161 |
if ($ignore_custom) { |
|---|
| 1162 |
continue; |
|---|
| 1163 |
} |
|---|
| 1164 |
$problem_dests[] = array('status' => 'CUSTOM', |
|---|
| 1165 |
'dest' => $adest['dest'], |
|---|
| 1166 |
'description' => $adest['description'], |
|---|
| 1167 |
'edit_url' => $adest['edit_url'], |
|---|
| 1168 |
); |
|---|
| 1169 |
} else if (is_array($identities[$adest['dest']])){ |
|---|
| 1170 |
foreach ($identities[$adest['dest']] as $details) { |
|---|
| 1171 |
if (empty($details)) { |
|---|
| 1172 |
$problem_dests[] = array('status' => 'ORPHAN', |
|---|
| 1173 |
'dest' => $adest['dest'], |
|---|
| 1174 |
'description' => $adest['description'], |
|---|
| 1175 |
'edit_url' => $adest['edit_url'], |
|---|
| 1176 |
); |
|---|
| 1177 |
|
|---|
| 1178 |
} |
|---|
| 1179 |
break; // there is only one set per array |
|---|
| 1180 |
} |
|---|
| 1181 |
} else { |
|---|
| 1182 |
echo "ERROR?\n"; |
|---|
| 1183 |
var_dump($adest); |
|---|
| 1184 |
} |
|---|
| 1185 |
} |
|---|
| 1186 |
} |
|---|
| 1187 |
return $problem_dests; |
|---|
| 1188 |
} |
|---|
| 1189 |
|
|---|
| 1190 |
/** sort the hash based on the inner key |
|---|
| 1191 |
*/ |
|---|
| 1192 |
function _framework_sort_exten($a, $b) { |
|---|
| 1193 |
$a_key = array_keys($a); |
|---|
| 1194 |
$a_key = $a_key[0]; |
|---|
| 1195 |
$b_key = array_keys($b); |
|---|
| 1196 |
$b_key = $b_key[0]; |
|---|
| 1197 |
if ($a_key == $b_key) { |
|---|
| 1198 |
return 0; |
|---|
| 1199 |
} else { |
|---|
| 1200 |
return ($a_key < $b_key) ? -1 : 1; |
|---|
| 1201 |
} |
|---|
| 1202 |
} |
|---|
| 1203 |
|
|---|
| 1204 |
/** create a comprehensive list of all extensions conflicts |
|---|
| 1205 |
* @return array an array of the destinations that are empty, orphaned or custom |
|---|
| 1206 |
* @description This returns an array structure with information about all |
|---|
| 1207 |
* extension numbers that are in conflict. This means the same number |
|---|
| 1208 |
* is being used by 2 or more modules and the results will be ambiguous |
|---|
| 1209 |
* which one will be ignored when dialed. See the code for the |
|---|
| 1210 |
* structure of the retured array. |
|---|
| 1211 |
*/ |
|---|
| 1212 |
function framework_list_extension_conflicts($module_hash=false) { |
|---|
| 1213 |
global $active_modules; |
|---|
| 1214 |
|
|---|
| 1215 |
if (!is_array($module_hash)) { |
|---|
| 1216 |
$module_hash = $active_modules; |
|---|
| 1217 |
} |
|---|
| 1218 |
|
|---|
| 1219 |
$exten_list = framework_check_extension_usage(true,$module_hash); |
|---|
| 1220 |
|
|---|
| 1221 |
/** Bookkeeping hashes |
|---|
| 1222 |
* full_hash[] will contain the first extension encountered |
|---|
| 1223 |
* conflict_hash[] will contain any subsequent extensions if conflicts |
|---|
| 1224 |
* |
|---|
| 1225 |
* If there are conflicts, the full set is what is in conflict_hash + the |
|---|
| 1226 |
* first extension encoutnered in full_hash[] |
|---|
| 1227 |
*/ |
|---|
| 1228 |
$full_hash = array(); |
|---|
| 1229 |
$conflict_hash = array(); |
|---|
| 1230 |
|
|---|
| 1231 |
foreach ($exten_list as $mod => $mod_extens) { |
|---|
| 1232 |
foreach ($mod_extens as $exten => $details) { |
|---|
| 1233 |
if (!isset($full_hash[$exten])) { |
|---|
| 1234 |
$full_hash[$exten] = $details; |
|---|
| 1235 |
} else { |
|---|
| 1236 |
$conflict_hash[] = array($exten => $details); |
|---|
| 1237 |
} |
|---|
| 1238 |
} |
|---|
| 1239 |
} |
|---|
| 1240 |
|
|---|
| 1241 |
// extract conflicting remaining extension from full_hash but needs to be unique |
|---|
| 1242 |
// |
|---|
| 1243 |
if (!empty($conflict_hash)) { |
|---|
| 1244 |
$other_conflicts = array(); |
|---|
| 1245 |
foreach ($conflict_hash as $item) { |
|---|
| 1246 |
foreach (array_keys($item) as $exten) { |
|---|
| 1247 |
$other_conflicts[$exten] = $full_hash[$exten]; |
|---|
| 1248 |
} |
|---|
| 1249 |
} |
|---|
| 1250 |
foreach ($other_conflicts as $exten => $details) { |
|---|
| 1251 |
$conflict_hash[] = array($exten => $details); |
|---|
| 1252 |
} |
|---|
| 1253 |
usort($conflict_hash, "_framework_sort_exten"); |
|---|
| 1254 |
return $conflict_hash; |
|---|
| 1255 |
} |
|---|
| 1256 |
} |
|---|
| 1257 |
|
|---|
| 1258 |
/** Expands variables from amportal.conf |
|---|
| 1259 |
* Replaces any variables enclosed in percent (%) signs with their value |
|---|
| 1260 |
* eg, "%AMPWEBROOT%/admin/functions.inc.php" |
|---|
| 1261 |
*/ |
|---|
| 1262 |
function expand_variables($string) { |
|---|
| 1263 |
global $amp_conf; |
|---|
| 1264 |
$search = $replace = array(); |
|---|
| 1265 |
foreach ($amp_conf as $key=>$value) { |
|---|
| 1266 |
$search[] = '%'.$key.'%'; |
|---|
| 1267 |
$replace[] = $value; |
|---|
| 1268 |
} |
|---|
| 1269 |
return str_replace($search, $replace, $string); |
|---|
| 1270 |
} |
|---|
| 1271 |
|
|---|
| 1272 |
// returns true if extension is within allowed range |
|---|
| 1273 |
function checkRange($extension){ |
|---|
| 1274 |
$low = isset($_SESSION["AMP_user"]->_extension_low)?$_SESSION["AMP_user"]->_extension_low:''; |
|---|
| 1275 |
$high = isset($_SESSION["AMP_user"]->_extension_high)?$_SESSION["AMP_user"]->_extension_high:''; |
|---|
| 1276 |
|
|---|
| 1277 |
if ((($extension >= $low) && ($extension <= $high)) || ($low == '' && $high == '')) |
|---|
| 1278 |
return true; |
|---|
| 1279 |
else |
|---|
| 1280 |
return false; |
|---|
| 1281 |
} |
|---|
| 1282 |
|
|---|
| 1283 |
function getAmpAdminUsers() { |
|---|
| 1284 |
global $db; |
|---|
| 1285 |
|
|---|
| 1286 |
$sql = "SELECT username FROM ampusers WHERE sections='*'"; |
|---|
| 1287 |
$results = $db->getAll($sql); |
|---|
| 1288 |
if(DB::IsError($results)) { |
|---|
| 1289 |
die_freepbx($sql."<br>\n".$results->getMessage()); |
|---|
| 1290 |
} |
|---|
| 1291 |
return $results; |
|---|
| 1292 |
} |
|---|
| 1293 |
|
|---|
| 1294 |
function getAmpUser($username) { |
|---|
| 1295 |
global $db; |
|---|
| 1296 |
|
|---|
| 1297 |
$sql = "SELECT username, password_sha1, extension_low, extension_high, deptname, sections FROM ampusers WHERE username = '".$db->escapeSimple($username)."'"; |
|---|
| 1298 |
$results = $db->getAll($sql); |
|---|
| 1299 |
if(DB::IsError($results)) { |
|---|
| 1300 |
die_freepbx($sql."<br>\n".$results->getMessage()); |
|---|
| 1301 |
} |
|---|
| 1302 |
|
|---|
| 1303 |
if (count($results) > 0) { |
|---|
| 1304 |
$user = array(); |
|---|
| 1305 |
$user["username"] = $results[0][0]; |
|---|
| 1306 |
$user["password_sha1"] = $results[0][1]; |
|---|
| 1307 |
$user["extension_low"] = $results[0][2]; |
|---|
| 1308 |
$user["extension_high"] = $results[0][3]; |
|---|
| 1309 |
$user["deptname"] = $results[0][4]; |
|---|
| 1310 |
$user["sections"] = explode(";",$results[0][5]); |
|---|
| 1311 |
return $user; |
|---|
| 1312 |
} else { |
|---|
| 1313 |
return false; |
|---|
| 1314 |
} |
|---|
| 1315 |
} |
|---|
| 1316 |
|
|---|
| 1317 |
// returns true if department string matches dept for this user |
|---|
| 1318 |
function checkDept($dept){ |
|---|
| 1319 |
$deptname = isset($_SESSION["AMP_user"])?$_SESSION["AMP_user"]->_deptname:null; |
|---|
| 1320 |
|
|---|
| 1321 |
if ( ($dept == null) || ($dept == $deptname) ) |
|---|
| 1322 |
return true; |
|---|
| 1323 |
else |
|---|
| 1324 |
return false; |
|---|
| 1325 |
} |
|---|
| 1326 |
|
|---|
| 1327 |
/** |
|---|
| 1328 |
* returns true if asterisk is running with chan_dahdi |
|---|
| 1329 |
* |
|---|
| 1330 |
* @return bool |
|---|
| 1331 |
*/ |
|---|
| 1332 |
function ast_with_dahdi() { |
|---|
| 1333 |
global $version; |
|---|
| 1334 |
global $astman; |
|---|
| 1335 |
global $amp_conf; |
|---|
| 1336 |
|
|---|
| 1337 |
if (!$amp_conf['ZAP2DAHDICOMPAT']) { |
|---|
| 1338 |
return false; |
|---|
| 1339 |
} |
|---|
| 1340 |
|
|---|
| 1341 |
if (empty($version)) { |
|---|
| 1342 |
$engine_info = engine_getinfo(); |
|---|
| 1343 |
$version = $engine_info['version']; |
|---|
| 1344 |
} |
|---|
| 1345 |
|
|---|
| 1346 |
if (version_compare($version, '1.4', 'ge') && $amp_conf['AMPENGINE'] == 'asterisk') { |
|---|
| 1347 |
if (isset($astman) && $astman->connected()) { |
|---|
| 1348 |
$response = $astman->send_request('Command', array('Command' => 'module show like chan_dahdi')); |
|---|
| 1349 |
if (preg_match('/1 modules loaded/', $response['data'])) { |
|---|
| 1350 |
return true; |
|---|
| 1351 |
} |
|---|
| 1352 |
} |
|---|
| 1353 |
} |
|---|
| 1354 |
return false; |
|---|
| 1355 |
} |
|---|
| 1356 |
|
|---|
| 1357 |
function engine_getinfo() { |
|---|
| 1358 |
global $amp_conf; |
|---|
| 1359 |
global $astman; |
|---|
| 1360 |
|
|---|
| 1361 |
switch ($amp_conf['AMPENGINE']) { |
|---|
| 1362 |
case 'asterisk': |
|---|
| 1363 |
if (isset($astman) && $astman->connected()) { |
|---|
| 1364 |
//get version (1.4) |
|---|
| 1365 |
$response = $astman->send_request('Command', array('Command'=>'core show version')); |
|---|
| 1366 |
if (preg_match('/No such command/',$response['data'])) { |
|---|
| 1367 |
// get version (1.2) |
|---|
| 1368 |
$response = $astman->send_request('Command', array('Command'=>'show version')); |
|---|
| 1369 |
} |
|---|
| 1370 |
$verinfo = $response['data']; |
|---|
| 1371 |
} else { |
|---|
| 1372 |
// could not connect to asterisk manager, try console |
|---|
| 1373 |
$verinfo = exec('asterisk -V'); |
|---|
| 1374 |
} |
|---|
| 1375 |
|
|---|
| 1376 |
if (preg_match('/Asterisk (\d+(\.\d+)*)(-?(\S*))/', $verinfo, $matches)) { |
|---|
| 1377 |
return array('engine'=>'asterisk', 'version' => $matches[1], 'additional' => $matches[4], 'raw' => $verinfo); |
|---|
| 1378 |
} elseif (preg_match('/Asterisk SVN-(\d+(\.\d+)*)(-?(\S*))/', $verinfo, $matches)) { |
|---|
| 1379 |
return array('engine'=>'asterisk', 'version' => $matches[1], 'additional' => $matches[4], 'raw' => $verinfo); |
|---|
| 1380 |
} elseif (preg_match('/Asterisk SVN-branch-(\d+(\.\d+)*)-r(-?(\S*))/', $verinfo, $matches)) { |
|---|
| 1381 |
return array('engine'=>'asterisk', 'version' => $matches[1].'.'.$matches[4], 'additional' => $matches[4], 'raw' => $verinfo); |
|---|
| 1382 |
} elseif (preg_match('/Asterisk SVN-trunk-r(-?(\S*))/', $verinfo, $matches)) { |
|---|
| 1383 |
return array('engine'=>'asterisk', 'version' => '1.6', 'additional' => $matches[1], 'raw' => $verinfo); |
|---|
| 1384 |
} elseif (preg_match('/Asterisk SVN-.+-(\d+(\.\d+)*)-r(-?(\S*))-(.+)/', $verinfo, $matches)) { |
|---|
| 1385 |
return array('engine'=>'asterisk', 'version' => $matches[1], 'additional' => $matches[3], 'raw' => $verinfo); |
|---|
| 1386 |
} elseif (preg_match('/Asterisk [B].(\d+(\.\d+)*)(-?(\S*))/', $verinfo, $matches)) { |
|---|
| 1387 |
return array('engine'=>'asterisk', 'version' => '1.2', 'additional' => $matches[3], 'raw' => $verinfo); |
|---|
| 1388 |
} elseif (preg_match('/Asterisk [C].(\d+(\.\d+)*)(-?(\S*))/', $verinfo, $matches)) { |
|---|
| 1389 |
return array('engine'=>'asterisk', 'version' => '1.4', 'additional' => $matches[3], 'raw' => $verinfo); |
|---|
| 1390 |
} |
|---|
| 1391 |
|
|---|
| 1392 |
return array('engine'=>'ERROR-UNABLE-TO-PARSE', 'version'=>'0', 'additional' => '0', 'raw' => $verinfo); |
|---|
| 1393 |
break; |
|---|
| 1394 |
} |
|---|
| 1395 |
return array('engine'=>'ERROR-UNSUPPORTED-ENGINE-'.$amp_conf['AMPENGINE'], 'version'=>'0', 'additional' => '0', 'raw' => $verinfo); |
|---|
| 1396 |
} |
|---|
| 1397 |
|
|---|
| 1398 |
if (!function_exists('version_compare_freepbx')) { |
|---|
| 1399 |
/* verison_compare that works with freePBX version numbers |
|---|
| 1400 |
*/ |
|---|
| 1401 |
function version_compare_freepbx($version1, $version2, $op = null) { |
|---|
| 1402 |
$version1 = str_replace("rc","RC", strtolower($version1)); |
|---|
| 1403 |
$version2 = str_replace("rc","RC", strtolower($version2)); |
|---|
| 1404 |
if (!is_null($op)) { |
|---|
| 1405 |
return version_compare($version1, $version2, $op); |
|---|
| 1406 |
} else { |
|---|
| 1407 |
return version_compare($version1, $version2); |
|---|
| 1408 |
} |
|---|
| 1409 |
} |
|---|
| 1410 |
} |
|---|
| 1411 |
|
|---|
| 1412 |
/* queries database using PEAR. |
|---|
| 1413 |
* $type can be query, getAll, getRow, getCol, getOne, etc |
|---|
| 1414 |
* $fetchmode can be DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC, DB_FETCHMODE_OBJECT |
|---|
| 1415 |
* returns array, unless using getOne |
|---|
| 1416 |
*/ |
|---|
| 1417 |
function sql($sql,$type="query",$fetchmode=null) { |
|---|
| 1418 |
global $db; |
|---|
| 1419 |
$results = $db->$type($sql,$fetchmode); |
|---|
| 1420 |
if(DB::IsError($results)) { |
|---|
| 1421 |
die_freepbx($results->getDebugInfo() . "SQL - <br /> $sql" ); |
|---|
| 1422 |
} |
|---|
| 1423 |
return $results; |
|---|
| 1424 |
} |
|---|
| 1425 |
|
|---|
| 1426 |
/** Format input so it can be safely used as a literal in a query. |
|---|
| 1427 |
* Literals are values such as strings or numbers which get utilized in places |
|---|
| 1428 |
* like WHERE, SET and VALUES clauses of SQL statements. |
|---|
| 1429 |
* The format returned depends on the PHP data type of input and the database |
|---|
| 1430 |
* type being used. This simply calls PEAR's DB::smartQuote() function |
|---|
| 1431 |
* @param mixed The value to go into the database |
|---|
| 1432 |
* @return string A value that can be safely inserted into an SQL query |
|---|
| 1433 |
*/ |
|---|
| 1434 |
function q(&$value) { |
|---|
| 1435 |
global $db; |
|---|
| 1436 |
return $db->quoteSmart($value); |
|---|
| 1437 |
} |
|---|
| 1438 |
|
|---|
| 1439 |
// sql text formatting -- couldn't see that one was available already |
|---|
| 1440 |
function sql_formattext($txt) { |
|---|
| 1441 |
global $db; |
|---|
| 1442 |
if (isset($txt)) { |
|---|
| 1443 |
$fmt = $db->escapeSimple($txt); |
|---|
| 1444 |
$fmt = "'" . $fmt . "'"; |
|---|
| 1445 |
} else { |
|---|
| 1446 |
$fmt = 'null'; |
|---|
| 1447 |
} |
|---|
| 1448 |
|
|---|
| 1449 |
return $fmt; |
|---|
| 1450 |
} |
|---|
| 1451 |
|
|---|
| 1452 |
function die_freepbx($text, $extended_text="", $type="FATAL") { |
|---|
| 1453 |
if (function_exists('fatal')) { |
|---|
| 1454 |
// "custom" error handler |
|---|
| 1455 |
// fatal may only take one param, so we suppress error messages because it doesn't really matter |
|---|
| 1456 |
@fatal($text, $extended_text, $type); |
|---|
| 1457 |
} else if (isset($_SERVER['REQUEST_METHOD'])) { |
|---|
| 1458 |
// running in webserver |
|---|
| 1459 |
echo "<h1>".$type." ERROR</h1>\n"; |
|---|
| 1460 |
echo "<h3>".$text."</h3>\n"; |
|---|
| 1461 |
if (!empty($extended_text)) { |
|---|
| 1462 |
echo "<p>".$extended_text."</p>\n"; |
|---|
| 1463 |
} |
|---|
| 1464 |
} else { |
|---|
| 1465 |
// CLI |
|---|
| 1466 |
echo "[$type] ".$text." ".$extended_text."\n"; |
|---|
| 1467 |
} |
|---|
| 1468 |
|
|---|
| 1469 |
// always ensure we exit at this point |
|---|
| 1470 |
exit(1); |
|---|
| 1471 |
} |
|---|
| 1472 |
|
|---|
| 1473 |
//tell application we need to reload asterisk |
|---|
| 1474 |
function needreload() { |
|---|
| 1475 |
global $db; |
|---|
| 1476 |
$sql = "UPDATE admin SET value = 'true' WHERE variable = 'need_reload'"; |
|---|
| 1477 |
$result = $db->query($sql); |
|---|
| 1478 |
if(DB::IsError($result)) { |
|---|
| 1479 |
die_freepbx($sql."<br>\n".$result->getMessage()); |
|---|
| 1480 |
} |
|---|
| 1481 |
} |
|---|
| 1482 |
|
|---|
| 1483 |
function check_reload_needed() { |
|---|
| 1484 |
global $db; |
|---|
| 1485 |
global $amp_conf; |
|---|
| 1486 |
$sql = "SELECT value FROM admin WHERE variable = 'need_reload'"; |
|---|
| 1487 |
$row = $db->getRow($sql); |
|---|
| 1488 |
if(DB::IsError($row)) { |
|---|
| 1489 |
die_freepbx($sql."<br>\n".$row->getMessage()); |
|---|
| 1490 |
} |
|---|
| 1491 |
return ($row[0] == 'true' || $amp_conf['DEVELRELOAD']); |
|---|
| 1492 |
} |
|---|
| 1493 |
|
|---|
| 1494 |
function do_reload() { |
|---|
| 1495 |
global $amp_conf, $asterisk_conf, $db, $astman; |
|---|
| 1496 |
|
|---|
| 1497 |
$notify =& notifications::create($db); |
|---|
| 1498 |
|
|---|
| 1499 |
$return = array('num_errors'=>0,'test'=>'abc'); |
|---|
| 1500 |
$exit_val = null; |
|---|
| 1501 |
|
|---|
| 1502 |
if (isset($amp_conf["PRE_RELOAD"]) && !empty($amp_conf['PRE_RELOAD'])) { |
|---|
| 1503 |
exec( $amp_conf["PRE_RELOAD"], $output, $exit_val ); |
|---|
| 1504 |
|
|---|
| 1505 |
if ($exit_val != 0) { |
|---|
| 1506 |
$desc = sprintf(_("Exit code was %s and output was: %s"), $exit_val, "\n\n".implode("\n",$output)); |
|---|
| 1507 |
$notify->add_error('freepbx','reload_pre_script', sprintf(_('Could not run %s script.'), $amp_conf['PRE_RELOAD']), $desc); |
|---|
| 1508 |
|
|---|
| 1509 |
$return['num_errors']++; |
|---|
| 1510 |
} else { |
|---|
| 1511 |
$notify->delete('freepbx', 'reload_pre_script'); |
|---|
| 1512 |
} |
|---|
| 1513 |
} |
|---|
| 1514 |
|
|---|
| 1515 |
$retrieve = $amp_conf['AMPBIN'].'/retrieve_conf 2>&1'; |
|---|
| 1516 |
//exec($retrieve.'&>'.$asterisk_conf['astlogdir'].'/freepbx-retrieve.log', $output, $exit_val); |
|---|
| 1517 |
exec($retrieve, $output, $exit_val); |
|---|
| 1518 |
|
|---|
| 1519 |
// retrive_conf html output |
|---|
| 1520 |
$return['retrieve_conf'] = 'exit: '.$exit_val.'<br/>'.implode('<br/>',$output); |
|---|
| 1521 |
|
|---|
| 1522 |
if ($exit_val != 0) { |
|---|
| 1523 |
$return['status'] = false; |
|---|
| 1524 |
$return['message'] = sprintf(_('Reload failed because retrieve_conf encountered an error: %s'),$exit_val); |
|---|
| 1525 |
$return['num_errors']++; |
|---|
| 1526 |
$notify->add_critical('freepbx','RCONFFAIL', _("retrieve_conf failed, config not applied"), $return['message']); |
|---|
| 1527 |
return $return; |
|---|
| 1528 |
} |
|---|
| 1529 |
|
|---|
| 1530 |
if (!isset($astman) || !$astman) { |
|---|
| 1531 |
$return['status'] = false; |
|---|
| 1532 |
$return['message'] = _('Reload failed because FreePBX could not connect to the asterisk manager interface.'); |
|---|
| 1533 |
$return['num_errors']++; |
|---|
| 1534 |
$notify->add_critical('freepbx','RCONFFAIL', _("retrieve_conf failed, config not applied"), $return['message']); |
|---|
| 1535 |
return $return; |
|---|
| 1536 |
} |
|---|
| 1537 |
$notify->delete('freepbx', 'RCONFFAIL'); |
|---|
| 1538 |
|
|---|
| 1539 |
//reload MOH to get around 'reload' not actually doing that. |
|---|
| 1540 |
$astman->send_request('Command', array('Command'=>'moh reload')); |
|---|
| 1541 |
|
|---|
| 1542 |
//reload asterisk |
|---|
| 1543 |
$astman->send_request('Command', array('Command'=>'reload')); |
|---|
| 1544 |
|
|---|
| 1545 |
$return['status'] = true; |
|---|
| 1546 |
$return['message'] = _('Successfully reloaded'); |
|---|
| 1547 |
|
|---|
| 1548 |
|
|---|
| 1549 |
if ($amp_conf['FOPRUN'] && !$amp_conf['FOPDISABLE']) { |
|---|
| 1550 |
//bounce op_server.pl |
|---|
| 1551 |
$wOpBounce = $amp_conf['AMPBIN'].'/bounce_op.sh'; |
|---|
| 1552 |
exec($wOpBounce.' &>'.$asterisk_conf['astlogdir'].'/freepbx-bounce_op.log', $output, $exit_val); |
|---|
| 1553 |
|
|---|
| 1554 |
if ($exit_val != 0) { |
|---|
| 1555 |
$desc = _('Could not reload the FOP operator panel server using the bounce_op.sh script. Configuration changes may not be reflected in the panel display.'); |
|---|
| 1556 |
$notify->add_error('freepbx','reload_fop', _('Could not reload FOP server'), $desc); |
|---|
| 1557 |
|
|---|
| 1558 |
$return['num_errors']++; |
|---|
| 1559 |
} else { |
|---|
| 1560 |
$notify->delete('freepbx','reload_fop'); |
|---|
| 1561 |
} |
|---|
| 1562 |
} |
|---|
| 1563 |
|
|---|
| 1564 |
//store asterisk reloaded status |
|---|
| 1565 |
$sql = "UPDATE admin SET value = 'false' WHERE variable = 'need_reload'"; |
|---|
| 1566 |
$result = $db->query($sql); |
|---|
| 1567 |
if(DB::IsError($result)) { |
|---|
| 1568 |
$return['message'] = _('Successful reload, but could not clear reload flag due to a database error: ').$db->getMessage(); |
|---|
| 1569 |
$return['num_errors']++; |
|---|
| 1570 |
} |
|---|
| 1571 |
|
|---|
| 1572 |
if (isset($amp_conf["POST_RELOAD"]) && !empty($amp_conf['POST_RELOAD'])) { |
|---|
| 1573 |
exec( $amp_conf["POST_RELOAD"], $output, $exit_val ); |
|---|
| 1574 |
|
|---|
| 1575 |
if ($exit_val != 0) { |
|---|
| 1576 |
$desc = sprintf(_("Exit code was %s and output was: %s"), $exit_val, "\n\n".implode("\n",$output)); |
|---|
| 1577 |
$notify->add_error('freepbx','reload_post_script', sprintf(_('Could not run %s script.'), 'POST_RELOAD'), $desc); |
|---|
| 1578 |
|
|---|
| 1579 |
$return['num_errors']++; |
|---|
| 1580 |
} else { |
|---|
| 1581 |
$notify->delete('freepbx', 'reload_post_script'); |
|---|
| 1582 |
} |
|---|
| 1583 |
} |
|---|
| 1584 |
|
|---|
| 1585 |
return $return; |
|---|
| 1586 |
} |
|---|
| 1587 |
|
|---|
| 1588 |
//get the version number |
|---|
| 1589 |
function getversion() { |
|---|
| 1590 |
global $db; |
|---|
| 1591 |
$sql = "SELECT value FROM admin WHERE variable = 'version'"; |
|---|
| 1592 |
$results = $db->getRow($sql); |
|---|
| 1593 |
if(DB::IsError($results)) { |
|---|
| 1594 |
die_freepbx($sql."<br>\n".$results->getMessage()); |
|---|
| 1595 |
} |
|---|
| 1596 |
return $results[0]; |
|---|
| 1597 |
} |
|---|
| 1598 |
|
|---|
| 1599 |
//get the version number |
|---|
| 1600 |
function get_framework_version() { |
|---|
| 1601 |
global $db; |
|---|
| 1602 |
$sql = "SELECT version FROM modules WHERE modulename = 'framework' AND enabled = 1"; |
|---|
| 1603 |
$version = $db->getOne($sql); |
|---|
| 1604 |
if(DB::IsError($version)) { |
|---|
| 1605 |
die_freepbx($sql."<br>\n".$version->getMessage()); |
|---|
| 1606 |
} |
|---|
| 1607 |
return $version; |
|---|
| 1608 |
} |
|---|
| 1609 |
|
|---|
| 1610 |
// draw list for users and devices with paging |
|---|
| 1611 |
// $skip has been dprecated, used to be used to page-enate |
|---|
| 1612 |
function drawListMenu($results, $skip, $type, $dispnum, $extdisplay, $description=false) { |
|---|
| 1613 |
|
|---|
| 1614 |
$index = 0; |
|---|
| 1615 |
echo "<ul>\n"; |
|---|
| 1616 |
if ($description !== false) { |
|---|
| 1617 |
echo "\t<li><a ".($extdisplay=='' ? 'class="current"':'')." href=\"config.php?type=".$type."&display=".$dispnum."\">"._("Add")." ".$description."</a></li>\n"; |
|---|
| 1618 |
} |
|---|
| 1619 |
if (isset($results)) { |
|---|
| 1620 |
foreach ($results as $key=>$result) { |
|---|
| 1621 |
$index= $index + 1; |
|---|
| 1622 |
echo "\t<li><a".($extdisplay==$result[0] ? ' class="current"':''). " href=\"config.php?type=".$type."&display=".$dispnum."&extdisplay={$result[0]}\">{$result[1]} <{$result[0]}></a></li>\n"; |
|---|
| 1623 |
} |
|---|
| 1624 |
} |
|---|
| 1625 |
echo "</ul>\n"; |
|---|
| 1626 |
} |
|---|
| 1627 |
|
|---|
| 1628 |
// this function returns true if $astman is defined and set to something (implying a current connection, false otherwise. |
|---|
| 1629 |
// this function no longer puts out an error message, it is up to the caller to handle the situation. |
|---|
| 1630 |
// Should probably be changed (at least name) to check if a connection is available to the current engine) |
|---|
| 1631 |
// |
|---|
| 1632 |
function checkAstMan() { |
|---|
| 1633 |
global $astman; |
|---|
| 1634 |
|
|---|
| 1635 |
return ($astman)?true:false; |
|---|
| 1636 |
} |
|---|
| 1637 |
|
|---|
| 1638 |
/* merge_ext_followme($dest) { |
|---|
| 1639 |
* |
|---|
| 1640 |
* The purpose of this function is to take a destination |
|---|
| 1641 |
* that was either a core extension OR a findmefollow-destination |
|---|
| 1642 |
* and convert it so that they are merged and handled just like |
|---|
| 1643 |
* direct-did routing |
|---|
| 1644 |
* |
|---|
| 1645 |
* Assuming an extension number of 222: |
|---|
| 1646 |
* |
|---|
| 1647 |
* The two formats that existed for findmefollow were: |
|---|
| 1648 |
* |
|---|
| 1649 |
* ext-findmefollow,222,1 |
|---|
| 1650 |
* ext-findmefollow,FM222,1 |
|---|
| 1651 |
* |
|---|
| 1652 |
* The one format that existed for core was: |
|---|
| 1653 |
* |
|---|
| 1654 |
* ext-local,222,1 |
|---|
| 1655 |
* |
|---|
| 1656 |
* In all those cases they should be converted to: |
|---|
| 1657 |
* |
|---|
| 1658 |
* from-did-direct,222,1 |
|---|
| 1659 |
* |
|---|
| 1660 |
*/ |
|---|
| 1661 |
function merge_ext_followme($dest) { |
|---|
| 1662 |
|
|---|
| 1663 |
if (preg_match("/^\s*ext-findmefollow,(FM)?(\d+),(\d+)/",$dest,$matches) || |
|---|
| 1664 |
preg_match("/^\s*ext-local,(FM)?(\d+),(\d+)/",$dest,$matches) ) { |
|---|
| 1665 |
// matches[2] => extn |
|---|
| 1666 |
// matches[3] => priority |
|---|
| 1667 |
return "from-did-direct,".$matches[2].",".$matches[3]; |
|---|
| 1668 |
} else { |
|---|
| 1669 |
return $dest; |
|---|
| 1670 |
} |
|---|
| 1671 |
} |
|---|
| 1672 |
|
|---|
| 1673 |
/** Recursively read voicemail.conf (and any included files) |
|---|
| 1674 |
* This function is called by getVoicemailConf() |
|---|
| 1675 |
*/ |
|---|
| 1676 |
function parse_voicemailconf($filename, &$vmconf, &$section) { |
|---|
| 1677 |
if (is_null($vmconf)) { |
|---|
| 1678 |
$vmconf = array(); |
|---|
| 1679 |
} |
|---|
| 1680 |
if (is_null($section)) { |
|---|
| 1681 |
$section = "general"; |
|---|
| 1682 |
} |
|---|
| 1683 |
|
|---|
| 1684 |
if (file_exists($filename)) { |
|---|
| 1685 |
$fd = fopen($filename, "r"); |
|---|
| 1686 |
while ($line = fgets($fd, 1024)) { |
|---|
| 1687 |
if (preg_match("/^\s*(\d+)\s*=>\s*(\d*),(.*),(.*),(.*),(.*)\s*([;#].*)?/",$line,$matches)) { |
|---|
| 1688 |
// "mailbox=>password,name,email,pager,options" |
|---|
| 1689 |
// this is a voicemail line |
|---|
| 1690 |
$vmconf[$section][ $matches[1] ] = array("mailbox"=>$matches[1], |
|---|
| 1691 |
"pwd"=>$matches[2], |
|---|
| 1692 |
"name"=>$matches[3], |
|---|
| 1693 |
"email"=>$matches[4], |
|---|
| 1694 |
"pager"=>$matches[5], |
|---|
| 1695 |
"options"=>array(), |
|---|
| 1696 |
); |
|---|
| 1697 |
|
|---|
| 1698 |
// parse options |
|---|
| 1699 |
//output($matches); |
|---|
| 1700 |
foreach (explode("|",$matches[6]) as $opt) { |
|---|
| 1701 |
$temp = explode("=",$opt); |
|---|
| 1702 |
//output($temp); |
|---|
| 1703 |
if (isset($temp[1])) { |
|---|
| 1704 |
list($key,$value) = $temp; |
|---|
| 1705 |
$vmconf[$section][ $matches[1] ]["options"][$key] = $value; |
|---|
| 1706 |
} |
|---|
| 1707 |
} |
|---|
| 1708 |
} else if (preg_match("/^\s*(\d+)\s*=>\s*dup,(.*)\s*([;#].*)?/",$line,$matches)) { |
|---|
| 1709 |
// "mailbox=>dup,name" |
|---|
| 1710 |
// duplace name line |
|---|
| 1711 |
$vmconf[$section][ $matches[1] ]["dups"][] = $matches[2]; |
|---|
| 1712 |
} else if (preg_match("/^\s*#include\s+(.*)\s*([;#].*)?/",$line,$matches)) { |
|---|
| 1713 |
// include another file |
|---|
| 1714 |
|
|---|
| 1715 |
if ($matches[1][0] == "/") { |
|---|
| 1716 |
// absolute path |
|---|
| 1717 |
$filename = $matches[1]; |
|---|
| 1718 |
} else { |
|---|
| 1719 |
// relative path |
|---|
| 1720 |
$filename = dirname($filename)."/".$matches[1]; |
|---|
| 1721 |
} |
|---|
| 1722 |
|
|---|
| 1723 |
parse_voicemailconf($filename, $vmconf, $section); |
|---|
| 1724 |
|
|---|
| 1725 |
} else if (preg_match("/^\s*\[(.+)\]/",$line,$matches)) { |
|---|
| 1726 |
// section name |
|---|
| 1727 |
$section = strtolower($matches[1]); |
|---|
| 1728 |
} else if (preg_match("/^\s*([a-zA-Z0-9-_]+)\s*=\s*(.*?)\s*([;#].*)?$/",$line,$matches)) { |
|---|
| 1729 |
// name = value |
|---|
| 1730 |
// option line |
|---|
| 1731 |
$vmconf[$section][ $matches[1] ] = $matches[2]; |
|---|
| 1732 |
} |
|---|
| 1733 |
} |
|---|
| 1734 |
fclose($fd); |
|---|
| 1735 |
} |
|---|
| 1736 |
} |
|---|
| 1737 |
|
|---|
| 1738 |
/** Write the voicemail.conf file |
|---|
| 1739 |
* This is called by saveVoicemail() |
|---|
| 1740 |
* It's important to make a copy of $vmconf before passing it. Since this is a recursive function, has to |
|---|
| 1741 |
* pass by reference. At the same time, it removes entries as it writes them to the file, so if you don't have |
|---|
| 1742 |
* a copy, by the time it's done $vmconf will be empty. |
|---|
| 1743 |
*/ |
|---|
| 1744 |
function write_voicemailconf($filename, &$vmconf, &$section, $iteration = 0) { |
|---|
| 1745 |
global $amp_conf; |
|---|
| 1746 |
if ($iteration == 0) { |
|---|
| 1747 |
$section = null; |
|---|
| 1748 |
} |
|---|
| 1749 |
|
|---|
| 1750 |
$output = array(); |
|---|
| 1751 |
|
|---|
| 1752 |
// if the file does not, copy if from the template. |
|---|
| 1753 |
// TODO: is this logical? |
|---|
| 1754 |
// TODO: don't use hardcoded path...? |
|---|
| 1755 |
if (!file_exists($filename)) { |
|---|
| 1756 |
if (!copy( rtrim($amp_conf["ASTETCDIR"],"/")."/voicemail.conf.template", $filename )){ |
|---|
| 1757 |
return; |
|---|
| 1758 |
} |
|---|
| 1759 |
} |
|---|
| 1760 |
|
|---|
| 1761 |
$fd = fopen($filename, "r"); |
|---|
| 1762 |
while ($line = fgets($fd, 1024)) { |
|---|
| 1763 |
if (preg_match("/^(\s*)(\d+)(\s*)=>(\s*)(\d*),(.*),(.*),(.*),(.*)(\s*[;#].*)?$/",$line,$matches)) { |
|---|
| 1764 |
// "mailbox=>password,name,email,pager,options" |
|---|
| 1765 |
// this is a voicemail line |
|---|
| 1766 |
//DEBUG echo "\nmailbox"; |
|---|
| 1767 |
|
|---|
| 1768 |
// make sure we have something as a comment |
|---|
| 1769 |
if (!isset($matches[10])) { |
|---|
| 1770 |
$matches[10] = ""; |
|---|
| 1771 |
} |
|---|
| 1772 |
|
|---|
| 1773 |
// $matches[1] [3] and [4] are to preserve indents/whitespace, we add these back in |
|---|
| 1774 |
|
|---|
| 1775 |
if (isset($vmconf[$section][ $matches[2] ])) { |
|---|
| 1776 |
// we have this one loaded |
|---|
| 1777 |
// repopulate from our version |
|---|
| 1778 |
$temp = & $vmconf[$section][ $matches[2] ]; |
|---|
| 1779 |
|
|---|
| 1780 |
$options = array(); |
|---|
| 1781 |
foreach ($temp["options"] as $key=>$value) { |
|---|
| 1782 |
$options[] = $key."=".$value; |
|---|
| 1783 |
} |
|---|
| 1784 |
|
|---|
| 1785 |
$output[] = $matches[1].$temp["mailbox"].$matches[3]."=>".$matches[4].$temp["pwd"].",".$temp["name"].",".$temp["email"].",".$temp["pager"].",". implode("|",$options).$matches[10]; |
|---|
| 1786 |
|
|---|
| 1787 |
// remove this one from $vmconf |
|---|
| 1788 |
unset($vmconf[$section][ $matches[2] ]); |
|---|
| 1789 |
} else { |
|---|
| 1790 |
// we don't know about this mailbox, so it must be deleted |
|---|
| 1791 |
// (and hopefully not JUST added since we did read_voiceamilconf) |
|---|
| 1792 |
|
|---|
| 1793 |
// do nothing |
|---|
| 1794 |
} |
|---|
| 1795 |
|
|---|
| 1796 |
} else if (preg_match("/^(\s*)(\d+)(\s*)=>(\s*)dup,(.*)(\s*[;#].*)?$/",$line,$matches)) { |
|---|
| 1797 |
// "mailbox=>dup,name" |
|---|
| 1798 |
// duplace name line |
|---|
| 1799 |
// leave it as-is (for now) |
|---|
| 1800 |
//DEBUG echo "\ndup mailbox"; |
|---|
| 1801 |
$output[] = $line; |
|---|
| 1802 |
} else if (preg_match("/^(\s*)#include(\s+)(.*)(\s*[;#].*)?$/",$line,$matches)) { |
|---|
| 1803 |
// include another file |
|---|
| 1804 |
//DEBUG echo "\ninclude ".$matches[3]."<blockquote>"; |
|---|
| 1805 |
|
|---|
| 1806 |
// make sure we have something as a comment |
|---|
| 1807 |
if (!isset($matches[4])) { |
|---|
| 1808 |
$matches[4] = ""; |
|---|
| 1809 |
} |
|---|
| 1810 |
|
|---|
| 1811 |
if ($matches[3][0] == "/") { |
|---|
| 1812 |
// absolute path |
|---|
| 1813 |
$include_filename = $matches[3]; |
|---|
| 1814 |
} else { |
|---|
| 1815 |
// relative path |
|---|
| 1816 |
$include_filename = dirname($filename)."/".$matches[3]; |
|---|
| 1817 |
} |
|---|
| 1818 |
|
|---|
| 1819 |
$output[] = $matches[1]."#include".$matches[2].$matches[3].$matches[4]; |
|---|
| 1820 |
write_voicemailconf($include_filename, $vmconf, $section, $iteration+1); |
|---|
| 1821 |
|
|---|
| 1822 |
//DEBUG echo "</blockquote>"; |
|---|
| 1823 |
|
|---|
| 1824 |
} else if (preg_match("/^(\s*)\[(.+)\](\s*[;#].*)?$/",$line,$matches)) { |
|---|
| 1825 |
// section name |
|---|
| 1826 |
//DEBUG echo "\nsection"; |
|---|
| 1827 |
|
|---|
| 1828 |
// make sure we have something as a comment |
|---|
| 1829 |
if (!isset($matches[3])) { |
|---|
| 1830 |
$matches[3] = ""; |
|---|
| 1831 |
} |
|---|
| 1832 |
|
|---|
| 1833 |
// check if this is the first run (section is null) |
|---|
| 1834 |
if ($section !== null) { |
|---|
| 1835 |
// we need to add any new entries here, before the section changes |
|---|
| 1836 |
//DEBUG echo "<blockquote><i>"; |
|---|
| 1837 |
//DEBUG var_dump($vmconf[$section]); |
|---|
| 1838 |
if (isset($vmconf[$section])){ //need this, or we get an error if we unset the last items in this section - should probably automatically remove the section/context from voicemail.conf |
|---|
| 1839 |
foreach ($vmconf[$section] as $key=>$value) { |
|---|
| 1840 |
if (is_array($value)) { |
|---|
| 1841 |
// mailbox line |
|---|
| 1842 |
|
|---|
| 1843 |
$temp = & $vmconf[$section][ $key ]; |
|---|
| 1844 |
|
|---|
| 1845 |
$options = array(); |
|---|
| 1846 |
foreach ($temp["options"] as $key1=>$value) { |
|---|
| 1847 |
$options[] = $key1."=".$value; |
|---|
| 1848 |
} |
|---|
| 1849 |
|
|---|
| 1850 |
$output[] = $temp["mailbox"]." => ".$temp["pwd"].",".$temp["name"].",".$temp["email"].",".$temp["pager"].",". implode("|",$options); |
|---|
| 1851 |
|
|---|
| 1852 |
// remove this one from $vmconf |
|---|
| 1853 |
unset($vmconf[$section][ $key ]); |
|---|
| 1854 |
|
|---|
| 1855 |
} else { |
|---|
| 1856 |
// option line |
|---|
| 1857 |
|
|---|
| 1858 |
$output[] = $key."=".$vmconf[$section][ $key ]; |
|---|
| 1859 |
|
|---|
| 1860 |
// remove this one from $vmconf |
|---|
| 1861 |
unset($vmconf[$section][ $key ]); |
|---|
| 1862 |
} |
|---|
| 1863 |
} |
|---|
| 1864 |
} |
|---|
| 1865 |
//DEBUG echo "</i></blockquote>"; |
|---|
| 1866 |
} |
|---|
| 1867 |
|
|---|
| 1868 |
$section = strtolower($matches[2]); |
|---|
| 1869 |
$output[] = $matches[1]."[".$section."]".$matches[3]; |
|---|
| 1870 |
$existing_sections[] = $section; //remember that this section exists |
|---|
| 1871 |
|
|---|
| 1872 |
} else if (preg_match("/^(\s*)([a-zA-Z0-9-_]+)(\s*)=(\s*)(.*?)(\s*[;#].*)?$/",$line,$matches)) { |
|---|
| 1873 |
// name = value |
|---|
| 1874 |
// option line |
|---|
| 1875 |
//DEBUG echo "\noption line"; |
|---|
| 1876 |
|
|---|
| 1877 |
|
|---|
| 1878 |
// make sure we have something as a comment |
|---|
| 1879 |
if (!isset($matches[6])) { |
|---|
| 1880 |
$matches[6] = ""; |
|---|
| 1881 |
} |
|---|
| 1882 |
|
|---|
| 1883 |
if (isset($vmconf[$section][ $matches[2] ])) { |
|---|
| 1884 |
$output[] = $matches[1].$matches[2].$matches[3]."=".$matches[4].$vmconf[$section][ $matches[2] ].$matches[6]; |
|---|
| 1885 |
|
|---|
| 1886 |
// remove this one from $vmconf |
|---|
| 1887 |
unset($vmconf[$section][ $matches[2] ]); |
|---|
| 1888 |
} |
|---|
| 1889 |
// else it's been deleted, so we don't write it in |
|---|
| 1890 |
|
|---|
| 1891 |
} else { |
|---|
| 1892 |
// unknown other line -- probably a comment or whitespace |
|---|
| 1893 |
//DEBUG echo "\nother: ".$line; |
|---|
| 1894 |
|
|---|
| 1895 |
$output[] = str_replace(array("\n","\r"),"",$line); // str_replace so we don't double-space |
|---|
| 1896 |
} |
|---|
| 1897 |
} |
|---|
| 1898 |
|
|---|
| 1899 |
if (($iteration == 0) && (is_array($vmconf))) { |
|---|
| 1900 |
// we need to add any new entries here, since it's the end of the file |
|---|
| 1901 |
//DEBUG echo "END OF FILE!! <blockquote><i>"; |
|---|
| 1902 |
//DEBUG var_dump($vmconf); |
|---|
| 1903 |
foreach (array_keys($vmconf) as $section) { |
|---|
| 1904 |
if (!in_array($section,$existing_sections)) // If this is a new section, write the context label |
|---|
| 1905 |
$output[] = "[".$section."]"; |
|---|
| 1906 |
foreach ($vmconf[$section] as $key=>$value) { |
|---|
| 1907 |
if (is_array($value)) { |
|---|
| 1908 |
// mailbox line |
|---|
| 1909 |
|
|---|
| 1910 |
$temp = & $vmconf[$section][ $key ]; |
|---|
| 1911 |
|
|---|
| 1912 |
$options = array(); |
|---|
| 1913 |
foreach ($temp["options"] as $key=>$value) { |
|---|
| 1914 |
$options[] = $key."=".$value; |
|---|
| 1915 |
} |
|---|
| 1916 |
|
|---|
| 1917 |
$output[] = $temp["mailbox"]." => ".$temp["pwd"].",".$temp["name"].",".$temp["email"].",".$temp["pager"].",". implode("|",$options); |
|---|
| 1918 |
|
|---|
| 1919 |
// remove this one from $vmconf |
|---|
| 1920 |
unset($vmconf[$section][ $key ]); |
|---|
| 1921 |
|
|---|
| 1922 |
} else { |
|---|
| 1923 |
// option line |
|---|
| 1924 |
|
|---|
| 1925 |
$output[] = $key."=".$vmconf[$section][ $key ]; |
|---|
| 1926 |
|
|---|
| 1927 |
// remove this one from $vmconf |
|---|
| 1928 |
unset($vmconf[$section][$key ]); |
|---|
| 1929 |
} |
|---|
| 1930 |
} |
|---|
| 1931 |
} |
|---|
| 1932 |
//DEBUG echo "</i></blockquote>"; |
|---|
| 1933 |
} |
|---|
| 1934 |
|
|---|
| 1935 |
fclose($fd); |
|---|
| 1936 |
|
|---|
| 1937 |
//DEBUG echo "\n\nwriting ".$filename; |
|---|
| 1938 |
//DEBUG echo "\n-----------\n"; |
|---|
| 1939 |
//DEBUG echo implode("\n",$output); |
|---|
| 1940 |
//DEBUG echo "\n-----------\n"; |
|---|
| 1941 |
|
|---|
| 1942 |
// write this file back out |
|---|
| 1943 |
|
|---|
| 1944 |
if ($fd = fopen($filename, "w")) { |
|---|
| 1945 |
fwrite($fd, implode("\n",$output)."\n"); |
|---|
| 1946 |
fclose($fd); |
|---|
| 1947 |
} |
|---|
| 1948 |
} |
|---|
| 1949 |
|
|---|
| 1950 |
// $goto is the current goto destination setting |
|---|
| 1951 |
// $i is the destination set number (used when drawing multiple destination sets in a single form ie: digital receptionist) |
|---|
| 1952 |
// esnure that any form that includes this calls the setDestinations() javascript function on submit. |
|---|
| 1953 |
// ie: if the form name is "edit", and drawselects has been called with $i=2 then use onsubmit="setDestinations(edit,2)" |
|---|
| 1954 |
function drawselects($goto,$i,$show_custom=false) { |
|---|
| 1955 |
global $tabindex; |
|---|
| 1956 |
|
|---|
| 1957 |
/* --- MODULES BEGIN --- */ |
|---|
| 1958 |
global $active_modules; |
|---|
| 1959 |
|
|---|
| 1960 |
$all_destinations = array(); |
|---|
| 1961 |
$module_hash = array(); |
|---|
| 1962 |
|
|---|
| 1963 |
$selectHtml = '<tr><td colspan=2>'; |
|---|
| 1964 |
|
|---|
| 1965 |
//check for module-specific destination functions |
|---|
| 1966 |
foreach ($active_modules as $rawmod => $module) { |
|---|
| 1967 |
$funct = strtolower($rawmod.'_destinations'); |
|---|
| 1968 |
|
|---|
| 1969 |
//if the modulename_destinations() function exits, run it and display selections for it |
|---|
| 1970 |
if (function_exists($funct)) { |
|---|
| 1971 |
$destArray = $funct(); //returns an array with 'destination' and 'description', and optionally 'category' |
|---|
| 1972 |
if (is_Array($destArray)) { |
|---|
| 1973 |
foreach ($destArray as $dest) { |
|---|
| 1974 |
$cat = (isset($dest['category']) ? $dest['category'] : $module['displayname']); |
|---|
| 1975 |
$all_destinations[$cat][] = $dest; |
|---|
| 1976 |
$module_hash[$cat] = $rawmod; |
|---|
| 1977 |
} |
|---|
| 1978 |
} |
|---|
| 1979 |
} |
|---|
| 1980 |
} |
|---|
| 1981 |
|
|---|
| 1982 |
$foundone = false; |
|---|
| 1983 |
$tabindex_needed = true; |
|---|
| 1984 |
foreach ($all_destinations as $cat=>$destination) { |
|---|
| 1985 |
// create a select option for each destination |
|---|
| 1986 |
$options = ""; |
|---|
| 1987 |
$checked = false; |
|---|
| 1988 |
foreach ($destination as $dest) { |
|---|
| 1989 |
$options .= '<option value="'.$dest['destination'].'" '.(strpos($goto,$dest['destination']) === false ? '' : 'SELECTED').'>'.($dest['description'] ? $dest['description'] : $dest['destination']); |
|---|
| 1990 |
|
|---|
| 1991 |
// check to see if the currently selected goto matches one these destinations |
|---|
| 1992 |
if($dest['destination'] == $goto) $checked = true; |
|---|
| 1993 |
} |
|---|
| 1994 |
|
|---|
| 1995 |
// make a unique id to be used for the HTML id |
|---|
| 1996 |
// This allows us to have multiple drawselect() sets on the page without |
|---|
| 1997 |
// conflicting with each other |
|---|
| 1998 |
$radioid = uniqid("drawselect"); |
|---|
| 1999 |
|
|---|
| 2000 |
$cat_identifier = preg_replace('/[^a-zA-Z0-9]/','_', $cat); |
|---|
| 2001 |
|
|---|
| 2002 |
// We bind to the hosting module's domain. If we find the translation there we use it, if not |
|---|
| 2003 |
// we try the default 'amp' domain. If still no luck, we will try the _() which is the current |
|---|
| 2004 |
// module's display since some old translation code may have stored it localy but should migrate |
|---|
| 2005 |
// |
|---|
| 2006 |
bindtextdomain($module_hash[$cat],"modules/".$module_hash[$cat]."/i18n"); |
|---|
| 2007 |
bind_textdomain_codeset($module_hash[$cat], 'utf8'); |
|---|
| 2008 |
$label_text = dgettext($module_hash[$cat],$cat); |
|---|
| 2009 |
if ($label_text == $cat) { |
|---|
| 2010 |
$label_text = dgettext('amp',$label_text); |
|---|
| 2011 |
} |
|---|
| 2012 |
if ($label_text == $cat) { |
|---|
| 2013 |
$label_text = _($label_text); |
|---|
| 2014 |
} |
|---|
| 2015 |
|
|---|
| 2016 |
if ($tabindex_needed && ($checked || ! $goto)) { |
|---|
| 2017 |
$tabindex_txt = (isset($tabindex) && $tabindex != '') ? ' tabindex="'.++$tabindex.'" ':''; |
|---|
| 2018 |
$tabindex_needed = false; |
|---|
| 2019 |
} else { |
|---|
| 2020 |
$tabindex_txt = ''; |
|---|
| 2021 |
} |
|---|
| 2022 |
$selectHtml .= '<input type="radio"'.$tabindex_txt.' id="'.$radioid.'" name="goto'.$i.'" value="'.$cat_identifier.'" '. |
|---|
| 2023 |
//'onclick="javascript:this.form.goto'.$i.'.value=\''.$cat.'\';" '. |
|---|
| 2024 |
//'onkeypress="javascript:if (event.keyCode == 0 || (document.all && event.keyCode == 13)) this.form.goto'.$i.'.value=\''.$cat.'\';" '. |
|---|
| 2025 |
($checked? 'CHECKED=CHECKED' : '').' /> '; |
|---|
| 2026 |
$selectHtml .= '<label for="'.$radioid.'">'.$label_text.':</label> '; |
|---|
| 2027 |
|
|---|
| 2028 |
// set the |
|---|
| 2029 |
// if ($checked) { $gotomod = $cat; } |
|---|
| 2030 |
|
|---|
| 2031 |
$selectHtml .= '<select name="'.$cat_identifier.$i.'" onfocus="document.getElementById(\''.$radioid.'\').checked = true; this.form.goto'.$i.'.value=\''.$cat.'\';">'; |
|---|
| 2032 |
$selectHtml .= $options; |
|---|
| 2033 |
$selectHtml .= "</select><br />\n"; |
|---|
| 2034 |
|
|---|
| 2035 |
if ($checked) $foundone = true; |
|---|
| 2036 |
} |
|---|
| 2037 |
/* --- MODULES END --- */ |
|---|
| 2038 |
|
|---|
| 2039 |
// This is selected if $foundone is false (and goto is not blank) - basically, a fallback |
|---|
| 2040 |
// The ONLY time no radio box is selected is if $goto is empty |
|---|
| 2041 |
$custom_selected = !$foundone && !empty($goto); |
|---|
| 2042 |
|
|---|
| 2043 |
//display a custom goto field |
|---|
| 2044 |
if ($custom_selected || $show_custom) { |
|---|
| 2045 |
if ($show_custom) { |
|---|
| 2046 |
$custom_style = ""; |
|---|
| 2047 |
$custom_background = ""; |
|---|
| 2048 |
} else { |
|---|
| 2049 |
$custom_style = " style='color:red' "; |
|---|
| 2050 |
$custom_background = " style='background:red' readonly='yes' "; |
|---|
| 2051 |
} |
|---|
| 2052 |
$radioid = uniqid("drawselect"); |
|---|
| 2053 |
$selectHtml .= '<input type="radio" id="'.$radioid.'" name="goto'.$i.'" value="custom" '. |
|---|
| 2054 |
//'onclick="javascript:this.form.goto'.$i.'.value=\'custom\';" '. |
|---|
| 2055 |
//'onkeypress="javascript:if (event.keyCode == 0 || (document.all && event.keyCode == 13)) this.form.goto'.$i.'.value=\'custom\';" '. |
|---|
| 2056 |
($custom_selected ? 'CHECKED=CHECKED' : '').' />'; |
|---|
| 2057 |
$selectHtml .= '<a href="#" class="info" '.$custom_style.'>'._("Unknown Destination").' <span>'._("ERROR: You have an unknown destination. If this was carried over as a Custom App from an earlier version, you must go register the destination in the Custom Destination tab provided by the Custom Applications module.<br />This will remain active until you change it but you can no longer edit or add a new one here.").'</span></a>:'; |
|---|
| 2058 |
$selectHtml .= '<input '.$custom_background.' type="text" size="15" name="custom'.$i.'" value="'.($custom_selected ? $goto : '').'" onfocus="document.getElementById(\''.$radioid.'\').checked = true;" />'; |
|---|
| 2059 |
|
|---|
| 2060 |
//close off our row |
|---|
| 2061 |
} |
|---|
| 2062 |
$selectHtml .= '</td></tr>'; |
|---|
| 2063 |
|
|---|
| 2064 |
return $selectHtml; |
|---|
| 2065 |
} |
|---|
| 2066 |
|
|---|
| 2067 |
/* below are legacy functions required to allow pre 2.0 modules to function (ie: interact with 'extensions' table) */ |
|---|
| 2068 |
|
|---|
| 2069 |
//add to extensions table - used in callgroups.php |
|---|
| 2070 |
function legacy_extensions_add($addarray) { |
|---|
| 2071 |
global $db; |
|---|
| 2072 |
$sql = "INSERT INTO extensions (context, extension, priority, application, args, descr, flags) VALUES ('".$addarray[0]."', '".$addarray[1]."', '".$addarray[2]."', '".$addarray[3]."', '".$addarray[4]."', '".$addarray[5]."' , '".$addarray[6]."')"; |
|---|
| 2073 |
$result = $db->query($sql); |
|---|
| 2074 |
if(DB::IsError($result)) { |
|---|
| 2075 |
die_freepbx($sql."<br>\n".$result->getMessage()); |
|---|
| 2076 |
} |
|---|
| 2077 |
return $result; |
|---|
| 2078 |
} |
|---|
| 2079 |
|
|---|
| 2080 |
//delete extension from extensions table |
|---|
| 2081 |
function legacy_extensions_del($context,$exten) { |
|---|
| 2082 |
global $db; |
|---|
| 2083 |
$sql = "DELETE FROM extensions WHERE context = '".$db->escapeSimple($context)."' AND `extension` = '".$db->escapeSimple($exten)."'"; |
|---|
| 2084 |
$result = $db->query($sql); |
|---|
| 2085 |
if(DB::IsError($result)) { |
|---|
| 2086 |
die_freepbx($sql."<br>\n".$result->getMessage()); |
|---|
| 2087 |
} |
|---|
| 2088 |
return $result; |
|---|
| 2089 |
} |
|---|
| 2090 |
|
|---|
| 2091 |
//get args for specified exten and priority - primarily used to grab goto destination |
|---|
| 2092 |
function legacy_args_get($exten,$priority,$context) { |
|---|
| 2093 |
global $db; |
|---|
| 2094 |
$sql = "SELECT args FROM extensions WHERE extension = '".$db->escapeSimple($exten)."' AND priority = '".$db->escapeSimple($priority)."' AND context = '".$db->escapeSimple($context)."'"; |
|---|
| 2095 |
list($args) = $db->getRow($sql); |
|---|
| 2096 |
return $args; |
|---|
| 2097 |
} |
|---|
| 2098 |
|
|---|
| 2099 |
/* end legacy functions */ |
|---|
| 2100 |
|
|---|
| 2101 |
|
|---|
| 2102 |
function get_headers_assoc($url ) { |
|---|
| 2103 |
$url_info=parse_url($url); |
|---|
| 2104 |
if (isset($url_info['scheme']) && $url_info['scheme'] == 'https') { |
|---|
| 2105 |
$port = isset($url_info['port']) ? $url_info['port'] : 443; |
|---|
| 2106 |
@$fp=fsockopen('ssl://'.$url_info['host'], $port, $errno, $errstr, 10); |
|---|
| 2107 |
} else { |
|---|
| 2108 |
$port = isset($url_info['port']) ? $url_info['port'] : 80; |
|---|
| 2109 |
@$fp=fsockopen($url_info['host'], $port, $errno, $errstr, 10); |
|---|
| 2110 |
} |
|---|
| 2111 |
if ($fp) { |
|---|
| 2112 |
stream_set_timeout($fp, 10); |
|---|
| 2113 |
$head = "HEAD ".@$url_info['path']."?".@$url_info['query']; |
|---|
| 2114 |
$head .= " HTTP/1.0\r\nHost: ".@$url_info['host']."\r\n\r\n"; |
|---|
| 2115 |
fputs($fp, $head); |
|---|
| 2116 |
while(!feof($fp)) { |
|---|
| 2117 |
if($header=trim(fgets($fp, 1024))) { |
|---|
| 2118 |
$sc_pos = strpos($header, ':'); |
|---|
| 2119 |
if ($sc_pos === false) { |
|---|
| 2120 |
$headers['status'] = $header; |
|---|
| 2121 |
} else { |
|---|
| 2122 |
$label = substr( $header, 0, $sc_pos ); |
|---|
| 2123 |
$value = substr( $header, $sc_pos+1 ); |
|---|
| 2124 |
$headers[strtolower($label)] = trim($value); |
|---|
| 2125 |
} |
|---|
| 2126 |
} |
|---|
| 2127 |
} |
|---|
| 2128 |
return $headers; |
|---|
| 2129 |
} else { |
|---|
| 2130 |
return false; |
|---|
| 2131 |
} |
|---|
| 2132 |
} |
|---|
| 2133 |
|
|---|
| 2134 |
function execSQL( $file ) { |
|---|
| 2135 |
global $db; |
|---|
| 2136 |
$data = null; |
|---|
| 2137 |
|
|---|
| 2138 |
// run sql script |
|---|
| 2139 |
$fd = fopen( $file ,"r" ); |
|---|
| 2140 |
|
|---|
| 2141 |
while (!feof($fd)) { |
|---|
| 2142 |
$data .= fread($fd, 1024); |
|---|
| 2143 |
} |
|---|
| 2144 |
fclose($fd); |
|---|
| 2145 |
|
|---|
| 2146 |
preg_match_all("/((SELECT|INSERT|UPDATE|DELETE|CREATE|DROP).*);\s*\n/Us", $data, $matches); |
|---|
| 2147 |
foreach ($matches[1] as $sql) { |
|---|
| 2148 |
$result = $db->query($sql); |
|---|
| 2149 |
if(DB::IsError($result)) { return false; } |
|---|
| 2150 |
} |
|---|
| 2151 |
} |
|---|
| 2152 |
|
|---|
| 2153 |
// Dragged this in from page.modules.php, so it can be used by install_amp. |
|---|
| 2154 |
function runModuleSQL($moddir,$type){ |
|---|
| 2155 |
trigger_error("runModuleSQL() is depreciated - please use _module_runscripts(), or preferably module_install() or module_enable() instead", E_USER_WARNING); |
|---|
| 2156 |
_module_runscripts($moddir, $type); |
|---|
| 2157 |
} |
|---|
| 2158 |
|
|---|
| 2159 |
/** Replaces variables in a string with the values from ampconf |
|---|
| 2160 |
* eg, "%AMPWEBROOT%/admin" => "/var/www/html/admin" |
|---|
| 2161 |
*/ |
|---|
| 2162 |
function ampconf_string_replace($string) { |
|---|
| 2163 |
global $amp_conf; |
|---|
| 2164 |
|
|---|
| 2165 |
$target = array(); |
|---|
| 2166 |
$replace = array(); |
|---|
| 2167 |
|
|---|
| 2168 |
foreach ($amp_conf as $key=>$value) { |
|---|
| 2169 |
$target[] = '%'.$key.'%'; |
|---|
| 2170 |
$replace[] = $value; |
|---|
| 2171 |
} |
|---|
| 2172 |
|
|---|
| 2173 |
return str_replace($target, $replace, $string); |
|---|
| 2174 |
} |
|---|
| 2175 |
|
|---|
| 2176 |
/*********************************************************************************************************** |
|---|
| 2177 |
Module functions |
|---|
| 2178 |
************************************************************************************************************/ |
|---|
| 2179 |
|
|---|
| 2180 |
/** Get the latest module.xml file for this FreePBX version. |
|---|
| 2181 |
* Caches in the database for 5 mintues. |
|---|
| 2182 |
* If $module is specified, only returns the data for that module. |
|---|
| 2183 |
* If the module is not found (or none are available for whatever reason), |
|---|
| 2184 |
* then null is returned. |
|---|
| 2185 |
* |
|---|
| 2186 |
* Sets the global variable $module_getonlinexml_error to true if an error |
|---|
| 2187 |
* occured getting the module from the repository, false if no error occured, |
|---|
| 2188 |
* or null if the repository wasn't checked. Note that this may change in the |
|---|
| 2189 |
* future if we decide we need to return more error codes, but as long as it's |
|---|
| 2190 |
* a php zero-value (false, null, 0, etc) then no error happened. |
|---|
| 2191 |
*/ |
|---|
| 2192 |
function module_getonlinexml($module = false, $override_xml = false) { // was getModuleXml() |
|---|
| 2193 |
global $amp_conf; |
|---|
| 2194 |
global $db; |
|---|
| 2195 |
global $module_getonlinexml_error; // okay, yeah, this sucks, but there's no other good way to do it without breaking BC |
|---|
| 2196 |
$module_getonlinexml_error = null; |
|---|
| 2197 |
$got_new = false; |
|---|
| 2198 |
$skip_cache = false; |
|---|
| 2199 |
|
|---|
| 2200 |
$result = sql("SELECT * FROM module_xml WHERE id = 'xml'",'getRow',DB_FETCHMODE_ASSOC); |
|---|
| 2201 |
$data = $result['data']; |
|---|
| 2202 |
|
|---|
| 2203 |
// Check if the cached module xml is for the same repo as being requested |
|---|
| 2204 |
// if not, then we get it anyhow |
|---|
| 2205 |
// |
|---|
| 2206 |
$repo_url = ($override_xml === false) ? "http://mirror.freepbx.org/" : $override_xml; |
|---|
| 2207 |
$result2 = sql("SELECT * FROM module_xml WHERE id = 'module_repo'",'getRow',DB_FETCHMODE_ASSOC); |
|---|
| 2208 |
$last_repo = $result2['data']; |
|---|
| 2209 |
if ($last_repo !== $repo_url) { |
|---|
| 2210 |
sql("DELETE FROM module_xml WHERE id = 'module_repo'"); |
|---|
| 2211 |
$data4sql = $db->escapeSimple($repo_url); |
|---|
| 2212 |
sql("INSERT INTO module_xml (id,time,data) VALUES ('module_repo',".time().",'".$data4sql."')"); |
|---|
| 2213 |
$skip_cache = true; |
|---|
| 2214 |
} |
|---|
| 2215 |
|
|---|
| 2216 |
// if the epoch in the db is more than 2 hours old, or the xml is less than 100 bytes, then regrab xml |
|---|
| 2217 |
// Changed to 5 minutes while not in release. Change back for released version. |
|---|
| 2218 |
// |
|---|
| 2219 |
// used for debug, time set to 0 to always fall through |
|---|
| 2220 |
// if((time() - $result['time']) > 0 || strlen($result['data']) < 100 ) { |
|---|
| 2221 |
if((time() - $result['time']) > 300 || $skip_cache || strlen($data) < 100 ) { |
|---|
| 2222 |
$version = getversion(); |
|---|
| 2223 |
// we need to know the freepbx major version we have running (ie: 2.1.2 is 2.1) |
|---|
| 2224 |
preg_match('/(\d+\.\d+)/',$version,$matches); |
|---|
| 2225 |
//echo "the result is ".$matches[1]; |
|---|
| 2226 |
if ($override_xml) { |
|---|
| 2227 |
$fn = $override_xml."modules-".$matches[1].".xml"; |
|---|
| 2228 |
} else { |
|---|
| 2229 |
$fn = "http://mirror.freepbx.org/modules-".$matches[1].".xml"; |
|---|
| 2230 |
// echo "(From default)"; //debug |
|---|
| 2231 |
} |
|---|
| 2232 |
//$fn = "/usr/src/freepbx-modules/modules.xml"; |
|---|
| 2233 |
if (!$amp_conf['MODULEADMINWGET']) { |
|---|
| 2234 |
$data = @ file_get_contents($fn); |
|---|
| 2235 |
} else { |
|---|
| 2236 |
$data = ""; |
|---|
| 2237 |
} |
|---|
| 2238 |
|
|---|
| 2239 |
if (empty($data)) { |
|---|
| 2240 |
exec("wget -O - $fn 2> /dev/null", $data_arr, $retcode); |
|---|
| 2241 |
$data = implode("\n",$data_arr); |
|---|
| 2242 |
$module_getonlinexml_error = ($retcode == 0)?false:true; |
|---|
| 2243 |
} |
|---|
| 2244 |
|
|---|
| 2245 |
$old_xml = array(); |
|---|
| 2246 |
$got_new = false; |
|---|
| 2247 |
if (!empty($data)) { |
|---|
| 2248 |
// Compare the download to our current XML to see if anything changed for the notification system. |
|---|
| 2249 |
// |
|---|
| 2250 |
$sql = "SELECT data FROM module_xml WHERE id = 'xml'"; |
|---|
| 2251 |
$old_xml = sql($sql, "getOne"); |
|---|
| 2252 |
$got_new = true; |
|---|
| 2253 |
// remove the old xml |
|---|
| 2254 |
sql("DELETE FROM module_xml WHERE id = 'xml'"); |
|---|
| 2255 |
// update the db with the new xml |
|---|
| 2256 |
$data4sql = $db->escapeSimple($data); |
|---|
| 2257 |
sql("INSERT INTO module_xml (id,time,data) VALUES ('xml',".time().",'".$data4sql."')"); |
|---|
| 2258 |
} |
|---|
| 2259 |
} |
|---|
| 2260 |
|
|---|
| 2261 |
if (empty($data)) { |
|---|
| 2262 |
// no data, probably couldn't connect online, and nothing cached |
|---|
| 2263 |
return null; |
|---|
| 2264 |
} |
|---|
| 2265 |
|
|---|
| 2266 |
$parser = new xml2ModuleArray($data); |
|---|
| 2267 |
$xmlarray = $parser->parseAdvanced($data); |
|---|
| 2268 |
|
|---|
| 2269 |
if ($got_new) { |
|---|
| 2270 |
module_update_notifications($old_xml, $xmlarray, ($old_xml == $data4sql)); |
|---|
| 2271 |
} |
|---|
| 2272 |
|
|---|
| 2273 |
if (isset($xmlarray['xml']['module'])) { |
|---|
| 2274 |
|
|---|
| 2275 |
if ($module != false) { |
|---|
| 2276 |
foreach ($xmlarray['xml']['module'] as $mod) { |
|---|
| 2277 |
if ($module == $mod['rawname']) { |
|---|
| 2278 |
return $mod; |
|---|
| 2279 |
} |
|---|
| 2280 |
} |
|---|
| 2281 |
return null; |
|---|
| 2282 |
} else { |
|---|
| 2283 |
$modules = array(); |
|---|
| 2284 |
foreach ($xmlarray['xml']['module'] as $mod) { |
|---|
| 2285 |
$modules[ $mod['rawname'] ] = $mod; |
|---|
| 2286 |
} |
|---|
| 2287 |
return $modules; |
|---|
| 2288 |
} |
|---|
| 2289 |
} |
|---|
| 2290 |
return null; |
|---|
| 2291 |
} |
|---|
| 2292 |
|
|---|
| 2293 |
/** Determines if there are updates we don't already know about and posts to notification |
|---|
| 2294 |
* server about those updates. |
|---|
| 2295 |
* |
|---|
| 2296 |
*/ |
|---|
| 2297 |
function module_update_notifications(&$old_xml, &$xmlarray, $passive) { |
|---|
| 2298 |
global $db; |
|---|
| 2299 |
|
|---|
| 2300 |
$notifications =& notifications::create($db); |
|---|
| 2301 |
|
|---|
| 2302 |
$reset_value = $passive ? 'PASSIVE' : false; |
|---|
| 2303 |
$old_parser = new xml2ModuleArray($old_xml); |
|---|
| 2304 |
$old_xmlarray = $old_parser->parseAdvanced($old_xml); |
|---|
| 2305 |
|
|---|
| 2306 |
$new_modules = array(); |
|---|
| 2307 |
if (count($xmlarray)) { |
|---|
| 2308 |
foreach ($xmlarray['xml']['module'] as $mod) { |
|---|
| 2309 |
$new_modules[$mod['rawname']] = $mod; |
|---|
| 2310 |
} |
|---|
| 2311 |
} |
|---|
| 2312 |
$old_modules = array(); |
|---|
| 2313 |
if (count($old_xmlarray)) { |
|---|
| 2314 |
foreach ($old_xmlarray['xml']['module'] as $mod) { |
|---|
| 2315 |
$old_modules[$mod['rawname']] = $mod; |
|---|
| 2316 |
} |
|---|
| 2317 |
} |
|---|
| 2318 |
|
|---|
| 2319 |
// If keys (rawnames) are different then there are new modules, create a notification. |
|---|
| 2320 |
// This will always be the case the first time it is run since the xml is empty. |
|---|
| 2321 |
// |
|---|
| 2322 |
// TODO: if old_modules is empty, should I populate it from getinfo to at find out what |
|---|
| 2323 |
// is installed or otherwise, just skip it since it is the first time? |
|---|
| 2324 |
// |
|---|
| 2325 |
$diff_modules = array_diff_assoc($new_modules, $old_modules); |
|---|
| 2326 |
$cnt = count($diff_modules); |
|---|
| 2327 |
if ($cnt) { |
|---|
| 2328 |
$extext = _("The following new modules are available for download. Click delete icon on the right to remove this notice.")."<br />"; |
|---|
| 2329 |
foreach ($diff_modules as $mod) { |
|---|
| 2330 |
$extext .= $mod['rawname']." (".$mod['version'].")<br />"; |
|---|
| 2331 |
} |
|---|
| 2332 |
$notifications->add_notice('freepbx', 'NEWMODS', sprintf(_('%s New modules are available'),$cnt), $extext, '', $reset_value, true); |
|---|
| 2333 |
} |
|---|
| 2334 |
|
|---|
| 2335 |
// Now check if any of the installed modules need updating |
|---|
| 2336 |
// |
|---|
| 2337 |
module_upgrade_notifications($new_modules, $reset_value); |
|---|
| 2338 |
} |
|---|
| 2339 |
|
|---|
| 2340 |
/** Compare installed (enabled or disabled) modules against the xml to generate or |
|---|
| 2341 |
* update the noticiation table of which modules have available updates. If the list |
|---|
| 2342 |
* is empty then delete the notification. |
|---|
| 2343 |
*/ |
|---|
| 2344 |
function module_upgrade_notifications(&$new_modules, $passive_value) { |
|---|
| 2345 |
global $db; |
|---|
| 2346 |
$notifications =& notifications::create($db); |
|---|
| 2347 |
|
|---|
| 2348 |
$installed_status = array(MODULE_STATUS_ENABLED, MODULE_STATUS_DISABLED); |
|---|
| 2349 |
$modules_local = module_getinfo(false, $installed_status); |
|---|
| 2350 |
|
|---|
| 2351 |
$modules_upgradable = array(); |
|---|
| 2352 |
foreach (array_keys($modules_local) as $name) { |
|---|
| 2353 |
if (isset($new_modules[$name])) { |
|---|
| 2354 |
if (version_compare_freepbx($modules_local[$name]['version'], $new_modules[$name]['version']) < 0) { |
|---|
| 2355 |
$modules_upgradable[] = array( |
|---|
| 2356 |
'name' => $name, |
|---|
| 2357 |
'local_version' => $modules_local[$name]['version'], |
|---|
| 2358 |
'online_version' => $new_modules[$name]['version'], |
|---|
| 2359 |
); |
|---|
| 2360 |
} |
|---|
| 2361 |
} |
|---|
| 2362 |
} |
|---|
| 2363 |
$cnt = count($modules_upgradable); |
|---|
| 2364 |
if ($cnt) { |
|---|
| 2365 |
if ($cnt == 1) { |
|---|
| 2366 |
$text = _("There is 1 module available for online upgrade"); |
|---|
| 2367 |
} else { |
|---|
| 2368 |
$text = sprintf(_("There are %s modules available for online upgrades"),$cnt); |
|---|
| 2369 |
} |
|---|
| 2370 |
$extext = ""; |
|---|
| 2371 |
foreach ($modules_upgradable as $mod) { |
|---|
| 2372 |
$extext .= sprintf(_("%s (current: %s)"), $mod['name'].' '.$mod['online_version'], $mod['local_version'])."\n"; |
|---|
| 2373 |
} |
|---|
| 2374 |
$notifications->add_update('freepbx', 'NEWUPDATES', $text, $extext, '', $passive_value); |
|---|
| 2375 |
} else { |
|---|
| 2376 |
$notifications->delete('freepbx', 'NEWUPDATES'); |
|---|
| 2377 |
} |
|---|
| 2378 |
} |
|---|
| 2379 |
|
|---|
| 2380 |
/** Looks through the modules directory and modules database and returns all available |
|---|
| 2381 |
* information about one or all modules |
|---|
| 2382 |
* @param string (optional) The module name to query, or false for all module |
|---|
| 2383 |
* @param mixed (optional) The status(es) to show, using MODULE_STATUS_* constants. Can |
|---|
| 2384 |
* either be one value, or an array of values. |
|---|
| 2385 |
*/ |
|---|
| 2386 |
function module_getinfo($module = false, $status = false, $forceload = false) { |
|---|
| 2387 |
|
|---|
| 2388 |
global $amp_conf, $db; |
|---|
| 2389 |
$modules = array(); |
|---|
| 2390 |
|
|---|
| 2391 |
if ($module) { |
|---|
| 2392 |
// get info on only one module |
|---|
| 2393 |
$xml = _module_readxml($module); |
|---|
| 2394 |
if (!is_null($xml)) { |
|---|
| 2395 |
$modules[$module] = $xml; |
|---|
| 2396 |
// if status is anything else, it will be updated below when we read the db |
|---|
| 2397 |
$modules[$module]['status'] = MODULE_STATUS_NOTINSTALLED; |
|---|
| 2398 |
} |
|---|
| 2399 |
|
|---|
| 2400 |
// query to get just this one |
|---|
| 2401 |
$sql = 'SELECT * FROM modules WHERE modulename = "'.$module.'"'; |
|---|
| 2402 |
} else { |
|---|
| 2403 |
// create the modulelist so it is static and does not need to be recreated |
|---|
| 2404 |
// in subsequent calls |
|---|
| 2405 |
// |
|---|
| 2406 |
$modulelist =& modulelist::create($db); |
|---|
| 2407 |
if ($forceload) { |
|---|
| 2408 |
$modulelist->invalidate(); |
|---|
| 2409 |
} |
|---|
| 2410 |
if (!$modulelist->is_loaded()) { |
|---|
| 2411 |
// initialize list with "builtin" module |
|---|
| 2412 |
$module_list = array('builtin'); |
|---|
| 2413 |
|
|---|
| 2414 |
// read modules dir for module names |
|---|
| 2415 |
$dir = opendir($amp_conf['AMPWEBROOT'].'/admin/modules'); |
|---|
| 2416 |
while ($file = readdir($dir)) { |
|---|
| 2417 |
if (($file != ".") && ($file != "..") && ($file != "CVS") && |
|---|
| 2418 |
($file != ".svn") && ($file != "_cache") && |
|---|
| 2419 |
is_dir($amp_conf['AMPWEBROOT'].'/admin/modules/'.$file)) { |
|---|
| 2420 |
$module_list[] = $file; |
|---|
| 2421 |
} |
|---|
| 2422 |
} |
|---|
| 2423 |
|
|---|
| 2424 |
// read the xml for each |
|---|
| 2425 |
foreach ($module_list as $file) { |
|---|
| 2426 |
$xml = _module_readxml($file); |
|---|
| 2427 |
if (!is_null($xml)) { |
|---|
| 2428 |
$modules[$file] = $xml; |
|---|
| 2429 |
// if status is anything else, it will be updated below when we read the db |
|---|
| 2430 |
$modules[$file]['status'] = MODULE_STATUS_NOTINSTALLED; |
|---|
| 2431 |
} |
|---|
| 2432 |
} |
|---|
| 2433 |
closedir($dir); |
|---|
| 2434 |
|
|---|
| 2435 |
// query to get everything |
|---|
| 2436 |
$sql = 'SELECT * FROM modules'; |
|---|
| 2437 |
} |
|---|
| 2438 |
} |
|---|
| 2439 |
// determine details about this module from database |
|---|
| 2440 |
// modulename should match the directory name |
|---|
| 2441 |
|
|---|
| 2442 |
if ($module || !$modulelist->is_loaded()) { |
|---|
| 2443 |
$results = $db->getAll($sql,DB_FETCHMODE_ASSOC); |
|---|
| 2444 |
if(DB::IsError($results)) { |
|---|
| 2445 |
die_freepbx($sql."<br>\n".$results->getMessage()); |
|---|
| 2446 |
} |
|---|
| 2447 |
|
|---|
| 2448 |
if (is_array($results)) { |
|---|
| 2449 |
foreach($results as $row) { |
|---|
| 2450 |
if (isset($modules[ $row['modulename'] ])) { |
|---|
| 2451 |
if ($row['enabled'] != 0) { |
|---|
| 2452 |
|
|---|
| 2453 |
// check if file and registered versions are the same |
|---|
| 2454 |
// version_compare returns 0 if no difference |
|---|
| 2455 |
if (version_compare_freepbx($row['version'], $modules[ $row['modulename'] ]['version']) == 0) { |
|---|
| 2456 |
$modules[ $row['modulename'] ]['status'] = MODULE_STATUS_ENABLED; |
|---|
| 2457 |
} else { |
|---|
| 2458 |
$modules[ $row['modulename'] ]['status'] = MODULE_STATUS_NEEDUPGRADE; |
|---|
| 2459 |
} |
|---|
| 2460 |
|
|---|
| 2461 |
} else { |
|---|
| 2462 |
$modules[ $row['modulename'] ]['status'] = MODULE_STATUS_DISABLED; |
|---|
| 2463 |
} |
|---|
| 2464 |
} else { |
|---|
| 2465 |
// no directory for this db entry |
|---|
| 2466 |
$modules[ $row['modulename'] ]['status'] = MODULE_STATUS_BROKEN; |
|---|
| 2467 |
} |
|---|
| 2468 |
$modules[ $row['modulename'] ]['dbversion'] = $row['version']; |
|---|
| 2469 |
} |
|---|
| 2470 |
} |
|---|
| 2471 |
|
|---|
| 2472 |
// "builtin" module is always enabled |
|---|
| 2473 |
$modules['builtin']['status'] = MODULE_STATUS_ENABLED; |
|---|
| 2474 |
} |
|---|
| 2475 |
if (!$module && !$modulelist->is_loaded()) { |
|---|
| 2476 |
$modulelist->initialize($modules); |
|---|
| 2477 |
} |
|---|
| 2478 |
|
|---|
| 2479 |
if ($status === false) { |
|---|
| 2480 |
if (!$module) { |
|---|
| 2481 |
return $modulelist->module_array; |
|---|
| 2482 |
} else { |
|---|
| 2483 |
return $modules; |
|---|
| 2484 |
} |
|---|
| 2485 |
} else { |
|---|
| 2486 |
if (!$module) { |
|---|
| 2487 |
$modules = $modulelist->module_array; |
|---|
| 2488 |
} |
|---|
| 2489 |
if (!is_array($status)) { |
|---|
| 2490 |
// make a one element array so we can use in_array below |
|---|
| 2491 |
$status = array($status); |
|---|
| 2492 |
} |
|---|
| 2493 |
foreach (array_keys($modules) as $name) { |
|---|
| 2494 |
if (!in_array($modules[$name]['status'], $status)) { |
|---|
| 2495 |
// not found in the $status array, remove it |
|---|
| 2496 |
unset($modules[$name]); |
|---|
| 2497 |
} |
|---|
| 2498 |
} |
|---|
| 2499 |
return $modules; |
|---|
| 2500 |
} |
|---|
| 2501 |
} |
|---|
| 2502 |
|
|---|
| 2503 |
/** Check if a module meets dependencies. |
|---|
| 2504 |
* @param mixed The name of the module, or the modulexml Array |
|---|
| 2505 |
* @return mixed Returns true if dependencies are met, or an array |
|---|
| 2506 |
* containing a list of human-readable errors if not. |
|---|
| 2507 |
* NOTE: you must use strict type checking (===) to test |
|---|
| 2508 |
* for true, because array() == true ! |
|---|
| 2509 |
*/ |
|---|
| 2510 |
function module_checkdepends($modulename) { |
|---|
| 2511 |
|
|---|
| 2512 |
// check if we were passed a modulexml array, or a string (name) |
|---|
| 2513 |
// ensure $modulexml is the modules array, and $modulename is the name (as a string) |
|---|
| 2514 |
if (is_array($modulename)) { |
|---|
| 2515 |
$modulexml = $modulename; |
|---|
| 2516 |
$modulename = $modulename['rawname']; |
|---|
| 2517 |
} else { |
|---|
| 2518 |
$modulexml = module_getinfo($modulename); |
|---|
| 2519 |
} |
|---|
| 2520 |
|
|---|
| 2521 |
$errors = array(); |
|---|
| 2522 |
|
|---|
| 2523 |
// special handling for engine |
|---|
| 2524 |
$engine_dependency = false; // if we've found ANY engine dependencies to check |
|---|
| 2525 |
$engine_matched = false; // if an engine dependency has matched |
|---|
| 2526 |
$engine_errors = array(); // the error strings for engines |
|---|
| 2527 |
|
|---|
| 2528 |
if (isset($modulexml['depends'])) { |
|---|
| 2529 |
foreach ($modulexml['depends'] as $type => $requirements) { |
|---|
| 2530 |
// if only a single item, make it an array so we can use the same code as for multiple items |
|---|
| 2531 |
// this is because if there is <module>a</module><module>b</module> we will get array('module' => array('a','b')) |
|---|
| 2532 |
if (!is_array($requirements)) { |
|---|
| 2533 |
$requirements = array($requirements); |
|---|
| 2534 |
} |
|---|
| 2535 |
|
|---|
| 2536 |
foreach ($requirements as $value) { |
|---|
| 2537 |
switch ($type) { |
|---|
| 2538 |
case 'version': |
|---|
| 2539 |
if (preg_match('/^(lt|le|gt|ge|==|=|eq|!=|ne)?\s*(\d*[beta|alpha|rc|RC]?\d+(\.[^\.]+)*)$/i', $value, $matches)) { |
|---|
| 2540 |
// matches[1] = operator, [2] = version |
|---|
| 2541 |
$installed_ver = getversion(); |
|---|
| 2542 |
$operator = (!empty($matches[1]) ? $matches[1] : 'ge'); // default to >= |
|---|
| 2543 |
$compare_ver = $matches[2]; |
|---|
| 2544 |
if (version_compare_freepbx($installed_ver, $compare_ver, $operator) ) { |
|---|
| 2545 |
// version is good |
|---|
| 2546 |
} else { |
|---|
| 2547 |
$errors[] = _module_comparison_error_message('FreePBX', $compare_ver, $installed_ver, $operator); |
|---|
| 2548 |
} |
|---|
| 2549 |
} |
|---|
| 2550 |
break; |
|---|
| 2551 |
case 'phpversion': |
|---|
| 2552 |
/* accepted formats |
|---|
| 2553 |
<depends> |
|---|
| 2554 |
<phpversion>5.1.0<phpversion> TRUE: if php is >= 5.1.0 |
|---|
| 2555 |
<phpversion>gt 5.1.0<phpversion> TRUE: if php is > 5.1.0 |
|---|
| 2556 |
</depends> |
|---|
| 2557 |
*/ |
|---|
| 2558 |
if (preg_match('/^(lt|le|gt|ge|==|=|eq|!=|ne)?\s*(\d*[beta|alpha|rc|RC]?\d+(\.[^\.]+)*)$/i', $value, $matches)) { |
|---|
| 2559 |
// matches[1] = operator, [2] = version |
|---|
| 2560 |
$installed_ver = phpversion(); |
|---|
| 2561 |
$operator = (!empty($matches[1]) ? $matches[1] : 'ge'); // default to >= |
|---|
| 2562 |
$compare_ver = $matches[2]; |
|---|
| 2563 |
if (version_compare($installed_ver, $compare_ver, $operator) ) { |
|---|
| 2564 |
// php version is good |
|---|
| 2565 |
} else { |
|---|
| 2566 |
$errors[] = _module_comparison_error_message('PHP', $compare_ver, $installed_ver, $operator); |
|---|
| 2567 |
} |
|---|
| 2568 |
} |
|---|
| 2569 |
break; |
|---|
| 2570 |
case 'phpcomponent': |
|---|
| 2571 |
/* accepted formats |
|---|
| 2572 |
<depends> |
|---|
| 2573 |
<phpversion>zlib<phpversion> TRUE: if extension zlib is loaded |
|---|
| 2574 |
<phpversion>zlib 1.2<phpversion> TRUE: if extension zlib is loaded and >= 1.2 |
|---|
| 2575 |
<phpversion>zlib gt 1.2<phpversion> TRUE: if extension zlib is loaded and > 1.2 |
|---|
| 2576 |
</depends> |
|---|
| 2577 |
*/ |
|---|
| 2578 |
if (preg_match('/^([a-z0-9_]+)(\s+(lt|le|gt|ge|==|=|eq|!=|ne)?\s*(\d+(\.\d*[beta|alpha|rc|RC]*\d+)+))?$/i', $value, $matches)) { |
|---|
| 2579 |
// matches[1] = extension name, [3]=comparison operator, [4] = version |
|---|
| 2580 |
$compare_ver = isset($matches[4]) ? $matches[4] : ''; |
|---|
| 2581 |
if (extension_loaded($matches[1])) { |
|---|
| 2582 |
if (empty($compare_ver)) { |
|---|
| 2583 |
// extension is loaded and no version specified |
|---|
| 2584 |
} else { |
|---|
| 2585 |
if (($installed_ver = phpversion($matches[1])) != '') { |
|---|
| 2586 |
$operator = (!empty($matches[3]) ? $matches[3] : 'ge'); // default to >= |
|---|
| 2587 |
if (version_compare($installed_ver, $compare_ver, $operator) ) { |
|---|
| 2588 |
// version is good |
|---|
| 2589 |
} else { |
|---|
| 2590 |
$errors[] = _module_comparison_error_message("PHP Component ".$matches[1], $compare_ver, $installed_ver, $operator); |
|---|
| 2591 |
} |
|---|
| 2592 |
} else { |
|---|
| 2593 |
$errors[] = _module_comparison_error_message("PHP Component ".$matches[1], $compare_ver, "<no version info>", $operator); |
|---|
| 2594 |
} |
|---|
| 2595 |
} |
|---|
| 2596 |
} else { |
|---|
| 2597 |
if ($compare_version == '') { |
|---|
| 2598 |
$errors[] = sprintf(_('PHP Component %s is required but missing from you PHP installation.'), $matches[1]); |
|---|
| 2599 |
} else { |
|---|
| 2600 |
$errors[] = sprintf(_('PHP Component %s version %s is required but missing from you PHP installation.'), $matches[1], $compare_version); |
|---|
| 2601 |
} |
|---|
| 2602 |
} |
|---|
| 2603 |
} |
|---|
| 2604 |
break; |
|---|
| 2605 |
case 'module': |
|---|
| 2606 |
// Modify to allow versions such as 2.3.0beta1.2 |
|---|
| 2607 |
if (preg_match('/^([a-z0-9_]+)(\s+(lt|le|gt|ge|==|=|eq|!=|ne)?\s*(\d+(\.\d*[beta|alpha|rc|RC]*\d+)+))?$/i', $value, $matches)) { |
|---|
| 2608 |
// matches[1] = modulename, [3]=comparison operator, [4] = version |
|---|
| 2609 |
$modules = module_getinfo($matches[1]); |
|---|
| 2610 |
if (isset($modules[$matches[1]])) { |
|---|
| 2611 |
$needed_module = "<strong>".(isset($modules[$matches[1]]['name'])?$modules[$matches[1]]['name']:$matches[1])."</strong>"; |
|---|
| 2612 |
switch ($modules[$matches[1]]['status'] ) { |
|---|
| 2613 |
case MODULE_STATUS_ENABLED: |
|---|
| 2614 |
if (!empty($matches[4])) { |
|---|
| 2615 |
// also doing version checking |
|---|
| 2616 |
$installed_ver = $modules[$matches[1]]['dbversion']; |
|---|
| 2617 |
$compare_ver = $matches[4]; |
|---|
| 2618 |
$operator = (!empty($matches[3]) ? $matches[3] : 'ge'); // default to >= |
|---|
| 2619 |
|
|---|
| 2620 |
if (version_compare_freepbx($installed_ver, $compare_ver, $operator) ) { |
|---|
| 2621 |
// version is good |
|---|
| 2622 |
} else { |
|---|
| 2623 |
$errors[] = _module_comparison_error_message($needed_module.' module', $compare_ver, $installed_ver, $operator); |
|---|
| 2624 |
} |
|---|
| 2625 |
} |
|---|
| 2626 |
break; |
|---|
| 2627 |
case MODULE_STATUS_BROKEN: |
|---|
| 2628 |
$errors[] = sprintf(_('Module %s is required, but yours is broken. You should reinstall '. |
|---|
| 2629 |
'it and try again.'), $needed_module); |
|---|
| 2630 |
break; |
|---|
| 2631 |
case MODULE_STATUS_DISABLED: |
|---|
| 2632 |
$errors[] = sprintf(_('Module %s is required, but yours is disabled.'), $needed_module); |
|---|
| 2633 |
break; |
|---|
| 2634 |
case MODULE_STATUS_NEEDUPGRADE: |
|---|
| 2635 |
$errors[] = sprintf(_('Module %s is required, but yours is disabled because it needs to '. |
|---|
| 2636 |
'be upgraded. Please upgrade %s first, and then try again.'), |
|---|
| 2637 |
$needed_module, $needed_module); |
|---|
| 2638 |
break; |
|---|
| 2639 |
default: |
|---|
| 2640 |
case MODULE_STATUS_NOTINSTALLED: |
|---|
| 2641 |
$errors[] = sprintf(_('Module %s is required, yours is not installed.'), $needed_module); |
|---|
| 2642 |
break; |
|---|
| 2643 |
} |
|---|
| 2644 |
} else { |
|---|
| 2645 |
$errors[] = sprintf(_('Module %s is required.'), $matches[1]); |
|---|
| 2646 |
} |
|---|
| 2647 |
} |
|---|
| 2648 |
break; |
|---|
| 2649 |
case 'file': // file exists |
|---|
| 2650 |
// replace embedded amp_conf %VARIABLES% in string |
|---|
| 2651 |
$file = ampconf_string_replace($value); |
|---|
| 2652 |
|
|---|
| 2653 |
if (!file_exists( $file )) { |
|---|
| 2654 |
$errors[] = sprintf(_('File %s must exist.'), $file); |
|---|
| 2655 |
} |
|---|
| 2656 |
break; |
|---|
| 2657 |
case 'engine': |
|---|
| 2658 |
/**************************** |
|---|
| 2659 |
* NOTE: there is special handling for this check. We want to "OR" conditions, instead of |
|---|
| 2660 |
* "AND"ing like the rest of them. |
|---|
| 2661 |
*/ |
|---|
| 2662 |
|
|---|
| 2663 |
// we found at least one engine, so mark that we're matching this |
|---|
| 2664 |
$engine_dependency = true; |
|---|
| 2665 |
|
|---|
| 2666 |
if (preg_match('/^([a-z0-9_]+)(\s+(lt|le|gt|ge|==|=|eq|!=|ne)?\s*(\d+(\.[^\.]+)*))?$/i', $value, $matches)) { |
|---|
| 2667 |
// matches[1] = engine, [3]=comparison operator, [4] = version |
|---|
| 2668 |
$operator = (!empty($matches[3]) ? $matches[3] : 'ge'); // default to >= |
|---|
| 2669 |
|
|---|
| 2670 |
$engine = engine_getinfo(); |
|---|
| 2671 |
if (($engine['engine'] == $matches[1]) && |
|---|
| 2672 |
(empty($matches[4]) || !version_compare($matches[4], $engine['version'], $operator)) |
|---|
| 2673 |
) { |
|---|
| 2674 |
|
|---|
| 2675 |
$engine_matched = true; |
|---|
| 2676 |
} else { |
|---|
| 2677 |
// add it to the error messages |
|---|
| 2678 |
if ($matches[4]) { |
|---|
| 2679 |
// version specified |
|---|
| 2680 |
$operator_friendly = str_replace(array('gt','ge','lt','le','eq','ne'), array('>','>=','<','<=','=','not ='), $operator); |
|---|
| 2681 |
$engine_errors[] = $matches[1].' ('.$operator_friendly.' '.$matches[4].')'; |
|---|
| 2682 |
} else { |
|---|
| 2683 |
// no version |
|---|
| 2684 |
$engine_errors[] = $matches[1]; |
|---|
| 2685 |
} |
|---|
| 2686 |
} |
|---|
| 2687 |
} |
|---|
| 2688 |
break; |
|---|
| 2689 |
} |
|---|
| 2690 |
} |
|---|
| 2691 |
} |
|---|
| 2692 |
|
|---|
| 2693 |
// special handling for engine |
|---|
| 2694 |
// if we've had at least one engine dependency check, and no engine dependencies matched, we have an error |
|---|
| 2695 |
if ($engine_dependency && !$engine_matched) { |
|---|
| 2696 |
|
|---|
| 2697 |
$engineinfo = engine_getinfo(); |
|---|
| 2698 |
$yourengine = $engineinfo['engine'].' '.$engineinfo['version']; |
|---|
| 2699 |
// print it nicely |
|---|
| 2700 |
if (count($engine_errors) == 1) { |
|---|
| 2701 |
$errors[] = sprintf(_('Requires engine %s, you have: %s'),$engine_errors[0],$yourengine); |
|---|
| 2702 |
} else { |
|---|
| 2703 |
$errors[] = sprintf(_('Requires one of the following engines: %s; you have: %s'),implode(', ', $engine_errors),$yourengine); |
|---|
| 2704 |
} |
|---|
| 2705 |
} |
|---|
| 2706 |
} |
|---|
| 2707 |
|
|---|
| 2708 |
if (count($errors) > 0) { |
|---|
| 2709 |
return $errors; |
|---|
| 2710 |
} else { |
|---|
| 2711 |
return true; |
|---|
| 2712 |
} |
|---|
| 2713 |
} |
|---|
| 2714 |
|
|---|
| 2715 |
function _module_comparison_error_message($module, $reqversion, $version, $operator) { |
|---|
| 2716 |
switch ($operator) { |
|---|
| 2717 |
case 'lt': case '<': |
|---|
| 2718 |
return sprintf(_('A %s version below %s is required, you have %s'), $module, $reqversion, $version); |
|---|
| 2719 |
break; |
|---|
| 2720 |
case 'le': case '<='; |
|---|
| 2721 |
return sprintf(_('%s version %s or below is required, you have %s'), $module, $reqversion, $version); |
|---|
| 2722 |
break; |
|---|
| 2723 |
case 'gt': case '>'; |
|---|
| 2724 |
return sprintf(_('A %s version newer than %s required, you have %s'), $module, $reqversion, $version); |
|---|
| 2725 |
break; |
|---|
| 2726 |
case 'ne': case '!=': case '<>': |
|---|
| 2727 |
return sprintf(_('Your %s version (%s) is incompatible.'), $version, $reqversion); |
|---|
| 2728 |
break; |
|---|
| 2729 |
case 'eq': case '==': case '=': |
|---|
| 2730 |
return sprintf(_('Only %s version %s is compatible, you have %s'), $module, $reqversion, $version); |
|---|
| 2731 |
break; |
|---|
| 2732 |
default: |
|---|
| 2733 |
case 'ge': case '>=': |
|---|
| 2734 |
return sprintf(_('%s version %s or higher is required, you have %s'), $module, $reqversion, $version); |
|---|
| 2735 |
} |
|---|
| 2736 |
} |
|---|
| 2737 |
|
|---|
| 2738 |
/** Finds all the enabled modules that depend on a given module |
|---|
| 2739 |
* @param mixed The name of the module, or the modulexml Array |
|---|
| 2740 |
* @return array Array containing the list of modules, or false if no dependencies |
|---|
| 2741 |
*/ |
|---|
| 2742 |
function module_reversedepends($modulename) { |
|---|
| 2743 |
// check if we were passed a modulexml array, or a string (name) |
|---|
| 2744 |
// ensure $modulename is the name (as a string) |
|---|
| 2745 |
if (is_array($modulename)) { |
|---|
| 2746 |
$modulename = $modulename['rawname']; |
|---|
| 2747 |
} |
|---|
| 2748 |
|
|---|
| 2749 |
$modules = module_getinfo(false, MODULE_STATUS_ENABLED); |
|---|
| 2750 |
|
|---|
| 2751 |
$depends = array(); |
|---|
| 2752 |
|
|---|
| 2753 |
foreach (array_keys($modules) as $name) { |
|---|
| 2754 |
if (isset($modules[$name]['depends'])) { |
|---|
| 2755 |
foreach ($modules[$name]['depends'] as $type => $requirements) { |
|---|
| 2756 |
if ($type == 'module') { |
|---|
| 2757 |
// if only a single item, make it an array so we can use the same code as for multiple items |
|---|
| 2758 |
// this is because if there is <module>a</module><module>b</module> we will get array('module' => array('a','b')) |
|---|
| 2759 |
if (!is_array($requirements)) { |
|---|
| 2760 |
$requirements = array($requirements); |
|---|
| 2761 |
} |
|---|
| 2762 |
|
|---|
| 2763 |
foreach ($requirements as $value) { |
|---|
| 2764 |
if (preg_match('/^([a-z0-9_]+)(\s+(>=|>|=|<|<=|!=)?\s*(\d(\.\d)*))?$/i', $value, $matches)) { |
|---|
| 2765 |
// matches[1] = modulename, [3]=comparison operator, [4] = version |
|---|
| 2766 |
|
|---|
| 2767 |
// note, we're not checking version here. Normally this function is used when |
|---|
| 2768 |
// uninstalling a module, so it doesn't really matter anyways, and version |
|---|
| 2769 |
// dependency should have already been checked when the module was installed |
|---|
| 2770 |
if ($matches[1] == $modulename) { |
|---|
| 2771 |
$depends[] = $name; |
|---|
| 2772 |
} |
|---|
| 2773 |
} |
|---|
| 2774 |
} |
|---|
| 2775 |
} |
|---|
| 2776 |
} |
|---|
| 2777 |
} |
|---|
| 2778 |
} |
|---|
| 2779 |
|
|---|
| 2780 |
return (count($depends) > 0) ? $depends : false; |
|---|
| 2781 |
} |
|---|
| 2782 |
|
|---|
| 2783 |
/** Enables a module |
|---|
| 2784 |
* @param string The name of the module to enable |
|---|
| 2785 |
* @param bool If true, skips status and dependency checks |
|---|
| 2786 |
* @return mixed True if succesful, array of error messages if not succesful |
|---|
| 2787 |
*/ |
|---|
| 2788 |
function module_enable($modulename, $force = false) { // was enableModule |
|---|
| 2789 |
$modules = module_getinfo($modulename); |
|---|
| 2790 |
|
|---|
| 2791 |
if ($modules[$modulename]['status'] == MODULE_STATUS_ENABLED) { |
|---|
| 2792 |
return array(_("Module ".$modulename." is already enabled")); |
|---|
| 2793 |
} |
|---|
| 2794 |
|
|---|
| 2795 |
// doesn't make sense to skip this on $force - eg, we can't enable a non-installed or broken module |
|---|
| 2796 |
if ($modules[$modulename]['status'] != MODULE_STATUS_DISABLED) { |
|---|
| 2797 |
return array(_("Module ".$modulename." cannot be enabled")); |
|---|
| 2798 |
} |
|---|
| 2799 |
|
|---|
| 2800 |
if (!$force) { |
|---|
| 2801 |
if (($errors = module_checkdepends($modules[$modulename])) !== true) { |
|---|
| 2802 |
return $errors; |
|---|
| 2803 |
} |
|---|
| 2804 |
} |
|---|
| 2805 |
|
|---|
| 2806 |
// disabled (but doesn't needupgrade or need install), and meets dependencies |
|---|
| 2807 |
_module_setenabled($modulename, true); |
|---|
| 2808 |
needreload(); |
|---|
| 2809 |
return true; |
|---|
| 2810 |
} |
|---|
| 2811 |
|
|---|
| 2812 |
/** Downloads the latest version of a module |
|---|
| 2813 |
* and extracts it to the directory |
|---|
| 2814 |
* @param string The name of the module to install |
|---|
| 2815 |
* @param bool If true, skips status and dependency checks |
|---|
| 2816 |
* @param string The name of a callback function to call with progress updates. |
|---|
| 2817 |
function($action, $params). Possible actions: |
|---|
| 2818 |
getinfo: while downloading modules.xml |
|---|
| 2819 |
downloading: while downloading file; params include 'read' and 'total' |
|---|
| 2820 |
untar: before untarring |
|---|
| 2821 |
done: when complete |
|---|
| 2822 |
* @return mixed True if succesful, array of error messages if not succesful |
|---|
| 2823 |
*/ |
|---|
| 2824 |
|
|---|
| 2825 |
// was fetchModule |
|---|
| 2826 |
function module_download($modulename, $force = false, $progress_callback = null, $override_svn = false, $override_xml = false) { |
|---|
| 2827 |
global $amp_conf; |
|---|
| 2828 |
|
|---|
| 2829 |
if ($time_limit = ini_get('max_execution_time')) { |
|---|
| 2830 |
set_time_limit($time_limit); |
|---|
| 2831 |
} |
|---|
| 2832 |
|
|---|
| 2833 |
// size of download blocks to fread() |
|---|
| 2834 |
// basically, this controls how often progress_callback is called |
|---|
| 2835 |
$download_chunk_size = 12*1024; |
|---|
| 2836 |
|
|---|
| 2837 |
// invoke progress callback |
|---|
| 2838 |
if (function_exists($progress_callback)) { |
|---|
| 2839 |
$progress_callback('getinfo', array('module'=>$modulename)); |
|---|
| 2840 |
} |
|---|
| 2841 |
|
|---|
| 2842 |
$res = module_getonlinexml($modulename, $override_xml); |
|---|
| 2843 |
if ($res == null) { |
|---|
| 2844 |
return array(_("Module not found in repository")); |
|---|
| 2845 |
} |
|---|
| 2846 |
|
|---|
| 2847 |
$file = basename($res['location']); |
|---|
| 2848 |
$filename = $amp_conf['AMPWEBROOT']."/admin/modules/_cache/".$file; |
|---|
| 2849 |
// if we're not forcing the download, and a file with the target name exists.. |
|---|
| 2850 |
if (!$force && file_exists($filename)) { |
|---|
| 2851 |
// We might already have it! Let's check the MD5. |
|---|
| 2852 |
$filedata = ""; |
|---|
| 2853 |
if ( $fh = @ fopen($filename, "r") ) { |
|---|
| 2854 |
while (!feof($fh)) { |
|---|
| 2855 |
$filedata .= fread($fh, 8192); |
|---|
| 2856 |
} |
|---|
| 2857 |
fclose($fh); |
|---|
| 2858 |
} |
|---|
| 2859 |
|
|---|
| 2860 |
if (isset($res['md5sum']) && $res['md5sum'] == md5 ($filedata)) { |
|---|
| 2861 |
// Note, if there's no MD5 information, it will redownload |
|---|
| 2862 |
// every time. Otherwise theres no way to avoid a corrupt |
|---|
| 2863 |
// download |
|---|
| 2864 |
|
|---|
| 2865 |
// invoke progress callback |
|---|
| 2866 |
if (function_exists($progress_callback)) { |
|---|
| 2867 |
$progress_callback('untar', array('module'=>$modulename, 'size'=>filesize($filename))); |
|---|
| 2868 |
} |
|---|
| 2869 |
|
|---|
| 2870 |
/* We will explode the tarball in the cache directory and then once successful, remove the old module before before |
|---|
| 2871 |
* moving the new one over. This way, things like removed files end up being removed instead of laying around |
|---|
| 2872 |
* |
|---|
| 2873 |
* TODO: save old module being replaced, if there is an old one. |
|---|
| 2874 |
*/ |
|---|
| 2875 |
exec("rm -rf ".$amp_conf['AMPWEBROOT']."/admin/modules/_cache/$modulename", $output, $exitcode); |
|---|
| 2876 |
if ($exitcode != 0) { |
|---|
| 2877 |
return array(sprintf(_('Could not remove %s to install new version'), $amp_conf['AMPWEBROOT'].'/admin/modules/_cache/'.$modulenam)); |
|---|
| 2878 |
} |
|---|
| 2879 |
exec("tar zxf ".escapeshellarg($filename)." -C ".escapeshellarg($amp_conf['AMPWEBROOT'].'/admin/modules/_cache/'), $output, $exitcode); |
|---|
| 2880 |
if ($exitcode != 0) { |
|---|
| 2881 |
return array(sprintf(_('Could not untar %s to %s'), $filename, $amp_conf['AMPWEBROOT'].'/admin/modules/_cache')); |
|---|
| 2882 |
} |
|---|
| 2883 |
exec("rm -rf ".$amp_conf['AMPWEBROOT']."/admin/modules/$modulename", $output, $exitcode); |
|---|
| 2884 |
if ($exitcode != 0) { |
|---|
| 2885 |
return array(sprintf(_('Could not remove old module %s to install new version'), $amp_conf['AMPWEBROOT'].'/admin/modules/'.$modulename)); |
|---|
| 2886 |
} |
|---|
| 2887 |
exec("mv ".$amp_conf['AMPWEBROOT']."/admin/modules/_cache/$modulename ".$amp_conf['AMPWEBROOT']."/admin/modules/$modulename", $output, $exitcode); |
|---|
| 2888 |
if ($exitcode != 0) { |
|---|
| 2889 |
return array(sprintf(_('Could not move %s to %s'), $amp_conf['AMPWEBROOT']."/admin/modules/_cache/$modulename", $amp_conf['AMPWEBROOT'].'/admin/modules/')); |
|---|
| 2890 |
} |
|---|
| 2891 |
|
|---|
| 2892 |
// invoke progress_callback |
|---|
| 2893 |
if (function_exists($progress_callback)) { |
|---|
| 2894 |
$progress_callback('done', array('module'=>$modulename)); |
|---|
| 2895 |
} |
|---|
| 2896 |
|
|---|
| 2897 |
return true; |
|---|
| 2898 |
} else { |
|---|
| 2899 |
unlink($filename); |
|---|
| 2900 |
} |
|---|
| 2901 |
} |
|---|
| 2902 |
|
|---|
| 2903 |
if ($override_svn) { |
|---|
| 2904 |
$url = $override_svn.$res['location']; |
|---|
| 2905 |
} else { |
|---|
| 2906 |
$url = "http://mirror.freepbx.org/modules/".$res['location']; |
|---|
| 2907 |
} |
|---|
| 2908 |
|
|---|
| 2909 |
if (!($fp = @fopen($filename,"w"))) { |
|---|
| 2910 |
return array(sprintf(_("Error opening %s for writing"), $filename)); |
|---|
| 2911 |
} |
|---|
| 2912 |
|
|---|
| 2913 |
$headers = get_headers_assoc($url); |
|---|
| 2914 |
|
|---|
| 2915 |
$totalread = 0; |
|---|
| 2916 |
// invoke progress_callback |
|---|
| 2917 |
if (function_exists($progress_callback)) { |
|---|
| 2918 |
$progress_callback('downloading', array('module'=>$modulename, 'read'=>$totalread, 'total'=>$headers['content-length'])); |
|---|
| 2919 |
} |
|---|
| 2920 |
|
|---|
| 2921 |
// Check MODULEADMINWGET first so we don't execute the fopen() if set |
|---|
| 2922 |
// |
|---|
| 2923 |
if ($amp_conf['MODULEADMINWGET'] || !$dp = @fopen($url,'r')) { |
|---|
| 2924 |
exec("wget -O $filename $url 2> /dev/null", $filedata, $retcode); |
|---|
| 2925 |
if ($retcode != 0) { |
|---|
| 2926 |
return array(sprintf(_("Error opening %s for reading"), $url)); |
|---|
| 2927 |
} else { |
|---|
| 2928 |
if (!$dp = @fopen($filename,'r')) { |
|---|
| 2929 |
return array(sprintf(_("Error opening %s for reading"), $url)); |
|---|
| 2930 |
} |
|---|
| 2931 |
} |
|---|
| 2932 |
} |
|---|
| 2933 |
|
|---|
| 2934 |
$filedata = ''; |
|---|
| 2935 |
while (!feof($dp)) { |
|---|
| 2936 |
$data = fread($dp, $download_chunk_size); |
|---|
| 2937 |
$filedata .= $data; |
|---|
| 2938 |
$totalread += strlen($data); |
|---|
| 2939 |
if (function_exists($progress_callback)) { |
|---|
| 2940 |
$progress_callback('downloading', array('module'=>$modulename, 'read'=>$totalread, 'total'=>$headers['content-length'])); |
|---|
| 2941 |
} |
|---|
| 2942 |
} |
|---|
| 2943 |
fwrite($fp,$filedata); |
|---|
| 2944 |
fclose($dp); |
|---|
| 2945 |
fclose($fp); |
|---|
| 2946 |
|
|---|
| 2947 |
|
|---|
| 2948 |
if (is_readable($filename) !== TRUE ) { |
|---|
| 2949 |
return array(sprintf(_('Unable to save %s'),$filename)); |
|---|
| 2950 |
} |
|---|
| 2951 |
|
|---|
| 2952 |
// Check the MD5 info against what's in the module's XML |
|---|
| 2953 |
if (!isset($res['md5sum']) || empty($res['md5sum'])) { |
|---|
| 2954 |
//echo "<div class=\"error\">"._("Unable to Locate Integrity information for")." {$filename} - "._("Continuing Anyway")."</div>"; |
|---|
| 2955 |
} else if ($res['md5sum'] != md5 ($filedata)) { |
|---|
| 2956 |
unlink($filename); |
|---|
| 2957 |
return array(sprintf(_('File Integrity failed for %s - aborting'), $filename)); |
|---|
| 2958 |
} |
|---|
| 2959 |
|
|---|
| 2960 |
// invoke progress callback |
|---|
| 2961 |
if (function_exists($progress_callback)) { |
|---|
| 2962 |
$progress_callback('untar', array('module'=>$modulename, 'size'=>filesize($filename))); |
|---|
| 2963 |
} |
|---|
| 2964 |
|
|---|
| 2965 |
/* We will explode the tarball in the cache directory and then once successful, remove the old module before before |
|---|
| 2966 |
* moving the new one over. This way, things like removed files end up being removed instead of laying around |
|---|
| 2967 |
* |
|---|
| 2968 |
* TODO: save old module being replaced, if there is an old one. |
|---|
| 2969 |
* |
|---|
| 2970 |
*/ |
|---|
| 2971 |
exec("rm -rf ".$amp_conf['AMPWEBROOT']."/admin/modules/_cache/$modulename", $output, $exitcode); |
|---|
| 2972 |
if ($exitcode != 0) { |
|---|
| 2973 |
return array(sprintf(_('Could not remove %s to install new version'), $amp_conf['AMPWEBROOT'].'/admin/modules/_cache/'.$modulenam)); |
|---|
| 2974 |
} |
|---|
| 2975 |
exec("tar zxf ".escapeshellarg($filename)." -C ".escapeshellarg($amp_conf['AMPWEBROOT'].'/admin/modules/_cache/'), $output, $exitcode); |
|---|
| 2976 |
if ($exitcode != 0) { |
|---|
| 2977 |
return array(sprintf(_('Could not untar %s to %s'), $filename, $amp_conf['AMPWEBROOT'].'/admin/modules/_cache')); |
|---|
| 2978 |
} |
|---|
| 2979 |
exec("rm -rf ".$amp_conf['AMPWEBROOT']."/admin/modules/$modulename", $output, $exitcode); |
|---|
| 2980 |
if ($exitcode != 0) { |
|---|
| 2981 |
return array(sprintf(_('Could not remove old module %s to install new version'), $amp_conf['AMPWEBROOT'].'/admin/modules/'.$modulename)); |
|---|
| 2982 |
} |
|---|
| 2983 |
exec("mv ".$amp_conf['AMPWEBROOT']."/admin/modules/_cache/$modulename ".$amp_conf['AMPWEBROOT']."/admin/modules/$modulename", $output, $exitcode); |
|---|
| 2984 |
if ($exitcode != 0) { |
|---|
| 2985 |
return array(sprintf(_('Could not move %s to %s'), $amp_conf['AMPWEBROOT']."/admin/modules/_cache/$modulename", $amp_conf['AMPWEBROOT'].'/admin/modules/')); |
|---|
| 2986 |
} |
|---|
| 2987 |
|
|---|
| 2988 |
// invoke progress_callback |
|---|
| 2989 |
if (function_exists($progress_callback)) { |
|---|
| 2990 |
$progress_callback('done', array('module'=>$modulename)); |
|---|
| 2991 |
} |
|---|
| 2992 |
|
|---|
| 2993 |
return true; |
|---|
| 2994 |
} |
|---|
| 2995 |
|
|---|
| 2996 |
|
|---|
| 2997 |
function module_handleupload($uploaded_file) { |
|---|
| 2998 |
global $amp_conf; |
|---|
| 2999 |
$errors = array(); |
|---|
| 3000 |
|
|---|
| 3001 |
if (!isset($uploaded_file['tmp_name']) || !file_exists($uploaded_file['tmp_name'])) { |
|---|
| 3002 |
$errors[] = _("Error finding uploaded file - check your PHP and/or web server configuration"); |
|---|
| 3003 |
return $errors; |
|---|
| 3004 |
} |
|---|
| 3005 |
|
|---|
| 3006 |
if (!preg_match('/\.(tar\.gz|tgz)$/', $uploaded_file['name'])) { |
|---|
| 3007 |
$errors[] = _("File must be in tar+gzip (.tgz or .tar.gz) format"); |
|---|
| 3008 |
return $errors; |
|---|
| 3009 |
} |
|---|
| 3010 |
|
|---|
| 3011 |
if (!preg_match('/^([A-Za-z][A-Za-z0-9_]+)\-([0-9a-z]+(\.[0-9a-z]+)*)\.(tar\.gz|tgz)$/', $uploaded_file['name'], $matches)) { |
|---|
| 3012 |
$errors[] = _("Filename not in correct format: must be modulename-version.tar.gz (eg. custommodule-0.1.tar.gz)"); |
|---|
| 3013 |
return $errors; |
|---|
| 3014 |
} else { |
|---|
| 3015 |
$modulename = $matches[1]; |
|---|
| 3016 |
$moduleversion = $matches[2]; |
|---|
| 3017 |
} |
|---|
| 3018 |
|
|---|
| 3019 |
$temppath = $amp_conf['AMPWEBROOT'].'/admin/modules/_cache/'.uniqid("upload"); |
|---|
| 3020 |
if (! @mkdir($temppath) ) { |
|---|
| 3021 |
return array(sprintf(_("Error creating temporary directory: %s"), $temppath)); |
|---|
| 3022 |
} |
|---|
| 3023 |
$filename = $temppath.'/'.$uploaded_file['name']; |
|---|
| 3024 |
|
|---|
| 3025 |
move_uploaded_file($uploaded_file['tmp_name'], $filename); |
|---|
| 3026 |
|
|---|
| 3027 |
exec("tar ztf ".escapeshellarg($filename), $output, $exitcode); |
|---|
| 3028 |
if ($exitcode != 0) { |
|---|
| 3029 |
$errors[] = _("Error untaring uploaded file. Must be a tar+gzip file"); |
|---|
| 3030 |
return $errors; |
|---|
| 3031 |
} |
|---|
| 3032 |
|
|---|
| 3033 |
foreach ($output as $line) { |
|---|
| 3034 |
// make sure all lines start with "modulename/" |
|---|
| 3035 |
if (!preg_match('/^'.$modulename.'\//', $line)) { |
|---|
| 3036 |
$errors[] = 'File extracting to invalid location: '.$line; |
|---|
| 3037 |
} |
|---|
| 3038 |
} |
|---|
| 3039 |
if (count($errors)) { |
|---|
| 3040 |
return $errors; |
|---|
| 3041 |
} |
|---|
| 3042 |
|
|---|
| 3043 |
/* We will explode the tarball in the cache directory and then once successful, remove the old module before before |
|---|
| 3044 |
* moving the new one over. This way, things like removed files end up being removed instead of laying around |
|---|
| 3045 |
* |
|---|
| 3046 |
* TODO: save old module being replaced, if there is an old one. |
|---|
| 3047 |
* |
|---|
| 3048 |
*/ |
|---|
| 3049 |
exec("rm -rf ".$amp_conf['AMPWEBROOT']."/admin/modules/_cache/$modulename", $output, $exitcode); |
|---|
| 3050 |
if ($exitcode != 0) { |
|---|
| 3051 |
return array(sprintf(_('Could not remove %s to install new version'), $amp_conf['AMPWEBROOT'].'/admin/modules/_cache/'.$modulenam)); |
|---|
| 3052 |
} |
|---|
| 3053 |
exec("tar zxf ".escapeshellarg($filename)." -C ".escapeshellarg($amp_conf['AMPWEBROOT'].'/admin/modules/_cache/'), $output, $exitcode); |
|---|
| 3054 |
if ($exitcode != 0) { |
|---|
| 3055 |
return array(sprintf(_('Could not untar %s to %s'), $filename, $amp_conf['AMPWEBROOT'].'/admin/modules/_cache')); |
|---|
| 3056 |
} |
|---|
| 3057 |
exec("rm -rf ".$amp_conf['AMPWEBROOT']."/admin/modules/$modulename", $output, $exitcode); |
|---|
| 3058 |
if ($exitcode != 0) { |
|---|
| 3059 |
return array(sprintf(_('Could not remove old module %s to install new version'), $amp_conf['AMPWEBROOT'].'/admin/modules/'.$modulename)); |
|---|
| 3060 |
} |
|---|
| 3061 |
exec("mv ".$amp_conf['AMPWEBROOT']."/admin/modules/_cache/$modulename ".$amp_conf['AMPWEBROOT']."/admin/modules/$modulename", $output, $exitcode); |
|---|
| 3062 |
if ($exitcode != 0) { |
|---|
| 3063 |
return array(sprintf(_('Could not move %s to %s'), $amp_conf['AMPWEBROOT']."/admin/modules/_cache/$modulename", $amp_conf['AMPWEBROOT'].'/admin/modules/')); |
|---|
| 3064 |
} |
|---|
| 3065 |
|
|---|
| 3066 |
exec("rm -rf ".$temppath, $output, $exitcode); |
|---|
| 3067 |
if ($exitcode != 0) { |
|---|
| 3068 |
$errors[] = sprintf(_('Error removing temporary directory: %s'), $temppath); |
|---|
| 3069 |
} |
|---|
| 3070 |
|
|---|
| 3071 |
if (count($errors)) { |
|---|
| 3072 |
return $errors; |
|---|
| 3073 |
} |
|---|
| 3074 |
|
|---|
| 3075 |
// finally, module installation is successful |
|---|
| 3076 |
return true; |
|---|
| 3077 |
} |
|---|
| 3078 |
|
|---|
| 3079 |
/** Installs or upgrades a module from it's directory |
|---|
| 3080 |
* Checks dependencies, and enables |
|---|
| 3081 |
* @param string The name of the module to install |
|---|
| 3082 |
* @param bool If true, skips status and dependency checks |
|---|
| 3083 |
* @return mixed True if succesful, array of error messages if not succesful |
|---|
| 3084 |
*/ |
|---|
| 3085 |
function module_install($modulename, $force = false) { |
|---|
| 3086 |
global $db, $amp_conf; |
|---|
| 3087 |
|
|---|
| 3088 |
if ($time_limit = ini_get('max_execution_time')) { |
|---|
| 3089 |
set_time_limit($time_limit); |
|---|
| 3090 |
} |
|---|
| 3091 |
|
|---|
| 3092 |
$modules = module_getinfo($modulename); |
|---|
| 3093 |
|
|---|
| 3094 |
// make sure we have a directory, to begin with |
|---|
| 3095 |
$dir = $amp_conf['AMPWEBROOT'].'/admin/modules/'.$modulename; |
|---|
| 3096 |
if (!is_dir($dir)) { |
|---|
| 3097 |
return array(_("Cannot find module")); |
|---|
| 3098 |
} |
|---|
| 3099 |
|
|---|
| 3100 |
// read the module.xml file |
|---|
| 3101 |
$modules = module_getinfo($modulename); |
|---|
| 3102 |
if (!isset($modules[$modulename])) { |
|---|
| 3103 |
return array(_("Could not read module.xml")); |
|---|
| 3104 |
} |
|---|
| 3105 |
|
|---|
| 3106 |
// don't force this bit - we can't install a broken module (missing files) |
|---|
| 3107 |
if ($modules[$modulename]['status'] == MODULE_STATUS_BROKEN) { |
|---|
| 3108 |
return array(_("Module ".$modules[$modulename]['rawname']." is broken and cannot be installed. You should try to download it again.")); |
|---|
| 3109 |
} |
|---|
| 3110 |
|
|---|
| 3111 |
if (!$force) { |
|---|
| 3112 |
|
|---|
| 3113 |
if (!in_array($modules[$modulename]['status'], array(MODULE_STATUS_NOTINSTALLED, MODULE_STATUS_NEEDUPGRADE))) { |
|---|
| 3114 |
//return array(_("This module is already installed.")); |
|---|
| 3115 |
// This isn't really an error, we just exit |
|---|
| 3116 |
return true; |
|---|
| 3117 |
} |
|---|
| 3118 |
|
|---|
| 3119 |
// check dependencies |
|---|
| 3120 |
if (is_array($errors = module_checkdepends($modules[$modulename]))) { |
|---|
| 3121 |
return $errors; |
|---|
| 3122 |
} |
|---|
| 3123 |
} |
|---|
| 3124 |
|
|---|
| 3125 |
// run the scripts |
|---|
| 3126 |
if (!_module_runscripts($modulename, 'install')) { |
|---|
| 3127 |
return array(_("Failed to run installation scripts")); |
|---|
| 3128 |
} |
|---|
| 3129 |
|
|---|
| 3130 |
if ($modules[$modulename]['status'] == MODULE_STATUS_NOTINSTALLED) { |
|---|
| 3131 |
// customize INSERT query |
|---|
| 3132 |
$sql = "INSERT INTO modules (modulename, version, enabled) values ('".$db->escapeSimple($modules[$modulename]['rawname'])."','".$db->escapeSimple($modules[$modulename]['version'])."', 1);"; |
|---|
| 3133 |
} else { |
|---|
| 3134 |
// just need to update the version |
|---|
| 3135 |
$sql = "UPDATE modules SET version='".$db->escapeSimple($modules[$modulename]['version'])."' WHERE modulename = '".$db->escapeSimple($modules[$modulename]['rawname'])."'"; |
|---|
| 3136 |
} |
|---|
| 3137 |
|
|---|
| 3138 |
// run query |
|---|
| 3139 |
$results = $db->query($sql); |
|---|
| 3140 |
if(DB::IsError($results)) { |
|---|
| 3141 |
return array(sprintf(_("Error updating database. Command was: %s; error was: %s "), $sql, $results->getMessage())); |
|---|
| 3142 |
} |
|---|
| 3143 |
|
|---|
| 3144 |
// module is now installed & enabled, invalidate the modulelist class since it is now stale |
|---|
| 3145 |
$modulelist =& modulelist::create($db); |
|---|
| 3146 |
$modulelist->invalidate(); |
|---|
| 3147 |
|
|---|
| 3148 |
// edit the notification table to list any remaining upgrades available or clear |
|---|
| 3149 |
// it if none are left. It requres a copy of the most recent module_xml to compare |
|---|
| 3150 |
// against the installed modules. |
|---|
| 3151 |
// |
|---|
| 3152 |
$sql = 'SELECT data FROM module_xml WHERE id = "xml"'; |
|---|
| 3153 |
$data = sql($sql, "getOne"); |
|---|
| 3154 |
$parser = new xml2ModuleArray($data); |
|---|
| 3155 |
$xmlarray = $parser->parseAdvanced($data); |
|---|
| 3156 |
$new_modules = array(); |
|---|
| 3157 |
if (count($xmlarray)) { |
|---|
| 3158 |
foreach ($xmlarray['xml']['module'] as $mod) { |
|---|
| 3159 |
$new_modules[$mod['rawname']] = $mod; |
|---|
| 3160 |
} |
|---|
| 3161 |
} |
|---|
| 3162 |
module_upgrade_notifications($new_modules, 'PASSIVE'); |
|---|
| 3163 |
needreload(); |
|---|
| 3164 |
return true; |
|---|
| 3165 |
} |
|---|
| 3166 |
|
|---|
| 3167 |
/** Disable a module, but reqmains installed |
|---|
| 3168 |
* @param string The name of the module to disable |
|---|
| 3169 |
* @param bool If true, skips status and dependency checks |
|---|
| 3170 |
* @return mixed True if succesful, array of error messages if not succesful |
|---|
| 3171 |
*/ |
|---|
| 3172 |
function module_disable($modulename, $force = false) { // was disableModule |
|---|
| 3173 |
$modules = module_getinfo($modulename); |
|---|
| 3174 |
if (!isset($modules[$modulename])) { |
|---|
| 3175 |
return array(_("Specified module not found")); |
|---|
| 3176 |
} |
|---|
| 3177 |
|
|---|
| 3178 |
if (!$force) { |
|---|
| 3179 |
if ($modules[$modulename]['status'] != MODULE_STATUS_ENABLED) { |
|---|
| 3180 |
return array(_("Module not enabled: cannot disable")); |
|---|
| 3181 |
} |
|---|
| 3182 |
|
|---|
| 3183 |
if ( ($depmods = module_reversedepends($modulename)) !== false) { |
|---|
| 3184 |
return array(_("Cannot disable: The following modules depend on this one: ").implode(',',$depmods)); |
|---|
| 3185 |
} |
|---|
| 3186 |
} |
|---|
| 3187 |
|
|---|
| 3188 |
_module_setenabled($modulename, false); |
|---|
| 3189 |
needreload(); |
|---|
| 3190 |
return true; |
|---|
| 3191 |
} |
|---|
| 3192 |
|
|---|
| 3193 |
/** Uninstall a module, but files remain |
|---|
| 3194 |
* @param string The name of the module to install |
|---|
| 3195 |
* @param bool If true, skips status and dependency checks |
|---|
| 3196 |
* @return mixed True if succesful, array of error messages if not succesful |
|---|
| 3197 |
*/ |
|---|
| 3198 |
function module_uninstall($modulename, $force = false) { |
|---|
| 3199 |
global $db; |
|---|
| 3200 |
|
|---|
| 3201 |
$modules = module_getinfo($modulename); |
|---|
| 3202 |
if (!isset($modules[$modulename])) { |
|---|
| 3203 |
return array(_("Specified module not found")); |
|---|
| 3204 |
} |
|---|
| 3205 |
|
|---|
| 3206 |
if (!$force) { |
|---|
| 3207 |
if ($modules[$modulename]['status'] == MODULE_STATUS_NOTINSTALLED) { |
|---|
| 3208 |
return array(_("Module not installed: cannot uninstall")); |
|---|
| 3209 |
} |
|---|
| 3210 |
|
|---|
| 3211 |
if ( ($depmods = module_reversedepends($modulename)) !== false) { |
|---|
| 3212 |
return array(_("Cannot disable: The following modules depend on this one: ").implode(',',$depmods)); |
|---|
| 3213 |
} |
|---|
| 3214 |
} |
|---|
| 3215 |
|
|---|
| 3216 |
$sql = "DELETE FROM modules WHERE modulename = '".$db->escapeSimple($modulename)."'"; |
|---|
| 3217 |
$results = $db->query($sql); |
|---|
| 3218 |
if(DB::IsError($results)) { |
|---|
| 3219 |
return array(_("Error updating database: ").$results->getMessage()); |
|---|
| 3220 |
} |
|---|
| 3221 |
|
|---|
| 3222 |
if (!_module_runscripts($modulename, 'uninstall')) { |
|---|
| 3223 |
return array(_("Failed to run un-installation scripts")); |
|---|
| 3224 |
} |
|---|
| 3225 |
|
|---|
| 3226 |
needreload(); |
|---|
| 3227 |
return true; |
|---|
| 3228 |
} |
|---|
| 3229 |
|
|---|
| 3230 |
/** Totally deletes a module |
|---|
| 3231 |
* @param string The name of the module to install |
|---|
| 3232 |
* @param bool If true, skips status and dependency checks |
|---|
| 3233 |
* @return mixed True if succesful, array of error messages if not succesful |
|---|
| 3234 |
*/ |
|---|
| 3235 |
function module_delete($modulename, $force = false) { |
|---|
| 3236 |
global $amp_conf; |
|---|
| 3237 |
|
|---|
| 3238 |
$modules = module_getinfo($modulename); |
|---|
| 3239 |
if (!isset($modules[$modulename])) { |
|---|
| 3240 |
return array(_("Specified module not found")); |
|---|
| 3241 |
} |
|---|
| 3242 |
|
|---|
| 3243 |
if ($modules[$modulename]['status'] != MODULE_STATUS_NOTINSTALLED) { |
|---|
| 3244 |
if (is_array($errors = module_uninstall($modulename, $force))) { |
|---|
| 3245 |
return $errors; |
|---|
| 3246 |
} |
|---|
| 3247 |
} |
|---|
| 3248 |
|
|---|
| 3249 |
// delete module directory |
|---|
| 3250 |
//TODO : do this in pure php |
|---|
| 3251 |
$dir = $amp_conf['AMPWEBROOT'].'/admin/modules/'.$modulename; |
|---|
| 3252 |
if (!is_dir($dir)) { |
|---|
| 3253 |
return array(sprintf(_("Cannot delete directory %s"), $dir)); |
|---|
| 3254 |
} |
|---|
| 3255 |
if (strpos($dir,"..") !== false) { |
|---|
| 3256 |
die_freepbx("Security problem, denying delete"); |
|---|
| 3257 |
} |
|---|
| 3258 |
exec("rm -r ".escapeshellarg($dir),$output, $exitcode); |
|---|
| 3259 |
if ($exitcode != 0) { |
|---|
| 3260 |
return array(sprintf(_("Error deleting directory %s (code %d)"), $dir, $exitcode)); |
|---|
| 3261 |
} |
|---|
| 3262 |
|
|---|
| 3263 |
// uninstall will have called needreload() if necessary |
|---|
| 3264 |
return true; |
|---|
| 3265 |
} |
|---|
| 3266 |
|
|---|
| 3267 |
/** Internal use only */ |
|---|
| 3268 |
function _module_setenabled($modulename, $enabled) { |
|---|
| 3269 |
global $db; |
|---|
| 3270 |
$sql = 'UPDATE modules SET enabled = '.($enabled ? '1' : '0').' WHERE modulename = "'.$db->escapeSimple($modulename).'"'; |
|---|
| 3271 |
$results = $db->query($sql); |
|---|
| 3272 |
if(DB::IsError($results)) { |
|---|
| 3273 |
die_freepbx($sql."<br>\n".$results->getMessage()); |
|---|
| 3274 |
} |
|---|
| 3275 |
$modulelist =& modulelist::create($db); |
|---|
| 3276 |
$modulelist->invalidate(); |
|---|
| 3277 |
} |
|---|
| 3278 |
|
|---|
| 3279 |
function _module_readxml($modulename) { |
|---|
| 3280 |
global $amp_conf; |
|---|
| 3281 |
switch ($modulename) { |
|---|
| 3282 |
case 'builtin': // special handling |
|---|
| 3283 |
$dir = $amp_conf['AMPWEBROOT']; |
|---|
| 3284 |
$xmlfile = $dir.'/admin/module-builtin.xml'; |
|---|
| 3285 |
break; |
|---|
| 3286 |
default: |
|---|
| 3287 |
$dir = $amp_conf['AMPWEBROOT'].'/admin/modules/'.$modulename; |
|---|
| 3288 |
$xmlfile = $dir.'/module.xml'; |
|---|
| 3289 |
break; |
|---|
| 3290 |
} |
|---|
| 3291 |
|
|---|
| 3292 |
if (file_exists($xmlfile)) { |
|---|
| 3293 |
$data = file_get_contents($xmlfile); |
|---|
| 3294 |
//$parser = new xml2ModuleArray($data); |
|---|
| 3295 |
//$xmlarray = $parser->parseModulesXML($data); |
|---|
| 3296 |
$parser = new xml2Array($data); |
|---|
| 3297 |
$xmlarray = $parser->data; |
|---|
| 3298 |
if (isset($xmlarray['module'])) { |
|---|
| 3299 |
// add a couple fields first |
|---|
| 3300 |
$xmlarray['module']['name'] = str_replace("\n&\n","&",$xmlarray['module']['name']); |
|---|
| 3301 |
$xmlarray['module']['displayname'] = $xmlarray['module']['name']; |
|---|
| 3302 |
if (isset($xmlarray['module']['description'])) { |
|---|
| 3303 |
$xmlarray['module']['description'] = trim(str_replace("\n","",$xmlarray['module']['description'])); |
|---|
| 3304 |
} |
|---|
| 3305 |
if (isset($xmlarray['module']['menuitems'])) { |
|---|
| 3306 |
|
|---|
| 3307 |
foreach ($xmlarray['module']['menuitems'] as $item=>$displayname) { |
|---|
| 3308 |
$displayname = str_replace("\n&\n","&",$displayname); |
|---|
| 3309 |
$xmlarray['module']['menuitems'][$item] = $displayname; |
|---|
| 3310 |
$path = '/module/menuitems/'.$item; |
|---|
| 3311 |
|
|---|
| 3312 |
// find category |
|---|
| 3313 |
if (isset($parser->attributes[$path]['category'])) { |
|---|
| 3314 |
$category = str_replace("\n&\n","&",$parser->attributes[$path]['category']); |
|---|
| 3315 |
} else if (isset($xmlarray['module']['category'])) { |
|---|
| 3316 |
$category = str_replace("\n&\n","&",$xmlarray['module']['category']); |
|---|
| 3317 |
} else { |
|---|
| 3318 |
$category = 'Basic'; |
|---|
| 3319 |
} |
|---|
| 3320 |
|
|---|
| 3321 |
// find type |
|---|
| 3322 |
if (isset($parser->attributes[$path]['type'])) { |
|---|
| 3323 |
$type = $parser->attributes[$path]['type']; |
|---|
| 3324 |
} else if (isset($xmlarray['module']['type'])) { |
|---|
| 3325 |
$type = $xmlarray['module']['type']; |
|---|
| 3326 |
} else { |
|---|
| 3327 |
$type = 'setup'; |
|---|
| 3328 |
} |
|---|
| 3329 |
|
|---|
| 3330 |
// sort priority |
|---|
| 3331 |
if (isset($parser->attributes[$path]['sort'])) { |
|---|
| 3332 |
// limit to -10 to 10 |
|---|
| 3333 |
if ($parser->attributes[$path]['sort'] > 10) { |
|---|
| 3334 |
$sort = 10; |
|---|
| 3335 |
} else if ($parser->attributes[$path]['sort'] < -10) { |
|---|
| 3336 |
$sort = -10; |
|---|
| 3337 |
} else { |
|---|
| 3338 |
$sort = $parser->attributes[$path]['sort']; |
|---|
| 3339 |
} |
|---|
| 3340 |
} else { |
|---|
| 3341 |
$sort = 0; |
|---|
| 3342 |
} |
|---|
| 3343 |
|
|---|
| 3344 |
// setup basic items array |
|---|
| 3345 |
$xmlarray['module']['items'][$item] = array( |
|---|
| 3346 |
'name' => $displayname, |
|---|
| 3347 |
'type' => $type, |
|---|
| 3348 |
'category' => $category, |
|---|
| 3349 |
'sort' => $sort, |
|---|
| 3350 |
); |
|---|
| 3351 |
|
|---|
| 3352 |
// add optional values: |
|---|
| 3353 |
$optional_attribs = array( |
|---|
| 3354 |
'href', // custom href |
|---|
| 3355 |
'target', // custom target frame |
|---|
| 3356 |
'display', // display= override |
|---|
| 3357 |
'needsenginedb', // set to true if engine db access required (e.g. astman access) |
|---|
| 3358 |
'needsenginerunning', // set to true if required to run |
|---|
| 3359 |
'access', // set to all if all users should always have access |
|---|
| 3360 |
); |
|---|
| 3361 |
foreach ($optional_attribs as $attrib) { |
|---|
| 3362 |
if (isset($parser->attributes[$path][ $attrib ])) { |
|---|
| 3363 |
$xmlarray['module']['items'][$item][ $attrib ] = $parser->attributes[$path][ $attrib ]; |
|---|
| 3364 |
} |
|---|
| 3365 |
} |
|---|
| 3366 |
|
|---|
| 3367 |
} |
|---|
| 3368 |
} |
|---|
| 3369 |
return $xmlarray['module']; |
|---|
| 3370 |
} |
|---|
| 3371 |
} |
|---|
| 3372 |
return null; |
|---|
| 3373 |
} |
|---|
| 3374 |
|
|---|
| 3375 |
// Temporarily copied here, for people that haven't upgraded their |
|---|
| 3376 |
// IVR module.. |
|---|
| 3377 |
|
|---|
| 3378 |
function modules_getversion($modname) { |
|---|
| 3379 |
return _modules_getversion($modname); |
|---|
| 3380 |
} |
|---|
| 3381 |
|
|---|
| 3382 |
// This returns the version of a module |
|---|
| 3383 |
function _modules_getversion($modname) { |
|---|
| 3384 |
global $db; |
|---|
| 3385 |
|
|---|
| 3386 |
$sql = "SELECT version FROM modules WHERE modulename = '".$db->escapeSimple($modname)."'"; |
|---|
| 3387 |
$results = $db->getRow($sql,DB_FETCHMODE_ASSOC); |
|---|
| 3388 |
if (isset($results['version'])) |
|---|
| 3389 |
return $results['version']; |
|---|
| 3390 |
else |
|---|
| 3391 |
return null; |
|---|
| 3392 |
} |
|---|
| 3393 |
|
|---|
| 3394 |
/** Updates the version field in the module table |
|---|
| 3395 |
* Should only be called internally |
|---|
| 3396 |
*/ |
|---|
| 3397 |
function _modules_setversion($modname, $vers) { |
|---|
| 3398 |
global $db; |
|---|
| 3399 |
|
|---|
| 3400 |
return ; |
|---|
| 3401 |
} |
|---|
| 3402 |
|
|---|
| 3403 |
/** Run the module install/uninstall scripts |
|---|
| 3404 |
* @param string The name of the module |
|---|
| 3405 |
* @param string The action to perform, either 'install' or 'uninstall' |
|---|
| 3406 |
* @return boolean If the action was succesful |
|---|
| 3407 |
*/ |
|---|
| 3408 |
function _module_runscripts($modulename, $type) { |
|---|
| 3409 |
global $amp_conf; |
|---|
| 3410 |
$db_engine = $amp_conf["AMPDBENGINE"]; |
|---|
| 3411 |
|
|---|
| 3412 |
$moduledir = $amp_conf["AMPWEBROOT"]."/admin/modules/".$modulename; |
|---|
| 3413 |
if (!is_dir($moduledir)) { |
|---|
| 3414 |
return false; |
|---|
| 3415 |
} |
|---|
| 3416 |
|
|---|
| 3417 |
switch ($type) { |
|---|
| 3418 |
case 'install': |
|---|
| 3419 |
// install sql files |
|---|
| 3420 |
$sqlfilename = "install.sql"; |
|---|
| 3421 |
|
|---|
| 3422 |
if (is_file($moduledir.'/'.$sqlfilename)) { |
|---|
| 3423 |
execSQL($moduledir.'/'.$sqlfilename); |
|---|
| 3424 |
} |
|---|
| 3425 |
|
|---|
| 3426 |
// then run .php scripts |
|---|
| 3427 |
_modules_doinclude($moduledir.'/install.php', $modulename); |
|---|
| 3428 |
break; |
|---|
| 3429 |
case 'uninstall': |
|---|
| 3430 |
// run uninstall .php scripts first |
|---|
| 3431 |
_modules_doinclude($moduledir.'/uninstall.php', $modulename); |
|---|
| 3432 |
|
|---|
| 3433 |
$sqlfilename = "uninstall.sql"; |
|---|
| 3434 |
|
|---|
| 3435 |
// then uninstall sql files |
|---|
| 3436 |
if (is_file($moduledir.'/'.$sqlfilename)) { |
|---|
| 3437 |
execSQL($moduledir.'/'.$sqlfilename); |
|---|
| 3438 |
} |
|---|
| 3439 |
|
|---|
| 3440 |
break; |
|---|
| 3441 |
default: |
|---|
| 3442 |
return false; |
|---|
| 3443 |
} |
|---|
| 3444 |
|
|---|
| 3445 |
return true; |
|---|
| 3446 |
} |
|---|
| 3447 |
|
|---|
| 3448 |
function _modules_doinclude($filename, $modulename) { |
|---|
| 3449 |
// we provide the following variables to the included file (as well as $filename and $modulename) |
|---|
| 3450 |
global $db, $amp_conf, $asterisk_conf; |
|---|
| 3451 |
|
|---|
| 3452 |
if (file_exists($filename) && is_file($filename)) { |
|---|
| 3453 |
include_once($filename); |
|---|
| 3454 |
} |
|---|
| 3455 |
} |
|---|
| 3456 |
|
|---|
| 3457 |
/* module_get_annoucements() |
|---|
| 3458 |
|
|---|
| 3459 |
Get's any annoucments, security warnings, etc. that may be related to the current freepbx version. Also |
|---|
| 3460 |
transmits a uniqueid to help track the number of installations using the online module admin system. |
|---|
| 3461 |
The uniqueid used is completely anonymous and not trackable. |
|---|
| 3462 |
*/ |
|---|
| 3463 |
function module_get_annoucements() { |
|---|
| 3464 |
global $db; |
|---|
| 3465 |
global $amp_conf; |
|---|
| 3466 |
$firstinstall=false; |
|---|
| 3467 |
$type=null; |
|---|
| 3468 |
|
|---|
| 3469 |
$sql = "SELECT * FROM module_xml WHERE id = 'installid'"; |
|---|
| 3470 |
$result = sql($sql,'getRow',DB_FETCHMODE_ASSOC); |
|---|
| 3471 |
|
|---|
| 3472 |
// if not set so this is a first time install |
|---|
| 3473 |
// get a new hash to account for first time install |
|---|
| 3474 |
// |
|---|
| 3475 |
if (!isset($result['data']) || trim($result['data']) == "") { |
|---|
| 3476 |
|
|---|
| 3477 |
$firstinstall=true; |
|---|
| 3478 |
$install_hash = _module_generate_unique_id(); |
|---|
| 3479 |
$installid = $install_hash['uniqueid']; |
|---|
| 3480 |
$type = $install_hash['type']; |
|---|
| 3481 |
|
|---|
| 3482 |
// save the hash so we remeber this is a first time install |
|---|
| 3483 |
// |
|---|
| 3484 |
$data4sql = $db->escapeSimple($installid); |
|---|
| 3485 |
sql("INSERT INTO module_xml (id,time,data) VALUES ('installid',".time().",'".$data4sql."')"); |
|---|
| 3486 |
$data4sql = $db->escapeSimple($type); |
|---|
| 3487 |
sql("INSERT INTO module_xml (id,time,data) VALUES ('type',".time().",'".$data4sql."')"); |
|---|
| 3488 |
|
|---|
| 3489 |
// Not a first time so save the queried hash and check if there is a type set |
|---|
| 3490 |
// |
|---|
| 3491 |
} else { |
|---|
| 3492 |
$installid=$result['data']; |
|---|
| 3493 |
$sql = "SELECT * FROM module_xml WHERE id = 'type'"; |
|---|
| 3494 |
$result = sql($sql,'getRow',DB_FETCHMODE_ASSOC); |
|---|
| 3495 |
|
|---|
| 3496 |
if (isset($result['data']) && trim($result['data']) != "") { |
|---|
| 3497 |
$type=$result['data']; |
|---|
| 3498 |
} |
|---|
| 3499 |
} |
|---|
| 3500 |
|
|---|
| 3501 |
// Now we have the id and know if this is a firstime install so we can get the announcement |
|---|
| 3502 |
// |
|---|
| 3503 |
$options = "?installid=".urlencode($installid); |
|---|
| 3504 |
|
|---|
| 3505 |
if (trim($type) != "") { |
|---|
| 3506 |
$options .= "&type=".urlencode($type); |
|---|
| 3507 |
} |
|---|
| 3508 |
if ($firstinstall) { |
|---|
| 3509 |
$options .= "&firstinstall=yes"; |
|---|
| 3510 |
} |
|---|
| 3511 |
$engver=engine_getinfo(); |
|---|
| 3512 |
if ($engver['engine'] == 'asterisk' && trim($engver['engine']) != "") { |
|---|
| 3513 |
$options .="&astver=".urlencode($engver['version']); |
|---|
| 3514 |
} else { |
|---|
| 3515 |
$options .="&astver=".urlencode($engver['raw']); |
|---|
| 3516 |
} |
|---|
| 3517 |
|
|---|
| 3518 |
$fn = "http://mirror.freepbx.org/version-".getversion().".html".$options; |
|---|
| 3519 |
if (!$amp_conf['MODULEADMINWGET']) { |
|---|
| 3520 |
$announcement = @ file_get_contents($fn); |
|---|
| 3521 |
} else { |
|---|
| 3522 |
$announcement = ''; |
|---|
| 3523 |
} |
|---|
| 3524 |
if (empty($announcement)) { |
|---|
| 3525 |
$fn2 = str_replace('&','\\&',$fn); |
|---|
| 3526 |
exec("wget -O - $fn2 2>> /dev/null", $data_arr, $retcode); |
|---|
| 3527 |
$announcement = implode("\n",$data_arr); |
|---|
| 3528 |
} |
|---|
| 3529 |
return $announcement; |
|---|
| 3530 |
} |
|---|
| 3531 |
|
|---|
| 3532 |
/* Assumes properly formated input, which is ok since |
|---|
| 3533 |
this is a private function and error checking is done |
|---|
| 3534 |
through proper regex scanning above |
|---|
| 3535 |
|
|---|
| 3536 |
Returns: random md5 hash |
|---|
| 3537 |
*/ |
|---|
| 3538 |
function _module_generate_random_id($type=null, $mac=null) { |
|---|
| 3539 |
|
|---|
| 3540 |
if (trim($mac) == "") { |
|---|
| 3541 |
$id['uniqueid'] = md5(mt_rand()); |
|---|
| 3542 |
} else { |
|---|
| 3543 |
// MD5 hash of the MAC so it is not identifiable |
|---|
| 3544 |
// |
|---|
| 3545 |
$id['uniqueid'] = md5($mac); |
|---|
| 3546 |
} |
|---|
| 3547 |
$id['type'] = $type; |
|---|
| 3548 |
|
|---|
| 3549 |
return $id; |
|---|
| 3550 |
} |
|---|
| 3551 |
|
|---|
| 3552 |
/* _module_generate_unique_id |
|---|
| 3553 |
|
|---|
| 3554 |
The purpose of this function is to generate a unique id that will try |
|---|
| 3555 |
and regenerate the same unique id on a system if called multiple |
|---|
| 3556 |
times. The id is unique but is not in any way identifable so that |
|---|
| 3557 |
privacy is not compromised. |
|---|
| 3558 |
|
|---|
| 3559 |
Returns: |
|---|
| 3560 |
|
|---|
| 3561 |
Array: ["uniqueid"] => unique_md5_hash |
|---|
| 3562 |
["type"] => type_passed_in |
|---|
| 3563 |
|
|---|
| 3564 |
*/ |
|---|
| 3565 |
function _module_generate_unique_id($type=null) { |
|---|
| 3566 |
|
|---|
| 3567 |
// Array of macs that require identification so we know these are not |
|---|
| 3568 |
// 'real' systems. Either home setups or test environments |
|---|
| 3569 |
// |
|---|
| 3570 |
$ids = array('000C29' => 'vmware', |
|---|
| 3571 |
'000569' => 'vmware', |
|---|
| 3572 |
'00163E' => 'xensource' |
|---|
| 3573 |
); |
|---|
| 3574 |
$mac_address = array(); |
|---|
| 3575 |
$chosen_mac = null; |
|---|
| 3576 |
|
|---|
| 3577 |
// TODO: put proper path in places for ifconfig, try various locations where it may be if |
|---|
| 3578 |
// non-0 return code. |
|---|
| 3579 |
// |
|---|
| 3580 |
exec('/sbin/ifconfig',$output, $return); |
|---|
| 3581 |
|
|---|
| 3582 |
if ($return != '0') { |
|---|
| 3583 |
|
|---|
| 3584 |
// OK try another path |
|---|
| 3585 |
// |
|---|
| 3586 |
exec('ifconfig',$output, $return); |
|---|
| 3587 |
|
|---|
| 3588 |
if ($return != '0') { |
|---|
| 3589 |
// No seed available so return with random seed |
|---|
| 3590 |
return _module_generate_random_id($type); |
|---|
| 3591 |
} |
|---|
| 3592 |
} |
|---|
| 3593 |
|
|---|
| 3594 |
// parse the output of ifconfig to get list of MACs returned |
|---|
| 3595 |
// |
|---|
| 3596 |
foreach ($output as $str) { |
|---|
| 3597 |
// make sure each line contains a valid MAC and IP address and then |
|---|
| 3598 |
// |
|---|
| 3599 |
if (preg_match("/([0-9A-Fa-f]{2}(:[0-9A-Fa-f]{2}){5})/", $str, $mac)) { |
|---|
| 3600 |
$mac_address[] = strtoupper(preg_replace("/:/","",$mac[0])); |
|---|
| 3601 |
} |
|---|
| 3602 |
} |
|---|
| 3603 |
|
|---|
| 3604 |
if (trim($type) == "") { |
|---|
| 3605 |
foreach ($mac_address as $mac) { |
|---|
| 3606 |
$id = substr($mac,0,6); |
|---|
| 3607 |
|
|---|
| 3608 |
// If we care about this id, then choose it and set the type |
|---|
| 3609 |
// we only choose the first one we see |
|---|
| 3610 |
// |
|---|
| 3611 |
if (array_key_exists($id,$ids)) { |
|---|
| 3612 |
$chosen_mac = $mac; |
|---|
| 3613 |
$type = $ids[$id]; |
|---|
| 3614 |
break; |
|---|
| 3615 |
} |
|---|
| 3616 |
} |
|---|
| 3617 |
} |
|---|
| 3618 |
|
|---|
| 3619 |
// Now either we have a chosen_mac, we will use the first mac, or if something went wrong |
|---|
| 3620 |
// and there is nothing in the array (couldn't find a mac) then we will make it purely random |
|---|
| 3621 |
// |
|---|
| 3622 |
if ($type == "vmware" || $type == "xensource") { |
|---|
| 3623 |
// vmware, xensource machines will have repeated macs so make random |
|---|
| 3624 |
return _module_generate_random_id($type); |
|---|
| 3625 |
} else if ($chosen_mac != "") { |
|---|
| 3626 |
return _module_generate_random_id($type, $chosen_mac); |
|---|
| 3627 |
} else if (isset($mac_address[0])) { |
|---|
| 3628 |
return _module_generate_random_id($type, $mac_address[0]); |
|---|
| 3629 |
} else { |
|---|
| 3630 |
return _module_generate_random_id($type); |
|---|
| 3631 |
} |
|---|
| 3632 |
} |
|---|
| 3633 |
|
|---|
| 3634 |
function module_run_notification_checks() { |
|---|
| 3635 |
global $db; |
|---|
| 3636 |
$modules_needup = module_getinfo(false, MODULE_STATUS_NEEDUPGRADE); |
|---|
| 3637 |
$modules_broken = module_getinfo(false, MODULE_STATUS_BROKEN); |
|---|
| 3638 |
|
|---|
| 3639 |
$notifications =& notifications::create($db); |
|---|
| 3640 |
if ($cnt = count($modules_needup)) { |
|---|
| 3641 |
$text = (($cnt > 1) ? sprintf(_('You have %s disabled modules'), $cnt) : _('You have a disabled module')); |
|---|
| 3642 |
$desc = _('The following modules are disabled because they need to be upgraded:')."\n".implode(", ",array_keys($modules_needup)); |
|---|
| 3643 |
$desc .= "\n\n"._('You should go to the module admin page to fix these.'); |
|---|
| 3644 |
$notifications->add_error('freepbx', 'modules_disabled', $text, $desc, '?type=tool&display=modules'); |
|---|
| 3645 |
} else { |
|---|
| 3646 |
$notifications->delete('freepbx', 'modules_disabled'); |
|---|
| 3647 |
} |
|---|
| 3648 |
if ($cnt = count($modules_broken)) { |
|---|
| 3649 |
$text = (($cnt > 1) ? sprintf(_('You have %s broken modules'), $cnt) : _('You have a broken module')); |
|---|
| 3650 |
$desc = _('The following modules are disabled because they are broken:')."\n".implode(", ",array_keys($modules_broken)); |
|---|
| 3651 |
$desc .= "\n\n"._('You should go to the module admin page to fix these.'); |
|---|
| 3652 |
$notifications->add_critical('freepbx', 'modules_broken', $text, $desc, '?type=tool&display=modules', false); |
|---|
| 3653 |
} else { |
|---|
| 3654 |
$notifications->delete('freepbx', 'modules_broken'); |
|---|
| 3655 |
} |
|---|
| 3656 |
} |
|---|
| 3657 |
|
|---|
| 3658 |
/** Log a debug message to a debug file |
|---|
| 3659 |
* @param string debug message to be printed |
|---|
| 3660 |
* @param string optional mode, default 'a' |
|---|
| 3661 |
* @param string optinal filename, default /tmp/freepbx_debug.log |
|---|
| 3662 |
*/ |
|---|
| 3663 |
function freepbx_debug($string, $option='a', $filename='/tmp/freepbx_debug.log') { |
|---|
| 3664 |
$fh = fopen($filename,$option); |
|---|
| 3665 |
fwrite($fh,date("Y-M-d H:i:s")."\n");//add timestamp |
|---|
| 3666 |
if (is_array($string)) { |
|---|
| 3667 |
fwrite($fh,print_r($string,true)."\n"); |
|---|
| 3668 |
} else { |
|---|
| 3669 |
fwrite($fh,$string."\n"); |
|---|
| 3670 |
} |
|---|
| 3671 |
fclose($fh); |
|---|
| 3672 |
} |
|---|
| 3673 |
//lazy, I mean efficient, alias for function freepbx_debug |
|---|
| 3674 |
function dbug(){ |
|---|
| 3675 |
$args=func_get_args(); |
|---|
| 3676 |
call_user_func_array('freepbx_debug',$args); |
|---|
| 3677 |
} |
|---|
| 3678 |
|
|---|
| 3679 |
/** Log an error to the (database-based) log |
|---|
| 3680 |
* @param string The section or script where the error occured |
|---|
| 3681 |
* @param string The level/severity of the error. Valid levels: 'error', 'warning', 'debug', 'devel-debug' |
|---|
| 3682 |
* @param string The error message |
|---|
| 3683 |
*/ |
|---|
| 3684 |
function freepbx_log($section, $level, $message) { |
|---|
| 3685 |
global $db; |
|---|
| 3686 |
global $debug; // This is used by retrieve_conf |
|---|
| 3687 |
global $amp_conf; |
|---|
| 3688 |
|
|---|
| 3689 |
if (isset($debug) && ($debug != false)) { |
|---|
| 3690 |
print "[DEBUG-$section] ($level) $message\n"; |
|---|
| 3691 |
} |
|---|
| 3692 |
if (!$amp_conf['AMPENABLEDEVELDEBUG'] && strtolower(trim($level)) == 'devel-debug') { |
|---|
| 3693 |
return true; |
|---|
| 3694 |
} |
|---|
| 3695 |
|
|---|
| 3696 |
if (!$amp_conf['AMPDISABLELOG']) { |
|---|
| 3697 |
switch (strtoupper($amp_conf['AMPSYSLOGLEVEL'])) { |
|---|
| 3698 |
case 'LOG_EMERG': |
|---|
| 3699 |
syslog(LOG_EMERG,"FreePBX-[$level][$section] $message"); |
|---|
| 3700 |
break; |
|---|
| 3701 |
case 'LOG_ALERT': |
|---|
| 3702 |
syslog(LOG_ALERT,"FreePBX-[$level][$section] $message"); |
|---|
| 3703 |
break; |
|---|
| 3704 |
case 'LOG_CRIT': |
|---|
| 3705 |
syslog(LOG_CRIT,"FreePBX-[$level][$section] $message"); |
|---|
| 3706 |
break; |
|---|
| 3707 |
case 'LOG_ERR': |
|---|
| 3708 |
syslog(LOG_ERR,"FreePBX-[$level][$section] $message"); |
|---|
| 3709 |
break; |
|---|
| 3710 |
case 'LOG_WARNING': |
|---|
| 3711 |
syslog(LOG_WARNING,"FreePBX-[$level][$section] $message"); |
|---|
| 3712 |
break; |
|---|
| 3713 |
case 'LOG_NOTICE': |
|---|
| 3714 |
syslog(LOG_NOTICE,"FreePBX-[$level][$section] $message"); |
|---|
| 3715 |
break; |
|---|
| 3716 |
case 'LOG_INFO': |
|---|
| 3717 |
syslog(LOG_INFO,"FreePBX-[$level][$section] $message"); |
|---|
| 3718 |
break; |
|---|
| 3719 |
case 'LOG_DEBUG': |
|---|
| 3720 |
syslog(LOG_DEBUG,"FreePBX-[$level][$section] $message"); |
|---|
| 3721 |
break; |
|---|
| 3722 |
case 'SQL': |
|---|
| 3723 |
case 'LOG_SQL': |
|---|
| 3724 |
default: |
|---|
| 3725 |
$sth = $db->prepare("INSERT INTO freepbx_log (time, section, level, message) VALUES (NOW(),?,?,?)"); |
|---|
| 3726 |
$db->execute($sth, array($section, $level, $message)); |
|---|
| 3727 |
break; |
|---|
| 3728 |
} |
|---|
| 3729 |
|
|---|
| 3730 |
} |
|---|
| 3731 |
} |
|---|
| 3732 |
|
|---|
| 3733 |
/** Abort all output, and redirect the browser's location. |
|---|
| 3734 |
* |
|---|
| 3735 |
* Useful for returning to the user to a GET location immediately after doing |
|---|
| 3736 |
* a successful POST operation. This avoids the "this page was sent via POST, resubmit?" |
|---|
| 3737 |
* message in the users browser, and also overwrites the POST page as a location in |
|---|
| 3738 |
* the browser's URL history (eg, they can't press the back button and end up re-submitting |
|---|
| 3739 |
* the page). |
|---|
| 3740 |
* |
|---|
| 3741 |
* @param string The url to go to |
|---|
| 3742 |
* @param bool If execution should stop after the function. Defaults to true |
|---|
| 3743 |
*/ |
|---|
| 3744 |
function redirect($url, $stop_processing = true) { |
|---|
| 3745 |
// TODO: If I don't call ob_end_clean() then is output buffering still on? Do I need to run it off still? |
|---|
| 3746 |
// (note ob_end_flush() results in the same php NOTICE so not sure how to turn it off. (?ob_implicit_flush(true)?) |
|---|
| 3747 |
// |
|---|
| 3748 |
@ob_end_clean(); |
|---|
| 3749 |
@header('Location: '.$url); |
|---|
| 3750 |
if ($stop_processing) exit; |
|---|
| 3751 |
} |
|---|
| 3752 |
|
|---|
| 3753 |
/** Abort all output, and redirect the browser's location using standard |
|---|
| 3754 |
* FreePBX user interface variables. By default, will take POST/GET variables |
|---|
| 3755 |
* 'type' and 'display' and pass them along in the URL. |
|---|
| 3756 |
* Also accepts a variable number of parameters, each being the name of a variable |
|---|
| 3757 |
* to pass on. |
|---|
| 3758 |
* |
|---|
| 3759 |
* For example, calling redirect_standard('extdisplay','test'); will take $_REQUEST['type'], |
|---|
| 3760 |
* $_REQUEST['display'], $_REQUEST['extdisplay'], and $_REQUEST['test'], |
|---|
| 3761 |
* and if any are present, use them to build a GET string (eg, "config.php?type=setup& |
|---|
| 3762 |
* display=somemodule&extdisplay=53&test=yes", which is then passed to redirect() to send the browser |
|---|
| 3763 |
* there. |
|---|
| 3764 |
* |
|---|
| 3765 |
* redirect_standard_continue does exactly the same thing but does NOT abort processing. This |
|---|
| 3766 |
* is used when you wish to do a redirect but there is a possibility of other hooks still needing |
|---|
| 3767 |
* to continue processing. Note that this is used in core when in 'extensions' mode, as both the |
|---|
| 3768 |
* users and devices modules need to hook into it together. |
|---|
| 3769 |
* |
|---|
| 3770 |
* @param string (optional, variable number) The name of a variable from $_REQUEST to |
|---|
| 3771 |
* pass on to a GET URL. |
|---|
| 3772 |
* |
|---|
| 3773 |
*/ |
|---|
| 3774 |
function redirect_standard( /* Note. Read the next line. Varaible No of Paramas */ ) { |
|---|
| 3775 |
$args = func_get_Args(); |
|---|
| 3776 |
|
|---|
| 3777 |
foreach (array_merge(array('type','display'),$args) as $arg) { |
|---|
| 3778 |
if (isset($_REQUEST[$arg])) { |
|---|
| 3779 |
$urlopts[] = $arg.'='.urlencode($_REQUEST[$arg]); |
|---|
| 3780 |
} |
|---|
| 3781 |
} |
|---|
| 3782 |
$url = $_SERVER['PHP_SELF'].'?'.implode('&',$urlopts); |
|---|
| 3783 |
redirect($url); |
|---|
| 3784 |
} |
|---|
| 3785 |
|
|---|
| 3786 |
function redirect_standard_continue( /* Note. Read the next line. Varaible No of Paramas */ ) { |
|---|
| 3787 |
$args = func_get_Args(); |
|---|
| 3788 |
|
|---|
| 3789 |
foreach (array_merge(array('type','display'),$args) as $arg) { |
|---|
| 3790 |
if (isset($_REQUEST[$arg])) { |
|---|
| 3791 |
$urlopts[] = $arg.'='.urlencode($_REQUEST[$arg]); |
|---|
| 3792 |
} |
|---|
| 3793 |
} |
|---|
| 3794 |
$url = $_SERVER['PHP_SELF'].'?'.implode('&',$urlopts); |
|---|
| 3795 |
redirect($url, false); |
|---|
| 3796 |
} |
|---|
| 3797 |
|
|---|
| 3798 |
//This function calls modulename_contexts() |
|---|
| 3799 |
//expects a returned array which minimally includes 'context' => the actual context to include |
|---|
| 3800 |
//can also define 'description' => the display for this context - if undefined will be set to 'context' |
|---|
| 3801 |
//'module' => the display for the section this should be listed under defaults to modlue display (can be used to group subsets within one module) |
|---|
| 3802 |
//'parent' => if including another context automatically includes this one, list the parent context |
|---|
| 3803 |
//'priority' => default sort order for includes range -50 to +50, 0 is default |
|---|
| 3804 |
//'enabled' => can be used to flag a context as disabled and it won't be included, but will not have its settings removed. |
|---|
| 3805 |
//'extension' => can be used to tag with an extension for checkRange($extension) |
|---|
| 3806 |
//'dept' => can be used to tag with a department for checkDept($dept) |
|---|
| 3807 |
// this defaults to false for disabled modules. |
|---|
| 3808 |
function freepbx_get_contexts() { |
|---|
| 3809 |
$modules = module_getinfo(false, array(MODULE_STATUS_ENABLED, MODULE_STATUS_DISABLED, MODULE_STATUS_NEEDUPGRADE)); |
|---|
| 3810 |
|
|---|
| 3811 |
$contexts = array(); |
|---|
| 3812 |
|
|---|
| 3813 |
foreach ($modules as $modname => $mod) { |
|---|
| 3814 |
$funct = strtolower($modname.'_contexts'); |
|---|
| 3815 |
if (function_exists($funct)) { |
|---|
| 3816 |
// call the modulename_contexts() function |
|---|
| 3817 |
$contextArray = $funct(); |
|---|
| 3818 |
if (is_array($contextArray)) { |
|---|
| 3819 |
foreach ($contextArray as $con) { |
|---|
| 3820 |
if (isset($con['context'])) { |
|---|
| 3821 |
if (!isset($con['description'])) { |
|---|
| 3822 |
$con['description'] = $con['context']; |
|---|
| 3823 |
} |
|---|
| 3824 |
if (!isset($con['module'])) { |
|---|
| 3825 |
$con['module'] = $mod['displayName']; |
|---|
| 3826 |
} |
|---|
| 3827 |
if (!isset($con['priority'])) { |
|---|
| 3828 |
$con['priority'] = 0; |
|---|
| 3829 |
} |
|---|
| 3830 |
if (!isset($con['parent'])) { |
|---|
| 3831 |
$con['parent'] = ''; |
|---|
| 3832 |
} |
|---|
| 3833 |
if (!isset($con['extension'])) { |
|---|
| 3834 |
$con['extension'] = null; |
|---|
| 3835 |
} |
|---|
| 3836 |
if (!isset($con['dept'])) { |
|---|
| 3837 |
$con['dept'] = null; |
|---|
| 3838 |
} |
|---|
| 3839 |
if ($mod['status'] == MODULE_STATUS_ENABLED) { |
|---|
| 3840 |
if (!isset($con['enabled'])) { |
|---|
| 3841 |
$con['enabled'] = true; |
|---|
| 3842 |
} |
|---|
| 3843 |
} else { |
|---|
| 3844 |
$con['enabled'] = false; |
|---|
| 3845 |
} |
|---|
| 3846 |
$contexts[ $con['context'] ] = $con; |
|---|
| 3847 |
} |
|---|
| 3848 |
} |
|---|
| 3849 |
} |
|---|
| 3850 |
} |
|---|
| 3851 |
} |
|---|
| 3852 |
return $contexts; |
|---|
| 3853 |
} |
|---|
| 3854 |
|
|---|
| 3855 |
?> |
|---|