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

Revision 7272, 209.6 kB (checked in by p_lindheimer, 5 years ago)

Merged revisions 7261 via svnmerge from
http://svn.freepbx.org/modules/branches/2.6

........

r7261 | mickecarlsson | 2008-11-12 13:41:50 -0800 (Wed, 12 Nov 2008) | 1 line


Closes #3380 fixes various string enclosures for localization. Thank you chocho

........

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