Thirdlane Lumenvox Grammar Autogeneration

Situation

When using Thirdlane with Lumenvox, there is the need to update the grammar file each time an extension is added/modified/deleted. On top of that, the generation of the first grammar file takes some time.

Solution

1) Create a script that will:

  • Generate the entire grammar file based on the voicemail.conf file
  • Update the grammar file based on the voicemail.conf file when an extension is updated
  • Delete the proper entry from the grammar file when an extension is deleted
  • Add the proper entry to the grammar file based on the voicemail.conf file when an extension is created

2) Trigger this script from Thirdlane with the corresponding parameters.

Usage

Add

1
buildgrammar.php add 1102

Adds extension 1102 to directory.gram IF IT EXISTS in voicemail.conf

Delete

1
buildgrammar.php delete 1102

Deletes extension 1102 from directory.gram IF IT EXISTS in directory.gram

Update

1
buildgrammar.php update 1102

Updates extension 1102 in directory.gram IF IT EXISTS in directory.gram ONLY IF the name (ie: $jasonshane ) changed.

Generate all

1
buildgrammar.php generate all

Generates the entire directory.gram file based on the voicemail.conf file.

Configuration

You need to set the location for voicemail.conf and directory.gram

1
2
3
/********************* PATHS ***************************/
$voicemailConfFilePath = "/usr/local/www/data-dist/test/tests/lumenvoxgrammar/voicemail.conf";
$grammarFilePath = "/usr/local/www/data-dist/test/tests/lumenvoxgrammar/directory.gram";

Code

buildgrammar.php script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
#!/usr/local/bin/php -q
<?php
/* EXAMPLE COMMANDS
buildgrammar.php add 1102 -> adds extension 1102 to directory.gram IF IT EXISTS in voicemail.conf
buildgrammar.php delete 1102 -> deletes extension 1102 from directory.gram IF IT EXISTS in directory.gram
buildgrammar.php update 1102 -> updates extension 1102 in directory.gram IF IT EXISTS in directory.gram ONLY IF the name (ie: $jasonshane ) changed.
buildgrammar.php generate all -> generates the entire directory.gram file based on the voicemail.conf file
*/
/********************* PATHS ***************************/
$voicemailConfFilePath = "/usr/local/www/data-dist/test/tests/lumenvoxgrammar/voicemail.conf";
$grammarFilePath = "/usr/local/www/data-dist/test/tests/lumenvoxgrammar/directory.gram";
/********************* FILE HEADER *********************/
$fheader =
"#ABNF 1.0;
language en-US;
mode voice;
tag-format <semantics/1.0.2006>;
root \$company_directory;
";
/******************** FUNCTIONS ************************/
function sendError($errorMessage){
    echo $errorMessage;
}
function validate($type,$element){
    switch ($type){
        case 'mode':
                    if($element == 'add' || $element == 'delete' || $element == 'update' || $element == 'generate'){ $result['tf'] = true; } else { $result['tf'] = false; $result['msg'] = 'invalid_action'; };
        break;
        
        case 'number':
                    if(is_numeric($element) || $element == 'all'){ $result['tf'] = true; } else { $result['tf'] = false; $result['msg'] = 'invalid_number'; };
        break;
    }
    return $result;
}
function file2array($filepath){
    if(is_file($filepath)){
        $lines = file($filepath);
        
        return $lines;
    } else {
        return false;
    }
}
function write2file($filepath, $lines){
    if(is_file($filepath)){
        $Handle = fopen($filepath, 'w');
        fwrite($Handle, $lines);
        fclose($Handle);
    }
}
function buildgrammarAll($voicemailConfFilePath,$grammarFilePath,$fheader){
    $vmFileArray = file2array($voicemailConfFilePath);
    $startWrite = false;
    $grammarLines = '';
    $grammarDirectory = "\$company_directory = (";
    
    //build $grammarLines and $grammarDirectory
    $lineCounter = 0;
    $vmFullName = '';
    foreach ($vmFileArray as $line){    
        
        if( substr (trim($line),0,1) == '[' ){
            if( trim($line) == '[default]'){ $startWrite = true;} else { $startWrite = false; }
        }
        //Set values for $vmAccount and $vmFullName
        if( $startWrite && trim($line) != '' ){
            $tempDataArray = explode('=>',$line);    
            $vmAccount = trim($tempDataArray[0]);
            
            $tempDataArray = explode(',',trim($tempDataArray[1]));
            $vmFullName = trim($tempDataArray[1]);
        }
        
        if(trim($vmFullName) != ''){
            $thisname = explode(' ',$vmFullName);
            
            if(count($thisname)>1)
                { $thisnameString = $thisname[0].' ['.$thisname[1].']'; }
                else { $thisnameString = $thisname[0]; }
            
            $thisline = "$".strtolower(str_replace(' ','',$vmFullName)). " = (".$thisnameString.") {out=\"".$vmAccount."\"};\n";
            
            $grammarLines .= $thisline;
            //$jasonshane = (Jason [Shane]) {out="1411"};
            
            $grammarDirectory .= "$".strtolower(str_replace(' ','',$vmFullName))."|";
            //$company_directory = ($jasonshane|$lukeroman|$ketanpatel|$jasonthacker|$kiranpatel|$hasushah|$bartmehta|$receptionist|$operator|$janthornton) {out = rules.latest()};
        }
        
    }//endLoop
    
    //Build final string and write to file
    $grammarDirectory = substr_replace($grammarDirectory ,"",-1).") {out = rules.latest()};";    
    $grammarFileFullText = $fheader . $grammarLines . $grammarDirectory;
    write2file($grammarFilePath,$grammarFileFullText);
}
function addToGrammar($voicemailConfFilePath,$grammarFilePath,$fheader,$mode,$number){
    //read grammar file to grammar array
    $grammarFileArray = file2array($grammarFilePath);
        
    //read voicemail.conf file to array
    $vmFileArray = file2array($voicemailConfFilePath);
    
    //look for extension in voicemail.conf and get fullname
    $vmFullName = '';
    $extensionFound = false;
    $noFullName = true;
    foreach($vmFileArray as $line){
        if(!($extensionFound)){
            $tempDataArray = explode('=>',$line);    
            $vmAccount = trim($tempDataArray[0]);
            
            if($vmAccount == $number){
                $extensionFound = true;
                $tempDataArray = explode(',',trim($tempDataArray[1]));
                $vmFullName = trim($tempDataArray[1]);
                if(trim($vmFullName) != ''){
                    $noFullName = false;
                }
            };
        }
    }
    
    //If extension and fullname was found then..
    if($extensionFound && !($noFullName)){
        //build grammar entry with fullname and extension
        //$jasonshane = (Jason [Shane]) {out="1411"};
        $thisname = explode(' ',$vmFullName);
            
        if(count($thisname)>1){ $thisnameString = $thisname[0].' ['.$thisname[1].']'; }
            else { $thisnameString = $thisname[0]; }
        $thisline = "$".strtolower(str_replace(' ','',$vmFullName)). " = (".$thisnameString.") {out=\"".$vmAccount."\"};\n";
        
        //$company_directory
        //add a new line to the array and copy $company_directory entry to it
        $grammarFileArray[] = $grammarFileArray[(count($grammarFileArray)-1)];
        
        //then replace line (n-1) for the new added grammar line
        $grammarFileArray[(count($grammarFileArray)-2)] = $thisline;
        
        //finally add the new name to the grammar directory
        $grammarFileArray[(count($grammarFileArray)-1)] = str_replace(") {out = rules.latest()};","|$".strtolower(str_replace(' ','',$vmFullName)).") {out = rules.latest()};", $grammarFileArray[(count($grammarFileArray)-1)]);        
        
        //write lines to file
        foreach($grammarFileArray as $line){
            $grammarLines .= $line;
            //echo $line;
        }
        //echo $grammarLines;
        write2file($grammarFilePath,$grammarLines);
    }
}
function deleteFromGrammar($voicemailConfFilePath,$grammarFilePath,$fheader,$mode,$number){
    //read grammar
    //loop and build new array without the one that needs to be deleted
    //write ALL with new array
    
    //read grammar file to grammar array
    $grammarFileArray = file2array($grammarFilePath);
    
    foreach($grammarFileArray as $line){
        if( (substr($line,0,1) == '$')){
                if( ( stripos($line, "{out=\"".$number."\"}" ) === false ) ){
                    //add line
                    $newGrammarFile[] = $line;
                } else {
                    //get $namelastname to remove from directory
                    $tempData = explode("=",$line);
                    $theFullName = trim($tempData[0]);
                }    
            }
    }
    
    if(count($newGrammarFile)>2 && $theFullName != ''){
        //remove from directory
        $newGrammarFile[count($newGrammarFile)-1] = str_replace($theFullName,'',$newGrammarFile[count($newGrammarFile)-1]);
        //fix string
        $newGrammarFile[count($newGrammarFile)-1] = str_replace('||','|',$newGrammarFile[count($newGrammarFile)-1]);
        $newGrammarFile[count($newGrammarFile)-1] = str_replace('|)',')',$newGrammarFile[count($newGrammarFile)-1]);
        $newGrammarFile[count($newGrammarFile)-1] = str_replace('(|','(',$newGrammarFile[count($newGrammarFile)-1]);
        
        //new file ready, then...
        
        //build string to write
        $grammarLines = $fheader;
        foreach($newGrammarFile as $line){
            $grammarLines .= $line;
            //echo $line;
        }
        //write to file
        write2file($grammarFilePath,$grammarLines);
    }
}
function updateGrammar($voicemailConfFilePath,$grammarFilePath,$fheader,$mode,$number){
    //read grammar
    //read voicemail.conf
    //look for name in voicemail.conf
    //build $fullname
    //look for extension in grammar
    //IF $fullname found in grammar does not match, then update
    
    //read grammar file to grammar array
    $grammarFileArray = file2array($grammarFilePath);
    //get fullname from grammar and array line number
    $lineCounter = 0;
    $lineFound = false;
    foreach($grammarFileArray as $line){
        if( !(stripos($line, "{out=\"".$number."\"}" )) === false ){
            $lineFound = true;
            $lineFoundAt = $lineCounter;
            //get $namelastname
            $tempData = explode("=",$line);
            $theFullName = trim($tempData[0]);
            //echo $line;
        }
        $lineCounter ++;
    }
    //IF it was found, then look in voicemail.conf for the new fullname
    // compare vm.fullname with grammar.fullname
    // IF != , then update grammar
    if($lineFound){
        //read voicemail.conf file to array
        $vmFileArray = file2array($voicemailConfFilePath);
        //look for extension in voicemail.conf and get fullname
        $vmFullName = '';
        $extensionFound = false;
        $noFullName = true;
        foreach($vmFileArray as $line){
            if(!($extensionFound)){
                $tempDataArray = explode('=>',$line);    
                $vmAccount = trim($tempDataArray[0]);
                
                if($vmAccount == $number){
                    $extensionFound = true;
                    $tempDataArray = explode(',',trim($tempDataArray[1]));
                    $vmFullName = trim($tempDataArray[1]);
                    if(trim($vmFullName) != ''){
                        $noFullName = false;
                    }
                };
            }
        }
        //John Doe
        $thisname = explode(' ',$vmFullName);
        if(count($thisname)>1) {
            $thisnameString = $thisname[0].' ['.$thisname[1].']';
        } else {
            $thisnameString = $thisname[0];
            }
        $thisline = "$".strtolower(str_replace(' ','',$vmFullName)). " = (".$thisnameString.") {out=\"".$vmAccount."\"};\n";
        //$johndoe
        $vmFullName = "$".strtolower(str_replace(' ','',trim($vmFullName)));
        //compare vm.fullname with grammar.fullname
        //update both, the grammar line and the gramar directory entry
        if( $vmFullName != $theFullName ){
            //Update grammar line
            $grammarFileArray[$lineFoundAt] = $thisline;
            //Update directory - replace the grammar entry for the vm entry
            $directoryLine = $grammarFileArray[count($grammarFileArray)-1];
            $directoryLine = str_replace($theFullName, $vmFullName, $directoryLine);
            $grammarFileArray[count($grammarFileArray)-1] = $directoryLine;
            //build string to write
            $grammarLines = $fheader;
            foreach($grammarFileArray as $line){
                $grammarLines .= $line;
                //echo $line;
            }
            //write to file
            write2file($grammarFilePath,$grammarLines);
            //echo $grammarLines;
        }
        /*
        echo "\nVMFN :".$vmFullName;
        echo "\ngramFL:".$theFullName."\n";
        echo $grammarFileArray[$lineFoundAt];
        */
    }
    
    
    if(count($newGrammarFile)>2 && $theFullName != '' && $cocoa == 'loloa'){
        
        //remove from directory
        $newGrammarFile[count($newGrammarFile)-1] = str_replace($theFullName,'',$newGrammarFile[count($newGrammarFile)-1]);
        //fix string
        $newGrammarFile[count($newGrammarFile)-1] = str_replace('||','|',$newGrammarFile[count($newGrammarFile)-1]);
        $newGrammarFile[count($newGrammarFile)-1] = str_replace('|)',')',$newGrammarFile[count($newGrammarFile)-1]);
        $newGrammarFile[count($newGrammarFile)-1] = str_replace('(|','(',$newGrammarFile[count($newGrammarFile)-1]);
        
        //new file ready
        
        
    }
    //updates extension 1102 in directory.gram IF IT EXISTS in directory.gram ONLY IF the name (ie: $jasonshane ) changed
    
    //echo 'updateGrammar'.'|'.$voicemailConfFilePath.'|'.$grammarFilePath.'|'.$fheader;
}
function buildgrammar($voicemailConfFilePath,$grammarFilePath,$fheader,$mode,$number){
    switch ($mode){
        case 'generate':
            if($number == 'all'){
                buildgrammarAll($voicemailConfFilePath,$grammarFilePath,$fheader);    
            } else {
                sendError('generate_all_only');
            }
        break;
        
        case 'add':
            if($number != 'all'){
                addToGrammar($voicemailConfFilePath,$grammarFilePath,$fheader,$mode,$number);    
            } else {
                sendError('add_numbers_only');
            }
        break;
        
        case 'delete':
            if($number != 'all'){
                deleteFromGrammar($voicemailConfFilePath,$grammarFilePath,$fheader,$mode,$number);    
            } else {
                sendError('delete_numbers_only');
            }
        break;
        
        case 'update':
            if($number != 'all'){
                updateGrammar($voicemailConfFilePath,$grammarFilePath,$fheader,$mode,$number);    
            } else {
                sendError('update_numbers_only');
            }
        break;
    }
}
/*******************************************************/
/*******************************************************
* MAIN
******************************************************/
/* avoid dialplan errors */
if($argc != 3){
    sendError("not_enough_parameters");
    //ends here
} else {
    /*load parameters*/
    $mode = $argv[1];
    $number = $argv[2]; /* can be an extesion number or the "all" word IF mode = generate*/
    /*validate parameters*/
    $counter = 1;
    $isValid['tf'] = true;
    $isValid['msg'] = '';
    $isValidMode = validate('mode',$mode);
    $isValidNumber = validate('number',$number);
    if(!($isValidMode['tf'])){
        $counter ++;
        $isValid['tf'] = false;
        $isValid['msg'] = $isValidMode['msg'];
    }
    if(!($isValidNumber['tf'])){
        $isValid['tf'] = false;
        if($counter > 1){ $isValid['msg'] .= " | ".$isValidNumber['msg']; } else { $isValid['msg'] = $isValidNumber['msg']; }
    }
    
    /*Apply action if validation succeded*/
    if($isValid['tf']){
        buildgrammar($voicemailConfFilePath,$grammarFilePath,$fheader,$mode,$number);
    } else {
        sendError($isValid['msg']);
    }
}
?>

