| 1 |
#!/usr/bin/php -q |
|---|
| 2 |
<?php |
|---|
| 3 |
|
|---|
| 4 |
// Copyright (C) 2003 Zac Sprackett <zsprackett-asterisk@sprackett.com> |
|---|
| 5 |
// |
|---|
| 6 |
// This program is free software; you can redistribute it and/or |
|---|
| 7 |
// modify it under the terms of the GNU General Public License |
|---|
| 8 |
// as published by the Free Software Foundation; either version 2 |
|---|
| 9 |
// of the License, or (at your option) any later version. |
|---|
| 10 |
// |
|---|
| 11 |
// This program is distributed in the hope that it will be useful, |
|---|
| 12 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 |
// GNU General Public License for more details. |
|---|
| 15 |
// |
|---|
| 16 |
// Amended by Coalescent Systems Inc. Sept, 2004 |
|---|
| 17 |
// to include support for DND, Call Waiting, and CF to external trunk |
|---|
| 18 |
// info@coalescentsystems.ca |
|---|
| 19 |
// |
|---|
| 20 |
// This script has been ported to PHP by |
|---|
| 21 |
// Diego Iastrubni <diego.iastrubni@xorcom.com> and the FreePBX community |
|---|
| 22 |
|
|---|
| 23 |
/* --------WARNING--------- |
|---|
| 24 |
* |
|---|
| 25 |
* This script is auto-copied from an included module and will get overwritten. |
|---|
| 26 |
* If you modify it, you must change it to write only, in the agi-bin directory, |
|---|
| 27 |
* to keep it from getting changed. |
|---|
| 28 |
*/ |
|---|
| 29 |
|
|---|
| 30 |
require_once "phpagi.php"; |
|---|
| 31 |
require_once "phpagi-asmanager.php"; |
|---|
| 32 |
|
|---|
| 33 |
$ext = array(); // Hash that will contain our list of extensions to call |
|---|
| 34 |
$ext_hunt = array(); // Hash that will contain our list of extensions to call used by huntgroup |
|---|
| 35 |
$cidnum = ""; // Caller ID Number for this call |
|---|
| 36 |
$cidname = ""; // Caller ID Name for this call |
|---|
| 37 |
$timer = ""; // Call timer for Dial command |
|---|
| 38 |
$dialopts = ""; // options for dialing |
|---|
| 39 |
$rc = ""; // Catch return code |
|---|
| 40 |
$priority = ""; // Next priority |
|---|
| 41 |
$rgmethod = ""; // If Ring Group what ringing method was chosen |
|---|
| 42 |
$dsarray = array(); // This will hold all the dial strings, used to check for duplicate extensions |
|---|
| 43 |
|
|---|
| 44 |
$AGI = new AGI(); |
|---|
| 45 |
debug("Starting New Dialparties.agi", 1); |
|---|
| 46 |
|
|---|
| 47 |
// Get required channels variables that used to come from amportal.conf |
|---|
| 48 |
$ampmgruser = get_var( $AGI, "AMPMGRUSER" ); |
|---|
| 49 |
$ampmgrpass = get_var( $AGI, "AMPMGRPASS" ); |
|---|
| 50 |
$cwinusebusy = get_var( $AGI, "CWINUSEBUSY" ); |
|---|
| 51 |
$ast_version = get_var( $AGI, "ASTVERSION" ); |
|---|
| 52 |
|
|---|
| 53 |
$cwignore = get_var( $AGI, "CWIGNORE" ); |
|---|
| 54 |
$cwignore = strtoupper(trim($cwignore)); |
|---|
| 55 |
|
|---|
| 56 |
$astman = new AGI_AsteriskManager( ); |
|---|
| 57 |
if (!$astman->connect("127.0.0.1", $ampmgruser , $ampmgrpass)) { |
|---|
| 58 |
exit (1); |
|---|
| 59 |
} |
|---|
| 60 |
|
|---|
| 61 |
$priority = get_var( $AGI, "priority" ) + 1; |
|---|
| 62 |
|
|---|
| 63 |
// Caller ID info is stored in $request in AGI class, passed from Asterisk |
|---|
| 64 |
$cidnum = $AGI->request['agi_callerid']; |
|---|
| 65 |
$cidname = $AGI->request['agi_calleridname']; |
|---|
| 66 |
debug("Caller ID name is '$cidname' number is '$cidnum'", 1); |
|---|
| 67 |
|
|---|
| 68 |
// From this point forward, Set KEEPCID in the channel so subsequent calls, CF, etc. retain the incoming |
|---|
| 69 |
// CID that get sent down channel local. |
|---|
| 70 |
$AGI->set_variable('__KEEPCID','TRUE'); |
|---|
| 71 |
|
|---|
| 72 |
// Set to '' in case it was previously set |
|---|
| 73 |
// |
|---|
| 74 |
$AGI->set_variable('DIALSTATUS_CW',''); |
|---|
| 75 |
|
|---|
| 76 |
$timer = get_var( $AGI, "ARG1" ); |
|---|
| 77 |
$dialopts = get_var( $AGI, "ARG2" ); |
|---|
| 78 |
$rgmethod = get_var( $AGI, "RingGroupMethod" ); |
|---|
| 79 |
$rgmethod = trim($rgmethod); |
|---|
| 80 |
|
|---|
| 81 |
$alertinfo = get_var( $AGI, "ALERT_INFO" ); |
|---|
| 82 |
if ($alertinfo) { |
|---|
| 83 |
debug("Setting Alert-Info: $alertinfo", 4); |
|---|
| 84 |
$AGI->set_alertinfo($alertinfo); |
|---|
| 85 |
} |
|---|
| 86 |
|
|---|
| 87 |
$sippheader = get_var( $AGI, "SIPADDHEADER" ); |
|---|
| 88 |
if ($sippheader) { |
|---|
| 89 |
$fields = explode(':',$sippheader,2); |
|---|
| 90 |
debug("Setting sipheader ".$fields[0].": ".$fields[1], 4); |
|---|
| 91 |
$AGI->exec_sipaddheader($fields[0], $fields[1]); |
|---|
| 92 |
} |
|---|
| 93 |
|
|---|
| 94 |
$pr_dialstatus = get_var( $AGI, "PR_DIALSTATUS" ); |
|---|
| 95 |
|
|---|
| 96 |
$fmgrp = get_var( $AGI, "FMGRP" ); |
|---|
| 97 |
$nodest = get_var( $AGI, "NODEST" ); |
|---|
| 98 |
if (empty($nodest)) { |
|---|
| 99 |
$nodest = ''; |
|---|
| 100 |
} |
|---|
| 101 |
|
|---|
| 102 |
$ringgroup_index = get_var( $AGI, "RINGGROUP_INDEX" ); |
|---|
| 103 |
$use_confirmation = get_var( $AGI, "USE_CONFIRMATION" ); |
|---|
| 104 |
if (empty($use_confirmation)) { |
|---|
| 105 |
$use_confirmation = "FALSE"; |
|---|
| 106 |
} |
|---|
| 107 |
debug("USE_CONFIRMATION: '$use_confirmation'", 5); |
|---|
| 108 |
debug("RINGGROUP_INDEX: '$ringgroup_index'", 5); |
|---|
| 109 |
|
|---|
| 110 |
if (empty($timer)) { |
|---|
| 111 |
$timer = 0; |
|---|
| 112 |
} |
|---|
| 113 |
if (empty($dialopts)) { |
|---|
| 114 |
$dialopts = ""; |
|---|
| 115 |
} |
|---|
| 116 |
if (empty($rgmethod)) { |
|---|
| 117 |
$rgmethod = "none"; |
|---|
| 118 |
} |
|---|
| 119 |
|
|---|
| 120 |
debug("Methodology of ring is '$rgmethod'", 1); |
|---|
| 121 |
|
|---|
| 122 |
// reset the ringgroup method to its fundamental algorithm and pull out if |
|---|
| 123 |
// master mode. |
|---|
| 124 |
|
|---|
| 125 |
$recall_mastermode=$rgmethod; |
|---|
| 126 |
|
|---|
| 127 |
switch ($rgmethod) { |
|---|
| 128 |
case 'ringall-prim': |
|---|
| 129 |
$rgmethod = "ringall"; |
|---|
| 130 |
$mastermode = 1; |
|---|
| 131 |
break; |
|---|
| 132 |
case 'hunt-prim': |
|---|
| 133 |
$rgmethod = "hunt"; |
|---|
| 134 |
$mastermode = 1; |
|---|
| 135 |
break; |
|---|
| 136 |
case 'memoryhunt-prim': |
|---|
| 137 |
$rgmethod = "memoryhunt"; |
|---|
| 138 |
$mastermode = 1; |
|---|
| 139 |
break; |
|---|
| 140 |
case 'ringallv2-prim': |
|---|
| 141 |
$rgmethod = "ringallv2"; |
|---|
| 142 |
$mastermode = 1; |
|---|
| 143 |
break; |
|---|
| 144 |
default: |
|---|
| 145 |
$mastermode = 0; |
|---|
| 146 |
$pr_dialstatus = ""; // not relevant if not mastermode, clear it so dnd doesn't propagate, and other |
|---|
| 147 |
} |
|---|
| 148 |
|
|---|
| 149 |
// call confirmation only works with ringall and ringall-prim. The javascripts in ringgroups |
|---|
| 150 |
// and follow-me should enforce this. If that has been overridden then force ringall. |
|---|
| 151 |
// Keep this code after the matermode check above, since they will at least get mastermode |
|---|
| 152 |
// if they set a -prim mode in one of the others |
|---|
| 153 |
// |
|---|
| 154 |
if ( ($use_confirmation != "FALSE") && ($rgmethod != "ringall") && ($rgmethod != "ringallv2") && ($rgmethod != "hunt") ) { |
|---|
| 155 |
debug("Unsupported RingMethod: '$rgmethod' resetting to ringall", 1); |
|---|
| 156 |
$rgmethod = "ringall"; |
|---|
| 157 |
} |
|---|
| 158 |
|
|---|
| 159 |
// Start with Arg Count set to 3 as two args are used |
|---|
| 160 |
$arg_cnt = 3; |
|---|
| 161 |
while($arg = get_var($AGI,"ARG". $arg_cnt)) { |
|---|
| 162 |
// not sure why, dialparties will get stuck in a loop if noresponse |
|---|
| 163 |
if ($arg == '-') { |
|---|
| 164 |
debug("get_variable got a \"noresponse\"! Exiting",3); |
|---|
| 165 |
exit($arg_cnt); |
|---|
| 166 |
} |
|---|
| 167 |
$extarray = split( '-', $arg ); |
|---|
| 168 |
foreach ( $extarray as $k ) { |
|---|
| 169 |
$ext[] = $k; |
|---|
| 170 |
debug("Added extension $k to extension map", 3); |
|---|
| 171 |
} |
|---|
| 172 |
$arg_cnt++; |
|---|
| 173 |
} |
|---|
| 174 |
|
|---|
| 175 |
// FollowMe Preparation for Pre-Ring: |
|---|
| 176 |
// |
|---|
| 177 |
// If the primary extension is in the ringgroup list, then it should be rung |
|---|
| 178 |
// during both the pre-ring time and the list time, so it's real prering time |
|---|
| 179 |
// is the entire time. If it is not in the list, then it should only ring |
|---|
| 180 |
// for the pre-ring time. This section determines the times and then adds it |
|---|
| 181 |
// to the list if not already there, so that the dialstring is computed |
|---|
| 182 |
// appropriately. This section also makes sure that the primary extension |
|---|
| 183 |
// is at the top of the list. |
|---|
| 184 |
// |
|---|
| 185 |
// Notes before I forget. The primary may have been in the list and screwed |
|---|
| 186 |
// above. So ... do I need to move this up, probably. |
|---|
| 187 |
// |
|---|
| 188 |
if ($rgmethod == "ringallv2" && $fmgrp != "") { |
|---|
| 189 |
|
|---|
| 190 |
$fmgrp_primaryremoved = 0; |
|---|
| 191 |
|
|---|
| 192 |
$fmgrp_prering = $AGI->database_get('AMPUSER', $fmgrp."/followme/prering"); |
|---|
| 193 |
$fmgrp_prering = $fmgrp_prering['data'] > 1 ? $fmgrp_prering['data'] : 2; |
|---|
| 194 |
|
|---|
| 195 |
$fmgrp_grptime = $AGI->database_get('AMPUSER', $fmgrp."/followme/grptime"); |
|---|
| 196 |
$fmgrp_grptime = $fmgrp_grptime['data']; |
|---|
| 197 |
debug("got fmgrp_prering: $fmgrp_prering, fmgrp_grptime: $fmgrp_grptime",4); |
|---|
| 198 |
|
|---|
| 199 |
$fmgrp_totalprering = $fmgrp_grptime + $fmgrp_prering; |
|---|
| 200 |
debug("fmgrp_totalprering: $fmgrp_totalprering",4); |
|---|
| 201 |
|
|---|
| 202 |
if (in_array($fmgrp, $ext)) { |
|---|
| 203 |
debug("found extension in pre-ring and array",4); |
|---|
| 204 |
$fmgrp_realprering = $fmgrp_totalprering; |
|---|
| 205 |
if ($ext[0] != $fmgrp) { |
|---|
| 206 |
$tmpx=array_flip($ext); |
|---|
| 207 |
unset($ext[$tmpx[$fmgrp]]); |
|---|
| 208 |
array_unshift($ext,$fmgrp); |
|---|
| 209 |
} |
|---|
| 210 |
} else { |
|---|
| 211 |
debug("extension not in group list, ringging only during prering time",4); |
|---|
| 212 |
$fmgrp_realprering = $fmgrp_prering; |
|---|
| 213 |
array_unshift($ext,$fmgrp); |
|---|
| 214 |
} |
|---|
| 215 |
debug("ringallv2 ring times: REALPRERING: $fmgrp_realprering, PRERING: $fmgrp_prering",4); |
|---|
| 216 |
} |
|---|
| 217 |
|
|---|
| 218 |
// IF THE FIRST EXTENSION IS CALL FORWARD ENABLED (put in logic) then we don't do master mode |
|---|
| 219 |
// which means we reset the flag here after detecting that and just say we are not in master |
|---|
| 220 |
// mode and all is well. That means the loop below needs to be modified to detect the first |
|---|
| 221 |
// extension and do this if the case. |
|---|
| 222 |
|
|---|
| 223 |
// Check for call forwarding first |
|---|
| 224 |
// If call forward is enabled, we use chan_local |
|---|
| 225 |
// Hacky. We should be using an associative array, shouldn't we? |
|---|
| 226 |
$count = 0; |
|---|
| 227 |
foreach ($ext as $k) { |
|---|
| 228 |
$cf = $AGI->database_get('CF',$k); |
|---|
| 229 |
$cf = $cf['data']; |
|---|
| 230 |
if (strlen($cf)) { |
|---|
| 231 |
// append a hash sign so we can send out on chan_local below. |
|---|
| 232 |
$ext[$count] = $cf.'#'; |
|---|
| 233 |
debug("Extension $k has call forward set to $cf", 1); |
|---|
| 234 |
|
|---|
| 235 |
// if this is the primary extension and CF enabled, then cancel mastermode |
|---|
| 236 |
// whether it is or not, no need to check. |
|---|
| 237 |
// |
|---|
| 238 |
if ($count == 0) { |
|---|
| 239 |
$mastermode = 0; |
|---|
| 240 |
$pr_dialstatus = ""; // not relevant if not mastermode, clear it so dnd doesn't propagate, and other |
|---|
| 241 |
debug("Primary ext is CF so disabling mastermode if it was set", 4); |
|---|
| 242 |
} |
|---|
| 243 |
} |
|---|
| 244 |
else { |
|---|
| 245 |
debug("Extension $k cf is disabled", 3); |
|---|
| 246 |
} |
|---|
| 247 |
$count++; |
|---|
| 248 |
} |
|---|
| 249 |
|
|---|
| 250 |
// IF DND AND we process it as a DND (no CF enabled) then we need to some how flag that ALL THE REST |
|---|
| 251 |
// should now be ignored and not processed if in master mode (and this primary). Do this by setting some |
|---|
| 252 |
// sort of flag that says master mode DND so skip everything else below (set them all to ""). |
|---|
| 253 |
// |
|---|
| 254 |
|
|---|
| 255 |
// Hacky. |
|---|
| 256 |
$count = 0; |
|---|
| 257 |
$dndprimary = 0; |
|---|
| 258 |
// Now check for DND |
|---|
| 259 |
foreach ( $ext as $k ) { |
|---|
| 260 |
if ( (strpos($k,"#")==0) ) { |
|---|
| 261 |
// no point in doing if cf is enabled |
|---|
| 262 |
$dnd = $AGI->database_get('DND',$k); |
|---|
| 263 |
$dnd = $dnd['data']; |
|---|
| 264 |
if (strlen($dnd) || $pr_dialstatus == "BUSY") { |
|---|
| 265 |
debug("Extension $k has do not disturb enabled, or followme pre-ring returned busy", 2); |
|---|
| 266 |
unset($ext[$count]); |
|---|
| 267 |
$AGI->set_variable('DIALSTATUS','BUSY'); |
|---|
| 268 |
// if this is primary set dndprimary and figure out if needed below |
|---|
| 269 |
// |
|---|
| 270 |
if ($count == 0 && $mastermode) { |
|---|
| 271 |
$dndprimary = 1; |
|---|
| 272 |
debug("Primary extension is DND, so if mastermode, all should be dnd", 4); |
|---|
| 273 |
} |
|---|
| 274 |
if ($count == 0) { |
|---|
| 275 |
$fmgrp_primaryremoved = 1; |
|---|
| 276 |
} |
|---|
| 277 |
} |
|---|
| 278 |
else { |
|---|
| 279 |
debug("Extension $k do not disturb is disabled", 3); |
|---|
| 280 |
} |
|---|
| 281 |
} |
|---|
| 282 |
$count++; |
|---|
| 283 |
} |
|---|
| 284 |
|
|---|
| 285 |
// Main calling loop |
|---|
| 286 |
// |
|---|
| 287 |
$skipremaining = 0; // used to allow primary to ring but skip the rest |
|---|
| 288 |
$ds = ''; |
|---|
| 289 |
foreach ( $ext as $k ) { |
|---|
| 290 |
// mastermode description: |
|---|
| 291 |
// |
|---|
| 292 |
// if mastermode is set then the first extension will be examined and mastermode will be reset so that the others |
|---|
| 293 |
// are left alone. If the remaining extensions are not to be tried, skpremaining will be set to 1 which will |
|---|
| 294 |
// result in dndprimary being set to 1 thus diabling the remaining list. |
|---|
| 295 |
// |
|---|
| 296 |
// if cf unconditional was already detected on the primary, then mastermode will have been reset at this point |
|---|
| 297 |
// since that will negate the mastermode concpet. |
|---|
| 298 |
// |
|---|
| 299 |
// if dnd was set on the primary then dndprimary will already be set resulting in a completly blanked out list |
|---|
| 300 |
// since dnd on the primary means don't bother me on any. |
|---|
| 301 |
|
|---|
| 302 |
// Don't bother checking these if we will be blanking the extnum anyhow |
|---|
| 303 |
if ($skipremaining == 1) { |
|---|
| 304 |
$dndprimary = 1; |
|---|
| 305 |
} |
|---|
| 306 |
if ($dndprimary == 0) { |
|---|
| 307 |
// TODO what are these comments...? do we need to remove them...? |
|---|
| 308 |
$extnum = $k; |
|---|
| 309 |
|
|---|
| 310 |
// CWIGNORE is sent down the channel when all extensions should be treated as if they do not have |
|---|
| 311 |
// call waiting enabled. This is used primarily by Queue type setups (sometimes Ring Groups) when |
|---|
| 312 |
// you want to assure that calls go on to the next agent if the current one is on the phone instead |
|---|
| 313 |
// of ringing their line constantly. |
|---|
| 314 |
// |
|---|
| 315 |
if ($cwignore) { |
|---|
| 316 |
$exthascw = 0; |
|---|
| 317 |
} else { |
|---|
| 318 |
$exthascw = $AGI->database_get('CW', $extnum);// ? 1 : 0; |
|---|
| 319 |
$exthascw = $exthascw['data']? 1:0; |
|---|
| 320 |
} |
|---|
| 321 |
|
|---|
| 322 |
$extcfb = $AGI->database_get('CFB', $extnum);//? 1 : 0; |
|---|
| 323 |
$extcfb = $extcfb['data']; |
|---|
| 324 |
$exthascfb = (strlen($extcfb) > 0) ? 1 : 0; |
|---|
| 325 |
$extcfu = $AGI->database_get('CFU', $extnum);// ? 1 : 0; |
|---|
| 326 |
$extcfu = $extcfu['data']; |
|---|
| 327 |
$exthascfu = (strlen($extcfu) > 0) ? 1 : 0; |
|---|
| 328 |
|
|---|
| 329 |
// Dump details in level 4 |
|---|
| 330 |
debug("extnum $extnum has: cw: $exthascw; hascfb: $exthascfb [$extcfb] hascfu: $exthascfu [$extcfu]",4); |
|---|
| 331 |
|
|---|
| 332 |
// check if mastermode and then reset here. If mastermode, this will be the first extension so |
|---|
| 333 |
// the state is checked and a decision is made as to what to do. We have gotten all the cf variables |
|---|
| 334 |
// above. If CF unconditional was set, we never get here because we alread reset mastermode. If DND |
|---|
| 335 |
// were set then we never get here becasue didprimary was set |
|---|
| 336 |
if ($mastermode == 1) { |
|---|
| 337 |
$mastermode = 0; |
|---|
| 338 |
$extstate = is_ext_avail($extnum); |
|---|
| 339 |
debug("Extension $extnum has ExtensionState: $extstate",1); |
|---|
| 340 |
|
|---|
| 341 |
if ( ($exthascw == 1) && ($extstate == 1) ) { |
|---|
| 342 |
// process this one extension but the remaining should be skipped since there is cw and |
|---|
| 343 |
// the extension is occupied. This will try this extension but not the others. |
|---|
| 344 |
$skipremaining = 1; |
|---|
| 345 |
debug("In mastermode with cw enabled so $extnum will be tried and others skipped",4); |
|---|
| 346 |
} elseif ( ($exthascw == 0) && ($extstate == 1) ) { |
|---|
| 347 |
// no cw, ext is busy. So if cfb is set, it will forward there and if not, it will be |
|---|
| 348 |
// ignored as normal behavior. In either case, we skip the remaining numbers. |
|---|
| 349 |
$skipremaining = 1; |
|---|
| 350 |
debug("In mastermode with cw disabled so $extnum will be processed in case cfb set",4); |
|---|
| 351 |
} |
|---|
| 352 |
// All other cases should act like normal. Unavailable, not busy, ringing, etc. |
|---|
| 353 |
// should not be effected |
|---|
| 354 |
} |
|---|
| 355 |
} // end if ($dndprimary == 0) |
|---|
| 356 |
// $dndprimary == 1 so clear the extension |
|---|
| 357 |
else { |
|---|
| 358 |
// clear the current extension if dndprimary has been set. This will only be the case if in mastermode so no need to check |
|---|
| 359 |
// that. Use this to skip remaining extensions also if just ringing the primary. |
|---|
| 360 |
$extnum = ''; |
|---|
| 361 |
} |
|---|
| 362 |
|
|---|
| 363 |
// if CF is not in use and $dndprimary is not set otherwise $extnum has been cleared and nothing to do |
|---|
| 364 |
// |
|---|
| 365 |
if ( (strpos($k,"#")==0) && $dndprimary == 0) { |
|---|
| 366 |
// CW is not in use or CFB is in use on this extension, then we need to check! |
|---|
| 367 |
if ( ($exthascw == 0) || ($exthascfb == 1) || ($exthascfu == 1) ) { |
|---|
| 368 |
// get ExtensionState: 0-idle; 1-busy; 4-unavail; 8-ringing <--- these are unconfirmed |
|---|
| 369 |
$extstate = is_ext_avail($extnum); |
|---|
| 370 |
debug("Extension $extnum has ExtensionState: $extstate",1); |
|---|
| 371 |
|
|---|
| 372 |
// Ext has CFU and is Unavailable |
|---|
| 373 |
if ( ($exthascfu == 1) && ($extstate == 4) ) { |
|---|
| 374 |
// If part of a ring group, then just do what CF does, otherwise needs to |
|---|
| 375 |
// drop back to dialplan with NOANSWER |
|---|
| 376 |
if ($rgmethod != '' && $rgmethod != 'none') { |
|---|
| 377 |
debug("Extension $extnum has call forward on no answer set and is unavailable and is part of a Ring Group forwarding to '$extcfu'",1); |
|---|
| 378 |
$extnum = $extcfu . '#'; # same method as the normal cf, i.e. send to Local |
|---|
| 379 |
} else { |
|---|
| 380 |
debug("Extension $extnum has call forward on no answer set and is unavailable",1); |
|---|
| 381 |
$extnum = ''; |
|---|
| 382 |
$AGI->set_variable('DIALSTATUS','NOANSWER'); |
|---|
| 383 |
} |
|---|
| 384 |
} elseif ( ($exthascw == 0) || ($exthascfb == 1) ) { |
|---|
| 385 |
debug("Checking CW and CFB status for extension $extnum",3); |
|---|
| 386 |
// extension in use |
|---|
| 387 |
if ($extstate > 0 && $extstate != 4) { |
|---|
| 388 |
debug("Extension $extnum is not available to be called", 1); |
|---|
| 389 |
// extension in use |
|---|
| 390 |
if ($exthascfb == 1) { |
|---|
| 391 |
debug("Extension $extnum has call forward on busy set to $extcfb",1); |
|---|
| 392 |
$extnum = $extcfb . '#'; # same method as the normal cf, i.e. send to Local |
|---|
| 393 |
// CW not in use |
|---|
| 394 |
} elseif ($exthascw == 0) { |
|---|
| 395 |
debug("Extension $extnum has call waiting disabled",1); |
|---|
| 396 |
$extnum = ''; |
|---|
| 397 |
$AGI->set_variable('DIALSTATUS','BUSY'); |
|---|
| 398 |
} else { |
|---|
| 399 |
debug("Extension $extnum has call waiting enabled",1); |
|---|
| 400 |
} |
|---|
| 401 |
} |
|---|
| 402 |
// -1 means couldn't read status usually due to missing HINT |
|---|
| 403 |
} elseif ($extstate < 0) { |
|---|
| 404 |
debug("ExtensionState for $extnum could not be read...assuming ok",3); |
|---|
| 405 |
} else { |
|---|
| 406 |
debug("Extension $extnum is available",1); |
|---|
| 407 |
} |
|---|
| 408 |
} elseif ($rgmethod == "none" && $exthascw == 1 && $cwinusebusy) { |
|---|
| 409 |
$extstate = is_ext_avail($extnum); |
|---|
| 410 |
if ($extstate == 1) { |
|---|
| 411 |
$AGI->set_variable('DIALSTATUS_CW','BUSY'); |
|---|
| 412 |
debug("Extension $extnum has call waiting enabled with state: $extstate",1); |
|---|
| 413 |
} |
|---|
| 414 |
// get ExtensionState: 0-idle; 1-busy; 4-unavail; 8-ringing <--- these are unconfirmed |
|---|
| 415 |
} elseif ( ($exthascw == 1) && ($rgmethod == 'firstnotonphone') ) { |
|---|
| 416 |
$extstate = is_ext_avail($extnum); |
|---|
| 417 |
debug("Extension $extnum has ExtensionState: $extstate",1); |
|---|
| 418 |
// CW in use - but blocked for hunt |
|---|
| 419 |
if ($extstate == 1) { |
|---|
| 420 |
debug("Extension $extnum has call waiting enabled but blocked for hunt",1); |
|---|
| 421 |
$extnum = ''; |
|---|
| 422 |
$AGI->set_variable('DIALSTATUS','BUSY'); |
|---|
| 423 |
} |
|---|
| 424 |
} |
|---|
| 425 |
} |
|---|
| 426 |
|
|---|
| 427 |
if ($extnum != '') { |
|---|
| 428 |
// Still got an extension to be called? |
|---|
| 429 |
// check if we already have a dial string for this extension |
|---|
| 430 |
// if so, ignore it as it's pointless ringing it twice ! |
|---|
| 431 |
$realext = str_replace("#", "", $extnum); |
|---|
| 432 |
if ( isset($dsarray[$realext]) ) { |
|---|
| 433 |
debug("Extension '$realext' already in the dialstring, ignoring duplicate",1); |
|---|
| 434 |
} else { |
|---|
| 435 |
$dsarray[$realext] = 1; // could be dial string i suppose but currently only using for duplicate check |
|---|
| 436 |
$extds = get_dial_string( $AGI, $extnum, $use_confirmation, $ringgroup_index); |
|---|
| 437 |
if (strlen($extds)) { |
|---|
| 438 |
$ds .= $extds . '&'; |
|---|
| 439 |
} |
|---|
| 440 |
// Update Caller ID for calltrace application |
|---|
| 441 |
if ((strpos($k,"#")==0) && (($rgmethod != "hunt") && ($rgmethod != "memoryhunt") && ($rgmethod != "firstavailable") && ($rgmethod != "firstnotonphone")) ) { |
|---|
| 442 |
if ( isset($cidnum) && is_numeric($cidnum) ) { |
|---|
| 443 |
$rc = $AGI->database_put('CALLTRACE', $k, $cidnum); |
|---|
| 444 |
if ($rc['result'] == 1) { |
|---|
| 445 |
debug("dbset CALLTRACE/$k to $cidnum", 3); |
|---|
| 446 |
} else { |
|---|
| 447 |
debug("Failed to DbSet CALLTRACE/$k to $cidnum ({$rc['result']})", 1); |
|---|
| 448 |
} |
|---|
| 449 |
} else { |
|---|
| 450 |
// We don't care about retval, this key may not exist |
|---|
| 451 |
$AGI->database_del('CALLTRACE', $k); |
|---|
| 452 |
debug("DbDel CALLTRACE/$k - Caller ID is not defined", 3); |
|---|
| 453 |
} |
|---|
| 454 |
} else { |
|---|
| 455 |
$ext_hunt[$k]=$extds; // Need to have the extension HASH set with technology for hunt group ring |
|---|
| 456 |
} |
|---|
| 457 |
} |
|---|
| 458 |
} |
|---|
| 459 |
} // end foreach ( $ext as $k ) |
|---|
| 460 |
|
|---|
| 461 |
$dial_filtered = implode('-',array_keys($dsarray)); |
|---|
| 462 |
$AGI->set_variable('FILTERED_DIAL',$dial_filtered); |
|---|
| 463 |
debug("Filtered ARG3: $dial_filtered", 3); |
|---|
| 464 |
|
|---|
| 465 |
$dshunt = ''; |
|---|
| 466 |
$loops = 0; |
|---|
| 467 |
$myhuntmember = ""; |
|---|
| 468 |
|
|---|
| 469 |
/** Here we setup the Channel Variables that are used to do the dialing, in all cases you will have: |
|---|
| 470 |
* ${HuntMembers} set to the number of phones to ring |
|---|
| 471 |
* ${HuntMemberN} set to the dial pattern that should be dialed. (N is 0, 1, 2 etc.) |
|---|
| 472 |
*/ |
|---|
| 473 |
if (($rgmethod == "hunt") || ($rgmethod == "memoryhunt") || ($rgmethod == "firstavailable") || ($rgmethod == "firstnotonphone")) { |
|---|
| 474 |
if ($cidnum) { |
|---|
| 475 |
$AGI->set_variable('CALLTRACE_HUNT',$cidnum); |
|---|
| 476 |
} |
|---|
| 477 |
foreach ($extarray as $k ) { |
|---|
| 478 |
// we loop through the original array to get the extensions in order of importance |
|---|
| 479 |
if ($ext_hunt[$k]) { |
|---|
| 480 |
//If the original array is included in the extension hash then set variables |
|---|
| 481 |
$myhuntmember="HuntMember"."$loops"; |
|---|
| 482 |
if (($rgmethod == "hunt") || ($rgmethod == "firstavailable") || ($rgmethod == "firstnotonphone")) { |
|---|
| 483 |
$AGI->set_variable($myhuntmember,$ext_hunt[$k]); |
|---|
| 484 |
} elseif ($rgmethod == "memoryhunt") { |
|---|
| 485 |
if ($loops==0) { |
|---|
| 486 |
$dshunt =$ext_hunt[$k]; |
|---|
| 487 |
} else { |
|---|
| 488 |
$dshunt .='&'.$ext_hunt[$k]; |
|---|
| 489 |
} |
|---|
| 490 |
$AGI->set_variable($myhuntmember,$dshunt); |
|---|
| 491 |
} |
|---|
| 492 |
$loops += 1; |
|---|
| 493 |
} |
|---|
| 494 |
} |
|---|
| 495 |
} |
|---|
| 496 |
|
|---|
| 497 |
$ds = chop($ds," &"); |
|---|
| 498 |
|
|---|
| 499 |
if ($nodest != '' && $use_confirmation == 'FALSE') { |
|---|
| 500 |
if (strpos($dialopts,"M(auto-blkvm)") > 0 || strpos($dialopts,"M(auto-blkvm)") === 0 || |
|---|
| 501 |
strpos($dialopts,"M(auto-confirm") > 0 || strpos($dialopts,"M(auto-confirm") === 0 || |
|---|
| 502 |
strpos($dialopts,"M(confirm") > 0 || strpos($dialopts,"M(confirm") === 0) { |
|---|
| 503 |
debug("NODEST: $nodest blkvm enabled macro already in dialopts: $dialopts",4); |
|---|
| 504 |
} else { |
|---|
| 505 |
$dialopts .= "M(auto-blkvm)"; |
|---|
| 506 |
debug("NODEST: $nodest adding M(auto-blkvm) to dialopts: $dialopts",4); |
|---|
| 507 |
} |
|---|
| 508 |
} |
|---|
| 509 |
|
|---|
| 510 |
// FollowMe Changes: |
|---|
| 511 |
// |
|---|
| 512 |
// We need to determine if the generated dialstring can be dialed as is. This will be the case if there are no |
|---|
| 513 |
// or is only a single extension to dial. |
|---|
| 514 |
// |
|---|
| 515 |
// First, unset any blank fields so we know how many extensions there are to call. |
|---|
| 516 |
// |
|---|
| 517 |
// If mastermode (skipremaining == 1) was triggered then we just set the ringtime to what the primary extension |
|---|
| 518 |
// should ring for and let this dialstring go. |
|---|
| 519 |
// |
|---|
| 520 |
// If there is only one extension in the list, then we need to determine how long to ring it (depending on if it |
|---|
| 521 |
// was the primary or another extension, then let the generated dialstring ring it. |
|---|
| 522 |
// |
|---|
| 523 |
// Otherwise, we need to re-create the dialstring to be processed by our special dialplan that will ring the |
|---|
| 524 |
// primary extension and hold the group list for the required delay. Also - if we are in a call confirmation mode |
|---|
| 525 |
// then we need to reset the call confirm variables with one level of inheritance so that they remain in the new |
|---|
| 526 |
// channels but don't get further propogated after that. We also clear it for the remainder of this instance since |
|---|
| 527 |
// we are not yet triggering further actions until the next call. |
|---|
| 528 |
// |
|---|
| 529 |
// Notes: $fmgrp_primaryremoved is set to 1 if the primary has been removed from the list so we know that it was dnd-ed. |
|---|
| 530 |
// this only matters in non-prim mode, where we need to know if the remaining list contains the primary extension |
|---|
| 531 |
// or not. |
|---|
| 532 |
// |
|---|
| 533 |
if ($rgmethod == 'ringallv2') { |
|---|
| 534 |
$count = 0; |
|---|
| 535 |
foreach ($ext as $x) { |
|---|
| 536 |
if ($x == '') { |
|---|
| 537 |
unset($ext[$count]); |
|---|
| 538 |
} |
|---|
| 539 |
$count++; |
|---|
| 540 |
} |
|---|
| 541 |
|
|---|
| 542 |
if (($skipremaining == 1) || (count($ext) == 1 && $fmgrp_primaryremoved == 0)) { |
|---|
| 543 |
$timer = $fmgrp_realprering; |
|---|
| 544 |
} elseif (count($ext) == 1 && $fmgrp_primaryremoved == 1) { |
|---|
| 545 |
$timer = $fmgrp_grptime; |
|---|
| 546 |
} elseif (count($ext) == 1) { |
|---|
| 547 |
$timer = $fmgrp_totalprering; // not sure what would trigger this ? |
|---|
| 548 |
} else { |
|---|
| 549 |
$timer = $fmgrp_totalprering; |
|---|
| 550 |
$ds = "Local/FMPR-".array_shift($ext)."@from-internal&Local/FMGL-".implode('-',$ext)."@from-internal"; |
|---|
| 551 |
|
|---|
| 552 |
$fmgrp_fmunique = $AGI->request['agi_channel']; |
|---|
| 553 |
$AGI->set_variable('_FMUNIQUE',$fmgrp_fmunique); |
|---|
| 554 |
$AGI->set_variable('_RingGroupMethod',"ringall"); |
|---|
| 555 |
$fmgrp_prering -= 2; |
|---|
| 556 |
$AGI->set_variable('_FMPRERING',$fmgrp_prering); |
|---|
| 557 |
$AGI->set_variable('_FMREALPRERING',$fmgrp_realprering); |
|---|
| 558 |
$AGI->set_variable('_FMGRPTIME',$fmgrp_grptime); |
|---|
| 559 |
$AGI->set_variable('_FMPRIME',($recall_mastermode == "ringallv2")?"FALSE":"TRUE"); |
|---|
| 560 |
|
|---|
| 561 |
debug("FMUNIQUE: $fmgrp_fmunique, FMRERING: $fmgrp_prering, FMREALPRERING: $fmgrp_realprering, FMGRPTIME: $fmgrp_grptime",6); |
|---|
| 562 |
|
|---|
| 563 |
if ($use_confirmation != 'FALSE') { |
|---|
| 564 |
$AGI->set_variable('_USE_CONFIRMATION',$use_confirmation); |
|---|
| 565 |
$AGI->set_variable('_RINGGROUP_INDEX',$ringgroup_index); |
|---|
| 566 |
$use_confirmation = 'FALSE'; |
|---|
| 567 |
} |
|---|
| 568 |
} |
|---|
| 569 |
} |
|---|
| 570 |
|
|---|
| 571 |
if ($nodest != '' && $use_confirmation == 'FALSE') { |
|---|
| 572 |
if (strpos($dialopts,"M(auto-blkvm)") > 0 || strpos($dialopts,"M(auto-blkvm)") === 0 || |
|---|
| 573 |
strpos($dialopts,"M(auto-confirm") > 0 || strpos($dialopts,"M(auto-confirm") === 0 || |
|---|
| 574 |
strpos($dialopts,"M(confirm") > 0 || strpos($dialopts,"M(confirm") === 0) { |
|---|
| 575 |
debug("NODEST: $nodest blkvm enabled macro already in dialopts: $dialopts",4); |
|---|
| 576 |
} else { |
|---|
| 577 |
$dialopts .= "M(auto-blkvm)"; |
|---|
| 578 |
debug("NODEST: $nodest adding M(auto-blkvm) to dialopts: $dialopts",4); |
|---|
| 579 |
} |
|---|
| 580 |
} |
|---|
| 581 |
|
|---|
| 582 |
if (!strlen($ds)) { |
|---|
| 583 |
$AGI->noop(''); |
|---|
| 584 |
} else { |
|---|
| 585 |
// Asterisk 1.6 uses , instead of | and 1.4 can't recieve a , in the ds. |
|---|
| 586 |
// |
|---|
| 587 |
if (version_compare($ast_version, "1.6", "ge")) { |
|---|
| 588 |
$ds_seperator = ','; |
|---|
| 589 |
} else { |
|---|
| 590 |
$ds_seperator = '|'; |
|---|
| 591 |
} |
|---|
| 592 |
|
|---|
| 593 |
if (($rgmethod == "hunt") || ($rgmethod == "memoryhunt") || ($rgmethod == "firstavailable") || ($rgmethod == "firstnotonphone")) { |
|---|
| 594 |
$ds = $ds_seperator; |
|---|
| 595 |
if ($timer) { |
|---|
| 596 |
$ds .= $timer; |
|---|
| 597 |
} |
|---|
| 598 |
$ds .= $ds_seperator . $dialopts; // pound to transfer, provide ringing |
|---|
| 599 |
$AGI->set_variable('ds',$ds); |
|---|
| 600 |
$AGI->set_variable("HuntMembers",$loops); |
|---|
| 601 |
$AGI->set_priority("huntdial"); // dial command was at priority 20 where dialplan handles calling a ringgroup with strategy of "hunt" or "MemoryHunt" |
|---|
| 602 |
} else { |
|---|
| 603 |
$ds .= $ds_seperator; |
|---|
| 604 |
if ($timer) { |
|---|
| 605 |
$ds .= $timer; |
|---|
| 606 |
if (trim($use_confirmation) != "FALSE") { |
|---|
| 607 |
$AGI->set_variable('__RT',$timer); |
|---|
| 608 |
} |
|---|
| 609 |
} |
|---|
| 610 |
$ds .= $ds_seperator . $dialopts; // pound to transfer, provide ringing |
|---|
| 611 |
if (trim($use_confirmation) != "FALSE") { |
|---|
| 612 |
$AGI->set_variable('__RG_IDX',$ringgroup_index); |
|---|
| 613 |
if ( isset($cidnum) && is_numeric($cidnum) ) { |
|---|
| 614 |
$AGI->set_variable('__CALLCONFIRMCID',$cidnum); |
|---|
| 615 |
} else { |
|---|
| 616 |
$AGI->set_variable('__CALLCONFIRMCID',"999"); |
|---|
| 617 |
} |
|---|
| 618 |
} |
|---|
| 619 |
$AGI->set_variable('ds',$ds); |
|---|
| 620 |
$AGI->set_priority("normdial"); // dial command was at priority 10 |
|---|
| 621 |
} |
|---|
| 622 |
} |
|---|
| 623 |
|
|---|
| 624 |
// sanity check make sure dialstatus is set to something |
|---|
| 625 |
// |
|---|
| 626 |
if (! $ds) { |
|---|
| 627 |
$dialstatus = get_var( $AGI, "DIALSTATUS" ); |
|---|
| 628 |
if (! $dialstatus) { |
|---|
| 629 |
debug("Setting default NOANSWER DIALSTATUS since no extensions available",1); |
|---|
| 630 |
$AGI->set_variable('DIALSTATUS','NOANSWER'); |
|---|
| 631 |
} |
|---|
| 632 |
} |
|---|
| 633 |
|
|---|
| 634 |
$astman->disconnect(); |
|---|
| 635 |
|
|---|
| 636 |
// EOF dialparties.agi |
|---|
| 637 |
exit( 0 ); |
|---|
| 638 |
|
|---|
| 639 |
// helper functions |
|---|
| 640 |
function get_var( $agi, $value) { |
|---|
| 641 |
$r = $agi->get_variable( $value ); |
|---|
| 642 |
|
|---|
| 643 |
if ($r['result'] == 1) { |
|---|
| 644 |
$result = $r['data']; |
|---|
| 645 |
return $result; |
|---|
| 646 |
} |
|---|
| 647 |
return ''; |
|---|
| 648 |
} |
|---|
| 649 |
|
|---|
| 650 |
function get_dial_string( $agi, $extnum, $use_confirmation, $ringgroup_index ) { |
|---|
| 651 |
$dialstring = ''; |
|---|
| 652 |
|
|---|
| 653 |
if (strpos($extnum,'#') != 0) { |
|---|
| 654 |
// "#" used to identify external numbers in forwards and callgourps |
|---|
| 655 |
// If using call confirmation, need to put the # back into the new dialstring |
|---|
| 656 |
// we then place all external calls (denoted with a # at the end) through |
|---|
| 657 |
// the [grps] extension for the RINGGROUP_INDEX that was called. This |
|---|
| 658 |
// triggers the call confirmation macro along with the required messages |
|---|
| 659 |
// that were set. |
|---|
| 660 |
// |
|---|
| 661 |
$extnum = str_replace("#", "", $extnum); |
|---|
| 662 |
if (trim($use_confirmation) == "FALSE") { |
|---|
| 663 |
$dialstring = 'Local/'.$extnum.'@from-internal/n'; |
|---|
| 664 |
} else { |
|---|
| 665 |
$dialstring = 'Local/RG-'.$ringgroup_index.'-'.$extnum.'#@from-internal'; |
|---|
| 666 |
} |
|---|
| 667 |
debug("Built External dialstring component for $extnum: $dialstring", 4); |
|---|
| 668 |
} else { |
|---|
| 669 |
$device_str = sprintf("%s/device", $extnum); |
|---|
| 670 |
$device = $agi->database_get('AMPUSER',$device_str); |
|---|
| 671 |
$device = $device['data']; |
|---|
| 672 |
|
|---|
| 673 |
// a user can be logged into multipe devices, append the dial string for each |
|---|
| 674 |
$device_array = split( '&', $device ); |
|---|
| 675 |
foreach ($device_array as $adevice) { |
|---|
| 676 |
if (trim($use_confirmation) == "FALSE") { |
|---|
| 677 |
$dds = $agi->database_get('DEVICE',$adevice.'/dial'); |
|---|
| 678 |
$dialstring .= $dds['data']; |
|---|
| 679 |
$dialstring .= '&'; |
|---|
| 680 |
} else { |
|---|
| 681 |
$dialstring .= 'Local/LC-'.$adevice.'@from-internal&'; |
|---|
| 682 |
} |
|---|
| 683 |
} |
|---|
| 684 |
$dialstring = trim($dialstring," &"); |
|---|
| 685 |
} |
|---|
| 686 |
return $dialstring; |
|---|
| 687 |
} |
|---|
| 688 |
|
|---|
| 689 |
function debug($string, $level=3) { |
|---|
| 690 |
global $AGI; |
|---|
| 691 |
$AGI->verbose($string, $level); |
|---|
| 692 |
} |
|---|
| 693 |
|
|---|
| 694 |
function mycallback( $rc ) { |
|---|
| 695 |
debug("User hung up. (rc=" . $rc . ")", 1); |
|---|
| 696 |
exit ($rc); |
|---|
| 697 |
} |
|---|
| 698 |
|
|---|
| 699 |
function is_ext_avail( $extnum ) { |
|---|
| 700 |
global $astman; |
|---|
| 701 |
|
|---|
| 702 |
$status = $astman->ExtensionState( $extnum, 'from-internal' ); |
|---|
| 703 |
|
|---|
| 704 |
$status = $status['Status']; |
|---|
| 705 |
debug("ExtensionState: $status", 4); |
|---|
| 706 |
return $status; |
|---|
| 707 |
} |
|---|
| 708 |
|
|---|
| 709 |
?> |
|---|