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

Revision 5575, 183.2 kB (checked in by p_lindheimer, 5 years ago)

#2191 revert patch to send cidname - there have been reports that some providers ignore all CID when this is done or even reject calls, and since it is rare that a provider will even look at cidname in most of the world, it has been chosen to go back to previous behavior. If there is enough feedback that an option to have the name sent out is desired, we can look at adding a conifguration switch that would allow it on a given installation

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