Example Configuration Files

directory.gram

1
2
3
4
5
6
7
8
9
10
11
12
13
#ABNF 1.0;
language en-US;
mode voice;
tag-format <semantics/1.0.2006>;
root $company_directory;
$johndoe = (John [Doe]) {out="1411"};
$lukeroman = (Luke [Roman]) {out="1400"};
$company_directory = ($johndoe |$janedoe) {out = rules.latest()};

voicemail.conf

1
2
3
4
5
6
7
8
9
10
11
12
;
; Voicemail Configuration
;
...
...
...
[default]
1411 => 1411,John Doe,john.doe@demo.com,,delete=no|attach=yes
1411 => 1411,Jane Doe,jane.doe@demo.com,,delete=no|attach=yes
...
...
...

Posted in Scripts | Tagged , , , , | 2 Comments

Asterisk AMI Conference Rescue

Description

This script transfers a user from a conference room to your extension. First you have to join the room, then press the xml key that triggers the script making you hanging up and then receiving the call from the user that was in the conference.

Usage

This script was thought to be called from an xml key, but it could be called from the dial plan also. So, in the programmable section of the configuration web page of the Aastra phone you have to configure a key of type “XML” and the following value:

1
http://<web_server>/conference_rescue.php?$$SIPUSERNAME$$

Side Effect

As the conference users can be distinguishable or not. This script will transfer the first user that entered in the room different to the one that press the xml key.

Different approach

A slightly different solution could be that the user don’t have to log to the conference room, a user menu can be created so the user just have to put the conference number and will receive the call from the one that was in the conference. But his will work only with Aastra phones.

Portability

This script will work on every phone that can trigger a web page and send the sip user as a parameter.

Dependencies

This library is required: asterisk_ami_class.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
&lt;?php
/**
* Includes wrappers for database functions
*
*/
class AstMan {
var $socket;
var $error;
function AstMan()
{
$this->socket = FALSE;
$this->error = "";
}
//function Login($host="localhost", $username="admin", $password="xerxes"){
function Login($host, $username, $password){
$this->socket = @fsockopen("127.0.0.1","5038", $errno, $errstr, 1);
if (!$this->socket) {
$this->error = "Could not connect - $errstr ($errno)";
return FALSE;
}else{
stream_set_timeout($this->socket, 1);
$wrets = $this->Query("Action: Login\r\nUserName: $username\r\nSecret: $password\r\nEvents: off\r\n\r\n");
if (strpos($wrets, "Message: Authentication accepted") != FALSE){
return true;
}else{
$this->error = "Could not login - Authentication failed";
fclose($this->socket);
$this->socket = FALSE;
return FALSE;
}
}
}
function Logout(){
if ($this->socket){
fputs($this->socket, "Action: Logoff\r\n\r\n");
while (!feof($this->socket)) {
$wrets .= fread($this->socket, 8192);
}
fclose($this->socket);
$this->socket = "FALSE";
}
return;
}
function Query($query){
$wrets = "";
if ($this->socket === FALSE)
return FALSE;
fputs($this->socket, $query);
do
{
$line = fgets($this->socket, 4096);
$wrets .= $line;
$info = stream_get_meta_data($this->socket);
}while ($line != "\r\n" && $infotimed_out >'timed_out' == false );
return $wrets;
}
function GetError(){
return $this->error;
}
function GetDB($family, $key){
$value = "";
$wrets = $this->Query("Action: Command\r\nCommand: database get $family $key\r\n\r\n");
if ($wrets){
$value_start = strpos($wrets, "Value: ") + 7;
$value_stop = strpos($wrets, "\n", $value_start);
if ($value_start > 8){
$value = substr($wrets, $value_start, $value_stop - $value_start);
}
}
return $value;
}
function PutDB($family, $key, $value){
$wrets = $this->Query("Action: Command\r\nCommand: database put $family $key $value\r\n\r\n");
if (strpos($wrets, "Updated database successfully") != FALSE){
return TRUE;
}
$this->error = "Could not updated database";
return FALSE;
}
function DelDB($family, $key){
$wrets = $this->Query("Action: Command\r\nCommand: database del $family $key\r\n\r\n");
if (strpos($wrets, "Database entry removed.") != FALSE){
return TRUE;
}
$this->error = "Database entry does not exist";
return FALSE;
}
function GetFamilyDB($family){
$wrets = $this->Query("Action: Command\r\nCommand: database show $family\r\n\r\n");
if ($wrets){
$value_start = strpos($wrets, "Response: Follows\r\n") + 19;
$value_stop = strpos($wrets, "--END COMMAND--\r\n", $value_start);
if ($value_start > 18){
$wrets = substr($wrets, $value_start, $value_stop - $value_start);
}
$lines = explode("\n", $wrets);
foreach($lines as $line){
if (strlen($line) > 4){
$value_start = strpos($line, ": ") + 2;
$value_stop = strpos($line, " ", $value_start);
$key = trim(substr($line, strlen($family) + 2, strpos($line, " ") - strlen($family) + 2));
$value[$key] = trim(substr($line, $value_start));
}
}
return $value;
}
return FALSE;
}
function CliCommand($clicommand){
if ($this->socket){
fputs($this->socket, "Action: Command\r\n");
fputs($this->socket, "Command: ".$clicommand."\r\n\r\n");
$wrets=fgets($this->socket,128);
}
return;
}
function CliCommandReturn($clicommand){
if ($this->socket){
fputs($this->socket, "Action: Command\r\n");
fputs($this->socket, "Command: ".$clicommand."\r\n\r\n");
$wrets=fgets($this->socket,128);
}
return $wrets; /* only diff with CliCommand */
}
//end.class
}
?>

