Jump to content

Using X-Lite Softphone with Kazoo


Recommended Posts

I need some advice on static caller ID, please!

We have created callflows for *24 and *25 that use:

URL = http://pivot.server.center/pivot/callerID.php

Method =  POST

Format = Kazoo

Using an X-Lite softphone from a number (extension, actually) that we control, I'm testing the Pivot script.

In the PHP script, the key/value pairs in the $_POST array are converted to local variables.  Like this:

foreach ($_POST as $key=>$value) {
  $$key = $value;
  $post .= "$key = $value\n";
}

When this will be static caller ID, I put the "number to spoof" into a local variable:

$CIDtoSpoof = "2025556969"; // Not the real number we'll be using.

Then:

$pieces = preg_split("\*", $To);

// This expects to get *25*OUTBOUNDNUMBER or in $To from the POST data when using static called ID

// It expects to get  *24*NUMBERTOSPOOF*OUTBOUNDNUMBER in $To when using dynamic caller ID

// Now the "*"s are gone...
if($pieces[0] == "25") {
      // Static CID spoofing
      $NumToCall = $pieces[1];
}
elseif ($pieces[0] == "24") {  // This expects to get *25*OUTBOUNDNUMBER in $To from the POST data
    // Dynamic CID spoofing
    $CIDtoSpoof = $pieces[1];
    $NumToCall = $pieces[2];
}

 

As I understand it, the PHP script should strip off the "*25" and save the outbound number to send back to Kazoo, so I have a local variable, $NumToCall to hold the outbound number.

From what I've read, we should send this JSON back to Kazoo:

$JSON_DATA = '{
  "children": {
    "_": {
      "data": {
        "to_did": "+1$NumToCall",
        "use_local_resources": false
      },
      "module": "resources"
    }
  },
  "data": {
    "caller_id_number": "+1$CIDtoSpoof"
  },
  "module": "set_cid"
}';

As a test, I've used: 

echo("$post");

to send all the POSTed data back to Kazoo so I could be sure that something was being sent back. 

First problem: I can type *25 into the X-Lite softphone, hit the dial button and then check the Live Debug in Kazoo. So far, so good. The data doesn't include an outbound phone number in the "To:" field; it only has "To: *25". But at least all the stuff sent to Kazoo is caught.

But if I send *25*2125553333 or *252125553333, I get absolutely nothing in the Body field of Live Debug's Response pane. It seems that no data that the script wants to send is being received.  

In both cases, I get the error message "Failed to establish call - busy" in the softphone. I don't expect it to establish a call with the outbound number but when I sent *25 followed by *OUTBOUNDNUMBER or just OUTBOUNDNUMBER, it seems like it shuts down and doesn't "hear" the response from the script. 

Second problem: I'm not quite sure how to make the script send its payload back to Pivot/Kazoo. Will echo("$JSON_DATA") work? Or must I use cURL?

Any help getting this moving forward would be greatly appreciated.

Thanks,

Steve


 

 

 

 

Link to comment
Share on other sites

  • 2600Hz Employees

Hi @Andres Gomez!

So a couple things:

1. How is your callflow for *25 configured? Did you set that in "patterns" with a regex to match? Or "numbers":["*25"]? If "numbers", that will only match the explicit *25. If patterns, make sure the regex used will match what you're dialing.

2. To return JSON from php, typically you set the header('content-type', 'application/json') and echo the JSON. Some basic PHP scripts exist that may help.

Link to comment
Share on other sites

Hello,

I am doing this using Pivot and X-Lite.  Grab your apache logs to see the exact URI getting sent to your PHP file and use it to test the pivot script in a browser.  It should return JSON.  In this pivot $callerid gets set based on the dialed numbers area code.  I replaced my numbers with +15555555555.

Setup a call flow using the API that uses a pattern.  I think in my call flow I am just matching * + 11 digits.

