This Python package performs external routing for Asterisk.
While Asterisk has an event-based interface (and a REST-based interface), it lacks a simple straightforward way to forward phone calls from A to B. Also, mangling phone numbers is rather awkward in Asterisk’s AEL.
This package is useful if you want to write your phone number mangling and rewriting in Python.
Installation
Install Asterisk and this module.
Create an appropriate configuration file.
Add this to extensions.ael:
// Your SIP calls arrive here. Add one of these for each SIP peer.
context in_foo {
includes { default; };
_[+0-9]. => &aroute(foo,${EXTEN});
}
context default {
h => Hangup();
i => Hangup();
}
macro aroute(src,ext) {
Verbose(0,CALL: ${src}:${CALLERID(NUM)}:${ext});
Set(curl=http://localhost:50080/route/${src}:${CALLERID(NUM)}:${ext});
Verbose(0, = ${CURL(${curl})});
Set(dispatch=${CURL(${curl})});
&get(hangup); Set(hangup=${res});
if("${hangup}" = "") {
&get(chan); Set(chan=${res});
if("${chan}" = "Local") {
&get(dest); Set(dest=${res});
Set(dest=Local/${STRREPLACE(dest,+,@in_${src}&Local/)}@in_${src})
Dial(${chan}/${dest});
} else {
&get(a_nr); Set(a_nr=${res});
&get(b_nr); Set(b_nr=${res});
&get(p_nr); Set(p_nr=${res});
&get(end); Set(end=${res});
Set(CALLERID(num)=${a_nr});
Dial(${chan}/${b_nr}@${end});
}
} else {
// error
PJSIPHangup(${hangup});
}
Hangup();
return;
}
macro get(name) {
// extract a field from the CURL result.
//
// dispatch="foo=bar:baz=quux"
// get(foo) -> bar
//
Set(disp=${dispatch});
while("${disp}"!="") {
Set(assign=${CUT(disp,:,1)});
Set(disp=${CUT(disp,:,2-99)});
Set(var=${CUT(assign,=,1)});
Set(res=${CUT(assign,=,2)});
if("${var}"=="${name}") {
return;
}
}
Set(res=);
return;
}
Variables
This dialplan accepts these parameters:
a_nr number part of the caller id. This might need to be our SIP ID.
p_nr The real a_nr (SIP: P-Preferred-Identity)
b_nr Number to dial. This may need to be the destination SIP ID.
chan Channel. You probably want PJSIP. To divert to a local channel use “Local”.
dest Destination endpoint. This is the dialplan context when diverting to a local channel.
or
hangup PJSIP cause code.
For diverting a call to a local context, set chan=Local dest=context_name b_nr=extension.
Configuration
Bugs
hypercorn, which we use as an HTTP server, has an annoying bug in releases up to and including 0.17.3: it ignores a Connection: close header. This causes problems with clients like Icinga.
Zoom Phone integration
Get an API token from Zoom. It needs to be able to read your user records.
Create a secrets.yaml file:
zoom: # API to them account: "xxxxxxxxxxxxxxxxxxxxxx" client: "xxxxxxxxxxxxxxxxxxxxxx" password: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # Sign replies to the callback from them # TODO #token: "xxxxxxxxxxxxxxxxxxxxxx"
Add something like this to your routing.yaml:
route:
- match: "496990009(0|[1-6]{2,3})"
dest: zoom
use: known
- match: "496990009(0|[1-6]{2,3})"
dest: legacy_pbx
legacy_pbx:
fallback: zoom
zoom:
type: zoom
fallback: legacy_pbx
# Interval for updating extensions allocated on Zoom.
# -1: read once (and when refreshing), 0: don't read at all
update: 1200
# Numbers to forward to Zoom, regardless of whether they are known
known:
- "496990009123"
use: known # only forward numbers that have been assigned
route:
- match: "(0|[1-6][0-9]{2,3})"
result: "496990009$1"
dest: legacy_pbx
a_in: false
b_in: true
a_out: null
b_out: true
p_out: false
chan: "PJSIP" # default
# end: "zoom" # endpoint. Default: provider name
zoom:
# auth
auth_url: https://zoom.us/oauth/token
cred:
# API
account: !secret zoom.account
client: !secret zoom.client
secret: !secret zoom.password
# callbacks
#token: !secret zoom.token
The “fallback” causes a call that originates from this provider and gets routed back to the same provider to be routed to the fallback provider instead.
Release files for ast-route 0.9.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ast_route-0.9.2.tar.gz | 130.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ast_route-0.9.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 264.6 kB
Release files / ast_route-0.9.2.tar.gz
| Download URL | ast_route-0.9.2.tar.gz |
|---|---|
| Size | 130.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
544ddd2314b3f0389a3fba698bb399191ad9f732a3016425d160ca14d631a87f
|
|
BLAKE2b-256 checksum How to use checksums |
c420b277ae5cd68c66a7c366e300fa67561295ec025a91d224f38b562198281d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.5
|
Release files / ast_route-0.9.2-py3-none-any.whl
| Download URL | ast_route-0.9.2-py3-none-any.whl |
|---|---|
| Size | 134.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c97908950398d6be3314e31203920f77f6426075984ba1229358b44b81c781a3
|
|
BLAKE2b-256 checksum How to use checksums |
bd356b7899b86246d45a43985b289ac2227de80ebb39a893e7c60041422ff670
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.5
|