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

Revision 7737, 247.4 kB (checked in by p_lindheimer, 4 years ago)

closes #3546, closes #3685, closes #3686, re #2768 - add ringinuse and more queue agent restrictions on how extensions are rung, and move agent-add/del from core to queues

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