Compare commits

...

172 Commits
master ... 20.2

Author SHA1 Message Date
Asterisk Development Team 1d64cb99d2 Update for 20.2.1 2023-04-03 10:49:49 -05:00
Mike Bradeen f8dfbaf225 res_pjsip_pubsub: subscription cleanup changes
There are two main parts of the change associated with this
commit. These are driven by the change in call order of
pubsub_on_rx_refresh and pubsub_on_evsub_state by pjproject
when an in-dialog SUBSCRIBE is received.

First, the previous behavior was for pjproject to call
pubsub_on_rx_refresh before calling pubsub_on_evsub_state
when an in-dialog SUBSCRIBE was received that changes the
subscription state.

If that change was a termination due to a re-SUBSCRIBE with
an expires of 0, we used to use the call to pubsub_on_rx_refresh
to set the substate of the evsub to TERMINATE_PENDING before
pjproject could call pubsub_on_evsub_state.

This substate let pubsub_on_evsub_state know that the
subscription TERMINATED event could be ignored as there was
still a subsequent NOTIFY that needed to be generated and
another call to pubsub_on_evsub_state to come with it.

That NOTIFY was sent via serialized_pubsub_on_refresh_timeout
which would see the TERMINATE_PENDING state and transition it
to TERMINATE_IN_PROGRESS before triggering another call to
pubsub_on_evsub_state (which now would clean up the evsub.)

The new pjproject behavior is to call pubsub_on_evsub_state
before pubsub_on_rx_refresh. This means we no longer can set
the state to TERMINATE_PENDING to tell pubsub_on_evsub_state
that it can ignore the first TERMINATED event.

To handle this, we now look directly at the event type,
method type and the expires value to determine whether we
want to ignore the event or use it to trigger the evsub
cleanup.

Second, pjproject now expects the NOTIFY to actually be sent
during pubsub_on_rx_refresh and avoids the protocol violation
inherent in sending a NOTIFY before the SUBSCRIBE is
acknowledged by caching the sent NOTIFY then sending it
after responding to the SUBSCRIBE.

This requires we send the NOTIFY using the non-serialized
pubsub_on_refresh_timeout directly and let pjproject handle
the protocol violation.

ASTERISK-30469

Change-Id: I05c1d91a44fe28244ae93faa4a2268a3332b5fd7
2023-04-03 09:43:55 -05:00
Sean Bright 6e50550d28 Revert "pbx_ael: Global variables are not expanded."
This reverts commit 56051d1ac5.

Reason for revert: Behavior change that breaks existing dialplan.

ASTERISK-30472 #close

Change-Id: I83bed3b800d36228a04ded0a6164b795f7f16bd6
2023-03-20 06:50:49 -06:00
Asterisk Development Team e7f0440032 Update for 20.2.0 2023-03-09 12:17:03 -05:00
Asterisk Development Team 460d13e916 Update for 20.2.0-rc1 2023-03-02 11:45:57 -05:00
Asterisk Development Team 93813c9dca Update CHANGES and UPGRADE.txt for 20.2.0 2023-03-02 11:37:42 -05:00
George Joseph ceda5a9859 res_pjsip: Replace invalid UTF-8 sequences in callerid name
* Added a new function ast_utf8_replace_invalid_chars() to
  utf8.c that copies a string replacing any invalid UTF-8
  sequences with the Unicode specified U+FFFD replacement
  character.  For example:  "abc\xffdef" becomes "abc\uFFFDdef".
  Any UTF-8 compliant implementation will show that character
  as a � character.

* Updated res_pjsip:set_id_from_hdr() to use
  ast_utf8_replace_invalid_chars and print a warning if any
  invalid sequences were found during the copy.

* Updated stasis_channels:ast_channel_publish_varset to use
  ast_utf8_replace_invalid_chars and print a warning if any
  invalid sequences were found during the copy.

ASTERISK-27830

Change-Id: I4ffbdb19c80bf0efc675d40078a3ca4f85c567d8
2023-03-01 09:49:39 -06:00
Sean Bright e5c5cd6e25 test.c: Avoid passing -1 to FD_* family of functions.
This avoids buffer overflow errors when running tests that capture
output from child processes.

This also corrects a copypasta in an off-nominal error message.

Change-Id: Ib482847a3515364f14c7e7a0c0a4213851ddb10d
2023-02-28 10:48:11 -06:00
Naveen Albert ede67a99be chan_iax2: Fix jitterbuffer regression prior to receiving audio.
ASTERISK_29392 (a security fix) introduced a regression by
not processing frames when we don't have an audio format.

Currently, chan_iax2 only calls jb_get to read frames from
the jitterbuffer when the voiceformat has been set on the pvt.
However, this only happens when we receive a voice frame, which
means that prior to receiving voice frames, other types of frames
get stalled completely in the jitterbuffer.

To fix this, we now fallback to using the format negotiated during
call setup until we've actually received a voice frame with a format.
This ensures we're always able to read from the jitterbuffer.

ASTERISK-30354 #close
ASTERISK-30162 #close

Change-Id: Ie4fd1e8e088a145ad89e0427c2100a530e964fe9
2023-02-28 07:55:13 -06:00
Sean Bright 827222d607 test_crypto.c: Fix getcwd(…) build error.
`getcwd(…)` is decorated with the `warn_unused_result` attribute and
therefore needs its return value checked.

Change-Id: Idcccb20a0abf293202c28633d0e9ee0f6a9dbe93
2023-02-27 15:39:49 -06:00
Nick French 200dc7d0e8 pjproject_bundled: Fix cross-compilation with SSL libs.
Asterisk makefiles auto-detect SSL library availability,
then they assume that pjproject makefiles will also autodetect
an SSL library at the same time, so they do not pass on the
autodetection result to pjproject.

This normally works, except the pjproject makefiles disables
autodetection when cross-compiling.

Fix by explicitly configuring pjproject to use SSL if we
have been told to use it or it was autodetected

ASTERISK-30424 #close

Change-Id: I8fe2999ea46710e21d1d55a1bed92769c6ebded9
2023-02-27 14:48:41 -06:00
Mike Bradeen 5c11d7adea app_read: Add an option to return terminator on empty digits.
Adds 'e' option to allow Read() to return the terminator as the
dialed digits in the case where only the terminator is entered.

ie; if "#" is entered, return "#" if the 'e' option is set and ""
if it is not.

ASTERISK-30411

Change-Id: I49f3221824330a193a20c660f99da0f1fc2cbbc5
2023-02-27 13:42:39 -06:00
cmaj 5b0e3444c3 res_phoneprov.c: Multihomed SERVER cache prevention
Phones moving between subnets on multi-homed server have their
initially connected interface IP cached in the SERVER variable,
even when it is not specified in the configuration files. This
prevents phones from obtaining the correct SERVER variable value
when they move to another subnet.

ASTERISK-30388 #close
Reported-by: cmaj

Change-Id: I1d18987a9d58e85556b4c4a6814ce7006524cc92
2023-02-27 13:41:40 -06:00
Mike Bradeen 2308afed8e app_directory: Add a 'skip call' option.
Adds 's' option to skip calling the extension and instead set the
extension as DIRECTORY_EXTEN channel variable.

ASTERISK-30405

Change-Id: Ib9d9db1ba5b7524594c640461b4aa8f752db8299
2023-02-27 12:04:39 -06:00
Mike Bradeen 98742388b6 app_senddtmf: Add option to answer target channel.
Adds a new option to SendDTMF() which will answer the specified
channel if it is not already up. If no channel is specified, the
current channel will be answered instead.

ASTERISK-30422

Change-Id: Iddcbd501fcdf9fef0f453b7a8115a90b11f1d085
2023-02-27 11:13:27 -06:00
Mike Bradeen 37e558f6ef res_pjsip: Prevent SEGV in pjsip_evsub_send_request
contributed pjproject - patch to check sub->pending_notify
in evsub.c:on_tsx_state before calling
pjsip_evsub_send_request()

res_pjsip_pubsub - change post pjsip 2.13 behavior to use
pubsub_on_refresh_timeout to avoid the ao2_cleanup call on
the sub_tree. This is is because the final NOTIFY send is no
longer the last place the sub_tree is referenced.

ASTERISK-30419

Change-Id: Ib5cc662ce578e9adcda312e16c58a10b6453e438
2023-02-23 10:10:54 -06:00
Sean Bright aeb16aa7d8 app_queue: Minor docs and logging fixes for UnpauseQueueMember.
ASTERISK-30417 #close

Change-Id: I7534e7a925bf92a7b5a5347f5f54225768c162fe
2023-02-20 06:19:32 -06:00
Sean Bright aef0c0ce0e app_queue: Reset all queue defaults before reload.
Several queue fields were not being set to their default value during
a reload.

Additionally added some sample configuration options that were missing
from queues.conf.sample.

Change-Id: I3a88c7877af91752b1b46a0c087384f7eb9c47e4
2023-02-13 07:53:29 -06:00
Mike Bradeen 58636a6ea6 res_pjsip: Upgraded bundled pjsip to 2.13
Removed multiple patches.

Code chages in res_pjsip_pubsub due to changes in evsub.

Pjsip now calls on_evsub_state() before on_rx_refresh(),
so the sub tree deletion that used to take place in
on_evsub_state() now must take place in on_rx_refresh().

Additionally, pjsip now requires that you send the NOTIFY
from within on_rx_refresh(), otherwise it will assert
when going to send the 200 OK. The idea is that it will
look for this NOTIFY and cache it until after sending the
response in order to deal with the self-imposed message
mis-order. Asterisk previously dealt with this by pushing
the NOTIFY in on_rx_refresh(), but pjsip now forces us
to use it's method.

Changes were required to configure in order to detect
which way pjsip handles this as the two are not
compatible for the reasons mentioned above.

A corresponding change in testsuite is required in order
to deal with the small interal timing changes caused by
moving the NOTIFY send.

ASTERISK-30325

Change-Id: I50b00cac89d950d3511d7b250a1c641965d9fe7f
2023-02-06 18:15:35 -07:00
Sean Bright 96d9ad51ac doxygen: Fix doxygen errors.
Change-Id: Ic50e95b4fc10f74ab15416d908e8a87ee8ec2f85
2023-01-31 12:59:16 -06:00
Naveen Albert 88b2c741ca app_signal: Add signaling applications
Adds the Signal and WaitForSignal
applications, which can be used for inter-channel
signaling in the dialplan.

Signal supports sending a signal to other channels
listening for a signal of the same name, with an
optional data payload. The signal is received by
all channels waiting for that named signal.

ASTERISK-29810 #close

Change-Id: Ic34439de3d60f8609357666a465c354d81f5fef3
2023-01-31 05:53:37 -06:00
Mike Bradeen 70856e865f app_directory: add ability to specify configuration file
Adds option to app_directory to specify a filename from which to
read configuration instead of voicemail.conf ie;

same => n,Directory(,,c(directory.conf))

This configuration should contain a list of extensions using the
voicemail.conf format, ie;

2020=2020,Dog Dog,,,,attach=no|saycid=no|envelope=no|delete=no

ASTERISK-30404

Change-Id: Id58ccb1344ad1e563fa10db12f172fbd104a9d13
2023-01-30 09:51:06 -06:00
Naveen Albert 8a45cd7af4 func_json: Enhance parsing capabilities of JSON_DECODE
Adds support for arrays to JSON_DECODE by allowing the
user to print out entire arrays or index a particular
key or print the number of keys in a JSON array.

Additionally, adds support for recursively iterating a
JSON tree in a single function call, making it easier
to parse JSON results with multiple levels. A maximum
depth is imposed to prevent potentially blowing
the stack.

Also fixes a bug with the unit tests causing an empty
string to be printed instead of the actual test result.

ASTERISK-29913 #close

Change-Id: I603940b216a3911b498fc6583b18934011ef5d5b
2023-01-30 08:50:48 -06:00
sungtae kim f99849f8d5 res_stasis_snoop: Fix snoop crash
Added NULL pointer check and channel lock to prevent resource release
while the chanspy is processing.

ASTERISK-29604

Change-Id: Ibdc675f98052da32333b19685b1708a3751b6d24
2023-01-30 08:26:18 -06:00
Sean Bright 56051d1ac5 pbx_ael: Global variables are not expanded.
Variable references within global variable assignments are now
expanded rather than being included literally.

ASTERISK-30406 #close

Change-Id: I136e8d6395e90a4c92d9777a46a7bc3edb08d05d
2023-01-30 07:48:11 -06:00
Naveen Albert a1da8042d1 res_pjsip_session: Add overlap_context option.
Adds the overlap_context option, which can be used
to explicitly specify a context to use for overlap
dialing extension matches, rather than forcibly
using the context configured for the endpoint.

ASTERISK-30262 #close

Change-Id: Ibbcd4a8b11402428a187fb56b8d4e7408774a0db
2023-01-26 07:38:30 -06:00
Sean Bright ef16eaee36 app_playback.c: Fix PLAYBACKSTATUS regression.
In Asterisk 11, if a channel was redirected away during Playback(),
the PLAYBACKSTATUS variable would be set to SUCCESS. In Asterisk 12
(specifically commit 7d9871b394) that
behavior was inadvertently changed and the same operation would result
in the PLAYBACKSTATUS variable being set to FAILED. The Asterisk 11
behavior has been restored.

Partial fix for ASTERISK~25661.

Change-Id: I53f54e56b59b61c99403a481b6cb8d88b5a559ff
2023-01-13 08:28:53 -06:00
George Joseph 2f5aece0c9 res_rtp_asterisk: Don't use double math to generate timestamps
Rounding issues with double math were causing rtp timestamp
slips in outgoing packets.  We're now back to integer math
and are getting no more slips.

ASTERISK-30391

Change-Id: I6ba992b49ffdf9ebea074581dfa784a188c661a4
2023-01-12 06:00:37 -07:00
Alexei Gradinari e86d5d7fda format_wav: replace ast_log(LOG_DEBUG, ...) by ast_debug(1, ...)
Each playback of WAV files results in logging
"Skipping unknown block 'LIST'".

To prevent unnecessary flooding of this DEBUG log this patch replaces
ast_log(LOG_DEBUG, ...) by ast_debug(1, ...).

Change-Id: Iaa09cf19c5348a05385518fdb8cb181b45fe05f0
2023-01-10 13:32:49 -06:00
Igor Goncharovsky 3526441e41 res_pjsip_rfc3326: Add SIP causes support for RFC3326
Add ability to set HANGUPCAUSE when SIP causecode received in BYE (in addition to currently supported Q.850).

ASTERISK-30319 #close

Change-Id: I3f55622dc680ce713a2ffb5a458ef5dd39fcf645
2023-01-10 13:31:14 -06:00
George Joseph 4710f37ef6 res_rtp_asterisk: Asterisk Media Experience Score (MES)
-----------------

This commit reinstates MES with some casting fixes to the
functions in time.h that convert between doubles and timeval
structures.  The casting issues were causing incorrect
timestamps to be calculated which caused transcoding from/to
G722 to produce bad or no audio.

ASTERISK-30391

-----------------

This module has been updated to provide additional
quality statistics in the form of an Asterisk
Media Experience Score.  The score is avilable using
the same mechanisms you'd use to retrieve jitter, loss,
and rtt statistics.  For more information about the
score and how to retrieve it, see
https://wiki.asterisk.org/wiki/display/AST/Media+Experience+Score

* Updated chan_pjsip to set quality channel variables when a
  call ends.
* Updated channels/pjsip/dialplan_functions.c to add the ability
  to retrieve the MES along with the existing rtcp stats when
  using the CHANNEL dialplan function.
* Added the ast_debug_rtp_is_allowed and ast_debug_rtcp_is_allowed
  checks for debugging purposes.
* Added several function to time.h for manipulating time-in-samples
  and times represented as double seconds.
* Updated rtp_engine.c to pass through the MES when stats are
  requested.  Also debug output that dumps the stats when an
  rtp instance is destroyed.
* Updated res_rtp_asterisk.c to implement the calculation of the
  MES.  In the process, also had to update the calculation of
  jitter.  Many debugging statements were also changed to be
  more informative.
* Added a unit test for internal testing.  The test should not be
  run during normal operation and is disabled by default.

Change-Id: I4fce265965e68c3fdfeca55e614371ee69c65038
2023-01-09 11:40:46 -06:00
George Joseph 62ca063fca Revert "res_rtp_asterisk: Asterisk Media Experience Score (MES)"
This reverts commit d454801c2d.

Reason for revert: Issue when transcoding to/from g722

Change-Id: I09f49e171b1661548657a9ba7a978c29d0b5be86
2023-01-09 08:24:06 -06:00
Naveen Albert d33bd6d67a loader: Allow declined modules to be unloaded.
Currently, if a module declines to load, dlopen is called
to register the module but dlclose never gets called.
Furthermore, loader.c currently doesn't allow dlclose
to ever get called on the module, since it declined to
load and the unload function bails early in this case.

This can be problematic if a module is updated, since the
new module cannot be loaded into memory since we haven't
closed all references to it. To fix this, we now allow
modules to be unloaded, even if they never "loaded" in
Asterisk itself, so that dlclose is called and the module
can be properly cleaned up, allowing the updated module
to be loaded from scratch next time.

ASTERISK-30345 #close

Change-Id: Ifc743aadfa85ebe3284e02a63e124dafa64988d5
2023-01-05 06:13:25 -06:00
Naveen Albert e06fe8e344 app_broadcast: Add Broadcast application
Adds a new application, Broadcast, which can be used for
one-to-many transmission and many-to-one reception of
channel audio in Asterisk. This is similar to ChanSpy,
except it is designed for multiple channel targets instead
of a single one. This can make certain kinds of audio
manipulation more efficient and streamlined. New kinds
of audio injection impossible with ChanSpy are also made
possible.

ASTERISK-30180 #close

Change-Id: I7ba72f765dbab9b58deeae028baca3f4f8377726
2023-01-05 06:12:10 -06:00
Naveen Albert 68e345286b func_frame_trace: Print text for text frames.
Since text frames contain a text body, make FRAME_TRACE
more useful for text frames by actually printing the text.

ASTERISK-30353 #close

Change-Id: Ia6ce3d15cecd7a673a528d34faac86854a2bab50
2023-01-05 06:11:02 -06:00
Naveen Albert 3b3fef2347 json.h: Add ast_json_object_real_get.
json.h contains macros to get a string and an integer
from a JSON object. However, the macro to do this for
JSON reals is missing. This adds that.

ASTERISK-30361 #close

Change-Id: I8d0e28d763febf27b05801cdc83b73282aa6ee7a
2023-01-04 05:52:23 -06:00
Naveen Albert 7b8f7428da manager: Fix appending variables.
The if statement here is always false after the for
loop finishes, so variables are never appended.
This removes that to properly append to the end
of the variable list.

ASTERISK-30351 #close
Reported by: Sebastian Gutierrez

Change-Id: I1b7f8b85a8918f6a814cb933a479d4278cf16199
2023-01-04 05:51:18 -06:00
George Joseph 24102ba236 res_pjsip_transport_websocket: Add remote port to transport
When Asterisk receives a new websocket conenction, it creates a new
pjsip transport for it and copies connection data into it.  The
transport manager then uses the remote IP address and port on the
transport to create a monitor for each connection.  However, the
remote port wasn't being copied, only the IP address which meant
that the transport manager was creating only 1 monitoring entry for
all websocket connections from the same IP address. Therefore, if
one of those connections failed, it deleted the transport taking
all the the connections from that same IP address with it.

* We now copy the remote port into the created transport and the
  transport manager behaves correctly.

ASTERISK-30369

Change-Id: Ib506d40897ea6286455ac0be4dfbb0ed43b727e1
2023-01-03 10:53:20 -06:00
Boris P. Korzun edc90c96ac http.c: Fix NULL pointer dereference bug
If native HTTP is disabled but HTTPS is enabled and status page enabled
too, Core/HTTP crashes while loading. 'global_http_server' references
to NULL, but the status page tries to dereference it.

The patch adds a check for HTTP is enabled.

ASTERISK-30379 #close

Change-Id: I11b02fc920b72aaed9c809fc43210523ccfdc249
2023-01-03 09:55:42 -06:00
Holger Hans Peter Freyther 3d9b9a2b16 res_http_media_cache: Do not crash when there is no extension
Do not crash when a URL has no path component as in this case the
ast_uri_path function will return NULL. Make the code cope with not
having a path.

The below would crash
> media cache create http://google.com /tmp/foo.wav

Thread 1 "asterisk" received signal SIGSEGV, Segmentation fault.
0x0000ffff836616cc in strrchr () from /lib/aarch64-linux-gnu/libc.so.6
(gdb) bt
 #0  0x0000ffff836616cc in strrchr () from /lib/aarch64-linux-gnu/libc.so.6
 #1  0x0000ffff43d43a78 in file_extension_from_string (str=<optimized out>, buffer=buffer@entry=0xffffca9973c0 "",
    capacity=capacity@entry=64) at res_http_media_cache.c:288
 #2  0x0000ffff43d43bac in file_extension_from_url_path (bucket_file=bucket_file@entry=0x3bf96568,
    buffer=buffer@entry=0xffffca9973c0 "", capacity=capacity@entry=64) at res_http_media_cache.c:378
 #3  0x0000ffff43d43c74 in bucket_file_set_extension (bucket_file=bucket_file@entry=0x3bf96568) at res_http_media_cache.c:392
 #4  0x0000ffff43d43d10 in bucket_file_run_curl (bucket_file=0x3bf96568) at res_http_media_cache.c:555
 #5  0x0000ffff43d43f74 in bucket_http_wizard_create (sorcery=<optimized out>, data=<optimized out>, object=<optimized out>)
    at res_http_media_cache.c:613
 #6  0x0000000000487638 in bucket_file_wizard_create (sorcery=<optimized out>, data=<optimized out>, object=<optimized out>)
    at bucket.c:191
 #7  0x0000000000554408 in sorcery_wizard_create (object_wizard=object_wizard@entry=0x3b9f0718,
    details=details@entry=0xffffca9974a8) at sorcery.c:2027
 #8  0x0000000000559698 in ast_sorcery_create (sorcery=<optimized out>, object=object@entry=0x3bf96568) at sorcery.c:2077
 #9  0x00000000004893a4 in ast_bucket_file_create (file=file@entry=0x3bf96568) at bucket.c:727
 #10 0x00000000004f877c in ast_media_cache_create_or_update (uri=0x3bfa1103 "https://google.com",
    file_path=0x3bfa1116 "/tmp/foo.wav", metadata=metadata@entry=0x0) at media_cache.c:335
 #11 0x00000000004f88ec in media_cache_handle_create_item (e=<optimized out>, cmd=<optimized out>, a=0xffffca9976b8)
    at media_cache.c:640

ASTERISK-30375 #close

Change-Id: I6a9433688cb5d3d4be8758b7642d923bdde6c273
2023-01-03 09:37:02 -06:00
George Joseph d454801c2d res_rtp_asterisk: Asterisk Media Experience Score (MES)
This module has been updated to provide additional
quality statistics in the form of an Asterisk
Media Experience Score.  The score is avilable using
the same mechanisms you'd use to retrieve jitter, loss,
and rtt statistics.  For more information about the
score and how to retrieve it, see
https://wiki.asterisk.org/wiki/display/AST/Media+Experience+Score

* Updated chan_pjsip to set quality channel variables when a
  call ends.
* Updated channels/pjsip/dialplan_functions.c to add the ability
  to retrieve the MES along with the existing rtcp stats when
  using the CHANNEL dialplan function.
* Added the ast_debug_rtp_is_allowed and ast_debug_rtcp_is_allowed
  checks for debugging purposes.
* Added several function to time.h for manipulating time-in-samples
  and times represented as double seconds.
* Updated rtp_engine.c to pass through the MES when stats are
  requested.  Also debug output that dumps the stats when an
  rtp instance is destroyed.
* Updated res_rtp_asterisk.c to implement the calculation of the
  MES.  In the process, also had to update the calculation of
  jitter.  Many debugging statements were also changed to be
  more informative.
* Added a unit test for internal testing.  The test should not be
  run during normal operation and is disabled by default.

ASTERISK-30280

Change-Id: I458cb9a311e8e5dc1db769b8babbcf2e093f107a
2023-01-03 07:54:54 -06:00
Naveen Albert cc8d9b947b pbx_app: Update outdated pbx_exec channel snapshots.
pbx_exec makes a channel snapshot before executing applications.
This doesn't cause an issue during normal dialplan execution
where pbx_exec is called over and over again in succession.
However, if pbx_exec is called "one off", e.g. using
ast_pbx_exec_application, then a channel snapshot never ends
up getting made after the executed application returns, and
inaccurate snapshot information will linger for a while, causing
"core show channels", etc. to show erroneous info.

This is fixed by manually making a channel snapshot at the end
of ast_pbx_exec_application, since we anticipate that pbx_exec
might not get called again immediately.

ASTERISK-30367 #close

Change-Id: I2a5131053aa9d11badbc0ef2ef40b1f83d0af086
2022-12-22 09:19:55 -05:00
Naveen Albert c7598ee947 res_pjsip_session: Use Caller ID for extension matching.
Currently, there is no Caller ID available to us when
checking for an extension match when handling INVITEs.
As a result, extension patterns that depend on the Caller ID
are not matched and calls may be incorrectly rejected.

The Caller ID is not available because the supplement that
adds Caller ID to the session does not execute until after
this check. Supplement callbacks cannot yet be executed
at this point since the session is not yet in the appropriate
state.

To fix this without impacting existing behavior, the Caller ID
number is now retrieved before attempting to pattern match.
This ensures pattern matching works correctly and there is
no behavior change to the way supplements are called.

ASTERISK-28767 #close

Change-Id: Iec7f5a3b90e51b65ccf74342f96bf80314b7cfc7
2022-12-20 14:13:15 -06:00
Ben Ford 881faf544f res_pjsip_sdp_rtp.c: Use correct timeout when put on hold.
When a call is put on hold and it has moh_passthrough and rtp_timeout
set on the endpoint, the wrong timeout will be used. rtp_timeout_hold is
expected to be used, but rtp_timeout is used instead. This change adds a
couple of checks for locally_held to determine if rtp_timeout_hold needs
to be used instead of rtp_timeout.

ASTERISK-30350

Change-Id: I7b106fc244332014216d12bba851cefe884cc25f
2022-12-20 09:38:05 -06:00
Naveen Albert 20d4775d0a app_voicemail_odbc: Fix string overflow warning.
Fixes a negative offset warning by initializing
the buffer to empty.

Additionally, although it doesn't currently complain
about it, the size of a buffer is increased to
accomodate the maximum size contents it could have.

ASTERISK-30240 #close

Change-Id: I8eecedf14d3f2a75864797f802277cac89a32877
2022-12-20 08:57:32 -06:00
Naveen Albert cbb1fd2cb9 func_callerid: Warn about invalid redirecting reason.
Currently, if a user attempts to set a Caller ID related
function to an invalid value, a warning is emitted,
except for when setting the redirecting reason.
We now emit a warning if we were unable to successfully
parse the user-provided reason.

ASTERISK-30332 #close

Change-Id: Ic341f5d5f7303b6f1115549be64db58a85944f5a
2022-12-20 08:53:25 -06:00
Igor Goncharovsky 115a1b4f0a res_pjsip: Fix path usage in case dialing with '@'
Fix aor lookup on sip path addition. Issue happens in case of dialing
with @ and overriding user part of RURI.

ASTERISK-30100 #close
Reported-by: Yury Kirsanov

Change-Id: I3f2c42a583578c94397b113e32ca3ebf2d600e13
2022-12-20 08:52:49 -06:00
Peter Fern 58404b5c22 streams: Ensure that stream is closed in ast_stream_and_wait on error
When ast_stream_and_wait returns an error (for example, when attempting
to stream to a channel after hangup) the stream is not closed, and
callers typically do not check the return code. This results in leaking
file descriptors, leading to resource exhaustion.

This change ensures that the stream is closed in case of error.

ASTERISK-30198 #close
Reported-by: Julien Alie

Change-Id: Ie46b67314590ad75154595a3d34d461060b2e803
2022-12-20 08:51:42 -06:00
Naveen Albert 36bea9ad33 app_sendtext: Remove references to removed applications.
Removes see-also references to applications that don't
exist anymore (removed in Asterisk 19),
so these dead links don't show up on the wiki.

ASTERISK-30347 #close

Change-Id: I9539bc30f57cd65aa4e2d5ce8185eafa09567909
2022-12-20 08:19:37 -06:00
Asterisk Development Team fefc236e7c Update CHANGES and UPGRADE.txt for 20.1.0 2022-12-15 07:40:01 -05:00
Alexandre Fournier 01b3962201 res_geoloc: fix NULL pointer dereference bug
The `ast_geoloc_datastore_add_eprofile` function does not return 0 on
success, it returns the size of the underlying datastore. This means
that the datastore will be freed and its pointer set to NULL when no
error occured at all.

ASTERISK-30346

Change-Id: Iea9b209bd1244cc57b903b9496cb680c356e4bb9
2022-12-13 10:55:50 -06:00
Joshua C. Colp b6855755ce res_pjsip_aoc: Don't assume a body exists on responses.
When adding AOC to an outgoing response the code
assumed that a body would exist for comparing the
Content-Type. This isn't always true.

The code now checks to make sure the response has
a body before checking the Content-Type.

ASTERISK-21502

Change-Id: Iaead371434fc3bc693dad487228106a7d7a5ac76
2022-12-13 10:52:58 -06:00
Naveen Albert 2f9cdfbc50 app_if: Fix format truncation errors.
Fixes format truncation warnings in gcc 12.2.1.

ASTERISK-30349 #close

Change-Id: I42be4edf0284358b906e765d1966b6b9d66e1d3c
2022-12-13 08:18:08 -05:00
Michael Kuron 5c114dcb4a manager: AOC-S support for AOCMessage
ASTERISK-21502

Change-Id: I051b778f8c862d3b4794d28f2f3d782316707b08
2022-12-09 07:59:21 -06:00
Michael Kuron fee9012fe1 res_pjsip_aoc: New module for sending advice-of-charge with chan_pjsip
chan_sip supported sending AOC-D and AOC-E information in SIP INFO
messages in an "AOC" header in a format that was originally defined by
Snom. In the meantime, ETSI TS 124 647 introduced an XML-based AOC
format that is supported by devices from multiple vendors, including
Snom phones with firmware >= 8.4.2 (released in 2010).

This commit adds a new res_pjsip_aoc module that inserts AOC information
into outgoing messages or sends SIP INFO messages as described below.
It also fixes a small issue in res_pjsip_session which didn't always
call session supplements on outgoing_response.

* AOC-S in the 180/183/200 responses to an INVITE request
* AOC-S in SIP INFO (if a 200 response has already been sent or if the
  INVITE was sent by Asterisk)
* AOC-D in SIP INFO
* AOC-D in the 200 response to a BYE request (if the client hangs up)
* AOC-D in a BYE request (if Asterisk hangs up)
* AOC-E in the 200 response to a BYE request (if the client hangs up)
* AOC-E in a BYE request (if Asterisk hangs up)

The specification defines one more, AOC-S in an INVITE request, which
is not implemented here because it is not currently possible in
Asterisk to have AOC data ready at this point in call setup. Once
specifying AOC-S via the dialplan or passing it through from another
SIP channel's INVITE is possible, that might be added.

The SIP INFO requests are sent out immediately when the AOC indication
is received. The others are inserted into an appropriate outgoing
message whenever that is ready to be sent. In the latter case, the XML
is stored in a channel variable at the time the AOC indication is
received. Depending on where the AOC indications are coming from (e.g.
PRI or AMI), it may not always be possible to guarantee that the AOC-E
is available in time for the BYE.

Successfully tested AOC-D and both variants of AOC-E with a Snom D735
running firmware 10.1.127.10. It does not appear to properly support
AOC-S however, so that could only be tested by inspecting SIP traces.

ASTERISK-21502 #close
Reported-by: Matt Jordan <mjordan@digium.com>

Change-Id: Iebb7ad0d5f88526bc6629d3a1f9f11665434d333
2022-12-09 07:57:21 -06:00
Joshua C. Colp 564349ff5d ari: Destroy body variables in channel create.
When passing a JSON body to the 'create' channel route
it would be converted into Asterisk variables, but never
freed resulting in a memory leak.

This change makes it so that the variables are freed in
all cases.

ASTERISK-30344

Change-Id: I924dbd866a01c6073e2d6fb846ccaa27ef72d49d
2022-12-09 06:48:54 -06:00
Naveen Albert b9c031c1f8 app_voicemail: Fix missing email in msg_create_from_file.
msg_create_from_file currently does not dispatch emails,
which means that applications using this function, such
as MixMonitor, will not trigger notifications to users
(only AMI events are sent our currently). This is inconsistent
with other ways users can receive voicemail.

This is fixed by adding an option that attempts to send
an email and falling back to just the notifications as
done now if that fails. The existing behavior remains
the default.

ASTERISK-30283 #close

Change-Id: I597cbb9cf971a18d8776172b26ab187dc096a5c7
2022-12-09 06:45:16 -06:00
Marcel Wagner 58534b309f res_pjsip: Fix typo in from_domain documentation
This fixes a small typo in the from_domain documentation on the endpoint documentation

ASTERISK-30328 #close

Change-Id: Ia6f0897c3f5cab899ef2cde6b3ac07265b8beb21
2022-12-09 06:44:07 -06:00
Naveen Albert 531eacd6c9 res_hep: Add support for named capture agents.
Adds support for the capture agent name field
of the Homer protocol to Asterisk by allowing
users to specify a name that will be sent to
the HEP server.

ASTERISK-30322 #close

Change-Id: I6136583017f9dd08daeb8be02f60fb8df4639a2b
2022-12-08 21:31:42 -06:00
Naveen Albert b365ea8601 app_if: Adds conditional branch applications
Adds the If, ElseIf, Else, ExitIf, and EndIf
applications for conditional execution
of a block of dialplan, similar to the While,
EndWhile, and ExitWhile applications. The
appropriate branch is executed at most once
if available and may be broken out of while
inside.

ASTERISK-29497

Change-Id: I3aa3bd35a5add82465c6ee9bd86b64601f0e1f49
2022-12-08 13:57:57 -06:00
Naveen Albert 0d6003fa9a res_pjsip_session.c: Map empty extensions in INVITEs to s.
Some SIP devices use an empty extension for PLAR functionality.

Rather than rejecting these empty extensions, we now use the s
extension for such calls to mirror the existing PLAR functionality
in Asterisk (e.g. chan_dahdi).

ASTERISK-30265 #close

Change-Id: I0861a405cd49bbbf532b52f7b47f0e2810832590
2022-12-08 13:56:38 -06:00
Marcel Wagner b83af13f65 res_pjsip: Update contact_user to point out default
Updates the documentation for the 'contact_user' field to point out the
default outbound contact if no contact_user is specified 's'

ASTERISK-30316 #close

Change-Id: I61f24fb9164e4d07e05908a2511805281874c876
2022-12-08 12:39:46 -06:00
Naveen Albert 80e6205bb0 res_adsi: Fix major regression caused by media format rearchitecture.
The commit that rearchitected media formats,
a2c912e997 (ASTERISK_23114)
introduced a regression by improperly translating code in res_adsi.c.
In particular, the pointer to the frame buffer was initialized
at the top of adsi_careful_send, rather than dynamically updating it
for each frame, as is required.

This resulted in the first frame being repeatedly sent,
rather than advancing through the frames.
This corrupted the transmission of the CAS to the CPE,
which meant that CPE would never respond with the DTMF acknowledgment,
effectively completely breaking ADSI functionality.

This issue is now fixed, and ADSI now works properly again.

ASTERISK-29793 #close

Change-Id: Icdeddf733eda2981c98712d1ac9cddc0db507dbe
2022-12-08 12:37:12 -06:00
Naveen Albert 406143ae61 res_pjsip_header_funcs: Add custom parameter support.
Adds support for custom URI and header parameters
in the From header in PJSIP. Parameters can be
both set and read using this function.

ASTERISK-30150 #close

Change-Id: Ifb1bc3c512ad5f6faeaebd7817f004a2ecbd6428
2022-12-08 12:25:26 -06:00
Naveen Albert 83eb113e0f func_presencestate: Fix invalid memory access.
When parsing information from AstDB while loading,
it is possible that certain pointers are never
set, which leads to invalid memory access and
then, fatally, invalid free attempts on this memory.
We now initialize to NULL to prevent this.

ASTERISK-30311 #close

Change-Id: I6120681d04fd2c12a9473f35ce95a1f8e74e3929
2022-12-08 10:21:26 -06:00
Naveen Albert b90e57758b sig_analog: Fix no timeout duration.
ASTERISK_28702 previously attempted to fix an
issue with flash hook hold timing out after
just under 17 minutes, when it should have never
been timing out. It fixed this by changing 999999
to INT_MAX, but it did so in chan_dahdi, which
is the wrong place since ss_thread is now in
sig_analog and the one in chan_dahdi is mostly
dead code.

This fixes this by porting the fix to sig_analog.

ASTERISK-30336 #close

Change-Id: I05eb69cc0b5319d357842a70bd26ef64d145cb15
2022-12-08 10:13:47 -06:00
Naveen Albert 52c7d3ed07 xmldoc: Allow XML docs to be reloaded.
The XML docs are currently only loaded on
startup with no way to update them during runtime.
This makes it impossible to load modules that
use ACO/Sorcery (which require documentation)
if they are added to the source tree and built while
Asterisk is running (e.g. external modules).

This adds a CLI command to reload the XML docs
during runtime so that documentation can be updated
without a full restart of Asterisk.

ASTERISK-30289 #close

Change-Id: I4f265b0e5517e757c5453a0f241201a5788d3a07
2022-12-08 09:17:26 -06:00
Naveen Albert a4bcdce1db rtp_engine.h: Update examples using ast_format_set.
This file includes some doxygen comments referencing
ast_format_set. This is an obsolete API that was
removed years back, but documentation was not fully
updated to reflect that. These examples are
updated to the current way of doing things
(using the format cache).

ASTERISK-30327 #close

Change-Id: I570f3b8007fa17ba470cc7117f44bfe7c555d2f7
2022-12-08 09:17:18 -06:00
Naveen Albert 691178c48e app_mixmonitor: Add option to use real Caller ID for voicemail.
MixMonitor currently uses the Connected Line as the Caller ID
for voicemails. This is due to the implementation being written
this way for use with Digium phones. However, in general this
is not correct for generic usage in the dialplan, and people
may need the real Caller ID instead. This adds an option to do that.

ASTERISK-30286 #close

Change-Id: I3d0ce76dfe75e2a614e0f709ab27acbd2478267c
2022-12-08 08:04:35 -06:00
Ben Ford d476994768 pjproject: 2.13 security fixes
Backports two security fixes (c4d3498 and 450baca) from pjproject 2.13.

ASTERISK-30338

Change-Id: I86fdc003d5d22cb66e7cc6dc3313a8194f27eb69
2022-12-03 10:26:40 -06:00
George Joseph 7684c9e907 pjsip_transport_events: Fix possible use after free on transport
It was possible for a module that registered for transport monitor
events to pass in a pjsip_transport that had already been freed.
This caused pjsip_transport_events to crash when looking up the
monitor for the transport.  The fix is a two pronged approach.

1. We now increment the reference count on pjsip_transports when we
create monitors for them, then decrement the count when the
transport is going to be destroyed.

2. There are now APIs to register and unregister monitor callbacks
by "transport key" which is a string concatenation of the remote ip
address and port.  This way the module needing to monitor the
transport doesn't have to hold on to the transport object itself to
unregister.  It just has to save the transport_key.

* Added the pjsip_transport reference increment and decrement.

