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

Revision 6406, 200.1 kB (checked in by p_lindheimer, 5 years ago)

closes #3072, always moves disallow=all to the top of a sip/iax section, also removes record_in and record_out from sip, iax settings which are bogus

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