<?php
	
    function left($str, $length) {
        return substr($str, 0, $length);
    }

    function right($str, $length) {
        return substr($str, -$length);
    }
    
    //enable logging
    $logging = false;
    
    
    
    if ($logging) {

        $req_dump = print_r($_REQUEST, TRUE);
      
        $fp = fopen('dynamic_set_cid.log', 'a');
        fwrite($fp, $req_dump);
        
    }

    // set destination number to variable   
    $to = $_REQUEST['To'];
    
    //find area code, set to $areacode
    if (strlen($to) > 11) {
    
        $areacode = right(left($to,5),3);
        
        } else {
            
            $areacode = right(left($to,4),3);
        }
    
	if ($logging) {
        fwrite($fp, '$to = ' . $to."\r\n");
        fwrite($fp, '$areacode = ' . $areacode."\r\n");
    }
    
    //select outbound callerid based on area code
    switch ($areacode) {
        
    case "231":
        $callerid = "+15555555555";
        break;

    case "248":
        $callerid = "+15555555555";
        break;

    case "586":
        $callerid = "+15555555555";
        break;
        
    case "734":
        $callerid = "+15555555555";
        break;
        
    case "810":
        $callerid = "+15555555555";
        break;
	default:
		$callerid = "+15555555555";
		break;
    }
	  
    //remove * from destination number
    $dest_number = str_replace("*", "", $to);
    
    if ($logging) {
        fwrite($fp, '$dest_number = ' . $dest_number."\r\n");
        fwrite($fp, '$callerid = ' . $callerid."\r\n");
        fclose($fp);
    }
   	
    header('content-type: application/json'); 
?>
{
"children": {
"_": {
"data": {
"to_did": "<?php echo $dest_number ?>"
,"use_local_resources":false
},
"module": "resources"
}
},
"data": {
"caller_id_number": "<?php echo $callerid ?>"
},
"module": "set_cid"
}

 

 

Link to comment
Share on other sites

On 5/9/2018 at 2:22 AM, mc_ said:

Hi @Andres Gomez!

So a couple things:

1. How is your callflow for *25 configured? Did you set that in "patterns" with a regex to match? Or "numbers":["*25"]? If "numbers", that will only match the explicit *25. If patterns, make sure the regex used will match what you're dialing.

2. To return JSON from php, typically you set the header('content-type', 'application/json') and echo the JSON. Some basic PHP scripts exist that may help.

Hi mc_,

 

I used this example:

curl -X PUT http://ui.zswitch.net/v2/accounts/ACCOUNTID/callflows/ -H "Content-Type:application/json" -H "X-Auth-Token:AUTHTOKEN" -d '{"data":{"flow":{"data":{"method":"GET","req_timeout":"5","req_format":"kazoo","voice_url":"https://api.telkit.tk/scid/NUMBERTOSPOOF","debug":false},"module":"pivot","children":{}},"numbers":[],"patterns":["^\\*FEATURECODE"],"contact_list":{"exclude":true}}}'

to construct the API call to create the callflow...

Here's the JSON string I'm sending to https://{SERVER}/v2/accounts/ACCOUNTID/callflows/ --

$data_json = '{"data":{"flow":{"data":{"method":"GET","req_timeout":"5","req_format":"kazoo","voice_url":"https://{SERVER}/pivot/script.php","debug":false},"module":"pivot","children":{}},"numbers":[],"patterns":["^\\*25"],"contact_list":{"exclude":true}}}';

using cURL via PHP:

$token = authenticateUser();
$ch = curl_init($service_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-Auth-Token: $token", "Content-Type: application/json", "Content-Length: " . strlen($data_json)));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_json);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

to create that callflow for *25 (followed by the outbound number).

Yes, it could have been done by simply entering the cURL command in a terminal. But we wanted a general-purpose, re-usable, callflow script that could take different account IDs, etc. Fewer changes, fewer chances for error.

I'm getting this error when I run the script:

"json":{"invalid":{"message":"invalid_string around 213","target":"body"}}}

Character 213, according to my editor, is the first "\" in the patterns regex ->  "patterns":["^\\*25"]
Do you know why this regex would be rejected? 

I also tried this regex for patterns: "patterns":["^\\*25[0-9]{7,}"], to make sure it was matching *25 plus 7 or more digits.