* Changed the internal transport monitor container key from the
  transport->obj_name (which may not be unique anyway) to the
  transport_key.

* Added a helper macro AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR() that
  fills a buffer with the transport_key using a passed-in
  pjsip_transport.

* Added the following functions:
  ast_sip_transport_monitor_register_key
  ast_sip_transport_monitor_register_replace_key
  ast_sip_transport_monitor_unregister_key
  and marked their non-key counterparts as deprecated.

* Updated res_pjsip_pubsub and res_pjsip_outbound_register to use
  the new "key" monitor functions.

NOTE: res_pjsip_registrar also uses the transport monitor
functionality but doesn't have a persistent object other than
contact to store a transport key.  At this time, it continues to
use the non-key monitor functions.

ASTERISK-30244

Change-Id: I1a20baf2a8643c272dcf819871d6c395f148f00b
2022-12-03 10:24:36 -06:00
Mike Bradeen 81f10e847e manager: prevent file access outside of config dir
Add live_dangerously flag to manager and use this flag to
determine if a configuation file outside of AST_CONFIG_DIR
should be read.

ASTERISK-30176

Change-Id: I46b26af4047433b49ae5c8a85cb8cda806a07404
2022-12-03 10:22:18 -06:00
Mike Bradeen eb1d7ab53c ooh323c: not checking for IE minimum length
When decoding q.931 encoded calling/called number
now checking for length being less than minimum required.

ASTERISK-30103

Change-Id: I3dcfce0f35eca258dc450f87c92d4d7af402c2e7
2022-12-01 11:11:42 -06:00
Naveen Albert c7df5ee7c1 pbx_builtins: Allow Answer to return immediately.
The Answer application currently waits for up to 500ms
for media, even if users specify a different timeout.

This adds an option to not wait for media on the channel
by doing a raw answer instead. The default 500ms threshold
is also documented.

ASTERISK-30308 #close

Change-Id: Id59cd340c44b8b8b2384c479e17e5123e917cba4
2022-11-29 09:23:49 -06:00
Naveen Albert 5ede4e217a chan_dahdi: Allow FXO channels to start immediately.
Currently, chan_dahdi will wait for at least one
ring before an incoming call can enter the dialplan.
This is generally necessary in order to receive
the Caller ID spill and/or distinctive ringing
detection.

However, if neither of these is required, then there
is nothing gained by waiting for one ring and this
unnecessarily delays call setup. Users can now
use immediate=yes to make FXO channels (FXS signaled)
begin processing dialplan as soon as Asterisk receives
the call.

ASTERISK-30305 #close

Change-Id: I20818b370b2e4892c7f40c8a8753fa06a81750b5
2022-11-29 08:29:21 -06:00
Maximilian Fridrich 60b81eabe0 core & res_pjsip: Improve topology change handling.
This PR contains two relatively separate changes in channel.c and
res_pjsip_session.c which ensure that topology changes are not ignored
in cases where they should be handled.

For channel.c:

The function ast_channel_request_stream_topology_change only triggers a
stream topology request change indication, if the channel's topology
does not equal the requested topology. However, a channel could be in a
state where it is currently "negotiating" a new topology but hasn't
updated it yet, so the topology request change would be lost. Channels
need to be able to handle such situations internally and stream
topology requests should therefore always be passed on.

In the case of chan_pjsip for example, it queues a session refresh
(re-INVITE) if it is currently in the middle of a transaction or has
pending requests (among other reasons).

Now, ast_channel_request_stream_topology_change always indicates a
stream topology request change even if the requested topology equals the
channel's topology.

For res_pjsip_session.c:

The function resolve_refresh_media_states does not process stream state
changes if the delayed active state differs from the current active
state. I.e. if the currently active stream state has changed between the
time the sip session refresh request was queued and the time it is being
processed, the session refresh is ignored. However, res_pjsip_session
contains logic that ensures that session refreshes are queued and
re-queued correctly if a session refresh is currently not possible. So
this check is not necessary and led to some session refreshes being
lost.

Now, a session refresh is done even if the delayed active state differs
from the current active state and it is checked whether the delayed
pending state differs from the current active - because that means a
refresh is necessary.

Further, the unit test of resolve_refresh_media_states was adapted to
reflect the new behavior. I.e. the changes to delayed pending are
prioritized over the changes to current active because we want to
preserve the original intention of the pending state.

ASTERISK-30184

Change-Id: Icd0703295271089057717006730b555b9a1d4e5a
2022-11-29 08:23:49 -06:00
Naveen Albert 2efa290d3c sla: Prevent deadlock and crash due to autoservicing.
SLAStation currently autoservices the station channel before
creating a thread to actually dial the trunk. This leads
to duplicate servicing of the channel which causes assertions,
deadlocks, crashes, and moreover not the correct behavior.

Removing the autoservice prevents the crash, but if the station
hangs up before the trunk answers, the call hangs since the hangup
was never serviced on the channel.

This is fixed by not autoservicing the channel, but instead
servicing it in the thread dialing the trunk, since it is doing
so synchronously to begin with. Instead of sleeping for 100ms
in a loop, we simply use the channel for timing, and abort
if it disappears.

The same issue also occurs with SLATrunk when a call is answered,
because ast_answer invokes ast_waitfor_nandfds. Thus, we use
ast_raw_answer instead which does not cause any conflict and allows
the call to be answered normally without thread blocking issues.

ASTERISK-29998 #close

Change-Id: Icc237d50354b5910000d2305901e86d2c87bb9d8
2022-11-28 08:54:30 -06:00
Jaco Kroon ce2153fc5a Build system: Avoid executable stack.
Found in res_geolocation, but I believe others may have similar issues,
thus not linking to a specific issue.

Essentially gcc doesn't mark the stack for being non-executable unless
it's compiling the source, this informs ld via gcc to mark the object as
not requiring an executable stack (which a binary blob obviously
doesn't).

ASTERISK-30321

Change-Id: I71bcc2fd1fe0c82a28b3257405d6f2b566fd9bfc
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
2022-11-21 08:52:49 -06:00
Naveen Albert 002afc3f2a func_json: Fix memory leak.
A memory leak was present in func_json due to
using ast_json_free, which just calls ast_free,
as opposed to recursively freeing the JSON
object as needed. This is now fixed to use the
right free functions.

ASTERISK-30293 #close

Change-Id: I982324dde841dc9147c8d8ad35c8719daf418b49
2022-11-21 08:29:40 -06:00
Naveen Albert 1e77b8c473 test_json: Remove duplicated static function.
Removes the function mkstemp_file and uses
ast_file_mkftemp from file.h instead.

ASTERISK-30295 #close

Change-Id: I7412ec06f88c39ee353bcdb8c976c2fcac546609
2022-11-21 07:43:38 -06:00
Joshua C. Colp 61922d2934 res_agi: Respect "transmit_silence" option for "RECORD FILE".
The "RECORD FILE" command in res_agi has its own
implementation for actually doing the recording. This
has resulted in it not actually obeying the option
"transmit_silence" when recording.

This change causes it to now send silence if the
option is enabled.

ASTERISK-30314

Change-Id: Ib3a85601ff35d1b904f836691bad8a4b7e957174
2022-11-16 06:43:41 -05:00
Naveen Albert 6e59b01e1a app_mixmonitor: Add option to delete files on exit.
Adds an option that allows MixMonitor to delete
its copy of any recording files before exiting.

This can be handy in conjunction with options
like m, which copy the file elsewhere, and the
original files may no longer be needed.

ASTERISK-30284 #close

Change-Id: Ida093679c67e300efc154a97b6d8ec0f104e581e
2022-11-08 13:46:50 -06:00
Naveen Albert 49cfdbbdff manager: Update ModuleCheck documentation.
The ModuleCheck XML documentation falsely
claims that the module's version number is returned.
This has not been the case since 14, since the version
number is not available anymore, but the documentation
was not changed at the time. It is now updated to
reflect this.

ASTERISK-30285 #close

Change-Id: Idde2d1205a11f2623fa1ddab192faa3dc4081e91
2022-11-08 08:16:53 -06:00
Naveen Albert 8142b313c3 file.c: Don't emit warnings on winks.
Adds an ignore case for wink since it should
pass through with no warning.

ASTERISK-30290 #close

Change-Id: Ieb7e34daa717357ac5c93efb0059f6c2321f16ad
2022-11-06 11:51:02 -05:00
George Joseph 0c1c623dee runUnittests.sh: Save coredumps to proper directory
Fixed the specification of "outputdir" when calling ast_coredumper
so the txt files are saved in the correct place.

ASTERISK-30282

Change-Id: Ic631cb90c1e4c29d970c982dff45fda5e0eb15b6
2022-11-02 12:02:55 -05:00
Naveen Albert dfe2f38642 app_stack: Print proper exit location for PBXless channels.
When gosub is executed on channels without a PBX, the context,
extension, and priority are initialized to the channel driver's
default location for that endpoint. As a result, the last Return
will restore this location and the Gosub logs will print out bogus
information about our exit point.

To fix this, on channels that don't have a PBX, the execution
location is left intact on the last return if there are no
further stack frames left. This allows the correct location
to be printed out to the user, rather than the bogus default
context.

ASTERISK-30076 #close

Change-Id: I1d42a99c9aa9e3708d32718863175158a894e414
2022-11-02 10:50:27 -05:00
George Joseph f723b465e5 chan_rtp: Make usage of ast_rtp_instance_get_local_address clearer
unicast_rtp_request() was setting the channel variables like this:

pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_ADDRESS",
    ast_sockaddr_stringify_addr(&local_address));
ast_rtp_instance_get_local_address(instance, &local_address);
pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_PORT",
    ast_sockaddr_stringify_port(&local_address));

...which made it appear that UNICASTRTP_LOCAL_ADDRESS was being
set before local_address was set.  In fact, the address part of
local_address was set earlier in the function, just not the port.
This was confusing however so ast_rtp_instance_get_local_address()
is now being called before setting UNICASTRTP_LOCAL_ADDRESS.

ASTERISK-30281

Change-Id: I872ac49477100f4eb33891d46efc6ca21ec81aa4
2022-11-02 08:55:51 -05:00
Mike Bradeen 50e2921a48 res_pjsip: prevent crash on websocket disconnect
When a websocket (or potentially any stateful connection) is quickly
created then destroyed, it is possible that the qualify thread will
destroy the transaction before the initialzing thread is finished
with it.

Depending on the timing, this can cause an assertion within pjsip.

To prevent this, ast_send_stateful_response will now create the group
lock and add a reference to it before creating the transaction.

While this should resolve the crash, there is still the potential that
the contact will not be cleaned up properly, see:ASTERISK~29286. As a
result, the contact has to 'time out' before it will be removed.

ASTERISK-28689

Change-Id: Id050fded2247a04d8f0fc5b8a2cf3e5482cb8cee
2022-10-31 10:09:39 -05:00
Naveen Albert afd86b47c1 tcptls: Prevent crash when freeing OpenSSL errors.
write_openssl_error_to_log has been erroneously
using ast_free instead of free, which will
cause a crash when MALLOC_DEBUG is enabled since
the memory was not allocated by Asterisk's memory
manager. This changes it to use the actual free
function directly to avoid this.

ASTERISK-30278 #close

Change-Id: Iac8b6468b718075809c45d8ad16b101af21a474d
2022-10-31 09:41:52 -05:00
Igor Goncharovsky 096529d33f res_pjsip_outbound_registration: Allow to use multiple proxies for registration
Current registration code use pjsip_parse_uri to verify outbound_proxy
that is different from the reading this option for the endpoint. This
made value with multiple proxies invalid for registration pjsip settings.
Removing URI validation helps to use registration through multiple proxies.

ASTERISK-30217 #close

Change-Id: I064558e66f04b9f3260c46181812a01349761357
2022-10-28 11:38:41 -05:00
Naveen Albert ca8900b0f6 tests: Fix compilation errors on 32-bit.
Fix compilation errors caused by using size_t
instead of uintmax_t and non-portable format
specifiers.

ASTERISK-30273 #close

Change-Id: I363e6057ef84d54b88af80d23ad6147eef9216ee
2022-10-27 14:29:45 -05:00
Henning Westerholt 12445040d3 res_pjsip: return all codecs on a re-INVITE without SDP
Currently chan_pjsip on receiving a re-INVITE without SDP will only
return the codecs that are previously negotiated and not offering
all enabled codecs.

This causes interoperability issues with different equipment (e.g.
from Cisco) for some of our customers and probably also in other
scenarios involving 3PCC infrastructure.

According to RFC 3261, section 14.2 we SHOULD return all codecs
on a re-INVITE without SDP

The PR proposes a new parameter to configure this behaviour:
all_codecs_on_empty_reinvite. It includes the code, documentation,
alembic migrations, CHANGES file and example configuration additions.

ASTERISK-30193 #close

Change-Id: I69763708d5039d512f391e296ee8a4d43a1e2148
2022-10-27 11:22:20 -05:00
Naveen Albert 40b52322e5 res_pjsip_notify: Add option support for AMI.
The PJSIP notify CLI commands allow for using
"options" configured in pjsip_notify.conf.

This allows these same options to be used in
AMI actions as well.

Additionally, as part of this improvement,
some repetitive common code is refactored.

ASTERISK-30263 #close

Change-Id: Ie4496b322b63b61eaf9672183a959ab99a04b6b5
2022-10-27 10:07:20 -05:00
Naveen Albert c32b39d123 res_pjsip_logger: Add method-based logging option.
Expands the pjsip logger to support the ability to filter
by SIP message method. This can make certain types of SIP debugging
easier by only logging messages of particular method(s).

ASTERISK-30146 #close

Co-authored-by: Sean Bright <sean@seanbright.com>
Change-Id: I9c8cbb6fc8686ef21190eb42e08bc9a9b147707f
2022-10-27 09:00:29 -05:00
Frederic LE FOLL 50a4495799 Dialing API: Cancel a running async thread, may not cancel all calls
race condition: ast_dial_join() may not cancel outgoing call, if
function is called just after called party answer and before
application execution (bit is_running_app not yet set).

This fix adds ast_softhangup() calls in addition to existing
pthread_kill() when is_running_app is not set.

ASTERISK-30258

Change-Id: Idbdd5c15122159661aa8e996a42d5800083131e4
2022-10-27 07:52:12 -05:00
Naveen Albert 180ca32565 chan_dahdi: Fix unavailable channels returning busy.
This fixes dahdi_request to properly set the cause
code to CONGESTION instead of BUSY if no channels
were actually available.

Currently, the cause is erroneously set to busy
if the channel itself is found, regardless of its
current state. However, if the channel is not available
(e.g. T1 down, card not operable, etc.), then the
channel itself may not be in a functional state,
in which case CHANUNAVAIL is the correct cause to use.

This adds a simple check to ensure that busy tone
is only returned if a channel is encountered that
has an owner, since that is the only possible way
that a channel could actually be busy.

ASTERISK-30274 #close

Change-Id: Iad5870223c081240c925b19df8d6af136953b994
2022-10-26 11:14:25 -05:00
Naveen Albert 9258d8212a res_pjsip_pubsub: Prevent removing subscriptions.
pjproject does not provide any mechanism of removing
event packages, which means that once a subscription
handler is registered, it is effectively permanent.

pjproject will assert if the same event package is
ever registered again, so currently unloading and
loading any Asterisk modules that use subscriptions
will cause a crash that is beyond our control.

For that reason, we now prevent users from being
able to unload these modules, to prevent them
from ever being loaded twice.

ASTERISK-30264 #close

Change-Id: I7fdcb1a5e44d38b7ba10c44259fe98f0ae9bc12c
2022-10-26 09:08:17 -05:00
Naveen Albert 407216a0a5 say: Don't prepend ampersand erroneously.
Some logic in say.c for determining if we need
to also add an ampersand for file seperation was faulty,
as non-successful files would increment the count, causing
a leading ampersand to be added improperly.

This is fixed, and a unit test that captures this regression
is also added.

ASTERISK-30248 #close

Change-Id: I02c1d3a11d82fe4ea8b462070cbd1effb5834d2b
2022-10-26 07:48:17 -05:00
Philip Prindeville d0bea5a725 res_crypto: handle unsafe private key files
ASTERISK-30213 #close

Change-Id: I4a77143d41615b7c4fc25bb1251c0a9cb87b417a
2022-10-14 10:01:06 -05:00
Mike Bradeen 907d7e7d7d audiohook: add directional awareness
Add enum to allow setting optional direction. If set to only one
direction, only feed matching-direction frames to the associated
slin factory.

This prevents mangling the transcoder on non-mixed frames when the
READ and WRITE frames would have otherwise required it.  Also
removes the need to mute or discard the un-wanted frames as they
are no longer added in the first place.

res_stasis_snoop is changed to use this addition to set direction
on audiohook based on spy direction.

If no direction is set, the ast_audiohook_init will init this enum
to BOTH which maintains existing functionality.

ASTERISK-30252

Change-Id: If8716bad334562a5d812be4eeb2a92e4f3be28eb
2022-10-11 08:13:18 -05:00
Naveen Albert b331caca30 cdr: Allow bridging and dial state changes to be ignored.
Allows bridging, parking, and dial messages to be globally
ignored for all CDRs such that only a single CDR record
is generated per channel.

This is useful when CDRs should endure for the lifetime of
an entire channel and bridging and dial updates in the
dialplan should not result in multiple CDR records being
created for the call. With the ignore bridging option,
bridging changes have no impact on the channel's CDRs.
With the ignore dial state option, multiple Dials and their
outcomes have no impact on the channel's CDRs. The
last disposition on the channel is preserved in the CDR,
so the actual disposition of the call remains available.

These two options can reduce the amount of "CDR hacks" that
have hitherto been necessary to ensure that CDR was not
"spoiled" by these messages if that was undesired, such as
putting a dummy optimization-disabled local channel between
the caller and the actual call and putting the CDR on the channel
in the middle to ensure that CDR would persist for the entire
call and properly record start, answer, and end times.
Enabling these options is desirable when calls correspond
to the entire lifetime of channels and the CDR should
reflect that.

Current default behavior remains unchanged.

ASTERISK-30091 #close

Change-Id: I393981af42732ec5ac3ff9266444abb453b7c832
2022-10-10 12:06:36 -05:00
Naveen Albert e0e7f35730 res_tonedetect: Add ringback support to TONE_DETECT.
Adds support for detecting audible ringback tone
to the TONE_DETECT function using the p option.

ASTERISK-30254 #close

Change-Id: Ie2329ff245248768367d26749c285fbe823f6414
2022-10-10 12:04:33 -05:00
Naveen Albert 98fc05f13b chan_dahdi: Resolve format truncation warning.
Fixes a format truncation warning in notify_message.

ASTERISK-30256 #close

Change-Id: I983a423c0214641ca4f8c9dfe0b19c47448fdee1
2022-10-10 10:31:13 -05:00
Philip Prindeville ef74ecacc7 res_crypto: don't modify fname in try_load_key()
"fname" is passed in as a const char *, but strstr() mangles that
into a char *, and we were attempting to modify the string in place.
This is an unwanted (and undocumented) side-effect.

ASTERISK-30213

Change-Id: Ifa36d352aafeb7f9beec3f746332865c7d21e629
2022-10-10 10:13:41 -05:00
Philip Prindeville 5e2485b5c0 res_crypto: use ast_file_read_dirs() to iterate
ASTERISK-30213

Change-Id: I115f5f8942ffcfb23cd2559a55bac8a2eba081e0
2022-10-10 10:11:15 -05:00
George Joseph 2a500b325a res_geolocation: Update wiki documentation
Also added a note to the geolocation.conf.sample file
and added a README to the res/res_geolocation/wiki
directory.

Change-Id: I89c3c5db8c0701b33127993622d5e4f904bddfbc
2022-10-10 07:31:43 -05:00
Maximilian Fridrich 0d2e140123 res_pjsip: Add mediasec capabilities.
This patch adds support for mediasec SIP headers and SDP attributes.
These are defined in RFC 3329, 3GPP TS 24.229 and
draft-dawes-sipcore-mediasec-parameter. The new features are
implemented so that a backbone for RFC 3329 is present to streamline
future work on RFC 3329.

With this patch, Asterisk can communicate with Deutsche Telekom trunks
which require these fields.

ASTERISK-30032

Change-Id: Ia7f5b5ba42db18074fdd5428c4e1838728586be2
2022-09-29 04:10:48 -05:00
Asterisk Development Team 7f80830ced Update CHANGES and UPGRADE.txt for 20.0.0 2022-09-28 07:44:57 -05:00
Holger Hans Peter Freyther 62881c668b res_prometheus: Do not crash on invisible bridges
Avoid crashing by skipping invisible bridges and checking the
snapshot for a null pointer. In effect this is how the bridges
are enumerated in res/ari/resource_bridges.c already.

ASTERISK-30239
ASTERISK-30237

Change-Id: I58ef9f44036feded5966b5fc70ae754f8182883d
2022-09-26 19:27:58 -05:00
Naveen Albert 8afb313a43 res_pjsip_geolocation: Change some notices to debugs.
If geolocation is not in use for an endpoint, the NOTICE
log level is currently spammed with messages about this,
even though nothing is wrong and these messages provide
no real value. These log messages are therefore changed
to debugs.

ASTERISK-30241 #close

Change-Id: I656b355d812f67cc0f0fdf09b00b0e1458598bb4
2022-09-26 15:03:32 -05:00
Naveen Albert 7335b0cffe db: Fix incorrect DB tree count for AMI.
The DBGetTree AMI action's ListItem previously
always reported 1, regardless of the count. This
is corrected to report the actual count.

ASTERISK-30245 #close
patches:
  gettreecount.diff submitted by Birger Harzenetter (license 5870)

Change-Id: I46d8992710f1b8524426b1255f57d1ef4a4934d4
2022-09-26 14:11:17 -05:00
Naveen Albert 407167cc28 func_logic: Don't emit warning if both IF branches are empty.
The IF function currently emits warnings if both IF branches
are empty. However, there is no actual necessity that either
branch be non-empty as, unlike other conditional applications/
functions, nothing is inherently done with IF, and both
sides could legitimately be empty. The warning is thus turned
into a debug message.

ASTERISK-30243 #close

Change-Id: I5250625dd720f95e1859b5dfb933905d7e7a730e
2022-09-26 12:20:21 -05:00
Naveen Albert a5ec60e6c6 features: Add no answer option to Bridge.
Adds the n "no answer" option to the Bridge application
so that answer supervision can not automatically
be provided when Bridge is executed.

Additionally, a mechanism (dialplan variable)
is added to prevent bridge targets (typically the
target of a masquerade) from answering the channel
when they enter the bridge.

ASTERISK-30223 #close

Change-Id: I76f73fcd8e403bcd18f2abb40c658f537ac1ba6d
2022-09-26 11:44:20 -05:00
Naveen Albert 1e29607b5c app_bridgewait: Add option to not answer channel.
Adds the n option to not answer the channel when calling
BridgeWait, so the application can be used without
forcing answer supervision.

ASTERISK-30216 #close

Change-Id: I6b85ef300b1f7b5170f8537e2b10889cc2e6605a
2022-09-26 10:41:46 -05:00
Naveen Albert 8c791f9a65 app_amd: Add option to play audio during AMD.
Adds an option that will play an audio file
to the party while AMD is running on the
channel, so the called party does not just
hear silence.

ASTERISK-30179 #close

Change-Id: I4af306274552b61b3d9f0883c33f698abd4699b6
2022-09-26 09:43:14 -05:00
Philip Prindeville 3e7ce90f9c test: initialize capture structure before freeing
ASTERISK-30232 #close

Change-Id: I2603e2cef8f93f6b0a6ef39f7eac744251bb3902
2022-09-26 09:40:26 -05:00
Naveen Albert 1ed4518328 func_export: Add EXPORT function
Adds the EXPORT function, which allows write
access to variables and functions on other
channels.

ASTERISK-29432 #close

Change-Id: I7492645ae4307553d0f586d78e13a4f586231fdf
2022-09-26 07:53:20 -05:00
Maximilian Fridrich 5bbad0d27c res_pjsip: Add 100rel option "peer_supported".
This patch adds a new option to the 100rel parameter for pjsip
endpoints called "peer_supported". When an endpoint with this option
receives an incoming request and the request indicated support for the
100rel extension, then Asterisk will send 1xx responses reliably. If
the request did not indicate 100rel support, Asterisk sends 1xx
responses normally.

ASTERISK-30158

Change-Id: Id6d95ffa8f00dab118e0b386146e99f254f287ad
2022-09-22 18:39:50 -05:00
Naveen Albert 8aae0b9f08 func_scramble: Fix null pointer dereference.
Fix segfault due to null pointer dereference
inside the audiohook callback.

ASTERISK-30220 #close

Change-Id: Ideb80f606974366e89d619d908744230b5a5a259
2022-09-22 11:26:09 -05:00
Jaco Kroon 278c5726ca manager: be more aggressive about purging http sessions.
If we find that n_max (currently hard wired to 1) sessions were purged,
schedule the next purge for 1ms into the future rather than 5000ms (as
per current).  This way we will purge up to 1000 sessions per second
rather than 1 every 5 seconds.

This mitigates a build-up of sessions should http sessions gets
established faster than 1 per 5 seconds.

Change-Id: I9820d39aa080109df44fe98c1325cafae48d54f5
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
2022-09-22 11:11:40 -05:00
Naveen Albert ab1dbfef75 func_strings: Add trim functions.
Adds TRIM, LTRIM, and RTRIM, which can be used
for trimming leading and trailing whitespace
from strings.

ASTERISK-30222 #close

Change-Id: I50fb0c40726d044a7a41939fa9026f3da4872554
2022-09-22 05:49:00 -05:00
George Joseph e25b690d10 res_crypto: Memory issues and uninitialized variable errors
ASTERISK-30235

Change-Id: Ia1e326e7b52cd06fd5e6c9009e3e63193c92f6cd
2022-09-19 05:32:32 -06:00
George Joseph e33f2dcc0f res_geolocation: Fix issues exposed by compiling with -O2
Fixed "may be used uninitialized" errors in geoloc_config.c.

ASTERISK-30234

Change-Id: I1ea336bf7abbc16fa59b75720f0db8f1d960b3d4
2022-09-16 08:42:26 -06:00
Philip Prindeville 026dc08529 res_crypto: don't complain about directories
ASTERISK-30226 #close

Change-Id: I5695fb0c9521f112f754b8362cff2a8f3eff05c5
2022-09-14 23:16:37 -06:00
Asterisk Development Team f01ed3eea4 Update CHANGES and UPGRADE.txt for 20.0.0 2022-09-14 09:25:44 -05:00
Mike Bradeen 7a44296ca9 res_pjsip: Add user=phone on From and PAID for usereqphone=yes
Adding user=phone to local-side uri's when user_eq_phone=yes is set for
an endpoint. Previously this would only add the header to the To and R-URI.

ASTERISK-30178

Change-Id: Id3bfb5d225d762e7d2668c023fe09e4541ae8600
2022-09-14 07:20:22 -05:00
George Joseph 8cbea1c7ef res_geolocation: Fix segfault when there's an empty element
Fixed a segfault caused by var_list_from_loc_info() encountering
an empty location info element.

Fixed an issue in ast_strsep() where a value with only whitespace
wasn't being preserved.

Fixed an issue in ast_variable_list_from_quoted_string() where
an empty value was considered a failure.

ASTERISK-30215
Reported by: Dan Cropp

Change-Id: Ieca64e061a6d9298f0196c694b60d986ef82613a
2022-09-13 09:51:25 -05:00
sungtae kim 80bc844fd6 res_musiconhold: Add option to not play music on hold on unanswered channels
This change adds an option, answeredonly, that will prevent music on
hold on channels that are not answered.

ASTERISK-30135

Change-Id: I1ab0defa43a29a26ae39f94c623596cf90fddc08
2022-09-13 05:46:48 -05:00
Ben Ford 881a3f2306 res_pjsip: Add TEL URI support for basic calls.
This change allows TEL URI requests to come through for basic calls. The
allowed requests are INVITE, ACK, BYE, and CANCEL. The From and To
headers will now allow TEL URIs, as well as the request URI.

Support is only for TEL URIs present in traffic from a remote party.
Asterisk does not generate any TEL URIs on its own.

ASTERISK-26894

Change-Id: If5729e6cd583be7acf666373bf9f1b9d653ec29a
2022-09-13 04:51:00 -05:00
Philip Prindeville 3e054c9ebc res_crypto: Use EVP API's instead of legacy API's
ASTERISK-30046 #close

Change-Id: I5c738756de75fd27ebad54be144c0ac6193f21b2
2022-09-12 16:19:37 -05:00
Philip Prindeville 736cdf84f4 test: Add coverage for res_crypto
We're validating the following functionality:

encrypting a block of data with RSA
decrypting a block of data with RSA
signing a block of data with RSA
verifying a signature with RSA
encrypting a block of data with AES-ECB
encrypting a block of data with AES-ECB

as well as accessing test keys from the keystore.

ASTERISK-30045 #close

Change-Id: I0d10e7b41009c5290a4356c6480e636712d5c96d
2022-09-12 16:18:19 -05:00
Philip Prindeville 2d7656cb50 res_crypto: make keys reloadable on demand for testing
ASTERISK-30045

Change-Id: If59bbb50c1771084bfe2fef307a6077c90d35ce8
2022-09-12 13:08:49 -05:00
Philip Prindeville 5809d879b0 test: Add test coverage for capture child process output
ASTERISK-30037 #close

Change-Id: I0273e85eeeb6b8e46703f24cd74d84f3daf0a69a
2022-09-12 11:23:04 -05:00
Philip Prindeville 2c4c44ca64 main/utils: allow checking for command in $PATH
ASTERISK-30037

Change-Id: I4b6f7264c8c737c476c798d2352f3232b263bbdf
2022-09-12 09:49:21 -05:00
Philip Prindeville b9df2c481b test: Add ability to capture child process output
ASTERISK-30037

Change-Id: Icbf84ce05addb197a458361c35d784e460d8d6c2
2022-09-12 08:15:27 -05:00
Philip Prindeville d13afaf302 res_crypto: Don't load non-regular files in keys directory
ASTERISK-30046

Change-Id: Ie77e0648f8b0b1c2159fb24662d1989cfd4cc36d
2022-09-12 07:55:33 -05:00
Naveen Albert 2dac2bf8dc func_frame_trace: Remove bogus assertion.
The FRAME_TRACE function currently asserts if it sees
a MASQUERADE_NOTIFY. However, this is a legitimate thing
that can happen so asserting is inappropriate, as there
are no clear negative ramifications of such a thing. This
is adjusted to be like the other frames to print out
the subclass.

ASTERISK-30210 #close

Change-Id: I8ecbdcf17e35f64bdeab42868471f581ad1d1a56
2022-09-11 18:04:59 -05:00
Naveen Albert c487425620 lock.c: Add AMI event for deadlocks.
Adds an AMI event to indicate that a deadlock
has likely started, when Asterisk is compiled
with DETECT_DEADLOCKS enabled. This can make
it easier to perform automated deadlock detection
and take appropriate action (such as doing a core
dump). Unlike the deadlock warnings, the AMI event
is emitted only once per deadlock.

ASTERISK-30161 #close

Change-Id: Ifc6ed3e390f8b4cff7f8077a50e4d7a5b54e42fb
2022-09-11 18:02:24 -05:00
Naveen Albert 205c7c8d21 app_confbridge: Add end_marked_any option.
Adds the end_marked_any option, which can be used
to kick a user from a conference if any marked user
leaves.

ASTERISK-30211 #close

Change-Id: I9e8da7ccb892e522546c0f2b5476d172e022c2f5
2022-09-11 16:22:18 -05:00
Naveen Albert 2de016b181 pbx_variables: Use const char if possible.
Use const char for char arguments to
pbx_substitute_variables_helper_full_location
that can do so (context and exten).

ASTERISK-30209 #close

Change-Id: I001357177e9c3dca2b2b4eebc5650c1095b3da6f
2022-09-11 08:33:06 -05:00
George Joseph 05f42806cc res_geolocation: Add two new options to GEOLOC_PROFILE
Added an 'a' option to the GEOLOC_PROFILE function to allow
variable lists like location_info_refinement to be appended
to instead of replacing the entire list.

Added an 'r' option to the GEOLOC_PROFILE function to resolve all
variables before a read operation and after a Set operation.

Added a few missing parameters to the ones allowed for writing
with GEOLOC_PROFILE.

Fixed a bug where calling GEOLOC_PROFILE to read a parameter
might actually update the profile object.

Cleaned up XML documentation a bit.

ASTERISK-30190

Change-Id: I75f541db43345509a2e86225bfa4cf8e242e5b6c
2022-09-10 12:54:24 -05:00
George Joseph c799db6a21 res_geolocation: Allow location parameters on the profile object
You can now specify the location object's format, location_info,
method, location_source and confidence parameters directly on
a profile object for simple scenarios where the location
information isn't common with any other profiles.  This is
mutually exclusive with setting location_reference on the
profile.

Updated appdocsxml.dtd to allow xi:include in a configObject
element.  This makes it easier to link to complete configOptions
in another object.  This is used to add the above fields to the
profile object without having to maintain the option descriptions
in two places.

ASTERISK-30185

Change-Id: Ifd5f05be0a76f0a6ad49fa28d17c394027677569
2022-09-10 12:51:02 -05:00
George Joseph 4ffc5561c4 res_geolocation: Add profile parameter suppress_empty_ca_elements
Added profile parameter "suppress_empty_ca_elements" that
will cause Civic Address elements that are empty to be
suppressed from the outgoing PIDF-LO document.

Fixed a possible SEGV if a sub-parameter value didn't have a
value.

ASTERISK-30177

Change-Id: I924ccc5aa2f45110a3155b22e53dfaf3ef2092dd
2022-09-10 11:07:51 -05:00
George Joseph 2d5a6498dd res_geolocation: Add built-in profiles
The trigger to perform outgoing geolocation processing is the
presence of a geoloc_outgoing_call_profile on an endpoint. This
is intentional so as to not leak location information to
destinations that shouldn't receive it.   In a totally dynamic
configuration scenario however, there may not be any profiles
defined in geolocation.conf.  This makes it impossible to do
outgoing processing without defining a "dummy" profile in the
config file.

This commit adds 4 built-in profiles:
  "<prefer_config>"
  "<discard_config>"
  "<prefer_incoming>"
  "<discard_incoming>"
The profiles are empty except for having their precedence
set and can be set on an endpoint to allow processing without
entries in geolocation.conf.  "<discard_config>" is actually the
best one to use in this situation.

ASTERISK-30182

Change-Id: I1819ccfa404ce59802a3a07ad1cabed60fb9480a
2022-09-10 11:04:46 -05:00
Joshua C. Colp f3de933b16 res_pjsip_sdp_rtp: Skip formats without SDP details.
When producing an outgoing SDP we iterate through the configured
formats and produce SDP information. It is possible for some
configured formats to not have SDP information available. If this
is the case we skip over them to allow the SDP to still be
produced.

ASTERISK-29185

Change-Id: I3e37569aa4ca341260e6ca5904dc2f75e46a1749
2022-09-10 11:00:38 -05:00
Naveen Albert c7612521be cli: Prevent assertions on startup from bad ao2 refs.
If "core show channels" is run before startup has completed, it
is possible for bad ao2 refs to occur because the system is not
yet fully initialized. This will lead to an assertion failing.

To prevent this, initialization of CLI builtins is moved to be
later along in the main load sequence. Core CLI commands are
loaded at the same time, but channel-related commands are loaded
later on.

ASTERISK-29846 #close

Change-Id: If6b3cde802876bd738c1b4cf2683bea6ddc615b6
2022-09-09 20:41:46 -05:00
Joshua C. Colp a0713a9f70 pjsip: Add TLS transport reload support for certificate and key.
This change adds support using the pjsip_tls_transport_restart
function for reloading the TLS certificate and key, if the filenames
remain unchanged. This is useful for Let's Encrypt and other
situations. Note that no restart of the transport will occur if
the certificate and key remain unchanged.

ASTERISK-30186

Change-Id: I9bc95a6bf791830a9491ad9fa43c17d4010028d0
2022-09-09 18:41:12 -05:00
Naveen Albert 754346a4a9 res_tonedetect: Fix typos referring to wrong variables.
Fixes two typos that cause fax detection to not work.
One refers to the wrong frame variable, and the other
refers to the subclass.integer instead of the frametype
as it should.

ASTERISK-30192 #close

Change-Id: I7b35fdb7bcf25a29a212eee37c20812c64ab3ef1
2022-09-09 13:31:39 -05:00
Mike Bradeen 46776c77c4 alembic: add missing ps_endpoints columns
The following required columns were missing,
now added to the ps_endpoints table:

incoming_call_offer_pref
outgoing_call_offer_pref
stir_shaken_profile

ASTERISK-29453

Change-Id: I5cf565edf30195844d6acbc1e1de8c5f0d837568
2022-09-09 11:35:04 -05:00
Sean Bright 583e017f34 chan_dahdi.c: Resolve a format-truncation build warning.
With gcc (Ubuntu 11.2.0-19ubuntu1) 11.2.0:

> chan_dahdi.c:4129:18: error: ‘%s’ directive output may be truncated
>   writing up to 255 bytes into a region of size between 242 and 252
>   [-Werror=format-truncation=]

This removes the error-prone sizeof(...) calculations in favor of just
doubling the size of the base buffer.

Change-Id: I2d276785286730d3d5d0a921bcea2e065dbf27c5
2022-09-09 09:39:21 -05:00
Alexei Gradinari 12c4c1bf5f res_pjsip_pubsub: Postpone destruction of old subscriptions on RLS update
Set termination state to old subscriptions to prevent queueing and sending
NOTIFY messages on exten/device state changes.

Postpone destruction of old subscriptions until all already queued tasks
that may be using old subscriptions have completed.

ASTERISK-29906

Change-Id: I96582aad3a26515ca73a8460ee6756f56f6ba23b
2022-09-09 08:35:53 -05:00
Sean Bright 155c796203 channel.h: Remove redundant declaration.
The DECLARE_STRINGFIELD_SETTERS_FOR() declares ast_channel_name_set()
for us, so no need to declare it separately.

Change-Id: I4813a884ada475ddc62bca480bceb4a53b3ec59a
2022-09-09 05:59:45 -05:00
Naveen Albert 3fa66c92b5 features: Add transfer initiation options.
Adds additional control options over the transfer
feature functionality to give users more control
in how the transfer feature sounds and works.

First, the "transfer" sound that plays when a transfer is
initiated can now be customized by the user in
features.conf, just as with the other transfer sounds.

Secondly, the user can now specify the transfer extension
in advance by using the TRANSFER_EXTEN variable. If
a valid extension is contained in this variable, the call
will automatically be transferred to this destination.
Otherwise, it will fall back to collecting the extension
from the user as is always done now.

ASTERISK-29899 #close

Change-Id: Ibff309caa459a2b958706f2ed0ca393b1ef502e3
2022-09-08 13:47:25 -05:00
Mike Bradeen adffb975dc CI: Fixing path issue on venv check
ASTERISK-26826

Change-Id: I07388d16f74452cebc9c981f99044eb6b77df792
2022-08-31 15:56:52 -05:00
Mike Bradeen 4fc9e06db1 CI: use Python3 virtual environment
Requires Python3 testsuite changes

ASTERISK-26826

Change-Id: I92ec7dec751ad455503a584d6e860db88c56d6bc
2022-08-30 11:41:54 -05:00
Naveen Albert e2e049e473 general: Very minor coding guideline fixes.
Fixes a few coding guideline violations:
* Use of C99 comments
* Opening brace on same line as function prototype

ASTERISK-30163 #close

