root/modules/branches/2.6/core/functions.inc.php

Revision 8263, 248.5 kB (checked in by p_lindheimer, 4 years ago)

fixes #3700 use user's voicemail settings if defined to determine if stardard vm instructions should be played, otherwise use general settings defaults

  • Property svn:mime-type set to text/plain
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 <?php
2 //This file is part of FreePBX.
3 //
4 //    FreePBX is free software: you can redistribute it and/or modify
5 //    it under the terms of the GNU General Public License as published by
6 //    the Free Software Foundation, either version 2 of the License, or
7 //    (at your option) any later version.
8 //
9 //    FreePBX 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 //    You should have received a copy of the GNU General Public License
15 //    along with FreePBX.  If not, see <http://www.gnu.org/licenses/>.
16 //
17 //    Copyright (C) 2004 Coalescent Systems Inc. (info@coalescentsystems.ca)
18 //
19 class core_conf {
20   var $_sip_general    = array();
21   var $_iax_general    = array();
22   var $_featuregeneral = array();
23   var $_featuremap     = array();
24   var $_applicationmap = array();
25   // return an array of filenames to write
26   function get_filename() {
27     global $chan_dahdi;
28    
29     $files = array(
30       'sip_additional.conf',
31       'sip_registrations.conf',
32       'iax_additional.conf',
33       'iax_registrations.conf',
34       'sip_general_additional.conf',
35       'iax_general_additional.conf',
36       'features_general_additional.conf',
37       'features_applicationmap_additional.conf',
38       'features_featuremap_additional.conf',
39       'localprefixes.conf',
40     );
41
42     if ($chan_dahdi) {
43       $files[] =  'chan_dahdi_additional.conf';
44     } else {
45       $files[] =  'zapata_additional.conf';
46     }
47
48     return $files;
49   }
50  
51   // return the output that goes in each of the files
52   function generateConf($file) {
53     global $version;
54
55     switch ($file) {
56       case 'sip_general_additional.conf':
57         return $this->generate_sip_general_additional($version);
58         break;
59       case 'sip_additional.conf':
60         return $this->generate_sip_additional($version);
61         break;
62       case 'sip_registrations.conf':
63         return $this->generate_sip_registrations($version);
64         break;
65       case 'iax_general_additional.conf':
66         return $this->generate_iax_general_additional($version);
67         break;
68       case 'iax_additional.conf':
69         return $this->generate_iax_additional($version);
70         break;
71       case 'iax_registrations.conf':
72         return $this->generate_iax_registrations($version);
73         break;
74       case 'chan_dahdi_additional.conf':
75         return $this->generate_zapata_additional($version);
76         break;
77       case 'zapata_additional.conf':
78         return $this->generate_zapata_additional($version);
79         break;
80       case 'features_general_additional.conf':
81         return $this->generate_featuregeneral_additional($version);
82         break;
83       case 'features_applicationmap_additional.conf':
84         return $this->generate_applicationmap_additional($version);
85         break;
86       case 'features_featuremap_additional.conf':
87         return $this->generate_featuremap_additional($version);
88         break;
89       case 'localprefixes.conf':
90         return $this->generate_localprefixes($version);
91         break;
92     }
93   }
94
95   function addSipGeneral($key, $value) {
96     $this->_sip_general[] = array('key' => $key, 'value' => $value);
97   }
98
99   function generate_sip_general_additional($ast_version) {
100     $output = '';
101
102     if (isset($this->_sip_general) && is_array($this->_sip_general)) {
103       foreach ($this->_sip_general as $values) {
104         $output .= $values['key']."=".$values['value']."\n";
105       }
106     }
107     return $output;
108   }
109
110   function addIaxGeneral($key, $value) {
111     $this->_iax_general[] = array('key' => $key, 'value' => $value);
112   }
113
114   function generate_iax_general_additional($ast_version) {
115     $output = '';
116
117     if (isset($this->_iax_general) && is_array($this->_iax_general)) {
118       foreach ($this->_iax_general as $values) {
119         $output .= $values['key']."=".$values['value']."\n";
120       }
121     }
122     return $output;
123   }
124
125   function addFeatureGeneral($key, $value) {
126     $this->_featuregeneral[] = array('key' => $key, 'value' => $value);
127   }
128
129   function generate_featuregeneral_additional($ast_version) {
130     $output = '';
131
132     if (isset($this->_featuregeneral) && is_array($this->_featuregeneral)) {
133       foreach ($this->_featuregeneral as $values) {
134         $output .= $values['key']."=".$values['value']."\n";
135       }
136     }
137     return $output;
138   }
139
140   function addFeatureMap($key, $value) {
141     $this->_featuremap[] = array('key' => $key, 'value' => $value);
142   }
143
144   function generate_featuremap_additional($ast_version) {
145     $output = '';
146
147     if (isset($this->_featuremap) && is_array($this->_featuremap)) {
148       foreach ($this->_featuremap as $values) {
149         $output .= $values['key']."=".$values['value']."\n";
150       }
151     }
152     return $output;
153   }
154
155   function addApplicationMap($key, $value) {
156     $this->_applicationmap[] = array('key' => $key, 'value' => $value);
157   }
158
159   function generate_applicationmap_additional($ast_version) {
160     $output = '';
161
162     if (isset($this->_applicationmap) && is_array($this->_applicationmap)) {
163       foreach ($this->_applicationmap as $values) {
164         $output .= $values['key']."=".$values['value']."\n";
165       }
166     }
167     return $output;
168   }
169
170   function generate_sip_additional($ast_version) {
171     global $db;
172
173     $table_name = "sip";
174     $additional = "";
175     $output = "";
176
177     // Asterisk 1.4 requires call-limit be set for hints to work properly
178     //
179     if (version_compare($ast_version, "1.4", "ge")) {
180       $call_limit = "call-limit=50\n";
181       $ver12 = false;
182     } else {
183       $call_limit = "";
184       $ver12 = true;
185     }
186
187     $sql = "SELECT keyword,data from $table_name where id=-1 and keyword <> 'account' and flags <> 1";
188     $results = $db->getAll($sql, DB_FETCHMODE_ASSOC);
189     if(DB::IsError($results)) {
190       die($results->getMessage());
191     }
192     foreach ($results as $result) {
193       if ($ver12) {
194         $additional .= $result['keyword']."=".$result['data']."\n";
195       } else {
196         $option = $result['data'];
197         switch (strtolower($result['keyword'])) {
198           case 'insecure':
199             if ($option == 'very')
200               $additional .= "insecure=port,invite\n";
201             else if ($option == 'yes')
202               $additional .= "insecure=port\n";
203             else
204               $additional .= $result['keyword']."=$option\n";
205             break;
206           case 'allow':
207           case 'disallow':
208             if ($option != '')
209               $additional .= $result['keyword']."=$option\n";
210             break;
211           default:
212             $additional .= $result['keyword']."=$option\n";
213         }
214       }
215     }
216
217     $sql = "SELECT data,id from $table_name where keyword='account' and flags <> 1 group by data";
218     $results = $db->getAll($sql, DB_FETCHMODE_ASSOC);
219     if(DB::IsError($results)) {
220       die($results->getMessage());
221     }
222
223     foreach ($results as $result) {
224       $account = $result['data'];
225       $id = $result['id'];
226       $output .= "[$account]\n";
227  
228       $sql = "SELECT keyword,data from $table_name where id='$id' and keyword <> 'account' and flags <> 1 order by flags, keyword DESC";
229       $results2_pre = $db->getAll($sql, DB_FETCHMODE_ASSOC);
230       if(DB::IsError($results2_pre)) {
231         die($results2->getMessage());
232       }
233
234       // Move all 'disallow=all' and 'deny' to the top to avoid errors
235       //
236       $results2 = array();
237       foreach ($results2_pre as $element) {
238         if (strtolower(trim($element['keyword'])) != 'secret') {
239           $options = explode("&", $element['data']);
240           foreach ($options as $option) {
241             if (($element['keyword'] == 'disallow' && $option == 'all') | ($element['keyword'] == 'deny')) {
242               array_unshift($results2,array('keyword'=>$element['keyword'],'data'=>$option));
243             } else {
244               $results2[] = array('keyword'=>$element['keyword'],'data'=>$option);
245             }
246           }
247         } else {
248           $results2[] = array('keyword'=>$element['keyword'],'data'=>$element['data']);
249         }
250       }
251       unset($results2_pre);
252
253       $context='';
254       foreach ($results2 as $result2) {
255         $option = strtolower($result2['data']);
256         if ($ver12) {
257           switch (strtolower($result2['keyword'])) {
258             case 'context':
259               $context = $option;
260               //fall-through
261             default:
262               $output .= $result2['keyword']."=".$result2['data']."\n";
263           }
264         } else {
265           switch (strtolower($result2['keyword'])) {
266             case 'insecure':
267               if ($option == 'very')
268                 $output .= "insecure=port,invite\n";
269               else if ($option == 'yes')
270                 $output .= "insecure=port\n";
271               else
272                 $output .= $result2['keyword']."=".$result2['data']."\n";
273               break;
274             case 'allow':
275             case 'disallow':
276               if ($option != '')
277                 $output .= $result2['keyword']."=".$result2['data']."\n";
278               break;
279             case 'record_in':
280             case 'record_out':
281               break;
282             case 'context':
283               $context = $result2['data'];
284               //fall-through
285             default:
286               $output .= $result2['keyword']."=".$result2['data']."\n";
287           }
288         }
289       }
290       switch (substr($id,0,8)) {
291         case 'tr-peer-':
292           if ($context == '') {
293             $output .= "context=from-trunk-sip-$account\n";
294           }
295           break;
296         case 'tr-user-':
297           if ($context == '') {
298             $tn = substr($id, 8);
299             // this is a 'user' trunk, we need to get the name of the corresponding 'peer'
300             // trunk so we can set the context appropriately for the group count
301             //
302             $td = core_trunks_getDetails($tn);
303             if (isset($td['channelid'])) {
304               $output .= "context=from-trunk-sip-".$td['channelid']."\n";
305             }
306           }
307           break;
308         default:
309           if ($call_limit) {
310             $output .= $call_limit;
311           }
312       }
313       $output .= $additional."\n";
314     }
315     return $output;
316   }
317
318   function generate_sip_registrations($ast_version) {
319     global $db;
320
321     $table_name = "sip";
322     $output = "";
323
324     $sql = "SELECT keyword,data FROM $table_name WHERE `id` LIKE 'tr-reg-%' AND keyword <> 'account' AND flags <> 1";
325     $results = $db->getAll($sql, DB_FETCHMODE_ASSOC);
326     if(DB::IsError($results)) {
327       die($results->getMessage());
328     }
329
330     foreach ($results as $result) {
331       $output .= $result['keyword']."=".$result['data']."\n";
332     }
333
334     return $output;
335   }
336
337   function generate_iax_additional($ast_version) {
338     global $db;
339
340     $table_name = "iax";
341     $additional = "";
342     $output = "";
343
344     $ver12 = version_compare($ast_version, '1.4', 'lt');
345
346     $sql = "SELECT keyword,data from $table_name where id=-1 and keyword <> 'account' and flags <> 1";
347     $results = $db->getAll($sql, DB_FETCHMODE_ASSOC);
348     if(DB::IsError($results)) {
349       die($results->getMessage());
350     }
351     foreach ($results as $result) {
352       if ($ver12) {
353         $additional .= $result['keyword']."=".$result['data']."\n";
354       } else {
355         $option = $result['data'];
356         switch ($result['keyword']) {
357           case 'notransfer':
358             if (strtolower($option) == 'yes') {
359               $additional .= "transfer=no\n";
360             } else if (strtolower($option) == 'no') {
361               $additional .= "transfer=yes\n";
362             } else if (strtolower($option) == 'mediaonly') {
363               $additional .= "transfer=mediaonly\n";
364             } else {
365               $additional .= $result['keyword']."=$option\n";
366             }
367             break;
368           case 'allow':
369           case 'disallow':
370             if ($option != '')
371               $additional .= $result['keyword']."=$option\n";
372             break;
373           default:
374             $additional .= $result['keyword']."=$option\n";
375         }
376       }
377     }
378
379     $sql = "SELECT data,id from $table_name where keyword='account' and flags <> 1 group by data";
380     $results = $db->getAll($sql, DB_FETCHMODE_ASSOC);
381     if(DB::IsError($results)) {
382       die($results->getMessage());
383     }
384    
385     foreach ($results as $result) {
386       $account = $result['data'];
387       $id = $result['id'];
388       $output .= "[$account]\n";
389  
390       $sql = "SELECT keyword,data from $table_name where id='$id' and keyword <> 'account' and flags <> 1 order by flags, keyword DESC";
391       $results2_pre = $db->getAll($sql, DB_FETCHMODE_ASSOC);
392       if(DB::IsError($results2)) {
393         die($results2_pre->getMessage());
394       }
395
396       // Move all 'disallow=all' and 'deny=' to the top to avoid errors
397       //
398       $results2 = array();
399       foreach ($results2_pre as $element) {
400         if (strtolower(trim($element['keyword'])) != 'secret') {
401           $options = explode("&", $element['data']);
402           foreach ($options as $option) {
403             if (($element['keyword'] == 'disallow' && $option == 'all') | ($element['keyword'] == 'deny')) {
404               array_unshift($results2,array('keyword'=>$element['keyword'],'data'=>$option));
405             } else {
406               $results2[] = array('keyword'=>$element['keyword'],'data'=>$option);
407             }
408           }
409         } else {
410           $results2[] = array('keyword'=>$element['keyword'],'data'=>$element['data']);
411         }
412       }
413       unset($results2_pre);
414
415       $context='';
416       foreach ($results2 as $result2) {
417         $option = strtolower($result2['data']);
418         if ($ver12) {
419           switch (strtolower($result2['keyword'])) {
420             case 'context':
421               $context = $result2['data'];
422               //fall-through
423             default:
424               $output .= $result2['keyword']."=".$result2['data']."\n";
425           }
426         } else {
427           switch ($result2['keyword']) {
428             case 'notransfer':
429               if (strtolower($option) == 'yes') {
430                 $output .= "transfer=no\n";
431               } else if (strtolower($option) == 'no') {
432                 $output .= "transfer=yes\n";
433               } else if (strtolower($option) == 'mediaonly') {
434                 $output .= "transfer=mediaonly\n";
435               } else {
436                 $output .= $result2['keyword']."=".$result2['data']."\n";
437               }
438               break;
439             case 'allow':
440             case 'disallow':
441               if ($option != '')
442                 $output .= $result2['keyword']."=".$result2['data']."\n";
443               break;
444             case 'record_in':
445             case 'record_out':
446               break;
447             case 'context':
448               $context = $option;
449               //fall-through
450             default:
451               $output .= $result2['keyword']."=".$result2['data']."\n";
452           }
453         }
454       }
455       switch (substr($id,0,8)) {
456         case 'tr-peer-':
457           if ($context == '') {
458             $output .= "context=from-trunk-iax2-$account\n";
459           }
460           break;
461         case 'tr-user-':
462           if ($context == '') {
463             $tn = substr($id, 8);
464             // this is a 'user' trunk, we need to get the name of the corresponding 'peer'
465             // trunk so we can set the context appropriately for the group count
466             //
467             $td = core_trunks_getDetails($tn);
468             if (isset($td['channelid'])) {
469               $output .= "context=from-trunk-iax2-".$td['channelid']."\n";
470             }
471           }
472           break;
473         default:
474           if ($call_limit) {
475             $output .= $call_limit;
476           }
477       }
478       $output .= $additional."\n";
479     }
480     return $output;
481   }
482
483   function generate_iax_registrations($ast_version) {
484     global $db;
485
486     $table_name = "iax";
487     $output = "";
488
489     $sql = "SELECT keyword,data FROM $table_name WHERE `id` LIKE 'tr-reg-%' AND keyword <> 'account' AND flags <> 1";
490     $results = $db->getAll($sql, DB_FETCHMODE_ASSOC);
491     if(DB::IsError($results)) {
492       die($results->getMessage());
493     }
494
495     foreach ($results as $result) {
496       $output .= $result['keyword']."=".$result['data']."\n";
497     }
498
499     return $output;
500   }
501
502   function generate_zapata_additional($ast_version) {
503     global $db;
504
505     $table_name = "zap";
506
507     $additional = "";
508     $output = '';
509
510     $sql = "SELECT keyword,data from $table_name where id=-1 and keyword <> 'account' and flags <> 1";
511     $results = $db->getAll($sql, DB_FETCHMODE_ASSOC);
512     if(DB::IsError($results)) {
513       die($results->getMessage());
514     }
515     foreach ($results as $result) {
516       $additional .= $result['keyword']."=".$result['data']."\n";
517     }
518
519     $sql = "SELECT data,id from $table_name where keyword='account' and flags <> 1 group by data";
520     $results = $db->getAll($sql, DB_FETCHMODE_ASSOC);
521     if(DB::IsError($results)) {
522       die($results->getMessage());
523     }
524
525     foreach ($results as $result) {
526       $account = $result['data'];
527       $id = $result['id'];
528       $output .= ";;;;;;[$account]\n";
529  
530       $sql = "SELECT keyword,data from $table_name where id=$id and keyword <> 'account' and flags <> 1 order by keyword DESC";
531       $results2 = $db->getAll($sql, DB_FETCHMODE_ASSOC);
532       if(DB::IsError($results2)) {
533         die($results2->getMessage());
534       }
535       $zapchannel="";
536       foreach ($results2 as $result2) {
537         switch ($result2['keyword']) {
538           case 'channel':
539             $zapchannel = $result2['data'];
540             break;
541
542           // These are not zapata.conf variables so keep out of file
543           case 'record_out':
544           case 'record_in':
545           case 'dial':
546             break;
547           default:
548             $output .= $result2['keyword']."=".$result2['data']."\n";
549         }
550       }
551       $output .= "channel=>$zapchannel\n";
552       $output .= $additional."\n";
553     }
554     return $output;
555   }
556   function generate_localprefixes($ast_version) {
557     $output = "";
558
559     $conf =  core_trunks_readDialRulesFile();
560     foreach ($conf as $section=>$values) {
561       $output .=  "[".$section."]\n";
562       foreach ($values as $key=>$value) {
563         $output .= $key."=".$value."\n";
564       }
565       $output .= "\n";
566     }
567     return $output;
568   }
569 }
570
571 // The destinations this module provides
572 // returns a associative arrays with keys 'destination' and 'description'
573 function core_destinations() {
574   //static destinations
575   $extens = array();
576   $category = _("Terminate Call");
577   $extens[] = array('destination' => 'app-blackhole,hangup,1', 'description' => _("Hangup"), 'category' => $category);
578   $extens[] = array('destination' => 'app-blackhole,congestion,1', 'description' => _("Congestion"), 'category' => $category);
579   $extens[] = array('destination' => 'app-blackhole,busy,1', 'description' => _("Busy"), 'category' => $category);
580   $extens[] = array('destination' => 'app-blackhole,zapateller,1', 'description' => _("Play SIT Tone (Zapateller)"), 'category' => $category);
581   $extens[] = array('destination' => 'app-blackhole,musiconhold,1', 'description' => _("Put caller on hold forever"), 'category' => $category);
582   $extens[] = array('destination' => 'app-blackhole,ring,1', 'description' => _("Play ringtones to caller until they hangup"), 'category' => $category);
583  
584   //get the list of meetmes
585   $results = core_users_list();
586  
587   if (isset($results) && function_exists('voicemail_getVoicemail')) {
588     //get voicemail
589     $uservm = voicemail_getVoicemail();
590     $vmcontexts = array_keys($uservm);
591     foreach ($results as $thisext) {
592       $extnum = $thisext[0];
593       // search vm contexts for this extensions mailbox
594       foreach ($vmcontexts as $vmcontext) {
595         if(isset($uservm[$vmcontext][$extnum])){
596           //$vmname = $uservm[$vmcontext][$extnum]['name'];
597           //$vmboxes[$extnum] = array($extnum, '"' . $vmname . '" <' . $extnum . '>');
598           $vmboxes[$extnum] = true;
599         }
600       }
601     }
602   }
603  
604   // return an associative array with destination and description
605   // core provides both users and voicemail boxes as destinations
606   if (isset($results)) {
607     foreach($results as $result) {
608       $extens[] = array('destination' => 'from-did-direct,'.$result['0'].',1', 'description' => ' <'.$result['0'].'> '.$result['1'], 'category' => 'Extensions');
609       if(isset($vmboxes[$result['0']])) {
610         $extens[] = array('destination' => 'ext-local,vmb'.$result['0'].',1', 'description' => '<'.$result[0].'> '.$result[1].' (busy)', 'category' => 'Voicemail');
611         $extens[] = array('destination' => 'ext-local,vmu'.$result['0'].',1', 'description' => '<'.$result[0].'> '.$result[1].' (unavail)', 'category' => 'Voicemail');
612         $extens[] = array('destination' => 'ext-local,vms'.$result['0'].',1', 'description' => '<'.$result[0].'> '.$result[1].' (no-msg)', 'category' => 'Voicemail');
613       }
614     }
615   }
616  
617   if (isset($extens))
618     return $extens;
619   else
620     return null;
621 }
622
623 function core_getdest($exten) {
624   $dests[] = 'from-did-direct,'.$exten.',1';
625   if (!function_exists('voicemail_mailbox_get')) {
626     return $dests;
627   }
628   $box = voicemail_mailbox_get($exten);
629   if ($box == null) {
630     return $dests;
631   }
632   $dests[] = 'ext-local,vmb'.$exten.',1';
633   $dests[] = 'ext-local,vmu'.$exten.',1';
634   $dests[] = 'ext-local,vms'.$exten.',1';
635
636   return $dests;
637 }
638
639 function core_getdestinfo($dest) {
640   global $active_modules;
641
642   // Check for Extension Number Destinations
643   //
644   if (substr(trim($dest),0,16) == 'from-did-direct,') {
645     $exten = explode(',',$dest);
646     $exten = $exten[1];
647     $thisexten = core_users_get($exten);
648     if (empty($thisexten)) {
649       return array();
650     } else {
651       //$type = isset($active_modules['announcement']['type'])?$active_modules['announcement']['type']:'setup';
652       $display = ($amp_conf['AMPEXTENSIONS'] == "deviceanduser")?'users':'extensions';
653       return array('description' => sprintf(_("User Extension %s: %s"),$exten,$thisexten['name']),
654                    'edit_url' => "config.php?type=setup&display=$display&extdisplay=".urlencode($exten)."&skip=0",
655                   );
656     }
657
658   // Check for voicemail box destinations
659   //
660   } else if (substr(trim($dest),0,12) == 'ext-local,vm') {
661     $exten = explode(',',$dest);
662     $exten = substr($exten[1],3);
663     if (!function_exists('voicemail_mailbox_get')) {
664       return array();
665     }
666     $thisexten = core_users_get($exten);
667     if (empty($thisexten)) {
668       return array();
669     }
670     $box = voicemail_mailbox_get($exten);
671     if ($box == null) {
672       return array();
673     }
674     $display = ($amp_conf['AMPEXTENSIONS'] == "deviceanduser")?'users':'extensions';
675     return array('description' => 'User Extension '.$exten.': '.$thisexten['name'],
676                  'edit_url' => "config.php?type=setup&display=$display&extdisplay=".urlencode($exten)."&skip=0",
677                 );
678
679   // Check for blackhole Termination Destinations
680   //
681   } else if (substr(trim($dest),0,14) == 'app-blackhole,') {
682     $exten = explode(',',$dest);
683     $exten = $exten[1];
684
685     switch ($exten) {
686       case 'hangup':
687         $description = 'Hangup';
688         break;
689       case 'congestion':
690         $description = 'Congestion';
691         break;
692       case 'busy':
693         $description = 'Busy';
694         break;
695       case 'zapateller':
696         $description = 'Play SIT Tone (Zapateller)';
697         break;
698       case 'musiconhold':
699         $description = 'Put caller on hold forever';
700         break;
701       case 'ring':
702         $description = 'Play ringtones to caller';
703         break;
704       default:
705         $description = false;
706     }
707     if ($description) {
708       return array('description' => 'Core: '.$description,
709                    'edit_url' => false,
710                    );
711     } else {
712       return array();
713     }
714
715   // None of the above, so not one of ours
716   //
717   } else {
718     return false;
719   }
720 }
721 /*  Generates dialplan for "core" components (extensions & inbound routing)
722   We call this with retrieve_conf
723 */
724 function core_get_config($engine) {
725   global $ext;  // is this the best way to pass this?
726   global $version;  // this is not the best way to pass this, this should be passetd together with $engine
727   global $engineinfo;
728   global $amp_conf;
729   global $core_conf;
730   global $chan_dahdi;
731   global $astman;;
732
733   $modulename = "core";
734  
735   switch($engine) {
736     case "asterisk":
737
738       $ast_ge_14 = version_compare($version, '1.4', 'ge');
739       $ast_lt_16 = version_compare($version, '1.6', 'lt');
740
741       // Now add to sip_general_addtional.conf
742       //
743       if (isset($core_conf) && is_a($core_conf, "core_conf")) {
744         $core_conf->addSipGeneral('disallow','all');
745         $core_conf->addSipGeneral('allow','ulaw');
746         $core_conf->addSipGeneral('allow','alaw');
747         $core_conf->addSipGeneral('context','from-sip-external');
748         $core_conf->addSipGeneral('callerid','Unknown');
749         $core_conf->addSipGeneral('notifyringing','yes');
750         if ($ast_ge_14) {
751           $core_conf->addSipGeneral('notifyhold','yes');
752           $core_conf->addSipGeneral('limitonpeers','yes');
753           $core_conf->addSipGeneral('tos_sip','cs3');    // Recommended setting from doc/ip-tos.txt
754           $core_conf->addSipGeneral('tos_audio','ef');   // Recommended setting from doc/ip-tos.txt
755           $core_conf->addSipGeneral('tos_video','af41'); // Recommended setting from doc/ip-tos.txt
756           $core_conf->addSipGeneral('alwaysauthreject','yes');
757         } else {
758           $core_conf->addSipGeneral('tos','0x68'); // This really doesn't do anything with astersk not running as root
759         }
760         $core_conf->addIaxGeneral('disallow','all');
761         $core_conf->addIaxGeneral('allow','ulaw');
762         $core_conf->addIaxGeneral('allow','alaw');
763         $core_conf->addIaxGeneral('allow','gsm');
764         $core_conf->addIaxGeneral('mailboxdetail','yes');
765         if ($ast_ge_14) {
766           $core_conf->addIaxGeneral('tos','ef'); // Recommended setting from doc/ip-tos.txt
767         }
768
769         $fcc = new featurecode($modulename, 'blindxfer');
770         $code = $fcc->getCodeActive();
771         unset($fcc);
772         if ($code != '') {
773           $core_conf->addFeatureMap('blindxfer',$code);
774         }
775
776         $fcc = new featurecode($modulename, 'atxfer');
777         $code = $fcc->getCodeActive();
778         unset($fcc);
779         if ($code != '') {
780           $core_conf->addFeatureMap('atxfer',$code);
781         }
782
783         $fcc = new featurecode($modulename, 'automon');
784         $code = $fcc->getCodeActive();
785         unset($fcc);
786         if ($code != '') {
787           $core_conf->addFeatureMap('automon',$code);
788         }
789
790         $fcc = new featurecode($modulename, 'disconnect');
791         $code = $fcc->getCodeActive();
792         unset($fcc);
793         if ($code != '') {
794           $core_conf->addFeatureMap('disconnect',$code);
795         }
796
797         $fcc = new featurecode($modulename, 'pickupexten');
798         $code = $fcc->getCodeActive();
799         unset($fcc);
800         if ($code != '') {
801           $core_conf->addFeatureGeneral('pickupexten',$code);
802         }
803       }
804
805       // FeatureCodes
806       $fcc = new featurecode($modulename, 'userlogon');
807       $fc_userlogon = $fcc->getCodeActive();
808       unset($fcc);
809
810       $fcc = new featurecode($modulename, 'userlogoff');
811       $fc_userlogoff = $fcc->getCodeActive();
812       unset($fcc);
813
814       $fcc = new featurecode($modulename, 'zapbarge');
815       $fc_zapbarge = $fcc->getCodeActive();
816       unset($fcc);
817
818       $fcc = new featurecode($modulename, 'chanspy');
819       $fc_chanspy = $fcc->getCodeActive();
820       unset($fcc);
821
822       $fcc = new featurecode($modulename, 'simu_pstn');
823       $fc_simu_pstn = $fcc->getCodeActive();
824       unset($fcc);
825
826       $fcc = new featurecode($modulename, 'simu_fax');
827       $fc_simu_fax = $fcc->getCodeActive();
828       unset($fcc);
829
830       $fcc = new featurecode($modulename, 'pickup');
831       $fc_pickup = $fcc->getCodeActive();
832       unset($fcc);
833
834       // Log on / off -- all in one context
835       if ($fc_userlogoff != '' || $fc_userlogon != '') {
836         $ext->addInclude('from-internal-additional', 'app-userlogonoff'); // Add the include from from-internal
837        
838         if ($fc_userlogoff != '') {
839           $ext->add('app-userlogonoff', $fc_userlogoff, '', new ext_macro('user-logoff'));
840           $ext->add('app-userlogonoff', $fc_userlogoff, 'hook_off', new ext_hangup(''));
841         }
842  
843         if ($fc_userlogon != '') {
844           $ext->add('app-userlogonoff', $fc_userlogon, '', new ext_macro('user-logon'));
845           $ext->add('app-userlogonoff', $fc_userlogon, 'hook_on_1', new ext_hangup(''));
846          
847           $clen = strlen($fc_userlogon);
848           $fc_userlogon = "_$fc_userlogon.";
849           $ext->add('app-userlogonoff', $fc_userlogon, '', new ext_macro('user-logon,${EXTEN:'.$clen.'}'));
850           $ext->add('app-userlogonoff', $fc_userlogon, 'hook_on_2', new ext_hangup(''));
851         }
852       }
853
854       // Call pickup using app_pickup - Note that '**xtn' is hard-coded into the GXPs and SNOMs as a number to dial
855       // when a user pushes a flashing BLF.
856       //
857       // We need to add ringgoups to this so that if an extension is part of a ringgroup, we can try to pickup that
858       // extension by trying the ringgoup which is what the pickup application is going to respond to.
859       //
860       // NOTICE: this may be confusing, we check if this is a BRI build of Asterisk and use dpickup instead of pickup
861       //         if it is. So we simply assign the varaible $ext_pickup which one it is, and use that variable when
862       //         creating all the extnesions below. So those are "$ext_pickup" on purpose!
863       //
864       if ($fc_pickup != '' && $ast_ge_14) {
865         $ext->addInclude('from-internal-additional', 'app-pickup');
866         $fclen = strlen($fc_pickup);
867         $ext_pickup = (strstr($engineinfo['raw'], 'BRI')) ? 'ext_dpickup' : 'ext_pickup';
868
869         $fcc = new featurecode('paging', 'intercom-prefix');
870         $intercom_code = $fcc->getCodeActive();
871         unset($fcc);
872
873         $picklist = '${EXTEN:'.$fclen.'}';
874         $picklist .= '&${EXTEN:'.$fclen.'}@ext-local';
875         $picklist .= '&${EXTEN:'.$fclen.'}@from-internal';
876         $picklist .= '&${EXTEN:'.$fclen.'}@from-internal-xfer';
877         $picklist .= '&${EXTEN:'.$fclen.'}@from-did-direct';
878         $picklist .= '&LC-${EXTEN:'.$fclen.'}@from-internal';
879         $picklist .= '&LC-${EXTEN:'.$fclen.'}@from-internal-xfer';
880         $picklist .= '&FMPR-${EXTEN:'.$fclen.'}@from-internal';
881         $picklist .= '&FMPR-${EXTEN:'.$fclen.'}@from-internal-xfer';
882         $picklist .= '&FMPR-${EXTEN:'.$fclen.'}@from-did-direct';
883
884         $ext->add('app-pickup', "_$fc_pickup.", '', new $ext_pickup($picklist));
885         $ext->add('app-pickup', "_$fc_pickup.", '', new ext_hangup(''));
886
887         if ($intercom_code != '') {
888           $len = strlen($fc_pickup.$intercom_code);
889           $picklist  = '${EXTEN:'.$len.'}';
890           $picklist .= '&${EXTEN:'.$len.'}@ext-local';
891           $picklist .= '&${EXTEN:'.$len.'}@from-internal';
892           $picklist .= '&${EXTEN:'.$len.'}@from-internal-xfer';
893           $picklist .= '&${EXTEN:'.$len.'}@from-did-direct';
894           $picklist .= '&LC-${EXTEN:'.$len.'}@from-internal';
895           $picklist .= '&LC-${EXTEN:'.$len.'}@from-internal-xfer';
896           $picklist .= '&FMPR-${EXTEN:'.$len.'}@from-internal';
897           $picklist .= '&FMPR-${EXTEN:'.$len.'}@from-internal-xfer';
898           $picklist .= '&FMPR-${EXTEN:'.$len.'}@from-did-direct';
899
900           $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup($picklist));
901           $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new ext_hangup(''));
902         }
903         // In order to do call pickup in ringgroups, we will need to try the ringgoup number
904         // when doing call pickup for that ringgoup so we must see who is a member of what ringgroup
905         // and then generate the dialplan
906         //
907         $rg_members = array();
908         if (function_exists('ringgroups_list')) {
909           $rg_list = ringgroups_list(true);
910           foreach ($rg_list as $item) {
911             $thisgrp = ringgroups_get($item['grpnum']);
912             $grpliststr = $thisgrp['grplist'];
913             $grplist = explode("-", $grpliststr);
914             foreach ($grplist as $exten) {
915               if (strpos($exten,"#") === false) {
916                 $rg_members[$exten][] = $item['grpnum'];
917               }
918             }
919           }
920         }
921         // Now we have a hash of extensions and what ringgoups they are members of
922         // so we need to generate the callpickup dialplan for these specific extensions
923         // to try the ringgoup.
924         foreach ($rg_members as $exten => $grps) {
925           $picklist  = $exten;
926           $picklist .= '&'.$exten.'@ext-local';
927           $picklist .= '&'.$exten.'@from-internal';
928           $picklist .= '&'.$exten.'@from-internal-xfer';
929           $picklist .= '&'.$exten.'@from-did-direct';
930           $picklist .= '&LC-'.$exten.'@from-internal';
931           $picklist .= '&LC-'.$exten.'@from-internal-xfer';
932           $picklist .= '&FMPR-'.$exten.'@from-internal';
933           $picklist .= '&FMPR-'.$exten.'@from-internal-xfer';
934           $picklist .= '&FMPR-'.$exten.'@from-did-direct';
935
936           foreach ($grps as $grp) {
937             $picklist .= '&'.$grp.'@from-internal';
938             $picklist .= '&'.$grp.'@from-internal-xfer';
939             $picklist .= '&'.$grp.'@ext-group';
940           }
941           $ext->add('app-pickup', "$fc_pickup".$exten, '', new $ext_pickup($picklist));
942           $ext->add('app-pickup', "$fc_pickup".$exten, '', new ext_hangup(''));
943           if ($intercom_code != '') {
944             $ext->add('app-pickup', "$fc_pickup".$intercom_code.$exten, '', new $ext_pickup($picklist));
945             $ext->add('app-pickup', "$fc_pickup".$intercom_code.$exten, '', new ext_hangup(''));
946           }
947         }
948       } elseif ($fc_pickup != '') {
949         $ext->addInclude('from-internal-additional', 'app-pickup');
950         $fclen = strlen($fc_pickup);
951         $ext_pickup = (strstr($engineinfo['raw'], 'BRI')) ? 'ext_dpickup' : 'ext_pickup';
952
953         $fcc = new featurecode('paging', 'intercom-prefix');
954         $intercom_code = $fcc->getCodeActive();
955         unset($fcc);
956
957
958         $ext->add('app-pickup', "_$fc_pickup.", '', new ext_NoOp('Attempt to Pickup ${EXTEN:'.$fclen.'} by ${CALLERID(num)}'));
959         $ext->add('app-pickup', "_$fc_pickup.", '', new $ext_pickup('${EXTEN:'.$fclen.'}'));
960         $ext->add('app-pickup', "_$fc_pickup.", '', new $ext_pickup('${EXTEN:'.$fclen.'}@ext-local'));
961         $ext->add('app-pickup', "_$fc_pickup.", '', new $ext_pickup('${EXTEN:'.$fclen.'}@from-internal'));
962         $ext->add('app-pickup', "_$fc_pickup.", '', new $ext_pickup('${EXTEN:'.$fclen.'}@from-internal-xfer'));
963         $ext->add('app-pickup', "_$fc_pickup.", '', new $ext_pickup('${EXTEN:'.$fclen.'}@from-did-direct'));
964         $ext->add('app-pickup', "_$fc_pickup.", '', new $ext_pickup('FMPR-${EXTEN:'.$fclen.'}'));
965         $ext->add('app-pickup', "_$fc_pickup.", '', new $ext_pickup('LC-${EXTEN:'.$fclen.'}@from-internal'));
966         $ext->add('app-pickup', "_$fc_pickup.", '', new $ext_pickup('LC-${EXTEN:'.$fclen.'}@from-internal-xfer'));
967         $ext->add('app-pickup', "_$fc_pickup.", '', new $ext_pickup('FMPR-${EXTEN:'.$fclen.'}@from-internal'));
968         $ext->add('app-pickup', "_$fc_pickup.", '', new $ext_pickup('FMPR-${EXTEN:'.$fclen.'}@from-internal-xfer'));
969         $ext->add('app-pickup', "_$fc_pickup.", '', new $ext_pickup('FMPR-${EXTEN:'.$fclen.'}@from-did-direct'));
970         if ($intercom_code != '') {
971           $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('${EXTEN:'.strlen($fc_pickup.$intercom_code).'}'));
972           $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('${EXTEN:'.strlen($fc_pickup.$intercom_code).'}@from-internal'));
973           $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('${EXTEN:'.strlen($fc_pickup.$intercom_code).'}@from-internal-xfer'));
974           $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('${EXTEN:'.strlen($fc_pickup.$intercom_code).'}@from-did-direct'));
975           $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('FMPR-${EXTEN:'.strlen($fc_pickup.$intercom_code).'}'));
976           $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('FMPR-${EXTEN:'.strlen($fc_pickup.$intercom_code).'}@from-internal'));
977           $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('FMPR-${EXTEN:'.strlen($fc_pickup.$intercom_code).'}@from-internal-xfer'));
978           $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('FMPR-${EXTEN:'.strlen($fc_pickup.$intercom_code).'}@from-did-direct'));
979         }
980         $ext->add('app-pickup', "_$fc_pickup.", '', new ext_hangup(''));
981         // In order to do call pickup in ringgroups, we will need to try the ringgoup number
982         // when doing call pickup for that ringgoup so we must see who is a member of what ringgroup
983         // and then generate the dialplan
984         //
985         $rg_members = array();
986         if (function_exists('ringgroups_list')) {
987           $rg_list = ringgroups_list(true);
988           foreach ($rg_list as $item) {
989             $thisgrp = ringgroups_get($item['grpnum']);
990             $grpliststr = $thisgrp['grplist'];
991             $grplist = explode("-", $grpliststr);
992             foreach ($grplist as $exten) {
993               if (strpos($exten,"#") === false) {
994                 $rg_members[$exten][] = $item['grpnum'];
995               }
996             }
997           }
998         }
999         // Now we have a hash of extensions and what ringgoups they are members of
1000         // so we need to generate the callpickup dialplan for these specific extensions
1001         // to try the ringgoup.
1002         foreach ($rg_members as $exten => $grps) {
1003           $ext->add('app-pickup', "$fc_pickup".$exten, '', new $ext_pickup($exten));
1004           $ext->add('app-pickup', "$fc_pickup".$exten, '', new $ext_pickup($exten.'@ext-local'));
1005           $ext->add('app-pickup', "$fc_pickup".$exten, '', new $ext_pickup($exten.'@from-internal'));
1006           $ext->add('app-pickup', "$fc_pickup".$exten, '', new $ext_pickup($exten.'@from-internal-xfer'));
1007           $ext->add('app-pickup', "$fc_pickup".$exten, '', new $ext_pickup($exten.'@from-did-direct'));
1008           $ext->add('app-pickup', "$fc_pickup".$exten, '', new $ext_pickup('LC-'.$exten.'@from-internal'));
1009           $ext->add('app-pickup', "$fc_pickup".$exten, '', new $ext_pickup('LC-'.$exten.'@from-internal-xfer'));
1010           $ext->add('app-pickup', "$fc_pickup".$exten, '', new $ext_pickup('FMPR-'.$exten));
1011           $ext->add('app-pickup', "$fc_pickup".$exten, '', new $ext_pickup('FMPR-'.$exten.'@from-internal'));
1012           $ext->add('app-pickup', "$fc_pickup".$exten, '', new $ext_pickup('FMPR-'.$exten.'@from-internal-xfer'));
1013           $ext->add('app-pickup', "$fc_pickup".$exten, '', new $ext_pickup('FMPR-'.$exten.'@from-did-direct'));
1014           foreach ($grps as $grp) {
1015             $ext->add('app-pickup', "$fc_pickup".$exten, '', new $ext_pickup($grp.'@from-internal'));
1016             $ext->add('app-pickup', "$fc_pickup".$exten, '', new $ext_pickup($grp.'@from-internal-xfer'));
1017             $ext->add('app-pickup', "$fc_pickup".$exten, '', new $ext_pickup($grp.'@ext-group'));
1018           }
1019           $ext->add('app-pickup', "$fc_pickup".$exten, '', new ext_hangup(''));
1020         }
1021       }
1022      
1023      
1024       // zap barge
1025       if ($fc_zapbarge != '') {
1026         $ext->addInclude('from-internal-additional', 'app-zapbarge'); // Add the include from from-internal
1027        
1028         $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_macro('user-callerid'));
1029         $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_setvar('GROUP()','${CALLERID(number)}'));
1030         $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_answer(''));
1031         $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_wait(1));
1032         $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_zapbarge(''));
1033         $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_hangup(''));
1034       }
1035
1036       // chan spy
1037       if ($fc_chanspy != '') {
1038         $ext->addInclude('from-internal-additional', 'app-chanspy'); // Add the include from from-internal
1039         $ext->add('app-chanspy', $fc_chanspy, '', new ext_macro('user-callerid'));
1040         $ext->add('app-chanspy', $fc_chanspy, '', new ext_answer(''));
1041         $ext->add('app-chanspy', $fc_chanspy, '', new ext_wait(1));
1042         $ext->add('app-chanspy', $fc_chanspy, '', new ext_chanspy(''));
1043         $ext->add('app-chanspy', $fc_chanspy, '', new ext_hangup(''));
1044       }
1045      
1046       // Simulate options (ext-test)
1047       if ($fc_simu_pstn != '' || $fc_simu_fax != '') {
1048         $ext->addInclude('from-internal-additional', 'ext-test'); // Add the include from from-internal
1049        
1050         if ($fc_simu_pstn != '') {
1051           if (ctype_digit($fc_simu_pstn)) {
1052             $ext->add('ext-test', $fc_simu_pstn, '', new ext_goto('1', '${EXTEN}', 'from-pstn'));
1053           } else {
1054             $ext->add('ext-test', $fc_simu_pstn, '', new ext_goto('1', 's', 'from-pstn'));
1055           }
1056         }
1057
1058         if ($fc_simu_fax != '') {
1059           $ext->add('ext-test', $fc_simu_fax, '', new ext_goto('1', 'in_fax', 'ext-fax'));
1060         }
1061
1062         $ext->add('ext-test', 'h', '', new ext_macro('hangupcall'));
1063       }
1064      
1065       /* Always have Fax detection in ext-did, no matter what */
1066
1067       $ext->addInclude('ext-did', 'ext-did-0001'); // Add the include from from-internal
1068       $ext->addInclude('ext-did', 'ext-did-0002'); // Add the include from from-internal
1069       $ext->add('ext-did-0001', 'fax', '', new ext_goto('1','in_fax','ext-fax'));
1070       $ext->add('ext-did-0002', 'fax', '', new ext_goto('1','in_fax','ext-fax'));
1071       $ext->add('ext-did', 'fax', '', new ext_goto('1','in_fax','ext-fax'));
1072
1073       /* inbound routing extensions */
1074       $didlist = core_did_list();
1075       if(is_array($didlist)){
1076         $catchall = false;
1077         $catchall_context='ext-did-catchall';
1078         foreach($didlist as $item) {
1079           if (trim($item['destination']) == '') {
1080             continue;
1081           }
1082           $exten = trim($item['extension']);
1083           $cidnum = trim($item['cidnum']);
1084
1085           // If the user put in just a cid number for routing, we add _. pattern to catch
1086           // all DIDs with that CID number. Asterisk will complain about _. being dangerous
1087           // but we don't want to limit this to just numberic as someone may be trying to
1088           // route a non-numeric did
1089           //
1090           $cidroute = false;
1091           if ($cidnum != '' && $exten == '') {
1092             $exten = '_.';
1093             $pricid = ($item['pricid']) ? true:false;
1094             $cidroute = true;
1095           } else if (($cidnum != '' && $exten != '') || ($cidnum == '' && $exten == '')) {
1096             $pricid = true;
1097           } else {
1098             $pricid = false;
1099           }
1100           $context = ($pricid) ? "ext-did-0001":"ext-did-0002";
1101
1102           $exten = (($exten == "")?"s":$exten);
1103           $exten = $exten.(($cidnum == "")?"":"/".$cidnum); //if a CID num is defined, add it
1104
1105           if ($cidroute) {
1106             $ext->add($context, $exten, '', new ext_setvar('__FROM_DID','${EXTEN}'));
1107             $ext->add($context, $exten, '', new ext_goto('1','s'));
1108             $exten = "s/$cidnum";
1109             $ext->add($context, $exten, '', new ext_execif('$["${FROM_DID}" = ""]','Set','__FROM_DID=${EXTEN}'));
1110           } else {
1111             $ext->add($context, $exten, '', new ext_setvar('__FROM_DID','${EXTEN}'));
1112           }
1113           // always set callerID name
1114           $ext->add($context, $exten, '', new ext_execif('$[ "${CALLERID(name)}" = "" ] ','Set','CALLERID(name)=${CALLERID(num)}'));
1115
1116           if (!empty($item['mohclass']) && trim($item['mohclass']) != 'default') {
1117             $ext->add($context, $exten, '', new ext_setmusiconhold($item['mohclass']));
1118             $ext->add($context, $exten, '', new ext_setvar('__MOHCLASS',$item['mohclass']));
1119           }
1120
1121           // If we require RINGING, signal it as soon as we enter.
1122           if ($item['ringing'] === "CHECKED") {
1123             $ext->add($context, $exten, '', new ext_ringing(''));
1124           }
1125           if ($item['delay_answer']) {
1126             $ext->add($context, $exten, '', new ext_wait($item['delay_answer']));
1127           }
1128
1129           if ($exten == "s") { 
1130             //if the exten is s, then also make a catchall for undefined DIDs
1131             $catchaccount = "_.".(empty($cidnum)?"":"/".$cidnum);
1132             if ($catchaccount =="_." && ! $catchall) {
1133               $catchall = true;
1134               $ext->add($catchall_context, $catchaccount, '', new ext_NoOp('Catch-All DID Match - Found ${EXTEN} - You probably want a DID for this.'));
1135               $ext->add($catchall_context, $catchaccount, '', new ext_goto('1','s','ext-did'));
1136             }
1137           }
1138          
1139           if ($item['faxexten'] != "default") {
1140             $ext->add($context, $exten, '', new ext_setvar('FAX_RX',$item['faxexten']));
1141           }
1142           if (!empty($item['faxemail'])) {
1143             $ext->add($context, $exten, '', new ext_setvar('FAX_RX_EMAIL',$item['faxemail']));
1144           }
1145           if ($item['answer'] == "1") {
1146             $ext->add($context, $exten, '', new ext_answer(''));
1147             $ext->add($context, $exten, '', new ext_wait($item['wait']));
1148           }
1149           if ($item['answer'] == "2") { // NVFaxDetect
1150             $ext->add($context, $exten, '', new ext_answer(''));
1151             $ext->add($context, $exten, '', new ext_playtones('ring'));
1152             $ext->add($context, $exten, '', new ext_nvfaxdetect($item['wait']."|t"));
1153           }
1154           if ($item['privacyman'] == "1") {
1155             $ext->add($context, $exten, '', new ext_macro('privacy-mgr'));
1156           } else {
1157             // if privacymanager is used, this is not necessary as it will not let blocked/anonymous calls through
1158             // otherwise, we need to save the caller presence to set it properly if we forward the call back out the pbx
1159             // note - the indirect table could go away as of 1.4.20 where it is fixed so that SetCallerPres can take
1160             // the raw format.
1161             //
1162             if ($ast_lt_16) {
1163               $ext->add($context, $exten, '', new ext_setvar('__CALLINGPRES_SV','${CALLINGPRES_${CALLINGPRES}}'));
1164             } else {
1165               $ext->add($context, $exten, '', new ext_setvar('__CALLINGPRES_SV','${CALLERPRES()}'));
1166             }
1167             $ext->add($context, $exten, '', new ext_setcallerpres('allowed_not_screened'));
1168           }
1169           if (!empty($item['alertinfo'])) {
1170             $ext->add($context, $exten, '', new ext_setvar("__ALERT_INFO", str_replace(';', '\;', $item['alertinfo'])));
1171           }
1172           // Add CID prefix, no need to do checks for existing pre-pends, this is an incoming did so this should
1173           // be the first time the CID is manipulated. We set _RGPREFIX which is the same used throughout the different
1174           // modules.
1175           //
1176           // TODO: If/When RGPREFIX is added to trunks, then see code in ringgroups to strip prefix if added here.
1177           //
1178           // TODO: core FreePBX documentation about this standard. (and probably rename from RGPREFIX to CIDPREFIX)
1179           //
1180           if (!empty($item['grppre'])) {
1181             $ext->add($context, $exten, '', new ext_setvar('_RGPREFIX', $item['grppre']));
1182             $ext->add($context, $exten, '', new ext_setvar('CALLERID(name)','${RGPREFIX}${CALLERID(name)}'));
1183           }
1184          
1185           //the goto destination
1186           // destination field in 'incoming' database is backwards from what ext_goto expects
1187           $goto_context = strtok($item['destination'],',');
1188           $goto_exten = strtok(',');
1189           $goto_pri = strtok(',');
1190           $ext->add($context, $exten, '', new ext_goto($goto_pri,$goto_exten,$goto_context));
1191          
1192         }
1193         // If there's not a catchall, make one with an error message
1194         if (!$catchall) {
1195           $ext->add($catchall_context, 's', '', new ext_noop("No DID or CID Match"));
1196           $ext->add($catchall_context, 's', 'a2', new ext_answer(''));
1197           $ext->add($catchall_context, 's', '', new ext_wait('2'));
1198           $ext->add($catchall_context, 's', '', new ext_playback('ss-noservice'));
1199           $ext->add($catchall_context, 's', '', new ext_sayalpha('${FROM_DID}'));
1200           $ext->add($catchall_context, 's', '', new ext_hangup(''));
1201           $ext->add($catchall_context, '_.', '', new ext_setvar('__FROM_DID', '${EXTEN}'));
1202           $ext->add($catchall_context, '_.', '', new ext_noop('Received an unknown call with DID set to ${EXTEN}'));
1203           $ext->add($catchall_context, '_.', '', new ext_goto('a2','s'));
1204           $ext->add($catchall_context, 'h', '', new ext_hangup(''));
1205         }
1206          
1207       }
1208
1209       // Now create macro-from-zaptel-nnn for each defined channel to route it to the DID routing
1210       // Send it to from-trunk so it is handled as other dids would be handled.
1211       //
1212       foreach (core_zapchandids_list() as $row) {
1213         $channel = $row['channel'];
1214         $did     = $row['did'];
1215
1216         $zap_context = "macro-from-zaptel-{$channel}";
1217         $ext->add($zap_context, 's', '', new ext_noop('Entering '.$zap_context.' with DID = ${DID} and setting to: '.$did));
1218         $ext->add($zap_context, 's', '', new ext_setvar('__FROM_DID',$did));
1219         $ext->add($zap_context, 's', '', new ext_goto('1',$did,'from-trunk'));
1220       }
1221
1222       /* user extensions */
1223       $ext->addInclude('from-internal-additional','ext-local');
1224
1225       // If running in Dynamic mode, this will insert the hints through an Asterisk #exec call.
1226       // which require "execincludes=yes" to be set in the [options] section of asterisk.conf
1227       //
1228
1229       $fcc = new featurecode('paging', 'intercom-prefix');
1230       $intercom_code = $fcc->getCodeActive();
1231       unset($fcc);
1232
1233       $intercom_code = ($intercom_code == '') ? 'nointercom' : $intercom_code;
1234
1235       // Pass the code so agi scripts like user_login_logout know to generate hints
1236       //
1237       $ext->addGlobal('INTERCOMCODE',$intercom_code);
1238
1239       if ($amp_conf['DYNAMICHINTS']) {
1240         if ($amp_conf['USEDEVSTATE'] && function_exists('donotdisturb_get_config')) {
1241           $add_dnd = ' dnd';
1242         } else {
1243           $add_dnd = '';
1244         }
1245         $ext->addExec('ext-local',$amp_conf['AMPBIN'].'/generate_hints.php '.$intercom_code.$add_dnd);
1246       }
1247       $userlist = core_users_list();
1248       if (is_array($userlist)) {
1249         foreach($userlist as $item) {
1250           $exten = core_users_get($item[0]);
1251           $vm = ((($exten['voicemail'] == "novm") || ($exten['voicemail'] == "disabled") || ($exten['voicemail'] == "")) ? "novm" : $exten['extension']);
1252
1253           if (isset($exten['ringtimer']) && $exten['ringtimer'] != 0)
1254             $ext->add('ext-local', $exten['extension'], '', new ext_setvar('__RINGTIMER',$exten['ringtimer']));
1255          
1256           $ext->add('ext-local', $exten['extension'], '', new ext_macro('exten-vm',$vm.",".$exten['extension']));
1257          
1258           if($vm != "novm") {
1259             $ext->add('ext-local', $exten['extension'], '', new ext_goto('1','vmret'));
1260             $ext->add('ext-local', '${VM_PREFIX}'.$exten['extension'], '', new ext_macro('vm',$vm.',DIRECTDIAL,${IVR_RETVM}'));
1261             $ext->add('ext-local', '${VM_PREFIX}'.$exten['extension'], '', new ext_goto('1','vmret'));
1262             $ext->add('ext-local', 'vmb'.$exten['extension'], '', new ext_macro('vm',$vm.',BUSY,${IVR_RETVM}'));
1263             $ext->add('ext-local', 'vmb'.$exten['extension'], '', new ext_goto('1','vmret'));
1264             $ext->add('ext-local', 'vmu'.$exten['extension'], '', new ext_macro('vm',$vm.',NOANSWER,${IVR_RETVM}'));
1265             $ext->add('ext-local', 'vmu'.$exten['extension'], '', new ext_goto('1','vmret'));
1266             $ext->add('ext-local', 'vms'.$exten['extension'], '', new ext_macro('vm',$vm.',NOMESSAGE,${IVR_RETVM}'));
1267             $ext->add('ext-local', 'vms'.$exten['extension'], '', new ext_goto('1','vmret'));
1268           } else {
1269             // If we return from teh macro, it means we are suppose to return to the IVR
1270             //
1271             $ext->add('ext-local', $exten['extension'], '', new ext_goto('1','return','${IVR_CONTEXT}'));
1272           }
1273            
1274           // Create the hints if running in normal mode
1275           //
1276           if (!$amp_conf['DYNAMICHINTS']) {
1277             $hint = core_hint_get($exten['extension']);
1278             $dnd_string = ($amp_conf['USEDEVSTATE'] && function_exists('donotdisturb_get_config')) ? "&Custom:DND".$exten['extension'] : '';
1279             if (!empty($hint)) {
1280               $ext->addHint('ext-local', $exten['extension'], $hint.$dnd_string);
1281               if ($intercom_code != '') {
1282                 $ext->addHint('ext-local', $intercom_code.$exten['extension'], $hint.$dnd_string);
1283               }
1284             } else if ($dnd_string) {
1285               $ext->addHint('ext-local', $exten['extension'], "&Custom:DND".$exten['extension']);
1286               if ($intercom_code != '') {
1287                 $ext->addHint('ext-local', $intercom_code.$exten['extension'], "&Custom:DND".$exten['extension']);
1288               }
1289             }
1290           }
1291           if ($exten['sipname']) {
1292             $ext->add('ext-local', $exten['sipname'], '', new ext_goto('1',$item[0],'from-internal'));
1293           }
1294           // Now make a special context for the IVR inclusions of local extension dialing so that
1295           // when people use the Queues breakout ability, and break out to someone's extensions, voicemail
1296           // works.
1297           //
1298           $ivr_context = 'from-did-direct-ivr';
1299           $ext->add($ivr_context, $exten['extension'],'', new ext_execif('$["${BLKVM_OVERRIDE}" != ""]','dbDel','${BLKVM_OVERRIDE}'));
1300           $ext->add($ivr_context, $exten['extension'],'', new ext_setvar('__NODEST', ''));
1301           $ext->add($ivr_context, $exten['extension'],'', new ext_goto('1',$exten['extension'],'from-did-direct'));
1302           if($vm != "novm") {
1303             $ext->add($ivr_context, '${VM_PREFIX}'.$exten['extension'],'', new ext_execif('$["${BLKVM_OVERRIDE}" != ""]','dbDel','${BLKVM_OVERRIDE}'));
1304             $ext->add($ivr_context, '${VM_PREFIX}'.$exten['extension'],'', new ext_setvar('__NODEST', ''));
1305             $ext->add($ivr_context, '${VM_PREFIX}'.$exten['extension'],'', new ext_macro('vm',$vm.',DIRECTDIAL,${IVR_RETVM}'));
1306             $ext->add($ivr_context, '${VM_PREFIX}'.$exten['extension'],'', new ext_gotoif('$["${IVR_RETVM}" = "RETURN" & "${IVR_CONTEXT}" != ""]','ext-local,vmret,playret'));
1307           }
1308         }
1309         $ext->add('ext-local', 'vmret', '', new ext_gotoif('$["${IVR_RETVM}" = "RETURN" & "${IVR_CONTEXT}" != ""]','playret'));
1310         $ext->add('ext-local', 'vmret', '', new ext_hangup(''));
1311         $ext->add('ext-local', 'vmret', 'playret', new ext_playback('exited-vm-will-be-transfered&silence/1'));
1312         $ext->add('ext-local', 'vmret', '', new ext_goto('1','return','${IVR_CONTEXT}'));
1313       }
1314
1315
1316       // create from-trunk context for each trunk that adds counts to channels
1317       //
1318       $trunklist = core_trunks_list(true);
1319       if (is_array($trunklist)) {
1320         foreach ($trunklist as $trunkprops) {
1321           if (trim($trunkprops['value']) == 'on') {
1322             // value of on is disabled and for zap we don't create a context
1323             continue;
1324           }
1325           switch ($trunkprops['tech']) {
1326             case 'DUNDI':
1327               $macro_name = 'macro-dundi-'.substr($trunkprops['globalvar'],4);
1328               $ext->addSwitch($macro_name,'DUNDI/'.$trunkprops['name']);
1329               $ext->add($macro_name, 's', '', new ext_goto('1','${ARG1}'));
1330             case 'IAX':
1331             case 'IAX2':
1332             case 'SIP':
1333               $trunkgroup = $trunkprops['globalvar'];
1334               $trunkcontext  = "from-trunk-".strtolower($trunkprops['tech'])."-".$trunkprops['name'];
1335               $ext->add($trunkcontext, '_.', '', new ext_setvar('GROUP()',$trunkgroup));
1336               $ext->add($trunkcontext, '_.', '', new ext_goto('1','${EXTEN}','from-trunk'));
1337               break;
1338             default:
1339           }
1340         }
1341       }
1342
1343       /* dialplan globals */
1344       // modules should NOT use the globals table to store anything!
1345       // modules should use $ext->addGlobal("testvar","testval"); in their module_get_config() function instead
1346       // I'm cheating for core functionality - do as I say, not as I do ;-)   
1347
1348       // Auto add these globals to give access to agi scripts and other needs, unless defined in the global table.
1349       //
1350       $amp_conf_globals = array(
1351         "ASTETCDIR",
1352         "ASTMODDIR",
1353         "ASTVARLIBDIR",
1354         "ASTAGIDIR",
1355         "ASTSPOOLDIR",
1356         "ASTRUNDIR",
1357         "ASTLOGDIR",
1358         "CWINUSEBUSY",
1359         "AMPMGRUSER",
1360         "AMPMGRPASS",
1361         // Before you get upset about these being exposed to the dialplan,
1362         // they are ALREADY readable from /etc/amportal.conf - adding them
1363         // here means that AGI's and Dialplan can connect to the database
1364         // without resorting to re-parsing amportal.conf.
1365         "AMPDBENGINE",
1366         "AMPDBHOST",
1367         "AMPDBNAME",
1368         "AMPDBUSER",
1369         "AMPDBPASS",
1370         "AMPDBFILE"
1371       );
1372
1373       $disable_recording = false;
1374
1375       $sql = "SELECT * FROM globals";
1376       $globals = sql($sql,"getAll",DB_FETCHMODE_ASSOC);
1377       foreach($globals as $global) {
1378         $value = $global['value'];
1379         $ext->addGlobal($global['variable'],$value);
1380
1381         // now if for some reason we have a variable in the global table
1382         // that is in our $amp_conf_globals list, then remove it so we
1383         // don't duplicate, the sql table will take precedence
1384         //
1385         if (array_key_exists($global['variable'],$amp_conf_globals)) {
1386           $rm_keys = array_keys($amp_conf_globals,$global['variable']);
1387           foreach ($rm_keys as $index) {
1388             unset($amp_conf_globals[$index]);
1389           }
1390         }
1391         if (($global['variable'] == 'RECORDING_STATE') && (strtoupper($global['value']) == 'DISABLED')) {
1392           $disable_recording = true;
1393         }
1394       }
1395       foreach ($amp_conf_globals as $global) {
1396         if (isset($amp_conf[$global])) {
1397           $value = $amp_conf[$global];
1398           if ($value === true || $value === false) {
1399             $value = ($value) ? 'true':'false';
1400           }
1401           $ext->addGlobal($global, $value);
1402           out("Added to globals: $global = $value");
1403         }
1404       }
1405       // Put the asterisk version in a global for agi etc.
1406       $ext->addGlobal('ASTVERSION', $version);
1407       // Put the use of chan_dahdi in a global for dialparties
1408       $ext->addGlobal('ASTCHANDAHDI', $chan_dahdi ? '1' : '0');
1409      
1410       // Create CallingPresTable to deal with difference that ${CALINGPRES} returns vs. what
1411       // SetCallerPres() accepts. This is a workaround that gets resolved in 1.6 where
1412       // function CALLINGPRES() is consistent.
1413       // This should be fixed in 1.4.20 but for now we keep it in until 1.6
1414       //
1415       if ($ast_lt_16) {
1416         $ext->addGlobal('CALLINGPRES_0', 'allowed_not_screened');
1417         $ext->addGlobal('CALLINGPRES_1', 'allowed_passed_screen');
1418         $ext->addGlobal('CALLINGPRES_2', 'allowed_failed_screen');
1419         $ext->addGlobal('CALLINGPRES_3', 'allowed');
1420         $ext->addGlobal('CALLINGPRES_32', 'prohib_not_screened');
1421         $ext->addGlobal('CALLINGPRES_33', 'prohib_passed_screen');
1422         $ext->addGlobal('CALLINGPRES_34', 'prohib_failed_screen');
1423         $ext->addGlobal('CALLINGPRES_35', 'prohib');
1424         $ext->addGlobal('CALLINGPRES_67', 'unavailable');
1425       }
1426
1427       // This checks if we have func_extstate loaded, if so we set the global which dialparties
1428       // can use (and any other AGI script) to determine that this function exists and not connect
1429       // to the manager to get the information
1430       //
1431       if ($ast_ge_14 && $ast_lt_16) {
1432         $response = $astman->send_request('Command', array('Command' => 'module show like func_extstate'));
1433         if (preg_match('/1 modules loaded/', $response['data'])) {
1434           $ext->addGlobal('HAS_EXTENSION_STATE', 'TRUE');
1435         }
1436       }
1437
1438       // Let's create globals for each trunk to determine which one's have fixlocalprefix settings.
1439       // this allows us to skip calling the agi script if there are no rules to process saving
1440       // on performance
1441       //
1442       $conf = core_trunks_readDialRulesFile();
1443       if (is_array($conf)) {
1444         foreach ($conf as $trunknum => $entries) {
1445           $trunkname = substr($trunknum,6);
1446           $ext->addGlobal("PREFIX_TRUNK_$trunkname",count($entries));
1447         }
1448       }
1449
1450       // Now let's create the required globals for the trunks so outbound routes work. These used to
1451       // be stored in the globals table but are not generated by retrieve conf and pulled from the
1452       // trunks table
1453       //
1454       $sqlstr = "
1455         SELECT `trunkid`, `tech`, `outcid`, `keepcid`, `maxchans`, `failscript`, `dialoutprefix`, `channelid`, `disabled`
1456         FROM `trunks` ORDER BY `trunkid`
1457       ";
1458       $trunks = sql($sqlstr,"getAll",DB_FETCHMODE_ASSOC);
1459       foreach ($trunks as $trunk) {
1460         $tid = $trunk['trunkid'];
1461         $tech = strtoupper($trunk['tech']);
1462         if ($tech == 'IAX') {
1463           $tech = 'IAX2';
1464         } elseif ($tech == 'ZAP' && $chan_dahdi) {
1465           $tech = 'DAHDI';
1466         }
1467         if ($tech == 'CUSTOM') {
1468           $ext->addGlobal('OUT_'.$tid, 'AMP:'.$trunk['channelid']);
1469         } else {
1470           $ext->addGlobal('OUT_'.$tid, $tech."/".$trunk['channelid']);
1471         }
1472         $ext->addGlobal('OUTCID_'.$tid,      $trunk['outcid']);
1473         $ext->addGlobal('OUTKEEPCID_'.$tid,  $trunk['keepcid']);
1474         $ext->addGlobal('OUTMAXCHANS_'.$tid, $trunk['maxchans']);
1475         $ext->addGlobal('OUTFAIL_'.$tid,     $trunk['failscript']);
1476         $ext->addGlobal('OUTPREFIX_'.$tid,   $trunk['dialoutprefix']);
1477         $ext->addGlobal('OUTDISABLE_'.$tid,  $trunk['disabled']);
1478       }
1479
1480       // Generate macro-record-enable, if recording is disabled then we just make it a stub
1481       // Otherwise we make it right
1482       //
1483       $context = 'macro-record-enable';
1484       $exten = 's';
1485       if ($disable_recording) {
1486         $ext->add($context, $exten, '', new ext_macroexit());
1487       } else {
1488         $ext->add($context, $exten, '', new ext_gotoif('$["${BLINDTRANSFER}" = ""]', 'check'));
1489         $ext->add($context, $exten, '', new ext_resetcdr('w'));
1490
1491         if ($ast_ge_14) {
1492           $ext->add($context, $exten, '', new ext_stopmixmonitor());
1493         } else {
1494           $ext->add($context, $exten, '', new ext_stopmonitor());
1495         }
1496
1497         $ext->add($context, $exten, 'check', new ext_agi('recordingcheck,${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)},${UNIQUEID}'));
1498         $ext->add($context, $exten, '', new ext_macroexit());
1499         // keep this 999 in case people have issues updating their recording script
1500         $ext->add($context, $exten, 'record', new ext_mixmonitor('${MIXMON_DIR}${CALLFILENAME}.${MIXMON_FORMAT}','','${MIXMON_POST}'),'1',998);
1501       }
1502
1503       /* outbound routes */
1504       // modules should use their own table for storage (and module_get_config() to add dialplan)
1505       // modules should NOT use the extension table to store anything!
1506       $sql = "SELECT application FROM extensions where context = 'outbound-allroutes' ORDER BY application";
1507       $outrts = sql($sql,"getAll",DB_FETCHMODE_ASSOC);
1508       $ext->addInclude('from-internal-additional','outbound-allroutes');
1509       $ext->add('outbound-allroutes', 'foo', '', new ext_noop('bar'));
1510       foreach($outrts as $outrt) {
1511         $ext->addInclude('outbound-allroutes',$outrt['application']);
1512         $sql = "SELECT * FROM extensions where context = '".$outrt['application']."' ORDER BY extension, CAST(priority AS UNSIGNED) ASC";
1513         $thisrt = sql($sql,"getAll",DB_FETCHMODE_ASSOC);
1514         $lastexten = false;
1515         foreach($thisrt as $exten) {
1516           //if emergencyroute, then set channel var
1517           if(strpos($exten['args'],"EMERGENCYROUTE") !== false)
1518             $ext->add($outrt['application'], $exten['extension'], '', new ext_setvar("EMERGENCYROUTE",substr($exten['args'],15)));
1519           if(strpos($exten['args'],"INTRACOMPANYROUTE") !== false)
1520             $ext->add($outrt['application'], $exten['extension'], '', new ext_setvar("INTRACOMPANYROUTE",substr($exten['args'],18)));
1521           // Don't set MOHCLASS if already set, threre may be a feature code that overrode it
1522           if(strpos($exten['args'],"MOHCLASS") !== false)
1523             $ext->add($outrt['application'], $exten['extension'], '', new ext_setvar("MOHCLASS", '${IF($["x${MOHCLASS}"="x"]?'.substr($exten['args'],9).':${MOHCLASS})}' ));
1524           if(strpos($exten['args'],"dialout-trunk") !== false || strpos($exten['args'],"dialout-enum") !== false || strpos($exten['args'],"dialout-dundi") !== false) {
1525             if ($exten['extension'] !== $lastexten) {
1526
1527               // If NODEST is set, clear it. No point in remembering since dialout-trunk will just end in the
1528               // bit bucket. But if answered by an outside line with transfer capability, we want NODEST to be
1529               // clear so a subsequent transfer to an internal extension works and goes to voicmail or other
1530               // destinations.
1531               //
1532               // Then do one call to user-callerid and record-enable instead of each time as in the past
1533               //
1534               $ext->add($outrt['application'], $exten['extension'], '', new ext_macro('user-callerid,SKIPTTL'));
1535               $ext->add($outrt['application'], $exten['extension'], '', new ext_setvar("_NODEST",""));
1536               $ext->add($outrt['application'], $exten['extension'], '', new ext_macro('record-enable,${AMPUSER},OUT'));
1537               $lastexten = $exten['extension'];
1538             }
1539             $ext->add($outrt['application'], $exten['extension'], '', new ext_macro($exten['args']));
1540           }
1541           if(strpos($exten['args'],"outisbusy") !== false)
1542             $ext->add($outrt['application'], $exten['extension'], '', new ext_macro("outisbusy"));
1543         }
1544       }
1545
1546       general_generate_indications();
1547
1548       // "blackhole" destinations
1549       $ext->add('app-blackhole', 'hangup', '', new ext_noop('Blackhole Dest: Hangup'));
1550       $ext->add('app-blackhole', 'hangup', '', new ext_hangup());
1551
1552       $ext->add('app-blackhole', 'zapateller', '', new ext_noop('Blackhole Dest: Play SIT Tone'));
1553       $ext->add('app-blackhole', 'zapateller', '', new ext_answer());
1554       $ext->add('app-blackhole', 'zapateller', '', new ext_zapateller());
1555       // Should hangup ?
1556       // $ext->add('app-blackhole', 'zapateller', '', new ext_hangup());
1557          
1558       $ext->add('app-blackhole', 'musiconhold', '', new ext_noop('Blackhole Dest: Put caller on hold forever'));
1559       $ext->add('app-blackhole', 'musiconhold', '', new ext_answer());
1560       $ext->add('app-blackhole', 'musiconhold', '', new ext_musiconhold());
1561
1562       $ext->add('app-blackhole', 'congestion', '', new ext_noop('Blackhole Dest: Congestion'));
1563       $ext->add('app-blackhole', 'congestion', '', new ext_answer());
1564       $ext->add('app-blackhole', 'congestion', '', new ext_playtones('congestion'));
1565       $ext->add('app-blackhole', 'congestion', '', new ext_congestion());
1566       $ext->add('app-blackhole', 'congestion', '', new ext_hangup());
1567
1568       $ext->add('app-blackhole', 'busy', '', new ext_noop('Blackhole Dest: Busy'));
1569       $ext->add('app-blackhole', 'busy', '', new ext_answer());
1570       $ext->add('app-blackhole', 'busy', '', new ext_playtones('busy'));
1571       $ext->add('app-blackhole', 'busy', '', new ext_busy());
1572       $ext->add('app-blackhole', 'busy', '', new ext_hangup());
1573
1574       $ext->add('app-blackhole', 'ring', '', new ext_noop('Blackhole Dest: Ring'));
1575       $ext->add('app-blackhole', 'ring', '', new ext_answer());
1576       $ext->add('app-blackhole', 'ring', '', new ext_playtones('ring'));
1577       $ext->add('app-blackhole', 'ring', '', new ext_wait(300));
1578       $ext->add('app-blackhole', 'ring', '', new ext_hangup());
1579
1580       if ($amp_conf['AMPBADNUMBER'] !== false) {
1581         $context = 'bad-number';
1582         $exten = '_X.';
1583         $ext->add($context, $exten, '', new extension('ResetCDR()'));
1584         $ext->add($context, $exten, '', new extension('NoCDR()'));
1585         $ext->add($context, $exten, '', new ext_wait('1'));
1586         $ext->add($context, $exten, '', new ext_playback('silence/1&cannot-complete-as-dialed&check-number-dial-again,noanswer'));
1587         $ext->add($context, $exten, '', new ext_wait('1'));
1588         $ext->add($context, $exten, '', new ext_congestion('20'));
1589         $ext->add($context, $exten, '', new ext_hangup());
1590       }
1591
1592       /*
1593       ;------------------------------------------------------------------------
1594       ; [macro-confirm]
1595       ;------------------------------------------------------------------------
1596       ; CONTEXT:      macro-confirm                                                                                                             
1597       ; PURPOSE:      added default message if none supplied
1598       ;
1599       ; Follom-Me and Ringgroups provide an option to supply a message to be
1600       ; played as part of the confirmation. These changes have added a default
1601       ; message if none is supplied.
1602       ;
1603       ;------------------------------------------------------------------------
1604       */
1605       $context = 'macro-confirm';
1606       $exten = 's';
1607
1608       $ext->add($context, $exten, '', new ext_setvar('LOOPCOUNT','0'));
1609       $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT','ABORT'));
1610       $ext->add($context, $exten, '', new ext_setvar('MSG1','${IF($["foo${ARG1}" != "foo"]?${ARG1}:"incoming-call-1-accept-2-decline")}'));
1611       if ($ast_ge_14) {
1612         $ext->add($context, $exten, 'start', new ext_background('${MSG1},m,${CHANNEL(language)},macro-confirm'));
1613       } else {
1614         $ext->add($context, $exten, 'start', new ext_background('${MSG1},m,${LANGUAGE},macro-confirm'));
1615       }
1616       $ext->add($context, $exten, '', new ext_read('INPUT', '', 1, '', '', 4));
1617       $ext->add($context, $exten, '', new ext_gotoif('$[${LEN(${INPUT})} > 0]', '${INPUT},1', 't,1'));
1618
1619       $exten = '1';
1620       $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}" = "0"]', 'toolate,1'));
1621       $ext->add($context, $exten, '', new ext_dbdel('RG/${ARG3}/${UNIQCHAN}'));
1622       $ext->add($context, $exten, '', new ext_dbdel('${BLKVM_OVERRIDE}'));
1623       $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT',''));
1624       $ext->add($context, $exten, 'exitopt1', new ext_macroexit());
1625
1626       $exten = '2';
1627       $ext->add($context, $exten, '', new ext_goto(1, 'noanswer'));
1628
1629       $exten = '3';
1630       $ext->add($context, $exten, '', new ext_saydigits('${CALLCONFIRMCID}'));
1631       $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}" = "0"]', 'toolate,1','s,start'));
1632
1633       $exten = 't';
1634       $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}" = "0"]', 'toolate,1'));
1635       $ext->add($context, $exten, '', new ext_setvar('LOOPCOUNT','$[ ${LOOPCOUNT} + 1 ]'));
1636       $ext->add($context, $exten, '', new ext_gotoif('$[ ${LOOPCOUNT} < 5 ]', 's,start','noanswer,1'));
1637
1638       $exten = '_X';
1639       if ($ast_ge_14) {
1640         $ext->add($context, $exten, '', new ext_background('invalid,m,${CHANNEL(language)},macro-confirm'));
1641       } else {
1642         $ext->add($context, $exten, '', new ext_background('invalid,m,${LANGUAGE},macro-confirm'));
1643       }
1644       $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}" = "0"]', 'toolate,1'));
1645       $ext->add($context, $exten, '', new ext_setvar('LOOPCOUNT','$[ ${LOOPCOUNT} + 1 ]'));
1646       $ext->add($context, $exten, '', new ext_gotoif('$[ ${LOOPCOUNT} < 5 ]', 's,start','noanswer,1'));
1647
1648       $exten = 'noanswer';
1649       $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT','ABORT'));
1650       $ext->add($context, $exten, 'exitnoanswer', new ext_macroexit());
1651
1652       $exten = 'toolate';
1653       $ext->add($context, $exten, '', new ext_setvar('MSG2','${IF($["foo${ARG2}" != "foo"]?${ARG2}:"incoming-call-no-longer-avail")}'));
1654       $ext->add($context, $exten, '', new ext_playback('${MSG2}'));
1655       $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT','ABORT'));
1656       $ext->add($context, $exten, 'exittoolate', new ext_macroexit());
1657
1658       $exten = 'h';
1659       $ext->add($context, $exten, '', new ext_macro('hangupcall'));
1660
1661       /*
1662       ;------------------------------------------------------------------------
1663       ; [macro-auto-confirm]
1664       ;------------------------------------------------------------------------
1665       ; This macro is called from ext-local-confirm to auto-confirm a call so that other extensions
1666       ; are aware that the call has been answered.
1667       ;
1668       ;------------------------------------------------------------------------
1669       */
1670       $context = 'macro-auto-confirm';
1671       $exten = 's';
1672       $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT',''));
1673       $ext->add($context, $exten, '', new ext_dbdel('${BLKVM_OVERRIDE}'));
1674       $ext->add($context, $exten, '', new ext_dbdel('RG/${ARG1}/${UNIQCHAN}'));
1675
1676
1677       /*
1678       ;------------------------------------------------------------------------
1679       ; [macro-auto-blkvm]
1680       ;------------------------------------------------------------------------
1681       ; This macro is called for any extension dialed form a queue, ringgroup
1682       ; or followme, so that the answering extension can clear the voicemail block
1683       ; override allow subsequent transfers to properly operate.
1684       ;
1685       ;------------------------------------------------------------------------
1686       */
1687       $context = 'macro-auto-blkvm';
1688       $exten = 's';
1689       $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT',''));
1690       $ext->add($context, $exten, '', new ext_dbdel('${BLKVM_OVERRIDE}'));
1691
1692       /*
1693       ;------------------------------------------------------------------------
1694       ; [sub-pincheck]
1695       ;------------------------------------------------------------------------
1696       ; This subroutine checks the pincode and then resets the CDR from that point
1697       ; if the pincode passes. This way the billsec and duration fields are set
1698       ; properly for pin dialing.
1699       ;
1700       ; ${ARG3} is the pincode if this was called, used by dialout-trunk, dialout-enum
1701       ; and dialout-dundi
1702       ;
1703       ;------------------------------------------------------------------------
1704       */
1705       $context = 'sub-pincheck';
1706       $exten = 's';
1707       $ext->add($context, $exten, '', new ext_authenticate('${ARG3}'));
1708       $ext->add($context, $exten, '', new ext_resetcdr(''));
1709       $ext->add($context, $exten, '', new ext_return(''));
1710
1711      
1712       /*
1713        * dialout using a trunk, using pattern matching (don't strip any prefix)
1714        * arg1 = trunk number, arg2 = number, arg3 = route password
1715        *
1716        * MODIFIED (PL)
1717        *
1718        * Modified both Dial() commands to include the new TRUNK_OPTIONS from the general
1719        * screen of AMP
1720        */
1721        
1722       $context = 'macro-dialout-trunk';
1723       $exten = 's';
1724
1725       $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK', '${ARG1}'));
1726       $ext->add($context, $exten, '', new ext_gosubif('$[$["${ARG3}" != ""] & $["${DB(AMPUSER/${AMPUSER}/pinless)}" != "NOPASSWD"]]','sub-pincheck,s,1'));
1727       $ext->add($context, $exten, '', new ext_gotoif('$["x${OUTDISABLE_${DIAL_TRUNK}}" = "xon"]', 'disabletrunk,1'));
1728       $ext->add($context, $exten, '', new ext_set('DIAL_NUMBER', '${ARG2}')); // fixlocalprefix depends on this
1729       $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK_OPTIONS', '${DIAL_OPTIONS}')); // will be reset to TRUNK_OPTIONS if not intra-company
1730       $ext->add($context, $exten, '', new ext_set('OUTBOUND_GROUP', 'OUT_${DIAL_TRUNK}'));
1731       $ext->add($context, $exten, '', new ext_gotoif('$["${OUTMAXCHANS_${DIAL_TRUNK}}foo" = "foo"]', 'nomax'));
1732       $ext->add($context, $exten, '', new ext_gotoif('$[ ${GROUP_COUNT(OUT_${DIAL_TRUNK})} >= ${OUTMAXCHANS_${DIAL_TRUNK}} ]', 'chanfull'));
1733       $ext->add($context, $exten, 'nomax', new ext_gotoif('$["${INTRACOMPANYROUTE}" = "YES"]', 'skipoutcid'));  // Set to YES if treated like internal
1734       $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK_OPTIONS', '${TRUNK_OPTIONS}'));
1735       $ext->add($context, $exten, '', new ext_macro('outbound-callerid', '${DIAL_TRUNK}'));
1736       $ext->add($context, $exten, 'skipoutcid', new ext_execif('$["${PREFIX_TRUNK_${DIAL_TRUNK}}" != ""]','AGI','fixlocalprefix'));  // this sets DIAL_NUMBER to the proper dial string for this trunk
1737       $ext->add($context, $exten, '', new ext_set('OUTNUM', '${OUTPREFIX_${DIAL_TRUNK}}${DIAL_NUMBER}'));  // OUTNUM is the final dial number
1738       $ext->add($context, $exten, '', new ext_set('custom', '${CUT(OUT_${DIAL_TRUNK},:,1)}'));  // Custom trunks are prefixed with "AMP:"
1739    
1740       // Back to normal processing, whether intracompany or not.
1741       // But add the macro-setmusic if we don't want music on this outbound call
1742       $ext->add($context, $exten, '', new ext_execif('$[$["${MOHCLASS}" != "default"] & $["${MOHCLASS}" != ""]]', 'Set', 'DIAL_TRUNK_OPTIONS=M(setmusic^${MOHCLASS})${DIAL_TRUNK_OPTIONS}'));
1743    
1744       // This macro call will always be blank and is provided as a hook for customization required prior to making a call
1745       // such as adding SIP header information or other requirements. All the channel variables from above are present
1746      
1747       $ext->add($context, $exten, 'gocall', new ext_macro('dialout-trunk-predial-hook'));
1748       $ext->add($context, $exten, '', new ext_gotoif('$["${PREDIAL_HOOK_RET}" = "BYPASS"]', 'bypass,1'));
1749    
1750       $ext->add($context, $exten, '', new ext_gotoif('$["${custom}" = "AMP"]', 'customtrunk'));
1751       $ext->add($context, $exten, '', new ext_dial('${OUT_${DIAL_TRUNK}}/${OUTNUM}', '300,${DIAL_TRUNK_OPTIONS}'));  // Regular Trunk Dial
1752       $ext->add($context, $exten, '', new ext_goto(1, 's-${DIALSTATUS}'));
1753      
1754       $ext->add($context, $exten, 'customtrunk', new ext_set('pre_num', '${CUT(OUT_${DIAL_TRUNK},$,1)}'));
1755       $ext->add($context, $exten, '', new ext_set('the_num', '${CUT(OUT_${DIAL_TRUNK},$,2)}'));  // this is where we expect to find string OUTNUM
1756       $ext->add($context, $exten, '', new ext_set('post_num', '${CUT(OUT_${DIAL_TRUNK},$,3)}'));
1757       $ext->add($context, $exten, '', new ext_gotoif('$["${the_num}" = "OUTNUM"]', 'outnum', 'skipoutnum'));  // if we didn't find "OUTNUM", then skip to Dial
1758       $ext->add($context, $exten, 'outnum', new ext_set('the_num', '${OUTNUM}'));  // replace "OUTNUM" with the actual number to dial
1759       $ext->add($context, $exten, 'skipoutnum', new ext_dial('${pre_num:4}${the_num}${post_num}', '300,${DIAL_TRUNK_OPTIONS}'));
1760       $ext->add($context, $exten, '', new ext_goto(1, 's-${DIALSTATUS}'));
1761      
1762       $ext->add($context, $exten, 'chanfull', new ext_noop('max channels used up'));
1763    
1764       $exten = 's-BUSY';
1765       $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting BUSY - giving up'));
1766       $ext->add($context, $exten, '', new ext_playtones('busy'));
1767       $ext->add($context, $exten, '', new ext_busy(20));
1768    
1769       $exten = 's-NOANSWER';
1770       $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting NOANSWER - giving up'));
1771       $ext->add($context, $exten, '', new ext_playtones('congestion'));
1772       $ext->add($context, $exten, '', new ext_congestion(20));
1773    
1774       $exten = 's-CANCEL';
1775       $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting CANCEL - giving up'));
1776       $ext->add($context, $exten, '', new ext_playtones('congestion'));
1777       $ext->add($context, $exten, '', new ext_congestion(20));
1778
1779       $exten = 's-CHANUNAVAIL';
1780       $ext->add($context, $exten, '', new ext_gotoif('$["x${OUTFAIL_${ARG1}}" = "x"]', 'noreport'));
1781       $ext->add($context, $exten, '', new ext_agi('${OUTFAIL_${ARG1}}'));
1782       $ext->add($context, $exten, 'noreport', new ext_noop('TRUNK Dial failed due to ${DIALSTATUS} (hangupcause: ${HANGUPCAUSE}) - failing through to other trunks'));
1783    
1784       $exten = '_s-.';
1785       $ext->add($context, $exten, '', new ext_gotoif('$["x${OUTFAIL_${ARG1}}" = "x"]', 'noreport'));
1786       $ext->add($context, $exten, '', new ext_agi('${OUTFAIL_${ARG1}}'));
1787       $ext->add($context, $exten, 'noreport', new ext_noop('TRUNK Dial failed due to ${DIALSTATUS} - failing through to other trunks'));
1788      
1789       $ext->add($context, 'disabletrunk', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} DISABLED - falling through to next trunk'));
1790       $ext->add($context, 'bypass', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} BYPASSING because dialout-trunk-predial-hook'));
1791    
1792       $ext->add($context, 'h', '', new ext_macro('hangupcall'));
1793
1794
1795
1796
1797       $context = 'macro-dialout-dundi';
1798       $exten = 's';
1799      
1800       /*
1801        * Dialout Dundi Trunk
1802        */
1803       $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK', '${ARG1}'));
1804       $ext->add($context, $exten, '', new ext_gosubif('$[$["${ARG3}" != ""] & $["${DB(AMPUSER/${AMPUSER}/pinless)}" != "NOPASSWD"]]','sub-pincheck,s,1'));
1805       $ext->add($context, $exten, '', new ext_gotoif('$["x${OUTDISABLE_${DIAL_TRUNK}}" = "xon"]', 'disabletrunk,1'));
1806       $ext->add($context, $exten, '', new ext_set('DIAL_NUMBER', '${ARG2}')); // fixlocalprefix depends on this
1807       $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK_OPTIONS', '${DIAL_OPTIONS}')); // will be reset to TRUNK_OPTIONS if not intra-company
1808       $ext->add($context, $exten, '', new ext_set('OUTBOUND_GROUP', 'OUT_${DIAL_TRUNK}'));
1809       $ext->add($context, $exten, '', new ext_gotoif('$["${OUTMAXCHANS_${DIAL_TRUNK}}foo" = "foo"]', 'nomax'));
1810       $ext->add($context, $exten, '', new ext_gotoif('$[ ${GROUP_COUNT(OUT_${DIAL_TRUNK})} >= ${OUTMAXCHANS_${DIAL_TRUNK}} ]', 'chanfull'));
1811       $ext->add($context, $exten, 'nomax', new ext_gotoif('$["${INTRACOMPANYROUTE}" = "YES"]', 'skipoutcid'));  // Set to YES if treated like internal
1812       $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK_OPTIONS', '${TRUNK_OPTIONS}'));
1813       $ext->add($context, $exten, '', new ext_macro('outbound-callerid', '${DIAL_TRUNK}'));
1814       $ext->add($context, $exten, 'skipoutcid', new ext_execif('$["${PREFIX_TRUNK_${DIAL_TRUNK}}" != ""]','AGI','fixlocalprefix'));  // this sets DIAL_NUMBER to the proper dial string for this trunk
1815       $ext->add($context, $exten, '', new ext_set('OUTNUM', '${OUTPREFIX_${DIAL_TRUNK}}${DIAL_NUMBER}'));  // OUTNUM is the final dial number
1816
1817       // Back to normal processing, whether intracompany or not.
1818       // But add the macro-setmusic if we don't want music on this outbound call
1819       $ext->add($context, $exten, '', new ext_execif('$[$["${MOHCLASS}" != "default"] & $["${MOHCLASS}" != ""]]', 'Set', 'DIAL_TRUNK_OPTIONS=M(setmusic^${MOHCLASS})${DIAL_TRUNK_OPTIONS}'));
1820    
1821       // This macro call will always be blank and is provided as a hook for customization required prior to making a call
1822       // such as adding SIP header information or other requirements. All the channel variables from above are present
1823      
1824       $ext->add($context, $exten, 'gocall', new ext_macro('dialout-dundi-predial-hook'));
1825       $ext->add($context, $exten, '', new ext_gotoif('$["${PREDIAL_HOOK_RET}" = "BYPASS"]', 'bypass,1'));
1826    
1827       $ext->add($context, $exten, '', new ext_gotoif('$["${custom}" = "AMP"]', 'customtrunk'));
1828
1829       $ext->add($context, $exten, '', new ext_macro('dundi-${DIAL_TRUNK}','${OUTNUM}'));
1830       $ext->add($context, $exten, '', new ext_goto(1, 's-${DIALSTATUS}'));
1831      
1832       $ext->add($context, $exten, 'chanfull', new ext_noop('max channels used up'));
1833    
1834       $exten = 's-BUSY';
1835       $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting BUSY - giving up'));
1836       $ext->add($context, $exten, '', new ext_playtones('busy'));
1837       $ext->add($context, $exten, '', new ext_busy(20));
1838    
1839       $exten = 's-NOANSWER';
1840       $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting NOANSWER - giving up'));
1841       $ext->add($context, $exten, '', new ext_playtones('congestion'));
1842       $ext->add($context, $exten, '', new ext_congestion(20));
1843    
1844       $exten = 's-CANCEL';
1845       $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting CANCEL - giving up'));
1846       $ext->add($context, $exten, '', new ext_playtones('congestion'));
1847       $ext->add($context, $exten, '', new ext_congestion(20));
1848    
1849       $exten = '_s-.';
1850       $ext->add($context, $exten, '', new ext_gotoif('$["x${OUTFAIL_${ARG1}}" = "x"]', 'noreport'));
1851       $ext->add($context, $exten, '', new ext_agi('${OUTFAIL_${ARG1}}'));
1852       $ext->add($context, $exten, 'noreport', new ext_noop('TRUNK Dial failed due to ${DIALSTATUS} - failing through to other trunks'));
1853      
1854       $ext->add($context, 'disabletrunk', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} DISABLED - falling through to next trunk'));
1855       $ext->add($context, 'bypass', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} BYPASSING because dialout-dundi-predial-hook'));
1856    
1857       $ext->add($context, 'h', '', new ext_macro('hangupcall'));
1858
1859
1860
1861       /*
1862        * sets the callerid of the device to that of the logged in user
1863        *
1864        * ${AMPUSER} is set upon return to the real user despite any aliasing that may
1865        * have been set as a result of the AMPUSER/<nnn>/cidnum field. This is used by
1866        * features like DND, CF, etc. to set the proper structure on aliased instructions
1867        */
1868       $context = 'macro-user-callerid';
1869       $exten = 's';
1870      
1871       //$ext->add($context, $exten, '', new ext_noop('user-callerid: ${CALLERID(name)} ${CALLERID(number)}'));
1872              
1873       // make sure AMPUSER is set if it doesn't get set below     
1874       $ext->add($context, $exten, '', new ext_set('AMPUSER', '${IF($["foo${AMPUSER}" = "foo"]?${CALLERID(number)}:${AMPUSER})}'));
1875       $ext->add($context, $exten, '', new ext_gotoif('$["${CHANNEL:0:5}" = "Local"]', 'report'));
1876       $ext->add($context, $exten, '', new ext_execif('$["${REALCALLERIDNUM:1:2}" = ""]', 'Set', 'REALCALLERIDNUM=${CALLERID(number)}'));
1877       //$ext->add($context, $exten, 'start', new ext_noop('REALCALLERIDNUM is ${REALCALLERIDNUM}'));
1878       $ext->add($context, $exten, '', new ext_set('AMPUSER', '${DB(DEVICE/${REALCALLERIDNUM}/user)}'));
1879       $ext->add($context, $exten, '', new ext_set('AMPUSERCIDNAME', '${DB(AMPUSER/${AMPUSER}/cidname)}'));
1880       $ext->add($context, $exten, '', new ext_gotoif('$["x${AMPUSERCIDNAME:1:2}" = "x"]', 'report'));
1881
1882       // user may masquerade as a different user internally, so set the internal cid as indicated
1883       // but keep the REALCALLERID which is used to determine their true identify and lookup info
1884       // during outbound calls.
1885       $ext->add($context, $exten, '', new ext_set('AMPUSERCID', '${IF($["${DB_EXISTS(AMPUSER/${AMPUSER}/cidnum)}" = "1"]?${DB_RESULT}:${AMPUSER})}'));
1886       $ext->add($context, $exten, '', new ext_set('CALLERID(all)', '"${AMPUSERCIDNAME}" <${AMPUSERCID}>'));
1887       /*
1888        * This is where to splice in things like setting the language based on a user's astdb setting,
1889        * or where you might set the CID account code based on a user instead of the device settings.
1890        */
1891       $ext->add($context, $exten, 'report', new ext_gotoif('$[ "${ARG1}" = "SKIPTTL" ]', 'continue'));
1892       $ext->add($context, $exten, 'report2', new ext_set('__TTL', '${IF($["foo${TTL}" = "foo"]?64:$[ ${TTL} - 1 ])}'));
1893       $ext->add($context, $exten, '', new ext_gotoif('$[ ${TTL} > 0 ]', 'continue'));
1894       $ext->add($context, $exten, '', new ext_wait('${RINGTIMER}'));  // wait for a while, to give it a chance to be picked up by voicemail
1895       $ext->add($context, $exten, '', new ext_answer());
1896       $ext->add($context, $exten, '', new ext_wait('2'));
1897       $ext->add($context, $exten, '', new ext_playback('im-sorry&an-error-has-occured&with&call-forwarding'));
1898       $ext->add($context, $exten, '', new ext_macro('hangupcall'));
1899       $ext->add($context, $exten, '', new ext_congestion(20));
1900       $ext->add($context, $exten, 'continue', new ext_noop('Using CallerID ${CALLERID(all)}'));
1901       $ext->add($context, 'h', '', new ext_macro('hangupcall'));
1902      
1903       /*
1904        * arg1 = trunk number, arg2 = number
1905        *
1906        * Re-written to use enumlookup.agi
1907        */
1908  
1909       $context = 'macro-dialout-enum';
1910       $exten = 's';
1911  
1912       $ext->add($context, $exten, '', new ext_gosubif('$[$["${ARG3}" != ""] & $["${DB(AMPUSER/${AMPUSER}/pinless)}" != "NOPASSWD"]]','sub-pincheck,s,1'));
1913       $ext->add($context, $exten, '', new ext_macro('outbound-callerid', '${ARG1}'));
1914       $ext->add($context, $exten, '', new ext_set('OUTBOUND_GROUP', 'OUT_${ARG1}'));
1915       $ext->add($context, $exten, '', new ext_gotoif('$["${OUTMAXCHANS_${ARG1}}foo" = "foo"]', 'nomax'));
1916       $ext->add($context, $exten, '', new ext_gotoif('$[ ${GROUP_COUNT(OUT_${ARG1})} >= ${OUTMAXCHANS_${ARG1}} ]', 'nochans'));
1917       $ext->add($context, $exten, 'nomax', new ext_set('DIAL_NUMBER', '${ARG2}'));
1918       $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK', '${ARG1}'));
1919       $ext->add($context, $exten, '', new ext_execif('$["${PREFIX_TRUNK_${DIAL_TRUNK}}" != ""]','AGI','fixlocalprefix'));  // this sets DIAL_NUMBER to the proper dial string for this trunk
1920       //  Replacement for asterisk's ENUMLOOKUP function
1921       $ext->add($context, $exten, '', new ext_agi('enumlookup.agi'));
1922       // Now we have the variable DIALARR set to a list of URI's that can be called, in order of priority
1923       // Loop through them trying them in order.
1924       $ext->add($context, $exten, 'dialloop', new ext_gotoif('$["foo${DIALARR}"="foo"]', 'end'));
1925       $ext->add($context, $exten, '', new ext_set('TRYDIAL', '${CUT(DIALARR,%,1)}'));
1926       $ext->add($context, $exten, '', new ext_set('DIALARR', '${CUT(DIALARR,%,2-)}'));
1927       $ext->add($context, $exten, '', new ext_dial('${TRYDIAL}', ''));
1928       $ext->add($context, $exten, '', new ext_noop('Dial exited in macro-enum-dialout with ${DIALSTATUS}'));
1929       // Now, if we're still here, that means the Dial failed for some reason.
1930       // If it's CONGESTION or CHANUNAVAIL we want to try again on a different
1931       // different channel. If there's no more left, the dialloop tag will exit.
1932       $ext->add($context, $exten, '', new ext_gotoif('$[ $[ "${DIALSTATUS}" = "CHANUNAVAIL" ] | $[ "${DIALSTATUS}" = "CONGESTION" ] ]', 'dialloop'));
1933       // If we're here, then it's BUSY or NOANSWER or something and well, deal with it.
1934       $ext->add($context, $exten, 'dialfailed', new ext_goto(1, 's-${DIALSTATUS}'));
1935       // Here are the exit points for the macro.
1936       $ext->add($context, $exten, 'nochans', new ext_noop('max channels used up'));
1937       $ext->add($context, $exten, 'end', new ext_noop('Exiting macro-dialout-enum'));
1938       $ext->add($context, 's-BUSY', '', new ext_noop('Trunk is reporting BUSY'));
1939       $ext->add($context, 's-BUSY', '', new ext_busy(20));
1940       $ext->add($context, '_s-.', '', new ext_noop('Dial failed due to ${DIALSTATUS}'));     
1941      
1942       /*
1943        * overrides callerid out trunks
1944        * arg1 is trunk
1945        * macro-user-callerid should be called _before_ using this macro
1946        */
1947
1948       $context = 'macro-outbound-callerid';
1949       $exten = 's';
1950      
1951       // If we modified the caller presence, set it back. This allows anonymous calls to be internally prepended but keep
1952       // their status if forwarded back out. Not doing this can result in the trunk CID being displayed vs. 'blocked call'
1953       //
1954       if ($ast_lt_16) {
1955         $ext->add($context, $exten, '', new ext_execif('$["${CALLINGPRES_SV}" != ""]', 'SetCallerPres', '${CALLINGPRES_SV}'));
1956       } else {
1957         $ext->add($context, $exten, '', new ext_execif('$["${CALLINGPRES_SV}" != ""]', 'Set', 'CALLERPRES()=${CALLINGPRES_SV}'));
1958       }
1959
1960       // Keep the original CallerID number, for failover to the next trunk.
1961
1962       $ext->add($context, $exten, '', new ext_execif('$["${REALCALLERIDNUM:1:2}" = ""]', 'Set', 'REALCALLERIDNUM=${CALLERID(number)}'));
1963       // If this came through a ringgroup or CF, then we want to retain original CID unless
1964       // OUTKEEPCID_${trunknum} is set.
1965       // Save then CIDNAME while it is still intact in case we end up sending out this same CID
1966       $ext->add($context, $exten, 'start', new ext_gotoif('$[ $["${REALCALLERIDNUM}" = ""] | $["${KEEPCID}" != "TRUE"] | $["${OUTKEEPCID_${ARG1}}" = "on"] ]', 'normcid'));  // Set to TRUE if coming from ringgroups, CF, etc.
1967       $ext->add($context, $exten, '', new ext_set('USEROUTCID', '${REALCALLERIDNUM}'));
1968       //$ext->add($context, $exten, '', new ext_set('REALCALLERIDNAME', '${CALLERID(name)}'));
1969
1970       // We now have to make sure the CID is valid. If we find an AMPUSER with the same CID, we assume it is an internal
1971       // call (would be quite a conincidence if not) and go through the normal processing to get that CID. If a device
1972       // is set for this CID, then it must be internal
1973       // If we end up using USEROUTCID at the end, it may still be the REALCALLERIDNUM we saved above. That is determined
1974       // if the two are equal, AND there is no CALLERID(name) present since it has been removed by the CALLERID(all)=${USEROUTCID}
1975       // setting. If this is the case, then we put the orignal name back in to send out. Although the CNAME is not honored by most
1976       // carriers, there are cases where it is so this preserves that information to be used by those carriers who do honor it.
1977       $ext->add($context, $exten, '', new ext_gotoif('$["foo${DB(AMPUSER/${REALCALLERIDNUM}/device)}" = "foo"]', 'bypass'));
1978
1979       $ext->add($context, $exten, 'normcid', new ext_set('USEROUTCID', '${DB(AMPUSER/${AMPUSER}/outboundcid)}'));
1980       $ext->add($context, $exten, 'bypass', new ext_set('EMERGENCYCID', '${DB(DEVICE/${REALCALLERIDNUM}/emergency_cid)}'));
1981       $ext->add($context, $exten, '', new ext_set('TRUNKOUTCID', '${OUTCID_${ARG1}}'));
1982       $ext->add($context, $exten, '', new ext_gotoif('$[ $["${EMERGENCYROUTE:1:2}" = ""] | $["${EMERGENCYCID:1:2}" = ""] ]', 'trunkcid'));  // check EMERGENCY ROUTE
1983       $ext->add($context, $exten, '', new ext_set('CALLERID(all)', '${EMERGENCYCID}'));  // emergency cid for device
1984       $ext->add($context, $exten, 'exit', new ext_macroexit());
1985
1986
1987       $ext->add($context, $exten, 'trunkcid', new ext_execif('$["${TRUNKOUTCID:1:2}" != ""]', 'Set', 'CALLERID(all)=${TRUNKOUTCID}'));
1988
1989       $ext->add($context, $exten, 'usercid', new ext_execif('$["${USEROUTCID:1:2}" != ""]', 'Set', 'CALLERID(all)=${USEROUTCID}'));  // check CID override for extension
1990       if ($ast_lt_16) {
1991         $ext->add($context, $exten, 'hidecid', new ext_execif('$["${CALLERID(name)}"="hidden"]', 'SetCallerPres', 'prohib_passed_screen'));
1992       } else {
1993         $ext->add($context, $exten, 'hidecid', new ext_execif('$["${CALLERID(name)}"="hidden"]', 'Set', 'CALLERPRES()=prohib_passed_screen'));
1994       }
1995       //$ext->add($context, $exten, 'checkname', new ext_execif('$[ $[ "${CALLERID(number)}" = "${REALCALLERIDNUM}" ] & $[ "${CALLERID(name)}" = "" ] ]', 'Set', 'CALLERID(name)=${REALCALLERIDNAME}'));
1996
1997      
1998
1999       $context = 'macro-systemrecording';
2000      
2001       //exten => s,1,Set(RECFILE=${IF($["${ARG2}" = ""]?/tmp/${AMPUSER}-ivrrecording:${ARG2})})
2002       $ext->add($context, 's', '', new ext_setvar('RECFILE','${IF($["${ARG2}" = ""]?/tmp/${AMPUSER}-ivrrecording:${ARG2})}'));
2003       $ext->add($context, 's', '', new ext_execif('$["${ARG3}" != ""]','Authenticate','${ARG3}'));
2004       $ext->add($context, 's', '', new ext_goto(1, '${ARG1}'));
2005      
2006       $exten = 'dorecord';
2007      
2008       // Delete all versions of the current sound file (does not consider languages though
2009       // otherwise you might have some versions that are not re-recorded
2010       //
2011       $ext->add($context, $exten, '', new ext_system('rm ${ASTVARLIBDIR}/sounds/${RECFILE}.*'));
2012       $ext->add($context, $exten, '', new ext_record('${RECFILE}:wav'));
2013       $ext->add($context, $exten, '', new ext_wait(1));
2014       $ext->add($context, $exten, '', new ext_goto(1, 'confmenu'));
2015
2016       $exten = 'docheck';
2017      
2018       $ext->add($context, $exten, '', new ext_playback('beep'));
2019       if ($ast_ge_14) {
2020         $ext->add($context, $exten, 'dc_start', new ext_background('${RECFILE},m,${CHANNEL(language)},macro-systemrecording'));
2021       } else {
2022         $ext->add($context, $exten, 'dc_start', new ext_background('${RECFILE},m,${LANGUAGE},macro-systemrecording'));
2023       }
2024       $ext->add($context, $exten, '', new ext_wait(1));
2025       $ext->add($context, $exten, '', new ext_goto(1, 'confmenu'));
2026
2027       $exten = 'confmenu';
2028       if ($ast_ge_14) {
2029         $ext->add($context, $exten, '', new ext_background('to-listen-to-it&press-1&to-rerecord-it&press-star&astcc-followed-by-pound,m,${CHANNEL(language)},macro-systemrecording'));
2030       } else {
2031         $ext->add($context, $exten, '', new ext_background('to-listen-to-it&press-1&to-rerecord-it&press-star&astcc-followed-by-pound,m,${LANGUAGE},macro-systemrecording'));
2032       }
2033       $ext->add($context, $exten, '', new ext_read('RECRESULT', '', 1, '', '', 4));
2034       $ext->add($context, $exten, '', new ext_gotoif('$["x${RECRESULT}"="x*"]', 'dorecord,1'));
2035       $ext->add($context, $exten, '', new ext_gotoif('$["x${RECRESULT}"="x1"]', 'docheck,2'));
2036       $ext->add($context, $exten, '', new ext_goto(1));
2037      
2038       $ext->add($context, '1', '', new ext_goto('dc_start', 'docheck'));
2039       $ext->add($context, '*', '', new ext_goto(1, 'dorecord'));
2040      
2041       $ext->add($context, 't', '', new ext_playback('goodbye'));
2042       $ext->add($context, 't', '', new ext_hangup());
2043      
2044       $ext->add($context, 'i', '', new ext_playback('pm-invalid-option'));
2045       $ext->add($context, 'i', '', new ext_goto(1, 'confmenu'));
2046
2047       $ext->add($context, 'h', '', new ext_hangup());
2048
2049      
2050       $context = 'from-zaptel';
2051       $exten = '_X.';
2052      
2053       $ext->add($context, $exten, '', new ext_set('DID', '${EXTEN}'));
2054       $ext->add($context, $exten, '', new ext_goto(1, 's'));
2055
2056       $exten = 's';
2057       $ext->add($context, $exten, '', new ext_noop('Entering from-zaptel with DID == ${DID}'));
2058       // Some trunks _require_ a RINGING be sent before an Answer.
2059       $ext->add($context, $exten, '', new ext_ringing());
2060       // If ($did == "") { $did = "s"; }
2061       $ext->add($context, $exten, '', new ext_set('DID', '${IF($["${DID}"= ""]?s:${DID})}'));
2062       $ext->add($context, $exten, '', new ext_noop('DID is now ${DID}'));
2063       if ($chan_dahdi) {
2064         $ext->add($context, $exten, '', new ext_gotoif('$["${CHANNEL:0:5}"="DAHDI"]', 'zapok', 'notzap'));
2065       } else {
2066         $ext->add($context, $exten, '', new ext_gotoif('$["${CHANNEL:0:3}"="Zap"]', 'zapok', 'notzap'));
2067       }
2068       $ext->add($context, $exten, 'notzap', new ext_goto('1', '${DID}', 'from-pstn'));
2069       // If there's no ext-did,s,1, that means there's not a no did/no cid route. Hangup.
2070       $ext->add($context, $exten, '', new ext_macro('Hangupcall', 'dummy'));
2071       $ext->add($context, $exten, 'zapok', new ext_noop('Is a Zaptel Channel'));
2072       if ($chan_dahdi) {
2073         $ext->add($context, $exten, '', new ext_set('CHAN', '${CHANNEL:6}'));
2074       } else {
2075         $ext->add($context, $exten, '', new ext_set('CHAN', '${CHANNEL:4}'));
2076       }       
2077       $ext->add($context, $exten, '', new ext_set('CHAN', '${CUT(CHAN,-,1)}'));
2078       $ext->add($context, $exten, '', new ext_macro('from-zaptel-${CHAN}', '${DID},1'));
2079       // If nothing there, then treat it as a DID
2080       $ext->add($context, $exten, '', new ext_noop('Returned from Macro from-zaptel-${CHAN}'));
2081       $ext->add($context, $exten, '', new ext_goto(1, '${DID}', 'from-pstn'));
2082       $ext->add($context, 'fax', '', new ext_goto(1, 'in_fax', 'ext-fax'));
2083
2084       /*
2085       * vm-callme context plays voicemail over telephone for web click-to-call
2086       * MSG and MBOX are channel variables that must be set when originating the call
2087       */
2088
2089       $context = 'vm-callme';
2090
2091       $ext->add($context, 's', '', new ext_answer());
2092       $ext->add($context, 's', '', new ext_wait(1));
2093       $ext->add($context, 's', 'repeat', new ext_background('${MSG}&silence/2&vm-repeat&vm-starmain'));
2094       $ext->add($context, 's', '', new ext_waitexten(15));
2095
2096       $ext->add($context, '5', '', new ext_goto('repeat', 's'));
2097
2098       $ext->add($context, '#', '', new ext_playback('vm-goodbye'));
2099       $ext->add($context, '#', '', new ext_hangup());
2100
2101       $ext->add($context, '*', '', new ext_macro('get-vmcontext', '${MBOX}'));
2102       $ext->add($context, '*', '', new ext_vmmain('${MBOX}@${VMCONTEXT},s'));
2103
2104       $ext->add($context, 'i', '', new ext_playback('pm-invalid-option'));
2105       $ext->add($context, 'i', '', new ext_goto('repeat', 's'));
2106
2107       $ext->add($context, 't', '', new ext_playback('vm-goodbye'));
2108       $ext->add($context, 't', '', new ext_hangup());
2109
2110       $ext->add($context, 'h', '', new ext_hangup());
2111
2112       /* end vm-callme context  */
2113
2114       /*
2115       * macro-vm
2116       */
2117      
2118       /*
2119                         ;------------------------------------------------------------------------
2120                         ; [macro-vm]
2121                         ;------------------------------------------------------------------------
2122                         ; CONTEXT:      macro-vm
2123                         ; PURPOSE:      call voicemail system and extend with personal ivr
2124                         ;
2125                         ; Under normal use, this macro will call the voicemail system with the extension and
2126                         ; desired greeting mode of busy, unavailable or as specified with direct voicemail
2127                         ; calls (usually unavailable) when entered from destinations.
2128                         ;
2129                         ; The voicemail system's two greetings have been 'hijacked' as follows to extend the
2130                         ; system by giving the option of a private 'ivr' for each voicemail user. The following
2131                         ; applies to both the busy and unavailable modes of voicemail and can be applied to one
2132                         ; or both, and differently.
2133                         ;
2134                         ; Global Defaults:
2135                         ;
2136                         ; The following are default values, used in both busy and unavail modes if no specific
2137                         ; values are specified.
2138                         ;
2139                         ; VMX_REPEAT
2140                         ;                                       The number of times to repeat the users message if no option is pressed.
2141                         ; VMX_TIMEOUT
2142                         ;                                       The timeout to wait after playing message before repeating or giving up.
2143                         ; VMX_LOOPS
2144                         ;                                       The number of times it should replay the message and check for an option when
2145                         ;                                       an invalid option is pressed.
2146                         ;
2147                         ; VMX_OPTS_DOVM
2148                         ;                                       Default voicemail option to use if vm is chosen as an option. No options will
2149                         ;                                       cause Allison's generic message, 's' will go straight to beep.
2150                         ; VMX_OPTS_TIMEOUT
2151                         ;                                       Default voicemail option to use if it times out with no options. No options will
2152                         ;                                       cause Allison's generic message, 's' will go straight to beep.
2153                         ;                                       IF THE USER PRESSES # - it will look like a timeout as well since no option will
2154                         ;                                       be presented. If the user wishes to enable a mode where a caller can press #
2155                         ;                                       during their message and it goes straight to voicemail with only a 'beep' then
2156                         ;                                       this should be set to 's'.
2157                         ; VMX_OPTS_LOOPS
2158                         ;                                       Default voicemail option to use if to many wrong options occur. No options will
2159                         ;                                       cause Allison's generic message, 's' will go straight to beep.
2160                         ;
2161                         ; VMX_CONTEXT
2162                         ;                                       Default context for user destinations if not supplied in the user's settings
2163                         ; VMX_PRI
2164                         ;                                       Default priority for user destinations if not supplied in the user's settings
2165                         ;
2166                         ; VMX_TIMEDEST_CONTEXT
2167                         ;                                       Default context for timeout destination if not supplied in the user's settings
2168                         ; VMX_TIMEDEST_EXT
2169                         ;                                       Default extension for timeout destination if not supplied in the user's settings
2170                         ; VMX_TIMEDEST_PRI
2171                         ;                                       Default priority for timeout destination if not supplied in the user's settings
2172                         ;
2173                         ; VMX_LOOPDEST_CONTEXT
2174                         ;                                       Default context for loops  destination if not supplied in the user's settings
2175                         ; VMX_LOOPDEST_EXT
2176                         ;                                       Default extension for loops  destination if not supplied in the user's settings
2177                         ; VMX_LOOPDEST_PRI
2178                         ;                                       Default priority for loops  destination if not supplied in the user's settings
2179                         ;
2180                         ;
2181                         ; The AMPUSER database variable has been extended with a 'vmx' tree (vm-extension). A
2182                         ; duplicate set is included for both unavail and busy. You could choose for to have an
2183                         ; ivr when unavail is taken, but not with busy - or a different once with busy.
2184                         ; The full list is below, each specific entry is futher described:
2185                         ;
2186                         ; state:                Whether teh current mode is enabled or disabled. Anything but 'enabled' is
2187                         ;                                               treated as disabled.
2188                         ; repeat:               This is the number of times that the users message should be played after the
2189                         ;                                               timeout if the user has not entered anything. It is just a variable to the
2190                         ;                                               Read() function which will do the repeating.
2191                         ; timeout:      This is how long to wait after the message has been read for a response from
2192                         ;                                               the user. A caller can enter a digit any time during the playback.
2193                         ; loops:                This is the number of loops that the system will allow a caller to retry if
2194                         ;                                               they enter a bad menu choice, before going to the loop failover destination
2195                         ; vmxopts:      This is the vm options to send to the voicemail command used when a specific
2196                         ;                                               voicemail destination is chosen (inidcated by 'dovm' in the ext field). This is
2197                         ;                                               typically either set to 's' or left blank. When set to 's' there will be no
2198                         ;                                               message played when entering the voicemail, just a beep. When blank, you will
2199                         ;                                               have Allison's generic message played. It is not typical to play the greetings
2200                         ;                                               since they have been 'hijacked' for these IVR's and from a caller's perspecitive
2201                         ;                                               this system appears interconnected with the voicemail so instructions can be
2202                         ;                                               left there.
2203                         ; timedest: The three variables: ext, context and pri are the goto destination if the caller
2204                         ;                                               enters no options and it timesout. None have to be set and a system default
2205                         ;                                               will be used. If just ext is set, then defaults will be used for context and
2206                         ;                                               pri, etc.
2207                         ; loopdest:     This is identical to timedest but used if the caller exceeds the maximum invalid
2208                         ;                                               menu choices.
2209                         ; [0-9*]:               The user can specify up to 11 ivr options, all as single digits from 0-9 or *. The
2210                         ;                                               # key can not be used since it is used as a terminator key for the Read command
2211                         ;                                               and will never be returned. A minimum of the ext must be specified for each valid
2212                         ;                                               option and as above, the context and priority can also be specified if the default
2213                         ;                                               is not to be used.
2214                         ;                                               Option '0' takes on a special meaning. Since a user is able to break out of the
2215                         ;                                               voicemail command once entering it with a 0, if specified, the 0 destination will
2216                         ;                                               be used.
2217                         ;                                               Option '*' can also be used to breakout. It is undecided at this point whether
2218                         ;                                               providing that option will be used as well. (probably should).
2219                         ;
2220                         ;
2221                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/state:                                                              enabled|disabled
2222                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/repeat:                                                             n (times to repeat message)
2223                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/timeout:                                                    n (timeout to wait for digit)
2224                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/loops:                                                              n (loop returies for invalid entries)
2225                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/vmxopts/dovm:                                       vmoptions (if ext is dovm)
2226                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/vmxopts/timeout:                    vmoptions (if timeout)
2227                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/vmxopts/loops:                              vmoptions (if loops)
2228                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/timedest/ext:                                       extension (if timeout)
2229                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/timedest/context:                   context (if timeout)
2230                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/timedest/pri:                                       priority (if timeout)
2231                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/loopdest/ext:                                       extension (if too many failures)
2232                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/loopdest/context:                   context (if too many failures)
2233                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/loopdest/pri:                                       priority (if too many failures)
2234                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/[0-9*]/ext:                                         extension (dovm for vm access)
2235                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/[0-9*]/context:                             context
2236                         ; /AMPUSER/<ext>/vmx/[busy|unavail]/[0-9*]/pri:                                         priority
2237                         ;------------------------------------------------------------------------
2238
2239       */
2240       // ARG1 - extension
2241       // ARG2 - DIRECTDIAL/BUSY
2242       // ARG3 - RETURN makes macro return, otherwise hangup
2243       //
2244       $ext->add('macro-vm', 's', '', new ext_macro('user-callerid', 'SKIPTTL'));
2245       $ext->add('macro-vm','s', '', new ext_setvar("VMGAIN", '${IF($["foo${VM_GAIN}"!="foo"]?"g(${VM_GAIN})":"")}'));
2246
2247       // If BLKVM_OVERRIDE is set, then someone told us to block calls from going to
2248       // voicemail. This variable is reset by the answering channel so subsequent
2249       // transfers will properly function.
2250       //
2251       $ext->add('macro-vm','s', '', new ext_gotoif('$["foo${DB(${BLKVM_OVERRIDE})}" != "fooTRUE"]','vmx,1'));
2252
2253       // we didn't branch so block this from voicemail
2254       //
2255       $ext->add('macro-vm','s', '', new ext_NoOp('CAME FROM: ${NODEST} - Blocking VM cause of key: ${DB(BLKVM_OVERRIDE)}'));
2256       $ext->add('macro-vm','s', '', new ext_hangup(''));
2257
2258       // If vmx not enabled for the current mode,then jump to normal voicemail behavior
2259       // also - if not message (no-msg) is requested, straight to voicemail
2260       //
2261
2262       $ext->add('macro-vm','vmx', '', new ext_setvar("MEXTEN", '${ARG1}'));
2263       $ext->add('macro-vm','vmx', '', new ext_setvar("MMODE", '${ARG2}'));
2264       $ext->add('macro-vm','vmx', '', new ext_setvar("RETVM", '${ARG3}'));
2265       $ext->add('macro-vm','vmx', '', new ext_setvar("MODE", '${IF($["${MMODE}"="BUSY"]?busy:unavail)}'));
2266
2267       // If this use has individual option set for playing standardized message, then override the global option
2268       //
2269       $ext->add('macro-vm','vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/vmxopts/timeout)}" = "0"]','chknomsg'));
2270       $ext->add('macro-vm','vmx', '', new ext_setvar("VM_OPTS", '${DB_RESULT}'));
2271
2272       $ext->add('macro-vm','vmx', 'chknomsg', new ext_gotoif('$["${MMODE}"="NOMESSAGE"]','s-${MMODE},1'));
2273       $ext->add('macro-vm','vmx', '', new ext_gotoif('$["${MMODE}" != "DIRECTDIAL"]','notdirect'));
2274       $ext->add('macro-vm','vmx', '', new ext_setvar("MODE", '${IF($["${REGEX("[b]" ${VM_DDTYPE})}" = "1"]?busy:${MODE})}'));
2275       $ext->add('macro-vm','vmx', 'notdirect', new ext_NoOp('Checking if ext ${MEXTEN} is enabled: ${DB(AMPUSER/${MEXTEN}/vmx/${MODE}/state)}'));
2276       $ext->add('macro-vm','vmx', '', new ext_gotoif('$["${DB(AMPUSER/${MEXTEN}/vmx/${MODE}/state)}" != "enabled"]','s-${MMODE},1'));
2277
2278       // If the required voicemail file does not exist, then abort and go to normal voicemail behavior
2279       //
2280       // If 1.4 or above, use the STAT function to check for the file. Prior to 1.4, use the AGI script since the System() command tried
2281       // in the past had errors.
2282       //
2283       $ext->add('macro-vm', 'vmx', '', new ext_macro('get-vmcontext', '${MEXTEN}'));     
2284       //$ext->add('macro-vm', 'vmx', '', new ext_trysystem('/bin/ls ${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/${MODE}.[wW][aA][vV]'));
2285       if ($ast_ge_14) {
2286         $ext->add('macro-vm','vmx', '', new ext_gotoif('$[(${STAT(f,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/temp.wav)} = 1) || (${STAT(f,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/temp.WAV)} = 1)]','tmpgreet'));
2287         $ext->add('macro-vm','vmx', '', new ext_gotoif('$[(${STAT(f,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/${MODE}.wav)} = 0) && (${STAT(f,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/${MODE}.WAV)} = 0)]','nofile'));
2288       } else {
2289         $ext->add('macro-vm', 'vmx', '',new ext_agi('checksound.agi,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/temp'));
2290         $ext->add('macro-vm','vmx', '', new ext_gotoif('$["${SYSTEMSTATUS}" = "SUCCESS"]','tmpgreet'));
2291         $ext->add('macro-vm', 'vmx', '',new ext_agi('checksound.agi,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/${MODE}'));
2292         $ext->add('macro-vm','vmx', '', new ext_gotoif('$["${SYSTEMSTATUS}" != "SUCCESS"]','nofile'));
2293       }
2294
2295       $ext->add('macro-vm','vmx', '', new ext_setvar("LOOPCOUNT", '0'));     
2296       $ext->add('macro-vm','vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/repeat)}" = "0"]','vmxtime'));
2297       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_REPEAT", '${DB_RESULT}'));
2298       $ext->add('macro-vm','vmx', 'vmxtime', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timeout)}" = "0"]','vmxloops'));
2299       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_TIMEOUT", '${DB_RESULT}'));
2300       $ext->add('macro-vm','vmx', 'vmxloops', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loops)}" = "0"]','vmxanswer'));
2301       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_LOOPS", '${DB_RESULT}'));
2302       $ext->add('macro-vm','vmx','vmxanswer',new ext_answer(''));
2303
2304       // Now play the users voicemail recording as the basis for their ivr, the Read command will repeat as needed and if it timesout
2305       // then we go to the timeout. Otherwise handle invalid options by looping until the limit until a valid option is played.
2306       //
2307       $ext->add('macro-vm','vmx','loopstart',new ext_read('ACTION', '${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/${MODE}', 1, 'skip', '${VMX_REPEAT}', '${VMX_TIMEOUT}'));
2308       $ext->add('macro-vm','vmx', '', new ext_gotoif('$["${EXISTS(${ACTION})}" = "1"]','checkopt'));
2309
2310       // If we are here we timed out, go to the required destination
2311       //
2312       $ext->add('macro-vm','vmx', 'noopt', new ext_NoOp('Timeout: going to timeout dest'));     
2313       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_OPTS", '${VMX_OPTS_TIMEOUT}'));
2314       $ext->add('macro-vm','vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/vmxopts/timeout)}" = "0"]','chktime'));
2315       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_OPTS", '${DB_RESULT}'));
2316       $ext->add('macro-vm','vmx', 'chktime', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timedest/ext)}" = "0"]','dotime'));
2317       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_TIMEDEST_EXT",'${DB_RESULT}'));
2318       $ext->add('macro-vm','vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timedest/context)}" = "0"]','timepri'));
2319       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_TIMEDEST_CONTEXT",'${DB_RESULT}'));
2320       $ext->add('macro-vm','vmx', 'timepri', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timedest/pri)}" = "0"]','dotime'));
2321       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_TIMEDEST_PRI",'${DB_RESULT}'));
2322       $ext->add('macro-vm','vmx','dotime',new ext_goto('${VMX_TIMEDEST_PRI}', '${VMX_TIMEDEST_EXT}', '${VMX_TIMEDEST_CONTEXT}'));
2323
2324       // We got an option, check if the option is defined, or one of the system defaults
2325       //
2326       $ext->add('macro-vm','vmx', 'checkopt', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/${ACTION}/ext)}" = "1"]','doopt'));
2327       $ext->add('macro-vm','vmx', '', new ext_gotoif('$["${ACTION}" = "0"]','o,1'));
2328       $ext->add('macro-vm','vmx', '', new ext_gotoif('$["${ACTION}" = "*"]','adef,1'));
2329
2330       // Got invalid option loop until the max
2331       //
2332       $ext->add('macro-vm','vmx', '', new ext_setvar("LOOPCOUNT",'$[${LOOPCOUNT} + 1]'));
2333       $ext->add('macro-vm','vmx', '', new ext_gotoif('$[${LOOPCOUNT} > ${VMX_LOOPS}]','toomany'));
2334       $ext->add('macro-vm','vmx','',new ext_playback('pm-invalid-option&please-try-again'));     
2335       $ext->add('macro-vm','vmx','',new ext_goto('loopstart'));
2336
2337       // tomany: to many invalid options, go to the specified destination
2338       //
2339       $ext->add('macro-vm','vmx', 'toomany', new ext_NoOp('Too Many invalid entries, got to invalid dest'));     
2340       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_OPTS",'${VMX_OPTS_LOOPS}'));
2341       $ext->add('macro-vm','vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/vmxopts/loops)}" = "0"]','chkloop'));
2342       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_OPTS",'${DB_RESULT}'));
2343       $ext->add('macro-vm','vmx', 'chkloop', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loopdest/ext)}" = "0"]','doloop'));
2344       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_LOOPDEST_EXT",'${DB_RESULT}'));
2345       $ext->add('macro-vm','vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loopdest/context)}" = "0"]','looppri'));
2346       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_LOOPDEST_CONTEXT",'${DB_RESULT}'));
2347       $ext->add('macro-vm','vmx', 'looppri', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loopdest/pri)}" = "0"]','doloop'));
2348       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_LOOPDEST_PRI",'${DB_RESULT}'));
2349       $ext->add('macro-vm','vmx','doloop',new ext_goto('${VMX_LOOPDEST_PRI}','${VMX_LOOPDEST_EXT}','${VMX_LOOPDEST_CONTEXT}'));
2350
2351       // doopt: execute the valid option that was chosen
2352       //
2353       $ext->add('macro-vm','vmx', 'doopt', new ext_NoOp('Got a valid option: ${DB_RESULT}'));     
2354       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_EXT",'${DB_RESULT}'));
2355
2356       // Special case, if this option was to go to voicemail, set options and go
2357       //
2358       $ext->add('macro-vm','vmx', '', new ext_gotoif('$["${VMX_EXT}" != "dovm"]','getdest'));
2359       $ext->add('macro-vm','vmx', 'vmxopts', new ext_setvar("VMX_OPTS",'${VMX_OPTS_DOVM}'));
2360       $ext->add('macro-vm','vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/vmxopts/dovm)}" = "0"]','vmxdovm'));
2361       $ext->add('macro-vm','vmx', 'vmxopts', new ext_setvar("VMX_OPTS",'${DB_RESULT}'));
2362       $ext->add('macro-vm','vmx','vmxdovm',new ext_goto('1','dovm'));     
2363
2364       // General case, setup the goto destination and go there (no error checking, its up to the GUI's to assure
2365       // reasonable values
2366       //
2367       $ext->add('macro-vm','vmx', 'getdest', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/${ACTION}/context)}" = "0"]','vmxpri'));
2368       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_CONTEXT",'${DB_RESULT}'));
2369       $ext->add('macro-vm','vmx', 'vmxpri', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/${ACTION}/pri)}" = "0"]','vmxgoto'));
2370       $ext->add('macro-vm','vmx', '', new ext_setvar("VMX_PRI",'${DB_RESULT}'));
2371       $ext->add('macro-vm','vmx','vmxgoto',new ext_goto('${VMX_PRI}','${VMX_EXT}','${VMX_CONTEXT}'));
2372
2373       // If the required voicemail file is not present, then revert to normal voicemail
2374       // behavior treating as if it was not set
2375       //
2376       $ext->add('macro-vm','vmx', 'nofile', new ext_NoOp('File for mode: ${MODE} does not exist, SYSTEMSTATUS: ${SYSTEMSTATUS}, going to normal voicemail'));
2377       $ext->add('macro-vm','vmx','',new ext_goto('1','s-${MMODE}'));
2378       $ext->add('macro-vm','vmx', 'tmpgreet', new ext_NoOp('Temporary Greeting Detected, going to normal voicemail'));
2379       $ext->add('macro-vm','vmx','',new ext_goto('1','s-${MMODE}'));
2380
2381       // Drop into voicemail either as a direct destination (in which case VMX_OPTS might be set to something) or
2382       // if the user timed out or broke out of the loop then VMX_OPTS is always cleared such that an Allison
2383       // message is played and the caller know's what is going on.
2384       //
2385       $ext->add('macro-vm','dovm', '', new ext_NoOp('VMX Timeout - go to voicemail'));
2386       $ext->add('macro-vm','dovm', '',new ext_vm('${MEXTEN}@${VMCONTEXT},${VMX_OPTS}${VMGAIN}'));
2387       $ext->add('macro-vm','dovm', '',new ext_goto('1','exit-${VMSTATUS}'));
2388
2389       $ext->add('macro-vm','s-BUSY','',new ext_NoOp('BUSY voicemail'));
2390       $ext->add('macro-vm','s-BUSY','',new ext_macro('get-vmcontext','${MEXTEN}'));
2391       $ext->add('macro-vm','s-BUSY', '',new ext_vm('${MEXTEN}@${VMCONTEXT},${VM_OPTS}b${VMGAIN}'));
2392       $ext->add('macro-vm','s-BUSY', '',new ext_goto('1','exit-${VMSTATUS}'));
2393
2394       $ext->add('macro-vm','s-NOMESSAGE','',new ext_NoOp('NOMESSAGE (beeb only) voicemail'));
2395       $ext->add('macro-vm','s-NOMESSAGE','',new ext_macro('get-vmcontext','${MEXTEN}'));
2396       $ext->add('macro-vm','s-NOMESSAGE','',new ext_vm('${MEXTEN}@${VMCONTEXT},s${VM_OPTS}${VMGAIN}'));
2397       $ext->add('macro-vm','s-NOMESSAGE','',new ext_goto('1','exit-${VMSTATUS}'));
2398
2399       $ext->add('macro-vm','s-DIRECTDIAL','',new ext_NoOp('DIRECTDIAL voicemail'));
2400       $ext->add('macro-vm','s-DIRECTDIAL','',new ext_macro('get-vmcontext','${MEXTEN}'));
2401       $ext->add('macro-vm','s-DIRECTDIAL','',new ext_vm('${MEXTEN}@${VMCONTEXT},${VM_OPTS}${VM_DDTYPE}${VMGAIN}'));
2402       $ext->add('macro-vm','s-DIRECTDIAL','',new ext_goto('1','exit-${VMSTATUS}'));
2403
2404       $ext->add('macro-vm','_s-.','',new ext_macro('get-vmcontext','${MEXTEN}'));
2405       $ext->add('macro-vm','_s-.','',new ext_vm('${MEXTEN}@${VMCONTEXT},${VM_OPTS}u${VMGAIN}'));
2406       $ext->add('macro-vm','_s-.','',new ext_goto('1','exit-${VMSTATUS}'));
2407
2408       // If the user has a 0 option defined, use that for operator zero-out from within voicemail
2409       // as well to keep it consistant with the menu structure
2410       //
2411       $ext->add('macro-vm','o','',new ext_background('one-moment-please'));
2412       $ext->add('macro-vm','o','',new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/0/ext)}" = "0"]','doopdef'));
2413       $ext->add('macro-vm','o','',new ext_setvar("VMX_OPDEST_EXT",'${DB_RESULT}'));
2414       $ext->add('macro-vm','o','',new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/0/context)}" = "1"]','opcontext'));
2415       $ext->add('macro-vm','o','',new ext_setvar("DB_RESULT",'${VMX_CONTEXT}'));
2416       $ext->add('macro-vm','o','opcontext',new ext_setvar("VMX_OPDEST_CONTEXT",'${DB_RESULT}'));
2417       $ext->add('macro-vm','o','',new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/0/pri)}" = "1"]','oppri'));
2418       $ext->add('macro-vm','o','',new ext_setvar("DB_RESULT",'${VMX_PRI}'));
2419       $ext->add('macro-vm','o','oppri',new ext_setvar("VMX_OPDEST_PRI",'${DB_RESULT}'));
2420       $ext->add('macro-vm','o','',new ext_goto('${VMX_OPDEST_PRI}','${VMX_OPDEST_EXT}','${VMX_OPDEST_CONTEXT}'));
2421       $ext->add('macro-vm','o','doopdef',new ext_gotoif('$["x${OPERATOR_XTN}"="x"]','nooper','from-internal,${OPERATOR_XTN},1'));
2422       $ext->add('macro-vm','o','nooper',new ext_gotoif('$["x${FROM_DID}"="x"]','nodid'));
2423       $ext->add('macro-vm','o','',new ext_dial('Local/${FROM_DID}@from-pstn',''));
2424       $ext->add('macro-vm','o','',new ext_macro('hangup'));
2425       $ext->add('macro-vm','o','nodid',new ext_dial('Local/s@from-pstn',''));
2426       $ext->add('macro-vm','o','',new ext_macro('hangup'));
2427
2428       // If the user has a * option defined, use that for the * out from within voicemail
2429       // as well to keep it consistant with the menu structure
2430       //
2431       $ext->add('macro-vm','a','',new ext_macro('get-vmcontext','${MEXTEN}'));
2432       $ext->add('macro-vm','a','',new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/*/ext)}" = "0"]','adef,1'));
2433       $ext->add('macro-vm','a','',new ext_setvar("VMX_ADEST_EXT",'${DB_RESULT}'));
2434       $ext->add('macro-vm','a','',new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/*/context)}" = "1"]','acontext'));
2435       $ext->add('macro-vm','a','',new ext_setvar("DB_RESULT",'${VMX_CONTEXT}'));
2436       $ext->add('macro-vm','a','acontext',new ext_setvar("VMX_ADEST_CONTEXT",'${DB_RESULT}'));
2437
2438       $ext->add('macro-vm','a','',new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/*/pri)}" = "1"]','apri'));
2439       $ext->add('macro-vm','a','',new ext_setvar("DB_RESULT",'${VMX_PRI}'));
2440       $ext->add('macro-vm','a','apri',new ext_setvar("VMX_ADEST_PRI",'${DB_RESULT}'));
2441       $ext->add('macro-vm','a','',new ext_goto('${VMX_ADEST_PRI}','${VMX_ADEST_EXT}','${VMX_ADEST_CONTEXT}'));
2442       $ext->add('macro-vm','adef','',new ext_vmmain('${MEXTEN}@${VMCONTEXT}'));
2443       $ext->add('macro-vm','adef','',new ext_gotoif('$["${RETVM}" = "RETURN"]','exit-RETURN,1'));
2444       $ext->add('macro-vm','adef','',new ext_hangup(''));
2445
2446       $ext->add('macro-vm','exit-FAILED','',new ext_playback('im-sorry&an-error-has-occured'));
2447       $ext->add('macro-vm','exit-FAILED','',new ext_gotoif('$["${RETVM}" = "RETURN"]','exit-RETURN,1'));
2448       $ext->add('macro-vm','exit-FAILED','',new ext_hangup(''));
2449
2450       $ext->add('macro-vm','exit-SUCCESS','',new ext_gotoif('$["${RETVM}" = "RETURN"]','exit-RETURN,1'));
2451       $ext->add('macro-vm','exit-SUCCESS','',new ext_playback('goodbye'));
2452       $ext->add('macro-vm','exit-SUCCESS','',new ext_hangup(''));
2453
2454       $ext->add('macro-vm','exit-USEREXIT','',new ext_gotoif('$["${RETVM}" = "RETURN"]','exit-RETURN,1'));
2455       $ext->add('macro-vm','exit-USEREXIT','',new ext_playback('goodbye'));
2456       $ext->add('macro-vm','exit-USEREXIT','',new ext_hangup(''));
2457
2458       $ext->add('macro-vm','exit-RETURN','',new ext_noop('Returning From Voicemail because macro'));
2459       $ext->add('macro-vm','t','',new ext_hangup(''));
2460
2461       /* end macro-vm  */
2462                  
2463     break;
2464   }
2465 }
2466
2467 /* begin page.ampusers.php functions */
2468
2469 function core_ampusers_add($username, $password, $extension_low, $extension_high, $deptname, $sections) {
2470   $sql = "INSERT INTO ampusers (username, password_sha1, extension_low, extension_high, deptname, sections) VALUES (";
2471   $sql .= "'".$username."',";
2472   if (strlen($password) == 40) {
2473     // It's already a hash
2474     $sql .= "'".$password."'";
2475   } else {
2476     // Hash it.
2477     $sql .= "'".sha1($password)."',";
2478   }
2479   $sql .= "'".$extension_low."',";
2480   $sql .= "'".$extension_high."',";
2481   $sql .= "'".$deptname."',";
2482   $sql .= "'".implode(";",$sections)."');";
2483  
2484   sql($sql,"query");
2485 }
2486
2487 function core_ampusers_del($username) {
2488   $sql = "DELETE FROM ampusers WHERE username = '".$username."'";
2489   sql($sql,"query");
2490 }
2491
2492 function core_ampusers_list() {
2493   $sql = "SELECT username FROM ampusers ORDER BY username";
2494   return sql($sql,"getAll");
2495 }
2496
2497 /* end page.ampusers.php functions */
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507 /* begin page.did.php functions */
2508
2509 function core_did_list($order='extension'){
2510   switch ($order) {
2511     case 'description':
2512       $sql = "SELECT * FROM incoming ORDER BY description,extension,cidnum";
2513       break;
2514     case 'extension':
2515     default:
2516       $sql = "SELECT * FROM incoming ORDER BY extension,cidnum";
2517   }
2518   return sql($sql,"getAll",DB_FETCHMODE_ASSOC);
2519 }
2520
2521 function core_did_get($extension="",$cidnum=""){
2522   $sql = "SELECT * FROM incoming WHERE cidnum = \"$cidnum\" AND extension = \"$extension\"";
2523   return sql($sql,"getRow",DB_FETCHMODE_ASSOC);
2524 }
2525
2526 function core_did_del($extension,$cidnum){
2527   $sql="DELETE FROM incoming WHERE cidnum = \"$cidnum\" AND extension = \"$extension\"";
2528   sql($sql);
2529 }
2530
2531 function core_did_edit($old_extension,$old_cidnum, $incoming){
2532   global $db;
2533
2534   $old_extension = $db->escapeSimple(trim($old_extension));
2535   $old_cidnum = $db->escapeSimple(trim($old_cidnum));
2536
2537   $incoming['extension'] = trim($incoming['extension']);
2538   $incoming['cidnum'] = trim($incoming['cidnum']);
2539
2540   $extension = $db->escapeSimple($incoming['extension']);
2541   $cidnum = $db->escapeSimple($incoming['cidnum']);
2542
2543   // if did or cid changed, then check to make sure that this pair is not already being used.
2544   //
2545   if (($extension != $old_extension) || ($cidnum != $old_cidnum)) {
2546     $existing=core_did_get($extension,$cidnum);
2547   }
2548
2549   if (empty($existing)) {
2550     core_did_del($old_extension,$old_cidnum);
2551     core_did_add($incoming);
2552     return true;
2553   } else {
2554     echo "<script>javascript:alert('"._("A route for this DID/CID already exists!")." => ".$existing['extension']."/".$existing['cidnum']."')</script>";
2555   }
2556   return false;
2557 }
2558
2559 /* Create a new did with values passed into $did_vars and defaults used otherwise
2560 */
2561 function core_did_create_update($did_vars) {
2562   $did_create['extension'] = isset($did_vars['extension']) ? $did_vars['extension'] : '';
2563   $did_create['cidnum']    = isset($did_vars['cidnum']) ? $did_vars['cidnum'] : '';
2564
2565   if (count(core_did_get($did_create['extension'], $did_create['$cidnum']))) {
2566     return core_did_edit_properties($did_vars); //already exists so just edit properties
2567   } else {
2568     $did_create['faxexten']    = isset($did_vars['faxexten'])    ? $did_vars['faxexten']    : '';
2569     $did_create['faxemail']    = isset($did_vars['faxemail'])    ? $did_vars['faxemail']    : '';
2570     $did_create['answer']      = isset($did_vars['answer'])      ? $did_vars['answer']      : '0';
2571     $did_create['wait']        = isset($did_vars['wait'])        ? $did_vars['wait']        : '0';
2572     $did_create['privacyman']  = isset($did_vars['privacyman'])  ? $did_vars['privacyman']  : '';
2573     $did_create['alertinfo']   = isset($did_vars['alertinfo'])   ? $did_vars['alertinfo']   : '';
2574     $did_create['ringing']     = isset($did_vars['ringing'])     ? $did_vars['ringing']     : '';
2575     $did_create['mohclass']    = isset($did_vars['mohclass'])    ? $did_vars['mohclass']    : 'default';
2576     $did_create['description'] = isset($did_vars['description']) ? $did_vars['description'] : '';
2577     $did_create['grppre']      = isset($did_vars['grppre'])      ? $did_vars['grppre']      : '';
2578     $did_create['delay_answer']= isset($did_vars['delay_answer'])? $did_vars['delay_answer']: '0';
2579     $did_create['pricid']      = isset($did_vars['pricid'])      ? $did_vars['pricid']      : '';
2580
2581     $did_dest                  = isset($did_vars['destination']) ? $did_vars['destination'] : '';
2582     return core_did_add($did_vars, $did_dest);
2583  }
2584 }
2585
2586
2587 /* Edits the poperties of a did, but not the did or cid nums since those could of course be
2588    in conflict
2589 */
2590 function core_did_edit_properties($did_vars) {
2591   global $db;
2592
2593   if (!is_array($did_vars)) {
2594     return false;
2595   }
2596
2597   $extension = $db->escapeSimple(isset($did_vars['extension']) ? $did_vars['extension'] : '');
2598   $cidnum    = $db->escapeSimple(isset($did_vars['cidnum']) ? $did_vars['cidnum'] : '');
2599   $sql = "";
2600   foreach ($did_vars as $key => $value) {
2601     switch ($key) {
2602       case 'faxexten':
2603       case 'faxemail':
2604       case 'answer':
2605       case 'wait':
2606       case 'privacyman':
2607       case 'alertinfo':
2608       case 'ringing':
2609       case 'mohclass':
2610       case 'description':
2611       case 'grppre':
2612       case 'delay_answer':
2613       case 'pricid':
2614       case 'destination':
2615         $sql_value = $db->escapeSimple($value);
2616         $sql .= " `$key` = '$sql_value',";
2617       break;
2618     default:
2619     }
2620   }
2621   if ($sql == '') {
2622     return false;
2623   }
2624   $sql = substr($sql,0,(strlen($sql)-1)); //strip off tailing ','
2625   $sql_update = "UPDATE `incoming` SET"."$sql WHERE `extension` = '$extension' AND `cidnum` = '$cidnum'";
2626   return sql($sql_update);
2627 }
2628
2629 function core_did_add($incoming,$target=false){
2630   global $db;
2631   foreach ($incoming as $key => $val) { ${$key} = $db->escapeSimple($val); } // create variables from request
2632
2633   // Check to make sure the did is not being used elsewhere
2634   //
2635   $existing=core_did_get($extension,$cidnum);
2636
2637   if (empty($existing)) {
2638     $destination= ($target) ? $target : ${$goto0.'0'};
2639     $sql="INSERT INTO incoming (cidnum,extension,destination,faxexten,faxemail,answer,wait,privacyman,alertinfo, ringing, mohclass, description, grppre, delay_answer, pricid) values ('$cidnum','$extension','$destination','$faxexten','$faxemail','$answer','$wait','$privacyman','$alertinfo', '$ringing', '$mohclass', '$description', '$grppre', '$delay_answer', '$pricid')";
2640     sql($sql);
2641     return true;
2642   } else {
2643     echo "<script>javascript:alert('"._("A route for this DID/CID already exists!")." => ".$existing['extension']."/".$existing['cidnum']."')</script>";
2644     return false;
2645   }
2646 }
2647
2648 /* end page.did.php functions */
2649
2650
2651 /* begin page.devices.php functions */
2652
2653 //get the existing devices
2654 function core_devices_list($tech="all",$detail=false,$get_all=false) {
2655   if (strtolower($detail) == 'full') {
2656     $sql = "SELECT * FROM devices";
2657   } else {
2658     $sql = "SELECT id,description FROM devices";
2659   }
2660   switch (strtoupper($tech)) {
2661     case "IAX":
2662       $sql .= " WHERE tech = 'iax2'";
2663       break;
2664     case "IAX2":
2665     case "SIP":
2666     case "ZAP":
2667       $sql .= " WHERE tech = '".strtolower($tech)."'";
2668       break;
2669     case "ALL":
2670     default:
2671   }
2672   $sql .= ' ORDER BY id';
2673   $results = sql($sql,"getAll",DB_FETCHMODE_ASSOC);
2674
2675   $extens = null;
2676   foreach($results as $result){
2677     if ($get_all || checkRange($result['id'])){
2678
2679       $record = array();
2680       $record[0] = $result['id'];  // for backwards compatibility
2681       $record[1] = $result['description'];  // for backwards compatibility
2682       foreach ($result as $key => $value) {
2683         $record[$key] = $value;
2684       }
2685       $extens[] = $record;
2686       /*
2687       $extens[] = array(
2688         0=>$result[0],  // for backwards compatibility
2689         1=>$result[1],
2690         'id'=>$result[0], // FETCHMODE_ASSOC emulation
2691         'description'=>$result[1],
2692       );
2693       */
2694     }
2695   }
2696   return $extens;
2697 }
2698
2699
2700 function core_devices_add($id,$tech,$dial,$devicetype,$user,$description,$emergency_cid=null,$editmode=false){
2701   global $amp_conf;
2702   global $currentFile;
2703   global $astman;
2704   global $db;
2705  
2706   $display = isset($_REQUEST['display'])?$_REQUEST['display']:'';
2707
2708   if (trim($id) == '' ) {
2709     if ($display != 'extensions') {
2710       echo "<script>javascript:alert('"._("You must put in a device id")."');</script>";
2711     }
2712     return false;
2713   }
2714  
2715   //ensure this id is not already in use
2716   $devices = core_devices_list();
2717   if (is_array($devices)) {
2718     foreach($devices as $device) {
2719       if ($device[0] === $id) {
2720         if ($display <> 'extensions') echo "<script>javascript:alert('"._("This device id is already in use")."');</script>";
2721         return false;
2722       }
2723     }
2724   }
2725   //unless defined, $dial is TECH/id
2726   if ( $dial == '' ) {
2727     //zap is an exception
2728     if ( strtolower($tech) == "zap" ) {
2729       $zapchan = $_REQUEST['devinfo_channel'] != '' ? $_REQUEST['devinfo_channel'] : $_REQUEST['channel'];
2730       $dial = 'ZAP/'.$zapchan;
2731     } else {
2732       $dial = strtoupper($tech)."/".$id;
2733     }
2734   }
2735  
2736   //check to see if we are requesting a new user
2737   if ($user == "new") {
2738     $user = $id;
2739     $jump = true;
2740   }
2741  
2742   if(!get_magic_quotes_gpc()) {
2743     if(!empty($emergency_cid))
2744       $emergency_cid = $db->escapeSimple($emergency_cid);
2745     if(!empty($description))
2746       $description = $db->escapeSimple($description);
2747   }
2748  
2749   //insert into devices table
2750   $sql="INSERT INTO devices (id,tech,dial,devicetype,user,description,emergency_cid) values (\"$id\",\"$tech\",\"$dial\",\"$devicetype\",\"$user\",\"$description\",\"$emergency_cid\")";
2751   sql($sql);
2752  
2753   //add details to astdb
2754   if ($astman) {
2755     // if adding or editting a fixed device, user property should always be set
2756     if ($devicetype == 'fixed' || !$editmode) {
2757       $astman->database_put("DEVICE",$id."/user",$user);
2758     }
2759     // If changing from a fixed to an adhoc, the user property should be intialized
2760     // to the new default, not remain as the previous fixed user
2761     if ($editmode) {
2762       $previous_type = $astman->database_get("DEVICE",$id."/type");
2763       if ($previous_type == 'fixed' && $devicetype == 'adhoc') {
2764         $astman->database_put("DEVICE",$id."/user",$user);
2765       }
2766     }
2767     $astman->database_put("DEVICE",$id."/dial",$dial);
2768     $astman->database_put("DEVICE",$id."/type",$devicetype);
2769     $astman->database_put("DEVICE",$id."/default_user",$user);
2770     if($emergency_cid != '') {
2771       $astman->database_put("DEVICE",$id."/emergency_cid","\"".$emergency_cid."\"");
2772     }
2773
2774     if ($user != "none") {
2775       $existingdevices = $astman->database_get("AMPUSER",$user."/device");
2776       if (empty($existingdevices)) {
2777         $astman->database_put("AMPUSER",$user."/device",$id);
2778       } else {
2779         $existingdevices_array = explode('&',$existingdevices);
2780         if (!in_array($id, $existingdevices_array)) {
2781           $existingdevices_array[]=$id;
2782           $existingdevices = implode('&',$existingdevices_array);
2783           $astman->database_put("AMPUSER",$user."/device",$existingdevices);
2784         }
2785       }
2786     }
2787
2788   } else {
2789     fatal("Cannot connect to Asterisk Manager with ".$amp_conf["AMPMGRUSER"]."/".$amp_conf["AMPMGRPASS"]);
2790   }
2791  
2792   // create a voicemail symlink if needed
2793   $thisUser = core_users_get($user);
2794   if(isset($thisUser['voicemail']) && ($thisUser['voicemail'] != "novm")) {
2795     if(empty($thisUser['voicemail'])) {
2796       $vmcontext = "default";
2797     } else {
2798       $vmcontext = $thisUser['voicemail'];
2799     }
2800    
2801     //voicemail symlink
2802     exec("rm -f /var/spool/asterisk/voicemail/device/".$id);
2803     exec("/bin/ln -s /var/spool/asterisk/voicemail/".$vmcontext."/".$user."/ /var/spool/asterisk/voicemail/device/".$id);
2804   }
2805    
2806   //take care of sip/iax/zap config
2807   $funct = "core_devices_add".strtolower($tech);
2808  
2809   // before calling device specifc funcitions, get rid of any bogus fields in the REQUEST array
2810   //
2811   if (isset($_REQUEST['devinfo_secret_origional'])) {
2812     unset($_REQUEST['devinfo_secret_origional']);
2813   }
2814   if(function_exists($funct)){
2815     $funct($id);
2816   }
2817  
2818 /*  if($user != "none") {
2819     core_hint_add($user);
2820   }*/
2821  
2822   //if we are requesting a new user, let's jump to users.php
2823   if (isset($jump)) {
2824     echo("<script language=\"JavaScript\">window.location=\"config.php?display=users&extdisplay={$id}&name={$description}\";</script>");
2825   }
2826   return true;
2827 }
2828
2829 function core_devices_del($account,$editmode=false){
2830   global $amp_conf;
2831   global $currentFile;
2832   global $astman;
2833  
2834   //get all info about device
2835   $devinfo = core_devices_get($account);
2836  
2837   //delete details to astdb
2838   if ($astman) {
2839     // If a user was selected, remove this device from the user
2840     $deviceuser = $astman->database_get("DEVICE",$account."/user");
2841     if (isset($deviceuser) && $deviceuser != "none") {
2842       // Remove the device record from the user's device list
2843       $userdevices = $astman->database_get("AMPUSER",$deviceuser."/device");
2844
2845       // We need to remove just this user and leave the rest alone
2846       $userdevicesarr = explode("&", $userdevices);
2847       $userdevicesarr_hash = array_flip($userdevicesarr);
2848       unset($userdevicesarr_hash[$account]);
2849       $userdevicesarr = array_flip($userdevicesarr_hash);
2850       $userdevices = implode("&", $userdevicesarr);
2851      
2852       if (empty($userdevices)) {
2853           $astman->database_del("AMPUSER",$deviceuser."/device");
2854       } else {
2855           $astman->database_put("AMPUSER",$deviceuser."/device",$userdevices);
2856       }
2857     }
2858     if (! $editmode) {
2859       $astman->database_del("DEVICE",$account."/dial");
2860       $astman->database_del("DEVICE",$account."/type");
2861       $astman->database_del("DEVICE",$account."/user");
2862       $astman->database_del("DEVICE",$account."/default_user");
2863       $astman->database_del("DEVICE",$account."/emergency_cid");
2864     }
2865
2866     //delete from devices table
2867     $sql="DELETE FROM devices WHERE id = \"$account\"";
2868     sql($sql);
2869
2870     //voicemail symlink
2871     exec("rm -f /var/spool/asterisk/voicemail/device/".$account);
2872   } else {
2873     fatal("Cannot connect to Asterisk Manager with ".$amp_conf["AMPMGRUSER"]."/".$amp_conf["AMPMGRPASS"]);
2874   }
2875  
2876   //take care of sip/iax/zap config
2877   $funct = "core_devices_del".strtolower($devinfo['tech']);
2878   if(function_exists($funct)){
2879     $funct($account);
2880   }
2881 }
2882
2883 function core_devices_get($account){
2884   //get all the variables for the meetme
2885   $sql = "SELECT * FROM devices WHERE id = '$account'";
2886   $results = sql($sql,"getRow",DB_FETCHMODE_ASSOC);
2887  
2888   //take care of sip/iax/zap config
2889   $funct = "core_devices_get".strtolower($results['tech']);
2890   if (!empty($results['tech']) && function_exists($funct)) {
2891     $devtech = $funct($account);
2892     if (is_array($devtech)){
2893       $results = array_merge($results,$devtech);
2894     }
2895   }
2896  
2897   return $results;
2898 }
2899
2900 // this function rebuilds the astdb based on device table contents
2901 // used on devices.php if action=resetall
2902 function core_devices2astdb(){
2903   global $astman;
2904   global $amp_conf;
2905
2906   $sql = "SELECT * FROM devices";
2907   $devresults = sql($sql,"getAll",DB_FETCHMODE_ASSOC);
2908
2909   //add details to astdb
2910   if ($astman) {
2911     $astman->database_deltree("DEVICE");
2912     foreach ($devresults as $dev) {
2913       extract($dev); 
2914       $astman->database_put("DEVICE",$id."/dial",$dial);
2915       $astman->database_put("DEVICE",$id."/type",$devicetype);
2916       $astman->database_put("DEVICE",$id."/user",$user);   
2917       $astman->database_put("DEVICE",$id."/default_user",$user);
2918       if(trim($emergency_cid) != '') {
2919         $astman->database_put("DEVICE",$id."/emergency_cid","\"".$emergency_cid."\"");
2920       }
2921       // If a user is selected, add this device to the user
2922       if ($user != "none") {
2923           $existingdevices = $astman->database_get("AMPUSER",$user."/device");
2924           if (empty($existingdevices)) {
2925             $astman->database_put("AMPUSER",$user."/device",$id);
2926           } else {
2927             $existingdevices_array = explode('&',$existingdevices);
2928             if (!in_array($id, $existingdevices_array)) {
2929               $existingdevices_array[]=$id;
2930               $existingdevices = implode('&',$existingdevices_array);
2931               $astman->database_put("AMPUSER",$user."/device",$existingdevices);
2932             }
2933           }
2934         }
2935
2936      
2937       // create a voicemail symlink if needed
2938       $thisUser = core_users_get($user);
2939       if(isset($thisUser['voicemail']) && ($thisUser['voicemail'] != "novm")) {
2940         if(empty($thisUser['voicemail']))
2941           $vmcontext = "default";
2942         else
2943           $vmcontext = $thisUser['voicemail'];
2944         //voicemail symlink
2945         exec("rm -f /var/spool/asterisk/voicemail/device/".$id);
2946         exec("/bin/ln -s /var/spool/asterisk/voicemail/".$vmcontext."/".$user."/ /var/spool/asterisk/voicemail/device/".$id);
2947       }
2948     }
2949     return true;
2950   } else {
2951     return false;
2952   }
2953 }
2954
2955 // this function rebuilds the astdb based on users table contents
2956 // used on devices.php if action=resetall
2957 function core_users2astdb(){
2958   global $amp_conf;
2959   global $astman;
2960   global $db;
2961
2962   $sql = "SELECT * FROM users";
2963   $userresults = sql($sql,"getAll",DB_FETCHMODE_ASSOC);
2964  
2965   //add details to astdb
2966   if ($astman) {
2967     foreach($userresults as $usr) {
2968       extract($usr);
2969       $astman->database_put("AMPUSER",$extension."/password",$password);
2970       $astman->database_put("AMPUSER",$extension."/ringtimer",$ringtimer);
2971       $astman->database_put("AMPUSER",$extension."/noanswer",$noanswer);
2972       $astman->database_put("AMPUSER",$extension."/recording",$recording);
2973       $astman->database_put("AMPUSER",$extension."/outboundcid","\"".$db->escapeSimple($outboundcid)."\"");
2974       $astman->database_put("AMPUSER",$extension."/cidname","\"".$db->escapeSimple($name)."\"");
2975       $astman->database_put("AMPUSER",$extension."/voicemail","\"".$voicemail."\"");
2976     }
2977     return true;
2978   } else {
2979     return false;
2980   }
2981
2982 //  TODO: this was...
2983 //  return $astman->disconnect();
2984 //  is "true" the correct value...?
2985 }
2986
2987 //add to sip table
2988 function core_devices_addsip($account) {
2989   global $db;
2990   global $currentFile;
2991
2992   $flag = 2;
2993   foreach ($_REQUEST as $req=>$data) {
2994     if ( substr($req, 0, 8) == 'devinfo_' ) {
2995       $keyword = substr($req, 8);
2996       if ( $keyword == 'dial' && $data == '' ) {
2997         $sipfields[] = array($account, $keyword, 'SIP/'.$account, $flag++);
2998       } elseif ($keyword == 'mailbox' && $data == '') {
2999         $sipfields[] = array($account,'mailbox',$account.'@device', $flag++);
3000       } else {
3001         $sipfields[] = array($account, $keyword, $data, $flag++);
3002       }
3003     }
3004   }
3005  
3006   if ( !is_array($sipfields) ) { // left for compatibilty....lord knows why !
3007     $sipfields = array(
3008       array($account,'accountcode',$db->escapeSimple((isset($_REQUEST['accountcode']))?$_REQUEST['accountcode']:''),$flag++),
3009       array($account,'secret',$db->escapeSimple((isset($_REQUEST['secret']))?$_REQUEST['secret']:''),$flag++),
3010       array($account,'canreinvite',$db->escapeSimple((isset($_REQUEST['canreinvite']))?$_REQUEST['canreinvite']:'no'),$flag++),
3011       array($account,'context',$db->escapeSimple((isset($_REQUEST['context']))?$_REQUEST['context']:'from-internal'),$flag++),
3012       array($account,'dtmfmode',$db->escapeSimple((isset($_REQUEST['dtmfmode']))?$_REQUEST['dtmfmode']:''),$flag++),
3013       array($account,'host',$db->escapeSimple((isset($_REQUEST['host']))?$_REQUEST['host']:'dynamic'),$flag++),
3014       array($account,'type',$db->escapeSimple((isset($_REQUEST['type']))?$_REQUEST['type']:'friend'),$flag++),
3015       array($account,'mailbox',$db->escapeSimple((isset($_REQUEST['mailbox']) && !empty($_REQUEST['mailbox']))?$_REQUEST['mailbox']:$account.'@device'),$flag++),
3016       array($account,'username',$db->escapeSimple((isset($_REQUEST['username']))?$_REQUEST['username']:$account),$flag++),
3017       array($account,'nat',$db->escapeSimple((isset($_REQUEST['nat']))?$_REQUEST['nat']:'yes'),$flag++),
3018       array($account,'port',$db->escapeSimple((isset($_REQUEST['port']))?$_REQUEST['port']:'5060'),$flag++),
3019       array($account,'qualify',$db->escapeSimple((isset($_REQUEST['qualify']))?$_REQUEST['qualify']:'yes'),$flag++),
3020       array($account,'callgroup',$db->escapeSimple((isset($_REQUEST['callgroup']))?$_REQUEST['callgroup']:''),$flag++),
3021       array($account,'pickupgroup',$db->escapeSimple((isset($_REQUEST['pickupgroup']))?$_REQUEST['pickupgroup']:''),$flag++),
3022       array($account,'deny',$db->escapeSimple((isset($_REQUEST['deny']))?$_REQUEST['deny']:''),$flag++),
3023       array($account,'permit',$db->escapeSimple((isset($_REQUEST['permit']))?$_REQUEST['permit']:''),$flag++),     
3024       array($account,'disallow',$db->escapeSimple((isset($_REQUEST['disallow']))?$_REQUEST['disallow']:''),$flag++),
3025       array($account,'allow',$db->escapeSimple((isset($_REQUEST['allow']))?$_REQUEST['allow']:''),$flag++)
3026     );
3027   }
3028
3029   // Very bad
3030   $sipfields[] = array($account,'account',$db->escapeSimple($account),$flag++);
3031   $sipfields[] = array($account,'callerid',$db->escapeSimple((isset($_REQUEST['description']) && $_REQUEST['description'])?$_REQUEST['description']." <".$account.'>':'device'." <".$account.'>'),$flag++);
3032  
3033   // Where is this in the interface ??????
3034   $sipfields[] = array($account,'record_in',$db->escapeSimple(($_REQUEST['record_in'])?$_REQUEST['record_in']:'On-Demand'),$flag++);
3035   $sipfields[] = array($account,'record_out',$db->escapeSimple(($_REQUEST['record_out'])?$_REQUEST['record_out']:'On-Demand'),$flag++);
3036
3037   $compiled = $db->prepare('INSERT INTO sip (id, keyword, data, flags) values (?,?,?,?)');
3038   $result = $db->executeMultiple($compiled,$sipfields);
3039   if(DB::IsError($result)) {
3040     die_freepbx($result->getDebugInfo()."<br><br>".'error adding to SIP table'); 
3041   }
3042 }
3043
3044 function core_devices_delsip($account) {
3045   global $db;
3046   global $currentFile;
3047  
3048   $sql = "DELETE FROM sip WHERE id = '$account'";
3049   $result = $db->query($sql);
3050  
3051   if(DB::IsError($result)) {
3052     die_freepbx($result->getMessage().$sql);
3053   }
3054 }
3055
3056 function core_devices_getsip($account) {
3057   global $db;
3058   $sql = "SELECT keyword,data FROM sip WHERE id = '$account'";
3059   $results = $db->getAssoc($sql);
3060   if(DB::IsError($results)) {
3061     $results = null;
3062   }
3063  
3064   return $results;
3065 }
3066
3067 //add to iax table
3068 function core_devices_addiax2($account) {
3069   global $db;
3070   global $currentFile;
3071
3072   $flag = 2;
3073   foreach ($_REQUEST as $req=>$data) {
3074     if ( substr($req, 0, 8) == 'devinfo_' ) {
3075       $keyword = substr($req, 8);
3076       if ( $keyword == 'dial' && $data == '' ) {
3077         $iaxfields[] = array($account, $keyword, 'IAX2/'.$account, $flag++);
3078       } elseif ($keyword == 'mailbox' && $data == '') {
3079         $iaxfields[] = array($account,'mailbox',$account.'@device', $flag++);
3080       } else {
3081         $iaxfields[] = array($account, $keyword, $data, $flag++);
3082       }
3083     }
3084   }
3085  
3086   if ( !is_array($iaxfields) ) { // left for compatibilty....lord knows why !
3087     $iaxfields = array(
3088       array($account,'secret',$db->escapeSimple(($_REQUEST['secret'])?$_REQUEST['secret']:''),$flag++),
3089       array($account,'notransfer',$db->escapeSimple(($_REQUEST['notransfer'])?$_REQUEST['notransfer']:'yes'),$flag++),
3090       array($account,'context',$db->escapeSimple(($_REQUEST['context'])?$_REQUEST['context']:'from-internal'),$flag++),
3091       array($account,'host',$db->escapeSimple(($_REQUEST['host'])?$_REQUEST['host']:'dynamic'),$flag++),
3092       array($account,'type',$db->escapeSimple(($_REQUEST['type'])?$_REQUEST['type']:'friend'),$flag++),
3093       array($account,'mailbox',$db->escapeSimple(($_REQUEST['mailbox'])?$_REQUEST['mailbox']:$account.'@device'),$flag++),
3094       array($account,'username',$db->escapeSimple(($_REQUEST['username'])?$_REQUEST['username']:$account),$flag++),
3095       array($account,'port',$db->escapeSimple(($_REQUEST['port'])?$_REQUEST['port']:'4569'),$flag++),
3096       array($account,'qualify',$db->escapeSimple(($_REQUEST['qualify'])?$_REQUEST['qualify']:'yes'),$flag++),
3097       array($account,'deny',$db->escapeSimple((isset($_REQUEST['deny']))?$_REQUEST['deny']:''),$flag++),
3098       array($account,'permit',$db->escapeSimple((isset($_REQUEST['permit']))?$_REQUEST['permit']:''),$flag++),     
3099       array($account,'disallow',$db->escapeSimple(($_REQUEST['disallow'])?$_REQUEST['disallow']:''),$flag++),
3100       array($account,'allow',$db->escapeSimple(($_REQUEST['allow'])?$_REQUEST['allow']:''),$flag++),
3101       array($account,'accountcode',$db->escapeSimple(($_REQUEST['accountcode'])?$_REQUEST['accountcode']:''),$flag++)
3102     );
3103   }
3104
3105   // Very bad
3106   $iaxfields[] = array($account,'account',$db->escapeSimple($account),$flag++);
3107   $iaxfields[] = array($account,'callerid',$db->escapeSimple((isset($_REQUEST['description']) && $_REQUEST['description'] != '')?$_REQUEST['description']." <".$account.'>':'device'." <".$account.'>'),$flag++);
3108   // Asterisk treats no caller ID from an IAX device as 'hide callerid', and ignores the caller ID
3109   // set in iax.conf. As we rely on this for pretty much everything, we need to specify the
3110   // callerid as a variable which gets picked up in macro-callerid.
3111   // Ref - http://bugs.digium.com/view.php?id=456
3112   $iaxfields[] = array($account,'setvar',$db->escapeSimple("REALCALLERIDNUM=$account"),$flag++);
3113  
3114   // Where is this in the interface ??????
3115   $iaxfields[] = array($account,'record_in',$db->escapeSimple(($_REQUEST['record_in'])?$_REQUEST['record_in']:'On-Demand'),$flag++);
3116   $iaxfields[] = array($account,'record_out',$db->escapeSimple(($_REQUEST['record_out'])?$_REQUEST['record_out']:'On-Demand'),$flag++);
3117  
3118   $compiled = $db->prepare('INSERT INTO iax (id, keyword, data, flags) values (?,?,?,?)');
3119   $result = $db->executeMultiple($compiled,$iaxfields);
3120   if(DB::IsError($result)) {
3121     die_freepbx($result->getMessage()."<br><br>error adding to IAX table");
3122   }
3123 }
3124
3125 function core_devices_deliax2($account) {
3126   global $db;
3127   global $currentFile;
3128  
3129   $sql = "DELETE FROM iax WHERE id = '$account'";
3130   $result = $db->query($sql);
3131  
3132   if(DB::IsError($result)) {
3133     die_freepbx($result->getMessage().$sql);
3134   }
3135 }
3136
3137 function core_devices_getiax2($account) {
3138   global $db;
3139   $sql = "SELECT keyword,data FROM iax WHERE id = '$account'";
3140   $results = $db->getAssoc($sql);
3141   if(DB::IsError($results)) {
3142     $results = null;
3143   }
3144  
3145   return $results;
3146 }
3147
3148 function core_devices_addzap($account) {
3149   global $db;
3150   global $currentFile;
3151    
3152   foreach ($_REQUEST as $req=>$data) {
3153     if ( substr($req, 0, 8) == 'devinfo_' ) {
3154       $keyword = substr($req, 8);
3155       if ( $keyword == 'dial' && $data == '' ) {
3156         $zapchan = $_REQUEST['devinfo_channel'] != '' ? $_REQUEST['devinfo_channel'] : $_REQUEST['channel'];
3157         $zapfields[] = array($account, $keyword, 'ZAP/'.$zapchan);
3158       } elseif ($keyword == 'mailbox' && $data == '') {
3159         $zapfields[] = array($account,'mailbox',$account.'@device');
3160       } else {
3161         $zapfields[] = array($account, $keyword, $data);
3162       }
3163     }
3164   }
3165  
3166   if ( !is_array($zapfields) ) { // left for compatibilty....lord knows why !
3167     $zapfields = array(
3168       array($account,'context',$db->escapeSimple(($_REQUEST['context'])?$_REQUEST['context']:'from-internal')),
3169       array($account,'mailbox',$db->escapeSimple(($_REQUEST['mailbox'])?$_REQUEST['mailbox']:$account.'@device')),
3170       array($account,'immediate',$db->escapeSimple(($_REQUEST['immediate'])?$_REQUEST['immediate']:'no')),
3171       array($account,'signalling',$db->escapeSimple(($_REQUEST['signalling'])?$_REQUEST['signalling']:'fxo_ks')),
3172       array($account,'echocancel',$db->escapeSimple(($_REQUEST['echocancel'])?$_REQUEST['echocancel']:'yes')),
3173       array($account,'echocancelwhenbridged',$db->escapeSimple(($_REQUEST['echocancelwhenbridged'])?$_REQUEST['echocancelwhenbridged']:'no')),
3174       array($account,'immediate',$db->escapeSimple(($_REQUEST['immediate'])?$_REQUEST['immediate']:'no')), 
3175       array($account,'echotraining',$db->escapeSimple(($_REQUEST['echotraining'])?$_REQUEST['echotraining']:'800')),
3176       array($account,'busydetect',$db->escapeSimple(($_REQUEST['busydetect'])?$_REQUEST['busydetect']:'no')),
3177       array($account,'busycount',$db->escapeSimple(($_REQUEST['busycount'])?$_REQUEST['busycount']:'7')),
3178       array($account,'callprogress',$db->escapeSimple(($_REQUEST['callprogress'])?$_REQUEST['callprogress']:'no')),
3179       array($account,'accountcode',$db->escapeSimple((isset($_REQUEST['accountcode']))?$_REQUEST['accountcode']:'')),
3180       array($account,'callgroup',$db->escapeSimple((isset($_REQUEST['callgroup']))?$_REQUEST['callgroup']:'')),
3181       array($account,'pickupgroup',$db->escapeSimple((isset($_REQUEST['pickupgroup']))?$_REQUEST['pickupgroup']:'')),
3182       array($account,'channel',$db->escapeSimple(($_REQUEST['channel'])?$_REQUEST['channel']:''))
3183     );
3184   }
3185
3186   // Very bad
3187   $zapfields[] = array($account,'account',$db->escapeSimple($account));
3188   $zapfields[] = array($account,'callerid',$db->escapeSimple(($_REQUEST['description'])?$_REQUEST['description']." <".$account.'>':'device'." <".$account.'>'));
3189  
3190   // Where is this in the interface ??????
3191   $zapfields[] = array($account,'record_in',$db->escapeSimple(($_REQUEST['record_in'])?$_REQUEST['record_in']:'On-Demand'));
3192   $zapfields[] = array($account,'record_out',$db->escapeSimple(($_REQUEST['record_out'])?$_REQUEST['record_out']:'On-Demand'));
3193
3194   $compiled = $db->prepare('INSERT INTO zap (id, keyword, data) values (?,?,?)');
3195   $result = $db->executeMultiple($compiled,$zapfields);
3196   if(DB::IsError($result)) {
3197     die_freepbx($result->getMessage()."<br><br>error adding to ZAP table");
3198   }
3199 }
3200
3201 function core_devices_delzap($account) {
3202   global $db;
3203   global $currentFile;
3204  
3205   $sql = "DELETE FROM zap WHERE id = '$account'";
3206   $result = $db->query($sql);
3207   if(DB::IsError($result)) {
3208     die_freepbx($result->getMessage().$sql);
3209   }
3210 }
3211
3212 function core_devices_getzap($account) {
3213   global $db;
3214   $sql = "SELECT keyword,data FROM zap WHERE id = '$account'";
3215   $results = $db->getAssoc($sql);
3216   if(DB::IsError($results)) {
3217     $results = null;
3218   }
3219   return $results;
3220 }
3221 /* end page.devices.php functions */
3222
3223
3224
3225
3226 function core_hint_get($account){
3227   global $astman;
3228
3229   $chan_dahdi = ast_with_dahdi();
3230   // We should always check the AMPUSER in case they logged into a device
3231   // but we will fall back to the old methond if $astman not open although
3232   // I'm pretty sure everything else will puke anyhow if not running
3233   //
3234   if ($astman) {
3235     $device=$astman->database_get("AMPUSER",$account."/device");
3236     $device_arr = explode('&',$device);
3237     $sql = "SELECT dial from devices where id in ('".implode("','",$device_arr)."')";
3238   } else {
3239     $sql = "SELECT dial from devices where user = '{$account}'";
3240   }
3241   $results = sql($sql,"getAll",DB_FETCHMODE_ASSOC);
3242  
3243   //create an array of strings
3244   if (is_array($results)){
3245     foreach ($results as $result) {
3246       if ($chan_dahdi) {
3247         $dial[] = str_replace('ZAP', 'DAHDI', $result['dial']);
3248       } else {
3249         $dial[] = $result['dial'];
3250       }
3251     }
3252   }
3253  
3254   //create a string with & delimiter
3255   if (isset($dial) && is_array($dial)){
3256     $hint = implode($dial,"&");
3257   } else {
3258     if (isset($results[0]['dial'])) {
3259       $hint = $results[0]['dial'];
3260     } else {
3261       $hint = null;
3262     }
3263   }
3264  
3265   return $hint;
3266 }
3267
3268
3269
3270 /* begin page.users.php functions */
3271
3272 // get the existing extensions
3273 // the returned arrays contain [0]:extension [1]:name
3274 function core_users_list() {
3275   $results = sql("SELECT extension,name,voicemail FROM users ORDER BY extension","getAll");
3276
3277   //only allow extensions that are within administrator's allowed range
3278   foreach($results as $result){
3279     if (checkRange($result[0])){
3280       $extens[] = array($result[0],$result[1],$result[2]);
3281     }
3282   }
3283  
3284   if (isset($extens)) {
3285     sort($extens);
3286     return $extens;
3287   } else {
3288     return null;
3289   }
3290 }
3291
3292 function core_check_extensions($exten=true) {
3293   global $amp_conf;
3294
3295   $extenlist = array();
3296   if (is_array($exten) && empty($exten)) {
3297     return $extenlist;
3298   }
3299   $sql = "SELECT extension, name FROM users ";
3300   if (is_array($exten)) {
3301     $sql .= "WHERE extension in ('".implode("','",$exten)."')";
3302   }
3303   $sql .= " ORDER BY CAST(extension AS UNSIGNED)";
3304   $results = sql($sql,"getAll",DB_FETCHMODE_ASSOC);
3305
3306   foreach ($results as $result) {
3307     $thisexten = $result['extension'];
3308     $extenlist[$thisexten]['description'] = _("User Extension: ").$result['name'];
3309     $extenlist[$thisexten]['status'] = 'INUSE';
3310     $display = ($amp_conf['AMPEXTENSIONS'] == "deviceanduser")?'users':'extensions';
3311     $extenlist[$thisexten]['edit_url'] = "config.php?type=setup&display=$display&extdisplay=".urlencode($thisexten)."&skip=0";
3312   }
3313   return $extenlist;
3314 }
3315
3316 function core_check_destinations($dest=true) {
3317   global $active_modules;
3318
3319   $destlist = array();
3320   if (is_array($dest) && empty($dest)) {
3321     return $destlist;
3322   }
3323   $sql = "SELECT extension, cidnum, description, destination FROM incoming ";
3324   if ($dest !== true) {
3325     $sql .= "WHERE destination in ('".implode("','",$dest)."')";
3326   }
3327   $sql .= "ORDER BY extension, cidnum";
3328   $results = sql($sql,"getAll",DB_FETCHMODE_ASSOC);
3329
3330   //$type = isset($active_modules['announcement']['type'])?$active_modules['announcement']['type']:'setup';
3331
3332   foreach ($results as $result) {
3333     $thisdest = $result['destination'];
3334     $thisid   = $result['extension'].'/'.$result['cidnum'];
3335     $destlist[] = array(
3336       'dest' => $thisdest,
3337       'description' => sprintf(_("Inbound Route: %s (%s)"),$result['description'],$thisid),
3338       'edit_url' => 'config.php?display=did&extdisplay='.urlencode($thisid),
3339     );
3340   }
3341   return $destlist;
3342 }
3343
3344 function core_sipname_check($sipname, $extension) {
3345   global $db;
3346   if (!isset($sipname) || trim($sipname)=='')
3347     return true;
3348
3349   $sql = "SELECT sipname FROM users WHERE sipname = '$sipname' AND extension != '$extension'";
3350   $results = $db->getRow($sql,DB_FETCHMODE_ASSOC);
3351   if(DB::IsError($results)) {
3352         die_freepbx($results->getMessage().$sql);
3353   }
3354  
3355   if (isset($results['sipname']) && trim($results['sipname']) == $sipname)
3356     return false;
3357   else
3358     return true;
3359 }
3360
3361 function core_users_add($vars, $editmode=false) {
3362   extract($vars);
3363  
3364   global $db;
3365   global $amp_conf;
3366   global $astman;
3367
3368   $thisexten = isset($thisexten) ? $thisexten : '';
3369
3370   if (trim($extension) == '' ) {
3371     echo "<script>javascript:alert('"._("You must put in an extension (or user) number")."');</script>";
3372     return false;
3373   }
3374
3375   //ensure this id is not already in use
3376   $extens = core_users_list();
3377   if(is_array($extens)) {
3378     foreach($extens as $exten) {
3379       if ($exten[0]===$extension) {
3380         echo "<script>javascript:alert('".sprintf(_("This user/extension %s is already in use"),$extension)."');</script>";
3381         return false;
3382       }
3383     }
3384   }
3385
3386   $newdid_name = isset($newdid_name) ? $db->escapeSimple($newdid_name) : '';
3387   $newdid = isset($newdid) ? $newdid : '';
3388   $newdid = preg_replace("/[^0-9._XxNnZz\[\]\-\+]/" ,"", trim($newdid));
3389
3390   $newdidcid = isset($newdidcid) ? trim($newdidcid) : '';
3391   if (!preg_match('/^priv|^block|^unknown|^restrict|^unavail|^anonym/',strtolower($newdidcid))) {
3392     $newdidcid = preg_replace("/[^0-9._XxNnZz\[\]\-\+]/" ,"", $newdidcid);
3393   }
3394
3395   // Well more ugliness since the javascripts are already in here
3396   if ($newdid != '' || $newdidcid != '') {
3397     $existing = core_did_get($newdid, $newdidcid);
3398     if (! empty($existing)) {
3399       echo "<script>javascript:alert('".sprintf(_("A route with this DID/CID: %s/%s already exists"),$existing['extension'],$existing['cidnum'])."')</script>";
3400       return false;
3401     }
3402   }
3403
3404   $sipname = preg_replace("/\s/" ,"", trim($sipname));
3405   if (! core_sipname_check($sipname, $extension)) {
3406     echo "<script>javascript:alert('"._("This sipname: {$sipname} is already in use")."');</script>";
3407     return false;
3408   }
3409  
3410   //build the recording variable
3411   $recording = "out=".$record_out."|in=".$record_in;
3412  
3413   //escape quotes and any other bad chars:
3414   if(!get_magic_quotes_gpc()) {
3415     $outboundcid = $db->escapeSimple($outboundcid);
3416     $name = $db->escapeSimple($name);
3417   }
3418
3419   //if voicemail is enabled, set the box@context to use
3420   //havn't checked but why is voicemail needed on users anyway?  Doesn't exactly make it modular !
3421   if ( function_exists('voicemail_mailbox_get') ) {
3422     $vmbox = voicemail_mailbox_get($extension);
3423     if ( $vmbox == null ) {
3424       $voicemail = "novm";
3425     } else {
3426       $voicemail = $vmbox['vmcontext'];
3427     }
3428   }
3429
3430   // Clean replace any <> with () in display name - should have javascript stopping this but ...
3431   //
3432   $name = preg_replace(array('/</','/>/'), array('(',')'), trim($name));
3433  
3434   //insert into users table
3435   $sql="INSERT INTO users (extension,password,name,voicemail,ringtimer,noanswer,recording,outboundcid,sipname) values (\"";
3436   $sql.= "$extension\", \"";
3437   $sql.= isset($password)?$password:'';
3438   $sql.= "\", \"";
3439   $sql.= isset($name)?$name:'';
3440   $sql.= "\", \"";
3441   $sql.= isset($voicemail)?$voicemail:'default';
3442   $sql.= "\", \"";
3443   $sql.= isset($ringtimer)?$ringtimer:'';
3444   $sql.= "\", \"";
3445   $sql.= isset($noanswer)?$noanswer:'';
3446   $sql.= "\", \"";
3447   $sql.= isset($recording)?$recording:'';
3448   $sql.= "\", \"";
3449   $sql.= isset($outboundcid)?$outboundcid:'';
3450   $sql.= "\", \"";
3451   $sql.= isset($sipname)?$sipname:'';
3452   $sql.= "\")";
3453   sql($sql);
3454
3455   //write to astdb
3456   if ($astman) {
3457     $cid_masquerade = (isset($cid_masquerade) && trim($cid_masquerade) != "")?trim($cid_masquerade):$extension;
3458     $astman->database_put("AMPUSER",$extension."/password",isset($password)?$password:'');
3459     $astman->database_put("AMPUSER",$extension."/ringtimer",isset($ringtimer)?$ringtimer:'');
3460     $astman->database_put("AMPUSER",$extension."/noanswer",isset($noanswer)?$noanswer:'');
3461     $astman->database_put("AMPUSER",$extension."/recording",isset($recording)?$recording:'');
3462     $astman->database_put("AMPUSER",$extension."/outboundcid",isset($outboundcid)?"\"".$outboundcid."\"":'');
3463     $astman->database_put("AMPUSER",$extension."/cidname",isset($name)?"\"".$name."\"":'');
3464     $astman->database_put("AMPUSER",$extension."/cidnum",$cid_masquerade);
3465     $astman->database_put("AMPUSER",$extension."/voicemail","\"".isset($voicemail)?$voicemail:''."\"");
3466     switch ($call_screen) {
3467       case '0':
3468         $astman->database_del("AMPUSER",$extension."/screen");
3469         break;
3470       case 'nomemory':
3471         $astman->database_put("AMPUSER",$extension."/screen","\"nomemory\"");
3472         break;
3473       case 'memory':
3474         $astman->database_put("AMPUSER",$extension."/screen","\"memory\"");
3475         break;
3476       default:
3477     }
3478
3479     if (!$editmode) {
3480       $astman->database_put("AMPUSER",$extension."/device","\"".((isset($device))?$device:'')."\"");
3481     }
3482
3483     if (trim($callwaiting) == 'enabled') {
3484       $astman->database_put("CW",$extension,"\"ENABLED\"");
3485     } else if (trim($callwaiting) == 'disabled') {
3486       $astman->database_del("CW",$extension);
3487     } else {
3488       echo "ERROR: this state should not exist<br>";
3489     }
3490
3491     if (trim($pinless) == 'enabled') {
3492       $astman->database_put("AMPUSER",$extension."/pinless","\"NOPASSWD\"");
3493     } else if (trim($pinless) == 'disabled') {
3494       $astman->database_del("AMPUSER",$extension."/pinless");
3495     } else {
3496       echo "ERROR: this state should not exist<br>";
3497     }
3498
3499     // Moved VmX setup to voicemail module since it is part of voicemail
3500     //
3501   } else {
3502     fatal("Cannot connect to Asterisk Manager with ".$amp_conf["AMPMGRUSER"]."/".$amp_conf["AMPMGRPASS"]);
3503   }
3504
3505   // OK - got this far, if they entered a new inbound DID/CID let's deal with it now
3506   // remember - in the nice and ugly world of this old code, $vars has been extracted
3507   // newdid and newdidcid
3508
3509   // Now if $newdid is set we need to add the DID to the routes
3510   //
3511   if ($newdid != '' || $newdidcid != '') {
3512     $did_dest                = 'from-did-direct,'.$extension.',1';
3513     $did_vars['extension']   = $newdid;
3514     $did_vars['cidnum']      = $newdidcid;
3515     $did_vars['faxexten']    = '';
3516     $did_vars['faxemail']    = '';
3517     $did_vars['answer']      = '0';
3518     $did_vars['wait']        = '0';
3519     $did_vars['privacyman']  = '';
3520     $did_vars['alertinfo']   = '';
3521     $did_vars['ringing']     = '';
3522     $did_vars['mohclass']    = 'default';
3523     $did_vars['description'] = $newdid_name;
3524     $did_vars['grppre']      = '';
3525     $did_vars['delay_answer']= '0';
3526     $did_vars['pricid']= '';
3527     core_did_add($did_vars, $did_dest);
3528   }
3529
3530   return true;
3531 }
3532
3533 function core_users_get($extension){
3534   global $db;
3535   global $amp_conf;
3536   global $astman;
3537   //get all the variables for the meetme
3538   $sql = "SELECT * FROM users WHERE extension = '$extension'";
3539   $results = $db->getRow($sql,DB_FETCHMODE_ASSOC);
3540   if(DB::IsError($results)) {
3541     die_freepbx($results->getMessage().$sql);
3542   }
3543   if (empty($results)) {
3544     return array();
3545   }
3546  
3547   //explode recording vars
3548   $recording = explode("|",$results['recording']);
3549   if (isset($recording[1])) {
3550     $recout = substr($recording[0],4);
3551     $recin = substr($recording[1],3);
3552     $results['record_in']=$recin;
3553     $results['record_out']=$recout;
3554   } else {
3555     $results['record_in']='Adhoc';
3556     $results['record_out']='Adhoc';
3557   }
3558   if ($astman) {
3559     $cw = $astman->database_get("CW",$extension);
3560     $results['callwaiting'] = (trim($cw) == 'ENABLED') ? 'enabled' : 'disabled';
3561     $cid_masquerade=$astman->database_get("AMPUSER",$extension."/cidnum");
3562     $results['cid_masquerade'] = (trim($cid_masquerade) != "")?$cid_masquerade:$extension;
3563
3564     $call_screen=$astman->database_get("AMPUSER",$extension."/screen");
3565     $results['call_screen'] = (trim($call_screen) != "")?$call_screen:'0';
3566
3567     $pinless=$astman->database_get("AMPUSER",$extension."/pinless");
3568     $results['pinless'] = (trim($pinless) == 'NOPASSWD') ? 'enabled' : 'disabled';
3569   } else {
3570     fatal("Cannot connect to Asterisk Manager with ".$amp_conf["AMPMGRUSER"]."/".$amp_conf["AMPMGRPASS"]);
3571   }
3572
3573   return $results;
3574 }
3575
3576 function core_users_del($extension, $editmode=false){
3577   global $db;
3578   global $amp_conf;
3579   global $astman;
3580  
3581   //delete from devices table
3582   $sql="DELETE FROM users WHERE extension = \"$extension\"";
3583   $results = $db->query($sql);
3584   if(DB::IsError($results)) {
3585     die_freepbx($results->getMessage().$sql);
3586   }
3587
3588   //delete details to astdb
3589   if($astman)  {
3590     $astman->database_del("AMPUSER",$extension."/screen");
3591   }
3592   if ($astman && !$editmode) {
3593     // TODO just change this to delete everything
3594     $astman->database_deltree("AMPUSER/".$extension);
3595   }
3596 }
3597
3598 function core_users_directdid_get($directdid=""){
3599   return array();
3600 }
3601
3602 function core_users_cleanastdb($extension) {
3603   // This is called to remove any ASTDB traces of the user after a deletion. Otherwise,
3604   // call forwarding, call waiting settings could hang around and bite someone if they
3605   // recycle an extension. Is called from page.xtns and page.users.
3606   global $amp_conf;
3607   global $astman;
3608
3609   if ($astman) {
3610     $astman->database_del("CW",$extension);
3611     $astman->database_del("CF",$extension);
3612     $astman->database_del("CFB",$extension);
3613     $astman->database_del("CFU",$extension);
3614
3615   } else {
3616     fatal("Cannot connect to Asterisk Manager with ".$amp_conf["AMPMGRUSER"]."/".$amp_conf["AMPMGRPASS"]);
3617   }
3618 }
3619
3620 function core_users_edit($extension,$vars){
3621   global $db;
3622   global $amp_conf;
3623   global $astman;
3624  
3625   //I we are editing, we need to remember existing user<->device mapping, so we can delete and re-add
3626   if ($astman) {
3627     $ud = $astman->database_get("AMPUSER",$extension."/device");
3628     $current_vmcontext = $astman->database_get("AMPUSER",$extension."/voicemail");
3629     $new_vmcontext = isset($vars['vmcontext']) ? $vars['vmcontext'] : 'novm';
3630     $vars['device'] = $ud;
3631   } else {
3632     fatal("Cannot connect to Asterisk Manager with ".$amp_conf["AMPMGRUSER"]."/".$amp_conf["AMPMGRPASS"]);
3633   }
3634  
3635   // clean and check the did to make sure it is not being used by another extension or in did routing
3636   //
3637   $newdid_name = isset($newdid_name) ? $db->escapeSimple($newdid_name) : '';
3638   $newdid = isset($vars['newdid']) ? $vars['newdid'] : '';
3639   $newdid = preg_replace("/[^0-9._XxNnZz\[\]\-\+]/" ,"", trim($newdid));
3640
3641   $newdidcid = isset($vars['newdidcid']) ? trim($vars['newdidcid']) : '';
3642   if (!preg_match('/^priv|^block|^unknown|^restrict|^unavail|^anonym/',strtolower($newdidcid))) {
3643     $newdidcid = preg_replace("/[^0-9._XxNnZz\[\]\-\+]/" ,"", $newdidcid);
3644   }
3645
3646   // Well more ugliness since the javascripts are already in here
3647   if ($newdid != '' || $newdidcid != '') {
3648     $existing = core_did_get($newdid, $newdidcid);
3649     if (! empty($existing)) {
3650       echo "<script>javascript:alert('".sprintf(_("A route with this DID/CID: %s/%s already exists"),$existing['extension'],$existing['cidnum'])."')</script>";
3651       return false;
3652     }
3653   }
3654
3655   //delete and re-add
3656   if (core_sipname_check($vars['sipname'],$extension)) {
3657     core_users_del($extension, true);
3658     core_users_add($vars, true);
3659
3660     // If the vmcontext has changed, we need to change all the links. In extension mode, the link
3661     // to the current fixed device will get changed, but none others will
3662     //
3663     if ($current_vmcontext != $new_vmcontext) {
3664       $user_devices = explode('&',$ud);
3665       foreach ($user_devices as $user_device) {
3666         exec("rm -f /var/spool/asterisk/voicemail/device/".$user_device);
3667         if ($new_context != 'novm') {
3668           exec("/bin/ln -s /var/spool/asterisk/voicemail/".$new_vmcontext."/".$extension."/ /var/spool/asterisk/voicemail/device/".$user_device);
3669         }
3670       }
3671     }
3672   }
3673   return true;
3674 }
3675
3676 function core_directdid_list(){
3677   return array();
3678 }
3679
3680 function core_zapchandids_add($description, $channel, $did) {
3681   global $db;
3682
3683
3684   if (!ctype_digit(trim($channel)) || trim($channel) == '') {
3685     echo "<script>javascript:alert('"._("Invalid Channel Number, must be numeric and not blank")."')</script>";
3686     return false;
3687   }
3688   if (trim($did) == '') {
3689     echo "<script>javascript:alert('"._("Invalid DID, must be a non-blank DID")."')</script>";
3690     return false;
3691   }
3692
3693   $description = q($description);
3694   $channel     = q($channel);
3695   $did         = q($did);
3696
3697   $sql = "INSERT INTO zapchandids (channel, description, did) VALUES ($channel, $description, $did)";
3698   $results = $db->query($sql);
3699   if (DB::IsError($results)) {
3700     if ($results->getCode() == DB_ERROR_ALREADY_EXISTS) {
3701       echo "<script>javascript:alert('"._("Error Duplicate Channel Entry")."')</script>";
3702       return false;
3703     } else {
3704       die_freepbx($results->getMessage()."<br><br>".$sql);
3705     }
3706   }
3707   return true;
3708 }
3709
3710 function core_zapchandids_edit($description, $channel, $did) {
3711   global $db;
3712
3713   $description = q($description);
3714   $channel     = q($channel);
3715   $did         = q($did);
3716
3717   $sql = "UPDATE zapchandids SET description = $description, did = $did WHERE channel = $channel";
3718   $results = $db->query($sql);
3719   if (DB::IsError($results)) {
3720     die_freepbx($results->getMessage()."<br><br>".$sql);
3721   }
3722   return true;
3723 }
3724
3725 function core_zapchandids_delete($channel) {
3726   global $db;
3727
3728   $channel     = q($channel);
3729
3730   $sql = "DELETE FROM zapchandids WHERE channel = $channel";
3731   $results = $db->query($sql);
3732   if (DB::IsError($results)) {
3733     die_freepbx($results->getMessage()."<br><br>".$sql);
3734   }
3735   return true;
3736 }
3737
3738 function core_zapchandids_list() {
3739   global $db;
3740
3741   $sql = "SELECT * FROM zapchandids ORDER BY channel";
3742   return sql($sql,"getAll",DB_FETCHMODE_ASSOC);
3743 }
3744
3745 function core_zapchandids_get($channel) {
3746   global $db;
3747
3748   $channel     = q($channel);
3749
3750   $sql = "SELECT * FROM zapchandids WHERE channel = $channel";
3751   return sql($sql,"getRow",DB_FETCHMODE_ASSOC);
3752 }
3753
3754 /* end page.users.php functions */
3755
3756
3757
3758
3759
3760 /* begin page.trunks.php functions */
3761
3762 // we're adding ,don't require a $trunknum
3763 function core_trunks_add($tech, $channelid, $dialoutprefix, $maxchans, $outcid, $peerdetails, $usercontext, $userconfig, $register, $keepcid, $failtrunk, $disabletrunk, $name="", $provider="") {
3764   global $db;
3765  
3766   $name = trim($name) == "" ? $channelid : $name;
3767
3768   // find the next available ID
3769   $trunknum = 1;
3770
3771   // This is pretty ugle, will fix when we redo trunks and routes with proper uniqueids.
3772   // get the list, sort them, then look for a hole and use it, or overflow to the end if
3773   // not and use that
3774   //
3775   $trunk_hash = array();
3776   foreach(core_trunks_list() as $trunk) {
3777     $trunknum = ltrim($trunk[0],"OUT_");
3778     $trunk_hash[] = $trunknum;
3779   }
3780   sort($trunk_hash);
3781   $trunknum = 1;
3782   foreach ($trunk_hash as $trunk_id) {
3783     if ($trunk_id != $trunknum) {
3784       break;
3785     }
3786     $trunknum++;
3787   }
3788
3789   core_trunks_backendAdd($trunknum, $tech, $channelid, $dialoutprefix, $maxchans, $outcid, $peerdetails, $usercontext, $userconfig, $register, $keepcid, $failtrunk, $disabletrunk, $name, $provider);
3790   return $trunknum;
3791 }
3792
3793 function core_trunks_del($trunknum, $tech = null) {
3794   global $db;
3795  
3796   if ($tech === null) { // in EditTrunk, we get this info anyways
3797     $tech = core_trunks_getTrunkTech($trunknum);
3798   }
3799
3800   // conditionally, delete from iax or sip
3801   switch (strtolower($tech)) {
3802     case "iax2":
3803       $tech = "iax";
3804       // fall through
3805     case "iax":
3806     case "sip":
3807       sql("DELETE FROM `$tech` WHERE `id` IN ('tr-peer-$trunknum', 'tr-user-$trunknum', 'tr-reg-$trunknum')");
3808     break;
3809   }
3810   sql("DELETE FROM `trunks` WHERE `trunkid` = '$trunknum'");
3811 }
3812
3813 function core_trunks_edit($trunknum, $channelid, $dialoutprefix, $maxchans, $outcid, $peerdetails, $usercontext, $userconfig, $register, $keepcid, $failtrunk, $disabletrunk, $name="", $provider="") {
3814   global $db;
3815   $name = trim($name) == "" ? $channelid : $name;
3816
3817   $tech = core_trunks_getTrunkTech($trunknum);
3818   if ($tech == "") {
3819     return false;
3820   }
3821   core_trunks_del($trunknum, $tech);
3822   core_trunks_backendAdd($trunknum, $tech, $channelid, $dialoutprefix, $maxchans, $outcid, $peerdetails, $usercontext, $userconfig, $register, $keepcid, $failtrunk, $disabletrunk, $name, $provider);
3823 }
3824
3825 // just used internally by addTrunk() and editTrunk()
3826 //obsolete
3827 function core_trunks_backendAdd($trunknum, $tech, $channelid, $dialoutprefix, $maxchans, $outcid, $peerdetails, $usercontext, $userconfig, $register, $keepcid, $failtrunk, $disabletrunk, $name, $provider) {
3828   global $db;
3829  
3830   if  (is_null($dialoutprefix)) $dialoutprefix = ""; // can't be NULL
3831  
3832   //echo  "backendAddTrunk($trunknum, $tech, $channelid, $dialoutprefix, $maxchans, $outcid, $peerdetails, $usercontext, $userconfig, $register)";
3833  
3834   // change iax to "iax2" (only spot we actually store iax2, since its used by Dial()..)
3835   $techtemp = ((strtolower($tech) == "iax") ? "iax2" : $tech);
3836   $outval = (($techtemp == "custom") ? "AMP:".$channelid : strtoupper($techtemp).'/'.$channelid);
3837   unset($techtemp);
3838  
3839   $disable_flag = ($disabletrunk == "on")?1:0;
3840  
3841   switch (strtolower($tech)) {
3842     case "iax":
3843     case "iax2":
3844       core_trunks_addSipOrIax($peerdetails,'iax',$channelid,$trunknum,$disable_flag,'peer');
3845       if ($usercontext != ""){
3846         core_trunks_addSipOrIax($userconfig,'iax',$usercontext,$trunknum,$disable_flag,'user');
3847       }
3848       if ($register != ""){
3849         core_trunks_addRegister($trunknum,'iax',$register,$disable_flag);
3850       }
3851     break;
3852     case "sip":
3853       core_trunks_addSipOrIax($peerdetails,'sip',$channelid,$trunknum,$disable_flag,'peer');
3854       if ($usercontext != ""){
3855         core_trunks_addSipOrIax($userconfig,'sip',$usercontext,$trunknum,$disable_flag,'user');
3856       }
3857       if ($register != ""){
3858         core_trunks_addRegister($trunknum,'sip',$register,$disable_flag);
3859       }
3860     break;
3861   }
3862
3863   $sql = "
3864     INSERT INTO `trunks`
3865     (`trunkid`, `name`, `tech`, `outcid`, `keepcid`, `maxchans`, `failscript`, `dialoutprefix`, `channelid`, `usercontext`, `provider`, `disabled`)
3866     VALUES (
3867       '$trunknum',
3868       '".$db->escapeSimple($name)."',
3869       '".$db->escapeSimple($tech)."',
3870       '".$db->escapeSimple($outcid)."',
3871       '".$db->escapeSimple($keepcid)."',
3872       '".$db->escapeSimple($maxchans)."',
3873       '".$db->escapeSimple($failtrunk)."',
3874       '".$db->escapeSimple($dialoutprefix)."',
3875       '".$db->escapeSimple($channelid)."',
3876       '".$db->escapeSimple($usercontext)."',
3877       '".$db->escapeSimple($provider)."',
3878       '".$db->escapeSimple($disabletrunk)."'
3879     )";
3880     sql($sql);
3881 }
3882
3883 //TODO: replace with NEW table
3884 //
3885 function core_trunks_getTrunkTech($trunknum) {
3886   $tech = sql("SELECT `tech` FROM `trunks` WHERE `trunkid` = $trunknum", "getOne");
3887   if (!$tech) {
3888     return false;
3889   }
3890   $tech = strtolower($tech);
3891   if ($tech == "iax2") {
3892     $tech = "iax"; // same thing, here
3893   }
3894   return $tech;
3895 }
3896
3897 //add trunk info to sip or iax table
3898 function core_trunks_addSipOrIax($config,$table,$channelid,$trunknum,$disable_flag=0,$type='peer') {
3899   global $db;
3900
3901   switch ($type) {
3902     case 'peer':
3903       $trunknum = 'tr-peer-'.$trunknum;
3904       break;
3905     case 'user':
3906       $trunknum = 'tr-user-'.$trunknum;
3907       break;
3908   }
3909
3910   $confitem['account'] = $channelid;
3911   $gimmieabreak = nl2br($config);
3912   $lines = split('<br />',$gimmieabreak);
3913   foreach ($lines as $line) {
3914     $line = trim($line);
3915     if (count(split('=',$line)) > 1) {
3916       $tmp = split('=',$line,2);
3917       $key=trim($tmp[0]);
3918       $value=trim($tmp[1]);
3919       if (isset($confitem[$key]) && !empty($confitem[$key]))
3920         $confitem[$key].="&".$value;
3921       else
3922         $confitem[$key]=$value;
3923     }
3924   }
3925   // rember 1=disabled so we start at 2 (1 + the first 1)
3926   $seq = 1;
3927   foreach($confitem as $k=>$v) {
3928     $seq = ($disable_flag == 1) ? 1 : $seq+1;
3929     $dbconfitem[]=array($db->escapeSimple($k),$db->escapeSimple($v),$seq);
3930   }
3931   $compiled = $db->prepare("INSERT INTO $table (id, keyword, data, flags) values ('$trunknum',?,?,?)");
3932   $result = $db->executeMultiple($compiled,$dbconfitem);
3933   if(DB::IsError($result)) {
3934     die_freepbx($result->getMessage()."<br><br>INSERT INTO $table (id, keyword, data, flags) values ('$trunknum',?,?,'$disable_flag')"); 
3935   }
3936 }
3937
3938 //Sort trunks for sqlite
3939 function sort_trunks($a,$b)  {
3940         global $unique_trunks;
3941         ereg("OUT_([0-9]+)",$unique_trunks[$a][0],$trunk_num1);
3942         ereg("OUT_([0-9]+)",$unique_trunks[$b][0],$trunk_num2);
3943         return ($trunk_num1[1] >= $trunk_num2[1]? 1:-1);
3944 }
3945
3946 //get unique trunks
3947 function core_trunks_getDetails($trunkid='') {
3948   global $db;
3949   global $amp_conf;
3950
3951   if ($trunkid != '') {
3952     $sql = "SELECT * FROM `trunks` WHERE `trunkid` = '$trunkid'";
3953     $trunk = sql($sql,"getRow",DB_FETCHMODE_ASSOC);
3954
3955     $tech = strtolower($trunk['tech']);
3956     switch ($tech) {
3957       case 'iax2':
3958         $trunk['tech'] = 'iax';
3959         break;
3960       default:
3961         $trunk['tech'] = $tech;
3962         break;
3963     }
3964   } else {
3965     $sql = "SELECT * FROM `trunks` ORDER BY tech, name";
3966     $trunk = sql($sql,"getAll",DB_FETCHMODE_ASSOC);
3967   }
3968   return $trunk;
3969 }
3970
3971 function core_trunks_list($assoc = false) {
3972   // TODO: $assoc default to true, eventually..
3973
3974   global $db;
3975   global $amp_conf;
3976  
3977   $sql = "SELECT `trunkid` , `tech` , `channelid` , `disabled` FROM `trunks` ORDER BY `trunkid`";
3978   $trunks = sql($sql,"getAll",DB_FETCHMODE_ASSOC);
3979
3980   $unique_trunks = array();
3981   foreach ($trunks as $trunk) {
3982     $trunk_id = "OUT_".$trunk['trunkid'];
3983     $disabled = $trunk['disabled'];
3984     $tech = strtoupper($trunk['tech']);
3985     switch ($tech) {
3986       case 'IAX':
3987         $dialstring = 'IAX2/'.$trunk['channelid'];
3988         break;
3989       case 'CUSTOM':
3990         $dialstring = 'AMP:'.$trunk['channelid'];
3991         break;
3992       default:
3993         $dialstring = $tech.'/'.$trunk['channelid'];
3994         break;
3995     }
3996     $unique_trunks[] = array($trunk_id, $dialstring, $disabled);
3997   }
3998
3999   if ($assoc) {
4000     $trunkinfo = array();
4001
4002     foreach ($unique_trunks as $trunk) {
4003       list($tech,$name) = explode('/',$trunk[1]);
4004       $trunkinfo[$trunk[1]] = array(
4005         'name' => $name,
4006         'tech' => $tech,
4007         'globalvar' => $trunk[0], // ick
4008         'value' => $trunk[2], // ??  no idea what this is.
4009       ); 
4010     }
4011
4012     return $trunkinfo;
4013   } else {
4014     return $unique_trunks;
4015   }
4016 }
4017
4018 function core_trunks_addRegister($trunknum,$tech,$reg,$disable_flag=0) {
4019   sql("INSERT INTO $tech (id, keyword, data, flags) values ('tr-reg-$trunknum','register','$reg','$disable_flag')");
4020 }
4021
4022
4023 function core_trunks_addDialRules($trunknum, $dialrules) {
4024   global $db;
4025
4026   $values = array();
4027   $rules_arr = array();
4028   $i = 1;
4029   foreach ($dialrules as $rule) {
4030     $rules_arr[] = array($db->escapeSimple($rule),$i);
4031     $values["rule".$i++] = $rule;
4032   }
4033  
4034   sql("DELETE FROM `trunks_dialpatterns` WHERE `trunkid` = $trunknum");
4035   $compiled = $db->prepare("INSERT INTO `trunks_dialpatterns` (trunkid, rule, seq) VALUES ($trunknum,?,?)");
4036   $result = $db->executeMultiple($compiled,$rules_arr);
4037   if(DB::IsError($result)) {
4038     die_freepbx($result->getDebugInfo()."<br><br>".'error adding to trunks_dialpatterns table'); 
4039   }
4040 }
4041
4042 function core_trunks_readDialRulesFile() {
4043   $rule_hash = array();
4044   $sqlstr = "SELECT `trunkid`, `rule` FROM `trunks_dialpatterns` ORDER BY `trunkid`, `seq`";
4045   $patterns = sql($sqlstr,"getAll",DB_FETCHMODE_ASSOC);
4046   $trunk_num = false;
4047   foreach ($patterns as $pattern) {
4048     if ($pattern['trunkid'] != $trunk_num) {
4049       $rule_num = 1;
4050       $trunk_num = $pattern['trunkid'];
4051     }
4052     $rule_hash['trunk-'.$pattern['trunkid']]['rule'.$rule_num++] = $pattern['rule'];
4053   }
4054  
4055   return $rule_hash;
4056 }
4057
4058 /* DEPRECATED - SHOULD NO LONGER BE USED, generated from core_conf in retrieve_conf
4059  *
4060 function core_trunks_writeDialRulesFile($conf) {
4061   global $amp_conf;
4062   $localPrefixFile = $amp_conf['ASTETCDIR']."/localprefixes.conf";
4063  
4064   $fd = fopen($localPrefixFile,"w");
4065   foreach ($conf as $section=>$values) {
4066     fwrite($fd, "[".$section."]\n");
4067     foreach ($values as $key=>$value) {
4068       fwrite($fd, $key."=".$value."\n");
4069     }
4070     fwrite($fd, "\n");
4071   }
4072   fclose($fd);
4073 }
4074 */
4075
4076 /* THIS HAS BEEN DEPRECATED BUT WILL REMAIN IN FOR A FEW RELEASES */
4077 function core_trunks_parse_conf($filename, &$conf, &$section) {
4078   if (is_null($conf)) {
4079     $conf = array();
4080   }
4081   if (is_null($section)) {
4082     $section = "general";
4083   }
4084  
4085   if (file_exists($filename)) {
4086     $fd = fopen($filename, "r");
4087     while ($line = fgets($fd, 1024)) {
4088       if (preg_match("/^\s*([a-zA-Z0-9-_]+)\s*=\s*(.*?)\s*([;#].*)?$/",$line,$matches)) {
4089         // name = value
4090         // option line
4091         $conf[$section][ $matches[1] ] = $matches[2];
4092       } else if (preg_match("/^\s*\[(.+)\]/",$line,$matches)) {
4093         // section name
4094         $section = strtolower($matches[1]);
4095       } else if (preg_match("/^\s*#include\s+(.*)\s*([;#].*)?/",$line,$matches)) {
4096         // include another file
4097        
4098         if ($matches[1][0] == "/") {
4099           // absolute path
4100           $filename = $matches[1];
4101         } else {
4102           // relative path
4103           $filename =  dirname($filename)."/".$matches[1];
4104         }
4105        
4106         core_trunks_parse_conf($filename, $conf, $section);
4107       }
4108     }
4109   }
4110 }
4111
4112 function core_trunks_getTrunkTrunkName($trunknum) {
4113   $name = sql("SELECT `name` FROM `trunks` WHERE `trunkid` = $trunknum", "getOne");
4114   return $name;
4115 }
4116
4117 function core_trunks_getTrunkPeerDetails($trunknum) {
4118   global $db;
4119  
4120   $tech = core_trunks_getTrunkTech($trunknum);
4121  
4122   if ($tech == "zap" || $tech == "") return ""; // zap has no details
4123  
4124   $results = sql("SELECT keyword,data FROM $tech WHERE `id` = 'tr-peer-$trunknum' ORDER BY flags, keyword DESC","getAll");
4125  
4126   foreach ($results as $result) {
4127     if ($result[0] != 'account') {
4128       if (isset($confdetail))
4129         $confdetail .= $result[0] .'='. $result[1] . "\n";
4130       else
4131         $confdetail = $result[0] .'='. $result[1] . "\n";
4132     }
4133   }
4134   return $confdetail;
4135 }
4136
4137 function core_trunks_getTrunkUserContext($trunknum) {
4138   $usercontext = sql("SELECT `usercontext` FROM `trunks` WHERE `trunkid` = $trunknum", "getOne");
4139   return ((isset($usercontext)) ? $usercontext : '');
4140 }
4141
4142 function core_trunks_getTrunkUserConfig($trunknum) {
4143   global $db;
4144  
4145   $tech = core_trunks_getTrunkTech($trunknum);
4146  
4147   if ($tech == "zap" || $tech == "") return ""; // zap has no details
4148  
4149   $results = sql("SELECT keyword,data FROM $tech WHERE `id` = 'tr-user-$trunknum' ORDER BY flags, keyword DESC","getAll");
4150
4151   foreach ($results as $result) {
4152     if ($result[0] != 'account') {
4153       if (isset($confdetail))
4154         $confdetail .= $result[0] .'='. $result[1] . "\n";
4155       else
4156         $confdetail = $result[0] .'='. $result[1] . "\n";
4157     }
4158   }
4159   return isset($confdetail)?$confdetail:null;
4160 }
4161
4162 //get trunk account register string
4163 function core_trunks_getTrunkRegister($trunknum) {
4164   $tech = core_trunks_getTrunkTech($trunknum);
4165  
4166   if ($tech == "zap" || $tech == "") return ""; // zap has no register
4167  
4168   $results = sql("SELECT `keyword`, `data` FROM $tech WHERE `id` = 'tr-reg-$trunknum'","getAll");
4169
4170   foreach ($results as $result) {
4171       $register = $result[1];
4172   }
4173   return isset($register)?$register:null;
4174 }
4175
4176 function core_trunks_getDialRules($trunknum) {
4177   $conf = core_trunks_readDialRulesFile();
4178   if (isset($conf["trunk-".$trunknum])) {
4179     return $conf["trunk-".$trunknum];
4180   }
4181   return false;
4182 }
4183
4184 //get outbound routes for a given trunk
4185 function core_trunks_gettrunkroutes($trunknum) {
4186   $sql_code = "SELECT DISTINCT SUBSTRING(context,7) route ,args trunk FROM extensions WHERE context LIKE 'outrt-%' AND
4187     (args LIKE 'dialout-trunk,%' OR args LIKE 'dialout-enum,%' OR args LIKE 'dialout-dundi,%') ORDER BY context,priority";
4188   $results = sql( $sql_code, "getAll" ,DB_FETCHMODE_ASSOC);
4189   $routeseq = array();
4190   foreach ($results as $entry) {
4191     $pos1 = strpos($entry['trunk'],',')+1;
4192     $routeseq[$entry['route']][] = substr($entry['trunk'],$pos1,strpos($entry['trunk'],',',$pos1)-$pos1);
4193   }
4194   $routes = array();
4195   foreach ($routeseq as $key => $value) {
4196     $pos = array_search($trunknum, array_values(array_unique($value)));
4197     if ($pos !== false) {
4198       $routes[$key] = $pos+1; // start at 1, not 0
4199     }
4200   }
4201   return $routes;
4202 }
4203
4204 function core_trunks_deleteDialRules($trunknum) {
4205   sql("DELETE FROM `trunks_dialpatterns` WHERE `trunkid` = $trunknum");
4206 }
4207
4208 /* end page.trunks.php functions */
4209
4210
4211 /* begin page.routing.php functions */
4212
4213 //get unique outbound route names
4214 function core_routing_getroutenames()
4215 {
4216   global $amp_conf;
4217  
4218   if ($amp_conf["AMPDBENGINE"] == "sqlite3")
4219   {
4220     // SUBSTRING is not supported under sqlite3, we need to filter
4221     // this in php. I am not sure why "6" and not "7"
4222     // but I don't really care -> it works :)
4223     $results = sql("SELECT DISTINCT context FROM extensions WHERE context LIKE 'outrt-%' ORDER BY context ","getAll");
4224     foreach( array_keys($results) as $idx )
4225     {
4226        $results[$idx][0] = substr( $results[$idx][0], 6);
4227     }
4228   }
4229   else
4230   {
4231     // we SUBSTRING() to remove "outrt-"
4232     $results = sql("SELECT DISTINCT SUBSTRING(context,7) FROM extensions WHERE context LIKE 'outrt-%' ORDER BY context ","getAll");
4233   }
4234
4235
4236   //TODO: This needs to be yanked, should be in the upgrade script somewhere not here
4237   //
4238   if (count($results) == 0) {
4239     // see if they're still using the old dialprefix method
4240     if ($amp_conf["AMPDBENGINE"] == "sqlite3")  {
4241       $sql ="SELECT variable,value FROM globals WHERE variable LIKE 'DIAL\_OUT\_%' ESCAPE '\'";
4242     }
4243     else  {
4244       $sql ="SELECT variable,value FROM globals WHERE variable LIKE 'DIAL\\\_OUT\\\_%'";
4245     }
4246     $results = sql($sql,"getAll");
4247     // we SUBSTRING() to remove "outrt-"
4248    
4249     if (count($results) > 0) {
4250       // yes, they are using old method, let's update
4251      
4252       // get the default trunk
4253       $results_def = sql("SELECT value FROM globals WHERE variable = 'OUT'","getAll");
4254      
4255       if (preg_match("/{OUT_(\d+)}/", $results_def[0][0], $matches)) {
4256         $def_trunk = $matches[1];
4257       } else {
4258         $def_trunk = "";
4259       }
4260      
4261       $default_patterns = array(  // default patterns that used to be in extensions.conf
4262             "NXXXXXX",
4263             "NXXNXXXXXX",
4264             "1800NXXXXXX",
4265             "1888NXXXXXX",
4266             "1877NXXXXXX",
4267             "1866NXXXXXX",
4268             "1NXXNXXXXXX",
4269             "011.",
4270             "911",
4271             "411",
4272             "311",
4273             );
4274      
4275       foreach ($results as $temp) {
4276         // temp[0] is "DIAL_OUT_1"
4277         // temp[1] is the dial prefix
4278        
4279         $trunknum = substr($temp[0],9);
4280        
4281         $name = "route".$trunknum;
4282        
4283         $trunks = array(1=>"OUT_".$trunknum); // only one trunk to use
4284        
4285         $patterns = array();
4286         foreach ($default_patterns as $pattern) {
4287           $patterns[] = $temp[1]."|".$pattern;
4288         }
4289        
4290         if ($trunknum == $def_trunk) {
4291           // this is the default trunk, add the patterns with no prefix
4292           $patterns = array_merge($patterns, $default_patterns);
4293         }
4294        
4295         // add this as a new route
4296         core_routing_add($name, $patterns, $trunks,"new");
4297       }
4298      
4299      
4300       // delete old values
4301       if ($amp_conf["AMPDBENGINE"] == "sqlite3")  {
4302         $sql = "DELETE FROM globals WHERE (variable LIKE 'DIAL\_OUT\_%') ESCAPE '\' OR (variable = 'OUT') ";
4303       }
4304       else  {
4305         $sql = "DELETE FROM globals WHERE (variable LIKE 'DIAL\\\_OUT\\\_%') OR (variable = 'OUT') ";
4306       }
4307       sql($sql);
4308
4309       // we need to re-generate extensions_additional.conf
4310       // i'm not sure how to do this from here
4311      
4312       // re-run our query
4313       $results = sql("SELECT DISTINCT SUBSTRING(context,7) FROM extensions WHERE context LIKE 'outrt-%' ORDER BY context ","getAll");
4314       // we SUBSTRING() to remove "outrt-"
4315     }
4316    
4317   } // else, it just means they have no routes.
4318  
4319   return $results;
4320 }
4321
4322 function core_routing_setroutepriority($routepriority, $reporoutedirection, $reporoutekey)
4323 {
4324   global $db, $amp_conf;
4325   $counter=-1;
4326   foreach ($routepriority as $tresult)
4327   {
4328     $counter++;
4329     if (($counter==($reporoutekey-1)) && ($reporoutedirection=="up")) {
4330       // swap this one with the one before (move up)
4331       $temproute = $routepriority[$counter];
4332       $routepriority[ $counter ] = $routepriority[ $counter+1 ];
4333       $routepriority[ $counter+1 ] = $temproute;
4334      
4335     } else if (($counter==($reporoutekey)) && ($reporoutedirection=="down")) {
4336       // swap this one with the one after (move down)
4337       $temproute = $routepriority[ $counter+1 ];
4338       $routepriority[ $counter+1 ] = $routepriority[ $counter ];
4339       $routepriority[ $counter ] = $temproute;
4340     }
4341   }
4342   unset($temproute);
4343   $routepriority = array_values($routepriority); // resequence our numbers
4344   $counter=0;
4345   foreach ($routepriority as $tresult) {
4346     $order=core_routing_setroutepriorityvalue($counter++);
4347     $sql = sprintf("Update extensions set context='outrt-%s-%s' WHERE context='outrt-%s'",$order,substr($tresult[0],4), $tresult[0]);
4348     $result = $db->query($sql);
4349     if(DB::IsError($result)) {     
4350       die_freepbx($result->getMessage());
4351     }
4352   }
4353  
4354   // Delete and readd the outbound-allroutes entries
4355   $sql = "delete from  extensions WHERE context='outbound-allroutes'";
4356   $result = $db->query($sql);
4357   if(DB::IsError($result)) {
4358           die_freepbx($result->getMessage().$sql);
4359   }
4360  
4361   $sql = "SELECT DISTINCT context FROM extensions WHERE context like 'outrt-%' ORDER BY context";
4362   $results = $db->getAll($sql);
4363   if(DB::IsError($results)) {
4364     die_freepbx($results->getMessage());
4365   }
4366
4367   $priority_loops=1; 
4368   foreach ($results as $row) {
4369     $sql = "INSERT INTO extensions (context, extension, priority, application, args, descr, flags) VALUES ";
4370     $sql .= "('outbound-allroutes', ";
4371     $sql .= "'include', ";
4372     $sql .= "'".$priority_loops++."', ";
4373     $sql .= "'".$row[0]."', ";
4374     $sql .= "'', ";
4375     $sql .= "'', ";
4376     $sql .= "'2')";
4377  
4378     //$sql = sprintf("Update extensions set application='outrt-%s-%s' WHERE context='outbound-allroutes' and  application='outrt-%s'",$order,substr($tresult[0],4), $tresult[0]);
4379     $result = $db->query($sql);
4380     if(DB::IsError($result)) {     
4381       die_freepbx($result->getMessage(). $sql);
4382     }
4383   }
4384  
4385   if ( $amp_conf["AMPDBENGINE"] == "sqlite3")
4386     $sql = "SELECT DISTINCT context FROM extensions WHERE context LIKE 'outrt-%' ORDER BY context ";
4387   else
4388     $sql = "SELECT DISTINCT SUBSTRING(context,7) FROM extensions WHERE context LIKE 'outrt-%' ORDER BY context ";
4389
4390         // we SUBSTRING() to remove "outrt-"
4391         $routepriority = $db->getAll($sql);
4392         if(DB::IsError($routepriority)) {
4393                 die_freepbx($routepriority->getMessage());
4394         }
4395
4396   // TODO: strip the context on the sqlite3 backend
4397   // not sure where does it effects, since this is working on my setup...
4398   // welcome to funky town
4399         return ($routepriority);
4400 }
4401
4402 function core_routing_setroutepriorityvalue($key)
4403 {
4404   $key=$key+1;
4405   if ($key<10)
4406     $prefix = sprintf("00%d",$key);
4407   else if ((9<$key)&&($key<100))
4408     $prefix = sprintf("0%d",$key);
4409   else if ($key>100)
4410     $prefix = sprintf("%d",$key);
4411   return ($prefix);
4412 }
4413
4414
4415 function core_routing_add($name, $patterns, $trunks, $method, $pass, $emergency = "", $intracompany = "", $mohsilence = "") {
4416
4417   global $db;
4418
4419   $trunktech=array();
4420
4421   // Make sure only valid characters are there, javascript should enforce this (and more)
4422   //
4423   $name = preg_replace("/[^a-zA-Z0-9_\-]/" ,"",$name);
4424
4425   //Retrieve each trunk tech for later lookup
4426   //
4427   $result = core_trunks_list(true);
4428   foreach($result as $tr) {
4429     $trunktech[$tr['globalvar']] = $tr['tech'];
4430   }
4431  
4432   if ($method=="new") {
4433     $sql="select DISTINCT context FROM extensions WHERE context LIKE 'outrt-%' ORDER BY context";
4434     $routepriority = $db->getAll($sql);
4435     if(DB::IsError($routepriority)) {
4436       die_freepbx($routepriority->getMessage());
4437     }
4438     $order=core_routing_setroutepriorityvalue(count($routepriority));
4439     $name = sprintf ("%s-%s",$order,$name);
4440   }
4441   $trunks = array_values($trunks); // probably already done, but it's important for our dialplan
4442
4443  
4444   foreach ($patterns as $pattern) {
4445     if (false !== ($pos = strpos($pattern,"|"))) {
4446       // we have a | meaning to not pass the digits on
4447       // (ie, 9|NXXXXXX should use the pattern _9NXXXXXX but only pass NXXXXXX, not the leading 9)
4448      
4449       $pattern = str_replace("|","",$pattern); // remove all |'s
4450       $exten = "EXTEN:".$pos; // chop off leading digit
4451     } else {
4452       // we pass the full dialed number as-is
4453       $exten = "EXTEN";
4454     }
4455    
4456     if (!preg_match("/^[0-9*]+$/",$pattern)) {
4457       // note # is not here, as asterisk doesn't recoginize it as a normal digit, thus it requires _ pattern matching
4458      
4459       // it's not strictly digits, so it must have patterns, so prepend a _
4460       $pattern = "_".$pattern;
4461     }
4462    
4463     // 1st priority is emergency dialing variable (if set)
4464     if(!empty($emergency)) {
4465       $startpriority = 1;
4466       $sql = "INSERT INTO extensions (context, extension, priority, application, args, descr) VALUES ";
4467       $sql .= "('outrt-".$name."', ";
4468       $sql .= "'".$pattern."', ";
4469       $sql .= "'".$startpriority."', ";
4470       $sql .= "'SetVar', ";
4471       $sql .= "'EMERGENCYROUTE=YES', ";
4472       $sql .= "'Use Emergency CID for device')";
4473       $result = $db->query($sql);
4474       if(DB::IsError($result)) {
4475         die_freepbx($result->getMessage());
4476       }
4477     } else {
4478       $startpriority = 0;
4479     }
4480
4481     // Next Priority (either first or second depending on above)
4482     if(!empty($intracompany)) {
4483          $startpriority += 1;
4484          $sql = "INSERT INTO extensions (context, extension, priority, application, args, descr) VALUES ";
4485          $sql .= "('outrt-".$name."', ";
4486          $sql .= "'".$pattern."', ";
4487          $sql .= "'".$startpriority."', ";
4488          $sql .= "'SetVar', ";
4489          $sql .= "'INTRACOMPANYROUTE=YES', ";
4490          $sql .= "'Preserve Intenal CID Info')";
4491          $result = $db->query($sql);
4492         if(DB::IsError($result)) {
4493              die_freepbx($result->getMessage());
4494         }
4495     }
4496
4497     // Next Priority (either first, second or third depending on above)
4498     if(!empty($mohsilence) && trim($mohsilence) != 'default') {
4499          $startpriority += 1;
4500          $sql = "INSERT INTO extensions (context, extension, priority, application, args, descr) VALUES ";
4501          $sql .= "('outrt-".$name."', ";
4502          $sql .= "'".$pattern."', ";
4503          $sql .= "'".$startpriority."', ";
4504          $sql .= "'SetVar', ";
4505          $sql .= "'MOHCLASS=".$mohsilence."', ";
4506          $sql .= "'Do not play moh on this route')";
4507          $result = $db->query($sql);
4508         if(DB::IsError($result)) {
4509              die_freepbx($result->getMessage());
4510         }
4511     }
4512
4513     $first_trunk = 1;
4514     foreach ($trunks as $priority => $trunk) {
4515       $priority += $startpriority;
4516       $priority += 1; // since arrays are 0-based, but we want priorities to start at 1
4517      
4518       $sql = "INSERT INTO extensions (context, extension, priority, application, args) VALUES ";
4519       $sql .= "('outrt-".$name."', ";
4520       $sql .= "'".$pattern."', ";
4521       $sql .= "'".$priority."', ";
4522       $sql .= "'Macro', ";
4523       if ($first_trunk)
4524         $pass_str = $pass;
4525       else
4526         $pass_str = "";
4527
4528       if ($trunktech[$trunk] == "ENUM") {
4529         $sql .= "'dialout-enum,".substr($trunk,4).",\${".$exten."},".$pass_str."'"; // cut off OUT_ from $trunk
4530       } else if ($trunktech[$trunk] == "DUNDI") {
4531         $sql .= "'dialout-dundi,".substr($trunk,4).",\${".$exten."},".$pass_str."'"; // cut off OUT_ from $trunk
4532       } else {
4533         $sql .= "'dialout-trunk,".substr($trunk,4).",\${".$exten."},".$pass_str."'"; // cut off OUT_ from $trunk
4534       }
4535       $sql .= ")";
4536      
4537       $result = $db->query($sql);
4538       if(DB::IsError($result)) {
4539         die_freepbx($result->getMessage());
4540       }
4541       //To identify the first trunk in a pattern
4542       //so that passwords are in the first trunk in
4543       //each pattern
4544       $first_trunk = 0;
4545     }
4546    
4547     $priority += 1;
4548     $sql = "INSERT INTO extensions (context, extension, priority, application, args, descr) VALUES ";
4549     $sql .= "('outrt-".$name."', ";
4550     $sql .= "'".$pattern."', ";
4551     $sql .= "'".$priority."', ";
4552     $sql .= "'Macro', ";
4553     $sql .= "'outisbusy', ";
4554     $sql .= "'No available circuits')";
4555    
4556     $result = $db->query($sql);
4557     if(DB::IsError($result)) {
4558       die_freepbx($result->getMessage());
4559     }
4560   }
4561
4562  
4563   // add an include=>outrt-$name  to [outbound-allroutes]:
4564  
4565   // we have to find the first available priority.. priority doesn't really matter for the include, but
4566   // there is a unique index on (context,extension,priority) so if we don't do this we can't put more than
4567   // one route in the outbound-allroutes context.
4568   $sql = "SELECT priority FROM extensions WHERE context = 'outbound-allroutes' AND extension = 'include'";
4569   $results = $db->getAll($sql);
4570   if(DB::IsError($results)) {
4571     die_freepbx($results->getMessage());
4572   }
4573   $priorities = array();
4574   foreach ($results as $row) {
4575     $priorities[] = $row[0];
4576   }
4577   for ($priority = 1; in_array($priority, $priorities); $priority++);
4578  
4579   // $priority should now be the lowest available number
4580  
4581   $sql = "INSERT INTO extensions (context, extension, priority, application, args, descr, flags) VALUES ";
4582   $sql .= "('outbound-allroutes', ";
4583   $sql .= "'include', ";
4584   $sql .= "'".$priority."', ";
4585   $sql .= "'outrt-".$name."', ";
4586   $sql .= "'', ";
4587   $sql .= "'', ";
4588   $sql .= "'2')";
4589  
4590   $result = $db->query($sql);
4591   if(DB::IsError($result)) {
4592     die_freepbx($priority.$result->getMessage());
4593   }
4594  
4595 }
4596
4597 function core_routing_edit($name, $patterns, $trunks, $pass, $emergency="", $intracompany = "", $mohsilence="") {
4598   core_routing_del($name);
4599   core_routing_add($name, $patterns, $trunks,"edit", $pass, $emergency, $intracompany, $mohsilence);
4600 }
4601
4602 function core_routing_del($name) {
4603   global $db;
4604   $sql = "DELETE FROM extensions WHERE context = 'outrt-".$name."'";
4605   $result = $db->query($sql);
4606   if(DB::IsError($result)) {
4607     die_freepbx($result->getMessage());
4608   }
4609  
4610   $sql = "DELETE FROM extensions WHERE context = 'outbound-allroutes' AND application = 'outrt-".$name."' ";
4611   $result = $db->query($sql);
4612   if(DB::IsError($result)) {
4613     die_freepbx($result->getMessage());
4614   }
4615  
4616   return $result;
4617 }
4618
4619 /* Delete all occurences of the specified trunk from all routes that may use it
4620  */
4621 function core_routing_trunk_del($trunknum) {
4622   global $db;
4623
4624   $sql = "DELETE FROM `extensions` WHERE `application` = 'Macro' AND `context` LIKE 'outrt-%' AND `args` LIKE 'dialout-%,$trunknum,%'";
4625   $result = $db->query($sql);
4626 }
4627
4628 function core_routing_rename($oldname, $newname) {
4629   global $db;
4630
4631   $route_prefix=substr($oldname,0,4);
4632   $newname=$route_prefix.$newname;
4633   $sql = "SELECT context FROM extensions WHERE context = 'outrt-".$newname."'";
4634   $results = $db->getAll($sql);
4635   if (count($results) > 0) {
4636     // there's already a route with this name
4637     return false;
4638   }
4639  
4640   $sql = "UPDATE extensions SET context = 'outrt-".$newname."' WHERE context = 'outrt-".$oldname."'";
4641   $result = $db->query($sql);
4642   if(DB::IsError($result)) {
4643     die_freepbx($result->getMessage());
4644   }
4645         $mypriority=sprintf("%d",$route_prefix); 
4646   $sql = "UPDATE extensions SET application = 'outrt-".$newname."', priority = '$mypriority' WHERE context = 'outbound-allroutes' AND application = 'outrt-".$oldname."' ";
4647   $result = $db->query($sql);
4648   if(DB::IsError($result)) {
4649     die_freepbx($result->getMessage());
4650   }
4651  
4652   return true;
4653 }
4654
4655 //get unique outbound route patterns for a given context
4656 function core_routing_getroutepatterns($route) {
4657   global $db;
4658   $sql = "SELECT extension, args FROM extensions WHERE context = 'outrt-".$route."' AND (args LIKE 'dialout-trunk%' OR args LIKE 'dialout-enum%' OR args LIKE 'dialout-dundi%') ORDER BY extension ";
4659   $results = $db->getAll($sql);
4660   if(DB::IsError($results)) {
4661     die_freepbx($results->getMessage());
4662   }
4663  
4664   $patterns = array();
4665   foreach ($results as $row) {
4666     if ($row[0][0] == "_") {
4667       // remove leading _
4668       $pattern = substr($row[0],1);
4669     } else {
4670       $pattern = $row[0];
4671     }
4672    
4673     if (preg_match("/{EXTEN:(\d+)}/", $row[1], $matches)) {
4674       // this has a digit offset, we need to insert a |
4675       $pattern = substr($pattern,0,$matches[1])."|".substr($pattern,$matches[1]);
4676     }
4677    
4678     $patterns[] = $pattern;
4679   }
4680   return array_unique($patterns);
4681 }
4682
4683 //get unique outbound route trunks for a given context
4684 function core_routing_getroutetrunks($route) {
4685   global $db;
4686   $sql = "SELECT DISTINCT args FROM extensions WHERE context = 'outrt-".$route."' AND (args LIKE 'dialout-trunk,%' OR args LIKE 'dialout-enum,%' OR args LIKE 'dialout-dundi,%') ORDER BY CAST(priority as UNSIGNED) ";
4687   $results = $db->getAll($sql);
4688   if(DB::IsError($results)) {
4689     die_freepbx($results->getMessage());
4690   }
4691  
4692   $trunks = array();
4693   foreach ($results as $row) {
4694     if (preg_match('/^dialout-trunk,(\d+)/', $row[0], $matches)) {
4695       // check in_array -- even though we did distinct
4696       // we still might get ${EXTEN} and ${EXTEN:1} if they used | to split a pattern
4697       if (!in_array("OUT_".$matches[1], $trunks)) {
4698         $trunks[] = "OUT_".$matches[1];
4699       }
4700     } else if (preg_match('/^dialout-enum,(\d+)/', $row[0], $matches)) {
4701       if (!in_array("OUT_".$matches[1], $trunks)) {
4702         $trunks[] = "OUT_".$matches[1];
4703       }
4704     } else if (preg_match('/^dialout-dundi,(\d+)/', $row[0], $matches)) {
4705       if (!in_array("OUT_".$matches[1], $trunks)) {
4706         $trunks[] = "OUT_".$matches[1];
4707       }
4708     }
4709   }
4710   return $trunks;
4711 }
4712
4713
4714 //get password for this route
4715 function core_routing_getroutepassword($route) {
4716   global $db;
4717   $sql = "SELECT DISTINCT args FROM extensions WHERE context = 'outrt-".$route."' AND (args LIKE 'dialout-trunk,%' OR args LIKE 'dialout-enum,%' OR args LIKE 'dialout-dundi,%') ORDER BY CAST(priority as UNSIGNED) ";
4718   $results = $db->getOne($sql);
4719   if(DB::IsError($results)) {
4720     die_freepbx($results->getMessage());
4721   }
4722   if (preg_match('/^.*,.*,.*,(\d+|\/\S+)/', $results, $matches)) {
4723     $password = $matches[1];
4724   } else {
4725     $password = "";
4726   }
4727  
4728   return $password;
4729 }
4730
4731 //get emergency state for this route
4732 function core_routing_getrouteemergency($route) {
4733   global $db;
4734   $sql = "SELECT DISTINCT args FROM extensions WHERE context = 'outrt-".$route."' AND (args LIKE 'EMERGENCYROUTE%') ";
4735   $results = $db->getOne($sql);
4736   if(DB::IsError($results)) {
4737     die_freepbx($results->getMessage());
4738   }
4739   if (preg_match('/^.*=(.*)/', $results, $matches)) {
4740     $emergency = $matches[1];
4741   } else {
4742     $emergency = "";
4743   }
4744  
4745   return $emergency;
4746 }
4747
4748 //get intracompany routing status for this route
4749 function core_routing_getrouteintracompany($route) {
4750
4751        global $db;
4752        $sql = "SELECT DISTINCT args FROM extensions WHERE context = 'outrt-".$route."' AND (args LIKE 'INTRACOMPANYROUTE%') ";
4753        $results = $db->getOne($sql);
4754        if(DB::IsError($results)) {
4755                die_freepbx($results->getMessage());
4756        }
4757        if (preg_match('/^.*=(.*)/', $results, $matches)) {
4758                $intracompany = $matches[1];
4759        } else {
4760                $intracompany = "";
4761        }
4762        return $intracompany;
4763 }
4764
4765 //get mohsilence routing status for this route
4766 function core_routing_getroutemohsilence($route) {
4767
4768        global $db;
4769        $sql = "SELECT DISTINCT args FROM extensions WHERE context = 'outrt-".$route."' AND (args LIKE 'MOHCLASS%') ";
4770        $results = $db->getOne($sql);
4771        if(DB::IsError($results)) {
4772                die_freepbx($results->getMessage());
4773        }
4774        if (preg_match('/^.*=(.*)/', $results, $matches)) {
4775                $mohsilence = $matches[1];
4776        } else {
4777                $mohsilence = "";
4778        }
4779        return $mohsilence;
4780 }
4781
4782 function general_get_zonelist() {
4783   return array(
4784  array ( "name" => "Austria",  "iso" => "at", "conf" => "ringcadence = 1000,5000\ndial = 420\nbusy = 420/400,0/400\nring = 420/1000,0/5000\ncongestion = 420/200,0/200\ncallwaiting = 420/40,0/1960\ndialrecall = 420\nrecord = 1400/80,0/14920\ninfo = 950/330,1450/330,1850/330,0/1000\nstutter = 380+420\n"),
4785  array ( "name" => "Australia",  "iso" => "au", "conf" => "ringcadence = 400,200,400,2000\ndial = 413+438\nbusy = 425/375,0/375\nring = 413+438/400,0/200,413+438/400,0/2000\ncongestion = 425/375,0/375,420/375,0/375\ncallwaiting = 425/200,0/200,425/200,0/4400\ndialrecall = 413+438\nrecord = !425/1000,!0/15000,425/360,0/15000\ninfo = 425/2500,0/500\nstd = !525/100,!0/100,!525/100,!0/100,!525/100,!0/100,!525/100,!0/100,!525/100\nfacility = 425\nstutter = 413+438/100,0/40\nringmobile = 400+450/400,0/200,400+450/400,0/2000\n"),
4786  array ( "name" => "Brazil",  "iso" => "br", "conf" => "ringcadence = 1000,4000\ndial = 425\nbusy = 425/250,0/250\nring = 425/1000,0/4000\ncongestion = 425/250,0/250,425/750,0/250\ncallwaiting = 425/50,0/1000\ndialrecall = 350+440\nrecord = 425/250,0/250\ninfo = 950/330,1400/330,1800/330\nstutter = 350+440\n"),
4787  array ( "name" => "Belgium",  "iso" => "be", "conf" => "ringcadence = 1000,3000\ndial = 425\nbusy = 425/500,0/500\nring = 425/1000,0/3000\ncongestion = 425/167,0/167\ncallwaiting = 1400/175,0/175,1400/175,0/3500\ndialrecall = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440\nrecord = 1400/500,0/15000\ninfo = 900/330,1400/330,1800/330,0/1000\nstutter = 425/1000,0/250\n"),
4788  array ( "name" => "Bulgaria",  "iso" => "bg", "conf" => "ringcadence = 1000,4000\ndial = 425\nbusy = 425/500,0/500\nring = 425/1000,0/4000\ncongestion = 425/250,0/250\ncallwaiting = 425/150,0/150,425/150,0/4000\ndialrecall = !425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425\nrecord = 1400/425,0/15000\ninfo = 950/330,1400/330,1800/330,0/1000\nstutter = 425/1500,0/100\n"),
4789  array ( "name" => "Switzerland",  "iso" => "ch", "conf" => "ringcadence = 1000,4000\ndial = 425\nbusy = 425/500,0/500\nring = 425/1000,0/4000\ncongestion = 425/200,0/200\ncallwaiting = 425/200,0/200,425/200,0/4000\ndialrecall = !425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425\nrecord = 1400/80,0/15000\ninfo = 950/330,1400/330,1800/330,0/1000\nstutter = 425+340/1100,0/1100\n"),
4790  array ( "name" => "Chile",  "iso" => "cl", "conf" => "ringcadence = 1000,3000\ndial = 400\nbusy = 400/500,0/500\nring = 400/1000,0/3000\ncongestion = 400/200,0/200\ncallwaiting = 400/250,0/8750\ndialrecall = !400/100,!0/100,!400/100,!0/100,!400/100,!0/100,400\nrecord = 1400/500,0/15000\ninfo = 950/333,1400/333,1800/333,0/1000\nstutter = !400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,400\n"),
4791  array ( "name" => "China",  "iso" => "cn", "conf" => "ringcadence = 1000,4000\ndial = 450\nbusy = 450/350,0/350\nring = 450/1000,0/4000\ncongestion = 450/700,0/700\ncallwaiting = 450/400,0/4000\ndialrecall = 450\nrecord = 950/400,0/10000\ninfo = 450/100,0/100,450/100,0/100,450/100,0/100,450/400,0/400\nstutter = 450+425\n"),
4792  array ( "name" => "Czech Republic",  "iso" => "cz", "conf" => "ringcadence = 1000,4000\ndial = 425/330,0/330,425/660,0/660\nbusy = 425/330,0/330\nring = 425/1000,0/4000\ncongestion = 425/165,0/165\ncallwaiting = 425/330,0/9000\ndialrecall = !425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425/330,0/330,425/660,0/660\nrecord = 1400/500,0/14000\ninfo = 950/330,0/30,1400/330,0/30,1800/330,0/1000\nstutter = 425/450,0/50\n"),
4793  array ( "name" => "Germany",  "iso" => "de", "conf" => "ringcadence = 1000,4000\ndial = 425\nbusy = 425/480,0/480\nring = 425/1000,0/4000\ncongestion = 425/240,0/240\ncallwaiting = !425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,0\ndialrecall = !425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425\nrecord = 1400/80,0/15000\ninfo = 950/330,1400/330,1800/330,0/1000\nstutter = 425+400\n"),
4794  array ( "name" => "Denmark",  "iso" => "dk", "conf" => "ringcadence = 1000,4000\ndial = 425\nbusy = 425/500,0/500\nring = 425/1000,0/4000\ncongestion = 425/200,0/200\ncallwaiting = !425/200,!0/600,!425/200,!0/3000,!425/200,!0/200,!425/200,0\ndialrecall = !425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425\nrecord = 1400/80,0/15000\ninfo = 950/330,1400/330,1800/330,0/1000\nstutter = 425/450,0/50\n"),
4795  array ( "name" => "Estonia",  "iso" => "ee", "conf" => "ringcadence = 1000,4000\ndial = 425\nbusy = 425/300,0/300\nring = 425/1000,0/4000\ncongestion = 425/200,0/200\ncallwaiting = 950/650,0/325,950/325,0/30,1400/1300,0/2600\ndialrecall = 425/650,0/25\nrecord = 1400/500,0/15000\ninfo = 950/650,0/325,950/325,0/30,1400/1300,0/2600\nstutter = !425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425\n"),
4796  array ( "name" => "Finland",  "iso" => "fi", "conf" => "ringcadence = 1000,4000\ndial = 425\nbusy = 425/300,0/300\nring = 425/1000,0/4000\ncongestion = 425/200,0/200\ncallwaiting = 425/150,0/150,425/150,0/8000\ndialrecall = 425/650,0/25\nrecord = 1400/500,0/15000\ninfo = 950/650,0/325,950/325,0/30,1400/1300,0/2600\nstutter = 425/650,0/25\n"),
4797  array ( "name" => "France",  "iso" => "fr", "conf" => "ringcadence = 1500,3500\ndial = 440\nbusy = 440/500,0/500\nring = 440/1500,0/3500\ncongestion = 440/250,0/250\ncallwait = 440/300,0/10000\ndialrecall = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440\nrecord = 1400/500,0/15000\ninfo = !950/330,!1400/330,!1800/330\nstutter = !440/100,!0/100,!440/100,!0/100,!440/100,!0/100,!440/100,!0/100,!440/100,!0/100,!440/100,!0/100,440\n"),
4798  array ( "name" => "Greece",  "iso" => "gr", "conf" => "ringcadence = 1000,4000\ndial = 425/200,0/300,425/700,0/800\nbusy = 425/300,0/300\nring = 425/1000,0/4000\ncongestion = 425/200,0/200\ncallwaiting = 425/150,0/150,425/150,0/8000\ndialrecall = 425/650,0/25\nrecord = 1400/400,0/15000\ninfo = !950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0\nstutter = 425/650,0/25\n"),
4799  array ( "name" => "Hong Kong", "iso" => "hk", "conf" => "ringcadence = 400,200,400,3000\ndial = 350+440\nbusy = 480+620/500,0/500\nring = 440+480/400,0/200,440+480/400,0/3000\ncongestion = 480+620/250,0/250\ncallwaiting = 440/300,0/10000\ndialrecall = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440\nrecord = 1400/500,0/15000\ninfo = !950/330,!1400/330,!1800/330,0\nstutter = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440\n"),
4800  array ( "name" => "Hungary",  "iso" => "hu", "conf" => "ringcadence = 1250,3750\ndial = 425\nbusy = 425/300,0/300\nring = 425/1250,0/3750\ncongestion = 425/300,0/300\ncallwaiting = 425/40,0/1960\ndialrecall = 425+450\nrecord = 1400/400,0/15000\ninfo = !950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0\nstutter = 350+375+400\n"),
4801  array ( "name" => "India",  "iso" => "in", "conf" => "ringcadence = 400,200,400,2000\ndial = 400*25\nbusy = 400/750,0/750\nring = 400*25/400,0/200,400*25/400,0/2000\ncongestion = 400/250,0/250\ncallwaiting = 400/200,0/100,400/200,0/7500\ndialrecall = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440\nrecord = 1400/500,0/15000\ninfo = !950/330,!1400/330,!1800/330,0/1000\nstutter = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440\n"),
4802  array ( "name" => "Israel",  "iso" => "il", "conf" => "ringcadence = 1000,3000\ndial = 414\nbusy = 414/500,0/500\nring = 414/1000,0/3000\ncongestion = 414/250,0/250\ncallwaiting = 414/100,0/100,414/100,0/100,414/600,0/3000 \ndialrecall = !414/100,!0/100,!414/100,!0/100,!414/100,!0/100,414\nrecord = 1400/500,0/15000\ninfo = 1000/330,1400/330,1800/330,0/1000\nstutter = !414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,414 \n"),
4803  array ( "name" => "Italy",  "iso" => "it", "conf" => "ringcadence = 1000,4000\ndial = 425/200,0/200,425/600,0/1000\nbusy = 425/500,0/500\nring = 425/1000,0/4000\ncongestion = 425/200,0/200\ncallwaiting = 425/400,0/100,425/250,0/100,425/150,0/14000\ndialrecall = 470/400,425/400\nrecord = 1400/400,0/15000\ninfo = !950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0\nstutter = 470/400,425/400\n"),
4804  array ( "name" => "Japan",  "iso" => "jp", "conf" => "ringcadence = 1000,2000\ndial = 400\nbusy = 400/500,0/500\nring = 400+15/1000,0/2000\ncongestion = 400/500,0/500\ncallwaiting = 400+16/500,0/8000\ndialrecall = !400/200,!0/200,!400/200,!0/200,!400/200,!0/200,400\nrecord = 1400/500,0/15000\ninfo = !950/330,!1400/330,!1800/330,0\nstutter = !400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,400\n"),
4805  array ( "name" => "Lithuania",  "iso" => "lt", "conf" => "ringcadence = 1000,4000\ndial = 425\nbusy = 425/350,0/350\nring = 425/1000,0/4000\ncongestion = 425/200,0/200\ncallwaiting = 425/150,0/150,425/150,0/4000\ndialrecall = 425/500,0/50\nrecord = 1400/500,0/15000\ninfo = !950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0\nstutter = !425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425\n"),
4806  array ( "name" => "Mexico",  "iso" => "mx", "conf" => "ringcadence = 2000,4000\ndial = 425\nbusy = 425/250,0/250\nring = 425/1000,0/4000\ncongestion = 425/250,0/250\ncallwaiting = 425/200,0/600,425/200,0/10000\ndialrecall = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440\nrecord = 1400/500,0/15000\ninfo = 950/330,0/30,1400/330,0/30,1800/330,0/1000\nstutter = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440\n"),
4807  array ( "name" => "Netherlands",  "iso" => "nl", "conf" => "ringcadence = 1000,4000\ndial = 425\nbusy = 425/500,0/500\nring = 425/1000,0/4000\ncongestion = 425/250,0/250\ncallwaiting = 425/500,0/9500\ndialrecall = 425/500,0/50\nrecord = 1400/500,0/15000\ninfo = 950/330,1400/330,1800/330,0/1000\nstutter = 425/500,0/50\n"),
4808  array ( "name" => "Norway",  "iso" => "no", "conf" => "ringcadence = 1000,4000\ndial = 425\nbusy = 425/500,0/500\nring = 425/1000,0/4000\ncongestion = 425/200,0/200\ncallwaiting = 425/200,0/600,425/200,0/10000\ndialrecall = 470/400,425/400\nrecord = 1400/400,0/15000\ninfo = !950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0\nstutter = 470/400,425/400\n"),
4809  array ( "name" => "New Zealand",  "iso" => "nz", "conf" => "ringcadence = 400,200,400,2000\ndial = 400\nbusy = 400/250,0/250\nring = 400+450/400,0/200,400+450/400,0/2000\ncongestion = 400/375,0/375\ncallwaiting = !400/200,!0/3000,!400/200,!0/3000,!400/200,!0/3000,!400/200\ndialrecall = !400/100!0/100,!400/100,!0/100,!400/100,!0/100,400\nrecord = 1400/425,0/15000\ninfo = 400/750,0/100,400/750,0/100,400/750,0/100,400/750,0/400\nstutter = !400/100!0/100,!400/100,!0/100,!400/100,!0/100,!400/100!0/100,!400/100,!0/100,!400/100,!0/100,400\n"),
4810  array ( "name" => "Philippines",  "iso" => "phl", "conf" => "ringcadence = 1000,4000\ndial = 425\nbusy = 480+620/500,0/500\nring = 425+480/1000,0/4000\ncongestion = 480+620/250,0/250\ncallwaiting = 440/300,0/10000\ndialrecall = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440\nrecord = 1400/500,0/15000\ninfo = !950/330,!1400/330,!1800/330,0\nstutter = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440\n"),
4811  array ( "name" => "Poland",  "iso" => "pl", "conf" => "ringcadence = 1000,4000\ndial = 425\nbusy = 425/500,0/500\nring = 425/1000,0/4000\ncongestion = 425/500,0/500\ncallwaiting = 425/150,0/150,425/150,0/4000\ndialrecall = 425/500,0/50\nrecord = 1400/500,0/15000\ninfo = !950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000\nstutter = !425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425\n"),
4812  array ( "name" => "Portugal",  "iso" => "pt", "conf" => "ringcadence = 1000,5000\ndial = 425\nbusy = 425/500,0/500\nring = 425/1000,0/5000\ncongestion = 425/200,0/200\ncallwaiting = 440/300,0/10000\ndialrecall = 425/1000,0/200\nrecord = 1400/500,0/15000\ninfo = 950/330,1400/330,1800/330,0/1000\nstutter = !425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425\n"),
4813  array ( "name" => "Russia / ex Soviet Union",  "iso" => "ru", "conf" => "ringcadence = 800,3200\ndial = 425\nbusy = 425/350,0/350\nring = 425/800,0/3200\ncongestion = 425/350,0/350\ncallwaiting = 425/200,0/5000\ndialrecall = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440\nrecord = 1400/500,0/15000\ninfo = !950/330,!1400/330,!1800/330,0\n"),
4814  array ( "name" => "Singapore",  "iso" => "sg", "conf" => "ringcadence = 400,200,400,2000\ndial = 425\nring = 425*24/400,0/200,425*24/400,0/2000 ; modulation should be 100%, not 90%\nbusy = 425/750,0/750\ncongestion = 425/250,0/250\ncallwaiting = 425*24/300,0/200,425*24/300,0/3200\nstutter = !425/200,!0/200,!425/600,!0/200,!425/200,!0/200,!425/600,!0/200,!425/200,!0/200,!425/600,!0/200,!425/200,!0/200,!425/600,!0/200,425\ninfo = 950/330,1400/330,1800/330,0/1000 ; not currently in use acc. to reference\ndialrecall = 425*24/500,0/500,425/500,0/2500 ; unspecified in IDA reference, use repeating Holding Tone A,B\nrecord = 1400/500,0/15000 ; unspecified in IDA reference, use 0.5s tone every 15s\nnutone = 425/2500,0/500\nintrusion = 425/250,0/2000\nwarning = 425/624,0/4376 ; end of period tone, warning\nacceptance = 425/125,0/125\nholdinga = !425*24/500,!0/500 ; followed by holdingb\nholdingb = !425/500,!0/2500\n"),
4815  array ( "name" => "South Africa",  "iso" => "za", "conf" => "ringcadence = 400,200,400,2000\ndial = 400*33\nbusy = 400/500,0/500\nring = 400*33/400,0/200,400*33/400,0/2000\ncongestion = 400/250,0/250\ncallwaiting = 400*33/250,0/250,400*33/250,0/250,400*33/250,0/250,400*33/250,0/250\ndialrecall = 350+440\nrecord = 1400/500,0/10000\ninfo = 950/330,1400/330,1800/330,0/330\nstutter =!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,400*33 \n"),
4816  array ( "name" => "Spain",  "iso" => "es", "conf" => "ringcadence = 1500,3000\ndial = 425\nbusy = 425/200,0/200\nring = 425/1500,0/3000\ncongestion = 425/200,0/200,425/200,0/200,425/200,0/600\ncallwaiting = 425/175,0/175,425/175,0/3500\ndialrecall = !425/200,!0/200,!425/200,!0/200,!425/200,!0/200,425\nrecord = 1400/500,0/15000\ninfo = 950/330,0/1000\ndialout = 500\n\n"),
4817  array ( "name" => "Sweden",  "iso" => "se", "conf" => "ringcadence = 1000,5000\ndial = 425\nbusy = 425/250,0/250\nring = 425/1000,0/5000\ncongestion = 425/250,0/750\ncallwaiting = 425/200,0/500,425/200,0/9100\ndialrecall = !425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425\nrecord = 1400/500,0/15000\ninfo = !950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,!950/332,!0/24,!1400/332,!0/24,!1800/332,0\nstutter = !425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425\n"),
4818  array ( "name" => "Turkey", "iso" => "tr", "conf" => "ringcadance = 2000,4000\ndial = 450\nbusy = 450/500,0/500\nring = 450/2000,450/4000\ncongestion = 450/200,0/200,450/200,0/200,450/200,0/200,450/600,0/200\ncallwaiting = 450/200,0/600,450/200,0/8000\ndialrecall = 450/1000,0/250\nrecord = 1400/500,0/15000\ninfo = !950/300,!1400/300,!1800/300,!0/1000,!950/300,!1400/300,!1800/300,!0/1000,!950/300,!1400/300,!1800/300,!0/1000,0\n"),
4819  array ( "name" => "United Kingdom",  "iso" => "uk", "conf" => "ringcadence = 400,200,400,2000\ndial = 350+440\nspecialdial = 350+440/750,440/750\nbusy = 400/375,0/375\ncongestion = 400/400,0/350,400/225,0/525\nspecialcongestion = 400/200,1004/300\nunobtainable = 400\nring = 400+450/400,0/200,400+450/400,0/2000\ncallwaiting = 400/100,0/4000\nspecialcallwaiting = 400/250,0/250,400/250,0/250,400/250,0/5000\ncreditexpired = 400/125,0/125\nconfirm = 1400\nswitching = 400/200,0/400,400/2000,0/400\ninfo = 950/330,0/15,1400/330,0/15,1800/330,0/1000\nrecord = 1400/500,0/60000\nstutter = 350+440/750,440/750\n"),
4820  array ( "name" => "United States / North America",  "iso" => "us", "conf" => "ringcadence = 2000,4000\ndial = 350+440\nbusy = 480+620/500,0/500\nring = 440+480/2000,0/4000\ncongestion = 480+620/250,0/250\ncallwaiting = 440/300,0/10000\ndialrecall = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440\nrecord = 1400/500,0/15000\ninfo = !950/330,!1400/330,!1800/330,0\nstutter = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440\n"),
4821  array ( "name" => "United States Circa 1950/ North America",  "iso" => "us-old", "conf" => "ringcadence = 2000,4000\ndial = 600*120\nbusy = 500*100/500,0/500\nring = 420*40/2000,0/4000\ncongestion = 500*100/250,0/250\ncallwaiting = 440/300,0/10000\ndialrecall = !600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,600*120\nrecord = 1400/500,0/15000\ninfo = !950/330,!1400/330,!1800/330,0\nstutter = !600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,600*120\n"),
4822  array ( "name" => "Taiwan",  "iso" => "tw", "conf" => "ringcadence = 1000,4000\ndial = 350+440\nbusy = 480+620/500,0/500\nring = 440+480/1000,0/2000\ncongestion = 480+620/250,0/250\ncallwaiting = 350+440/250,0/250,350+440/250,0/3250\ndialrecall = 300/1500,0/500\nrecord = 1400/500,0/15000\ninfo = !950/330,!1400/330,!1800/330,0\nstutter = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440\n"),
4823  array ( "name" => "Venezuela / South America",  "iso" => "ve", "conf" => "; Tone definition source for ve found on\n; Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf\nringcadence = 1000,4000\ndial = 425\nbusy = 425/500,0/500\nring = 425/1000,0/4000\ncongestion = 425/250,0/250\ncallwaiting = 400+450/300,0/6000\ndialrecall = 425\nrecord =  1400/500,0/15000\ninfo = !950/330,!1440/330,!1800/330,0/1000\n"),);
4824 }
4825
4826 function general_display_zones($curzone) {
4827   $zonelist = general_get_zonelist();
4828   echo "<select name='TONEZONE'>\n";
4829   foreach ($zonelist as $zone) {
4830     if ($zone['iso'] == $curzone)
4831       echo "<option selected value='{$zone['iso']}'>{$zone['name']}</option>\n";
4832     else 
4833       echo "<option value='{$zone['iso']}'>{$zone['name']}</option>\n";
4834   }
4835   echo "</select>";
4836  
4837 }
4838
4839 function general_generate_indications() {
4840   global $db;
4841   global $asterisk_conf;
4842
4843   $notify =& notifications::create($db);
4844
4845   $sql = "SELECT value FROM globals WHERE variable='TONEZONE'";
4846   $result = $db->getRow($sql,DB_FETCHMODE_ASSOC);
4847
4848   $filename = isset($asterisk_conf["astetcdir"]) && $asterisk_conf["astetcdir"] != '' ? rtrim($asterisk_conf["astetcdir"],DIRECTORY_SEPARATOR) : "/etc/asterisk";
4849   $filename .= "/indications.conf";
4850
4851   if (($fd = fopen($filename, "w")) === false) {
4852     $desc = sprintf(_("Failed to open %s for writing, aborting attempt to write the country indications. The file may be readonly or the permissions may be incorrect."), $filename);
4853     $notify->add_error('core','INDICATIONS',_("Failed to write indications.conf"), $desc);
4854     return;
4855   }
4856   $notify->delete('core', 'INDICATIONS');
4857   $country=$result['value'];
4858         $indication_warning = ";--------------------------------------------------------------------------------;
4859 ; Do NOT edit this file as it is auto-generated by FreePBX. All modifications to ;
4860 ; this file must be done via the web gui.                                        ;
4861 ;--------------------------------------------------------------------------------;\n\n";
4862
4863         fwrite($fd, $indication_warning);
4864   fwrite($fd, "[general]\ncountry=".$country."\n\n[".$country."]\n");
4865
4866   $zonelist = general_get_zonelist();
4867     foreach ($zonelist as $key => $value) {
4868       if ($value['iso'] == $country) {
4869        
4870         fwrite($fd, "description = {$value['name']}\n");
4871         fwrite($fd, "{$value['conf']}\n\n");
4872       }
4873   }
4874   fclose($fd);
4875 }
4876 /* end page.routing.php functions */
4877
4878
4879
4880 // init registered 'your' config load and config process functions
4881 function core_users_configpageinit($dispnum) {
4882   global $currentcomponent;
4883   global $amp_conf;
4884
4885   if ( $dispnum == 'users' || $dispnum == 'extensions' ) {
4886     // Setup option list we need
4887     $currentcomponent->addoptlistitem('recordoptions', 'Adhoc', _("On Demand"));
4888     $currentcomponent->addoptlistitem('recordoptions', 'Always', _("Always"));
4889     $currentcomponent->addoptlistitem('recordoptions', 'Never', _("Never"));
4890     $currentcomponent->setoptlistopts('recordoptions', 'sort', false);
4891
4892     $currentcomponent->addoptlistitem('callwaiting', 'enabled', _("Enable"));
4893     $currentcomponent->addoptlistitem('callwaiting', 'disabled', _("Disable"));
4894     $currentcomponent->setoptlistopts('callwaiting', 'sort', false);
4895
4896     $currentcomponent->addoptlistitem('pinless', 'disabled', _("Disable"));
4897     $currentcomponent->addoptlistitem('pinless', 'enabled', _("Enable"));
4898     $currentcomponent->setoptlistopts('pinless', 'sort', false);
4899
4900     $currentcomponent->addoptlistitem('call_screen', '0', _("Disable"));
4901     $currentcomponent->addoptlistitem('call_screen', 'nomemory', _("Screen Caller: No Memory"));
4902     $currentcomponent->addoptlistitem('call_screen', 'memory', _("Screen Caller: Memory"));
4903     $currentcomponent->setoptlistopts('call_screen', 'sort', false);
4904
4905     $currentcomponent->addoptlistitem('ringtime', '0', _("Default"));
4906     for ($i=1; $i <= 120; $i++) {
4907       $currentcomponent->addoptlistitem('ringtime', "$i", "$i");
4908     }
4909     $currentcomponent->setoptlistopts('ringtime', 'sort', false);
4910
4911     // Special CID handling to deal with Private, etc.
4912     //
4913     $js =
4914     'var mycid = thiscid.toLowerCase();
4915     if (isDialpattern(thiscid) || mycid.substring(0,4) == "priv" || mycid.substring(0,5) == "block" || mycid == "unknown" || mycid.substring(0,8) == "restrict" || mycid.substring(0,7) == "unavail" || mycid.substring(0,6) == "anonym") { return true } else { return false };
4916     ';
4917     $currentcomponent->addjsfunc('isValidCID(thiscid)', $js);
4918
4919     // Add the 'proces' functions
4920     $currentcomponent->addguifunc('core_users_configpageload');
4921     // Ensure users is called in middle order ($sortorder = 5), this is to allow
4922     // other modules to call stuff before / after the processing of users if needed
4923     // e.g. Voicemail module needs to create mailbox BEFORE the users as the mailbox
4924     // context is needed by the add users function
4925     $currentcomponent->addprocessfunc('core_users_configprocess', 5);     
4926   }
4927 }
4928
4929 // Used below in usort
4930 function dev_grp($a, $b) {
4931   if ($a['devicetype'] == $b['devicetype']) {
4932     return ($a['id'] < $b['id']) ? -1 : 1;
4933   } else {
4934     return ($a['devicetype'] > $b['devicetype']) ? -1 : 1;
4935   }
4936 }
4937
4938 function core_users_configpageload() {
4939   global $currentcomponent;
4940   global $amp_conf;
4941
4942   // Ensure variables possibly extracted later exist
4943   $name = $outboundcid = $record_in = $record_out =  $sipname = $cid_masquerade = $newdid_name = $newdid = $newdidcid = null;
4944
4945   // Init vars from $_REQUEST[]
4946   $display = isset($_REQUEST['display'])?$_REQUEST['display']:null;;
4947   $action = isset($_REQUEST['action'])?$_REQUEST['action']:null;
4948   $extdisplay = isset($_REQUEST['extdisplay'])?$_REQUEST['extdisplay']:null;
4949   $tech_hardware = isset($_REQUEST['tech_hardware'])?$_REQUEST['tech_hardware']:null;
4950
4951   if ( $action == 'del' ) { // Deleted
4952
4953     $currentcomponent->addguielem('_top', new gui_subheading('del', $extdisplay.' '._("deleted"), false));
4954
4955   } elseif ( $display == 'extensions' && ($extdisplay == '' && $tech_hardware == '') ) { // Adding
4956
4957     // do nothing as you want the Devices to handle this bit
4958
4959   } else {
4960
4961     $delURL = $_SERVER['PHP_SELF'].'?'.$_SERVER['QUERY_STRING'].'&action=del';
4962  
4963     if ( is_string($extdisplay) ) {
4964
4965       if (!isset($GLOBALS['abort']) || $GLOBALS['abort'] !== true) {
4966         $extenInfo=core_users_get($extdisplay);
4967         extract($extenInfo);
4968       }
4969       if (isset($deviceInfo) && is_array($deviceInfo))
4970         extract($deviceInfo);
4971  
4972       if ( $display == 'extensions' ) {
4973         $currentcomponent->addguielem('_top', new gui_pageheading('title', _("Extension").": $extdisplay", false), 0);
4974         if (!isset($GLOBALS['abort']) || $GLOBALS['abort'] !== true) {
4975           $tlabel = sprintf(_("Delete Extension %s"),$extdisplay);
4976           $label = '<span><img width="16" height="16" border="0" title="'.$tlabel.'" alt="" src="images/user_delete.png"/>&nbsp;'.$tlabel.'</span>';
4977           $currentcomponent->addguielem('_top', new gui_link('del', $label, $delURL, true, false), 0);
4978
4979           $usage_list = framework_display_destination_usage(core_getdest($extdisplay));
4980           if (!empty($usage_list)) {
4981             $currentcomponent->addguielem('_top', new gui_link_label('dests', $usage_list['text'], $usage_list['tooltip'], true), 0);
4982           }
4983         }
4984       } else {
4985         $currentcomponent->addguielem('_top', new gui_pageheading('title', _("User").": $extdisplay", false), 0);
4986         if (!isset($GLOBALS['abort']) || $GLOBALS['abort'] !== true) {
4987           $tlabel = sprintf(_("Delete User %s"),$extdisplay);
4988           $label = '<span><img width="16" height="16" border="0" title="'.$tlabel.'" alt="" src="images/user_delete.png"/>&nbsp;'.$tlabel.'</span>';
4989           $currentcomponent->addguielem('_top', new gui_link('del', $label, $delURL, true, false), 0);
4990
4991           $usage_list = framework_display_destination_usage(core_getdest($extdisplay));
4992           if (!empty($usage_list)) {
4993             $currentcomponent->addguielem('_top', new gui_link_label('dests', $usage_list['text'], $usage_list['tooltip'], true), 0);
4994           }
4995         }
4996       }
4997
4998     } elseif ( $display != 'extensions' ) {
4999       $currentcomponent->addguielem('_top', new gui_pageheading('title', _("Add User/Extension")), 0);
5000     }
5001    
5002     // Setup vars for use in the gui later on             
5003     $fc_logon = featurecodes_getFeatureCode('core', 'userlogon');
5004     $fc_logoff = featurecodes_getFeatureCode('core', 'userlogoff');
5005    
5006     $msgInvalidExtNum = _("Please enter a valid extension number.");
5007     $msgInvalidCidNum = _("Please enter a valid CID Num Alias (must be a valid number).");
5008     $msgInvalidExtPwd = _("Please enter valid User Password using numbers only");
5009     $msgInvalidDispName = _("Please enter a valid Display Name");
5010     $msgInvalidOutboundCID = _("Please enter a valid Outbound CID");
5011     $msgInvalidPause = _("Please enter a valid pause time in seconds, using digits only");
5012     $msgInvalidDIDNum = _("You have entered a non-standard dialpattern for your DID. You can only enter standard dialpatterns. You must use the inbound routing form to enter non-standard patterns");
5013     $msgInvalidCIDNum = _("Please enter a valid Caller ID Number or leave it blank for your Assigned DID/CID pair");
5014
5015     // This is the actual gui stuff
5016     $currentcomponent->addguielem('_top', new gui_hidden('action', ($extdisplay ? 'edit' : 'add')));
5017     $currentcomponent->addguielem('_top', new gui_hidden('extdisplay', $extdisplay));
5018    
5019     if ( $display == 'extensions' ) {
5020       $section = ($extdisplay ? _("Edit Extension") : _("Add Extension"));     
5021     } else {
5022       $section = ($extdisplay ? _("Edit User") : _("Add User"));
5023     }
5024     if ( trim($extdisplay) != '' ) {
5025       $currentcomponent->addguielem($section, new gui_hidden('extension', $extdisplay), 2);
5026     } else {
5027       $currentcomponent->addguielem($section, new gui_textbox('extension', $extdisplay, _("User Extension"), _("The extension number to dial to reach this user."), '!isInteger()', $msgInvalidExtNum, false), 3);
5028     }
5029     if ( $display != 'extensions' ) {
5030       $currentcomponent->addguielem($section, new gui_password('password', $password, _("User Password"), _("A user will enter this password when logging onto a device.").' '.$fc_logon.' '._("logs into a device.").' '.$fc_logoff.' '._("logs out of a device."), '!isInteger() && !isWhitespace()', $msgInvalidExtPwd, true));
5031       // extra JS function check required for blank password warning -- call last in the onsubmit() function
5032       $currentcomponent->addjsfunc('onsubmit()', "\treturn checkBlankUserPwd();\n", 9);
5033     }
5034     $currentcomponent->addguielem($section, new gui_textbox('name', $name, _("Display Name"), _("The caller id name for calls from this user will be set to this name. Only enter the name, NOT the number."),  '!isAlphanumeric() || isWhitespace()', $msgInvalidDispName, false));
5035     $cid_masquerade = (trim($cid_masquerade) == $extdisplay)?"":$cid_masquerade;
5036     $currentcomponent->addguielem($section, new gui_textbox('cid_masquerade', $cid_masquerade, _("CID Num Alias"), _("The CID Number to use for internal calls, if different from the extension number. This is used to masquerade as a different user. A common example is a team of support people who would like their internal callerid to display the general support number (a ringgroup or queue). There will be no effect on external calls."), '!isWhitespace() && !isInteger()', $msgInvalidCidNum, false));
5037     $currentcomponent->addguielem($section, new gui_textbox('sipname', $sipname, _("SIP Alias"), _("If you want to support direct sip dialing of users internally or through anonymous sip calls, you can supply a friendly name that can be used in addition to the users extension to call them.")));
5038
5039     // If user mode, list devices associated with this user
5040     //
5041     if ($display == 'users' && trim($extdisplay != '')) {
5042       $section = _("User Devices");
5043       $device_list = core_devices_list('all','full');
5044
5045       usort($device_list,'dev_grp');
5046
5047       $link_count = 0;
5048       foreach ($device_list as $device_item) {
5049         if ($device_item['user'] == $extdisplay) {
5050           $editURL = $_SERVER['PHP_SELF'].'?type=setup&display=devices&skip=0&extdisplay='.$device_item['id'];
5051           $device_icon = ($device_item['devicetype'] == 'fixed') ? 'images/telephone_key.png' : 'images/telephone_edit.png';
5052           $device_label  = '&nbsp;';
5053           $device_label .=  _("Edit:");
5054           $device_label .= '&nbsp;'.$device_item['id'].'&nbsp;'.$device_item['description'];
5055
5056           $device_label = '<span>
5057             <img width="16" height="16" border="0" title="Edit Device" alt="Edit Device" src="'.$device_icon.'"/>'.$device_label.
5058             '</span> ';
5059          
5060           $currentcomponent->addguielem($section, new gui_link('dev'.$link_count++, $device_label, $editURL, true, false), 2);
5061         }
5062       }
5063     }
5064    
5065     $section = _("Extension Options");
5066     $currentcomponent->addguielem($section, new gui_textbox('outboundcid', $outboundcid, _("Outbound CID"), _("Overrides the caller id when dialing out a trunk. Any setting here will override the common outbound caller id set in the Trunks admin.<br><br>Format: <b>\"caller name\" &lt;#######&gt;</b><br><br>Leave this field blank to disable the outbound callerid feature for this user."), '!isCallerID()', $msgInvalidOutboundCID, true),3);
5067     $ringtimer = (isset($ringtimer) ? $ringtimer : '0');
5068     $currentcomponent->addguielem($section, new gui_selectbox('ringtimer', $currentcomponent->getoptlist('ringtime'), $ringtimer, _("Ring Time"), _("Number of seconds to ring prior to going to voicemail. Default will use the value set in the General Tab. If no voicemail is configured this will be ignored."), false));
5069     if (!isset($callwaiting)) {
5070       if ($amp_conf['ENABLECW']) {
5071         $callwaiting = 'enabled';
5072       } else {
5073         $callwaiting = 'disabled';
5074       }
5075     }
5076     $currentcomponent->addguielem($section, new gui_selectbox('callwaiting', $currentcomponent->getoptlist('callwaiting'), $callwaiting, _("Call Waiting"), _("Set the initial/current Call Waiting state for this user's extension"), false));
5077     $currentcomponent->addguielem($section, new gui_selectbox('call_screen', $currentcomponent->getoptlist('call_screen'), $call_screen, _("Call Screening"),_("Call Screening requires external callers to say their name, which will be played back to the user and allow the user to accept or reject the call.  Screening with memory only verifies a caller for their caller-id once. Screening without memory always requires a caller to say their name. Either mode will always announce the caller based on the last introduction saved with that callerid. If any user on the system uses the memory option, when that user is called, the caller will be required to re-introduce themselves and all users on the system will have that new introduction associated with the caller's CallerId."), false));
5078     $currentcomponent->addguielem($section, new gui_selectbox('pinless', $currentcomponent->getoptlist('pinless'), $pinless, _("Pinless Dialing"), _("Enabling Pinless Dialing will allow this extension to bypass any pin codes normally required on outbound calls"), false));
5079
5080     $section = _("Assigned DID/CID");
5081     $currentcomponent->addguielem($section, new gui_textbox('newdid_name', $newdid_name, _("DID Description"), _("A description for this DID, such as \"Fax\"")), 4);
5082     $currentcomponent->addguielem($section, new gui_textbox('newdid', $newdid, _("Add Inbound DID"), _("A direct DID that is associated with this extension. The DID should be in the same format as provided by the provider (e.g. full number, 4 digits for 10x4, etc).<br><br>Format should be: <b>XXXXXXXXXX</b><br><br>.An optional CID can also be associated with this DID by setting the next box"),'!isDialpattern()',$msgInvalidDIDNum,true), 4);
5083     $currentcomponent->addguielem($section, new gui_textbox('newdidcid', $newdidcid, _("Add Inbound CID"), _("Add a CID for more specific DID + CID routing. A DID must be specified in the above Add DID box. In addition to standard dial sequences, you can also put Private, Blocked, Unknown, Restricted, Anonymous and Unavailable in order to catch these special cases if the Telco transmits them."),"!frm_${display}_isValidCID()",$msgInvalidCIDNum,true), 4);
5084
5085     $dids = core_did_list('extension');
5086     $did_count = 0;
5087     foreach ($dids as $did) {
5088       $did_dest = split(',',$did['destination']);
5089       if (isset($did_dest[1]) && $did_dest[1] == $extdisplay) {
5090
5091         $did_title = ($did['description'] != '') ? $did['description'] : _("DID / CID");
5092
5093         $addURL = $_SERVER['PHP_SELF'].'?type=setup&display=did&&extdisplay='.$did['extension'].'/'.$did['cidnum'];
5094         $did_icon = 'images/email_edit.png';
5095         $did_label = trim($did['extension']) == '' ? ' '._("Any DID") : ' '.$did['extension'];
5096         if (trim($did['cidnum']) != '') {
5097           $did_label .= ' / '.$did['cidnum'];
5098         }
5099         if (trim($did['description']) != '') {
5100           $did_label .= ' ('.$did['description'].')';
5101         }
5102
5103         $did_label = '&nbsp;<span>
5104           <img width="16" height="16" border="0" title="'.$did_title.'" alt="" src="'.$did_icon.'"/>'.$did_label.
5105           '</span> ';
5106
5107         $currentcomponent->addguielem($section, new gui_link('did_'.$did_count++, $did_label, $addURL, true, false), 4);
5108       }
5109     }
5110
5111     $section = _("Recording Options");
5112     $currentcomponent->addguielem($section, new gui_selectbox('record_in', $currentcomponent->getoptlist('recordoptions'), $record_in, _("Record Incoming"), _("Record all inbound calls received at this extension."), false));
5113     $currentcomponent->addguielem($section, new gui_selectbox('record_out', $currentcomponent->getoptlist('recordoptions'), $record_out, _("Record Outgoing"), _("Record all outbound calls received at this extension."), false));
5114   }
5115 }
5116
5117 function core_users_configprocess() {
5118   if ( !class_exists('agi_asteriskmanager') )
5119     include 'common/php-asmanager.php';
5120  
5121   //create vars from the request
5122   extract($_REQUEST);
5123  
5124   //make sure we can connect to Asterisk Manager
5125   if (!checkAstMan()) {
5126     return false;
5127   }
5128
5129   //check if the extension is within range for this user
5130   if (isset($extension) && !checkRange($extension)){
5131     echo "<script>javascript:alert('". _("Warning! Extension")." ".$extension." "._("is not allowed for your account").".');</script>";
5132     $GLOBALS['abort'] = true;
5133   } else {
5134     //if submitting form, update database
5135     if (!isset($action)) $action = null;
5136     switch ($action) {
5137       case "add":
5138         $conflict_url = array();
5139         $usage_arr = framework_check_extension_usage($_REQUEST['extension']);
5140         if (!empty($usage_arr)) {
5141           $GLOBALS['abort'] = true;
5142           $conflict_url = framework_display_extension_usage_alert($usage_arr,true);
5143           global $currentcomponent;
5144           $id=0;
5145           $currentcomponent->addguielem('_top', new gui_link_label('conflict', _("Conflicting Extensions"), _("The following extension numbers are in conflict, you can click on the item(s) below to edit the conflicting entity."), true));
5146           foreach ($conflict_url as $edit_link) {
5147             $currentcomponent->addguielem('_top', new gui_link('conflict'.$i++, $edit_link['label'], $edit_link['url']));
5148           }
5149           $msg = ($_REQUEST['display'] == 'users') ? _("Configure user again:") : _("Configure extension again:");
5150           $currentcomponent->addguielem('_top', new gui_subheading('conflict_end', $msg, false));
5151           unset($_REQUEST['action']);
5152           redirect_standard_continue();
5153         } elseif (core_users_add($_REQUEST)) {
5154           needreload();
5155           redirect_standard_continue();
5156         } else {
5157           // really bad hack - but if core_users_add fails, want to stop core_devices_add
5158           // Comment, this does not help everywhere. Other hooks functions can hook before
5159           // this like voicemail!
5160           //
5161           $GLOBALS['abort'] = true;
5162         }
5163       break;
5164       case "del":
5165         core_users_del($extdisplay);
5166         core_users_cleanastdb($extdisplay);
5167         if (function_exists('findmefollow_del')) {
5168             findmefollow_del($extdisplay);
5169         }
5170         needreload();
5171         redirect_standard_continue();
5172       break;
5173       case "edit":
5174         if (core_users_edit($extdisplay,$_REQUEST)) {
5175           needreload();
5176           redirect_standard_continue('extdisplay');
5177         } else {
5178           // really bad hack - but if core_users_edit fails, want to stop core_devices_edit
5179           $GLOBALS['abort'] = true;
5180         }
5181       break;
5182     }
5183   }
5184   return true;
5185 }
5186
5187
5188 function core_devices_configpageinit($dispnum) {
5189   global $currentcomponent;
5190
5191   if ( $dispnum == 'devices' || $dispnum == 'extensions' ) {
5192     // Setup arrays for device types
5193     $currentcomponent->addgeneralarray('devtechs');
5194    
5195     // Some errors for the validation bits
5196     $msgInvalidDTMFMODE = _("Please enter the dtmfmode for this device");
5197     $msgInvalidChannel = _("Please enter the channel for this device");
5198     $msgConfirmSecret = _("You have not entered a Secret for this device, although this is possible it is generally bad practice to not assign a Secret to a device. Are you sure you want to leave the Secret empty?");
5199     $msgInvalidSecret = _("Please enter a Secret for this device");
5200    
5201     // zap
5202     $tmparr = array();
5203     $tmparr['channel'] = array('value' => '', 'level' => 0, 'jsvalidation' => 'isEmpty()', 'failvalidationmsg' => $msgInvalidChannel);
5204     $tmparr['context'] = array('value' => 'from-internal', 'level' => 1);
5205     $tmparr['immediate'] = array('value' => 'no', 'level' => 1);
5206     $tmparr['signalling'] = array('value' => 'fxo_ks', 'level' => 1);
5207     $tmparr['echocancel'] = array('value' => 'yes', 'level' => 1);
5208     $tmparr['echocancelwhenbridged'] = array('value' => 'no', 'level' => 1);
5209     $tmparr['echotraining'] = array('value' => '800', 'level' => 1);
5210     $tmparr['busydetect'] = array('value' => 'no', 'level' => 1);
5211     $tmparr['busycount'] = array('value' => '7', 'level' => 1);
5212     $tmparr['callprogress'] = array('value' => 'no', 'level' => 1);
5213     $tmparr['dial'] = array('value' => '', 'level' => 1);
5214     $tmparr['accountcode'] = array('value' => '', 'level' => 1);
5215     $tmparr['callgroup'] = array('value' => '', 'level' => 1);
5216     $tmparr['pickupgroup'] = array('value' => '', 'level' => 1);
5217     $tmparr['mailbox'] = array('value' => '', 'level' => 1);
5218     $currentcomponent->addgeneralarrayitem('devtechs', 'zap', $tmparr);
5219     unset($tmparr);
5220    
5221     // iax2
5222     $tmparr = array();
5223     $tmparr['secret'] = array('value' => '', 'level' => 0, 'jsvalidation' => 'isEmpty() && !confirm("'.$msgConfirmSecret.'")', 'failvalidationmsg' => $msgInvalidSecret);
5224     $tmparr['secret'] = array('value' => '', 'level' => 0, 'jsvalidation' => '(isEmpty() && !confirm("'.$msgConfirmSecret.'")) || (!isEmpty() && weakSecret())', 'failvalidationmsg' => $msgInvalidSecret);
5225     $tmparr['notransfer'] = array('value' => 'yes', 'level' => 1);
5226     $tmparr['context'] = array('value' => 'from-internal', 'level' => 1);
5227     $tmparr['host'] = array('value' => 'dynamic', 'level' => 1);
5228     $tmparr['type'] = array('value' => 'friend', 'level' => 1);
5229     $tmparr['port'] = array('value' => '4569', 'level' => 1);
5230     $tmparr['qualify'] = array('value' => 'yes', 'level' => 1);
5231     $tmparr['disallow'] = array('value' => '', 'level' => 1);
5232     $tmparr['allow'] = array('value' => '', 'level' => 1);
5233     $tmparr['dial'] = array('value' => '', 'level' => 1);
5234     $tmparr['accountcode'] = array('value' => '', 'level' => 1);
5235     $tmparr['mailbox'] = array('value' => '', 'level' => 1);
5236     $tmparr['deny'] = array('value' => '0.0.0.0/0.0.0.0', 'level' => 1);
5237     $tmparr['permit'] = array('value' => '0.0.0.0/0.0.0.0', 'level' => 1);
5238     $currentcomponent->addgeneralarrayitem('devtechs', 'iax2', $tmparr);
5239     unset($tmparr);
5240
5241     // sip
5242     $tmparr = array();
5243     $tmparr['secret'] = array('value' => '', 'level' => 0, 'jsvalidation' => '(isEmpty() && !confirm("'.$msgConfirmSecret.'")) || (!isEmpty() && weakSecret())', 'failvalidationmsg' => $msgInvalidSecret);
5244     $tmparr['dtmfmode'] = array('value' => 'rfc2833', 'level' => 0, 'jsvalidation' => 'isEmpty()', 'failvalidationmsg' => $msgInvalidDTMFMODE );
5245     $tmparr['canreinvite'] = array('value' => 'no', 'level' => 1);
5246     $tmparr['context'] = array('value' => 'from-internal', 'level' => 1);
5247     $tmparr['host'] = array('value' => 'dynamic', 'level' => 1);
5248     $tmparr['type'] = array('value' => 'friend', 'level' => 1);
5249     $tmparr['nat'] = array('value' => 'yes', 'level' => 1);
5250     $tmparr['port'] = array('value' => '5060', 'level' => 1);
5251     $tmparr['qualify'] = array('value' => 'yes', 'level' => 1);
5252     $tmparr['callgroup'] = array('value' => '', 'level' => 1);
5253     $tmparr['pickupgroup'] = array('value' => '', 'level' => 1);
5254     $tmparr['disallow'] = array('value' => '', 'level' => 1);
5255     $tmparr['allow'] = array('value' => '', 'level' => 1);
5256     $tmparr['dial'] = array('value' => '', 'level' => 1);
5257     $tmparr['accountcode'] = array('value' => '', 'level' => 1);
5258     $tmparr['mailbox'] = array('value' => '', 'level' => 1);
5259     $tmparr['deny'] = array('value' => '0.0.0.0/0.0.0.0', 'level' => 1);
5260         $tmparr['permit'] = array('value' => '0.0.0.0/0.0.0.0', 'level' => 1);
5261     $currentcomponent->addgeneralarrayitem('devtechs', 'sip', $tmparr);
5262     unset($tmparr);
5263
5264     // custom
5265     $tmparr = array();
5266     $tmparr['dial'] = array('value' => '', 'level' => 0);
5267     $currentcomponent->addgeneralarrayitem('devtechs', 'custom', $tmparr);
5268     unset($tmparr);
5269    
5270     // Devices list
5271     if ($_SESSION["AMP_user"]->checkSection('999')) {
5272     $currentcomponent->addoptlistitem('devicelist', 'sip_generic', _("Generic SIP Device"));
5273     $currentcomponent->addoptlistitem('devicelist', 'iax2_generic', _("Generic IAX2 Device"));
5274     $currentcomponent->addoptlistitem('devicelist', 'zap_generic', _("Generic ZAP Device"));
5275     $currentcomponent->addoptlistitem('devicelist', 'custom_custom', _("Other (Custom) Device"));
5276     }
5277     if ( $dispnum != 'devices' ) {
5278       $currentcomponent->addoptlistitem('devicelist', 'virtual', _("None (virtual exten)"));
5279     }
5280     $currentcomponent->setoptlistopts('devicelist', 'sort', false);
5281
5282
5283     // Option lists used by the gui
5284     $currentcomponent->addoptlistitem('devicetypelist', 'fixed', _("Fixed"));
5285     $currentcomponent->addoptlistitem('devicetypelist', 'adhoc', _("Adhoc"));
5286     $currentcomponent->setoptlistopts('devicetypelist', 'sort', false);
5287    
5288     $currentcomponent->addoptlistitem('deviceuserlist', 'none', _("none"));
5289     $currentcomponent->addoptlistitem('deviceuserlist', 'new', _("New User"));
5290     $users = core_users_list();
5291     if (isset($users)) {
5292       foreach ($users as $auser) {
5293         $currentcomponent->addoptlistitem('deviceuserlist', $auser[0], $auser[0]);
5294       }
5295     }
5296     $currentcomponent->setoptlistopts('deviceuserlist', 'sort', false);
5297
5298     // Add the 'proces' functions
5299     $currentcomponent->addguifunc('core_devices_configpageload');
5300     $currentcomponent->addprocessfunc('core_devices_configprocess');
5301   }
5302 }
5303
5304 function core_devices_configpageload() {
5305   global $currentcomponent;
5306
5307   $tech_hardware = isset($_REQUEST['tech_hardware'])?$_REQUEST['tech_hardware']:null;
5308   if ($devinfo_tech == 'virtual') {
5309     return true;
5310   }
5311
5312   // Init vars from $_REQUEST[]
5313   $display = isset($_REQUEST['display'])?$_REQUEST['display']:null;;
5314   $action = isset($_REQUEST['action'])?$_REQUEST['action']:null;
5315   $extdisplay = isset($_REQUEST['extdisplay'])?$_REQUEST['extdisplay']:null;
5316  
5317   if ( $action == 'del' ) { // Deleted
5318
5319     if ( $display != 'extensions' )
5320       $currentcomponent->addguielem('_top', new gui_subheading('del', $extdisplay.' '._("deleted"), false));
5321
5322   } elseif ( $extdisplay == '' && $tech_hardware == '' ) { // Adding
5323
5324       if ( $display != 'extensions') {
5325         $currentcomponent->addguielem('_top', new gui_pageheading('title', _("Add Device")), 0);
5326       } else {
5327         $currentcomponent->addguielem('_top', new gui_pageheading('title', _("Add an Extension")), 0);
5328       }
5329       $currentcomponent->addguielem('_top', new gui_label('instructions', _("Please select your Device below then click Submit")));
5330       $currentcomponent->addguielem('Device', new gui_selectbox('tech_hardware', $currentcomponent->getoptlist('devicelist'), '', _("Device"), '', false));
5331
5332   } else {
5333
5334     $deviceInfo = array();
5335     if ( $extdisplay ) { // Editing
5336
5337       $deviceInfo = core_devices_get($extdisplay);
5338
5339       if ( $display != 'extensions' ) {
5340         $currentcomponent->addguielem('_top', new gui_pageheading('title', _("Device").": $extdisplay", false), 0);
5341
5342         $delURL = $_SERVER['PHP_SELF'].'?'.$_SERVER['QUERY_STRING'].'&action=del';
5343         $tlabel = sprintf(_("Delete Device %s"),$extdisplay);
5344         $label = '<span><img width="16" height="16" border="0" title="'.$tlabel.'" alt="" src="images/telephone_delete.png"/>&nbsp;'.$tlabel.'</span>';
5345         $currentcomponent->addguielem('_top', new gui_link('del', $label, $delURL, true, false), 0);
5346
5347         if ($deviceInfo['device_user'] != 'none') {
5348           $editURL = $_SERVER['PHP_SELF'].'?type=setup&display=users&skip=0&extdisplay='.$deviceInfo['user'];
5349           $tlabel =  $deviceInfo['devicetype'] == 'adhoc' ? sprintf(_("Edit Default User: %s"),$deviceInfo['user']) : sprintf(_("Edit Fixed User: %s"),$deviceInfo['user']);
5350           $label = '<span><img width="16" height="16" border="0" title="'.$tlabel.'" alt="" src="images/user_edit.png"/>&nbsp;'.$tlabel.'</span>';
5351           $currentcomponent->addguielem('_top', new gui_link('edit_user', $label, $editURL, true, false), 0);
5352         }
5353       }
5354     } else {
5355
5356       $tmparr = explode('_', $tech_hardware);
5357       $deviceInfo['tech'] = $tmparr[0];
5358       $deviceInfo['hardware'] = $tmparr[1];
5359       unset($tmparr);
5360      
5361       if ( $display != 'extensions' ) {
5362         $currentcomponent->addguielem('_top', new gui_pageheading('title', sprintf(_("Add %s Device"), strtoupper($deviceInfo['tech'])) ), 0);
5363       } else {
5364         $currentcomponent->addguielem('_top', new gui_pageheading('title', sprintf(_("Add %s Extension"), strtoupper($deviceInfo['tech'])) ), 0);
5365       }
5366     }
5367
5368     // Ensure they exist before the extract
5369     $devinfo_description = $devinfo_emergency_cid = null;
5370     $devinfo_devicetype = $devinfo_user = $devinfo_hardware = null;
5371     if ( is_array($deviceInfo) ) {
5372       extract($deviceInfo, EXTR_PREFIX_ALL, 'devinfo');
5373     }
5374
5375     // Setup vars for use in the gui later on             
5376     $fc_logon = featurecodes_getFeatureCode('core', 'userlogon');
5377     $fc_logoff = featurecodes_getFeatureCode('core', 'userlogoff');
5378
5379     $msgInvalidDevID = _("Please enter a device id.");
5380     $msgInvalidDevDesc = _("Please enter a valid Description for this device");
5381     $msgInvalidEmergCID = _("Please enter a valid Emergency CID");
5382     $msgInvalidExtNum = _("Please enter a valid extension number.");
5383    
5384     // Actual gui
5385     $currentcomponent->addguielem('_top', new gui_hidden('action', ($extdisplay ? 'edit' : 'add')));
5386     $currentcomponent->addguielem('_top', new gui_hidden('extdisplay', $extdisplay));
5387
5388     if ( $display != 'extensions' ) {
5389       $section = _("Device Info");
5390       if ( $extdisplay ) { // Editing
5391         $currentcomponent->addguielem($section, new gui_hidden('deviceid', $extdisplay));
5392       } else { // Adding
5393         $currentcomponent->addguielem($section, new gui_textbox('deviceid', $extdisplay, _("Device ID"), _("Give your device a unique integer ID.  The device will use this ID to authenticate to the system."), '!isInteger()', $msgInvalidDevID, false));
5394       }
5395       $currentcomponent->addguielem($section, new gui_textbox('description', $devinfo_description, _("Description"), _("The caller id name for this device will be set to this description until it is logged into."), '!isAlphanumeric() || isWhitespace()', $msgInvalidDevDesc, false));
5396       $currentcomponent->addguielem($section, new gui_textbox('emergency_cid', $devinfo_emergency_cid, _("Emergency CID"), _("This caller id will always be set when dialing out an Outbound Route flagged as Emergency.  The Emergency CID overrides all other caller id settings."), '!isCallerID()', $msgInvalidEmergCID));
5397       $currentcomponent->addguielem($section, new gui_selectbox('devicetype', $currentcomponent->getoptlist('devicetypelist'), $devinfo_devicetype, _("Device Type"), _("Devices can be fixed or adhoc. Fixed devices are always associated to the same extension/user. Adhoc devices can be logged into and logged out of by users.").' '.$fc_logon.' '._("logs into a device.").' '.$fc_logoff.' '._("logs out of a device."), false));
5398       $currentcomponent->addguielem($section, new gui_selectbox('deviceuser', $currentcomponent->getoptlist('deviceuserlist'), $devinfo_user, _("Default User"), _("Fixed devices will always mapped to this user.  Adhoc devices will be mapped to this user by default.<br><br>If selecting 'New User', a new User Extension of the same Device ID will be set as the Default User."), false));
5399     } else {
5400       $section = _("Extension Options");
5401       $currentcomponent->addguielem($section, new gui_textbox('emergency_cid', $devinfo_emergency_cid, _("Emergency CID"), _("This caller id will always be set when dialing out an Outbound Route flagged as Emergency.  The Emergency CID overrides all other caller id settings."), '!isCallerID()', $msgInvalidEmergCID));
5402     }
5403     $currentcomponent->addguielem($section, new gui_hidden('tech', $devinfo_tech));
5404     $currentcomponent->addguielem($section, new gui_hidden('hardware', $devinfo_hardware));
5405
5406     if ($devinfo_tech != "virtual") {
5407       $section = _("Device Options");
5408
5409       $device_uses = sprintf(_("This device uses %s technology."),$devinfo_tech).(strtoupper($devinfo_tech) == 'ZAP' && ast_with_dahdi()?" ("._("Via DAHDI compatibility mode").")":"");
5410       $currentcomponent->addguielem($section, new gui_label('techlabel', $device_uses),4);
5411       $devopts = $currentcomponent->getgeneralarrayitem('devtechs', $devinfo_tech);
5412       if (is_array($devopts)) {
5413         foreach ($devopts as $devopt=>$devoptarr) {
5414           $devopname = 'devinfo_'.$devopt;
5415           $devoptcurrent = isset($$devopname) ? $$devopname : $devoptarr['value'];
5416           $devoptjs = isset($devoptarr['jsvalidation']) ? $devoptarr['jsvalidation'] : '';
5417           $devoptfailmsg = isset($devoptarr['failvalidationmsg']) ? $devoptarr['failvalidationmsg'] : '';
5418
5419           // We compare the existing secret against what might be in the put to detect changes when validating
5420           if ($devopt == "secret") {
5421             $currentcomponent->addguielem($section, new gui_hidden($devopname . "_origional", $devoptcurrent), 4);
5422           }
5423  
5424           if ( $devoptarr['level'] == 0 || ($extdisplay && $devoptarr['level'] == 1) ) { // editing to show advanced as well
5425             $currentcomponent->addguielem($section, new gui_textbox($devopname, $devoptcurrent, $devopt, '', $devoptjs, $devoptfailmsg), 4);
5426           } else { // add so only basic
5427             $currentcomponent->addguielem($section, new gui_hidden($devopname, $devoptcurrent), 4);
5428           }
5429         }
5430       }
5431     }
5432   }
5433 }
5434
5435 function core_devices_configprocess() {
5436   if ( !class_exists('agi_asteriskmanager') )
5437     include 'common/php-asmanager.php';
5438
5439   //make sure we can connect to Asterisk Manager
5440   if (!checkAstMan()) {
5441     return false;
5442   }
5443  
5444   //create vars from the request
5445   extract($_REQUEST);
5446
5447   if ($tech == "virtual") {
5448     return true;
5449   }
5450   $extension = isset($extension)?$extension:null;
5451   $deviceid = isset($deviceid)?$deviceid:null;
5452   $name = isset($name)?$name:null;
5453   $action = isset($action)?$action:null;
5454
5455   // fixed users only in extensions mode
5456   if ( $display == 'extensions' ) {
5457     $devicetype = 'fixed';
5458     $deviceid = $deviceuser = $extension;
5459         $description = $name;
5460   }
5461  
5462   //if submitting form, update database
5463   switch ($action) {
5464     case "add":
5465     // really bad hack - but if core_users_add fails, want to stop core_devices_add
5466
5467     if (!isset($GLOBALS['abort']) || $GLOBALS['abort'] !== true || !$_SESSION["AMP_user"]->checkSection('999')) {
5468       if (core_devices_add($deviceid,$tech,$devinfo_dial,$devicetype,$deviceuser,$description,$emergency_cid)) {
5469         needreload();
5470         if ($deviceuser != 'new') {
5471           redirect_standard_continue();
5472         }
5473       }
5474     } else {
5475       // This is a bit messy, because by this time, other modules may have added the device but this tries to block
5476       // the user who does not have add permission from adding a new extension.
5477       //
5478       $GLOBALS['abort'] = true;
5479     }
5480     break;
5481     case "del":
5482       core_devices_del($extdisplay);
5483       needreload();
5484       redirect_standard_continue();
5485     break;
5486     case "edit":  //just delete and re-add
5487       // really bad hack - but if core_users_edit fails, want to stop core_devices_edit
5488       if (!isset($GLOBALS['abort']) || $GLOBALS['abort'] !== true) {
5489         core_devices_del($extdisplay,true);
5490         core_devices_add($deviceid,$tech,$devinfo_dial,$devicetype,$deviceuser,$description,$emergency_cid,true);
5491         needreload();
5492         redirect_standard_continue('extdisplay');
5493       }
5494       break;
5495       case "resetall":  //form a url with this option to nuke the AMPUSER & DEVICE trees and start over.
5496         core_users2astdb();
5497         core_devices2astdb();
5498       break;
5499   }
5500   return true;
5501 }
5502
5503 ?>
Note: See TracBrowser for help on using the browser.