(I'm not sure that's necessary, but I figured I'd try it. )

I removed the first "\" and it still failed - at character 213, the remaining "\".

Thanks in advance,
Steve (Andres is on vacation today)

Link to comment
Share on other sites

  • 2600Hz Employees

Hmm, not sure where the problem is.

$ curl -v -X PUT -H "X-Auth-Token: $AUTH_TOKEN" http://192.168.1.100:8000/v2/accounts/$ACCOUNT_ID/callflows -d '{"data":{"flow":{"data":{"method":"GET","req_timeout":"5","req_format":"kazoo","voice_url":"https://{SERVER}/pivot/script.php","debug":false},"module":"pivot","children":{}},"numbers":[],"patterns":["^\\*25"],"contact_list":{"exclude":true}}}'
*   Trying 192.168.1.100...
* TCP_NODELAY set
* Connected to 192.168.1.100 (192.168.1.100) port 8000 (#0)
> PUT /v2/accounts/36f9fc70e306b8900714bf284b863b94/callflows HTTP/1.1
> Host: 192.168.1.100:8000
> User-Agent: curl/7.58.0
> Accept: */*
> X-Auth-Token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImQ3OTNmNDA4NjdkMzFlM2JkNDFlZTU3NWYwYTk1MjAyIn0.eyJpc3MiOiJrYXpvbyIsImlkZW50aXR5X3NpZyI6IkZFTnkyQkd3dnNlQ1lxaUVwQXU0a3ZRdFNHREtnTVZIMmgtSjdqcHBORW8iLCJhY2NvdW50X2lkIjoiMzZmOWZjNzBlMzA2Yjg5MDA3MTRiZjI4NGI4NjNiOTQiLCJvd25lcl9pZCI6IjM1MzM4NmM5ZDdkNDg1ZTFkZjhmODRjZDk5NDI5ZWU1IiwibWV0aG9kIjoiY2JfdXNlcl9hdXRoIiwiZXhwIjoxNTI1OTgwNjQ4fQ.cIQMRemZCfwudU3Pm_h87wrAcLIs1tKiSpZ4nQ0a4_P3zJVAjkPD44Qep593uR3EJJCu4miI8tGqB1v6KD6LF_hYlAeb9aGIJDn_NQuwKz1_7VMrJVvPOOHZhlJF0rxNpnOXTsRlW6m51pZ7-o67DUu3KUIyUJ4TWkEnu-Unj-HADEb4BXe9La9A-QhIdakw6lCIpAITxMFFQDU-Elc9-9jIIVPTbGj5oae3U3T-AHYqRnlbczppodowT-V_FiyicDpKai-e2UPEWBV1eQkf0vI0dyAY9JGMtFbkk64ocuGOw96HjSyvhJDUMzNgdXPkEN6JA-6vPjVlH1ZG_eCM-g
> Content-Length: 242
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 242 out of 242 bytes
< HTTP/1.1 201 Created
< content-language: en
< content-length: 1250
< content-type: application/json
< date: Thu, 10 May 2018 18:31:56 GMT
< location: 2926f7a520b36cf337570146586aa06e
< server: Cowboy
< vary: accept-language, accept
< x-request-id: e12c81ce816e04c6d317548f33004605
< 
{"data":{"flow":{"data":{"method":"GET","req_timeout":"5","req_format":"kazoo","voice_url":"https://{SERVER}/pivot/script.php","debug":false,"req_body_format":"form"},"module":"pivot","children":{}},"numbers":[],"patterns":["^\\*25"],"contact_list":{"exclude":true},"id":"2926f7a520b36cf337570146586aa06e"},"revision":"1-986a627d1c305599b4f41e443002ee15","timestamp":"2018-05-10T18:31:56","version":"{VERSION}","node":"sA6dSvoWhUzdXcDMEReg2w","request_id":"e12c81ce816e04c6d317548f33004605","status":"success","auth_token":"{AUTH_TOKEN}"}

I would debug your PHP code as your JSON works fine for me using cURL.

If you are getting a response back from the server, use the request_id to grep the server logs and see what it says (in debug mode).

Link to comment
Share on other sites

Curiouser and curiouser. The PHP script is running on one of our servers. There are no errors, warnings or even notices generated there when I run the script.  I'll have to get access to the server logs on the host where Kazoo is running and see if there's anything in the logs of that server that could help. It may be something flaky or poorly defined over there.

Thanks,

Steve

Link to comment
Share on other sites

1 hour ago, mc_ said:

Hmm, not sure where the problem is.


$ curl -v -X PUT -H "X-Auth-Token: $AUTH_TOKEN" http://192.168.1.100:8000/v2/accounts/$ACCOUNT_ID/callflows -d '{"data":{"flow":{"data":{"method":"GET","req_timeout":"5","req_format":"kazoo","voice_url":"https://{SERVER}/pivot/script.php","debug":false},"module":"pivot","children":{}},"numbers":[],"patterns":["^\\*25"],"contact_list":{"exclude":true}}}'
*   Trying 192.168.1.100...
* TCP_NODELAY set
* Connected to 192.168.1.100 (192.168.1.100) port 8000 (#0)
> PUT /v2/accounts/36f9fc70e306b8900714bf284b863b94/callflows HTTP/1.1
> Host: 192.168.1.100:8000
> User-Agent: curl/7.58.0
> Accept: */*
> X-Auth-Token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImQ3OTNmNDA4NjdkMzFlM2JkNDFlZTU3NWYwYTk1MjAyIn0.eyJpc3MiOiJrYXpvbyIsImlkZW50aXR5X3NpZyI6IkZFTnkyQkd3dnNlQ1lxaUVwQXU0a3ZRdFNHREtnTVZIMmgtSjdqcHBORW8iLCJhY2NvdW50X2lkIjoiMzZmOWZjNzBlMzA2Yjg5MDA3MTRiZjI4NGI4NjNiOTQiLCJvd25lcl9pZCI6IjM1MzM4NmM5ZDdkNDg1ZTFkZjhmODRjZDk5NDI5ZWU1IiwibWV0aG9kIjoiY2JfdXNlcl9hdXRoIiwiZXhwIjoxNTI1OTgwNjQ4fQ.cIQMRemZCfwudU3Pm_h87wrAcLIs1tKiSpZ4nQ0a4_P3zJVAjkPD44Qep593uR3EJJCu4miI8tGqB1v6KD6LF_hYlAeb9aGIJDn_NQuwKz1_7VMrJVvPOOHZhlJF0rxNpnOXTsRlW6m51pZ7-o67DUu3KUIyUJ4TWkEnu-Unj-HADEb4BXe9La9A-QhIdakw6lCIpAITxMFFQDU-Elc9-9jIIVPTbGj5oae3U3T-AHYqRnlbczppodowT-V_FiyicDpKai-e2UPEWBV1eQkf0vI0dyAY9JGMtFbkk64ocuGOw96HjSyvhJDUMzNgdXPkEN6JA-6vPjVlH1ZG_eCM-g
> Content-Length: 242
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 242 out of 242 bytes
< HTTP/1.1 201 Created
< content-language: en
< content-length: 1250
< content-type: application/json
< date: Thu, 10 May 2018 18:31:56 GMT
< location: 2926f7a520b36cf337570146586aa06e
< server: Cowboy
< vary: accept-language, accept
< x-request-id: e12c81ce816e04c6d317548f33004605
< 
{"data":{"flow":{"data":{"method":"GET","req_timeout":"5","req_format":"kazoo","voice_url":"https://{SERVER}/pivot/script.php","debug":false,"req_body_format":"form"},"module":"pivot","children":{}},"numbers":[],"patterns":["^\\*25"],"contact_list":{"exclude":true},"id":"2926f7a520b36cf337570146586aa06e"},"revision":"1-986a627d1c305599b4f41e443002ee15","timestamp":"2018-05-10T18:31:56","version":"{VERSION}","node":"sA6dSvoWhUzdXcDMEReg2w","request_id":"e12c81ce816e04c6d317548f33004605","status":"success","auth_token":"{AUTH_TOKEN}"}

I would debug your PHP code as your JSON works fine for me using cURL.

If you are getting a response back from the server, use the request_id to grep the server logs and see what it says (in debug mode).

 

Here's the API response:

{"data":{"json":{"invalid":{"message":"invalid_string around 213","target":"body"}}},"error":"400","message":"validation error","status":"error","timestamp":"2018-05-10T19:49:12","version":"4.2.28","node":"J-InVzrRrnEpEMp0baYQ0Q","request_id":"6e9cafc7e370c28cb87d7d5e9a6ba31d","auth_token":"undefined"}
Service URL: https://KAZOO_SERVER/v2/accounts/ACCOUNT_ID/callflows/

This is followed by a listing of the existing callflows used by this account. a few more items and the auth_token and a }.

As far as I know, I don't have access to the server running Kazoo. 
 

 

Link to comment
Share on other sites

  • 2600Hz Employees

You'll probably want to capture the network traffic to see what PHP is putting on the wire to the server. Or see if the PHP cURL stuff can write verbose logs to a file or something. I copy/pasted your JSON to use for my cURL command locally and it processed fine. Let's see what your script is putting on the wire and maybe it will reveal why the JSON is corrupted when Kazoo receives it.

Link to comment
Share on other sites

  • 2 weeks later...

Hey guys,

I have it working now to a predefined dialed number like *252015555555. But When I go to callflows and change the extension number from  *252015555555 to a regex I am having a tough time getting kazoo to match *25 + 11 digit number and trigering the pivot. Do you know what the regex should look like in callflows for the extension field?

Link to comment
Share on other sites

The last time I was able to run the command to create the callflow using "patterns" : [ "^\\*25[0-9]*$"], the response said that a callflow using that pattern already existed:

Command:

 curl -v -X PUT -H "X-Auth-Token: {AUTH_TOKEN}" https://{SERVER}:8443/v2/accounts/47e2f51feb67e1d0303c5ba7cda5e123/callflows -d '{"data":{"flow":{"data":{"method":"GET","req_timeout":"5","req_format":"kazoo","voice_url":"https://{SERVER}:8443/path/to/script.php","debug":false},"module":"pivot","children":{}},"numbers":[],"patterns":["^\\*25([0-9]*)$"],"featurecode":{"name":"CallerID","number":"25"},"contact_list":{"exclude":true}}}' 

Response:

{"data":{"patterns":{"unique":{"message":"Pattern ^\\*25([0-9]*)$ exists in callflow 8a9175d8af5b696abba11ecfa917b45c 8a9175d8af5b696abba11ecfa917b45c","cause":"^\\*25([0-9]*)$"}}},"error":"400","message":"validation error","status":"error","timestamp":"2018-05-21T21:03:51","version":"4.2.28","node":"3A84g8C1-SlJxAeyNspJwQ","request_id":"{REQUEST_ID}","auth_token":"{AUTH_TOKEN}*

However, no such callflow exists (callflow id: 8a9175d8af5b696abba11ecfa917b45c, right?), according to the callflows list in the Callflows app. 

Edited by Andres Gomez (see edit history)
Link to comment
Share on other sites

 

Is it possible to create a pivot using the Pivot app, Numbers Routing screen to make the system respond to *25 followed by any number of digits?

If so, exactly what do we enter in the Number field of the "Create a new Pivot Callflow" form ?

We've spent far too much time trying to complete the seemingly simple task.

Background ---

This pivot would simply call a script. The script will check for anything that begins with *25 and removes the *25. What remains is the NumberToCall.

We have chosen a number to appear as the $CIDtoSpoof for any number that begins with *25.

Thus the script sends this:

 '{
  "children": {
    "_": {
      "data": {
        "to_did": "+1$NumToCall",
        "use_local_resources": false
      },
      "module": "resources"
    }
  },
  "data": {
    "caller_id_number": "+1$CIDtoSpoof"
  },
  "module": "set_cid"
}'

We know the script works as designed because we created a Pivot Action for *259194712386 (one specific phone number) and it worked perfectly.

 We used the curl command to create a callflow with the API and data including:

... "patterns":["^\\*25([0-9]*)$"],"featurecode":{"name":"CallerIDspoof","number":"25"}, ... and it simply doesn't work. [Note: There are other callflows using similar regex patterns that DO work...! ]

Not only does this not work, the callflow doesn't appear in the list of Callflows in the Callflows app.
Callflows created with the Pivot app, Numbers Routing, Create a new Pivot Action although it DOES appear in the response to this API call:

curl -v -X GET \

-H "X-Auth-Token: {AUTH_TOKEN}" \

http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows

Edited by Andres Gomez (see edit history)
Link to comment
Share on other sites

The body of your Curl should be something like the below. Try using Postman.

PUT http://{{API_VER}}/accounts/{{ACCOUNT_ID}}/callflows

{"data":{"flow":{"data":{"method":"GET","req_timeout":"5","req_format":"kazoo","voice_url":"https://pivot.yourdomain.com/path/","debug":false},
"module":"pivot",
"children":{}},
"numbers":[],
"patterns":["^\\*25"],
"contact_list":{"exclude":true}}}

Link to comment
Share on other sites

  • 2600Hz Employees

Callflows have two ways to determine if a call should be executed by a callflow:

1. The "numbers" array is a list of possible dialed numbers (or letters/unicode) that must match exactly. So "numbers":["2005","+12229992005","marvin"] would execute the callflow if any of those are dialed (after normalization).

2. The "patterns" array is a list of regexes that is used to match the dialed number.

"numbers" will be tried first followed by "patterns".

I don't know if the Advanced Callflows app exposes the ability to do patterns so you may have to use the API to do so.

 

Your pattern should work:

> re:run(<<"*259194712386">>, <<"^\\*25([0-9]*)$">>, [{capture, all_but_first, binary}]).                                                                                                
{match,[<<"9194712386">>]}

Put it in the "patterns" array and it should work fine. If not, please pull logs of the call attempt so we can look at what callflows did.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...