Change-Id: I07771c4c89facd41ce8d323859f022ddbddf6ca7
2022-08-17 11:05:08 -05:00
George Joseph 8a8416e365 res_geolocation: Address user issues, remove complexity, plug leaks
* Added processing for the 'confidence' element.
* Added documentation to some APIs.
* removed a lot of complex code related to the very-off-nominal
  case of needing to process multiple location info sources.
* Create a new 'ast_geoloc_eprofile_to_pidf' API that just takes
  one eprofile instead of a datastore of multiples.
* Plugged a huge leak in XML processing that arose from
  insufficient documentation by the libxml/libxslt authors.
* Refactored stylesheets to be more efficient.
* Renamed 'profile_action' to 'profile_precedence' to better
  reflect it's purpose.
* Added the config option for 'allow_routing_use' which
  sets the value of the 'Geolocation-Routing' header.
* Removed the GeolocProfileCreate and GeolocProfileDelete
  dialplan apps.
* Changed the GEOLOC_PROFILE dialplan function as follows:
  * Removed the 'profile' argument.
  * Automatically create a profile if it doesn't exist.
  * Delete a profile if 'inheritable' is set to no.
* Fixed various bugs and leaks
* Updated Asterisk WiKi documentation.

ASTERISK-30167

Change-Id: If38c23f26228e96165be161c2f5e849cb8e16fa0
2022-08-10 12:50:01 -05:00
Naveen Albert ff044c222b chan_iax2: Add missing options documentation.
Adds missing dial resource option documentation.

ASTERISK-30164 #close

Change-Id: I674e1fc9b1e5d67a20599bd4b418ce294d48fc83
2022-08-10 08:36:21 -05:00
Naveen Albert dc7ec11c26 app_confbridge: Fix memory leak on updated menu options.
If the CONFBRIDGE function is used to dynamically set
menu options, a memory leak occurs when a menu option
that has been set is overridden, since the menu entry
is not destroyed before being freed. This ensures that
it is.

Additionally, logic that duplicates the destroy function
is removed in lieu of the destroy function itself.

ASTERISK-28422 #close

Change-Id: I71cfb5c24e636984d41086d1333a416dc12ff995
2022-08-08 05:19:40 -05:00
George Joseph 30d7a212b0 Geolocation: Wiki Documentation
Change-Id: I68ba22db0a69d9e2eabcc2141b48a2395f7f1a23
2022-08-05 10:02:30 -05:00
Naveen Albert f4a020a45b manager: Remove documentation for nonexistent action.
The manager XML documentation documents a "FilterList"
action, but there is no such action. Therefore, this can
lead to confusion when people try to use a documented
action that does not, in fact, exist. This is removed
as the action never did exist in the past, nor would it
be trivial to add since we only store the regex_t
objects, so the filter list can't actually be provided
without storing that separately. Most likely, the
documentation was originally added (around version 10)
in anticipation of something that never happened.

ASTERISK-29917 #close

Change-Id: I846b16fd6f80a91d4ddc5d8a861b522d7c6f8f97
2022-08-02 09:09:43 -05:00
Naveen Albert c654486547 general: Improve logging levels of some log messages.
Adjusts some logging levels to be more or less important,
that is more prominent when actual problems occur and less
prominent for less noteworthy things.

ASTERISK-30153 #close

Change-Id: Ifc8f7df427aa018627db462125ae744986d3261b
2022-08-01 11:03:46 -05:00
Naveen Albert 5feebc0857 cdr.conf: Remove obsolete app_mysql reference.
The CDR sample config still mentions that app_mysql
is available in the addons directory, but this is
incorrect as it was removed as of 19. This removes
that to avoid confusion.

ASTERISK-30160 #close

Change-Id: Ie5293ccb4f2b365896981811b480544e67bb9cd7
2022-08-01 10:09:53 -05:00
Naveen Albert 165368bf0b general: Remove obsolete SVN references.
There are a handful of files in the tree that
reference an SVN link for the coding guidelines.

This removes these because the links are dead
and the vast majority of source files do not
contain these links, so this is more consistent.

app_skel still maintains an (up to date) link
to the coding guidelines.

ASTERISK-30159 #close

Change-Id: I35bbb20f66982e98099cff3029ede20091ffdac7
2022-08-01 09:58:58 -05:00
Naveen Albert 2d8f2696b2 app_confbridge: Add missing AMI documentation.
Documents the ConfbridgeListRooms AMI response,
which is currently not documented.

ASTERISK-30020 #close

Change-Id: Id6fff7a936244bae7b52686301eb740c1169cdea
2022-08-01 08:58:50 -05:00
Naveen Albert 4af881506e app_meetme: Add missing AMI documentation.
The MeetmeList and MeetmeListRooms AMI
responses are currently completely undocumented.
This adds documentation for these responses.

ASTERISK-30018 #close

Change-Id: Id93135b7edf01de6f8fba266e2122989dc8996b8
2022-08-01 07:57:21 -05:00
Naveen Albert 83912496ab func_srv: Document field parameter.
Adds missing documentation for the field parameter
for the SRVRESULT function.

ASTERISK-30151
Reported by: Chris Young

Change-Id: I4385a2e0892a07e30dea1a8a0588e2c1bea2b1f1
2022-07-27 12:10:25 -05:00
Naveen Albert c771e2dd7a pbx_functions.c: Manually update ast_str strlen.
When ast_func_read2 is used to read a function using
its read function (as opposed to a native ast_str read2
function), the result is copied directly by the function
into the ast_str buffer. As a result, the ast_str length
remains initialized to 0, which is a bug because this is
not the real string length.

This can cascade and have issues elsewhere, such as when
reading substrings of functions that only register read
as opposed to read2 callbacks. In this case, since reading
ast_str_strlen returns 0, the returned substring is empty
as opposed to the actual substring. This has caused
the ast_str family of functions to behave inconsistently
and erroneously, in contrast to the pbx_variables substitution
functions which work correctly.

This fixes this issue by manually updating the ast_str length
when the result is copied directly into the ast_str buffer.

Additionally, an assertion and a unit test that previously
exposed these issues are added, now that the issue is fixed.

ASTERISK-29966 #close

Change-Id: I4e2dba41410f9d4dff61c995d2ca27718248e07f
2022-07-26 10:48:19 -05:00
Sergey V. Lobanov f645157a4b build: fix bininstall launchd issue on cross-platform build
configure script detects /sbin/launchd, but the result of this
check is not used in Makefile (bininstall). Makefile also detects
/sbin/launchd file to decide if it is required to install
safe_asterisk.

configure script correctly detects cross compile build and sets
PBX_LAUNCHD=0

In case of building asterisk on MacOS host for Linux target using
external toolchain (e.g. OpenWrt toolchain), bininstall does not
install safe_asterisk (due to /sbin/launchd detection in Makefile),
but it is required on target (Linux).

This patch adds HAVE_SBIN_LAUNCHD=@PBX_LAUNCHD@ to makeopts.in to
use the result of /sbin/launchd detection from configure script in
Makefile.
Also this patch uses HAVE_SBIN_LAUNCHD in Makefile (bininstall) to
decide if it is required to install safe_asterisk.

ASTERISK-29905 #close

Change-Id: Iff61217276cd188f43f51ef4cdbffe39d9f07f65
2022-07-24 11:52:30 -05:00
Naveen Albert a9223f210e db: Add AMI action to retrieve DB keys at prefix.
Adds the DBGetTree action, which can be used to
retrieve all of the DB keys beginning with a
particular prefix, similar to the capability
provided by the database show CLI command.

ASTERISK-30136 #close

Change-Id: I3be9425e53be71f24303fdd4d2923c14e84337e6
2022-07-20 13:02:12 -05:00
Naveen Albert ce18196280 manager: Fix incomplete filtering of AMI events.
The global event filtering code was only in one
possible execution path, so not all events were
being properly filtered out if requested. This moves
that into the universal AMI handling code so all
events are properly handled.

Additionally, the CLI listing of disabled events can
also get truncated, so we now print out everything.

ASTERISK-30137 #close

Change-Id: If8c42edcb2abc5158552da7eba2a8ff6b20e1959
2022-07-20 09:46:11 -05:00
George Joseph f8000daff5 Update defaultbranch to 20
Change-Id: Ib91db9223a78188667e15053bcc73931b878414e
2022-07-20 04:59:53 -06:00
232 changed files with 133144 additions and 14829 deletions

View File

@ -1,6 +1,5 @@
[gerrit]
defaultbranch=master
basebranch=master
defaultbranch=20
#
# Intentional padding to ensure it is possible to point a commit
# to an alternative gerrit server/repository without breaking

1
.lastclean Normal file
View File

@ -0,0 +1 @@
40

1
.version Normal file
View File

@ -0,0 +1 @@
20.2.1

306
CHANGES
View File

@ -12,10 +12,316 @@
===
==============================================================================
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 20.1.0 to Asterisk 20.2.0 ------------
------------------------------------------------------------------------------
app_broadcast
------------------
* A Broadcast application is now available which allows
for asynchronous one-to-many and many-to-one channel audio.
app_directory
------------------
* A new option 's' has been added to the Directory() application that
will skip calling the extension and instead set the extension as
DIRECTORY_EXTEN channel variable.
app_read
------------------
* A new option 'e' has been added to allow Read() to return the
terminator as the dialed digits in the case where only the terminator
is entered.
app_senddtmf
------------------
* A new option has been added to SendDTMF() which will answer the
specified channel if it is not already up. If no channel is specified,
the current channel will be answered instead.
app_signal
------------------
* Adds Signal and WaitForSignal applications
which can be used for signaling or as a
simple message queue in the dialplan.
func_json
------------------
* Additional parsing capabilities have been added to the
JSON_DECODE function, including support for arrays
and recursive indexing.
res_phoneprov
------------------
* On multihomed Asterisk servers with dynamic SERVER template variables,
reloading this module is no longer required when re-provisioning your
phone to another interface address (e.g. when moving between VLANs.)
res_pjsip_rfc3326
------------------
* Add ability to set HANGUPCAUSE when SIP causecode received in BYE Reason header (in
addition to currently supported Q.850). The first header found will be used to set
the HANGUPCAUSE variable.
res_pjsip_session
------------------
* The overlap_context option now allows explicitly
specifying a context to use for overlap dialing matches.
res_rtp_asterisk
------------------
* This module has been updated to provide additional
quality statistics in the form of an Asterisk
Media Experience Score. The score is available using
the same mechanisms you'd use to retrieve jitter, loss,
and rtt statistics. For more information about the
score and how to retrieve it, see
https://wiki.asterisk.org/wiki/display/AST/Media+Experience+Score
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 20.0.0 to Asterisk 20.1.0 ------------
------------------------------------------------------------------------------
AMI
------------------
* The AOCMessage action can now be used to generate AOC-S messages.
Add support for named capture agent.
------------------
* A name for the capture agent can now be specified
using the capture_name option which, if specified,
will be sent to the HEP server.
app_if
------------------
* Adds the If, ElseIf, Else, EndIf, and ExitIf applications
for conditional execution of a block of code.
app_mixmonitor
------------------
* The d option for MixMonitor now allows deleting
the original recording when MixMonitor exits,
which can be useful when MixMonitor copies it
somewhere else before exiting.
* Adds the c option to use the real Caller ID on
the channel in voicemail recordings as opposed
to the Connected Line.
app_voicemail
------------------
* The voicemail user option attachextrecs can
now be set to control whether external recordings
trigger voicemail email notifications.
cdr
------------------
* Two new options have been added which allow
bridging and dial state changes to be ignored
in CDRs, which can be useful if a single CDR
is desired for a channel.
chan_dahdi
------------------
* FXO channels (FXS signaled) that don't use callerid or
distinctive ring detection can now be configured
to enter the dialplan immediately using immediate=yes,
instead of waiting for at least one ring.
pbx_builtins
------------------
* It is now possible to not wait for media on
a channel when answering it using Answer,
by specifying the i option.
res_pjsip
------------------
* Added options "security_negotiation" and "security_mechanisms" to pjsip
endpoints and registrations. "security_negotiation" can be set to "no" (default)
or "mediasec", and "security_mechanisms" can be a list of comma-separated
security_mechanisms in the form defined by RFC 3329 section 2.2.
* A new option named "all_codecs_on_empty_reinvite" has been added to the
global section. When this option is enabled, on reception of a re-INVITE
without SDP, Asterisk will send an SDP offer in the 200 OK response containing
all configured codecs on the endpoint, instead of simply those that have
already been negotiated. RFC 3261 specifies this as a SHOULD requirement.
The default value is "off".
res_pjsip_aoc
------------------
* Added res_pjsip_aoc which gives chan_pjsip the ability to send Advice-of-Charge messages.
A new endpoint option, send_aoc, controls this.
res_pjsip_header_funcs
------------------
* The new PJSIP_HEADER_PARAM function now fully supports both
URI and header parameters. Both reading and writing
parameters are supported.
res_pjsip_logger
------------------
* SIP messages can now be filtered by SIP request method
(INVITE, CANCEL, ACK, BYE, REGISTER, OPTION,
SUBSCRIBE, NOTIFY, PUBLISH, INFO, and MESSAGE),
allowing for more granular debugging to be done
in the CLI. This applies to requests but not responses.
res_pjsip_notify
------------------
* Allows using the config options in pjsip_notify.conf
from AMI actions as with the existing CLI commands.
res_tonedetect
------------------
* The TONE_DETECT function now supports
detection of audible ringback tone
using the p option.
xmldocs
------------------
* The XML documentation can now be reloaded without restarting
Asterisk, which makes it possible to load new modules that
enforce documentation without restarting Asterisk.
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 19.0.0 to Asterisk 20.0.0 ------------
------------------------------------------------------------------------------
New EXPORT function
------------------
* A new function, EXPORT, allows writing variables
and functions on other channels, the complement
of the IMPORT function.
app_amd
------------------
* An audio file to play during AMD processing can
now be specified to the AMD application or configured
in the amd.conf configuration file.
app_bridgewait
------------------
* Adds the n option to not answer the channel when
the BridgeWait application is called.
features
------------------
* The Bridge application now has the n "no answer" option
that can be used to prevent the channel from being
automatically answered prior to bridging.
func_strings
------------------
* Three new functions, TRIM, LTRIM, and RTRIM, are
now available for trimming leading and trailing
whitespace.
res_pjsip
------------------
* A new option named "peer_supported" has been added to the endpoint option
100rel. When set to this option, Asterisk sends provisional responses
reliably if the peer supports it. If the peer does not support reliable
provisional responses, Asterisk sends them normally.
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 19.0.0 to Asterisk 20.0.0 ------------
------------------------------------------------------------------------------
Transfer feature
------------------
* The following capabilities have been added to the
transfer feature:
- The transfer initiation announcement prompt can
now be customized in features.conf.
- The TRANSFER_EXTEN variable now can be set on the
transferer's channel in order to allow the transfer
function to automatically attempt to go to the extension
contained in this variable, if it exists. The transfer
context behavior is not changed (TRANSFER_CONTEXT is used
if it exists; otherwise the default context is used).
app_confbridge
------------------
* Adds the end_marked_any option which can be used
to kick users from a conference after any
marked user leaves (including marked users).
db
------------------
* The DBPrefixGet AMI action now allows retrieving
all of the DB keys beginning with a particular
prefix.
locks
------------------
* A new AMI event, DeadlockStart, is now available
when Asterisk is compiled with DETECT_DEADLOCKS,
and can indicate that a deadlock has occured.
res_geolocation
------------------
* * Added processing for the 'confidence' element.
* Added documentation to some APIs.
* removed a lot of complex code related to the very-off-nominal
case of needing to process multiple location info sources.
* Create a new 'ast_geoloc_eprofile_to_pidf' API that just takes
one eprofile instead of a datastore of multiples.
* Plugged a huge leak in XML processing that arose from
insufficient documentation by the libxml/libxslt authors.
* Refactored stylesheets to be more efficient.
* Renamed 'profile_action' to 'profile_precedence' to better
reflect it's purpose.
* Added the config option for 'allow_routing_use' which
sets the value of the 'Geolocation-Routing' header.
* Removed the GeolocProfileCreate and GeolocProfileDelete
dialplan apps.
* Changed the GEOLOC_PROFILE dialplan function as follows:
* Removed the 'profile' argument.
* Automatically create a profile if it doesn't exist.
* Delete a profile if 'inheritable' is set to no.
* Fixed various bugs and leaks
* Updated Asterisk WiKi documentation.
Added 4 built-in profiles:
"<prefer_config>"
"<discard_config>"
"<prefer_incoming>"
"<discard_incoming>"
The profiles are empty except for having their precedence
set.
Added profile parameter "suppress_empty_ca_elements" that
will cause Civic Address elements that are empty to be
suppressed from the outgoing PIDF-LO document.
You can now specify the location object's format, location_info,
method, location_source and confidence parameters directly on
a profile object for simple scenarios where the location
information isn't common with any other profiles. This is
mutually exclusive with setting location_reference on the
profile.
Added an 'a' option to the GEOLOC_PROFILE function to allow
variable lists like location_info_refinement to be appended
to instead of replacing the entire list.
Added an 'r' option to the GEOLOC_PROFILE function to resolve all
variables before a read operation and after a Set operation.
res_musiconhold_answeredonly
------------------
* This change adds an option, answeredonly, that will prevent music
on hold on channels that are not answered.
res_pjsip
------------------
* TLS transports in res_pjsip can now reload their TLS certificate
and private key files, provided the filename of them has not
changed.
Applications
------------------
* added support for Danish syntax, playing the correct plural sound file

106191
ChangeLog Normal file

File diff suppressed because it is too large Load Diff

View File

@ -561,9 +561,9 @@ bininstall: _all installdirs $(SUBDIRS_INSTALL) main-bininstall
$(INSTALL) -m 755 contrib/scripts/astversion "$(DESTDIR)$(ASTSBINDIR)/"
$(INSTALL) -m 755 contrib/scripts/astgenkey "$(DESTDIR)$(ASTSBINDIR)/"
$(INSTALL) -m 755 contrib/scripts/autosupport "$(DESTDIR)$(ASTSBINDIR)/"
if [ ! -f /sbin/launchd ]; then \
./build_tools/install_subst contrib/scripts/safe_asterisk "$(DESTDIR)$(ASTSBINDIR)/safe_asterisk"; \
fi
ifneq ($(HAVE_SBIN_LAUNCHD),1)
./build_tools/install_subst contrib/scripts/safe_asterisk "$(DESTDIR)$(ASTSBINDIR)/safe_asterisk";
endif
ifneq ($(DISABLE_XMLDOC),yes)
$(INSTALL) -m 644 doc/core-*.xml "$(DESTDIR)$(ASTDATADIR)/documentation"

View File

@ -213,10 +213,10 @@ endif
# extern const size_t _binary_abc_def_xml_size;
%.o: %.xml
$(ECHO_PREFIX) echo " [LD] $^ -> $@"
$(CMD_PREFIX) $(CC) -g -nostartfiles -nodefaultlibs -nostdlib -r -Wl,-b,binary -o $@ $^
$(CMD_PREFIX) $(CC) -g -Wl,-znoexecstack -nostartfiles -nodefaultlibs -nostdlib -r -Wl,-b,binary -o $@ $^
%.o: %.xslt
$(ECHO_PREFIX) echo " [LD] $^ -> $@"
$(CMD_PREFIX) $(CC) -g -nostartfiles -nodefaultlibs -nostdlib -r -Wl,-b,binary -o $@ $^
$(CMD_PREFIX) $(CC) -g -Wl,-znoexecstack -nostartfiles -nodefaultlibs -nostdlib -r -Wl,-b,binary -o $@ $^
dist-clean:: clean

View File

@ -18,6 +18,42 @@
===
===========================================================
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 20.1.0 to Asterisk 20.2.0 ------------
------------------------------------------------------------------------------
app_playback
------------------
* In Asterisk 11, if a channel was redirected away during Playback(),
the PLAYBACKSTATUS variable would be set to SUCCESS. In Asterisk 12
(specifically commit 7d9871b3940fa50e85039aef6a8fb9870a7615b9) that
behavior was inadvertently changed and the same operation would result
in the PLAYBACKSTATUS variable being set to FAILED. The Asterisk 11
behavior has been restored.
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 20.0.0 to Asterisk 20.1.0 ------------
------------------------------------------------------------------------------
AMI (Asterisk Manager Interface)
------------------
* Previously, GetConfig and UpdateConfig were able to access files outside of
the Asterisk configuration directory. Now this access is put behind the
live_dangerously configuration option in asterisk.conf, which is disabled by
default. If access to configuration files outside of the Asterisk configuation
directory is required via AMI, then the live_dangerously configuration option
must be set to yes.
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 19.0.0 to Asterisk 20.0.0 ------------
------------------------------------------------------------------------------
res_crypto
------------------
* In addition to only paying attention to files ending with .key or .pub
in the keys directory, we now also ignore any files which aren't regular
files.
------------------------------------------------------------------------------
--- New functionality introduced in Asterisk 20.0.0 --------------------------
------------------------------------------------------------------------------

View File

@ -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");

View File

@ -92,6 +92,12 @@
<para>Is the maximum duration of a word to accept.</para>
<para>If exceeded, then the result is detection as a MACHINE</para>
</parameter>
<parameter name="audioFile" required="false">
<para>Is an audio file to play to the caller while AMD is in progress.</para>
<para>By default, no audio file is played.</para>
<para>If an audio file is configured in amd.conf, then that file will be used
if one is not specified here. That file may be overridden by this argument.</para>
</parameter>
</syntax>
<description>
<para>This application attempts to detect answering machines at the beginning
@ -155,6 +161,9 @@ static int dfltBetweenWordsSilence = 50;
static int dfltMaximumNumberOfWords = 2;
static int dfltSilenceThreshold = 256;
static int dfltMaximumWordLength = 5000; /* Setting this to a large default so it is not used unless specify it in the configs or command line */
static char *dfltAudioFile = NULL;
static ast_mutex_t config_lock;
/* Set to the lowest ms value provided in amd.conf or application parameters */
static int dfltMaxWaitTimeForFrame = 50;
@ -179,7 +188,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
char amdCause[256] = "", amdStatus[256] = "";
char *parse = ast_strdupa(data);
/* Lets set the initial values of the variables that will control the algorithm.
/* Let's set the initial values of the variables that will control the algorithm.
The initial values are the default ones. If they are passed as arguments
when invoking the application, then the default values will be overwritten
by the ones passed as parameters. */
@ -193,6 +202,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
int silenceThreshold = dfltSilenceThreshold;
int maximumWordLength = dfltMaximumWordLength;
int maxWaitTimeForFrame = dfltMaxWaitTimeForFrame;
const char *audioFile = NULL;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(argInitialSilence);
@ -204,8 +214,15 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
AST_APP_ARG(argMaximumNumberOfWords);
AST_APP_ARG(argSilenceThreshold);
AST_APP_ARG(argMaximumWordLength);
AST_APP_ARG(audioFile);
);
ast_mutex_lock(&config_lock);
if (!ast_strlen_zero(dfltAudioFile)) {
audioFile = ast_strdupa(dfltAudioFile);
}
ast_mutex_unlock(&config_lock);
ast_verb(3, "AMD: %s %s %s (Fmt: %s)\n", ast_channel_name(chan),
S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, "(N/A)"),
S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "(N/A)"),
@ -233,6 +250,9 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
silenceThreshold = atoi(args.argSilenceThreshold);
if (!ast_strlen_zero(args.argMaximumWordLength))
maximumWordLength = atoi(args.argMaximumWordLength);
if (!ast_strlen_zero(args.audioFile)) {
audioFile = args.audioFile;
}
} else {
ast_debug(1, "AMD using the default parameters.\n");
}
@ -280,6 +300,11 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
/* Set our start time so we can tie the loop to real world time and not RTP updates */
amd_tvstart = ast_tvnow();
/* Optional audio file to play to caller while AMD is doing its thing. */
if (!ast_strlen_zero(audioFile)) {
ast_streamfile(chan, audioFile, ast_channel_language(chan));
}
/* Now we go into a loop waiting for frames from the channel */
while ((res = ast_waitfor(chan, 2 * maxWaitTimeForFrame)) > -1) {
int ms = 0;
@ -462,10 +487,14 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
/* Free the DSP used to detect silence */
ast_dsp_free(silenceDetector);
/* If we were playing something to pass the time, stop it now. */
if (!ast_strlen_zero(audioFile)) {
ast_stopstream(chan);
}
return;
}
static int amd_exec(struct ast_channel *chan, const char *data)
{
isAnsweringMachine(chan, data);
@ -516,7 +545,16 @@ static int load_config(int reload)
dfltMaximumNumberOfWords = atoi(var->value);
} else if (!strcasecmp(var->name, "maximum_word_length")) {
dfltMaximumWordLength = atoi(var->value);
} else if (!strcasecmp(var->name, "playback_file")) {
ast_mutex_lock(&config_lock);
if (dfltAudioFile) {
ast_free(dfltAudioFile);
dfltAudioFile = NULL;
}
if (!ast_strlen_zero(var->value)) {
dfltAudioFile = ast_strdup(var->value);
}
ast_mutex_unlock(&config_lock);
} else {
ast_log(LOG_WARNING, "%s: Cat:%s. Unknown keyword %s at line %d of amd.conf\n",
app, cat, var->name, var->lineno);
@ -539,6 +577,12 @@ static int load_config(int reload)
static int unload_module(void)
{
ast_mutex_lock(&config_lock);
if (dfltAudioFile) {
ast_free(dfltAudioFile);
}
ast_mutex_unlock(&config_lock);
ast_mutex_destroy(&config_lock);
return ast_unregister_application(app);
}
@ -554,6 +598,7 @@ static int unload_module(void)
*/
static int load_module(void)
{
ast_mutex_init(&config_lock);
if (load_config(0) || ast_register_application_xml(app, amd_exec)) {
return AST_MODULE_LOAD_DECLINE;
}

View File

@ -100,6 +100,9 @@
<para>Automatically exit the bridge and return to the PBX after
<emphasis>duration</emphasis> seconds.</para>
</option>
<option name="n">
<para>Do not automatically answer the channel.</para>
</option>
</optionlist>
</parameter>
</syntax>
@ -108,7 +111,7 @@
The channel will then wait in the holding bridge until some event occurs
which removes it from the holding bridge.</para>
<note><para>This application will answer calls which haven't already
been answered.</para></note>
been answered, unless the n option is provided.</para></note>
</description>
</application>
***/
@ -186,6 +189,7 @@ enum bridgewait_flags {
MUXFLAG_MOHCLASS = (1 << 0),
MUXFLAG_ENTERTAINMENT = (1 << 1),
MUXFLAG_TIMEOUT = (1 << 2),
MUXFLAG_NOANSWER = (1 << 3),
};
enum bridgewait_args {
@ -199,6 +203,7 @@ AST_APP_OPTIONS(bridgewait_opts, {
AST_APP_OPTION_ARG('e', MUXFLAG_ENTERTAINMENT, OPT_ARG_ENTERTAINMENT),
AST_APP_OPTION_ARG('m', MUXFLAG_MOHCLASS, OPT_ARG_MOHCLASS),
AST_APP_OPTION_ARG('S', MUXFLAG_TIMEOUT, OPT_ARG_TIMEOUT),
AST_APP_OPTION('n', MUXFLAG_NOANSWER),
});
static int bridgewait_timeout_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
@ -458,7 +463,7 @@ static int bridgewait_exec(struct ast_channel *chan, const char *data)
}
/* Answer the channel if needed */
if (ast_channel_state(chan) != AST_STATE_UP) {
if (ast_channel_state(chan) != AST_STATE_UP && !ast_test_flag(&flags, MUXFLAG_NOANSWER)) {
ast_answer(chan);
}

619
apps/app_broadcast.c Normal file
View File

@ -0,0 +1,619 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2022, Naveen Albert
*
* 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 Channel audio broadcasting
*
* \author Naveen Albert <asterisk@phreaknet.org>
*
* \ingroup applications
*/
/*** MODULEINFO
<support_level>extended</support_level>
***/
#include "asterisk.h"
#include <ctype.h>
#include <errno.h>
#include "asterisk/channel.h"
#include "asterisk/audiohook.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/options.h"
#include "asterisk/autochan.h"
#include "asterisk/format_cache.h"
#include "asterisk/cli.h" /* use ESS macro */
/*** DOCUMENTATION
<application name="Broadcast" language="en_US">
<synopsis>
Transmit or receive audio to or from multiple channels simultaneously
</synopsis>
<syntax>
<parameter name="options">
<optionlist>
<option name="b">
<para>In addition to broadcasting to target channels, also
broadcast to any channels to which target channels are bridged.</para>
</option>
<option name="l">
<para>Allow usage of a long queue to store audio frames.</para>
<note><para>This may introduce some delay in the received audio feed, but will improve the audio quality.</para></note>
</option>
<option name="o">
<para>Do not mix streams when combining audio from target channels (only applies with s option).</para>
</option>
<option name="r">
<para>Feed frames to barge channels in "reverse" by injecting them into the primary channel's read queue instead.</para>
<para>This option is required for barge to work in a n-party bridge (but not for 2-party bridges). Alternately, you
can add an intermediate channel by using a non-optimized Local channel, so that the target channel is bridged with
a single channel that is connected to the bridge, but it is recommended this option be used instead.</para>
<para>Note that this option will always feed injected audio to the other party, regardless of whether the target
channel is bridged or not.</para>
</option>
<option name="s">
<para>Rather than broadcast audio to a bunch of channels, receive the combined audio from the target channels.</para>
</option>
<option name="w">
<para>Broadcast audio received on this channel to other channels.</para>
</option>
</optionlist>
</parameter>
<parameter name="channels" required="true" argsep=",">
<para>List of channels for broadcast targets.</para>
<para>Channel names must be the full channel names, not merely device names.</para>
<para>Broadcasting will continue until the broadcasting channel hangs up or all target channels have hung up.</para>
</parameter>
</syntax>
<description>
<para>This application can be used to broadcast audio to multiple channels at once.
Any audio received on this channel will be transmitted to all of the specified channels and, optionally, their bridged peers.</para>
<para>It can also be used to aggregate audio from multiple channels at once.
Any audio on any of the specified channels, and optionally their bridged peers, will be transmitted to this channel.</para>
<para>Execution of the application continues until either the broadcasting channel hangs up
or all specified channels have hung up.</para>
<para>This application is used for one-to-many and many-to-one audio applications where
bridge mixing cannot be done synchronously on all the involved channels.
This is primarily useful for injecting the same audio stream into multiple channels at once,
or doing the reverse, combining the audio from multiple channels into a single stream.
This contrasts with using a separate injection channel for each target channel and/or
using a conference bridge.</para>
<para>The channel running the Broadcast application must do so synchronously. The specified channels,
however, may be doing other things.</para>
<example title="Broadcast received audio to three channels and their bridged peers">
same => n,Broadcast(wb,DAHDI/1,DAHDI/3,PJSIP/doorphone)
</example>
<example title="Broadcast received audio to three channels, only">
same => n,Broadcast(w,DAHDI/1,DAHDI/3,PJSIP/doorphone)
</example>
<example title="Combine audio from three channels and their bridged peers to us">
same => n,Broadcast(s,DAHDI/1,DAHDI/3,PJSIP/doorphone)
</example>
<example title="Combine audio from three channels to us">
same => n,Broadcast(so,DAHDI/1,DAHDI/3,PJSIP/doorphone)
</example>
<example title="Two-way audio with a bunch of channels">
same => n,Broadcast(wbso,DAHDI/1,DAHDI/3,PJSIP/doorphone)
</example>
<para>Note that in the last example above, this is NOT the same as a conference bridge.
The specified channels are not audible to each other, only to the channel running the
Broadcast application. The two-way audio is only between the broadcasting channel and
each of the specified channels, individually.</para>
</description>
<see-also>
<ref type="application">ChanSpy</ref>
</see-also>
</application>
***/
static const char app_broadcast[] = "Broadcast";
enum {
OPTION_READONLY = (1 << 0), /* Don't mix the two channels */
OPTION_BARGE = (1 << 1), /* Barge mode (whisper to both channels) */
OPTION_LONG_QUEUE = (1 << 2), /* Allow usage of a long queue to store audio frames. */
OPTION_WHISPER = (1 << 3),
OPTION_SPY = (1 << 4),
OPTION_REVERSE_FEED = (1 << 5),
OPTION_ANSWER_WARN = (1 << 6), /* Internal flag, not set by user */
};
AST_APP_OPTIONS(spy_opts, {
AST_APP_OPTION('b', OPTION_BARGE),
AST_APP_OPTION('l', OPTION_LONG_QUEUE),
AST_APP_OPTION('o', OPTION_READONLY),
AST_APP_OPTION('r', OPTION_REVERSE_FEED),
AST_APP_OPTION('s', OPTION_SPY),
AST_APP_OPTION('w', OPTION_WHISPER),
});
struct multi_autochan {
char *name;
struct ast_autochan *autochan;
struct ast_autochan *bridge_autochan;
struct ast_audiohook whisper_audiohook;
struct ast_audiohook bridge_whisper_audiohook;
struct ast_audiohook spy_audiohook;
unsigned int connected:1;
unsigned int bridge_connected:1;
unsigned int spying:1;
AST_LIST_ENTRY(multi_autochan) entry; /*!< Next record */
};
AST_RWLIST_HEAD(multi_autochan_list, multi_autochan);
struct multi_spy {
struct multi_autochan_list *chanlist;
unsigned int readonly:1;
};
static void *spy_alloc(struct ast_channel *chan, void *data)
{
return data; /* just store the data pointer in the channel structure */
}
static void spy_release(struct ast_channel *chan, void *data)
{
return; /* nothing to do */
}
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
{
struct multi_spy *multispy = data;
struct multi_autochan_list *chanlist = multispy->chanlist;
struct multi_autochan *mac;
struct ast_frame *f;
short *data1, *data2;
int res, i;
/* All the frames we get are slin, so they will all have the same number of samples. */
static const int num_samples = 160;
short combine_buf[num_samples];
struct ast_frame wf = {
.frametype = AST_FRAME_VOICE,
.offset = 0,
.subclass.format = ast_format_slin,
.datalen = num_samples * 2,
.samples = num_samples,
.src = __FUNCTION__,
};
memset(&combine_buf, 0, sizeof(combine_buf));
wf.data.ptr = combine_buf;
AST_RWLIST_WRLOCK(chanlist);
AST_RWLIST_TRAVERSE_SAFE_BEGIN(chanlist, mac, entry) {
ast_audiohook_lock(&mac->spy_audiohook);
if (mac->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
ast_audiohook_unlock(&mac->spy_audiohook); /* Channel is already gone more than likely, the broadcasting channel will clean this up. */
continue;
}
if (multispy->readonly) { /* Option 'o' was set, so don't mix channel audio */
f = ast_audiohook_read_frame(&mac->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, ast_format_slin);
} else {
f = ast_audiohook_read_frame(&mac->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, ast_format_slin);
}
ast_audiohook_unlock(&mac->spy_audiohook);
if (!f) {
continue; /* No frame? No problem. */
}
/* Mix the samples. */
for (i = 0, data1 = combine_buf, data2 = f->data.ptr; i < num_samples; i++, data1++, data2++) {
ast_slinear_saturated_add(data1, data2);
}
ast_frfree(f);
}
AST_RWLIST_TRAVERSE_SAFE_END;
AST_RWLIST_UNLOCK(chanlist);
res = ast_write(chan, &wf);
ast_frfree(&wf);
return res;
}
static struct ast_generator spygen = {
.alloc = spy_alloc,
.release = spy_release,
.generate = spy_generate,
};
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
{
int res;
ast_autochan_channel_lock(autochan);
ast_debug(1, "Attaching spy channel %s to %s\n", spychan_name, ast_channel_name(autochan->chan));
if (ast_test_flag(flags, OPTION_READONLY)) {
ast_set_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE);
} else {
ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
}
if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
ast_debug(2, "Using a long queue to store audio frames in spy audiohook\n");
} else {
ast_set_flag(audiohook, AST_AUDIOHOOK_SMALL_QUEUE);
}
res = ast_audiohook_attach(autochan->chan, audiohook);
ast_autochan_channel_unlock(autochan);
return res;
}
static int attach_barge(struct ast_autochan *spyee_autochan, struct ast_autochan **spyee_bridge_autochan,
struct ast_audiohook *bridge_whisper_audiohook, const char *spyer_name, const char *name, struct ast_flags *flags)
{
int retval = 0;
struct ast_autochan *internal_bridge_autochan;
struct ast_channel *spyee_chan;
RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup);
ast_autochan_channel_lock(spyee_autochan);
spyee_chan = ast_channel_ref(spyee_autochan->chan);
ast_autochan_channel_unlock(spyee_autochan);
/* Note that ast_channel_bridge_peer only returns non-NULL for 2-party bridges, not n-party bridges (e.g. ConfBridge) */
bridged = ast_channel_bridge_peer(spyee_chan);
ast_channel_unref(spyee_chan);
if (!bridged) {
ast_debug(9, "Channel %s is not yet bridged, unable to setup barge\n", ast_channel_name(spyee_chan));
/* If we're bridged, but it's not a 2-party bridge, then we probably should have used OPTION_REVERSE_FEED. */
if (ast_test_flag(flags, OPTION_ANSWER_WARN) && ast_channel_is_bridged(spyee_chan)) {
ast_clear_flag(flags, OPTION_ANSWER_WARN); /* Don't warn more than once. */
ast_log(LOG_WARNING, "Barge failed: channel is bridged, but not to a 2-party bridge. Use the 'r' option.\n");
}
return -1;
}
ast_audiohook_init(bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Broadcast", 0);
internal_bridge_autochan = ast_autochan_setup(bridged);
if (!internal_bridge_autochan) {
return -1;
}
if (start_spying(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook, flags)) {
ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
retval = -1;
}
*spyee_bridge_autochan = internal_bridge_autochan;
return retval;
}
static void multi_autochan_free(struct multi_autochan *mac)
{
if (mac->connected) {
if (mac->whisper_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
ast_debug(2, "Whisper audiohook no longer running\n");
}
ast_audiohook_lock(&mac->whisper_audiohook);
ast_audiohook_detach(&mac->whisper_audiohook);
ast_audiohook_unlock(&mac->whisper_audiohook);
ast_audiohook_destroy(&mac->whisper_audiohook);
}
if (mac->bridge_connected) {
if (mac->bridge_whisper_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
ast_debug(2, "Whisper (bridged) audiohook no longer running\n");
}
ast_audiohook_lock(&mac->bridge_whisper_audiohook);
ast_audiohook_detach(&mac->bridge_whisper_audiohook);
ast_audiohook_unlock(&mac->bridge_whisper_audiohook);
ast_audiohook_destroy(&mac->bridge_whisper_audiohook);
}
if (mac->spying) {
if (mac->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
ast_debug(2, "Spy audiohook no longer running\n");
}
ast_audiohook_lock(&mac->spy_audiohook);
ast_audiohook_detach(&mac->spy_audiohook);
ast_audiohook_unlock(&mac->spy_audiohook);
ast_audiohook_destroy(&mac->spy_audiohook);
}
if (mac->name) {
int total = mac->connected + mac->bridge_connected + mac->spying;
ast_debug(1, "Removing channel %s from target list (%d hook%s)\n", mac->name, total, ESS(total));
ast_free(mac->name);
}
if (mac->autochan) {
ast_autochan_destroy(mac->autochan);
}
if (mac->bridge_autochan) {
ast_autochan_destroy(mac->bridge_autochan);
}
ast_free(mac);
}
static int do_broadcast(struct ast_channel *chan, struct ast_flags *flags, const char *channels)
{
int res = 0;
struct ast_frame *f;
struct ast_silence_generator *silgen = NULL;
struct multi_spy multispy;
struct multi_autochan_list chanlist;
struct multi_autochan *mac;
int numchans = 0;
int readonly = ast_test_flag(flags, OPTION_READONLY) ? 1 : 0;
char *next, *chansdup = ast_strdupa(channels);
AST_RWLIST_HEAD_INIT(&chanlist);
ast_channel_set_flag(chan, AST_FLAG_SPYING);
ast_set_flag(flags, OPTION_ANSWER_WARN); /* Initialize answer warn to 1 */
/* Hey, look ma, no list lock needed! Sometimes, it's nice to not have to share... */
/* Build a list of targets */
while ((next = strsep(&chansdup, ","))) {
struct ast_channel *ochan;
if (ast_strlen_zero(next)) {
continue;
}
if (!strcmp(next, ast_channel_name(chan))) {
ast_log(LOG_WARNING, "Refusing to broadcast to ourself: %s\n", next);
continue;
}
ochan = ast_channel_get_by_name(next);
if (!ochan) {
ast_log(LOG_WARNING, "No such channel: %s\n", next);
continue;
}
/* Append to end of list. */
if (!(mac = ast_calloc(1, sizeof(*mac)))) {
ast_log(LOG_WARNING, "Multi autochan allocation failure\n");
continue;
}
mac->name = ast_strdup(next);
mac->autochan = ast_autochan_setup(ochan);
if (!mac->name || !mac->autochan) {
multi_autochan_free(mac);
continue;
}
if (ast_test_flag(flags, OPTION_WHISPER)) {
mac->connected = 1;
ast_audiohook_init(&mac->whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Broadcast", 0);
/* Inject audio from our channel to this target. */
if (start_spying(mac->autochan, next, &mac->whisper_audiohook, flags)) {
ast_log(LOG_WARNING, "Unable to attach whisper audiohook to %s\n", next);
multi_autochan_free(mac);
continue;
}
}
if (ast_test_flag(flags, OPTION_SPY)) {
mac->spying = 1;
ast_audiohook_init(&mac->spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "Broadcast", 0);
if (start_spying(mac->autochan, next, &mac->spy_audiohook, flags)) {
ast_log(LOG_WARNING, "Unable to attach spy audiohook to %s\n", next);
multi_autochan_free(mac);
continue;
}
}
AST_RWLIST_INSERT_TAIL(&chanlist, mac, entry);
numchans++;
ochan = ast_channel_unref(ochan);
}
ast_verb(4, "Broadcasting to %d channel%s on %s\n", numchans, ESS(numchans), ast_channel_name(chan));
ast_debug(1, "Broadcasting: (TX->1) whisper=%d, (TX->2) barge=%d, (RX<-%d) spy=%d (%s)\n",
ast_test_flag(flags, OPTION_WHISPER) ? 1 : 0,
ast_test_flag(flags, OPTION_BARGE) ? 1 : 0,
readonly ? 1 : 2,
ast_test_flag(flags, OPTION_SPY) ? 1 : 0,
readonly ? "single" : "both");
if (ast_test_flag(flags, OPTION_SPY)) {
multispy.chanlist = &chanlist;
multispy.readonly = readonly;
ast_activate_generator(chan, &spygen, &multispy);
} else {
/* We're not expecting to read any audio, just broadcast audio to a bunch of other channels. */
silgen = ast_channel_start_silence_generator(chan);
}
while (numchans && ast_waitfor(chan, -1) > 0) {
int fres = 0;
f = ast_read(chan);
if (!f) {
ast_debug(1, "Channel %s must have hung up\n", ast_channel_name(chan));
res = -1;
break;
}
if (f->frametype != AST_FRAME_VOICE) { /* Ignore any non-voice frames */
ast_frfree(f);
continue;
}
/* Write the frame to all our targets. */
AST_RWLIST_WRLOCK(&chanlist);
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&chanlist, mac, entry) {
/* Note that if no media is received, execution is suspended, but assuming continuous or
* or frequent audio on the broadcasting channel, we'll quickly enough detect hung up targets.
* This isn't really an issue, just something that might be confusing at first, but this is
* due to the limitation with audiohooks of using the channel for timing. */
if ((ast_test_flag(flags, OPTION_WHISPER) && mac->whisper_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING)
|| (ast_test_flag(flags, OPTION_SPY) && mac->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING)
|| (mac->bridge_connected && ast_test_flag(flags, OPTION_BARGE) && mac->bridge_whisper_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING)) {
/* Even if we're spying only and not actually broadcasting audio, we need to detect channel hangup. */
AST_RWLIST_REMOVE_CURRENT(entry);
ast_debug(2, "Looks like %s has hung up\n", mac->name);
multi_autochan_free(mac);
numchans--;
ast_debug(2, "%d channel%s remaining in broadcast on %s\n", numchans, ESS(numchans), ast_channel_name(chan));
continue;
}
if (ast_test_flag(flags, OPTION_WHISPER)) {
ast_audiohook_lock(&mac->whisper_audiohook);
fres |= ast_audiohook_write_frame(&mac->whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
ast_audiohook_unlock(&mac->whisper_audiohook);
}
if (ast_test_flag(flags, OPTION_BARGE)) {
/* This hook lets us inject audio into the channel that the spyee is currently
* bridged with. If the spyee isn't bridged with anything yet, nothing will
* be attached and we'll need to continue attempting to attach the barge
* audio hook.
* The exception to this is if we are emulating barge by doing it "directly",
* that is injecting the frames onto this channel's read queue, rather than
* its bridged peer's write queue, then skip this. We only do one or the other. */
if (!ast_test_flag(flags, OPTION_REVERSE_FEED) && !mac->bridge_connected && !attach_barge(mac->autochan, &mac->bridge_autochan,
&mac->bridge_whisper_audiohook, ast_channel_name(chan), mac->name, flags)) {
ast_debug(2, "Attached barge channel for %s\n", mac->name);
mac->bridge_connected = 1;
}
if (mac->bridge_connected) {
ast_audiohook_lock(&mac->bridge_whisper_audiohook);
fres |= ast_audiohook_write_frame(&mac->bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
ast_audiohook_unlock(&mac->bridge_whisper_audiohook);
} else if (ast_test_flag(flags, OPTION_REVERSE_FEED)) {
/* So, this is really clever...
* If we're connected to an n-party bridge instead of a 2-party bridge,
* attach_barge will ALWAYS fail because we're connected to a bridge, not
* a single peer channel.
* Recall that the objective is for injected audio to be audible to both
* sides of the channel. So really, the typical way of doing this by
* directly injecting frames separately onto both channels is kind of
* bizarre to begin with, when you think about it.
*
* In other words, this is how ChanSpy and this module by default work:
* We have audio F to inject onto channels A and B, which are <= bridged =>:
* READ <- A -> WRITE <==> READ <- B -> WRITE
* F --^ F --^
*
* So that makes the same audio audible to both channels A and B, but
* in kind of a roundabout way. What if the bridged peer changes at
* some point, for example?
*
* While that method works for 2-party bridges, it doesn't work at all
* for an n-party bridge, so we do the thing that seems obvious to begin with:
* dump the frames onto THIS channel's read queue, and the channels will
* make their way into the bridge like any other audio from this channel,
* and everything just works perfectly, no matter what kind of bridging
* scenario is being used. At that point, we don't even care if we're
* bridged or not, and really, why should we?
*
* In other words, we do this:
* READ <- A -> WRITE <==> READ <- B -> WRITE
* F --^ F --^
*/
ast_audiohook_lock(&mac->whisper_audiohook);
fres |= ast_audiohook_write_frame(&mac->whisper_audiohook, AST_AUDIOHOOK_DIRECTION_READ, f);
ast_audiohook_unlock(&mac->whisper_audiohook);
}
}
if (fres) {
ast_log(LOG_WARNING, "Failed to write to audiohook for %s\n", mac->name);
fres = 0;
}
}
AST_RWLIST_TRAVERSE_SAFE_END;
AST_RWLIST_UNLOCK(&chanlist);
ast_frfree(f);
}
if (!numchans) {
ast_debug(1, "Exiting due to all target channels having left the broadcast\n");
}
if (ast_test_flag(flags, OPTION_SPY)) {
ast_deactivate_generator(chan);
} else {
ast_channel_stop_silence_generator(chan, silgen);
}
/* Cleanup any remaining targets */
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&chanlist, mac, entry) {
AST_RWLIST_REMOVE_CURRENT(entry);
multi_autochan_free(mac);
}
AST_RWLIST_TRAVERSE_SAFE_END;
ast_channel_clear_flag(chan, AST_FLAG_SPYING);
return res;
}
static int broadcast_exec(struct ast_channel *chan, const char *data)
{
struct ast_flags flags;
struct ast_format *write_format;
int res = -1;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(options);
AST_APP_ARG(channels); /* Channel list last, so we can have multiple */
);
char *parse = NULL;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Broadcast requires at least one channel\n");
return -1;
}
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.channels)) {
ast_log(LOG_WARNING, "Must specify at least one channel for broadcast\n");
return -1;
}
if (args.options) {
ast_app_parse_options(spy_opts, &flags, NULL, args.options);
} else {
ast_clear_flag(&flags, AST_FLAGS_ALL);
}
if (!ast_test_flag(&flags, OPTION_BARGE) && !ast_test_flag(&flags, OPTION_SPY) && !ast_test_flag(&flags, OPTION_WHISPER)) {
ast_log(LOG_WARNING, "At least one of the b, s, or w option must be specified (provided options have no effect)\n");
return -1;
}
write_format = ao2_bump(ast_channel_writeformat(chan));
if (ast_set_write_format(chan, ast_format_slin) < 0) {
ast_log(LOG_ERROR, "Failed to set write format to slin.\n");
goto cleanup;
}
res = do_broadcast(chan, &flags, args.channels);
/* Restore previous write format */
if (ast_set_write_format(chan, write_format)) {
ast_log(LOG_ERROR, "Failed to restore write format for channel %s\n", ast_channel_name(chan));
}
cleanup:
ao2_ref(write_format, -1);
return res;
}
static int unload_module(void)
{
return ast_unregister_application(app_broadcast);
}
static int load_module(void)
{
return ast_register_application_xml(app_broadcast, broadcast_exec);
}
AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Channel Audio Broadcasting");

View File

@ -393,6 +393,37 @@
ConfbridgeListRoomsComplete.</para>
</description>
</manager>
<managerEvent language="en_US" name="ConfbridgeListRooms">
<managerEventInstance class="EVENT_FLAG_REPORTING">
<synopsis>Raised as part of the ConfbridgeListRooms action response list.</synopsis>
<syntax>
<parameter name="Conference">
<para>The name of the Confbridge conference.</para>
</parameter>
<parameter name="Parties">
<para>Number of users in the conference.</para>
<para>This includes both active and waiting users.</para>
</parameter>
<parameter name="Marked">
<para>Number of marked users in the conference.</para>
</parameter>
<parameter name="Locked">
<para>Is the conference locked?</para>
<enumlist>
<enum name="Yes"/>
<enum name="No"/>
</enumlist>
</parameter>
<parameter name="Muted">
<para>Is the conference muted?</para>
<enumlist>
<enum name="Yes"/>
<enum name="No"/>
</enumlist>
</parameter>
</syntax>
</managerEventInstance>
</managerEvent>
<manager name="ConfbridgeMute" language="en_US">
<synopsis>
Mute a Confbridge user.
@ -3991,6 +4022,7 @@ static int action_confbridgelist_item(struct mansession *s, const char *id_text,
"MarkedUser: %s\r\n"
"WaitMarked: %s\r\n"
"EndMarked: %s\r\n"
"EndMarkedAny: %s\r\n"
"Waiting: %s\r\n"
"Muted: %s\r\n"
"Talking: %s\r\n"
@ -4003,6 +4035,7 @@ static int action_confbridgelist_item(struct mansession *s, const char *id_text,
AST_YESNO(ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)),
AST_YESNO(ast_test_flag(&user->u_profile, USER_OPT_WAITMARKED)),
AST_YESNO(ast_test_flag(&user->u_profile, USER_OPT_ENDMARKED)),
AST_YESNO(ast_test_flag(&user->u_profile, USER_OPT_ENDMARKEDANY)),
AST_YESNO(waiting),
AST_YESNO(user->muted),
AST_YESNO(user->talking),

View File

@ -103,6 +103,14 @@
receiver to their ear while entering DTMF.</para>
<argument name="n" required="true" />
</option>
<option name="c">
<para>Load the specified config file instead of voicemail.conf</para>
<argument name="filename" required="true" />
</option>
<option name="s">
<para>Skip calling the extension, instead set it in the <variable>DIRECTORY_EXTEN</variable>
channel variable.</para>
</option>
</optionlist>
<note><para>Only one of the <replaceable>f</replaceable>, <replaceable>l</replaceable>, or <replaceable>b</replaceable>
options may be specified. <emphasis>If more than one is specified</emphasis>, then Directory will act as
@ -114,12 +122,12 @@
<description>
<para>This application will present the calling channel with a directory of extensions from which they can search
by name. The list of names and corresponding extensions is retrieved from the
voicemail configuration file, <filename>voicemail.conf</filename>.</para>
voicemail configuration file, <filename>voicemail.conf</filename>, or from the specified filename.</para>
<para>This application will immediately exit if one of the following DTMF digits are
received and the extension to jump to exists:</para>
<para><literal>0</literal> - Jump to the 'o' extension, if it exists.</para>
<para><literal>*</literal> - Jump to the 'a' extension, if it exists.</para>
<para>This application will set the following channel variable before completion:</para>
<para>This application will set the following channel variables before completion:</para>
<variablelist>
<variable name="DIRECTORY_RESULT">
<para>Reason Directory application exited.</para>
@ -131,6 +139,10 @@
<value name="USEREXIT">User exited with '#' during selection</value>
<value name="FAILED">The application failed</value>
</variable>
<variable name="DIRECTORY_EXTEN">
<para>If the skip calling option is set this will be set to the selected extension
provided one is selected.</para>
</variable>
</variablelist>
</description>
</application>
@ -153,6 +165,8 @@ enum {
OPT_PAUSE = (1 << 5),
OPT_NOANSWER = (1 << 6),
OPT_ALIAS = (1 << 7),
OPT_CONFIG_FILE = (1 << 8),
OPT_SKIP = (1 << 9),
};
enum {
@ -160,8 +174,9 @@ enum {
OPT_ARG_LASTNAME = 1,
OPT_ARG_EITHER = 2,
OPT_ARG_PAUSE = 3,
OPT_ARG_FILENAME = 4,
/* This *must* be the last value in this enum! */
OPT_ARG_ARRAY_SIZE = 4,
OPT_ARG_ARRAY_SIZE = 5,
};
struct directory_item {
@ -183,6 +198,8 @@ AST_APP_OPTIONS(directory_app_options, {
AST_APP_OPTION('m', OPT_SELECTFROMMENU),
AST_APP_OPTION('n', OPT_NOANSWER),
AST_APP_OPTION('a', OPT_ALIAS),
AST_APP_OPTION_ARG('c', OPT_CONFIG_FILE, OPT_ARG_FILENAME),
AST_APP_OPTION('s', OPT_SKIP),
});
static int compare(const char *text, const char *template)
@ -318,6 +335,9 @@ static int select_entry(struct ast_channel *chan, const char *dialcontext, const
if (ast_test_flag(flags, OPT_FROMVOICEMAIL)) {
/* We still want to set the exten though */
ast_channel_exten_set(chan, item->exten);
} else if (ast_test_flag(flags, OPT_SKIP)) {
/* Skip calling the extension, only set it in the channel variable. */
pbx_builtin_setvar_helper(chan, "DIRECTORY_EXTEN", item->exten);
} else if (ast_goto_if_exists(chan, S_OR(dialcontext, item->context), item->exten, 1)) {
ast_log(LOG_WARNING,
"Can't find extension '%s' in context '%s'. "
@ -458,7 +478,7 @@ static int select_item_menu(struct ast_channel *chan, struct directory_item **it
AST_THREADSTORAGE(commonbuf);
static struct ast_config *realtime_directory(char *context)
static struct ast_config *realtime_directory(char *context, const char *filename)
{
struct ast_config *cfg;
struct ast_config *rtdata = NULL;
@ -475,14 +495,14 @@ static struct ast_config *realtime_directory(char *context)
}
/* Load flat file config. */
cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
cfg = ast_config_load(filename, config_flags);
if (!cfg) {
/* Loading config failed. */
ast_log(LOG_WARNING, "Loading config failed.\n");
return NULL;
} else if (cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", VOICEMAIL_CONFIG);
ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", filename);
return NULL;
}
@ -867,7 +887,9 @@ static int directory_exec(struct ast_channel *chan, const char *data)
if (args.options && ast_app_parse_options(directory_app_options, &flags, opts, args.options))
return -1;
if (!(cfg = realtime_directory(args.vmcontext))) {
cfg = realtime_directory(args.vmcontext, S_OR(opts[OPT_ARG_FILENAME], VOICEMAIL_CONFIG));
if (!cfg) {
ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
return -1;
}

383
apps/app_if.c Normal file
View File

@ -0,0 +1,383 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright 2022, Naveen Albert <asterisk@phreaknet.org>
*
* Naveen Albert <asterisk@phreaknet.org>
*
* 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 If Branch Implementation
*
* \author Naveen Albert <asterisk@phreaknet.org>
*
* \ingroup applications
*/
/*** MODULEINFO
<support_level>extended</support_level>
***/
#include "asterisk.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/channel.h"
/*** DOCUMENTATION
<application name="If" language="en_US">
<synopsis>
Start an if branch.
</synopsis>
<syntax>
<parameter name="expr" required="true" />
</syntax>
<description>
<para>Start an If branch. Execution will continue inside the branch
if expr is true.</para>
<note><para>This application (and related applications) set variables
internally during execution.</para></note>
</description>
<see-also>
<ref type="application">ElseIf</ref>
<ref type="application">Else</ref>
<ref type="application">EndIf</ref>
<ref type="application">ExitIf</ref>
</see-also>
</application>
<application name="ElseIf" language="en_US">
<synopsis>
Start an else if branch.
</synopsis>
<syntax>
<parameter name="expr" required="true" />
</syntax>
<description>
<para>Start an optional ElseIf branch. Execution will continue inside the branch
if expr is true and if previous If and ElseIf branches evaluated to false.</para>
<para>Please note that execution inside a true If branch will fallthrough into
ElseIf unless the If segment is terminated with an ExitIf call. This is only
necessary with ElseIf but not with Else.</para>
</description>
<see-also>
<ref type="application">If</ref>
<ref type="application">Else</ref>
<ref type="application">EndIf</ref>
<ref type="application">ExitIf</ref>
</see-also>
</application>
<application name="Else" language="en_US">
<synopsis>
Define an optional else branch.
</synopsis>
<syntax>
<parameter name="expr" required="true" />
</syntax>
<description>
<para>Start an Else branch. Execution will jump here if all previous
If and ElseIf branches evaluated to false.</para>
</description>
<see-also>
<ref type="application">If</ref>
<ref type="application">ElseIf</ref>
<ref type="application">EndIf</ref>
<ref type="application">ExitIf</ref>
</see-also>
</application>
<application name="EndIf" language="en_US">
<synopsis>
End an if branch.
</synopsis>
<syntax />
<description>
<para>Ends the branch begun by the preceding <literal>If()</literal> application.</para>
</description>
<see-also>
<ref type="application">If</ref>
<ref type="application">ElseIf</ref>
<ref type="application">Else</ref>
<ref type="application">ExitIf</ref>
</see-also>
</application>
<application name="ExitIf" language="en_US">
<synopsis>
End an If branch.
</synopsis>
<syntax />
<description>
<para>Exits an <literal>If()</literal> branch, whether or not it has completed.</para>
</description>
<see-also>
<ref type="application">If</ref>
<ref type="application">ElseIf</ref>
<ref type="application">Else</ref>
<ref type="application">EndIf</ref>
</see-also>
</application>
***/
static char *if_app = "If";
static char *elseif_app = "ElseIf";
static char *else_app = "Else";
static char *stop_app = "EndIf";
static char *exit_app = "ExitIf";
#define VAR_SIZE 64
static const char *get_index(struct ast_channel *chan, const char *prefix, int idx)
{
char varname[VAR_SIZE];
snprintf(varname, VAR_SIZE, "%s_%d", prefix, idx);
return pbx_builtin_getvar_helper(chan, varname);
}
static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
{
struct ast_exten *e;
struct ast_context *c2;
int idx;
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);
if (e)
return e;
}
}
}
return NULL;
}
static int find_matching_endif(struct ast_channel *chan, const char *otherapp)
{
struct ast_context *c;
int res = -1;
if (ast_rdlock_contexts()) {
ast_log(LOG_ERROR, "Failed to lock contexts list\n");
return -1;
}
for (c = ast_walk_contexts(NULL); c; c = ast_walk_contexts(c)) {
struct ast_exten *e;
if (!ast_rdlock_context(c)) {
if (!strcmp(ast_get_context_name(c), ast_channel_context(chan))) {
/* This is the matching context we want */
int cur_priority = ast_channel_priority(chan) + 1, level = 1;
for (e = find_matching_priority(c, ast_channel_exten(chan), cur_priority,
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
e;
e = find_matching_priority(c, ast_channel_exten(chan), ++cur_priority,
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
if (!strcasecmp(ast_get_extension_app(e), "IF")) {
level++;
} else if (!strcasecmp(ast_get_extension_app(e), "ENDIF")) {
level--;
}
if (!otherapp && level == 0) {
res = cur_priority;
break;
} else if (otherapp && level == 1 && !strcasecmp(ast_get_extension_app(e), otherapp)) {
res = cur_priority;
break;
}
}
}
ast_unlock_context(c);
if (res > 0) {
break;
}
}
}
ast_unlock_contexts();
return res;
}
static int if_helper(struct ast_channel *chan, const char *data, int end)
{
int res = 0;
const char *if_pri = NULL;
char *my_name = NULL;
const char *label = NULL;
char varname[VAR_SIZE + 3]; /* + IF_ */
char end_varname[sizeof(varname) + 4]; /* + END_ + sizeof(varname) */
const char *prefix = "IF";
size_t size = 0;
int used_index_i = -1, x = 0;
char used_index[VAR_SIZE] = "0", new_index[VAR_SIZE] = "0";
if (!chan) {
return -1;
}
for (x = 0 ;; x++) {
if (get_index(chan, prefix, x)) {
used_index_i = x;
} else {
break;
}
}
snprintf(used_index, sizeof(used_index), "%d", used_index_i);
snprintf(new_index, sizeof(new_index), "%d", used_index_i + 1);
size = strlen(ast_channel_context(chan)) + strlen(ast_channel_exten(chan)) + 32;
my_name = ast_alloca(size);
memset(my_name, 0, size);
snprintf(my_name, size, "%s_%s_%d", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
ast_channel_lock(chan);
if (end > 1) {
label = used_index;
} else if (!(label = pbx_builtin_getvar_helper(chan, my_name))) {
label = new_index;
pbx_builtin_setvar_helper(chan, my_name, label);
}
snprintf(varname, sizeof(varname), "%s_%s", prefix, label);
if ((if_pri = pbx_builtin_getvar_helper(chan, varname)) && !end) {
if_pri = ast_strdupa(if_pri);
snprintf(end_varname,sizeof(end_varname),"END_%s",varname);
}
ast_channel_unlock(chan);
if ((end <= 1 && !pbx_checkcondition(ast_strdupa(data))) || (end > 1)) {
/* Condition Met (clean up helper vars) */
const char *goto_str;
int pri, endifpri;
pbx_builtin_setvar_helper(chan, varname, NULL);
pbx_builtin_setvar_helper(chan, my_name, NULL);
snprintf(end_varname,sizeof(end_varname),"END_%s",varname);
ast_channel_lock(chan);
endifpri = find_matching_endif(chan, NULL);
if ((goto_str = pbx_builtin_getvar_helper(chan, end_varname))) {
ast_parseable_goto(chan, goto_str);
pbx_builtin_setvar_helper(chan, end_varname, NULL);
} else if (end <= 1 && (pri = find_matching_endif(chan, "ElseIf")) > 0 && pri < endifpri) {
pri--; /* back up a priority, since it returned the priority after the ElseIf */
/* If is false, and ElseIf exists, so jump to ElseIf */
ast_verb(3, "Taking conditional false branch, jumping to priority %d\n", pri);
ast_channel_priority_set(chan, pri);
} else if (end <= 1 && (pri = find_matching_endif(chan, "Else")) > 0 && pri < endifpri) {
/* don't need to back up a priority, because we don't actually need to execute Else, just jump to the priority after. Directly executing Else will exit the conditional. */
/* If is false, and Else exists, so jump to Else */
ast_verb(3, "Taking absolute false branch, jumping to priority %d\n", pri);
ast_channel_priority_set(chan, pri);
} else {
pri = endifpri;
if (pri > 0) {
ast_verb(3, "Exiting conditional, jumping to priority %d\n", pri);
ast_channel_priority_set(chan, pri);
} else if (end == 4) { /* Condition added because of end > 0 instead of end == 4 */
ast_log(LOG_WARNING, "Couldn't find matching EndIf? (If at %s@%s priority %d)\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
}
}
ast_channel_unlock(chan);
return res;
}
if (end <= 1 && !if_pri) {
char *goto_str;
size = strlen(ast_channel_context(chan)) + strlen(ast_channel_exten(chan)) + 32;
goto_str = ast_alloca(size);
memset(goto_str, 0, size);
snprintf(goto_str, size, "%s,%s,%d", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
pbx_builtin_setvar_helper(chan, varname, goto_str);
} else if (end > 1 && if_pri) {
/* END of branch */
snprintf(end_varname, sizeof(end_varname), "END_%s", varname);
if (!pbx_builtin_getvar_helper(chan, end_varname)) {
char *goto_str;
size = strlen(ast_channel_context(chan)) + strlen(ast_channel_exten(chan)) + 32;
goto_str = ast_alloca(size);
memset(goto_str, 0, size);
snprintf(goto_str, size, "%s,%s,%d", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan)+1);
pbx_builtin_setvar_helper(chan, end_varname, goto_str);
}
ast_parseable_goto(chan, if_pri);
}
return res;
}
static int if_exec(struct ast_channel *chan, const char *data) {
return if_helper(chan, data, 0);
}
static int elseif_exec(struct ast_channel *chan, const char *data) {
return if_helper(chan, data, 1);
}
static int end_exec(struct ast_channel *chan, const char *data) {
return if_helper(chan, data, 2);
}
static int else_exec(struct ast_channel *chan, const char *data) {
return if_helper(chan, data, 3);
}
static int exit_exec(struct ast_channel *chan, const char *data) {
return if_helper(chan, data, 4);
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(if_app);
res |= ast_unregister_application(elseif_app);
res |= ast_unregister_application(stop_app);
res |= ast_unregister_application(else_app);
res |= ast_unregister_application(exit_app);
return res;
}
static int load_module(void)
{
int res;
res = ast_register_application_xml(if_app, if_exec);
res |= ast_register_application_xml(elseif_app, elseif_exec);
res |= ast_register_application_xml(stop_app, end_exec);
res |= ast_register_application_xml(else_app, else_exec);
res |= ast_register_application_xml(exit_app, exit_exec);
return res;
}
AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "If Branch and Conditional Execution");

View File

@ -639,6 +639,82 @@
</syntax>
</managerEventInstance>
</managerEvent>
<managerEvent language="en_US" name="MeetmeList">
<managerEventInstance class="EVENT_FLAG_CALL">
<synopsis>Raised in response to a MeetmeList command.</synopsis>
<syntax>
<parameter name="Conference">
<para>Conference ID.</para>
</parameter>
<parameter name="UserNumber">
<para>User ID.</para>
</parameter>
<parameter name="CallerIDNum">
<para>Caller ID number.</para>
</parameter>
<parameter name="CallerIDName">
<para>Caller ID name.</para>
</parameter>
<parameter name="ConnectedLineNum">
<para>Connected Line number.</para>
</parameter>
<parameter name="ConnectedLineName">
<para>Connected Line name.</para>
</parameter>
<parameter name="Channel">
<para>Channel name</para>
</parameter>
<parameter name="Admin">
<para>Whether or not the user is an admin.</para>
</parameter>
<parameter name="Role">
<para>User role. Can be "Listen only", "Talk only", or "Talk and listen".</para>
</parameter>
<parameter name="MarkedUser">
<para>Whether or not the user is a marked user.</para>
</parameter>
<parameter name="Muted">
<para>Whether or not the user is currently muted.</para>
</parameter>
<parameter name="Talking">
<para>Whether or not the user is currently talking.</para>
</parameter>
</syntax>
<see-also>
<ref type="manager">MeetmeList</ref>
<ref type="application">MeetMe</ref>
</see-also>
</managerEventInstance>
</managerEvent>
<managerEvent language="en_US" name="MeetmeListRooms">
<managerEventInstance class="EVENT_FLAG_CALL">
<synopsis>Raised in response to a MeetmeListRooms command.</synopsis>
<syntax>
<parameter name="Conference">
<para>Conference ID.</para>
</parameter>
<parameter name="Parties">
<para>Number of parties in the conference.</para>
</parameter>
<parameter name="Marked">
<para>Number of marked users in the conference.</para>
</parameter>
<parameter name="Activity">
<para>Total duration of conference in HH:MM:SS format.</para>
</parameter>
<parameter name="Creation">
<para>How the conference was created: "Dyanmic" or "Static".</para>
</parameter>
<parameter name="Locked">
<para>Whether or not the conference is locked.</para>
</parameter>
</syntax>
<see-also>
<ref type="manager">MeetmeListRooms</ref>
<ref type="application">MeetMe</ref>
</see-also>
</managerEventInstance>
</managerEvent>
***/
#define CONFIG_FILE_NAME "meetme.conf"
@ -6073,7 +6149,7 @@ struct run_station_args {
static void answer_trunk_chan(struct ast_channel *chan)
{
ast_answer(chan);
ast_raw_answer(chan);
ast_indicate(chan, -1);
}
@ -6918,8 +6994,18 @@ static void *dial_trunk(void *data)
return NULL;
}
for (;;) {
/* Wait for dial to end, while servicing the channel */
while (ast_waitfor(trunk_ref->chan, 100)) {
unsigned int done = 0;
struct ast_frame *fr = ast_read(trunk_ref->chan);
if (!fr) {
ast_debug(1, "Channel %s did not return a frame, must have hung up\n", ast_channel_name(trunk_ref->chan));
done = 1;
break;
}
ast_frfree(fr); /* Ignore while dialing */
switch ((dial_res = ast_dial_state(dial))) {
case AST_DIAL_RESULT_ANSWERED:
trunk_ref->trunk->chan = ast_dial_answered(dial);
@ -6956,8 +7042,6 @@ static void *dial_trunk(void *data)
last_state = current_state;
}
/* avoid tight loop... sleep for 1/10th second */
ast_safe_sleep(trunk_ref->chan, 100);
}
if (!trunk_ref->trunk->chan) {
@ -7116,8 +7200,10 @@ static int sla_station_exec(struct ast_channel *chan, const char *data)
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
/* Create a thread to dial the trunk and dump it into the conference.
* However, we want to wait until the trunk has been dialed and the
* conference is created before continuing on here. */
ast_autoservice_start(chan);
* conference is created before continuing on here.
* Don't autoservice the channel or we'll have multiple threads
* handling it. dial_trunk services the channel.
*/
ast_mutex_init(&cond_lock);
ast_cond_init(&cond, NULL);
ast_mutex_lock(&cond_lock);
@ -7126,7 +7212,7 @@ static int sla_station_exec(struct ast_channel *chan, const char *data)
ast_mutex_unlock(&cond_lock);
ast_mutex_destroy(&cond_lock);
ast_cond_destroy(&cond);
ast_autoservice_stop(chan);
if (!trunk_ref->trunk->chan) {
ast_debug(1, "Trunk didn't get created. chan: %lx\n", (unsigned long) trunk_ref->trunk->chan);
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");

View File

@ -235,6 +235,7 @@ static const char sendmf_name[] = "SendMF";
* \param buflen Size of buffer
* \param timeout ms to wait for all digits before giving up
* \param features Any additional DSP features to use
* \param laxkp Receive digits even if KP not received
* \param override Start over if we receive additional KPs
* \param no_kp Don't include KP in the output
* \param no_st Don't include start digits in the output

View File

@ -90,6 +90,16 @@
<para>Play a periodic beep while this call is being recorded.</para>
<argument name="interval"><para>Interval, in seconds. Default is 15.</para></argument>
</option>
<option name="c">
<para>Use the real Caller ID from the channel for the voicemail Caller ID.</para>
<para>By default, the Connected Line is used. If you want the channel caller's
real number, you may need to specify this option.</para>
</option>
<option name="d">
<para>Delete the recording file as soon as MixMonitor is done with it.</para>
<para>For example, if you use the m option to dispatch the recording to a voicemail box,
you can specify this option to delete the original copy of it afterwards.</para>
</option>
<option name="v">
<para>Adjust the <emphasis>heard</emphasis> volume by a factor of <replaceable>x</replaceable>
(range <literal>-4</literal> to <literal>4</literal>)</para>
@ -407,6 +417,8 @@ enum mixmonitor_flags {
MUXFLAG_BEEP_STOP = (1 << 13),
MUXFLAG_DEPRECATED_RWSYNC = (1 << 14),
MUXFLAG_NO_RWSYNC = (1 << 15),
MUXFLAG_AUTO_DELETE = (1 << 16),
MUXFLAG_REAL_CALLERID = (1 << 17),
};
enum mixmonitor_args {
@ -427,6 +439,8 @@ AST_APP_OPTIONS(mixmonitor_opts, {
AST_APP_OPTION('a', MUXFLAG_APPEND),
AST_APP_OPTION('b', MUXFLAG_BRIDGED),
AST_APP_OPTION_ARG('B', MUXFLAG_BEEP, OPT_ARG_BEEP_INTERVAL),
AST_APP_OPTION('c', MUXFLAG_REAL_CALLERID),
AST_APP_OPTION('d', MUXFLAG_AUTO_DELETE),
AST_APP_OPTION('p', MUXFLAG_BEEP_START),
AST_APP_OPTION('P', MUXFLAG_BEEP_STOP),
AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME),
@ -860,6 +874,19 @@ static void *mixmonitor_thread(void *obj)
ast_debug(3, "No recipients to forward monitor to, moving on.\n");
}
if (ast_test_flag(mixmonitor, MUXFLAG_AUTO_DELETE)) {
ast_debug(3, "Deleting our copies of recording files\n");
if (!ast_strlen_zero(fs_ext)) {
ast_filedelete(mixmonitor->filename, fs_ext);
}
if (!ast_strlen_zero(fs_read_ext)) {
ast_filedelete(mixmonitor->filename_read, fs_ext);
}
if (!ast_strlen_zero(fs_write_ext)) {
ast_filedelete(mixmonitor->filename_write, fs_ext);
}
}
mixmonitor_free(mixmonitor);
ast_module_unref(ast_module_info->self);
@ -1015,20 +1042,37 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
if (!ast_strlen_zero(recipients)) {
char callerid[256];
struct ast_party_connected_line *connected;
ast_channel_lock(chan);
/* We use the connected line of the invoking channel for caller ID. */
/* We use the connected line of the invoking channel for caller ID,
* unless we've been told to use the Caller ID.
* The initial use for this relied on Connected Line to get the
* actual number for recording with Digium phones,
* but in generic use the Caller ID is likely what people want.
*/
connected = ast_channel_connected(chan);
ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
connected->id.name.str, connected->id.number.valid,
connected->id.number.str);
ast_callerid_merge(callerid, sizeof(callerid),
S_COR(connected->id.name.valid, connected->id.name.str, NULL),
S_COR(connected->id.number.valid, connected->id.number.str, NULL),
"Unknown");
if (ast_test_flag(mixmonitor, MUXFLAG_REAL_CALLERID)) {
struct ast_party_caller *caller;
caller = ast_channel_caller(chan);
ast_debug(3, "Caller ID = %d - %s : %d - %s\n", caller->id.name.valid,
caller->id.name.str, caller->id.number.valid,
caller->id.number.str);
ast_callerid_merge(callerid, sizeof(callerid),
S_COR(caller->id.name.valid, caller->id.name.str, NULL),
S_COR(caller->id.number.valid, caller->id.number.str, NULL),
"Unknown");
} else {
struct ast_party_connected_line *connected;
connected = ast_channel_connected(chan);
ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
connected->id.name.str, connected->id.number.valid,
connected->id.number.str);
ast_callerid_merge(callerid, sizeof(callerid),
S_COR(connected->id.name.valid, connected->id.name.str, NULL),
S_COR(connected->id.number.valid, connected->id.number.str, NULL),
"Unknown");
}
ast_string_field_set(mixmonitor, call_context, ast_channel_context(chan));
ast_string_field_set(mixmonitor, call_macrocontext, ast_channel_macrocontext(chan));

View File

@ -101,7 +101,7 @@ static int mp3play(const char *filename, unsigned int sampling_rate, int fd)
/* Execute mpg123, but buffer if it's a net connection */
if (!strncasecmp(filename, "http://", 7) && strstr(filename, ".m3u")) {
char buffer_size_str[8];
snprintf(buffer_size_str, 8, "%u", (int) 0.5*2*sampling_rate/1000); // 0.5 seconds for a live stream
snprintf(buffer_size_str, 8, "%u", (int) 0.5*2*sampling_rate/1000); /* 0.5 seconds for a live stream */
/* Most commonly installed in /usr/local/bin */
execl(LOCAL_MPG_123, "mpg123", "-e", "s16", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, "-@", filename, (char *)NULL);
/* But many places has it in /usr/bin */
@ -111,7 +111,7 @@ static int mp3play(const char *filename, unsigned int sampling_rate, int fd)
}
else if (!strncasecmp(filename, "http://", 7)) {
char buffer_size_str[8];
snprintf(buffer_size_str, 8, "%u", 6*2*sampling_rate/1000); // 6 seconds for a remote MP3 file
snprintf(buffer_size_str, 8, "%u", 6*2*sampling_rate/1000); /* 6 seconds for a remote MP3 file */
/* Most commonly installed in /usr/local/bin */
execl(LOCAL_MPG_123, "mpg123", "-e", "s16", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, filename, (char *)NULL);
/* But many places has it in /usr/bin */

View File

@ -507,8 +507,7 @@ static int playback_exec(struct ast_channel *chan, const char *data)
if (!res) {
res = ast_waitstream(chan, "");
ast_stopstream(chan);
}
if (res) {
} else {
if (!ast_check_hangup(chan)) {
ast_log(LOG_WARNING, "Playback failed on %s for %s\n", ast_channel_name(chan), (char *)data);
}

View File

@ -1277,7 +1277,7 @@
</syntax>
<see-also>
<ref type="application">PauseQueueMember</ref>
<ref type="application">UnPauseQueueMember</ref>
<ref type="application">UnpauseQueueMember</ref>
</see-also>
</managerEventInstance>
</managerEvent>
@ -2956,7 +2956,11 @@ static void init_queue(struct call_queue *q)
q->timeout = DEFAULT_TIMEOUT;
q->maxlen = 0;
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, "");
q->announcefrequency = 0;
q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
@ -2985,7 +2989,10 @@ static void init_queue(struct call_queue *q)
q->periodicannouncefrequency = 0;
q->randomperiodicannounce = 0;
q->numperiodicannounce = 0;
q->relativeperiodicannounce = 0;
q->autopause = QUEUE_AUTOPAUSE_OFF;
q->autopausebusy = 0;
q->autopauseunavail = 0;
q->timeoutpriority = TIMEOUT_PRIORITY_APP;
q->autopausedelay = 0;
if (!q->members) {
@ -3010,6 +3017,7 @@ static void init_queue(struct call_queue *q)
ast_string_field_set(q, sound_minute, "queue-minute");
ast_string_field_set(q, sound_seconds, "queue-seconds");
ast_string_field_set(q, sound_thanks, "queue-thankyou");
ast_string_field_set(q, sound_callerannounce, "");
ast_string_field_set(q, sound_reporthold, "queue-reporthold");
if (!q->sound_periodicannounce[0]) {
@ -8172,7 +8180,7 @@ static int pqm_exec(struct ast_channel *chan, const char *data)
return 0;
}
/*! \brief UnPauseQueueMember application */
/*! \brief UnpauseQueueMember application */
static int upqm_exec(struct ast_channel *chan, const char *data)
{
char *parse;
@ -8193,7 +8201,7 @@ static int upqm_exec(struct ast_channel *chan, const char *data)
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.interface)) {
ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
ast_log(LOG_WARNING, "Missing interface argument to UnpauseQueueMember ([queuename],interface[,options[,reason]])\n");
return -1;
}

View File

@ -85,6 +85,13 @@
and you will need to rely on duration and max digits
for ending input.</para>
</option>
<option name="e">
<para>to read the terminator as the digit string if the
only digit read is the terminator. This is for cases
where the terminator is a valid digit, but only by itself.
ie; <literal>1234</literal> and <literal>#</literal> are
valid, but <literal>1234#</literal> is not.</para>
</option>
</optionlist>
</parameter>
<parameter name="attempts">
@ -125,6 +132,7 @@ enum read_option_flags {
OPT_INDICATION = (1 << 1),
OPT_NOANSWER = (1 << 2),
OPT_TERMINATOR = (1 << 3),
OPT_KEEP_TERMINATOR = (1 << 4),
};
enum {
@ -138,6 +146,7 @@ AST_APP_OPTIONS(read_app_options, {
AST_APP_OPTION('i', OPT_INDICATION),
AST_APP_OPTION('n', OPT_NOANSWER),
AST_APP_OPTION_ARG('t', OPT_TERMINATOR, OPT_ARG_TERMINATOR),
AST_APP_OPTION('e', OPT_KEEP_TERMINATOR),
});
static char *app = "Read";
@ -261,12 +270,20 @@ static int read_exec(struct ast_channel *chan, const char *data)
}
} else {
res = ast_app_getdata_terminator(chan, arglist.filename, tmp, maxdigits, to, terminator);
if (res == AST_GETDATA_COMPLETE || res == AST_GETDATA_EMPTY_END_TERMINATED)
if (res == AST_GETDATA_COMPLETE) {
status = "OK";
else if (res == AST_GETDATA_TIMEOUT)
} else if (res == AST_GETDATA_EMPTY_END_TERMINATED) {
if (ast_test_flag(&flags, OPT_KEEP_TERMINATOR)) {
/* if the option is set to do so, read the
returned string as the terminator string */
ast_copy_string(tmp, terminator, sizeof(tmp));
}
status = "OK";
} else if (res == AST_GETDATA_TIMEOUT) {
status = "TIMEOUT";
else if (res == AST_GETDATA_INTERRUPTED)
} else if (res == AST_GETDATA_INTERRUPTED) {
status = "INTERRUPTED";
}
}
if (res > -1) {
pbx_builtin_setvar_helper(chan, arglist.variable, tmp);

View File

@ -57,6 +57,15 @@
<parameter name="channel" required="false">
<para>Channel where digits will be played</para>
</parameter>
<parameter name="options">
<optionlist>
<option name="a">
<para>Answer the channel specified by the <literal>channel</literal>
parameter if it is not already up. If no <literal>channel</literal>
parameter is provided, the current channel will be answered.</para>
</option>
</optionlist>
</parameter>
</syntax>
<description>
<para>It will send all digits or terminate if it encounters an error.</para>
@ -90,6 +99,19 @@
</manager>
***/
enum read_option_flags {
OPT_ANSWER = (1 << 0),
};
AST_APP_OPTIONS(senddtmf_app_options, {
AST_APP_OPTION('a', OPT_ANSWER),
});
enum {
/* note: this entry _MUST_ be the last one in the enum */
OPT_ARG_ARRAY_SIZE,
};
static const char senddtmf_name[] = "SendDTMF";
static int senddtmf_exec(struct ast_channel *chan, const char *vdata)
@ -100,11 +122,14 @@ static int senddtmf_exec(struct ast_channel *chan, const char *vdata)
struct ast_channel *chan_found = NULL;
struct ast_channel *chan_dest = chan;
struct ast_channel *chan_autoservice = NULL;
char *opt_args[OPT_ARG_ARRAY_SIZE];
struct ast_flags flags = {0};
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(digits);
AST_APP_ARG(dinterval);
AST_APP_ARG(duration);
AST_APP_ARG(channel);
AST_APP_ARG(options);
);
if (ast_strlen_zero(vdata)) {
@ -136,6 +161,12 @@ static int senddtmf_exec(struct ast_channel *chan, const char *vdata)
chan_autoservice = chan;
}
}
if (!ast_strlen_zero(args.options)) {
ast_app_parse_options(senddtmf_app_options, &flags, opt_args, args.options);
}
if (ast_test_flag(&flags, OPT_ANSWER)) {
ast_auto_answer(chan_dest);
}
res = ast_dtmf_stream(chan_dest, chan_autoservice, args.digits,
dinterval <= 0 ? 250 : dinterval, duration);
if (chan_found) {

View File

@ -139,8 +139,6 @@
</example>
</description>
<see-also>
<ref type="application">SendImage</ref>
<ref type="application">SendURL</ref>
<ref type="application">ReceiveText</ref>
</see-also>
</application>
@ -182,8 +180,6 @@
</description>
<see-also>
<ref type="application">SendText</ref>
<ref type="application">SendImage</ref>
<ref type="application">SendURL</ref>
</see-also>
</application>
***/

471
apps/app_signal.c Normal file
View File

@ -0,0 +1,471 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2022, Naveen Albert
*
* Naveen Albert <asterisk@phreaknet.org>
*
* 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 Channel signaling applications
*
* \author Naveen Albert <asterisk@phreaknet.org>
*
* \ingroup applications
*/
/*** MODULEINFO
<support_level>extended</support_level>
***/
#include "asterisk.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/module.h"
/*** DOCUMENTATION
<application name="Signal" language="en_US">
<synopsis>
Sends a signal to any waiting channels.
</synopsis>
<syntax>
<parameter name="signalname" required="true">
<para>Name of signal to send.</para>
</parameter>
<parameter name="payload" required="false">
<para>Payload data to deliver.</para>
</parameter>
</syntax>
<description>
<para>Sends a named signal to any channels that may be
waiting for one. Acts as a producer in a simple
message queue.</para>
<variablelist>
<variable name="SIGNALSTATUS">
<value name="SUCCESS">
Signal was successfully sent to at least
one listener for processing.
</value>
<value name="FAILURE">
Signal could not be sent or nobody
was listening for this signal.
</value>
</variable>
</variablelist>
<example title="Send a signal named workdone">
same => n,Signal(workdone,Work has completed)
</example>
</description>
<see-also>
<ref type="application">WaitForSignal</ref>
</see-also>
</application>
<application name="WaitForSignal" language="en_US">
<synopsis>
Waits for a named signal on a channel.
</synopsis>
<syntax>
<parameter name="signalname" required="true">
<para>Name of signal to send.</para>
</parameter>
<parameter name="signaltimeout" required="false">
<para>Maximum time, in seconds, to wait for signal.</para>
</parameter>
</syntax>
<description>
<para>Waits for <replaceable>signaltimeout</replaceable> seconds on the current
channel to receive a signal with name <replaceable>signalname</replaceable>.
Acts as a consumer in a simple message queue.</para>
<para>Result of signal wait will be stored in the following variables:</para>
<variablelist>
<variable name="WAITFORSIGNALSTATUS">
<value name="SIGNALED">
Signal was received.
</value>
<value name="TIMEOUT">
Timed out waiting for signal.
</value>
<value name="HANGUP">
Channel hung up before signal was received.
</value>
</variable>
<variable name="WAITFORSIGNALPAYLOAD">
<para>Data payload attached to signal, if it exists</para>
</variable>
</variablelist>
<example title="Wait for the workdone signal, indefinitely, and print out payload">
same => n,WaitForSignal(workdone)
same => n,NoOp(Received: ${WAITFORSIGNALPAYLOAD})
</example>
</description>
<see-also>
<ref type="application">Signal</ref>
</see-also>
</application>
***/
static const char * const app = "Signal";
static const char * const app2 = "WaitForSignal";
struct signalitem {
ast_mutex_t lock;
char name[AST_MAX_CONTEXT];
int sig_alert_pipe[2];
int watchers;
unsigned int signaled:1;
char *payload;
AST_LIST_ENTRY(signalitem) entry; /*!< Next Signal item */
};
static AST_RWLIST_HEAD_STATIC(signals, signalitem);
static struct signalitem *alloc_signal(const char *sname)
{
struct signalitem *s;
if (!(s = ast_calloc(1, sizeof(*s)))) {
return NULL;
}
ast_mutex_init(&s->lock);
ast_copy_string(s->name, sname, sizeof(s->name));
s->sig_alert_pipe[0] = -1;
s->sig_alert_pipe[1] = -1;
s->watchers = 0;
s->payload = NULL;
ast_alertpipe_init(s->sig_alert_pipe);
return s;
}
static int dealloc_signal(struct signalitem *s)
{
if (s->watchers) { /* somebody is still using us... refuse to go away */
ast_debug(1, "Signal '%s' is still being used by %d listener(s)\n", s->name, s->watchers);
return -1;
}
ast_alertpipe_close(s->sig_alert_pipe);
ast_mutex_destroy(&s->lock);
if (s->payload) {
ast_free(s->payload);
s->payload = NULL;
}
ast_free(s);
s = NULL;
return 0;
}
static int remove_signal(char *sname)
{
int res = -1;
struct signalitem *s;
AST_LIST_TRAVERSE_SAFE_BEGIN(&signals, s, entry) {
if (!strcmp(s->name, sname)) {
AST_LIST_REMOVE_CURRENT(entry);
res = dealloc_signal(s);
ast_debug(1, "Removed signal '%s'\n", sname);
}
}
AST_LIST_TRAVERSE_SAFE_END;
return res;
}
static struct signalitem *get_signal(char *sname, int addnew)
{
struct signalitem *s = NULL;
AST_RWLIST_WRLOCK(&signals);
AST_LIST_TRAVERSE(&signals, s, entry) {
if (!strcasecmp(s->name, sname)) {
ast_debug(1, "Using existing signal item '%s'\n", sname);
break;
}
}
if (!s) {
if (addnew) { /* signal doesn't exist, so create it */
s = alloc_signal(sname);
/* Totally fail if we fail to find/create an entry */
if (s) {
ast_debug(1, "Created new signal item '%s'\n", sname);
AST_RWLIST_INSERT_HEAD(&signals, s, entry);
} else {
ast_log(LOG_WARNING, "Failed to create signal item for '%s'\n", sname);
}
} else {
ast_debug(1, "Signal '%s' doesn't exist, and not creating it\n", sname);
}
}
AST_RWLIST_UNLOCK(&signals);
return s;
}
static int wait_for_signal_or_hangup(struct ast_channel *chan, char *signame, int timeout)
{
struct signalitem *s = NULL;
int ms, remaining_time, res = 1, goaway = 0;
struct timeval start;
struct ast_frame *frame = NULL;
remaining_time = timeout;
start = ast_tvnow();
s = get_signal(signame, 1);
ast_mutex_lock(&s->lock);
s->watchers = s->watchers + 1; /* we unlock, because a) other people need to use this and */
ast_mutex_unlock(&s->lock); /* b) the signal will be available to us as long as watchers > 0 */
while (timeout == 0 || remaining_time > 0) {
int ofd, exception;
ms = 1000;
errno = 0;
if (ast_waitfor_nandfds(&chan, 1, &s->sig_alert_pipe[0], 1, &exception, &ofd, &ms)) { /* channel won */
if (!(frame = ast_read(chan))) { /* channel hung up */
ast_debug(1, "Channel '%s' did not return a frame; probably hung up.\n", ast_channel_name(chan));
res = -1;
break;
} else {
ast_frfree(frame); /* handle frames */
}
} else if (ofd == s->sig_alert_pipe[0]) { /* fd won */
if (ast_alertpipe_read(s->sig_alert_pipe) == AST_ALERT_READ_SUCCESS) {
ast_debug(1, "Alert pipe has data for us\n");
res = 0;
break;
} else {
ast_debug(1, "Alert pipe does not have data for us\n");
}
} else { /* nobody won */
if (ms && (ofd < 0)) {
if (!((errno == 0) || (errno == EINTR))) {
ast_log(LOG_WARNING, "Something bad happened while channel '%s' was polling.\n", ast_channel_name(chan));
break;
}
} /* else, nothing happened */
}
if (timeout) {
remaining_time = ast_remaining_ms(start, timeout);
}
}
/* WRLOCK the list so that if we're going to destroy the signal now, nobody else can grab it before that happens. */
AST_RWLIST_WRLOCK(&signals);
ast_mutex_lock(&s->lock);
if (s->payload) {
pbx_builtin_setvar_helper(chan, "WAITFORSIGNALPAYLOAD", s->payload);
}
s->watchers = s->watchers - 1;
if (s->watchers) { /* folks are still waiting for this, pass it on... */
int save_errno = errno;
if (ast_alertpipe_write(s->sig_alert_pipe)) {
ast_log(LOG_WARNING, "%s: write() failed: %s\n", __FUNCTION__, strerror(errno));
}
errno = save_errno;
} else { /* nobody else is waiting for this */
goaway = 1; /* we were the last guy using this, so mark signal item for destruction */
}
ast_mutex_unlock(&s->lock);
if (goaway) {
/* remove_signal calls ast_mutex_destroy, so don't call it with the mutex itself locked. */
remove_signal(signame);
}
AST_RWLIST_UNLOCK(&signals);
return res;
}
static int send_signal(char *signame, char *payload)
{
struct signalitem *s;
int save_errno = errno;
int res = 0;
s = get_signal(signame, 0); /* if signal doesn't exist already, no point in creating it, because nobody could be waiting for it! */
if (!s) {
return -1; /* this signal didn't exist, so we can't send a signal for it */
}
/* at this point, we know someone is listening, since signals are destroyed when watchers gets down to 0 */
ast_mutex_lock(&s->lock);
s->signaled = 1;
if (payload && *payload) {
int len = strlen(payload);
if (s->payload) {
ast_free(s->payload); /* if there was already a payload, replace it */
s->payload = NULL;
}
s->payload = ast_malloc(len + 1);
if (!s->payload) {
ast_log(LOG_WARNING, "Failed to allocate signal payload '%s'\n", payload);
} else {
ast_copy_string(s->payload, payload, len + 1);
}
}
if (ast_alertpipe_write(s->sig_alert_pipe)) {
ast_log(LOG_WARNING, "%s: write() failed: %s\n", __FUNCTION__, strerror(errno));
s->signaled = 0; /* okay, so we didn't send a signal after all... */
res = -1;
}
errno = save_errno;
ast_debug(1, "Sent '%s' signal to %d listeners\n", signame, s->watchers);
ast_mutex_unlock(&s->lock);
return res;
}
static int waitsignal_exec(struct ast_channel *chan, const char *data)
{
char *argcopy;
int r = 0, timeoutms = 0;
double timeout = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(signame);
AST_APP_ARG(sigtimeout);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Signal() requires arguments\n");
return -1;
}
argcopy = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, argcopy);
if (ast_strlen_zero(args.signame)) {
ast_log(LOG_WARNING, "Missing signal name\n");
return -1;
}
if (strlen(args.signame) >= AST_MAX_CONTEXT) {
ast_log(LOG_WARNING, "Signal name '%s' is too long\n", args.signame);
return -1;
}
if (!ast_strlen_zero(args.sigtimeout)) {
if (sscanf(args.sigtimeout, "%30lg", &timeout) != 1 || timeout < 0) {
ast_log(LOG_WARNING, "Invalid timeout provided: %s. Defaulting to no timeout.\n", args.sigtimeout);
} else {
timeoutms = timeout * 1000; /* sec to msec */
}
}
if (timeout > 0) {
ast_debug(1, "Waiting for signal '%s' for %d ms\n", args.signame, timeoutms);
} else {
ast_debug(1, "Waiting for signal '%s', indefinitely\n", args.signame);
}
r = wait_for_signal_or_hangup(chan, args.signame, timeoutms);
if (r == 1) {
ast_verb(3, "Channel '%s' timed out, waiting for signal '%s'\n", ast_channel_name(chan), args.signame);
pbx_builtin_setvar_helper(chan, "WAITFORSIGNALSTATUS", "TIMEOUT");
} else if (!r) {
ast_verb(3, "Received signal '%s' on channel '%s'\n", args.signame, ast_channel_name(chan));
pbx_builtin_setvar_helper(chan, "WAITFORSIGNALSTATUS", "SIGNALED");
} else {
pbx_builtin_setvar_helper(chan, "WAITFORSIGNALSTATUS", "HANGUP");
ast_verb(3, "Channel '%s' hung up\n", ast_channel_name(chan));
return -1;
}
return 0;
}
static int signal_exec(struct ast_channel *chan, const char *data)
{
char *argcopy;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(signame);
AST_APP_ARG(payload);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Signal() requires arguments\n");
return -1;
}
argcopy = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, argcopy);
if (ast_strlen_zero(args.signame)) {
ast_log(LOG_WARNING, "Missing signal name\n");
return -1;
}
if (strlen(args.signame) >= AST_MAX_CONTEXT) {
ast_log(LOG_WARNING, "Signal name '%s' is too long\n", args.signame);
return -1;
}
if (send_signal(args.signame, args.payload)) {
pbx_builtin_setvar_helper(chan, "SIGNALSTATUS", "FAILURE");
} else {
pbx_builtin_setvar_helper(chan, "SIGNALSTATUS", "SUCCESS");
}
return 0;
}
static int unload_module(void)
{
struct signalitem *s;
int res = 0;
/* To avoid a locking nightmare, and for logistical reasons, this module
* will refuse to unload if watchers > 0. That way we know a signal's
* pipe won't disappear while it's being used. */
AST_RWLIST_WRLOCK(&signals);
/* Don't just use AST_RWLIST_REMOVE_HEAD, because if dealloc_signal fails, it should stay in the list. */
AST_LIST_TRAVERSE_SAFE_BEGIN(&signals, s, entry) {
int mres = dealloc_signal(s);
res |= mres;
if (!mres) {
AST_LIST_REMOVE_CURRENT(entry);
}
}
AST_LIST_TRAVERSE_SAFE_END;
AST_RWLIST_UNLOCK(&signals);
/* One or more signals still has watchers. */
if (res) {
ast_log(LOG_WARNING, "One or more signals is currently in use. Unload failed.\n");
return res;
}
res |= ast_unregister_application(app);
res |= ast_unregister_application(app2);
return res;
}
static int load_module(void)
{
int res;
res = ast_register_application_xml(app, signal_exec);
res |= ast_register_application_xml(app2, waitsignal_exec);
return res;
}
AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Channel Signaling Applications");

View File

@ -377,6 +377,26 @@ static int pop_exec(struct ast_channel *chan, const char *data)
return res;
}
static int frames_left(struct ast_channel *chan)
{
struct ast_datastore *stack_store;
struct gosub_stack_list *oldlist;
int exists;
ast_channel_lock(chan);
stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
if (!stack_store) {
ast_channel_unlock(chan);
return -1;
}
oldlist = stack_store->data;
AST_LIST_LOCK(oldlist);
exists = oldlist->first ? 1 : 0;
AST_LIST_UNLOCK(oldlist);
ast_channel_unlock(chan);
return exists;
}
static int return_exec(struct ast_channel *chan, const char *data)
{
struct ast_datastore *stack_store;
@ -384,6 +404,7 @@ static int return_exec(struct ast_channel *chan, const char *data)
struct gosub_stack_list *oldlist;
const char *retval = data;
int res = 0;
int lastframe;
ast_channel_lock(chan);
if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
@ -395,6 +416,7 @@ static int return_exec(struct ast_channel *chan, const char *data)
oldlist = stack_store->data;
AST_LIST_LOCK(oldlist);
oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
lastframe = oldlist->first ? 0 : 1;
AST_LIST_UNLOCK(oldlist);
if (!oldframe) {
@ -412,12 +434,19 @@ static int return_exec(struct ast_channel *chan, const char *data)
* what was there before. Channels that do not have a PBX may
* not have the context or exten set.
*/
ast_channel_context_set(chan, oldframe->context);
ast_channel_exten_set(chan, oldframe->extension);
if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
--oldframe->priority;
if (ast_channel_pbx(chan) || !lastframe) {
/* If there's no PBX, the "old location" is simply
* the configured context for the device, such as
* for pre-dial handlers, and restoring this location
* is nonsensical. So if no PBX and there are no further
* frames, leave the location as it is. */
ast_channel_context_set(chan, oldframe->context);
ast_channel_exten_set(chan, oldframe->extension);
if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
--oldframe->priority;
}
ast_channel_priority_set(chan, oldframe->priority);
}
ast_channel_priority_set(chan, oldframe->priority);
ast_set2_flag(ast_channel_flags(chan), oldframe->in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
gosub_release_frame(chan, oldframe);
@ -1068,15 +1097,18 @@ static int gosub_run(struct ast_channel *chan, const char *sub_args, int ignore_
ast_channel_priority(chan), ast_channel_name(chan));
}
/* Did the routine return? */
if (ast_channel_priority(chan) == saved_priority
/* Did the routine return?
* For things like predial where there's no PBX on the channel yet,
* the last return leaves the location alone so we can print it out correctly here.
* So to ensure we finished properly, make sure there are no frames left in that case. */
if ((!ast_channel_pbx(chan) && !frames_left(chan)) || (ast_channel_priority(chan) == saved_priority
&& !strcmp(ast_channel_context(chan), saved_context)
&& !strcmp(ast_channel_exten(chan), saved_exten)) {
&& !strcmp(ast_channel_exten(chan), saved_exten))) {
ast_verb(3, "%s Internal %s(%s) complete GOSUB_RETVAL=%s\n",
ast_channel_name(chan), app_gosub, sub_args,
S_OR(pbx_builtin_getvar_helper(chan, "GOSUB_RETVAL"), ""));
} else {
ast_log(LOG_NOTICE, "%s Abnormal '%s(%s)' exit. Popping routine return locations.\n",
ast_log(LOG_WARNING, "%s Abnormal '%s(%s)' exit. Popping routine return locations.\n",
ast_channel_name(chan), app_gosub, sub_args);
balance_stack(chan);
pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", "");

View File

@ -570,6 +570,7 @@ static AST_LIST_HEAD_STATIC(vmstates, vmstate);
#define VM_MOVEHEARD (1 << 16) /*!< Move a "heard" message to Old after listening to it */
#define VM_MESSAGEWRAP (1 << 17) /*!< Wrap around from the last message to the first, and vice-versa */
#define VM_FWDURGAUTO (1 << 18) /*!< Autoset of Urgent flag on forwarded Urgent messages set globally */
#define VM_EMAIL_EXT_RECS (1 << 19) /*!< Send voicemail emails when an external recording is added to a mailbox */
#define ERROR_LOCK_PATH -100
#define ERROR_MAX_MSGS -101
#define OPERATOR_EXIT 300
@ -1258,6 +1259,8 @@ static void apply_option(struct ast_vm_user *vmu, const char *var, const char *v
ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
} else if (!strcasecmp(var, "attachfmt")) {
ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
} else if (!strcasecmp(var, "attachextrecs")) {
ast_set2_flag(vmu, ast_true(value), VM_EMAIL_EXT_RECS);
} else if (!strcasecmp(var, "serveremail")) {
ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
} else if (!strcasecmp(var, "fromstring")) {
@ -4481,15 +4484,16 @@ static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxco
*/
static int remove_file(char *dir, int msgnum)
{
char fn[PATH_MAX];
char full_fn[PATH_MAX];
char fn[PATH_MAX] = "";
char full_fn[PATH_MAX + 4]; /* Plus .txt */
char msgnums[80];
if (msgnum > -1) {
snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
make_file(fn, sizeof(fn), dir, msgnum);
} else
} else {
ast_copy_string(fn, dir, sizeof(fn));
}
ast_filedelete(fn, NULL);
snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
unlink(full_fn);
@ -6418,6 +6422,12 @@ static int msg_create_from_file(struct ast_vm_recording_data *recdata)
* to do both with one line and is also safe to use with file storage mode. Also, if we are using ODBC, now is a good
* time to create the voicemail database entry. */
if (ast_fileexists(destination, NULL, NULL) > 0) {
struct ast_channel *chan = NULL;
char fmt[80];
char clid[80];
char cidnum[80], cidname[80];
int send_email;
if (ast_check_realtime("voicemail_data")) {
get_date(date, sizeof(date));
ast_store_realtime("voicemail_data",
@ -6437,7 +6447,27 @@ static int msg_create_from_file(struct ast_vm_recording_data *recdata)
}
STORE(dir, recipient->mailbox, recipient->context, msgnum, NULL, recipient, fmt, 0, vms, "", msg_id);
notify_new_state(recipient);
send_email = ast_test_flag(recipient, VM_EMAIL_EXT_RECS);
if (send_email) {
/* Send an email if possible, fall back to just notifications if not. */
ast_copy_string(fmt, recdata->recording_ext, sizeof(fmt));
ast_copy_string(clid, recdata->call_callerid, sizeof(clid));
ast_callerid_split(clid, cidname, sizeof(cidname), cidnum, sizeof(cidnum));
/* recdata->call_callerchan itself no longer exists, so we can't use the real channel. Use a dummy one. */
chan = ast_dummy_channel_alloc();
}
if (chan) {
notify_new_message(chan, recipient, NULL, msgnum, duration, fmt, cidnum, cidname, "");
ast_channel_unref(chan);
} else {
if (send_email) { /* We tried and failed. */
ast_log(LOG_WARNING, "Failed to allocate dummy channel, email will not be sent\n");
}
notify_new_state(recipient);
}
}
free_user(recipient);
@ -11197,12 +11227,14 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_
password[0] = '\0';
} else {
if (ast_streamfile(chan, vm_password, ast_channel_language(chan))) {
ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
if (!ast_check_hangup(chan)) {
ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
}
free_user(vmu);
return -1;
}
if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
ast_log(AST_LOG_WARNING, "Unable to read password\n");
ast_log(AST_LOG_NOTICE, "Unable to read password\n");
free_user(vmu);
return -1;
} else if (password[0] == '*') {

View File

@ -120,6 +120,9 @@
<configOption name="end_marked">
<synopsis>Kick the user from the conference when the last marked user leaves</synopsis>
</configOption>
<configOption name="end_marked_any">
<synopsis>Kick the user from the conference when any marked user leaves</synopsis>
</configOption>
<configOption name="talk_detection_events">
<synopsis>Set whether or not notifications of when a user begins and ends talking should be sent out as events over AMI</synopsis>
</configOption>
@ -1440,10 +1443,7 @@ static int add_menu_entry(struct conf_menu *menu, const char *dtmf, const char *
/* if adding any of the actions failed, bail */
if (res) {
struct conf_menu_action *menu_action;
while ((menu_action = AST_LIST_REMOVE_HEAD(&menu_entry->actions, action))) {
ast_free(menu_action);
}
conf_menu_entry_destroy(menu_entry);
ast_free(menu_entry);
return -1;
}
@ -1452,6 +1452,7 @@ static int add_menu_entry(struct conf_menu *menu, const char *dtmf, const char *
AST_LIST_TRAVERSE_SAFE_BEGIN(&menu->entries, cur, entry) {
if (!strcasecmp(cur->dtmf, menu_entry->dtmf)) {
AST_LIST_REMOVE_CURRENT(entry);
conf_menu_entry_destroy(cur);
ast_free(cur);
break;
}
@ -1583,9 +1584,12 @@ static char *handle_cli_confbridge_show_user_profile(struct ast_cli_entry *e, in
ast_cli(a->fd,"Wait Marked: %s\n",
u_profile.flags & USER_OPT_WAITMARKED ?
"enabled" : "disabled");
ast_cli(a->fd,"END Marked: %s\n",
ast_cli(a->fd,"END Marked (All): %s\n",
u_profile.flags & USER_OPT_ENDMARKED ?
"enabled" : "disabled");
ast_cli(a->fd,"END Marked (Any): %s\n",
u_profile.flags & USER_OPT_ENDMARKEDANY ?
"enabled" : "disabled");
ast_cli(a->fd,"Drop_silence: %s\n",
u_profile.flags & USER_OPT_DROP_SILENCE ?
"enabled" : "disabled");
@ -2409,6 +2413,7 @@ int conf_load_config(void)
aco_option_register(&cfg_info, "announce_only_user", ACO_EXACT, user_types, "yes", OPT_BOOLFLAG_T, 0, FLDSET(struct user_profile, flags), USER_OPT_NOONLYPERSON);
aco_option_register(&cfg_info, "wait_marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_WAITMARKED);
aco_option_register(&cfg_info, "end_marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ENDMARKED);
aco_option_register(&cfg_info, "end_marked_any", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ENDMARKEDANY);
aco_option_register(&cfg_info, "talk_detection_events", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_TALKER_DETECT);
aco_option_register(&cfg_info, "dtmf_passthrough", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_DTMF_PASS);
aco_option_register(&cfg_info, "announce_join_leave", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ANNOUNCE_JOIN_LEAVE);

View File

@ -14,9 +14,6 @@
* 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.
*
* Please follow coding guidelines
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
*/
/*! \file

View File

@ -14,9 +14,6 @@
* 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.
*
* Please follow coding guidelines
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
*/
/*! \file

View File

@ -14,9 +14,6 @@
* 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.
*
* Please follow coding guidelines
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
*/
/*! \file

View File

@ -14,9 +14,6 @@
* 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.
*
* Please follow coding guidelines
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
*/
/*! \file

View File

@ -14,9 +14,6 @@
* 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.
*
* Please follow coding guidelines
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
*/
/*! \file
@ -85,37 +82,39 @@ static void leave_marked(struct confbridge_user *user)
conf_remove_user_marked(user->conference, user);
if (user->conference->markedusers == 0) {
AST_LIST_TRAVERSE_SAFE_BEGIN(&user->conference->active_list, user_iter, list) {
/* Kick ENDMARKED cbu_iters */
if (ast_test_flag(&user_iter->u_profile, USER_OPT_ENDMARKED) && !user_iter->kicked) {
if (ast_test_flag(&user_iter->u_profile, USER_OPT_WAITMARKED)
&& !ast_test_flag(&user_iter->u_profile, USER_OPT_MARKEDUSER)) {
AST_LIST_REMOVE_CURRENT(list);
user_iter->conference->activeusers--;
AST_LIST_INSERT_TAIL(&user_iter->conference->waiting_list, user_iter, list);
user_iter->conference->waitingusers++;
}
user_iter->kicked = 1;
pbx_builtin_setvar_helper(user_iter->chan, "CONFBRIDGE_RESULT", "ENDMARKED");
ast_bridge_remove(user_iter->conference->bridge, user_iter->chan);
} else if (ast_test_flag(&user_iter->u_profile, USER_OPT_WAITMARKED)
&& !ast_test_flag(&user_iter->u_profile, USER_OPT_MARKEDUSER)) {
need_prompt = 1;
/* If all marked users have left, or we're set to kick if any marked user leaves, then boot everyone */
AST_LIST_TRAVERSE_SAFE_BEGIN(&user->conference->active_list, user_iter, list) {
if (user->conference->markedusers > 0 && !ast_test_flag(&user_iter->u_profile, USER_OPT_ENDMARKEDANY)) {
continue;
}
/* Kick ENDMARKED cbu_iters */
if ((ast_test_flag(&user_iter->u_profile, USER_OPT_ENDMARKED) || ast_test_flag(&user_iter->u_profile, USER_OPT_ENDMARKEDANY)) && !user_iter->kicked) {
if (ast_test_flag(&user_iter->u_profile, USER_OPT_WAITMARKED)
&& (!ast_test_flag(&user_iter->u_profile, USER_OPT_MARKEDUSER) || ast_test_flag(&user_iter->u_profile, USER_OPT_ENDMARKEDANY))) {
AST_LIST_REMOVE_CURRENT(list);
user_iter->conference->activeusers--;
AST_LIST_INSERT_TAIL(&user_iter->conference->waiting_list, user_iter, list);
user_iter->conference->waitingusers++;
} else {
/* User is neither wait_marked nor end_marked; however, they
* should still hear the prompt.
*/
need_prompt = 1;
}
user_iter->kicked = 1;
pbx_builtin_setvar_helper(user_iter->chan, "CONFBRIDGE_RESULT", "ENDMARKED");
ast_bridge_remove(user_iter->conference->bridge, user_iter->chan);
} else if (ast_test_flag(&user_iter->u_profile, USER_OPT_WAITMARKED)
&& !ast_test_flag(&user_iter->u_profile, USER_OPT_MARKEDUSER)) {
need_prompt = 1;
AST_LIST_REMOVE_CURRENT(list);
user_iter->conference->activeusers--;
AST_LIST_INSERT_TAIL(&user_iter->conference->waiting_list, user_iter, list);
user_iter->conference->waitingusers++;
} else {
/* User is neither wait_marked nor end_marked nor end_marked_any; however, they
* should still hear the prompt.
*/
need_prompt = 1;
}
AST_LIST_TRAVERSE_SAFE_END;
}
AST_LIST_TRAVERSE_SAFE_END;
switch (user->conference->activeusers) {
case 0:

View File

@ -14,9 +14,6 @@
* 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.
*
* Please follow coding guidelines
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
*/
/*! \file

View File

@ -14,9 +14,6 @@
* 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.
*
* Please follow coding guidelines
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
*/
/*! \file

View File

@ -14,9 +14,6 @@
* 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.
*
* Please follow coding guidelines
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
*/
/*! \file

View File

@ -71,6 +71,7 @@ enum user_profile_flags {
USER_OPT_TEXT_MESSAGING = (1 << 19), /*!< Send text messages to the user */
USER_OPT_ANSWER_CHANNEL = (1 << 20), /*!< Sets if the channel should be answered if currently unanswered */
USER_OPT_HEAR_OWN_JOIN_SOUND = (1 << 21), /*!< Set if the caller should hear the join sound */
USER_OPT_ENDMARKEDANY = (1 << 22), /*!< Set if the user should be kicked after any marked user exits */
};
enum bridge_profile_flags {

View File

@ -0,0 +1,15 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><title>Release Summary - asterisk-20.2.1</title><h1 align="center"><a name="top">Release Summary</a></h1><h3 align="center">asterisk-20.2.1</h3><h3 align="center">Date: 2023-04-03</h3><h3 align="center">&lt;asteriskteam@digium.com&gt;</h3><hr><h2 align="center">Table of Contents</h2><ol>
<li><a href="#summary">Summary</a></li>
<li><a href="#contributors">Contributors</a></li>
<li><a href="#closed_issues">Closed Issues</a></li>
<li><a href="#diffstat">Diffstat</a></li>
</ol><hr><a name="summary"><h2 align="center">Summary</h2></a><center><a href="#top">[Back to Top]</a></center><p>This release is a point release of an existing major version. The changes included were made to address problems that have been identified in this release series, or are minor, backwards compatible new features or improvements. Users should be able to safely upgrade to this version if this release series is already in use. Users considering upgrading from a previous version are strongly encouraged to review the UPGRADE.txt document as well as the CHANGES document for information about upgrading to this release series.</p><p>The data in this summary reflects changes that have been made since the previous release, asterisk-20.2.0.</p><hr><a name="contributors"><h2 align="center">Contributors</h2></a><center><a href="#top">[Back to Top]</a></center><p>This table lists the people who have submitted code, those that have tested patches, as well as those that reported issues on the issue tracker that were resolved in this release. For coders, the number is how many of their patches (of any size) were committed into this release. For testers, the number is the number of times their name was listed as assisting with testing a patch. Finally, for reporters, the number is the number of issues that they reported that were affected by commits that went into this release.</p><table width="100%" border="0">
<tr><th width="33%">Coders</th><th width="33%">Testers</th><th width="33%">Reporters</th></tr>
<tr valign="top"><td width="33%">1 Sean Bright <sean@seanbright.com><br/>1 Mike Bradeen <mbradeen@sangoma.com><br/></td><td width="33%"><td width="33%">1 N A <asterisk@phreaknet.org><br/>1 isrl <isrlgb@gmail.com><br/></td></tr>
</table><hr><a name="closed_issues"><h2 align="center">Closed Issues</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all issues from the issue tracker that were closed by changes that went into this release.</p><h3>Bug</h3><h4>Category: PBX/pbx_ael</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30472">ASTERISK-30472</a>: pbx_ael: Literal usage for variables broken<br/>Reported by: isrl<ul>
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=6e50550d28f90676a8510045e45f7750b88964b5">[6e50550d28]</a> Sean Bright -- Revert "pbx_ael: Global variables are not expanded."</li>
</ul><br><h4>Category: Resources/res_pjsip_pubsub</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-30469">ASTERISK-30469</a>: res_pjsip_pubsub: Regression for subscription shutdowns<br/>Reported by: N A<ul>
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=f8dfbaf22594c110e84d35e2a7dff5a998e4547f">[f8dfbaf225]</a> Mike Bradeen -- res_pjsip_pubsub: subscription cleanup changes</li>
</ul><br><hr><a name="diffstat"><h2 align="center">Diffstat Results</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a summary of the changes to the source code that went into this release that was generated using the diffstat utility.</p><pre>ael/pval.c | 14 +--------
res_pjsip_pubsub.c | 81 +++++++++++++++++++++++++++++++----------------------
2 files changed, 51 insertions(+), 44 deletions(-)</pre><br></html>

View File

@ -0,0 +1,91 @@
Release Summary
asterisk-20.2.1
Date: 2023-04-03
<asteriskteam@digium.com>
----------------------------------------------------------------------
Table of Contents
1. Summary
2. Contributors
3. Closed Issues
4. Diffstat
----------------------------------------------------------------------
Summary
[Back to Top]
This release is a point release of an existing major version. The changes
included were made to address problems that have been identified in this
release series, or are minor, backwards compatible new features or
improvements. Users should be able to safely upgrade to this version if
this release series is already in use. Users considering upgrading from a
previous version are strongly encouraged to review the UPGRADE.txt
document as well as the CHANGES document for information about upgrading
to this release series.
The data in this summary reflects changes that have been made since the
previous release, asterisk-20.2.0.
----------------------------------------------------------------------
Contributors
[Back to Top]
This table lists the people who have submitted code, those that have
tested patches, as well as those that reported issues on the issue tracker
that were resolved in this release. For coders, the number is how many of
their patches (of any size) were committed into this release. For testers,
the number is the number of times their name was listed as assisting with
testing a patch. Finally, for reporters, the number is the number of
issues that they reported that were affected by commits that went into
this release.
Coders Testers Reporters
1 Sean Bright 1 N A
1 Mike Bradeen 1 isrl
----------------------------------------------------------------------
Closed Issues
[Back to Top]
This is a list of all issues from the issue tracker that were closed by
changes that went into this release.
Bug
Category: PBX/pbx_ael
ASTERISK-30472: pbx_ael: Literal usage for variables broken
Reported by: isrl
* [6e50550d28] Sean Bright -- Revert "pbx_ael: Global variables are not
expanded."
Category: Resources/res_pjsip_pubsub
ASTERISK-30469: res_pjsip_pubsub: Regression for subscription shutdowns
Reported by: N A
* [f8dfbaf225] Mike Bradeen -- res_pjsip_pubsub: subscription cleanup
changes
----------------------------------------------------------------------
Diffstat Results
[Back to Top]
This is a summary of the changes to the source code that went into this
release that was generated using the diffstat utility.
ael/pval.c | 14 +--------
res_pjsip_pubsub.c | 81 +++++++++++++++++++++++++++++++----------------------
2 files changed, 51 insertions(+), 44 deletions(-)

View File

@ -3447,7 +3447,7 @@ struct sig_ss7_callback sig_ss7_callbacks =
*/
static void notify_message(char *mailbox, int thereornot)
{
char s[sizeof(mwimonitornotify) + 80];
char s[sizeof(mwimonitornotify) + 164];
if (ast_strlen_zero(mailbox)) {
return;
@ -4115,7 +4115,7 @@ static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_leve
{
#define CONTEXT_TAG "Context - "
char logmsg[256];
char completemsg[sizeof(logmsg) + sizeof(CONTEXT_TAG) - 1];
char completemsg[sizeof(logmsg) * 2];
vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
snprintf(completemsg, sizeof(completemsg), CONTEXT_TAG "%s", logmsg);
dahdi_r2_write_log(level, completemsg);
@ -4128,10 +4128,11 @@ static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level
{
#define CHAN_TAG "Chan "
char logmsg[256];
char completemsg[sizeof(logmsg) + sizeof(CHAN_TAG) - 1];
char completemsg[sizeof(logmsg) * 2];
vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d - %s", openr2_chan_get_number(r2chan), logmsg);
dahdi_r2_write_log(level, completemsg);
#undef CHAN_TAG
}
static int dahdi_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
@ -13651,6 +13652,7 @@ static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap
struct ast_channel *tmp = NULL;
struct dahdi_pvt *exitpvt;
int channelmatched = 0;
int foundowner = 0;
int groupmatched = 0;
#if defined(HAVE_PRI) || defined(HAVE_SS7)
int transcapdigital = 0;
@ -13674,6 +13676,10 @@ static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap
if (start.roundrobin)
round_robin[start.rr_starting_point] = p;
if (p->owner) {
foundowner++;
}
if (is_group_or_channel_match(p, start.span, start.groupmatch, &groupmatched, start.channelmatch, &channelmatched)
&& available(&p, channelmatched)) {
ast_debug(1, "Using channel %d\n", p->channel);
@ -13792,7 +13798,7 @@ next:
ast_mutex_unlock(&iflock);
restart_monitor();
if (cause && !tmp) {
if (callwait || channelmatched) {
if (callwait || (channelmatched && foundowner)) {
*cause = AST_CAUSE_BUSY;
} else if (groupmatched) {
*cause = AST_CAUSE_CONGESTION;
@ -19411,7 +19417,7 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
report_alarms = REPORT_SPAN_ALARMS;
}
} else if (!(options & PROC_DAHDI_OPT_NOWARN) )
ast_log(LOG_WARNING, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
ast_log(LOG_NOTICE, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
}
if (dahdichan) {

View File

@ -226,6 +226,16 @@
</enum>
</enumlist>
</info>
<info name="Dial_Resource" language="en_US" tech="IAX2">
<para>The general syntax is:</para>
<para><literal>Dial(IAX2/[username[:password]@]peer[:port][/exten[@context]][/options]</literal></para>
<para>IAX2 optionally allows modifiers to be specified after the extension.</para>
<enumlist>
<enum name="a">
<para>Request auto answer (supporting equipment/configuration required)</para>
</enum>
</enumlist>
</info>
<manager name="IAXpeers" language="en_US">
<synopsis>
List IAX peers.
@ -3407,7 +3417,7 @@ static int send_packet(struct iax_frame *f)
/* Called with iaxsl held */
if (iaxdebug) {
ast_debug(3, "Sending %u on %d/%d to %s\n", f->ts, callno, iaxs[callno]->peercallno, ast_sockaddr_stringify(&iaxs[callno]->addr));
ast_debug(8, "Sending %u on %d/%d to %s\n", f->ts, callno, iaxs[callno]->peercallno, ast_sockaddr_stringify(&iaxs[callno]->addr));
}
if (f->transfer) {
iax_outputframe(f, NULL, 0, &iaxs[callno]->transfer, f->datalen - sizeof(struct ast_iax2_full_hdr));
@ -4148,9 +4158,19 @@ static void __get_from_jb(const void *p)
now.tv_usec += 1000;
ms = ast_tvdiff_ms(now, pvt->rxcore);
voicefmt = ast_format_compatibility_bitfield2format(pvt->voiceformat);
if (voicefmt && ms >= (next = jb_next(pvt->jb))) {
if (ms >= (next = jb_next(pvt->jb))) {
voicefmt = ast_format_compatibility_bitfield2format(pvt->voiceformat);
if (!voicefmt) {
/* pvt->voiceformat won't be set if we haven't received any voice frames yet.
* In this case, fall back to using the format negotiated during call setup,
* so we don't stall the jitterbuffer completely. */
voicefmt = ast_format_compatibility_bitfield2format(pvt->peerformat);
}
if (!voicefmt) {
/* Really shouldn't happen, but if it does, should be looked into */
ast_log(LOG_WARNING, "No voice format and no peer format available on %s, backlogging frame\n", ast_channel_name(pvt->owner));
goto cleanup; /* Don't crash if there's no voice format */
}
ret = jb_get(pvt->jb, &frame, ms, ast_format_get_default_ms(voicefmt));
switch(ret) {
case JB_OK:
@ -4192,6 +4212,7 @@ static void __get_from_jb(const void *p)
break;
}
}
cleanup:
if (pvt)
update_jbsched(pvt);
ast_mutex_unlock(&iaxsl[callno]);
@ -6384,7 +6405,7 @@ static int invalid_key(ast_aes_decrypt_key *ecx)
#ifdef HAVE_OPENSSL
int i;
for (i = 0; i < 60; i++) {
if (ecx->rd_key[i]) {
if (ecx->raw[i]) {
return 0; /* stop if we encounter anything non-zero */
}
}
@ -10363,7 +10384,7 @@ static int socket_process_helper(struct iax2_thread *thread)
}
if (ast_test_flag64(iaxs[fr->callno], IAX_ENCRYPTED) && !decrypted) {
if (decrypt_frame(fr->callno, fh, &f, &res)) {
ast_log(LOG_NOTICE, "Packet Decrypt Failed!\n");
ast_log(LOG_WARNING, "Packet Decrypt Failed!\n");
ast_variables_destroy(ies.vars);
ast_mutex_unlock(&iaxsl[fr->callno]);
return 1;
@ -12033,7 +12054,7 @@ immediatedial:
iaxs[fr->callno]->last = fr->ts;
#if 1
if (iaxdebug)
ast_debug(3, "For call=%d, set last=%u\n", fr->callno, fr->ts);
ast_debug(8, "For call=%d, set last=%u\n", fr->callno, fr->ts);
#endif
}

View File

@ -2513,6 +2513,15 @@ static int hangup(void *data)
if (session) {
int cause = h_data->cause;
if (channel->session->active_media_state &&
channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]) {
struct ast_sip_session_media *media =
channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
if (media->rtp) {
ast_rtp_instance_set_stats_vars(ast, media->rtp);
}
}
/*
* It's possible that session_terminate might cause the session to be destroyed
* immediately so we need to keep a reference to it so we can NULL session->channel
@ -2872,97 +2881,6 @@ static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text)
return rc;
}
/*! \brief Convert SIP hangup causes to Asterisk hangup causes */
static int hangup_sip2cause(int cause)
{
/* Possible values taken from causes.h */
switch(cause) {
case 401: /* Unauthorized */
return AST_CAUSE_CALL_REJECTED;
case 403: /* Not found */
return AST_CAUSE_CALL_REJECTED;
case 404: /* Not found */
return AST_CAUSE_UNALLOCATED;
case 405: /* Method not allowed */
return AST_CAUSE_INTERWORKING;
case 407: /* Proxy authentication required */
return AST_CAUSE_CALL_REJECTED;
case 408: /* No reaction */
return AST_CAUSE_NO_USER_RESPONSE;
case 409: /* Conflict */
return AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
case 410: /* Gone */
return AST_CAUSE_NUMBER_CHANGED;
case 411: /* Length required */
return AST_CAUSE_INTERWORKING;
case 413: /* Request entity too large */
return AST_CAUSE_INTERWORKING;
case 414: /* Request URI too large */
return AST_CAUSE_INTERWORKING;
case 415: /* Unsupported media type */
return AST_CAUSE_INTERWORKING;
case 420: /* Bad extension */
return AST_CAUSE_NO_ROUTE_DESTINATION;
case 480: /* No answer */
return AST_CAUSE_NO_ANSWER;
case 481: /* No answer */
return AST_CAUSE_INTERWORKING;
case 482: /* Loop detected */
return AST_CAUSE_INTERWORKING;
case 483: /* Too many hops */
return AST_CAUSE_NO_ANSWER;
case 484: /* Address incomplete */
return AST_CAUSE_INVALID_NUMBER_FORMAT;
case 485: /* Ambiguous */
return AST_CAUSE_UNALLOCATED;
case 486: /* Busy everywhere */
return AST_CAUSE_BUSY;
case 487: /* Request terminated */
return AST_CAUSE_INTERWORKING;
case 488: /* No codecs approved */
return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
case 491: /* Request pending */
return AST_CAUSE_INTERWORKING;
case 493: /* Undecipherable */
return AST_CAUSE_INTERWORKING;
case 500: /* Server internal failure */
return AST_CAUSE_FAILURE;
case 501: /* Call rejected */
return AST_CAUSE_FACILITY_REJECTED;
case 502:
return AST_CAUSE_DESTINATION_OUT_OF_ORDER;
case 503: /* Service unavailable */
return AST_CAUSE_CONGESTION;
case 504: /* Gateway timeout */
return AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
case 505: /* SIP version not supported */
return AST_CAUSE_INTERWORKING;
case 600: /* Busy everywhere */
return AST_CAUSE_USER_BUSY;
case 603: /* Decline */
return AST_CAUSE_CALL_REJECTED;
case 604: /* Does not exist anywhere */
return AST_CAUSE_UNALLOCATED;
case 606: /* Not acceptable */
return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
default:
if (cause < 500 && cause >= 400) {
/* 4xx class error that is unknown - someting wrong with our request */
return AST_CAUSE_INTERWORKING;
} else if (cause < 600 && cause >= 500) {
/* 5xx class error - problem in the remote end */
return AST_CAUSE_CONGESTION;
} else if (cause < 700 && cause >= 600) {
/* 6xx - global errors in the 4xx class */
return AST_CAUSE_INTERWORKING;
}
return AST_CAUSE_NORMAL;
}
/* Never reached */
return 0;
}
static void chan_pjsip_session_begin(struct ast_sip_session *session)
{
RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
@ -2993,11 +2911,21 @@ static void chan_pjsip_session_end(struct ast_sip_session *session)
SCOPE_EXIT_RTN("No channel\n");
}
if (session->active_media_state &&
session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]) {
struct ast_sip_session_media *media =
session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
if (media->rtp) {
ast_rtp_instance_set_stats_vars(session->channel, media->rtp);
}
}
chan_pjsip_remove_hold(ast_channel_uniqueid(session->channel));
ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0);
if (!ast_channel_hangupcause(session->channel) && session->inv_session) {
int cause = hangup_sip2cause(session->inv_session->cause);
int cause = ast_sip_hangup_sip2cause(session->inv_session->cause);
ast_queue_hangup_with_cause(session->channel, cause);
} else {
@ -3009,11 +2937,11 @@ static void chan_pjsip_session_end(struct ast_sip_session *session)
static void set_sipdomain_variable(struct ast_sip_session *session)
{
pjsip_sip_uri *sip_ruri = pjsip_uri_get_uri(session->request_uri);
size_t size = pj_strlen(&sip_ruri->host) + 1;
const pj_str_t *host = ast_sip_pjsip_uri_get_hostname(session->request_uri);
size_t size = pj_strlen(host) + 1;
char *domain = ast_alloca(size);
ast_copy_pj_str(domain, &sip_ruri->host, size);
ast_copy_pj_str(domain, host, size);
pbx_builtin_setvar_helper(session->channel, "SIPDOMAIN", domain);
return;
@ -3191,7 +3119,7 @@ static void chan_pjsip_incoming_response_update_cause(struct ast_sip_session *se
snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "SIP %d %.*s", status.code,
(int) pj_strlen(&status.reason), pj_strbuf(&status.reason));
cause_code->ast_cause = hangup_sip2cause(status.code);
cause_code->ast_cause = ast_sip_hangup_sip2cause(status.code);
ast_queue_control_data(session->channel, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
ast_channel_hangupcause_hash_set(session->channel, cause_code, data_size);

View File

@ -381,9 +381,9 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form
ast_channel_tech_pvt_set(chan, instance);
ast_rtp_instance_get_local_address(instance, &local_address);
pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_ADDRESS",
ast_sockaddr_stringify_addr(&local_address));
ast_rtp_instance_get_local_address(instance, &local_address);
pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_PORT",
ast_sockaddr_stringify_port(&local_address));

View File

@ -304,6 +304,12 @@
<enum name="rtt">
<para>Round trip time</para>
</enum>
<enum name="txmes">
<para>Transmitted Media Experience Score</para>
</enum>
<enum name="rxmes">
<para>Received Media Experience Score</para>
</enum>
</enumlist>
</enum>
<enum name="all_jitter">
@ -387,6 +393,37 @@
</enum>
</enumlist>
</enum>
<enum name="all_mes">
<para>Retrieve a summary of all RTCP Media Experience Score information.</para>
<para>The following data items are returned in a semi-colon
delineated list:</para>
<enumlist>
<enum name="minmes">
<para>Minimum MES based on us analysing received packets.</para>
</enum>
<enum name="maxmes">
<para>Maximum MES based on us analysing received packets.</para>
</enum>
<enum name="avgmes">
<para>Average MES based on us analysing received packets.</para>
</enum>
<enum name="stdevmes">
<para>Standard deviation MES based on us analysing received packets.</para>
</enum>
<enum name="reported_minmes">
<para>Minimum MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
</enum>
<enum name="reported_maxmes">
<para>Maximum MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
</enum>
<enum name="reported_avgmes">
<para>Average MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
</enum>
<enum name="reported_stdevmes">
<para>Standard deviation MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
</enum>
</enumlist>
</enum>
<enum name="txcount"><para>Transmitted packet count</para></enum>
<enum name="rxcount"><para>Received packet count</para></enum>
<enum name="txjitter"><para>Transmitted packet jitter</para></enum>
@ -416,6 +453,24 @@
<enum name="stdevrtt"><para>Standard deviation round trip time</para></enum>
<enum name="local_ssrc"><para>Our Synchronization Source identifier</para></enum>
<enum name="remote_ssrc"><para>Their Synchronization Source identifier</para></enum>
<enum name="txmes"><para>
Current MES based on us analyzing rtt, jitter and loss
in the actual received RTP stream received from the remote end.
I.E. This is the MES for the incoming audio stream.
</para></enum>
<enum name="rxmes"><para>
Current MES based on rtt and the jitter and loss values in
RTCP sender and receiver reports we receive from the
remote end. I.E. This is the MES for the outgoing audio stream.
</para></enum>
<enum name="remote_maxmes"><para>Max MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
<enum name="remote_minmes"><para>Min MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
<enum name="remote_normdevmes"><para>Average MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
<enum name="remote_stdevmes"><para>Standard deviation MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
<enum name="local_maxmes"><para>Max MES based on us analyzing the received RTP stream</para></enum>
<enum name="local_minmes"><para>Min MES based on us analyzing the received RTP stream</para></enum>
<enum name="local_normdevmes"><para>Average MES based on us analyzing the received RTP stream</para></enum>
<enum name="local_stdevmes"><para>Standard deviation MES based on us analyzing the received RTP stream</para></enum>
</enumlist>
</parameter>
<parameter name="media_type" required="false">
@ -678,6 +733,8 @@ static int channel_read_rtcp(struct ast_channel *chan, const char *type, const c
stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT;
} else if (!strcasecmp(type, "all_loss")) {
stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS;
} else if (!strcasecmp(type, "all_mes")) {
stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES;
}
if (!ast_rtp_instance_get_quality(media->rtp, stat_field, buf, buflen)) {
@ -724,6 +781,16 @@ static int channel_read_rtcp(struct ast_channel *chan, const char *type, const c
{ "stdevrtt", DBL, { .d8 = &stats.stdevrtt, }, },
{ "local_ssrc", INT, { .i4 = &stats.local_ssrc, }, },
{ "remote_ssrc", INT, { .i4 = &stats.remote_ssrc, }, },
{ "txmes", DBL, { .d8 = &stats.txmes, }, },
{ "rxmes", DBL, { .d8 = &stats.rxmes, }, },
{ "remote_maxmes", DBL, { .d8 = &stats.remote_maxmes, }, },
{ "remote_minmes", DBL, { .d8 = &stats.remote_minmes, }, },
{ "remote_normdevmes", DBL, { .d8 = &stats.remote_normdevmes, }, },
{ "remote_stdevmes", DBL, { .d8 = &stats.remote_stdevmes, }, },
{ "local_maxmes", DBL, { .d8 = &stats.local_maxmes, }, },
{ "local_minmes", DBL, { .d8 = &stats.local_minmes, }, },
{ "local_normdevmes", DBL, { .d8 = &stats.local_normdevmes, }, },
{ "local_stdevmes", DBL, { .d8 = &stats.local_stdevmes, }, },
{ NULL, },
};

View File

@ -2138,7 +2138,7 @@ static void *__analog_ss_thread(void *data)
/* If starting a threeway call, never timeout on the first digit so someone
can use flash-hook as a "hold" feature */
if (p->subs[ANALOG_SUB_THREEWAY].owner) {
timeout = 999999;
timeout = INT_MAX;
}
while (len < AST_MAX_EXTENSION-1) {
int is_exten_parking = 0;
@ -3731,6 +3731,32 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
/* Handle an event on a given channel for the monitor thread. */
switch (event) {
case ANALOG_EVENT_WINKFLASH:
case ANALOG_EVENT_RINGBEGIN:
switch (i->sig) {
case ANALOG_SIG_FXSLS:
case ANALOG_SIG_FXSGS:
case ANALOG_SIG_FXSKS:
if (i->immediate) {
if (i->use_callerid || i->usedistinctiveringdetection) {
ast_log(LOG_WARNING, "Can't start PBX immediately, must wait for Caller ID / distinctive ring\n");
} else {
/* If we don't care about Caller ID or Distinctive Ring, then there's
* no need to wait for anything before accepting the call, as
* waiting will buy us nothing.
* So if the channel is configured for immediate, actually start immediately
* and get the show on the road as soon as possible. */
ast_debug(1, "Disabling ring timeout (previously %d) to begin handling immediately\n", i->ringt_base);
analog_set_ringtimeout(i, 0);
}
}
break;
default:
break;
}
/* Fall through */
if (!(ISTRUNK(i) && i->immediate && !i->use_callerid && !i->usedistinctiveringdetection)) {
break;
}
case ANALOG_EVENT_RINGOFFHOOK:
if (i->inalarm) {
break;

View File

@ -8,6 +8,11 @@ total_analysis_time = 5000 ; Maximum time allowed for the algorithm to decide
silence_threshold = 256 ; If the average level of noise in a sample does not reach
; this value, from a scale of 0 to 32767, then we will consider
; it to be silence.
;playback_file = ; Audio file to play while AMD is running, so the caller
; does not just hear silence. Note that specifying this here
; will apply to ALL AMD runs, so you may wish to set it
; in the dialplan as an argument to AMD() instead.
; Default is no audio file (not to play anything).
; Greeting ;
initial_silence = 2500 ; Maximum silence duration before the greeting.
@ -19,7 +24,7 @@ greeting = 1500 ; Maximum length of a greeting. If exceeded, then the
; Word detection ;
min_word_length = 100 ; Minimum duration of Voice to considered as a word
maximum_word_length = 5000 ; Maximum duration of a single Voice utterance allowed.
maximum_word_length = 5000 ; Maximum duration of a single Voice utterance allowed.
between_words_silence = 50 ; Minimum duration of silence after a word to consider
; the audio what follows as a new word

View File

@ -95,10 +95,13 @@ documentation_language = en_US ; Set the language you want documentation
; documented in extensions.conf.sample.
; Default gosub.
;live_dangerously = no ; Enable the execution of 'dangerous' dialplan
; functions from external sources (AMI,
; etc.) These functions (such as SHELL) are
; considered dangerous because they can allow
; privilege escalation.
; functions and configuration file access from
; external sources (AMI, etc.) These functions
; (such as SHELL) are considered dangerous
; because they can allow privilege escalation.
; Configuration files are considered dangerous
; if they exist outside of the Asterisk
; configuration directory.
; Default no
;entityid=00:11:22:33:44:55 ; Entity ID.
; This is in the form of a MAC address.

View File

@ -32,6 +32,17 @@
; is "no".
;congestion = no
; Define whether or not to ignore bridging changes in CDRs. This prevents
; bridging changes from resulting in multiple CDRs for different parts of
; a call. Default is "no". This setting cannot be changed on a reload.
;ignorestatechanges = no
; Define whether or not to ignore dial updates in CDRs. This prevents
; dial updates from resulting in multiple CDRs for different parts of
; a call. The last disposition on the channel will be used for the CDR.
; Use with caution. Default is "no".
;ignoredialchanges = no
; Normally, CDR's are not closed out until after all extensions are finished
; executing. By enabling this option, the CDR will be ended before executing
; the "h" extension and hangup handlers so that CDR values such as "end" and
@ -102,8 +113,6 @@
; Here are all the possible back ends:
;
; csv, custom, manager, odbc, pgsql, radius, sqlite, tds
; (also, mysql is available via the asterisk-addons, due to licensing
; requirements)
; (please note, also, that other backends can be created, by creating
; a new backend module in the source cdr/ directory!)
;

View File

@ -936,8 +936,13 @@ pickupgroup=1
; target of the transfer.
;
; Specify whether the channel should be answered immediately or if the simple
; switch should provide dialtone, read digits, etc.
; On FXS channels (FXO signaled), specifies whether the channel should enter the dialplan
; immediately or if the simple switch should provide dialtone, read digits, etc.
; On FXO channels (FXS signaled), specifies whether the call should enter the dialplan
; immediately or if we should wait for at least one ring. This is required if
; Caller ID or distinctive ringing is enabled. If you do not need either, you can
; skip waiting for the first ring to begin call processing sooner.
;
; Note: If immediate=yes the dialplan execution will always start at extension
; 's' priority 1 regardless of the dialed number!
;

View File

@ -58,8 +58,11 @@ type=user
; when a channel enters a empty conference. On by default.
;wait_marked=yes ; Sets if the user must wait for a marked user to enter before
; joining the conference. Off by default.
;end_marked=yes ; This option will kick every user with this option set in their
; user profile after the last Marked user exists the conference.
;end_marked=yes ; This option will kick every non-marked user with this option set in their
; user profile after the last marked user exits the conference.
;end_marked_any=no ; This option will kick every user with this option set in
; their user profile after any marked user exits the conference.
; Additionally, note that unlike end_marked, this includes marked users.
;dsp_drop_silence=yes ; This option drops what Asterisk detects as silence from
; entering into the bridge. Enabling this option will drastically

View File

@ -6,7 +6,11 @@
[general]
;transferdigittimeout => 3 ; Number of seconds to wait between digits when transferring a call
; (default is 3 seconds)
; (default is 3 seconds). If the TRANSFER_EXTEN dialplan variable has been set
; on the channel of the user that is invoking the transfer feature, then
; this option is not used as the user is transferred directly to the extension
; specified by TRANSFER_EXTEN (the transfer context remains the context specified
; by TRANSFER_CONTEXT, if set, and otherwise the default context).
;xfersound = beep ; to indicate an attended transfer is complete
;xferfailsound = beeperr ; to indicate a failed transfer
;pickupexten = *8 ; Configure the pickup extension. (default is *8)
@ -26,12 +30,13 @@
; By default, this is 2.
;transferdialattempts = 3 ; Number of times that a transferer may attempt to dial an extension before
; being kicked back to the original call.
;transferannouncesound = beep ; Sound to play to a transferer to indicate transfer process has begun. If empty, no sound will be played.
;transferretrysound = beep ; Sound to play when a transferer fails to dial a valid extension.
;transferinvalidsound = beeperr ; Sound to play when a transferer fails to dial a valid extension and is out of retries.
;atxferabort = *1 ; cancel the attended transfer
;atxfercomplete = *2 ; complete the attended transfer, dropping out of the call
;atxferthreeway = *3 ; complete the attended transfer, but stay in the call. This will turn the call into a multi-party bridge
;atxferswap = *4 ; swap to the other party. Once an attended transfer has begun, this options may be used multiple times
;atxferswap = *4 ; swap to the other party. Once an attended transfer has begun, this option may be used multiple times
; Note that the DTMF features listed below only work when two channels have answered and are bridged together.
; They can not be used while the remote party is ringing or in progress. If you require this feature you can use

View File

@ -1,6 +1,8 @@
;--
Geolocation Profile Sample Configuration
Please see https://wiki.asterisk.org/wiki/display/AST/Geolocation
for the most current information.
--;
;--
@ -134,14 +136,24 @@ allowed. See RFC8787.
Example:
location_source = sip1.myserver.net
-- confidence (optional) -----------------------------------------
The confidence in the location specified.
confidence = pdf=[ unknown | normal | rectangular ], value=<percent_confident>
Please see RFC7459 for the exact description of this parameter.
Example:
confidence = pdf=normal, value=75
-- Location Example ---------------------------------------------------
[mylocation]
type = location
format = civicAddress
location_info = country=US
location_info = A1="New York", A3="New York", A4=Manhattan
location_info = HNO=1633, PRD=W, RD=46th, STS=Street
location_info = A1="New York", A3="New York", A4=Manhattan
location_info = HNO=1633, PRD=W, RD=46th, STS=Street
location_info = PC=10222
method = Manual
location_source = sip1.myserver.net
@ -160,9 +172,10 @@ location_source = sip1.myserver.net
Defines the object type.
type = profile
-- profile_action (optional) ------------------------------------------
-- profile_precedence (optional) --------------------------------------
Sets how to reconcile incoming and configured profiles.
profile_action = < prefer_incoming | prefer_config | discard_incoming
profile_precedence = < prefer_incoming | prefer_config | discard_incoming
| discard_config >
On an incoming call leg, "incoming" is the location description
@ -188,11 +201,13 @@ discard_config: Discard any configured location description. If
discard_incoming is the default.
Example:
profile_action = prefer_config
profile_precedence = prefer_config
-- pidf_element (optional) --------------------------------------------
PIDF-LO element in which to place the location description.
pidf_element = < tuple | device | person >
Default: device
If the format is civicAddress or GML, this sets the PIDF element into
which the location information will be placed.
@ -207,10 +222,12 @@ Per [RFC5491], "device" is preferred and therefore the default.
Example:
pidf_element = tuple
-- geolocation_routing (optional) -------------------------------------
-- allow_routing_use (optional) ---------------------------------------
Sets whether the "Geolocation-Routing" header is added to outgoing
requests.
geolocation_routing = < yes | no >
allow_routing_use = < yes | no >
Default: no
Set to "yes" to indicate that servers later in the path
can use the location information for routing purposes. Set to "no"
@ -218,7 +235,7 @@ if they should not. If this value isn't specified, no
"Geolocation-Routing" header will be added.
Example:
geolocation_routing = yes
allow_routing_use = yes
-- location_reference (optional) --------------------------------------
The name of an existing Location object.
@ -243,7 +260,7 @@ floor and room just for this profile
Example:
location_info_refinement = floor=20, room=20a2
-- location_variables -------------------------------------------------
-- location_variables (optional) --------------------------------------
If the referenced Location object uses any replacement variables, they
can be assigned here. There is no need to define variables that come
@ -251,6 +268,33 @@ from the channel using this profile. They get assigned automatically.
location_variables = myfloor=20, myroom=222
-- suppress_empty_ca_elements (optional) ------------------------------
Sets whether empty values for Civic Address elements should be
suppressed from the outgoing PIDF-LO document.
suppress_empty_ca_elements = < yes | no >
Default: no
Setting to "yes" allows you to define a location info template
with channel variables that may or may not exist.
For example, with:
location_info_refinement = FLR=${MyFlr}
suppress_empty_ca_elements = no ; the default
If the MyFlr channel variable weren't set, the outgoing PIDF-LO document
would have an empty <FLR/> element in it. If suppress_empty_ca_elements
were set to "yes", the FLR element would be dropped from the PIDF-LO
document altogether.
-- format, location_info, location_source, method, confidence ---------
You can specify the location object's format, location_info,
method, location_source and confidence parameters directly on
a profile object for simple scenarios where the location
information isn't common with any other profiles. This is
mutually exclusive with setting location_reference on the
profile.
-- Profile Example ----------------------------------------------------
[myprofile]
@ -262,3 +306,13 @@ profile_action = discard_incoming
=======================================================================
--;
-- NOTE ---------------------------------------------------------------
There are 4 built-in profiles that can be assigned to endpoints:
"<prefer_config>"
"<discard_config>"
"<prefer_incoming>"
"<discard_incoming>"
The profiles are empty except for having their precedence
set.

View File

@ -22,6 +22,9 @@ capture_password = foo ; If specified, the authorization password
capture_id = 1234 ; A unique integer identifier for this
; server. This ID will be embedded sent
; with each packet from this server.
;capture_name = asterisk ; A unique string identifier for this
; server. This ID will be embedded sent
; 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 or chan_sip SIP

View File

@ -82,6 +82,9 @@ directory=moh
; ; in alphabetical order. If 'randstart', the files are sorted
; ; in alphabetical order as well, but the first file is chosen
; ; at random. If unspecified, the sort order is undefined.
;answeredonly=yes ; Only allow answered channels to have music on hold.
; Enabling this will prevent MOH on unanswered channels.
; (default: "no")
;[native-alphabetical]
;mode=files

View File

@ -616,6 +616,8 @@
;aggregate_mwi=yes ; (default: "yes")
;allow= ; Media Codec s to allow (default: "")
;allow_overlap=yes ; Enable RFC3578 overlap dialing support. (default: "yes")
;overlap_context=default ; Context to used for overlap dialing matches
; (default: same as context option)
;aors= ; AoR s to be used with the endpoint (default: "")
;auth= ; Authentication Object s associated with the endpoint (default: "")
;callerid= ; CallerID information for the endpoint (default: "")
@ -964,6 +966,11 @@
; by the channel driver from the dialplan before they're forwarded
; the remote endpoint.
;
; send_aoc =
; This options turns on and off support for sending AOC to endpoints.
; AOC updates can be sent using the AOCMessage AMI action or come
; from PRI channels.
; (default: no)
;==========================AUTH SECTION OPTIONS=========================
@ -1054,11 +1061,16 @@
; and/or "asterisk_ecc.pem" are loaded (certificate, inter-
; mediates, private key), to support multiple algorithms for
; server authentication (RSA, DSA, ECDSA). If the chains are
; different, at least OpenSSL 1.0.2 is required.
; different, at least OpenSSL 1.0.2 is required. This option
; can be reloaded resulting in an updated certificate if the
; filename remains unchanged.
; (default: "")
;cipher= ; Preferred cryptography cipher names TLS ONLY (default: "")
;method= ; Method of SSL transport TLS ONLY (default: "")
;priv_key_file= ; Private key file TLS ONLY (default: "")
;priv_key_file= ; Private key file TLS ONLY. This option can be reloaded
; resulting in an updated private key if the filename remains
; unchanged.
; (default: "")
;verify_client= ; Require verification of client certificate TLS ONLY (default:
; "")
;verify_server= ; Require verification of server certificate TLS ONLY (default:
@ -1331,6 +1343,13 @@
; creating an implicit subscription (see RFC 4488).
; (default: "yes")
;all_codecs_on_empty_reinvite=yes
; On reception of a re-INVITE without SDP Asterisk will send an SDP
; offer in the 200 OK response containing all configured codecs on the
; endpoint, instead of simply those that have already been negotiated.
; RFC 3261 specifies this as a SHOULD requirement.
; (default: "no")
;allow_sending_180_after_183=yes ; Allow Asterisk to send 180 Ringing to an endpoint
; after 183 Session Progress has been send.
; If disabled Asterisk will instead send only a
@ -1582,3 +1601,16 @@
;mailbox_state_filter= ; Optional regular expression used to filter what
; mailboxes we accept events for.
;================================TEL URIs=====================================
;
; Asterisk has TEL URI support, but with limited scope. Support is only for
; TEL URIs present in traffic from a remote party. Asterisk does not generate
; any TEL URIs of its own.
;
; Currently, the allowed request types are INVITE, ACK, BYE, and CANCEL. Any
; other request type that contains a TEL URI will behave as it did before.
; TEL URIs are allowed in the request, From, and To headers.
;
; You can match a TEL URI From header by IP, header, or auth_username.

View File

@ -78,6 +78,12 @@ monitor-type = MixMonitor
;
;announce = queue-markq
;
; An announcement may be specified which is played to the caller just
; before they are bridged with an agent. The default is to not play an
; announcement to the caller.
;
;queue-callerannounce = you-are-being-connected
;
; A strategy may be specified. Valid strategies include:
;
; ringall - ring all available channels until one answers (default)
@ -354,6 +360,10 @@ monitor-type = MixMonitor
;queue-thereare = queue-thereare
; ("calls waiting.")
;queue-callswaiting = queue-callswaiting
; ("Currently there are more than")
;queue-quantity1 = queue-quantity1
; ("callers waiting to speak with a representative")
;queue-quantity2 = queue-quantity2
; ("The current est. holdtime is")
;queue-holdtime = queue-holdtime
; ("minute.")

View File

@ -262,6 +262,8 @@ pagerdateformat=%A, %B %d, %Y at %r
; option lets you customize the format sent to particular mailboxes.
; Useful if Windows users want wav49, but Linux users want gsm.
; [per-mailbox only]
; attachextrecs=no ; Whether to attach recordings that are externally added to mailboxes,
; such as through MixMonitor. Default is no.
; saycid=yes ; Say the caller id information before the message. If not described,
; or set to no, it will be in the envelope. When enabled, if a recorded file
; with the same name as the caller id exists in

17860
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -589,6 +589,8 @@ AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS], [PJSIP INVIT
AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_ENDPOINT_COMPACT_FORM], [PJSIP Compact Form Support on Endpoint], [PJPROJECT], [pjsip])
AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_TRANSPORT_DISABLE_CONNECTION_REUSE], [PJSIP Transport Connection Reuse Disabling], [PJPROJECT], [pjsip])
AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_OAUTH_AUTHENTICATION], [PJSIP OAuth Authentication Support], [PJPROJECT], [pjsip])
AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_TLS_TRANSPORT_RESTART], [PJSIP TLS Transport Restart Support], [PJPROJECT], [pjsip])
AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EVSUB_PENDING_NOTIFY], [PJSIP NOTIFY Required on SUBSCRIBE], [PJPROJECT], [pjsip])
fi
AST_EXT_LIB_SETUP([POPT], [popt], [popt])
@ -1397,6 +1399,16 @@ else
fi
AC_SUBST(AST_NO_FORMAT_TRUNCATION)
AC_MSG_CHECKING(for -Wno-format-y2k)
if $(${CC} -Wno-format-y2k -Werror -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then
AC_MSG_RESULT(yes)
AST_NO_FORMAT_Y2K=-Wno-format-y2k
else
AC_MSG_RESULT(no)
AST_NO_FORMAT_Y2K=
fi
AC_SUBST(AST_NO_FORMAT_Y2K)
AC_MSG_CHECKING(for -Wno-stringop-truncation)
if $(${CC} -Wno-stringop-truncation -Werror -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then
AC_MSG_RESULT(yes)
@ -2495,6 +2507,19 @@ if test "$USE_PJPROJECT" != "no" ; then
AST_EXT_LIB_CHECK([PJSIP_INV_SESSION_REF], [pjsip], [pjsip_inv_add_ref], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS])
AST_EXT_LIB_CHECK([PJSIP_AUTH_CLT_DEINIT], [pjsip], [pjsip_auth_clt_deinit], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS])
AST_EXT_LIB_CHECK([PJSIP_TSX_LAYER_FIND_TSX2], [pjsip], [pjsip_tsx_layer_find_tsx2], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS])
AST_EXT_LIB_CHECK([PJSIP_TLS_TRANSPORT_RESTART], [pjsip], [pjsip_tls_transport_restart], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS])
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pending_notify in evsub.c" >&5
$as_echo_n "checking for pending_notify in evsub... " >&6; }
pending_notify=$(${SED} -n -r -e '/^struct\s+pjsip_evsub/,/^\s+void\s+*mod_data/!d ; /pending_notify/p' $(find $PJSIP_EVSUB_PENDING_NOTIFY_DIR -name evsub.c))
if test -n "$pending_notify" ; then
AC_DEFINE(HAVE_PJSIP_EVSUB_PENDING_NOTIFY, 1, [Define to 1 if evsub requires a NOTIFY on SUBSCRIBE.])
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
fi
fi

View File

@ -0,0 +1,49 @@
"""add security_negotiation and security_mechanisms to endpoint
Revision ID: 417c0247fd7e
Revises: 539f68bede2c
Create Date: 2022-08-08 15:35:31.416964
"""
# revision identifiers, used by Alembic.
revision = '417c0247fd7e'
down_revision = '539f68bede2c'
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import ENUM
SECURITY_NEGOTIATION_NAME = 'security_negotiation_values'
SECURITY_NEGOTIATION_VALUES = ['no', 'mediasec']
def upgrade():
context = op.get_context()
if context.bind.dialect.name == 'postgresql':
security_negotiation_values = ENUM(*SECURITY_NEGOTIATION_VALUES, name=SECURITY_NEGOTIATION_NAME)
security_negotiation_values.create(op.get_bind(), checkfirst=False)
op.add_column('ps_endpoints', sa.Column('security_negotiation',
ENUM(*SECURITY_NEGOTIATION_VALUES, name=SECURITY_NEGOTIATION_NAME, create_type=False)))
op.add_column('ps_endpoints', sa.Column('security_mechanisms', sa.String(512)))
op.add_column('ps_registrations', sa.Column('security_negotiation',
ENUM(*SECURITY_NEGOTIATION_VALUES, name=SECURITY_NEGOTIATION_NAME, create_type=False)))
op.add_column('ps_registrations', sa.Column('security_mechanisms', sa.String(512)))
def downgrade():
context = op.get_context()
if context.bind.dialect.name == 'mssql':
op.drop_constraint('ck_ps_endpoints_security_negotiation_security_negotiation_values', 'ps_endpoints')
op.drop_constraint('ck_ps_registrations_security_negotiation_security_negotiation_values', 'ps_registrations')
op.drop_column('ps_endpoints', 'security_negotiation')
op.drop_column('ps_endpoints', 'security_mechanisms')
op.drop_column('ps_registrations', 'security_negotiation')
op.drop_column('ps_registrations', 'security_mechanisms')
if context.bind.dialect.name == 'postgresql':
enum = ENUM(*SECURITY_NEGOTIATION_VALUES, name=SECURITY_NEGOTIATION_NAME)
enum.drop(op.get_bind(), checkfirst=False)

View File

@ -0,0 +1,57 @@
"""Add peer_supported to 100rel
Revision ID: 539f68bede2c
Revises: 9f3692b1654b
Create Date: 2022-08-10 09:36:16.576049
"""
# revision identifiers, used by Alembic.
revision = '539f68bede2c'
down_revision = '9f3692b1654b'
from alembic import op
from sqlalchemy.dialects.postgresql import ENUM
import sqlalchemy as sa
OLD_ENUM = ['no', 'required', 'yes']
NEW_ENUM = ['no', 'required', 'peer_supported', 'yes']
old_type = sa.Enum(*OLD_ENUM, name='pjsip_100rel_values')
new_type = sa.Enum(*NEW_ENUM, name='pjsip_100rel_values_v2')
def upgrade():
context = op.get_context()
# Upgrading to this revision WILL clear your directmedia values.
if context.bind.dialect.name != 'postgresql':
op.alter_column('ps_endpoints', '100rel',
type_=new_type,
existing_type=old_type)
else:
enum = ENUM(*NEW_ENUM, name='pjsip_100rel_values_v2')
enum.create(op.get_bind(), checkfirst=False)
op.execute('ALTER TABLE ps_endpoints ALTER COLUMN 100rel TYPE'
' pjsip_100rel_values_v2 USING'
' 100rel::text::pjsip_100rel_values_v2')
ENUM(name="pjsip_100rel_values").drop(op.get_bind(), checkfirst=False)
def downgrade():
context = op.get_context()
if context.bind.dialect.name != 'postgresql':
op.alter_column('ps_endpoints', '100rel',
type_=old_type,
existing_type=new_type)
else:
enum = ENUM(*OLD_ENUM, name='pjsip_100rel_values')
enum.create(op.get_bind(), checkfirst=False)
op.execute('ALTER TABLE ps_endpoints ALTER COLUMN 100rel TYPE'
' pjsip_100rel_values USING'
' 100rel::text::pjsip_100rel_values')
ENUM(name="pjsip_100rel_values_v2").drop(op.get_bind(), checkfirst=False)

View File

@ -0,0 +1,38 @@
"""add aoc option
Revision ID: 5a2247c957d2
Revises: ccf795ee535f
Create Date: 2022-10-30 12:47:56.173511
"""
# revision identifiers, used by Alembic.
revision = '5a2247c957d2'
down_revision = 'ccf795ee535f'
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import ENUM
AST_BOOL_NAME = 'ast_bool_values'
# We'll just ignore the n/y and f/t abbreviations as Asterisk does not write
# those aliases.
AST_BOOL_VALUES = [ '0', '1',
'off', 'on',
'false', 'true',
'no', 'yes' ]
def upgrade():
############################# Enums ##############################
# ast_bool_values has already been created, so use postgres enum object
# type to get around "already created" issue - works okay with mysql
ast_bool_values = ENUM(*AST_BOOL_VALUES, name=AST_BOOL_NAME, create_type=False)
op.add_column('ps_endpoints', sa.Column('send_aoc', ast_bool_values))
def downgrade():
if op.get_context().bind.dialect.name == 'mssql':
op.drop_constraint('ck_ps_endpoints_send_aoc_ast_bool_values', 'ps_endpoints')
op.drop_column('ps_endpoints', 'send_aoc')
pass

View File

@ -0,0 +1,58 @@
"""Add Stir Shaken Profile and Codec Preference to ps endpoint
Revision ID: 9f3692b1654b
Revises: 7197536bb68d
Create Date: 2022-08-17 11:20:56.433088
"""
# revision identifiers, used by Alembic.
revision = '9f3692b1654b'
down_revision = '7197536bb68d'
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import ENUM
PJSIP_INCOMING_CALL_OFFER_PREF_NAME ='pjsip_incoming_call_offer_pref_values'
PJSIP_INCOMING_CALL_OFFER_PREF_VALUES = ['local', 'local_first',
'remote', 'remote_first']
PJSIP_OUTGOING_CALL_OFFER_PREF_NAME = 'pjsip_outgoing_call_offer_pref_values'
PJSIP_OUTGOING_CALL_OFFER_PREF_VALUES = ['local', 'local_merge', 'local_first',
'remote', 'remote_merge', 'remote_first']
def upgrade():
context = op.get_context()
if context.bind.dialect.name == 'postgresql':
enum_in = ENUM(*PJSIP_INCOMING_CALL_OFFER_PREF_VALUES, name=PJSIP_INCOMING_CALL_OFFER_PREF_NAME)
enum_out = ENUM(*PJSIP_OUTGOING_CALL_OFFER_PREF_VALUES, name=PJSIP_OUTGOING_CALL_OFFER_PREF_NAME)
enum_in.create(op.get_bind(), checkfirst=False)
enum_out.create(op.get_bind(), checkfirst=False)
op.add_column('ps_endpoints', sa.Column('incoming_call_offer_pref',
sa.Enum(*PJSIP_INCOMING_CALL_OFFER_PREF_VALUES, name=PJSIP_INCOMING_CALL_OFFER_PREF_NAME)))
op.add_column('ps_endpoints', sa.Column('outgoing_call_offer_pref',
sa.Enum(*PJSIP_OUTGOING_CALL_OFFER_PREF_VALUES, name=PJSIP_OUTGOING_CALL_OFFER_PREF_NAME)))
op.add_column('ps_endpoints', sa.Column('stir_shaken_profile', sa.String(80)))
def downgrade():
context = op.get_context()
if context.bind.dialect.name == 'mssql':
op.drop_constraint('ck_ps_endpoints_incoming_call_offer_pref_pjsip_incoming_call_offer_pref_values', 'ps_endpoints')
op.drop_constraint('ck_ps_endpoints_outgoing_call_offer_pref_pjsip_outgoing_call_offer_pref_values', 'ps_endpoints')
op.drop_column('ps_endpoints', 'outgoing_call_offer_pref')
op.drop_column('ps_endpoints', 'incoming_call_offer_pref')
op.drop_column('ps_endpoints', 'stir_shaken_profile')
enums = [PJSIP_INCOMING_CALL_OFFER_PREF_NAME, PJSIP_OUTGOING_CALL_OFFER_PREF_NAME]
if context.bind.dialect.name == 'postgresql':
for e in enums:
ENUM(name=e).drop(op.get_bind(), checkfirst=False)

View File

@ -0,0 +1,37 @@
"""all_codecs_on_empty_reinvite
Revision ID: ccf795ee535f
Revises: 539f68bede2c
Create Date: 2022-09-28 09:14:36.709781
"""
# revision identifiers, used by Alembic.
revision = 'ccf795ee535f'
down_revision = '417c0247fd7e'
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import ENUM
AST_BOOL_NAME = 'ast_bool_values'
# We'll just ignore the n/y and f/t abbreviations as Asterisk does not write
# those aliases.
AST_BOOL_VALUES = [ '0', '1',
'off', 'on',
'false', 'true',
'no', 'yes' ]
def upgrade():
############################# Enums ##############################
# ast_bool_values has already been created, so use postgres enum object
# type to get around "already created" issue - works okay with mysql
ast_bool_values = ENUM(*AST_BOOL_VALUES, name=AST_BOOL_NAME, create_type=False)
op.add_column('ps_globals', sa.Column('all_codecs_on_empty_reinvite', ast_bool_values))
def downgrade():
if op.get_context().bind.dialect.name == 'mssql':
op.drop_constraint('ck_ps_globals_all_codecs_on_empty_reinvite_ast_bool_values', 'ps_globals')
op.drop_column('ps_globals', 'all_codecs_on_empty_reinvite')

View File

@ -0,0 +1,21 @@
"""add overlap_context
Revision ID: f261363a857f
Revises: 5a2247c957d2
Create Date: 2022-12-09 13:58:48.622000
"""
# revision identifiers, used by Alembic.
revision = 'f261363a857f'
down_revision = '5a2247c957d2'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column('ps_endpoints', sa.Column('overlap_context', sa.String(80)))
def downgrade():
op.drop_column('ps_endpoints', 'overlap_context')

View File

@ -0,0 +1,41 @@
CREATE TABLE alembic_version (
version_num VARCHAR(32) NOT NULL,
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
);
-- Running upgrade -> 210693f3123d
CREATE TABLE cdr (
accountcode VARCHAR(20),
src VARCHAR(80),
dst VARCHAR(80),
dcontext VARCHAR(80),
clid VARCHAR(80),
channel VARCHAR(80),
dstchannel VARCHAR(80),
lastapp VARCHAR(80),
lastdata VARCHAR(80),
start DATETIME,
answer DATETIME,
end DATETIME,
duration INTEGER,
billsec INTEGER,
disposition VARCHAR(45),
amaflags VARCHAR(45),
userfield VARCHAR(256),
uniqueid VARCHAR(150),
linkedid VARCHAR(150),
peeraccount VARCHAR(20),
sequence INTEGER
);
INSERT INTO alembic_version (version_num) VALUES ('210693f3123d');
-- Running upgrade 210693f3123d -> 54cde9847798
ALTER TABLE cdr MODIFY accountcode VARCHAR(80) NULL;
ALTER TABLE cdr MODIFY peeraccount VARCHAR(80) NULL;
UPDATE alembic_version SET version_num='54cde9847798' WHERE alembic_version.version_num = '210693f3123d';

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
CREATE TABLE alembic_version (
version_num VARCHAR(32) NOT NULL,
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
);
-- Running upgrade -> a2e9769475e
CREATE TABLE voicemail_messages (
dir VARCHAR(255) NOT NULL,
msgnum INTEGER NOT NULL,
context VARCHAR(80),
macrocontext VARCHAR(80),
callerid VARCHAR(80),
origtime INTEGER,
duration INTEGER,
recording BLOB,
flag VARCHAR(30),
category VARCHAR(30),
mailboxuser VARCHAR(30),
mailboxcontext VARCHAR(30),
msg_id VARCHAR(40)
);
ALTER TABLE voicemail_messages ADD CONSTRAINT voicemail_messages_dir_msgnum PRIMARY KEY (dir, msgnum);
CREATE INDEX voicemail_messages_dir ON voicemail_messages (dir);
INSERT INTO alembic_version (version_num) VALUES ('a2e9769475e');
-- Running upgrade a2e9769475e -> 39428242f7f5
ALTER TABLE voicemail_messages MODIFY recording BLOB(4294967295) NULL;
UPDATE alembic_version SET version_num='39428242f7f5' WHERE alembic_version.version_num = 'a2e9769475e';

View File

@ -0,0 +1,45 @@
BEGIN;
CREATE TABLE alembic_version (
version_num VARCHAR(32) NOT NULL,
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
);
-- Running upgrade -> 210693f3123d
CREATE TABLE cdr (
accountcode VARCHAR(20),
src VARCHAR(80),
dst VARCHAR(80),
dcontext VARCHAR(80),
clid VARCHAR(80),
channel VARCHAR(80),
dstchannel VARCHAR(80),
lastapp VARCHAR(80),
lastdata VARCHAR(80),
start TIMESTAMP WITHOUT TIME ZONE,
answer TIMESTAMP WITHOUT TIME ZONE,
"end" TIMESTAMP WITHOUT TIME ZONE,
duration INTEGER,
billsec INTEGER,
disposition VARCHAR(45),
amaflags VARCHAR(45),
userfield VARCHAR(256),
uniqueid VARCHAR(150),
linkedid VARCHAR(150),
peeraccount VARCHAR(20),
sequence INTEGER
);
INSERT INTO alembic_version (version_num) VALUES ('210693f3123d');
-- Running upgrade 210693f3123d -> 54cde9847798
ALTER TABLE cdr ALTER COLUMN accountcode TYPE VARCHAR(80);
ALTER TABLE cdr ALTER COLUMN peeraccount TYPE VARCHAR(80);
UPDATE alembic_version SET version_num='54cde9847798' WHERE alembic_version.version_num = '210693f3123d';
COMMIT;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,39 @@
BEGIN;
CREATE TABLE alembic_version (
version_num VARCHAR(32) NOT NULL,
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
);
-- Running upgrade -> a2e9769475e
CREATE TABLE voicemail_messages (
dir VARCHAR(255) NOT NULL,
msgnum INTEGER NOT NULL,
context VARCHAR(80),
macrocontext VARCHAR(80),
callerid VARCHAR(80),
origtime INTEGER,
duration INTEGER,
recording BYTEA,
flag VARCHAR(30),
category VARCHAR(30),
mailboxuser VARCHAR(30),
mailboxcontext VARCHAR(30),
msg_id VARCHAR(40)
);
ALTER TABLE voicemail_messages ADD CONSTRAINT voicemail_messages_dir_msgnum PRIMARY KEY (dir, msgnum);
CREATE INDEX voicemail_messages_dir ON voicemail_messages (dir);
INSERT INTO alembic_version (version_num) VALUES ('a2e9769475e');
-- Running upgrade a2e9769475e -> 39428242f7f5
ALTER TABLE voicemail_messages ALTER COLUMN recording TYPE BYTEA;
UPDATE alembic_version SET version_num='39428242f7f5' WHERE alembic_version.version_num = 'a2e9769475e';
COMMIT;

View File

@ -69,10 +69,10 @@
<!ATTLIST configInfo name CDATA #REQUIRED>
<!ATTLIST configInfo language CDATA #REQUIRED>
<!ELEMENT configFile (configObject+)>
<!ELEMENT configFile (configObject|xi:include)+>
<!ATTLIST configFile name CDATA #REQUIRED>
<!ELEMENT configObject (synopsis?|description?|syntax?|see-also?|configOption)*>
<!ELEMENT configObject (synopsis?|description?|syntax?|see-also?|(configOption|xi:include))*>
<!ATTLIST configObject name CDATA #REQUIRED>
<!ELEMENT configOption (synopsis,description?,syntax?,see-also?)*>

View File

@ -189,7 +189,7 @@ static int check_header(FILE *f, int hz)
}
if(memcmp(buf, "data", 4) == 0 )
break;
ast_log(LOG_DEBUG, "Skipping unknown block '%.4s'\n", buf);
ast_debug(1, "Skipping unknown block '%.4s'\n", buf);
if (fseek(f,data,SEEK_CUR) == -1 ) {
ast_log(LOG_WARNING, "Failed to skip '%.4s' block: %d\n", buf, data);
return -1;

View File

@ -1611,6 +1611,7 @@ static int redirecting_write(struct ast_channel *chan, const char *cmd, char *da
* reason, so we can just set the reason string to what was given and set the
* code to be unknown
*/
ast_log(LOG_WARNING, "Unknown redirecting reason '%s', defaulting to unknown\n", val);
redirecting.orig_reason.code = AST_REDIRECTING_REASON_UNKNOWN;
redirecting.orig_reason.str = val;
set_it(chan, &redirecting, NULL);

107
funcs/func_export.c Normal file
View File

@ -0,0 +1,107 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2021-2022, Naveen Albert
*
* 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 Set variables and functions on other channels
*
* \author Naveen Albert <asterisk@phreaknet.org>
*
* \ingroup functions
*/
/*** MODULEINFO
<support_level>extended</support_level>
***/
#include "asterisk.h"
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
#include "asterisk/stringfields.h"
/*** DOCUMENTATION
<function name="EXPORT" language="en_US">
<synopsis>
Set variables or dialplan functions on any arbitrary channel that exists.
</synopsis>
<syntax>
<parameter name="channel" required="true">
<para>The complete channel name: <literal>SIP/12-abcd1234</literal>.</para>
</parameter>
<parameter name="var" required="true">
<para>Variable name</para>
</parameter>
</syntax>
<description>
<para>Allows setting variables or functions on any existing channel if it exists.</para>
</description>
<see-also>
<ref type="function">IMPORT</ref>
<ref type="function">MASTER_CHANNEL</ref>
<ref type="function">SHARED</ref>
</see-also>
</function>
***/
static int func_export_write(struct ast_channel *chan, const char *function, char *data, const char *value)
{
struct ast_channel *ochan;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(channel);
AST_APP_ARG(var);
);
AST_STANDARD_APP_ARGS(args, data);
if (!args.channel) {
ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
return -1;
}
if (!args.var) {
ast_log(LOG_WARNING, "No variable name was provided to %s function.\n", function);
return -1;
}
ochan = ast_channel_get_by_name(args.channel);
if (!ochan) {
ast_log(LOG_WARNING, "Channel '%s' not found! '%s' not set.\n", args.channel, args.var);
return -1;
}
pbx_builtin_setvar_helper(ochan, data, value);
ast_channel_unref(ochan);
return 0;
}
static struct ast_custom_function export_function = {
.name = "EXPORT",
.write = func_export_write,
};
static int unload_module(void)
{
return ast_custom_function_unregister(&export_function);
}
static int load_module(void)
{
return ast_custom_function_register(&export_function);
}
AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Set variables and functions on other channels");

View File

@ -341,8 +341,7 @@ static void print_frame(struct ast_frame *frame)
ast_verbose("SubClass: PVT_CAUSE_CODE\n");
break;
case AST_CONTROL_MASQUERADE_NOTIFY:
/* Should never happen. */
ast_assert(0);
ast_verbose("SubClass: MASQUERADE_NOTIFY\n");
break;
case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE:
ast_verbose("SubClass: STREAM_TOPOLOGY_REQUEST_CHANGE\n");
@ -398,6 +397,7 @@ static void print_frame(struct ast_frame *frame)
break;
case AST_FRAME_TEXT:
ast_verbose("FrameType: TXT\n");
ast_verbose("Text: %.*s\n", frame->datalen, (char*) frame->data.ptr);
break;
case AST_FRAME_TEXT_DATA:
ast_verbose("FrameType: TXT_DATA\n");

View File

@ -1,7 +1,7 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2021, Naveen Albert
* Copyright (C) 2021-2022, Naveen Albert
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
@ -54,6 +54,21 @@
</parameter>
<parameter name="item" required="true">
<para>The name of the key whose value to return.</para>
<para>Multiple keys can be listed separated by a hierarchy delimeter, which will recursively index into a nested JSON string to retrieve a specific subkey's value.</para>
</parameter>
<parameter name="separator" required="false">
<para>A single character that delimits a key hierarchy for nested indexing. Default is a period (.)</para>
<para>This value should not appear in the key or hierarchy of keys itself, except to delimit the hierarchy of keys.</para>
</parameter>
<parameter name="options" required="no">
<optionlist>
<option name="c">
<para>For keys that reference a JSON array, return
the number of items in the array.</para>
<para>This option has no effect on any other type
of value.</para>
</option>
</optionlist>
</parameter>
</syntax>
<description>
@ -69,19 +84,131 @@
AST_THREADSTORAGE(result_buf);
enum json_option_flags {
OPT_COUNT = (1 << 0),
};
AST_APP_OPTIONS(json_options, {
AST_APP_OPTION('c', OPT_COUNT),
});
#define MAX_JSON_STACK 32
static int parse_node(char **key, char *currentkey, char *nestchar, int count, struct ast_json *json, char *buf, size_t len, int *depth)
{
const char *result = NULL;
char *previouskey;
struct ast_json *jsonval = json;
/* Prevent a huge JSON string from blowing the stack. */
if (*depth > MAX_JSON_STACK) {
ast_log(LOG_WARNING, "Max JSON stack (%d) exceeded\n", MAX_JSON_STACK);
return -1;
}
snprintf(buf, len, "%s", ""); /* clear the buffer from previous round if necessary */
if (!json) { /* no error or warning should be thrown */
ast_debug(1, "Could not find key '%s' in parsed JSON\n", currentkey);
return -1;
}
switch(ast_json_typeof(jsonval)) {
unsigned long int size;
int r;
case AST_JSON_STRING:
result = ast_json_string_get(jsonval);
ast_debug(1, "Got JSON string: %s\n", result);
ast_copy_string(buf, result, len);
break;
case AST_JSON_INTEGER:
r = ast_json_integer_get(jsonval);
ast_debug(1, "Got JSON integer: %d\n", r);
snprintf(buf, len, "%d", r); /* the snprintf below is mutually exclusive with this one */
break;
case AST_JSON_ARRAY:
ast_debug(1, "Got JSON array\n");
previouskey = currentkey;
currentkey = strsep(key, nestchar); /* retrieve the desired index */
size = ast_json_array_size(jsonval);
ast_debug(1, "Parsed JSON array of size %lu, key: %s\n", size, currentkey);
if (!currentkey) { /* this is the end, so just dump the array */
if (count) {
ast_debug(1, "No key on which to index in the array, so returning count: %lu\n", size);
snprintf(buf, len, "%lu", size);
return 0;
} else {
char *result2 = ast_json_dump_string(jsonval);
ast_debug(1, "No key on which to index in the array, so dumping '%s' array\n", previouskey);
ast_copy_string(buf, result2, len);
ast_json_free(result2);
}
} else if (ast_str_to_int(currentkey, &r) || r < 0) {
ast_debug(1, "Requested index '%s' is not numeric or is invalid\n", currentkey);
} else if (r >= size) {
ast_debug(1, "Requested index '%d' does not exist in parsed array\n", r);
} else {
struct ast_json *json2 = ast_json_array_get(jsonval, r);
if (!json2) {
ast_debug(1, "Array index %d contains empty item\n", r);
return -1;
}
previouskey = currentkey;
currentkey = strsep(key, nestchar); /* get the next subkey */
ast_debug(1, "Recursing on index %d in array (key was '%s' and is now '%s')\n", r, previouskey, currentkey);
/* json2 is a borrowed ref. That's fine, since json won't get freed until recursing is over */
/* If there are keys remaining, then parse the next object we can get. Otherwise, just dump the child */
if (parse_node(key, currentkey, nestchar, count, currentkey ? ast_json_object_get(json2, currentkey) : json2, buf, len, depth)) { /* recurse on this node */
return -1;
}
}
break;
case AST_JSON_OBJECT:
default:
ast_debug(1, "Got generic JSON object for key %s\n", currentkey);
if (!currentkey) { /* this is the end, so just dump the object */
char *result2 = ast_json_dump_string(jsonval);
ast_copy_string(buf, result2, len);
ast_json_free(result2);
} else {
previouskey = currentkey;
currentkey = strsep(key, nestchar); /* retrieve the desired index */
ast_debug(1, "Recursing on object (key was '%s' and is now '%s')\n", previouskey, currentkey);
if (parse_node(key, currentkey, nestchar, count, ast_json_object_get(jsonval, currentkey), buf, len, depth)) { /* recurse on this node */
return -1;
}
}
break;
}
return 0;
}
static int json_decode_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
struct ast_json *json, *jsonval;
int count = 0;
struct ast_flags flags = {0};
struct ast_json *json = NULL;
char *nestchar = "."; /* default delimeter for nesting key indexing is . */
int res, depth = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(varname);
AST_APP_ARG(key);
AST_APP_ARG(nestchar);
AST_APP_ARG(options);
);
char *varsubst, *result2;
const char *result = NULL;
char *varsubst, *key, *currentkey, *nextkey, *firstkey, *tmp;
struct ast_str *str = ast_str_thread_get(&result_buf, 16);
AST_STANDARD_APP_ARGS(args, data);
if (!ast_strlen_zero(args.options)) {
ast_app_parse_options(json_options, &flags, NULL, args.options);
if (ast_test_flag(&flags, OPT_COUNT)) {
count = 1;
}
}
if (ast_strlen_zero(args.varname)) {
ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
return -1;
@ -90,6 +217,15 @@ static int json_decode_read(struct ast_channel *chan, const char *cmd, char *dat
ast_log(LOG_WARNING, "%s requires a key\n", cmd);
return -1;
}
key = ast_strdupa(args.key);
if (!ast_strlen_zero(args.nestchar)) {
int seplen = strlen(args.nestchar);
if (seplen != 1) {
ast_log(LOG_WARNING, "Nesting separator '%s' has length %d and is invalid (must be a single character)\n", args.nestchar, seplen);
} else {
nestchar = args.nestchar;
}
}
varsubst = ast_alloca(strlen(args.varname) + 4); /* +4 for ${} and null terminator */
if (!varsubst) {
@ -98,45 +234,43 @@ static int json_decode_read(struct ast_channel *chan, const char *cmd, char *dat
}
sprintf(varsubst, "${%s}", args.varname); /* safe, because of the above allocation */
ast_str_substitute_variables(&str, 0, chan, varsubst);
ast_debug(1, "Parsing JSON using nesting delimeter '%s'\n", nestchar);
if (ast_str_strlen(str) == 0) {
ast_debug(1, "Variable '%s' contains no data, nothing to search!\n", args.varname);
return -1; /* empty json string */
}
ast_debug(1, "Parsing JSON: %s\n", ast_str_buffer(str));
/* allow for multiple key nesting */
currentkey = key;
firstkey = ast_strdupa(currentkey);
tmp = strstr(firstkey, nestchar);
if (tmp) {
*tmp = '\0';
}
/* parse a string as JSON */
ast_debug(1, "Parsing JSON: %s (key: '%s')\n", ast_str_buffer(str), currentkey);
if (ast_strlen_zero(currentkey)) {
ast_debug(1, "Empty JSON key\n");
return -1;
}
if (ast_str_strlen(str) == 0) {
ast_debug(1, "JSON node '%s', contains no data, nothing to search!\n", currentkey);
return -1; /* empty json string */
}
json = ast_json_load_str(str, NULL);
if (!json) {
ast_log(LOG_WARNING, "Failed to parse as JSON: %s\n", ast_str_buffer(str));
return -1;
}
jsonval = ast_json_object_get(json, args.key);
if (!jsonval) { /* no error or warning should be thrown */
ast_debug(1, "Could not find key '%s' in parsed JSON\n", args.key);
ast_json_free(json);
return -1;
}
switch(ast_json_typeof(jsonval)) {
int r;
case AST_JSON_STRING:
result = ast_json_string_get(jsonval);
snprintf(buf, len, "%s", result);
break;
case AST_JSON_INTEGER:
r = ast_json_integer_get(jsonval);
snprintf(buf, len, "%d", r); /* the snprintf below is mutually exclusive with this one */
break;
default:
result2 = ast_json_dump_string(jsonval);
snprintf(buf, len, "%s", result2);
ast_json_free(result2);
break;
}
ast_json_free(json);
return 0;
/* parse the JSON object, potentially recursively */
nextkey = strsep(&key, nestchar);
res = parse_node(&key, nextkey, nestchar, count, ast_json_object_get(json, firstkey), buf, len, &depth);
ast_json_unref(json);
return res;
}
static struct ast_custom_function json_decode_function = {
@ -151,12 +285,26 @@ AST_TEST_DEFINE(test_JSON_DECODE)
struct ast_channel *chan; /* dummy channel */
struct ast_str *str; /* fancy string for holding comparing value */
const char *test_strings[][5] = {
{"{\"city\": \"Anytown\", \"state\": \"USA\"}", "city", "Anytown"},
{"{\"city\": \"Anytown\", \"state\": \"USA\"}", "state", "USA"},
{"{\"city\": \"Anytown\", \"state\": \"USA\"}", "blah", ""},
{"{\"key1\": \"123\", \"key2\": \"456\"}", "key1", "123"},
{"{\"key1\": 123, \"key2\": 456}", "key1", "123"},
const char *test_strings[][6] = {
{"{\"city\": \"Anytown\", \"state\": \"USA\"}", "", "city", "Anytown"},
{"{\"city\": \"Anytown\", \"state\": \"USA\"}", "", "state", "USA"},
{"{\"city\": \"Anytown\", \"state\": \"USA\"}", "", "blah", ""},
{"{\"key1\": \"123\", \"key2\": \"456\"}", "", "key1", "123"},
{"{\"key1\": 123, \"key2\": 456}", "", "key1", "123"},
{"{ \"path\": { \"to\": { \"elem\": \"someVar\" } } }", "/", "path/to/elem", "someVar"},
{"{ \"path\": { \"to\": { \"elem\": \"someVar\" } } }", "", "path.to.elem2", ""},
{"{ \"path\": { \"to\": { \"arr\": [ \"item0\", \"item1\" ] } } }", "/", "path/to/arr/2", ""}, /* nonexistent index */
{"{ \"path\": { \"to\": { \"arr\": [ \"item0\", \"item1\" ] } } }", "/", "path/to/arr/-1", ""}, /* bogus index */
{"{ \"path\": { \"to\": { \"arr\": [ \"item0\", \"item1\" ] } } }", "/", "path/to/arr/test", ""}, /* bogus index */
{"{ \"path\": { \"to\": { \"arr\": [ \"item0\", \"item1\" ] } } }", "", "path.to.arr.test.test2.subkey", ""}, /* bogus index */
{"{ \"path\": { \"to\": { \"arr\": [ \"item0\", \"item1\" ] } } }", ",c", "path.to.arr", "2"}, /* test count */
{"{ \"path\": { \"to\": { \"arr\": [ \"item0\", \"item1\" ] } } }", "", "path.to.arr", "[\"item0\",\"item1\"]"},
{"{ \"path\": { \"to\": { \"arr\": [ \"item0\", \"item1\" ] } } }", ".", "path.to.arr.1", "item1"},
{"{ \"path\": { \"to\": { \"arr\": [ \"item0\", \"item1\" ] } } }", "/", "path/to/arr", "[\"item0\",\"item1\"]"},
{"{ \"path\": { \"to\": { \"arr\": [ \"item0\", \"item1\" ] } } }", "/", "path/to/arr/1", "item1"},
{"{ \"path\": { \"to\": { \"arr\": [ {\"name\": \"John Smith\", \"phone\": \"123\"}, {\"name\": \"Jane Doe\", \"phone\": \"234\"} ] } } }", ",c", "path.to.arr.0.name", "John Smith"},
{"{ \"path\": { \"to\": { \"arr\": [ {\"name\": 1, \"phone\": 123}, {\"name\": 2, \"phone\": 234} ] } } }", ",c", "path.to.arr.0.name", "1"},
{"{ \"path\": { \"to\": { \"arr\": [ {\"name\": [ \"item11\", \"item12\" ], \"phone\": [ \"item13\", \"item14\" ]}, {\"name\": [ \"item15\", \"item16\" ], \"phone\": [ \"item17\", \"item18\" ]} ] } } }", ",c", "path.to.arr.0.name.1", "item12"},
};
switch (cmd) {
@ -182,7 +330,7 @@ AST_TEST_DEFINE(test_JSON_DECODE)
}
for (i = 0; i < ARRAY_LEN(test_strings); i++) {
char tmp[512], tmp2[512] = "";
char tmp[512];
struct ast_var_t *var = ast_var_assign("test_string", test_strings[i][0]);
if (!var) {
@ -194,11 +342,11 @@ AST_TEST_DEFINE(test_JSON_DECODE)
AST_LIST_INSERT_HEAD(ast_channel_varshead(chan), var, entries);
snprintf(tmp, sizeof(tmp), "${JSON_DECODE(%s,%s)}", "test_string", test_strings[i][1]);
snprintf(tmp, sizeof(tmp), "${JSON_DECODE(%s,%s,%s)}", "test_string", test_strings[i][2], test_strings[i][1]);
ast_str_substitute_variables(&str, 0, chan, tmp);
if (strcmp(test_strings[i][2], ast_str_buffer(str))) {
ast_test_status_update(test, "Format string '%s' substituted to '%s'. Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][2]);
if (strcmp(test_strings[i][3], ast_str_buffer(str))) {
ast_test_status_update(test, "Format string '%s' substituted to '%s' (key: %s). Expected '%s'.\n", test_strings[i][0], ast_str_buffer(str), test_strings[i][2], test_strings[i][3]);
res = AST_TEST_FAIL;
}
}
@ -214,7 +362,9 @@ static int unload_module(void)
{
int res;
#ifdef TEST_FRAMEWORK
AST_TEST_UNREGISTER(test_JSON_DECODE);
#endif
res = ast_custom_function_unregister(&json_decode_function);
return res;
@ -224,7 +374,9 @@ static int load_module(void)
{
int res;
#ifdef TEST_FRAMEWORK
AST_TEST_REGISTER(test_JSON_DECODE);
#endif
res = ast_custom_function_register(&json_decode_function);
return res;

View File

@ -187,8 +187,7 @@ static int acf_if(struct ast_channel *chan, const char *cmd, char *data, char *b
AST_NONSTANDARD_APP_ARGS(args2, args1.remainder, ':');
if (ast_strlen_zero(args1.expr) || !(args2.iftrue || args2.iffalse)) {
ast_log(LOG_WARNING, "Syntax IF(<expr>?[<true>][:<false>]) (expr must be non-null, and either <true> or <false> must be non-null)\n");
ast_log(LOG_WARNING, " In this case, <expr>='%s', <true>='%s', and <false>='%s'\n", args1.expr, args2.iftrue, args2.iffalse);
ast_debug(1, "<expr>='%s', <true>='%s', and <false>='%s'\n", args1.expr, args2.iftrue, args2.iffalse);
return -1;
}

View File

@ -850,8 +850,8 @@ static int load_module(void)
for (; db_entry; db_entry = db_entry->next) {
const char *dev_name = strrchr(db_entry->key, '/') + 1;
enum ast_presence_state state;
char *message;
char *subtype;
char *message = NULL;
char *subtype = NULL;
if (dev_name <= (const char *) 1) {
continue;
}

View File

@ -211,6 +211,15 @@ AST_TEST_DEFINE(test_SAYFILES_function)
res = AST_TEST_FAIL;
}
/* + should be ignored and there should not be a leading & */
ast_str_set(&expr, 0, "${SAYFILES(+18005551212,digits)}");
ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
if (strcmp(ast_str_buffer(result), "digits/1&digits/8&digits/0&digits/0&digits/5&digits/5&digits/5&digits/1&digits/2&digits/1&digits/2") != 0) {
ast_test_status_update(test, "SAYFILES(+18005551212,digits) test failed ('%s')\n",
ast_str_buffer(result));
res = AST_TEST_FAIL;
}
ast_str_set(&expr, 0, "${SAYFILES(35,number)}");
ast_str_substitute_variables(&result, 0, NULL, ast_str_buffer(expr));
if (strcmp(ast_str_buffer(result), "digits/30&digits/5") != 0) {

View File

@ -125,6 +125,7 @@ static int scramble_callback(struct ast_audiohook *audiohook, struct ast_channel
}
if (frame->frametype == AST_FRAME_VOICE) { /* only invert voice frequencies */
ni = datastore->data;
/* Based on direction of frame, and confirm it is applicable */
if (!(direction == AST_AUDIOHOOK_DIRECTION_READ ? ni->rx : ni->tx)) {
return 0;

View File

@ -65,6 +65,16 @@
as <literal>getnum</literal>, then it will return the total number of results
that are available.</para>
</parameter>
<parameter name="field" required="false">
<para>The field of the result to retrieve.</para>
<para>The fields that can be retrieved are:</para>
<enumlist>
<enum name="host"/>
<enum name="port"/>
<enum name="priority"/>
<enum name="weight"/>
</enumlist>
</parameter>
</syntax>
<description>
<para>This function will retrieve results from a previous use

View File

@ -4,7 +4,7 @@
* Copyright (C) 2005-2006, Digium, Inc.
* Portions Copyright (C) 2005, Tilghman Lesher. All rights reserved.
* Portions Copyright (C) 2005, Anthony Minessale II
* Portions Copyright (C) 2021, Naveen Albert
* Portions Copyright (C) 2021, 2022, Naveen Albert
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
@ -183,6 +183,51 @@ AST_THREADSTORAGE(tmp_buf);
</example>
</description>
</function>
<function name="TRIM" language="en_US">
<synopsis>
Trim leading and trailing whitespace in a string
</synopsis>
<syntax>
<parameter name="string" required="true" />
</syntax>
<description>
<para>Replaces all leading and trailing whitespace in the provided string.</para>
</description>
<see-also>
<ref type="function">LTRIM</ref>
<ref type="function">RTRIM</ref>
</see-also>
</function>
<function name="LTRIM" language="en_US">
<synopsis>
Trim leading whitespace in a string
</synopsis>
<syntax>
<parameter name="string" required="true" />
</syntax>
<description>
<para>Replaces all leading whitespace in the provided string.</para>
</description>
<see-also>
<ref type="function">TRIM</ref>
<ref type="function">RTRIM</ref>
</see-also>
</function>
<function name="RTRIM" language="en_US">
<synopsis>
Trim trailing whitespace in a string
</synopsis>
<syntax>
<parameter name="string" required="true" />
</syntax>
<description>
<para>Replaces all trailing whitespace in the provided string.</para>
</description>
<see-also>
<ref type="function">TRIM</ref>
<ref type="function">LTRIM</ref>
</see-also>
</function>
<function name="PASSTHRU" language="en_US">
<synopsis>
Pass the given argument back as a value.
@ -1045,6 +1090,84 @@ static struct ast_custom_function strbetween_function = {
.read2 = strbetween,
};
#define ltrim(s) while (isspace(*s)) s++;
#define rtrim(s) { \
if (s) { \
char *back = s + strlen(s); \
while (back != s && isspace(*--back)); \
if (*s) { \
*(back + 1) = '\0'; \
} \
} \
}
static int function_trim(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
char *c;
if (ast_strlen_zero(data)) {
return -1;
}
c = ast_strdupa(data);
ltrim(c);
rtrim(c);
ast_copy_string(buf, c, len);
return 0;
}
static int function_ltrim(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
char *c;
if (ast_strlen_zero(data)) {
return -1;
}
c = data;
ltrim(c);
ast_copy_string(buf, c, len);
return 0;
}
static int function_rtrim(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
char *c;
if (ast_strlen_zero(data)) {
return -1;
}
c = ast_strdupa(data);
rtrim(c);
ast_copy_string(buf, c, len);
return 0;
}
#undef ltrim
#undef rtrim
static struct ast_custom_function trim_function = {
.name = "TRIM",
.read = function_trim,
};
static struct ast_custom_function ltrim_function = {
.name = "LTRIM",
.read = function_ltrim,
};
static struct ast_custom_function rtrim_function = {
.name = "RTRIM",
.read = function_rtrim,
};
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
size_t len)
{
@ -2126,6 +2249,59 @@ AST_TEST_DEFINE(test_STRBETWEEN)
return res;
}
AST_TEST_DEFINE(test_TRIM)
{
int i, res = AST_TEST_PASS;
struct ast_channel *chan; /* dummy channel */
struct ast_str *str; /* fancy string for holding comparing value */
const char *test_strings[][5] = {
{"TRIM", " abcd ", "abcd"},
{"LTRIM", " abcd ", "abcd "},
{"RTRIM", " abcd ", " abcd"},
{"TRIM", "abcd", "abcd"},
{"TRIM", " a b c d ", "a b c d"},
};
switch (cmd) {
case TEST_INIT:
info->name = "func_TRIM";
info->category = "/funcs/func_strings/";
info->summary = "Test TRIM functions";
info->description = "Verify TRIM behavior";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
if (!(chan = ast_dummy_channel_alloc())) {
ast_test_status_update(test, "Unable to allocate dummy channel\n");
return AST_TEST_FAIL;
}
if (!(str = ast_str_create(64))) {
ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
ast_channel_release(chan);
return AST_TEST_FAIL;
}
for (i = 0; i < ARRAY_LEN(test_strings); i++) {
char tmp[512], tmp2[512] = "";
snprintf(tmp, sizeof(tmp), "${%s(%s)}", test_strings[i][0], test_strings[i][1]);
ast_str_substitute_variables(&str, 0, chan, tmp);
if (strcmp(test_strings[i][2], ast_str_buffer(str))) {
ast_test_status_update(test, "Format string '%s' substituted to '%s'. Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][2]);
res = AST_TEST_FAIL;
}
}
ast_free(str);
ast_channel_release(chan);
return res;
}
#endif
static int unload_module(void)
@ -2137,6 +2313,7 @@ static int unload_module(void)
AST_TEST_UNREGISTER(test_FILTER);
AST_TEST_UNREGISTER(test_STRREPLACE);
AST_TEST_UNREGISTER(test_STRBETWEEN);
AST_TEST_UNREGISTER(test_TRIM);
res |= ast_custom_function_unregister(&fieldqty_function);
res |= ast_custom_function_unregister(&fieldnum_function);
res |= ast_custom_function_unregister(&filter_function);
@ -2163,6 +2340,9 @@ static int unload_module(void)
res |= ast_custom_function_unregister(&push_function);
res |= ast_custom_function_unregister(&unshift_function);
res |= ast_custom_function_unregister(&passthru_function);
res |= ast_custom_function_unregister(&trim_function);
res |= ast_custom_function_unregister(&ltrim_function);
res |= ast_custom_function_unregister(&rtrim_function);
return res;
}
@ -2176,6 +2356,7 @@ static int load_module(void)
AST_TEST_REGISTER(test_FILTER);
AST_TEST_REGISTER(test_STRREPLACE);
AST_TEST_REGISTER(test_STRBETWEEN);
AST_TEST_REGISTER(test_TRIM);
res |= ast_custom_function_register(&fieldqty_function);
res |= ast_custom_function_register(&fieldnum_function);
res |= ast_custom_function_register(&filter_function);
@ -2202,6 +2383,9 @@ static int load_module(void)
res |= ast_custom_function_register(&push_function);
res |= ast_custom_function_register(&unshift_function);
res |= ast_custom_function_register(&passthru_function);
res |= ast_custom_function_register(&trim_function);
res |= ast_custom_function_register(&ltrim_function);
res |= ast_custom_function_register(&rtrim_function);
return res;
}

View File

@ -37,6 +37,7 @@ int ast_term_init(void); /*!< Provided by term.c */
int astdb_init(void); /*!< Provided by db.c */
int ast_channels_init(void); /*!< Provided by channel.c */
void ast_builtins_init(void); /*!< Provided by cli.c */
void ast_cli_channels_init(void); /*!< Provided by cli.c */
int ast_cli_perms_init(int reload); /*!< Provided by cli.c */
void dnsmgr_start_refresh(void); /*!< Provided by dnsmgr.c */
int ast_dns_system_resolver_init(void); /*!< Provided by dns_system_resolver.c */

View File

@ -118,6 +118,7 @@ struct ast_audiohook {
ast_audiohook_manipulate_callback manipulate_callback; /*!< Manipulation callback */
struct ast_audiohook_options options; /*!< Applicable options */
unsigned int hook_internal_samp_rate; /*!< internal read/write sample rate on the audiohook.*/
enum ast_audiohook_direction direction; /*!< Intended audiohook direction, BOTH by default on init */
AST_LIST_ENTRY(ast_audiohook) list; /*!< Linked list information */
};
@ -140,6 +141,14 @@ int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type
*/
int ast_audiohook_destroy(struct ast_audiohook *audiohook);
/*! \brief Sets direction on audiohook
* \param audiohook
* \param direction In which direction should the audiohook feed frames, ie if we are snooping 'in', set direction to READ so that only the 'in' frames are fed to the slin factory
* \retval 0 on success
* \retval -1 on failure due to audiohook already in use or in shutdown. Can only set direction on NEW audiohooks
*/
int ast_audiohook_set_frame_feed_direction(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction);
/*! \brief Writes a frame into the audiohook structure
* \param audiohook
* \param direction Direction the audio frame came from

View File

@ -632,6 +632,9 @@
/* Define to 1 if PJPROJECT has the PJSIP EVSUB Group Lock support feature. */
#undef HAVE_PJSIP_EVSUB_GRP_LOCK
/* Define to 1 if evsub requires a NOTIFY on SUBSCRIBE. */
#undef HAVE_PJSIP_EVSUB_PENDING_NOTIFY
/* Define to 1 if PJPROJECT has the PJSIP External Resolver Support feature.
*/
#undef HAVE_PJSIP_EXTERNAL_RESOLVER
@ -656,6 +659,10 @@
/* Define if your system has the PJSIP_TLS_TRANSPORT_PROTO headers. */
#undef HAVE_PJSIP_TLS_TRANSPORT_PROTO
/* Define to 1 if PJPROJECT has the PJSIP TLS Transport Restart Support
feature. */
#undef HAVE_PJSIP_TLS_TRANSPORT_RESTART
/* Define if your system has the PJSIP_TRANSPORT_DISABLE_CONNECTION_REUSE
headers. */
#undef HAVE_PJSIP_TRANSPORT_DISABLE_CONNECTION_REUSE

View File

@ -225,6 +225,8 @@ enum ast_cdr_settings {
CDR_INITIATED_SECONDS = 1 << 5, /*!< Include microseconds into the billing time */
CDR_DEBUG = 1 << 6, /*!< Enables extra debug statements */
CDR_CHANNEL_DEFAULT_ENABLED = 1 << 7, /*!< Whether CDR is enabled for each channel by default */
CDR_IGNORE_STATE_CHANGES = 1 << 8, /*!< Whether to ignore bridge and other call state change events */
CDR_IGNORE_DIAL_CHANGES = 1 << 9, /*!< Whether to ignore dial state changes */
};
/*! \brief CDR Batch Mode settings */

View File

@ -2255,8 +2255,8 @@ int ast_senddigit_mf_end(struct ast_channel *chan);
* \param chan channel to act upon
* \param digit the MF digit to send, encoded in ASCII
* \param duration the duration of a numeric digit ending in ms
* \param duration the duration of a KP digit ending in ms
* \param duration the duration of a ST, STP, ST2P, or ST3P digit ending in ms
* \param durationkp the duration of a KP digit ending in ms
* \param durationst the duration of a ST, STP, ST2P, or ST3P digit ending in ms
* \param is_external 1 if called by a thread that is not the channel's media
* handler thread, 0 if called by the channel's media handler
* thread.
@ -4112,8 +4112,6 @@ struct ast_channel_monitor {
};
/* ACCESSOR FUNCTIONS */
/*! \brief Set the channel name */
void ast_channel_name_set(struct ast_channel *chan, const char *name);
#define DECLARE_STRINGFIELD_SETTERS_FOR(field) \
void ast_channel_##field##_set(struct ast_channel *chan, const char *field); \

View File

@ -30,20 +30,22 @@ extern "C" {
#include "asterisk/optional_api.h"
#include "asterisk/logger.h"
#ifdef HAVE_CRYPTO
#include "openssl/aes.h"
typedef AES_KEY ast_aes_encrypt_key;
typedef AES_KEY ast_aes_decrypt_key;
#else /* !HAVE_CRYPTO */
typedef char ast_aes_encrypt_key;
typedef char ast_aes_decrypt_key;
#endif /* HAVE_CRYPTO */
/* We previously used the key length explicitly; replace with constant.
* For now, Asterisk is limited to 1024 bit (128 byte) RSA keys.
*/
#define AST_CRYPTO_RSA_KEY_BITS 1024
#define AST_CRYPTO_AES_BLOCKSIZE 128
struct aes_key {
unsigned char raw[AST_CRYPTO_AES_BLOCKSIZE / 8];
};
typedef struct aes_key ast_aes_encrypt_key;
typedef struct aes_key ast_aes_decrypt_key;
#define AST_KEY_PUBLIC (1 << 0)
#define AST_KEY_PRIVATE (1 << 1)
struct ast_key;
/*!
* \brief Retrieve a key
* \param kname Name of the key we are retrieving
@ -108,10 +110,10 @@ AST_OPTIONAL_API(int, ast_sign_bin, (struct ast_key *key, const char *msg, int m
/*!
* \brief Encrypt a message using a given private key
* \param key a private key to use to encrypt
* \param dst a pointer to a buffer of at least srclen * 1.5 bytes in which the encrypted
* \param src the message to encrypt
* \param srclen the length of the message to encrypt
* \param dst a pointer to a buffer of at least srclen * 1.5 bytes in which the encrypted
* \param key a private key to use to encrypt
* answer will be stored
*
* \retval length of encrypted data on success.
@ -122,10 +124,10 @@ AST_OPTIONAL_API(int, ast_encrypt_bin, (unsigned char *dst, const unsigned char
/*!
* \brief Decrypt a message using a given private key
* \param key a private key to use to decrypt
* \param dst a pointer to a buffer of at least srclen bytes in which the decrypted
* \param src the message to decrypt
* \param srclen the length of the message to decrypt
* \param dst a pointer to a buffer of at least srclen bytes in which the decrypted
* \param key a private key to use to decrypt
* answer will be stored
*
* \retval length of decrypted data on success.
@ -162,24 +164,30 @@ AST_OPTIONAL_API(int, ast_aes_set_decrypt_key,
* \brief AES encrypt data
* \param in data to be encrypted
* \param out pointer to a buffer to hold the encrypted output
* \param ctx address of an aes encryption context filled in with ast_aes_set_encrypt_key
* \param key pointer to the ast_aes_encrypt_key to use for encryption
* \retval <= 0 failure
* \retval otherwise number of bytes in output buffer
*/
AST_OPTIONAL_API(void, ast_aes_encrypt,
(const unsigned char *in, unsigned char *out, const ast_aes_encrypt_key *ctx),
{ ast_log(LOG_WARNING, "AES encryption disabled. Install OpenSSL.\n");return; });
AST_OPTIONAL_API(int, ast_aes_encrypt,
(const unsigned char *in, unsigned char *out, const ast_aes_encrypt_key *key),
{ ast_log(LOG_WARNING, "AES encryption disabled. Install OpenSSL.\n");return -1; });
/*!
* \brief AES decrypt data
* \param in encrypted data
* \param out pointer to a buffer to hold the decrypted output
* \param ctx address of an aes encryption context filled in with ast_aes_set_decrypt_key
* \param key pointer to the ast_aes_decrypt_key to use for decryption
* \retval <= 0 failure
* \retval otherwise number of bytes in output buffer
*/
AST_OPTIONAL_API(void, ast_aes_decrypt,
(const unsigned char *in, unsigned char *out, const ast_aes_decrypt_key *ctx),
{ ast_log(LOG_WARNING, "AES encryption disabled. Install OpenSSL.\n");return; });
AST_OPTIONAL_API(int, ast_aes_decrypt,
(const unsigned char *in, unsigned char *out, const ast_aes_decrypt_key *key),
{ ast_log(LOG_WARNING, "AES encryption disabled. Install OpenSSL.\n");return -1; });
AST_OPTIONAL_API(int, ast_crypto_loaded, (void), { return 0; });
AST_OPTIONAL_API(int, ast_crypto_reload, (void), { return 0; });
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif

View File

@ -72,6 +72,8 @@ struct ast_features_xfer_config {
AST_STRING_FIELD(transferretrysound);
/*! Sound played when an invalid extension is dialed, and the transferer is being returned to the call. */
AST_STRING_FIELD(transferinvalidsound);
/*! Sound to play to announce the transfer process has started. */
AST_STRING_FIELD_EXTENDED(transferannouncesound);
);
/*! Seconds allowed between digit presses when dialing transfer destination */
unsigned int transferdigittimeout;

View File

@ -80,6 +80,7 @@ int ast_streamfile(struct ast_channel *c, const char *filename, const char *pref
* \brief stream file until digit
* If the file name is non-empty, try to play it.
* \note If digits == "" then we can simply check for non-zero.
* \note If a failure is encountered, the stream will be closed before returning.
* \retval 0 if success.
* \retval -1 if error.
* \retval digit if interrupted by a digit.

View File

@ -592,6 +592,15 @@ struct ast_json *ast_json_object_get(struct ast_json *object, const char *key);
*/
#define ast_json_object_integer_get(object, key) ast_json_integer_get(ast_json_object_get(object, key))
/*!
* \brief Get a double field from a JSON object.
* \param object JSON object.
* \param key Key of double field to look up.
* \return Value of a JSON double.
* \retval 0 if \a real is not a JSON real number.
*/
#define ast_json_object_real_get(object, key) ast_json_real_get(ast_json_object_get(object, key))
/*!
* \brief Set a field in a JSON object.
* \since 12.0.0

View File

@ -350,6 +350,18 @@ void astman_send_list_complete_start(struct mansession *s, const struct message
*/
void astman_send_list_complete_end(struct mansession *s);
/*!
* \brief Enable/disable the inclusion of 'dangerous' configurations outside
* of the ast_config_AST_CONFIG_DIR
*
* This function can globally enable/disable the loading of configuration files
* outside of ast_config_AST_CONFIG_DIR.
*
* \param new_live_dangerously If true, enable the access of files outside
* ast_config_AST_CONFIG_DIR from astman.
*/
void astman_live_dangerously(int new_live_dangerously);
void __attribute__((format(printf, 2, 3))) astman_append(struct mansession *s, const char *fmt, ...);
/*! \brief Determine if a manager session ident is authenticated */

View File

@ -271,9 +271,9 @@ int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data);
/*!
* \brief Execute an application
*
* \param c channel to execute on
* \param app name of app to execute
* \param data the data passed into the app
* \param chan channel to execute on
* \param app_name name of app to execute
* \param app_args the data passed into the app
*
* This application executes an application by name on a given channel.
* It is a wrapper around pbx_exec that will perform variable substitution
@ -1432,7 +1432,7 @@ void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead
/*!
* \brief Substitutes variables, similar to pbx_substitute_variables_helper_full, but allows passing the context, extension, and priority in.
*/
void pbx_substitute_variables_helper_full_location(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used, char *context, char *exten, int pri);
void pbx_substitute_variables_helper_full_location(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used, const char *context, const char *exten, int pri);
/*! @} */
/*! @name Substitution routines, using dynamic string buffers

View File

@ -55,7 +55,7 @@ struct ao2_container *ast_aeap_client_configs_get(const char *protocol);
/*!
* \brief Retrieve codec capabilities from the configuration
*
* \param config A configuration object
* \param cfg A configuration object
*
* \returns The configuration's codec capabilities
*/
@ -64,7 +64,7 @@ const struct ast_format_cap *ast_aeap_client_config_codecs(const struct ast_aeap
/*!
* \brief Check a given protocol against that in an Asterisk external application configuration
*
* \param config A configuration object
* \param cfg A configuration object
* \param protocol The protocol to check
*
* \returns True if the configuration's protocol matches, false otherwise
@ -294,7 +294,8 @@ void ast_aeap_user_data_unregister(struct ast_aeap *aeap, const char *id);
* handler that [potentially] frees it the caller of this function must ensure
* it's done using the returned object before it's unregistered.
*
* \param data A user data object
* \param aeap An Asterisk external application object
* \param id The look up id for the object
*
* \returns A user data object
*/
@ -359,7 +360,6 @@ struct ast_aeap_tsx_params {
* is specified in "params".
*
* \param aeap An Asterisk external application object
* \param msg The message to send
* \param params (optional) Additional parameters to consider when sending. Heap allocation
* not required.
*

View File

@ -241,7 +241,6 @@ struct ast_aeap_message *ast_aeap_message_create_response(const struct ast_aeap_
* \param name The name of the message
* \param id Optional id
* \param error_msg Error message to set
* \param params Other optional parameter(s) to possibly use
*
* \returns An ao2 reference counted AEAP response object, or NULL on error
*/
@ -315,7 +314,7 @@ const char *ast_aeap_message_name(const struct ast_aeap_message *message);
* \note Case insensitive
*
* \param message A message object
* \param message name The name to check against
* \param name The name to check against
*
* \returns True if matched, false otherwise
*/

View File

@ -29,8 +29,8 @@
enum ast_geoloc_pidf_element {
AST_PIDF_ELEMENT_NONE = 0,
AST_PIDF_ELEMENT_TUPLE,
AST_PIDF_ELEMENT_DEVICE,
AST_PIDF_ELEMENT_TUPLE,
AST_PIDF_ELEMENT_PERSON,
AST_PIDF_ELEMENT_LAST,
};
@ -43,13 +43,22 @@ enum ast_geoloc_format {
AST_GEOLOC_FORMAT_LAST,
};
enum ast_geoloc_action {
AST_GEOLOC_ACT_PREFER_INCOMING = 0,
AST_GEOLOC_ACT_PREFER_CONFIG,
AST_GEOLOC_ACT_DISCARD_INCOMING,
AST_GEOLOC_ACT_DISCARD_CONFIG,
enum ast_geoloc_precedence {
AST_GEOLOC_PRECED_PREFER_INCOMING = 0,
AST_GEOLOC_PRECED_PREFER_CONFIG,
AST_GEOLOC_PRECED_DISCARD_INCOMING,
AST_GEOLOC_PRECED_DISCARD_CONFIG,
};
#define CONFIG_STR_TO_ENUM_DECL(_stem) int ast_geoloc_ ## _stem ## _str_to_enum(const char *str);
CONFIG_STR_TO_ENUM_DECL(pidf_element)
CONFIG_STR_TO_ENUM_DECL(format);
CONFIG_STR_TO_ENUM_DECL(precedence);
#define GEOLOC_ENUM_TO_NAME_DECL(_stem) const char * ast_geoloc_ ## _stem ## _to_name(int ix);
GEOLOC_ENUM_TO_NAME_DECL(pidf_element)
GEOLOC_ENUM_TO_NAME_DECL(format);
GEOLOC_ENUM_TO_NAME_DECL(precedence);
struct ast_geoloc_location {
SORCERY_OBJECT(details);
AST_DECLARE_STRING_FIELDS(
@ -58,6 +67,7 @@ struct ast_geoloc_location {
);
enum ast_geoloc_format format;
struct ast_variable *location_info;
struct ast_variable *confidence;
};
struct ast_geoloc_profile {
@ -65,13 +75,19 @@ struct ast_geoloc_profile {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(location_reference);
AST_STRING_FIELD(notes);
AST_STRING_FIELD(method);
AST_STRING_FIELD(location_source);
);
enum ast_geoloc_pidf_element pidf_element;
enum ast_geoloc_action action;
int geolocation_routing;
enum ast_geoloc_precedence precedence;
int allow_routing_use;
struct ast_variable *location_refinement;
struct ast_variable *location_variables;
struct ast_variable *usage_rules;
int suppress_empty_ca_elements;
enum ast_geoloc_format format;
struct ast_variable *location_info;
struct ast_variable *confidence;
};
struct ast_geoloc_eprofile {
@ -83,14 +99,16 @@ struct ast_geoloc_eprofile {
AST_STRING_FIELD(notes);
);
enum ast_geoloc_pidf_element pidf_element;
enum ast_geoloc_action action;
int geolocation_routing;
enum ast_geoloc_precedence precedence;
int allow_routing_use;
enum ast_geoloc_format format;
struct ast_variable *location_info;
struct ast_variable *location_refinement;
struct ast_variable *location_variables;
struct ast_variable *effective_location;
struct ast_variable *usage_rules;
struct ast_variable *confidence;
int suppress_empty_ca_elements;
};
/*!
@ -147,7 +165,7 @@ const char *ast_geoloc_validate_result_to_str(enum ast_geoloc_validate_result re
* \brief Validate that the names of the variables in the list are valid codes or synonyms
*
* \param varlist Variable list to check.
* \param result[OUT] Pointer to char * to receive failing item.
* \param[out] result Pointer to char * to receive failing item.
*
* \return result code.
*/
@ -158,7 +176,7 @@ enum ast_geoloc_validate_result ast_geoloc_civicaddr_validate_varlist(
* \brief Validate that the variables in the list represent a valid GML shape
*
* \param varlist Variable list to check.
* \param result[OUT] Pointer to char * to receive failing item.
* \param[out] result Pointer to char * to receive failing item.
*
* \return result code.
*/
@ -299,6 +317,15 @@ struct ast_datastore *ast_geoloc_datastore_find(struct ast_channel *chan);
*/
struct ast_geoloc_eprofile *ast_geoloc_eprofile_alloc(const char *name);
/*!
* \brief Duplicate an effective profile.
*
* \param src The eprofile to duplicate.
*
* \return The duplicated effective profile ao2 object.
*/
struct ast_geoloc_eprofile *ast_geoloc_eprofile_dup(struct ast_geoloc_eprofile *src);
/*!
* \brief Allocate a new effective profile from an existing profile.
*
@ -331,12 +358,45 @@ struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_pidf(
struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_uri(const char *uri,
const char *reference_string);
/*!
* \brief Convert a URI eprofile to a URI string
*
* \param eprofile Effective profile to convert
* \param chan Channel to use to resolve variables
* \param buf Pointer to ast_str pointer to use for work
* \param ref_string An identifying string to use in error messages.
*
* \return String representation of URI allocated from buf or NULL on failure
*/
const char *ast_geoloc_eprofile_to_uri(struct ast_geoloc_eprofile *eprofile,
struct ast_channel *chan, struct ast_str **buf, const char *ref_string);
/*!
* \brief Convert a datastore containing eprofiles to a PIDF-LO document
*
* \param ds Datastore containing effective profiles to convert
* \param chan Channel to use to resolve variables
* \param buf Pointer to ast_str pointer to use for work
* \param ref_string An identifying string to use in error messages.
*
* \return String representation PIDF-LO allocated from buf or NULL on failure.
*/
const char *ast_geoloc_eprofiles_to_pidf(struct ast_datastore *ds,
struct ast_channel *chan, struct ast_str **buf, const char * ref_string);
/*!
* \brief Convert a single eprofile to a PIDF-LO document
*
* \param eprofile Effective profile to convert
* \param chan Channel to use to resolve variables
* \param buf Pointer to ast_str pointer to use for work
* \param ref_string An identifying string to use in error messages.
*
* \return String representation PIDF-LO allocated from buf or NULL on failure.
*/
const char *ast_geoloc_eprofile_to_pidf(struct ast_geoloc_eprofile *eprofile,
struct ast_channel *chan, struct ast_str **buf, const char * ref_string);
/*!
* \brief Refresh the effective profile with any changed info.
*

View File

@ -51,6 +51,11 @@
#include "asterisk/stasis_endpoints.h"
#include "asterisk/stream.h"
#ifdef HAVE_PJSIP_TLS_TRANSPORT_RESTART
/* Needed for knowing if the cert or priv key files changed */
#include <sys/stat.h>
#endif
#define PJSIP_MINVERSION(m,n,p) (((m << 24) | (n << 16) | (p << 8)) >= PJ_VERSION_NUM)
#ifndef PJSIP_EXPIRES_NOT_SPECIFIED
@ -82,6 +87,26 @@
#define AST_STIR_SHAKEN_RESPONSE_STR_UNSUPPORTED_CREDENTIAL "Unsupported Credential"
#define AST_STIR_SHAKEN_RESPONSE_STR_INVALID_IDENTITY_HEADER "Invalid Identity Header"
/* ":12345" */
#define COLON_PORT_STRLEN 6
/*
* "<ipaddr>:<port>"
* PJ_INET6_ADDRSTRLEN includes the NULL terminator
*/
#define IP6ADDR_COLON_PORT_BUFLEN (PJ_INET6_ADDRSTRLEN + COLON_PORT_STRLEN)
/*!
* \brief Fill a buffer with a pjsip transport's remote ip address and port
*
* \param _transport The pjsip_transport to use
* \param _dest The destination buffer of at least IP6ADDR_COLON_PORT_BUFLEN bytes
*/
#define AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(_transport, _dest) \
snprintf(_dest, IP6ADDR_COLON_PORT_BUFLEN, \
PJSTR_PRINTF_SPEC ":%d", \
PJSTR_PRINTF_VAR(_transport->remote_name.host), \
_transport->remote_name.port);
/* Forward declarations of PJSIP stuff */
struct pjsip_rx_data;
struct pjsip_module;
@ -100,6 +125,8 @@ struct pjsip_tpselector;
AST_VECTOR(ast_sip_service_route_vector, char *);
static const pj_str_t AST_PJ_STR_EMPTY = { "", 0 };
/*!
* \brief Structure for SIP transport information
*/
@ -184,6 +211,16 @@ struct ast_sip_transport_state {
* If true, fail if server certificate cannot verify (TLS only)
*/
int verify_server;
#ifdef HAVE_PJSIP_TLS_TRANSPORT_RESTART
/*!
* The stats information for the certificate file, if configured
*/
struct stat cert_file_stat;
/*!
* The stats information for the private key file, if configured
*/
struct stat privkey_file_stat;
#endif
};
#define ast_sip_transport_is_nonlocal(transport_state, addr) \
@ -302,6 +339,45 @@ struct ast_sip_nat_hook {
void (*outgoing_external_message)(struct pjsip_tx_data *tdata, struct ast_sip_transport *transport);
};
/*!
* \brief The kind of security negotiation
*/
enum ast_sip_security_negotiation {
/*! No security mechanism negotiation */
AST_SIP_SECURITY_NEG_NONE = 0,
/*! Use mediasec security mechanism negotiation */
AST_SIP_SECURITY_NEG_MEDIASEC,
/* Add RFC 3329 (sec-agree) mechanism negotiation in the future */
};
/*!
* \brief The security mechanism type
*/
enum ast_sip_security_mechanism_type {
AST_SIP_SECURITY_MECH_NONE = 0,
/* Use msrp-tls as security mechanism */
AST_SIP_SECURITY_MECH_MSRP_TLS,
/* Use sdes-srtp as security mechanism */
AST_SIP_SECURITY_MECH_SDES_SRTP,
/* Use dtls-srtp as security mechanism */
AST_SIP_SECURITY_MECH_DTLS_SRTP,
/* Add RFC 3329 (sec-agree) mechanisms like tle, digest, ipsec-ike in the future */
};
/*!
* \brief Structure representing a security mechanism as defined in RFC 3329
*/
struct ast_sip_security_mechanism {
/* Used to determine which security mechanism to use. */
enum ast_sip_security_mechanism_type type;
/* The preference of this security mechanism. The higher the value, the more preferred. */
float qvalue;
/* Optional mechanism parameters. */
struct ast_vector_string mechanism_parameters;
};
AST_VECTOR(ast_sip_security_mechanism_vector, struct ast_sip_security_mechanism *);
/*!
* \brief Contact associated with an address of record
*/
@ -373,6 +449,13 @@ struct ast_sip_contact_status {
);
/*! The round trip time in microseconds */
int64_t rtt;
/*!
* The security mechanism list of the contact (RFC 3329).
* Stores the values of Security-Server headers in 401/421/494 responses to an
* in-dialog request or successful outbound registration which will be used to
* set the Security-Verify headers of all subsequent requests to the contact.
*/
struct ast_sip_security_mechanism_vector security_mechanisms;
/*! Current status for a contact (default - unavailable) */
enum ast_sip_contact_status_type status;
/*! Last status for a contact (default - unavailable) */
@ -432,6 +515,20 @@ struct ast_sip_contact_wrapper {
struct ast_sip_contact *contact;
};
/*!
* \brief 100rel modes for SIP endpoints
*/
enum ast_sip_100rel_mode {
/*! Do not support 100rel. (no) */
AST_SIP_100REL_UNSUPPORTED = 0,
/*! As UAC, indicate 100rel support in Supported header. (yes) */
AST_SIP_100REL_SUPPORTED,
/*! As UAS, send 1xx responses reliably, if the UAC indicated its support. Otherwise same as AST_SIP_100REL_SUPPORTED. (peer_supported) */
AST_SIP_100REL_PEER_SUPPORTED,
/*! Require the use of 100rel. (required) */
AST_SIP_100REL_REQUIRED,
};
/*!
* \brief DTMF modes for SIP endpoints
*/
@ -956,6 +1053,10 @@ struct ast_sip_endpoint {
unsigned int suppress_q850_reason_headers;
/*! Ignore 183 if no SDP is present */
unsigned int ignore_183_without_sdp;
/*! Type of security negotiation to use (RFC 3329). */
enum ast_sip_security_negotiation security_negotiation;
/*! Client security mechanisms (RFC 3329). */
struct ast_sip_security_mechanism_vector security_mechanisms;
/*! Set which STIR/SHAKEN behaviors we want on this endpoint */
unsigned int stir_shaken;
/*! Should we authenticate OPTIONS requests per RFC 3261? */
@ -964,6 +1065,12 @@ struct ast_sip_endpoint {
AST_STRING_FIELD_EXTENDED(geoloc_incoming_call_profile);
/*! The name of the geoloc profile to apply when Asterisk sends a call to this endpoint */
AST_STRING_FIELD_EXTENDED(geoloc_outgoing_call_profile);
/*! The context to use for overlap dialing, if different from the endpoint's context */
AST_STRING_FIELD_EXTENDED(overlap_context);
/*! 100rel mode to use with this endpoint */
enum ast_sip_100rel_mode rel100;
/*! Send Advice-of-Charge messages */
unsigned int send_aoc;
};
/*! URI parameter for symmetric transport */
@ -987,8 +1094,8 @@ extern pjsip_media_type pjsip_media_type_text_plain;
/*!
* \brief Compare pjsip media types
*
* \param pjsip_media_type a
* \param pjsip_media_type b
* \param a the first media type
* \param b the second media type
* \retval 1 Media types are equal
* \retval 0 Media types are not equal
*/
@ -1004,6 +1111,87 @@ int ast_sip_are_media_types_equal(pjsip_media_type *a, pjsip_media_type *b);
*/
int ast_sip_is_media_type_in(pjsip_media_type *a, ...) attribute_sentinel;
/*!
* \brief Add security headers to transmission data
*
* \param security_mechanisms Vector of security mechanisms.
* \param header_name The header name under which to add the security mechanisms.
* One of Security-Client, Security-Server, Security-Verify.
* \param add_qval If zero, don't add the q-value to the header.
* \param tdata The transmission data.
* \retval 0 Success
* \retval non-zero Failure
*/
int ast_sip_add_security_headers(struct ast_sip_security_mechanism_vector *security_mechanisms,
const char *header_name, int add_qval, pjsip_tx_data *tdata);
/*!
* \brief Append to security mechanism vector from SIP header
*
* \param hdr The header of the security mechanisms.
* \param security_mechanisms Vector of security mechanisms to append to.
* Header name must be one of Security-Client, Security-Server, Security-Verify.
*/
void ast_sip_header_to_security_mechanism(const pjsip_generic_string_hdr *hdr,
struct ast_sip_security_mechanism_vector *security_mechanisms);
/*!
* \brief Initialize security mechanism vector from string of security mechanisms.
*
* \param security_mechanism Pointer to vector of security mechanisms to initialize.
* \param value String of security mechanisms as defined in RFC 3329.
* \retval 0 Success
* \retval non-zero Failure
*/
int ast_sip_security_mechanism_vector_init(struct ast_sip_security_mechanism_vector *security_mechanism, const char *value);
/*!
* \brief Removes all headers of a specific name and value from a pjsip_msg.
*
* \param msg PJSIP message from which to remove headers.
* \param hdr_name Name of the header to remove.
* \param value Optional string value of the header to remove.
* If NULL, remove all headers of given hdr_name.
*/
void ast_sip_remove_headers_by_name_and_value(pjsip_msg *msg, const pj_str_t *hdr_name, const char* value);
/*!
* \brief Duplicate a security mechanism.
*
* \param dst Security mechanism to duplicate to.
* \param src Security mechanism to duplicate.
*/
void ast_sip_security_mechanisms_vector_copy(struct ast_sip_security_mechanism_vector *dst,
const struct ast_sip_security_mechanism_vector *src);
/*!
* \brief Free contents of a security mechanism vector.
*
* \param security_mechanisms Vector whose contents are to be freed
*/
void ast_sip_security_mechanisms_vector_destroy(struct ast_sip_security_mechanism_vector *security_mechanisms);
/*!
* \brief Allocate a security mechanism from a string.
*
* \param security_mechanism Pointer-pointer to the security mechanism to allocate.
* \param value The security mechanism string as defined in RFC 3329 (section 2.2)
* \param ... in the form \<mechanism_name>;q=\<q_value>;\<mechanism_parameters>
* \retval 0 Success
* \retval non-zero Failure
*/
int ast_sip_str_to_security_mechanism(struct ast_sip_security_mechanism **security_mechanism, const char *value);
/*!
* \brief Set the security negotiation based on a given string.
*
* \param security_negotiation Security negotiation enum to set.
* \param val String that represents a security_negotiation value.
* \retval 0 Success
* \retval non-zero Failure
*/
int ast_sip_set_security_negotiation(enum ast_sip_security_negotiation *security_negotiation, const char *val);
/*!
* \brief Initialize an auth vector with the configured values.
*
@ -3417,6 +3605,25 @@ struct ast_sip_service_route_vector *ast_sip_service_route_vector_alloc(void);
*/
void ast_sip_service_route_vector_destroy(struct ast_sip_service_route_vector *service_routes);
/*!
* \brief Set the ID for a connected line update
*
* \retval -1 on failure, 0 on success
*/
int ast_sip_set_id_connected_line(struct pjsip_rx_data *rdata, struct ast_party_id *id);
/*!
* \brief Set the ID from an INVITE
*
* \param rdata
* \param id ID structure to fill
* \param default_id Default ID structure with data to use (for non-trusted endpoints)
* \param trust_inbound Whether or not the endpoint is trusted (controls whether PAI or RPID can be used)
*
* \retval -1 on failure, 0 on success
*/
int ast_sip_set_id_from_invite(struct pjsip_rx_data *rdata, struct ast_party_id *id, struct ast_party_id *default_id, int trust_inbound);
/*!
* \brief Set name and number information on an identity header.
*
@ -3581,6 +3788,7 @@ enum ast_transport_monitor_reg {
/*!
* \brief Register a reliable transport shutdown monitor callback.
* \deprecated Replaced with ast_sip_transport_monitor_register_key().
* \since 13.20.0
*
* \param transport Transport to monitor for shutdown.
@ -3598,8 +3806,29 @@ enum ast_transport_monitor_reg {
enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transport *transport,
ast_transport_monitor_shutdown_cb cb, void *ao2_data);
/*!
* \brief Register a reliable transport shutdown monitor callback.
*
* \param transport_key Key for the transport to monitor for shutdown.
* Create the key with AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR.
* \param cb Who to call when transport is shutdown.
* \param ao2_data Data to pass with the callback.
*
* \note The data object passed will have its reference count automatically
* incremented by this call and automatically decremented after the callback
* runs or when the callback is unregistered.
*
* There is no checking for duplicate registrations.
*
* \return enum ast_transport_monitor_reg
*/
enum ast_transport_monitor_reg ast_sip_transport_monitor_register_key(
const char *transport_key, ast_transport_monitor_shutdown_cb cb,
void *ao2_data);
/*!
* \brief Register a reliable transport shutdown monitor callback replacing any duplicate.
* \deprecated Replaced with ast_sip_transport_monitor_register_replace_key().
* \since 13.26.0
* \since 16.3.0
*
@ -3621,8 +3850,32 @@ enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transpor
enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace(pjsip_transport *transport,
ast_transport_monitor_shutdown_cb cb, void *ao2_data, ast_transport_monitor_data_matcher matches);
/*!
* \brief Register a reliable transport shutdown monitor callback replacing any duplicate.
*
* \param transport_key Key for the transport to monitor for shutdown.
* Create the key with AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR.
* \param cb Who to call when transport is shutdown.
* \param ao2_data Data to pass with the callback.
* \param matches Matcher function that returns true if data matches a previously
* registered data object
*
* \note The data object passed will have its reference count automatically
* incremented by this call and automatically decremented after the callback
* runs or when the callback is unregistered.
*
* This function checks for duplicates, and overwrites/replaces the old monitor
* with the given one.
*
* \return enum ast_transport_monitor_reg
*/
enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace_key(
const char *transport_key, ast_transport_monitor_shutdown_cb cb,
void *ao2_data, ast_transport_monitor_data_matcher matches);
/*!
* \brief Unregister a reliable transport shutdown monitor
* \deprecated Replaced with ast_sip_transport_monitor_unregister_key().
* \since 13.20.0
*
* \param transport Transport to monitor for shutdown.
@ -3638,6 +3891,23 @@ enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace(pjsip_
void ast_sip_transport_monitor_unregister(pjsip_transport *transport,
ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches);
/*!
* \brief Unregister a reliable transport shutdown monitor
*
* \param transport_key Key for the transport to monitor for shutdown.
* Create the key with AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR.
* \param cb The callback that was used for the original register.
* \param data Data to pass to the matcher. May be NULL and does NOT need to be an ao2 object.
* If NULL, all monitors with the provided callback are unregistered.
* \param matches Matcher function that returns true if data matches the previously
* registered data object. If NULL, a simple pointer comparison is done.
*
* \note The data object passed into the original register will have its reference count
* automatically decremented.
*/
void ast_sip_transport_monitor_unregister_key(const char *transport_key,
ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches);
/*!
* \brief Unregister a transport shutdown monitor from all reliable transports
* \since 13.20.0
@ -3677,4 +3947,95 @@ void ast_sip_transport_state_register(struct ast_sip_tpmgr_state_callback *eleme
*/
void ast_sip_transport_state_unregister(struct ast_sip_tpmgr_state_callback *element);
/*!
* \brief Check whether a pjsip_uri is SIP/SIPS or not
* \since 16.28.0
*
* \param uri The pjsip_uri to check
*
* \retval 1 if true
* \retval 0 if false
*/
int ast_sip_is_uri_sip_sips(pjsip_uri *uri);
/*!
* \brief Check whether a pjsip_uri is allowed or not
* \since 16.28.0
*
* \param uri The pjsip_uri to check
*
* \retval 1 if allowed
* \retval 0 if not allowed
*/
int ast_sip_is_allowed_uri(pjsip_uri *uri);
/*!
* \brief Get the user portion of the pjsip_uri
* \since 16.28.0
*
* \param uri The pjsip_uri to get the user from
*
* \note This function will check what kind of URI it receives and return
* the user based off of that
*
* \return User string or empty string if not present
*/
const pj_str_t *ast_sip_pjsip_uri_get_username(pjsip_uri *uri);
/*!
* \brief Get the host portion of the pjsip_uri
* \since 16.28.0
*
* \param uri The pjsip_uri to get the host from
*
* \note This function will check what kind of URI it receives and return
* the host based off of that
*
* \return Host string or empty string if not present
*/
const pj_str_t *ast_sip_pjsip_uri_get_hostname(pjsip_uri *uri);
/*!
* \brief Find an 'other' SIP/SIPS URI parameter by name
* \since 16.28.0
*
* A convenience function to find a named parameter from a SIP/SIPS URI. This
* function will not find the following standard SIP/SIPS URI parameters which
* are stored separately by PJSIP:
*
* \li `user`
* \li `method`
* \li `transport`
* \li `ttl`
* \li `lr`
* \li `maddr`
*
* \param uri The pjsip_uri to get the parameter from
* \param param_str The name of the parameter to find
*
* \note This function will check what kind of URI it receives and return
* the parameter based off of that
*
* \return Find parameter or NULL if not present
*/
struct pjsip_param *ast_sip_pjsip_uri_get_other_param(pjsip_uri *uri, const pj_str_t *param_str);
/*!
* \brief Retrieve the system setting 'all_codecs_on_empty_reinvite'.
*
* \retval non zero if we should return all codecs on empty re-INVITE
*/
unsigned int ast_sip_get_all_codecs_on_empty_reinvite(void);
/*!
* \brief Convert SIP hangup causes to Asterisk hangup causes
*
* \param cause SIP cause
*
* \retval matched cause code from causes.h
*/
const int ast_sip_hangup_sip2cause(int cause);
#endif /* _RES_PJSIP_H */

View File

@ -33,6 +33,8 @@
/* Needed for pjmedia_sdp_session and pjsip_inv_session */
#include <pjsip_ua.h>
/* Needed for ast_sip_security_mechanism_vector */
#include "asterisk/res_pjsip.h"
/* Forward declarations */
struct ast_sip_endpoint;

View File

@ -156,7 +156,7 @@ struct ast_stir_shaken_payload *ast_stir_shaken_verify2(const char *header, cons
* \param signature The payload signature
* \param algorithm The signature algorithm
* \param public_cert_url The public key URL
* \param failure_code Additional failure information
* \param failure Additional failure information
* \param profile The stir_shaken_profile
*
* \retval ast_stir_shaken_payload on success

Some files were not shown because too many files have changed in this diff Show More