The include in the php script must be changed to where you place this file.

Script

The first three variables of the script must be set to whatever is configured in /etc/asterisk/manager.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//#!/usr/bin/php
include('/var/www/html/bemgr-open/includes/class/asterisk.ami.class.php');
$asteriskAMIHost="127.0.0.1";
$asteriskAMIUser="admin";
$asteriskAMIPass="xerxes";
$clicommand = '';
//ChannelMain is the channels that we are going to barge
$channelMain="";
$channelExt="";
#####################################################################
# Aastra_decode_HTTP_header
#
# Returns an array
# 0 Phone Type
# 1 Phone MAC Address
# 2 Phone firmware version
#####################################################################
function Aastra_decode_HTTP_header()
{
$user_agent=$_SERVER["HTTP_USER_AGENT"];
if(stristr($user_agent,"Aastra")) {
$value=preg_split("/ MAC:/",$user_agent);
$fin=preg_split("/ /",$value[1]);
$value[1]=preg_replace("/\-/","",$fin[0]);
$value[2]=preg_replace("/V:/","",$fin[1]);
} else {
$value[0]="MSIE";
$value[1]="NA";
$value[2]="NA";
}
return($value);
}
//Receives a sip account ID and returns the channel that this user is on
function getChannel($amiObject, $exten) {
$clicommand = "Action: Command\r\nCommand: show channels\r\n\r\n";
$res = $amiObject->Query($clicommand);
$channels = explode("\n", $res);
$res = "";
//echo $channels[0]."\n";
for ($i=3; $i < count($channels); $i++) {
//echo "Canal ".$i.": ".$channels[$i]."\n";
$line = explode(" ", $channels[$i]);
//echo "Linea :". $line[0]."\n";
if (substr_count($line[0], "/".$exten) >= 1) {
//echo "Linea :". $line[0]."\n";
$res = $line[0];
break;
}
}
return $res;
}
//Receives a channel as parameter and returns the channel that is bridged with
function getExtChannel($amiObject, $channel) {
$clicommand = "Action: Command\r\nCommand: show channel ".$channel."\r\n\r\n";
$res = $amiObject->Query($clicommand);
$channels = explode("\n", $res);
$res = "";
for ($i=3; $i < count($channels); $i++) {
//echo "Channel: \n";
$line = explode("=", $channels[$i]);
if (substr_count($line[0], "BRIDGEPEER") >= 1) {
$res = $line[1];
break;
}
//for ($j=0;$j<count($line);$j++) {
// echo "Linea :".$j." ". $line[$j]."\n";
//}
}
return $res;
}
//Send one or two channels to conference, the second channel can be empty
//@param4: String exten --> extension where to send the channel/s
function sendChannelsToExten($amiObject, $channelMain, $channelExt, $exten) {
$clicommand = "Action: Redirect\r\n";
$clicommand .= "Channel: ".$channelMain."\r\n";
if (strlen($channelExt) > 0) {
$clicommand .= "ExtraChannel: ".$channelExt."\r\n";
}
$clicommand .= "Exten: ".$exten."\r\n";
// $clicommand .= "Context: barge\r\n";
$clicommand .= "Priority: 1\r\n\r\n";
$res = $amiObject->Query($clicommand);
return $res;
}
//Send one extension to another extension of the dialplan
function sendExtenToConf($amiObject, $exten, $confExten) {
$channel = getChannel($amiObject, $exten);
echo "Channel: ".$channel."\n";
sendChannelsToConf($amiObject, $channel, "", $confExten);
}
function setVar($amiObject, $variable, $channel, $confExten) {
// $channel = getChannel($amiObject, $exten);
$clicommand = "Action: Setvar\r\n";
$clicommand .= "Channel: ".$channel."\r\n";
$clicommand .= "Variable: ".$variable."\r\n";
$clicommand .= "Value: ".$confExten."\r\n\r\n";
$res = $amiObject->Query($clicommand);
}
/*This function Originate a call between two points
@channel --> Channel we want to call: SIP/1104, Zap/g0/911
@ The call will be place after this channel is picked up
@destiny --> exten we want to call: 1104
*/
function sendCall($amiObject, $channel, $destiny) {
$clicommand = "Action: Originate\r\n";
$clicommand .= "Channel: ".$channel."\r\n";
$clicommand .= "Context: longdistance\r\n";
$clicommand .= "Exten: ".$destiny."\r\n";
$clicommand .= "Priority: 1\r\n\r\n";
$res = $amiObject->Query($clicommand);
echo $res;
echo "channel: ".$channel."\n";
}
//Gets the roomnumber where is $exten
function getRoomNumber($amiObject, $exten) {
$clicommand = "Action: Command\r\n";
$clicommand .= "Command: meetme\r\n\r\n";
$res = $amiObject->Query($clicommand);
$rooms = explode("\n", $res);
for ($i=3;$i<count($rooms)-4 ;$i++) {
//remove extra white spaces
$raw_line = preg_replace('/\s\s+/', ' ', $rooms[$i]);
//split into words
$line = preg_split("/[\s,]+/",$raw_line);
//Is expected that the room is in that position of the array
$room =$line[0];
$clicommand = "Action: Command\r\n";
$clicommand .= "Command: meetme list ".$room."\r\n\r\n";
$res = $amiObject->Query($clicommand);
$users = explode("\n", $res);
for ($j=2;$j<count($users)-4;$j++) {
$raw_line = preg_replace('/\s\s+/', ' ', $users[$j]);
$line = preg_split("/[\s,]+/",$raw_line);
if ($line[3] == $exten) {
return $room;
}
}
}
return -1;
}
function getChannelFromConf($amiObject, $exten) {
$room = getRoomNumber($amiObject, $exten);
$channel = getChannel($amiObject, $exten);
$clicommand = "Action: Command\r\n";
$clicommand .= "Command: meetme list ".$room."\r\n\r\n";
$res = $amiObject->Query($clicommand);
$users = explode("\n", $res);
for ($j=2;$j<count($users)-4;$j++) {
$raw_line = preg_replace('/\s\s+/', ' ', $users[$j]);
$line = preg_split("/[\s,]+/",$raw_line);
if ($line[7] != $channel) return $line[7];
}
return -1;
}
function displayRoom($room) {
header("Content-Type: text/xml");
$output = "<AastraIPPhoneFormattedTextScreen destroyOnExit=\"yes\" Timeout=\"6\">\n";
$output .= "<Line Size=\"normal\" Align=\"center\">ROOM: ".$room."</Line>\n";
// $output .= "<Line Size=\"normal\" Align=\"center\">".$room."</Line>\n";
$output .= "</AastraIPPhoneFormattedTextScreen>\n";
header("Content-Length: ".strlen($output));
echo $output;
}
function hangup($amiObject, $channel) {
$clicommand = "Action: Hangup\r\n";
$clicommand .= "Channel: ".$channel."\r\n\r\n";
$res = $amiObject->Query($clicommand);
}
### MAIN CODE
# Retrieve parameters
$user=$_GET['user'];
//$user = "1104";
$amiObject = new AstMan();
$amiObject->Login($asteriskAMIHost,$asteriskAMIUser,$asteriskAMIPass);
//Get channel from conference
$channelExt = getChannelFromConf($amiObject, $user);
$channel = getChannel($amiObject, $user);
//Hanging up the channel
hangup($amiObject, $channel);
//Send the channel to user extension
sendChannelsToExten($amiObject, $channelExt, "", $user);
$amiObject->Logout();
?>

Posted in Scripts | Tagged , , , | Leave a comment

Asterisk AMI 3way-call-to-conference

Description

This script moves a three-way call to conference. In a 3-way call there is a initiator and two invited. The two invited are moved to a room immediately. The initiator original call will hang up and will be call 2 seconds later to join the room.

Implementation

For implementing this script in a customer we have to set up:

  1. XML key in the phone to trigger this script
  2. Conference rooms to send the calls
  3. Dial plan
  4. Scripts parameters

Dial Plan Example

1
exten => 1997,1,Meetme(${conf_room}|q)

1997 is an example, could be any, the only importance is to match with the one set it in the script.

Script Config Parameters

Besides AMI parameters: host, user, etc. These parameters have to be set starting at line 352:

