Compare commits
465 Commits
Author | SHA1 | Date |
---|---|---|
Naveen Albert | 8dd77df69b | |
Naveen Albert | b05865d8e9 | |
Sean Bright | 18ed610d4e | |
Sean Bright | 4ecbac98d8 | |
Stanislav Abramenkov | 83a4d37d9f | |
Sean Bright | 1965574944 | |
Maximilian Fridrich | 3d71b494d8 | |
Sean Bright | 6938b7f962 | |
George Joseph | 755bf72329 | |
George Joseph | 12d2bd23d5 | |
Naveen Albert | e4adc962ca | |
Naveen Albert | 082966bdad | |
Shaaah | c6ff7a6a51 | |
Naveen Albert | 3c42b141d7 | |
Sean Bright | 93e40968c3 | |
George Joseph | 9f182e9f58 | |
George Joseph | 267348bee3 | |
George Joseph | df0221b53d | |
George Joseph | eed8288d0c | |
George Joseph | e6c7f1aee0 | |
Sean Bright | d122225279 | |
Sebastian Jennen | a47acba99b | |
Shyju Kanaprath | 667b5ee192 | |
Sean Bright | 31fc2877cb | |
George Joseph | bbafb63bb5 | |
George Joseph | 7bd9f2b5a5 | |
romryz | 335b925fac | |
Naveen Albert | 59df4892ad | |
George Joseph | cb057a6381 | |
George Joseph | a433ed0d5a | |
Naveen Albert | 54b804fc3b | |
Ben Ford | bbfaff33cf | |
cmaj | 63b5a03538 | |
Joshua C. Colp | 167d393c0f | |
Mike Bradeen | 0d17ee6930 | |
George Joseph | 0f3f0f3529 | |
Naveen Albert | 64f9df5e59 | |
Sean Bright | 103a6dc987 | |
Brad Smith | 921b1d9cbc | |
Brad Smith | 57ea2912e2 | |
Sean Bright | 0fdaf7fc80 | |
Sean Bright | 2aaf28c95f | |
Naveen Albert | d50d981543 | |
Naveen Albert | 8eb6a329d6 | |
Sean Bright | f541f8d8c4 | |
Mike Bradeen | f5d622413a | |
Naveen Albert | f17910ded5 | |
Naveen Albert | 2b587d1d99 | |
PeterHolik | 416d9dfb85 | |
PeterHolik | 83d6f0f48b | |
Naveen Albert | d075a08d7e | |
George Joseph | 4715c1b11c | |
Naveen Albert | f22f49e77a | |
Maximilian Fridrich | 3e069f3274 | |
Naveen Albert | 83a0cb51e5 | |
Naveen Albert | b9ed57092f | |
George Joseph | b074c97f00 | |
Gitea | 5e168ebcd8 | |
Mike Bradeen | 5de9d317c7 | |
George Joseph | 00921cecda | |
Ben Ford | ce4f512bb7 | |
Naveen Albert | fcf36a8766 | |
Naveen Albert | bc53a2a087 | |
Sean Bright | 91c733bc69 | |
Naveen Albert | 8f5581b0d0 | |
George Joseph | 0005aa2995 | |
Maximilian Fridrich | dcf58ee88f | |
George Joseph | 44f1522907 | |
Sean Bright | 0b6e3bc59b | |
Matthew Fredrickson | bfac3945f6 | |
Sean Bright | a2f0d99d9d | |
Sean Bright | 4327ec2907 | |
Sean Bright | 2293edffd0 | |
Sean Bright | 6556a92393 | |
Naveen Albert | 22e34193ee | |
Sean Bright | 3859b630a7 | |
Sean Bright | 0dcf03e844 | |
Naveen Albert | c222343ec6 | |
Sean Bright | f8212d4594 | |
Sean Bright | ff012323e8 | |
Sean Bright | 9e1a60727e | |
Sean Bright | f2961f048d | |
Sean Bright | 978d09fc35 | |
George Joseph | d10d4d9ddd | |
Naveen Albert | 12b353eae0 | |
Matthew Fredrickson | 275f7911b5 | |
Naveen Albert | 1f19227eab | |
Naveen Albert | a0fc8d1b5f | |
Sean Bright | d2afb10eed | |
George Joseph | d819a6bccb | |
Sean Bright | a83c761c95 | |
Sean Bright | 26918d05f4 | |
George Joseph | cd77953172 | |
Sean Bright | 0e126b3841 | |
Naveen Albert | 4b9a4483fc | |
Holger Hans Peter Freyther | 56733c73b4 | |
Holger Hans Peter Freyther | 157389bc59 | |
Brad Smith | e7943dd4d9 | |
Brad Smith | 65d38c8104 | |
Naveen Albert | 5046620fa3 | |
Naveen Albert | 2191a0d33f | |
Mark Murawski | 2ed8daa3cb | |
Naveen Albert | cf9d7fa9f6 | |
Sean Bright | fb937d1d89 | |
George Joseph | f301d4559e | |
Naveen Albert | 8d9d0d3738 | |
Mike Bradeen | c3e2bff36e | |
Sean Bright | deeb1acffe | |
Sean Bright | d4e4942cf5 | |
George Joseph | b619b64137 | |
Sean Bright | 9d329da346 | |
Samuel Olaechea | ebc78a83be | |
George Joseph | 9efc4bdfbc | |
sungtae kim | f89e56c178 | |
George Joseph | be1e83a6ac | |
George Joseph | 289aa1840e | |
George Joseph | 0c1c6e9ada | |
Mike Bradeen | 79220e3f0c | |
Holger Hans Peter Freyther | 1171dcee02 | |
Sean Bright | acb2348f90 | |
George Joseph | 20398e8e95 | |
George Joseph | e9abf11a26 | |
Joshua C. Colp | ef7b0f4c3b | |
George Joseph | b52e07ee1b | |
George Joseph | a9d4175e1d | |
Mike Bradeen | 933490b758 | |
Naveen Albert | 945babf25c | |
Bastian Triller | e6d5b8d8cf | |
Mike Bradeen | 8c934fb7ed | |
Naveen Albert | c04923fcda | |
Eduardo | 11d87713eb | |
George Joseph | 7e2243f9e1 | |
George Joseph | 07cf37531a | |
Tinet-mucw | edc674a6ca | |
Mike Bradeen | 248b92563c | |
Naveen Albert | 71215561d8 | |
George Joseph | 4493d2b2fc | |
Naveen Albert | 833ee80789 | |
Vitezslav Novy | 5179f1af24 | |
George Joseph | 06da7b342e | |
Mike Bradeen | dd817c2708 | |
Sean Bright | 3fafd7c0b7 | |
Mike Bradeen | b53e946b59 | |
George Joseph | 9e2433f73f | |
George Joseph | c929146c61 | |
Maximilian Fridrich | 98ffcfebda | |
Jaco Kroon | a4cb63e231 | |
Joshua C. Colp | abe4f62554 | |
George Joseph | a64718c32c | |
George Joseph | b7dae87d1d | |
George Joseph | c06f938851 | |
Bastian Triller | 0c0b99c5a1 | |
George Joseph | ddbc56505e | |
Naveen Albert | 4542ffe5d5 | |
Mike Bradeen | 36b749ddf8 | |
George Joseph | cb9223cdb9 | |
Naveen Albert | 5077301de6 | |
zhengsh | afe461419e | |
George Joseph | 715594767d | |
Maximilian Fridrich | fcdffe0074 | |
Naveen Albert | 52283301e8 | |
Matthew Fredrickson | 9a28531362 | |
Matthew Fredrickson | c8f2698ec6 | |
George Joseph | d9494ca392 | |
Jason D. McCormick | fc57dca50d | |
MikeNaso | b286d1cca2 | |
Sean Bright | 29eb4fe620 | |
George Joseph | 64b29be702 | |
Naveen Albert | 8be503b663 | |
George Joseph | caf51592e7 | |
Joshua C. Colp | 07d798875d | |
Maximilian Fridrich | 8824b845c4 | |
Naveen Albert | c16cc93a4b | |
Joshua C. Colp | 5ebe1b61bd | |
Naveen Albert | 5516763e57 | |
Holger Hans Peter Freyther | a10de8bc72 | |
Sean Bright | b5762cd54e | |
phoneben | c0b8adfe4d | |
Sean Bright | df87ada8ac | |
Sean Bright | b8aee4a2c6 | |
Joshua C. Colp | 879d4ff56a | |
George Joseph | 12f231c717 | |
George Joseph | 74c809d71f | |
George Joseph | 10b3c2dc45 | |
Sean Bright | d26a00ef34 | |
Sean Bright | e120694711 | |
Mike Bradeen | b8db3dda7e | |
Mike Bradeen | 9b5c29d943 | |
zhengsh | 25a766f49d | |
George Joseph | 0f9de8a3f0 | |
George Joseph | cd7e513087 | |
Naveen Albert | d87abb2ec9 | |
Sean Bright | d902e8e817 | |
George Joseph | 640ead0071 | |
Stanislav Abramenkov | d596c0248a | |
George Joseph | 31663fed53 | |
Mike Bradeen | 2711fba4b9 | |
Mike Bradeen | 9c889911ad | |
Mike Bradeen | 3acdffc17e | |
George Joseph | 4ff17f44a4 | |
George Joseph | caf0fd357c | |
George Joseph | 80d042cb01 | |
George Joseph | b008fd5919 | |
George Joseph | 44c0e1b756 | |
George Joseph | 91503078ff | |
George Joseph | de40ea0f79 | |
George Joseph | 07a3784745 | |
George Joseph | 426b9c568c | |
Olaf Titz | af2ced484e | |
Sean Bright | 4a1edb9a8c | |
Ben Ford | ad120e5d0b | |
Nathan Bruning | 6084bbfe0e | |
Sean Bright | b7eae29fb9 | |
Sean Bright | 97b901a29b | |
Sean Bright | 21d3c4ae58 | |
zhou_jiajian | f7e1f1fbbd | |
Sean Bright | ea63148b23 | |
George Joseph | 25bc5544d8 | |
Sean Bright | ebc007322b | |
Jaco Kroon | 4a637d6d11 | |
Jiajian Zhou | 8e3f9dcc7b | |
George Joseph | 83781c23b9 | |
George Joseph | 6c8b23a688 | |
George Joseph | b3c2a9cd44 | |
Sean Bright | fe15631d38 | |
alex2grad | a8ea16cdf8 | |
Sean Bright | ada3dc2adb | |
Miguel Angel Nubla | 95d339ac7a | |
Naveen Albert | edf488c76e | |
Naveen Albert | 86a11d5b19 | |
Ben Ford | e72b277828 | |
Naveen Albert | 87f44dc0f9 | |
Joe Searle | ec64828c8f | |
Niklas Larsson | df774619fb | |
George Joseph | a83f35c58e | |
Mike Bradeen | f19a6cf11e | |
George Joseph | 7bbeda3908 | |
George Joseph | 2a75114b6d | |
Naveen Albert | d3227a614a | |
Naveen Albert | 22c9d52289 | |
Maximilian Fridrich | 1a7dada804 | |
Naveen Albert | 22b599d86f | |
George Joseph | 15439d08bd | |
Naveen Albert | cfae64a70d | |
George Joseph | 7193e95676 | |
George Joseph | af0535f302 | |
George Joseph | e72b35e7fb | |
Jaco Kroon | f178bf78b7 | |
Sean Bright | 2d18fb6e9d | |
zhengsh | 8abb294063 | |
Sean Bright | 19973b73fd | |
Joshua C. Colp | f0e2d45089 | |
Gitea | c0e32d8245 | |
Joshua C. Colp | 851ec44714 | |
George Joseph | 9d99f6aaf1 | |
Henning Westerholt | 37a41a2a20 | |
Mike Bradeen | 8d3d8fcdcd | |
Sean Bright | 5c6d5ea38f | |
George Joseph | 9097fc7515 | |
George Joseph | fbde0a71f0 | |
George Joseph | aced9046ca | |
George Joseph | b7eeef6314 | |
Maximilian Fridrich | f3cc1e7fbd | |
George Joseph | 3707140472 | |
Joshua C. Colp | a614604f32 | |
Naveen Albert | 82d7bb49dd | |
George Joseph | ef644c3e93 | |
George Joseph | 313cd9dd84 | |
George Joseph | 987315a5fa | |
George Joseph | f8dc014819 | |
Joshua C. Colp | 6c53e5e870 | |
Joshua Colp | de15852ef0 | |
Naveen Albert | 66a7cff57e | |
Naveen Albert | b33f92cbb5 | |
The_Blode | de9aaf7e97 | |
Henning Westerholt | 1c5720b802 | |
Naveen Albert | d0f39250ee | |
Naveen Albert | bad5bda08c | |
George Joseph | a0fd95ef52 | |
Mike Bradeen | df554a447c | |
Jaco Kroon | 019dc51139 | |
Sean Bright | 6dab013e49 | |
Sean Bright | 34ff836db5 | |
Sean Bright | 1ba3b34f77 | |
Mike Bradeen | ffe346b2de | |
Mike Bradeen | fa635a872e | |
Mike Bradeen | 8d2ffc8aa5 | |
Sean Bright | a3ec3efa02 | |
Naveen Albert | f9fd76677f | |
Naveen Albert | 3556ca239a | |
Naveen Albert | 090ec448cf | |
Fabrice Fontaine | cb0220dec2 | |
Mike Bradeen | 405211eff7 | |
Jaco Kroon | 3fd0b65bae | |
George Joseph | bbec5d1a99 | |
Holger Hans Peter Freyther | 8f088aa0f7 | |
Fabrice Fontaine | 030b7b9009 | |
Sean Bright | 46bdd5e3be | |
Asterisk Development Team | 93813c9dca | |
George Joseph | ceda5a9859 | |
Sean Bright | e5c5cd6e25 | |
Naveen Albert | ede67a99be | |
Sean Bright | 827222d607 | |
Nick French | 200dc7d0e8 | |
Mike Bradeen | 5c11d7adea | |
cmaj | 5b0e3444c3 | |
Mike Bradeen | 2308afed8e | |
Mike Bradeen | 98742388b6 | |
Mike Bradeen | 37e558f6ef | |
Sean Bright | aeb16aa7d8 | |
Sean Bright | aef0c0ce0e | |
Mike Bradeen | 58636a6ea6 | |
Sean Bright | 96d9ad51ac | |
Naveen Albert | 88b2c741ca | |
Mike Bradeen | 70856e865f | |
Naveen Albert | 8a45cd7af4 | |
sungtae kim | f99849f8d5 | |
Sean Bright | 56051d1ac5 | |
Naveen Albert | a1da8042d1 | |
Sean Bright | ef16eaee36 | |
George Joseph | 2f5aece0c9 | |
Alexei Gradinari | e86d5d7fda | |
Igor Goncharovsky | 3526441e41 | |
George Joseph | 4710f37ef6 | |
George Joseph | 62ca063fca | |
Naveen Albert | d33bd6d67a | |
Naveen Albert | e06fe8e344 | |
Naveen Albert | 68e345286b | |
Naveen Albert | 3b3fef2347 | |
Naveen Albert | 7b8f7428da | |
George Joseph | 24102ba236 | |
Boris P. Korzun | edc90c96ac | |
Holger Hans Peter Freyther | 3d9b9a2b16 | |
George Joseph | d454801c2d | |
Naveen Albert | cc8d9b947b | |
Naveen Albert | c7598ee947 | |
Ben Ford | 881faf544f | |
Naveen Albert | 20d4775d0a | |
Naveen Albert | cbb1fd2cb9 | |
Igor Goncharovsky | 115a1b4f0a | |
Peter Fern | 58404b5c22 | |
Naveen Albert | 36bea9ad33 | |
Asterisk Development Team | fefc236e7c | |
Alexandre Fournier | 01b3962201 | |
Joshua C. Colp | b6855755ce | |
Naveen Albert | 2f9cdfbc50 | |
Michael Kuron | 5c114dcb4a | |
Michael Kuron | fee9012fe1 | |
Joshua C. Colp | 564349ff5d | |
Naveen Albert | b9c031c1f8 | |
Marcel Wagner | 58534b309f | |
Naveen Albert | 531eacd6c9 | |
Naveen Albert | b365ea8601 | |
Naveen Albert | 0d6003fa9a | |
Marcel Wagner | b83af13f65 | |
Naveen Albert | 80e6205bb0 | |
Naveen Albert | 406143ae61 | |
Naveen Albert | 83eb113e0f | |
Naveen Albert | b90e57758b | |
Naveen Albert | 52c7d3ed07 | |
Naveen Albert | a4bcdce1db | |
Naveen Albert | 691178c48e | |
Ben Ford | d476994768 | |
George Joseph | 7684c9e907 | |
Mike Bradeen | 81f10e847e | |
Mike Bradeen | eb1d7ab53c | |
Naveen Albert | c7df5ee7c1 | |
Naveen Albert | 5ede4e217a | |
Maximilian Fridrich | 60b81eabe0 | |
Naveen Albert | 2efa290d3c | |
Jaco Kroon | ce2153fc5a | |
Naveen Albert | 002afc3f2a | |
Naveen Albert | 1e77b8c473 | |
Joshua C. Colp | 61922d2934 | |
Naveen Albert | 6e59b01e1a | |
Naveen Albert | 49cfdbbdff | |
Naveen Albert | 8142b313c3 | |
George Joseph | 0c1c623dee | |
Naveen Albert | dfe2f38642 | |
George Joseph | f723b465e5 | |
Mike Bradeen | 50e2921a48 | |
Naveen Albert | afd86b47c1 | |
Igor Goncharovsky | 096529d33f | |
Naveen Albert | ca8900b0f6 | |
Henning Westerholt | 12445040d3 | |
Naveen Albert | 40b52322e5 | |
Naveen Albert | c32b39d123 | |
Frederic LE FOLL | 50a4495799 | |
Naveen Albert | 180ca32565 | |
Naveen Albert | 9258d8212a | |
Naveen Albert | 407216a0a5 | |
Philip Prindeville | d0bea5a725 | |
Mike Bradeen | 907d7e7d7d | |
Naveen Albert | b331caca30 | |
Naveen Albert | e0e7f35730 | |
Naveen Albert | 98fc05f13b | |
Philip Prindeville | ef74ecacc7 | |
Philip Prindeville | 5e2485b5c0 | |
George Joseph | 2a500b325a | |
Maximilian Fridrich | 0d2e140123 | |
Asterisk Development Team | 7f80830ced | |
Holger Hans Peter Freyther | 62881c668b | |
Naveen Albert | 8afb313a43 | |
Naveen Albert | 7335b0cffe | |
Naveen Albert | 407167cc28 | |
Naveen Albert | a5ec60e6c6 | |
Naveen Albert | 1e29607b5c | |
Naveen Albert | 8c791f9a65 | |
Philip Prindeville | 3e7ce90f9c | |
Naveen Albert | 1ed4518328 | |
Maximilian Fridrich | 5bbad0d27c | |
Naveen Albert | 8aae0b9f08 | |
Jaco Kroon | 278c5726ca | |
Naveen Albert | ab1dbfef75 | |
George Joseph | e25b690d10 | |
George Joseph | e33f2dcc0f | |
Philip Prindeville | 026dc08529 | |
Asterisk Development Team | f01ed3eea4 | |
Mike Bradeen | 7a44296ca9 | |
George Joseph | 8cbea1c7ef | |
sungtae kim | 80bc844fd6 | |
Ben Ford | 881a3f2306 | |
Philip Prindeville | 3e054c9ebc | |
Philip Prindeville | 736cdf84f4 | |
Philip Prindeville | 2d7656cb50 | |
Philip Prindeville | 5809d879b0 | |
Philip Prindeville | 2c4c44ca64 | |
Philip Prindeville | b9df2c481b | |
Philip Prindeville | d13afaf302 | |
Naveen Albert | 2dac2bf8dc | |
Naveen Albert | c487425620 | |
Naveen Albert | 205c7c8d21 | |
Naveen Albert | 2de016b181 | |
George Joseph | 05f42806cc | |
George Joseph | c799db6a21 | |
George Joseph | 4ffc5561c4 | |
George Joseph | 2d5a6498dd | |
Joshua C. Colp | f3de933b16 | |
Naveen Albert | c7612521be | |
Joshua C. Colp | a0713a9f70 | |
Naveen Albert | 754346a4a9 | |
Mike Bradeen | 46776c77c4 | |
Sean Bright | 583e017f34 | |
Alexei Gradinari | 12c4c1bf5f | |
Sean Bright | 155c796203 | |
Naveen Albert | 3fa66c92b5 | |
Mike Bradeen | adffb975dc | |
Mike Bradeen | 4fc9e06db1 | |
Naveen Albert | e2e049e473 | |
George Joseph | 8a8416e365 | |
Naveen Albert | ff044c222b | |
Naveen Albert | dc7ec11c26 | |
George Joseph | 30d7a212b0 | |
Naveen Albert | f4a020a45b | |
Naveen Albert | c654486547 | |
Naveen Albert | 5feebc0857 | |
Naveen Albert | 165368bf0b | |
Naveen Albert | 2d8f2696b2 | |
Naveen Albert | 4af881506e | |
Naveen Albert | 83912496ab | |
Naveen Albert | c771e2dd7a | |
Sergey V. Lobanov | f645157a4b | |
Naveen Albert | a9223f210e | |
Naveen Albert | ce18196280 | |
George Joseph | f8000daff5 |
|
@ -77,7 +77,7 @@ body:
|
|||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
[Asterisk Issue Guidelines](https://docs.asterisk.org/Asterisk-Community/Asterisk-Issue-Guidelines/)
|
||||
[Asterisk Issue Guidelines](https://wiki.asterisk.org/wiki/display/AST/Asterisk+Issue+Guidelines)
|
||||
- type: checkboxes
|
||||
id: guidelines
|
||||
attributes:
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
name: NightlyAdmin
|
||||
name: Nightly Admin
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
ASTERISK_REPO: ${{ github.repository }}
|
||||
|
@ -14,6 +13,16 @@ env:
|
|||
|
||||
jobs:
|
||||
CloseStaleIssues:
|
||||
uses: asterisk/asterisk-ci-actions/.github/workflows/CloseStaleIssuesAndPRs.yml@main
|
||||
secrets:
|
||||
ASTERISKTEAM_PAT: ${{ secrets.ASTERISKTEAM_PAT }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Close Stale Issues
|
||||
uses: actions/stale@v7
|
||||
with:
|
||||
stale-issue-message: 'This issue is stale because it has been open 7 days with no activity. Remove stale label or comment or this will be closed in 14 days.'
|
||||
stale-issue-label: stale
|
||||
close-issue-message: 'This issue was closed because it has been stalled for 14 days with no activity.'
|
||||
days-before-stale: 7
|
||||
days-before-close: 14
|
||||
days-before-pr-close: -1
|
||||
only-labels: triage,feedback-required
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ OPTIMIZE?=-O3
|
|||
|
||||
ifneq ($(findstring darwin,$(OSARCH)),)
|
||||
ifeq ($(shell if test `/usr/bin/sw_vers -productVersion | cut -c4` -gt 5; then echo 6; else echo 0; fi),6)
|
||||
# Snow Leopard/Lion has an issue with this optimization flag on large files
|
||||
# Snow Leopard/Lion has an issue with this optimization flag on large files (like chan_sip)
|
||||
OPTIMIZE+=-fno-inline-functions
|
||||
endif
|
||||
endif
|
||||
|
|
|
@ -52,28 +52,28 @@ request.
|
|||
```INI
|
||||
[incoming]
|
||||
exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
|
||||
exten => _X.,n,Dial(PJSIP/${EXTEN})
|
||||
exten => _X.,n,Dial(SIP/${EXTEN})
|
||||
exten => _X.,n,Hangup()
|
||||
```
|
||||
|
||||
This dialplan may be utilized to accept calls to extensions, which then dial a
|
||||
numbered device name configured in one of the channel configuration files (such
|
||||
as pjsip.conf, iax.conf, etc...) (see [Proper Device Naming] for more information
|
||||
as sip.conf, iax.conf, etc...) (see [Proper Device Naming] for more information
|
||||
on why this approach is flawed).
|
||||
|
||||
The example we've given above looks harmless enough until you take into
|
||||
consideration that several channel technologies accept characters that could
|
||||
be utilized in a clever attack. For example, instead of just sending a request
|
||||
to dial extension 500 (which in our example above would create the string
|
||||
PJSIP/500 and is then used by the Dial() application to place a call), someone
|
||||
could potentially send a string like "500&PJSIP/itsp/14165551212".
|
||||
SIP/500 and is then used by the Dial() application to place a call), someone
|
||||
could potentially send a string like "500&SIP/itsp/14165551212".
|
||||
|
||||
The string "500&PJSIP/itsp/14165551212" would then be contained within the
|
||||
The string "500&SIP/itsp/14165551212" would then be contained within the
|
||||
${EXTEN} channel variable, which is then utilized by the Dial() application in
|
||||
our example, thereby giving you the dialplan line of:
|
||||
|
||||
```INI
|
||||
exten => _X.,n,Dial(PJSIP/500&PJSIP/itsp/14165551212)
|
||||
exten => _X.,n,Dial(SIP/500&SIP/itsp/14165551212)
|
||||
```
|
||||
|
||||
Our example above has now provided someone with a method to place calls out of
|
||||
|
@ -83,10 +83,10 @@ the FILTER() dialplan function.
|
|||
|
||||
The CALLERID(num) and CALLERID(name) values are other commonly used values that
|
||||
are sources of data potentially supplied by outside sources. If you use these
|
||||
values as parameters to the System() or MixMonitor() applications or the SHELL()
|
||||
dialplan function, you can allow injection of arbitrary operating system command
|
||||
execution. The FILTER() dialplan function is available to remove dangerous
|
||||
characters from untrusted strings to block the command injection.
|
||||
values as parameters to the System(), MixMonitor(), or Monitor() applications
|
||||
or the SHELL() dialplan function, you can allow injection of arbitrary operating
|
||||
system command execution. The FILTER() dialplan function is available to remove
|
||||
dangerous characters from untrusted strings to block the command injection.
|
||||
|
||||
|
||||
### Strict Pattern Matching
|
||||
|
@ -98,7 +98,7 @@ to only accept three digit extensions, we could change our pattern match to
|
|||
be:
|
||||
|
||||
```INI
|
||||
exten => _XXX,n,Dial(PJSIP/${EXTEN})
|
||||
exten => _XXX,n,Dial(SIP/${EXTEN})
|
||||
```
|
||||
|
||||
In this way, we have minimized our impact because we're not allowing anything
|
||||
|
@ -124,7 +124,7 @@ we will accept to just numbers. Our example would then change to something like:
|
|||
```INI
|
||||
[incoming]
|
||||
exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
|
||||
exten => _X.,n,Dial(PJSIP/${FILTER(0-9,${EXTEN})})
|
||||
exten => _X.,n,Dial(SIP/${FILTER(0-9,${EXTEN})})
|
||||
exten => _X.,n,Hangup()
|
||||
```
|
||||
|
||||
|
@ -141,7 +141,7 @@ necessary, and to handle error checking in a separate location.
|
|||
[incoming]
|
||||
exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
|
||||
exten => _X.,n,Set(SAFE_EXTEN=${FILTER(0-9,${EXTEN})})
|
||||
exten => _X.,n,Dial(PJSIP/${SAFE_EXTEN})
|
||||
exten => _X.,n,Dial(SIP/${SAFE_EXTEN})
|
||||
exten => _X.,n,Hangup()
|
||||
```
|
||||
|
||||
|
@ -155,7 +155,7 @@ passed back by FILTER(), and to fail the call if things do not match.
|
|||
exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
|
||||
exten => _X.,n,Set(SAFE_EXTEN=${FILTER(0-9,${EXTEN})})
|
||||
exten => _X.,n,GotoIf($[${EXTEN} != ${SAFE_EXTEN}]?error,1)
|
||||
exten => _X.,n,Dial(PJSIP/${SAFE_EXTEN})
|
||||
exten => _X.,n,Dial(SIP/${SAFE_EXTEN})
|
||||
exten => _X.,n,Hangup()
|
||||
|
||||
exten => error,1,Verbose(2,Values of EXTEN and SAFE_EXTEN did not match.)
|
||||
|
@ -170,7 +170,7 @@ we're expecting to get a SIP URI for dialing.
|
|||
```INI
|
||||
[incoming]
|
||||
exten => _[0-9a-zA-Z].,1,Verbose(2,Incoming call to extension ${EXTEN})
|
||||
exten => _[0-9a-zA-Z].,n,Dial(PJSIP/${FILTER(.@0-9a-zA-Z,${EXTEN})
|
||||
exten => _[0-9a-zA-Z].,n,Dial(SIP/${FILTER(.@0-9a-zA-Z,${EXTEN})
|
||||
exten => _[0-9a-zA-Z].,n,Hangup()
|
||||
```
|
||||
|
||||
|
@ -201,14 +201,13 @@ It can also be a security hazard to name your devices with a number, as this can
|
|||
open you up to brute force attacks. Many of the current exploits deal with
|
||||
device configurations which utilize a number, and even worse, a password that
|
||||
matches the devices name. For example, take a look at this poorly created device
|
||||
in pjsip.conf:
|
||||
in sip.conf:
|
||||
|
||||
```INI
|
||||
[1000]
|
||||
type=auth
|
||||
auth_type=userpass
|
||||
password=1000
|
||||
username=1000
|
||||
type=friend
|
||||
context=international_dialing
|
||||
secret=1000
|
||||
```
|
||||
|
||||
As implied by the context, we've permitted a device named 1000 with a password
|
||||
|
@ -224,10 +223,9 @@ Passwords). The following example would be more secure:
|
|||
|
||||
```INI
|
||||
[0004f2040001]
|
||||
type=auth
|
||||
auth_type=userpass
|
||||
password=aE3%B8*$jk^G
|
||||
username=0004f2040001
|
||||
type=friend
|
||||
context=international_dialing
|
||||
secret=aE3%B8*$jk^G
|
||||
```
|
||||
|
||||
Then in your dialplan, you would reference the device via the MAC address of the
|
||||
|
@ -325,7 +323,7 @@ the Originate manager command:
|
|||
|
||||
```
|
||||
Action: Originate
|
||||
Channel: PJSIP/foo
|
||||
Channel: SIP/foo
|
||||
Exten: s
|
||||
Context: default
|
||||
Priority: 1
|
||||
|
@ -342,7 +340,7 @@ circumvent these checks. For example, take the following dialplan:
|
|||
```INI
|
||||
exten => s,1,Verbose(Incoming call)
|
||||
same => n,MixMonitor(foo.wav,,${EXEC_COMMAND})
|
||||
same => n,Dial(PJSIP/bar)
|
||||
same => n,Dial(SIP/bar)
|
||||
same => n,Hangup()
|
||||
```
|
||||
|
||||
|
|
|
@ -3248,7 +3248,7 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc
|
|||
if (peer->t38support == T38_DISABLED) {
|
||||
ast_cli(a->fd, "%s\n", "disabled");
|
||||
} else if (peer->t38support == T38_FAXGW) {
|
||||
ast_cli(a->fd, "%s\n", "faxgw compatible");
|
||||
ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible");
|
||||
}
|
||||
if (peer->faxdetect == (FAXDETECT_CNG | FAXDETECT_T38)) {
|
||||
ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Yes");
|
||||
|
@ -3386,7 +3386,7 @@ static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struc
|
|||
if (user->t38support == T38_DISABLED) {
|
||||
ast_cli(a->fd, "%s\n", "disabled");
|
||||
} else if (user->t38support == T38_FAXGW) {
|
||||
ast_cli(a->fd, "%s\n", "faxgw compatible");
|
||||
ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible");
|
||||
}
|
||||
if (user->faxdetect == (FAXDETECT_CNG | FAXDETECT_T38)) {
|
||||
ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Yes");
|
||||
|
@ -3633,7 +3633,7 @@ static char *handle_cli_ooh323_show_config(struct ast_cli_entry *e, int cmd, str
|
|||
if (gT38Support == T38_DISABLED) {
|
||||
ast_cli(a->fd, "%s\n", "disabled");
|
||||
} else if (gT38Support == T38_FAXGW) {
|
||||
ast_cli(a->fd, "%s\n", "faxgw compatible");
|
||||
ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible");
|
||||
}
|
||||
if (gFAXdetect == (FAXDETECT_CNG | FAXDETECT_T38)) {
|
||||
ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Yes");
|
||||
|
@ -5047,7 +5047,7 @@ struct ast_frame *ooh323_rtp_read(struct ast_channel *ast, struct ooh323_pvt *p)
|
|||
p->faxdetected = 1;
|
||||
ooRequestChangeMode(p->callToken, 1);
|
||||
} else if ((dfr->subclass.integer == 'f') && !p->faxdetected) {
|
||||
const char *target_context = ast_channel_context(p->owner);
|
||||
const char *target_context = S_OR(ast_channel_macrocontext(p->owner), ast_channel_context(p->owner));
|
||||
if ((strcmp(ast_channel_exten(p->owner), "fax")) &&
|
||||
(ast_exists_extension(p->owner, target_context, "fax", 1,
|
||||
S_COR(ast_channel_caller(p->owner)->id.number.valid, ast_channel_caller(p->owner)->id.number.str, NULL)))) {
|
||||
|
@ -5123,7 +5123,7 @@ void onModeChanged(ooCallData *call, int t38mode) {
|
|||
if ((p->faxdetect & FAXDETECT_T38) && !p->faxdetected) {
|
||||
const char *target_context;
|
||||
ast_debug(1, "* Detected T.38 Request\n");
|
||||
target_context = ast_channel_context(p->owner);
|
||||
target_context = S_OR(ast_channel_macrocontext(p->owner), ast_channel_context(p->owner));
|
||||
if ((strcmp(ast_channel_exten(p->owner), "fax")) &&
|
||||
(ast_exists_extension(p->owner, target_context, "fax", 1,
|
||||
S_COR(ast_channel_caller(p->owner)->id.number.valid, ast_channel_caller(p->owner)->id.number.str, NULL)))) {
|
||||
|
|
|
@ -192,11 +192,13 @@ EXTERN int ooQ931Decode
|
|||
screening indicators ;-) */
|
||||
if(ie->discriminator == Q931CallingPartyNumberIE)
|
||||
{
|
||||
int numoffset=1;
|
||||
OOTRACEDBGB1(" CallingPartyNumber IE = {\n");
|
||||
if(ie->length < OO_MAX_NUMBER_LENGTH)
|
||||
if(!(0x80 & ie->data[0])) numoffset = 2;
|
||||
|
||||
if( (ie->length >= numoffset) &&
|
||||
(ie->length < OO_MAX_NUMBER_LENGTH) )
|
||||
{
|
||||
int numoffset=1;
|
||||
if(!(0x80 & ie->data[0])) numoffset = 2;
|
||||
memcpy(number, ie->data+numoffset,ie->length-numoffset);
|
||||
number[ie->length-numoffset]='\0';
|
||||
OOTRACEDBGB2(" %s\n", number);
|
||||
|
@ -204,7 +206,7 @@ EXTERN int ooQ931Decode
|
|||
ooCallSetCallingPartyNumber(call, number);
|
||||
}
|
||||
else{
|
||||
OOTRACEERR3("Error:Calling party number too long. (%s, %s)\n",
|
||||
OOTRACEERR3("Error:Calling party number outside range. (%s, %s)\n",
|
||||
call->callType, call->callToken);
|
||||
}
|
||||
OOTRACEDBGB1(" }\n");
|
||||
|
@ -214,7 +216,8 @@ EXTERN int ooQ931Decode
|
|||
if(ie->discriminator == Q931CalledPartyNumberIE)
|
||||
{
|
||||
OOTRACEDBGB1(" CalledPartyNumber IE = {\n");
|
||||
if(ie->length < OO_MAX_NUMBER_LENGTH)
|
||||
if( (ie->length >= 1) &&
|
||||
(ie->length < OO_MAX_NUMBER_LENGTH) )
|
||||
{
|
||||
memcpy(number, ie->data+1,ie->length-1);
|
||||
number[ie->length-1]='\0';
|
||||
|
@ -223,7 +226,7 @@ EXTERN int ooQ931Decode
|
|||
ooCallSetCalledPartyNumber(call, number);
|
||||
}
|
||||
else{
|
||||
OOTRACEERR3("Error:Calling party number too long. (%s, %s)\n",
|
||||
OOTRACEERR3("Error:Calling party number outside range. (%s, %s)\n",
|
||||
call->callType, call->callToken);
|
||||
}
|
||||
OOTRACEDBGB1(" }\n");
|
||||
|
|
|
@ -51,7 +51,8 @@
|
|||
# going to http://www.mpg123.de/cgi-bin/sitexplorer.cgi?/mpg123/
|
||||
# Be sure to download mpg123-0.59r.tar.gz because it is known to
|
||||
# work with Asterisk and hopefully isn't the release with that
|
||||
# awful security problem. If you're using Fedora Core 3 do make
|
||||
# awful security problem. If you're using Fedora Core 3 with
|
||||
# Alsa like me, make linux-alsa isn't going to work. Do make
|
||||
# linux-devel and you're peachy keen.
|
||||
#
|
||||
# - You won't get nifty STDERR debug messages if you're using a
|
||||
|
|
|
@ -58,6 +58,6 @@ app_voicemail_imap.o: _ASTCFLAGS+=$(AST_NO_FORMAT_TRUNCATION) -DIMAP_STORAGE
|
|||
app_while.o: _ASTCFLAGS+=$(AST_NO_FORMAT_TRUNCATION)
|
||||
|
||||
ifneq ($(findstring $(OSARCH), mingw32 cygwin ),)
|
||||
LIBS+= -lres_ael_share.so -lres_speech.so
|
||||
LIBS+= -lres_ael_share.so -lres_monitor.so -lres_speech.so
|
||||
LIBS+= -lres_smdi.so
|
||||
endif
|
||||
|
|
|
@ -38,6 +38,26 @@
|
|||
#include "asterisk/stasis_message_router.h"
|
||||
|
||||
/*** DOCUMENTATION
|
||||
<application name="NoCDR" language="en_US">
|
||||
<synopsis>
|
||||
Tell Asterisk to not maintain a CDR for this channel.
|
||||
</synopsis>
|
||||
<syntax />
|
||||
<description>
|
||||
<para>This application will tell Asterisk not to maintain a CDR for
|
||||
the current channel. This does <emphasis>NOT</emphasis> mean that
|
||||
information is not tracked; rather, if the channel is hung up no
|
||||
CDRs will be created for that channel.</para>
|
||||
<para>If a subsequent call to ResetCDR occurs, all non-finalized
|
||||
CDRs created for the channel will be enabled.</para>
|
||||
<note><para>This application is deprecated. Please use the CDR_PROP
|
||||
function to disable CDRs on a channel.</para></note>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">ResetCDR</ref>
|
||||
<ref type="function">CDR_PROP</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
<application name="ResetCDR" language="en_US">
|
||||
<synopsis>
|
||||
Resets the Call Data Record.
|
||||
|
@ -48,6 +68,10 @@
|
|||
<option name="v">
|
||||
<para>Save the CDR variables during the reset.</para>
|
||||
</option>
|
||||
<option name="e">
|
||||
<para>Enable the CDRs for this channel only (negate
|
||||
effects of NoCDR).</para>
|
||||
</option>
|
||||
</optionlist>
|
||||
</parameter>
|
||||
</syntax>
|
||||
|
@ -60,14 +84,21 @@
|
|||
current time.</para>
|
||||
<para>3. All variables are wiped from the CDR. Note that this step
|
||||
can be prevented with the <literal>v</literal> option.</para>
|
||||
<para>On the other hand, if the <literal>e</literal> option is
|
||||
specified, the effects of the NoCDR application will be lifted. CDRs
|
||||
will be re-enabled for this channel.</para>
|
||||
<note><para>The <literal>e</literal> option is deprecated. Please
|
||||
use the CDR_PROP function instead.</para></note>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">ForkCDR</ref>
|
||||
<ref type="application">NoCDR</ref>
|
||||
<ref type="function">CDR_PROP</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
***/
|
||||
|
||||
static const char nocdr_app[] = "NoCDR";
|
||||
static const char resetcdr_app[] = "ResetCDR";
|
||||
|
||||
enum reset_cdr_options {
|
||||
|
@ -78,6 +109,7 @@ enum reset_cdr_options {
|
|||
|
||||
AST_APP_OPTIONS(resetcdr_opts, {
|
||||
AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
|
||||
AST_APP_OPTION('e', AST_CDR_FLAG_DISABLE_ALL),
|
||||
});
|
||||
|
||||
STASIS_MESSAGE_TYPE_DEFN_LOCAL(appcdr_message_type);
|
||||
|
@ -86,6 +118,10 @@ STASIS_MESSAGE_TYPE_DEFN_LOCAL(appcdr_message_type);
|
|||
struct app_cdr_message_payload {
|
||||
/*! The name of the channel to be manipulated */
|
||||
const char *channel_name;
|
||||
/*! Disable the CDR for this channel */
|
||||
unsigned int disable:1;
|
||||
/*! Re-enable the CDR for this channel */
|
||||
unsigned int reenable:1;
|
||||
/*! Reset the CDR */
|
||||
unsigned int reset:1;
|
||||
/*! If reseting the CDR, keep the variables */
|
||||
|
@ -105,9 +141,24 @@ static void appcdr_callback(void *data, struct stasis_subscription *sub, struct
|
|||
return;
|
||||
}
|
||||
|
||||
if (payload->disable) {
|
||||
if (ast_cdr_set_property(payload->channel_name, AST_CDR_FLAG_DISABLE_ALL)) {
|
||||
ast_log(AST_LOG_WARNING, "Failed to disable CDRs on channel %s\n",
|
||||
payload->channel_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (payload->reenable) {
|
||||
if (ast_cdr_clear_property(payload->channel_name, AST_CDR_FLAG_DISABLE_ALL)) {
|
||||
ast_log(AST_LOG_WARNING, "Failed to enable CDRs on channel %s\n",
|
||||
payload->channel_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (payload->reset) {
|
||||
if (ast_cdr_reset(payload->channel_name, payload->keep_variables)) {
|
||||
ast_log(AST_LOG_WARNING, "Failed to reset CDRs on channel %s\n", payload->channel_name);
|
||||
ast_log(AST_LOG_WARNING, "Failed to reset CDRs on channel %s\n",
|
||||
payload->channel_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,6 +204,10 @@ static int resetcdr_exec(struct ast_channel *chan, const char *data)
|
|||
payload->channel_name = ast_channel_name(chan);
|
||||
payload->reset = 1;
|
||||
|
||||
if (ast_test_flag(&flags, AST_CDR_FLAG_DISABLE_ALL)) {
|
||||
payload->reenable = 1;
|
||||
}
|
||||
|
||||
if (ast_test_flag(&flags, AST_CDR_FLAG_KEEP_VARS)) {
|
||||
payload->keep_variables = 1;
|
||||
}
|
||||
|
@ -160,6 +215,21 @@ static int resetcdr_exec(struct ast_channel *chan, const char *data)
|
|||
return publish_app_cdr_message(chan, payload);
|
||||
}
|
||||
|
||||
static int nocdr_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
RAII_VAR(struct app_cdr_message_payload *, payload,
|
||||
ao2_alloc(sizeof(*payload), NULL), ao2_cleanup);
|
||||
|
||||
if (!payload) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
payload->channel_name = ast_channel_name(chan);
|
||||
payload->disable = 1;
|
||||
|
||||
return publish_app_cdr_message(chan, payload);
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
RAII_VAR(struct stasis_message_router *, router, ast_cdr_message_router(), ao2_cleanup);
|
||||
|
@ -168,6 +238,7 @@ static int unload_module(void)
|
|||
stasis_message_router_remove(router, appcdr_message_type());
|
||||
}
|
||||
STASIS_MESSAGE_TYPE_CLEANUP(appcdr_message_type);
|
||||
ast_unregister_application(nocdr_app);
|
||||
ast_unregister_application(resetcdr_app);
|
||||
return 0;
|
||||
}
|
||||
|
@ -182,8 +253,10 @@ static int load_module(void)
|
|||
}
|
||||
|
||||
res |= STASIS_MESSAGE_TYPE_INIT(appcdr_message_type);
|
||||
res |= ast_register_application_xml(nocdr_app, nocdr_exec);
|
||||
res |= ast_register_application_xml(resetcdr_app, resetcdr_exec);
|
||||
res |= stasis_message_router_add(router, appcdr_message_type(), appcdr_callback, NULL);
|
||||
res |= stasis_message_router_add(router, appcdr_message_type(),
|
||||
appcdr_callback, NULL);
|
||||
|
||||
if (res) {
|
||||
unload_module();
|
||||
|
|
|
@ -964,6 +964,8 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
|
|||
ast_channel_lock(chan);
|
||||
if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
|
||||
ast_copy_string(exitcontext, c, sizeof(exitcontext));
|
||||
} else if (!ast_strlen_zero(ast_channel_macrocontext(chan))) {
|
||||
ast_copy_string(exitcontext, ast_channel_macrocontext(chan), sizeof(exitcontext));
|
||||
} else {
|
||||
ast_copy_string(exitcontext, ast_channel_context(chan), sizeof(exitcontext));
|
||||
}
|
||||
|
|
168
apps/app_dial.c
168
apps/app_dial.c
|
@ -211,7 +211,7 @@
|
|||
and <emphasis>start</emphasis> execution at that location.</para>
|
||||
<para>NOTE: Any channel variables you want the called channel to inherit from the caller channel must be
|
||||
prefixed with one or two underbars ('_').</para>
|
||||
<para>NOTE: Using this option from a GoSub() might not make sense as there would be no return points.</para>
|
||||
<para>NOTE: Using this option from a Macro() or GoSub() might not make sense as there would be no return points.</para>
|
||||
</option>
|
||||
<option name="g">
|
||||
<para>Proceed with dialplan execution at the next priority in the current extension if the
|
||||
|
@ -304,6 +304,47 @@
|
|||
channel answers. A specific music on hold <replaceable>class</replaceable>
|
||||
(as defined in <filename>musiconhold.conf</filename>) can be specified.</para>
|
||||
</option>
|
||||
<option name="M" argsep="^">
|
||||
<argument name="macro" required="true">
|
||||
<para>Name of the macro that should be executed.</para>
|
||||
</argument>
|
||||
<argument name="arg" multiple="true">
|
||||
<para>Macro arguments</para>
|
||||
</argument>
|
||||
<para>Execute the specified <replaceable>macro</replaceable> for the <emphasis>called</emphasis> channel
|
||||
before connecting to the calling channel. Arguments can be specified to the Macro
|
||||
using <literal>^</literal> as a delimiter. The macro can set the variable
|
||||
<variable>MACRO_RESULT</variable> to specify the following actions after the macro is
|
||||
finished executing:</para>
|
||||
<variablelist>
|
||||
<variable name="MACRO_RESULT">
|
||||
<para>If set, this action will be taken after the macro finished executing.</para>
|
||||
<value name="ABORT">
|
||||
Hangup both legs of the call
|
||||
</value>
|
||||
<value name="CONGESTION">
|
||||
Behave as if line congestion was encountered
|
||||
</value>
|
||||
<value name="BUSY">
|
||||
Behave as if a busy signal was encountered
|
||||
</value>
|
||||
<value name="CONTINUE">
|
||||
Hangup the called party and allow the calling party to continue dialplan execution at the next priority
|
||||
</value>
|
||||
<value name="GOTO:[[<context>^]<exten>^]<priority>">
|
||||
Transfer the call to the specified destination.
|
||||
</value>
|
||||
</variable>
|
||||
</variablelist>
|
||||
<para>NOTE: You cannot use any additional action post answer options in conjunction
|
||||
with this option. Also, pbx services are run on the peer (called) channel,
|
||||
so you will not be able to set timeouts via the <literal>TIMEOUT()</literal> function in this macro.</para>
|
||||
<para>WARNING: Be aware of the limitations that macros have, specifically with regards to use of
|
||||
the <literal>WaitExten</literal> application. For more information, see the documentation for
|
||||
<literal>Macro()</literal>.</para>
|
||||
<para>NOTE: Macros are deprecated, GoSub should be used instead,
|
||||
see the <literal>U</literal> option.</para>
|
||||
</option>
|
||||
<option name="n">
|
||||
<argument name="delete">
|
||||
<para>With <replaceable>delete</replaceable> either not specified or set to <literal>0</literal>,
|
||||
|
@ -367,6 +408,8 @@
|
|||
to send no cause. See the <filename>causes.h</filename> file for the
|
||||
full list of valid causes and names.
|
||||
</para>
|
||||
<para>NOTE: chan_sip does not support setting the cause on a CANCEL to anything
|
||||
other than ANSWERED_ELSEWHERE.</para>
|
||||
</option>
|
||||
<option name="r">
|
||||
<para>Default: Indicate ringing to the calling party, even if the called party isn't actually ringing. Pass no audio to the calling
|
||||
|
@ -621,6 +664,7 @@
|
|||
<ref type="application">RetryDial</ref>
|
||||
<ref type="application">SendDTMF</ref>
|
||||
<ref type="application">Gosub</ref>
|
||||
<ref type="application">Macro</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
<application name="RetryDial" language="en_US">
|
||||
|
@ -675,6 +719,7 @@ enum {
|
|||
OPT_ORIGINAL_CLID = (1 << 8),
|
||||
OPT_DURATION_LIMIT = (1 << 9),
|
||||
OPT_MUSICBACK = (1 << 10),
|
||||
OPT_CALLEE_MACRO = (1 << 11),
|
||||
OPT_SCREEN_NOINTRO = (1 << 12),
|
||||
OPT_SCREEN_NOCALLERID = (1 << 13),
|
||||
OPT_IGNORE_CONNECTEDLINE = (1 << 14),
|
||||
|
@ -720,6 +765,7 @@ enum {
|
|||
OPT_ARG_GOTO,
|
||||
OPT_ARG_DURATION_LIMIT,
|
||||
OPT_ARG_MUSICBACK,
|
||||
OPT_ARG_CALLEE_MACRO,
|
||||
OPT_ARG_RINGBACK,
|
||||
OPT_ARG_CALLEE_GOSUB,
|
||||
OPT_ARG_CALLEE_GO_ON,
|
||||
|
@ -762,6 +808,7 @@ AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
|
|||
AST_APP_OPTION('K', OPT_CALLER_PARK),
|
||||
AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
|
||||
AST_APP_OPTION_ARG('m', OPT_MUSICBACK, OPT_ARG_MUSICBACK),
|
||||
AST_APP_OPTION_ARG('M', OPT_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO),
|
||||
AST_APP_OPTION_ARG('n', OPT_SCREEN_NOINTRO, OPT_ARG_SCREEN_NOINTRO),
|
||||
AST_APP_OPTION('N', OPT_SCREEN_NOCALLERID),
|
||||
AST_APP_OPTION_ARG('o', OPT_ORIGINAL_CLID, OPT_ARG_ORIGINAL_CLID),
|
||||
|
@ -787,7 +834,7 @@ END_OPTIONS );
|
|||
#define CAN_EARLY_BRIDGE(flags,chan,peer) (!ast_test_flag64(flags, OPT_CALLEE_HANGUP | \
|
||||
OPT_CALLER_HANGUP | OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | \
|
||||
OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | OPT_CALLEE_PARK | \
|
||||
OPT_CALLER_PARK | OPT_ANNOUNCE | OPT_CALLEE_GOSUB) && \
|
||||
OPT_CALLER_PARK | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB) && \
|
||||
!ast_channel_audiohooks(chan) && !ast_channel_audiohooks(peer) && \
|
||||
ast_framehook_list_is_empty(ast_channel_framehooks(chan)) && ast_framehook_list_is_empty(ast_channel_framehooks(peer)))
|
||||
|
||||
|
@ -899,6 +946,10 @@ static int onedigit_goto(struct ast_channel *chan, const char *context, char ext
|
|||
} else {
|
||||
if (!ast_goto_if_exists(chan, ast_channel_context(chan), rexten, pri))
|
||||
return 1;
|
||||
else if (!ast_strlen_zero(ast_channel_macrocontext(chan))) {
|
||||
if (!ast_goto_if_exists(chan, ast_channel_macrocontext(chan), rexten, pri))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -910,8 +961,8 @@ static const char *get_cid_name(char *name, int namelen, struct ast_channel *cha
|
|||
const char *exten;
|
||||
|
||||
ast_channel_lock(chan);
|
||||
context = ast_strdupa(ast_channel_context(chan));
|
||||
exten = ast_strdupa(ast_channel_exten(chan));
|
||||
context = ast_strdupa(S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)));
|
||||
exten = ast_strdupa(S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan)));
|
||||
ast_channel_unlock(chan);
|
||||
|
||||
return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : "";
|
||||
|
@ -1046,7 +1097,7 @@ static void do_forward(struct chanlist *o, struct cause_args *num,
|
|||
ast_party_number_init(&ast_channel_redirecting(c)->from.number);
|
||||
ast_channel_redirecting(c)->from.number.valid = 1;
|
||||
ast_channel_redirecting(c)->from.number.str =
|
||||
ast_strdup(ast_channel_exten(in));
|
||||
ast_strdup(S_OR(ast_channel_macroexten(in), ast_channel_exten(in)));
|
||||
}
|
||||
|
||||
ast_channel_dialed(c)->transit_network_select = ast_channel_dialed(in)->transit_network_select;
|
||||
|
@ -1095,12 +1146,17 @@ static void do_forward(struct chanlist *o, struct cause_args *num,
|
|||
* Redirecting updates to the caller make sense only on single
|
||||
* calls.
|
||||
*
|
||||
* Need to re-evalute if unlocking is still required here as macro is gone
|
||||
* We must unlock c before calling
|
||||
* ast_channel_redirecting_macro, because we put c into
|
||||
* autoservice there. That is pretty much a guaranteed
|
||||
* deadlock. This is why the handling of c's lock may seem a
|
||||
* bit unusual here.
|
||||
*/
|
||||
ast_party_redirecting_init(&redirecting);
|
||||
ast_party_redirecting_copy(&redirecting, ast_channel_redirecting(c));
|
||||
ast_channel_unlock(c);
|
||||
if (ast_channel_redirecting_sub(c, in, &redirecting, 0)) {
|
||||
if (ast_channel_redirecting_sub(c, in, &redirecting, 0) &&
|
||||
ast_channel_redirecting_macro(c, in, &redirecting, 1, 0)) {
|
||||
ast_channel_update_redirecting(in, &redirecting, NULL);
|
||||
}
|
||||
ast_party_redirecting_free(&redirecting);
|
||||
|
@ -1176,7 +1232,8 @@ static void update_connected_line_from_peer(struct ast_channel *chan, struct ast
|
|||
ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(peer));
|
||||
ast_channel_unlock(peer);
|
||||
connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
|
||||
if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)) {
|
||||
if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)
|
||||
&& ast_channel_connected_line_macro(peer, chan, &connected_caller, is_caller, 0)) {
|
||||
ast_channel_update_connected_line(chan, &connected_caller, NULL);
|
||||
}
|
||||
ast_party_connected_line_free(&connected_caller);
|
||||
|
@ -1311,7 +1368,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
update_connected_line_from_peer(in, c, 1);
|
||||
} else if (!single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
|
||||
if (o->pending_connected_update) {
|
||||
if (ast_channel_connected_line_sub(c, in, &o->connected, 0)) {
|
||||
if (ast_channel_connected_line_sub(c, in, &o->connected, 0) &&
|
||||
ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) {
|
||||
ast_channel_update_connected_line(in, &o->connected, NULL);
|
||||
}
|
||||
} else if (!ast_test_flag64(o, DIAL_CALLERID_ABSENT)) {
|
||||
|
@ -1409,7 +1467,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
update_connected_line_from_peer(in, c, 1);
|
||||
} else if (!single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
|
||||
if (o->pending_connected_update) {
|
||||
if (ast_channel_connected_line_sub(c, in, &o->connected, 0)) {
|
||||
if (ast_channel_connected_line_sub(c, in, &o->connected, 0) &&
|
||||
ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) {
|
||||
ast_channel_update_connected_line(in, &o->connected, NULL);
|
||||
}
|
||||
} else if (!ast_test_flag64(o, DIAL_CALLERID_ABSENT)) {
|
||||
|
@ -1653,7 +1712,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
o->pending_connected_update = 1;
|
||||
break;
|
||||
}
|
||||
if (ast_channel_connected_line_sub(c, in, f, 1)) {
|
||||
if (ast_channel_connected_line_sub(c, in, f, 1) &&
|
||||
ast_channel_connected_line_macro(c, in, f, 1, 1)) {
|
||||
ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
|
||||
}
|
||||
break;
|
||||
|
@ -1682,7 +1742,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
}
|
||||
ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
|
||||
ast_channel_name(c), ast_channel_name(in));
|
||||
if (ast_channel_redirecting_sub(c, in, f, 1)) {
|
||||
if (ast_channel_redirecting_sub(c, in, f, 1) &&
|
||||
ast_channel_redirecting_macro(c, in, f, 1, 1)) {
|
||||
ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
|
||||
}
|
||||
pa->sentringing = 0;
|
||||
|
@ -1894,7 +1955,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(o->chan));
|
||||
break;
|
||||
}
|
||||
if (ast_channel_connected_line_sub(in, o->chan, f, 1)) {
|
||||
if (ast_channel_connected_line_sub(in, o->chan, f, 1) &&
|
||||
ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) {
|
||||
ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
|
||||
}
|
||||
break;
|
||||
|
@ -1903,7 +1965,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(o->chan));
|
||||
break;
|
||||
}
|
||||
if (ast_channel_redirecting_sub(in, o->chan, f, 1)) {
|
||||
if (ast_channel_redirecting_sub(in, o->chan, f, 1) &&
|
||||
ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) {
|
||||
ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
|
||||
}
|
||||
break;
|
||||
|
@ -2467,7 +2530,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
if (ast_test_flag64(&opts, OPT_FORCECLID)) {
|
||||
if (ast_strlen_zero(opt_args[OPT_ARG_FORCECLID])) {
|
||||
ast_channel_lock(chan);
|
||||
forced_clid.number.str = ast_strdupa(ast_channel_exten(chan));
|
||||
forced_clid.number.str = ast_strdupa(S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan)));
|
||||
ast_channel_unlock(chan);
|
||||
forced_clid_name[0] = '\0';
|
||||
forced_clid.name.str = (char *) get_cid_name(forced_clid_name,
|
||||
|
@ -2544,7 +2607,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
stored_clid.name.valid = 1;
|
||||
}
|
||||
ast_channel_lock(chan);
|
||||
stored_clid.number.str = ast_strdupa(ast_channel_exten(chan));
|
||||
stored_clid.number.str = ast_strdupa(S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan)));
|
||||
stored_clid.number.valid = 1;
|
||||
ast_channel_unlock(chan);
|
||||
}
|
||||
|
@ -2579,7 +2642,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
/* Set per dial instance flags. These flags are also passed back to RetryDial. */
|
||||
ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID
|
||||
| OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_CANCEL_TIMEOUT
|
||||
| OPT_ANNOUNCE | OPT_CALLEE_GOSUB | OPT_FORCECLID);
|
||||
| OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB | OPT_FORCECLID);
|
||||
|
||||
/* PREDIAL: Run gosub on the caller's channel */
|
||||
if (ast_test_flag64(&opts, OPT_PREDIAL_CALLER)
|
||||
|
@ -2819,8 +2882,11 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
|
||||
|
||||
/* Inherit context and extension */
|
||||
ast_channel_dialcontext_set(tc, ast_channel_context(chan));
|
||||
ast_channel_exten_set(tc, ast_channel_exten(chan));
|
||||
ast_channel_dialcontext_set(tc, ast_strlen_zero(ast_channel_macrocontext(chan)) ? ast_channel_context(chan) : ast_channel_macrocontext(chan));
|
||||
if (!ast_strlen_zero(ast_channel_macroexten(chan)))
|
||||
ast_channel_exten_set(tc, ast_channel_macroexten(chan));
|
||||
else
|
||||
ast_channel_exten_set(tc, ast_channel_exten(chan));
|
||||
|
||||
ast_channel_stage_snapshot_done(tc);
|
||||
|
||||
|
@ -3160,7 +3226,9 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
} else {
|
||||
other_chan = chan;
|
||||
}
|
||||
if (ast_channel_connected_line_sub(active_chan, other_chan, fr, 1)) {
|
||||
if (ast_channel_connected_line_sub(active_chan, other_chan, fr, 1)
|
||||
&& ast_channel_connected_line_macro(active_chan,
|
||||
other_chan, fr, other_chan == chan, 1)) {
|
||||
ast_indicate_data(other_chan, fr->subclass.integer,
|
||||
fr->data.ptr, fr->datalen);
|
||||
}
|
||||
|
@ -3207,6 +3275,66 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
goto done;
|
||||
}
|
||||
|
||||
if (ast_test_flag64(&opts, OPT_CALLEE_MACRO) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_MACRO])) {
|
||||
const char *macro_result_peer;
|
||||
int macro_res;
|
||||
|
||||
/* Set peer->exten and peer->context so that MACRO_EXTEN and MACRO_CONTEXT get set */
|
||||
ast_channel_lock_both(chan, peer);
|
||||
ast_channel_context_set(peer, ast_channel_context(chan));
|
||||
ast_channel_exten_set(peer, ast_channel_exten(chan));
|
||||
ast_channel_unlock(peer);
|
||||
ast_channel_unlock(chan);
|
||||
ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]);
|
||||
macro_res = ast_app_exec_macro(chan, peer, opt_args[OPT_ARG_CALLEE_MACRO]);
|
||||
|
||||
ast_channel_lock(peer);
|
||||
|
||||
if (!macro_res && (macro_result_peer = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) {
|
||||
char *macro_result = ast_strdupa(macro_result_peer);
|
||||
char *macro_transfer_dest;
|
||||
|
||||
ast_channel_unlock(peer);
|
||||
|
||||
if (!strcasecmp(macro_result, "BUSY")) {
|
||||
ast_copy_string(pa.status, macro_result, sizeof(pa.status));
|
||||
ast_set_flag64(peerflags, OPT_GO_ON);
|
||||
macro_res = -1;
|
||||
} else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) {
|
||||
ast_copy_string(pa.status, macro_result, sizeof(pa.status));
|
||||
ast_set_flag64(peerflags, OPT_GO_ON);
|
||||
macro_res = -1;
|
||||
} else if (!strcasecmp(macro_result, "CONTINUE")) {
|
||||
/* hangup peer and keep chan alive assuming the macro has changed
|
||||
the context / exten / priority or perhaps
|
||||
the next priority in the current exten is desired.
|
||||
*/
|
||||
ast_set_flag64(peerflags, OPT_GO_ON);
|
||||
macro_res = -1;
|
||||
} else if (!strcasecmp(macro_result, "ABORT")) {
|
||||
/* Hangup both ends unless the caller has the g flag */
|
||||
macro_res = -1;
|
||||
} else if (!strncasecmp(macro_result, "GOTO:", 5)) {
|
||||
macro_transfer_dest = macro_result + 5;
|
||||
macro_res = -1;
|
||||
/* perform a transfer to a new extension */
|
||||
if (strchr(macro_transfer_dest, '^')) { /* context^exten^priority*/
|
||||
ast_replace_subargument_delimiter(macro_transfer_dest);
|
||||
}
|
||||
if (!ast_parseable_goto(chan, macro_transfer_dest)) {
|
||||
ast_set_flag64(peerflags, OPT_GO_ON);
|
||||
}
|
||||
}
|
||||
if (macro_res && !dial_end_raised) {
|
||||
ast_channel_publish_dial(chan, peer, NULL, macro_result);
|
||||
dial_end_raised = 1;
|
||||
}
|
||||
} else {
|
||||
ast_channel_unlock(peer);
|
||||
}
|
||||
res = macro_res;
|
||||
}
|
||||
|
||||
if (ast_test_flag64(&opts, OPT_CALLEE_GOSUB) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GOSUB])) {
|
||||
const char *gosub_result_peer;
|
||||
char *gosub_argstart;
|
||||
|
|
|
@ -355,7 +355,9 @@ static int compare(const char *text, const char *template)
|
|||
|
||||
static int goto_exten(struct ast_channel *chan, const char *dialcontext, char *ext)
|
||||
{
|
||||
if (!ast_goto_if_exists(chan, S_OR(dialcontext, ast_channel_context(chan)), ext, 1)) {
|
||||
if (!ast_goto_if_exists(chan, S_OR(dialcontext, ast_channel_context(chan)), ext, 1) ||
|
||||
(!ast_strlen_zero(ast_channel_macrocontext(chan)) &&
|
||||
!ast_goto_if_exists(chan, ast_channel_macrocontext(chan), ext, 1))) {
|
||||
return 0;
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Can't find extension '%s' in current context. "
|
||||
|
|
|
@ -1531,7 +1531,8 @@ static int app_exec(struct ast_channel *chan, const char *data)
|
|||
|
||||
/* Update connected line to caller if available. */
|
||||
if (targs->pending_out_connected_update) {
|
||||
if (ast_channel_connected_line_sub(outbound, caller, &targs->connected_out, 0)) {
|
||||
if (ast_channel_connected_line_sub(outbound, caller, &targs->connected_out, 0) &&
|
||||
ast_channel_connected_line_macro(outbound, caller, &targs->connected_out, 1, 0)) {
|
||||
ast_channel_update_connected_line(caller, &targs->connected_out, NULL);
|
||||
}
|
||||
}
|
||||
|
@ -1556,7 +1557,8 @@ static int app_exec(struct ast_channel *chan, const char *data)
|
|||
|
||||
/* Update connected line to winner if changed. */
|
||||
if (targs->pending_in_connected_update) {
|
||||
if (ast_channel_connected_line_sub(caller, outbound, &targs->connected_in, 0)) {
|
||||
if (ast_channel_connected_line_sub(caller, outbound, &targs->connected_in, 0) &&
|
||||
ast_channel_connected_line_macro(caller, outbound, &targs->connected_in, 0, 0)) {
|
||||
ast_channel_update_connected_line(outbound, &targs->connected_in, NULL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
</description>
|
||||
<see-also>
|
||||
<ref type="function">CDR</ref>
|
||||
<ref type="function">CDR_PROP</ref>
|
||||
<ref type="application">NoCDR</ref>
|
||||
<ref type="application">ResetCDR</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
|
|
|
@ -0,0 +1,694 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Dial plan macro Implementation
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<defaultenabled>no</defaultenabled>
|
||||
<support_level>deprecated</support_level>
|
||||
<replacement>app_stack (GoSub)</replacement>
|
||||
<deprecated_in>16</deprecated_in>
|
||||
<removed_in>21</removed_in>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/extconf.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
/*** DOCUMENTATION
|
||||
<application name="Macro" language="en_US">
|
||||
<synopsis>
|
||||
Macro Implementation.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="name" required="true">
|
||||
<para>The name of the macro</para>
|
||||
</parameter>
|
||||
<parameter name="args">
|
||||
<argument name="arg1" required="true" />
|
||||
<argument name="arg2" multiple="true" />
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Executes a macro using the context macro-<replaceable>name</replaceable>,
|
||||
jumping to the <literal>s</literal> extension of that context and executing each step,
|
||||
then returning when the steps end.</para>
|
||||
<para>The calling extension, context, and priority are stored in <variable>MACRO_EXTEN</variable>,
|
||||
<variable>MACRO_CONTEXT</variable> and <variable>MACRO_PRIORITY</variable> respectively. Arguments
|
||||
become <variable>ARG1</variable>, <variable>ARG2</variable>, etc in the macro context.</para>
|
||||
<para>If you Goto out of the Macro context, the Macro will terminate and control will be returned
|
||||
at the location of the Goto.</para>
|
||||
<para>If <variable>MACRO_OFFSET</variable> is set at termination, Macro will attempt to continue
|
||||
at priority MACRO_OFFSET + N + 1 if such a step exists, and N + 1 otherwise.</para>
|
||||
<warning><para>Because of the way Macro is implemented (it executes the priorities contained within
|
||||
it via sub-engine), and a fixed per-thread memory stack allowance, macros are limited to 7 levels
|
||||
of nesting (macro calling macro calling macro, etc.); It may be possible that stack-intensive
|
||||
applications in deeply nested macros could cause asterisk to crash earlier than this limit.
|
||||
It is advised that if you need to deeply nest macro calls, that you use the Gosub application
|
||||
(now allows arguments like a Macro) with explicit Return() calls instead.</para></warning>
|
||||
<warning><para>Use of the application <literal>WaitExten</literal> within a macro will not function
|
||||
as expected. Please use the <literal>Read</literal> application in order to read DTMF from a channel
|
||||
currently executing a macro.</para></warning>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">MacroExit</ref>
|
||||
<ref type="application">Goto</ref>
|
||||
<ref type="application">Gosub</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
<application name="MacroIf" language="en_US">
|
||||
<synopsis>
|
||||
Conditional Macro implementation.
|
||||
</synopsis>
|
||||
<syntax argsep="?">
|
||||
<parameter name="expr" required="true" />
|
||||
<parameter name="destination" required="true" argsep=":">
|
||||
<argument name="macroiftrue" required="true">
|
||||
<argument name="macroiftrue" required="true" />
|
||||
<argument name="arg1" multiple="true" />
|
||||
</argument>
|
||||
<argument name="macroiffalse">
|
||||
<argument name="macroiffalse" required="true" />
|
||||
<argument name="arg1" multiple="true" />
|
||||
</argument>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Executes macro defined in <replaceable>macroiftrue</replaceable> if
|
||||
<replaceable>expr</replaceable> is true (otherwise <replaceable>macroiffalse</replaceable>
|
||||
if provided)</para>
|
||||
<para>Arguments and return values as in application Macro()</para>
|
||||
<xi:include xpointer="xpointer(/docs/application[@name='Macro']/description/warning[2])" />
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">GotoIf</ref>
|
||||
<ref type="application">GosubIf</ref>
|
||||
<ref type="function">IF</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
<application name="MacroExclusive" language="en_US">
|
||||
<synopsis>
|
||||
Exclusive Macro Implementation.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="name" required="true">
|
||||
<para>The name of the macro</para>
|
||||
</parameter>
|
||||
<parameter name="arg1" />
|
||||
<parameter name="arg2" multiple="true" />
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Executes macro defined in the context macro-<replaceable>name</replaceable>.
|
||||
Only one call at a time may run the macro. (we'll wait if another call is busy
|
||||
executing in the Macro)</para>
|
||||
<para>Arguments and return values as in application Macro()</para>
|
||||
<xi:include xpointer="xpointer(/docs/application[@name='Macro']/description/warning[2])" />
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">Macro</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
<application name="MacroExit" language="en_US">
|
||||
<synopsis>
|
||||
Exit from Macro.
|
||||
</synopsis>
|
||||
<syntax />
|
||||
<description>
|
||||
<para>Causes the currently running macro to exit as if it had
|
||||
ended normally by running out of priorities to execute.
|
||||
If used outside a macro, will likely cause unexpected behavior.</para>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">Macro</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
***/
|
||||
|
||||
#define MAX_ARGS 80
|
||||
|
||||
/* special result value used to force macro exit */
|
||||
#define MACRO_EXIT_RESULT 1024
|
||||
|
||||
static char *app = "Macro";
|
||||
static char *if_app = "MacroIf";
|
||||
static char *exclusive_app = "MacroExclusive";
|
||||
static char *exit_app = "MacroExit";
|
||||
|
||||
static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
|
||||
|
||||
static const struct ast_datastore_info macro_ds_info = {
|
||||
.type = "MACRO",
|
||||
.chan_fixup = macro_fixup,
|
||||
};
|
||||
|
||||
static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
|
||||
{
|
||||
int i;
|
||||
char varname[10];
|
||||
pbx_builtin_setvar_helper(new_chan, "MACRO_DEPTH", "0");
|
||||
pbx_builtin_setvar_helper(new_chan, "MACRO_CONTEXT", NULL);
|
||||
pbx_builtin_setvar_helper(new_chan, "MACRO_EXTEN", NULL);
|
||||
pbx_builtin_setvar_helper(new_chan, "MACRO_PRIORITY", NULL);
|
||||
pbx_builtin_setvar_helper(new_chan, "MACRO_OFFSET", NULL);
|
||||
for (i = 1; i < 100; i++) {
|
||||
snprintf(varname, sizeof(varname), "ARG%d", i);
|
||||
while (pbx_builtin_getvar_helper(new_chan, varname)) {
|
||||
/* Kill all levels of arguments */
|
||||
pbx_builtin_setvar_helper(new_chan, varname, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten,
|
||||
int priority, const char *callerid, int iter, int *had_error)
|
||||
{
|
||||
struct ast_exten *e;
|
||||
struct ast_context *c2;
|
||||
int idx;
|
||||
|
||||
if (iter >= AST_PBX_MAX_STACK) {
|
||||
if (!(*had_error)) {
|
||||
*had_error = 1;
|
||||
ast_log(LOG_ERROR, "Potential infinite loop detected, will not recurse further.\n");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) {
|
||||
if (ast_extension_match(ast_get_extension_name(e), exten)) {
|
||||
int needmatch = ast_get_extension_matchcid(e);
|
||||
if ((needmatch && ast_extension_match(ast_get_extension_cidmatch(e), callerid)) ||
|
||||
(!needmatch)) {
|
||||
/* This is the matching extension we want */
|
||||
struct ast_exten *p;
|
||||
for (p=ast_walk_extension_priorities(e, NULL); p; p=ast_walk_extension_priorities(e, p)) {
|
||||
if (priority != ast_get_extension_priority(p))
|
||||
continue;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* No match; run through includes */
|
||||
for (idx = 0; idx < ast_context_includes_count(c); idx++) {
|
||||
const struct ast_include *i = ast_context_includes_get(c, idx);
|
||||
|
||||
for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) {
|
||||
if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) {
|
||||
e = find_matching_priority(c2, exten, priority, callerid, iter + 1, had_error);
|
||||
if (e)
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive)
|
||||
{
|
||||
const char *s;
|
||||
char *tmp;
|
||||
char *cur, *rest;
|
||||
char *macro;
|
||||
char fullmacro[80];
|
||||
char varname[80];
|
||||
char runningapp[80], runningdata[1024];
|
||||
char *oldargs[MAX_ARGS + 1] = { NULL, };
|
||||
int argc, x;
|
||||
int res=0;
|
||||
char oldexten[256]="";
|
||||
int oldpriority, gosub_level = 0;
|
||||
char pc[80], depthc[12];
|
||||
char oldcontext[AST_MAX_CONTEXT] = "";
|
||||
const char *inhangupc;
|
||||
int offset, depth = 0, maxdepth = 7;
|
||||
int setmacrocontext=0;
|
||||
int autoloopflag, inhangup = 0;
|
||||
struct ast_str *tmp_subst = NULL;
|
||||
const char *my_macro_exten = NULL;
|
||||
char *save_macro_exten;
|
||||
char *save_macro_context;
|
||||
char *save_macro_priority;
|
||||
char *save_macro_offset;
|
||||
int save_in_subroutine;
|
||||
struct ast_datastore *macro_store;
|
||||
int had_infinite_include_error = 0;
|
||||
static int deprecation_notice = 0;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Macro() requires arguments. See \"core show application macro\" for help.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!deprecation_notice) {
|
||||
deprecation_notice = 1;
|
||||
ast_log(LOG_WARNING, "Macro() is deprecated and will be removed from a future version of Asterisk.\n");
|
||||
ast_log(LOG_WARNING, "Dialplan should be updated to use Gosub instead.\n");
|
||||
}
|
||||
|
||||
ast_channel_lock(chan);
|
||||
|
||||
macro_store = ast_channel_datastore_find(chan, ¯o_ds_info, NULL);
|
||||
|
||||
do {
|
||||
if (macro_store) {
|
||||
break;
|
||||
}
|
||||
if (!(macro_store = ast_datastore_alloc(¯o_ds_info, NULL))) {
|
||||
ast_log(LOG_WARNING, "Unable to allocate new datastore.\n");
|
||||
break;
|
||||
}
|
||||
/* Just the existence of this datastore is enough. */
|
||||
macro_store->inheritance = DATASTORE_INHERIT_FOREVER;
|
||||
ast_channel_datastore_add(chan, macro_store);
|
||||
} while (0);
|
||||
|
||||
/* does the user want a deeper rabbit hole? */
|
||||
if ((s = pbx_builtin_getvar_helper(chan, "MACRO_RECURSION"))) {
|
||||
sscanf(s, "%30d", &maxdepth);
|
||||
}
|
||||
|
||||
/* Count how many levels deep the rabbit hole goes */
|
||||
if ((s = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH"))) {
|
||||
sscanf(s, "%30d", &depth);
|
||||
}
|
||||
|
||||
/* Used for detecting whether to return when a Macro is called from another Macro after hangup */
|
||||
if (strcmp(ast_channel_exten(chan), "h") == 0)
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_IN_HANGUP", "1");
|
||||
|
||||
if ((inhangupc = pbx_builtin_getvar_helper(chan, "MACRO_IN_HANGUP"))) {
|
||||
sscanf(inhangupc, "%30d", &inhangup);
|
||||
}
|
||||
ast_channel_unlock(chan);
|
||||
|
||||
if (depth >= maxdepth) {
|
||||
ast_log(LOG_ERROR, "Macro(): possible infinite loop detected. Returning early.\n");
|
||||
return 0;
|
||||
}
|
||||
snprintf(depthc, sizeof(depthc), "%d", depth + 1);
|
||||
|
||||
tmp = ast_strdupa(data);
|
||||
rest = tmp;
|
||||
macro = strsep(&rest, ",");
|
||||
if (ast_strlen_zero(macro)) {
|
||||
ast_log(LOG_WARNING, "Invalid macro name specified\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
|
||||
|
||||
/* first search for the macro */
|
||||
if (!ast_context_find(fullmacro)) {
|
||||
ast_log(LOG_WARNING, "No such context '%s' for macro '%s'. Was called by %s@%s\n",
|
||||
fullmacro, macro, ast_channel_exten(chan), ast_channel_context(chan));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* now search for the right extension */
|
||||
if (ast_exists_extension(chan, fullmacro, "s", 1,
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid,
|
||||
ast_channel_caller(chan)->id.number.str, NULL))) {
|
||||
/* We have a normal macro */
|
||||
my_macro_exten = "s";
|
||||
} else if (ast_exists_extension(chan, fullmacro, "~~s~~", 1,
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid,
|
||||
ast_channel_caller(chan)->id.number.str, NULL))) {
|
||||
/* We have an AEL generated macro */
|
||||
my_macro_exten = "~~s~~";
|
||||
}
|
||||
|
||||
/* do we have a valid exten? */
|
||||
if (!my_macro_exten) {
|
||||
ast_log(LOG_WARNING,
|
||||
"Context '%s' for macro '%s' lacks 's' extension, priority 1\n",
|
||||
fullmacro, macro);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we are to run the macro exclusively, take the mutex */
|
||||
if (exclusive) {
|
||||
ast_debug(1, "Locking macrolock for '%s'\n", fullmacro);
|
||||
ast_autoservice_start(chan);
|
||||
if (ast_context_lockmacro(fullmacro)) {
|
||||
ast_log(LOG_WARNING, "Failed to lock macro '%s' as in-use\n", fullmacro);
|
||||
ast_autoservice_stop(chan);
|
||||
return 0;
|
||||
}
|
||||
ast_autoservice_stop(chan);
|
||||
}
|
||||
|
||||
if (!(tmp_subst = ast_str_create(16))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Save old info */
|
||||
ast_channel_lock(chan);
|
||||
oldpriority = ast_channel_priority(chan);
|
||||
ast_copy_string(oldexten, ast_channel_exten(chan), sizeof(oldexten));
|
||||
ast_copy_string(oldcontext, ast_channel_context(chan), sizeof(oldcontext));
|
||||
if (ast_strlen_zero(ast_channel_macrocontext(chan))) {
|
||||
ast_channel_macrocontext_set(chan, ast_channel_context(chan));
|
||||
ast_channel_macroexten_set(chan, ast_channel_exten(chan));
|
||||
ast_channel_macropriority_set(chan, ast_channel_priority(chan));
|
||||
setmacrocontext=1;
|
||||
}
|
||||
argc = 1;
|
||||
/* Save old macro variables */
|
||||
save_macro_exten = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_EXTEN"));
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);
|
||||
|
||||
save_macro_context = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"));
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);
|
||||
|
||||
save_macro_priority = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY"));
|
||||
snprintf(pc, sizeof(pc), "%d", oldpriority);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
|
||||
|
||||
save_macro_offset = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"));
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);
|
||||
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
|
||||
|
||||
save_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
|
||||
ast_set_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
|
||||
|
||||
/* Setup environment for new run */
|
||||
ast_channel_exten_set(chan, my_macro_exten);
|
||||
ast_channel_context_set(chan, fullmacro);
|
||||
ast_channel_priority_set(chan, 1);
|
||||
|
||||
while((cur = strsep(&rest, ",")) && (argc < MAX_ARGS)) {
|
||||
const char *argp;
|
||||
/* Save copy of old arguments if we're overwriting some, otherwise
|
||||
let them pass through to the other macro */
|
||||
snprintf(varname, sizeof(varname), "ARG%d", argc);
|
||||
if ((argp = pbx_builtin_getvar_helper(chan, varname))) {
|
||||
oldargs[argc] = ast_strdup(argp);
|
||||
}
|
||||
pbx_builtin_setvar_helper(chan, varname, cur);
|
||||
argc++;
|
||||
}
|
||||
autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
|
||||
ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
|
||||
ast_channel_unlock(chan);
|
||||
|
||||
while (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan),
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
|
||||
struct ast_context *c;
|
||||
struct ast_exten *e;
|
||||
int foundx;
|
||||
runningapp[0] = '\0';
|
||||
runningdata[0] = '\0';
|
||||
|
||||
/* What application will execute? */
|
||||
if (ast_rdlock_contexts()) {
|
||||
ast_log(LOG_WARNING, "Failed to lock contexts list\n");
|
||||
} else {
|
||||
for (c = ast_walk_contexts(NULL), e = NULL; c; c = ast_walk_contexts(c)) {
|
||||
if (!strcmp(ast_get_context_name(c), ast_channel_context(chan))) {
|
||||
if (ast_rdlock_context(c)) {
|
||||
ast_log(LOG_WARNING, "Unable to lock context?\n");
|
||||
} else {
|
||||
e = find_matching_priority(c, ast_channel_exten(chan), ast_channel_priority(chan),
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid,
|
||||
ast_channel_caller(chan)->id.number.str, NULL),
|
||||
0, &had_infinite_include_error);
|
||||
if (e) { /* This will only be undefined for pbx_realtime, which is majorly broken. */
|
||||
ast_copy_string(runningapp, ast_get_extension_app(e), sizeof(runningapp));
|
||||
ast_copy_string(runningdata, ast_get_extension_app_data(e), sizeof(runningdata));
|
||||
}
|
||||
ast_unlock_context(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast_unlock_contexts();
|
||||
|
||||
/* Reset the macro depth, if it was changed in the last iteration */
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
|
||||
|
||||
res = ast_spawn_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan),
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
|
||||
&foundx, 1);
|
||||
if (res) {
|
||||
/* Something bad happened, or a hangup has been requested. */
|
||||
if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
|
||||
(res == '*') || (res == '#')) {
|
||||
/* Just return result as to the previous application as if it had been dialed */
|
||||
ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
|
||||
break;
|
||||
}
|
||||
switch(res) {
|
||||
case MACRO_EXIT_RESULT:
|
||||
res = 0;
|
||||
goto out;
|
||||
default:
|
||||
ast_debug(2, "Spawn extension (%s,%s,%d) exited non-zero on '%s' in macro '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan), macro);
|
||||
ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s' in macro '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan), macro);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ast_debug(1, "Executed application: %s\n", runningapp);
|
||||
|
||||
if (!strcasecmp(runningapp, "GOSUB")) {
|
||||
gosub_level++;
|
||||
ast_debug(1, "Incrementing gosub_level\n");
|
||||
} else if (!strcasecmp(runningapp, "GOSUBIF")) {
|
||||
char *cond, *app_arg;
|
||||
char *app2;
|
||||
ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
|
||||
app2 = ast_str_buffer(tmp_subst);
|
||||
cond = strsep(&app2, "?");
|
||||
app_arg = strsep(&app2, ":");
|
||||
if (pbx_checkcondition(cond)) {
|
||||
if (!ast_strlen_zero(app_arg)) {
|
||||
gosub_level++;
|
||||
ast_debug(1, "Incrementing gosub_level\n");
|
||||
}
|
||||
} else {
|
||||
if (!ast_strlen_zero(app2)) {
|
||||
gosub_level++;
|
||||
ast_debug(1, "Incrementing gosub_level\n");
|
||||
}
|
||||
}
|
||||
} else if (!strcasecmp(runningapp, "RETURN")) {
|
||||
gosub_level--;
|
||||
ast_debug(1, "Decrementing gosub_level\n");
|
||||
} else if (!strcasecmp(runningapp, "STACKPOP")) {
|
||||
gosub_level--;
|
||||
ast_debug(1, "Decrementing gosub_level\n");
|
||||
} else if (!strncasecmp(runningapp, "EXEC", 4)) {
|
||||
/* Must evaluate args to find actual app */
|
||||
char *tmp2, *tmp3 = NULL;
|
||||
ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
|
||||
tmp2 = ast_str_buffer(tmp_subst);
|
||||
if (!strcasecmp(runningapp, "EXECIF")) {
|
||||
if ((tmp3 = strchr(tmp2, '|'))) {
|
||||
*tmp3++ = '\0';
|
||||
}
|
||||
if (!pbx_checkcondition(tmp2)) {
|
||||
tmp3 = NULL;
|
||||
}
|
||||
} else {
|
||||
tmp3 = tmp2;
|
||||
}
|
||||
|
||||
if (tmp3) {
|
||||
ast_debug(1, "Last app: %s\n", tmp3);
|
||||
}
|
||||
|
||||
if (tmp3 && !strncasecmp(tmp3, "GOSUB", 5)) {
|
||||
gosub_level++;
|
||||
ast_debug(1, "Incrementing gosub_level\n");
|
||||
} else if (tmp3 && !strncasecmp(tmp3, "RETURN", 6)) {
|
||||
gosub_level--;
|
||||
ast_debug(1, "Decrementing gosub_level\n");
|
||||
} else if (tmp3 && !strncasecmp(tmp3, "STACKPOP", 8)) {
|
||||
gosub_level--;
|
||||
ast_debug(1, "Decrementing gosub_level\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (gosub_level == 0 && strcasecmp(ast_channel_context(chan), fullmacro)) {
|
||||
ast_verb(2, "Channel '%s' jumping out of macro '%s'\n", ast_channel_name(chan), macro);
|
||||
break;
|
||||
}
|
||||
|
||||
/* don't stop executing extensions when we're in "h" */
|
||||
if (ast_check_hangup(chan) && !inhangup) {
|
||||
ast_debug(1, "Extension %s, macroexten %s, priority %d returned normally even though call was hung up\n",
|
||||
ast_channel_exten(chan),
|
||||
ast_channel_macroexten(chan),
|
||||
ast_channel_priority(chan));
|
||||
goto out;
|
||||
}
|
||||
ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
|
||||
}
|
||||
out:
|
||||
|
||||
/* Don't let the channel change now. */
|
||||
ast_channel_lock(chan);
|
||||
|
||||
/* Reset the depth back to what it was when the routine was entered (like if we called Macro recursively) */
|
||||
snprintf(depthc, sizeof(depthc), "%d", depth);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
|
||||
ast_set2_flag(ast_channel_flags(chan), autoloopflag, AST_FLAG_IN_AUTOLOOP);
|
||||
ast_set2_flag(ast_channel_flags(chan), save_in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
|
||||
|
||||
for (x = 1; x < argc; x++) {
|
||||
/* Restore old arguments and delete ours */
|
||||
snprintf(varname, sizeof(varname), "ARG%d", x);
|
||||
pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
|
||||
ast_free(oldargs[x]);
|
||||
}
|
||||
|
||||
/* Restore macro variables */
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
|
||||
ast_free(save_macro_exten);
|
||||
ast_free(save_macro_context);
|
||||
ast_free(save_macro_priority);
|
||||
|
||||
if (setmacrocontext) {
|
||||
ast_channel_macrocontext_set(chan, "");
|
||||
ast_channel_macroexten_set(chan, "");
|
||||
ast_channel_macropriority_set(chan, 0);
|
||||
}
|
||||
|
||||
if (!strcasecmp(ast_channel_context(chan), fullmacro)
|
||||
&& !(ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO)) {
|
||||
const char *offsets;
|
||||
|
||||
/* If we're leaving the macro normally, restore original information */
|
||||
ast_channel_priority_set(chan, oldpriority);
|
||||
ast_channel_context_set(chan, oldcontext);
|
||||
ast_channel_exten_set(chan, oldexten);
|
||||
if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
|
||||
/* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
|
||||
normally if there is any problem */
|
||||
if (sscanf(offsets, "%30d", &offset) == 1) {
|
||||
if (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan),
|
||||
ast_channel_priority(chan) + offset + 1,
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
|
||||
ast_channel_priority_set(chan, ast_channel_priority(chan) + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
|
||||
ast_free(save_macro_offset);
|
||||
|
||||
/* Unlock the macro */
|
||||
if (exclusive) {
|
||||
ast_debug(1, "Unlocking macrolock for '%s'\n", fullmacro);
|
||||
if (ast_context_unlockmacro(fullmacro)) {
|
||||
ast_log(LOG_ERROR, "Failed to unlock macro '%s' - that isn't good\n", fullmacro);
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
ast_channel_unlock(chan);
|
||||
ast_free(tmp_subst);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int macro_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
return _macro_exec(chan, data, 0);
|
||||
}
|
||||
|
||||
static int macroexclusive_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
return _macro_exec(chan, data, 1);
|
||||
}
|
||||
|
||||
static int macroif_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
char *expr = NULL, *label_a = NULL, *label_b = NULL;
|
||||
int res = 0;
|
||||
|
||||
expr = ast_strdupa(data);
|
||||
|
||||
if ((label_a = strchr(expr, '?'))) {
|
||||
*label_a = '\0';
|
||||
label_a++;
|
||||
if ((label_b = strchr(label_a, ':'))) {
|
||||
*label_b = '\0';
|
||||
label_b++;
|
||||
}
|
||||
if (pbx_checkcondition(expr))
|
||||
res = macro_exec(chan, label_a);
|
||||
else if (label_b)
|
||||
res = macro_exec(chan, label_b);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Invalid Syntax.\n");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int macro_exit_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
return MACRO_EXIT_RESULT;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(if_app);
|
||||
res |= ast_unregister_application(exit_app);
|
||||
res |= ast_unregister_application(app);
|
||||
res |= ast_unregister_application(exclusive_app);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_register_application_xml(exit_app, macro_exit_exec);
|
||||
res |= ast_register_application_xml(if_app, macroif_exec);
|
||||
res |= ast_register_application_xml(exclusive_app, macroexclusive_exec);
|
||||
res |= ast_register_application_xml(app, macro_exec);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD_DEPRECATED(ASTERISK_GPL_KEY, "Extension Macros");
|
2633
apps/app_meetme.c
2633
apps/app_meetme.c
File diff suppressed because it is too large
Load Diff
|
@ -1878,10 +1878,11 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
|
|||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
|
||||
"Unknown");
|
||||
snprintf(logbuf, sizeof(logbuf),
|
||||
/* "Mailbox:domain:exten:priority:callerchan:callerid:origdate:origtime:duration:durationstatus:accountcode" */
|
||||
"%s:%s:%s:%d:%s:%s:%s:%s:%d:%s:%s\n",
|
||||
/* "Mailbox:domain:macrocontext:exten:priority:callerchan:callerid:origdate:origtime:duration:durationstatus:accountcode" */
|
||||
"%s:%s:%s:%s:%d:%s:%s:%s:%s:%d:%s:%s\n",
|
||||
username,
|
||||
ast_channel_context(chan),
|
||||
ast_channel_macrocontext(chan),
|
||||
ast_channel_exten(chan),
|
||||
ast_channel_priority(chan),
|
||||
ast_channel_name(chan),
|
||||
|
@ -2139,6 +2140,8 @@ static int minivm_greet_exec(struct ast_channel *chan, const char *data)
|
|||
struct ast_flags flags = { 0 };
|
||||
char *opts[OPT_ARG_ARRAY_SIZE];
|
||||
int res = 0;
|
||||
int ausemacro = 0;
|
||||
int ousemacro = 0;
|
||||
int ouseexten = 0;
|
||||
char tmp[PATH_MAX];
|
||||
char dest[PATH_MAX];
|
||||
|
@ -2209,7 +2212,7 @@ static int minivm_greet_exec(struct ast_channel *chan, const char *data)
|
|||
}
|
||||
ast_debug(2, "Preparing to play message ...\n");
|
||||
|
||||
/* Check current context for special extensions */
|
||||
/* Check current or macro-calling context for special extensions */
|
||||
if (ast_test_flag(vmu, MVM_OPERATOR)) {
|
||||
if (!ast_strlen_zero(vmu->exit)) {
|
||||
if (ast_exists_extension(chan, vmu->exit, "o", 1,
|
||||
|
@ -2222,6 +2225,12 @@ static int minivm_greet_exec(struct ast_channel *chan, const char *data)
|
|||
strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
|
||||
ouseexten = 1;
|
||||
}
|
||||
else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
|
||||
&& ast_exists_extension(chan, ast_channel_macrocontext(chan), "o", 1,
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
|
||||
strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
|
||||
ousemacro = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(vmu->exit)) {
|
||||
|
@ -2232,6 +2241,11 @@ static int minivm_greet_exec(struct ast_channel *chan, const char *data)
|
|||
} else if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1,
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
|
||||
strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
|
||||
} else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
|
||||
&& ast_exists_extension(chan, ast_channel_macrocontext(chan), "a", 1,
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
|
||||
strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
|
||||
ausemacro = 1;
|
||||
}
|
||||
|
||||
res = 0; /* Reset */
|
||||
|
@ -2272,15 +2286,19 @@ static int minivm_greet_exec(struct ast_channel *chan, const char *data)
|
|||
ast_channel_exten_set(chan, "a");
|
||||
if (!ast_strlen_zero(vmu->exit)) {
|
||||
ast_channel_context_set(chan, vmu->exit);
|
||||
} else if (ausemacro && !ast_strlen_zero(ast_channel_macrocontext(chan))) {
|
||||
ast_channel_context_set(chan, ast_channel_macrocontext(chan));
|
||||
}
|
||||
ast_channel_priority_set(chan, 0);
|
||||
pbx_builtin_setvar_helper(chan, "MVM_GREET_STATUS", "USEREXIT");
|
||||
res = 0;
|
||||
} else if (res == '0') { /* Check for a '0' here */
|
||||
if(ouseexten) {
|
||||
if(ouseexten || ousemacro) {
|
||||
ast_channel_exten_set(chan, "o");
|
||||
if (!ast_strlen_zero(vmu->exit)) {
|
||||
ast_channel_context_set(chan, vmu->exit);
|
||||
} else if (ousemacro && !ast_strlen_zero(ast_channel_macrocontext(chan))) {
|
||||
ast_channel_context_set(chan, ast_channel_macrocontext(chan));
|
||||
}
|
||||
ast_play_and_wait(chan, "transfer");
|
||||
ast_channel_priority_set(chan, 0);
|
||||
|
|
|
@ -183,7 +183,10 @@
|
|||
function <variable>FILTER()</variable>.</para></warning>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">Monitor</ref>
|
||||
<ref type="application">StopMixMonitor</ref>
|
||||
<ref type="application">PauseMonitor</ref>
|
||||
<ref type="application">UnpauseMonitor</ref>
|
||||
<ref type="function">AUDIOHOOK_INHERIT</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
|
@ -386,6 +389,7 @@ struct mixmonitor {
|
|||
/* the below string fields describe data used for creating voicemails from the recording */
|
||||
AST_DECLARE_STRING_FIELDS(
|
||||
AST_STRING_FIELD(call_context);
|
||||
AST_STRING_FIELD(call_macrocontext);
|
||||
AST_STRING_FIELD(call_extension);
|
||||
AST_STRING_FIELD(call_callerchan);
|
||||
AST_STRING_FIELD(call_callerid);
|
||||
|
@ -656,6 +660,7 @@ static void copy_to_voicemail(struct mixmonitor *mixmonitor, const char *ext, co
|
|||
ast_string_field_set(&recording_data, recording_file, filename);
|
||||
ast_string_field_set(&recording_data, recording_ext, ext);
|
||||
ast_string_field_set(&recording_data, call_context, mixmonitor->call_context);
|
||||
ast_string_field_set(&recording_data, call_macrocontext, mixmonitor->call_macrocontext);
|
||||
ast_string_field_set(&recording_data, call_extension, mixmonitor->call_extension);
|
||||
ast_string_field_set(&recording_data, call_callerchan, mixmonitor->call_callerchan);
|
||||
ast_string_field_set(&recording_data, call_callerid, mixmonitor->call_callerid);
|
||||
|
@ -1070,6 +1075,7 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
|
|||
}
|
||||
|
||||
ast_string_field_set(mixmonitor, call_context, ast_channel_context(chan));
|
||||
ast_string_field_set(mixmonitor, call_macrocontext, ast_channel_macrocontext(chan));
|
||||
ast_string_field_set(mixmonitor, call_extension, ast_channel_exten(chan));
|
||||
ast_string_field_set(mixmonitor, call_callerchan, ast_channel_name(chan));
|
||||
ast_string_field_set(mixmonitor, call_callerid, callerid);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
134
apps/app_queue.c
134
apps/app_queue.c
|
@ -41,6 +41,7 @@
|
|||
* - Position announcement
|
||||
* - Abandoned/completed call counters
|
||||
* - Failout timer passed as optional app parameter
|
||||
* - Optional monitoring of calls, started when call is answered
|
||||
*
|
||||
* Patch Version 1.07 2003-12-24 01
|
||||
*
|
||||
|
@ -62,6 +63,7 @@
|
|||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<use type="module">res_monitor</use>
|
||||
<support_level>core</support_level>
|
||||
***/
|
||||
|
||||
|
@ -86,6 +88,7 @@
|
|||
#include "asterisk/cli.h"
|
||||
#include "asterisk/manager.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/monitor.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/causes.h"
|
||||
#include "asterisk/astdb.h"
|
||||
|
@ -171,7 +174,7 @@
|
|||
to the specified destination and <emphasis>start</emphasis> execution at that location.</para>
|
||||
<para>NOTE: Any channel variables you want the called channel to inherit from the caller channel must be
|
||||
prefixed with one or two underbars ('_').</para>
|
||||
<para>NOTE: Using this option from a GoSub() might not make sense as there would be no return points.</para>
|
||||
<para>NOTE: Using this option from a Macro() or GoSub() might not make sense as there would be no return points.</para>
|
||||
</option>
|
||||
<option name="h">
|
||||
<para>Allow <emphasis>callee</emphasis> to hang up by pressing <literal>*</literal>.</para>
|
||||
|
@ -216,6 +219,14 @@
|
|||
<option name="T">
|
||||
<para>Allow the <emphasis>calling</emphasis> user to transfer the call.</para>
|
||||
</option>
|
||||
<option name="w">
|
||||
<para>Allow the <emphasis>called</emphasis> user to write the conversation to
|
||||
disk via Monitor.</para>
|
||||
</option>
|
||||
<option name="W">
|
||||
<para>Allow the <emphasis>calling</emphasis> user to write the conversation to
|
||||
disk via Monitor.</para>
|
||||
</option>
|
||||
<option name="x">
|
||||
<para>Allow the <emphasis>called</emphasis> user to write the conversation
|
||||
to disk via MixMonitor.</para>
|
||||
|
@ -252,6 +263,10 @@
|
|||
<para>Will setup an AGI script to be executed on the calling party's channel once they are
|
||||
connected to a queue member.</para>
|
||||
</parameter>
|
||||
<parameter name="macro">
|
||||
<para>Will run a macro on the called party's channel (the queue member) once the parties are connected.</para>
|
||||
<para>NOTE: Macros are deprecated, GoSub should be used instead.</para>
|
||||
</parameter>
|
||||
<parameter name="gosub">
|
||||
<para>Will run a gosub on the called party's channel (the queue member)
|
||||
once the parties are connected. The subroutine execution starts in the
|
||||
|
@ -1798,6 +1813,8 @@ struct call_queue {
|
|||
AST_STRING_FIELD(announce);
|
||||
/*! Exit context */
|
||||
AST_STRING_FIELD(context);
|
||||
/*! Macro to run upon member connection */
|
||||
AST_STRING_FIELD(membermacro);
|
||||
/*! Gosub to run upon member connection */
|
||||
AST_STRING_FIELD(membergosub);
|
||||
/*! Default rule to use if none specified in call to Queue() */
|
||||
|
@ -1865,6 +1882,7 @@ struct call_queue {
|
|||
int servicelevel; /*!< seconds setting for servicelevel*/
|
||||
int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
|
||||
char monfmt[8]; /*!< Format to use when recording calls */
|
||||
int montype; /*!< Monitor type Monitor vs. MixMonitor */
|
||||
int count; /*!< How many entries */
|
||||
int maxlen; /*!< Max number of entries */
|
||||
int wrapuptime; /*!< Wrapup Time */
|
||||
|
@ -2956,6 +2974,7 @@ static void init_queue(struct call_queue *q)
|
|||
|
||||
ast_string_field_set(q, announce, "");
|
||||
ast_string_field_set(q, context, "");
|
||||
ast_string_field_set(q, membermacro, "");
|
||||
ast_string_field_set(q, membergosub, "");
|
||||
ast_string_field_set(q, defaultrule, "");
|
||||
|
||||
|
@ -2973,6 +2992,7 @@ static void init_queue(struct call_queue *q)
|
|||
q->setqueuevar = 0;
|
||||
q->setqueueentryvar = 0;
|
||||
q->autofill = autofill_default;
|
||||
q->montype = montype_default;
|
||||
q->monfmt[0] = '\0';
|
||||
q->reportholdtime = 0;
|
||||
q->wrapuptime = 0;
|
||||
|
@ -3350,6 +3370,8 @@ static void queue_set_param(struct call_queue *q, const char *param, const char
|
|||
q->setqueueentryvar = ast_true(val);
|
||||
} else if (!strcasecmp(param, "monitor-format")) {
|
||||
ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
|
||||
} else if (!strcasecmp(param, "membermacro")) {
|
||||
ast_string_field_set(q, membermacro, val);
|
||||
} else if (!strcasecmp(param, "membergosub")) {
|
||||
ast_string_field_set(q, membergosub, val);
|
||||
} else if (!strcasecmp(param, "queue-youarenext")) {
|
||||
|
@ -3461,6 +3483,10 @@ static void queue_set_param(struct call_queue *q, const char *param, const char
|
|||
}
|
||||
} else if (!strcasecmp(param, "autofill")) {
|
||||
q->autofill = ast_true(val);
|
||||
} else if (!strcasecmp(param, "monitor-type")) {
|
||||
if (!strcasecmp(val, "mixmonitor")) {
|
||||
q->montype = 1;
|
||||
}
|
||||
} else if (!strcasecmp(param, "autopause")) {
|
||||
q->autopause = autopause2int(val);
|
||||
} else if (!strcasecmp(param, "autopausedelay")) {
|
||||
|
@ -4751,6 +4777,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
|
|||
int status;
|
||||
char tech[256];
|
||||
char *location;
|
||||
const char *macrocontext, *macroexten;
|
||||
struct ast_format_cap *nativeformats;
|
||||
RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
|
||||
|
||||
|
@ -4811,8 +4838,8 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
|
|||
ast_channel_set_caller_event(tmp->chan, &caller, NULL);
|
||||
} else if (!ast_strlen_zero(ast_channel_dialed(qe->chan)->number.str)) {
|
||||
ast_set_callerid(tmp->chan, ast_channel_dialed(qe->chan)->number.str, NULL, NULL);
|
||||
} else if (!ast_strlen_zero(ast_channel_exten(qe->chan))) {
|
||||
ast_set_callerid(tmp->chan, ast_channel_exten(qe->chan), NULL, NULL);
|
||||
} else if (!ast_strlen_zero(S_OR(ast_channel_macroexten(qe->chan), ast_channel_exten(qe->chan)))) {
|
||||
ast_set_callerid(tmp->chan, S_OR(ast_channel_macroexten(qe->chan), ast_channel_exten(qe->chan)), NULL, NULL);
|
||||
}
|
||||
tmp->dial_callerid_absent = 1;
|
||||
}
|
||||
|
@ -4832,8 +4859,14 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
|
|||
ast_channel_adsicpe_set(tmp->chan, ast_channel_adsicpe(qe->chan));
|
||||
|
||||
/* Inherit context and extension */
|
||||
ast_channel_dialcontext_set(tmp->chan, ast_channel_context(qe->chan));
|
||||
ast_channel_exten_set(tmp->chan, ast_channel_exten(qe->chan));
|
||||
macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
|
||||
ast_channel_dialcontext_set(tmp->chan, ast_strlen_zero(macrocontext) ? ast_channel_context(qe->chan) : macrocontext);
|
||||
macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
|
||||
if (!ast_strlen_zero(macroexten)) {
|
||||
ast_channel_exten_set(tmp->chan, macroexten);
|
||||
} else {
|
||||
ast_channel_exten_set(tmp->chan, ast_channel_exten(qe->chan));
|
||||
}
|
||||
|
||||
/* Save the original channel name to detect call pickup masquerading in. */
|
||||
tmp->orig_chan_name = ast_strdup(ast_channel_name(tmp->chan));
|
||||
|
@ -5177,7 +5210,8 @@ static void update_connected_line_from_peer(struct ast_channel *chan, struct ast
|
|||
ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(peer));
|
||||
ast_channel_unlock(peer);
|
||||
connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
|
||||
if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)) {
|
||||
if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)
|
||||
&& ast_channel_connected_line_macro(peer, chan, &connected_caller, is_caller, 0)) {
|
||||
ast_channel_update_connected_line(chan, &connected_caller, NULL);
|
||||
}
|
||||
ast_party_connected_line_free(&connected_caller);
|
||||
|
@ -5297,7 +5331,8 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
|||
update_connected_line_from_peer(in, o->chan, 1);
|
||||
} else if (!o->block_connected_update) {
|
||||
if (o->pending_connected_update) {
|
||||
if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0)) {
|
||||
if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0) &&
|
||||
ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
|
||||
ast_channel_update_connected_line(in, &o->connected, NULL);
|
||||
}
|
||||
} else if (!o->dial_callerid_absent) {
|
||||
|
@ -5407,7 +5442,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
|||
ast_party_number_init(&ast_channel_redirecting(o->chan)->from.number);
|
||||
ast_channel_redirecting(o->chan)->from.number.valid = 1;
|
||||
ast_channel_redirecting(o->chan)->from.number.str =
|
||||
ast_strdup(ast_channel_exten(in));
|
||||
ast_strdup(S_OR(ast_channel_macroexten(in), ast_channel_exten(in)));
|
||||
}
|
||||
|
||||
ast_channel_dialed(o->chan)->transit_network_select = ast_channel_dialed(in)->transit_network_select;
|
||||
|
@ -5426,13 +5461,17 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
|||
* Redirecting updates to the caller make sense only on single
|
||||
* call at a time strategies.
|
||||
*
|
||||
* Need to re-evaluate if calling unlock is still required as we no longer
|
||||
* use macro.
|
||||
* We must unlock o->chan before calling
|
||||
* ast_channel_redirecting_macro, because we put o->chan into
|
||||
* autoservice there. That is pretty much a guaranteed
|
||||
* deadlock. This is why the handling of o->chan's lock may
|
||||
* seem a bit unusual here.
|
||||
*/
|
||||
ast_party_redirecting_init(&redirecting);
|
||||
ast_party_redirecting_copy(&redirecting, ast_channel_redirecting(o->chan));
|
||||
ast_channel_unlock(o->chan);
|
||||
if (ast_channel_redirecting_sub(o->chan, in, &redirecting, 0)) {
|
||||
if (ast_channel_redirecting_sub(o->chan, in, &redirecting, 0) &&
|
||||
ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0)) {
|
||||
ast_channel_update_redirecting(in, &redirecting, NULL);
|
||||
}
|
||||
ast_party_redirecting_free(&redirecting);
|
||||
|
@ -5481,7 +5520,8 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
|||
update_connected_line_from_peer(in, o->chan, 1);
|
||||
} else if (!o->block_connected_update) {
|
||||
if (o->pending_connected_update) {
|
||||
if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0)) {
|
||||
if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0) &&
|
||||
ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
|
||||
ast_channel_update_connected_line(in, &o->connected, NULL);
|
||||
}
|
||||
} else if (!o->dial_callerid_absent) {
|
||||
|
@ -5573,7 +5613,8 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
|||
*/
|
||||
o->dial_callerid_absent = 1;
|
||||
|
||||
if (ast_channel_connected_line_sub(o->chan, in, f, 1)) {
|
||||
if (ast_channel_connected_line_sub(o->chan, in, f, 1) &&
|
||||
ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
|
||||
ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
|
||||
}
|
||||
break;
|
||||
|
@ -5603,7 +5644,8 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
|||
}
|
||||
ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
|
||||
ochan_name, inchan_name);
|
||||
if (ast_channel_redirecting_sub(o->chan, in, f, 1)) {
|
||||
if (ast_channel_redirecting_sub(o->chan, in, f, 1) &&
|
||||
ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
|
||||
ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
|
||||
}
|
||||
break;
|
||||
|
@ -5684,7 +5726,8 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
|||
ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(o->chan));
|
||||
break;
|
||||
}
|
||||
if (ast_channel_connected_line_sub(in, o->chan, f, 1)) {
|
||||
if (ast_channel_connected_line_sub(in, o->chan, f, 1) &&
|
||||
ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) {
|
||||
ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
|
||||
}
|
||||
break;
|
||||
|
@ -5693,7 +5736,8 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
|||
ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(o->chan));
|
||||
break;
|
||||
}
|
||||
if (ast_channel_redirecting_sub(in, o->chan, f, 1)) {
|
||||
if (ast_channel_redirecting_sub(in, o->chan, f, 1) &&
|
||||
ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) {
|
||||
ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
|
||||
}
|
||||
break;
|
||||
|
@ -6967,10 +7011,11 @@ static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
|
|||
* \param[in,out] tries the number of times we have tried calling queue members
|
||||
* \param[out] noption set if the call to Queue() has the 'n' option set.
|
||||
* \param[in] agi the agi passed as the fifth parameter to the Queue() application
|
||||
* \param[in] macro the macro passed as the sixth parameter to the Queue() application
|
||||
* \param[in] gosub the gosub passed as the seventh parameter to the Queue() application
|
||||
* \param[in] ringing 1 if the 'r' option is set, otherwise 0
|
||||
*/
|
||||
static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *gosub, int ringing)
|
||||
static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
|
||||
{
|
||||
struct member *cur;
|
||||
struct callattempt *outgoing = NULL; /* the list of calls we are building */
|
||||
|
@ -6979,6 +7024,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
|
|||
char oldcontext[AST_MAX_CONTEXT]="";
|
||||
char queuename[256]="";
|
||||
struct ast_channel *peer;
|
||||
struct ast_channel *which;
|
||||
struct callattempt *lpeer;
|
||||
struct member *member;
|
||||
struct ast_app *application;
|
||||
|
@ -6991,8 +7037,10 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
|
|||
struct ast_bridge_config bridge_config;
|
||||
char nondataquality = 1;
|
||||
char *agiexec = NULL;
|
||||
char *macroexec = NULL;
|
||||
char *gosubexec = NULL;
|
||||
const char *monitorfilename;
|
||||
char tmpid[256];
|
||||
int forwardsallowed = 1;
|
||||
int block_connected_line = 0;
|
||||
struct ao2_iterator memi;
|
||||
|
@ -7001,6 +7049,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
|
|||
time_t starttime;
|
||||
|
||||
memset(&bridge_config, 0, sizeof(bridge_config));
|
||||
tmpid[0] = 0;
|
||||
time(&now);
|
||||
|
||||
/* If we've already exceeded our timeout, then just stop
|
||||
|
@ -7321,7 +7370,32 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
|
|||
|
||||
/* Begin Monitoring */
|
||||
if (*qe->parent->monfmt) {
|
||||
setup_mixmonitor(qe, monitorfilename);
|
||||
if (!qe->parent->montype) {
|
||||
const char *monexec;
|
||||
ast_debug(1, "Starting Monitor as requested.\n");
|
||||
ast_channel_lock(qe->chan);
|
||||
if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) {
|
||||
which = qe->chan;
|
||||
monexec = monexec ? ast_strdupa(monexec) : NULL;
|
||||
} else {
|
||||
which = peer;
|
||||
}
|
||||
ast_channel_unlock(qe->chan);
|
||||
if (monitorfilename) {
|
||||
ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT, NULL);
|
||||
} else if (qe->chan) {
|
||||
ast_monitor_start(which, qe->parent->monfmt, ast_channel_uniqueid(qe->chan), 1, X_REC_IN | X_REC_OUT, NULL);
|
||||
} else {
|
||||
/* Last ditch effort -- no channel, make up something */
|
||||
snprintf(tmpid, sizeof(tmpid), "chan-%lx", (unsigned long)ast_random());
|
||||
ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT, NULL);
|
||||
}
|
||||
if (!ast_strlen_zero(monexec)) {
|
||||
ast_monitor_setjoinfiles(which, 1);
|
||||
}
|
||||
} else {
|
||||
setup_mixmonitor(qe, monitorfilename);
|
||||
}
|
||||
}
|
||||
/* Drop out of the queue at this point, to prepare for next caller */
|
||||
leave_queue(qe);
|
||||
|
@ -7330,6 +7404,21 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
|
|||
ast_channel_sendurl(peer, url);
|
||||
}
|
||||
|
||||
/* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
|
||||
/* use macro from dialplan if passed as a option, otherwise use the default queue macro */
|
||||
if (!ast_strlen_zero(macro)) {
|
||||
macroexec = ast_strdupa(macro);
|
||||
} else {
|
||||
if (qe->parent->membermacro) {
|
||||
macroexec = ast_strdupa(qe->parent->membermacro);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(macroexec)) {
|
||||
ast_debug(1, "app_queue: macro=%s.\n", macroexec);
|
||||
ast_app_exec_macro(qe->chan, peer, macroexec);
|
||||
}
|
||||
|
||||
/* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
|
||||
/* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
|
||||
if (!ast_strlen_zero(gosub)) {
|
||||
|
@ -8529,6 +8618,7 @@ static int queue_exec(struct ast_channel *chan, const char *data)
|
|||
AST_APP_ARG(announceoverride);
|
||||
AST_APP_ARG(queuetimeoutstr);
|
||||
AST_APP_ARG(agi);
|
||||
AST_APP_ARG(macro);
|
||||
AST_APP_ARG(gosub);
|
||||
AST_APP_ARG(rule);
|
||||
AST_APP_ARG(position);
|
||||
|
@ -8540,7 +8630,7 @@ static int queue_exec(struct ast_channel *chan, const char *data)
|
|||
int max_forwards;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,gosub[,rule[,position]]]]]]]]\n");
|
||||
ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -8556,13 +8646,14 @@ static int queue_exec(struct ast_channel *chan, const char *data)
|
|||
parse = ast_strdupa(data);
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, timeout: %s, agi: %s, gosub: %s, rule: %s, position: %s\n",
|
||||
ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, timeout: %s, agi: %s, macro: %s, gosub: %s, rule: %s, position: %s\n",
|
||||
args.queuename,
|
||||
S_OR(args.options, ""),
|
||||
S_OR(args.url, ""),
|
||||
S_OR(args.announceoverride, ""),
|
||||
S_OR(args.queuetimeoutstr, ""),
|
||||
S_OR(args.agi, ""),
|
||||
S_OR(args.macro, ""),
|
||||
S_OR(args.gosub, ""),
|
||||
S_OR(args.rule, ""),
|
||||
S_OR(args.position, ""));
|
||||
|
@ -8788,7 +8879,7 @@ check_turns:
|
|||
}
|
||||
|
||||
/* Try calling all queue members for 'timeout' seconds */
|
||||
res = try_calling(&qe, opts, opt_args, args.announceoverride, args.url, &tries, &noption, args.agi, args.gosub, ringing);
|
||||
res = try_calling(&qe, opts, opt_args, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing);
|
||||
if (res) {
|
||||
goto stop;
|
||||
}
|
||||
|
@ -11936,4 +12027,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "True Call Queueing",
|
|||
.unload = unload_module,
|
||||
.reload = reload,
|
||||
.load_pri = AST_MODPRI_DEVSTATE_CONSUMER,
|
||||
.optional_modules = "res_monitor",
|
||||
);
|
||||
|
|
|
@ -113,7 +113,8 @@
|
|||
</para>
|
||||
<note><para>The text encoding and transmission method is completely at the
|
||||
discretion of the channel driver. chan_pjsip will use in-dialog SIP MESSAGE
|
||||
messages always.</para></note>
|
||||
messages always. chan_sip will use T.140 via RTP if a text media type was
|
||||
negotiated and in-dialog SIP MESSAGE messages otherwise.</para></note>
|
||||
<para>
|
||||
</para>
|
||||
<para>Examples:
|
||||
|
|
2875
apps/app_sla.c
2875
apps/app_sla.c
File diff suppressed because it is too large
Load Diff
|
@ -58,6 +58,7 @@
|
|||
</description>
|
||||
<see-also>
|
||||
<ref type="application">GosubIf</ref>
|
||||
<ref type="application">Macro</ref>
|
||||
<ref type="application">Goto</ref>
|
||||
<ref type="application">Return</ref>
|
||||
<ref type="application">StackPop</ref>
|
||||
|
@ -92,6 +93,7 @@
|
|||
<see-also>
|
||||
<ref type="application">Gosub</ref>
|
||||
<ref type="application">Return</ref>
|
||||
<ref type="application">MacroIf</ref>
|
||||
<ref type="function">IF</ref>
|
||||
<ref type="application">GotoIf</ref>
|
||||
<ref type="application">Goto</ref>
|
||||
|
|
|
@ -4374,7 +4374,7 @@ static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailbox
|
|||
|
||||
snprintf(msgnums, sizeof(msgnums), "%d", smsg);
|
||||
snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
|
||||
snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, msg_id, context, callerid, origtime, duration, recording, flag, mailboxuser, mailboxcontext) SELECT ?,?,?,context,callerid,origtime,duration,recording,flag,?,? FROM %s WHERE dir=? AND msgnum=?", odbc_table, odbc_table);
|
||||
snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, msg_id, context, macrocontext, callerid, origtime, duration, recording, flag, mailboxuser, mailboxcontext) SELECT ?,?,?,context,macrocontext,callerid,origtime,duration,recording,flag,?,? FROM %s WHERE dir=? AND msgnum=?", odbc_table, odbc_table);
|
||||
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
|
||||
if (!stmt)
|
||||
ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
|
||||
|
@ -4393,6 +4393,7 @@ struct insert_data {
|
|||
SQLLEN datalen;
|
||||
SQLLEN indlen;
|
||||
const char *context;
|
||||
const char *macrocontext;
|
||||
const char *callerid;
|
||||
const char *origtime;
|
||||
const char *duration;
|
||||
|
@ -4419,15 +4420,16 @@ static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
|
|||
SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
|
||||
SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
|
||||
SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
|
||||
SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
|
||||
SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
|
||||
SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
|
||||
SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
|
||||
SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
|
||||
SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
|
||||
SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msg_id), 0, (void *) data->msg_id, 0, NULL);
|
||||
SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
|
||||
SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
|
||||
SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
|
||||
SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
|
||||
SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
|
||||
SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
|
||||
SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
|
||||
SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msg_id), 0, (void *) data->msg_id, 0, NULL);
|
||||
if (!ast_strlen_zero(data->category)) {
|
||||
SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
|
||||
SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
|
||||
}
|
||||
res = ast_odbc_execute_sql(obj, stmt, data->sql);
|
||||
if (!SQL_SUCCEEDED(res)) {
|
||||
|
@ -4468,7 +4470,7 @@ static int store_file(const char *dir, const char *mailboxuser, const char *mail
|
|||
struct ast_config *cfg = NULL;
|
||||
struct odbc_obj *obj;
|
||||
struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
|
||||
.context = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "", .msg_id = "" };
|
||||
.context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "", .msg_id = "" };
|
||||
struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
|
||||
|
||||
delete_file(dir, msgnum);
|
||||
|
@ -4504,6 +4506,9 @@ static int store_file(const char *dir, const char *mailboxuser, const char *mail
|
|||
if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
|
||||
idata.context = "";
|
||||
}
|
||||
if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
|
||||
idata.macrocontext = "";
|
||||
}
|
||||
if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
|
||||
idata.callerid = "";
|
||||
}
|
||||
|
@ -4539,9 +4544,9 @@ static int store_file(const char *dir, const char *mailboxuser, const char *mail
|
|||
idata.datalen = idata.indlen = fdlen;
|
||||
|
||||
if (!ast_strlen_zero(idata.category))
|
||||
snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
|
||||
snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
|
||||
else
|
||||
snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
|
||||
snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
|
||||
|
||||
if (ast_strlen_zero(idata.origtime)) {
|
||||
idata.origtime = "0";
|
||||
|
@ -4821,7 +4826,7 @@ static void copy_plain_file(char *frompath, char *topath)
|
|||
{
|
||||
char frompath2[PATH_MAX], topath2[PATH_MAX];
|
||||
struct ast_variable *tmp, *var = NULL;
|
||||
const char *origmailbox = "", *context = "", *exten = "";
|
||||
const char *origmailbox = "", *context = "", *macrocontext = "", *exten = "";
|
||||
const char *priority = "", *callerchan = "", *callerid = "", *origdate = "";
|
||||
const char *origtime = "", *category = "", *duration = "";
|
||||
|
||||
|
@ -4837,6 +4842,8 @@ static void copy_plain_file(char *frompath, char *topath)
|
|||
origmailbox = tmp->value;
|
||||
} else if (!strcasecmp(tmp->name, "context")) {
|
||||
context = tmp->value;
|
||||
} else if (!strcasecmp(tmp->name, "macrocontext")) {
|
||||
macrocontext = tmp->value;
|
||||
} else if (!strcasecmp(tmp->name, "exten")) {
|
||||
exten = tmp->value;
|
||||
} else if (!strcasecmp(tmp->name, "priority")) {
|
||||
|
@ -4855,7 +4862,7 @@ static void copy_plain_file(char *frompath, char *topath)
|
|||
duration = tmp->value;
|
||||
}
|
||||
}
|
||||
ast_store_realtime("voicemail_data", "filename", topath, "origmailbox", origmailbox, "context", context, "exten", exten, "priority", priority, "callerchan", callerchan, "callerid", callerid, "origdate", origdate, "origtime", origtime, "category", category, "duration", duration, SENTINEL);
|
||||
ast_store_realtime("voicemail_data", "filename", topath, "origmailbox", origmailbox, "context", context, "macrocontext", macrocontext, "exten", exten, "priority", priority, "callerchan", callerchan, "callerid", callerid, "origdate", origdate, "origtime", origtime, "category", category, "duration", duration, SENTINEL);
|
||||
}
|
||||
copy(frompath2, topath2);
|
||||
ast_variables_destroy(var);
|
||||
|
@ -6405,6 +6412,7 @@ static int msg_create_from_file(struct ast_vm_recording_data *recdata)
|
|||
"[message]\n"
|
||||
"origmailbox=%s\n"
|
||||
"context=%s\n"
|
||||
"macrocontext=%s\n"
|
||||
"exten=%s\n"
|
||||
"rdnis=Unknown\n"
|
||||
"priority=%d\n"
|
||||
|
@ -6419,6 +6427,7 @@ static int msg_create_from_file(struct ast_vm_recording_data *recdata)
|
|||
|
||||
recdata->mailbox,
|
||||
S_OR(recdata->call_context, ""),
|
||||
S_OR(recdata->call_macrocontext, ""),
|
||||
S_OR(recdata->call_extension, ""),
|
||||
recdata->call_priority,
|
||||
S_OR(recdata->call_callerchan, "Unknown"),
|
||||
|
@ -6565,6 +6574,7 @@ static int msg_create_from_file(struct ast_vm_recording_data *recdata)
|
|||
ast_store_realtime("voicemail_data",
|
||||
"origmailbox", recdata->mailbox,
|
||||
"context", S_OR(recdata->context, ""),
|
||||
"macrocontext", S_OR(recdata->call_macrocontext, ""),
|
||||
"exten", S_OR(recdata->call_extension, ""),
|
||||
"priority", recdata->call_priority,
|
||||
"callerchan", S_OR(recdata->call_callerchan, "Unknown"),
|
||||
|
@ -6632,6 +6642,8 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
|
|||
int msgnum;
|
||||
int duration = 0;
|
||||
int sound_duration = 0;
|
||||
int ausemacro = 0;
|
||||
int ousemacro = 0;
|
||||
int ouseexten = 0;
|
||||
int greeting_only = 0;
|
||||
char tmpdur[16];
|
||||
|
@ -6742,7 +6754,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Check current context for special extensions */
|
||||
/* Check current or macro-calling context for special extensions */
|
||||
if (ast_test_flag(vmu, VM_OPERATOR)) {
|
||||
if (!ast_strlen_zero(vmu->exit)) {
|
||||
if (ast_exists_extension(chan, vmu->exit, "o", 1,
|
||||
|
@ -6754,6 +6766,11 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
|
|||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
|
||||
strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
|
||||
ouseexten = 1;
|
||||
} else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
|
||||
&& ast_exists_extension(chan, ast_channel_macrocontext(chan), "o", 1,
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
|
||||
strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
|
||||
ousemacro = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6765,6 +6782,11 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
|
|||
} else if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1,
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
|
||||
strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
|
||||
} else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
|
||||
&& ast_exists_extension(chan, ast_channel_macrocontext(chan), "a", 1,
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
|
||||
strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
|
||||
ausemacro = 1;
|
||||
}
|
||||
|
||||
if (ast_test_flag(options, OPT_DTMFEXIT)) {
|
||||
|
@ -6835,6 +6857,8 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
|
|||
ast_channel_exten_set(chan, "a");
|
||||
if (!ast_strlen_zero(vmu->exit)) {
|
||||
ast_channel_context_set(chan, vmu->exit);
|
||||
} else if (ausemacro && !ast_strlen_zero(ast_channel_macrocontext(chan))) {
|
||||
ast_channel_context_set(chan, ast_channel_macrocontext(chan));
|
||||
}
|
||||
ast_channel_priority_set(chan, 0);
|
||||
free_user(vmu);
|
||||
|
@ -6846,10 +6870,12 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
|
|||
/* Check for a '0' here */
|
||||
if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
|
||||
transfer:
|
||||
if (ouseexten) {
|
||||
if (ouseexten || ousemacro) {
|
||||
ast_channel_exten_set(chan, "o");
|
||||
if (!ast_strlen_zero(vmu->exit)) {
|
||||
ast_channel_context_set(chan, vmu->exit);
|
||||
} else if (ousemacro && !ast_strlen_zero(ast_channel_macrocontext(chan))) {
|
||||
ast_channel_context_set(chan, ast_channel_macrocontext(chan));
|
||||
}
|
||||
ast_play_and_wait(chan, "transfer");
|
||||
ast_channel_priority_set(chan, 0);
|
||||
|
@ -6973,6 +6999,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
|
|||
ast_store_realtime("voicemail_data",
|
||||
"origmailbox", ext,
|
||||
"context", ast_channel_context(chan),
|
||||
"macrocontext", ast_channel_macrocontext(chan),
|
||||
"exten", ast_channel_exten(chan),
|
||||
"priority", priority,
|
||||
"callerchan", ast_channel_name(chan),
|
||||
|
@ -7000,6 +7027,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
|
|||
"[message]\n"
|
||||
"origmailbox=%s\n"
|
||||
"context=%s\n"
|
||||
"macrocontext=%s\n"
|
||||
"exten=%s\n"
|
||||
"rdnis=%s\n"
|
||||
"priority=%d\n"
|
||||
|
@ -7011,6 +7039,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
|
|||
"msg_id=%s\n",
|
||||
ext,
|
||||
ast_channel_context(chan),
|
||||
ast_channel_macrocontext(chan),
|
||||
ast_channel_exten(chan),
|
||||
S_COR(ast_channel_redirecting(chan)->from.number.valid,
|
||||
ast_channel_redirecting(chan)->from.number.str, "unknown"),
|
||||
|
@ -8969,6 +8998,8 @@ static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struc
|
|||
category = ast_variable_retrieve(msg_cfg, "message", "category");
|
||||
|
||||
context = ast_variable_retrieve(msg_cfg, "message", "context");
|
||||
if (!strncasecmp("macro", context, 5)) /* Macro names in contexts are useless for our needs */
|
||||
context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
|
||||
if (!res) {
|
||||
res = play_message_category(chan, category);
|
||||
}
|
||||
|
@ -16043,6 +16074,8 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s
|
|||
cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
|
||||
|
||||
context = ast_variable_retrieve(msg_cfg, "message", "context");
|
||||
if (!strncasecmp("macro", context, 5)) /* Macro names in contexts are useless for our needs */
|
||||
context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
|
||||
switch (option) {
|
||||
case 3: /* Play message envelope */
|
||||
if (!res) {
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
dnl
|
||||
dnl @synopsis AST_CHECK_OSPTK([REQ_VER_MAJOR],[REQ_VER_MINOR],[REQ_VER_BUGFIX])
|
||||
dnl
|
||||
dnl @summary check for existence of OSP Toolkit package
|
||||
dnl
|
||||
dnl This macro check for existence of OSP Toolkit package by checking osp/osp.h
|
||||
dnl header file, OSPPInit function and OSP Toolkit version.
|
||||
dnl
|
||||
AC_DEFUN([AST_CHECK_OSPTK],
|
||||
[
|
||||
# if OSPTK has not been checked and is not excluded
|
||||
if test "x${PBX_OSPTK}" != "x1" -a "${USE_OSPTK}" != "no"; then
|
||||
# if --with-osptk=DIR has been specified, use it.
|
||||
if test "x${OSPTK_DIR}" != "x"; then
|
||||
osptk_cflags="-I${OSPTK_DIR}/include"
|
||||
osptk_ldflags="-L${OSPTK_DIR}/lib"
|
||||
else
|
||||
osptk_cflags=""
|
||||
osptk_ldflags=""
|
||||
fi
|
||||
|
||||
# check for the header
|
||||
osptk_saved_cppflags="${CPPFLAGS}"
|
||||
CPPFLAGS="${CPPFLAGS} ${osptk_cflags}"
|
||||
AC_CHECK_HEADER([osp/osp.h], [osptk_header_found=yes], [osptk_header_found=no])
|
||||
CPPFLAGS="${osptk_saved_cppflags}"
|
||||
|
||||
# check for the library
|
||||
if test "${osptk_header_found}" = "yes"; then
|
||||
osptk_extralibs="-lssl -lcrypto"
|
||||
|
||||
AC_CHECK_LIB([osptk], [OSPPInit], [osptk_library_found=yes], [osptk_library_found=no], ${osptk_ldflags} ${osptk_extralibs})
|
||||
|
||||
# check OSP Toolkit version
|
||||
if test "${osptk_library_found}" = "yes"; then
|
||||
AC_MSG_CHECKING(if OSP Toolkit version is compatible with app_osplookup)
|
||||
|
||||
osptk_saved_cppflags="${CPPFLAGS}"
|
||||
CPPFLAGS="${CPPFLAGS} ${osptk_cflags}"
|
||||
AC_RUN_IFELSE(
|
||||
[AC_LANG_SOURCE([[
|
||||
#include <osp/osp.h>
|
||||
int main(void) {
|
||||
int ver = OSP_CLIENT_TOOLKIT_VERSION_MAJOR * 10000 + OSP_CLIENT_TOOLKIT_VERSION_MINOR * 100 + OSP_CLIENT_TOOLKIT_VERSION_BUGFIX;
|
||||
int req = $1 * 10000 + $2 * 100 + $3;
|
||||
return (ver < req) ? 1 : 0;
|
||||
}
|
||||
]])],
|
||||
[osptk_compatible=yes],
|
||||
[osptk_compatible=no]
|
||||
)
|
||||
CPPFLAGS="${osptk_saved_cppflags}"
|
||||
|
||||
if test "${osptk_compatible}" = "yes"; then
|
||||
AC_MSG_RESULT(yes)
|
||||
PBX_OSPTK=1
|
||||
OSPTK_INCLUDE="${osptk_cflags}"
|
||||
OSPTK_LIB="${osptk_ldflags} -losptk ${osptk_extralibs}"
|
||||
AC_DEFINE_UNQUOTED([HAVE_OSPTK], 1, [Define this to indicate the ${OSPTK_DESCRIP} library])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
])
|
|
@ -26,6 +26,7 @@
|
|||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<use type="module">res_monitor</use>
|
||||
<support_level>core</support_level>
|
||||
***/
|
||||
|
||||
|
@ -48,6 +49,7 @@
|
|||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/parking.h"
|
||||
#include "asterisk/features_config.h"
|
||||
#include "asterisk/monitor.h"
|
||||
#include "asterisk/mixmonitor.h"
|
||||
#include "asterisk/audiohook.h"
|
||||
#include "asterisk/causes.h"
|
||||
|
@ -77,7 +79,7 @@ static void set_touch_variable(enum set_touch_variables_res *res, struct ast_cha
|
|||
}
|
||||
}
|
||||
|
||||
static enum set_touch_variables_res set_touch_variables(struct ast_channel *chan, char **touch_format, char **touch_monitor, char **touch_monitor_prefix, char **touch_monitor_beep)
|
||||
static enum set_touch_variables_res set_touch_variables(struct ast_channel *chan, int is_mixmonitor, char **touch_format, char **touch_monitor, char **touch_monitor_prefix, char **touch_monitor_beep)
|
||||
{
|
||||
enum set_touch_variables_res res = SET_TOUCH_UNSET;
|
||||
const char *var_format;
|
||||
|
@ -87,11 +89,17 @@ static enum set_touch_variables_res set_touch_variables(struct ast_channel *chan
|
|||
|
||||
SCOPED_CHANNELLOCK(lock, chan);
|
||||
|
||||
var_format = "TOUCH_MIXMONITOR_FORMAT";
|
||||
var_monitor = "TOUCH_MIXMONITOR";
|
||||
var_prefix = "TOUCH_MIXMONITOR_PREFIX";
|
||||
var_beep = "TOUCH_MIXMONITOR_BEEP";
|
||||
|
||||
if (is_mixmonitor) {
|
||||
var_format = "TOUCH_MIXMONITOR_FORMAT";
|
||||
var_monitor = "TOUCH_MIXMONITOR";
|
||||
var_prefix = "TOUCH_MIXMONITOR_PREFIX";
|
||||
var_beep = "TOUCH_MIXMONITOR_BEEP";
|
||||
} else {
|
||||
var_format = "TOUCH_MONITOR_FORMAT";
|
||||
var_monitor = "TOUCH_MONITOR";
|
||||
var_prefix = "TOUCH_MONITOR_PREFIX";
|
||||
var_beep = "TOUCH_MONITOR_BEEP";
|
||||
}
|
||||
set_touch_variable(&res, chan, var_format, touch_format);
|
||||
set_touch_variable(&res, chan, var_monitor, touch_monitor);
|
||||
set_touch_variable(&res, chan, var_prefix, touch_monitor_prefix);
|
||||
|
@ -100,6 +108,222 @@ static enum set_touch_variables_res set_touch_variables(struct ast_channel *chan
|
|||
return res;
|
||||
}
|
||||
|
||||
static void stop_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *stop_message)
|
||||
{
|
||||
ast_verb(4, "AutoMonitor used to stop recording call.\n");
|
||||
|
||||
ast_channel_lock(peer_chan);
|
||||
if (ast_channel_monitor(peer_chan)) {
|
||||
if (ast_channel_monitor(peer_chan)->stop(peer_chan, 1)) {
|
||||
ast_verb(4, "Cannot stop AutoMonitor for %s\n", ast_channel_name(bridge_channel->chan));
|
||||
if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
|
||||
ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
|
||||
}
|
||||
ast_channel_unlock(peer_chan);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* Something else removed the Monitor before we got to it. */
|
||||
ast_channel_unlock(peer_chan);
|
||||
return;
|
||||
}
|
||||
|
||||
ast_channel_unlock(peer_chan);
|
||||
|
||||
if (features_cfg && !(ast_strlen_zero(features_cfg->courtesytone))) {
|
||||
ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
|
||||
ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(stop_message)) {
|
||||
ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
|
||||
ast_bridge_channel_write_playfile(bridge_channel, NULL, stop_message, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void start_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *start_message)
|
||||
{
|
||||
char *touch_filename;
|
||||
size_t len;
|
||||
int x;
|
||||
char beep_id[64] = "";
|
||||
enum set_touch_variables_res set_touch_res;
|
||||
|
||||
RAII_VAR(char *, touch_format, NULL, ast_free);
|
||||
RAII_VAR(char *, touch_monitor, NULL, ast_free);
|
||||
RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
|
||||
RAII_VAR(char *, touch_monitor_beep, NULL, ast_free);
|
||||
|
||||
set_touch_res = set_touch_variables(bridge_channel->chan, 0, &touch_format,
|
||||
&touch_monitor, &touch_monitor_prefix, &touch_monitor_beep);
|
||||
switch (set_touch_res) {
|
||||
case SET_TOUCH_SUCCESS:
|
||||
break;
|
||||
case SET_TOUCH_UNSET:
|
||||
set_touch_res = set_touch_variables(peer_chan, 0, &touch_format, &touch_monitor,
|
||||
&touch_monitor_prefix, &touch_monitor_beep);
|
||||
if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case SET_TOUCH_ALLOC_FAILURE:
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(touch_monitor)) {
|
||||
len = strlen(touch_monitor) + 50;
|
||||
touch_filename = ast_alloca(len);
|
||||
snprintf(touch_filename, len, "%s-%ld-%s",
|
||||
S_OR(touch_monitor_prefix, "auto"),
|
||||
(long) time(NULL),
|
||||
touch_monitor);
|
||||
} else {
|
||||
char *caller_chan_id;
|
||||
char *peer_chan_id;
|
||||
|
||||
caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
|
||||
ast_channel_caller(bridge_channel->chan)->id.number.str, ast_channel_name(bridge_channel->chan)));
|
||||
peer_chan_id = ast_strdupa(S_COR(ast_channel_caller(peer_chan)->id.number.valid,
|
||||
ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
|
||||
len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
|
||||
touch_filename = ast_alloca(len);
|
||||
snprintf(touch_filename, len, "%s-%ld-%s-%s",
|
||||
S_OR(touch_monitor_prefix, "auto"),
|
||||
(long) time(NULL),
|
||||
caller_chan_id,
|
||||
peer_chan_id);
|
||||
}
|
||||
|
||||
for (x = 0; x < strlen(touch_filename); x++) {
|
||||
if (touch_filename[x] == '/') {
|
||||
touch_filename[x] = '-';
|
||||
}
|
||||
}
|
||||
|
||||
ast_verb(4, "AutoMonitor used to record call. Filename: %s\n", touch_filename);
|
||||
|
||||
if (!ast_strlen_zero(touch_monitor_beep)) {
|
||||
unsigned int interval = 15;
|
||||
if (sscanf(touch_monitor_beep, "%30u", &interval) != 1) {
|
||||
ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
|
||||
touch_monitor_beep, interval);
|
||||
}
|
||||
|
||||
if (interval > 0) {
|
||||
if (interval < 5) {
|
||||
interval = 5;
|
||||
ast_log(LOG_WARNING, "Interval '%s' too small for periodic beep. Using minimum of %u\n",
|
||||
touch_monitor_beep, interval);
|
||||
}
|
||||
|
||||
if (ast_beep_start(peer_chan, interval, beep_id, sizeof(beep_id))) {
|
||||
ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ast_monitor_start(peer_chan, touch_format, touch_filename, 1, X_REC_IN | X_REC_OUT, beep_id)) {
|
||||
ast_verb(4, "AutoMonitor feature was tried by '%s' but monitor failed to start.\n",
|
||||
ast_channel_name(bridge_channel->chan));
|
||||
return;
|
||||
}
|
||||
|
||||
ast_monitor_setjoinfiles(peer_chan, 1);
|
||||
|
||||
if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
|
||||
ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
|
||||
ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(start_message)) {
|
||||
ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
|
||||
ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
|
||||
}
|
||||
|
||||
pbx_builtin_setvar_helper(bridge_channel->chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
|
||||
pbx_builtin_setvar_helper(peer_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
|
||||
}
|
||||
|
||||
static int feature_automonitor(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
|
||||
{
|
||||
const char *start_message;
|
||||
const char *stop_message;
|
||||
struct ast_bridge_features_automonitor *options = hook_pvt;
|
||||
enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
|
||||
int is_monitoring;
|
||||
|
||||
RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
|
||||
RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
|
||||
|
||||
ast_channel_lock(bridge_channel->chan);
|
||||
features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
|
||||
ast_channel_unlock(bridge_channel->chan);
|
||||
ast_bridge_channel_lock_bridge(bridge_channel);
|
||||
peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, bridge_channel->chan);
|
||||
ast_bridge_unlock(bridge_channel->bridge);
|
||||
|
||||
if (!peer_chan) {
|
||||
ast_verb(4, "Cannot start AutoMonitor for %s - can not determine peer in bridge.\n",
|
||||
ast_channel_name(bridge_channel->chan));
|
||||
if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
|
||||
ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_channel_lock(bridge_channel->chan);
|
||||
start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
|
||||
"TOUCH_MONITOR_MESSAGE_START");
|
||||
start_message = ast_strdupa(S_OR(start_message, ""));
|
||||
stop_message = pbx_builtin_getvar_helper(bridge_channel->chan,
|
||||
"TOUCH_MONITOR_MESSAGE_STOP");
|
||||
stop_message = ast_strdupa(S_OR(stop_message, ""));
|
||||
ast_channel_unlock(bridge_channel->chan);
|
||||
|
||||
is_monitoring = ast_channel_monitor(peer_chan) != NULL;
|
||||
switch (start_stop) {
|
||||
case AUTO_MONITOR_TOGGLE:
|
||||
if (is_monitoring) {
|
||||
stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
|
||||
} else {
|
||||
start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
|
||||
}
|
||||
return 0;
|
||||
case AUTO_MONITOR_START:
|
||||
if (!is_monitoring) {
|
||||
start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
|
||||
return 0;
|
||||
}
|
||||
ast_verb(4, "AutoMonitor already recording call.\n");
|
||||
break;
|
||||
case AUTO_MONITOR_STOP:
|
||||
if (is_monitoring) {
|
||||
stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
|
||||
return 0;
|
||||
}
|
||||
ast_verb(4, "AutoMonitor already stopped on call.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fake start/stop to invoker so will think it did something but
|
||||
* was already in that mode.
|
||||
*/
|
||||
if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
|
||||
ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
|
||||
}
|
||||
if (is_monitoring) {
|
||||
if (!ast_strlen_zero(start_message)) {
|
||||
ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
|
||||
}
|
||||
} else {
|
||||
if (!ast_strlen_zero(stop_message)) {
|
||||
ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stop_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *stop_message)
|
||||
{
|
||||
|
@ -136,13 +360,13 @@ static void start_automixmonitor(struct ast_bridge_channel *bridge_channel, stru
|
|||
RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
|
||||
RAII_VAR(char *, touch_monitor_beep, NULL, ast_free);
|
||||
|
||||
set_touch_res = set_touch_variables(bridge_channel->chan, &touch_format,
|
||||
set_touch_res = set_touch_variables(bridge_channel->chan, 1, &touch_format,
|
||||
&touch_monitor, &touch_monitor_prefix, &touch_monitor_beep);
|
||||
switch (set_touch_res) {
|
||||
case SET_TOUCH_SUCCESS:
|
||||
break;
|
||||
case SET_TOUCH_UNSET:
|
||||
set_touch_res = set_touch_variables(peer_chan, &touch_format, &touch_monitor,
|
||||
set_touch_res = set_touch_variables(peer_chan, 1, &touch_format, &touch_monitor,
|
||||
&touch_monitor_prefix, &touch_monitor_beep);
|
||||
if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
|
||||
return;
|
||||
|
@ -323,6 +547,7 @@ static int feature_hangup(struct ast_bridge_channel *bridge_channel, void *hook_
|
|||
static int unload_module(void)
|
||||
{
|
||||
ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_HANGUP);
|
||||
ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_AUTOMON);
|
||||
ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_AUTOMIXMON);
|
||||
|
||||
return 0;
|
||||
|
@ -331,6 +556,7 @@ static int unload_module(void)
|
|||
static int load_module(void)
|
||||
{
|
||||
ast_bridge_features_register(AST_BRIDGE_BUILTIN_HANGUP, feature_hangup, NULL);
|
||||
ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMON, feature_automonitor, NULL);
|
||||
ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMIXMON, feature_automixmonitor, NULL);
|
||||
|
||||
/* This module cannot be unloaded until shutdown */
|
||||
|
@ -343,4 +569,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Built in bridging featur
|
|||
.support_level = AST_MODULE_SUPPORT_CORE,
|
||||
.load = load_module,
|
||||
.unload = unload_module,
|
||||
.optional_modules = "res_monitor",
|
||||
);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
ALSA=@PBX_ALSA@
|
||||
BLUETOOTH=@PBX_BLUETOOTH@
|
||||
BEANSTALK=@PBX_BEANSTALK@
|
||||
COROSYNC=@PBX_COROSYNC@
|
||||
|
@ -42,6 +43,7 @@ NEON29=@PBX_NEON29@
|
|||
OGG=@PBX_OGG@
|
||||
OPUS=@PBX_OPUS@
|
||||
OPUSFILE=@PBX_OPUSFILE@
|
||||
OSPTK=@PBX_OSPTK@
|
||||
PGSQL=@PBX_PGSQL@
|
||||
PJPROJECT=@PBX_PJPROJECT@
|
||||
POPT=@PBX_POPT@
|
||||
|
|
|
@ -19,14 +19,21 @@ all: _all
|
|||
|
||||
include $(ASTTOPDIR)/Makefile.moddir_rules
|
||||
|
||||
ifneq ($(findstring $(OSARCH), mingw32 cygwin ),)
|
||||
LIBS+= -lres_monitor.so
|
||||
endif
|
||||
|
||||
$(call MOD_ADD_C,chan_iax2,$(wildcard iax2/*.c))
|
||||
iax2/parser.o: _ASTCFLAGS+=$(call get_menuselect_cflags,MALLOC_DEBUG)
|
||||
|
||||
$(call MOD_ADD_C,chan_sip,$(wildcard sip/*.c))
|
||||
$(call MOD_ADD_C,chan_pjsip,$(wildcard pjsip/*.c))
|
||||
$(call MOD_ADD_C,chan_dahdi,$(wildcard dahdi/*.c) sig_analog.c sig_pri.c sig_ss7.c)
|
||||
|
||||
chan_dahdi.o: _ASTCFLAGS+=$(call get_menuselect_cflags,LOTS_OF_SPANS)
|
||||
chan_mgcp.o: _ASTCFLAGS+=$(AST_NO_FORMAT_TRUNCATION)
|
||||
chan_unistim.o: _ASTCFLAGS+=$(AST_NO_FORMAT_TRUNCATION)
|
||||
chan_phone.o: _ASTCFLAGS+=$(AST_NO_FORMAT_TRUNCATION)
|
||||
chan_sip.o: _ASTCFLAGS+=$(AST_NO_FORMAT_TRUNCATION)
|
||||
|
||||
$(call MOD_ADD_C,console_video.c vgrabbers.c console_board.c)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -35,9 +35,11 @@
|
|||
* - svn co https://www.portaudio.com/repos/portaudio/branches/v19-devel
|
||||
*
|
||||
* \note Since this works with any audio system that libportaudio supports,
|
||||
* including ALSA and OSS, it has come to replace the deprecated chan_alsa and
|
||||
* chan_oss. However, the following features *at least* need to be implemented
|
||||
* here for this to be a full replacement:
|
||||
* including ALSA and OSS, this may someday deprecate chan_alsa and chan_oss.
|
||||
* However, before that can be done, it needs to *at least* have all of the
|
||||
* features that these other channel drivers have. The features implemented
|
||||
* in at least one of the other console channel drivers that are not yet
|
||||
* implemented here are:
|
||||
*
|
||||
* - Set Auto-answer from the dialplan
|
||||
* - transfer CLI command
|
||||
|
|
|
@ -1829,7 +1829,7 @@ static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub a
|
|||
ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast_channel_name(ast));
|
||||
}
|
||||
if (strcmp(ast_channel_exten(ast), "fax")) {
|
||||
const char *target_context = ast_channel_context(ast);
|
||||
const char *target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast));
|
||||
|
||||
/*
|
||||
* We need to unlock 'ast' here because ast_exists_extension has the
|
||||
|
@ -7632,7 +7632,7 @@ static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame
|
|||
ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast_channel_name(ast));
|
||||
}
|
||||
if (strcmp(ast_channel_exten(ast), "fax")) {
|
||||
const char *target_context = ast_channel_context(ast);
|
||||
const char *target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast));
|
||||
|
||||
/*
|
||||
* We need to unlock 'ast' here because ast_exists_extension has the
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -784,7 +784,7 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_channel *ast, s
|
|||
return f;
|
||||
}
|
||||
|
||||
target_context = ast_channel_context(ast);
|
||||
target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast));
|
||||
|
||||
/*
|
||||
* We need to unlock the channel here because ast_exists_extension has the
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -99,20 +99,14 @@ if the formats are equivalent. This will save some unnecessary format
|
|||
conversion.
|
||||
|
||||
|
||||
In order to handle video you need to add the following to the endpoint in
|
||||
pjsip.conf
|
||||
In order to handle video you need to add to sip.conf (and presumably
|
||||
iax.conf too) the following:
|
||||
|
||||
[general](+)
|
||||
videosupport=yes
|
||||
allow=h263 ; this or other video formats
|
||||
allow=h263p ; this or other video formats
|
||||
|
||||
(Presumably, iax.conf would require):
|
||||
|
||||
[general](+)
|
||||
videosupport=yes
|
||||
allow=h263 ; this or other video formats
|
||||
allow=h263p ; this or other video formats
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,927 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip config parsing functions and unit tests
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>deprecated</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "include/sip.h"
|
||||
#include "include/config_parser.h"
|
||||
#include "include/sip_utils.h"
|
||||
|
||||
/*! \brief Parse register=> line in sip.conf
|
||||
*
|
||||
* \retval 0 on success
|
||||
* \retval -1 on failure
|
||||
*/
|
||||
int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const char *value, int lineno)
|
||||
{
|
||||
int portnum = 0;
|
||||
int domainport = 0;
|
||||
enum ast_transport transport = AST_TRANSPORT_UDP;
|
||||
char buf[256] = "";
|
||||
char *userpart = NULL, *hostpart = NULL;
|
||||
/* register => [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] */
|
||||
AST_DECLARE_APP_ARGS(pre1,
|
||||
AST_APP_ARG(peer);
|
||||
AST_APP_ARG(userpart);
|
||||
);
|
||||
AST_DECLARE_APP_ARGS(pre2,
|
||||
AST_APP_ARG(transport);
|
||||
AST_APP_ARG(blank);
|
||||
AST_APP_ARG(userpart);
|
||||
);
|
||||
AST_DECLARE_APP_ARGS(user1,
|
||||
AST_APP_ARG(userpart);
|
||||
AST_APP_ARG(secret);
|
||||
AST_APP_ARG(authuser);
|
||||
);
|
||||
AST_DECLARE_APP_ARGS(user2,
|
||||
AST_APP_ARG(user);
|
||||
AST_APP_ARG(domain);
|
||||
);
|
||||
AST_DECLARE_APP_ARGS(user3,
|
||||
AST_APP_ARG(authuser);
|
||||
AST_APP_ARG(domainport);
|
||||
);
|
||||
AST_DECLARE_APP_ARGS(host1,
|
||||
AST_APP_ARG(hostpart);
|
||||
AST_APP_ARG(expiry);
|
||||
);
|
||||
AST_DECLARE_APP_ARGS(host2,
|
||||
AST_APP_ARG(hostpart);
|
||||
AST_APP_ARG(extension);
|
||||
);
|
||||
AST_DECLARE_APP_ARGS(host3,
|
||||
AST_APP_ARG(host);
|
||||
AST_APP_ARG(port);
|
||||
);
|
||||
|
||||
if (!reg) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
reg->expire = -1;
|
||||
reg->timeout = -1;
|
||||
|
||||
if (!value) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_copy_string(buf, value, sizeof(buf));
|
||||
|
||||
/*
|
||||
* register => [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry]
|
||||
* becomes
|
||||
* userpart => [peer?][transport://]user[@domain][:secret[:authuser]]
|
||||
* hostpart => host[:port][/extension][~expiry]
|
||||
*/
|
||||
if ((hostpart = strrchr(buf, '@'))) {
|
||||
*hostpart++ = '\0';
|
||||
userpart = buf;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(userpart) || ast_strlen_zero(hostpart)) {
|
||||
ast_log(LOG_WARNING, "Format for registration is [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] at line %d\n", lineno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre1.userpart => [transport://]user[@domain][:secret[:authuser]]
|
||||
* hostpart => host[:port][/extension][~expiry]
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(pre1, userpart, '?');
|
||||
if (ast_strlen_zero(pre1.userpart)) {
|
||||
pre1.userpart = pre1.peer;
|
||||
pre1.peer = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre2.transport = transport
|
||||
* pre2.userpart => user[@domain][:secret[:authuser]]
|
||||
* hostpart => host[:port][/extension][~expiry]
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(pre2, pre1.userpart, '/');
|
||||
if (ast_strlen_zero(pre2.userpart)) {
|
||||
pre2.userpart = pre2.transport;
|
||||
pre2.transport = NULL;
|
||||
} else {
|
||||
pre2.transport[strlen(pre2.transport) - 1] = '\0'; /* Remove trailing : */
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(pre2.blank)) {
|
||||
ast_log(LOG_WARNING, "Format for registration is [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] at line %d\n", lineno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre2.transport = transport
|
||||
* user1.userpart => user[@domain]
|
||||
* user1.secret => secret
|
||||
* user1.authuser => authuser
|
||||
* hostpart => host[:port][/extension][~expiry]
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(user1, pre2.userpart, ':');
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre2.transport = transport
|
||||
* user1.userpart => user[@domain]
|
||||
* user1.secret => secret
|
||||
* user1.authuser => authuser
|
||||
* host1.hostpart => host[:port][/extension]
|
||||
* host1.expiry => [expiry]
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(host1, hostpart, '~');
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre2.transport = transport
|
||||
* user1.userpart => user[@domain]
|
||||
* user1.secret => secret
|
||||
* user1.authuser => authuser
|
||||
* host2.hostpart => host[:port]
|
||||
* host2.extension => [extension]
|
||||
* host1.expiry => [expiry]
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(host2, host1.hostpart, '/');
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre2.transport = transport
|
||||
* user1.userpart => user[@domain]
|
||||
* user1.secret => secret
|
||||
* user1.authuser => authuser
|
||||
* host3.host => host
|
||||
* host3.port => port
|
||||
* host2.extension => extension
|
||||
* host1.expiry => expiry
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(host3, host2.hostpart, ':');
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre2.transport = transport
|
||||
* user2.user => user
|
||||
* user2.domain => domain
|
||||
* user1.secret => secret
|
||||
* user1.authuser => authuser
|
||||
* host3.host => host
|
||||
* host3.port => port
|
||||
* host2.extension => extension
|
||||
* host1.expiry => expiry
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(user2, user1.userpart, '@');
|
||||
|
||||
/*
|
||||
* pre1.peer => peer
|
||||
* pre2.transport = transport
|
||||
* user2.user => user
|
||||
* user2.domain => domain
|
||||
* user1.secret => secret
|
||||
* user3.authuser => authuser
|
||||
* user3.domainport => domainport
|
||||
* host3.host => host
|
||||
* host3.port => port
|
||||
* host2.extension => extension
|
||||
* host1.expiry => expiry
|
||||
*/
|
||||
AST_NONSTANDARD_RAW_ARGS(user3, user1.authuser, ':');
|
||||
|
||||
/* Reordering needed due to fields being [(:secret[:username])|(:regdomainport:secret:username)]
|
||||
but parsing being [secret[:username[:regdomainport]]] */
|
||||
if (user3.argc == 2) {
|
||||
char *reorder = user3.domainport;
|
||||
user3.domainport = user1.secret;
|
||||
user1.secret = user3.authuser;
|
||||
user3.authuser = reorder;
|
||||
}
|
||||
|
||||
if (host3.port) {
|
||||
if (!(portnum = port_str2int(host3.port, 0))) {
|
||||
ast_log(LOG_NOTICE, "'%s' is not a valid port number on line %d of sip.conf. using default.\n", host3.port, lineno);
|
||||
}
|
||||
}
|
||||
if (user3.domainport) {
|
||||
if (!(domainport = port_str2int(user3.domainport, 0))) {
|
||||
ast_log(LOG_NOTICE, "'%s' is not a valid domain port number on line %d of sip.conf. using default.\n", user3.domainport, lineno);
|
||||
}
|
||||
}
|
||||
|
||||
/* set transport type */
|
||||
if (!pre2.transport) {
|
||||
transport = AST_TRANSPORT_UDP;
|
||||
} else if (!strncasecmp(pre2.transport, "tcp", 3)) {
|
||||
transport = AST_TRANSPORT_TCP;
|
||||
} else if (!strncasecmp(pre2.transport, "tls", 3)) {
|
||||
transport = AST_TRANSPORT_TLS;
|
||||
} else if (!strncasecmp(pre2.transport, "udp", 3)) {
|
||||
transport = AST_TRANSPORT_UDP;
|
||||
} else {
|
||||
transport = AST_TRANSPORT_UDP;
|
||||
ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type on line %d of sip.conf. defaulting to udp.\n", pre2.transport, lineno);
|
||||
}
|
||||
|
||||
/* if no portnum specified, set default for transport */
|
||||
if (!portnum) {
|
||||
if (transport == AST_TRANSPORT_TLS) {
|
||||
portnum = STANDARD_TLS_PORT;
|
||||
} else {
|
||||
portnum = STANDARD_SIP_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy into sip_registry object */
|
||||
ast_string_field_set(reg, callback, ast_strip_quoted(S_OR(host2.extension, "s"), "\"", "\""));
|
||||
ast_string_field_set(reg, username, ast_strip_quoted(S_OR(user2.user, ""), "\"", "\""));
|
||||
ast_string_field_set(reg, hostname, ast_strip_quoted(S_OR(host3.host, ""), "\"", "\""));
|
||||
ast_string_field_set(reg, authuser, ast_strip_quoted(S_OR(user3.authuser, ""), "\"", "\""));
|
||||
ast_string_field_set(reg, secret, ast_strip_quoted(S_OR(user1.secret, ""), "\"", "\""));
|
||||
ast_string_field_set(reg, peername, ast_strip_quoted(S_OR(pre1.peer, ""), "\"", "\""));
|
||||
ast_string_field_set(reg, regdomain, ast_strip_quoted(S_OR(user2.domain, ""), "\"", "\""));
|
||||
|
||||
reg->transport = transport;
|
||||
reg->portno = portnum;
|
||||
reg->regdomainport = domainport;
|
||||
reg->callid_valid = FALSE;
|
||||
reg->ocseq = INITIAL_CSEQ;
|
||||
reg->refresh = reg->expiry = reg->configured_expiry = (host1.expiry ? atoi(ast_strip_quoted(host1.expiry, "\"", "\"")) : default_expiry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef TEST_FRAMEWORK
|
||||
AST_TEST_DEFINE(sip_parse_register_line_test)
|
||||
{
|
||||
int res = AST_TEST_PASS;
|
||||
struct sip_registry *reg;
|
||||
int default_expiry = 120;
|
||||
const char *reg1 = "name@domain";
|
||||
const char *reg2 = "name:pass@domain";
|
||||
const char *reg3 = "name@namedomain:pass:authuser@domain";
|
||||
const char *reg4 = "name@namedomain:pass:authuser@domain/extension";
|
||||
const char *reg5 = "tcp://name@namedomain:pass:authuser@domain/extension";
|
||||
const char *reg6 = "tls://name@namedomain:pass:authuser@domain/extension~111";
|
||||
const char *reg7 = "peer?tcp://name@namedomain:pass:authuser@domain:1234/extension~111";
|
||||
const char *reg8 = "peer?name@namedomain:pass:authuser@domain:1234/extension~111";
|
||||
const char *reg9 = "peer?name:pass:authuser:1234/extension~111";
|
||||
const char *reg10 = "@domin:1234";
|
||||
const char *reg12 = "name@namedomain:4321:pass:authuser@domain";
|
||||
const char *reg13 = "name@namedomain:4321::@domain";
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "sip_parse_register_line_test";
|
||||
info->category = "/channels/chan_sip/";
|
||||
info->summary = "tests sip register line parsing";
|
||||
info->description =
|
||||
"Tests parsing of various register line configurations. "
|
||||
"Verifies output matches expected behavior.";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
/* ---Test reg 1, simple config --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg1, 1) ||
|
||||
strcmp(reg->callback, "s") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "") ||
|
||||
strcmp(reg->secret, "") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_UDP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != default_expiry ||
|
||||
reg->expiry != default_expiry ||
|
||||
reg->configured_expiry != default_expiry ||
|
||||
reg->portno != STANDARD_SIP_PORT ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 1: simple config failed\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 2, add secret --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg2, 1) ||
|
||||
strcmp(reg->callback, "s") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_UDP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != default_expiry ||
|
||||
reg->expiry != default_expiry ||
|
||||
reg->configured_expiry != default_expiry ||
|
||||
reg->portno != STANDARD_SIP_PORT ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 2: add secret failed\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 3, add userdomain and authuser --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg3, 1) ||
|
||||
strcmp(reg->callback, "s") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "authuser") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_UDP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != default_expiry ||
|
||||
reg->expiry != default_expiry ||
|
||||
reg->configured_expiry != default_expiry ||
|
||||
reg->portno != STANDARD_SIP_PORT ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 3: add userdomain and authuser failed\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 4, add callback extension --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg4, 1) ||
|
||||
strcmp(reg->callback, "extension") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "authuser") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_UDP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != default_expiry ||
|
||||
reg->expiry != default_expiry ||
|
||||
reg->configured_expiry != default_expiry ||
|
||||
reg->portno != STANDARD_SIP_PORT ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 4: add callback extension failed\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 5, add transport --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg5, 1) ||
|
||||
strcmp(reg->callback, "extension") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "authuser") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_TCP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != default_expiry ||
|
||||
reg->expiry != default_expiry ||
|
||||
reg->configured_expiry != default_expiry ||
|
||||
reg->portno != STANDARD_SIP_PORT ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 5: add transport failed\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 6, change to tls transport, add expiry --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg6, 1) ||
|
||||
strcmp(reg->callback, "extension") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "authuser") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_TLS ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != 111 ||
|
||||
reg->expiry != 111 ||
|
||||
reg->configured_expiry != 111 ||
|
||||
reg->portno != STANDARD_TLS_PORT ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 6: change to tls transport and add expiry failed\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 7, change transport to tcp, add custom port, and add peer --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg7, 1) ||
|
||||
strcmp(reg->callback, "extension") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "authuser") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "peer") ||
|
||||
reg->transport != AST_TRANSPORT_TCP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != 111 ||
|
||||
reg->expiry != 111 ||
|
||||
reg->configured_expiry != 111 ||
|
||||
reg->portno != 1234 ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 7, change transport to tcp, add custom port, and add peer failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 8, remove transport --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg8, 1) ||
|
||||
strcmp(reg->callback, "extension") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "authuser") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "peer") ||
|
||||
reg->transport != AST_TRANSPORT_UDP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != 111 ||
|
||||
reg->expiry != 111 ||
|
||||
reg->configured_expiry != 111 ||
|
||||
reg->portno != 1234 ||
|
||||
(reg->regdomainport) ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 8, remove transport failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 9, missing domain, expected to fail --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (!sip_parse_register_line(reg, default_expiry, reg9, 1)) {
|
||||
ast_test_status_update(test,
|
||||
"Test 9, missing domain, expected to fail but did not.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 10, missing user, expected to fail --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (!sip_parse_register_line(reg, default_expiry, reg10, 1)) {
|
||||
ast_test_status_update(test,
|
||||
"Test 10, missing user expected to fail but did not\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg 11, no registry object, expected to fail--- */
|
||||
if (!sip_parse_register_line(NULL, default_expiry, reg1, 1)) {
|
||||
ast_test_status_update(test,
|
||||
"Test 11, no registry object, expected to fail but did not.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
/* ---Test reg 12, no registry line, expected to fail --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (!sip_parse_register_line(reg, default_expiry, NULL, 1)) {
|
||||
|
||||
ast_test_status_update(test,
|
||||
"Test 12, NULL register line expected to fail but did not.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg13, add domain port --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg12, 1) ||
|
||||
strcmp(reg->callback, "s") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "authuser") ||
|
||||
strcmp(reg->secret, "pass") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_UDP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != default_expiry ||
|
||||
reg->expiry != default_expiry ||
|
||||
reg->configured_expiry != default_expiry ||
|
||||
reg->portno != STANDARD_SIP_PORT ||
|
||||
reg->regdomainport != 4321 ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 13, add domain port failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
/* ---Test reg14, domain port without secret --- */
|
||||
if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
|
||||
goto alloc_fail;
|
||||
} else if (
|
||||
sip_parse_register_line(reg, default_expiry, reg13, 1) ||
|
||||
strcmp(reg->callback, "s") ||
|
||||
strcmp(reg->username, "name") ||
|
||||
strcmp(reg->regdomain, "namedomain") ||
|
||||
strcmp(reg->hostname, "domain") ||
|
||||
strcmp(reg->authuser, "") ||
|
||||
strcmp(reg->secret, "") ||
|
||||
strcmp(reg->peername, "") ||
|
||||
reg->transport != AST_TRANSPORT_UDP ||
|
||||
reg->timeout != -1 ||
|
||||
reg->expire != -1 ||
|
||||
reg->refresh != default_expiry ||
|
||||
reg->expiry != default_expiry ||
|
||||
reg->configured_expiry != default_expiry ||
|
||||
reg->portno != STANDARD_SIP_PORT ||
|
||||
reg->regdomainport != 4321 ||
|
||||
reg->callid_valid != FALSE ||
|
||||
reg->ocseq != INITIAL_CSEQ) {
|
||||
|
||||
ast_test_status_update(test, "Test 14, domain port without secret failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
ast_string_field_free_memory(reg);
|
||||
ast_free(reg);
|
||||
|
||||
|
||||
return res;
|
||||
|
||||
alloc_fail:
|
||||
ast_test_status_update(test, "Out of memory. \n");
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum ast_transport *transport)
|
||||
{
|
||||
char *port;
|
||||
|
||||
if (ast_strlen_zero(line)) {
|
||||
*hostname = NULL;
|
||||
return -1;
|
||||
}
|
||||
if ((*hostname = strstr(line, "://"))) {
|
||||
*hostname += 3;
|
||||
|
||||
if (!strncasecmp(line, "tcp", 3)) {
|
||||
*transport = AST_TRANSPORT_TCP;
|
||||
} else if (!strncasecmp(line, "tls", 3)) {
|
||||
*transport = AST_TRANSPORT_TLS;
|
||||
} else if (!strncasecmp(line, "udp", 3)) {
|
||||
*transport = AST_TRANSPORT_UDP;
|
||||
} else if (lineno) {
|
||||
ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type on line %d of sip.conf. defaulting to udp.\n", line, lineno);
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type in sip config. defaulting to udp.\n", line);
|
||||
}
|
||||
} else {
|
||||
*hostname = line;
|
||||
*transport = AST_TRANSPORT_UDP;
|
||||
}
|
||||
|
||||
if ((line = strrchr(*hostname, '@')))
|
||||
line++;
|
||||
else
|
||||
line = *hostname;
|
||||
|
||||
if (ast_sockaddr_split_hostport(line, hostname, &port, 0) == 0) {
|
||||
if (lineno) {
|
||||
ast_log(LOG_WARNING, "Cannot parse host '%s' on line %d of sip.conf.\n",
|
||||
line, lineno);
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Cannot parse host '%s' in sip config.\n", line);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (port) {
|
||||
if (!sscanf(port, "%5d", portnum)) {
|
||||
if (lineno) {
|
||||
ast_log(LOG_NOTICE, "'%s' is not a valid port number on line %d of sip.conf. using default.\n", port, lineno);
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "'%s' is not a valid port number in sip config. using default.\n", port);
|
||||
}
|
||||
port = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!port) {
|
||||
if (*transport & AST_TRANSPORT_TLS) {
|
||||
*portnum = STANDARD_TLS_PORT;
|
||||
} else {
|
||||
*portnum = STANDARD_SIP_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef TEST_FRAMEWORK
|
||||
AST_TEST_DEFINE(sip_parse_host_line_test)
|
||||
{
|
||||
int res = AST_TEST_PASS;
|
||||
char *host;
|
||||
int port;
|
||||
enum ast_transport transport;
|
||||
char host1[] = "www.blah.com";
|
||||
char host2[] = "tcp://www.blah.com";
|
||||
char host3[] = "tls://10.10.10.10";
|
||||
char host4[] = "tls://10.10.10.10:1234";
|
||||
char host5[] = "10.10.10.10:1234";
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "sip_parse_host_line_test";
|
||||
info->category = "/channels/chan_sip/";
|
||||
info->summary = "tests sip.conf host line parsing";
|
||||
info->description =
|
||||
"Tests parsing of various host line configurations. "
|
||||
"Verifies output matches expected behavior.";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
/* test 1, simple host */
|
||||
sip_parse_host(host1, 1, &host, &port, &transport);
|
||||
if (port != STANDARD_SIP_PORT ||
|
||||
ast_strlen_zero(host) || strcmp(host, "www.blah.com") ||
|
||||
transport != AST_TRANSPORT_UDP) {
|
||||
ast_test_status_update(test, "Test 1: simple host failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
/* test 2, add tcp transport */
|
||||
sip_parse_host(host2, 1, &host, &port, &transport);
|
||||
if (port != STANDARD_SIP_PORT ||
|
||||
ast_strlen_zero(host) || strcmp(host, "www.blah.com") ||
|
||||
transport != AST_TRANSPORT_TCP) {
|
||||
ast_test_status_update(test, "Test 2: tcp host failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
/* test 3, add tls transport */
|
||||
sip_parse_host(host3, 1, &host, &port, &transport);
|
||||
if (port != STANDARD_TLS_PORT ||
|
||||
ast_strlen_zero(host) || strcmp(host, "10.10.10.10") ||
|
||||
transport != AST_TRANSPORT_TLS) {
|
||||
ast_test_status_update(test, "Test 3: tls host failed. \n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
/* test 4, add custom port with tls */
|
||||
sip_parse_host(host4, 1, &host, &port, &transport);
|
||||
if (port != 1234 || ast_strlen_zero(host) ||
|
||||
strcmp(host, "10.10.10.10") ||
|
||||
transport != AST_TRANSPORT_TLS) {
|
||||
ast_test_status_update(test, "Test 4: tls host with custom port failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
/* test 5, simple host with custom port */
|
||||
sip_parse_host(host5, 1, &host, &port, &transport);
|
||||
if (port != 1234 || ast_strlen_zero(host) ||
|
||||
strcmp(host, "10.10.10.10") ||
|
||||
transport != AST_TRANSPORT_UDP) {
|
||||
ast_test_status_update(test, "Test 5: simple host with custom port failed.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
/* test 6, expected failure with NULL input */
|
||||
if (!sip_parse_host(NULL, 1, &host, &port, &transport)) {
|
||||
ast_test_status_update(test, "Test 6: expected error on NULL input did not occur.\n");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! \brief Parse the comma-separated nat= option values */
|
||||
void sip_parse_nat_option(const char *value, struct ast_flags *mask, struct ast_flags *flags)
|
||||
{
|
||||
char *parse, *this;
|
||||
|
||||
if (!(parse = ast_strdupa(value))) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Since we need to completely override the general settings if we are being called
|
||||
* later for a peer, always set the flags for all options on the mask */
|
||||
ast_set_flag(&mask[0], SIP_NAT_FORCE_RPORT);
|
||||
ast_set_flag(&mask[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
ast_set_flag(&mask[2], SIP_PAGE3_NAT_AUTO_RPORT);
|
||||
ast_set_flag(&mask[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
|
||||
|
||||
while ((this = strsep(&parse, ","))) {
|
||||
if (ast_false(this)) {
|
||||
ast_clear_flag(&flags[0], SIP_NAT_FORCE_RPORT);
|
||||
ast_clear_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT);
|
||||
ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
|
||||
break; /* It doesn't make sense to have no + something else */
|
||||
} else if (!strcasecmp(this, "yes")) {
|
||||
ast_log(LOG_WARNING, "nat=yes is deprecated, use nat=force_rport,comedia instead\n");
|
||||
ast_set_flag(&flags[0], SIP_NAT_FORCE_RPORT);
|
||||
ast_set_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT);
|
||||
ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
|
||||
break; /* It doesn't make sense to have yes + something else */
|
||||
} else if (!strcasecmp(this, "force_rport") && !ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) {
|
||||
ast_set_flag(&flags[0], SIP_NAT_FORCE_RPORT);
|
||||
} else if (!strcasecmp(this, "comedia") && !ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA)) {
|
||||
ast_set_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
} else if (!strcasecmp(this, "auto_force_rport")) {
|
||||
ast_set_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT);
|
||||
/* In case someone did something dumb like nat=force_rport,auto_force_rport */
|
||||
ast_clear_flag(&flags[0], SIP_NAT_FORCE_RPORT);
|
||||
} else if (!strcasecmp(this, "auto_comedia")) {
|
||||
ast_set_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
|
||||
/* In case someone did something dumb like nat=comedia,auto_comedia*/
|
||||
ast_clear_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_FRAMEWORK
|
||||
#define TEST_FORCE_RPORT 1 << 0
|
||||
#define TEST_COMEDIA 1 << 1
|
||||
#define TEST_AUTO_FORCE_RPORT 1 << 2
|
||||
#define TEST_AUTO_COMEDIA 1 << 3
|
||||
static int match_nat_options(int val, struct ast_flags *flags)
|
||||
{
|
||||
if ((!ast_test_flag(&flags[0], SIP_NAT_FORCE_RPORT)) != !(val & TEST_FORCE_RPORT)) {
|
||||
return 0;
|
||||
}
|
||||
if (!ast_test_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP) != !(val & TEST_COMEDIA)) {
|
||||
return 0;
|
||||
}
|
||||
if (!ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT) != !(val & TEST_AUTO_FORCE_RPORT)) {
|
||||
return 0;
|
||||
}
|
||||
if (!ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA) != !(val & TEST_AUTO_COMEDIA)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(sip_parse_nat_test)
|
||||
{
|
||||
int i, res = AST_TEST_PASS;
|
||||
struct ast_flags mask[3] = {{0}}, flags[3] = {{0}};
|
||||
struct {
|
||||
const char *str;
|
||||
int i;
|
||||
} options[] = {
|
||||
{ "yes", TEST_FORCE_RPORT | TEST_COMEDIA },
|
||||
{ "no", 0 },
|
||||
{ "force_rport", TEST_FORCE_RPORT },
|
||||
{ "comedia", TEST_COMEDIA },
|
||||
{ "auto_force_rport", TEST_AUTO_FORCE_RPORT },
|
||||
{ "auto_comedia", TEST_AUTO_COMEDIA },
|
||||
{ "force_rport,auto_force_rport", TEST_AUTO_FORCE_RPORT },
|
||||
{ "auto_force_rport,force_rport", TEST_AUTO_FORCE_RPORT },
|
||||
{ "comedia,auto_comedia", TEST_AUTO_COMEDIA },
|
||||
{ "auto_comedia,comedia", TEST_AUTO_COMEDIA },
|
||||
{ "force_rport,comedia", TEST_FORCE_RPORT | TEST_COMEDIA },
|
||||
{ "force_rport,auto_comedia", TEST_FORCE_RPORT | TEST_AUTO_COMEDIA },
|
||||
{ "force_rport,yes,no", TEST_FORCE_RPORT | TEST_COMEDIA },
|
||||
{ "auto_comedia,no,yes", 0 },
|
||||
};
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "sip_parse_nat_test";
|
||||
info->category = "/channels/chan_sip/";
|
||||
info->summary = "tests sip.conf nat line parsing";
|
||||
info->description =
|
||||
"Tests parsing of various nat line configurations. "
|
||||
"Verifies output matches expected behavior.";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_LEN(options); i++) {
|
||||
sip_parse_nat_option(options[i].str, mask, flags);
|
||||
if (!match_nat_options(options[i].i, flags)) {
|
||||
ast_test_status_update(test, "Failed nat=%s\n", options[i].str);
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
memset(flags, 0, sizeof(flags));
|
||||
memset(mask, 0, sizeof(mask));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! \brief SIP test registration */
|
||||
void sip_config_parser_register_tests(void)
|
||||
{
|
||||
AST_TEST_REGISTER(sip_parse_register_line_test);
|
||||
AST_TEST_REGISTER(sip_parse_host_line_test);
|
||||
AST_TEST_REGISTER(sip_parse_nat_test);
|
||||
}
|
||||
|
||||
/*! \brief SIP test registration */
|
||||
void sip_config_parser_unregister_tests(void)
|
||||
{
|
||||
AST_TEST_UNREGISTER(sip_parse_register_line_test);
|
||||
AST_TEST_UNREGISTER(sip_parse_host_line_test);
|
||||
AST_TEST_UNREGISTER(sip_parse_nat_test);
|
||||
}
|
|
@ -0,0 +1,515 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip channel dialplan functions and unit tests
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>deprecated</support_level>
|
||||
***/
|
||||
|
||||
/*** DOCUMENTATION
|
||||
<info name="CHANNEL" language="en_US" tech="SIP">
|
||||
<enumlist>
|
||||
<enum name="peerip">
|
||||
<para>R/O Get the IP address of the peer.</para>
|
||||
</enum>
|
||||
<enum name="recvip">
|
||||
<para>R/O Get the source IP address of the peer.</para>
|
||||
</enum>
|
||||
<enum name="recvport">
|
||||
<para>R/O Get the source port of the peer.</para>
|
||||
</enum>
|
||||
<enum name="from">
|
||||
<para>R/O Get the URI from the From: header.</para>
|
||||
</enum>
|
||||
<enum name="uri">
|
||||
<para>R/O Get the URI from the Contact: header.</para>
|
||||
</enum>
|
||||
<enum name="ruri">
|
||||
<para>R/O Get the Request-URI from the INVITE header.</para>
|
||||
</enum>
|
||||
<enum name="useragent">
|
||||
<para>R/O Get the useragent.</para>
|
||||
</enum>
|
||||
<enum name="peername">
|
||||
<para>R/O Get the name of the peer.</para>
|
||||
</enum>
|
||||
<enum name="t38passthrough">
|
||||
<para>R/O <literal>1</literal> if T38 is offered or enabled in this channel,
|
||||
otherwise <literal>0</literal></para>
|
||||
</enum>
|
||||
<enum name="rtpqos">
|
||||
<para>R/O Get QOS information about the RTP stream</para>
|
||||
<para> This option takes two additional arguments:</para>
|
||||
<para> Argument 1:</para>
|
||||
<para> <literal>audio</literal> Get data about the audio stream</para>
|
||||
<para> <literal>video</literal> Get data about the video stream</para>
|
||||
<para> <literal>text</literal> Get data about the text stream</para>
|
||||
<para> Argument 2:</para>
|
||||
<para> <literal>local_ssrc</literal> Local SSRC (stream ID)</para>
|
||||
<para> <literal>local_lostpackets</literal> Local lost packets</para>
|
||||
<para> <literal>local_jitter</literal> Local calculated jitter</para>
|
||||
<para> <literal>local_maxjitter</literal> Local calculated jitter (maximum)</para>
|
||||
<para> <literal>local_minjitter</literal> Local calculated jitter (minimum)</para>
|
||||
<para> <literal>local_normdevjitter</literal>Local calculated jitter (normal deviation)</para>
|
||||
<para> <literal>local_stdevjitter</literal> Local calculated jitter (standard deviation)</para>
|
||||
<para> <literal>local_count</literal> Number of received packets</para>
|
||||
<para> <literal>remote_ssrc</literal> Remote SSRC (stream ID)</para>
|
||||
<para> <literal>remote_lostpackets</literal>Remote lost packets</para>
|
||||
<para> <literal>remote_jitter</literal> Remote reported jitter</para>
|
||||
<para> <literal>remote_maxjitter</literal> Remote calculated jitter (maximum)</para>
|
||||
<para> <literal>remote_minjitter</literal> Remote calculated jitter (minimum)</para>
|
||||
<para> <literal>remote_normdevjitter</literal>Remote calculated jitter (normal deviation)</para>
|
||||
<para> <literal>remote_stdevjitter</literal>Remote calculated jitter (standard deviation)</para>
|
||||
<para> <literal>remote_count</literal> Number of transmitted packets</para>
|
||||
<para> <literal>rtt</literal> Round trip time</para>
|
||||
<para> <literal>maxrtt</literal> Round trip time (maximum)</para>
|
||||
<para> <literal>minrtt</literal> Round trip time (minimum)</para>
|
||||
<para> <literal>normdevrtt</literal> Round trip time (normal deviation)</para>
|
||||
<para> <literal>stdevrtt</literal> Round trip time (standard deviation)</para>
|
||||
<para> <literal>all</literal> All statistics (in a form suited to logging,
|
||||
but not for parsing)</para>
|
||||
</enum>
|
||||
<enum name="rtpdest">
|
||||
<para>R/O Get remote RTP destination information.</para>
|
||||
<para> This option takes one additional argument:</para>
|
||||
<para> Argument 1:</para>
|
||||
<para> <literal>audio</literal> Get audio destination</para>
|
||||
<para> <literal>video</literal> Get video destination</para>
|
||||
<para> <literal>text</literal> Get text destination</para>
|
||||
<para> Defaults to <literal>audio</literal> if unspecified.</para>
|
||||
</enum>
|
||||
<enum name="rtpsource">
|
||||
<para>R/O Get source RTP destination information.</para>
|
||||
<para> This option takes one additional argument:</para>
|
||||
<para> Argument 1:</para>
|
||||
<para> <literal>audio</literal> Get audio destination</para>
|
||||
<para> <literal>video</literal> Get video destination</para>
|
||||
<para> <literal>text</literal> Get text destination</para>
|
||||
<para> Defaults to <literal>audio</literal> if unspecified.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</info>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/rtp_engine.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/acl.h"
|
||||
|
||||
#include "include/sip.h"
|
||||
#include "include/globals.h"
|
||||
#include "include/dialog.h"
|
||||
#include "include/dialplan_functions.h"
|
||||
#include "include/sip_utils.h"
|
||||
|
||||
|
||||
int sip_acf_channel_read(struct ast_channel *chan, const char *funcname, char *preparse, char *buf, size_t buflen)
|
||||
{
|
||||
struct sip_pvt *p = ast_channel_tech_pvt(chan);
|
||||
char *parse = ast_strdupa(preparse);
|
||||
int res = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(param);
|
||||
AST_APP_ARG(type);
|
||||
AST_APP_ARG(field);
|
||||
);
|
||||
|
||||
/* Check for zero arguments */
|
||||
if (ast_strlen_zero(parse)) {
|
||||
ast_log(LOG_ERROR, "Cannot call %s without arguments\n", funcname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
/* Sanity check */
|
||||
if (!IS_SIP_TECH(ast_channel_tech(chan))) {
|
||||
ast_log(LOG_ERROR, "Cannot call %s on a non-SIP channel\n", funcname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(buf, 0, buflen);
|
||||
|
||||
if (p == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!strcasecmp(args.param, "peerip")) {
|
||||
ast_copy_string(buf, ast_sockaddr_isnull(&p->sa) ? "" : ast_sockaddr_stringify_addr(&p->sa), buflen);
|
||||
} else if (!strcasecmp(args.param, "recvip")) {
|
||||
ast_copy_string(buf, ast_sockaddr_isnull(&p->recv) ? "" : ast_sockaddr_stringify_addr(&p->recv), buflen);
|
||||
} else if (!strcasecmp(args.param, "recvport")) {
|
||||
ast_copy_string(buf, ast_sockaddr_isnull(&p->recv) ? "" : ast_sockaddr_stringify_port(&p->recv), buflen);
|
||||
} else if (!strcasecmp(args.param, "from")) {
|
||||
ast_copy_string(buf, p->from, buflen);
|
||||
} else if (!strcasecmp(args.param, "uri")) {
|
||||
ast_copy_string(buf, p->uri, buflen);
|
||||
} else if (!strcasecmp(args.param, "ruri")) {
|
||||
if (p->initreq.data) {
|
||||
char *tmpruri = REQ_OFFSET_TO_STR(&p->initreq, rlpart2);
|
||||
ast_copy_string(buf, tmpruri, buflen);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else if (!strcasecmp(args.param, "useragent")) {
|
||||
ast_copy_string(buf, p->useragent, buflen);
|
||||
} else if (!strcasecmp(args.param, "peername")) {
|
||||
ast_copy_string(buf, p->peername, buflen);
|
||||
} else if (!strcasecmp(args.param, "t38passthrough")) {
|
||||
ast_copy_string(buf, (p->t38.state == T38_DISABLED) ? "0" : "1", buflen);
|
||||
} else if (!strcasecmp(args.param, "rtpdest")) {
|
||||
struct ast_sockaddr addr;
|
||||
struct ast_rtp_instance *stream;
|
||||
|
||||
if (ast_strlen_zero(args.type))
|
||||
args.type = "audio";
|
||||
|
||||
if (!strcasecmp(args.type, "audio"))
|
||||
stream = p->rtp;
|
||||
else if (!strcasecmp(args.type, "video"))
|
||||
stream = p->vrtp;
|
||||
else if (!strcasecmp(args.type, "text"))
|
||||
stream = p->trtp;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Return 0 to suppress a console warning message */
|
||||
if (!stream) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_rtp_instance_get_remote_address(stream, &addr);
|
||||
snprintf(buf, buflen, "%s", ast_sockaddr_stringify(&addr));
|
||||
} else if (!strcasecmp(args.param, "rtpsource")) {
|
||||
struct ast_sockaddr sa;
|
||||
struct ast_rtp_instance *stream;
|
||||
|
||||
if (ast_strlen_zero(args.type))
|
||||
args.type = "audio";
|
||||
|
||||
if (!strcasecmp(args.type, "audio"))
|
||||
stream = p->rtp;
|
||||
else if (!strcasecmp(args.type, "video"))
|
||||
stream = p->vrtp;
|
||||
else if (!strcasecmp(args.type, "text"))
|
||||
stream = p->trtp;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Return 0 to suppress a console warning message */
|
||||
if (!stream) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_rtp_instance_get_local_address(stream, &sa);
|
||||
|
||||
if (ast_sockaddr_isnull(&sa)) {
|
||||
struct ast_sockaddr dest_sa;
|
||||
ast_rtp_instance_get_remote_address(stream, &dest_sa);
|
||||
ast_ouraddrfor(&dest_sa, &sa);
|
||||
}
|
||||
|
||||
snprintf(buf, buflen, "%s", ast_sockaddr_stringify(&sa));
|
||||
} else if (!strcasecmp(args.param, "rtpqos")) {
|
||||
struct ast_rtp_instance *rtp = NULL;
|
||||
|
||||
if (ast_strlen_zero(args.type)) {
|
||||
args.type = "audio";
|
||||
}
|
||||
|
||||
if (!strcasecmp(args.type, "audio")) {
|
||||
rtp = p->rtp;
|
||||
} else if (!strcasecmp(args.type, "video")) {
|
||||
rtp = p->vrtp;
|
||||
} else if (!strcasecmp(args.type, "text")) {
|
||||
rtp = p->trtp;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(args.field) || !strcasecmp(args.field, "all")) {
|
||||
char quality_buf[AST_MAX_USER_FIELD];
|
||||
|
||||
if (!ast_rtp_instance_get_quality(rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_copy_string(buf, quality_buf, buflen);
|
||||
return res;
|
||||
} else {
|
||||
struct ast_rtp_instance_stats stats;
|
||||
int i;
|
||||
struct {
|
||||
const char *name;
|
||||
enum { INT, DBL } type;
|
||||
union {
|
||||
unsigned int *i4;
|
||||
double *d8;
|
||||
};
|
||||
} lookup[] = {
|
||||
{ "txcount", INT, { .i4 = &stats.txcount, }, },
|
||||
{ "rxcount", INT, { .i4 = &stats.rxcount, }, },
|
||||
{ "txjitter", DBL, { .d8 = &stats.txjitter, }, },
|
||||
{ "rxjitter", DBL, { .d8 = &stats.rxjitter, }, },
|
||||
{ "remote_maxjitter", DBL, { .d8 = &stats.remote_maxjitter, }, },
|
||||
{ "remote_minjitter", DBL, { .d8 = &stats.remote_minjitter, }, },
|
||||
{ "remote_normdevjitter", DBL, { .d8 = &stats.remote_normdevjitter, }, },
|
||||
{ "remote_stdevjitter", DBL, { .d8 = &stats.remote_stdevjitter, }, },
|
||||
{ "local_maxjitter", DBL, { .d8 = &stats.local_maxjitter, }, },
|
||||
{ "local_minjitter", DBL, { .d8 = &stats.local_minjitter, }, },
|
||||
{ "local_normdevjitter", DBL, { .d8 = &stats.local_normdevjitter, }, },
|
||||
{ "local_stdevjitter", DBL, { .d8 = &stats.local_stdevjitter, }, },
|
||||
{ "txploss", INT, { .i4 = &stats.txploss, }, },
|
||||
{ "rxploss", INT, { .i4 = &stats.rxploss, }, },
|
||||
{ "remote_maxrxploss", DBL, { .d8 = &stats.remote_maxrxploss, }, },
|
||||
{ "remote_minrxploss", DBL, { .d8 = &stats.remote_minrxploss, }, },
|
||||
{ "remote_normdevrxploss", DBL, { .d8 = &stats.remote_normdevrxploss, }, },
|
||||
{ "remote_stdevrxploss", DBL, { .d8 = &stats.remote_stdevrxploss, }, },
|
||||
{ "local_maxrxploss", DBL, { .d8 = &stats.local_maxrxploss, }, },
|
||||
{ "local_minrxploss", DBL, { .d8 = &stats.local_minrxploss, }, },
|
||||
{ "local_normdevrxploss", DBL, { .d8 = &stats.local_normdevrxploss, }, },
|
||||
{ "local_stdevrxploss", DBL, { .d8 = &stats.local_stdevrxploss, }, },
|
||||
{ "rtt", DBL, { .d8 = &stats.rtt, }, },
|
||||
{ "maxrtt", DBL, { .d8 = &stats.maxrtt, }, },
|
||||
{ "minrtt", DBL, { .d8 = &stats.minrtt, }, },
|
||||
{ "normdevrtt", DBL, { .d8 = &stats.normdevrtt, }, },
|
||||
{ "stdevrtt", DBL, { .d8 = &stats.stdevrtt, }, },
|
||||
{ "local_ssrc", INT, { .i4 = &stats.local_ssrc, }, },
|
||||
{ "remote_ssrc", INT, { .i4 = &stats.remote_ssrc, }, },
|
||||
{ NULL, },
|
||||
};
|
||||
|
||||
if (ast_rtp_instance_get_stats(rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; !ast_strlen_zero(lookup[i].name); i++) {
|
||||
if (!strcasecmp(args.field, lookup[i].name)) {
|
||||
if (lookup[i].type == INT) {
|
||||
snprintf(buf, buflen, "%u", *lookup[i].i4);
|
||||
} else {
|
||||
snprintf(buf, buflen, "%f", *lookup[i].d8);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ast_log(LOG_WARNING, "Unrecognized argument '%s' to %s\n", preparse, funcname);
|
||||
return -1;
|
||||
}
|
||||
} else if (!strcasecmp(args.param, "secure_signaling")) {
|
||||
snprintf(buf, buflen, "%s", p->socket.type == AST_TRANSPORT_TLS ? "1" : "");
|
||||
} else if (!strcasecmp(args.param, "secure_media")) {
|
||||
snprintf(buf, buflen, "%s", p->srtp ? "1" : "");
|
||||
} else {
|
||||
res = -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef TEST_FRAMEWORK
|
||||
static int test_sip_rtpqos_1_new(struct ast_rtp_instance *instance, struct ast_sched_context *sched, struct ast_sockaddr *addr, void *data)
|
||||
{
|
||||
/* Needed to pass sanity checks */
|
||||
ast_rtp_instance_set_data(instance, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_sip_rtpqos_1_destroy(struct ast_rtp_instance *instance)
|
||||
{
|
||||
/* Needed to pass sanity checks */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_frame *test_sip_rtpqos_1_read(struct ast_rtp_instance *instance, int rtcp)
|
||||
{
|
||||
/* Needed to pass sanity checks */
|
||||
return &ast_null_frame;
|
||||
}
|
||||
|
||||
static int test_sip_rtpqos_1_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
|
||||
{
|
||||
/* Needed to pass sanity checks */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_sip_rtpqos_1_get_stat(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat)
|
||||
{
|
||||
struct ast_rtp_instance_stats *s = ast_rtp_instance_get_data(instance);
|
||||
memcpy(stats, s, sizeof(*stats));
|
||||
return 0;
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(test_sip_rtpqos_1)
|
||||
{
|
||||
int i, res = AST_TEST_PASS;
|
||||
static struct ast_rtp_engine test_engine = {
|
||||
.name = "test",
|
||||
.new = test_sip_rtpqos_1_new,
|
||||
.destroy = test_sip_rtpqos_1_destroy,
|
||||
.read = test_sip_rtpqos_1_read,
|
||||
.write = test_sip_rtpqos_1_write,
|
||||
.get_stat = test_sip_rtpqos_1_get_stat,
|
||||
};
|
||||
struct ast_sockaddr sa = { {0, } };
|
||||
struct ast_rtp_instance_stats mine = { 0, };
|
||||
struct sip_pvt *p = NULL;
|
||||
struct ast_channel *chan = NULL;
|
||||
struct ast_str *varstr = NULL, *buffer = NULL;
|
||||
struct {
|
||||
const char *name;
|
||||
enum { INT, DBL } type;
|
||||
union {
|
||||
unsigned int *i4;
|
||||
double *d8;
|
||||
};
|
||||
} lookup[] = {
|
||||
{ "txcount", INT, { .i4 = &mine.txcount, }, },
|
||||
{ "rxcount", INT, { .i4 = &mine.rxcount, }, },
|
||||
{ "txjitter", DBL, { .d8 = &mine.txjitter, }, },
|
||||
{ "rxjitter", DBL, { .d8 = &mine.rxjitter, }, },
|
||||
{ "remote_maxjitter", DBL, { .d8 = &mine.remote_maxjitter, }, },
|
||||
{ "remote_minjitter", DBL, { .d8 = &mine.remote_minjitter, }, },
|
||||
{ "remote_normdevjitter", DBL, { .d8 = &mine.remote_normdevjitter, }, },
|
||||
{ "remote_stdevjitter", DBL, { .d8 = &mine.remote_stdevjitter, }, },
|
||||
{ "local_maxjitter", DBL, { .d8 = &mine.local_maxjitter, }, },
|
||||
{ "local_minjitter", DBL, { .d8 = &mine.local_minjitter, }, },
|
||||
{ "local_normdevjitter", DBL, { .d8 = &mine.local_normdevjitter, }, },
|
||||
{ "local_stdevjitter", DBL, { .d8 = &mine.local_stdevjitter, }, },
|
||||
{ "txploss", INT, { .i4 = &mine.txploss, }, },
|
||||
{ "rxploss", INT, { .i4 = &mine.rxploss, }, },
|
||||
{ "remote_maxrxploss", DBL, { .d8 = &mine.remote_maxrxploss, }, },
|
||||
{ "remote_minrxploss", DBL, { .d8 = &mine.remote_minrxploss, }, },
|
||||
{ "remote_normdevrxploss", DBL, { .d8 = &mine.remote_normdevrxploss, }, },
|
||||
{ "remote_stdevrxploss", DBL, { .d8 = &mine.remote_stdevrxploss, }, },
|
||||
{ "local_maxrxploss", DBL, { .d8 = &mine.local_maxrxploss, }, },
|
||||
{ "local_minrxploss", DBL, { .d8 = &mine.local_minrxploss, }, },
|
||||
{ "local_normdevrxploss", DBL, { .d8 = &mine.local_normdevrxploss, }, },
|
||||
{ "local_stdevrxploss", DBL, { .d8 = &mine.local_stdevrxploss, }, },
|
||||
{ "rtt", DBL, { .d8 = &mine.rtt, }, },
|
||||
{ "maxrtt", DBL, { .d8 = &mine.maxrtt, }, },
|
||||
{ "minrtt", DBL, { .d8 = &mine.minrtt, }, },
|
||||
{ "normdevrtt", DBL, { .d8 = &mine.normdevrtt, }, },
|
||||
{ "stdevrtt", DBL, { .d8 = &mine.stdevrtt, }, },
|
||||
{ "local_ssrc", INT, { .i4 = &mine.local_ssrc, }, },
|
||||
{ "remote_ssrc", INT, { .i4 = &mine.remote_ssrc, }, },
|
||||
{ NULL, },
|
||||
};
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "test_sip_rtpqos";
|
||||
info->category = "/channels/chan_sip/";
|
||||
info->summary = "Test retrieval of SIP RTP QOS stats";
|
||||
info->description =
|
||||
"Verify values in the RTP instance structure can be accessed through the dialplan.";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
ast_rtp_engine_register(&test_engine);
|
||||
/* Have to associate this with a SIP pvt and an ast_channel */
|
||||
if (!(p = sip_alloc(0, NULL, 0, SIP_NOTIFY, NULL, 0))) {
|
||||
res = AST_TEST_NOT_RUN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(p->rtp = ast_rtp_instance_new("test", sched, &bindaddr, &mine))) {
|
||||
res = AST_TEST_NOT_RUN;
|
||||
goto done;
|
||||
}
|
||||
ast_rtp_instance_set_remote_address(p->rtp, &sa);
|
||||
if (!(chan = ast_dummy_channel_alloc())) {
|
||||
res = AST_TEST_NOT_RUN;
|
||||
goto done;
|
||||
}
|
||||
ast_channel_tech_set(chan, &sip_tech);
|
||||
ast_channel_tech_pvt_set(chan, dialog_ref(p, "Give the owner channel a reference to the dialog"));
|
||||
p->owner = chan;
|
||||
|
||||
varstr = ast_str_create(16);
|
||||
buffer = ast_str_create(16);
|
||||
if (!varstr || !buffer) {
|
||||
res = AST_TEST_NOT_RUN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Populate "mine" with values, then retrieve them with the CHANNEL dialplan function */
|
||||
for (i = 0; !ast_strlen_zero(lookup[i].name); i++) {
|
||||
ast_str_set(&varstr, 0, "${CHANNEL(rtpqos,audio,%s)}", lookup[i].name);
|
||||
if (lookup[i].type == INT) {
|
||||
int j;
|
||||
char cmpstr[256];
|
||||
for (j = 1; j < 25; j++) {
|
||||
*lookup[i].i4 = j;
|
||||
ast_str_substitute_variables(&buffer, 0, chan, ast_str_buffer(varstr));
|
||||
snprintf(cmpstr, sizeof(cmpstr), "%d", j);
|
||||
if (strcmp(cmpstr, ast_str_buffer(buffer))) {
|
||||
res = AST_TEST_FAIL;
|
||||
ast_test_status_update(test, "%s != %s != %s\n", ast_str_buffer(varstr), cmpstr, ast_str_buffer(buffer));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
double j, cmpdbl = 0.0;
|
||||
for (j = 1.0; j < 10.0; j += 0.3) {
|
||||
*lookup[i].d8 = j;
|
||||
ast_str_substitute_variables(&buffer, 0, chan, ast_str_buffer(varstr));
|
||||
if (sscanf(ast_str_buffer(buffer), "%lf", &cmpdbl) != 1 || fabs(j - cmpdbl) > .05) {
|
||||
res = AST_TEST_FAIL;
|
||||
ast_test_status_update(test, "%s != %f != %s\n", ast_str_buffer(varstr), j, ast_str_buffer(buffer));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
ast_free(varstr);
|
||||
ast_free(buffer);
|
||||
|
||||
/* This unlink and unref will take care of destroying the channel, RTP instance, and SIP pvt */
|
||||
if (p) {
|
||||
dialog_unlink_all(p);
|
||||
dialog_unref(p, "Destroy test object");
|
||||
}
|
||||
if (chan) {
|
||||
ast_channel_unref(chan);
|
||||
}
|
||||
ast_rtp_engine_unregister(&test_engine);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! \brief SIP test registration */
|
||||
void sip_dialplan_function_register_tests(void)
|
||||
{
|
||||
AST_TEST_REGISTER(test_sip_rtpqos_1);
|
||||
}
|
||||
|
||||
/*! \brief SIP test registration */
|
||||
void sip_dialplan_function_unregister_tests(void)
|
||||
{
|
||||
AST_TEST_UNREGISTER(test_sip_rtpqos_1);
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip.conf parser header file
|
||||
*/
|
||||
|
||||
#include "sip.h"
|
||||
|
||||
#ifndef _SIP_CONF_PARSE_H
|
||||
#define _SIP_CONF_PARSE_H
|
||||
|
||||
/*!
|
||||
* \brief Parse register=> line in sip.conf
|
||||
*
|
||||
* \retval 0 on success
|
||||
* \retval -1 on failure
|
||||
*/
|
||||
int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const char *value, int lineno);
|
||||
|
||||
/*!
|
||||
* \brief parses a config line for a host with a transport
|
||||
*
|
||||
* An example input would be:
|
||||
* <code>tls://www.google.com:8056</code>
|
||||
*
|
||||
* \retval 0 on success
|
||||
* \retval -1 on failure
|
||||
*/
|
||||
int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum ast_transport *transport);
|
||||
|
||||
/*! \brief Parse the comma-separated nat= option values
|
||||
* \param value The comma-separated value
|
||||
* \param mask An array of ast_flags that will be set by this function
|
||||
* and used as a mask for copying the flags later
|
||||
* \param flags An array of ast_flags that will be set by this function
|
||||
*
|
||||
* \note The nat-related values in both mask and flags are assumed to empty. This function
|
||||
* will treat the first "yes" or "no" value in a list of values as overriding all other values
|
||||
* and will stop parsing. Auto values will override their non-auto counterparts.
|
||||
*/
|
||||
void sip_parse_nat_option(const char *value, struct ast_flags *mask, struct ast_flags *flags);
|
||||
|
||||
/*!
|
||||
* \brief register config parsing tests
|
||||
*/
|
||||
void sip_config_parser_register_tests(void);
|
||||
|
||||
/*!
|
||||
* \brief unregister config parsing tests
|
||||
*/
|
||||
void sip_config_parser_unregister_tests(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip dialog management header file
|
||||
*/
|
||||
|
||||
#include "sip.h"
|
||||
|
||||
#ifndef _SIP_DIALOG_H
|
||||
#define _SIP_DIALOG_H
|
||||
|
||||
/*! \brief
|
||||
* when we create or delete references, make sure to use these
|
||||
* functions so we keep track of the refcounts.
|
||||
* To simplify the code, we allow a NULL to be passed to dialog_unref().
|
||||
*/
|
||||
#define dialog_ref(dialog, tag) ao2_t_bump(dialog, tag)
|
||||
#define dialog_unref(dialog, tag) ({ ao2_t_cleanup(dialog, tag); (NULL); })
|
||||
|
||||
struct sip_pvt *__sip_alloc(ast_string_field callid, struct ast_sockaddr *sin,
|
||||
int useglobal_nat, const int intended_method, struct sip_request *req, ast_callid logger_callid,
|
||||
const char *file, int line, const char *func);
|
||||
|
||||
#define sip_alloc(callid, addr, useglobal_nat, intended_method, req, logger_callid) \
|
||||
__sip_alloc(callid, addr, useglobal_nat, intended_method, req, logger_callid, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
|
||||
/*!
|
||||
* \brief Schedule final destruction of SIP dialog.
|
||||
*
|
||||
* \note This cannot be canceled.
|
||||
*
|
||||
* \details
|
||||
* This function is used to keep a dialog around for a period of time in order
|
||||
* to properly respond to any retransmits.
|
||||
*/
|
||||
void sip_scheddestroy_final(struct sip_pvt *p, int ms);
|
||||
|
||||
/*! \brief Schedule destruction of SIP dialog */
|
||||
void sip_scheddestroy(struct sip_pvt *p, int ms);
|
||||
|
||||
/*! \brief Cancel destruction of SIP dialog. */
|
||||
void sip_cancel_destroy(struct sip_pvt *pvt);
|
||||
|
||||
/*!
|
||||
* \brief Unlink a dialog from the dialogs container, as well as any other places
|
||||
* that it may be currently stored.
|
||||
*
|
||||
* \note A reference to the dialog must be held before calling
|
||||
* this function, and this function does not release that
|
||||
* reference.
|
||||
*
|
||||
* \note The dialog must not be locked when called.
|
||||
*/
|
||||
void dialog_unlink_all(struct sip_pvt *dialog);
|
||||
|
||||
/*! \brief Acknowledges receipt of a packet and stops retransmission
|
||||
* called with p locked*/
|
||||
int __sip_ack(struct sip_pvt *p, uint32_t seqno, int resp, int sipmethod);
|
||||
|
||||
/*! \brief Pretend to ack all packets
|
||||
* called with p locked */
|
||||
void __sip_pretend_ack(struct sip_pvt *p);
|
||||
|
||||
/*! \brief Acks receipt of packet, keep it around (used for provisional responses) */
|
||||
int __sip_semi_ack(struct sip_pvt *p, uint32_t seqno, int resp, int sipmethod);
|
||||
|
||||
#endif /* defined(_SIP_DIALOG_H) */
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief SIP dialplan functions header file
|
||||
*/
|
||||
|
||||
#include "sip.h"
|
||||
|
||||
#ifndef _SIP_DIALPLAN_FUNCTIONS_H
|
||||
#define _SIP_DIALPLAN_FUNCTIONS_H
|
||||
|
||||
/*!
|
||||
* \brief Channel read dialplan function for SIP
|
||||
*/
|
||||
int sip_acf_channel_read(struct ast_channel *chan, const char *funcname, char *preparse, char *buf, size_t buflen);
|
||||
|
||||
/*!
|
||||
* \brief register dialplan function tests
|
||||
*/
|
||||
void sip_dialplan_function_register_tests(void);
|
||||
/*!
|
||||
* \brief unregister dialplan function tests
|
||||
*/
|
||||
void sip_dialplan_function_unregister_tests(void);
|
||||
|
||||
#endif /* !defined(_SIP_DIALPLAN_FUNCTIONS_H) */
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip global declaration header file
|
||||
*/
|
||||
|
||||
#include "sip.h"
|
||||
|
||||
#ifndef _SIP_GLOBALS_H
|
||||
#define _SIP_GLOBALS_H
|
||||
|
||||
extern struct ast_sockaddr bindaddr; /*!< UDP: The address we bind to */
|
||||
extern struct ast_sched_context *sched; /*!< The scheduling context */
|
||||
|
||||
/*! \brief Definition of this channel for PBX channel registration */
|
||||
extern struct ast_channel_tech sip_tech;
|
||||
|
||||
/*! \brief This version of the sip channel tech has no send_digit_begin
|
||||
* callback so that the core knows that the channel does not want
|
||||
* DTMF BEGIN frames.
|
||||
* The struct is initialized just before registering the channel driver,
|
||||
* and is for use with channels using SIP INFO DTMF.
|
||||
*/
|
||||
extern struct ast_channel_tech sip_tech_info;
|
||||
|
||||
#endif /* !defined(SIP_GLOBALS_H) */
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip request response parser header file
|
||||
*/
|
||||
|
||||
#ifndef _SIP_REQRESP_H
|
||||
#define _SIP_REQRESP_H
|
||||
|
||||
/*! \brief uri parameters */
|
||||
struct uriparams {
|
||||
char *transport;
|
||||
char *user;
|
||||
char *method;
|
||||
char *ttl;
|
||||
char *maddr;
|
||||
int lr;
|
||||
};
|
||||
|
||||
struct contact {
|
||||
AST_LIST_ENTRY(contact) list;
|
||||
char *name;
|
||||
char *user;
|
||||
char *pass;
|
||||
char *hostport;
|
||||
struct uriparams params;
|
||||
char *headers;
|
||||
char *expires;
|
||||
char *q;
|
||||
};
|
||||
|
||||
AST_LIST_HEAD_NOLOCK(contactliststruct, contact);
|
||||
|
||||
/*!
|
||||
* \brief parses a URI in its components.
|
||||
*
|
||||
* \note
|
||||
* - Multiple scheme's can be specified ',' delimited. ex: "sip:,sips:"
|
||||
* - If a component is not requested, do not split around it. This means
|
||||
* that if we don't have domain, we cannot split name:pass.
|
||||
* - It is safe to call with ret_name, pass, hostport pointing all to
|
||||
* the same place.
|
||||
* - If no secret parameter is provided, ret_name will return with both
|
||||
* parts, user:secret.
|
||||
* - If the URI contains a port number, hostport will return with both
|
||||
* parts, host:port.
|
||||
* - This function overwrites the URI string.
|
||||
*
|
||||
* \retval 0 on success
|
||||
* \retval -1 on error.
|
||||
*
|
||||
* \verbatim
|
||||
* general form we are expecting is sip:user:password;user-parameters@host:port;uri-parameters?headers
|
||||
* \endverbatim
|
||||
*/
|
||||
int parse_uri(char *uri, const char *scheme, char **ret_name, char **pass,
|
||||
char **hostport, char **transport);
|
||||
|
||||
/*!
|
||||
* \brief parses a URI in to all of its components and any trailing residue
|
||||
*
|
||||
* \retval 0 on success
|
||||
* \retval -1 on error.
|
||||
*
|
||||
*/
|
||||
int parse_uri_full(char *uri, const char *scheme, char **user, char **pass,
|
||||
char **hostport, struct uriparams *params, char **headers,
|
||||
char **residue);
|
||||
|
||||
/*!
|
||||
* \brief Get caller id name from SIP headers, copy into output buffer
|
||||
*
|
||||
* \return input string pointer placed after display-name field if possible
|
||||
*/
|
||||
const char *get_calleridname(const char *input, char *output, size_t outputsize);
|
||||
|
||||
/*!
|
||||
* \brief Get name and number from sip header
|
||||
*
|
||||
* \note name and number point to malloced memory on return and must be
|
||||
* freed. If name or number is not found, they will be returned as NULL.
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int get_name_and_number(const char *hdr, char **name, char **number);
|
||||
|
||||
/*! \brief Pick out text in brackets from character string
|
||||
* \return pointer to terminated stripped string
|
||||
* \param tmp input string that will be modified
|
||||
*
|
||||
* Examples:
|
||||
* \verbatim
|
||||
* "foo" <bar> valid input, returns bar
|
||||
* foo returns the whole string
|
||||
* < "foo ... > returns the string between brackets
|
||||
* < "foo... bogus (missing closing bracket), returns the whole string
|
||||
* \endverbatim
|
||||
*/
|
||||
char *get_in_brackets(char *tmp);
|
||||
|
||||
/*! \brief Get text in brackets on a const without copy
|
||||
*
|
||||
* \param src String to search
|
||||
* \param[out] start Set to first character inside left bracket.
|
||||
* \param[out] length Set to lenght of string inside brackets
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
* \retval 1 no brackets so got all
|
||||
*/
|
||||
int get_in_brackets_const(const char *src,const char **start,int *length);
|
||||
|
||||
/*! \brief Get text in brackets and any trailing residue
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
* \retval 1 no brackets so got all
|
||||
*/
|
||||
int get_in_brackets_full(char *tmp, char **out, char **residue);
|
||||
|
||||
/*! \brief Parse the ABNF structure
|
||||
* name-andor-addr = name-addr / addr-spec
|
||||
* into its components and return any trailing message-header parameters
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int parse_name_andor_addr(char *uri, const char *scheme, char **name,
|
||||
char **user, char **pass, char **domain,
|
||||
struct uriparams *params, char **headers,
|
||||
char **residue);
|
||||
|
||||
/*! \brief Parse all contact header contacts
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
* \retval 1 all contacts (star)
|
||||
*/
|
||||
|
||||
int get_comma(char *parse, char **out);
|
||||
|
||||
int parse_contact_header(char *contactheader, struct contactliststruct *contactlist);
|
||||
|
||||
/*!
|
||||
* \brief register request parsing tests
|
||||
*/
|
||||
void sip_request_parser_register_tests(void);
|
||||
|
||||
/*!
|
||||
* \brief unregister request parsing tests
|
||||
*/
|
||||
void sip_request_parser_unregister_tests(void);
|
||||
|
||||
/*!
|
||||
* \brief Parse supported header in incoming packet
|
||||
*
|
||||
* \details This function parses through the options parameters and
|
||||
* builds a bit field representing all the SIP options in that field. When an
|
||||
* item is found that is not supported, it is copied to the unsupported
|
||||
* out buffer.
|
||||
*
|
||||
* \param options list
|
||||
* \param[in,out] unsupported buffer (optional)
|
||||
* \param[in,out] unsupported_len buffer length
|
||||
*
|
||||
* \note Because this function can be called multiple times, it will append
|
||||
* whatever options are specified in \c options to \c unsupported. Callers
|
||||
* of this function should make sure the unsupported buffer is clear before
|
||||
* calling this function.
|
||||
*/
|
||||
unsigned int parse_sip_options(const char *options, char *unsupported, size_t unsupported_len);
|
||||
|
||||
/*!
|
||||
* \brief Compare two URIs as described in RFC 3261 Section 19.1.4
|
||||
*
|
||||
* \param input1 First URI
|
||||
* \param input2 Second URI
|
||||
* \retval 0 URIs match
|
||||
* \retval nonzero URIs do not match or one or both is malformed
|
||||
*/
|
||||
int sip_uri_cmp(const char *input1, const char *input2);
|
||||
|
||||
/*!
|
||||
* \brief initialize request and response parser data
|
||||
*
|
||||
* \retval 0 Success
|
||||
* \retval -1 Failure
|
||||
*/
|
||||
int sip_reqresp_parser_init(void);
|
||||
|
||||
/*!
|
||||
* \brief Free resources used by request and response parser
|
||||
*/
|
||||
void sip_reqresp_parser_exit(void);
|
||||
|
||||
/*!
|
||||
* \brief Parse a Via header
|
||||
*
|
||||
* This function parses the Via header and processes it according to section
|
||||
* 18.2 of RFC 3261 and RFC 3581. Since we don't have a transport layer, we
|
||||
* only care about the maddr and ttl parms. The received and rport params are
|
||||
* not parsed.
|
||||
*
|
||||
* \note This function fails to parse some odd combinations of SWS in parameter
|
||||
* lists.
|
||||
*
|
||||
* \code
|
||||
* VIA syntax. RFC 3261 section 25.1
|
||||
* Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
|
||||
* via-parm = sent-protocol LWS sent-by *( SEMI via-params )
|
||||
* via-params = via-ttl / via-maddr
|
||||
* / via-received / via-branch
|
||||
* / via-extension
|
||||
* via-ttl = "ttl" EQUAL ttl
|
||||
* via-maddr = "maddr" EQUAL host
|
||||
* via-received = "received" EQUAL (IPv4address / IPv6address)
|
||||
* via-branch = "branch" EQUAL token
|
||||
* via-extension = generic-param
|
||||
* sent-protocol = protocol-name SLASH protocol-version
|
||||
* SLASH transport
|
||||
* protocol-name = "SIP" / token
|
||||
* protocol-version = token
|
||||
* transport = "UDP" / "TCP" / "TLS" / "SCTP"
|
||||
* / other-transport
|
||||
* sent-by = host [ COLON port ]
|
||||
* ttl = 1*3DIGIT ; 0 to 255
|
||||
* \endcode
|
||||
*/
|
||||
struct sip_via *parse_via(const char *header);
|
||||
|
||||
/*!
|
||||
* \brief Free parsed Via data.
|
||||
*/
|
||||
void free_via(struct sip_via *v);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2013, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip_route header file
|
||||
*/
|
||||
|
||||
#ifndef _SIP_ROUTE_H
|
||||
#define _SIP_ROUTE_H
|
||||
|
||||
#include "asterisk/linkedlists.h"
|
||||
#include "asterisk/strings.h"
|
||||
|
||||
/*!
|
||||
* \brief Opaque storage of a sip route hop
|
||||
*/
|
||||
struct sip_route_hop;
|
||||
|
||||
/*!
|
||||
* \internal \brief Internal enum to remember last calculated
|
||||
*/
|
||||
enum sip_route_type {
|
||||
route_loose = 0, /*!< The first hop contains ;lr or does not exist */
|
||||
route_strict, /*!< The first hop exists and does not contain ;lr */
|
||||
route_invalidated, /*!< strict/loose routing needs to be rechecked */
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Structure to store route information
|
||||
*
|
||||
* \note This must be zero-filled on allocation
|
||||
*/
|
||||
struct sip_route {
|
||||
AST_LIST_HEAD_NOLOCK(, sip_route_hop) list;
|
||||
enum sip_route_type type;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Add a new hop to the route
|
||||
*
|
||||
* \param route Route
|
||||
* \param uri Address of this hop
|
||||
* \param len Length of hop not including null terminator
|
||||
* \param inserthead If true then inserted the new route to the top of the list
|
||||
*
|
||||
* \return Pointer to null terminated copy of URI on success
|
||||
* \retval NULL on error
|
||||
*/
|
||||
const char *sip_route_add(struct sip_route *route, const char *uri, size_t len, int inserthead);
|
||||
|
||||
/*!
|
||||
* \brief Add routes from header
|
||||
*
|
||||
* \note This procedure is for headers that require use of \<brackets\>.
|
||||
*/
|
||||
void sip_route_process_header(struct sip_route *route, const char *header, int inserthead);
|
||||
|
||||
/*!
|
||||
* \brief copy route-set
|
||||
*/
|
||||
void sip_route_copy(struct sip_route *dst, const struct sip_route *src);
|
||||
|
||||
/*!
|
||||
* \brief Free all routes in the list
|
||||
*/
|
||||
void sip_route_clear(struct sip_route *route);
|
||||
|
||||
/*!
|
||||
* \brief Verbose dump of all hops for debugging
|
||||
*/
|
||||
void sip_route_dump(const struct sip_route *route);
|
||||
|
||||
/*!
|
||||
* \brief Make the comma separated list of route hops
|
||||
*
|
||||
* \param route Source of route list
|
||||
* \param formatcli Add's space after comma's, print's N/A if list is empty.
|
||||
* \param skip Number of hops to skip
|
||||
*
|
||||
* \return an allocated struct ast_str on success
|
||||
* \retval NULL on failure
|
||||
*/
|
||||
struct ast_str *sip_route_list(const struct sip_route *route, int formatcli, int skip)
|
||||
__attribute__((__malloc__)) __attribute__((__warn_unused_result__));
|
||||
|
||||
/*!
|
||||
* \brief Check if the route is strict
|
||||
*
|
||||
* \note The result is cached in route->type
|
||||
*/
|
||||
int sip_route_is_strict(struct sip_route *route);
|
||||
|
||||
/*!
|
||||
* \brief Get the URI of the route's first hop
|
||||
*/
|
||||
const char *sip_route_first_uri(const struct sip_route *route);
|
||||
|
||||
/*!
|
||||
* \brief Check if route has no URI's
|
||||
*/
|
||||
#define sip_route_empty(route) AST_LIST_EMPTY(&(route)->list)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2011, Digium, Inc.
|
||||
*
|
||||
* Michael L. Young <elgueromexicano@gmail.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Generate security events in the SIP channel
|
||||
*
|
||||
* \author Michael L. Young <elgueromexicano@gmail.com>
|
||||
*/
|
||||
|
||||
#include "sip.h"
|
||||
|
||||
#ifndef _SIP_SECURITY_EVENTS_H
|
||||
#define _SIP_SECURITY_EVENTS_H
|
||||
|
||||
void sip_report_invalid_peer(const struct sip_pvt *p);
|
||||
void sip_report_failed_acl(const struct sip_pvt *p, const char *aclname);
|
||||
void sip_report_inval_password(const struct sip_pvt *p, const char *responsechallenge, const char *responsehash);
|
||||
void sip_report_auth_success(const struct sip_pvt *p, uint32_t using_password);
|
||||
void sip_report_session_limit(const struct sip_pvt *p);
|
||||
void sip_report_failed_challenge_response(const struct sip_pvt *p, const char *response, const char *expected_response);
|
||||
void sip_report_chal_sent(const struct sip_pvt *p);
|
||||
void sip_report_inval_transport(const struct sip_pvt *p, const char *transport);
|
||||
void sip_digest_parser(char *c, struct digestkeys *keys);
|
||||
int sip_report_security_event(const char *peer, struct ast_sockaddr *addr, const struct sip_pvt *p,
|
||||
const struct sip_request *req, const int res);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip utils header file
|
||||
*/
|
||||
|
||||
#ifndef _SIP_UTILS_H
|
||||
#define _SIP_UTILS_H
|
||||
|
||||
/* wrapper macro to tell whether t points to one of the sip_tech descriptors */
|
||||
#define IS_SIP_TECH(t) ((t) == &sip_tech || (t) == &sip_tech_info)
|
||||
|
||||
/*!
|
||||
* \brief converts ascii port to int representation.
|
||||
*
|
||||
* \arg pt[in] string that contains a port.
|
||||
* \arg standard[in] port to return in case the port string input is NULL
|
||||
* or if there is a parsing error.
|
||||
*
|
||||
* \return An integer port representation.
|
||||
*/
|
||||
unsigned int port_str2int(const char *pt, unsigned int standard);
|
||||
|
||||
/*! \brief Locate closing quote in a string, skipping escaped quotes.
|
||||
* optionally with a limit on the search.
|
||||
* start must be past the first quote.
|
||||
*/
|
||||
const char *find_closing_quote(const char *start, const char *lim);
|
||||
|
||||
|
||||
/*! \brief Convert SIP hangup causes to Asterisk hangup causes */
|
||||
int hangup_sip2cause(int cause);
|
||||
|
||||
/*! \brief Convert Asterisk hangup causes to SIP codes
|
||||
\verbatim
|
||||
Possible values from causes.h
|
||||
AST_CAUSE_NOTDEFINED AST_CAUSE_NORMAL AST_CAUSE_BUSY
|
||||
AST_CAUSE_FAILURE AST_CAUSE_CONGESTION AST_CAUSE_UNALLOCATED
|
||||
|
||||
In addition to these, a lot of PRI codes is defined in causes.h
|
||||
...should we take care of them too ?
|
||||
|
||||
Quote RFC 3398
|
||||
|
||||
ISUP Cause value SIP response
|
||||
---------------- ------------
|
||||
1 unallocated number 404 Not Found
|
||||
2 no route to network 404 Not found
|
||||
3 no route to destination 404 Not found
|
||||
16 normal call clearing --- (*)
|
||||
17 user busy 486 Busy here
|
||||
18 no user responding 408 Request Timeout
|
||||
19 no answer from the user 480 Temporarily unavailable
|
||||
20 subscriber absent 480 Temporarily unavailable
|
||||
21 call rejected 403 Forbidden (+)
|
||||
22 number changed (w/o diagnostic) 410 Gone
|
||||
22 number changed (w/ diagnostic) 301 Moved Permanently
|
||||
23 redirection to new destination 410 Gone
|
||||
26 non-selected user clearing 404 Not Found (=)
|
||||
27 destination out of order 502 Bad Gateway
|
||||
28 address incomplete 484 Address incomplete
|
||||
29 facility rejected 501 Not implemented
|
||||
31 normal unspecified 480 Temporarily unavailable
|
||||
\endverbatim
|
||||
*/
|
||||
const char *hangup_cause2sip(int cause);
|
||||
|
||||
/*! \brief Return a string describing the force_rport value for the given flags */
|
||||
const char *force_rport_string(struct ast_flags *flags);
|
||||
|
||||
/*! \brief Return a string describing the comedia value for the given flags */
|
||||
const char *comedia_string(struct ast_flags *flags);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2013, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief sip_route functions
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>deprecated</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
#include "include/route.h"
|
||||
#include "include/reqresp_parser.h"
|
||||
|
||||
/*!
|
||||
* \brief Traverse route hops
|
||||
*/
|
||||
#define sip_route_traverse(route,elem) AST_LIST_TRAVERSE(&(route)->list, elem, list)
|
||||
#define sip_route_first(route) AST_LIST_FIRST(&(route)->list)
|
||||
|
||||
/*!
|
||||
* \brief Structure to save a route hop
|
||||
*/
|
||||
struct sip_route_hop {
|
||||
AST_LIST_ENTRY(sip_route_hop) list;
|
||||
char uri[0];
|
||||
};
|
||||
|
||||
const char *sip_route_add(struct sip_route *route, const char *uri, size_t len, int inserthead)
|
||||
{
|
||||
struct sip_route_hop *hop;
|
||||
|
||||
if (!uri || len < 1 || uri[0] == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Expand len to include null terminator */
|
||||
len++;
|
||||
|
||||
/* ast_calloc is not needed because all fields are initialized in this block */
|
||||
hop = ast_malloc(sizeof(struct sip_route_hop) + len);
|
||||
if (!hop) {
|
||||
return NULL;
|
||||
}
|
||||
ast_copy_string(hop->uri, uri, len);
|
||||
|
||||
if (inserthead) {
|
||||
AST_LIST_INSERT_HEAD(&route->list, hop, list);
|
||||
route->type = route_invalidated;
|
||||
} else {
|
||||
if (sip_route_empty(route)) {
|
||||
route->type = route_invalidated;
|
||||
}
|
||||
AST_LIST_INSERT_TAIL(&route->list, hop, list);
|
||||
hop->list.next = NULL;
|
||||
}
|
||||
|
||||
return hop->uri;
|
||||
}
|
||||
|
||||
void sip_route_process_header(struct sip_route *route, const char *header, int inserthead)
|
||||
{
|
||||
const char *hop;
|
||||
int len = 0;
|
||||
const char *uri;
|
||||
|
||||
if (!route) {
|
||||
ast_log(LOG_ERROR, "sip_route_process_header requires non-null route");
|
||||
ast_do_crash();
|
||||
return;
|
||||
}
|
||||
|
||||
while (!get_in_brackets_const(header, &uri, &len)) {
|
||||
header = strchr(header, ',');
|
||||
if (header >= uri && header <= (uri + len)) {
|
||||
/* comma inside brackets */
|
||||
const char *next_br = strchr(header, '<');
|
||||
if (next_br && next_br <= (uri + len)) {
|
||||
header++;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ((hop = sip_route_add(route, uri, len, inserthead))) {
|
||||
ast_debug(2, "sip_route_process_header: <%s>\n", hop);
|
||||
}
|
||||
header = strchr(uri + len + 1, ',');
|
||||
if (header == NULL) {
|
||||
/* No more field-values, we're done with this header */
|
||||
break;
|
||||
}
|
||||
/* Advance past comma */
|
||||
header++;
|
||||
}
|
||||
}
|
||||
|
||||
void sip_route_copy(struct sip_route *dst, const struct sip_route *src)
|
||||
{
|
||||
struct sip_route_hop *hop;
|
||||
|
||||
/* make sure dst is empty */
|
||||
sip_route_clear(dst);
|
||||
|
||||
sip_route_traverse(src, hop) {
|
||||
const char *uri = sip_route_add(dst, hop->uri, strlen(hop->uri), 0);
|
||||
if (uri) {
|
||||
ast_debug(2, "sip_route_copy: copied hop: <%s>\n", uri);
|
||||
}
|
||||
}
|
||||
|
||||
dst->type = src->type;
|
||||
}
|
||||
|
||||
void sip_route_clear(struct sip_route *route)
|
||||
{
|
||||
struct sip_route_hop *hop;
|
||||
|
||||
while ((hop = AST_LIST_REMOVE_HEAD(&route->list, list))) {
|
||||
ast_free(hop);
|
||||
}
|
||||
|
||||
route->type = route_loose;
|
||||
}
|
||||
|
||||
void sip_route_dump(const struct sip_route *route)
|
||||
{
|
||||
if (sip_route_empty(route)) {
|
||||
ast_verbose("sip_route_dump: no route/path\n");
|
||||
} else {
|
||||
struct sip_route_hop *hop;
|
||||
sip_route_traverse(route, hop) {
|
||||
ast_verbose("sip_route_dump: route/path hop: <%s>\n", hop->uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ast_str *sip_route_list(const struct sip_route *route, int formatcli, int skip)
|
||||
{
|
||||
struct sip_route_hop *hop;
|
||||
const char *comma;
|
||||
struct ast_str *buf;
|
||||
int i = 0 - skip;
|
||||
|
||||
buf = ast_str_create(64);
|
||||
if (!buf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
comma = formatcli ? ", " : ",";
|
||||
|
||||
sip_route_traverse(route, hop) {
|
||||
if (i >= 0) {
|
||||
ast_str_append(&buf, 0, "%s<%s>", i ? comma : "", hop->uri);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (formatcli && i <= 0) {
|
||||
ast_str_append(&buf, 0, "N/A");
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
int sip_route_is_strict(struct sip_route *route)
|
||||
{
|
||||
if (!route) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (route->type == route_invalidated) {
|
||||
struct sip_route_hop *hop = sip_route_first(route);
|
||||
int ret = hop && (strstr(hop->uri, ";lr") == NULL);
|
||||
route->type = ret ? route_strict : route_loose;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return (route->type == route_strict) ? 1 : 0;
|
||||
}
|
||||
|
||||
const char *sip_route_first_uri(const struct sip_route *route)
|
||||
{
|
||||
struct sip_route_hop *hop = sip_route_first(route);
|
||||
return hop ? hop->uri : NULL;
|
||||
}
|
|
@ -0,0 +1,358 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012, Digium, Inc.
|
||||
*
|
||||
* Michael L. Young <elgueromexicano@gmail.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Generate security events in the SIP channel
|
||||
*
|
||||
* \author Michael L. Young <elgueromexicano@gmail.com>
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>deprecated</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "include/sip.h"
|
||||
#include "include/security_events.h"
|
||||
|
||||
/*! \brief Determine transport type used to receive request*/
|
||||
|
||||
static enum ast_transport security_event_get_transport(const struct sip_pvt *p)
|
||||
{
|
||||
return p->socket.type;
|
||||
}
|
||||
|
||||
void sip_report_invalid_peer(const struct sip_pvt *p)
|
||||
{
|
||||
char session_id[32];
|
||||
|
||||
struct ast_security_event_inval_acct_id inval_acct_id = {
|
||||
.common.event_type = AST_SECURITY_EVENT_INVAL_ACCT_ID,
|
||||
.common.version = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = p->exten,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
};
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&inval_acct_id));
|
||||
}
|
||||
|
||||
void sip_report_failed_acl(const struct sip_pvt *p, const char *aclname)
|
||||
{
|
||||
char session_id[32];
|
||||
|
||||
struct ast_security_event_failed_acl failed_acl_event = {
|
||||
.common.event_type = AST_SECURITY_EVENT_FAILED_ACL,
|
||||
.common.version = AST_SECURITY_EVENT_FAILED_ACL_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = p->exten,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
.acl_name = aclname,
|
||||
};
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&failed_acl_event));
|
||||
}
|
||||
|
||||
void sip_report_inval_password(const struct sip_pvt *p, const char *response_challenge, const char *response_hash)
|
||||
{
|
||||
char session_id[32];
|
||||
|
||||
struct ast_security_event_inval_password inval_password = {
|
||||
.common.event_type = AST_SECURITY_EVENT_INVAL_PASSWORD,
|
||||
.common.version = AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = p->exten,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
|
||||
.challenge = p->nonce,
|
||||
.received_challenge = response_challenge,
|
||||
.received_hash = response_hash,
|
||||
};
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&inval_password));
|
||||
}
|
||||
|
||||
void sip_report_auth_success(const struct sip_pvt *p, uint32_t using_password)
|
||||
{
|
||||
char session_id[32];
|
||||
|
||||
struct ast_security_event_successful_auth successful_auth = {
|
||||
.common.event_type = AST_SECURITY_EVENT_SUCCESSFUL_AUTH,
|
||||
.common.version = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = p->exten,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
.using_password = using_password,
|
||||
};
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&successful_auth));
|
||||
}
|
||||
|
||||
void sip_report_session_limit(const struct sip_pvt *p)
|
||||
{
|
||||
char session_id[32];
|
||||
|
||||
struct ast_security_event_session_limit session_limit = {
|
||||
.common.event_type = AST_SECURITY_EVENT_SESSION_LIMIT,
|
||||
.common.version = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = p->exten,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
};
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&session_limit));
|
||||
}
|
||||
|
||||
void sip_report_failed_challenge_response(const struct sip_pvt *p, const char *response, const char *expected_response)
|
||||
{
|
||||
char session_id[32];
|
||||
char account_id[256];
|
||||
|
||||
struct ast_security_event_chal_resp_failed chal_resp_failed = {
|
||||
.common.event_type = AST_SECURITY_EVENT_CHAL_RESP_FAILED,
|
||||
.common.version = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = account_id,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
|
||||
.challenge = p->nonce,
|
||||
.response = response,
|
||||
.expected_response = expected_response,
|
||||
};
|
||||
|
||||
if (!ast_strlen_zero(p->from)) { /* When dialing, show account making call */
|
||||
ast_copy_string(account_id, p->from, sizeof(account_id));
|
||||
} else {
|
||||
ast_copy_string(account_id, p->exten, sizeof(account_id));
|
||||
}
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&chal_resp_failed));
|
||||
}
|
||||
|
||||
void sip_report_chal_sent(const struct sip_pvt *p)
|
||||
{
|
||||
char session_id[32];
|
||||
char account_id[256];
|
||||
|
||||
struct ast_security_event_chal_sent chal_sent = {
|
||||
.common.event_type = AST_SECURITY_EVENT_CHAL_SENT,
|
||||
.common.version = AST_SECURITY_EVENT_CHAL_SENT_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = account_id,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
|
||||
.challenge = p->nonce,
|
||||
};
|
||||
|
||||
if (!ast_strlen_zero(p->from)) { /* When dialing, show account making call */
|
||||
ast_copy_string(account_id, p->from, sizeof(account_id));
|
||||
} else {
|
||||
ast_copy_string(account_id, p->exten, sizeof(account_id));
|
||||
}
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&chal_sent));
|
||||
}
|
||||
|
||||
void sip_report_inval_transport(const struct sip_pvt *p, const char *transport)
|
||||
{
|
||||
char session_id[32];
|
||||
|
||||
struct ast_security_event_inval_transport inval_transport = {
|
||||
.common.event_type = AST_SECURITY_EVENT_INVAL_TRANSPORT,
|
||||
.common.version = AST_SECURITY_EVENT_INVAL_TRANSPORT_VERSION,
|
||||
.common.service = "SIP",
|
||||
.common.account_id = p->exten,
|
||||
.common.local_addr = {
|
||||
.addr = &p->ourip,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.remote_addr = {
|
||||
.addr = &p->sa,
|
||||
.transport = security_event_get_transport(p)
|
||||
},
|
||||
.common.session_id = session_id,
|
||||
|
||||
.transport = transport,
|
||||
};
|
||||
|
||||
snprintf(session_id, sizeof(session_id), "%p", p);
|
||||
|
||||
ast_security_event_report(AST_SEC_EVT(&inval_transport));
|
||||
}
|
||||
|
||||
int sip_report_security_event(const char *peer, struct ast_sockaddr *addr, const struct sip_pvt *p,
|
||||
const struct sip_request *req, const int res)
|
||||
{
|
||||
|
||||
struct sip_peer *peer_report;
|
||||
enum check_auth_result res_report = res;
|
||||
struct ast_str *buf;
|
||||
char *c;
|
||||
const char *authtoken;
|
||||
char *reqheader, *respheader;
|
||||
int result = 0;
|
||||
char aclname[256];
|
||||
struct digestkeys keys[] = {
|
||||
[K_RESP] = { "response=", "" },
|
||||
[K_URI] = { "uri=", "" },
|
||||
[K_USER] = { "username=", "" },
|
||||
[K_NONCE] = { "nonce=", "" },
|
||||
[K_LAST] = { NULL, NULL}
|
||||
};
|
||||
|
||||
peer_report = sip_find_peer(peer, addr, TRUE, FINDPEERS, FALSE, p->socket.type);
|
||||
|
||||
switch(res_report) {
|
||||
case AUTH_DONT_KNOW:
|
||||
break;
|
||||
case AUTH_SUCCESSFUL:
|
||||
if (peer_report) {
|
||||
if (ast_strlen_zero(peer_report->secret) && ast_strlen_zero(peer_report->md5secret)) {
|
||||
sip_report_auth_success(p, 0);
|
||||
} else {
|
||||
sip_report_auth_success(p, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AUTH_CHALLENGE_SENT:
|
||||
sip_report_chal_sent(p);
|
||||
break;
|
||||
case AUTH_SECRET_FAILED:
|
||||
case AUTH_USERNAME_MISMATCH:
|
||||
sip_auth_headers(WWW_AUTH, &respheader, &reqheader);
|
||||
authtoken = sip_get_header(req, reqheader);
|
||||
buf = ast_str_thread_get(&check_auth_buf, CHECK_AUTH_BUF_INITLEN);
|
||||
ast_str_set(&buf, 0, "%s", authtoken);
|
||||
c = ast_str_buffer(buf);
|
||||
|
||||
sip_digest_parser(c, keys);
|
||||
|
||||
if (res_report == AUTH_SECRET_FAILED) {
|
||||
sip_report_inval_password(p, keys[K_NONCE].s, keys[K_RESP].s);
|
||||
} else {
|
||||
if (peer_report) {
|
||||
sip_report_failed_challenge_response(p, keys[K_USER].s, peer_report->username);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AUTH_NOT_FOUND:
|
||||
/* with sip_cfg.alwaysauthreject on, generates 2 events */
|
||||
sip_report_invalid_peer(p);
|
||||
break;
|
||||
case AUTH_UNKNOWN_DOMAIN:
|
||||
snprintf(aclname, sizeof(aclname), "domain_must_match");
|
||||
sip_report_failed_acl(p, aclname);
|
||||
break;
|
||||
case AUTH_PEER_NOT_DYNAMIC:
|
||||
snprintf(aclname, sizeof(aclname), "peer_not_dynamic");
|
||||
sip_report_failed_acl(p, aclname);
|
||||
break;
|
||||
case AUTH_ACL_FAILED:
|
||||
/* with sip_cfg.alwaysauthreject on, generates 2 events */
|
||||
snprintf(aclname, sizeof(aclname), "device_must_match_acl");
|
||||
sip_report_failed_acl(p, aclname);
|
||||
break;
|
||||
case AUTH_BAD_TRANSPORT:
|
||||
sip_report_inval_transport(p, sip_get_transport(req->socket.type));
|
||||
break;
|
||||
case AUTH_RTP_FAILED:
|
||||
break;
|
||||
case AUTH_SESSION_LIMIT:
|
||||
sip_report_session_limit(p);
|
||||
break;
|
||||
}
|
||||
|
||||
if (peer_report) {
|
||||
sip_unref_peer(peer_report, "sip_report_security_event: sip_unref_peer: from handle_incoming");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2012, Digium, Inc.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief Utility functions for chan_sip
|
||||
*
|
||||
* \author Terry Wilson <twilson@digium.com>
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>deprecated</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/cli.h"
|
||||
#include "include/sip.h"
|
||||
#include "include/sip_utils.h"
|
||||
|
||||
const char *force_rport_string(struct ast_flags *flags)
|
||||
{
|
||||
if (ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) {
|
||||
return ast_test_flag(&flags[0], SIP_NAT_FORCE_RPORT) ? "Auto (Yes)" : "Auto (No)";
|
||||
}
|
||||
return AST_CLI_YESNO(ast_test_flag(&flags[0], SIP_NAT_FORCE_RPORT));
|
||||
}
|
||||
|
||||
const char *comedia_string(struct ast_flags *flags)
|
||||
{
|
||||
if (ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA)) {
|
||||
return ast_test_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP) ? "Auto (Yes)" : "Auto (No)";
|
||||
}
|
||||
return AST_CLI_YESNO(ast_test_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP));
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
;
|
||||
; Open Sound System Console Driver Configuration File
|
||||
;
|
||||
[general]
|
||||
;
|
||||
; Automatically answer incoming calls on the console? Choose yes if
|
||||
; for example you want to use this as an intercom.
|
||||
;
|
||||
autoanswer=yes
|
||||
;
|
||||
; Default context (is overridden with @context syntax)
|
||||
;
|
||||
context=local
|
||||
;
|
||||
; Default extension to call
|
||||
;
|
||||
extension=s
|
||||
;
|
||||
; Default language
|
||||
;
|
||||
;language=en
|
||||
;
|
||||
; Default Music on Hold class to use when this channel is placed on hold in
|
||||
; the case that the music class is not set on the channel with
|
||||
; Set(CHANNEL(musicclass)=whatever) in the dialplan and the peer channel
|
||||
; putting this one on hold did not suggest a class to use.
|
||||
;
|
||||
;mohinterpret=default
|
||||
;
|
||||
; Silence suppression can be enabled when sound is over a certain threshold.
|
||||
; The value for the threshold should probably be between 500 and 2000 or so,
|
||||
; but your mileage may vary. Use the echo test to evaluate the best setting.
|
||||
;silencesuppression = yes
|
||||
;silencethreshold = 1000
|
||||
;
|
||||
; To set which ALSA device to use, change this parameter
|
||||
;input_device=hw:0,0
|
||||
;output_device=hw:0,0
|
||||
|
||||
;
|
||||
; Default mute state (can also be toggled via CLI)
|
||||
;mute=true
|
||||
|
||||
;
|
||||
; If enabled, no audio capture device will be opened. This is useful on
|
||||
; systems where there will be no return audio path, such as overhead pagers.
|
||||
;noaudiocapture=true
|
||||
|
||||
; ----------------------------- JITTER BUFFER CONFIGURATION --------------------------
|
||||
; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of an
|
||||
; ALSA channel. Defaults to "no". An enabled jitterbuffer will
|
||||
; be used only if the sending side can create and the receiving
|
||||
; side can not accept jitter. The ALSA channel can't accept jitter,
|
||||
; thus an enabled jitterbuffer on the receive ALSA side will always
|
||||
; be used if the sending side can create jitter.
|
||||
|
||||
; jbmaxsize = 200 ; Max length of the jitterbuffer in milliseconds.
|
||||
|
||||
; jbresyncthreshold = 1000 ; Jump in the frame timestamps over which the jitterbuffer is
|
||||
; resynchronized. Useful to improve the quality of the voice, with
|
||||
; big jumps in/broken timestamps, usually sent from exotic devices
|
||||
; and programs. Defaults to 1000.
|
||||
|
||||
; jbimpl = fixed ; Jitterbuffer implementation, used on the receiving side of a SIP
|
||||
; channel. Two implementations are currently available - "fixed"
|
||||
; (with size always equals to jbmax-size) and "adaptive" (with
|
||||
; variable size, actually the new jb of IAX2). Defaults to fixed.
|
||||
|
||||
; jbtargetextra = 40 ; This option only affects the jb when 'jbimpl = adaptive' is set.
|
||||
; The option represents the number of milliseconds by which the new
|
||||
; jitter buffer will pad its size. the default is 40, so without
|
||||
; modification, the new jitter buffer will set its size to the jitter
|
||||
; value plus 40 milliseconds. increasing this value may help if your
|
||||
; network normally has low jitter, but occasionally has spikes.
|
||||
|
||||
; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no".
|
||||
; ----------------------------------------------------------------------------------
|
|
@ -89,6 +89,8 @@ documentation_language = en_US ; Set the language you want documentation
|
|||
; configuration files (/etc/asterisk) with a
|
||||
; lock.
|
||||
;stdexten = gosub ; How to invoke the extensions.conf stdexten.
|
||||
; macro - Invoke the stdexten using a macro as
|
||||
; done by legacy Asterisk versions.
|
||||
; gosub - Invoke the stdexten using a gosub as
|
||||
; documented in extensions.conf.sample.
|
||||
; Default gosub.
|
||||
|
|
|
@ -181,10 +181,15 @@
|
|||
;
|
||||
; When using a generic CC agent, the caller who requested CC will be
|
||||
; called back when a called party becomes available. When the caller
|
||||
; answers his phone, the administrator may opt to have a subroutine
|
||||
; run. By default there is no callback subroutine configured. The
|
||||
; subroutine should be specified in the format:
|
||||
; [[context,]exten,]priority
|
||||
; answers his phone, the administrator may opt to have a macro run.
|
||||
; What this macro does is up to the administrator. By default there
|
||||
; is no callback macro configured.
|
||||
;
|
||||
;cc_callback_macro=
|
||||
;
|
||||
; Alternatively, the administrator may run a subroutine. By default
|
||||
; there is no callback subroutine configured. The subroutine should
|
||||
; be specified in the format: [[context,]exten,]priority
|
||||
;
|
||||
;cc_callback_sub=
|
||||
;
|
||||
|
|
|
@ -7,5 +7,6 @@
|
|||
; Any commands listed in this section will get automatically executed
|
||||
; when Asterisk starts as a daemon or foreground process (-c).
|
||||
;
|
||||
;sip set debug on = yes
|
||||
;core set verbose 3 = yes
|
||||
;core set debug 1 = yes
|
||||
|
|
|
@ -137,6 +137,8 @@ show queue=queue show
|
|||
add queue member=queue add member
|
||||
remove queue member=queue remove member
|
||||
ael no debug=ael nodebug
|
||||
sip debug=sip set debug
|
||||
sip no debug=sip set debug off
|
||||
show voicemail users=voicemail show users
|
||||
show voicemail zones=voicemail show zones
|
||||
iax2 trunk debug=iax2 set debug trunk
|
||||
|
@ -171,6 +173,9 @@ core set chanvar=dialplan set chanvar
|
|||
agi dumphtml=agi dump html
|
||||
ael debug=ael set debug
|
||||
funcdevstate list=devstate list
|
||||
sip history=sip set history on
|
||||
skinny debug=skinny set debug on
|
||||
mgcp set debug=mgcp set debug on
|
||||
abort shutdown=core abort shutdown
|
||||
stop now=core stop now
|
||||
stop gracefully=core stop gracefully
|
||||
|
|
|
@ -30,7 +30,7 @@ default_perm=permit ; To leave asterisk working as normal
|
|||
; This list is read in the sequence that is being written, so
|
||||
; In this example the user 'eliel' is allow to run only the following
|
||||
; commands:
|
||||
; pjsip show endpoints
|
||||
; sip show peer
|
||||
; core set debug
|
||||
; core set verbose
|
||||
; If the user is not specified, the default_perm option will be apply to
|
||||
|
@ -39,14 +39,14 @@ default_perm=permit ; To leave asterisk working as normal
|
|||
; Notice that you can also use regular expressions to allow or deny access to a
|
||||
; certain command like: 'core show application D*'. In this example the user will be
|
||||
; allowed to view the documentation for all the applications starting with 'D'.
|
||||
; Another regular expression could be: 'channel originate PJSIP/[0-9]* extension *'
|
||||
; allowing the user to use 'channel originate' on a pjsip channel and with the 'extension'
|
||||
; Another regular expression could be: 'channel originate SIP/[0-9]* extension *'
|
||||
; allowing the user to use 'channel originate' on a sip channel and with the 'extension'
|
||||
; parameter and avoiding the use of the 'application' parameter.
|
||||
;
|
||||
; We can also use the templates syntax:
|
||||
; [supportTemplate](!)
|
||||
; deny=all
|
||||
; permit=pjsip show ; all commands starting with 'pjsip show' will be allowed
|
||||
; permit=sip show ; all commands starting with 'sip show' will be allowed
|
||||
; permit=core show
|
||||
;
|
||||
; You can specify permissions for a local group instead of a user,
|
||||
|
@ -55,20 +55,20 @@ default_perm=permit ; To leave asterisk working as normal
|
|||
;
|
||||
;[@adm]
|
||||
;deny=all
|
||||
;permit=pjsip
|
||||
;permit=sip
|
||||
;permit=core
|
||||
;
|
||||
;
|
||||
;[eliel]
|
||||
;deny=all
|
||||
;permit=pjsip show endpoint
|
||||
;deny=pjsip show endpoints
|
||||
;permit=sip show peer
|
||||
;deny=sip show peers
|
||||
;permit=core set
|
||||
;
|
||||
;
|
||||
;User 'tommy' inherits from template 'supportTemplate':
|
||||
; deny=all
|
||||
; permit=pjsip show
|
||||
; permit=sip show
|
||||
; permit=core show
|
||||
;[tommy](supportTemplate)
|
||||
;permit=core set debug
|
||||
|
|
|
@ -83,10 +83,10 @@ genericplc_on_equal_codecs => false
|
|||
; Once this config file is loaded, silk8 can be used anywhere a
|
||||
; peer's codec capabilities are defined.
|
||||
;
|
||||
; In pjsip.conf 'silk8' can be defined as a capability for an endpoint.
|
||||
; [endpoint1]
|
||||
; In sip.conf 'silk8' can be defined as a capability for a peer.
|
||||
; [peer1]
|
||||
; type=peer
|
||||
; aor=endpoint1
|
||||
; host=dynamic
|
||||
; disallow=all
|
||||
; allow=silk8 ;custom codec defined in codecs.conf
|
||||
;
|
||||
|
|
|
@ -76,6 +76,8 @@
|
|||
;
|
||||
;iaxusers => odbc,asterisk
|
||||
;iaxpeers => odbc,asterisk
|
||||
;sippeers => odbc,asterisk
|
||||
;sipregs => odbc,asterisk ; (avoid sipregs if possible, e.g. by using a view)
|
||||
;ps_endpoints => odbc,asterisk
|
||||
;ps_auths => odbc,asterisk
|
||||
;ps_aors => odbc,asterisk
|
||||
|
|
|
@ -127,7 +127,7 @@ context ael-dundi-e164-customers {
|
|||
//
|
||||
// If you are an ITSP or Reseller, list your customers here.
|
||||
//
|
||||
//_12564286000 => Dial(PJSIP/customer1);
|
||||
//_12564286000 => Dial(SIP/customer1);
|
||||
//_12564286001 => Dial(IAX2/customer2);
|
||||
};
|
||||
|
||||
|
@ -141,7 +141,7 @@ context ael-dundi-e164-via-pstn {
|
|||
|
||||
context ael-dundi-e164-local {
|
||||
//
|
||||
// Context to put your dundi or IAX2 user in for
|
||||
// Context to put your dundi IAX2 or SIP user in for
|
||||
// full access
|
||||
//
|
||||
includes {
|
||||
|
@ -173,6 +173,18 @@ context ael-dundi-e164-lookup {
|
|||
//
|
||||
};
|
||||
|
||||
//
|
||||
// DUNDi can also be implemented as a Macro instead of using
|
||||
// the Local channel driver.
|
||||
//
|
||||
macro ael-dundi-e164(exten) {
|
||||
//
|
||||
// ARG1 is the extension to Dial
|
||||
//
|
||||
goto ${exten}|1;
|
||||
return;
|
||||
};
|
||||
|
||||
//
|
||||
// The SWITCH statement permits a server to share the dialplan with
|
||||
// another server. Use with care: Reciprocal switch statements are not
|
||||
|
@ -288,6 +300,22 @@ context ael-local {
|
|||
// eswitch => IAX2/context@${CURSERVER}
|
||||
|
||||
|
||||
macro ael-std-exten-ael( ext , dev ) {
|
||||
Dial(${dev}/${ext},20);
|
||||
switch(${DIALSTATUS}) {
|
||||
case BUSY:
|
||||
Voicemail(${ext},b);
|
||||
break;
|
||||
default:
|
||||
Voicemail(${ext},u);
|
||||
};
|
||||
catch a {
|
||||
VoiceMailMain(${ext});
|
||||
return;
|
||||
};
|
||||
return;
|
||||
};
|
||||
|
||||
context ael-demo {
|
||||
s => {
|
||||
Wait(1);
|
||||
|
@ -355,8 +383,11 @@ context ael-default {
|
|||
};
|
||||
//
|
||||
// Extensions like the two below can be used for FWD, Nikotel, sipgate etc.
|
||||
// Note that you must have a [sipprovider] section in sip.conf whereas
|
||||
// the otherprovider.net example does not require such a peer definition
|
||||
//
|
||||
//_42X. => Dial(PJSIP/user:passwd@${EXTEN:2}@otherprovider.net,30,rT);
|
||||
//_41X. => Dial(SIP/${EXTEN:2}@sipprovider,,r);
|
||||
//_42X. => Dial(SIP/user:passwd@${EXTEN:2}@otherprovider.net,30,rT);
|
||||
|
||||
// Real extensions would go here. Generally you want real extensions to be
|
||||
// 4 or 5 digits long (although there is no such requirement) and start with a
|
||||
|
@ -365,8 +396,8 @@ context ael-default {
|
|||
// them with names, too, and use global variables
|
||||
|
||||
// 6245 => {
|
||||
// hint(PJSIP/Grandstream1&PJSIP/Xlite1,Joe Schmoe); // Channel hints for presence
|
||||
// Dial(PJSIP/Grandstream1,20,rt); // permit transfer
|
||||
// hint(SIP/Grandstream1&SIP/Xlite1,Joe Schmoe); // Channel hints for presence
|
||||
// Dial(SIP/Grandstream1,20,rt); // permit transfer
|
||||
// Dial(${HINT}/5245},20,rtT); // Use hint as listed
|
||||
// switch(${DIALSTATUS}) {
|
||||
// case BUSY:
|
||||
|
@ -379,6 +410,7 @@ context ael-default {
|
|||
// };
|
||||
|
||||
// 6361 => Dial(IAX2/JaneDoe,,rm); // ring without time limit
|
||||
// 6389 => Dial(MGCP/aaln/1@192.168.0.14);
|
||||
// 6394 => Dial(Local/6275/n); // this will dial ${MARK}
|
||||
|
||||
// 6275 => &ael-stdexten(6275,${MARK}); // assuming ${MARK} is something like DAHDI/2
|
||||
|
|
|
@ -222,7 +222,7 @@ TRUNKMSD=1 ; MSD digits to strip (usually 1 or 0)
|
|||
;
|
||||
; so that dialtone remains even after dialing a 9. Please note that ignorepat
|
||||
; only works with channels which receive dialtone from the PBX, such as DAHDI,
|
||||
; Phone, and VPB. Other channels, such as IAX2, PJSIP, and SIP, which generate
|
||||
; Phone, and VPB. Other channels, such as IAX2, PJSIP, SIP and MGCP, which generate
|
||||
; generate their own dialtone and converse with the PBX only after a number is
|
||||
; complete, are generally unaffected by ignorepat (unless DISA or another method
|
||||
; is used to generate a dialtone after answering the channel).
|
||||
|
@ -289,7 +289,8 @@ include => dundi-e164-switch
|
|||
; ARG1 is the extension to Dial
|
||||
;
|
||||
; Extension "s" is not a wildcard extension that matches "anything".
|
||||
; In most other cases, you have to goto "s" to execute that extension.
|
||||
; In macros, it is the start extension. In most other cases,
|
||||
; you have to goto "s" to execute that extension.
|
||||
;
|
||||
; Note: In old versions of Asterisk the PBX in some cases defaulted to
|
||||
; extension "s" when a given extension was wrong (like in AMI originate).
|
||||
|
@ -424,14 +425,14 @@ exten => _X!,1,Verbose(2,Performing ISN lookup for ${EXTEN})
|
|||
same => n,GotoIf($["${FILTER(0-9,${SUFFIX})}" != "${SUFFIX}"]?fn-CONGESTION,1)
|
||||
; filter out bad characters per the README-SERIOUSLY.best-practices.txt document
|
||||
same => n,Set(TIMEOUT(absolute)=10800)
|
||||
same => n,Set(isnresult=${ENUMLOOKUP(${EXTEN},pjsip,,1,freenum.org)}) ; perform our lookup with freenum.org
|
||||
same => n,Set(isnresult=${ENUMLOOKUP(${EXTEN},sip,,1,freenum.org)}) ; perform our lookup with freenum.org
|
||||
same => n,GotoIf($["${isnresult}" != ""]?from)
|
||||
same => n,Set(DIALSTATUS=CONGESTION)
|
||||
same => n,Goto(fn-CONGESTION,1)
|
||||
same => n(from),Set(__SIPFROMUSER=${CALLERID(num)})
|
||||
same => n,GotoIf($["${GLOBAL(FREENUMDOMAIN)}" = ""]?dial) ; check if we set the FREENUMDOMAIN global variable in [global]
|
||||
same => n,Set(__SIPFROMDOMAIN=${GLOBAL(FREENUMDOMAIN)}) ; if we did set it, then we'll use it for our outbound dialing domain
|
||||
same => n(dial),Dial(PJSIP/${isnresult},40)
|
||||
same => n(dial),Dial(SIP/${isnresult},40)
|
||||
same => n,Goto(fn-${DIALSTATUS},1)
|
||||
|
||||
exten => fn-BUSY,1,Busy()
|
||||
|
@ -659,7 +660,9 @@ exten => _X.,1,Gosub(sub-page,s,1(SIP/${EXTEN}))
|
|||
|
||||
[public]
|
||||
;
|
||||
; ATTENTION: If your Asterisk is connected to the internet,
|
||||
; ATTENTION: If your Asterisk is connected to the internet and you do
|
||||
; not have allowguest=no in sip.conf, everybody out there may use your
|
||||
; public context without authentication. In that case you want to
|
||||
; double check which services you offer to the world.
|
||||
;
|
||||
include => demo
|
||||
|
@ -671,19 +674,26 @@ include => demo
|
|||
;
|
||||
include => demo
|
||||
|
||||
;
|
||||
; An extension like the one below can be used for FWD, Nikotel, sipgate etc.
|
||||
; Note that you must have a [sipprovider] section in sip.conf
|
||||
;
|
||||
;exten => _41X.,1,Dial(SIP/${FILTER(0-9,${EXTEN:2})}@sipprovider,,r)
|
||||
|
||||
; Real extensions would go here. Generally you want real extensions to be
|
||||
; 4 or 5 digits long (although there is no such requirement) and start with a
|
||||
; single digit that is fairly large (like 6 or 7) so that you have plenty of
|
||||
; room to overlap extensions and menu options without conflict. You can alias
|
||||
; them with names, too, and use global variables
|
||||
|
||||
;exten => 6245,hint,PJSIP/Grandstream1&PJSIP/Xlite1(Joe Schmoe) ; Channel hints for presence
|
||||
;exten => 6245,1,Dial(PJSIP/Grandstream1,20,rt) ; permit transfer
|
||||
;exten => 6245,hint,SIP/Grandstream1&SIP/Xlite1(Joe Schmoe) ; Channel hints for presence
|
||||
;exten => 6245,1,Dial(SIP/Grandstream1,20,rt) ; permit transfer
|
||||
;exten => 6245,n(dial),Dial(${HINT},20,rtT) ; Use hint as listed
|
||||
;exten => 6245,n,VoiceMail(6245,u) ; Voicemail (unavailable)
|
||||
;exten => 6245,s+1,Hangup ; s+1, same as n
|
||||
;exten => 6245,dial+101,VoiceMail(6245,b) ; Voicemail (busy)
|
||||
;exten => 6361,1,Dial(IAX2/JaneDoe,,rm) ; ring without time limit
|
||||
;exten => 6389,1,Dial(MGCP/aaln/1@192.168.0.14)
|
||||
;exten => 6390,1,Dial(JINGLE/caller/callee) ; Dial via jingle using labels
|
||||
;exten => 6391,1,Dial(JINGLE/asterisk@digium.com/mogorman@astjab.org) ;Dial via jingle using asterisk as the transport and calling mogorman.
|
||||
;exten => 6394,1,Dial(Local/6275/n) ; this will dial ${MARK}
|
||||
|
@ -698,7 +708,7 @@ include => demo
|
|||
;exten => wil,1,Goto(6236,1)
|
||||
|
||||
;If you want to subscribe to the status of a parking space, this is
|
||||
;how you do it. Subscribe to extension 6600, and you will see
|
||||
;how you do it. Subscribe to extension 6600 in sip, and you will see
|
||||
;the status of the first parking lot with this extensions' help
|
||||
;exten => 6600,hint,park:701@parkedcalls
|
||||
;exten => 6600,1,noop
|
||||
|
@ -748,7 +758,7 @@ include => demo
|
|||
;
|
||||
;exten => t,1,Goto(s,goodbye)
|
||||
;
|
||||
; this is the context our internal SIP hardphones use
|
||||
; this is the context our internal SIP hardphones use (see sip.conf)
|
||||
;
|
||||
;[acme-internal]
|
||||
;exten => s,1,Answer()
|
||||
|
@ -789,6 +799,28 @@ include => demo
|
|||
; ...
|
||||
; include => time
|
||||
;
|
||||
; Note: if you're geographically spread out, you can have SIP extensions
|
||||
; specify their own local timezone in sip.conf as:
|
||||
;
|
||||
; [boi]
|
||||
; type=friend
|
||||
; context=acme-internal
|
||||
; callerid="Boise Ofc. <2083451111>"
|
||||
; ...
|
||||
; ; use system-wide default timezone of MST7MDT
|
||||
;
|
||||
; [lws]
|
||||
; type=friend
|
||||
; context=acme-internal
|
||||
; callerid="Lewiston Ofc. <2087431111>"
|
||||
; ...
|
||||
; setvar=timezone=PST8PDT
|
||||
;
|
||||
; "timezone" isn't a 'reserved' name in any way, and other places where
|
||||
; the timezone is significant (e.g. calls to "SayUnixTime()", etc) will
|
||||
; require modification as well. Note that voicemail.conf already has
|
||||
; a mechanism for timezones.
|
||||
;
|
||||
|
||||
[time]
|
||||
exten => _X.,30000(time),NoOp(Time: ${EXTEN} ${timezone})
|
||||
|
@ -799,6 +831,7 @@ exten => _X.,30000(time),NoOp(Time: ${EXTEN} ${timezone})
|
|||
same => n,Set(FUTURETIME=$[${EPOCH} + 12])
|
||||
same => n,SayUnixTime(${FUTURETIME},Zulu,HNS)
|
||||
same => n,SayPhonetic(z)
|
||||
; use the timezone associated with the extension (sip only), or system-wide
|
||||
; default if one hasn't been set.
|
||||
same => n,SayUnixTime(${FUTURETIME},${timezone},HNS)
|
||||
same => n,Playback(spy-local)
|
||||
|
|
|
@ -212,7 +212,9 @@ extensions = {
|
|||
};
|
||||
|
||||
public = {
|
||||
-- ATTENTION: If your Asterisk is connected to the internet
|
||||
-- ATTENTION: If your Asterisk is connected to the internet and you do
|
||||
-- not have allowguest=no in sip.conf, everybody out there may use your
|
||||
-- public context without authentication. In that case you want to
|
||||
-- double check which services you offer to the world.
|
||||
--
|
||||
include = {"demo"};
|
||||
|
|
|
@ -4,9 +4,6 @@
|
|||
; This is an example on how to use the Mini-Voicemail system to build
|
||||
; voicemail systems.
|
||||
;
|
||||
; This example remains for now despite using macro, with the idea that if anyone is still
|
||||
; using this sample, they can be encouraged to re-write it using gosub.
|
||||
;
|
||||
;.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
|
||||
; A macro to test the MINIVMACCOUNT dialplan function
|
||||
; Currently, accountcode and pincode is not used in the application
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
;
|
||||
; Sample Call Features (transfer, mixmonitor, etc) configuration
|
||||
; Sample Call Features (transfer, monitor/mixmonitor, etc) configuration
|
||||
;
|
||||
|
||||
; Note: From Asterisk 12 - All parking lot configuration is now done in res_parking.conf
|
||||
|
@ -18,7 +18,7 @@
|
|||
;pickupfailsound = beeperr ; to indicate that the pickup failed (default: no sound)
|
||||
;featuredigittimeout = 1000 ; Max time (ms) between digits for
|
||||
; feature activation (default is 1000 ms)
|
||||
;recordingfailsound = beeperr ; indicates that a one-touch mixmonitor feature failed
|
||||
;recordingfailsound = beeperr ; indicates that a one-touch monitor or one-touch mixmonitor feature failed
|
||||
; to be applied to the call. (default: no sound)
|
||||
;atxfernoanswertimeout = 15 ; Timeout for answer on attended transfer default is 15 seconds.
|
||||
;atxferdropcall = no ; If someone does an attended transfer, then hangs up before the transfer
|
||||
|
@ -45,6 +45,7 @@
|
|||
[featuremap]
|
||||
;blindxfer => #1 ; Blind transfer (default is #) -- Make sure to set the T and/or t option in the Dial() or Queue() app call!
|
||||
;disconnect => *0 ; Disconnect (default is *) -- Make sure to set the H and/or h option in the Dial() or Queue() app call!
|
||||
;automon => *1 ; One Touch Record a.k.a. Touch Monitor -- Make sure to set the W and/or w option in the Dial() or Queue() app call!
|
||||
;atxfer => *2 ; Attended transfer -- Make sure to set the T and/or t option in the Dial() or Queue() app call!
|
||||
;parkcall => #72 ; Park call (one step parking) -- Make sure to set the K and/or k option in the Dial() app call!
|
||||
;automixmon => *3 ; One Touch Record a.k.a. Touch MixMonitor -- Make sure to set the X and/or x option in the Dial() or Queue() app call!
|
||||
|
@ -94,8 +95,8 @@
|
|||
; by the PBX core. In this case, these applications are executed outside of the
|
||||
; PBX core, so it does *not* make sense to use any application which has any
|
||||
; concept of dialplan flow. Examples of this would be things like Goto,
|
||||
; Background, WaitExten, and many more. The exceptions to this are Gosub
|
||||
; routines which must complete for the call to continue.
|
||||
; Background, WaitExten, and many more. The exceptions to this are Gosub and
|
||||
; Macro routines which must complete for the call to continue.
|
||||
;
|
||||
; Enabling these features means that the PBX needs to stay in the media flow and
|
||||
; media will not be re-directed if DTMF is sent in the media stream.
|
||||
|
@ -108,6 +109,11 @@
|
|||
; Set arbitrary channel variables, based upon CALLERID number (Note that the application
|
||||
; argument contains commas)
|
||||
;retrieveinfo => #8,peer,Set(ARRAY(CDR(mark),CDR(name))=${ODBC_FOO(${CALLERID(num)})})
|
||||
;
|
||||
;pauseMonitor => #1,self/callee,Pausemonitor ;Allow the callee to pause monitoring
|
||||
; ;on their channel
|
||||
;unpauseMonitor => #3,self/callee,UnPauseMonitor ;Allow the callee to unpause monitoring
|
||||
; ;on their channel
|
||||
|
||||
; Dynamic Feature Groups:
|
||||
; Dynamic feature groups are groupings of features defined in [applicationmap]
|
||||
|
@ -117,5 +123,5 @@
|
|||
; example:
|
||||
; [myGroupName] ; defines the group named myGroupName
|
||||
; testfeature => #9 ; associates testfeature with the group and the keycode '#9'.
|
||||
; retrieveinfo => ; associates retrieveinfo with the group and uses the keycode specified
|
||||
; pauseMonitor => ; associates pauseMonitor with the group and uses the keycode specified
|
||||
; ; in the [applicationmap].
|
||||
|
|
|
@ -27,8 +27,9 @@ capture_id = 1234 ; A unique integer identifier for this
|
|||
; with each packet from this server.
|
||||
uuid_type = call-id ; Specify the preferred source for the Homer
|
||||
; correlation UUID. Valid options are:
|
||||
; - 'call-id' for the PJSIP
|
||||
; - 'call-id' for the PJSIP or chan_sip SIP
|
||||
; Call-ID
|
||||
; - 'channel' for the Asterisk channel name
|
||||
; Note: If 'call-id' is specified but the
|
||||
; channel is not PJSIP then the Asterisk
|
||||
; channel name will be used instead.
|
||||
; channel is not PJSIP or chan_sip then the
|
||||
; Asterisk channel name will be used instead.
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
;
|
||||
; MGCP Configuration for Asterisk
|
||||
;
|
||||
[general]
|
||||
;port = 2427
|
||||
;bindaddr = 0.0.0.0
|
||||
|
||||
; See https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service for a description of these parameters.
|
||||
;tos=cs3 ; Sets TOS for signaling packets.
|
||||
;tos_audio=ef ; Sets TOS for RTP audio packets.
|
||||
;cos=3 ; Sets 802.1p priority for signaling packets.
|
||||
;cos_audio=5 ; Sets 802.1p priority for RTP audio packets.
|
||||
|
||||
; --------------------- DIGIT TIMEOUTS ----------------------------
|
||||
firstdigittimeout = 30000 ; default 16000 = 16s
|
||||
gendigittimeout = 10000 ; default 8000 = 8s
|
||||
matchdigittimeout = 5000 ; defaults 3000 = 3s
|
||||
|
||||
; ----------------------------- JITTER BUFFER CONFIGURATION --------------------------
|
||||
; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of a
|
||||
; MGCP channel. Defaults to "no". An enabled jitterbuffer will
|
||||
; be used only if the sending side can create and the receiving
|
||||
; side can not accept jitter. The MGCP channel can accept jitter,
|
||||
; thus an enabled jitterbuffer on the receive MGCP side will only
|
||||
; be used if the sending side can create jitter and jbforce is
|
||||
; also set to yes.
|
||||
|
||||
; jbforce = no ; Forces the use of a jitterbuffer on the receive side of a MGCP
|
||||
; channel. Defaults to "no".
|
||||
|
||||
; jbmaxsize = 200 ; Max length of the jitterbuffer in milliseconds.
|
||||
|
||||
; jbresyncthreshold = 1000 ; Jump in the frame timestamps over which the jitterbuffer is
|
||||
; resynchronized. Useful to improve the quality of the voice, with
|
||||
; big jumps in/broken timestamps, usually sent from exotic devices
|
||||
; and programs. Defaults to 1000.
|
||||
|
||||
; jbimpl = fixed ; Jitterbuffer implementation, used on the receiving side of a MGCP
|
||||
; channel. Two implementations are currently available - "fixed"
|
||||
; (with size always equals to jbmax-size) and "adaptive" (with
|
||||
; variable size, actually the new jb of IAX2). Defaults to fixed.
|
||||
|
||||
; jbtargetextra = 40 ; This option only affects the jb when 'jbimpl = adaptive' is set.
|
||||
; The option represents the number of milliseconds by which the new
|
||||
; jitter buffer will pad its size. the default is 40, so without
|
||||
; modification, the new jitter buffer will set its size to the jitter
|
||||
; value plus 40 milliseconds. increasing this value may help if your
|
||||
; network normally has low jitter, but occasionally has spikes.
|
||||
|
||||
; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no".
|
||||
; ----------------------------------------------------------------------------------
|
||||
|
||||
;[dlinkgw]
|
||||
;host = 192.168.0.64
|
||||
;context = default
|
||||
;directmedia = no
|
||||
;line => aaln/2
|
||||
;line => aaln/1
|
||||
|
||||
;; The MGCP channel supports the following service codes:
|
||||
;; # - Transfer
|
||||
;; *67 - Calling Number Delivery Blocking
|
||||
;; *70 - Cancel Call Waiting
|
||||
;; *72 - Call Forwarding Activation
|
||||
;; *73 - Call Forwarding Deactivation
|
||||
;; *78 - Do Not Disturb Activation
|
||||
;; *79 - Do Not Disturb Deactivation
|
||||
;; *8 - Call pick-up
|
||||
;
|
||||
; known to work with Swissvoice IP10s
|
||||
;[192.168.1.20]
|
||||
;context=local
|
||||
;host=192.168.1.20
|
||||
;callerid = "John Doe" <123>
|
||||
;callgroup=0 ; in the range from 0 to 63
|
||||
;pickupgroup=0 ; in the range from 0 to 63
|
||||
;nat=no
|
||||
;threewaycalling=yes
|
||||
;transfer=yes ; transfer requires threewaycalling=yes. Use FLASH to transfer
|
||||
;callwaiting=yes ; this might be a cause of trouble for ip10s
|
||||
;cancallforward=yes
|
||||
;line => aaln/1
|
||||
;
|
||||
|
||||
;[dph100]
|
||||
;
|
||||
; Supporting the DPH100M requires defining DLINK_BUGGY_FIRMWARE in
|
||||
; chan_mgcp.c in addition to enabling the slowsequence mode due to
|
||||
; bugs in the D-Link firmware
|
||||
;
|
||||
;context=local
|
||||
;host=dynamic
|
||||
;dtmfmode=none ; DTMF Mode can be 'none', 'rfc2833', or 'inband' or
|
||||
; 'hybrid' which starts in none and moves to inband. Default is none.
|
||||
;slowsequence=yes ; The DPH100M does not follow MGCP standards for sequencing
|
||||
;line => aaln/1
|
||||
|
||||
; known to work with wave7optics FTTH LMGs
|
||||
;[192.168.1.20]
|
||||
;accountcode = 1000 ; record this in cdr as account identification for billing
|
||||
;amaflags = billing ; record this in cdr as flagged for 'billing',
|
||||
; 'documentation', or 'omit'
|
||||
;context = local
|
||||
;host = 192.168.1.20
|
||||
;wcardep = aaln/* ; enables wildcard endpoint and sets it to 'aaln/*'
|
||||
; another common format is '*'
|
||||
;callerid = "Duane Cox" <123> ; now lets setup line 1 using per endpoint configuration...
|
||||
;callwaiting = no
|
||||
;callreturn = yes
|
||||
;cancallforward = yes
|
||||
;directmedia = no
|
||||
;transfer = no
|
||||
;dtmfmode = inband
|
||||
;setvar=one=1 ; Set channel variables associated with this incoming line
|
||||
;setvar=two=2
|
||||
;line => aaln/1 ; now lets save this config to line1 aka aaln/1
|
||||
;clearvars=all ; Reset list of variables back to none
|
||||
;callerid = "Duane Cox" <456> ; now lets setup line 2
|
||||
;callwaiting = no
|
||||
;callreturn = yes
|
||||
;cancallforward = yes
|
||||
;directmedia = no
|
||||
;transfer = no
|
||||
;dtmfmode = inband
|
||||
;line => aaln/2 ; now lets save this config to line2 aka aaln/2
|
||||
|
||||
; PacketCable
|
||||
;[sbv5121e-mta.test.local]
|
||||
;host = 10.0.1.3
|
||||
;callwaiting = 1
|
||||
;canreinvite = 1
|
||||
;dtmfmode = rfc2833
|
||||
;amaflags = BILLING
|
||||
;ncs = yes ; Use NCS 1.0 signalling
|
||||
;pktcgatealloc = yes ; Allocate DQOS gate on CMTS
|
||||
;hangupongateremove = yes ; Hangup the channel if the CMTS close the gate
|
||||
;callerid = 3622622225
|
||||
;accountcode = test-3622622225
|
||||
;line = aaln/1
|
||||
;callerid = 3622622226
|
||||
;accountcode = test-3622622226
|
||||
;line = aaln/2
|
|
@ -34,7 +34,7 @@ format=wav49
|
|||
;
|
||||
;Turn on logfile with the following syntax. One line per voicemail received
|
||||
;with minivmRecord()
|
||||
; Mailbox:domain:exten:priority:callerchan:callerid:origdate:origtime:duration:durationstatus:accountcode
|
||||
; Mailbox:domain:macrocontext:exten:priority:callerchan:callerid:origdate:origtime:duration:durationstatus:accountcode
|
||||
;logfile=/var/log/asterisk/minivm.log
|
||||
; Who the e-mail notification should appear to come from
|
||||
serveremail=asterisk
|
||||
|
|
|
@ -31,9 +31,10 @@ autoload=yes
|
|||
;
|
||||
;load = res_musiconhold.so
|
||||
;
|
||||
; Load one of: console (portaudio).
|
||||
; Load one of: alsa, or console (portaudio).
|
||||
; By default, load chan_console only (automatically).
|
||||
;
|
||||
noload = chan_alsa.so
|
||||
;noload = chan_console.so
|
||||
;
|
||||
; Do not load res_hep and kin unless you are using HEP monitoring
|
||||
|
@ -43,6 +44,9 @@ noload = res_hep.so
|
|||
noload = res_hep_pjsip.so
|
||||
noload = res_hep_rtcp.so
|
||||
;
|
||||
; Do not load chan_sip by default, it may conflict with res_pjsip.
|
||||
noload = chan_sip.so
|
||||
;
|
||||
; Load one of the voicemail modules as they are mutually exclusive.
|
||||
; By default, load app_voicemail only (automatically).
|
||||
;
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
;
|
||||
; Open Settlement Protocol Sample Configuration File
|
||||
;
|
||||
; This file contains configuration of OSP server providers that are used by the
|
||||
; Asterisk OSP module. The section "general" is reserved for global options.
|
||||
; All other sections describe specific OSP Providers. The provider "default"
|
||||
; is used when no provider is otherwise specified.
|
||||
;
|
||||
; The "servicepoint" and "source" parameters must be configured. For most
|
||||
; implementations the other parameters in this file can be left unchanged.
|
||||
;
|
||||
[general]
|
||||
;
|
||||
; Enable cryptographic acceleration hardware.
|
||||
; The default value is no.
|
||||
;
|
||||
;accelerate=no
|
||||
;
|
||||
; Enable security features.
|
||||
; If security features are disabled, Asterisk cannot validate signed tokens and
|
||||
; all certificate file name parameters are ignored.
|
||||
; The default value is no.
|
||||
;
|
||||
;securityfeatures=no
|
||||
;
|
||||
; Defines the status of tokens that Asterisk will validate.
|
||||
; 0 - signed tokens only
|
||||
; 1 - unsigned tokens only
|
||||
; 2 - both signed and unsigned
|
||||
; The default value is 0, i.e. the Asterisk will only validate signed tokens.
|
||||
; If securityfeatures are disabled, Asterisk cannot validate signed tokens.
|
||||
;
|
||||
;tokenformat=0
|
||||
;
|
||||
;[default]
|
||||
;
|
||||
; List all service points (OSP servers) for this provider.
|
||||
; Use either domain name or IP address. Most OSP servers use port 5045.
|
||||
;
|
||||
;servicepoint=http://osptestserver.transnexus.com:5045/osp
|
||||
;
|
||||
; Define the "source" device for requesting OSP authorization.
|
||||
; This value is usually the domain name or IP address of the the Asterisk server.
|
||||
;
|
||||
;source=domain name or [IP address in brackets]
|
||||
;
|
||||
; Define path and file name of crypto files.
|
||||
; The default path for crypto file is /var/lib/asterisk/keys. If no path is
|
||||
; defined, crypto files will in /var/lib/asterisk/keys directory.
|
||||
;
|
||||
; Specify the private key file name.
|
||||
; If this parameter is unspecified or not present, the default name will be the
|
||||
; osp.conf section name followed by "-privatekey.pem" (for example:
|
||||
; default-privatekey.pem)
|
||||
; If securityfeatures are disabled, this parameter is ignored.
|
||||
;
|
||||
;privatekey=pkey.pem
|
||||
;
|
||||
; Specify the local certificate file.
|
||||
; If this parameter is unspecified or not present, the default name will be the
|
||||
; osp.conf section name followed by "- localcert.pem " (for example:
|
||||
; default-localcert.pem)
|
||||
; If securityfeatures are disabled, this parameter is ignored.
|
||||
;
|
||||
;localcert=localcert.pem
|
||||
;
|
||||
; Specify one or more Certificate Authority key file names. If none are listed,
|
||||
; a single Certificate Authority key file name is added with the default name of
|
||||
; the osp.conf section name followed by "-cacert_0.pem " (for example:
|
||||
; default-cacert_0.pem)
|
||||
; If securityfeatures are disabled, this parameter is ignored.
|
||||
;
|
||||
;cacert=cacert_0.pem
|
||||
;
|
||||
; Configure parameters for OSP communication between Asterisk OSP client and OSP
|
||||
; servers.
|
||||
;
|
||||
; maxconnections: Max number of simultaneous connections to the provider OSP
|
||||
; server (default=20)
|
||||
; retrydelay: Extra delay between retries (default=0)
|
||||
; retrylimit: Max number of retries before giving up (default=2)
|
||||
; timeout: Timeout for response in milliseconds (default=500)
|
||||
;
|
||||
;maxconnections=20
|
||||
;retrydelay=0
|
||||
;retrylimit=2
|
||||
;timeout=500
|
||||
;
|
||||
; Set the authentication policy.
|
||||
; 0 - NO - Accept all calls.
|
||||
; 1 - YES - Accept calls with valid token or no token. Block calls with
|
||||
; invalid token.
|
||||
; 2 - EXCLUSIVE - Accept calls with valid token. Block calls with invalid token
|
||||
; or no token.
|
||||
; Default is 1,
|
||||
; If securityfeatures are disabled, Asterisk cannot validate signed tokens.
|
||||
;
|
||||
;authpolicy=1
|
||||
;
|
||||
; Set the default destination protocol. The OSP module supports SIP, H323, and
|
||||
; IAX protocols. The default protocol is set to SIP.
|
||||
;
|
||||
;defaultprotocol=SIP
|
||||
;
|
||||
; Set the work mode.
|
||||
; 0 - Direct
|
||||
; 1 - Indirect
|
||||
; Default is 0,
|
||||
;
|
||||
;workmode=0
|
||||
;
|
||||
; Set the service type.
|
||||
; 0 - Normal voice service
|
||||
; 1 - Ported number query service
|
||||
; Default is 0,
|
||||
;
|
||||
;servicetype=0
|
|
@ -1,15 +1,16 @@
|
|||
[general]
|
||||
; This section applies only to the default users.conf config provider
|
||||
; This section applies only to the default sip.conf/users.conf config provider
|
||||
; embedded in res_phoneprov. Other providers may provide their own default settings.
|
||||
|
||||
; The default behavior of res_phoneprov will be to set the SERVER template variable to
|
||||
; the IP address that the phone uses to contact the provisioning server. Unless you have
|
||||
; an unusual setup, you should not need to set serveraddr, serveriface, or serverport.
|
||||
; the IP address that the phone uses to contact the provisioning server and the
|
||||
; SERVER_PORT variable to the bindport setting in sip.conf. Unless you have a very
|
||||
; unusual setup, you should not need to set serveraddr, serveriface, or serverport.
|
||||
|
||||
;serveraddr=192.168.1.1 ; Override address to send to the phone to use as server address.
|
||||
;serveriface=eth0 ; Same as above, except an ethernet interface.
|
||||
; Useful for when the interface uses DHCP and the asterisk http
|
||||
; server listens on a different IP than sip.
|
||||
; server listens on a different IP than chan_sip.
|
||||
;serverport=5060 ; Override port to send to the phone to use as server port.
|
||||
default_profile=polycom ; The default profile to use if none specified in users.conf
|
||||
|
||||
|
|
|
@ -28,9 +28,16 @@ persistentmembers = yes
|
|||
;autofill = no
|
||||
;
|
||||
; Monitor Type
|
||||
; monitor-type = MixMonitor is the only currently supported option.
|
||||
; As MixMonitor mixes the audio by default, "joining/mixing" the in/out
|
||||
; files is not necissary.
|
||||
; By setting monitor-type = MixMonitor, when specifying monitor-format
|
||||
; to enable recording of queue member conversations, app_queue will
|
||||
; now use the new MixMonitor application instead of Monitor so
|
||||
; the concept of "joining/mixing" the in/out files now goes away
|
||||
; when this is enabled. You can set the default type for all queues
|
||||
; here, and then also change monitor-type for individual queues within
|
||||
; queue by using the same configuration parameter within a queue
|
||||
; configuration block. If you do not specify or comment out this option,
|
||||
; it will default to the old 'Monitor' behavior to keep backward
|
||||
; compatibility.
|
||||
;
|
||||
monitor-type = MixMonitor
|
||||
;
|
||||
|
@ -261,6 +268,12 @@ monitor-type = MixMonitor
|
|||
;
|
||||
;setqueuevar=no
|
||||
|
||||
; if set, run this macro when connected to the queue member
|
||||
; you can override this macro by setting the macro option on
|
||||
; the queue application
|
||||
;
|
||||
;membermacro=macro_name[,arg1[,...][,argN]]
|
||||
|
||||
; if set, run this gosub when connected to the queue member
|
||||
; you can override this gosub by setting the gosub option on
|
||||
; the queue application
|
||||
|
@ -388,7 +401,7 @@ monitor-type = MixMonitor
|
|||
; The announcements will be played in the order in which they are defined. After
|
||||
; playing the last announcement, the announcements begin again from the beginning.
|
||||
;
|
||||
; Calls may be recorded using Asterisk's MixMonitor resource.
|
||||
; Calls may be recorded using Asterisk's monitor/MixMonitor resource
|
||||
; This can be enabled from within the Queue application, starting recording
|
||||
; when the call is actually picked up; thus, only successful calls are
|
||||
; recorded, and you are not recording while people are listening to MOH.
|
||||
|
@ -405,9 +418,13 @@ monitor-type = MixMonitor
|
|||
; monitor-format = gsm|wav|wav49
|
||||
;
|
||||
; Monitor Type
|
||||
; monitor-type = MixMonitor is the only currently supported option.
|
||||
; As MixMonitor mixes the audio by default, "joining/mixing" the in/out
|
||||
; files is not necissary.
|
||||
; By setting monitor-type = MixMonitor, when specifying monitor-format
|
||||
; to enable recording of queue member conversations, app_queue will
|
||||
; now use the new MixMonitor application instead of Monitor so
|
||||
; the concept of "joining/mixing" the in/out files now goes away
|
||||
; when this is enabled. If you do not specify or comment out this option,
|
||||
; it will default to the old 'Monitor' behavior to keep backward
|
||||
; compatibility.
|
||||
;
|
||||
; monitor-type = MixMonitor
|
||||
;
|
||||
|
@ -422,15 +439,21 @@ monitor-type = MixMonitor
|
|||
; You can specify a post recording command to be executed after the end of
|
||||
; recording by calling (from the dialplan)
|
||||
;
|
||||
; Set(MONITOR_EXEC=mv /var/spool/asterisk/monitor/^{MONITOR_FILENAME} /tmp/^{MONITOR_FILENAME})
|
||||
;
|
||||
; or
|
||||
;
|
||||
; Set(MONITOR_EXEC=mv /var/spool/asterisk/monitor/^{MIXMONITOR_FILENAME} /tmp/^{MIXMONITOR_FILENAME})
|
||||
;
|
||||
; If you choose to use the latter, you will not be able to switch the monitor-type back to Monitor
|
||||
; without changing this in the dialplan.
|
||||
;
|
||||
;
|
||||
; The command specified within the contents of MONITOR_EXEC will be executed when
|
||||
; the recording is over. Any strings matching ^{X} will be unescaped to ${X} and
|
||||
; all variables will be evaluated just prior to recording being started.
|
||||
;
|
||||
; The contents of MIXMONITOR_FILENAME will also be unescaped from ^{X} to ${X} and
|
||||
; The contents of MONITOR_FILENAME will also be unescaped from ^{X} to ${X} and
|
||||
; all variables will be evaluated just prior to recording being started.
|
||||
;
|
||||
; ---------------------- Queue Empty Options ----------------------------------
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
; and writes should be performed to the same database.
|
||||
;
|
||||
; For example, in extconfig.conf, you could specify a line like:
|
||||
; queue_members => mysql,readhost.asterisk/writehost.asterisk,queue_members
|
||||
; sippeers => mysql,readhost.asterisk/writehost.asterisk,sippeers
|
||||
; and then define the contexts [readhost.asterisk] and [writehost.asterisk]
|
||||
; below.
|
||||
;
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
; In order to use this module, you start
|
||||
; in extconfig.conf with a configuration like this:
|
||||
;
|
||||
; sippeers = ldap,"dc=myDomain,dc=myDomainExt",sip
|
||||
; extensions = ldap,"dc=myDomain,dc=myDomainExt",extensions
|
||||
; sip.conf = ldap,"dc=myDomain,dc=myDomainExt",config
|
||||
;
|
||||
; In the case of LDAP the last keyword in each line above specifies
|
||||
; a section in this file.
|
||||
|
@ -68,6 +70,60 @@ app = AstExtensionApplication
|
|||
appdata = AstExtensionApplicationData
|
||||
additionalFilter=(objectClass=AstExtension)
|
||||
|
||||
;
|
||||
; Sip Users Table
|
||||
;
|
||||
[sip]
|
||||
name = cn ; We use the "cn" as the default value for name on the line above
|
||||
; because objectClass=AsteriskSIPUser does not include a uid as an allowed field
|
||||
; If your entry combines other objectClasses and uid is available, you may
|
||||
; prefer to change the line to be name = uid, especially if your LDAP entries
|
||||
; contain spaces in the cn field.
|
||||
; You may also find it appropriate to use something completely different.
|
||||
; This is possible by changing the line above to name = AstAccountName (or whatever you
|
||||
; prefer).
|
||||
;
|
||||
amaflags = AstAccountAMAFlags
|
||||
callgroup = AstAccountCallGroup
|
||||
callerid = AstAccountCallerID
|
||||
directmedia = AstAccountDirectMedia
|
||||
context = AstAccountContext
|
||||
dtmfmode = AstAccountDTMFMode
|
||||
fromuser = AstAccountFromUser
|
||||
fromdomain = AstAccountFromDomain
|
||||
fullcontact = AstAccountFullContact
|
||||
fullcontact = gecos
|
||||
host = AstAccountHost
|
||||
insecure = AstAccountInsecure
|
||||
mailbox = AstAccountMailbox
|
||||
md5secret = AstAccountRealmedPassword ; Must be an MD5 hash. Field value can start with
|
||||
; {md5} but it is not required.
|
||||
; Generate the password via the md5sum command, e.g.
|
||||
; echo "my_password" | md5sum
|
||||
nat = AstAccountNAT
|
||||
deny = AstAccountDeny
|
||||
permit = AstAccountPermit
|
||||
pickupgroup = AstAccountPickupGroup
|
||||
port = AstAccountPort
|
||||
qualify = AstAccountQualify
|
||||
restrictcid = AstAccountRestrictCID
|
||||
rtptimeout = AstAccountRTPTimeout
|
||||
rtpholdtimeout = AstAccountRTPHoldTimeout
|
||||
type = AstAccountType
|
||||
disallow = AstAccountDisallowedCodec
|
||||
allow = AstAccountAllowedCodec
|
||||
MusicOnHold = AstAccountMusicOnHold
|
||||
regseconds = AstAccountExpirationTimestamp
|
||||
regcontext = AstAccountRegistrationContext
|
||||
regexten = AstAccountRegistrationExten
|
||||
CanCallForward = AstAccountCanCallForward
|
||||
ipaddr = AstAccountIPAddress
|
||||
defaultuser = AstAccountDefaultUser
|
||||
regserver = AstAccountRegistrationServer
|
||||
lastms = AstAccountLastQualifyMilliseconds
|
||||
supportpath = AstAccountPathSupport
|
||||
additionalFilter=(objectClass=AsteriskSIPUser)
|
||||
|
||||
;
|
||||
; IAX Users Table
|
||||
;
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
;; Sample res_pktccops.conf
|
||||
;
|
||||
;[general]
|
||||
;gateinfoperiod => 60 ; default 60s
|
||||
;gatetimeout = 150 ; default 150
|
||||
;t1 => 250 ; default 250s
|
||||
;t7 => 200 ; default 200s
|
||||
;t8 => 300 ; default 300s
|
||||
;keepalive => 60 ; default 60s
|
||||
;
|
||||
;[teszt]
|
||||
;host => 192.168.0.24
|
||||
;pool => 10.0.1.0 10.0.1.255
|
||||
;pool => 10.0.3.0 10.0.3.255
|
||||
;pool => 10.0.7.0 10.0.8.255
|
||||
;pool => 10.0.10.0 10.0.11.255
|
||||
;
|
||||
;[general]
|
||||
;gateinfoperiod => 60 ; default 60s
|
||||
;gatetimeout = 150 ; default 150
|
||||
;t1 => 250 ; default 250s
|
||||
;t7 => 200 ; default 200s
|
||||
;t8 => 300 ; default 300s
|
||||
;keepalive => 60 ; default 60s
|
||||
;
|
||||
;[test]
|
||||
;host => 192.168.0.24
|
||||
;pool => 10.0.1.0 10.0.1.255
|
||||
;pool => 10.0.3.0 10.0.3.255
|
||||
;pool => 10.0.7.0 10.0.8.255
|
||||
;pool => 10.0.10.0 10.0.11.255
|
||||
;
|
|
@ -6,10 +6,11 @@
|
|||
; provided by the STUN server an event is sent out internally within Asterisk
|
||||
; to alert all listeners to that event of the change.
|
||||
|
||||
; The current default listeners for the network change event include chan_iax.
|
||||
; Both of these channel drivers by default react to this event by renewing all
|
||||
; outbound registrations. This allows the endpoints Asterisk is registering with
|
||||
; to become aware of the address change and know the new location.
|
||||
; The current default listeners for the network change event include chan_sip
|
||||
; and chan_iax. Both of these channel drivers by default react to this event
|
||||
; by renewing all outbound registrations. This allows the endpoints Asterisk
|
||||
; is registering with to become aware of the address change and know the new
|
||||
; location.
|
||||
;
|
||||
[general]
|
||||
;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,57 @@
|
|||
; rfc3842
|
||||
; put empty "Content=>" at the end to have CRLF after last body line
|
||||
|
||||
[clear-mwi]
|
||||
Event=>message-summary
|
||||
Content-type=>application/simple-message-summary
|
||||
Content=>Messages-Waiting: no
|
||||
Content=>Message-Account: sip:asterisk@127.0.0.1
|
||||
Content=>Voice-Message: 0/0 (0/0)
|
||||
Content=>
|
||||
|
||||
; Aastra
|
||||
|
||||
[aastra-check-cfg]
|
||||
Event=>check-sync
|
||||
|
||||
[aastra-xml]
|
||||
Event=>aastra-xml
|
||||
|
||||
; Digium
|
||||
|
||||
[digium-check-cfg]
|
||||
Event=>check-sync
|
||||
|
||||
; Linksys
|
||||
|
||||
[linksys-cold-restart]
|
||||
Event=>reboot_now
|
||||
|
||||
[linksys-warm-restart]
|
||||
Event=>restart_now
|
||||
|
||||
; Polycom
|
||||
|
||||
[polycom-check-cfg]
|
||||
Event=>check-sync
|
||||
|
||||
; Sipura
|
||||
|
||||
[sipura-check-cfg]
|
||||
Event=>resync
|
||||
|
||||
[sipura-get-report]
|
||||
Event=>report
|
||||
|
||||
; snom
|
||||
|
||||
[snom-check-cfg]
|
||||
Event=>check-sync\;reboot=false
|
||||
|
||||
[snom-reboot]
|
||||
Event=>check-sync\;reboot=true
|
||||
|
||||
; Cisco
|
||||
|
||||
[cisco-check-cfg]
|
||||
Event=>check-sync
|
|
@ -0,0 +1,207 @@
|
|||
;
|
||||
; Skinny Configuration for Asterisk
|
||||
;
|
||||
[general]
|
||||
bindaddr=0.0.0.0 ; Address to bind to
|
||||
bindport=2000 ; Port to bind to, default tcp/2000
|
||||
dateformat=M-D-Y ; M,D,Y in any order (6 chars max)
|
||||
; "A" may also be used, but it must be at the end.
|
||||
; Use M for month, D for day, Y for year, A for 12-hour time.
|
||||
keepalive=120
|
||||
|
||||
;authtimeout = 30 ; authtimeout specifies the maximum number of seconds a
|
||||
; client has to authenticate. If the client does not
|
||||
; authenticate beofre this timeout expires, the client
|
||||
; will be disconnected. (default: 30 seconds)
|
||||
|
||||
;authlimit = 50 ; authlimit specifies the maximum number of
|
||||
; unauthenticated sessions that will be allowed to
|
||||
; connect at any given time. (default: 50)
|
||||
|
||||
;vmexten=8500 ; Systemwide voicemailmain pilot number
|
||||
; It must be in the same context as the calling
|
||||
; device/line
|
||||
|
||||
; If regcontext is specified, Asterisk will dynamically create and destroy a
|
||||
; NoOp priority 1 extension for a given line which registers or unregisters with
|
||||
; us and have a "regexten=" configuration item.
|
||||
; Multiple contexts may be specified by separating them with '&'. The
|
||||
; actual extension is the 'regexten' parameter of the registering line or its
|
||||
; name if 'regexten' is not provided. If more than one context is provided,
|
||||
; the context must be specified within regexten by appending the desired
|
||||
; context after '@'. More than one regexten may be supplied if they are
|
||||
; separated by '&'. Patterns may be used in regexten.
|
||||
;
|
||||
;regcontext=skinnyregistrations
|
||||
|
||||
;allow=all ; see https://wiki.asterisk.org/wiki/display/AST/RTP+Packetization
|
||||
; for framing options
|
||||
;disallow=
|
||||
|
||||
; The imeddialkey option allows for a key to be used to immediately dial the already
|
||||
; entered number. This is useful where the dialplan includes variable length pattern
|
||||
; matching. Valid options are '#' and '*'. On devices with soft buttons, a button will
|
||||
; be available to immediately dial when a pattern than can be dialed has been entered.
|
||||
; Default is unset, that is no immediated dial key (softbutton still exists).
|
||||
;
|
||||
;immeddialkey=#
|
||||
|
||||
; See https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service for a description of these parameters.
|
||||
;tos=cs3 ; Sets TOS for signaling packets.
|
||||
;tos_audio=ef ; Sets TOS for RTP audio packets.
|
||||
;tos_video=af41 ; Sets TOS for RTP video packets.
|
||||
;cos=3 ; Sets 802.1p priority for signaling packets.
|
||||
;cos_audio=5 ; Sets 802.1p priority for RTP audio packets.
|
||||
;cos_video=4 ; Sets 802.1p priority for RTP video packets.
|
||||
|
||||
; ----------------------------- JITTER BUFFER CONFIGURATION --------------------------
|
||||
;jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of a
|
||||
; skinny channel. Defaults to "no". An enabled jitterbuffer will
|
||||
; be used only if the sending side can create and the receiving
|
||||
; side can not accept jitter. The skinny channel can accept
|
||||
; jitter, thus a jitterbuffer on the receive skinny side will be
|
||||
; used only if it is forced and enabled.
|
||||
|
||||
;jbforce = no ; Forces the use of a jitterbuffer on the receive side of a skinny
|
||||
; channel. Defaults to "no".
|
||||
|
||||
;jbmaxsize = 200 ; Max length of the jitterbuffer in milliseconds.
|
||||
|
||||
;jbresyncthreshold = 1000 ; Jump in the frame timestamps over which the jitterbuffer is
|
||||
; resynchronized. Useful to improve the quality of the voice, with
|
||||
; big jumps in/broken timestamps, usually sent from exotic devices
|
||||
; and programs. Defaults to 1000.
|
||||
|
||||
;jbimpl = fixed ; Jitterbuffer implementation, used on the receiving side of a
|
||||
; skinny channel. Two implementations are currently available
|
||||
; - "fixed" (with size always equals to jbmaxsize)
|
||||
; - "adaptive" (with variable size, actually the new jb of IAX2).
|
||||
; Defaults to fixed.
|
||||
|
||||
;jblog = no ; Enables jitterbuffer frame logging. Defaults to "no".
|
||||
; ----------------------------------------------------------------------------------
|
||||
|
||||
[lines]
|
||||
; ---------------------------------- LINES SECTION --------------------------------
|
||||
; Options set under [lines] apply to all lines unless explicitly set for a particular
|
||||
; device. The options that can be set under lines are specified in GENERAL LINE OPTIONS.
|
||||
; These options can also be set for each individual device as well as those under SPECIFIC
|
||||
; LINE OPTIONS.
|
||||
;
|
||||
; Each label below [lines] in [] is a new line with the specific options specified below
|
||||
; it. Config stops reading new lines when one of the following is found: [general], [devices]
|
||||
; or the end of skinny.conf.
|
||||
;
|
||||
; Where options are common to both lines and devices, the results typically take that of
|
||||
; the least permission. ie if a no is set for either line or device, the call will not be
|
||||
; able to use that permission
|
||||
; ------------------------------- GENERAL LINE OPTIONS -----------------------------
|
||||
;earlyrtp=1 ; whether audio signalling should be provided by asterisk
|
||||
; ; (earlyrtp=1) or device generated (earlyrtp=0). default=yes
|
||||
;transfer=1 ; whether the device is allowed to transfer. default=yes
|
||||
;context=default ; context to use for this line.
|
||||
;callfwdtimeout=20000 ; ms before cfwd_noans occurs (default 20 secs)
|
||||
; ------------------------------ SPECIFIC LINE OPTIONS -----------------------------
|
||||
;setvar= ; allows for the setting of chanvars.
|
||||
; ----------------------------------------------------------------------------------
|
||||
|
||||
;[100]
|
||||
;nat=yes
|
||||
;callerid="Customer Support" <810-234-1212>
|
||||
; Note: app_voicemail mailboxes must be in the form of mailbox@context.
|
||||
;mailbox=100
|
||||
;vmexten=8500 ; Device level voicemailmain pilot number
|
||||
;regexten=100
|
||||
;context=inbound
|
||||
;linelabel="Support Line" ; Displays next to the line
|
||||
; button on 7940's and 7960s
|
||||
;[110]
|
||||
;callerid="John Chambers" <408-526-4000>
|
||||
;context=did
|
||||
;regexten=110
|
||||
;linelabel="John"
|
||||
;mailbox=110
|
||||
|
||||
;[120]
|
||||
;Nothing set, so all the defaults are used
|
||||
|
||||
;[500]
|
||||
;nat=yes
|
||||
;callerid="George W. Bush" <202-456-1414>
|
||||
;setvar=CUSTID=5678 ; Channel variable to be set for all calls from this device
|
||||
;setvar=ATTENDED_TRANSFER_COMPLETE_SOUND=beep ; This channel variable will
|
||||
; cause the given audio file to
|
||||
; be played upon completion of
|
||||
; an attended transfer to the
|
||||
; target of the transfer.
|
||||
;mailbox=500
|
||||
;callwaiting=yes
|
||||
;transfer=yes
|
||||
;threewaycalling=yes
|
||||
;context=default
|
||||
;mohinterpret=default ; This option specifies a default music on hold class to
|
||||
; use when put on hold if the channel's moh class was not
|
||||
; explicitly set with Set(CHANNEL(musicclass)=whatever) and
|
||||
; the peer channel did not suggest a class to use.
|
||||
;mohsuggest=default ; This option specifies which music on hold class to suggest to the peer channel
|
||||
; when this channel places the peer on hold. It may be specified globally or on
|
||||
; a per-user or per-peer basis.
|
||||
|
||||
|
||||
[devices]
|
||||
; --------------------------------- DEVICES SECTION -------------------------------
|
||||
; Options set under [devices] apply to all devices unless explicitly set for a particular
|
||||
; device. The options that can be set under devices are specified in GENERAL DEVICE OPTIONS.
|
||||
; These options can also be set for each individual device as well as those under SPECIFIC
|
||||
; DEVICE OPTIONS.
|
||||
;
|
||||
; Each label below [devices] in [] is a new device with the specific options specified below
|
||||
; it. Config stop reading new devices when one of the following is found: [general], [lines]
|
||||
; or the end of skinny.conf.
|
||||
;
|
||||
; Where options are common to both lines and devices, the results typically take that of
|
||||
; the least permission. ie if a no is set for either line or device, the call will not be
|
||||
; able to use that permission
|
||||
; ------------------------------ GENERAL DEVICE OPTIONS ----------------------------
|
||||
;earlyrtp=1 ; whether audio signalling should be provided by asterisk
|
||||
; ; (earlyrtp=1) or device generated (earlyrtp=0). default=yes
|
||||
;transfer=1 ; whether the device is allowed to transfer. default=yes
|
||||
; ----------------------------- SPECIFIC DEVICE OPTIONS ----------------------------
|
||||
;device="SEPxxxxxxxxxxxx ; id of the device. Must be set.
|
||||
;version=P002G204 ; firmware version to be loaded. If this version is different
|
||||
; ; to the one on the device, the device will try to load this
|
||||
; ; version from the tftp server. Set to device firmware version.
|
||||
; ----------------------------------------------------------------------------------
|
||||
|
||||
; Typical config for 12SP+
|
||||
;[florian]
|
||||
;device=SEP00D0BA847E6B
|
||||
;version=P002G204 ; Thanks critch
|
||||
;context=did
|
||||
;directmedia=yes ; Allow media to go directly between two RTP endpoints.
|
||||
;line=120 ; Dial(Skinny/120@florian)
|
||||
|
||||
; Service URLs attached to line buttons (eg phone directory)
|
||||
; See http://www.voip-info.org/wiki/view/Asterisk+Cisco+79XX+XML+Services
|
||||
; for intro to xml structure.
|
||||
;serviceurl=Directory,http://host/file.xml
|
||||
|
||||
|
||||
; Typical config for a 7910
|
||||
;[duba] ; Device name
|
||||
;device=SEP0007EB463101 ; Official identifier
|
||||
;version=P002F202 ; Firmware version identifier
|
||||
;host=192.168.1.144
|
||||
;permit=192.168.0/24 ; Optional, used for authentication
|
||||
;line=500
|
||||
|
||||
|
||||
; Typical config for a 7940 with dual 7914s
|
||||
;[support]
|
||||
;device=SEP0007EB463121
|
||||
;line=100
|
||||
;line=110
|
||||
;speeddial => 111,Jack Smith ; Adds a speeddial button to a device.
|
||||
;speeddial => 112@hints,Bob Peterson ; When a context is specified, the speeddial watches a dialplan hint.
|
||||
;addon => 7914
|
||||
;addon => 7914
|
|
@ -63,6 +63,8 @@
|
|||
; decline=ast_channel_hangup_handler_type
|
||||
; decline=ast_channel_moh_start_type
|
||||
; decline=ast_channel_moh_stop_type
|
||||
; decline=ast_channel_monitor_start_type
|
||||
; decline=ast_channel_monitor_stop_type
|
||||
; decline=ast_channel_mixmonitor_start_type
|
||||
; decline=ast_channel_mixmonitor_stop_type
|
||||
; decline=ast_channel_agent_login_type
|
||||
|
|
|
@ -1,20 +1,15 @@
|
|||
;
|
||||
; User configuration
|
||||
;
|
||||
; WARNING: This configuration file is deprecated and will be removed in
|
||||
; a future version of Asterisk. It is recommended that you make configurations
|
||||
; in the appropriate module-specific configuration file for more flexibility.
|
||||
; Many Asterisk modules already no longer support users.conf.
|
||||
;
|
||||
; Creating entries in users.conf is a "shorthand" for creating individual
|
||||
; entries in each configuration file. Using users.conf is not intended to
|
||||
; provide you with as much flexibility as using the separate configuration
|
||||
; files (e.g. iax.conf, etc) but is intended to accelerate the
|
||||
; files (e.g. sip.conf, iax.conf, etc) but is intended to accelerate the
|
||||
; simple task of adding users. Note that creating individual items (e.g.
|
||||
; IAX friends, etc.) will allow you to override specific parameters within
|
||||
; this file. Parameter names here are the same as they appear in the
|
||||
; other configuration files. There is no way to change the value of a
|
||||
; parameter here for just one subsystem.
|
||||
; custom SIP peers, IAX friends, etc.) will allow you to override specific
|
||||
; parameters within this file. Parameter names here are the same as they
|
||||
; appear in the other configuration files. There is no way to change the
|
||||
; value of a parameter here for just one subsystem.
|
||||
;
|
||||
|
||||
[general]
|
||||
|
@ -27,7 +22,7 @@ fullname = New User
|
|||
;
|
||||
userbase = 6000
|
||||
;
|
||||
; Create voicemail mailbox
|
||||
; Create voicemail mailbox and use use macro-stdexten
|
||||
;
|
||||
hasvoicemail = yes
|
||||
;
|
||||
|
@ -35,6 +30,10 @@ hasvoicemail = yes
|
|||
;
|
||||
vmsecret = 1234
|
||||
;
|
||||
; Create SIP Peer
|
||||
;
|
||||
hassip = yes
|
||||
;
|
||||
; Create IAX friend
|
||||
;
|
||||
hasiax = yes
|
||||
|
@ -95,6 +94,7 @@ pickupgroup = 1
|
|||
;dahdichan = 1
|
||||
;hasvoicemail = yes
|
||||
;vmsecret = 1234
|
||||
;hassip = yes
|
||||
;hasiax = no
|
||||
;hash323 = no
|
||||
;hasmanager = no
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.71 for asterisk master.
|
||||
# Generated by GNU Autoconf 2.71 for asterisk 20.
|
||||
#
|
||||
# Report bugs to <https://github.com/asterisk/asterisk/issues>.
|
||||
#
|
||||
|
@ -613,8 +613,8 @@ MAKEFLAGS=
|
|||
# Identity of this package.
|
||||
PACKAGE_NAME='asterisk'
|
||||
PACKAGE_TARNAME='asterisk'
|
||||
PACKAGE_VERSION='master'
|
||||
PACKAGE_STRING='asterisk master'
|
||||
PACKAGE_VERSION='20'
|
||||
PACKAGE_STRING='asterisk 20'
|
||||
PACKAGE_BUGREPORT='https://github.com/asterisk/asterisk/issues'
|
||||
PACKAGE_URL=''
|
||||
|
||||
|
@ -677,6 +677,8 @@ GTK2_LIBS
|
|||
GTK2_CFLAGS
|
||||
PBX_LAUNCHD
|
||||
CONFIG_SDL
|
||||
PBX_SO_NOSIGPIPE
|
||||
PBX_MSG_NOSIGNAL
|
||||
GMIME_LIBS
|
||||
GMIME_CFLAGS
|
||||
PORTAUDIO_LIBS
|
||||
|
@ -1025,6 +1027,10 @@ PBX_PGSQL
|
|||
PGSQL_DIR
|
||||
PGSQL_INCLUDE
|
||||
PGSQL_LIB
|
||||
PBX_OSPTK
|
||||
OSPTK_DIR
|
||||
OSPTK_INCLUDE
|
||||
OSPTK_LIB
|
||||
PBX_OPUSFILE
|
||||
OPUSFILE_DIR
|
||||
OPUSFILE_INCLUDE
|
||||
|
@ -1192,6 +1198,10 @@ PBX_BFD
|
|||
BFD_DIR
|
||||
BFD_INCLUDE
|
||||
BFD_LIB
|
||||
PBX_ALSA
|
||||
ALSA_DIR
|
||||
ALSA_INCLUDE
|
||||
ALSA_LIB
|
||||
LIBJWT_INCLUDE
|
||||
LIBJWT_LIB
|
||||
PBX_LIBJWT
|
||||
|
@ -1400,6 +1410,7 @@ with_pjproject_bundled
|
|||
with_libjwt_bundled
|
||||
with_crypto
|
||||
with_ssl
|
||||
with_asound
|
||||
with_bfd
|
||||
with_execinfo
|
||||
with_bluetooth
|
||||
|
@ -1440,6 +1451,7 @@ with_ogg
|
|||
with_openr2
|
||||
with_opus
|
||||
with_opusfile
|
||||
with_osptk
|
||||
with_postgres
|
||||
with_beanstalk
|
||||
with_pjproject
|
||||
|
@ -2067,7 +2079,7 @@ if test "$ac_init_help" = "long"; then
|
|||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures asterisk master to adapt to many kinds of systems.
|
||||
\`configure' configures asterisk 20 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
|
@ -2133,7 +2145,7 @@ fi
|
|||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of asterisk master:";;
|
||||
short | recursive ) echo "Configuration of asterisk 20:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
|
@ -2171,6 +2183,7 @@ Optional Packages:
|
|||
--with-libjwt-bundled Use bundled libjwt library
|
||||
--with-crypto=PATH use OpenSSL Cryptography files in PATH
|
||||
--with-ssl=PATH use OpenSSL Secure Sockets Layer files in PATH
|
||||
--with-asound=PATH use Advanced Linux Sound Architecture files in PATH
|
||||
--with-bfd=PATH use Debug symbol decoding files in PATH
|
||||
--with-execinfo=PATH use Stack Backtrace files in PATH
|
||||
--with-bluetooth=PATH use Bluetooth files in PATH
|
||||
|
@ -2214,6 +2227,7 @@ Optional Packages:
|
|||
--with-openr2=PATH use MFR2 files in PATH
|
||||
--with-opus=PATH use Opus files in PATH
|
||||
--with-opusfile=PATH use Opusfile files in PATH
|
||||
--with-osptk=PATH use OSP Toolkit files in PATH
|
||||
--with-postgres=PATH use PostgreSQL files in PATH
|
||||
--with-beanstalk=PATH use Beanstalk Job Queue files in PATH
|
||||
--with-pjproject=PATH use PJPROJECT files in PATH
|
||||
|
@ -2381,7 +2395,7 @@ fi
|
|||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
asterisk configure master
|
||||
asterisk configure 20
|
||||
generated by GNU Autoconf 2.71
|
||||
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
|
@ -3117,7 +3131,7 @@ cat >config.log <<_ACEOF
|
|||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by asterisk $as_me master, which was
|
||||
It was created by asterisk $as_me 20, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
$ $0$ac_configure_args_raw
|
||||
|
@ -11351,6 +11365,39 @@ printf "%s\n" "#define HAVE_LIBJWT_BUNDLED 1" >>confdefs.h
|
|||
# to make things easier for the users.
|
||||
|
||||
|
||||
ALSA_DESCRIP="Advanced Linux Sound Architecture"
|
||||
ALSA_OPTION="asound"
|
||||
PBX_ALSA=0
|
||||
|
||||
# Check whether --with-asound was given.
|
||||
if test ${with_asound+y}
|
||||
then :
|
||||
withval=$with_asound;
|
||||
case ${withval} in
|
||||
n|no)
|
||||
USE_ALSA=no
|
||||
# -1 is a magic value used by menuselect to know that the package
|
||||
# was disabled, other than 'not found'
|
||||
PBX_ALSA=-1
|
||||
;;
|
||||
y|ye|yes)
|
||||
ac_mandatory_list="${ac_mandatory_list} ALSA"
|
||||
;;
|
||||
*)
|
||||
ALSA_DIR="${withval}"
|
||||
ac_mandatory_list="${ac_mandatory_list} ALSA"
|
||||
;;
|
||||
esac
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BFD_DESCRIP="Debug symbol decoding"
|
||||
BFD_OPTION="bfd"
|
||||
PBX_BFD=0
|
||||
|
@ -13086,6 +13133,39 @@ fi
|
|||
|
||||
|
||||
|
||||
OSPTK_DESCRIP="OSP Toolkit"
|
||||
OSPTK_OPTION="osptk"
|
||||
PBX_OSPTK=0
|
||||
|
||||
# Check whether --with-osptk was given.
|
||||
if test ${with_osptk+y}
|
||||
then :
|
||||
withval=$with_osptk;
|
||||
case ${withval} in
|
||||
n|no)
|
||||
USE_OSPTK=no
|
||||
# -1 is a magic value used by menuselect to know that the package
|
||||
# was disabled, other than 'not found'
|
||||
PBX_OSPTK=-1
|
||||
;;
|
||||
y|ye|yes)
|
||||
ac_mandatory_list="${ac_mandatory_list} OSPTK"
|
||||
;;
|
||||
*)
|
||||
OSPTK_DIR="${withval}"
|
||||
ac_mandatory_list="${ac_mandatory_list} OSPTK"
|
||||
;;
|
||||
esac
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
PGSQL_DESCRIP="PostgreSQL"
|
||||
PGSQL_OPTION="postgres"
|
||||
PBX_PGSQL=0
|
||||
|
@ -22225,6 +22305,103 @@ fi
|
|||
# do the package library checks now
|
||||
|
||||
|
||||
if test "x${PBX_ALSA}" != "x1" -a "${USE_ALSA}" != "no"; then
|
||||
pbxlibdir=""
|
||||
# if --with-ALSA=DIR has been specified, use it.
|
||||
if test "x${ALSA_DIR}" != "x"; then
|
||||
if test -d ${ALSA_DIR}/lib; then
|
||||
pbxlibdir="-L${ALSA_DIR}/lib"
|
||||
else
|
||||
pbxlibdir="-L${ALSA_DIR}"
|
||||
fi
|
||||
fi
|
||||
|
||||
ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
|
||||
CFLAGS="${CFLAGS} "
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for snd_pcm_open in -lasound" >&5
|
||||
printf %s "checking for snd_pcm_open in -lasound... " >&6; }
|
||||
if test ${ac_cv_lib_asound_snd_pcm_open+y}
|
||||
then :
|
||||
printf %s "(cached) " >&6
|
||||
else $as_nop
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lasound ${pbxlibdir} $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
char snd_pcm_open ();
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
return snd_pcm_open ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"
|
||||
then :
|
||||
ac_cv_lib_asound_snd_pcm_open=yes
|
||||
else $as_nop
|
||||
ac_cv_lib_asound_snd_pcm_open=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_snd_pcm_open" >&5
|
||||
printf "%s\n" "$ac_cv_lib_asound_snd_pcm_open" >&6; }
|
||||
if test "x$ac_cv_lib_asound_snd_pcm_open" = xyes
|
||||
then :
|
||||
AST_ALSA_FOUND=yes
|
||||
else $as_nop
|
||||
AST_ALSA_FOUND=no
|
||||
fi
|
||||
|
||||
CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
|
||||
|
||||
|
||||
# now check for the header.
|
||||
if test "${AST_ALSA_FOUND}" = "yes"; then
|
||||
ALSA_LIB="${pbxlibdir} -lasound "
|
||||
# if --with-ALSA=DIR has been specified, use it.
|
||||
if test "x${ALSA_DIR}" != "x"; then
|
||||
ALSA_INCLUDE="-I${ALSA_DIR}/include"
|
||||
fi
|
||||
ALSA_INCLUDE="${ALSA_INCLUDE} "
|
||||
|
||||
# check for the header
|
||||
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
|
||||
CPPFLAGS="${CPPFLAGS} ${ALSA_INCLUDE}"
|
||||
ac_fn_c_check_header_compile "$LINENO" "alsa/asoundlib.h" "ac_cv_header_alsa_asoundlib_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_alsa_asoundlib_h" = xyes
|
||||
then :
|
||||
ALSA_HEADER_FOUND=1
|
||||
else $as_nop
|
||||
ALSA_HEADER_FOUND=0
|
||||
fi
|
||||
|
||||
CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
|
||||
|
||||
if test "x${ALSA_HEADER_FOUND}" = "x0" ; then
|
||||
ALSA_LIB=""
|
||||
ALSA_INCLUDE=""
|
||||
else
|
||||
|
||||
PBX_ALSA=1
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_ALSA 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
if test "x${PBX_BFD}" != "x1" -a "${USE_BFD}" != "no"; then
|
||||
pbxlibdir=""
|
||||
# if --with-BFD=DIR has been specified, use it.
|
||||
|
@ -33191,6 +33368,137 @@ printf "%s\n" "#define HAVE_CRYPT_R 1" >>confdefs.h
|
|||
fi
|
||||
|
||||
|
||||
if test "$PBX_OPENSSL" = "1";
|
||||
then
|
||||
|
||||
# if OSPTK has not been checked and is not excluded
|
||||
if test "x${PBX_OSPTK}" != "x1" -a "${USE_OSPTK}" != "no"; then
|
||||
# if --with-osptk=DIR has been specified, use it.
|
||||
if test "x${OSPTK_DIR}" != "x"; then
|
||||
osptk_cflags="-I${OSPTK_DIR}/include"
|
||||
osptk_ldflags="-L${OSPTK_DIR}/lib"
|
||||
else
|
||||
osptk_cflags=""
|
||||
osptk_ldflags=""
|
||||
fi
|
||||
|
||||
# check for the header
|
||||
osptk_saved_cppflags="${CPPFLAGS}"
|
||||
CPPFLAGS="${CPPFLAGS} ${osptk_cflags}"
|
||||
ac_fn_c_check_header_compile "$LINENO" "osp/osp.h" "ac_cv_header_osp_osp_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_osp_osp_h" = xyes
|
||||
then :
|
||||
osptk_header_found=yes
|
||||
else $as_nop
|
||||
osptk_header_found=no
|
||||
fi
|
||||
|
||||
CPPFLAGS="${osptk_saved_cppflags}"
|
||||
|
||||
# check for the library
|
||||
if test "${osptk_header_found}" = "yes"; then
|
||||
osptk_extralibs="-lssl -lcrypto"
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for OSPPInit in -losptk" >&5
|
||||
printf %s "checking for OSPPInit in -losptk... " >&6; }
|
||||
if test ${ac_cv_lib_osptk_OSPPInit+y}
|
||||
then :
|
||||
printf %s "(cached) " >&6
|
||||
else $as_nop
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-losptk ${osptk_ldflags} ${osptk_extralibs} $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
char OSPPInit ();
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
return OSPPInit ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"
|
||||
then :
|
||||
ac_cv_lib_osptk_OSPPInit=yes
|
||||
else $as_nop
|
||||
ac_cv_lib_osptk_OSPPInit=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_osptk_OSPPInit" >&5
|
||||
printf "%s\n" "$ac_cv_lib_osptk_OSPPInit" >&6; }
|
||||
if test "x$ac_cv_lib_osptk_OSPPInit" = xyes
|
||||
then :
|
||||
osptk_library_found=yes
|
||||
else $as_nop
|
||||
osptk_library_found=no
|
||||
fi
|
||||
|
||||
|
||||
# check OSP Toolkit version
|
||||
if test "${osptk_library_found}" = "yes"; then
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if OSP Toolkit version is compatible with app_osplookup" >&5
|
||||
printf %s "checking if OSP Toolkit version is compatible with app_osplookup... " >&6; }
|
||||
|
||||
osptk_saved_cppflags="${CPPFLAGS}"
|
||||
CPPFLAGS="${CPPFLAGS} ${osptk_cflags}"
|
||||
if test "$cross_compiling" = yes
|
||||
then :
|
||||
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
|
||||
printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
|
||||
as_fn_error $? "cannot run test program while cross compiling
|
||||
See \`config.log' for more details" "$LINENO" 5; }
|
||||
else $as_nop
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
#include <osp/osp.h>
|
||||
int main(void) {
|
||||
int ver = OSP_CLIENT_TOOLKIT_VERSION_MAJOR * 10000 + OSP_CLIENT_TOOLKIT_VERSION_MINOR * 100 + OSP_CLIENT_TOOLKIT_VERSION_BUGFIX;
|
||||
int req = 4 * 10000 + 0 * 100 + 0;
|
||||
return (ver < req) ? 1 : 0;
|
||||
}
|
||||
|
||||
_ACEOF
|
||||
if ac_fn_c_try_run "$LINENO"
|
||||
then :
|
||||
osptk_compatible=yes
|
||||
else $as_nop
|
||||
osptk_compatible=no
|
||||
|
||||
fi
|
||||
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
|
||||
conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
fi
|
||||
|
||||
CPPFLAGS="${osptk_saved_cppflags}"
|
||||
|
||||
if test "${osptk_compatible}" = "yes"; then
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
printf "%s\n" "yes" >&6; }
|
||||
PBX_OSPTK=1
|
||||
OSPTK_INCLUDE="${osptk_cflags}"
|
||||
OSPTK_LIB="${osptk_ldflags} -losptk ${osptk_extralibs}"
|
||||
|
||||
printf "%s\n" "#define HAVE_OSPTK 1" >>confdefs.h
|
||||
|
||||
else
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
printf "%s\n" "no" >&6; }
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
|
||||
if test "x${PBX_SRTP}" != "x1" -a "${USE_SRTP}" != "no"; then
|
||||
pbxlibdir=""
|
||||
|
@ -35157,6 +35465,101 @@ printf "%s\n" "#define HAVE_LINUX_COMPILER_H 1" >>confdefs.h
|
|||
fi
|
||||
|
||||
|
||||
# Used in res/res_pktccops
|
||||
|
||||
if test "x${PBX_MSG_NOSIGNAL}" != "x1"; then
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MSG_NOSIGNAL in sys/socket.h" >&5
|
||||
printf %s "checking for MSG_NOSIGNAL in sys/socket.h... " >&6; }
|
||||
saved_cppflags="${CPPFLAGS}"
|
||||
if test "x${MSG_NOSIGNAL_DIR}" != "x"; then
|
||||
MSG_NOSIGNAL_INCLUDE="-I${MSG_NOSIGNAL_DIR}/include"
|
||||
fi
|
||||
CPPFLAGS="${CPPFLAGS} ${MSG_NOSIGNAL_INCLUDE}"
|
||||
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <sys/socket.h>
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
#if defined(MSG_NOSIGNAL)
|
||||
int foo = 0;
|
||||
#else
|
||||
int foo = bar;
|
||||
#endif
|
||||
0
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"
|
||||
then :
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
printf "%s\n" "yes" >&6; }
|
||||
PBX_MSG_NOSIGNAL=1
|
||||
|
||||
printf "%s\n" "#define HAVE_MSG_NOSIGNAL 1" >>confdefs.h
|
||||
|
||||
|
||||
|
||||
else $as_nop
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
printf "%s\n" "no" >&6; }
|
||||
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
CPPFLAGS="${saved_cppflags}"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if test "x${PBX_SO_NOSIGPIPE}" != "x1"; then
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SO_NOSIGPIPE in sys/socket.h" >&5
|
||||
printf %s "checking for SO_NOSIGPIPE in sys/socket.h... " >&6; }
|
||||
saved_cppflags="${CPPFLAGS}"
|
||||
if test "x${SO_NOSIGPIPE_DIR}" != "x"; then
|
||||
SO_NOSIGPIPE_INCLUDE="-I${SO_NOSIGPIPE_DIR}/include"
|
||||
fi
|
||||
CPPFLAGS="${CPPFLAGS} ${SO_NOSIGPIPE_INCLUDE}"
|
||||
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <sys/socket.h>
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
#if defined(SO_NOSIGPIPE)
|
||||
int foo = 0;
|
||||
#else
|
||||
int foo = bar;
|
||||
#endif
|
||||
0
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"
|
||||
then :
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
printf "%s\n" "yes" >&6; }
|
||||
PBX_SO_NOSIGPIPE=1
|
||||
|
||||
printf "%s\n" "#define HAVE_SO_NOSIGPIPE 1" >>confdefs.h
|
||||
|
||||
|
||||
|
||||
else $as_nop
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
printf "%s\n" "no" >&6; }
|
||||
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
CPPFLAGS="${saved_cppflags}"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
if test "x${PBX_SDL}" != "x1" -a "${USE_SDL}" != "no"; then
|
||||
|
@ -37020,7 +37423,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
|||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by asterisk $as_me master, which was
|
||||
This file was extended by asterisk $as_me 20, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
|
@ -37084,7 +37487,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
|
|||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config='$ac_cs_config_escaped'
|
||||
ac_cs_version="\\
|
||||
asterisk config.status master
|
||||
asterisk config.status 20
|
||||
configured by $0, generated by GNU Autoconf 2.71,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
|
14
configure.ac
14
configure.ac
|
@ -1,6 +1,6 @@
|
|||
AC_PREREQ(2.60a)
|
||||
|
||||
AC_INIT([asterisk], [master], [https://github.com/asterisk/asterisk/issues])
|
||||
AC_INIT([asterisk], [20], [https://github.com/asterisk/asterisk/issues])
|
||||
|
||||
# cross-compile macros
|
||||
AC_CANONICAL_BUILD
|
||||
|
@ -530,6 +530,7 @@ THIRD_PARTY_CONFIGURE()
|
|||
# by the --with option name (the third field),
|
||||
# to make things easier for the users.
|
||||
|
||||
AST_EXT_LIB_SETUP([ALSA], [Advanced Linux Sound Architecture], [asound])
|
||||
AST_EXT_LIB_SETUP([BFD], [Debug symbol decoding], [bfd])
|
||||
|
||||
# BKTR is used for backtrace support on platforms that do not
|
||||
|
@ -577,6 +578,7 @@ AST_EXT_LIB_SETUP([OGG], [OGG], [ogg])
|
|||
AST_EXT_LIB_SETUP([OPENR2], [MFR2], [openr2])
|
||||
AST_EXT_LIB_SETUP([OPUS], [Opus], [opus])
|
||||
AST_EXT_LIB_SETUP([OPUSFILE], [Opusfile], [opusfile])
|
||||
AST_EXT_LIB_SETUP([OSPTK], [OSP Toolkit], [osptk])
|
||||
AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres])
|
||||
AST_EXT_LIB_SETUP([BEANSTALK], [Beanstalk Job Queue], [beanstalk])
|
||||
|
||||
|
@ -1630,6 +1632,8 @@ fi
|
|||
|
||||
# do the package library checks now
|
||||
|
||||
AST_EXT_LIB_CHECK([ALSA], [asound], [snd_pcm_open], [alsa/asoundlib.h])
|
||||
|
||||
AST_EXT_LIB_CHECK([BFD], [bfd], [bfd_openr], [bfd.h])
|
||||
# Fedora/RedHat/CentOS require extra libraries
|
||||
AST_EXT_LIB_CHECK([BFD], [bfd], [bfd_openr], [bfd.h], [-ldl -liberty])
|
||||
|
@ -2704,6 +2708,11 @@ AC_SUBST(CRYPT_INCLUDE)
|
|||
AC_CHECK_LIB([crypt], [crypt_r],
|
||||
[AC_DEFINE([HAVE_CRYPT_R], [1], [Define to 1 if you have the 'crypt_r' function.])])
|
||||
|
||||
if test "$PBX_OPENSSL" = "1";
|
||||
then
|
||||
AST_CHECK_OSPTK([4], [0], [0])
|
||||
fi
|
||||
|
||||
AST_EXT_LIB_CHECK([SRTP], [srtp2], [srtp_init], [srtp2/srtp.h], [], [], [2])
|
||||
AST_EXT_LIB_CHECK_SHARED([SRTP], [srtp2], [srtp_init], [srtp2/srtp.h], [], [], [], [
|
||||
AC_MSG_WARN([***])
|
||||
|
@ -2807,6 +2816,9 @@ fi
|
|||
AC_CHECK_HEADER([linux/compiler.h],
|
||||
[AC_DEFINE_UNQUOTED([HAVE_LINUX_COMPILER_H], 1, [Define to 1 if your system has linux/compiler.h.])])
|
||||
|
||||
# Used in res/res_pktccops
|
||||
AST_C_DEFINE_CHECK([MSG_NOSIGNAL], [MSG_NOSIGNAL], [sys/socket.h])
|
||||
AST_C_DEFINE_CHECK([SO_NOSIGPIPE], [SO_NOSIGPIPE], [sys/socket.h])
|
||||
|
||||
AST_EXT_TOOL_CHECK([SDL], [sdl-config])
|
||||
AST_EXT_LIB_CHECK([SDL_IMAGE], [SDL_image], [IMG_Load], [SDL_image.h], [${SDL_LIB}], [${SDL_INCLUDE}])
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
"""add user-agent-header to ps_registrations
|
||||
|
||||
Revision ID: 24c12d8e9014
|
||||
Revises: 37a5332640e2
|
||||
Create Date: 2024-01-05 14:14:47.510917
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '24c12d8e9014'
|
||||
down_revision = '37a5332640e2'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column('ps_registrations', sa.Column('user_agent', sa.String(255)))
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_column('ps_registrations', 'user_agent')
|
|
@ -0,0 +1,25 @@
|
|||
"""dummy migration
|
||||
|
||||
This migration exists to ensure that all currently supported branches
|
||||
have the same alembic revision head. This makes managing migrations
|
||||
across supported branches less painful.
|
||||
|
||||
The migration that is stubbed here is:
|
||||
|
||||
https://github.com/asterisk/asterisk/commit/775352ee6c2a5bcd4f0e3df51aee5d1b0abf4cbe
|
||||
|
||||
Revision ID: 24c12d8e9014
|
||||
Revises: 37a5332640e2
|
||||
Create Date: 2024-01-05 14:14:47.510917
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '24c12d8e9014'
|
||||
down_revision = '37a5332640e2'
|
||||
|
||||
def upgrade():
|
||||
pass
|
||||
|
||||
def downgrade():
|
||||
pass
|
|
@ -1,9 +1,7 @@
|
|||
"""Remove macrocontext field
|
||||
|
||||
"""Macrocontext NoOp for sync
|
||||
Revision ID: 1c55c341360f
|
||||
Revises: 39428242f7f5
|
||||
Create Date: 2024-01-09 15:01:39.698918
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
|
@ -15,8 +13,8 @@ import sqlalchemy as sa
|
|||
|
||||
|
||||
def upgrade():
|
||||
op.drop_column('voicemail_messages', 'macrocontext')
|
||||
pass
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.add_column('voicemail_messages', sa.Column('macrocontext', sa.String(80)))
|
||||
pass
|
|
@ -15,7 +15,7 @@ SYNOPSIS
|
|||
$prog [ --help ] | [ [ --reset ] | [
|
||||
[ --uniqueid="<uniqueid>" ]
|
||||
|
||||
[ --pjsip-debug=<on|off> ]
|
||||
[ --pjsip-debug=<on|off> ] [ --sip-debug=<on|off> ]
|
||||
[ --iax2-debug=<on|off> ]
|
||||
|
||||
[ --agi-debug=<on|off> ] [ --ami-debug=<on|off> ]
|
||||
|
@ -26,7 +26,7 @@ SYNOPSIS
|
|||
[ --dtmf-debug=<on|off> ] [ --fax-debug=<on|off> ]
|
||||
[ --security-debug=<on|off> ]
|
||||
|
||||
[ --pjsip-history=<on|off> ]
|
||||
[ --pjsip-history=<on|off> ] [ --sip-history=<on|off> ]
|
||||
|
||||
[ --verbose=<level> ] [ --debug=<level> ]
|
||||
] ]
|
||||
|
@ -51,7 +51,7 @@ DESCRIPTION
|
|||
on/off commands will use the same uniqueid. Use the --reset
|
||||
option to reset it (and everything else).
|
||||
|
||||
--pjsip-debug --iax2-debug --agi-debug --ami-debug
|
||||
--pjsip-debug --sip-debug --iax2-debug --agi-debug --ami-debug
|
||||
--ari-debug --cdr-debug --channel-debug --rtp-debug --rtcp-debug
|
||||
Issues the subsystem appropriate command to turn on
|
||||
or off debugging. These are usually functional debug messages
|
||||
|
@ -62,10 +62,10 @@ DESCRIPTION
|
|||
These subsystems set up their own log channels so if turned
|
||||
on, log files will be created in \$astlogdir for them.
|
||||
|
||||
--pjsip-history
|
||||
The pjsip channels have the ability to output an abbreviated,
|
||||
one-line, packet summary. If enabled, the summaries will be
|
||||
written to \$astlogdir/pjsip_history.\$UNIQUEID and
|
||||
--pjsip-history --sip-history
|
||||
The pjsip and sip channels have the ability to output an
|
||||
abbreviated, one-line, packet summary. If enabled, the summaries
|
||||
will be written to \$astlogdir/pjsip_history.\$UNIQUEID and
|
||||
\$astlogdir/sip_history.\$UNIQUEID.
|
||||
|
||||
--verbose-level --debug-level
|
||||
|
@ -114,6 +114,7 @@ RESET=false
|
|||
|
||||
declare -A DEBUG_COMMANDS=(
|
||||
[PJSIP,on]="pjsip set logger on" [PJSIP,off]="pjsip set logger off"
|
||||
[SIP,on]="sip set debug on" [SIP,off]="sip set debug off"
|
||||
[IAX2,on]="iax2 set debug on" [IAX2,off]="iax2 set debug off"
|
||||
[ARI,on]="ari set debug all on" [ARI,off]="ari set debug all off"
|
||||
[AMI,on]="manager set debug on" [AMI,off]="manager set debug off"
|
||||
|
@ -151,6 +152,8 @@ for a in "$@" ; do
|
|||
DEBUGS=true
|
||||
;;
|
||||
--pjsip-history=*)
|
||||
;&
|
||||
--sip-history=*)
|
||||
subsystem=${a%-history=*}
|
||||
subsystem=${subsystem#--}
|
||||
if [[ ${a#*=} =~ ^[Yy].* ]] ; then
|
||||
|
@ -221,6 +224,8 @@ if $RESET ; then
|
|||
asterisk -rx "core set debug 0"
|
||||
asterisk -rx "pjsip set logger off"
|
||||
asterisk -rx "pjsip set history off"
|
||||
asterisk -rx "sip set debug off"
|
||||
asterisk -rx "sip set history off"
|
||||
asterisk -rx "iax2 set debug off"
|
||||
asterisk -rx "manager set debug off"
|
||||
asterisk -rx "ari set debug all off"
|
||||
|
@ -254,6 +259,9 @@ if ! grep -q "; --START DEBUG_LOGGING-- ;" $CLI_CONF ; then
|
|||
[pjsip_debug](!)
|
||||
pjsip set logger on = yes
|
||||
|
||||
[sip_debug](!)
|
||||
sip set debug on = yes
|
||||
|
||||
[iax2_debug](!)
|
||||
iax2 set debug on = yes
|
||||
|
||||
|
@ -291,6 +299,10 @@ if ! grep -q "; --START DEBUG_LOGGING-- ;" $CLI_CONF ; then
|
|||
logger add channel $PJSIP_HISTORY_LOG PJSIP_HISTORY = yes
|
||||
pjsip set history on = yes
|
||||
|
||||
[sip_history](!)
|
||||
logger add channel $SIP_HISTORY_LOG SIP_HISTORY = yes
|
||||
sip set history on = yes
|
||||
|
||||
[verbose_level](!)
|
||||
core set verbose 3 = yes
|
||||
|
||||
|
@ -315,12 +327,13 @@ else
|
|||
VERBOSE_LOG=$(sed -n -r -e "s@logger add channel ($LOG_DIR/message\..+)\s+NOTICE.*@\1@p" "$CLI_CONF")
|
||||
DEBUG_LOG=$(sed -n -r -e "s@logger add channel ($LOG_DIR/debug\..+)\s+DEBUG.*@\1@p" "$CLI_CONF")
|
||||
PJSIP_HISTORY_LOG=$(sed -n -r -e "s@logger add channel ($LOG_DIR/pjsip_history\..+)\s+PJSIP.*@\1@p" "$CLI_CONF")
|
||||
SIP_HISTORY_LOG=$(sed -n -r -e "s@logger add channel ($LOG_DIR/sip_history\..+)\s+SIP.*@\1@p" "$CLI_CONF")
|
||||
DTMF_LOG=$(sed -n -r -e "s@logger add channel ($LOG_DIR/dtmf\..+)\s+DTMF.*@\1@p" "$CLI_CONF")
|
||||
FAX_LOG=$(sed -n -r -e "s@logger add channel ($LOG_DIR/fax\..+)\s+FAX.*@\1@p" "$CLI_CONF")
|
||||
SECURITY_LOG=$(sed -n -r -e "s@logger add channel ($LOG_DIR/security\..+)\s+SECURITY.*@\1@p" "$CLI_CONF")
|
||||
fi
|
||||
|
||||
for x in PJSIP ARI AMI AGI ARI IAX2 CDR RTP RTCP ; do
|
||||
for x in PJSIP SIP ARI AMI AGI ARI IAX2 CDR RTP RTCP ; do
|
||||
if eval \$${x}_DEBUG_SPECIFIED ; then
|
||||
if eval \$${x}_DEBUG ; then
|
||||
if $ASTERISK_IS_RUNNING ; then
|
||||
|
@ -354,7 +367,7 @@ for x in DTMF FAX SECURITY ; do
|
|||
fi
|
||||
done
|
||||
|
||||
for x in PJSIP ; do
|
||||
for x in PJSIP SIP ; do
|
||||
if eval \$${x}_HISTORY_SPECIFIED ; then
|
||||
if eval \$${x}_HISTORY ; then
|
||||
if $ASTERISK_IS_RUNNING ; then
|
||||
|
|
|
@ -192,6 +192,7 @@ if [ -e /var/run/asterisk.ctl ] || [ -e /var/run/asterisk/asterisk.ctl ]; then
|
|||
"core show uptime" "core show settings" "core show sysinfo" "core show channels" \
|
||||
"pri show spans" "dahdi show status" "dahdi show channels" "dahdi show channel 1" \
|
||||
"pjsip show endpoints" "pjsip show registrations" "pjsip list channels" \
|
||||
"sip show peers" "sip show registry" "sip show channels" "sip show subscriptions" "sip show settings" \
|
||||
"show g729" "g729 show version" "g729 show licenses" "g729 show hostid" \
|
||||
"digium_phones show version" "digium_phones show alerts" "digium_phones show applications" \
|
||||
"digium_phones show firmwares" "digium_phones show lines" "digium_phones show networks" \
|
||||
|
|
|
@ -25,7 +25,7 @@ PACKAGES_DEBIAN="$PACKAGES_DEBIAN libedit-dev libjansson-dev libsqlite3-dev uuid
|
|||
# Asterisk: for addons:
|
||||
PACKAGES_DEBIAN="$PACKAGES_DEBIAN libspeex-dev libspeexdsp-dev libogg-dev libvorbis-dev libasound2-dev portaudio19-dev libcurl4-openssl-dev xmlstarlet bison flex"
|
||||
PACKAGES_DEBIAN="$PACKAGES_DEBIAN libpq-dev unixodbc-dev libneon27-dev libgmime-2.6-dev libgmime-3.0-dev liblua5.2-dev liburiparser-dev libxslt1-dev libssl-dev"
|
||||
PACKAGES_DEBIAN="$PACKAGES_DEBIAN libmysqlclient-dev libbluetooth-dev libradcli-dev freetds-dev libjack-jackd2-dev bash libcap-dev"
|
||||
PACKAGES_DEBIAN="$PACKAGES_DEBIAN libmysqlclient-dev libbluetooth-dev libradcli-dev freetds-dev libosptk-dev libjack-jackd2-dev bash libcap-dev"
|
||||
PACKAGES_DEBIAN="$PACKAGES_DEBIAN libsnmp-dev libiksemel-dev libcorosync-common-dev libcpg-dev libcfg-dev libnewt-dev libpopt-dev libical-dev libspandsp-dev"
|
||||
PACKAGES_DEBIAN="$PACKAGES_DEBIAN libresample1-dev libc-client2007e-dev binutils-dev libsrtp0-dev libsrtp2-dev libgsm1-dev doxygen graphviz zlib1g-dev libldap2-dev"
|
||||
PACKAGES_DEBIAN="$PACKAGES_DEBIAN libcodec2-dev libfftw3-dev libsndfile1-dev libunbound-dev"
|
||||
|
@ -39,7 +39,7 @@ PACKAGES_RH="make gcc gcc-c++ pkgconfig"
|
|||
# Asterisk: basic requirements:
|
||||
PACKAGES_RH="$PACKAGES_RH libedit-devel jansson-devel libuuid-devel sqlite-devel libxml2-devel"
|
||||
# Asterisk: for addons:
|
||||
PACKAGES_RH="$PACKAGES_RH speex-devel speexdsp-devel libogg-devel libvorbis-devel portaudio-devel libcurl-devel xmlstarlet bison flex"
|
||||
PACKAGES_RH="$PACKAGES_RH speex-devel speexdsp-devel libogg-devel libvorbis-devel alsa-lib-devel portaudio-devel libcurl-devel xmlstarlet bison flex"
|
||||
PACKAGES_RH="$PACKAGES_RH postgresql-devel unixODBC-devel neon-devel gmime-devel lua-devel uriparser-devel libxslt-devel openssl-devel"
|
||||
PACKAGES_RH="$PACKAGES_RH mysql-devel bluez-libs-devel radcli-devel freetds-devel jack-audio-connection-kit-devel bash libcap-devel"
|
||||
PACKAGES_RH="$PACKAGES_RH net-snmp-devel iksemel-devel corosynclib-devel newt-devel popt-devel libical-devel spandsp-devel"
|
||||
|
@ -55,7 +55,7 @@ PACKAGES_SUSE="make gcc gcc-c++ pkg-config"
|
|||
# Asterisk: basic requirements:
|
||||
PACKAGES_SUSE="$PACKAGES_SUSE libedit-devel libjansson-devel libuuid-devel sqlite3-devel libxml2-devel"
|
||||
# Asterisk: for addons:
|
||||
PACKAGES_SUSE="$PACKAGES_SUSE speex-devel speexdsp-devel libogg-devel libvorbis-devel portaudio-devel libcurl-devel xmlstarlet bison flex"
|
||||
PACKAGES_SUSE="$PACKAGES_SUSE speex-devel speexdsp-devel libogg-devel libvorbis-devel alsa-devel portaudio-devel libcurl-devel xmlstarlet bison flex"
|
||||
PACKAGES_SUSE="$PACKAGES_SUSE postgresql-devel unixODBC-devel libneon-devel gmime-devel lua-devel liburiparser-devel libxslt-devel libopenssl-devel"
|
||||
PACKAGES_SUSE="$PACKAGES_SUSE libmysqlclient-devel bluez-devel freeradius-client-devel freetds-devel bash libcap-devel"
|
||||
PACKAGES_SUSE="$PACKAGES_SUSE net-snmp-devel iksemel-devel libcorosync-devel newt-devel popt-devel libical-devel spandsp-devel"
|
||||
|
@ -71,7 +71,7 @@ PACKAGES_ARCH="make gcc pkg-config"
|
|||
# Asterisk: basic requirements:
|
||||
PACKAGES_ARCH="$PACKAGES_ARCH libedit jansson libutil-linux libxml2 sqlite"
|
||||
# Asterisk: for addons:
|
||||
PACKAGES_ARCH="$PACKAGES_ARCH speex speexdsp libogg libvorbis portaudio curl xmlstarlet bison flex"
|
||||
PACKAGES_ARCH="$PACKAGES_ARCH speex speexdsp libogg libvorbis alsa-lib portaudio curl xmlstarlet bison flex"
|
||||
PACKAGES_ARCH="$PACKAGES_ARCH postgresql-libs unixodbc neon gmime lua uriparser libxslt openssl"
|
||||
PACKAGES_ARCH="$PACKAGES_ARCH libmariadbclient bluez-libs radcli freetds bash libcap"
|
||||
PACKAGES_ARCH="$PACKAGES_ARCH net-snmp libnewt popt libical spandsp"
|
||||
|
@ -87,7 +87,7 @@ PACKAGES_GENTOO="sys-devel/make sys-devel/gcc dev-util/pkgconfig"
|
|||
# Asterisk: basic requirements:
|
||||
PACKAGES_GENTOO="$PACKAGES_GENTOO dev-libs/libedit dev-libs/jansson sys-libs/e2fsprogs-libs dev-libs/libxml2 dev-db/sqlite"
|
||||
# Asterisk: for addons:
|
||||
PACKAGES_GENTOO="$PACKAGES_GENTOO media-libs/speex media-libs/speexdsp media-libs/libogg media-libs/libvorbis media-libs/portaudio net-misc/curl app-text/xmlstarlet sys-devel/bison sys-devel/flex"
|
||||
PACKAGES_GENTOO="$PACKAGES_GENTOO media-libs/speex media-libs/speexdsp media-libs/libogg media-libs/libvorbis media-libs/alsa-lib media-libs/portaudio net-misc/curl app-text/xmlstarlet sys-devel/bison sys-devel/flex"
|
||||
PACKAGES_GENTOO="$PACKAGES_GENTOO dev-db/postgresql dev-db/unixODBC net-libs/neon dev-libs/gmime dev-lang/lua dev-libs/uriparser dev-libs/libxslt dev-libs/openssl"
|
||||
PACKAGES_GENTOO="$PACKAGES_GENTOO virtual/libmysqlclient net-wireless/bluez net-dialup/radiusclient-ng dev-db/freetds app-shells/bash sys-libs/libcap"
|
||||
PACKAGES_GENTOO="$PACKAGES_GENTOO net-analyzer/net-snmp dev-libs/iksemel sys-cluster/corosync dev-libs/newt dev-libs/popt dev-libs/libical media-libs/spandsp"
|
||||
|
@ -103,7 +103,7 @@ PACKAGES_NBSD="gmake pkg-config"
|
|||
# Asterisk: basic requirements:
|
||||
PACKAGES_NBSD="$PACKAGES_NBSD editline jansson sqlite3 libuuid libxml2"
|
||||
# Asterisk: for addons:
|
||||
PACKAGES_NBSD="$PACKAGES_NBSD speex speexdsp libogg libvorbis portaudio-devel curl bison flex"
|
||||
PACKAGES_NBSD="$PACKAGES_NBSD speex speexdsp libogg libvorbis alsa-lib portaudio-devel curl bison flex"
|
||||
PACKAGES_NBSD="$PACKAGES_NBSD postgresql10-client unixodbc neon gmime lua52 uriparser libxslt openssl"
|
||||
PACKAGES_NBSD="$PACKAGES_NBSD mysql-client radiusclient-ng freetds bash"
|
||||
PACKAGES_NBSD="$PACKAGES_NBSD net-snmp iksemel popt libical spandsp"
|
||||
|
@ -135,7 +135,7 @@ PACKAGES_FBSD="gmake pkgconf"
|
|||
# Asterisk: basic requirements:
|
||||
PACKAGES_FBSD="$PACKAGES_FBSD libedit jansson e2fsprogs-libuuid sqlite3 libxml2"
|
||||
# Asterisk: for addons:
|
||||
PACKAGES_FBSD="$PACKAGES_FBSD speex speexdsp libogg libvorbis portaudio curl xmlstarlet bison flex"
|
||||
PACKAGES_FBSD="$PACKAGES_FBSD speex speexdsp libogg libvorbis alsa-lib portaudio curl xmlstarlet bison flex"
|
||||
PACKAGES_FBSD="$PACKAGES_FBSD postgresql10-client unixODBC neon gmime26 lua52 uriparser libxslt openssl"
|
||||
PACKAGES_FBSD="$PACKAGES_FBSD mysql57-client radcli freetds"
|
||||
PACKAGES_FBSD="$PACKAGES_FBSD net-snmp iksemel corosync newt popt libical spandsp"
|
||||
|
@ -151,7 +151,7 @@ PACKAGES_DBSD="gmake pkgconf"
|
|||
# Asterisk: basic requirements:
|
||||
PACKAGES_DBSD="$PACKAGES_DBSD libedit jansson e2fsprogs-libuuid sqlite3 libxml2"
|
||||
# Asterisk: for addons:
|
||||
PACKAGES_DBSD="$PACKAGES_DBSD speex speexdsp libogg libvorbis portaudio curl xmlstarlet bison flex"
|
||||
PACKAGES_DBSD="$PACKAGES_DBSD speex speexdsp libogg libvorbis alsa-lib portaudio curl xmlstarlet bison flex"
|
||||
PACKAGES_DBSD="$PACKAGES_DBSD postgresql10-client unixODBC neon gmime26 lua52 uriparser libxslt libressl"
|
||||
PACKAGES_DBSD="$PACKAGES_DBSD mariadb101-client radcli freetds"
|
||||
PACKAGES_DBSD="$PACKAGES_DBSD net-snmp iksemel corosync newt popt libical spandsp"
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
#!/usr/bin/perl -Tw
|
||||
# Retrieves the sip user/peer entries from the database
|
||||
# Use these commands to create the appropriate tables in MySQL
|
||||
#
|
||||
#CREATE TABLE sip (id INT(11) DEFAULT -1 NOT NULL,keyword VARCHAR(20) NOT NULL,data VARCHAR(50) NOT NULL, flags INT(1) DEFAULT 0 NOT NULL,PRIMARY KEY (id,keyword));
|
||||
#
|
||||
# if flags = 1 then the records are not included in the output file
|
||||
|
||||
use DBI;
|
||||
################### BEGIN OF CONFIGURATION ####################
|
||||
|
||||
# the name of the extensions table
|
||||
$table_name = "sip";
|
||||
# the path to the extensions.conf file
|
||||
# WARNING: this file will be substituted by the output of this program
|
||||
$sip_conf = "/etc/asterisk/sip_additional.conf";
|
||||
# the name of the box the MySQL database is running on
|
||||
$hostname = "localhost";
|
||||
# the name of the database our tables are kept
|
||||
$database = "sip";
|
||||
# username to connect to the database
|
||||
$username = "root";
|
||||
# password to connect to the database
|
||||
$password = "";
|
||||
|
||||
################### END OF CONFIGURATION #######################
|
||||
|
||||
$additional = "";
|
||||
|
||||
open EXTEN, ">$sip_conf" || die "Cannot create/overwrite extensions file: $sip_conf\n";
|
||||
|
||||
$dbh = DBI->connect("dbi:mysql:dbname=$database;host=$hostname", "$username", "$password");
|
||||
$statement = "SELECT keyword,data from $table_name where id=0 and keyword <> 'account' and flags <> 1";
|
||||
my $result = $dbh->selectall_arrayref($statement);
|
||||
unless ($result) {
|
||||
# check for errors after every single database call
|
||||
print "dbh->selectall_arrayref($statement) failed!\n";
|
||||
print "DBI::err=[$DBI::err]\n";
|
||||
print "DBI::errstr=[$DBI::errstr]\n";
|
||||
exit;
|
||||
}
|
||||
my @resultSet = @{$result};
|
||||
if ( $#resultSet > -1 ) {
|
||||
foreach $row (@{ $result }) {
|
||||
my @result = @{ $row };
|
||||
$additional .= $result[0]."=".$result[1]."\n";
|
||||
}
|
||||
}
|
||||
|
||||
$statement = "SELECT data,id from $table_name where keyword='account' and flags <> 1 group by data";
|
||||
|
||||
$result = $dbh->selectall_arrayref($statement);
|
||||
unless ($result) {
|
||||
# check for errors after every single database call
|
||||
print "dbh->selectall_arrayref($statement) failed!\n";
|
||||
print "DBI::err=[$DBI::err]\n";
|
||||
print "DBI::errstr=[$DBI::errstr]\n";
|
||||
}
|
||||
|
||||
@resultSet = @{$result};
|
||||
if ( $#resultSet == -1 ) {
|
||||
print "No sip accounts defined in $table_name\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
foreach my $row ( @{ $result } ) {
|
||||
my $account = @{ $row }[0];
|
||||
my $id = @{ $row }[1];
|
||||
print EXTEN "[$account]\n";
|
||||
$statement = "SELECT keyword,data from $table_name where id=$id and keyword <> 'account' and flags <> 1 order by keyword";
|
||||
my $result = $dbh->selectall_arrayref($statement);
|
||||
unless ($result) {
|
||||
# check for errors after every single database call
|
||||
print "dbh->selectall_arrayref($statement) failed!\n";
|
||||
print "DBI::err=[$DBI::err]\n";
|
||||
print "DBI::errstr=[$DBI::errstr]\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
my @resSet = @{$result};
|
||||
if ( $#resSet == -1 ) {
|
||||
print "no results\n";
|
||||
exit;
|
||||
}
|
||||
foreach my $row ( @{ $result } ) {
|
||||
my @result = @{ $row };
|
||||
print EXTEN "$result[0]=$result[1]\n";
|
||||
}
|
||||
print EXTEN "$additional\n";
|
||||
}
|
||||
|
||||
exit 0;
|
|
@ -0,0 +1,67 @@
|
|||
#!/bin/sh
|
||||
|
||||
# sip_nat_settings: generate NAT settings for sip.conf of an Asterisk system
|
||||
# that is behind a NAT router.
|
||||
#
|
||||
# This is a script to generate sane defaults for externip and localnet
|
||||
# of sip.conf. The output should be included in the [general] section of
|
||||
# sip.conf .
|
||||
#
|
||||
# Multiple network interfaces: If you have multiple network interfaces,
|
||||
# this script will generate a 'localnet' line for each of them that has a
|
||||
# broadcast (ipv4) address, except the loopback interface (lo). You can
|
||||
# later rem-out all of those you don't need.
|
||||
#
|
||||
# Alternatively, provide a network interface as a parameter an a localnet
|
||||
# line will only be generated for its network.
|
||||
#
|
||||
# Copyright (C) 2005 by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
# see http://unix.stackexchange.com/q/22615
|
||||
externip=`dig @resolver1.opendns.com -4 myip.opendns.com A +short`
|
||||
|
||||
# optional parameter: network interface to use. By default: none.
|
||||
IFACE="$1"
|
||||
|
||||
OS=`uname -s`
|
||||
case "$OS" in
|
||||
Linux)
|
||||
echo "externip = $externip"
|
||||
if [ -x "${IFACE}" ]; then
|
||||
ip --brief -family inet address show scope global up dev $IFACE | awk '{print "localnet = " $3}'
|
||||
else
|
||||
ip --brief -family inet address show scope global up | awk '{print "localnet = " $3}'
|
||||
fi
|
||||
;;
|
||||
OpenBSD|FreeBSD)
|
||||
if [ "${OS}" = "FreeBSD" ]; then
|
||||
VER=`uname -r | cut -d . -f 1`
|
||||
if [ ${VER} -lt 7 ]; then
|
||||
echo "Unsupported OS"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo "externip = $externip"
|
||||
ip=`/sbin/ifconfig $IFACE | awk '/\tinet .* broadcast/{print $6}'`
|
||||
x=`/sbin/ifconfig $IFACE | awk '/\tinet .* broadcast/{print $4}'`
|
||||
printf 'localnet = %s/%u.%u.%u.%u\n' $ip $(($x>>24&0xff)) $(($x>>16&0xff)) $(($x>>8&0xff)) $(($x&0xff))
|
||||
;;
|
||||
*)
|
||||
echo >&2 "$0: Unsupported OS $OS"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
|
@ -17,6 +17,10 @@ ListenStream=0.0.0.0:5039
|
|||
ListenStream=127.0.0.1:8088
|
||||
# HTTPS
|
||||
ListenStream=127.0.0.1:8089
|
||||
# chan_sip TCP
|
||||
ListenStream=0.0.0.0:5060
|
||||
# chan_sip TLS
|
||||
ListenStream=0.0.0.0:5061
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
||||
|
|
|
@ -45,8 +45,8 @@ asterisk
|
|||
provides Private Branch eXchange (PBX), Interactive Voice Response (IVR),
|
||||
Automated Call Distribution (ACD), Voice over IP (VoIP) gatewaying,
|
||||
Conferencing, and a plethora of other telephony applications to a broad
|
||||
range of telephony devices including packet voice (SIP, IAX2, H.323, Unistim)
|
||||
devices (both endpoints and proxies), as well as traditional TDM
|
||||
range of telephony devices including packet voice (SIP, IAX2, MGCP, Skinny,
|
||||
H.323, Unistim) devices (both endpoints and proxies), as well as traditional TDM
|
||||
hardware including T1, E1, ISDN PRI, GR-303, RBS, Loopstart, Groundstart,
|
||||
ISDN BRI and many more.
|
||||
.PP
|
||||
|
|
|
@ -52,8 +52,8 @@
|
|||
provides Private Branch eXchange (PBX), Interactive Voice Response (IVR),
|
||||
Automated Call Distribution (ACD), Voice over IP (VoIP) gatewaying,
|
||||
Conferencing, and a plethora of other telephony applications to a broad
|
||||
range of telephony devices including packet voice (SIP, IAX2 H.323, Unistim)
|
||||
devices (both endpoints and proxies), as well as traditional TDM
|
||||
range of telephony devices including packet voice (SIP, IAX2, MGCP, Skinny,
|
||||
H.323, Unistim) devices (both endpoints and proxies), as well as traditional TDM
|
||||
hardware including T1, E1, ISDN PRI, GR-303, RBS, Loopstart, Groundstart,
|
||||
ISDN BRI and many more.
|
||||
</para>
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
<enum name="cc_recall_timer" />
|
||||
<enum name="cc_max_agents" />
|
||||
<enum name="cc_max_monitors" />
|
||||
<enum name="cc_callback_macro" />
|
||||
<enum name="cc_agent_dialstring" />
|
||||
</enumlist>
|
||||
</parameter>
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
<parameter name="number" required="true" />
|
||||
<parameter name="method-type">
|
||||
<para>If no <replaceable>method-type</replaceable> is given, the default will be
|
||||
<literal>pjsip</literal>.</para>
|
||||
<literal>sip</literal>.</para>
|
||||
</parameter>
|
||||
<parameter name="zone-suffix">
|
||||
<para>If no <replaceable>zone-suffix</replaceable> is given, the default will be
|
||||
|
@ -96,7 +96,7 @@
|
|||
<parameter name="number" required="true" />
|
||||
<parameter name="method-type">
|
||||
<para>If no <replaceable>method-type</replaceable> is given, the default will be
|
||||
<literal>pjsip</literal>.</para>
|
||||
<literal>sip</literal>.</para>
|
||||
</parameter>
|
||||
<parameter name="options">
|
||||
<optionlist>
|
||||
|
@ -185,7 +185,7 @@ static int function_enum(struct ast_channel *chan, const char *cmd, char *data,
|
|||
if (args.tech && !ast_strlen_zero(args.tech)) {
|
||||
ast_copy_string(tech,args.tech, sizeof(tech));
|
||||
} else {
|
||||
ast_copy_string(tech,"pjsip",sizeof(tech));
|
||||
ast_copy_string(tech,"sip",sizeof(tech));
|
||||
}
|
||||
|
||||
if (!args.zone) {
|
||||
|
@ -279,7 +279,7 @@ static int enum_query_read(struct ast_channel *chan, const char *cmd, char *data
|
|||
if (!args.zone)
|
||||
args.zone = "e164.zone";
|
||||
|
||||
ast_copy_string(tech, args.tech ? args.tech : "pjsip", sizeof(tech));
|
||||
ast_copy_string(tech, args.tech ? args.tech : "sip", sizeof(tech));
|
||||
|
||||
if (!(erds = ast_calloc(1, sizeof(*erds))))
|
||||
goto finish;
|
||||
|
|
|
@ -95,7 +95,9 @@ struct ast_vm_recording_data {
|
|||
AST_STRING_FIELD(folder);
|
||||
AST_STRING_FIELD(recording_file);
|
||||
AST_STRING_FIELD(recording_ext);
|
||||
|
||||
AST_STRING_FIELD(call_context);
|
||||
AST_STRING_FIELD(call_macrocontext);
|
||||
AST_STRING_FIELD(call_extension);
|
||||
AST_STRING_FIELD(call_callerchan);
|
||||
AST_STRING_FIELD(call_callerid);
|
||||
|
@ -169,6 +171,50 @@ enum ast_getdata_result ast_app_getdata_terminator(struct ast_channel *c, const
|
|||
/*! \brief Full version with audiofd and controlfd. NOTE: returns '2' on ctrlfd available, not '1' like other full functions */
|
||||
int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd);
|
||||
|
||||
/*!
|
||||
* \brief Run a macro on a channel, placing an optional second channel into autoservice.
|
||||
* \since 11.0
|
||||
*
|
||||
* \details
|
||||
* This is a shorthand method that makes it very easy to run a
|
||||
* macro on any given channel. It is perfectly reasonable to
|
||||
* supply a NULL autoservice_chan here in case there is no
|
||||
* channel to place into autoservice.
|
||||
*
|
||||
* \note Absolutely _NO_ channel locks should be held before calling this function.
|
||||
*
|
||||
* \param autoservice_chan A channel to place into autoservice while the macro is run
|
||||
* \param macro_chan Channel to execute macro on.
|
||||
* \param macro_args Macro application argument string.
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 on error
|
||||
*/
|
||||
int ast_app_exec_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const char *macro_args);
|
||||
|
||||
/*!
|
||||
* \since 1.8
|
||||
* \brief Run a macro on a channel, placing an optional second channel into autoservice.
|
||||
*
|
||||
* \details
|
||||
* This is a shorthand method that makes it very easy to run a
|
||||
* macro on any given channel. It is perfectly reasonable to
|
||||
* supply a NULL autoservice_chan here in case there is no
|
||||
* channel to place into autoservice.
|
||||
*
|
||||
* \note Absolutely _NO_ channel locks should be held before calling this function.
|
||||
*
|
||||
* \param autoservice_chan A channel to place into autoservice while the macro is run
|
||||
* \param macro_chan Channel to execute macro on.
|
||||
* \param macro_name The name of the macro to run.
|
||||
* \param macro_args The arguments to pass to the macro.
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 on error
|
||||
*/
|
||||
int ast_app_run_macro(struct ast_channel *autoservice_chan,
|
||||
struct ast_channel *macro_chan, const char *macro_name, const char *macro_args);
|
||||
|
||||
/*!
|
||||
* \brief Stack applications callback functions.
|
||||
*/
|
||||
|
|
|
@ -44,6 +44,9 @@
|
|||
/* Define to 1 if <alloca.h> works. */
|
||||
#undef HAVE_ALLOCA_H
|
||||
|
||||
/* Define to 1 if you have the Advanced Linux Sound Architecture library. */
|
||||
#undef HAVE_ALSA
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#undef HAVE_ARPA_INET_H
|
||||
|
||||
|
@ -517,6 +520,9 @@
|
|||
/* Define to 1 if you have a working `mmap' system call. */
|
||||
#undef HAVE_MMAP
|
||||
|
||||
/* Define if your system has the MSG_NOSIGNAL headers. */
|
||||
#undef HAVE_MSG_NOSIGNAL
|
||||
|
||||
/* Define to 1 if you have the `munmap' function. */
|
||||
#undef HAVE_MUNMAP
|
||||
|
||||
|
@ -580,6 +586,9 @@
|
|||
/* Define to 1 if you have the Opusfile library. */
|
||||
#undef HAVE_OPUSFILE
|
||||
|
||||
/* Define this to indicate the ${OSPTK_DESCRIP} library */
|
||||
#undef HAVE_OSPTK
|
||||
|
||||
/* Define to 1 if your system defines the file flag O_EVTONLY in fcntl.h */
|
||||
#undef HAVE_O_EVTONLY
|
||||
|
||||
|
@ -898,6 +907,9 @@
|
|||
/* Define to 1 if your system has soxmix application. */
|
||||
#undef HAVE_SOXMIX
|
||||
|
||||
/* Define if your system has the SO_NOSIGPIPE headers. */
|
||||
#undef HAVE_SO_NOSIGPIPE
|
||||
|
||||
/* Define if your system has the SPANDSP headers. */
|
||||
#undef HAVE_SPANDSP
|
||||
|
||||
|
|
|
@ -90,6 +90,12 @@ enum ast_bridge_builtin_feature {
|
|||
* parking slot to which it was parked.
|
||||
*/
|
||||
AST_BRIDGE_BUILTIN_PARKCALL,
|
||||
/*!
|
||||
* DTMF one-touch-record toggle using Monitor app.
|
||||
*
|
||||
* \note Only valid on two party bridges.
|
||||
*/
|
||||
AST_BRIDGE_BUILTIN_AUTOMON,
|
||||
/*!
|
||||
* DTMF one-touch-record toggle using MixMonitor app.
|
||||
*
|
||||
|
@ -299,14 +305,19 @@ struct ast_bridge_features_attended_transfer {
|
|||
};
|
||||
|
||||
enum ast_bridge_features_monitor {
|
||||
/*! Toggle start/stop of MixMonitor. */
|
||||
/*! Toggle start/stop of Monitor/MixMonitor. */
|
||||
AUTO_MONITOR_TOGGLE,
|
||||
/*! Start MixMonitor if not already started. */
|
||||
/*! Start Monitor/MixMonitor if not already started. */
|
||||
AUTO_MONITOR_START,
|
||||
/*! Stop MixMonitor if not already stopped. */
|
||||
/*! Stop Monitor/MixMonitor if not already stopped. */
|
||||
AUTO_MONITOR_STOP,
|
||||
};
|
||||
|
||||
struct ast_bridge_features_automonitor {
|
||||
/*! Start/Stop behavior. */
|
||||
enum ast_bridge_features_monitor start_stop;
|
||||
};
|
||||
|
||||
struct ast_bridge_features_automixmonitor {
|
||||
/*! Start/Stop behavior. */
|
||||
enum ast_bridge_features_monitor start_stop;
|
||||
|
|
|
@ -362,6 +362,22 @@ unsigned int ast_get_cc_max_monitors(struct ast_cc_config_params *config);
|
|||
*/
|
||||
void ast_set_cc_max_monitors(struct ast_cc_config_params *config, unsigned int value);
|
||||
|
||||
/*!
|
||||
* \since 1.8
|
||||
* \brief Get the name of the callback_macro
|
||||
* \param config The configuration to retrieve the callback_macro from
|
||||
* \return The callback_macro name
|
||||
*/
|
||||
const char *ast_get_cc_callback_macro(struct ast_cc_config_params *config);
|
||||
|
||||
/*!
|
||||
* \since 1.8
|
||||
* \brief Set the callback_macro name
|
||||
* \param config The configuration to set the callback_macro on
|
||||
* \param value The new callback macro we want to change to
|
||||
*/
|
||||
void ast_set_cc_callback_macro(struct ast_cc_config_params *config, const char * const value);
|
||||
|
||||
/*!
|
||||
* \since 11
|
||||
* \brief Get the name of the callback subroutine
|
||||
|
@ -502,7 +518,7 @@ struct ast_cc_monitor {
|
|||
* \details
|
||||
* When issuing a CC recall, some technologies will require
|
||||
* that a name other than the device name is dialed. For instance,
|
||||
* with SIP, a specific URI will be used which sip will be able
|
||||
* with SIP, a specific URI will be used which chan_sip will be able
|
||||
* to recognize as being a CC recall. Similarly, ISDN will need a specific
|
||||
* dial string to know that the call is a recall.
|
||||
*/
|
||||
|
|
|
@ -616,7 +616,7 @@ struct ast_msg_data;
|
|||
* Structure to describe a channel "technology", ie a channel driver
|
||||
* See for examples:
|
||||
* \arg chan_iax2.c - The Inter-Asterisk exchange protocol
|
||||
* \arg chan_pjsip.c - The SIP channel driver
|
||||
* \arg chan_sip.c - The SIP channel driver
|
||||
* \arg chan_dahdi.c - PSTN connectivity (TDM, PRI, T1/E1, FXO, FXS)
|
||||
*
|
||||
* \details
|
||||
|
@ -3847,6 +3847,37 @@ void ast_channel_update_redirecting(struct ast_channel *chan, const struct ast_p
|
|||
*/
|
||||
void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update);
|
||||
|
||||
/*!
|
||||
* \since 1.8
|
||||
* \brief Run a connected line interception macro and update a channel's connected line
|
||||
* information
|
||||
* \deprecated You should use the ast_channel_connected_line_sub() function instead.
|
||||
*
|
||||
* Whenever we want to update a channel's connected line information, we may need to run
|
||||
* a macro so that an administrator can manipulate the information before sending it
|
||||
* out. This function both runs the macro and sends the update to the channel.
|
||||
*
|
||||
* \param autoservice_chan Channel to place into autoservice while the macro is running.
|
||||
* It is perfectly safe for this to be NULL
|
||||
* \param macro_chan The channel to run the macro on. Also the channel from which we
|
||||
* determine which macro we need to run.
|
||||
* \param connected_info Either an ast_party_connected_line or ast_frame pointer of type
|
||||
* AST_CONTROL_CONNECTED_LINE
|
||||
* \param is_caller If true, then run CONNECTED_LINE_CALLER_SEND_MACRO with arguments from
|
||||
* CONNECTED_LINE_CALLER_SEND_MACRO_ARGS, otherwise run CONNECTED_LINE_CALLEE_SEND_MACRO
|
||||
* with arguments from CONNECTED_LINE_CALLEE_SEND_MACRO_ARGS
|
||||
* \param frame If true, then connected_info is an ast_frame pointer, otherwise it is an
|
||||
* ast_party_connected_line pointer.
|
||||
* \retval 0 Success
|
||||
* \retval -1 Either the macro does not exist, or there was an error while attempting to
|
||||
* run the macro
|
||||
*
|
||||
* \todo Have multiple return codes based on the MACRO_RESULT
|
||||
* \todo Make constants so that caller and frame can be more expressive than just '1' and
|
||||
* '0'
|
||||
*/
|
||||
int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int is_caller, int frame);
|
||||
|
||||
/*!
|
||||
* \since 11
|
||||
* \brief Run a connected line interception subroutine and update a channel's connected line
|
||||
|
@ -3871,6 +3902,38 @@ void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct
|
|||
*/
|
||||
int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *connected_info, int frame);
|
||||
|
||||
/*!
|
||||
* \since 1.8
|
||||
* \brief Run a redirecting interception macro and update a channel's redirecting information
|
||||
* \deprecated You should use the ast_channel_redirecting_sub() function instead.
|
||||
*
|
||||
* \details
|
||||
* Whenever we want to update a channel's redirecting information, we may need to run
|
||||
* a macro so that an administrator can manipulate the information before sending it
|
||||
* out. This function both runs the macro and sends the update to the channel.
|
||||
*
|
||||
* \param autoservice_chan Channel to place into autoservice while the macro is running.
|
||||
* It is perfectly safe for this to be NULL
|
||||
* \param macro_chan The channel to run the macro on. Also the channel from which we
|
||||
* determine which macro we need to run.
|
||||
* \param redirecting_info Either an ast_party_redirecting or ast_frame pointer of type
|
||||
* AST_CONTROL_REDIRECTING
|
||||
* \param is_caller If true, then run REDIRECTING_CALLER_SEND_MACRO with arguments from
|
||||
* REDIRECTING_CALLER_SEND_MACRO_ARGS, otherwise run REDIRECTING_CALLEE_SEND_MACRO with
|
||||
* arguments from REDIRECTING_CALLEE_SEND_MACRO_ARGS
|
||||
* \param is_frame If true, then redirecting_info is an ast_frame pointer, otherwise it is an
|
||||
* ast_party_redirecting pointer.
|
||||
*
|
||||
* \retval 0 Success
|
||||
* \retval -1 Either the macro does not exist, or there was an error while attempting to
|
||||
* run the macro
|
||||
*
|
||||
* \todo Have multiple return codes based on the MACRO_RESULT
|
||||
* \todo Make constants so that caller and frame can be more expressive than just '1' and
|
||||
* '0'
|
||||
*/
|
||||
int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *redirecting_info, int is_caller, int is_frame);
|
||||
|
||||
/*!
|
||||
* \since 11
|
||||
* \brief Run a redirecting interception subroutine and update a channel's redirecting information
|
||||
|
@ -4033,6 +4096,21 @@ enum AST_MONITORING_STATE {
|
|||
AST_MONITOR_PAUSED
|
||||
};
|
||||
|
||||
/*! Responsible for channel monitoring data */
|
||||
struct ast_channel_monitor {
|
||||
struct ast_filestream *read_stream;
|
||||
struct ast_filestream *write_stream;
|
||||
char read_filename[FILENAME_MAX];
|
||||
char write_filename[FILENAME_MAX];
|
||||
char filename_base[FILENAME_MAX];
|
||||
char beep_id[64];
|
||||
int filename_changed;
|
||||
char *format;
|
||||
int joinfiles;
|
||||
enum AST_MONITORING_STATE state;
|
||||
int (*stop)(struct ast_channel *chan, int need_lock);
|
||||
};
|
||||
|
||||
/* ACCESSOR FUNCTIONS */
|
||||
|
||||
#define DECLARE_STRINGFIELD_SETTERS_FOR(field) \
|
||||
|
@ -4090,6 +4168,10 @@ void ast_channel_context_set(struct ast_channel *chan, const char *value);
|
|||
const char *ast_channel_lastexten(const struct ast_channel *chan);
|
||||
const char *ast_channel_exten(const struct ast_channel *chan);
|
||||
void ast_channel_exten_set(struct ast_channel *chan, const char *value);
|
||||
const char *ast_channel_macrocontext(const struct ast_channel *chan);
|
||||
void ast_channel_macrocontext_set(struct ast_channel *chan, const char *value);
|
||||
const char *ast_channel_macroexten(const struct ast_channel *chan);
|
||||
void ast_channel_macroexten_set(struct ast_channel *chan, const char *value);
|
||||
|
||||
char ast_channel_dtmf_digit_to_emulate(const struct ast_channel *chan);
|
||||
void ast_channel_dtmf_digit_to_emulate_set(struct ast_channel *chan, char value);
|
||||
|
@ -4109,6 +4191,8 @@ int ast_channel_fdno(const struct ast_channel *chan);
|
|||
void ast_channel_fdno_set(struct ast_channel *chan, int value);
|
||||
int ast_channel_hangupcause(const struct ast_channel *chan);
|
||||
void ast_channel_hangupcause_set(struct ast_channel *chan, int value);
|
||||
int ast_channel_macropriority(const struct ast_channel *chan);
|
||||
void ast_channel_macropriority_set(struct ast_channel *chan, int value);
|
||||
int ast_channel_priority(const struct ast_channel *chan);
|
||||
void ast_channel_priority_set(struct ast_channel *chan, int value);
|
||||
int ast_channel_rings(const struct ast_channel *chan);
|
||||
|
@ -4153,6 +4237,8 @@ struct ast_channel *ast_channel_masq(const struct ast_channel *chan);
|
|||
void ast_channel_masq_set(struct ast_channel *chan, struct ast_channel *value);
|
||||
struct ast_channel *ast_channel_masqr(const struct ast_channel *chan);
|
||||
void ast_channel_masqr_set(struct ast_channel *chan, struct ast_channel *value);
|
||||
struct ast_channel_monitor *ast_channel_monitor(const struct ast_channel *chan);
|
||||
void ast_channel_monitor_set(struct ast_channel *chan, struct ast_channel_monitor *value);
|
||||
struct ast_filestream *ast_channel_stream(const struct ast_channel *chan);
|
||||
void ast_channel_stream_set(struct ast_channel *chan, struct ast_filestream *value);
|
||||
struct ast_filestream *ast_channel_vstream(const struct ast_channel *chan);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue