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

Revision 6553, 201.9 kB (checked in by p_lindheimer, 5 years ago)

closes #3142 delete all forms of a recorded file before re-recording so that there are not transcoded versions left around that say some thing different

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