1
2
3
4
5
6
7
//Range of avaiable conferences
$roomStart = 20;
$roomEnd = 40;
//Dialplan entry for conferences
$confExten = "1997";
//Dialplan context where is defined the previous extension
$context = "longdistance";

Script Parameter

This script have to receive only one parameter: the extension of the 3-way call initiator. Example of xml key configuration for an Aastra phone:

1
http://192.168.15.22:80/xml/asterisk/3way-call-to-conference.php?exten=$$SIPUSERNAME$$

Meetme Config

Remember to set in meetme.conf file the range of available rooms. This have to match with [$roomStart, $roomEnd] parameters.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
<?php
include('/var/www/html/bemgr-open/includes/class/asterisk.ami.class.php');
require_once('/var/www/html/xml/include/AastraIPPhoneConfiguration.class.php');
require_once('/var/www/html/xml/include/AastraIPPhoneTextScreen.class.php');
class AstManExtended extends AstMan {
function AstManExtended() {
}
//Function to generate random number for ramdoms conference rooms
function slotnumber()
{
srand(time());
for ($i=0; $i < 3; $i++) {
$random = (rand()%9);
$slot[] = $random;
}
$res = $slot[0].$slot[1].$slot[2];
return $res;
}
//Receives a sip account ID and returns the channel that this user is on
function getChannel($exten) {
$clicommand = "Action: Command\r\nCommand: show channels\r\n\r\n";
$res = $this->Query($clicommand);
$channels = explode("\n", $res);
$res = "";
//echo $channels[0]."\n";
for ($i=3; $i < count($channels); $i++) {
//echo "Canal ".$i.": ".$channels[$i]."\n";
$line = explode(" ", $channels[$i]);
//echo "Linea :". $line[0]."\n";
if (substr_count($line[0], "/".$exten) >= 1) {
//echo "Linea :". $line[0]."\n";
$res = $line[0];
break;
}
}
return $res;
}
//Return an array with all channels that belongs to an extension.
function getChannels($exten) {
$clicommand = "Action: Command\r\nCommand: show channels\r\n\r\n";
$res = $this->Query($clicommand);
$channels = explode("\n", $res);
$res = "";
$j = 0;
//echo $channels[0]."\n";
for ($i=3; $i < count($channels); $i++) {
echo "Canal ".$i.": ".$channels[$i]."\n";
$line = explode(" ", $channels[$i]);
echo "Linea :". $line[0]."\n";
if (substr_count($line[0], "/".$exten) >= 1) {
echo " STR:". $line[0]."\n";
$res[$j] = $line[0];
$j++;
}
}
return $res;
}
//Receives a channel as parameter and returns the channel that is bridged with
function getBridgedChannel($channel) {
$clicommand = "Action: Command\r\nCommand: show channel ".$channel."\r\n\r\n";
$res = $this->Query($clicommand);
$channels = explode("\n", $res);
$res = "";
for ($i=3; $i < count($channels); $i++) {
//echo "Channel: \n";
$line = explode("=", $channels[$i]);
if (substr_count($line[0], "BRIDGEPEER") >= 1) {
$res = $line[1];
break;
}
//for ($j=0;$j<count($line);$j++) {
// echo "Linea :".$j." ". $line[$j]."\n";
//}
}
return $res;
}
//Send one or two channels to conference, the second channel can be empty
//This function, in fact, sends two channels to $confExten extension.
function sendChannelsToConf($channelMain, $channelExt, $confExten) {
$clicommand = "Action: Redirect\r\n";
$clicommand .= "Channel: ".$channelMain."\r\n";
if (strlen($channelExt) > 0) {
$clicommand .= "ExtraChannel: ".$channelExt."\r\n";
}
$clicommand .= "Exten: ".$confExten."\r\n";
// $clicommand .= "Context: barge\r\n";
$clicommand .= "Priority: 1\r\n\r\n";
$res = $this->Query($clicommand);
}
function sendExtenToConf($exten, $confExten) {
$channel = $this->getChannel($exten);
echo "Channel: ".$channel."\n";
$this->sendChannelsToConf($channel, "", $confExten);
}
function getGlobalVar($variable) {
$clicommand = "Action: Command\r\n";
$clicommand .= "Command: show globals\r\n\r\n";
$res = $this->Query($clicommand);
$globals = explode("\n", $res);
$global = array();
$value = "";
for($i=0;$i<count($globals);$i++) {
if(stristr($globals[$i], $variable)) {
$global = explode("=", $globals[$i]);
$value = $global[1];
}
}
return $value;
}
function setGlobalVar($variable, $value) {
$clicommand = "Action: Command\r\n";
$clicommand .= "Command: set global $variable $value\r\n\r\n";
$res = $this->Query($clicommand);
}
function setVar($variable, $exten, $confExten) {
$channel = $this->getChannel($exten);
$clicommand = "Action: Setvar\r\n";
$clicommand .= "Channel: ".$channel."\r\n";
$clicommand .= "Variable: ".$variable."\r\n";
$clicommand .= "Value: ".$confExten."\r\n\r\n";
$res = $this->Query($clicommand);
}
function setVarChannel($variable, $channel, $confExten) {
$clicommand = "Action: Setvar\r\n";
$clicommand .= "Channel: ".$channel."\r\n";
$clicommand .= "Variable: ".$variable."\r\n";
$clicommand .= "Value: ".$confExten."\r\n\r\n";
$res = $this->Query($clicommand);
}
/*This function Originate a call between two points
@channel --> Channel we want to call: SIP/1104, Zap/g0/911
@ The call will be place after this channel is picked up
@destiny --> exten we want to call: 1104
*/
function sendCall($channel, $destiny) {
$clicommand = "Action: Originate\r\n";
$clicommand .= "Channel: ".$channel."\r\n";
$clicommand .= "Context: longdistance\r\n";
$clicommand .= "Exten: ".$destiny."\r\n";
$clicommand .= "Priority: 1\r\n\r\n";
$res = $this->Query($clicommand);
//echo $res;
echo "channel: ".$channel."\n";
}
//Gets the roomnumber where is $exten
function getRoomNumber($exten) {
$clicommand = "Action: Command\r\n";
$clicommand .= "Command: meetme\r\n\r\n";
$res = $this->Query($clicommand);
$rooms = explode("\n", $res);
for ($i=3;$i<count($rooms)-4 ;$i++) {
//remove extra white spaces
$raw_line = preg_replace('/\s\s+/', ' ', $rooms[$i]);
//split into words
$line = preg_split("/[\s,]+/",$raw_line);
//Is expected that the room is in that position of the array
$room =$line[0];
$clicommand = "Action: Command\r\n";
$clicommand .= "Command: meetme list ".$room."\r\n\r\n";
$res = $this->Query($clicommand);
$users = explode("\n", $res);
for ($j=2;$j<count($users)-4;$j++) {
$raw_line = preg_replace('/\s\s+/', ' ', $users[$j]);
$line = preg_split("/[\s,]+/",$raw_line);
if ($line[3] == $exten) {
return $room;
}
}
}
return -1;
}
function getRoomNumbers() {
$clicommand = "Action: Command\r\n";
$clicommand .= "Command: meetme\r\n\r\n";
$res = $this->Query($clicommand);
$rooms = explode("\n", $res);
$j = 0;
$roomNumbers = array();
for ($i=3;$i<count($rooms)-4 ;$i++) {
//remove extra white spaces
$raw_line = preg_replace('/\s\s+/', ' ', $rooms[$i]);
//split into words
$line = preg_split("/[\s,]+/",$raw_line);
//Is expected that the room is in that position of the array
$room =$line[0];
$roomNumbers[$j] = $room;
$j++;
}
return $roomNumbers;
}
function getRoomNumberByChannel($channel) {
$clicommand = "Action: Command\r\n";
$clicommand .= "Command: meetme\r\n\r\n";
$res = $this->Query($clicommand);
$rooms = explode("\n", $res);
for ($i=3;$i<count($rooms)-4 ;$i++) {
//remove extra white spaces
$raw_line = preg_replace('/\s\s+/', ' ', $rooms[$i]);
//split into words
$line = preg_split("/[\s,]+/",$raw_line);
//Is expected that the room is in that position of the array
$room =$line[0];
$clicommand = "Action: Command\r\n";
$clicommand .= "Command: meetme list ".$room." concise\r\n\r\n";
$res = $this->Query($clicommand);
$users = explode("\n", $res);
print_r($users);
for ($j=2;$j<count($users)-3;$j++) {
$raw_member = explode("!", $users[$j]);
echo "Channels: ".$raw_member[3]."\n";
if ($raw_member[3] == $channel) {
return $room;
}
}
}
return -1;
}
//Returns an Array with all the members of a conference room
function getConferenceMembers($room) {
//AMI offset of "concise" begining: 2, end: 3
$clicommand = "Action: Command\r\n";
$clicommand .= "Command: meetme list $room concise\r\n\r\n";
$res = $this->Query($clicommand);
$raw_members = explode("\n", $res);
$member = array();
$members = array();
//var_dump($raw_members);
for ($i=2;$i< count($raw_members)-3;$i++) {
$raw_member = explode("!", $raw_members[$i]);
// var_dump($raw_member);
$member['listIndex'] = $raw_member[0];
$member['extension'] = $raw_member[1];
$member['callerid'] = $raw_member[2];
$member['channel'] = $raw_member[3];
$member['timeOnline'] = $raw_member[8];
$members[$raw_member[1]] = $member;
}
return $members;
}
function loadSipPeer($extension) {
$clicommand = "Action: Command\r\n";
$clicommand .= "Command: sip show peer $extension\r\n\r\n";
$res = $this->Query($clicommand);
$lines = explode("\n", $res);
for($i=3; $i< count($lines); $i++) {
if (strstr($lines[$i], ":")) {
$raw_peer_attr = explode(":", $lines[$i], 2);
$key = trim($raw_peer_attr[0], "\x00..\x1F ");
$value = trim($raw_peer_attr[1], "\x00..\x1F ");
$peer[$key] = $value;
}
}
return $peer;
}
//This function locks or unlocks a conference
function setConference($newState, $room) {
$clicommand = "Action: Command\r\n";
$clicommand .= "Command: meetme $newState $room\r\n\r\n";
$res = $this->Query($clicommand);
}
}
#### End AMI standard library ##########
function push2phone($server, $phone, $data) {
$xml = "xml=".$data;
$post = "POST / HTTP/1.1\r\n";
$post .= "Host: $phone\r\n";
$post .= "Referer: $server\r\n";
$post .= "Connection: Keep-Alive\r\n";
$post .= "Content-Type: text/xml\r\n";
$post .= "Content-Length: ".strlen($xml)."\r\n\r\n";
$fp = @fsockopen ( $phone, 80, $errno, $errstr, 5);
if($fp) {
fputs($fp, $post.$xml);
flush();
fclose($fp);
}
}
function composeXmlMessage($text) {
###
$xml = "<AastraIPPhoneTextScreen Beep = 'yes'>\n";
$xml .= "<Title>BARGE</Title>\n";
$xml .= "<Text>$text.</Text>\n";
$xml .= "<SoftKey index=\"5\">\n";
$xml .= "<Label>Lock</Label>\n";
$xml .= "<URI>http://192.168.15.22/xml/asterisk/barge.php?action=lock&amp;ext=1104</URI>\n";
$xml .= "</SoftKey>\n";
$xml .= "</AastraIPPhoneTextScreen>\n";
return $xml;
}
function aastraTextScreen($textObject, $softkeyArray, $title = "", $message = "") {
$textObject->setTitle($title);
$textObject->setText($message);
$textObject->setDestroyOnExit();
foreach($softkeyArray as $key => $params) {
$textObject->addSoftkey($key, $params['label'], $params['uri']);
}
}
function getIpAddress($peerData) {
$ipaddrArray = explode(" ", $peerData['Addr->IP']);
$ipaddr = $ipaddrArray[0];
return $ipaddr;
}
function aastraConfigSoftKeys($configObject, $key, $label, $actionUri) {
$configObject->addEntry("sofkey$key type", "xml");
$configObject->addEntry("sofkey$key label", $label);
$configObject->addEntry("sofkey$key value", $actionUri);
}
function sendMsgAastraPhones($amiObject, $srcIpAddress, $extensionsArray, $message) {
//Perhaps at this point the phoneconfig could be retrieve from DB ---> pending
foreach($extensionsArray as $extension => $data) {
$peerData = $amiObject->loadSipPeer($extension);
$phoneIpAddress = getIpAddress($peerData);
$userAgent = $peerData['Useragent'];
if(stristr($userAgent, "Aastra 57i") || stristr($userAgent, "Aastra 55i")) {
echo "$srcIpAddress, $phoneIpAddress, $message\n";
push2phone($srcIpAddress, $phoneIpAddress, $message);
}
}
}
$asteriskAMIHost="127.0.0.1";
$asteriskAMIUser="admin";
$asteriskAMIPass="xerxes";
$asteriskIpAddr="192.168.15.22";
//Range of avaiable conferences
$roomStart = 20;
$roomEnd = 40;
//Dialplan entry for conferences
$confExten = "1997";
//Dialplan context where is defined the previous extension
$context = "longdistance";
$clicommand = '';
$amiObject = new AstManExtended();
$amiObject->Login($asteriskAMIHost,$asteriskAMIUser,$asteriskAMIPass);
/*** Script parameter needed for execution. ***/
if ($argc > 0) {
$exten = $argv[1];
}
if(isset($_REQUEST['exten']) {
$exten = $_REQUEST['exten'];
}
/*** ####################### ***/
$channels = $amiObject->getChannels($exten);
$bridged1 = $amiObject->getBridgedChannel($channels[0]);
if(count($channels) > 1) {
$bridged2 = $amiObject->getBridgedChannel($channels[1]);
}
$rooms = $amiObject->getRoomNumbers();
//At this point I have the channels, now I have to send them to the conference.
//Check which room I can use
$room = $roomStart;
$i = 0;
while($i < count($rooms) && $roomStart <= $roomEnd) {
if($rooms[$i] >= $roomStart) {
$rangeStart++;
} else {
$room = $roomStart;
break;
}
}
//I send first bridged channels
$amiObject->setVarChannel("conf_room",$bridged1,$room);
$amiObject->setVarChannel("conf_room",$bridged2,$room);
$amiObject->sendChannelsToConf($bridged1, $bridged2, $confExten);
$localChannel = "Local/$confExten@$context/n";
$amiObject->setVarChannel("conf_room","",$room);
//Send the initiater
$amiObject->sendCall($localChannel, $exten);
$amiObject->Logout();
?>

Posted in Scripts | Tagged , , , | Leave a comment

Cisco Hot Desking

Description

This method includes IVR integration with AGI script. The IVR part gets from the user the extension and voicemail passwd, gets the ipadress from the phone and executes the agi script.

IVR

This is a simple IVR that collects the data and loop till the user and password were properly populated. There is a wilcard extension that has to be created for logoff purposes. In the example below is set the extension 1000, and that extension has to have the context login-only. The only dial number the extension 1000 will be able to dial is the login extension. So all extensions that were logged off will be set to extension number 1000.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[cisco-provitioning]
exten =&gt; s,1,NoOp(Cisco provitioning IVR ${SIPPEER(${CALLERID(num)},ip)})
exten =&gt; s,n,Set(ipaddress=${SIPPEER(${CALLERID(num)},ip)})
exten =&gt; s,n(enterData),Read(extension,vm-extension,4)
exten =&gt; s,n,Read(secret,pls-enter-vm-password)
exten =&gt; s,n,AGI(cisco_provitioning.php,${ipaddress},${extension},${secret},login)
exten =&gt; s,n,Gotoif($["${cisco_validation_passwd}"=="no"]?wrongPasswd)
exten =&gt; s,n,Hangup()
exten =&gt; s,n(wrongPasswd),Playback(vm-invalid-password)
exten =&gt; s,n,Goto(enterData)
[login-only]
exten =&gt; _X.,1,NoOp(Cisco provitioning IVR)
exten =&gt; _X.,n,Goto(longdistance,8500,1)
[cisco-provitioning-logoff]
exten =&gt; s,1,NoOp(Cisco provitioning IVR ${SIPPEER(${CALLERID(num)},ip)})
exten =&gt; s,n,Set(ipaddress=${SIPPEER(${CALLERID(num)},ip)})
exten =&gt; s,n,AGI(cisco_provitioning.php,${ipaddress},1000,0000,logoff)
exten =&gt; s,n,Playback(vm-goodbye)
exten =&gt; s,n,Hangup()

AGI Code

This php script parses /etc/asterisk/sip.conf and /etc/asterisk/voicemail.conf and gets the data. The file sip.conf doesn’t has to have any “(” or “)” character.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/php -q
&lt;?php
function execute_agi($command) {
global $debug_mode, $log_file;
fwrite(STDOUT, "$command\n");
fflush(STDOUT);
$result = trim(fgets(STDIN));
$ret = array('code'=> -1, 'result'=> -1, 'timeout'=> false, 'data'=> '');
if (preg_match("/^([0-9]{1,3}) (.*)/", $result, $matches)) {
$ret['code'] = $matches[1];
$ret['result'] = 0;
if (preg_match('/^result=([0-9a-zA-Z]*)\s?(?:\(?(.*?)\)?)?$/', $matches[2], $match)) {
$ret['result'] = $match[1];
$ret['timeout'] = ($match[2] === 'timeout') ? true : false;
$ret['data'] = $match[2];
}
}
return $result;
}
function setDialplanVar($variable, $value){
$value = trim($value);
$variable = trim($variable);
$command = "SET VARIABLE $variable \"$value\"";
$res = execute_agi($command);
return 0;
}
function getMacAddress($ipaddress) {
$outArray = array();
$out = exec("/usr/sbin/arping -f $ipaddress", $outArray);
$outArray = explode('[',$outArray[1]);
$outArray = explode(']',$outArray[1]);
$out = str_replace(':','',$outArray[0]);
return $out;
}
function getIpAddress() {
$outArray = array();
$host = exec("/sbin/ifconfig eth0 | grep inet | awk {'print $2'} | sed 's/addr://'", $outArray);
return $outArray[0];
}
function getSipConfExtensionData($filePath, $extension, $asteriskRealtimeOnOff=false){
if($asteriskRealtimeOnOff){
$qry = "SELECT * FROM sip_buddies WHERE name = '".$extension."'";
$res = mysql_query($qry);
$dataArray = mysql_fetch_assoc($res);
} else {
$dataString = file_get_contents('/etc/asterisk/sip.conf');
$dataArray = explode("\n",$dataString);
$i = 0;
while($i &lt; count($dataArray) &amp;&amp; strpos($dataArray[$i],"[$extension]") !== 0) {
$i++;
}
$i++;
$sipValuesArray = array();
while(strpos($dataArray[$i],"[")!== 0 &amp;&amp; $i &lt; count($dataArray)) {
if($dataArray[$i] != "") {
$sipValue = explode('=',$dataArray[$i]);
$sipValuesArray[$sipValue[0]]=$sipValue[1];
}
$i++;
}
return $sipValuesArray;
}
}
function getVoicemailPasswd ($extension) {
$dataString = file_get_contents('/etc/asterisk/voicemail.conf');
$dataArray = explode("\n",$dataString);
$passwd = "";
foreach($dataArray as $exten =&gt; $data) {
if(strpos($data, $extension) === 0) {
$data = trim($data);
$dataArray = explode("=&gt;",$data);
$dataArray = explode(",",$dataArray[1]);
$passwd = trim($dataArray[0]);
break;
}
}
return $passwd;
}
function createCiscoCfg($host, $mac, $extension, $secret, $display) {
$ciscoTeamplate = file_get_contents('/tftpboot/SPAtemplate.cfg');
$ciscoTeamplate = str_replace('AST_DISPLAY_NAME', $display, $ciscoTeamplate);
$ciscoTeamplate = str_replace('AST_EXTENSION_NUMBER', $extension, $ciscoTeamplate);
$ciscoTeamplate = str_replace('AST_SECRET', $secret, $ciscoTeamplate);
$ciscoTeamplate = str_replace('AST_IP_ADDRESS', $host, $ciscoTeamplate);
$fileName = "/tftpboot/spa$mac.cfg";
if(file_exists($fileName)) {
unlink($fileName);
}
$fp = fopen($fileName, 'w+');
fwrite($fp, $ciscoTeamplate);
fclose($fp);
}
if ($argc == 5) {
$ipaddress = $argv[1];
$extension = $argv[2];
$inputPasswd = $argv[3];
$mode = $argv[4];
$mac = getMacAddress($ipaddress);
$mac = str_replace(':','',$mac);
$host = getIpAddress();
if( $mode == "logoff") {
createCiscoCfg($host, $mac, $extension, $inputPasswd , "Logged off");
} else {
$sipValuesArray = getSipConfExtensionData("/etc/asterisk/sip.conf", $extension);
$secret = $sipValuesArray['secret'];
$separatorPos = strpos( $sipValuesArray['callerid'], "&lt;");
if ($separatorPos !== false) {
$displayName = substr($sipValuesArray['callerid'],0,$separatorPos);
} else {
$displayName = $sipValuesArray['callerid'];
}
$passwd = getVoicemailPasswd ($extension);
if($inputPasswd != $passwd) {
setDialplanVar("cisco_validation_passwd", "no");
exit;
} else {
setDialplanVar("cisco_validation_passwd", "yes");
}
createCiscoCfg($host, $mac, $extension, $secret, $displayName);
}
$void = file_get_contents("http://$ipaddress/admin/resync?tftp://$host/spa$mac.cfg");
}
?&gt;

Template

The template file for spaxxxx.cfg has to be located in /tftpboot/SPAtemplate.cfg and there are some constants that don’t have to be modified, these are:

  • AST_DISPLAY_NAME
  • AST_EXTENSION_NUMBER
  • AST_SECRET
  • AST_IP_ADDRESS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<flat-profile>
<Line_Enable_1_ group="Ext_1/General">Yes</Line_Enable_1_>
<Share_Ext_1_ group="Ext_1/Share_Line_Appearance">private</Share_Ext_1_>
<Shared_User_ID_1_ group="Ext_1/Share_Line_Appearance"/>
<Subscription_Expires_1_ group="Ext_1/Share_Line_Appearance">3600</Subscription_Expires_1_>
<Monitor_User_ID_1_ group="Ext_1/Share_Line_Appearance"/>
<NAT_Mapping_Enable_1_ group="Ext_1/NAT_Settings">No</NAT_Mapping_Enable_1_>
<NAT_Keep_Alive_Enable_1_ group="Ext_1/NAT_Settings">No</NAT_Keep_Alive_Enable_1_>
<NAT_Keep_Alive_Msg_1_ group="Ext_1/NAT_Settings">$NOTIFY</NAT_Keep_Alive_Msg_1_>
<NAT_Keep_Alive_Dest_1_ group="Ext_1/NAT_Settings">$PROXY</NAT_Keep_Alive_Dest_1_>
<SIP_TOS_DiffServ_Value_1_ group="Ext_1/Network_Settings">0x68</SIP_TOS_DiffServ_Value_1_>
<SIP_CoS_Value_1_ group="Ext_1/Network_Settings">3</SIP_CoS_Value_1_>
<RTP_TOS_DiffServ_Value_1_ group="Ext_1/Network_Settings">0xb8</RTP_TOS_DiffServ_Value_1_>
<RTP_CoS_Value_1_ group="Ext_1/Network_Settings">6</RTP_CoS_Value_1_>
<Network_Jitter_Level_1_ group="Ext_1/Network_Settings">high</Network_Jitter_Level_1_>
<Jitter_Buffer_Adjustment_1_ group="Ext_1/Network_Settings">up and down</Jitter_Buffer_Adjustment_1_>
<SIP_Transport_1_ group="Ext_1/SIP_Settings">UDP</SIP_Transport_1_>
<SIP_Port_1_ group="Ext_1/SIP_Settings">5060</SIP_Port_1_>
<SIP_100REL_Enable_1_ group="Ext_1/SIP_Settings">No</SIP_100REL_Enable_1_>
<EXT_SIP_Port_1_ group="Ext_1/SIP_Settings"/>
<Auth_Resync-Reboot_1_ group="Ext_1/SIP_Settings">Yes</Auth_Resync-Reboot_1_>
<SIP_Proxy-Require_1_ group="Ext_1/SIP_Settings"/>
<SIP_Remote-Party-ID_1_ group="Ext_1/SIP_Settings">No</SIP_Remote-Party-ID_1_>
<Referor_Bye_Delay_1_ group="Ext_1/SIP_Settings">4</Referor_Bye_Delay_1_>
<Refer-To_Target_Contact_1_ group="Ext_1/SIP_Settings">No</Refer-To_Target_Contact_1_>
<Referee_Bye_Delay_1_ group="Ext_1/SIP_Settings">0</Referee_Bye_Delay_1_>
<SIP_Debug_Option_1_ group="Ext_1/SIP_Settings">none</SIP_Debug_Option_1_>
<Refer_Target_Bye_Delay_1_ group="Ext_1/SIP_Settings">0</Refer_Target_Bye_Delay_1_>
<Sticky_183_1_ group="Ext_1/SIP_Settings">No</Sticky_183_1_>
<Auth_INVITE_1_ group="Ext_1/SIP_Settings">No</Auth_INVITE_1_>
<Ntfy_Refer_On_1xx-To-Inv_1_ group="Ext_1/SIP_Settings">Yes</Ntfy_Refer_On_1xx-To-Inv_1_>
<Use_Anonymous_With_RPID_1_ group="Ext_1/SIP_Settings">Yes</Use_Anonymous_With_RPID_1_>
<Set_G729_annexb_1_ group="Ext_1/SIP_Settings">none</Set_G729_annexb_1_>
<Blind_Attn-Xfer_Enable_1_ group="Ext_1/Call_Feature_Settings">No</Blind_Attn-Xfer_Enable_1_>
<MOH_Server_1_ group="Ext_1/Call_Feature_Settings"/>
<Message_Waiting_1_ group="Ext_1/Call_Feature_Settings">No</Message_Waiting_1_>
<Auth_Page_1_ group="Ext_1/Call_Feature_Settings">No</Auth_Page_1_>
<Default_Ring__1__ group="Ext_1/Call_Feature_Settings">1</Default_Ring__1__>
<Auth_Page_Realm_1_ group="Ext_1/Call_Feature_Settings"/>
<Conference_Bridge_URL_1_ group="Ext_1/Call_Feature_Settings"/>
<Auth_Page_Password_1_ group="Ext_1/Call_Feature_Settings"/>
<Mailbox_ID_1_ group="Ext_1/Call_Feature_Settings"/>
<Voice_Mail_Server_1_ group="Ext_1/Call_Feature_Settings"/>
<State_Agent_1_ group="Ext_1/Call_Feature_Settings"/>
<CFWD_Notify_Serv_1_ group="Ext_1/Call_Feature_Settings">No</CFWD_Notify_Serv_1_>
<CFWD_Notifier_1_ group="Ext_1/Call_Feature_Settings"/>
<Proxy_1_ group="Ext_1/Proxy_and_Registration">AST_IP_ADDRESS</Proxy_1_>
<Outbound_Proxy_1_ group="Ext_1/Proxy_and_Registration"/>
<Use_Outbound_Proxy_1_ group="Ext_1/Proxy_and_Registration">No</Use_Outbound_Proxy_1_>
<Use_OB_Proxy_In_Dialog_1_ group="Ext_1/Proxy_and_Registration">Yes</Use_OB_Proxy_In_Dialog_1_>
<Register_1_ group="Ext_1/Proxy_and_Registration">Yes</Register_1_>
<Make_Call_Without_Reg_1_ group="Ext_1/Proxy_and_Registration">Yes</Make_Call_Without_Reg_1_>
<Register_Expires_1_ group="Ext_1/Proxy_and_Registration">3600</Register_Expires_1_>
<Ans_Call_Without_Reg_1_ group="Ext_1/Proxy_and_Registration">Yes</Ans_Call_Without_Reg_1_>
<Use_DNS_SRV_1_ group="Ext_1/Proxy_and_Registration">No</Use_DNS_SRV_1_>
<DNS_SRV_Auto_Prefix_1_ group="Ext_1/Proxy_and_Registration">No</DNS_SRV_Auto_Prefix_1_>
<Proxy_Fallback_Intvl_1_ group="Ext_1/Proxy_and_Registration">3600</Proxy_Fallback_Intvl_1_>
<Proxy_Redundancy_Method_1_ group="Ext_1/Proxy_and_Registration">Normal</Proxy_Redundancy_Method_1_>
<Display_Name_1_ group="Ext_1/Subscriber_Information">AST_DISPLAY_NAME</Display_Name_1_>
<User_ID_1_ group="Ext_1/Subscriber_Information">AST_EXTENSION_NUMBER</User_ID_1_>
<Password_1_ group="Ext_1/Subscriber_Information">AST_SECRET</Password_1_>
<Use_Auth_ID_1_ group="Ext_1/Subscriber_Information">No</Use_Auth_ID_1_>
<Auth_ID_1_ group="Ext_1/Subscriber_Information"/>
<Mini_Certificate_1_ group="Ext_1/Subscriber_Information"/>
<SRTP_Private_Key_1_ group="Ext_1/Subscriber_Information"/>
<Preferred_Codec_1_ group="Ext_1/Audio_Configuration">G711u</Preferred_Codec_1_>
<Use_Pref_Codec_Only_1_ group="Ext_1/Audio_Configuration">No</Use_Pref_Codec_Only_1_>
<Second_Preferred_Codec_1_ group="Ext_1/Audio_Configuration">Unspecified</Second_Preferred_Codec_1_>
<Third_Preferred_Codec_1_ group="Ext_1/Audio_Configuration">Unspecified</Third_Preferred_Codec_1_>
<G729a_Enable_1_ group="Ext_1/Audio_Configuration">Yes</G729a_Enable_1_>
<G722_Enable_1_ group="Ext_1/Audio_Configuration">Yes</G722_Enable_1_>
<G726-16_Enable_1_ group="Ext_1/Audio_Configuration">Yes</G726-16_Enable_1_>
<G726-24_Enable_1_ group="Ext_1/Audio_Configuration">Yes</G726-24_Enable_1_>
<G726-32_Enable_1_ group="Ext_1/Audio_Configuration">Yes</G726-32_Enable_1_>
<G726-40_Enable_1_ group="Ext_1/Audio_Configuration">Yes</G726-40_Enable_1_>
<Release_Unused_Codec_1_ group="Ext_1/Audio_Configuration">Yes</Release_Unused_Codec_1_>
<DTMF_Process_AVT_1_ group="Ext_1/Audio_Configuration">Yes</DTMF_Process_AVT_1_>
<Silence_Supp_Enable_1_ group="Ext_1/Audio_Configuration">No</Silence_Supp_Enable_1_>
<DTMF_Tx_Method_1_ group="Ext_1/Audio_Configuration">Auto</DTMF_Tx_Method_1_>
<DTMF_Tx_Volume_for_AVT_Packet_1_ group="Ext_1/Audio_Configuration">0</DTMF_Tx_Volume_for_AVT_Packet_1_>
<Dial_Plan_1_ group="Ext_1/Dial_Plan">
(*xx|[3469]11|0|00|[2-9]xxxxxx|1xxx[2-9]xxxxxxS0|xxxxxxxxxxxx.)
</Dial_Plan_1_>
<Caller_ID_Map_1_ group="Ext_1/Dial_Plan"/>
<Enable_IP_Dialing_1_ group="Ext_1/Dial_Plan">Yes</Enable_IP_Dialing_1_>
<Emergency_Number_1_ group="Ext_1/Dial_Plan"/>
</flat-profile>
<Mailbox_ID_1_ group="Ext_1/Call_Feature_Settings">3600</Mailbox_ID_1_>
<Message_Waiting_1_ group="Ext_1/Call_Feature_Settings">Yes</Message_Waiting_1_>
<LDAP_Dir_Enable group="Phone/LDAP_Corporate_Directory_Search">Yes</LDAP_Dir_Enable>
<LDAP_Corp_Dir_Name group="Phone/LDAP_Corporate_Directory_Search"/>
<LDAP_Server group="Phone/LDAP_Corporate_Directory_Search"/>
<LDAP_Auth_Method group="Phone/LDAP_Corporate_Directory_Search">None</LDAP_Auth_Method>
<LDAP_Client_DN group="Phone/LDAP_Corporate_Directory_Search"/>
<LDAP_Username group="Phone/LDAP_Corporate_Directory_Search"/>
<LDAP_Password group="Phone/LDAP_Corporate_Directory_Search"/>
<LDAP_Search_Base group="Phone/LDAP_Corporate_Directory_Search"/>
<LDAP_Last_Name_Filter group="Phone/LDAP_Corporate_Directory_Search"/>
<LDAP_First_Name_Filter group="Phone/LDAP_Corporate_Directory_Search"/>
<LDAP_Search_Item_3 group="Phone/LDAP_Corporate_Directory_Search"/>
<LDAP_Item_3_Filter group="Phone/LDAP_Corporate_Directory_Search"/>
<LDAP_Search_Item_4 group="Phone/LDAP_Corporate_Directory_Search"/>
<LDAP_item_4_Filter group="Phone/LDAP_Corporate_Directory_Search"/>
<LDAP_Display_Attrs group="Phone/LDAP_Corporate_Directory_Search"/>
<LDAP_Number_Mapping group="Phone/LDAP_Corporate_Directory_Search"/>
<XML_Directory_Service_Name group="Phone/XML_Service"/>
<XML_Directory_Service_URL group="Phone/XML_Service"/>
<XML_Application_Service_Name group="Phone/XML_Service"/>
<XML_Application_Service_URL group="Phone/XML_Service"/>
<Text_Logo group="Phone/General"/>
<BMP_Picture_Download_URL group="Phone/General"/>
<Select_Logo group="Phone/General">Default</Select_Logo>
<Select_Background_Picture group="Phone/General">BMP Picture</Select_Background_Picture>
<Softkey_Labels_Font group="Phone/General">Auto</Softkey_Labels_Font>
<Screen_Saver_Enable group="Phone/General">Yes</Screen_Saver_Enable>
<Screen_Saver_Wait group="Phone/General">300</Screen_Saver_Wait>
<Screen_Saver_Icon group="Phone/General">Background Picture</Screen_Saver_Icon>
<Primary_NTP_Server group="System/Optional_Network_Configuration">ntp.nasa.gov</Primary_NTP_Server>
<Resync_On_Reset group="Provisioning/Configuration_Profile">Yes</Resync_On_Reset>
<Resync_Random_Delay group="Provisioning/Configuration_Profile">2</Resync_Random_Delay>
<Resync_Periodic group="Provisioning/Configuration_Profile">86400</Resync_Periodic>
<Resync_Error_Retry_Delay group="Provisioning/Configuration_Profile">3600</Resync_Error_Retry_Delay>
<Forced_Resync_Delay group="Provisioning/Configuration_Profile">14400</Forced_Resync_Delay>
<Resync_From_SIP group="Provisioning/Configuration_Profile">Yes</Resync_From_SIP>
<Resync_After_Upgrade_Attempt group="Provisioning/Configuration_Profile">Yes</Resync_After_Upgrade_Attempt>
<Resync_Trigger_1 group="Provisioning/Configuration_Profile"/>
<Resync_Trigger_2 group="Provisioning/Configuration_Profile"/>
<Resync_Fails_On_FNF group="Provisioning/Configuration_Profile">Yes</Resync_Fails_On_FNF>

Posted in Scripts | Tagged , , | Leave a comment

Audicodes MP1XX FXS Configuration for Asterisk

This will be the last in the AudioCodes setup series. A quick and dirty configuration for a vanilla Asterisk setup. AudioCodes uses the network address 10.1.10.10 for FXS and 10.1.10.11 for FXO gateways. Setup your network accordingly to access the default address.

Asterisk Setup:
The Asterisk setup is easy. Just create standard type=friend extensions for as many phone extensions as you would like to create in sip.conf. A typical basic entry would look like below.

1
2
3
4
5
6
7
8
9
10
[1001]
type=friend
context=local ; Context for incoming calls for this user
host=dynamic ; This peer register with us
dtmfmode=inband ; Choices are inband, rfc2833, or info
username=1001
secret=1234
disallow=all
allow=ulaw ; dtmfmode=inband only works with ulaw or alaw!
;progressinband=no ; Polycom phones dont work properly with never

Audiocodes Setup:
Connect the gateway to a network switch and connect a computer to the same switch. Then configure the IP address of the computer to 10.1.10.XXX (anything but 10 or 11). Then run your web browser and point it to http://10.1.10.10 and login using

1
2
3
Default IP address: 10.1.10.10
Default username: Admin
Default password: Admin

Click -> “Quick Setup” and change the following:

1
2
3
4
5
6
IP Address => IP address of the AudioCodes 124
Subnet Mask => Set to the correct netmask for your local network
Default Gateway Address => Gateway IP address for your LAN
Working With Proxy => Yes
Proxy IP Address => IP address of the Asterisk server
Enable Registration => Set to Enable

Restart the gateway and log back in using the new IP address:

1
2
3
4
5
Protocol Management -> Protocol Definition -> Proxy & Registration
Registrar IP Address => Set to the IP address of the Asterisk server
Registration Time => 60
Subscription Mode => Per Endpoint
Authentication Mode => Per Endpoint

Go to Protocol Management -> Protocol Definition -> DTMF & Dialing
Max Digits In Phone Num -> Make it a large number like 32 digits

Go to Protocol Management -> Protocol Definition -> Coders
Add coders as needed You need to set at least G.711U-law

Go to Protocol Management -> Endpoint Settings -> Authentication
Set SIP username and password for each port to match your settings in sip.conf

Go to Protocol Management -> Endpoint Phone Numbers
Enter an extension (phone) number for every used channel to match entries in sip.conf

AudioCodes FXS gateway is ready. Worked here YMMV.

Posted in Configuration | Tagged , , | Leave a comment

Asterisk AGI get voicemail user email

Goal

To look for a user’s email address in the voicemail.conf file.

Usage

  • look for user 1234 and return email address to dialplan variable called vmuserEmail
  • NoOp the noopMessage created by the AGI

1
2
3
exten => 1921,n,AGI(getVMUserData|1234|vmuserEmail)
exten => 1921,n,NoOp(Resulting message for AGI ${noopMessage})
exten => 1921,n...

User and email found

1
2
3
[root@dev-pbx agi-bin]# php -f getVMUserData 6906 extEmailAddress
\SET VARIABLE noopMessage Voicemail_User_6906_FOUND_in_voicemail.conf "*#"
\SET VARIABLE extEmailAddress john.doe@eusnetworks.com "*#"

User found, but not email

1
2
3
[root@dev-pbx agi-bin]# php -f getVMUserData 9004 extEmailAddress
\SET VARIABLE noopMessage Warning-NO_EMAIL_ADDRESS_FOUND_for_Voicemail_User_9004_in_voicemail.conf "*#"
\SET VARIABLE extEmailAddress ERROR "*#"

User was not found

1
2
3
[root@dev-pbx agi-bin]# php -f getVMUserData 9988763 extEmailAddress
\SET VARIABLE noopMessage Warning-Voicemail_User_9988763_NOT_FOUND_in_voicemail.conf "*#"
\SET VARIABLE extEmailAddress ERROR "*#"

Script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#!/usr/bin/php -q
&lt;?php
/**
* Look for voicemail user in voicemail.comf and return its email address to the specified diaplan VARIABLE
* It also returns a message to the ${noopMessage} VARIABLE
*
* Possible results to the specified diaplan VARIABLE are:
* variable = ERROR and noopMessage = VMUser NOT FOUND
* variable = ERROR and noopMessage = NO EMAIL
* variable = email@address
*
* @param int $VMUser -> The voicemail user
* @param string $DPReturnVarName -> The name of the diaplan VARIABLE to return the email to
*
* EXAMPLE
*
* exten => 1921,n,AGI(getVMUserData|1234|vmuserEmail)
* exten => 1921,n,NoOp(Resulting message for AGI ${noopMessage})
* exten => 1921,n...
*
*
*/
/**
* Parse voicemail.conf file looking for a user
* Then return its email address
*
* @param int $VMUser
* @return string
*/
function lookForVMEmail($VMUser, $voicemailconf){
    $dataFound = array();
    $status = "VMUser NOT FOUND";
    $nomoreloop = false;
    
    $fileArray = file($voicemailconf);
    foreach ($fileArray as $line){
        //leave commented lines out
        if( strpos(trim($line), ';') !== 0 && !$nomoreloop ){
                        $findme = '=>';
                        $pos = strpos($line, $findme);
                        // Note our use of ===. Simply == would not work as expected
                        if ($pos !== false) {
                            /*
                            1104 => 7906,Jane Doe,,tz=eastern|attach=yes|saycid=no|review=yes|operator=yes|envelope=no|sayduration=no|
                            1234 => 1234,Some User,email@address.com,pager@address.com,saycid=yes|dialout=fromvm|callback=fromvm|review=yes|operator=yes
                            */
                            $elements = explode('=>', $line);
                            if(trim($elements[0]) == trim($VMUser)){
                                $nomoreloop = true;
                                $status = "NO EMAIL";
                                $elements2 = explode(',',$elements[1]);
                                
                                if(trim($elements2[2]) != ''){
                                    // DATA FOUND
                                    $status = trim($elements2[2]);
                                }
                            }
                        }
        }
    }
    return $status;
}
/* Parameters */
$VMUser = $argv[1];
$DPReturnVarName = $argv[2];
$foundEmail = '';
$voicemailconf = "/etc/asterisk/voicemail.conf";
/* Parse voicemail.conf and find data */
if(trim($DPReturnVarName) != '' && trim($VMUser) != ''){
    //both parametes ok
    //lets look for the user
    
    $foundEmail = lookForVMEmail($VMUser, $voicemailconf);
    switch ($foundEmail){
        
        case 'VMUser NOT FOUND':
            echo "\SET VARIABLE noopMessage Warning-Voicemail_User_". $VMUser ."_NOT_FOUND_in_voicemail.conf \"*#\"\n";
            echo "\SET VARIABLE $DPReturnVarName ERROR \"*#\"\n";
        break;
        
        case 'NO EMAIL':
            echo "\SET VARIABLE noopMessage Warning-NO_EMAIL_ADDRESS_FOUND_for_Voicemail_User_". $VMUser ."_in_voicemail.conf \"*#\"\n";
            echo "\SET VARIABLE $DPReturnVarName ERROR \"*#\"\n";
        break;
        
        default:
            /* Return required data to dialplan */
            echo "\SET VARIABLE noopMessage Voicemail_User_". $VMUser ."_FOUND_in_voicemail.conf \"*#\"\n";
            echo "\SET VARIABLE $DPReturnVarName " . $foundEmail . " \"*#\"\n";
        break;
    } //end Switch
  
    
} else {
    //missing parameter
    echo "\SET VARIABLE noopMessage Error-Missing_parameters-param1_is_".$VMUser."_param2_is_".$DPReturnVarName." \"*#\"\n";
}
?>

Posted in Scripts | Tagged , , | Leave a comment

Aastra Night mode Php Script – nightmode.php

The Day/Night mode feature is very straighforward to setup if you are using any of the Aastra phones with the XML capable mini-browser, such as the 57i. As a matter of fact, most Aastras do support it now, the only practical limit is the size of the display for each model.

The goal is to turn the PBX night mode service on and off by hiting a key in an Aastra phone.
This is achieved by having the XML library change the value of a specific Asterisk global variable wich holds the daynight-mode status.

This way, an operator or the last to leave the office, can turn the PBX night-mode on easily.

That being said, the requirements here are:
- XML capable Aastra phone.
- Aastra XML – API library. (download from the Aastra site)
- This script
- A web server to place the script (usually runing in the same box as the Asterisk system)
- Asterisk system with a variable called NIGHT to decide how calls are routed.

Through the web interface of the aastra phone, the button to configure must have the url of the web address where this script was deployed.
Eg: http://myweb-place/aastra_nightmode.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
&lt;?php
#############################################################################
# PHP customization for includes and warnings
#############################################################################
$os = strtolower(PHP_OS);
if(strpos($os, "win") === false) ini_set('include_path',ini_get('include_path').':include:../include');
else ini_set('include_path',ini_get('include_path').';include;..\include');
error_reporting(E_ERROR | E_PARSE);
#############################################################################
# Includes
#############################################################################
require_once('AastraCommon.php');
require_once('AastraAsterisk.php');
require_once('AastraIPPhoneTextScreen.class.php');
require_once('AastraIPPhoneFormattedTextScreen.class.php');
require_once('AastraIPPhoneExecute.class.php');
require_once('AastraIPPhoneStatus.class.php');
# Aastra_night_mode(action)
#
# Parameters
#
# action 'change'
#
# Returns current Night Mode status value (0 or 1 ) 0:off , 1:on
#
#####################################################################
function Aastra_manage_night_mode($action)
{
# Connect to AGI
$as = new AGI_AsteriskManager();
$res = $as-&gt;connect();
$night=0;
# Night mode GET
$res = $as-&gt;GetVar(NULL, 'NIGHT');
if($res['Value']=="ON") $night=1;
if($res['Value']=="OFF") $night=0;
# Change current value
if($action=='change') {
# change DND status
if($night==0) {
$res = $as-&gt;SetVar(NULL, 'NIGHT', 'ON');
$night=1;
}
else {
$res = $as-&gt;SetVar(NULL, 'NIGHT', 'OFF');
$night=0;
}
}
# Disconnect properly
$as-&gt;disconnect();
# Return current value
return($night);
}
####################################################################
# Main code
####################################################################
# Global parameters
$Server = "http://".$_SERVER['SERVER_ADDR'].$_SERVER['SCRIPT_NAME'];
# Retrieve parameters
//$user=$_GET['user'];
$action=$_GET['action'];
$status=$_GET['status'];
$key=$_GET['key'];
# Force default action
if($action=="") $action="change";
# Get header info
$header=Aastra_decode_HTTP_header();
# Setup header type
header("Content-Type: text/xml");
# Depending on action
switch($action)
{
case 'display':
$output = "\n";
if ($status==1) {
$output .= "Night Mode\n";
$output .= "Activated\n";
}
else {
$output .= "Night Mode\n";
$output .= "Deactivated\n";
}
$output .= "\n";
break;
case 'msg':
$output = "\n";
$output .= "NMODE\n";
if ($status==1) $output .= "NM activated\n";
else $output .= "\n";
$output .= "\n";
break;
case 'change':
$night_mode=Aastra_manage_night_mode($action);
$output = "\n";
$output .= "\n";
if($key!='') {
if ($night_mode==1) $output .= "\n";
else $output .= "\n";
}
$output .= "\n";
break;
}
# Display XML object
header("Content-Length: ".strlen($output));
echo $output;
?&gt;

Posted in Scripts | Tagged , , , | 3 Comments

Asterisk AGI Get User Data

Goal

To retrieve data from the Asterisk mysql database and return it to the dialplan.

Usage

Variables to pass on:

  • table name
  • field to lookup
  • value to lookup
  • field to be returned

”’userDataIs”’ is the name of the variable being returned to the dialplan.

1
2
3
exten =&gt; 1990,n,AGI(getUserData.php,TABLENAME,FIELDTODOLOOKUP,VALUETODOLOOKUP,
FIELDTORETURN)
exten =&gt; 1990,n,NoOp(${userDataIs})

Example: Get the email of a voicemail user

  • Get the email address (”’email”’)
  • from the ”’voicemail_users”’ table
  • where the ”’mailbox”’ field has the ”’1101”’ value on it.

1
2
3
4
5
exten =&gt; 1990,Answer()
exten =&gt; 1990,Wait(1)
exten =&gt; 1990,n,AGI(getUserData.php,voicemail_users,mailbox,1101,email)
exten =&gt; 1990,n,NoOp(XXXXXXXXXXXXXXXXXXXXXXXXXXX)
exten =&gt; 1990,n,NoOp(${userDataIs})

Code
1
2
#!/usr/bin/php -q
<!--?php //Get Table,field to lookup, value to lookup and field to return to dialplan $dbtable = $argv[1]; $lookupField = $argv[2]; $lookupValue = $argv[3]; $returnField = $argv[4]; //Connect and Query mysql DB mysql_connect("localhost", "root", "xerxes") or die(mysql_error()); mysql_select_db("asterisk") or die(mysql_error()); $query = "SELECT * FROM $dbtable WHERE $lookupField = '".$lookupValue."'"; $result = mysql_query($query) or die(mysql_error()); $row = mysql_fetch_array( $result ); $returnValue = $row[$returnField]; //Send back to Dialplan echo "\SET VARIABLE userDataIs " . $returnValue . " \"*#\"\n"; ?-->

Posted in Scripts | Tagged , , , | Leave a comment