summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--channels/Makefile1
-rw-r--r--channels/chan_gulp.c1445
-rw-r--r--configs/res_sip.conf.sample24
-rwxr-xr-xconfigure2383
-rw-r--r--include/asterisk/autoconfig.h.in76
-rw-r--r--include/asterisk/res_sip.h1092
-rw-r--r--include/asterisk/res_sip_pubsub.h346
-rw-r--r--include/asterisk/res_sip_session.h468
-rw-r--r--include/asterisk/sorcery.h7
-rw-r--r--include/asterisk/threadpool.h14
-rw-r--r--main/astobj2.c1
-rw-r--r--main/loader.c1
-rw-r--r--main/sorcery.c3
-rw-r--r--main/taskprocessor.c1
-rw-r--r--main/threadpool.c6
-rw-r--r--res/Makefile5
-rw-r--r--res/res_sip.c906
-rw-r--r--res/res_sip.exports.in52
-rw-r--r--res/res_sip/config_auth.c120
-rw-r--r--res/res_sip/config_domain_aliases.c65
-rw-r--r--res/res_sip/config_transport.c299
-rw-r--r--res/res_sip/include/res_sip_private.h57
-rw-r--r--res/res_sip/location.c262
-rw-r--r--res/res_sip/sip_configuration.c463
-rw-r--r--res/res_sip/sip_distributor.c239
-rw-r--r--res/res_sip/sip_options.c378
-rw-r--r--res/res_sip/sip_outbound_auth.c94
-rw-r--r--res/res_sip_acl.c222
-rw-r--r--res/res_sip_authenticator_digest.c455
-rw-r--r--res/res_sip_caller_id.c715
-rw-r--r--res/res_sip_dtmf_info.c128
-rw-r--r--res/res_sip_endpoint_identifier_constant.c67
-rw-r--r--res/res_sip_endpoint_identifier_ip.c151
-rw-r--r--res/res_sip_endpoint_identifier_user.c128
-rw-r--r--res/res_sip_logger.c81
-rw-r--r--res/res_sip_mwi.c709
-rw-r--r--res/res_sip_nat.c235
-rw-r--r--res/res_sip_outbound_authenticator_digest.c110
-rw-r--r--res/res_sip_outbound_registration.c708
-rw-r--r--res/res_sip_pubsub.c662
-rw-r--r--res/res_sip_pubsub.exports.in16
-rw-r--r--res/res_sip_registrar.c382
-rw-r--r--res/res_sip_rfc3326.c145
-rw-r--r--res/res_sip_sdp_rtp.c848
-rw-r--r--res/res_sip_session.c1799
-rw-r--r--res/res_sip_session.exports.in18
-rw-r--r--res/res_sorcery_config.c1
-rw-r--r--tests/test_sorcery.c3
48 files changed, 15180 insertions, 1211 deletions
diff --git a/channels/Makefile b/channels/Makefile
index ae5a0645a..10d487cfb 100644
--- a/channels/Makefile
+++ b/channels/Makefile
@@ -113,3 +113,4 @@ h323/Makefile.ast:
h323/libchanh323.a: h323/Makefile.ast
$(CMD_PREFIX) $(MAKE) -C h323 libchanh323.a
+
diff --git a/channels/chan_gulp.c b/channels/chan_gulp.c
new file mode 100644
index 000000000..39a69e886
--- /dev/null
+++ b/channels/chan_gulp.c
@@ -0,0 +1,1445 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Joshua Colp <jcolp@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \author Joshua Colp <jcolp@digium.com>
+ *
+ * \brief Gulp SIP Channel Driver
+ *
+ * \ingroup channel_drivers
+ */
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <depend>res_sip</depend>
+ <depend>res_sip_session</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_ua.h>
+#include <pjlib.h>
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/lock.h"
+#include "asterisk/channel.h"
+#include "asterisk/module.h"
+#include "asterisk/pbx.h"
+#include "asterisk/rtp_engine.h"
+#include "asterisk/acl.h"
+#include "asterisk/callerid.h"
+#include "asterisk/file.h"
+#include "asterisk/cli.h"
+#include "asterisk/app.h"
+#include "asterisk/musiconhold.h"
+#include "asterisk/causes.h"
+#include "asterisk/taskprocessor.h"
+
+#include "asterisk/res_sip.h"
+#include "asterisk/res_sip_session.h"
+
+/*** DOCUMENTATION
+ <function name="GULP_DIAL_CONTACTS" language="en_US">
+ <synopsis>
+ Return a dial string for dialing all contacts on an AOR.
+ </synopsis>
+ <syntax>
+ <parameter name="endpoint" required="true">
+ <para>Name of the endpoint</para>
+ </parameter>
+ <parameter name="aor" required="false">
+ <para>Name of an AOR to use, if not specified the configured AORs on the endpoint are used</para>
+ </parameter>
+ <parameter name="request_user" required="false">
+ <para>Optional request user to use in the request URI</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>Returns a properly formatted dial string for dialing all contacts on an AOR.</para>
+ </description>
+ </function>
+ ***/
+
+static const char desc[] = "Gulp SIP Channel";
+static const char channel_type[] = "Gulp";
+
+/*!
+ * \brief Positions of various media
+ */
+enum sip_session_media_position {
+ /*! \brief First is audio */
+ SIP_MEDIA_AUDIO = 0,
+ /*! \brief Second is video */
+ SIP_MEDIA_VIDEO,
+ /*! \brief Last is the size for media details */
+ SIP_MEDIA_SIZE,
+};
+
+struct gulp_pvt {
+ struct ast_sip_session *session;
+ struct ast_sip_session_media *media[SIP_MEDIA_SIZE];
+};
+
+static void gulp_pvt_dtor(void *obj)
+{
+ struct gulp_pvt *pvt = obj;
+ int i;
+ ao2_cleanup(pvt->session);
+ pvt->session = NULL;
+ for (i = 0; i < SIP_MEDIA_SIZE; ++i) {
+ ao2_cleanup(pvt->media[i]);
+ pvt->media[i] = NULL;
+ }
+}
+
+/* \brief Asterisk core interaction functions */
+static struct ast_channel *gulp_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
+static int gulp_sendtext(struct ast_channel *ast, const char *text);
+static int gulp_digit_begin(struct ast_channel *ast, char digit);
+static int gulp_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
+static int gulp_call(struct ast_channel *ast, const char *dest, int timeout);
+static int gulp_hangup(struct ast_channel *ast);
+static int gulp_answer(struct ast_channel *ast);
+static struct ast_frame *gulp_read(struct ast_channel *ast);
+static int gulp_write(struct ast_channel *ast, struct ast_frame *f);
+static int gulp_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
+static int gulp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+
+/*! \brief PBX interface structure for channel registration */
+static struct ast_channel_tech gulp_tech = {
+ .type = channel_type,
+ .description = "Gulp SIP Channel Driver",
+ .requester = gulp_request,
+ .send_text = gulp_sendtext,
+ .send_digit_begin = gulp_digit_begin,
+ .send_digit_end = gulp_digit_end,
+ .bridge = ast_rtp_instance_bridge,
+ .call = gulp_call,
+ .hangup = gulp_hangup,
+ .answer = gulp_answer,
+ .read = gulp_read,
+ .write = gulp_write,
+ .write_video = gulp_write,
+ .exception = gulp_read,
+ .indicate = gulp_indicate,
+ .fixup = gulp_fixup,
+ .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
+};
+
+/*! \brief SIP session interaction functions */
+static void gulp_session_begin(struct ast_sip_session *session);
+static void gulp_session_end(struct ast_sip_session *session);
+static int gulp_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
+static void gulp_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
+
+/*! \brief SIP session supplement structure */
+static struct ast_sip_session_supplement gulp_supplement = {
+ .method = "INVITE",
+ .priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL,
+ .session_begin = gulp_session_begin,
+ .session_end = gulp_session_end,
+ .incoming_request = gulp_incoming_request,
+ .incoming_response = gulp_incoming_response,
+};
+
+static int gulp_incoming_ack(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
+
+static struct ast_sip_session_supplement gulp_ack_supplement = {
+ .method = "ACK",
+ .priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL,
+ .incoming_request = gulp_incoming_ack,
+};
+
+/*! \brief Dialplan function for constructing a dial string for calling all contacts */
+static int gulp_dial_contacts(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(endpoint_name);
+ AST_APP_ARG(aor_name);
+ AST_APP_ARG(request_user);
+ );
+ RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
+ const char *aor_name;
+ char *rest;
+ RAII_VAR(struct ast_str *, dial, NULL, ast_free_ptr);
+
+ AST_STANDARD_APP_ARGS(args, data);
+
+ if (ast_strlen_zero(args.endpoint_name)) {
+ ast_log(LOG_WARNING, "An endpoint name must be specified when using the '%s' dialplan function\n", cmd);
+ return -1;
+ } else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", args.endpoint_name))) {
+ ast_log(LOG_WARNING, "Specified endpoint '%s' was not found\n", args.endpoint_name);
+ return -1;
+ }
+
+ aor_name = S_OR(args.aor_name, endpoint->aors);
+
+ if (ast_strlen_zero(aor_name)) {
+ ast_log(LOG_WARNING, "No AOR has been provided and no AORs are configured on endpoint '%s'\n", args.endpoint_name);
+ return -1;
+ } else if (!(dial = ast_str_create(len))) {
+ ast_log(LOG_WARNING, "Could not get enough buffer space for dialing contacts\n");
+ return -1;
+ } else if (!(rest = ast_strdupa(aor_name))) {
+ ast_log(LOG_WARNING, "Could not duplicate provided AORs\n");
+ return -1;
+ }
+
+ while ((aor_name = strsep(&rest, ","))) {
+ RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
+ RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
+ struct ao2_iterator it_contacts;
+ struct ast_sip_contact *contact;
+
+ if (!aor) {
+ /* If the AOR provided is not found skip it, there may be more */
+ continue;
+ } else if (!(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
+ /* No contacts are available, skip it as well */
+ continue;
+ } else if (!ao2_container_count(contacts)) {
+ /* We were given a container but no contacts are in it... */
+ continue;
+ }
+
+ it_contacts = ao2_iterator_init(contacts, 0);
+ for (; (contact = ao2_iterator_next(&it_contacts)); ao2_ref(contact, -1)) {
+ ast_str_append(&dial, -1, "Gulp/");
+
+ if (!ast_strlen_zero(args.request_user)) {
+ ast_str_append(&dial, -1, "%s@", args.request_user);
+ }
+ ast_str_append(&dial, -1, "%s/%s&", args.endpoint_name, contact->uri);
+ }
+ ao2_iterator_destroy(&it_contacts);
+ }
+
+ /* Trim the '&' at the end off */
+ ast_str_truncate(dial, ast_str_strlen(dial) - 1);
+
+ ast_copy_string(buf, ast_str_buffer(dial), len);
+
+ return 0;
+}
+
+static struct ast_custom_function gulp_dial_contacts_function = {
+ .name = "GULP_DIAL_CONTACTS",
+ .read = gulp_dial_contacts,
+};
+
+/*! \brief Function called by RTP engine to get local audio RTP peer */
+static enum ast_rtp_glue_result gulp_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
+{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
+ struct ast_sip_endpoint *endpoint;
+
+ if (!pvt || !pvt->session || !pvt->media[SIP_MEDIA_AUDIO]->rtp) {
+ return AST_RTP_GLUE_RESULT_FORBID;
+ }
+
+ endpoint = pvt->session->endpoint;
+
+ *instance = pvt->media[SIP_MEDIA_AUDIO]->rtp;
+ ao2_ref(*instance, +1);
+
+ ast_assert(endpoint != NULL);
+ if (endpoint->direct_media) {
+ return AST_RTP_GLUE_RESULT_REMOTE;
+ }
+
+ return AST_RTP_GLUE_RESULT_LOCAL;
+}
+
+/*! \brief Function called by RTP engine to get local video RTP peer */
+static enum ast_rtp_glue_result gulp_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
+{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
+
+ if (!pvt || !pvt->session || !pvt->media[SIP_MEDIA_VIDEO]->rtp) {
+ return AST_RTP_GLUE_RESULT_FORBID;
+ }
+
+ *instance = pvt->media[SIP_MEDIA_VIDEO]->rtp;
+ ao2_ref(*instance, +1);
+
+ return AST_RTP_GLUE_RESULT_LOCAL;
+}
+
+/*! \brief Function called by RTP engine to get peer capabilities */
+static void gulp_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
+{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
+ ast_format_cap_copy(result, pvt->session->endpoint->codecs);
+}
+
+static int send_direct_media_request(void *data)
+{
+ RAII_VAR(struct ast_sip_session *, session, data, ao2_cleanup);
+ return ast_sip_session_refresh(session, NULL, NULL, session->endpoint->direct_media_method, 1);
+}
+
+static struct ast_datastore_info direct_media_mitigation_info = { };
+
+static int direct_media_mitigate_glare(struct ast_sip_session *session)
+{
+ RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
+
+ if (session->endpoint->direct_media_glare_mitigation ==
+ AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE) {
+ return 0;
+ }
+
+ datastore = ast_sip_session_get_datastore(session, "direct_media_glare_mitigation");
+ if (!datastore) {
+ return 0;
+ }
+
+ /* Removing the datastore ensures we won't try to mitigate glare on subsequent reinvites */
+ ast_sip_session_remove_datastore(session, "direct_media_glare_mitigation");
+
+ if ((session->endpoint->direct_media_glare_mitigation ==
+ AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING &&
+ session->inv_session->role == PJSIP_ROLE_UAC) ||
+ (session->endpoint->direct_media_glare_mitigation ==
+ AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING &&
+ session->inv_session->role == PJSIP_ROLE_UAS)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int check_for_rtp_changes(struct ast_channel *chan, struct ast_rtp_instance *rtp,
+ struct ast_sip_session_media *media, int rtcp_fd)
+{
+ int changed = 0;
+
+ if (rtp) {
+ changed = ast_rtp_instance_get_and_cmp_remote_address(rtp, &media->direct_media_addr);
+ if (media->rtp) {
+ ast_channel_set_fd(chan, rtcp_fd, -1);
+ ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_RTCP, 0);
+ }
+ } else if (!ast_sockaddr_isnull(&media->direct_media_addr)){
+ ast_sockaddr_setnull(&media->direct_media_addr);
+ changed = 1;
+ if (media->rtp) {
+ ast_rtp_instance_set_prop(media->rtp, AST_RTP_PROPERTY_RTCP, 1);
+ ast_channel_set_fd(chan, rtcp_fd, ast_rtp_instance_fd(media->rtp, 1));
+ }
+ }
+
+ return changed;
+}
+
+/*! \brief Function called by RTP engine to change where the remote party should send media */
+static int gulp_set_rtp_peer(struct ast_channel *chan,
+ struct ast_rtp_instance *rtp,
+ struct ast_rtp_instance *vrtp,
+ struct ast_rtp_instance *tpeer,
+ const struct ast_format_cap *cap,
+ int nat_active)
+{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
+ struct ast_sip_session *session = pvt->session;
+ int changed = 0;
+
+ /* Don't try to do any direct media shenanigans on early bridges */
+ if ((rtp || vrtp || tpeer) && !ast_bridged_channel(chan)) {
+ return 0;
+ }
+
+ if (nat_active && session->endpoint->disable_direct_media_on_nat) {
+ return 0;
+ }
+
+ if (pvt->media[SIP_MEDIA_AUDIO]) {
+ changed |= check_for_rtp_changes(chan, rtp, pvt->media[SIP_MEDIA_AUDIO], 1);
+ }
+ if (pvt->media[SIP_MEDIA_VIDEO]) {
+ changed |= check_for_rtp_changes(chan, vrtp, pvt->media[SIP_MEDIA_VIDEO], 3);
+ }
+
+ if (direct_media_mitigate_glare(session)) {
+ return 0;
+ }
+
+ if (cap && !ast_format_cap_is_empty(cap) && !ast_format_cap_identical(session->direct_media_cap, cap)) {
+ ast_format_cap_copy(session->direct_media_cap, cap);
+ changed = 1;
+ }
+
+ if (changed) {
+ ao2_ref(session, +1);
+ ast_sip_push_task(session->serializer, send_direct_media_request, session);
+ }
+
+ return 0;
+}
+
+/*! \brief Local glue for interacting with the RTP engine core */
+static struct ast_rtp_glue gulp_rtp_glue = {
+ .type = "Gulp",
+ .get_rtp_info = gulp_get_rtp_peer,
+ .get_vrtp_info = gulp_get_vrtp_peer,
+ .get_codec = gulp_get_codec,
+ .update_peer = gulp_set_rtp_peer,
+};
+
+/*! \brief Function called to create a new Gulp Asterisk channel */
+static struct ast_channel *gulp_new(struct ast_sip_session *session, int state, const char *exten, const char *title, const char *linkedid, const char *cid_name)
+{
+ struct ast_channel *chan;
+ struct ast_format fmt;
+ struct gulp_pvt *pvt;
+
+ if (!(pvt = ao2_alloc(sizeof(*pvt), gulp_pvt_dtor))) {
+ return NULL;
+ }
+
+ if (!(chan = ast_channel_alloc(1, state, S_OR(session->id.number.str, ""), S_OR(session->id.name.str, ""), "", "", "", linkedid, 0, "Gulp/%s-%.*s", ast_sorcery_object_get_id(session->endpoint),
+ (int)session->inv_session->dlg->call_id->id.slen, session->inv_session->dlg->call_id->id.ptr))) {
+ ao2_cleanup(pvt);
+ return NULL;
+ }
+
+ ast_channel_tech_set(chan, &gulp_tech);
+
+ ao2_ref(session, +1);
+ pvt->session = session;
+ /* If res_sip_session is ever updated to create/destroy ast_sip_session_media
+ * during a call such as if multiple same-type stream support is introduced,
+ * these will need to be recaptured as well */
+ pvt->media[SIP_MEDIA_AUDIO] = ao2_find(session->media, "audio", OBJ_KEY);
+ pvt->media[SIP_MEDIA_VIDEO] = ao2_find(session->media, "video", OBJ_KEY);
+ ast_channel_tech_pvt_set(chan, pvt);
+
+ if (ast_format_cap_is_empty(session->req_caps)) {
+ ast_format_cap_copy(ast_channel_nativeformats(chan), session->endpoint->codecs);
+ } else {
+ ast_format_cap_copy(ast_channel_nativeformats(chan), session->req_caps);
+ }
+
+ ast_codec_choose(&session->endpoint->prefs, ast_channel_nativeformats(chan), 1, &fmt);
+ ast_format_copy(ast_channel_writeformat(chan), &fmt);
+ ast_format_copy(ast_channel_rawwriteformat(chan), &fmt);
+ ast_format_copy(ast_channel_readformat(chan), &fmt);
+ ast_format_copy(ast_channel_rawreadformat(chan), &fmt);
+
+ if (state == AST_STATE_RING) {
+ ast_channel_rings_set(chan, 1);
+ }
+
+ ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
+
+ ast_channel_context_set(chan, session->endpoint->context);
+ ast_channel_exten_set(chan, S_OR(exten, "s"));
+ ast_channel_priority_set(chan, 1);
+
+ return chan;
+}
+
+static int answer(void *data)
+{
+ pj_status_t status;
+ pjsip_tx_data *packet;
+ struct ast_sip_session *session = data;
+
+ if ((status = pjsip_inv_answer(session->inv_session, 200, NULL, NULL, &packet)) == PJ_SUCCESS) {
+ ast_sip_session_send_response(session, packet);
+ }
+
+ ao2_ref(session, -1);
+ return (status == PJ_SUCCESS) ? 0 : -1;
+}
+
+/*! \brief Function called by core when we should answer a Gulp session */
+static int gulp_answer(struct ast_channel *ast)
+{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ struct ast_sip_session *session = pvt->session;
+
+ if (ast_channel_state(ast) == AST_STATE_UP) {
+ return 0;
+ }
+
+ ast_setstate(ast, AST_STATE_UP);
+
+ ao2_ref(session, +1);
+ if (ast_sip_push_task(session->serializer, answer, session)) {
+ ast_log(LOG_WARNING, "Unable to push answer task to the threadpool. Cannot answer call\n");
+ ao2_cleanup(session);
+ return -1;
+ }
+ return 0;
+}
+
+/*! \brief Function called by core to read any waiting frames */
+static struct ast_frame *gulp_read(struct ast_channel *ast)
+{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ struct ast_frame *f;
+ struct ast_sip_session_media *media = NULL;
+ int rtcp = 0;
+ int fdno = ast_channel_fdno(ast);
+
+ switch (fdno) {
+ case 0:
+ media = pvt->media[SIP_MEDIA_AUDIO];
+ break;
+ case 1:
+ media = pvt->media[SIP_MEDIA_AUDIO];
+ rtcp = 1;
+ break;
+ case 2:
+ media = pvt->media[SIP_MEDIA_VIDEO];
+ break;
+ case 3:
+ media = pvt->media[SIP_MEDIA_VIDEO];
+ rtcp = 1;
+ break;
+ }
+
+ if (!media || !media->rtp) {
+ return &ast_null_frame;
+ }
+
+ f = ast_rtp_instance_read(media->rtp, rtcp);
+
+ if (f && f->frametype == AST_FRAME_VOICE) {
+ if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &f->subclass.format))) {
+ ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format));
+ ast_format_cap_set(ast_channel_nativeformats(ast), &f->subclass.format);
+ ast_set_read_format(ast, ast_channel_readformat(ast));
+ ast_set_write_format(ast, ast_channel_writeformat(ast));
+ }
+ }
+
+ return f;
+}
+
+/*! \brief Function called by core to write frames */
+static int gulp_write(struct ast_channel *ast, struct ast_frame *frame)
+{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ int res = 0;
+ struct ast_sip_session_media *media;
+
+ switch (frame->frametype) {
+ case AST_FRAME_VOICE:
+ media = pvt->media[SIP_MEDIA_AUDIO];
+
+ if (!media) {
+ return 0;
+ }
+ if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
+ char buf[256];
+
+ ast_log(LOG_WARNING,
+ "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
+ ast_getformatname(&frame->subclass.format),
+ ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
+ ast_getformatname(ast_channel_readformat(ast)),
+ ast_getformatname(ast_channel_writeformat(ast)));
+ return 0;
+ }
+ if (media->rtp) {
+ res = ast_rtp_instance_write(media->rtp, frame);
+ }
+ break;
+ case AST_FRAME_VIDEO:
+ if ((media = pvt->media[SIP_MEDIA_VIDEO]) && media->rtp) {
+ res = ast_rtp_instance_write(media->rtp, frame);
+ }
+ break;
+ default:
+ ast_log(LOG_WARNING, "Can't send %d type frames with Gulp\n", frame->frametype);
+ break;
+ }
+
+ return res;
+}
+
+struct fixup_data {
+ struct ast_sip_session *session;
+ struct ast_channel *chan;
+};
+
+static int fixup(void *data)
+{
+ struct fixup_data *fix_data = data;
+ fix_data->session->channel = fix_data->chan;
+ return 0;
+}
+
+/*! \brief Function called by core to change the underlying owner channel */
+static int gulp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
+{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(newchan);
+ struct ast_sip_session *session = pvt->session;
+ struct fixup_data fix_data;
+ fix_data.session = session;
+ fix_data.chan = newchan;
+
+ if (session->channel != oldchan) {
+ return -1;
+ }
+
+ if (ast_sip_push_task_synchronous(session->serializer, fixup, &fix_data)) {
+ ast_log(LOG_WARNING, "Unable to perform channel fixup\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+struct indicate_data {
+ struct ast_sip_session *session;
+ int condition;
+ int response_code;
+ void *frame_data;
+ size_t datalen;
+};
+
+static void indicate_data_destroy(void *obj)
+{
+ struct indicate_data *ind_data = obj;
+ ast_free(ind_data->frame_data);
+ ao2_ref(ind_data->session, -1);
+}
+
+static struct indicate_data *indicate_data_alloc(struct ast_sip_session *session,
+ int condition, int response_code, const void *frame_data, size_t datalen)
+{
+ struct indicate_data *ind_data = ao2_alloc(sizeof(*ind_data), indicate_data_destroy);
+ if (!ind_data) {
+ return NULL;
+ }
+ ind_data->frame_data = ast_malloc(datalen);
+ if (!ind_data->frame_data) {
+ ao2_ref(ind_data, -1);
+ return NULL;
+ }
+ memcpy(ind_data->frame_data, frame_data, datalen);
+ ind_data->datalen = datalen;
+ ind_data->condition = condition;
+ ind_data->response_code = response_code;
+ ao2_ref(session, +1);
+ ind_data->session = session;
+ return ind_data;
+}
+
+static int indicate(void *data)
+{
+ struct indicate_data *ind_data = data;
+ struct ast_sip_session *session = ind_data->session;
+ int response_code = ind_data->response_code;
+ pjsip_tx_data *packet = NULL;
+
+ if (pjsip_inv_answer(session->inv_session, response_code, NULL, NULL, &packet) == PJ_SUCCESS) {
+ ast_sip_session_send_response(session, packet);
+ }
+
+ ao2_ref(ind_data, -1);
+ return 0;
+}
+
+/*! \brief Send SIP INFO with video update request */
+static int transmit_info_with_vidupdate(void *data)
+{
+ const char * xml =
+ "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n"
+ " <media_control>\r\n"
+ " <vc_primitive>\r\n"
+ " <to_encoder>\r\n"
+ " <picture_fast_update/>\r\n"
+ " </to_encoder>\r\n"
+ " </vc_primitive>\r\n"
+ " </media_control>\r\n";
+
+ const struct ast_sip_body body = {
+ .type = "application",
+ .subtype = "media_control+xml",
+ .body_text = xml
+ };
+
+ struct ast_sip_session *session = data;
+ struct pjsip_tx_data *tdata;
+
+ if (ast_sip_create_request("INFO", session->inv_session->dlg, session->endpoint, NULL, &tdata)) {
+ ast_log(LOG_ERROR, "Could not create text video update INFO request\n");
+ return -1;
+ }
+ if (ast_sip_add_body(tdata, &body)) {
+ ast_log(LOG_ERROR, "Could not add body to text video update INFO request\n");
+ return -1;
+ }
+ ast_sip_session_send_request(session, tdata);
+
+ return 0;
+}
+
+/*! \brief Function called by core to ask the channel to indicate some sort of condition */
+static int gulp_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
+{
+ int res = 0;
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ struct ast_sip_session *session = pvt->session;
+ struct ast_sip_session_media *media;
+ int response_code = 0;
+
+ switch (condition) {
+ case AST_CONTROL_RINGING:
+ if (ast_channel_state(ast) == AST_STATE_RING) {
+ response_code = 180;
+ } else {
+ res = -1;
+ }
+ break;
+ case AST_CONTROL_BUSY:
+ if (ast_channel_state(ast) != AST_STATE_UP) {
+ response_code = 486;
+ } else {
+ res = -1;
+ }
+ break;
+ case AST_CONTROL_CONGESTION:
+ if (ast_channel_state(ast) != AST_STATE_UP) {
+ response_code = 503;
+ } else {
+ res = -1;
+ }
+ break;
+ case AST_CONTROL_INCOMPLETE:
+ if (ast_channel_state(ast) != AST_STATE_UP) {
+ response_code = 484;
+ } else {
+ res = -1;
+ }
+ break;
+ case AST_CONTROL_PROCEEDING:
+ if (ast_channel_state(ast) != AST_STATE_UP) {
+ response_code = 100;
+ } else {
+ res = -1;
+ }
+ break;
+ case AST_CONTROL_PROGRESS:
+ if (ast_channel_state(ast) != AST_STATE_UP) {
+ response_code = 183;
+ } else {
+ res = -1;
+ }
+ break;
+ case AST_CONTROL_VIDUPDATE:
+ media = pvt->media[SIP_MEDIA_VIDEO];
+ if (media && media->rtp) {
+ ast_sip_push_task(session->serializer, transmit_info_with_vidupdate, session);
+ } else
+ res = -1;
+ break;
+ case AST_CONTROL_UPDATE_RTP_PEER:
+ case AST_CONTROL_PVT_CAUSE_CODE:
+ break;
+ case AST_CONTROL_HOLD:
+ ast_moh_start(ast, data, NULL);
+ break;
+ case AST_CONTROL_UNHOLD:
+ ast_moh_stop(ast);
+ break;
+ case AST_CONTROL_SRCUPDATE:
+ break;
+ case AST_CONTROL_SRCCHANGE:
+ break;
+ case -1:
+ res = -1;
+ break;
+ default:
+ ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", condition);
+ res = -1;
+ break;
+ }
+
+ if (!res && response_code) {
+ struct indicate_data *ind_data = indicate_data_alloc(session, condition, response_code, data, datalen);
+ if (ind_data) {
+ res = ast_sip_push_task(session->serializer, indicate, ind_data);
+ if (res) {
+ ast_log(LOG_NOTICE, "Cannot send response code %d to endpoint %s. Could queue task properly\n",
+ response_code, ast_sorcery_object_get_id(session->endpoint));
+ ao2_cleanup(ind_data);
+ }
+ } else {
+ res = -1;
+ }
+ }
+
+ return res;
+}
+
+/*! \brief Function called by core to start a DTMF digit */
+static int gulp_digit_begin(struct ast_channel *chan, char digit)
+{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
+ struct ast_sip_session *session = pvt->session;
+ int res = 0;
+ struct ast_sip_session_media *media = pvt->media[SIP_MEDIA_AUDIO];
+
+ switch (session->endpoint->dtmf) {
+ case AST_SIP_DTMF_RFC_4733:
+ if (!media || !media->rtp) {
+ return -1;
+ }
+
+ ast_rtp_instance_dtmf_begin(media->rtp, digit);
+ case AST_SIP_DTMF_NONE:
+ break;
+ case AST_SIP_DTMF_INBAND:
+ res = -1;
+ break;
+ default:
+ break;
+ }
+
+ return res;
+}
+
+struct info_dtmf_data {
+ struct ast_sip_session *session;
+ char digit;
+ unsigned int duration;
+};
+
+static void info_dtmf_data_destroy(void *obj)
+{
+ struct info_dtmf_data *dtmf_data = obj;
+ ao2_ref(dtmf_data->session, -1);
+}
+
+static struct info_dtmf_data *info_dtmf_data_alloc(struct ast_sip_session *session, char digit, unsigned int duration)
+{
+ struct info_dtmf_data *dtmf_data = ao2_alloc(sizeof(*dtmf_data), info_dtmf_data_destroy);
+ if (!dtmf_data) {
+ return NULL;
+ }
+ ao2_ref(session, +1);
+ dtmf_data->session = session;
+ dtmf_data->digit = digit;
+ dtmf_data->duration = duration;
+ return dtmf_data;
+}
+
+static int transmit_info_dtmf(void *data)
+{
+ RAII_VAR(struct info_dtmf_data *, dtmf_data, data, ao2_cleanup);
+
+ struct ast_sip_session *session = dtmf_data->session;
+ struct pjsip_tx_data *tdata;
+
+ RAII_VAR(struct ast_str *, body_text, NULL, ast_free_ptr);
+
+ struct ast_sip_body body = {
+ .type = "application",
+ .subtype = "dtmf-relay",
+ };
+
+ if (!(body_text = ast_str_create(32))) {
+ ast_log(LOG_ERROR, "Could not allocate buffer for INFO DTMF.\n");
+ return -1;
+ }
+ ast_str_set(&body_text, 0, "Signal=%c\r\nDuration=%u\r\n", dtmf_data->digit, dtmf_data->duration);
+
+ body.body_text = ast_str_buffer(body_text);
+
+ if (ast_sip_create_request("INFO", session->inv_session->dlg, session->endpoint, NULL, &tdata)) {
+ ast_log(LOG_ERROR, "Could not create DTMF INFO request\n");
+ return -1;
+ }
+ if (ast_sip_add_body(tdata, &body)) {
+ ast_log(LOG_ERROR, "Could not add body to DTMF INFO request\n");
+ pjsip_tx_data_dec_ref(tdata);
+ return -1;
+ }
+ ast_sip_session_send_request(session, tdata);
+
+ return 0;
+}
+
+/*! \brief Function called by core to stop a DTMF digit */
+static int gulp_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
+{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ struct ast_sip_session *session = pvt->session;
+ int res = 0;
+ struct ast_sip_session_media *media = pvt->media[SIP_MEDIA_AUDIO];
+
+ switch (session->endpoint->dtmf) {
+ case AST_SIP_DTMF_INFO:
+ {
+ struct info_dtmf_data *dtmf_data = info_dtmf_data_alloc(session, digit, duration);
+
+ if (!dtmf_data) {
+ return -1;
+ }
+
+ if (ast_sip_push_task(session->serializer, transmit_info_dtmf, dtmf_data)) {
+ ast_log(LOG_WARNING, "Error sending DTMF via INFO.\n");
+ ao2_cleanup(dtmf_data);
+ return -1;
+ }
+ break;
+ }
+ case AST_SIP_DTMF_RFC_4733:
+ if (!media || !media->rtp) {
+ return -1;
+ }
+
+ ast_rtp_instance_dtmf_end_with_duration(media->rtp, digit, duration);
+ case AST_SIP_DTMF_NONE:
+ break;
+ case AST_SIP_DTMF_INBAND:
+ res = -1;
+ break;
+ }
+
+ return res;
+}
+
+static int call(void *data)
+{
+ struct ast_sip_session *session = data;
+ pjsip_tx_data *packet;
+
+ if (pjsip_inv_invite(session->inv_session, &packet) != PJ_SUCCESS) {
+ ast_queue_hangup(session->channel);
+ } else {
+ ast_sip_session_send_request(session, packet);
+ }
+
+ ao2_ref(session, -1);
+ return 0;
+}
+
+/*! \brief Function called by core to actually start calling a remote party */
+static int gulp_call(struct ast_channel *ast, const char *dest, int timeout)
+{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ struct ast_sip_session *session = pvt->session;
+
+ ao2_ref(session, +1);
+ if (ast_sip_push_task(session->serializer, call, session)) {
+ ast_log(LOG_WARNING, "Error attempting to place outbound call to call '%s'\n", dest);
+ ao2_cleanup(session);
+ return -1;
+ }
+ return 0;
+}
+
+/*! \brief Internal function which translates from Asterisk cause codes to SIP response codes */
+static int hangup_cause2sip(int cause)
+{
+ switch (cause) {
+ case AST_CAUSE_UNALLOCATED: /* 1 */
+ case AST_CAUSE_NO_ROUTE_DESTINATION: /* 3 IAX2: Can't find extension in context */
+ case AST_CAUSE_NO_ROUTE_TRANSIT_NET: /* 2 */
+ return 404;
+ case AST_CAUSE_CONGESTION: /* 34 */
+ case AST_CAUSE_SWITCH_CONGESTION: /* 42 */
+ return 503;
+ case AST_CAUSE_NO_USER_RESPONSE: /* 18 */
+ return 408;
+ case AST_CAUSE_NO_ANSWER: /* 19 */
+ case AST_CAUSE_UNREGISTERED: /* 20 */
+ return 480;
+ case AST_CAUSE_CALL_REJECTED: /* 21 */
+ return 403;
+ case AST_CAUSE_NUMBER_CHANGED: /* 22 */
+ return 410;
+ case AST_CAUSE_NORMAL_UNSPECIFIED: /* 31 */
+ return 480;
+ case AST_CAUSE_INVALID_NUMBER_FORMAT:
+ return 484;
+ case AST_CAUSE_USER_BUSY:
+ return 486;
+ case AST_CAUSE_FAILURE:
+ return 500;
+ case AST_CAUSE_FACILITY_REJECTED: /* 29 */
+ return 501;
+ case AST_CAUSE_CHAN_NOT_IMPLEMENTED:
+ return 503;
+ case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
+ return 502;
+ case AST_CAUSE_BEARERCAPABILITY_NOTAVAIL: /* Can't find codec to connect to host */
+ return 488;
+ case AST_CAUSE_INTERWORKING: /* Unspecified Interworking issues */
+ return 500;
+ case AST_CAUSE_NOTDEFINED:
+ default:
+ ast_debug(1, "AST hangup cause %d (no match found in PJSIP)\n", cause);
+ return 0;
+ }
+
+ /* Never reached */
+ return 0;
+}
+
+struct hangup_data {
+ int cause;
+ struct ast_channel *chan;
+};
+
+static void hangup_data_destroy(void *obj)
+{
+ struct hangup_data *h_data = obj;
+ h_data->chan = ast_channel_unref(h_data->chan);
+}
+
+static struct hangup_data *hangup_data_alloc(int cause, struct ast_channel *chan)
+{
+ struct hangup_data *h_data = ao2_alloc(sizeof(*h_data), hangup_data_destroy);
+ if (!h_data) {
+ return NULL;
+ }
+ h_data->cause = cause;
+ h_data->chan = ast_channel_ref(chan);
+ return h_data;
+}
+
+static int hangup(void *data)
+{
+ pj_status_t status;
+ pjsip_tx_data *packet = NULL;
+ struct hangup_data *h_data = data;
+ struct ast_channel *ast = h_data->chan;
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ struct ast_sip_session *session = pvt->session;
+ int cause = h_data->cause;
+
+ if (((status = pjsip_inv_end_session(session->inv_session, cause ? cause : 603, NULL, &packet)) == PJ_SUCCESS) && packet) {
+ if (packet->msg->type == PJSIP_RESPONSE_MSG) {
+ ast_sip_session_send_response(session, packet);
+ } else {
+ ast_sip_session_send_request(session, packet);
+ }
+ }
+
+ session->channel = NULL;
+ ast_channel_tech_pvt_set(ast, NULL);
+
+ ao2_cleanup(pvt);
+ ao2_cleanup(h_data);
+ return 0;
+}
+
+/*! \brief Function called by core to hang up a Gulp session */
+static int gulp_hangup(struct ast_channel *ast)
+{
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ struct ast_sip_session *session = pvt->session;
+ int cause = hangup_cause2sip(ast_channel_hangupcause(session->channel));
+ struct hangup_data *h_data = hangup_data_alloc(cause, ast);
+ if (!h_data) {
+ goto failure;
+ }
+
+ if (ast_sip_push_task(session->serializer, hangup, h_data)) {
+ ast_log(LOG_WARNING, "Unable to push hangup task to the threadpool. Expect bad things\n");
+ goto failure;
+ }
+ return 0;
+
+failure:
+ /* Go ahead and do our cleanup of the session and channel even if we're not going
+ * to be able to send our SIP request/response
+ */
+ ao2_cleanup(h_data);
+ session->channel = NULL;
+ ast_channel_tech_pvt_set(ast, NULL);
+
+ ao2_cleanup(pvt);
+ return -1;
+}
+
+struct request_data {
+ struct ast_sip_session *session;
+ struct ast_format_cap *caps;
+ const char *dest;
+ int cause;
+};
+
+static int request(void *obj)
+{
+ struct request_data *req_data = obj;
+ char *tmp = ast_strdupa(req_data->dest), *endpoint_name = NULL, *request_user = NULL;
+ RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
+ struct ast_sip_session *session = NULL;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(endpoint);
+ AST_APP_ARG(aor);
+ );
+
+ if (ast_strlen_zero(tmp)) {
+ ast_log(LOG_ERROR, "Unable to create Gulp channel with empty destination\n");
+ req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
+ return -1;
+ }
+
+ AST_NONSTANDARD_APP_ARGS(args, tmp, '/');
+
+ /* If a request user has been specified extract it from the endpoint name portion */
+ if ((endpoint_name = strchr(args.endpoint, '@'))) {
+ request_user = args.endpoint;
+ *endpoint_name++ = '\0';
+ } else {
+ endpoint_name = args.endpoint;
+ }
+
+ if (ast_strlen_zero(endpoint_name)) {
+ ast_log(LOG_ERROR, "Unable to create Gulp channel with empty endpoint name\n");
+ req_data->cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
+ } else if (!(endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
+ ast_log(LOG_ERROR, "Unable to create Gulp channel - endpoint '%s' was not found\n", endpoint_name);
+ req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION;
+ return -1;
+ }
+
+ if (!(session = ast_sip_session_create_outgoing(endpoint, args.aor, request_user, req_data->caps))) {
+ req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION;
+ return -1;
+ }
+
+ req_data->session = session;
+
+ return 0;
+}
+
+/*! \brief Function called by core to create a new outgoing Gulp session */
+static struct ast_channel *gulp_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
+{
+ struct request_data req_data;
+ struct ast_sip_session *session;
+
+ req_data.caps = cap;
+ req_data.dest = data;
+
+ if (ast_sip_push_task_synchronous(NULL, request, &req_data)) {
+ *cause = req_data.cause;
+ return NULL;
+ }
+
+ session = req_data.session;
+
+ if (!(session->channel = gulp_new(session, AST_STATE_DOWN, NULL, NULL, requestor ? ast_channel_linkedid(requestor) : NULL, NULL))) {
+ /* Session needs to be terminated prematurely */
+ return NULL;
+ }
+
+ return session->channel;
+}
+
+/*! \brief Function called by core to send text on Gulp session */
+static int gulp_sendtext(struct ast_channel *ast, const char *text)
+{
+ return 0;
+}
+
+/*! \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 gulp_session_begin(struct ast_sip_session *session)
+{
+ RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
+
+ if (session->endpoint->direct_media_glare_mitigation ==
+ AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE) {
+ return;
+ }
+
+ datastore = ast_sip_session_alloc_datastore(&direct_media_mitigation_info,
+ "direct_media_glare_mitigation");
+
+ if (!datastore) {
+ return;
+ }
+
+ ast_sip_session_add_datastore(session, datastore);
+}
+
+/*! \brief Function called when the session ends */
+static void gulp_session_end(struct ast_sip_session *session)
+{
+ if (!session->channel) {
+ return;
+ }
+
+ if (!ast_channel_hangupcause(session->channel) && session->inv_session) {
+ int cause = hangup_sip2cause(session->inv_session->cause);
+
+ ast_queue_hangup_with_cause(session->channel, cause);
+ } else {
+ ast_queue_hangup(session->channel);
+ }
+}
+
+/*! \brief Function called when a request is received on the session */
+static int gulp_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
+{
+ pjsip_tx_data *packet = NULL;
+ int res = AST_PBX_FAILED;
+
+ if (session->channel) {
+ return 0;
+ }
+
+ if (!(session->channel = gulp_new(session, AST_STATE_DOWN, session->exten, NULL, NULL, NULL))) {
+ if (pjsip_inv_end_session(session->inv_session, 503, NULL, &packet) == PJ_SUCCESS) {
+ ast_sip_session_send_response(session, packet);
+ }
+
+ ast_log(LOG_ERROR, "Failed to allocate new GULP channel on incoming SIP INVITE\n");
+ return -1;
+ }
+
+ ast_setstate(session->channel, AST_STATE_RING);
+ res = ast_pbx_start(session->channel);
+
+ switch (res) {
+ case AST_PBX_FAILED:
+ ast_log(LOG_WARNING, "Failed to start PBX ;(\n");
+ ast_channel_hangupcause_set(session->channel, AST_CAUSE_SWITCH_CONGESTION);
+ ast_hangup(session->channel);
+ break;
+ case AST_PBX_CALL_LIMIT:
+ ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
+ ast_channel_hangupcause_set(session->channel, AST_CAUSE_SWITCH_CONGESTION);
+ ast_hangup(session->channel);
+ break;
+ case AST_PBX_SUCCESS:
+ default:
+ break;
+ }
+
+ ast_debug(3, "Started PBX on new GULP channel %s\n", ast_channel_name(session->channel));
+
+ return (res == AST_PBX_SUCCESS) ? 0 : -1;
+}
+
+/*! \brief Function called when a response is received on the session */
+static void gulp_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
+{
+ struct pjsip_status_line status = rdata->msg_info.msg->line.status;
+
+ if (!session->channel) {
+ return;
+ }
+
+ switch (status.code) {
+ case 180:
+ ast_queue_control(session->channel, AST_CONTROL_RINGING);
+ if (ast_channel_state(session->channel) != AST_STATE_UP) {
+ ast_setstate(session->channel, AST_STATE_RINGING);
+ }
+ break;
+ case 183:
+ ast_queue_control(session->channel, AST_CONTROL_PROGRESS);
+ break;
+ case 200:
+ ast_queue_control(session->channel, AST_CONTROL_ANSWER);
+ break;
+ default:
+ break;
+ }
+}
+
+static int gulp_incoming_ack(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
+{
+ if (rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD) {
+ if (session->endpoint->direct_media) {
+ ast_queue_control(session->channel, AST_CONTROL_SRCCHANGE);
+ }
+ }
+ return 0;
+}
+
+/*!
+ * \brief Load the module
+ *
+ * Module loading including tests for configuration or dependencies.
+ * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
+ * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
+ * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
+ * configuration file or other non-critical problem return
+ * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
+ */
+static int load_module(void)
+{
+ if (!(gulp_tech.capabilities = ast_format_cap_alloc())) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ ast_format_cap_add_all_by_type(gulp_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
+
+ ast_rtp_glue_register(&gulp_rtp_glue);
+
+ if (ast_channel_register(&gulp_tech)) {
+ ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
+ goto end;
+ }
+
+ if (ast_custom_function_register(&gulp_dial_contacts_function)) {
+ ast_log(LOG_ERROR, "Unable to register GULP_DIAL_CONTACTS dialplan function\n");
+ goto end;
+ }
+
+ if (ast_sip_session_register_supplement(&gulp_supplement)) {
+ ast_log(LOG_ERROR, "Unable to register Gulp supplement\n");
+ goto end;
+ }
+
+ if (ast_sip_session_register_supplement(&gulp_ack_supplement)) {
+ ast_log(LOG_ERROR, "Unable to register Gulp ACK supplement\n");
+ ast_sip_session_unregister_supplement(&gulp_supplement);
+ goto end;
+ }
+
+ return 0;
+
+end:
+ ast_custom_function_unregister(&gulp_dial_contacts_function);
+ ast_channel_unregister(&gulp_tech);
+ ast_rtp_glue_unregister(&gulp_rtp_glue);
+
+ return AST_MODULE_LOAD_FAILURE;
+}
+
+/*! \brief Reload module */
+static int reload(void)
+{
+ return -1;
+}
+
+/*! \brief Unload the Gulp channel from Asterisk */
+static int unload_module(void)
+{
+ ast_sip_session_unregister_supplement(&gulp_supplement);
+ ast_custom_function_unregister(&gulp_dial_contacts_function);
+ ast_channel_unregister(&gulp_tech);
+ ast_rtp_glue_unregister(&gulp_rtp_glue);
+
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Gulp SIP Channel Driver",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload,
+ .load_pri = AST_MODPRI_CHANNEL_DRIVER,
+ );
diff --git a/configs/res_sip.conf.sample b/configs/res_sip.conf.sample
new file mode 100644
index 000000000..7fd93a72c
--- /dev/null
+++ b/configs/res_sip.conf.sample
@@ -0,0 +1,24 @@
+; This is an in-flux configuration file for the res_sip module, it will change as things progress
+
+;;; Transports
+[local]
+type=transport
+protocol=udp ; Supported protocols are udp, tcp, and tls
+bind=0.0.0.0 ; This supports both IPv4 and IPv6, port is optional
+
+;;; Endpoints
+[endpoint]
+type=endpoint
+context=default
+disallow=all
+allow=ulaw
+dtmfmode=rfc4733 ; Supported DTMF modes are rfc4733, inband, info, and none
+;transport=local ; Name of a specific transport to use when placing calls
+;100rel=yes ; Enable or disable 100rel support - valid options are: yes, no, required
+;timers=yes ; Enable or disable session timers support - valid options are: yes, no, required, always
+;timers_min_se=90 ; Minimum session timers expiration period, in seconds
+;timers_sess_expires=1800 ; Session timers expiration period, in seconds
+;mohsuggest=example ; What musiconhold class to suggest that the peer channel use when this endpoint places them on hold
+;rtp_ipv6=yes ; Force IPv6 for RTP transport
+;rtp_symmetric=yes ; Enable symmetric RTP support
+;use_ptime=yes ; Whether to use the ptime value received from the endpoint or not
diff --git a/configure b/configure
index c4dd40936..a7d0ad337 100755
--- a/configure
+++ b/configure
@@ -1,12 +1,14 @@
#! /bin/sh
-# From configure.ac Revision: 382812 .
+# From configure.ac Revision: 383581 .
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for asterisk trunk.
+# Generated by GNU Autoconf 2.65 for asterisk trunk.
#
# Report bugs to <https://issues.asterisk.org>.
#
#
-# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
#
#
# This configure script is free software; the Free Software Foundation
@@ -92,7 +94,6 @@ fi
IFS=" "" $as_nl"
# Find who we are. Look in the path if we contain no directory separator.
-as_myself=
case $0 in #((
*[\\/]* ) as_myself=$0 ;;
*) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
@@ -137,31 +138,6 @@ export LANGUAGE
# CDPATH.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-# Use a proper internal environment variable to ensure we don't fall
- # into an infinite loop, continuously re-executing ourselves.
- if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
- _as_can_reexec=no; export _as_can_reexec;
- # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-as_fn_exit 255
- fi
- # We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
@@ -195,8 +171,7 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
else
exitcode=1; echo positional parameters were not saved.
fi
-test x\$exitcode = x0 || exit 1
-test -x / || exit 1"
+test x\$exitcode = x0 || exit 1"
as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
@@ -241,25 +216,14 @@ IFS=$as_save_IFS
if test "x$CONFIG_SHELL" != x; then :
- export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
+ # We cannot yet assume a decent shell, so we have to provide a
+ # neutralization value for shells without unset; and this also
+ # works around shells that cannot unset nonexistent variables.
+ BASH_ENV=/dev/null
+ ENV=/dev/null
+ (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
fi
if test x$as_have_required = xno; then :
@@ -358,18 +322,10 @@ $as_echo X"$as_dir" |
test -d "$as_dir" && break
done
test -z "$as_dirs" || eval "mkdir $as_dirs"
- } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+ } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
} # as_fn_mkdir_p
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
- test -f "$1" && test -x "$1"
-} # as_fn_executable_p
# as_fn_append VAR VALUE
# ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take
@@ -406,19 +362,19 @@ else
fi # as_fn_arith
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
+# as_fn_error ERROR [LINENO LOG_FD]
+# ---------------------------------
# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
+# script with status $?, using 1 if that was 0.
as_fn_error ()
{
- as_status=$1; test $as_status -eq 0 && as_status=1
- if test "$4"; then
- as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ as_status=$?; test $as_status -eq 0 && as_status=1
+ if test "$3"; then
+ as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
fi
- $as_echo "$as_me: error: $2" >&2
+ $as_echo "$as_me: error: $1" >&2
as_fn_exit $as_status
} # as_fn_error
@@ -491,10 +447,6 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
chmod +x "$as_me.lineno" ||
{ $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
- # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
- # already done that, so ensure we don't try to do so again and fall
- # in an infinite loop. This has already happened in practice.
- _as_can_reexec=no; export _as_can_reexec
# Don't try to exec as it changes $[0], causing all sort of problems
# (the dirname of $[0] is not the place where we might find the
# original and so on. Autoconf is especially sensitive to this).
@@ -529,16 +481,16 @@ if (echo >conf$$.file) 2>/dev/null; then
# ... but there are two gotchas:
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
- # In both cases, we have to default to `cp -pR'.
+ # In both cases, we have to default to `cp -p'.
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
elif ln conf$$.file conf$$ 2>/dev/null; then
as_ln_s=ln
else
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
fi
else
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null
@@ -550,8 +502,28 @@ else
as_mkdir_p=false
fi
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -564,7 +536,7 @@ test -n "$DJDIR" || exec 7<&0 </dev/null
exec 6>&1
# Name of the host.
-# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
# so uname gets run too.
ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
@@ -679,8 +651,6 @@ ILBC_CFLAGS
ILBC_INTERNAL
GSM_INTERNAL
PBX_DAHDI_HALF_FULL
-PKG_CONFIG_LIBDIR
-PKG_CONFIG_PATH
PKG_CONFIG
PBX_DLADDR
PBX_IP_MTU_DISCOVER
@@ -1326,8 +1296,6 @@ CXXFLAGS
CCC
CXXCPP
PKG_CONFIG
-PKG_CONFIG_PATH
-PKG_CONFIG_LIBDIR
ILBC_CFLAGS
ILBC_LIBS
LIBEDIT_CFLAGS
@@ -1400,9 +1368,8 @@ do
fi
case $ac_option in
- *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
- *=) ac_optarg= ;;
- *) ac_optarg=yes ;;
+ *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *) ac_optarg=yes ;;
esac
# Accept the important Cygnus configure options, so we can diagnose typos.
@@ -1447,7 +1414,7 @@ do
ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid feature name: $ac_useropt"
+ as_fn_error "invalid feature name: $ac_useropt"
ac_useropt_orig=$ac_useropt
ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
@@ -1473,7 +1440,7 @@ do
ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid feature name: $ac_useropt"
+ as_fn_error "invalid feature name: $ac_useropt"
ac_useropt_orig=$ac_useropt
ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
@@ -1677,7 +1644,7 @@ do
ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid package name: $ac_useropt"
+ as_fn_error "invalid package name: $ac_useropt"
ac_useropt_orig=$ac_useropt
ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
@@ -1693,7 +1660,7 @@ do
ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid package name: $ac_useropt"
+ as_fn_error "invalid package name: $ac_useropt"
ac_useropt_orig=$ac_useropt
ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
@@ -1723,8 +1690,8 @@ do
| --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
x_libraries=$ac_optarg ;;
- -*) as_fn_error $? "unrecognized option: \`$ac_option'
-Try \`$0 --help' for more information"
+ -*) as_fn_error "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information."
;;
*=*)
@@ -1732,7 +1699,7 @@ Try \`$0 --help' for more information"
# Reject names that are not valid shell variable names.
case $ac_envvar in #(
'' | [0-9]* | *[!_$as_cr_alnum]* )
- as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ as_fn_error "invalid variable name: \`$ac_envvar'" ;;
esac
eval $ac_envvar=\$ac_optarg
export $ac_envvar ;;
@@ -1742,7 +1709,7 @@ Try \`$0 --help' for more information"
$as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
$as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
- : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
;;
esac
@@ -1750,13 +1717,13 @@ done
if test -n "$ac_prev"; then
ac_option=--`echo $ac_prev | sed 's/_/-/g'`
- as_fn_error $? "missing argument to $ac_option"
+ as_fn_error "missing argument to $ac_option"
fi
if test -n "$ac_unrecognized_opts"; then
case $enable_option_checking in
no) ;;
- fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;;
*) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
esac
fi
@@ -1779,7 +1746,7 @@ do
[\\/$]* | ?:[\\/]* ) continue;;
NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
esac
- as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+ as_fn_error "expected an absolute directory name for --$ac_var: $ac_val"
done
# There might be people who depend on the old broken behavior: `$host'
@@ -1793,6 +1760,8 @@ target=$target_alias
if test "x$host_alias" != x; then
if test "x$build_alias" = x; then
cross_compiling=maybe
+ $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
elif test "x$build_alias" != "x$host_alias"; then
cross_compiling=yes
fi
@@ -1807,9 +1776,9 @@ test "$silent" = yes && exec 6>/dev/null
ac_pwd=`pwd` && test -n "$ac_pwd" &&
ac_ls_di=`ls -di .` &&
ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
- as_fn_error $? "working directory cannot be determined"
+ as_fn_error "working directory cannot be determined"
test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
- as_fn_error $? "pwd does not report name of working directory"
+ as_fn_error "pwd does not report name of working directory"
# Find the source files, if location was not specified.
@@ -1848,11 +1817,11 @@ else
fi
if test ! -r "$srcdir/$ac_unique_file"; then
test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
- as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+ as_fn_error "cannot find sources ($ac_unique_file) in $srcdir"
fi
ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
ac_abs_confdir=`(
- cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg"
pwd)`
# When building in place, set srcdir=.
if test "$ac_abs_confdir" = "$ac_pwd"; then
@@ -1892,7 +1861,7 @@ Configuration:
--help=short display options specific to this package
--help=recursive display the short help of all the included packages
-V, --version display version information and exit
- -q, --quiet, --silent do not print \`checking ...' messages
+ -q, --quiet, --silent do not print \`checking...' messages
--cache-file=FILE cache test results in FILE [disabled]
-C, --config-cache alias for \`--cache-file=config.cache'
-n, --no-create do not create output files
@@ -2056,10 +2025,6 @@ Some influential environment variables:
CXXFLAGS C++ compiler flags
CXXCPP C++ preprocessor
PKG_CONFIG path to pkg-config utility
- PKG_CONFIG_PATH
- directories to add to pkg-config's search path
- PKG_CONFIG_LIBDIR
- path overriding pkg-config's built-in search path
ILBC_CFLAGS C compiler flags for ILBC, overriding pkg-config
ILBC_LIBS linker flags for ILBC, overriding pkg-config
LIBEDIT_CFLAGS
@@ -2143,9 +2108,9 @@ test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
asterisk configure trunk
-generated by GNU Autoconf 2.69
+generated by GNU Autoconf 2.65
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2009 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
@@ -2191,7 +2156,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_c_try_compile
@@ -2217,7 +2182,7 @@ $as_echo "$ac_try_echo"; } >&5
mv -f conftest.er1 conftest.err
fi
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } > conftest.i && {
+ test $ac_status = 0; } >/dev/null && {
test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
test ! -s conftest.err
}; then :
@@ -2228,7 +2193,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_c_try_cpp
@@ -2241,10 +2206,10 @@ fi
ac_fn_c_check_header_mongrel ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- if eval \${$3+:} false; then :
+ if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
fi
eval ac_res=\$$3
@@ -2280,7 +2245,7 @@ if ac_fn_c_try_cpp "$LINENO"; then :
else
ac_header_preproc=no
fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
$as_echo "$ac_header_preproc" >&6; }
@@ -2303,15 +2268,17 @@ $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
-( $as_echo "## ------------------------------------------ ##
+( cat <<\_ASBOX
+## ------------------------------------------ ##
## Report this to https://issues.asterisk.org ##
-## ------------------------------------------ ##"
+## ------------------------------------------ ##
+_ASBOX
) | sed "s/^/$as_me: WARNING: /" >&2
;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
eval "$3=\$ac_header_compiler"
@@ -2320,7 +2287,7 @@ eval ac_res=\$$3
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_c_check_header_mongrel
@@ -2361,7 +2328,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=$ac_status
fi
rm -rf conftest.dSYM conftest_ipa8_conftest.oo
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_c_try_run
@@ -2375,7 +2342,7 @@ ac_fn_c_check_header_compile ()
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -2393,7 +2360,7 @@ fi
eval ac_res=\$$3
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_c_check_header_compile
@@ -2430,7 +2397,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_cxx_try_compile
@@ -2456,7 +2423,7 @@ $as_echo "$ac_try_echo"; } >&5
mv -f conftest.er1 conftest.err
fi
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } > conftest.i && {
+ test $ac_status = 0; } >/dev/null && {
test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
test ! -s conftest.err
}; then :
@@ -2467,7 +2434,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_cxx_try_cpp
@@ -2499,7 +2466,7 @@ $as_echo "$ac_try_echo"; } >&5
test ! -s conftest.err
} && test -s conftest$ac_exeext && {
test "$cross_compiling" = yes ||
- test -x conftest$ac_exeext
+ $as_test_x conftest$ac_exeext
}; then :
ac_retval=0
else
@@ -2513,7 +2480,7 @@ fi
# interfere with the next link command; also delete a directory that is
# left behind by Apple's compiler. We do this before executing the actions.
rm -rf conftest.dSYM conftest_ipa8_conftest.oo
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_c_try_link
@@ -2526,7 +2493,7 @@ ac_fn_c_check_func ()
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -2581,7 +2548,7 @@ fi
eval ac_res=\$$3
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_c_check_func
@@ -2594,7 +2561,7 @@ ac_fn_c_check_type ()
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
eval "$3=no"
@@ -2635,7 +2602,7 @@ fi
eval ac_res=\$$3
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_c_check_type
@@ -2648,7 +2615,7 @@ ac_fn_c_check_member ()
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
$as_echo_n "checking for $2.$3... " >&6; }
-if eval \${$4+:} false; then :
+if { as_var=$4; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -2692,7 +2659,7 @@ fi
eval ac_res=\$$4
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_c_check_member
@@ -2713,8 +2680,7 @@ int
main ()
{
static int test_array [1 - 2 * !(($2) >= 0)];
-test_array [0] = 0;
-return test_array [0];
+test_array [0] = 0
;
return 0;
@@ -2730,8 +2696,7 @@ int
main ()
{
static int test_array [1 - 2 * !(($2) <= $ac_mid)];
-test_array [0] = 0;
-return test_array [0];
+test_array [0] = 0
;
return 0;
@@ -2757,8 +2722,7 @@ int
main ()
{
static int test_array [1 - 2 * !(($2) < 0)];
-test_array [0] = 0;
-return test_array [0];
+test_array [0] = 0
;
return 0;
@@ -2774,8 +2738,7 @@ int
main ()
{
static int test_array [1 - 2 * !(($2) >= $ac_mid)];
-test_array [0] = 0;
-return test_array [0];
+test_array [0] = 0
;
return 0;
@@ -2809,8 +2772,7 @@ int
main ()
{
static int test_array [1 - 2 * !(($2) <= $ac_mid)];
-test_array [0] = 0;
-return test_array [0];
+test_array [0] = 0
;
return 0;
@@ -2874,7 +2836,7 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
rm -f conftest.val
fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_c_compute_int
@@ -2887,10 +2849,10 @@ rm -f conftest.val
ac_fn_cxx_check_header_mongrel ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- if eval \${$3+:} false; then :
+ if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
fi
eval ac_res=\$$3
@@ -2926,7 +2888,7 @@ if ac_fn_cxx_try_cpp "$LINENO"; then :
else
ac_header_preproc=no
fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
$as_echo "$ac_header_preproc" >&6; }
@@ -2949,15 +2911,17 @@ $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
-( $as_echo "## ------------------------------------------ ##
+( cat <<\_ASBOX
+## ------------------------------------------ ##
## Report this to https://issues.asterisk.org ##
-## ------------------------------------------ ##"
+## ------------------------------------------ ##
+_ASBOX
) | sed "s/^/$as_me: WARNING: /" >&2
;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
eval "$3=\$ac_header_compiler"
@@ -2966,7 +2930,7 @@ eval ac_res=\$$3
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_cxx_check_header_mongrel
@@ -2997,7 +2961,7 @@ $as_echo "$ac_try_echo"; } >&5
test ! -s conftest.err
} && test -s conftest$ac_exeext && {
test "$cross_compiling" = yes ||
- test -x conftest$ac_exeext
+ $as_test_x conftest$ac_exeext
}; then :
ac_retval=0
else
@@ -3011,7 +2975,7 @@ fi
# interfere with the next link command; also delete a directory that is
# left behind by Apple's compiler. We do this before executing the actions.
rm -rf conftest.dSYM conftest_ipa8_conftest.oo
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
as_fn_set_status $ac_retval
} # ac_fn_cxx_try_link
@@ -3025,7 +2989,7 @@ ac_fn_cxx_check_header_compile ()
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -3043,7 +3007,7 @@ fi
eval ac_res=\$$3
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_cxx_check_header_compile
cat >config.log <<_ACEOF
@@ -3051,7 +3015,7 @@ This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by asterisk $as_me trunk, which was
-generated by GNU Autoconf 2.69. Invocation command line was
+generated by GNU Autoconf 2.65. Invocation command line was
$ $0 $@
@@ -3161,9 +3125,11 @@ trap 'exit_status=$?
{
echo
- $as_echo "## ---------------- ##
+ cat <<\_ASBOX
+## ---------------- ##
## Cache variables. ##
-## ---------------- ##"
+## ---------------- ##
+_ASBOX
echo
# The following way of writing the cache mishandles newlines in values,
(
@@ -3197,9 +3163,11 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
)
echo
- $as_echo "## ----------------- ##
+ cat <<\_ASBOX
+## ----------------- ##
## Output variables. ##
-## ----------------- ##"
+## ----------------- ##
+_ASBOX
echo
for ac_var in $ac_subst_vars
do
@@ -3212,9 +3180,11 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
echo
if test -n "$ac_subst_files"; then
- $as_echo "## ------------------- ##
+ cat <<\_ASBOX
+## ------------------- ##
## File substitutions. ##
-## ------------------- ##"
+## ------------------- ##
+_ASBOX
echo
for ac_var in $ac_subst_files
do
@@ -3228,9 +3198,11 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
fi
if test -s confdefs.h; then
- $as_echo "## ----------- ##
+ cat <<\_ASBOX
+## ----------- ##
## confdefs.h. ##
-## ----------- ##"
+## ----------- ##
+_ASBOX
echo
cat confdefs.h
echo
@@ -3285,12 +3257,7 @@ _ACEOF
ac_site_file1=NONE
ac_site_file2=NONE
if test -n "$CONFIG_SITE"; then
- # We do not want a PATH search for config.site.
- case $CONFIG_SITE in #((
- -*) ac_site_file1=./$CONFIG_SITE;;
- */*) ac_site_file1=$CONFIG_SITE;;
- *) ac_site_file1=./$CONFIG_SITE;;
- esac
+ ac_site_file1=$CONFIG_SITE
elif test "x$prefix" != xNONE; then
ac_site_file1=$prefix/share/config.site
ac_site_file2=$prefix/etc/config.site
@@ -3305,11 +3272,7 @@ do
{ $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
$as_echo "$as_me: loading site script $ac_site_file" >&6;}
sed 's/^/| /' "$ac_site_file" >&5
- . "$ac_site_file" \
- || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "failed to load site script $ac_site_file
-See \`config.log' for more details" "$LINENO" 5; }
+ . "$ac_site_file"
fi
done
@@ -3389,7 +3352,7 @@ if $ac_cache_corrupted; then
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
- as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+ as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
fi
## -------------------- ##
## Main body of script. ##
@@ -3406,22 +3369,16 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
# cross-compile macros
ac_aux_dir=
for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
- if test -f "$ac_dir/install-sh"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install-sh -c"
- break
- elif test -f "$ac_dir/install.sh"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install.sh -c"
- break
- elif test -f "$ac_dir/shtool"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/shtool install -c"
- break
- fi
+ for ac_t in install-sh install.sh shtool; do
+ if test -f "$ac_dir/$ac_t"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/$ac_t -c"
+ break 2
+ fi
+ done
done
if test -z "$ac_aux_dir"; then
- as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+ as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
fi
# These three variables are undocumented and unsupported,
@@ -3435,27 +3392,27 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
# Make sure we can run config.sub.
$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
- as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+ as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
$as_echo_n "checking build system type... " >&6; }
-if ${ac_cv_build+:} false; then :
+if test "${ac_cv_build+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_build_alias=$build_alias
test "x$ac_build_alias" = x &&
ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
test "x$ac_build_alias" = x &&
- as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5
ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
- as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+ as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
$as_echo "$ac_cv_build" >&6; }
case $ac_cv_build in
*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+*) as_fn_error "invalid value of canonical build" "$LINENO" 5;;
esac
build=$ac_cv_build
ac_save_IFS=$IFS; IFS='-'
@@ -3473,14 +3430,14 @@ case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
$as_echo_n "checking host system type... " >&6; }
-if ${ac_cv_host+:} false; then :
+if test "${ac_cv_host+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "x$host_alias" = x; then
ac_cv_host=$ac_cv_build
else
ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
- as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+ as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
fi
fi
@@ -3488,7 +3445,7 @@ fi
$as_echo "$ac_cv_host" >&6; }
case $ac_cv_host in
*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+*) as_fn_error "invalid value of canonical host" "$LINENO" 5;;
esac
host=$ac_cv_host
ac_save_IFS=$IFS; IFS='-'
@@ -3510,22 +3467,16 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
ac_aux_dir=
for ac_dir in `pwd` "$srcdir"/`pwd`; do
- if test -f "$ac_dir/install-sh"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install-sh -c"
- break
- elif test -f "$ac_dir/install.sh"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install.sh -c"
- break
- elif test -f "$ac_dir/shtool"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/shtool install -c"
- break
- fi
+ for ac_t in install-sh install.sh shtool; do
+ if test -f "$ac_dir/$ac_t"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/$ac_t -c"
+ break 2
+ fi
+ done
done
if test -z "$ac_aux_dir"; then
- as_fn_error $? "cannot find install-sh, install.sh, or shtool in \`pwd\` \"$srcdir\"/\`pwd\`" "$LINENO" 5
+ as_fn_error "cannot find install-sh, install.sh, or shtool in \`pwd\` \"$srcdir\"/\`pwd\`" "$LINENO" 5
fi
# These three variables are undocumented and unsupported,
@@ -3571,7 +3522,7 @@ if test -n "$ac_tool_prefix"; then
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+if test "${ac_cv_prog_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
@@ -3583,7 +3534,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -3615,7 +3566,7 @@ do
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_CC"; then
@@ -3627,7 +3578,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_CC="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -3667,8 +3618,8 @@ fi
test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "no acceptable C compiler found in \$PATH
-See \`config.log' for more details" "$LINENO" 5; }
+as_fn_error "no acceptable C compiler found in \$PATH
+See \`config.log' for more details." "$LINENO" 5; }
# Provide some information about the compiler.
$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
@@ -3782,8 +3733,9 @@ sed 's/^/| /' conftest.$ac_ext >&5
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "C compiler cannot create executables
-See \`config.log' for more details" "$LINENO" 5; }
+{ as_fn_set_status 77
+as_fn_error "C compiler cannot create executables
+See \`config.log' for more details." "$LINENO" 5; }; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
@@ -3825,8 +3777,8 @@ done
else
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details" "$LINENO" 5; }
+as_fn_error "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." "$LINENO" 5; }
fi
rm -f conftest conftest$ac_cv_exeext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
@@ -3883,9 +3835,9 @@ $as_echo "$ac_try_echo"; } >&5
else
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot run C compiled programs.
+as_fn_error "cannot run C compiled programs.
If you meant to cross compile, use \`--host'.
-See \`config.log' for more details" "$LINENO" 5; }
+See \`config.log' for more details." "$LINENO" 5; }
fi
fi
fi
@@ -3896,7 +3848,7 @@ rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
ac_clean_files=$ac_clean_files_save
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
$as_echo_n "checking for suffix of object files... " >&6; }
-if ${ac_cv_objext+:} false; then :
+if test "${ac_cv_objext+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -3936,8 +3888,8 @@ sed 's/^/| /' conftest.$ac_ext >&5
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of object files: cannot compile
-See \`config.log' for more details" "$LINENO" 5; }
+as_fn_error "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." "$LINENO" 5; }
fi
rm -f conftest.$ac_cv_objext conftest.$ac_ext
fi
@@ -3947,7 +3899,7 @@ OBJEXT=$ac_cv_objext
ac_objext=$OBJEXT
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if ${ac_cv_c_compiler_gnu+:} false; then :
+if test "${ac_cv_c_compiler_gnu+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -3984,7 +3936,7 @@ ac_test_CFLAGS=${CFLAGS+set}
ac_save_CFLAGS=$CFLAGS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
$as_echo_n "checking whether $CC accepts -g... " >&6; }
-if ${ac_cv_prog_cc_g+:} false; then :
+if test "${ac_cv_prog_cc_g+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_save_c_werror_flag=$ac_c_werror_flag
@@ -4062,7 +4014,7 @@ else
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if ${ac_cv_prog_cc_c89+:} false; then :
+if test "${ac_cv_prog_cc_c89+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_cv_prog_cc_c89=no
@@ -4071,7 +4023,8 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdarg.h>
#include <stdio.h>
-struct stat;
+#include <sys/types.h>
+#include <sys/stat.h>
/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
struct buf { int x; };
FILE * (*rcsopen) (struct buf *, struct stat *, int);
@@ -4170,7 +4123,7 @@ if test -n "$CPP" && test -d "$CPP"; then
CPP=
fi
if test -z "$CPP"; then
- if ${ac_cv_prog_CPP+:} false; then :
+ if test "${ac_cv_prog_CPP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
# Double quotes because CPP needs to be expanded
@@ -4200,7 +4153,7 @@ else
# Broken: fails on valid input.
continue
fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
# OK, works on sane cases. Now check whether nonexistent headers
# can be detected and how.
@@ -4216,11 +4169,11 @@ else
ac_preproc_ok=:
break
fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :
break
fi
@@ -4259,7 +4212,7 @@ else
# Broken: fails on valid input.
continue
fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
# OK, works on sane cases. Now check whether nonexistent headers
# can be detected and how.
@@ -4275,18 +4228,18 @@ else
ac_preproc_ok=:
break
fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :
else
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details" "$LINENO" 5; }
+as_fn_error "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." "$LINENO" 5; }
fi
ac_ext=c
@@ -4298,7 +4251,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
-if ${ac_cv_path_GREP+:} false; then :
+if test "${ac_cv_path_GREP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -z "$GREP"; then
@@ -4312,7 +4265,7 @@ do
for ac_prog in grep ggrep; do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_GREP" || continue
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
# Check for GNU ac_path_GREP and select it if it is found.
# Check for GNU $ac_path_GREP
case `"$ac_path_GREP" --version 2>&1` in
@@ -4347,7 +4300,7 @@ esac
done
IFS=$as_save_IFS
if test -z "$ac_cv_path_GREP"; then
- as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
fi
else
ac_cv_path_GREP=$GREP
@@ -4361,7 +4314,7 @@ $as_echo "$ac_cv_path_GREP" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
$as_echo_n "checking for egrep... " >&6; }
-if ${ac_cv_path_EGREP+:} false; then :
+if test "${ac_cv_path_EGREP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
@@ -4378,7 +4331,7 @@ do
for ac_prog in egrep; do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_EGREP" || continue
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
# Check for GNU ac_path_EGREP and select it if it is found.
# Check for GNU $ac_path_EGREP
case `"$ac_path_EGREP" --version 2>&1` in
@@ -4413,7 +4366,7 @@ esac
done
IFS=$as_save_IFS
if test -z "$ac_cv_path_EGREP"; then
- as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
fi
else
ac_cv_path_EGREP=$EGREP
@@ -4428,7 +4381,7 @@ $as_echo "$ac_cv_path_EGREP" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
$as_echo_n "checking for ANSI C header files... " >&6; }
-if ${ac_cv_header_stdc+:} false; then :
+if test "${ac_cv_header_stdc+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -4545,7 +4498,8 @@ do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF
@@ -4557,7 +4511,7 @@ done
ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default"
-if test "x$ac_cv_header_minix_config_h" = xyes; then :
+if test "x$ac_cv_header_minix_config_h" = x""yes; then :
MINIX=yes
else
MINIX=
@@ -4579,14 +4533,14 @@ $as_echo "#define _MINIX 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5
$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; }
-if ${ac_cv_safe_to_define___extensions__+:} false; then :
+if test "${ac_cv_safe_to_define___extensions__+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-# define __EXTENSIONS__ 1
- $ac_includes_default
+# define __EXTENSIONS__ 1
+ $ac_includes_default
int
main ()
{
@@ -4775,7 +4729,7 @@ if test -n "$ac_tool_prefix"; then
set dummy ${ac_tool_prefix}uname; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_UNAME+:} false; then :
+if test "${ac_cv_path_UNAME+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $UNAME in
@@ -4789,7 +4743,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_UNAME="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -4818,7 +4772,7 @@ if test -z "$ac_cv_path_UNAME"; then
set dummy uname; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_UNAME+:} false; then :
+if test "${ac_cv_path_ac_pt_UNAME+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_UNAME in
@@ -4832,7 +4786,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_ac_pt_UNAME="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -4885,7 +4839,7 @@ then
set dummy ${ac_tool_prefix}gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+if test "${ac_cv_prog_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
@@ -4897,7 +4851,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_CC="${ac_tool_prefix}gcc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -4925,7 +4879,7 @@ if test -z "$ac_cv_prog_CC"; then
set dummy gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_CC"; then
@@ -4937,7 +4891,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_CC="gcc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -4977,7 +4931,7 @@ fi
set dummy ${ac_tool_prefix}g++; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CXX+:} false; then :
+if test "${ac_cv_prog_CXX+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CXX"; then
@@ -4989,7 +4943,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_CXX="${ac_tool_prefix}g++"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -5017,7 +4971,7 @@ if test -z "$ac_cv_prog_CXX"; then
set dummy g++; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_CXX"; then
@@ -5029,7 +4983,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_CXX="g++"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -5069,7 +5023,7 @@ fi
set dummy ${ac_tool_prefix}ld; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_LD+:} false; then :
+if test "${ac_cv_prog_LD+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$LD"; then
@@ -5081,7 +5035,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_LD="${ac_tool_prefix}ld"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -5109,7 +5063,7 @@ if test -z "$ac_cv_prog_LD"; then
set dummy ld; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_LD+:} false; then :
+if test "${ac_cv_prog_ac_ct_LD+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_LD"; then
@@ -5121,7 +5075,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_LD="ld"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -5161,7 +5115,7 @@ fi
set dummy ${ac_tool_prefix}ranlib; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_RANLIB+:} false; then :
+if test "${ac_cv_prog_RANLIB+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$RANLIB"; then
@@ -5173,7 +5127,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -5201,7 +5155,7 @@ if test -z "$ac_cv_prog_RANLIB"; then
set dummy ranlib; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_RANLIB"; then
@@ -5213,7 +5167,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_RANLIB="ranlib"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -5267,7 +5221,7 @@ if test -z "$CXX"; then
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CXX+:} false; then :
+if test "${ac_cv_prog_CXX+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CXX"; then
@@ -5279,7 +5233,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -5311,7 +5265,7 @@ do
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_CXX"; then
@@ -5323,7 +5277,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_CXX="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -5389,7 +5343,7 @@ done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
-if ${ac_cv_cxx_compiler_gnu+:} false; then :
+if test "${ac_cv_cxx_compiler_gnu+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -5426,7 +5380,7 @@ ac_test_CXXFLAGS=${CXXFLAGS+set}
ac_save_CXXFLAGS=$CXXFLAGS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
$as_echo_n "checking whether $CXX accepts -g... " >&6; }
-if ${ac_cv_prog_cxx_g+:} false; then :
+if test "${ac_cv_prog_cxx_g+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_save_cxx_werror_flag=$ac_cxx_werror_flag
@@ -5520,7 +5474,7 @@ if test -n "$CPP" && test -d "$CPP"; then
CPP=
fi
if test -z "$CPP"; then
- if ${ac_cv_prog_CPP+:} false; then :
+ if test "${ac_cv_prog_CPP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
# Double quotes because CPP needs to be expanded
@@ -5550,7 +5504,7 @@ else
# Broken: fails on valid input.
continue
fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
# OK, works on sane cases. Now check whether nonexistent headers
# can be detected and how.
@@ -5566,11 +5520,11 @@ else
ac_preproc_ok=:
break
fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :
break
fi
@@ -5609,7 +5563,7 @@ else
# Broken: fails on valid input.
continue
fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
# OK, works on sane cases. Now check whether nonexistent headers
# can be detected and how.
@@ -5625,18 +5579,18 @@ else
ac_preproc_ok=:
break
fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :
else
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details" "$LINENO" 5; }
+as_fn_error "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." "$LINENO" 5; }
fi
ac_ext=c
@@ -5653,7 +5607,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
if test -z "$CXXCPP"; then
- if ${ac_cv_prog_CXXCPP+:} false; then :
+ if test "${ac_cv_prog_CXXCPP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
# Double quotes because CXXCPP needs to be expanded
@@ -5683,7 +5637,7 @@ else
# Broken: fails on valid input.
continue
fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
# OK, works on sane cases. Now check whether nonexistent headers
# can be detected and how.
@@ -5699,11 +5653,11 @@ else
ac_preproc_ok=:
break
fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :
break
fi
@@ -5742,7 +5696,7 @@ else
# Broken: fails on valid input.
continue
fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
# OK, works on sane cases. Now check whether nonexistent headers
# can be detected and how.
@@ -5758,18 +5712,18 @@ else
ac_preproc_ok=:
break
fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :
else
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check
-See \`config.log' for more details" "$LINENO" 5; }
+as_fn_error "C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." "$LINENO" 5; }
fi
ac_ext=c
@@ -5782,7 +5736,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
# the developers regenerating the configure script don't have to install libtool.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
$as_echo_n "checking for a sed that does not truncate output... " >&6; }
-if ${ac_cv_path_SED+:} false; then :
+if test "${ac_cv_path_SED+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
@@ -5802,7 +5756,7 @@ do
for ac_prog in sed gsed; do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_SED" || continue
+ { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
# Check for GNU ac_path_SED and select it if it is found.
# Check for GNU $ac_path_SED
case `"$ac_path_SED" --version 2>&1` in
@@ -5837,7 +5791,7 @@ esac
done
IFS=$as_save_IFS
if test -z "$ac_cv_path_SED"; then
- as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+ as_fn_error "no acceptable sed could be found in \$PATH" "$LINENO" 5
fi
else
ac_cv_path_SED=$SED
@@ -5851,7 +5805,7 @@ $as_echo "$ac_cv_path_SED" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
$as_echo_n "checking for egrep... " >&6; }
-if ${ac_cv_prog_egrep+:} false; then :
+if test "${ac_cv_prog_egrep+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if echo a | (grep -E '(a|b)') >/dev/null 2>&1
@@ -5911,7 +5865,7 @@ else
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
$as_echo_n "checking for non-GNU ld... " >&6; }
fi
-if ${lt_cv_path_LD+:} false; then :
+if test "${lt_cv_path_LD+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -z "$LD"; then
@@ -5948,10 +5902,10 @@ else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
-test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
-if ${lt_cv_prog_gnu_ld+:} false; then :
+if test "${lt_cv_prog_gnu_ld+set}" = set; then :
$as_echo_n "(cached) " >&6
else
# I'd rather use --version here, but apparently some GNU lds only accept -v.
@@ -5975,7 +5929,7 @@ do
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AWK+:} false; then :
+if test "${ac_cv_prog_AWK+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$AWK"; then
@@ -5987,7 +5941,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_AWK="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6028,7 +5982,7 @@ done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
$as_echo_n "checking for a BSD-compatible install... " >&6; }
if test -z "$INSTALL"; then
-if ${ac_cv_path_install+:} false; then :
+if test "${ac_cv_path_install+set}" = set; then :
$as_echo_n "(cached) " >&6
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
@@ -6048,7 +6002,7 @@ case $as_dir/ in #((
# by default.
for ac_prog in ginstall scoinst install; do
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
if test $ac_prog = install &&
grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
# AIX install. It has an incompatible calling convention.
@@ -6120,7 +6074,7 @@ if test -n "$ac_tool_prefix"; then
set dummy ${ac_tool_prefix}ranlib; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_RANLIB+:} false; then :
+if test "${ac_cv_prog_RANLIB+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$RANLIB"; then
@@ -6132,7 +6086,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6160,7 +6114,7 @@ if test -z "$ac_cv_prog_RANLIB"; then
set dummy ranlib; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_RANLIB"; then
@@ -6172,7 +6126,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_RANLIB="ranlib"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6209,7 +6163,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU make" >&5
$as_echo_n "checking for GNU make... " >&6; }
-if ${ac_cv_GNU_MAKE+:} false; then :
+if test "${ac_cv_GNU_MAKE+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_cv_GNU_MAKE='Not Found' ;
@@ -6229,7 +6183,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_GNU_MAKE" >&5
$as_echo "$ac_cv_GNU_MAKE" >&6; } ;
if test "x$ac_cv_GNU_MAKE" = "xNot Found" ; then
- as_fn_error $? "*** Please install GNU make. It is required to build Asterisk!" "$LINENO" 5
+ as_fn_error "*** Please install GNU make. It is required to build Asterisk!" "$LINENO" 5
exit 1
fi
GNU_MAKE=$ac_cv_GNU_MAKE
@@ -6237,7 +6191,7 @@ GNU_MAKE=$ac_cv_GNU_MAKE
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
$as_echo_n "checking for egrep... " >&6; }
-if ${ac_cv_path_EGREP+:} false; then :
+if test "${ac_cv_path_EGREP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
@@ -6254,7 +6208,7 @@ do
for ac_prog in egrep; do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_EGREP" || continue
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
# Check for GNU ac_path_EGREP and select it if it is found.
# Check for GNU $ac_path_EGREP
case `"$ac_path_EGREP" --version 2>&1` in
@@ -6289,7 +6243,7 @@ esac
done
IFS=$as_save_IFS
if test -z "$ac_cv_path_EGREP"; then
- as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
fi
else
ac_cv_path_EGREP=$EGREP
@@ -6310,7 +6264,7 @@ if test -n "$ac_tool_prefix"; then
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_STRIP+:} false; then :
+if test "${ac_cv_prog_STRIP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$STRIP"; then
@@ -6322,7 +6276,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_STRIP="$ac_tool_prefix$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6354,7 +6308,7 @@ do
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_STRIP"; then
@@ -6366,7 +6320,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_STRIP="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6410,7 +6364,7 @@ if test -n "$ac_tool_prefix"; then
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AR+:} false; then :
+if test "${ac_cv_prog_AR+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$AR"; then
@@ -6422,7 +6376,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6454,7 +6408,7 @@ do
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_AR+:} false; then :
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_AR"; then
@@ -6466,7 +6420,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_AR="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6514,7 +6468,7 @@ fi
set dummy bison; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_BISON+:} false; then :
+if test "${ac_cv_path_BISON+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $BISON in
@@ -6528,7 +6482,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_BISON="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6555,7 +6509,7 @@ fi
set dummy cmp; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CMP+:} false; then :
+if test "${ac_cv_path_CMP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CMP in
@@ -6569,7 +6523,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_CMP="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6596,7 +6550,7 @@ fi
set dummy flex; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_FLEX+:} false; then :
+if test "${ac_cv_path_FLEX+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $FLEX in
@@ -6610,7 +6564,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_FLEX="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6637,7 +6591,7 @@ fi
set dummy grep; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_GREP+:} false; then :
+if test "${ac_cv_path_GREP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $GREP in
@@ -6651,7 +6605,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_GREP="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6678,7 +6632,7 @@ fi
set dummy python; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PYTHON+:} false; then :
+if test "${ac_cv_path_PYTHON+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $PYTHON in
@@ -6692,7 +6646,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6719,7 +6673,7 @@ fi
set dummy find; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_FIND+:} false; then :
+if test "${ac_cv_path_FIND+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $FIND in
@@ -6733,7 +6687,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_FIND="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6760,7 +6714,7 @@ fi
set dummy compress; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_COMPRESS+:} false; then :
+if test "${ac_cv_path_COMPRESS+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $COMPRESS in
@@ -6774,7 +6728,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_COMPRESS="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6801,7 +6755,7 @@ fi
set dummy basename; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_BASENAME+:} false; then :
+if test "${ac_cv_path_BASENAME+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $BASENAME in
@@ -6815,7 +6769,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_BASENAME="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6842,7 +6796,7 @@ fi
set dummy dirname; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_DIRNAME+:} false; then :
+if test "${ac_cv_path_DIRNAME+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $DIRNAME in
@@ -6856,7 +6810,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_DIRNAME="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6883,7 +6837,7 @@ fi
set dummy sh; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_SHELL+:} false; then :
+if test "${ac_cv_path_SHELL+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $SHELL in
@@ -6897,7 +6851,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_SHELL="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6924,7 +6878,7 @@ fi
set dummy ln; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_LN+:} false; then :
+if test "${ac_cv_path_LN+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $LN in
@@ -6938,7 +6892,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_LN="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -6965,7 +6919,7 @@ fi
set dummy doxygen; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_DOXYGEN+:} false; then :
+if test "${ac_cv_path_DOXYGEN+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $DOXYGEN in
@@ -6979,7 +6933,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_DOXYGEN="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7006,7 +6960,7 @@ fi
set dummy dot; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_DOT+:} false; then :
+if test "${ac_cv_path_DOT+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $DOT in
@@ -7020,7 +6974,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_DOT="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7047,7 +7001,7 @@ fi
set dummy wget; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_WGET+:} false; then :
+if test "${ac_cv_path_WGET+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $WGET in
@@ -7061,7 +7015,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_WGET="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7088,7 +7042,7 @@ fi
set dummy curl; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CURL+:} false; then :
+if test "${ac_cv_path_CURL+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CURL in
@@ -7102,7 +7056,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_CURL="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7129,7 +7083,7 @@ fi
set dummy rubber; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_RUBBER+:} false; then :
+if test "${ac_cv_path_RUBBER+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $RUBBER in
@@ -7143,7 +7097,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_RUBBER="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7170,7 +7124,7 @@ fi
set dummy catdvi; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CATDVI+:} false; then :
+if test "${ac_cv_path_CATDVI+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CATDVI in
@@ -7184,7 +7138,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_CATDVI="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7211,7 +7165,7 @@ fi
set dummy kpsewhich; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_KPATHSEA+:} false; then :
+if test "${ac_cv_path_KPATHSEA+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $KPATHSEA in
@@ -7225,7 +7179,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_KPATHSEA="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7252,7 +7206,7 @@ fi
set dummy xmllint; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_XMLLINT+:} false; then :
+if test "${ac_cv_path_XMLLINT+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $XMLLINT in
@@ -7266,7 +7220,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_XMLLINT="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7293,7 +7247,7 @@ fi
set dummy xmlstarlet; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_XMLSTARLET+:} false; then :
+if test "${ac_cv_path_XMLSTARLET+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $XMLSTARLET in
@@ -7307,7 +7261,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_XMLSTARLET="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7334,7 +7288,7 @@ fi
set dummy git; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_GIT+:} false; then :
+if test "${ac_cv_path_GIT+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $GIT in
@@ -7348,7 +7302,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_GIT="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7380,7 +7334,7 @@ else
set dummy fetch; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_FETCH+:} false; then :
+if test "${ac_cv_path_FETCH+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $FETCH in
@@ -7394,7 +7348,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_FETCH="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7425,7 +7379,7 @@ fi
set dummy ldconfig; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_LDCONFIG+:} false; then :
+if test "${ac_cv_path_LDCONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $LDCONFIG in
@@ -7439,7 +7393,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_LDCONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7466,7 +7420,7 @@ fi
set dummy sha1sum; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_SHA1SUM+:} false; then :
+if test "${ac_cv_path_SHA1SUM+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $SHA1SUM in
@@ -7480,7 +7434,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_SHA1SUM="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7507,7 +7461,7 @@ fi
set dummy openssl; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_OPENSSL+:} false; then :
+if test "${ac_cv_path_OPENSSL+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $OPENSSL in
@@ -7521,7 +7475,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_OPENSSL="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7547,7 +7501,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for bison that supports parse-param" >&5
$as_echo_n "checking for bison that supports parse-param... " >&6; }
-if ${ac_cv_path_BISON2+:} false; then :
+if test "${ac_cv_path_BISON2+set}" = set; then :
$as_echo_n "(cached) " >&6
else
@@ -7601,7 +7555,7 @@ if test -n "$ac_tool_prefix"; then
set dummy ${ac_tool_prefix}soxmix; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_SOXMIX+:} false; then :
+if test "${ac_cv_prog_SOXMIX+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$SOXMIX"; then
@@ -7613,7 +7567,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_SOXMIX="${ac_tool_prefix}soxmix"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7641,7 +7595,7 @@ if test -z "$ac_cv_prog_SOXMIX"; then
set dummy soxmix; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_SOXMIX+:} false; then :
+if test "${ac_cv_prog_ac_ct_SOXMIX+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_SOXMIX"; then
@@ -7653,7 +7607,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_ac_ct_SOXMIX="soxmix"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7700,7 +7654,7 @@ do
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_MD5+:} false; then :
+if test "${ac_cv_prog_MD5+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$MD5"; then
@@ -7712,7 +7666,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_MD5="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -7866,7 +7820,7 @@ $as_echo_n "checking whether pthreads work with $flag... " >&6; }
set dummy pthread-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_acx_pthread_config+:} false; then :
+if test "${ac_cv_prog_acx_pthread_config+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$acx_pthread_config"; then
@@ -7878,7 +7832,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_acx_pthread_config="yes"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -8022,7 +7976,7 @@ do
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_PTHREAD_CC+:} false; then :
+if test "${ac_cv_prog_PTHREAD_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$PTHREAD_CC"; then
@@ -8034,7 +7988,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_PTHREAD_CC="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -8108,7 +8062,7 @@ if test "${enable_dev_mode+set}" = set; then :
AST_DEVMODE=yes
AST_DEVMODE_STRICT=yes
;;
- *) as_fn_error $? "bad value ${enableval} for --enable-dev-mode" "$LINENO" 5 ;;
+ *) as_fn_error "bad value ${enableval} for --enable-dev-mode" "$LINENO" 5 ;;
esac
fi
@@ -8122,7 +8076,7 @@ if test "${enable_coverage+set}" = set; then :
enableval=$enable_coverage; case "${enableval}" in
y|ye|yes) AST_CODE_COVERAGE=yes ;;
n|no) AST_CODE_COVERAGE=no ;;
- *) as_fn_error $? "bad value ${enableval} for --enable-coverage" "$LINENO" 5 ;;
+ *) as_fn_error "bad value ${enableval} for --enable-coverage" "$LINENO" 5 ;;
esac
fi
@@ -9067,7 +9021,7 @@ do
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AWK+:} false; then :
+if test "${ac_cv_prog_AWK+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$AWK"; then
@@ -9079,7 +9033,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_AWK="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -9115,7 +9069,7 @@ done
set dummy curl-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path__libcurl_config+:} false; then :
+if test "${ac_cv_path__libcurl_config+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $_libcurl_config in
@@ -9129,7 +9083,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path__libcurl_config="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -9157,7 +9111,7 @@ fi
set dummy curl-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path__libcurl_config+:} false; then :
+if test "${ac_cv_path__libcurl_config+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $_libcurl_config in
@@ -9171,7 +9125,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path__libcurl_config="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -9198,7 +9152,7 @@ fi
if test x$_libcurl_config != "x" ; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the version of libcurl" >&5
$as_echo_n "checking for the version of libcurl... " >&6; }
-if ${libcurl_cv_lib_curl_version+:} false; then :
+if test "${libcurl_cv_lib_curl_version+set}" = set; then :
$as_echo_n "(cached) " >&6
else
libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $2}'`
@@ -9212,7 +9166,7 @@ $as_echo "$libcurl_cv_lib_curl_version" >&6; }
if test $_libcurl_wanted -gt 0 ; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcurl >= version 7.10.1" >&5
$as_echo_n "checking for libcurl >= version 7.10.1... " >&6; }
-if ${libcurl_cv_lib_version_ok+:} false; then :
+if test "${libcurl_cv_lib_version_ok+set}" = set; then :
$as_echo_n "(cached) " >&6
else
@@ -9266,7 +9220,7 @@ $as_echo "$libcurl_cv_lib_version_ok" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libcurl is usable" >&5
$as_echo_n "checking whether libcurl is usable... " >&6; }
-if ${libcurl_cv_lib_curl_usable+:} false; then :
+if test "${libcurl_cv_lib_curl_usable+set}" = set; then :
$as_echo_n "(cached) " >&6
else
@@ -9325,7 +9279,7 @@ $as_echo "$libcurl_cv_lib_curl_usable" >&6; }
LIBS="$LIBS $CURL_LIB"
ac_fn_c_check_func "$LINENO" "curl_free" "ac_cv_func_curl_free"
-if test "x$ac_cv_func_curl_free" = xyes; then :
+if test "x$ac_cv_func_curl_free" = x""yes; then :
else
@@ -11149,22 +11103,11 @@ fi
# check for basic system features and functionality before
# checking for package libraries
-ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
-if test "x$ac_cv_type_size_t" = xyes; then :
-
-else
-
-cat >>confdefs.h <<_ACEOF
-#define size_t unsigned int
-_ACEOF
-
-fi
-
# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
# for constant arguments. Useless!
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5
$as_echo_n "checking for working alloca.h... " >&6; }
-if ${ac_cv_working_alloca_h+:} false; then :
+if test "${ac_cv_working_alloca_h+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -11197,7 +11140,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5
$as_echo_n "checking for alloca... " >&6; }
-if ${ac_cv_func_alloca_works+:} false; then :
+if test "${ac_cv_func_alloca_works+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -11216,7 +11159,7 @@ else
#pragma alloca
# else
# ifndef alloca /* predefined by HP cc +Olibcalls */
-void *alloca (size_t);
+char *alloca ();
# endif
# endif
# endif
@@ -11260,7 +11203,7 @@ $as_echo "#define C_ALLOCA 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5
$as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; }
-if ${ac_cv_os_cray+:} false; then :
+if test "${ac_cv_os_cray+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -11287,7 +11230,8 @@ if test $ac_cv_os_cray = yes; then
for ac_func in _getb67 GETB67 getb67; do
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+eval as_val=\$$as_ac_var
+ if test "x$as_val" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define CRAY_STACKSEG_END $ac_func
@@ -11301,7 +11245,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5
$as_echo_n "checking stack direction for C alloca... " >&6; }
-if ${ac_cv_c_stack_direction+:} false; then :
+if test "${ac_cv_c_stack_direction+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
@@ -11311,20 +11255,23 @@ else
/* end confdefs.h. */
$ac_includes_default
int
-find_stack_direction (int *addr, int depth)
+find_stack_direction ()
{
- int dir, dummy = 0;
- if (! addr)
- addr = &dummy;
- *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1;
- dir = depth ? find_stack_direction (addr, depth - 1) : 0;
- return dir + dummy;
+ static char *addr = 0;
+ auto char dummy;
+ if (addr == 0)
+ {
+ addr = &dummy;
+ return find_stack_direction ();
+ }
+ else
+ return (&dummy > addr) ? 1 : -1;
}
int
-main (int argc, char **argv)
+main ()
{
- return find_stack_direction (0, argc + !argv + 20) < 0;
+ return find_stack_direction () < 0;
}
_ACEOF
if ac_fn_c_try_run "$LINENO"; then :
@@ -11351,7 +11298,7 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5
$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; }
-if eval \${$as_ac_Header+:} false; then :
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -11378,7 +11325,8 @@ fi
eval ac_res=\$$as_ac_Header
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1
_ACEOF
@@ -11391,7 +11339,7 @@ done
if test $ac_header_dirent = dirent.h; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
$as_echo_n "checking for library containing opendir... " >&6; }
-if ${ac_cv_search_opendir+:} false; then :
+if test "${ac_cv_search_opendir+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
@@ -11425,11 +11373,11 @@ for ac_lib in '' dir; do
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if ${ac_cv_search_opendir+:} false; then :
+ if test "${ac_cv_search_opendir+set}" = set; then :
break
fi
done
-if ${ac_cv_search_opendir+:} false; then :
+if test "${ac_cv_search_opendir+set}" = set; then :
else
ac_cv_search_opendir=no
@@ -11448,7 +11396,7 @@ fi
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
$as_echo_n "checking for library containing opendir... " >&6; }
-if ${ac_cv_search_opendir+:} false; then :
+if test "${ac_cv_search_opendir+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
@@ -11482,11 +11430,11 @@ for ac_lib in '' x; do
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if ${ac_cv_search_opendir+:} false; then :
+ if test "${ac_cv_search_opendir+set}" = set; then :
break
fi
done
-if ${ac_cv_search_opendir+:} false; then :
+if test "${ac_cv_search_opendir+set}" = set; then :
else
ac_cv_search_opendir=no
@@ -11506,7 +11454,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
$as_echo_n "checking for ANSI C header files... " >&6; }
-if ${ac_cv_header_stdc+:} false; then :
+if test "${ac_cv_header_stdc+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -11618,7 +11566,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5
$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; }
-if ${ac_cv_header_sys_wait_h+:} false; then :
+if test "${ac_cv_header_sys_wait_h+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -11661,7 +11609,8 @@ for ac_header in arpa/inet.h fcntl.h inttypes.h libintl.h limits.h locale.h mall
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF
@@ -11692,7 +11641,7 @@ if test "x${PBX_TERMCAP}" != "x1" -a "${USE_TERMCAP}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_termcap_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -ltermcap" >&5
$as_echo_n "checking for ${pbxfuncname} in -ltermcap... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -11727,7 +11676,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_TERMCAP_FOUND=yes
else
AST_TERMCAP_FOUND=no
@@ -11750,7 +11700,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${TERMCAP_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default"
-if test "x$ac_cv_header_" = xyes; then :
+if test "x$ac_cv_header_" = x""yes; then :
TERMCAP_HEADER_FOUND=1
else
TERMCAP_HEADER_FOUND=0
@@ -11796,7 +11746,7 @@ if test "x${PBX_TINFO}" != "x1" -a "${USE_TINFO}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_tinfo_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -ltinfo" >&5
$as_echo_n "checking for ${pbxfuncname} in -ltinfo... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -11831,7 +11781,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_TINFO_FOUND=yes
else
AST_TINFO_FOUND=no
@@ -11854,7 +11805,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${TINFO_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default"
-if test "x$ac_cv_header_" = xyes; then :
+if test "x$ac_cv_header_" = x""yes; then :
TINFO_HEADER_FOUND=1
else
TINFO_HEADER_FOUND=0
@@ -11900,7 +11851,7 @@ if test "x${PBX_CURSES}" != "x1" -a "${USE_CURSES}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_curses_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lcurses" >&5
$as_echo_n "checking for ${pbxfuncname} in -lcurses... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -11935,7 +11886,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_CURSES_FOUND=yes
else
AST_CURSES_FOUND=no
@@ -11958,7 +11910,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${CURSES_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "curses.h" "ac_cv_header_curses_h" "$ac_includes_default"
-if test "x$ac_cv_header_curses_h" = xyes; then :
+if test "x$ac_cv_header_curses_h" = x""yes; then :
CURSES_HEADER_FOUND=1
else
CURSES_HEADER_FOUND=0
@@ -12004,7 +11956,7 @@ if test "x${PBX_NCURSES}" != "x1" -a "${USE_NCURSES}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_ncurses_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lncurses" >&5
$as_echo_n "checking for ${pbxfuncname} in -lncurses... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -12039,7 +11991,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_NCURSES_FOUND=yes
else
AST_NCURSES_FOUND=no
@@ -12062,7 +12015,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${NCURSES_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "curses.h" "ac_cv_header_curses_h" "$ac_includes_default"
-if test "x$ac_cv_header_curses_h" = xyes; then :
+if test "x$ac_cv_header_curses_h" = x""yes; then :
NCURSES_HEADER_FOUND=1
else
NCURSES_HEADER_FOUND=0
@@ -12108,7 +12061,7 @@ if test "x${PBX_UUID}" != "x1" -a "${USE_UUID}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_uuid_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -luuid" >&5
$as_echo_n "checking for ${pbxfuncname} in -luuid... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -12143,7 +12096,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_UUID_FOUND=yes
else
AST_UUID_FOUND=no
@@ -12166,7 +12120,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${UUID_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default"
-if test "x$ac_cv_header_uuid_uuid_h" = xyes; then :
+if test "x$ac_cv_header_uuid_uuid_h" = x""yes; then :
UUID_HEADER_FOUND=1
else
UUID_HEADER_FOUND=0
@@ -12212,7 +12166,7 @@ if test "x${PBX_JANSSON}" != "x1" -a "${USE_JANSSON}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_jansson_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -ljansson" >&5
$as_echo_n "checking for ${pbxfuncname} in -ljansson... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -12247,7 +12201,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_JANSSON_FOUND=yes
else
AST_JANSSON_FOUND=no
@@ -12270,7 +12225,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${JANSSON_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "jansson.h" "ac_cv_header_jansson_h" "$ac_includes_default"
-if test "x$ac_cv_header_jansson_h" = xyes; then :
+if test "x$ac_cv_header_jansson_h" = x""yes; then :
JANSSON_HEADER_FOUND=1
else
JANSSON_HEADER_FOUND=0
@@ -12307,16 +12262,16 @@ elif test "x$CURSES_LIB" != "x" ; then
elif test "x$NCURSES_LIB" != "x" ; then
EDITLINE_LIB="$NCURSES_LIB"
else
- as_fn_error $? "*** termcap support not found (on modern systems, this typically means the ncurses development package is missing)" "$LINENO" 5
+ as_fn_error "*** termcap support not found (on modern systems, this typically means the ncurses development package is missing)" "$LINENO" 5
fi
if test "x$UUID_LIB" == "x"; then
- as_fn_error $? "*** uuid support not found (this typically means the uuid development package is missing)" "$LINENO" 5
+ as_fn_error "*** uuid support not found (this typically means the uuid development package is missing)" "$LINENO" 5
fi
if test "x$JANSSON_LIB" == "x"; then
- as_fn_error $? "*** JSON support not found (this typically means the libjansson development package is missing)" "$LINENO" 5
+ as_fn_error "*** JSON support not found (this typically means the libjansson development package is missing)" "$LINENO" 5
fi
# Another mandatory item (unless it's explicitly disabled)
@@ -12325,7 +12280,7 @@ if test "${enable_xmldoc+set}" = set; then :
enableval=$enable_xmldoc; case "${enableval}" in
y|ye|yes) disable_xmldoc=no ;;
n|no) disable_xmldoc=yes ;;
- *) as_fn_error $? "bad value ${enableval} for --disable-xmldoc" "$LINENO" 5 ;;
+ *) as_fn_error "bad value ${enableval} for --disable-xmldoc" "$LINENO" 5 ;;
esac
else
disable_xmldoc=no
@@ -12341,7 +12296,7 @@ if test "${disable_xmldoc}" != "yes"; then
set dummy ${ac_tool_prefix}xml2-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CONFIG_LIBXML2+:} false; then :
+if test "${ac_cv_path_CONFIG_LIBXML2+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CONFIG_LIBXML2 in
@@ -12356,7 +12311,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_CONFIG_LIBXML2="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -12385,7 +12340,7 @@ if test -z "$ac_cv_path_CONFIG_LIBXML2"; then
set dummy xml2-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_CONFIG_LIBXML2+:} false; then :
+if test "${ac_cv_path_ac_pt_CONFIG_LIBXML2+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_CONFIG_LIBXML2 in
@@ -12400,7 +12355,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_ac_pt_CONFIG_LIBXML2="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -12500,7 +12455,7 @@ fi
for ac_header in xlocale.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "xlocale.h" "ac_cv_header_xlocale_h" "$ac_includes_default"
-if test "x$ac_cv_header_xlocale_h" = xyes; then :
+if test "x$ac_cv_header_xlocale_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_XLOCALE_H 1
_ACEOF
@@ -12514,7 +12469,8 @@ for ac_header in winsock.h winsock2.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF
@@ -12525,7 +12481,7 @@ done
ac_fn_c_check_header_mongrel "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_poll_h" = xyes; then :
+if test "x$ac_cv_header_sys_poll_h" = x""yes; then :
else
@@ -12544,7 +12500,7 @@ if test "$enable_largefile" != no; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
$as_echo_n "checking for special C compiler options needed for large files... " >&6; }
-if ${ac_cv_sys_largefile_CC+:} false; then :
+if test "${ac_cv_sys_largefile_CC+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_cv_sys_largefile_CC=no
@@ -12595,7 +12551,7 @@ $as_echo "$ac_cv_sys_largefile_CC" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
-if ${ac_cv_sys_file_offset_bits+:} false; then :
+if test "${ac_cv_sys_file_offset_bits+set}" = set; then :
$as_echo_n "(cached) " >&6
else
while :; do
@@ -12664,7 +12620,7 @@ rm -rf conftest*
if test $ac_cv_sys_file_offset_bits = unknown; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; }
-if ${ac_cv_sys_large_files+:} false; then :
+if test "${ac_cv_sys_large_files+set}" = set; then :
$as_echo_n "(cached) " >&6
else
while :; do
@@ -12731,74 +12687,90 @@ _ACEOF
esac
rm -rf conftest*
fi
-
-
fi
# Checks for typedefs, structures, and compiler characteristics.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5
$as_echo_n "checking for stdbool.h that conforms to C99... " >&6; }
-if ${ac_cv_header_stdbool_h+:} false; then :
+if test "${ac_cv_header_stdbool_h+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
- #include <stdbool.h>
- #ifndef bool
- "error: bool is not defined"
- #endif
- #ifndef false
- "error: false is not defined"
- #endif
- #if false
- "error: false is not 0"
- #endif
- #ifndef true
- "error: true is not defined"
- #endif
- #if true != 1
- "error: true is not 1"
- #endif
- #ifndef __bool_true_false_are_defined
- "error: __bool_true_false_are_defined is not defined"
- #endif
-
- struct s { _Bool s: 1; _Bool t; } s;
-
- char a[true == 1 ? 1 : -1];
- char b[false == 0 ? 1 : -1];
- char c[__bool_true_false_are_defined == 1 ? 1 : -1];
- char d[(bool) 0.5 == true ? 1 : -1];
- /* See body of main program for 'e'. */
- char f[(_Bool) 0.0 == false ? 1 : -1];
- char g[true];
- char h[sizeof (_Bool)];
- char i[sizeof s.t];
- enum { j = false, k = true, l = false * true, m = true * 256 };
- /* The following fails for
- HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */
- _Bool n[m];
- char o[sizeof n == m * sizeof n[0] ? 1 : -1];
- char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1];
- /* Catch a bug in an HP-UX C compiler. See
- http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html
- http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html
- */
- _Bool q = true;
- _Bool *pq = &q;
-
-int
-main ()
-{
-
- bool e = &s;
- *pq |= q;
- *pq |= ! q;
- /* Refer to every declared value, to avoid compiler optimizations. */
- return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l
- + !m + !n + !o + !p + !q + !pq);
+#include <stdbool.h>
+#ifndef bool
+ "error: bool is not defined"
+#endif
+#ifndef false
+ "error: false is not defined"
+#endif
+#if false
+ "error: false is not 0"
+#endif
+#ifndef true
+ "error: true is not defined"
+#endif
+#if true != 1
+ "error: true is not 1"
+#endif
+#ifndef __bool_true_false_are_defined
+ "error: __bool_true_false_are_defined is not defined"
+#endif
+
+ struct s { _Bool s: 1; _Bool t; } s;
+
+ char a[true == 1 ? 1 : -1];
+ char b[false == 0 ? 1 : -1];
+ char c[__bool_true_false_are_defined == 1 ? 1 : -1];
+ char d[(bool) 0.5 == true ? 1 : -1];
+ bool e = &s;
+ char f[(_Bool) 0.0 == false ? 1 : -1];
+ char g[true];
+ char h[sizeof (_Bool)];
+ char i[sizeof s.t];
+ enum { j = false, k = true, l = false * true, m = true * 256 };
+ /* The following fails for
+ HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */
+ _Bool n[m];
+ char o[sizeof n == m * sizeof n[0] ? 1 : -1];
+ char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1];
+# if defined __xlc__ || defined __GNUC__
+ /* Catch a bug in IBM AIX xlc compiler version 6.0.0.0
+ reported by James Lemley on 2005-10-05; see
+ http://lists.gnu.org/archive/html/bug-coreutils/2005-10/msg00086.html
+ This test is not quite right, since xlc is allowed to
+ reject this program, as the initializer for xlcbug is
+ not one of the forms that C requires support for.
+ However, doing the test right would require a runtime
+ test, and that would make cross-compilation harder.
+ Let us hope that IBM fixes the xlc bug, and also adds
+ support for this kind of constant expression. In the
+ meantime, this test will reject xlc, which is OK, since
+ our stdbool.h substitute should suffice. We also test
+ this with GCC, where it should work, to detect more
+ quickly whether someone messes up the test in the
+ future. */
+ char digs[] = "0123456789";
+ int xlcbug = 1 / (&(digs + 5)[-2 + (bool) 1] == &digs[4] ? 1 : -1);
+# endif
+ /* Catch a bug in an HP-UX C compiler. See
+ http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html
+ http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html
+ */
+ _Bool q = true;
+ _Bool *pq = &q;
+
+int
+main ()
+{
+
+ *pq |= q;
+ *pq |= ! q;
+ /* Refer to every declared value, to avoid compiler optimizations. */
+ return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l
+ + !m + !n + !o + !p + !q + !pq);
;
return 0;
@@ -12813,8 +12785,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5
$as_echo "$ac_cv_header_stdbool_h" >&6; }
- ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default"
-if test "x$ac_cv_type__Bool" = xyes; then :
+ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default"
+if test "x$ac_cv_type__Bool" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE__BOOL 1
@@ -12823,7 +12795,6 @@ _ACEOF
fi
-
if test $ac_cv_header_stdbool_h = yes; then
$as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h
@@ -12832,7 +12803,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
-if ${ac_cv_c_const+:} false; then :
+if test "${ac_cv_c_const+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -12841,11 +12812,11 @@ else
int
main ()
{
-
+/* FIXME: Include the comments suggested by Paul. */
#ifndef __cplusplus
- /* Ultrix mips cc rejects this sort of thing. */
+ /* Ultrix mips cc rejects this. */
typedef int charset[2];
- const charset cs = { 0, 0 };
+ const charset cs;
/* SunOS 4.1.1 cc rejects this. */
char const *const *pcpcc;
char **ppc;
@@ -12862,9 +12833,8 @@ main ()
++pcpcc;
ppc = (char**) pcpcc;
pcpcc = (char const *const *) ppc;
- { /* SCO 3.2v4 cc rejects this sort of thing. */
- char tx;
- char *t = &tx;
+ { /* SCO 3.2v4 cc rejects this. */
+ char *t;
char const *s = 0 ? (char *) 0 : (char const *) 0;
*t++ = 0;
@@ -12880,10 +12850,10 @@ main ()
iptr p = 0;
++p;
}
- { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying
+ { /* AIX XL C 1.02.0.0 rejects this saying
"k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
- struct s { int j; const int *ap[3]; } bx;
- struct s *b = &bx; b->j = 5;
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
}
{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
const int foo = 10;
@@ -12913,7 +12883,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5
$as_echo_n "checking for uid_t in sys/types.h... " >&6; }
-if ${ac_cv_type_uid_t+:} false; then :
+if test "${ac_cv_type_uid_t+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -12943,7 +12913,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
$as_echo_n "checking for inline... " >&6; }
-if ${ac_cv_c_inline+:} false; then :
+if test "${ac_cv_c_inline+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_cv_c_inline=no
@@ -12986,7 +12956,7 @@ esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double with more range or precision than double" >&5
$as_echo_n "checking for long double with more range or precision than double... " >&6; }
-if ${ac_cv_type_long_double_wider+:} false; then :
+if test "${ac_cv_type_long_double_wider+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -13013,8 +12983,7 @@ static int test_array [1 - 2 * !((0 < ((DBL_MAX_EXP < LDBL_MAX_EXP)
- (LDBL_MANT_DIG < DBL_MANT_DIG)))
&& (int) LDBL_EPSILON == 0
)];
-test_array [0] = 0;
-return test_array [0];
+test_array [0] = 0
;
return 0;
@@ -13036,7 +13005,7 @@ $as_echo "#define HAVE_LONG_DOUBLE_WIDER 1" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default"
-if test "x$ac_cv_type_mode_t" = xyes; then :
+if test "x$ac_cv_type_mode_t" = x""yes; then :
else
@@ -13047,7 +13016,7 @@ _ACEOF
fi
ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default"
-if test "x$ac_cv_type_off_t" = xyes; then :
+if test "x$ac_cv_type_off_t" = x""yes; then :
else
@@ -13058,7 +13027,7 @@ _ACEOF
fi
ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default"
-if test "x$ac_cv_type_pid_t" = xyes; then :
+if test "x$ac_cv_type_pid_t" = x""yes; then :
else
@@ -13069,7 +13038,7 @@ _ACEOF
fi
ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
-if test "x$ac_cv_type_size_t" = xyes; then :
+if test "x$ac_cv_type_size_t" = x""yes; then :
else
@@ -13080,7 +13049,7 @@ _ACEOF
fi
ac_fn_c_check_member "$LINENO" "struct stat" "st_blksize" "ac_cv_member_struct_stat_st_blksize" "$ac_includes_default"
-if test "x$ac_cv_member_struct_stat_st_blksize" = xyes; then :
+if test "x$ac_cv_member_struct_stat_st_blksize" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_STAT_ST_BLKSIZE 1
@@ -13092,7 +13061,7 @@ fi
ac_fn_c_check_member "$LINENO" "struct ucred" "uid" "ac_cv_member_struct_ucred_uid" "#include <sys/types.h>
#include <sys/socket.h>
"
-if test "x$ac_cv_member_struct_ucred_uid" = xyes; then :
+if test "x$ac_cv_member_struct_ucred_uid" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_UCRED_UID 1
@@ -13103,7 +13072,7 @@ fi
ac_fn_c_check_member "$LINENO" "struct ucred" "cr_uid" "ac_cv_member_struct_ucred_cr_uid" "#include <sys/types.h>
#include <sys/socket.h>
"
-if test "x$ac_cv_member_struct_ucred_cr_uid" = xyes; then :
+if test "x$ac_cv_member_struct_ucred_cr_uid" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_UCRED_CR_UID 1
@@ -13114,7 +13083,7 @@ fi
ac_fn_c_check_member "$LINENO" "struct sockpeercred" "uid" "ac_cv_member_struct_sockpeercred_uid" "#include <sys/types.h>
#include <sys/socket.h>
"
-if test "x$ac_cv_member_struct_sockpeercred_uid" = xyes; then :
+if test "x$ac_cv_member_struct_sockpeercred_uid" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_SOCKPEERCRED_UID 1
@@ -13125,7 +13094,7 @@ fi
ac_fn_c_check_member "$LINENO" "struct ifreq" "ifr_ifru.ifru_hwaddr" "ac_cv_member_struct_ifreq_ifr_ifru_ifru_hwaddr" "#include <net/if.h>
"
-if test "x$ac_cv_member_struct_ifreq_ifr_ifru_ifru_hwaddr" = xyes; then :
+if test "x$ac_cv_member_struct_ifreq_ifr_ifru_ifru_hwaddr" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_IFREQ_IFR_IFRU_IFRU_HWADDR 1
@@ -13136,7 +13105,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5
$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; }
-if ${ac_cv_header_time+:} false; then :
+if test "${ac_cv_header_time+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -13171,7 +13140,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5
$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; }
-if ${ac_cv_struct_tm+:} false; then :
+if test "${ac_cv_struct_tm+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -13206,7 +13175,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working volatile" >&5
$as_echo_n "checking for working volatile... " >&6; }
-if ${ac_cv_c_volatile+:} false; then :
+if test "${ac_cv_c_volatile+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -13239,7 +13208,7 @@ $as_echo "#define volatile /**/" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default"
-if test "x$ac_cv_type_ptrdiff_t" = xyes; then :
+if test "x$ac_cv_type_ptrdiff_t" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_PTRDIFF_T 1
@@ -13253,7 +13222,7 @@ fi
for ac_header in unistd.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default"
-if test "x$ac_cv_header_unistd_h" = xyes; then :
+if test "x$ac_cv_header_unistd_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_UNISTD_H 1
_ACEOF
@@ -13264,7 +13233,7 @@ done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working chown" >&5
$as_echo_n "checking for working chown... " >&6; }
-if ${ac_cv_func_chown_works+:} false; then :
+if test "${ac_cv_func_chown_works+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
@@ -13317,7 +13286,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether closedir returns void" >&5
$as_echo_n "checking whether closedir returns void... " >&6; }
-if ${ac_cv_func_closedir_void+:} false; then :
+if test "${ac_cv_func_closedir_void+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
@@ -13359,7 +13328,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for error_at_line" >&5
$as_echo_n "checking for error_at_line... " >&6; }
-if ${ac_cv_lib_error_at_line+:} false; then :
+if test "${ac_cv_lib_error_at_line+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -13395,7 +13364,7 @@ fi
for ac_header in vfork.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default"
-if test "x$ac_cv_header_vfork_h" = xyes; then :
+if test "x$ac_cv_header_vfork_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_VFORK_H 1
_ACEOF
@@ -13408,7 +13377,8 @@ for ac_func in fork vfork
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+eval as_val=\$$as_ac_var
+ if test "x$as_val" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -13419,7 +13389,7 @@ done
if test "x$ac_cv_func_fork" = xyes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5
$as_echo_n "checking for working fork... " >&6; }
-if ${ac_cv_func_fork_works+:} false; then :
+if test "${ac_cv_func_fork_works+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
@@ -13472,7 +13442,7 @@ ac_cv_func_vfork_works=$ac_cv_func_vfork
if test "x$ac_cv_func_vfork" = xyes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5
$as_echo_n "checking for working vfork... " >&6; }
-if ${ac_cv_func_vfork_works+:} false; then :
+if test "${ac_cv_func_vfork_works+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
@@ -13609,7 +13579,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGEFILE_SOURCE value needed for large files" >&5
$as_echo_n "checking for _LARGEFILE_SOURCE value needed for large files... " >&6; }
-if ${ac_cv_sys_largefile_source+:} false; then :
+if test "${ac_cv_sys_largefile_source+set}" = set; then :
$as_echo_n "(cached) " >&6
else
while :; do
@@ -13678,7 +13648,7 @@ fi
if test $ac_cv_c_compiler_gnu = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5
$as_echo_n "checking whether $CC needs -traditional... " >&6; }
-if ${ac_cv_prog_gcc_traditional+:} false; then :
+if test "${ac_cv_prog_gcc_traditional+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_pattern="Autoconf.*'x'"
@@ -13723,7 +13693,7 @@ fi
# AC_FUNC_REALLOC
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working memcmp" >&5
$as_echo_n "checking for working memcmp... " >&6; }
-if ${ac_cv_func_memcmp_working+:} false; then :
+if test "${ac_cv_func_memcmp_working+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
@@ -13791,7 +13761,8 @@ do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF
@@ -13810,7 +13781,7 @@ done
for ac_func in getpagesize
do :
ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize"
-if test "x$ac_cv_func_getpagesize" = xyes; then :
+if test "x$ac_cv_func_getpagesize" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_GETPAGESIZE 1
_ACEOF
@@ -13820,7 +13791,7 @@ done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5
$as_echo_n "checking for working mmap... " >&6; }
-if ${ac_cv_func_mmap_fixed_mapped+:} false; then :
+if test "${ac_cv_func_mmap_fixed_mapped+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
@@ -13988,7 +13959,8 @@ for ac_header in sys/select.h sys/socket.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF
@@ -13999,7 +13971,7 @@ done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking types of arguments for select" >&5
$as_echo_n "checking types of arguments for select... " >&6; }
-if ${ac_cv_func_select_args+:} false; then :
+if test "${ac_cv_func_select_args+set}" = set; then :
$as_echo_n "(cached) " >&6
else
for ac_arg234 in 'fd_set *' 'int *' 'void *'; do
@@ -14033,7 +14005,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
done
# Provide a safe default value.
-: "${ac_cv_func_select_args=int,int *,struct timeval *}"
+: ${ac_cv_func_select_args='int,int *,struct timeval *'}
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_select_args" >&5
@@ -14059,7 +14031,7 @@ _ACEOF
rm -f conftest*
-if ${ac_cv_func_setvbuf_reversed+:} false; then :
+if test "${ac_cv_func_setvbuf_reversed+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_cv_func_setvbuf_reversed=no
@@ -14068,7 +14040,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5
$as_echo_n "checking return type of signal handlers... " >&6; }
-if ${ac_cv_type_signal+:} false; then :
+if test "${ac_cv_type_signal+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -14101,7 +14073,7 @@ _ACEOF
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5
$as_echo_n "checking whether lstat correctly handles trailing slash... " >&6; }
-if ${ac_cv_func_lstat_dereferences_slashed_symlink+:} false; then :
+if test "${ac_cv_func_lstat_dereferences_slashed_symlink+set}" = set; then :
$as_echo_n "(cached) " >&6
else
rm -f conftest.sym conftest.file
@@ -14163,7 +14135,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat accepts an empty string" >&5
$as_echo_n "checking whether stat accepts an empty string... " >&6; }
-if ${ac_cv_func_stat_empty_string_bug+:} false; then :
+if test "${ac_cv_func_stat_empty_string_bug+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
@@ -14209,7 +14181,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working strcoll" >&5
$as_echo_n "checking for working strcoll... " >&6; }
-if ${ac_cv_func_strcoll_works+:} false; then :
+if test "${ac_cv_func_strcoll_works+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
@@ -14249,7 +14221,7 @@ fi
for ac_func in strftime
do :
ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime"
-if test "x$ac_cv_func_strftime" = xyes; then :
+if test "x$ac_cv_func_strftime" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRFTIME 1
_ACEOF
@@ -14258,7 +14230,7 @@ else
# strftime is in -lintl on SCO UNIX.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strftime in -lintl" >&5
$as_echo_n "checking for strftime in -lintl... " >&6; }
-if ${ac_cv_lib_intl_strftime+:} false; then :
+if test "${ac_cv_lib_intl_strftime+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -14292,7 +14264,7 @@ LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_strftime" >&5
$as_echo "$ac_cv_lib_intl_strftime" >&6; }
-if test "x$ac_cv_lib_intl_strftime" = xyes; then :
+if test "x$ac_cv_lib_intl_strftime" = x""yes; then :
$as_echo "#define HAVE_STRFTIME 1" >>confdefs.h
LIBS="-lintl $LIBS"
@@ -14301,17 +14273,13 @@ fi
fi
done
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working strnlen" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working strnlen" >&5
$as_echo_n "checking for working strnlen... " >&6; }
-if ${ac_cv_func_strnlen_working+:} false; then :
+if test "${ac_cv_func_strnlen_working+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
- # Guess no on AIX systems, yes otherwise.
- case "$host_os" in
- aix*) ac_cv_func_strnlen_working=no;;
- *) ac_cv_func_strnlen_working=yes;;
- esac
+ ac_cv_func_strnlen_working=no
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -14360,7 +14328,7 @@ esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working strtod" >&5
$as_echo_n "checking for working strtod... " >&6; }
-if ${ac_cv_func_strtod+:} false; then :
+if test "${ac_cv_func_strtod+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test "$cross_compiling" = yes; then :
@@ -14419,14 +14387,14 @@ if test $ac_cv_func_strtod = no; then
esac
ac_fn_c_check_func "$LINENO" "pow" "ac_cv_func_pow"
-if test "x$ac_cv_func_pow" = xyes; then :
+if test "x$ac_cv_func_pow" = x""yes; then :
fi
if test $ac_cv_func_pow = no; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pow in -lm" >&5
$as_echo_n "checking for pow in -lm... " >&6; }
-if ${ac_cv_lib_m_pow+:} false; then :
+if test "${ac_cv_lib_m_pow+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -14460,7 +14428,7 @@ LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_pow" >&5
$as_echo "$ac_cv_lib_m_pow" >&6; }
-if test "x$ac_cv_lib_m_pow" = xyes; then :
+if test "x$ac_cv_lib_m_pow" = x""yes; then :
POW_LIB=-lm
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot find library containing definition of pow" >&5
@@ -14476,7 +14444,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether utime accepts a null argument" >&5
$as_echo_n "checking whether utime accepts a null argument... " >&6; }
-if ${ac_cv_func_utime_null+:} false; then :
+if test "${ac_cv_func_utime_null+set}" = set; then :
$as_echo_n "(cached) " >&6
else
rm -f conftest.data; >conftest.data
@@ -14526,13 +14494,13 @@ rm -f conftest.data
for ac_func in vprintf
do :
ac_fn_c_check_func "$LINENO" "vprintf" "ac_cv_func_vprintf"
-if test "x$ac_cv_func_vprintf" = xyes; then :
+if test "x$ac_cv_func_vprintf" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_VPRINTF 1
_ACEOF
ac_fn_c_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt"
-if test "x$ac_cv_func__doprnt" = xyes; then :
+if test "x$ac_cv_func__doprnt" = x""yes; then :
$as_echo "#define HAVE_DOPRNT 1" >>confdefs.h
@@ -14546,7 +14514,8 @@ for ac_func in asprintf atexit closefrom dup2 eaccess endpwent euidaccess ffsll
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+eval as_val=\$$as_ac_var
+ if test "x$as_val" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -14559,7 +14528,7 @@ done
# so that AC_CHECK_FUNCS can detect functions in that library.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrt in -lm" >&5
$as_echo_n "checking for sqrt in -lm... " >&6; }
-if ${ac_cv_lib_m_sqrt+:} false; then :
+if test "${ac_cv_lib_m_sqrt+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -14593,7 +14562,7 @@ LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrt" >&5
$as_echo "$ac_cv_lib_m_sqrt" >&6; }
-if test "x$ac_cv_lib_m_sqrt" = xyes; then :
+if test "x$ac_cv_lib_m_sqrt" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_LIBM 1
_ACEOF
@@ -14607,7 +14576,8 @@ for ac_func in exp2 log2 exp10 log10 sin cos tan asin acos atan atan2 pow rint e
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+eval as_val=\$$as_ac_var
+ if test "x$as_val" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -14623,7 +14593,8 @@ if test "x${ac_cv_type_long_double_wider}" = "xyes" ; then
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+eval as_val=\$$as_ac_var
+ if test "x$as_val" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -14724,7 +14695,7 @@ LDFLAGS=${old_LDFLAGS}
rm -f conftest.dynamics
ac_fn_c_check_header_mongrel "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_poll_h" = xyes; then :
+if test "x$ac_cv_header_sys_poll_h" = x""yes; then :
HAS_POLL=1
$as_echo "#define HAVE_SYS_POLL_H 1" >>confdefs.h
@@ -14738,7 +14709,7 @@ if test "${enable_internal_poll+set}" = set; then :
enableval=$enable_internal_poll; case "${enableval}" in
y|ye|yes) HAS_POLL="";;
n|no) HAS_POLL="${HAS_POLL}" ;;
- *) as_fn_error $? "bad value ${enableval} for --enable-internal-poll" "$LINENO" 5 ;;
+ *) as_fn_error "bad value ${enableval} for --enable-internal-poll" "$LINENO" 5 ;;
esac
fi
@@ -14749,7 +14720,7 @@ if test "${enable_asteriskssl+set}" = set; then :
enableval=$enable_asteriskssl; case "${enableval}" in
y|ye|yes) AST_ASTERISKSSL=yes ;;
n|no) AST_ASTERISKSSL=no ;;
- *) as_fn_error $? "bad value ${enableval} for --disable-asteriskssl" "$LINENO" 5 ;;
+ *) as_fn_error "bad value ${enableval} for --disable-asteriskssl" "$LINENO" 5 ;;
esac
else
AST_ASTERISKSSL=yes
@@ -14763,7 +14734,8 @@ for ac_func in funopen fopencookie
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+eval as_val=\$$as_ac_var
+ if test "x$as_val" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -14775,7 +14747,7 @@ done
for ac_func in inet_aton
do :
ac_fn_c_check_func "$LINENO" "inet_aton" "ac_cv_func_inet_aton"
-if test "x$ac_cv_func_inet_aton" = xyes; then :
+if test "x$ac_cv_func_inet_aton" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_INET_ATON 1
_ACEOF
@@ -14815,7 +14787,7 @@ rm -f core conftest.err conftest.$ac_objext \
# some systems already have gethostbyname_r so we don't need to build ours in main/utils.c
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyname_r" >&5
$as_echo_n "checking for library containing gethostbyname_r... " >&6; }
-if ${ac_cv_search_gethostbyname_r+:} false; then :
+if test "${ac_cv_search_gethostbyname_r+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
@@ -14849,11 +14821,11 @@ for ac_lib in '' socket nsl; do
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if ${ac_cv_search_gethostbyname_r+:} false; then :
+ if test "${ac_cv_search_gethostbyname_r+set}" = set; then :
break
fi
done
-if ${ac_cv_search_gethostbyname_r+:} false; then :
+if test "${ac_cv_search_gethostbyname_r+set}" = set; then :
else
ac_cv_search_gethostbyname_r=no
@@ -14927,7 +14899,7 @@ rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
ac_fn_c_check_header_mongrel "$LINENO" "byteswap.h" "ac_cv_header_byteswap_h" "$ac_includes_default"
-if test "x$ac_cv_header_byteswap_h" = xyes; then :
+if test "x$ac_cv_header_byteswap_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_BYTESWAP_H 1
@@ -15380,7 +15352,7 @@ rm -f core conftest.err conftest.$ac_objext \
for ac_header in sys/thr.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "sys/thr.h" "ac_cv_header_sys_thr_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_thr_h" = xyes; then :
+if test "x$ac_cv_header_sys_thr_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_SYS_THR_H 1
_ACEOF
@@ -15512,8 +15484,8 @@ if test "${ac_cv_have_variable_fdset}x" = "0x"; then
if test "$cross_compiling" = yes; then :
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot run test program while cross compiling
-See \`config.log' for more details" "$LINENO" 5; }
+as_fn_error "cannot run test program while cross compiling
+See \`config.log' for more details." "$LINENO" 5; }
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -16556,7 +16528,7 @@ if test "${enable_rpath+set}" = set; then :
enableval=$enable_rpath; case "${enableval}" in
y|ye|yes) check_rpath=yes ;;
n|no) check_rpath=no ;;
- *) as_fn_error $? "bad value ${enableval} for --disable-rpath" "$LINENO" 5 ;;
+ *) as_fn_error "bad value ${enableval} for --disable-rpath" "$LINENO" 5 ;;
esac
else
check_rpath=yes
@@ -16606,7 +16578,7 @@ rm -f core conftest.err conftest.$ac_objext \
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing res_9_ninit" >&5
$as_echo_n "checking for library containing res_9_ninit... " >&6; }
-if ${ac_cv_search_res_9_ninit+:} false; then :
+if test "${ac_cv_search_res_9_ninit+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
@@ -16640,11 +16612,11 @@ for ac_lib in '' resolv; do
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if ${ac_cv_search_res_9_ninit+:} false; then :
+ if test "${ac_cv_search_res_9_ninit+set}" = set; then :
break
fi
done
-if ${ac_cv_search_res_9_ninit+:} false; then :
+if test "${ac_cv_search_res_9_ninit+set}" = set; then :
else
ac_cv_search_res_9_ninit=no
@@ -16691,7 +16663,7 @@ $as_echo "#define HAVE_RES_NINIT 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing res_9_ndestroy" >&5
$as_echo_n "checking for library containing res_9_ndestroy... " >&6; }
-if ${ac_cv_search_res_9_ndestroy+:} false; then :
+if test "${ac_cv_search_res_9_ndestroy+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
@@ -16725,11 +16697,11 @@ for ac_lib in '' resolv; do
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if ${ac_cv_search_res_9_ndestroy+:} false; then :
+ if test "${ac_cv_search_res_9_ndestroy+set}" = set; then :
break
fi
done
-if ${ac_cv_search_res_9_ndestroy+:} false; then :
+if test "${ac_cv_search_res_9_ndestroy+set}" = set; then :
else
ac_cv_search_res_9_ndestroy=no
@@ -16783,7 +16755,7 @@ rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing res_9_close" >&5
$as_echo_n "checking for library containing res_9_close... " >&6; }
-if ${ac_cv_search_res_9_close+:} false; then :
+if test "${ac_cv_search_res_9_close+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
@@ -16817,11 +16789,11 @@ for ac_lib in '' resolv; do
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if ${ac_cv_search_res_9_close+:} false; then :
+ if test "${ac_cv_search_res_9_close+set}" = set; then :
break
fi
done
-if ${ac_cv_search_res_9_close+:} false; then :
+if test "${ac_cv_search_res_9_close+set}" = set; then :
else
ac_cv_search_res_9_close=no
@@ -17023,7 +16995,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_fn_c_check_header_mongrel "$LINENO" "libkern/OSAtomic.h" "ac_cv_header_libkern_OSAtomic_h" "$ac_includes_default"
-if test "x$ac_cv_header_libkern_OSAtomic_h" = xyes; then :
+if test "x$ac_cv_header_libkern_OSAtomic_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_OSX_ATOMICS 1
@@ -17039,7 +17011,7 @@ fi
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5
$as_echo_n "checking size of int... " >&6; }
-if ${ac_cv_sizeof_int+:} false; then :
+if test "${ac_cv_sizeof_int+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then :
@@ -17048,8 +17020,9 @@ else
if test "$ac_cv_type_int" = yes; then
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (int)
-See \`config.log' for more details" "$LINENO" 5; }
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (int)
+See \`config.log' for more details." "$LINENO" 5; }; }
else
ac_cv_sizeof_int=0
fi
@@ -17072,7 +17045,7 @@ _ACEOF
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5
$as_echo_n "checking size of long... " >&6; }
-if ${ac_cv_sizeof_long+:} false; then :
+if test "${ac_cv_sizeof_long+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then :
@@ -17081,8 +17054,9 @@ else
if test "$ac_cv_type_long" = yes; then
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (long)
-See \`config.log' for more details" "$LINENO" 5; }
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (long)
+See \`config.log' for more details." "$LINENO" 5; }; }
else
ac_cv_sizeof_long=0
fi
@@ -17105,7 +17079,7 @@ _ACEOF
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5
$as_echo_n "checking size of long long... " >&6; }
-if ${ac_cv_sizeof_long_long+:} false; then :
+if test "${ac_cv_sizeof_long_long+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then :
@@ -17114,8 +17088,9 @@ else
if test "$ac_cv_type_long_long" = yes; then
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (long long)
-See \`config.log' for more details" "$LINENO" 5; }
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (long long)
+See \`config.log' for more details." "$LINENO" 5; }; }
else
ac_cv_sizeof_long_long=0
fi
@@ -17138,7 +17113,7 @@ _ACEOF
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of char *" >&5
$as_echo_n "checking size of char *... " >&6; }
-if ${ac_cv_sizeof_char_p+:} false; then :
+if test "${ac_cv_sizeof_char_p+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char *))" "ac_cv_sizeof_char_p" "$ac_includes_default"; then :
@@ -17147,8 +17122,9 @@ else
if test "$ac_cv_type_char_p" = yes; then
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (char *)
-See \`config.log' for more details" "$LINENO" 5; }
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (char *)
+See \`config.log' for more details." "$LINENO" 5; }; }
else
ac_cv_sizeof_char_p=0
fi
@@ -17171,7 +17147,7 @@ _ACEOF
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5
$as_echo_n "checking size of long... " >&6; }
-if ${ac_cv_sizeof_long+:} false; then :
+if test "${ac_cv_sizeof_long+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then :
@@ -17180,8 +17156,9 @@ else
if test "$ac_cv_type_long" = yes; then
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (long)
-See \`config.log' for more details" "$LINENO" 5; }
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (long)
+See \`config.log' for more details." "$LINENO" 5; }; }
else
ac_cv_sizeof_long=0
fi
@@ -17204,7 +17181,7 @@ _ACEOF
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5
$as_echo_n "checking size of long long... " >&6; }
-if ${ac_cv_sizeof_long_long+:} false; then :
+if test "${ac_cv_sizeof_long_long+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then :
@@ -17213,8 +17190,9 @@ else
if test "$ac_cv_type_long_long" = yes; then
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (long long)
-See \`config.log' for more details" "$LINENO" 5; }
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (long long)
+See \`config.log' for more details." "$LINENO" 5; }; }
else
ac_cv_sizeof_long_long=0
fi
@@ -17244,7 +17222,7 @@ fi
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of fd_set.fds_bits" >&5
$as_echo_n "checking size of fd_set.fds_bits... " >&6; }
-if ${ac_cv_sizeof_fd_set_fds_bits+:} false; then :
+if test "${ac_cv_sizeof_fd_set_fds_bits+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (fd_set.fds_bits))" "ac_cv_sizeof_fd_set_fds_bits" "$ac_includes_default"; then :
@@ -17253,8 +17231,9 @@ else
if test "$ac_cv_type_fd_set_fds_bits" = yes; then
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (fd_set.fds_bits)
-See \`config.log' for more details" "$LINENO" 5; }
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (fd_set.fds_bits)
+See \`config.log' for more details." "$LINENO" 5; }; }
else
ac_cv_sizeof_fd_set_fds_bits=0
fi
@@ -17327,18 +17306,13 @@ LIBS=${old_LIBS}
# PKGCONFIG is used in later tests
-
-
-
-
-
if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PKG_CONFIG+:} false; then :
+if test "${ac_cv_path_PKG_CONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $PKG_CONFIG in
@@ -17352,7 +17326,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -17381,7 +17355,7 @@ if test -z "$ac_cv_path_PKG_CONFIG"; then
set dummy pkg-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_PKG_CONFIG in
@@ -17395,7 +17369,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -17444,6 +17418,7 @@ $as_echo "yes" >&6; }
$as_echo "no" >&6; }
PKG_CONFIG=""
fi
+
fi
@@ -17469,7 +17444,7 @@ if test "x${PBX_ALSA}" != "x1" -a "${USE_ALSA}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_asound_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lasound" >&5
$as_echo_n "checking for ${pbxfuncname} in -lasound... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -17504,7 +17479,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_ALSA_FOUND=yes
else
AST_ALSA_FOUND=no
@@ -17527,7 +17503,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${ALSA_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "alsa/asoundlib.h" "ac_cv_header_alsa_asoundlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_alsa_asoundlib_h" = xyes; then :
+if test "x$ac_cv_header_alsa_asoundlib_h" = x""yes; then :
ALSA_HEADER_FOUND=1
else
ALSA_HEADER_FOUND=0
@@ -17574,7 +17550,7 @@ if test "x${PBX_BFD}" != "x1" -a "${USE_BFD}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_bfd_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lbfd" >&5
$as_echo_n "checking for ${pbxfuncname} in -lbfd... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -17609,7 +17585,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_BFD_FOUND=yes
else
AST_BFD_FOUND=no
@@ -17632,7 +17609,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${BFD_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "bfd.h" "ac_cv_header_bfd_h" "$ac_includes_default"
-if test "x$ac_cv_header_bfd_h" = xyes; then :
+if test "x$ac_cv_header_bfd_h" = x""yes; then :
BFD_HEADER_FOUND=1
else
BFD_HEADER_FOUND=0
@@ -17681,7 +17658,7 @@ if test "x${PBX_BFD}" != "x1" -a "${USE_BFD}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_bfd_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lbfd" >&5
$as_echo_n "checking for ${pbxfuncname} in -lbfd... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -17716,7 +17693,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_BFD_FOUND=yes
else
AST_BFD_FOUND=no
@@ -17739,7 +17717,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${BFD_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "bfd.h" "ac_cv_header_bfd_h" "$ac_includes_default"
-if test "x$ac_cv_header_bfd_h" = xyes; then :
+if test "x$ac_cv_header_bfd_h" = x""yes; then :
BFD_HEADER_FOUND=1
else
BFD_HEADER_FOUND=0
@@ -17788,7 +17766,7 @@ if test "x${PBX_CAP}" != "x1" -a "${USE_CAP}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_cap_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lcap" >&5
$as_echo_n "checking for ${pbxfuncname} in -lcap... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -17823,7 +17801,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_CAP_FOUND=yes
else
AST_CAP_FOUND=no
@@ -17846,7 +17825,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${CAP_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sys/capability.h" "ac_cv_header_sys_capability_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_capability_h" = xyes; then :
+if test "x$ac_cv_header_sys_capability_h" = x""yes; then :
CAP_HEADER_FOUND=1
else
CAP_HEADER_FOUND=0
@@ -18269,7 +18248,7 @@ if test "${USE_GSM}" != "no"; then
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gsm_create in -lgsm" >&5
$as_echo_n "checking for gsm_create in -lgsm... " >&6; }
-if ${ac_cv_lib_gsm_gsm_create+:} false; then :
+if test "${ac_cv_lib_gsm_gsm_create+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -18303,7 +18282,7 @@ LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gsm_gsm_create" >&5
$as_echo "$ac_cv_lib_gsm_gsm_create" >&6; }
-if test "x$ac_cv_lib_gsm_gsm_create" = xyes; then :
+if test "x$ac_cv_lib_gsm_gsm_create" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_GSM 1
@@ -18315,7 +18294,8 @@ fi
if test "x${GSM_DIR}" != "x" ; then
as_ac_Header=`$as_echo "ac_cv_header_${GSM_DIR}/include/gsm.h" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "${GSM_DIR}/include/gsm.h" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
GSM_HEADER_FOUND=1
else
GSM_HEADER_FOUND=0
@@ -18324,7 +18304,8 @@ fi
as_ac_Header=`$as_echo "ac_cv_header_${GSM_DIR}/include/gsm/gsm.h" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "${GSM_DIR}/include/gsm/gsm.h" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
GSM_GSM_HEADER_FOUND=1
else
GSM_GSM_HEADER_FOUND=0
@@ -18333,7 +18314,7 @@ fi
else
ac_fn_c_check_header_mongrel "$LINENO" "gsm.h" "ac_cv_header_gsm_h" "$ac_includes_default"
-if test "x$ac_cv_header_gsm_h" = xyes; then :
+if test "x$ac_cv_header_gsm_h" = x""yes; then :
GSM_HEADER_FOUND=1
else
GSM_HEADER_FOUND=0
@@ -18341,7 +18322,7 @@ fi
ac_fn_c_check_header_mongrel "$LINENO" "gsm/gsm.h" "ac_cv_header_gsm_gsm_h" "$ac_includes_default"
-if test "x$ac_cv_header_gsm_gsm_h" = xyes; then :
+if test "x$ac_cv_header_gsm_gsm_h" = x""yes; then :
GSM_GSM_HEADER_FOUND=1
else
GSM_GSM_HEADER_FOUND=0
@@ -18420,46 +18401,46 @@ pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ILBC" >&5
$as_echo_n "checking for ILBC... " >&6; }
-if test -n "$ILBC_CFLAGS"; then
- pkg_cv_ILBC_CFLAGS="$ILBC_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
- if test -n "$PKG_CONFIG" && \
+if test -n "$PKG_CONFIG"; then
+ if test -n "$ILBC_CFLAGS"; then
+ pkg_cv_ILBC_CFLAGS="$ILBC_CFLAGS"
+ else
+ if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libilbc\""; } >&5
($PKG_CONFIG --exists --print-errors "libilbc") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_ILBC_CFLAGS=`$PKG_CONFIG --cflags "libilbc" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
- else
- pkg_failed=untried
+ fi
+else
+ pkg_failed=untried
fi
-if test -n "$ILBC_LIBS"; then
- pkg_cv_ILBC_LIBS="$ILBC_LIBS"
- elif test -n "$PKG_CONFIG"; then
- if test -n "$PKG_CONFIG" && \
+if test -n "$PKG_CONFIG"; then
+ if test -n "$ILBC_LIBS"; then
+ pkg_cv_ILBC_LIBS="$ILBC_LIBS"
+ else
+ if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libilbc\""; } >&5
($PKG_CONFIG --exists --print-errors "libilbc") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_ILBC_LIBS=`$PKG_CONFIG --libs "libilbc" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
- else
- pkg_failed=untried
+ fi
+else
+ pkg_failed=untried
fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -18467,20 +18448,20 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- ILBC_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libilbc" 2>&1`
+ ILBC_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "libilbc"`
else
- ILBC_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libilbc" 2>&1`
+ ILBC_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "libilbc"`
fi
# Put the nasty error message in config.log where it belongs
echo "$ILBC_PKG_ERRORS" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
PBX_ILBC=0
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
PBX_ILBC=0
@@ -18527,46 +18508,46 @@ pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBEDIT" >&5
$as_echo_n "checking for LIBEDIT... " >&6; }
-if test -n "$LIBEDIT_CFLAGS"; then
- pkg_cv_LIBEDIT_CFLAGS="$LIBEDIT_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
- if test -n "$PKG_CONFIG" && \
+if test -n "$PKG_CONFIG"; then
+ if test -n "$LIBEDIT_CFLAGS"; then
+ pkg_cv_LIBEDIT_CFLAGS="$LIBEDIT_CFLAGS"
+ else
+ if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedit\""; } >&5
($PKG_CONFIG --exists --print-errors "libedit") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LIBEDIT_CFLAGS=`$PKG_CONFIG --cflags "libedit" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
- else
- pkg_failed=untried
+ fi
+else
+ pkg_failed=untried
fi
-if test -n "$LIBEDIT_LIBS"; then
- pkg_cv_LIBEDIT_LIBS="$LIBEDIT_LIBS"
- elif test -n "$PKG_CONFIG"; then
- if test -n "$PKG_CONFIG" && \
+if test -n "$PKG_CONFIG"; then
+ if test -n "$LIBEDIT_LIBS"; then
+ pkg_cv_LIBEDIT_LIBS="$LIBEDIT_LIBS"
+ else
+ if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedit\""; } >&5
($PKG_CONFIG --exists --print-errors "libedit") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_LIBEDIT_LIBS=`$PKG_CONFIG --libs "libedit" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
- else
- pkg_failed=untried
+ fi
+else
+ pkg_failed=untried
fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -18574,20 +18555,20 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LIBEDIT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libedit" 2>&1`
+ LIBEDIT_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "libedit"`
else
- LIBEDIT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libedit" 2>&1`
+ LIBEDIT_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "libedit"`
fi
# Put the nasty error message in config.log where it belongs
echo "$LIBEDIT_PKG_ERRORS" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
PBX_LIBEDIT=0
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
PBX_LIBEDIT=0
@@ -18637,7 +18618,7 @@ if test "x${PBX_ICONV}" != "x1" -a "${USE_ICONV}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_iconv_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -liconv" >&5
$as_echo_n "checking for ${pbxfuncname} in -liconv... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -18672,7 +18653,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_ICONV_FOUND=yes
else
AST_ICONV_FOUND=no
@@ -18695,7 +18677,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${ICONV_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "iconv.h" "ac_cv_header_iconv_h" "$ac_includes_default"
-if test "x$ac_cv_header_iconv_h" = xyes; then :
+if test "x$ac_cv_header_iconv_h" = x""yes; then :
ICONV_HEADER_FOUND=1
else
ICONV_HEADER_FOUND=0
@@ -18742,7 +18724,7 @@ if test "x${PBX_ICONV}" != "x1" -a "${USE_ICONV}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_iconv_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -liconv" >&5
$as_echo_n "checking for ${pbxfuncname} in -liconv... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -18777,7 +18759,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_ICONV_FOUND=yes
else
AST_ICONV_FOUND=no
@@ -18800,7 +18783,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${ICONV_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "iconv.h" "ac_cv_header_iconv_h" "$ac_includes_default"
-if test "x$ac_cv_header_iconv_h" = xyes; then :
+if test "x$ac_cv_header_iconv_h" = x""yes; then :
ICONV_HEADER_FOUND=1
else
ICONV_HEADER_FOUND=0
@@ -18847,7 +18830,7 @@ if test "x${PBX_ICONV}" != "x1" -a "${USE_ICONV}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_c_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lc" >&5
$as_echo_n "checking for ${pbxfuncname} in -lc... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -18882,7 +18865,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_ICONV_FOUND=yes
else
AST_ICONV_FOUND=no
@@ -18905,7 +18889,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${ICONV_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "iconv.h" "ac_cv_header_iconv_h" "$ac_includes_default"
-if test "x$ac_cv_header_iconv_h" = xyes; then :
+if test "x$ac_cv_header_iconv_h" = x""yes; then :
ICONV_HEADER_FOUND=1
else
ICONV_HEADER_FOUND=0
@@ -18953,7 +18937,7 @@ if test "x${PBX_ICAL}" != "x1" -a "${USE_ICAL}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_ical_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lical" >&5
$as_echo_n "checking for ${pbxfuncname} in -lical... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -18988,7 +18972,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_ICAL_FOUND=yes
else
AST_ICAL_FOUND=no
@@ -19011,7 +18996,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${ICAL_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libical/ical.h" "ac_cv_header_libical_ical_h" "$ac_includes_default"
-if test "x$ac_cv_header_libical_ical_h" = xyes; then :
+if test "x$ac_cv_header_libical_ical_h" = x""yes; then :
ICAL_HEADER_FOUND=1
else
ICAL_HEADER_FOUND=0
@@ -19058,7 +19043,7 @@ if test "x${PBX_IKSEMEL}" != "x1" -a "${USE_IKSEMEL}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_iksemel_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -liksemel" >&5
$as_echo_n "checking for ${pbxfuncname} in -liksemel... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -19093,7 +19078,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_IKSEMEL_FOUND=yes
else
AST_IKSEMEL_FOUND=no
@@ -19116,7 +19102,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${IKSEMEL_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "iksemel.h" "ac_cv_header_iksemel_h" "$ac_includes_default"
-if test "x$ac_cv_header_iksemel_h" = xyes; then :
+if test "x$ac_cv_header_iksemel_h" = x""yes; then :
IKSEMEL_HEADER_FOUND=1
else
IKSEMEL_HEADER_FOUND=0
@@ -19791,7 +19777,7 @@ if test "x${PBX_IODBC}" != "x1" -a "${USE_IODBC}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_iodbc_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -liodbc" >&5
$as_echo_n "checking for ${pbxfuncname} in -liodbc... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -19826,7 +19812,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_IODBC_FOUND=yes
else
AST_IODBC_FOUND=no
@@ -19849,7 +19836,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${IODBC_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sql.h" "ac_cv_header_sql_h" "$ac_includes_default"
-if test "x$ac_cv_header_sql_h" = xyes; then :
+if test "x$ac_cv_header_sql_h" = x""yes; then :
IODBC_HEADER_FOUND=1
else
IODBC_HEADER_FOUND=0
@@ -19896,7 +19883,7 @@ if test "x${PBX_INOTIFY}" != "x1" -a "${USE_INOTIFY}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_c_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lc" >&5
$as_echo_n "checking for ${pbxfuncname} in -lc... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -19931,7 +19918,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_INOTIFY_FOUND=yes
else
AST_INOTIFY_FOUND=no
@@ -19954,7 +19942,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${INOTIFY_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sys/inotify.h" "ac_cv_header_sys_inotify_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_inotify_h" = xyes; then :
+if test "x$ac_cv_header_sys_inotify_h" = x""yes; then :
INOTIFY_HEADER_FOUND=1
else
INOTIFY_HEADER_FOUND=0
@@ -20001,7 +19989,7 @@ if test "x${PBX_JACK}" != "x1" -a "${USE_JACK}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_jack_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -ljack" >&5
$as_echo_n "checking for ${pbxfuncname} in -ljack... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -20036,7 +20024,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_JACK_FOUND=yes
else
AST_JACK_FOUND=no
@@ -20059,7 +20048,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${JACK_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "jack/jack.h" "ac_cv_header_jack_jack_h" "$ac_includes_default"
-if test "x$ac_cv_header_jack_jack_h" = xyes; then :
+if test "x$ac_cv_header_jack_jack_h" = x""yes; then :
JACK_HEADER_FOUND=1
else
JACK_HEADER_FOUND=0
@@ -20107,7 +20096,7 @@ if test "x${PBX_KQUEUE}" != "x1" -a "${USE_KQUEUE}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_c_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lc" >&5
$as_echo_n "checking for ${pbxfuncname} in -lc... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -20142,7 +20131,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_KQUEUE_FOUND=yes
else
AST_KQUEUE_FOUND=no
@@ -20165,7 +20155,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${KQUEUE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sys/event.h" "ac_cv_header_sys_event_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_event_h" = xyes; then :
+if test "x$ac_cv_header_sys_event_h" = x""yes; then :
KQUEUE_HEADER_FOUND=1
else
KQUEUE_HEADER_FOUND=0
@@ -20196,7 +20186,7 @@ fi
for ac_func in kevent64
do :
ac_fn_c_check_func "$LINENO" "kevent64" "ac_cv_func_kevent64"
-if test "x$ac_cv_func_kevent64" = xyes; then :
+if test "x$ac_cv_func_kevent64" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_KEVENT64 1
_ACEOF
@@ -20226,7 +20216,7 @@ if test "x${PBX_LTDL}" != "x1" -a "${USE_LTDL}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_ltdl_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lltdl" >&5
$as_echo_n "checking for ${pbxfuncname} in -lltdl... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -20261,7 +20251,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_LTDL_FOUND=yes
else
AST_LTDL_FOUND=no
@@ -20284,7 +20275,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${LTDL_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "ltdl.h" "ac_cv_header_ltdl_h" "$ac_includes_default"
-if test "x$ac_cv_header_ltdl_h" = xyes; then :
+if test "x$ac_cv_header_ltdl_h" = x""yes; then :
LTDL_HEADER_FOUND=1
else
LTDL_HEADER_FOUND=0
@@ -20331,7 +20322,7 @@ if test "x${PBX_LDAP}" != "x1" -a "${USE_LDAP}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_ldap_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lldap" >&5
$as_echo_n "checking for ${pbxfuncname} in -lldap... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -20366,7 +20357,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_LDAP_FOUND=yes
else
AST_LDAP_FOUND=no
@@ -20389,7 +20381,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${LDAP_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "ldap.h" "ac_cv_header_ldap_h" "$ac_includes_default"
-if test "x$ac_cv_header_ldap_h" = xyes; then :
+if test "x$ac_cv_header_ldap_h" = x""yes; then :
LDAP_HEADER_FOUND=1
else
LDAP_HEADER_FOUND=0
@@ -20436,7 +20428,7 @@ if test "x${PBX_MISDN}" != "x1" -a "${USE_MISDN}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_mISDN_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lmISDN" >&5
$as_echo_n "checking for ${pbxfuncname} in -lmISDN... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -20471,7 +20463,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_MISDN_FOUND=yes
else
AST_MISDN_FOUND=no
@@ -20494,7 +20487,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${MISDN_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "mISDNuser/mISDNlib.h" "ac_cv_header_mISDNuser_mISDNlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_mISDNuser_mISDNlib_h" = xyes; then :
+if test "x$ac_cv_header_mISDNuser_mISDNlib_h" = x""yes; then :
MISDN_HEADER_FOUND=1
else
MISDN_HEADER_FOUND=0
@@ -20542,7 +20535,7 @@ if test "x${PBX_ISDNNET}" != "x1" -a "${USE_ISDNNET}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_isdnnet_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lisdnnet" >&5
$as_echo_n "checking for ${pbxfuncname} in -lisdnnet... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -20577,7 +20570,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_ISDNNET_FOUND=yes
else
AST_ISDNNET_FOUND=no
@@ -20600,7 +20594,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${ISDNNET_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "mISDNuser/isdn_net.h" "ac_cv_header_mISDNuser_isdn_net_h" "$ac_includes_default"
-if test "x$ac_cv_header_mISDNuser_isdn_net_h" = xyes; then :
+if test "x$ac_cv_header_mISDNuser_isdn_net_h" = x""yes; then :
ISDNNET_HEADER_FOUND=1
else
ISDNNET_HEADER_FOUND=0
@@ -20646,7 +20640,7 @@ if test "x${PBX_SUPPSERV}" != "x1" -a "${USE_SUPPSERV}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_suppserv_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsuppserv" >&5
$as_echo_n "checking for ${pbxfuncname} in -lsuppserv... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -20681,7 +20675,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_SUPPSERV_FOUND=yes
else
AST_SUPPSERV_FOUND=no
@@ -20704,7 +20699,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SUPPSERV_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "mISDNuser/suppserv.h" "ac_cv_header_mISDNuser_suppserv_h" "$ac_includes_default"
-if test "x$ac_cv_header_mISDNuser_suppserv_h" = xyes; then :
+if test "x$ac_cv_header_mISDNuser_suppserv_h" = x""yes; then :
SUPPSERV_HEADER_FOUND=1
else
SUPPSERV_HEADER_FOUND=0
@@ -20823,7 +20818,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_fn_c_check_header_mongrel "$LINENO" "linux/mISDNdsp.h" "ac_cv_header_linux_mISDNdsp_h" "$ac_includes_default"
-if test "x$ac_cv_header_linux_mISDNdsp_h" = xyes; then :
+if test "x$ac_cv_header_linux_mISDNdsp_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define MISDN_1_2 1
@@ -20834,7 +20829,7 @@ fi
ac_fn_c_check_member "$LINENO" "Q931_info_t" "redirect_dn" "ac_cv_member_Q931_info_t_redirect_dn" "#include <mISDNuser/mISDNlib.h>
"
-if test "x$ac_cv_member_Q931_info_t_redirect_dn" = xyes; then :
+if test "x$ac_cv_member_Q931_info_t_redirect_dn" = x""yes; then :
else
PBX_MISDN=0
@@ -20850,7 +20845,7 @@ fi
set dummy ${ac_tool_prefix}mysql_config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CONFIG_MYSQLCLIENT+:} false; then :
+if test "${ac_cv_path_CONFIG_MYSQLCLIENT+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CONFIG_MYSQLCLIENT in
@@ -20865,7 +20860,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_CONFIG_MYSQLCLIENT="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -20894,7 +20889,7 @@ if test -z "$ac_cv_path_CONFIG_MYSQLCLIENT"; then
set dummy mysql_config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_CONFIG_MYSQLCLIENT+:} false; then :
+if test "${ac_cv_path_ac_pt_CONFIG_MYSQLCLIENT+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_CONFIG_MYSQLCLIENT in
@@ -20909,7 +20904,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_ac_pt_CONFIG_MYSQLCLIENT="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -21013,7 +21008,7 @@ if test "x${PBX_NBS}" != "x1" -a "${USE_NBS}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_nbs_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lnbs" >&5
$as_echo_n "checking for ${pbxfuncname} in -lnbs... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -21048,7 +21043,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_NBS_FOUND=yes
else
AST_NBS_FOUND=no
@@ -21071,7 +21067,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${NBS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "nbs.h" "ac_cv_header_nbs_h" "$ac_includes_default"
-if test "x$ac_cv_header_nbs_h" = xyes; then :
+if test "x$ac_cv_header_nbs_h" = x""yes; then :
NBS_HEADER_FOUND=1
else
NBS_HEADER_FOUND=0
@@ -21106,7 +21102,7 @@ fi
set dummy ${ac_tool_prefix}neon-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CONFIG_NEON+:} false; then :
+if test "${ac_cv_path_CONFIG_NEON+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CONFIG_NEON in
@@ -21121,7 +21117,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_CONFIG_NEON="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -21150,7 +21146,7 @@ if test -z "$ac_cv_path_CONFIG_NEON"; then
set dummy neon-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_CONFIG_NEON+:} false; then :
+if test "${ac_cv_path_ac_pt_CONFIG_NEON+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_CONFIG_NEON in
@@ -21165,7 +21161,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_ac_pt_CONFIG_NEON="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -21257,7 +21253,7 @@ $as_echo "#define HAVE_NEON 1" >>confdefs.h
set dummy ${ac_tool_prefix}neon-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CONFIG_NEON29+:} false; then :
+if test "${ac_cv_path_CONFIG_NEON29+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CONFIG_NEON29 in
@@ -21272,7 +21268,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_CONFIG_NEON29="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -21301,7 +21297,7 @@ if test -z "$ac_cv_path_CONFIG_NEON29"; then
set dummy neon-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_CONFIG_NEON29+:} false; then :
+if test "${ac_cv_path_ac_pt_CONFIG_NEON29+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_CONFIG_NEON29 in
@@ -21316,7 +21312,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_ac_pt_CONFIG_NEON29="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -21410,7 +21406,7 @@ $as_echo "#define HAVE_NEON29 1" >>confdefs.h
set dummy ${ac_tool_prefix}net-snmp-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CONFIG_NETSNMP+:} false; then :
+if test "${ac_cv_path_CONFIG_NETSNMP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CONFIG_NETSNMP in
@@ -21425,7 +21421,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_CONFIG_NETSNMP="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -21454,7 +21450,7 @@ if test -z "$ac_cv_path_CONFIG_NETSNMP"; then
set dummy net-snmp-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_CONFIG_NETSNMP+:} false; then :
+if test "${ac_cv_path_ac_pt_CONFIG_NETSNMP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_CONFIG_NETSNMP in
@@ -21469,7 +21465,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_ac_pt_CONFIG_NETSNMP="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -21577,7 +21573,7 @@ if test "x${PBX_NEWT}" != "x1" -a "${USE_NEWT}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_newt_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lnewt" >&5
$as_echo_n "checking for ${pbxfuncname} in -lnewt... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -21612,7 +21608,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_NEWT_FOUND=yes
else
AST_NEWT_FOUND=no
@@ -21635,7 +21632,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${NEWT_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "newt.h" "ac_cv_header_newt_h" "$ac_includes_default"
-if test "x$ac_cv_header_newt_h" = xyes; then :
+if test "x$ac_cv_header_newt_h" = x""yes; then :
NEWT_HEADER_FOUND=1
else
NEWT_HEADER_FOUND=0
@@ -21682,7 +21679,7 @@ if test "x${PBX_UNIXODBC}" != "x1" -a "${USE_UNIXODBC}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_odbc_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lodbc" >&5
$as_echo_n "checking for ${pbxfuncname} in -lodbc... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -21717,7 +21714,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_UNIXODBC_FOUND=yes
else
AST_UNIXODBC_FOUND=no
@@ -21740,7 +21738,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${UNIXODBC_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sql.h" "ac_cv_header_sql_h" "$ac_includes_default"
-if test "x$ac_cv_header_sql_h" = xyes; then :
+if test "x$ac_cv_header_sql_h" = x""yes; then :
UNIXODBC_HEADER_FOUND=1
else
UNIXODBC_HEADER_FOUND=0
@@ -21787,7 +21785,7 @@ if test "x${PBX_OGG}" != "x1" -a "${USE_OGG}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_ogg_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -logg" >&5
$as_echo_n "checking for ${pbxfuncname} in -logg... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -21822,7 +21820,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_OGG_FOUND=yes
else
AST_OGG_FOUND=no
@@ -21845,7 +21844,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${OGG_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default"
-if test "x$ac_cv_header_" = xyes; then :
+if test "x$ac_cv_header_" = x""yes; then :
OGG_HEADER_FOUND=1
else
OGG_HEADER_FOUND=0
@@ -21893,7 +21892,7 @@ if test "x${PBX_BKTR}" != "x1" -a "${USE_BKTR}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_execinfo_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lexecinfo" >&5
$as_echo_n "checking for ${pbxfuncname} in -lexecinfo... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -21928,7 +21927,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_BKTR_FOUND=yes
else
AST_BKTR_FOUND=no
@@ -21951,7 +21951,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${BKTR_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default"
-if test "x$ac_cv_header_execinfo_h" = xyes; then :
+if test "x$ac_cv_header_execinfo_h" = x""yes; then :
BKTR_HEADER_FOUND=1
else
BKTR_HEADER_FOUND=0
@@ -21998,7 +21998,7 @@ if test "x${PBX_BKTR}" != "x1" -a "${USE_BKTR}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_c_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lc" >&5
$as_echo_n "checking for ${pbxfuncname} in -lc... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -22033,7 +22033,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_BKTR_FOUND=yes
else
AST_BKTR_FOUND=no
@@ -22056,7 +22057,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${BKTR_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default"
-if test "x$ac_cv_header_execinfo_h" = xyes; then :
+if test "x$ac_cv_header_execinfo_h" = x""yes; then :
BKTR_HEADER_FOUND=1
else
BKTR_HEADER_FOUND=0
@@ -22103,7 +22104,7 @@ if test "x${PBX_BLUETOOTH}" != "x1" -a "${USE_BLUETOOTH}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_bluetooth_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lbluetooth" >&5
$as_echo_n "checking for ${pbxfuncname} in -lbluetooth... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -22138,7 +22139,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_BLUETOOTH_FOUND=yes
else
AST_BLUETOOTH_FOUND=no
@@ -22161,7 +22163,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${BLUETOOTH_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "bluetooth/bluetooth.h" "ac_cv_header_bluetooth_bluetooth_h" "$ac_includes_default"
-if test "x$ac_cv_header_bluetooth_bluetooth_h" = xyes; then :
+if test "x$ac_cv_header_bluetooth_bluetooth_h" = x""yes; then :
BLUETOOTH_HEADER_FOUND=1
else
BLUETOOTH_HEADER_FOUND=0
@@ -22209,7 +22211,7 @@ if test "x${PBX_OSS}" != "x1" -a "${USE_OSS}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_ossaudio_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lossaudio" >&5
$as_echo_n "checking for ${pbxfuncname} in -lossaudio... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -22244,7 +22246,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_OSS_FOUND=yes
else
AST_OSS_FOUND=no
@@ -22267,7 +22270,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${OSS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "linux/soundcard.h" "ac_cv_header_linux_soundcard_h" "$ac_includes_default"
-if test "x$ac_cv_header_linux_soundcard_h" = xyes; then :
+if test "x$ac_cv_header_linux_soundcard_h" = x""yes; then :
OSS_HEADER_FOUND=1
else
OSS_HEADER_FOUND=0
@@ -22313,7 +22316,7 @@ if test "x${PBX_OSS}" != "x1" -a "${USE_OSS}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_ossaudio_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lossaudio" >&5
$as_echo_n "checking for ${pbxfuncname} in -lossaudio... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -22348,7 +22351,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_OSS_FOUND=yes
else
AST_OSS_FOUND=no
@@ -22371,7 +22375,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${OSS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sys/soundcard.h" "ac_cv_header_sys_soundcard_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_soundcard_h" = xyes; then :
+if test "x$ac_cv_header_sys_soundcard_h" = x""yes; then :
OSS_HEADER_FOUND=1
else
OSS_HEADER_FOUND=0
@@ -22417,7 +22421,7 @@ if test "x${PBX_OSS}" != "x1" -a "${USE_OSS}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_ossaudio_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lossaudio" >&5
$as_echo_n "checking for ${pbxfuncname} in -lossaudio... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -22452,7 +22456,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_OSS_FOUND=yes
else
AST_OSS_FOUND=no
@@ -22475,7 +22480,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${OSS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "soundcard.h" "ac_cv_header_soundcard_h" "$ac_includes_default"
-if test "x$ac_cv_header_soundcard_h" = xyes; then :
+if test "x$ac_cv_header_soundcard_h" = x""yes; then :
OSS_HEADER_FOUND=1
else
OSS_HEADER_FOUND=0
@@ -22510,7 +22515,7 @@ if test "${USE_PGSQL}" != "no"; then
set dummy ${ac_tool_prefix}pg_config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PG_CONFIG+:} false; then :
+if test "${ac_cv_path_PG_CONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $PG_CONFIG in
@@ -22524,7 +22529,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_PG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -22553,7 +22558,7 @@ if test -z "$ac_cv_path_PG_CONFIG"; then
set dummy pg_config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_PG_CONFIG+:} false; then :
+if test "${ac_cv_path_ac_pt_PG_CONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_PG_CONFIG in
@@ -22567,7 +22572,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_ac_pt_PG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -22622,7 +22627,7 @@ $as_echo "$as_me: *** including --without-postgres" >&6;}
set dummy ${ac_tool_prefix}pg_config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PG_CONFIG+:} false; then :
+if test "${ac_cv_path_PG_CONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $PG_CONFIG in
@@ -22636,7 +22641,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_PG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -22665,7 +22670,7 @@ if test -z "$ac_cv_path_PG_CONFIG"; then
set dummy pg_config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_PG_CONFIG+:} false; then :
+if test "${ac_cv_path_ac_pt_PG_CONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_PG_CONFIG in
@@ -22679,7 +22684,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_ac_pt_PG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -22735,7 +22740,7 @@ $as_echo "$as_me: *** including --without-postgres" >&6;}
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PQescapeStringConn in -lpq" >&5
$as_echo_n "checking for PQescapeStringConn in -lpq... " >&6; }
-if ${ac_cv_lib_pq_PQescapeStringConn+:} false; then :
+if test "${ac_cv_lib_pq_PQescapeStringConn+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -22769,7 +22774,7 @@ LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pq_PQescapeStringConn" >&5
$as_echo "$ac_cv_lib_pq_PQescapeStringConn" >&6; }
-if test "x$ac_cv_lib_pq_PQescapeStringConn" = xyes; then :
+if test "x$ac_cv_lib_pq_PQescapeStringConn" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_PGSQL 1
@@ -22838,46 +22843,46 @@ pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PJPROJECT" >&5
$as_echo_n "checking for PJPROJECT... " >&6; }
-if test -n "$PJPROJECT_CFLAGS"; then
- pkg_cv_PJPROJECT_CFLAGS="$PJPROJECT_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
- if test -n "$PKG_CONFIG" && \
+if test -n "$PKG_CONFIG"; then
+ if test -n "$PJPROJECT_CFLAGS"; then
+ pkg_cv_PJPROJECT_CFLAGS="$PJPROJECT_CFLAGS"
+ else
+ if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpjproject\""; } >&5
($PKG_CONFIG --exists --print-errors "libpjproject") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_PJPROJECT_CFLAGS=`$PKG_CONFIG --cflags "libpjproject" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
- else
- pkg_failed=untried
+ fi
+else
+ pkg_failed=untried
fi
-if test -n "$PJPROJECT_LIBS"; then
- pkg_cv_PJPROJECT_LIBS="$PJPROJECT_LIBS"
- elif test -n "$PKG_CONFIG"; then
- if test -n "$PKG_CONFIG" && \
+if test -n "$PKG_CONFIG"; then
+ if test -n "$PJPROJECT_LIBS"; then
+ pkg_cv_PJPROJECT_LIBS="$PJPROJECT_LIBS"
+ else
+ if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpjproject\""; } >&5
($PKG_CONFIG --exists --print-errors "libpjproject") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_PJPROJECT_LIBS=`$PKG_CONFIG --libs "libpjproject" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
- else
- pkg_failed=untried
+ fi
+else
+ pkg_failed=untried
fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -22885,20 +22890,20 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- PJPROJECT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpjproject" 2>&1`
+ PJPROJECT_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "libpjproject"`
else
- PJPROJECT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpjproject" 2>&1`
+ PJPROJECT_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "libpjproject"`
fi
# Put the nasty error message in config.log where it belongs
echo "$PJPROJECT_PKG_ERRORS" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
PBX_PJPROJECT=0
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
PBX_PJPROJECT=0
@@ -22940,7 +22945,7 @@ if test "x${PBX_POPT}" != "x1" -a "${USE_POPT}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_popt_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpopt" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpopt... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -22975,7 +22980,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_POPT_FOUND=yes
else
AST_POPT_FOUND=no
@@ -22998,7 +23004,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${POPT_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "popt.h" "ac_cv_header_popt_h" "$ac_includes_default"
-if test "x$ac_cv_header_popt_h" = xyes; then :
+if test "x$ac_cv_header_popt_h" = x""yes; then :
POPT_HEADER_FOUND=1
else
POPT_HEADER_FOUND=0
@@ -23045,7 +23051,7 @@ if test "x${PBX_PORTAUDIO}" != "x1" -a "${USE_PORTAUDIO}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_portaudio_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lportaudio" >&5
$as_echo_n "checking for ${pbxfuncname} in -lportaudio... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -23080,7 +23086,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PORTAUDIO_FOUND=yes
else
AST_PORTAUDIO_FOUND=no
@@ -23103,7 +23110,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PORTAUDIO_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "portaudio.h" "ac_cv_header_portaudio_h" "$ac_includes_default"
-if test "x$ac_cv_header_portaudio_h" = xyes; then :
+if test "x$ac_cv_header_portaudio_h" = x""yes; then :
PORTAUDIO_HEADER_FOUND=1
else
PORTAUDIO_HEADER_FOUND=0
@@ -23150,7 +23157,7 @@ if test "x${PBX_PRI}" != "x1" -a "${USE_PRI}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -23185,7 +23192,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_FOUND=yes
else
AST_PRI_FOUND=no
@@ -23208,7 +23216,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_HEADER_FOUND=1
else
PRI_HEADER_FOUND=0
@@ -23254,7 +23262,7 @@ if test "x${PBX_PRI_L2_PERSISTENCE}" != "x1" -a "${USE_PRI_L2_PERSISTENCE}" != "
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -23289,7 +23297,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_L2_PERSISTENCE_FOUND=yes
else
AST_PRI_L2_PERSISTENCE_FOUND=no
@@ -23312,7 +23321,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_L2_PERSISTENCE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_L2_PERSISTENCE_HEADER_FOUND=1
else
PRI_L2_PERSISTENCE_HEADER_FOUND=0
@@ -23358,7 +23367,7 @@ if test "x${PBX_PRI_DATETIME_SEND}" != "x1" -a "${USE_PRI_DATETIME_SEND}" != "no
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -23393,7 +23402,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_DATETIME_SEND_FOUND=yes
else
AST_PRI_DATETIME_SEND_FOUND=no
@@ -23416,7 +23426,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_DATETIME_SEND_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_DATETIME_SEND_HEADER_FOUND=1
else
PRI_DATETIME_SEND_HEADER_FOUND=0
@@ -23462,7 +23472,7 @@ if test "x${PBX_PRI_MWI_V2}" != "x1" -a "${USE_PRI_MWI_V2}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -23497,7 +23507,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_MWI_V2_FOUND=yes
else
AST_PRI_MWI_V2_FOUND=no
@@ -23520,7 +23531,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_MWI_V2_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_MWI_V2_HEADER_FOUND=1
else
PRI_MWI_V2_HEADER_FOUND=0
@@ -23566,7 +23577,7 @@ if test "x${PBX_PRI_DISPLAY_TEXT}" != "x1" -a "${USE_PRI_DISPLAY_TEXT}" != "no";
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -23601,7 +23612,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_DISPLAY_TEXT_FOUND=yes
else
AST_PRI_DISPLAY_TEXT_FOUND=no
@@ -23624,7 +23636,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_DISPLAY_TEXT_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_DISPLAY_TEXT_HEADER_FOUND=1
else
PRI_DISPLAY_TEXT_HEADER_FOUND=0
@@ -23670,7 +23682,7 @@ if test "x${PBX_PRI_MWI}" != "x1" -a "${USE_PRI_MWI}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -23705,7 +23717,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_MWI_FOUND=yes
else
AST_PRI_MWI_FOUND=no
@@ -23728,7 +23741,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_MWI_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_MWI_HEADER_FOUND=1
else
PRI_MWI_HEADER_FOUND=0
@@ -23774,7 +23787,7 @@ if test "x${PBX_PRI_MCID}" != "x1" -a "${USE_PRI_MCID}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -23809,7 +23822,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_MCID_FOUND=yes
else
AST_PRI_MCID_FOUND=no
@@ -23832,7 +23846,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_MCID_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_MCID_HEADER_FOUND=1
else
PRI_MCID_HEADER_FOUND=0
@@ -23878,7 +23892,7 @@ if test "x${PBX_PRI_CALL_WAITING}" != "x1" -a "${USE_PRI_CALL_WAITING}" != "no";
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -23913,7 +23927,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_CALL_WAITING_FOUND=yes
else
AST_PRI_CALL_WAITING_FOUND=no
@@ -23936,7 +23951,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_CALL_WAITING_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_CALL_WAITING_HEADER_FOUND=1
else
PRI_CALL_WAITING_HEADER_FOUND=0
@@ -23982,7 +23997,7 @@ if test "x${PBX_PRI_AOC_EVENTS}" != "x1" -a "${USE_PRI_AOC_EVENTS}" != "no"; the
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -24017,7 +24032,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_AOC_EVENTS_FOUND=yes
else
AST_PRI_AOC_EVENTS_FOUND=no
@@ -24040,7 +24056,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_AOC_EVENTS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_AOC_EVENTS_HEADER_FOUND=1
else
PRI_AOC_EVENTS_HEADER_FOUND=0
@@ -24086,7 +24102,7 @@ if test "x${PBX_PRI_TRANSFER}" != "x1" -a "${USE_PRI_TRANSFER}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -24121,7 +24137,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_TRANSFER_FOUND=yes
else
AST_PRI_TRANSFER_FOUND=no
@@ -24144,7 +24161,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_TRANSFER_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_TRANSFER_HEADER_FOUND=1
else
PRI_TRANSFER_HEADER_FOUND=0
@@ -24190,7 +24207,7 @@ if test "x${PBX_PRI_CCSS}" != "x1" -a "${USE_PRI_CCSS}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -24225,7 +24242,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_CCSS_FOUND=yes
else
AST_PRI_CCSS_FOUND=no
@@ -24248,7 +24266,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_CCSS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_CCSS_HEADER_FOUND=1
else
PRI_CCSS_HEADER_FOUND=0
@@ -24294,7 +24312,7 @@ if test "x${PBX_PRI_HANGUP_FIX}" != "x1" -a "${USE_PRI_HANGUP_FIX}" != "no"; the
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -24329,7 +24347,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_HANGUP_FIX_FOUND=yes
else
AST_PRI_HANGUP_FIX_FOUND=no
@@ -24352,7 +24371,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_HANGUP_FIX_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_HANGUP_FIX_HEADER_FOUND=1
else
PRI_HANGUP_FIX_HEADER_FOUND=0
@@ -24398,7 +24417,7 @@ if test "x${PBX_PRI_SUBADDR}" != "x1" -a "${USE_PRI_SUBADDR}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -24433,7 +24452,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_SUBADDR_FOUND=yes
else
AST_PRI_SUBADDR_FOUND=no
@@ -24456,7 +24476,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_SUBADDR_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_SUBADDR_HEADER_FOUND=1
else
PRI_SUBADDR_HEADER_FOUND=0
@@ -24502,7 +24522,7 @@ if test "x${PBX_PRI_CALL_HOLD}" != "x1" -a "${USE_PRI_CALL_HOLD}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -24537,7 +24557,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_CALL_HOLD_FOUND=yes
else
AST_PRI_CALL_HOLD_FOUND=no
@@ -24560,7 +24581,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_CALL_HOLD_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_CALL_HOLD_HEADER_FOUND=1
else
PRI_CALL_HOLD_HEADER_FOUND=0
@@ -24606,7 +24627,7 @@ if test "x${PBX_PRI_CALL_REROUTING}" != "x1" -a "${USE_PRI_CALL_REROUTING}" != "
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -24641,7 +24662,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_CALL_REROUTING_FOUND=yes
else
AST_PRI_CALL_REROUTING_FOUND=no
@@ -24664,7 +24686,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_CALL_REROUTING_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_CALL_REROUTING_HEADER_FOUND=1
else
PRI_CALL_REROUTING_HEADER_FOUND=0
@@ -24710,7 +24732,7 @@ if test "x${PBX_PRI_SETUP_KEYPAD}" != "x1" -a "${USE_PRI_SETUP_KEYPAD}" != "no";
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -24745,7 +24767,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_SETUP_KEYPAD_FOUND=yes
else
AST_PRI_SETUP_KEYPAD_FOUND=no
@@ -24768,7 +24791,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_SETUP_KEYPAD_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_SETUP_KEYPAD_HEADER_FOUND=1
else
PRI_SETUP_KEYPAD_HEADER_FOUND=0
@@ -24818,7 +24841,7 @@ if test "x${PBX_PRI_PROG_W_CAUSE}" != "x1" -a "${USE_PRI_PROG_W_CAUSE}" != "no";
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -24853,7 +24876,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_PROG_W_CAUSE_FOUND=yes
else
AST_PRI_PROG_W_CAUSE_FOUND=no
@@ -24876,7 +24900,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_PROG_W_CAUSE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_PROG_W_CAUSE_HEADER_FOUND=1
else
PRI_PROG_W_CAUSE_HEADER_FOUND=0
@@ -24922,7 +24946,7 @@ if test "x${PBX_PRI_INBANDDISCONNECT}" != "x1" -a "${USE_PRI_INBANDDISCONNECT}"
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -24957,7 +24981,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_INBANDDISCONNECT_FOUND=yes
else
AST_PRI_INBANDDISCONNECT_FOUND=no
@@ -24980,7 +25005,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_INBANDDISCONNECT_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_INBANDDISCONNECT_HEADER_FOUND=1
else
PRI_INBANDDISCONNECT_HEADER_FOUND=0
@@ -25026,7 +25051,7 @@ if test "x${PBX_PRI_SERVICE_MESSAGES}" != "x1" -a "${USE_PRI_SERVICE_MESSAGES}"
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -25061,7 +25086,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_SERVICE_MESSAGES_FOUND=yes
else
AST_PRI_SERVICE_MESSAGES_FOUND=no
@@ -25084,7 +25110,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_SERVICE_MESSAGES_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_SERVICE_MESSAGES_HEADER_FOUND=1
else
PRI_SERVICE_MESSAGES_HEADER_FOUND=0
@@ -25130,7 +25156,7 @@ if test "x${PBX_PRI_REVERSE_CHARGE}" != "x1" -a "${USE_PRI_REVERSE_CHARGE}" != "
as_ac_Lib=`$as_echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpri" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpri... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -25165,7 +25191,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_PRI_REVERSE_CHARGE_FOUND=yes
else
AST_PRI_REVERSE_CHARGE_FOUND=no
@@ -25188,7 +25215,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PRI_REVERSE_CHARGE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libpri.h" "ac_cv_header_libpri_h" "$ac_includes_default"
-if test "x$ac_cv_header_libpri_h" = xyes; then :
+if test "x$ac_cv_header_libpri_h" = x""yes; then :
PRI_REVERSE_CHARGE_HEADER_FOUND=1
else
PRI_REVERSE_CHARGE_HEADER_FOUND=0
@@ -25236,7 +25263,7 @@ if test "x${PBX_RESAMPLE}" != "x1" -a "${USE_RESAMPLE}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_resample_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lresample" >&5
$as_echo_n "checking for ${pbxfuncname} in -lresample... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -25271,7 +25298,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_RESAMPLE_FOUND=yes
else
AST_RESAMPLE_FOUND=no
@@ -25294,7 +25322,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${RESAMPLE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libresample.h" "ac_cv_header_libresample_h" "$ac_includes_default"
-if test "x$ac_cv_header_libresample_h" = xyes; then :
+if test "x$ac_cv_header_libresample_h" = x""yes; then :
RESAMPLE_HEADER_FOUND=1
else
RESAMPLE_HEADER_FOUND=0
@@ -25403,7 +25431,7 @@ if test "x${PBX_SPANDSP}" != "x1" -a "${USE_SPANDSP}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_spandsp_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lspandsp" >&5
$as_echo_n "checking for ${pbxfuncname} in -lspandsp... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -25438,7 +25466,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_SPANDSP_FOUND=yes
else
AST_SPANDSP_FOUND=no
@@ -25461,7 +25490,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SPANDSP_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "spandsp.h" "ac_cv_header_spandsp_h" "$ac_includes_default"
-if test "x$ac_cv_header_spandsp_h" = xyes; then :
+if test "x$ac_cv_header_spandsp_h" = x""yes; then :
SPANDSP_HEADER_FOUND=1
else
SPANDSP_HEADER_FOUND=0
@@ -25512,7 +25541,7 @@ if test "x${PBX_SPANDSP}" != "x1" -a "${USE_SPANDSP}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_spandsp_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lspandsp" >&5
$as_echo_n "checking for ${pbxfuncname} in -lspandsp... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -25547,7 +25576,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_SPANDSP_FOUND=yes
else
AST_SPANDSP_FOUND=no
@@ -25570,7 +25600,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SPANDSP_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "spandsp.h" "ac_cv_header_spandsp_h" "$ac_includes_default"
-if test "x$ac_cv_header_spandsp_h" = xyes; then :
+if test "x$ac_cv_header_spandsp_h" = x""yes; then :
SPANDSP_HEADER_FOUND=1
else
SPANDSP_HEADER_FOUND=0
@@ -25619,7 +25649,7 @@ if test "x${PBX_SS7}" != "x1" -a "${USE_SS7}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_ss7_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lss7" >&5
$as_echo_n "checking for ${pbxfuncname} in -lss7... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -25654,7 +25684,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_SS7_FOUND=yes
else
AST_SS7_FOUND=no
@@ -25677,7 +25708,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SS7_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "libss7.h" "ac_cv_header_libss7_h" "$ac_includes_default"
-if test "x$ac_cv_header_libss7_h" = xyes; then :
+if test "x$ac_cv_header_libss7_h" = x""yes; then :
SS7_HEADER_FOUND=1
else
SS7_HEADER_FOUND=0
@@ -25724,7 +25755,7 @@ if test "x${PBX_OPENR2}" != "x1" -a "${USE_OPENR2}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_openr2_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lopenr2" >&5
$as_echo_n "checking for ${pbxfuncname} in -lopenr2... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -25759,7 +25790,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_OPENR2_FOUND=yes
else
AST_OPENR2_FOUND=no
@@ -25782,7 +25814,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${OPENR2_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "openr2.h" "ac_cv_header_openr2_h" "$ac_includes_default"
-if test "x$ac_cv_header_openr2_h" = xyes; then :
+if test "x$ac_cv_header_openr2_h" = x""yes; then :
OPENR2_HEADER_FOUND=1
else
OPENR2_HEADER_FOUND=0
@@ -25827,7 +25859,8 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
if test "${PWLIBDIR:-unset}" != "unset" ; then
as_ac_Header=`$as_echo "ac_cv_header_${PWLIBDIR}/version.h" | $as_tr_sh`
ac_fn_cxx_check_header_mongrel "$LINENO" "${PWLIBDIR}/version.h" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
HAS_PWLIB=1
fi
@@ -25837,7 +25870,8 @@ if test "${HAS_PWLIB:-unset}" = "unset" ; then
if test "${OPENH323DIR:-unset}" != "unset"; then
as_ac_Header=`$as_echo "ac_cv_header_${OPENH323DIR}/../pwlib/version.h" | $as_tr_sh`
ac_fn_cxx_check_header_mongrel "$LINENO" "${OPENH323DIR}/../pwlib/version.h" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
HAS_PWLIB=1
fi
@@ -25848,7 +25882,8 @@ fi
else
as_ac_Header=`$as_echo "ac_cv_header_${HOME}/pwlib/include/ptlib.h" | $as_tr_sh`
ac_fn_cxx_check_header_mongrel "$LINENO" "${HOME}/pwlib/include/ptlib.h" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
HAS_PWLIB=1
fi
@@ -25857,7 +25892,7 @@ fi
PWLIBDIR="${HOME}/pwlib"
else
ac_fn_cxx_check_header_mongrel "$LINENO" "/usr/local/include/ptlib.h" "ac_cv_header__usr_local_include_ptlib_h" "$ac_includes_default"
-if test "x$ac_cv_header__usr_local_include_ptlib_h" = xyes; then :
+if test "x$ac_cv_header__usr_local_include_ptlib_h" = x""yes; then :
HAS_PWLIB=1
fi
@@ -25867,7 +25902,7 @@ fi
set dummy ptlib-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PTLIB_CONFIG+:} false; then :
+if test "${ac_cv_path_PTLIB_CONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $PTLIB_CONFIG in
@@ -25881,7 +25916,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_PTLIB_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -25919,7 +25954,7 @@ fi
PWLIB_LIB="-L${PWLIB_LIBDIR} `echo ${PWLIB_LIB}`"
else
ac_fn_cxx_check_header_mongrel "$LINENO" "/usr/include/ptlib.h" "ac_cv_header__usr_include_ptlib_h" "$ac_includes_default"
-if test "x$ac_cv_header__usr_include_ptlib_h" = xyes; then :
+if test "x$ac_cv_header__usr_include_ptlib_h" = x""yes; then :
HAS_PWLIB=1
fi
@@ -25929,7 +25964,7 @@ fi
set dummy ptlib-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PTLIB_CONFIG+:} false; then :
+if test "${ac_cv_path_PTLIB_CONFIG+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $PTLIB_CONFIG in
@@ -25943,7 +25978,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_PTLIB_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -26260,7 +26295,8 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
if test "${OPENH323DIR:-unset}" != "unset" ; then
as_ac_Header=`$as_echo "ac_cv_header_${OPENH323DIR}/version.h" | $as_tr_sh`
ac_fn_cxx_check_header_mongrel "$LINENO" "${OPENH323DIR}/version.h" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
HAS_OPENH323=1
fi
@@ -26269,7 +26305,8 @@ fi
if test "${HAS_OPENH323:-unset}" = "unset" ; then
as_ac_Header=`$as_echo "ac_cv_header_${PWLIBDIR}/../openh323/version.h" | $as_tr_sh`
ac_fn_cxx_check_header_mongrel "$LINENO" "${PWLIBDIR}/../openh323/version.h" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
OPENH323DIR="${PWLIBDIR}/../openh323"; HAS_OPENH323=1
fi
@@ -26281,7 +26318,8 @@ fi
as_ac_Header=`$as_echo "ac_cv_header_${OPENH323DIR}/include/h323.h" | $as_tr_sh`
ac_fn_cxx_check_header_compile "$LINENO" "${OPENH323DIR}/include/h323.h" "$as_ac_Header" "#include <ptlib.h>
"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
else
OPENH323_INCDIR="${PWLIB_INCDIR}/openh323"; OPENH323_LIBDIR="${PWLIB_LIBDIR}"
@@ -26295,7 +26333,8 @@ fi
as_ac_Header=`$as_echo "ac_cv_header_${HOME}/openh323/include/h323.h" | $as_tr_sh`
ac_fn_cxx_check_header_compile "$LINENO" "${HOME}/openh323/include/h323.h" "$as_ac_Header" "#include <ptlib.h>
"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
HAS_OPENH323=1
fi
@@ -26308,7 +26347,7 @@ fi
CPPFLAGS="${CPPFLAGS} -I/usr/local/include/openh323 -I${PWLIB_INCDIR}"
ac_fn_cxx_check_header_compile "$LINENO" "/usr/local/include/openh323/h323.h" "ac_cv_header__usr_local_include_openh323_h323_h" "#include <ptlib.h>
"
-if test "x$ac_cv_header__usr_local_include_openh323_h323_h" = xyes; then :
+if test "x$ac_cv_header__usr_local_include_openh323_h323_h" = x""yes; then :
HAS_OPENH323=1
fi
@@ -26327,7 +26366,7 @@ fi
CPPFLAGS="${CPPFLAGS} -I/usr/include/openh323 -I${PWLIB_INCDIR}"
ac_fn_cxx_check_header_compile "$LINENO" "/usr/include/openh323/h323.h" "ac_cv_header__usr_include_openh323_h323_h" "#include <ptlib.h>
"
-if test "x$ac_cv_header__usr_include_openh323_h323_h" = xyes; then :
+if test "x$ac_cv_header__usr_include_openh323_h323_h" = x""yes; then :
HAS_OPENH323=1
fi
@@ -26569,7 +26608,7 @@ if test "x${PBX_LUA}" != "x1" -a "${USE_LUA}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_lua5.1_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -llua5.1" >&5
$as_echo_n "checking for ${pbxfuncname} in -llua5.1... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -26604,7 +26643,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_LUA_FOUND=yes
else
AST_LUA_FOUND=no
@@ -26627,7 +26667,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "lua5.1/lua.h" "ac_cv_header_lua5_1_lua_h" "$ac_includes_default"
-if test "x$ac_cv_header_lua5_1_lua_h" = xyes; then :
+if test "x$ac_cv_header_lua5_1_lua_h" = x""yes; then :
LUA_HEADER_FOUND=1
else
LUA_HEADER_FOUND=0
@@ -26682,7 +26722,7 @@ if test "x${PBX_LUA}" != "x1" -a "${USE_LUA}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_lua_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -llua" >&5
$as_echo_n "checking for ${pbxfuncname} in -llua... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -26717,7 +26757,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_LUA_FOUND=yes
else
AST_LUA_FOUND=no
@@ -26740,7 +26781,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "lua.h" "ac_cv_header_lua_h" "$ac_includes_default"
-if test "x$ac_cv_header_lua_h" = xyes; then :
+if test "x$ac_cv_header_lua_h" = x""yes; then :
LUA_HEADER_FOUND=1
else
LUA_HEADER_FOUND=0
@@ -26787,7 +26828,7 @@ if test "x${PBX_RADIUS}" != "x1" -a "${USE_RADIUS}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_radiusclient-ng_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lradiusclient-ng" >&5
$as_echo_n "checking for ${pbxfuncname} in -lradiusclient-ng... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -26822,7 +26863,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_RADIUS_FOUND=yes
else
AST_RADIUS_FOUND=no
@@ -26845,7 +26887,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${RADIUS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "radiusclient-ng.h" "ac_cv_header_radiusclient_ng_h" "$ac_includes_default"
-if test "x$ac_cv_header_radiusclient_ng_h" = xyes; then :
+if test "x$ac_cv_header_radiusclient_ng_h" = x""yes; then :
RADIUS_HEADER_FOUND=1
else
RADIUS_HEADER_FOUND=0
@@ -26892,7 +26934,7 @@ if test "x${PBX_COROSYNC}" != "x1" -a "${USE_COROSYNC}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_cpg_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lcpg" >&5
$as_echo_n "checking for ${pbxfuncname} in -lcpg... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -26927,7 +26969,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_COROSYNC_FOUND=yes
else
AST_COROSYNC_FOUND=no
@@ -26950,7 +26993,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${COROSYNC_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "corosync/cpg.h" "ac_cv_header_corosync_cpg_h" "$ac_includes_default"
-if test "x$ac_cv_header_corosync_cpg_h" = xyes; then :
+if test "x$ac_cv_header_corosync_cpg_h" = x""yes; then :
COROSYNC_HEADER_FOUND=1
else
COROSYNC_HEADER_FOUND=0
@@ -26996,7 +27039,7 @@ if test "x${PBX_COROSYNC_CFG_STATE_TRACK}" != "x1" -a "${USE_COROSYNC_CFG_STATE_
as_ac_Lib=`$as_echo "ac_cv_lib_cfg_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lcfg" >&5
$as_echo_n "checking for ${pbxfuncname} in -lcfg... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -27031,7 +27074,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_COROSYNC_CFG_STATE_TRACK_FOUND=yes
else
AST_COROSYNC_CFG_STATE_TRACK_FOUND=no
@@ -27054,7 +27098,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${COROSYNC_CFG_STATE_TRACK_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "corosync/cfg.h" "ac_cv_header_corosync_cfg_h" "$ac_includes_default"
-if test "x$ac_cv_header_corosync_cfg_h" = xyes; then :
+if test "x$ac_cv_header_corosync_cfg_h" = x""yes; then :
COROSYNC_CFG_STATE_TRACK_HEADER_FOUND=1
else
COROSYNC_CFG_STATE_TRACK_HEADER_FOUND=0
@@ -27101,7 +27145,7 @@ if test "x${PBX_SPEEX}" != "x1" -a "${USE_SPEEX}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_speex_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lspeex" >&5
$as_echo_n "checking for ${pbxfuncname} in -lspeex... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -27136,7 +27180,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_SPEEX_FOUND=yes
else
AST_SPEEX_FOUND=no
@@ -27159,7 +27204,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SPEEX_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "speex/speex.h" "ac_cv_header_speex_speex_h" "$ac_includes_default"
-if test "x$ac_cv_header_speex_speex_h" = xyes; then :
+if test "x$ac_cv_header_speex_speex_h" = x""yes; then :
SPEEX_HEADER_FOUND=1
else
SPEEX_HEADER_FOUND=0
@@ -27207,7 +27252,7 @@ if test "x${PBX_SPEEX_PREPROCESS}" != "x1" -a "${USE_SPEEX_PREPROCESS}" != "no";
as_ac_Lib=`$as_echo "ac_cv_lib_speex_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lspeex" >&5
$as_echo_n "checking for ${pbxfuncname} in -lspeex... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -27242,7 +27287,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_SPEEX_PREPROCESS_FOUND=yes
else
AST_SPEEX_PREPROCESS_FOUND=no
@@ -27265,7 +27311,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SPEEX_PREPROCESS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "speex/speex.h" "ac_cv_header_speex_speex_h" "$ac_includes_default"
-if test "x$ac_cv_header_speex_speex_h" = xyes; then :
+if test "x$ac_cv_header_speex_speex_h" = x""yes; then :
SPEEX_PREPROCESS_HEADER_FOUND=1
else
SPEEX_PREPROCESS_HEADER_FOUND=0
@@ -27315,7 +27361,7 @@ if test "x${PBX_SPEEXDSP}" != "x1" -a "${USE_SPEEXDSP}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_speexdsp_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lspeexdsp" >&5
$as_echo_n "checking for ${pbxfuncname} in -lspeexdsp... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -27350,7 +27396,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_SPEEXDSP_FOUND=yes
else
AST_SPEEXDSP_FOUND=no
@@ -27373,7 +27420,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SPEEXDSP_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "speex/speex.h" "ac_cv_header_speex_speex_h" "$ac_includes_default"
-if test "x$ac_cv_header_speex_speex_h" = xyes; then :
+if test "x$ac_cv_header_speex_speex_h" = x""yes; then :
SPEEXDSP_HEADER_FOUND=1
else
SPEEXDSP_HEADER_FOUND=0
@@ -27425,7 +27472,7 @@ if test "x${PBX_SQLITE}" != "x1" -a "${USE_SQLITE}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_sqlite_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsqlite" >&5
$as_echo_n "checking for ${pbxfuncname} in -lsqlite... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -27460,7 +27507,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_SQLITE_FOUND=yes
else
AST_SQLITE_FOUND=no
@@ -27483,7 +27531,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SQLITE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sqlite.h" "ac_cv_header_sqlite_h" "$ac_includes_default"
-if test "x$ac_cv_header_sqlite_h" = xyes; then :
+if test "x$ac_cv_header_sqlite_h" = x""yes; then :
SQLITE_HEADER_FOUND=1
else
SQLITE_HEADER_FOUND=0
@@ -27530,7 +27578,7 @@ if test "x${PBX_SQLITE3}" != "x1" -a "${USE_SQLITE3}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_sqlite3_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsqlite3" >&5
$as_echo_n "checking for ${pbxfuncname} in -lsqlite3... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -27565,7 +27613,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_SQLITE3_FOUND=yes
else
AST_SQLITE3_FOUND=no
@@ -27588,7 +27637,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SQLITE3_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default"
-if test "x$ac_cv_header_sqlite3_h" = xyes; then :
+if test "x$ac_cv_header_sqlite3_h" = x""yes; then :
SQLITE3_HEADER_FOUND=1
else
SQLITE3_HEADER_FOUND=0
@@ -27643,7 +27692,7 @@ if test "x${PBX_CRYPTO}" != "x1" -a "${USE_CRYPTO}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_crypto_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lcrypto" >&5
$as_echo_n "checking for ${pbxfuncname} in -lcrypto... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -27678,7 +27727,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_CRYPTO_FOUND=yes
else
AST_CRYPTO_FOUND=no
@@ -27701,7 +27751,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${CRYPTO_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "openssl/aes.h" "ac_cv_header_openssl_aes_h" "$ac_includes_default"
-if test "x$ac_cv_header_openssl_aes_h" = xyes; then :
+if test "x$ac_cv_header_openssl_aes_h" = x""yes; then :
CRYPTO_HEADER_FOUND=1
else
CRYPTO_HEADER_FOUND=0
@@ -27750,7 +27800,7 @@ if test "x${PBX_OPENSSL}" != "x1" -a "${USE_OPENSSL}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_ssl_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lssl" >&5
$as_echo_n "checking for ${pbxfuncname} in -lssl... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -27785,7 +27835,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_OPENSSL_FOUND=yes
else
AST_OPENSSL_FOUND=no
@@ -27808,7 +27859,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${OPENSSL_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default"
-if test "x$ac_cv_header_openssl_ssl_h" = xyes; then :
+if test "x$ac_cv_header_openssl_ssl_h" = x""yes; then :
OPENSSL_HEADER_FOUND=1
else
OPENSSL_HEADER_FOUND=0
@@ -27854,7 +27905,7 @@ then
osptk_saved_cppflags="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${osptk_cflags}"
ac_fn_c_check_header_mongrel "$LINENO" "osp/osp.h" "ac_cv_header_osp_osp_h" "$ac_includes_default"
-if test "x$ac_cv_header_osp_osp_h" = xyes; then :
+if test "x$ac_cv_header_osp_osp_h" = x""yes; then :
osptk_header_found=yes
else
osptk_header_found=no
@@ -27869,7 +27920,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OSPPInit in -losptk" >&5
$as_echo_n "checking for OSPPInit in -losptk... " >&6; }
-if ${ac_cv_lib_osptk_OSPPInit+:} false; then :
+if test "${ac_cv_lib_osptk_OSPPInit+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -27903,7 +27954,7 @@ LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_osptk_OSPPInit" >&5
$as_echo "$ac_cv_lib_osptk_OSPPInit" >&6; }
-if test "x$ac_cv_lib_osptk_OSPPInit" = xyes; then :
+if test "x$ac_cv_lib_osptk_OSPPInit" = x""yes; then :
osptk_library_found=yes
else
osptk_library_found=no
@@ -27920,8 +27971,8 @@ $as_echo_n "checking if OSP Toolkit version is compatible with app_osplookup...
if test "$cross_compiling" = yes; then :
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot run test program while cross compiling
-See \`config.log' for more details" "$LINENO" 5; }
+as_fn_error "cannot run test program while cross compiling
+See \`config.log' for more details." "$LINENO" 5; }
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -27985,7 +28036,7 @@ if test "x${PBX_OPENSSL_SRTP}" != "x1" -a "${USE_OPENSSL_SRTP}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_ssl_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lssl" >&5
$as_echo_n "checking for ${pbxfuncname} in -lssl... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -28020,7 +28071,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_OPENSSL_SRTP_FOUND=yes
else
AST_OPENSSL_SRTP_FOUND=no
@@ -28043,7 +28095,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${OPENSSL_SRTP_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default"
-if test "x$ac_cv_header_openssl_ssl_h" = xyes; then :
+if test "x$ac_cv_header_openssl_ssl_h" = x""yes; then :
OPENSSL_SRTP_HEADER_FOUND=1
else
OPENSSL_SRTP_HEADER_FOUND=0
@@ -28091,7 +28143,7 @@ if test "x${PBX_SRTP}" != "x1" -a "${USE_SRTP}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_srtp_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsrtp" >&5
$as_echo_n "checking for ${pbxfuncname} in -lsrtp... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -28126,7 +28178,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_SRTP_FOUND=yes
else
AST_SRTP_FOUND=no
@@ -28149,7 +28202,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SRTP_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "srtp/srtp.h" "ac_cv_header_srtp_srtp_h" "$ac_includes_default"
-if test "x$ac_cv_header_srtp_srtp_h" = xyes; then :
+if test "x$ac_cv_header_srtp_srtp_h" = x""yes; then :
SRTP_HEADER_FOUND=1
else
SRTP_HEADER_FOUND=0
@@ -28247,46 +28300,46 @@ pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GMIME" >&5
$as_echo_n "checking for GMIME... " >&6; }
-if test -n "$GMIME_CFLAGS"; then
- pkg_cv_GMIME_CFLAGS="$GMIME_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
- if test -n "$PKG_CONFIG" && \
+if test -n "$PKG_CONFIG"; then
+ if test -n "$GMIME_CFLAGS"; then
+ pkg_cv_GMIME_CFLAGS="$GMIME_CFLAGS"
+ else
+ if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gmime-\$ver\""; } >&5
($PKG_CONFIG --exists --print-errors "gmime-$ver") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_GMIME_CFLAGS=`$PKG_CONFIG --cflags "gmime-$ver" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
- else
- pkg_failed=untried
+ fi
+else
+ pkg_failed=untried
fi
-if test -n "$GMIME_LIBS"; then
- pkg_cv_GMIME_LIBS="$GMIME_LIBS"
- elif test -n "$PKG_CONFIG"; then
- if test -n "$PKG_CONFIG" && \
+if test -n "$PKG_CONFIG"; then
+ if test -n "$GMIME_LIBS"; then
+ pkg_cv_GMIME_LIBS="$GMIME_LIBS"
+ else
+ if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gmime-\$ver\""; } >&5
($PKG_CONFIG --exists --print-errors "gmime-$ver") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_GMIME_LIBS=`$PKG_CONFIG --libs "gmime-$ver" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
- else
- pkg_failed=untried
+ fi
+else
+ pkg_failed=untried
fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -28294,20 +28347,20 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- GMIME_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gmime-$ver" 2>&1`
+ GMIME_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gmime-$ver"`
else
- GMIME_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gmime-$ver" 2>&1`
+ GMIME_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gmime-$ver"`
fi
# Put the nasty error message in config.log where it belongs
echo "$GMIME_PKG_ERRORS" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
PBX_GMIME=0
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
PBX_GMIME=0
@@ -28353,7 +28406,7 @@ if test "x${PBX_HOARD}" != "x1" -a "${USE_HOARD}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_hoard_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lhoard" >&5
$as_echo_n "checking for ${pbxfuncname} in -lhoard... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -28388,7 +28441,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_HOARD_FOUND=yes
else
AST_HOARD_FOUND=no
@@ -28411,7 +28465,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${HOARD_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default"
-if test "x$ac_cv_header_" = xyes; then :
+if test "x$ac_cv_header_" = x""yes; then :
HOARD_HEADER_FOUND=1
else
HOARD_HEADER_FOUND=0
@@ -28458,7 +28512,7 @@ if test "x${PBX_FREETDS}" != "x1" -a "${USE_FREETDS}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_sybdb_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsybdb" >&5
$as_echo_n "checking for ${pbxfuncname} in -lsybdb... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -28493,7 +28547,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_FREETDS_FOUND=yes
else
AST_FREETDS_FOUND=no
@@ -28516,7 +28571,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${FREETDS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "sybdb.h" "ac_cv_header_sybdb_h" "$ac_includes_default"
-if test "x$ac_cv_header_sybdb_h" = xyes; then :
+if test "x$ac_cv_header_sybdb_h" = x""yes; then :
FREETDS_HEADER_FOUND=1
else
FREETDS_HEADER_FOUND=0
@@ -28545,7 +28600,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for tone_zone_find_by_num in -ltonezone" >&5
$as_echo_n "checking for tone_zone_find_by_num in -ltonezone... " >&6; }
-if ${ac_cv_lib_tonezone_tone_zone_find_by_num+:} false; then :
+if test "${ac_cv_lib_tonezone_tone_zone_find_by_num+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -28579,7 +28634,7 @@ LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tonezone_tone_zone_find_by_num" >&5
$as_echo "$ac_cv_lib_tonezone_tone_zone_find_by_num" >&6; }
-if test "x$ac_cv_lib_tonezone_tone_zone_find_by_num" = xyes; then :
+if test "x$ac_cv_lib_tonezone_tone_zone_find_by_num" = x""yes; then :
tonezone_does_not_need_lm=yes
else
tonezone_does_not_need_lm=no
@@ -28610,7 +28665,7 @@ if test "x${PBX_TONEZONE}" != "x1" -a "${USE_TONEZONE}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_tonezone_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -ltonezone" >&5
$as_echo_n "checking for ${pbxfuncname} in -ltonezone... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -28645,7 +28700,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_TONEZONE_FOUND=yes
else
AST_TONEZONE_FOUND=no
@@ -28668,7 +28724,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${TONEZONE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "dahdi/tonezone.h" "ac_cv_header_dahdi_tonezone_h" "$ac_includes_default"
-if test "x$ac_cv_header_dahdi_tonezone_h" = xyes; then :
+if test "x$ac_cv_header_dahdi_tonezone_h" = x""yes; then :
TONEZONE_HEADER_FOUND=1
else
TONEZONE_HEADER_FOUND=0
@@ -28717,7 +28773,7 @@ if test "x${PBX_VORBIS}" != "x1" -a "${USE_VORBIS}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_vorbis_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lvorbis" >&5
$as_echo_n "checking for ${pbxfuncname} in -lvorbis... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -28752,7 +28808,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_VORBIS_FOUND=yes
else
AST_VORBIS_FOUND=no
@@ -28775,7 +28832,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${VORBIS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "vorbis/codec.h" "ac_cv_header_vorbis_codec_h" "$ac_includes_default"
-if test "x$ac_cv_header_vorbis_codec_h" = xyes; then :
+if test "x$ac_cv_header_vorbis_codec_h" = x""yes; then :
VORBIS_HEADER_FOUND=1
else
VORBIS_HEADER_FOUND=0
@@ -28822,7 +28879,7 @@ if test "x${PBX_VORBIS}" != "x1" -a "${USE_VORBIS}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_vorbis_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lvorbis" >&5
$as_echo_n "checking for ${pbxfuncname} in -lvorbis... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -28857,7 +28914,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_VORBIS_FOUND=yes
else
AST_VORBIS_FOUND=no
@@ -28880,7 +28938,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${VORBIS_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "vorbis/codec.h" "ac_cv_header_vorbis_codec_h" "$ac_includes_default"
-if test "x$ac_cv_header_vorbis_codec_h" = xyes; then :
+if test "x$ac_cv_header_vorbis_codec_h" = x""yes; then :
VORBIS_HEADER_FOUND=1
else
VORBIS_HEADER_FOUND=0
@@ -29043,7 +29101,7 @@ if test "x${PBX_ZLIB}" != "x1" -a "${USE_ZLIB}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_z_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lz" >&5
$as_echo_n "checking for ${pbxfuncname} in -lz... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -29078,7 +29136,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_ZLIB_FOUND=yes
else
AST_ZLIB_FOUND=no
@@ -29101,7 +29160,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${ZLIB_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_zlib_h" = xyes; then :
+if test "x$ac_cv_header_zlib_h" = x""yes; then :
ZLIB_HEADER_FOUND=1
else
ZLIB_HEADER_FOUND=0
@@ -29160,7 +29219,7 @@ rm -f core conftest.err conftest.$ac_objext \
fi
ac_fn_c_check_header_mongrel "$LINENO" "h323.h" "ac_cv_header_h323_h" "$ac_includes_default"
-if test "x$ac_cv_header_h323_h" = xyes; then :
+if test "x$ac_cv_header_h323_h" = x""yes; then :
PBX_H323=1
else
PBX_H323=0
@@ -29170,7 +29229,7 @@ fi
ac_fn_c_check_header_mongrel "$LINENO" "linux/compiler.h" "ac_cv_header_linux_compiler_h" "$ac_includes_default"
-if test "x$ac_cv_header_linux_compiler_h" = xyes; then :
+if test "x$ac_cv_header_linux_compiler_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_LINUX_COMPILER_H 1
@@ -29187,7 +29246,7 @@ ac_fn_c_check_header_compile "$LINENO" "linux/ixjuser.h" "ac_cv_header_linux_ixj
#endif
"
-if test "x$ac_cv_header_linux_ixjuser_h" = xyes; then :
+if test "x$ac_cv_header_linux_ixjuser_h" = x""yes; then :
PBX_IXJUSER=1
else
PBX_IXJUSER=0
@@ -29298,7 +29357,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
set dummy ${ac_tool_prefix}sdl-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_CONFIG_SDL+:} false; then :
+if test "${ac_cv_path_CONFIG_SDL+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $CONFIG_SDL in
@@ -29313,7 +29372,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_CONFIG_SDL="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -29342,7 +29401,7 @@ if test -z "$ac_cv_path_CONFIG_SDL"; then
set dummy sdl-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_CONFIG_SDL+:} false; then :
+if test "${ac_cv_path_ac_pt_CONFIG_SDL+set}" = set; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_CONFIG_SDL in
@@ -29357,7 +29416,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_path_ac_pt_CONFIG_SDL="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@@ -29460,7 +29519,7 @@ if test "x${PBX_SDL_IMAGE}" != "x1" -a "${USE_SDL_IMAGE}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_SDL_image_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lSDL_image" >&5
$as_echo_n "checking for ${pbxfuncname} in -lSDL_image... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -29495,7 +29554,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_SDL_IMAGE_FOUND=yes
else
AST_SDL_IMAGE_FOUND=no
@@ -29518,7 +29578,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${SDL_IMAGE_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "SDL_image.h" "ac_cv_header_SDL_image_h" "$ac_includes_default"
-if test "x$ac_cv_header_SDL_image_h" = xyes; then :
+if test "x$ac_cv_header_SDL_image_h" = x""yes; then :
SDL_IMAGE_HEADER_FOUND=1
else
SDL_IMAGE_HEADER_FOUND=0
@@ -29564,7 +29624,7 @@ if test "x${PBX_FFMPEG}" != "x1" -a "${USE_FFMPEG}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_avcodec_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lavcodec" >&5
$as_echo_n "checking for ${pbxfuncname} in -lavcodec... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -29599,7 +29659,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_FFMPEG_FOUND=yes
else
AST_FFMPEG_FOUND=no
@@ -29622,7 +29683,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${FFMPEG_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "ffmpeg/avcodec.h" "ac_cv_header_ffmpeg_avcodec_h" "$ac_includes_default"
-if test "x$ac_cv_header_ffmpeg_avcodec_h" = xyes; then :
+if test "x$ac_cv_header_ffmpeg_avcodec_h" = x""yes; then :
FFMPEG_HEADER_FOUND=1
else
FFMPEG_HEADER_FOUND=0
@@ -29651,7 +29712,7 @@ fi
# possible places for video4linux version 1
ac_fn_c_check_header_mongrel "$LINENO" "linux/videodev.h" "ac_cv_header_linux_videodev_h" "$ac_includes_default"
-if test "x$ac_cv_header_linux_videodev_h" = xyes; then :
+if test "x$ac_cv_header_linux_videodev_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_VIDEODEV_H 1
@@ -29682,7 +29743,7 @@ if test "x${PBX_X11}" != "x1" -a "${USE_X11}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_X11_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lX11" >&5
$as_echo_n "checking for ${pbxfuncname} in -lX11... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -29717,7 +29778,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_X11_FOUND=yes
else
AST_X11_FOUND=no
@@ -29740,7 +29802,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${X11_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "X11/Xlib.h" "ac_cv_header_X11_Xlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_X11_Xlib_h" = xyes; then :
+if test "x$ac_cv_header_X11_Xlib_h" = x""yes; then :
X11_HEADER_FOUND=1
else
X11_HEADER_FOUND=0
@@ -29790,7 +29852,7 @@ if test "x${PBX_X11}" != "x1" -a "${USE_X11}" != "no"; then
as_ac_Lib=`$as_echo "ac_cv_lib_X11_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lX11" >&5
$as_echo_n "checking for ${pbxfuncname} in -lX11... " >&6; }
-if eval \${$as_ac_Lib+:} false; then :
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -29825,7 +29887,8 @@ fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+eval as_val=\$$as_ac_Lib
+ if test "x$as_val" = x""yes; then :
AST_X11_FOUND=yes
else
AST_X11_FOUND=no
@@ -29848,7 +29911,7 @@ fi
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${X11_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "X11/Xlib.h" "ac_cv_header_X11_Xlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_X11_Xlib_h" = xyes; then :
+if test "x$ac_cv_header_X11_Xlib_h" = x""yes; then :
X11_HEADER_FOUND=1
else
X11_HEADER_FOUND=0
@@ -29884,11 +29947,11 @@ if test "${cross_compiling}" = "no";
then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for /sbin/launchd" >&5
$as_echo_n "checking for /sbin/launchd... " >&6; }
-if ${ac_cv_file__sbin_launchd+:} false; then :
+if test "${ac_cv_file__sbin_launchd+set}" = set; then :
$as_echo_n "(cached) " >&6
else
test "$cross_compiling" = yes &&
- as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
+ as_fn_error "cannot check for file existence when cross compiling" "$LINENO" 5
if test -r "/sbin/launchd"; then
ac_cv_file__sbin_launchd=yes
else
@@ -29897,7 +29960,7 @@ fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__sbin_launchd" >&5
$as_echo "$ac_cv_file__sbin_launchd" >&6; }
-if test "x$ac_cv_file__sbin_launchd" = xyes; then :
+if test "x$ac_cv_file__sbin_launchd" = x""yes; then :
$as_echo "#define HAVE_SBIN_LAUNCHD 1" >>confdefs.h
@@ -29916,46 +29979,46 @@ pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK2" >&5
$as_echo_n "checking for GTK2... " >&6; }
-if test -n "$GTK2_CFLAGS"; then
- pkg_cv_GTK2_CFLAGS="$GTK2_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
- if test -n "$PKG_CONFIG" && \
+if test -n "$PKG_CONFIG"; then
+ if test -n "$GTK2_CFLAGS"; then
+ pkg_cv_GTK2_CFLAGS="$GTK2_CFLAGS"
+ else
+ if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0\""; } >&5
($PKG_CONFIG --exists --print-errors "gtk+-2.0") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_GTK2_CFLAGS=`$PKG_CONFIG --cflags "gtk+-2.0" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
- else
- pkg_failed=untried
+ fi
+else
+ pkg_failed=untried
fi
-if test -n "$GTK2_LIBS"; then
- pkg_cv_GTK2_LIBS="$GTK2_LIBS"
- elif test -n "$PKG_CONFIG"; then
- if test -n "$PKG_CONFIG" && \
+if test -n "$PKG_CONFIG"; then
+ if test -n "$GTK2_LIBS"; then
+ pkg_cv_GTK2_LIBS="$GTK2_LIBS"
+ else
+ if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0\""; } >&5
($PKG_CONFIG --exists --print-errors "gtk+-2.0") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_GTK2_LIBS=`$PKG_CONFIG --libs "gtk+-2.0" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
- else
- pkg_failed=untried
+ fi
+else
+ pkg_failed=untried
fi
if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
@@ -29963,20 +30026,20 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- GTK2_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gtk+-2.0" 2>&1`
+ GTK2_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtk+-2.0"`
else
- GTK2_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gtk+-2.0" 2>&1`
+ GTK2_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtk+-2.0"`
fi
# Put the nasty error message in config.log where it belongs
echo "$GTK2_PKG_ERRORS" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
PBX_GTK2=0
elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
PBX_GTK2=0
@@ -30641,21 +30704,10 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
:end' >>confcache
if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
if test -w "$cache_file"; then
- if test "x$cache_file" != "x/dev/null"; then
+ test "x$cache_file" != "x/dev/null" &&
{ $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
$as_echo "$as_me: updating cache $cache_file" >&6;}
- if test ! -f "$cache_file" || test -h "$cache_file"; then
- cat confcache >"$cache_file"
- else
- case $cache_file in #(
- */* | ?:*)
- mv -f confcache "$cache_file"$$ &&
- mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
- mv -f confcache "$cache_file" ;;
- esac
- fi
- fi
+ cat confcache >$cache_file
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
@@ -30671,7 +30723,6 @@ DEFS=-DHAVE_CONFIG_H
ac_libobjs=
ac_ltlibobjs=
-U=
for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
# 1. Remove the extension, and $U if already installed.
ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
@@ -30687,7 +30738,7 @@ LTLIBOBJS=$ac_ltlibobjs
-: "${CONFIG_STATUS=./config.status}"
+: ${CONFIG_STATUS=./config.status}
ac_write_fail=0
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files $CONFIG_STATUS"
@@ -30788,7 +30839,6 @@ fi
IFS=" "" $as_nl"
# Find who we are. Look in the path if we contain no directory separator.
-as_myself=
case $0 in #((
*[\\/]* ) as_myself=$0 ;;
*) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
@@ -30834,19 +30884,19 @@ export LANGUAGE
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
+# as_fn_error ERROR [LINENO LOG_FD]
+# ---------------------------------
# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
+# script with status $?, using 1 if that was 0.
as_fn_error ()
{
- as_status=$1; test $as_status -eq 0 && as_status=1
- if test "$4"; then
- as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ as_status=$?; test $as_status -eq 0 && as_status=1
+ if test "$3"; then
+ as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
fi
- $as_echo "$as_me: error: $2" >&2
+ $as_echo "$as_me: error: $1" >&2
as_fn_exit $as_status
} # as_fn_error
@@ -30984,16 +31034,16 @@ if (echo >conf$$.file) 2>/dev/null; then
# ... but there are two gotchas:
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
- # In both cases, we have to default to `cp -pR'.
+ # In both cases, we have to default to `cp -p'.
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
elif ln conf$$.file conf$$ 2>/dev/null; then
as_ln_s=ln
else
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
fi
else
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null
@@ -31042,7 +31092,7 @@ $as_echo X"$as_dir" |
test -d "$as_dir" && break
done
test -z "$as_dirs" || eval "mkdir $as_dirs"
- } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+ } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
} # as_fn_mkdir_p
@@ -31053,16 +31103,28 @@ else
as_mkdir_p=false
fi
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
- test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -31084,7 +31146,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# values after options handling.
ac_log="
This file was extended by asterisk $as_me trunk, which was
-generated by GNU Autoconf 2.69. Invocation command line was
+generated by GNU Autoconf 2.65. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
@@ -31146,10 +31208,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
asterisk config.status trunk
-configured by $0, generated by GNU Autoconf 2.69,
+configured by $0, generated by GNU Autoconf 2.65,
with options \\"\$ac_cs_config\\"
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2009 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."
@@ -31166,16 +31228,11 @@ ac_need_defaults=:
while test $# != 0
do
case $1 in
- --*=?*)
+ --*=*)
ac_option=`expr "X$1" : 'X\([^=]*\)='`
ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
ac_shift=:
;;
- --*=)
- ac_option=`expr "X$1" : 'X\([^=]*\)='`
- ac_optarg=
- ac_shift=:
- ;;
*)
ac_option=$1
ac_optarg=$2
@@ -31197,7 +31254,6 @@ do
$ac_shift
case $ac_optarg in
*\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
- '') as_fn_error $? "missing file argument" ;;
esac
as_fn_append CONFIG_FILES " '$ac_optarg'"
ac_need_defaults=false;;
@@ -31210,7 +31266,7 @@ do
ac_need_defaults=false;;
--he | --h)
# Conflict between --help and --header
- as_fn_error $? "ambiguous option: \`$1'
+ as_fn_error "ambiguous option: \`$1'
Try \`$0 --help' for more information.";;
--help | --hel | -h )
$as_echo "$ac_cs_usage"; exit ;;
@@ -31219,7 +31275,7 @@ Try \`$0 --help' for more information.";;
ac_cs_silent=: ;;
# This is an error.
- -*) as_fn_error $? "unrecognized option: \`$1'
+ -*) as_fn_error "unrecognized option: \`$1'
Try \`$0 --help' for more information." ;;
*) as_fn_append ac_config_targets " $1"
@@ -31239,7 +31295,7 @@ fi
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
if \$ac_cs_recheck; then
- set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
shift
\$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
CONFIG_SHELL='$SHELL'
@@ -31273,7 +31329,7 @@ do
"makeopts") CONFIG_FILES="$CONFIG_FILES makeopts" ;;
"channels/h323/Makefile") CONFIG_FILES="$CONFIG_FILES channels/h323/Makefile" ;;
- *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
esac
done
@@ -31295,10 +31351,9 @@ fi
# after its creation but before its name has been assigned to `$tmp'.
$debug ||
{
- tmp= ac_tmp=
+ tmp=
trap 'exit_status=$?
- : "${ac_tmp:=$tmp}"
- { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+ { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
' 0
trap 'as_fn_exit 1' 1 2 13 15
}
@@ -31306,13 +31361,12 @@ $debug ||
{
tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
- test -d "$tmp"
+ test -n "$tmp" && test -d "$tmp"
} ||
{
tmp=./conf$$-$RANDOM
(umask 077 && mkdir "$tmp")
-} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
-ac_tmp=$tmp
+} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5
# Set up the scripts for CONFIG_FILES section.
# No need to generate them if there are no CONFIG_FILES.
@@ -31329,12 +31383,12 @@ if test "x$ac_cr" = x; then
fi
ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
- ac_cs_awk_cr='\\r'
+ ac_cs_awk_cr='\r'
else
ac_cs_awk_cr=$ac_cr
fi
-echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+echo 'BEGIN {' >"$tmp/subs1.awk" &&
_ACEOF
@@ -31343,18 +31397,18 @@ _ACEOF
echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
echo "_ACEOF"
} >conf$$subs.sh ||
- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
ac_delim='%!_!# '
for ac_last_try in false false false false false :; do
. ./conf$$subs.sh ||
- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
if test $ac_delim_n = $ac_delim_num; then
break
elif $ac_last_try; then
- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
else
ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
fi
@@ -31362,7 +31416,7 @@ done
rm -f conf$$subs.sh
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
_ACEOF
sed -n '
h
@@ -31410,7 +31464,7 @@ t delim
rm -f conf$$subs.awk
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
_ACAWK
-cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+cat >>"\$tmp/subs1.awk" <<_ACAWK &&
for (key in S) S_is_set[key] = 1
FS = ""
@@ -31442,29 +31496,21 @@ if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
else
cat
-fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
- || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
+ || as_fn_error "could not setup config files machinery" "$LINENO" 5
_ACEOF
-# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
-# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
# trailing colons and then remove the whole line if VPATH becomes empty
# (actually we leave an empty line to preserve line numbers).
if test "x$srcdir" = x.; then
- ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
-h
-s///
-s/^/:/
-s/[ ]*$/:/
-s/:\$(srcdir):/:/g
-s/:\${srcdir}:/:/g
-s/:@srcdir@:/:/g
-s/^:*//
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[ ]*\):*/\1/
s/:*$//
-x
-s/\(=[ ]*\).*/\1/
-G
-s/\n//
s/^[^=]*=[ ]*$//
}'
fi
@@ -31476,7 +31522,7 @@ fi # test -n "$CONFIG_FILES"
# No need to generate them if there are no CONFIG_HEADERS.
# This happens for instance with `./config.status Makefile'.
if test -n "$CONFIG_HEADERS"; then
-cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+cat >"$tmp/defines.awk" <<\_ACAWK ||
BEGIN {
_ACEOF
@@ -31488,11 +31534,11 @@ _ACEOF
# handling of long lines.
ac_delim='%!_!# '
for ac_last_try in false false :; do
- ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
- if test -z "$ac_tt"; then
+ ac_t=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_t"; then
break
elif $ac_last_try; then
- as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5
else
ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
fi
@@ -31577,7 +31623,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
_ACAWK
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
- as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+ as_fn_error "could not setup config headers machinery" "$LINENO" 5
fi # test -n "$CONFIG_HEADERS"
@@ -31590,7 +31636,7 @@ do
esac
case $ac_mode$ac_tag in
:[FHL]*:*);;
- :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;;
:[FH]-) ac_tag=-:-;;
:[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
esac
@@ -31609,7 +31655,7 @@ do
for ac_f
do
case $ac_f in
- -) ac_f="$ac_tmp/stdin";;
+ -) ac_f="$tmp/stdin";;
*) # Look for the file first in the build tree, then in the source tree
# (if the path is not absolute). The absolute path cannot be DOS-style,
# because $ac_f cannot contain `:'.
@@ -31618,7 +31664,7 @@ do
[\\/$]*) false;;
*) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
esac ||
- as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;;
esac
case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
as_fn_append ac_file_inputs " '$ac_f'"
@@ -31644,8 +31690,8 @@ $as_echo "$as_me: creating $ac_file" >&6;}
esac
case $ac_tag in
- *:-:* | *:-) cat >"$ac_tmp/stdin" \
- || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ *:-:* | *:-) cat >"$tmp/stdin" \
+ || as_fn_error "could not create $ac_file" "$LINENO" 5 ;;
esac
;;
esac
@@ -31775,24 +31821,23 @@ s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
s&@INSTALL@&$ac_INSTALL&;t t
$ac_datarootdir_hack
"
-eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
- >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
+ || as_fn_error "could not create $ac_file" "$LINENO" 5
test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
- { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
- { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
- "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined. Please make sure it is defined" >&5
+which seems to be undefined. Please make sure it is defined." >&5
$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined. Please make sure it is defined" >&2;}
+which seems to be undefined. Please make sure it is defined." >&2;}
- rm -f "$ac_tmp/stdin"
+ rm -f "$tmp/stdin"
case $ac_file in
- -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
- *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ -) cat "$tmp/out" && rm -f "$tmp/out";;
+ *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
esac \
- || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ || as_fn_error "could not create $ac_file" "$LINENO" 5
;;
:H)
#
@@ -31801,21 +31846,21 @@ which seems to be undefined. Please make sure it is defined" >&2;}
if test x"$ac_file" != x-; then
{
$as_echo "/* $configure_input */" \
- && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
- } >"$ac_tmp/config.h" \
- || as_fn_error $? "could not create $ac_file" "$LINENO" 5
- if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
+ } >"$tmp/config.h" \
+ || as_fn_error "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
$as_echo "$as_me: $ac_file is unchanged" >&6;}
else
rm -f "$ac_file"
- mv "$ac_tmp/config.h" "$ac_file" \
- || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ mv "$tmp/config.h" "$ac_file" \
+ || as_fn_error "could not create $ac_file" "$LINENO" 5
fi
else
$as_echo "/* $configure_input */" \
- && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
- || as_fn_error $? "could not create -" "$LINENO" 5
+ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error "could not create -" "$LINENO" 5
fi
;;
@@ -31830,7 +31875,7 @@ _ACEOF
ac_clean_files=$ac_clean_files_save
test $ac_write_fail = 0 ||
- as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+ as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5
# configure is writing to config.log, and then calls config.status.
@@ -31851,7 +31896,7 @@ if test "$no_create" != yes; then
exec 5>>config.log
# Use ||, not &&, to avoid exiting from the if with $? = 1, which
# would make configure fail if this is the last instruction.
- $ac_cs_success || as_fn_exit 1
+ $ac_cs_success || as_fn_exit $?
fi
if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in
index f7294b36e..60f2068e5 100644
--- a/include/asterisk/autoconfig.h.in
+++ b/include/asterisk/autoconfig.h.in
@@ -294,7 +294,7 @@
/* Define if your system has the GLOB_NOMAGIC headers. */
#undef HAVE_GLOB_NOMAGIC
-/* Define if your system has the GMIME libraries. */
+/* Define to 1 if you have the GMime library. */
#undef HAVE_GMIME
/* Define to indicate the GSM library */
@@ -306,7 +306,7 @@
/* Define to indicate that gsm.h has no prefix for its location */
#undef HAVE_GSM_HEADER
-/* Define if your system has the GTK2 libraries. */
+/* Define to 1 if you have the gtk2 library. */
#undef HAVE_GTK2
/* Define to 1 if you have the Hoard Memory Allocator library. */
@@ -324,7 +324,7 @@
/* Define to 1 if you have the Iksemel Jabber library. */
#undef HAVE_IKSEMEL
-/* Define if your system has the ILBC libraries. */
+/* Define to 1 if you have the System iLBC library. */
#undef HAVE_ILBC
/* Define if your system has the UW IMAP Toolkit c-client library. */
@@ -376,7 +376,7 @@
/* Define to 1 if you have the OpenLDAP library. */
#undef HAVE_LDAP
-/* Define if your system has the LIBEDIT libraries. */
+/* Define to 1 if you have the NetBSD Editline library library. */
#undef HAVE_LIBEDIT
/* Define to 1 if you have the <libintl.h> header file. */
@@ -551,7 +551,7 @@
/* Define to indicate presence of the pg_encoding_to_char API. */
#undef HAVE_PGSQL_pg_encoding_to_char
-/* Define if your system has the PJPROJECT libraries. */
+/* Define to 1 if you have the PJPROJECT library. */
#undef HAVE_PJPROJECT
/* Define to 1 if your system defines IP_PKTINFO. */
@@ -854,19 +854,19 @@
/* Define to 1 if you have the `strtoq' function. */
#undef HAVE_STRTOQ
-/* Define to 1 if `ifr_ifru.ifru_hwaddr' is a member of `struct ifreq'. */
+/* Define to 1 if `ifr_ifru.ifru_hwaddr' is member of `struct ifreq'. */
#undef HAVE_STRUCT_IFREQ_IFR_IFRU_IFRU_HWADDR
-/* Define to 1 if `uid' is a member of `struct sockpeercred'. */
+/* Define to 1 if `uid' is member of `struct sockpeercred'. */
#undef HAVE_STRUCT_SOCKPEERCRED_UID
-/* Define to 1 if `st_blksize' is a member of `struct stat'. */
+/* Define to 1 if `st_blksize' is member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_BLKSIZE
-/* Define to 1 if `cr_uid' is a member of `struct ucred'. */
+/* Define to 1 if `cr_uid' is member of `struct ucred'. */
#undef HAVE_STRUCT_UCRED_CR_UID
-/* Define to 1 if `uid' is a member of `struct ucred'. */
+/* Define to 1 if `uid' is member of `struct ucred'. */
#undef HAVE_STRUCT_UCRED_UID
/* Define to 1 if you have the mISDN Supplemental Services library. */
@@ -1144,12 +1144,12 @@
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
-/* Define to the home page for this package. */
-#undef PACKAGE_URL
-
/* Define to the version of this package. */
#undef PACKAGE_VERSION
+/* Define to 1 if the C compiler supports function prototypes. */
+#undef PROTOTYPES
+
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#undef PTHREAD_CREATE_JOINABLE
@@ -1169,6 +1169,11 @@
/* Define to the type of arg 5 for `select'. */
#undef SELECT_TYPE_ARG5
+/* Define to 1 if the `setvbuf' function takes the buffering type as its
+ second argument and the buffer pointer as the third, as on System V before
+ release 3. */
+#undef SETVBUF_REVERSED
+
/* The size of `char *', as computed by sizeof. */
#undef SIZEOF_CHAR_P
@@ -1204,39 +1209,24 @@
/* Define to a type of the same size as fd_set.fds_bits[[0]] */
#undef TYPEOF_FD_SET_FDS_BITS
-/* Enable extensions on AIX 3, Interix. */
+/* Define to 1 if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
-/* Enable GNU extensions on systems that have them. */
-#ifndef _GNU_SOURCE
-# undef _GNU_SOURCE
-#endif
-/* Enable threading extensions on Solaris. */
-#ifndef _POSIX_PTHREAD_SEMANTICS
-# undef _POSIX_PTHREAD_SEMANTICS
-#endif
-/* Enable extensions on HP NonStop. */
-#ifndef _TANDEM_SOURCE
-# undef _TANDEM_SOURCE
-#endif
-/* Enable general extensions on Solaris. */
-#ifndef __EXTENSIONS__
-# undef __EXTENSIONS__
-#endif
-
/* Define to 1 if running on Darwin. */
#undef _DARWIN_UNLIMITED_SELECT
-/* Enable large inode numbers on Mac OS X 10.5. */
-#ifndef _DARWIN_USE_64_BIT_INODE
-# define _DARWIN_USE_64_BIT_INODE 1
-#endif
-
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+
/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
#undef _LARGEFILE_SOURCE
@@ -1253,6 +1243,20 @@
/* Define to 1 if you need to in order for `stat' and other things to work. */
#undef _POSIX_SOURCE
+/* Enable extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+
+/* Define like PROTOTYPES; this can be used by system headers. */
+#undef __PROTOTYPES
+
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
diff --git a/include/asterisk/res_sip.h b/include/asterisk/res_sip.h
new file mode 100644
index 000000000..7cfc38260
--- /dev/null
+++ b/include/asterisk/res_sip.h
@@ -0,0 +1,1092 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#ifndef _RES_SIP_H
+#define _RES_SIP_H
+
+#include "asterisk/stringfields.h"
+/* Needed for struct ast_sockaddr */
+#include "asterisk/netsock2.h"
+/* Needed for linked list macros */
+#include "asterisk/linkedlists.h"
+/* Needed for ast_party_id */
+#include "asterisk/channel.h"
+/* Needed for ast_sorcery */
+#include "asterisk/sorcery.h"
+/* Needed for ast_dnsmgr */
+#include "asterisk/dnsmgr.h"
+/* Needed for pj_sockaddr */
+#include <pjlib.h>
+
+/* Forward declarations of PJSIP stuff */
+struct pjsip_rx_data;
+struct pjsip_module;
+struct pjsip_tx_data;
+struct pjsip_dialog;
+struct pjsip_transport;
+struct pjsip_tpfactory;
+struct pjsip_tls_setting;
+struct pjsip_tpselector;
+
+/*!
+ * \brief Structure for SIP transport information
+ */
+struct ast_sip_transport_state {
+ /*! \brief Transport itself */
+ struct pjsip_transport *transport;
+
+ /*! \brief Transport factory */
+ struct pjsip_tpfactory *factory;
+};
+
+#define SIP_SORCERY_DOMAIN_ALIAS_TYPE "domain_alias"
+
+/*!
+ * Details about a SIP domain alias
+ */
+struct ast_sip_domain_alias {
+ /*! Sorcery object details */
+ SORCERY_OBJECT(details);
+ AST_DECLARE_STRING_FIELDS(
+ /*! Domain to be aliased to */
+ AST_STRING_FIELD(domain);
+ );
+};
+
+/*!
+ * \brief Types of supported transports
+ */
+enum ast_sip_transport_type {
+ AST_SIP_TRANSPORT_UDP,
+ AST_SIP_TRANSPORT_TCP,
+ AST_SIP_TRANSPORT_TLS,
+ /* XXX Websocket ? */
+};
+
+/*! \brief Maximum number of ciphers supported for a TLS transport */
+#define SIP_TLS_MAX_CIPHERS 64
+
+/*
+ * \brief Transport to bind to
+ */
+struct ast_sip_transport {
+ /*! Sorcery object details */
+ SORCERY_OBJECT(details);
+ AST_DECLARE_STRING_FIELDS(
+ /*! Certificate of authority list file */
+ AST_STRING_FIELD(ca_list_file);
+ /*! Public certificate file */
+ AST_STRING_FIELD(cert_file);
+ /*! Optional private key of the certificate file */
+ AST_STRING_FIELD(privkey_file);
+ /*! Password to open the private key */
+ AST_STRING_FIELD(password);
+ /*! External signaling address */
+ AST_STRING_FIELD(external_signaling_address);
+ /*! External media address */
+ AST_STRING_FIELD(external_media_address);
+ /*! Optional domain to use for messages if provided could not be found */
+ AST_STRING_FIELD(domain);
+ );
+ /*! Type of transport */
+ enum ast_sip_transport_type type;
+ /*! Address and port to bind to */
+ pj_sockaddr host;
+ /*! Number of simultaneous asynchronous operations */
+ unsigned int async_operations;
+ /*! Optional external port for signaling */
+ unsigned int external_signaling_port;
+ /*! TLS settings */
+ pjsip_tls_setting tls;
+ /*! Configured TLS ciphers */
+ pj_ssl_cipher ciphers[SIP_TLS_MAX_CIPHERS];
+ /*! Optional local network information, used for NAT purposes */
+ struct ast_ha *localnet;
+ /*! DNS manager for refreshing the external address */
+ struct ast_dnsmgr_entry *external_address_refresher;
+ /*! Optional external address information */
+ struct ast_sockaddr external_address;
+ /*! Transport state information */
+ struct ast_sip_transport_state *state;
+};
+
+/*!
+ * \brief Structure for SIP nat hook information
+ */
+struct ast_sip_nat_hook {
+ /*! Sorcery object details */
+ SORCERY_OBJECT(details);
+ /*! Callback for when a message is going outside of our local network */
+ void (*outgoing_external_message)(struct pjsip_tx_data *tdata, struct ast_sip_transport *transport);
+};
+
+/*!
+ * \brief Contact associated with an address of record
+ */
+struct ast_sip_contact {
+ /*! Sorcery object details, the id is the aor name plus a random string */
+ SORCERY_OBJECT(details);
+ AST_DECLARE_STRING_FIELDS(
+ /*! Full URI of the contact */
+ AST_STRING_FIELD(uri);
+ );
+ /*! Absolute time that this contact is no longer valid after */
+ struct timeval expiration_time;
+};
+
+/*!
+ * \brief A SIP address of record
+ */
+struct ast_sip_aor {
+ /*! Sorcery object details, the id is the AOR name */
+ SORCERY_OBJECT(details);
+ AST_DECLARE_STRING_FIELDS(
+ /*! Voicemail boxes for this AOR */
+ AST_STRING_FIELD(mailboxes);
+ );
+ /*! Minimum expiration time */
+ unsigned int minimum_expiration;
+ /*! Maximum expiration time */
+ unsigned int maximum_expiration;
+ /*! Default contact expiration if one is not provided in the contact */
+ unsigned int default_expiration;
+ /*! Maximum number of external contacts, 0 to disable */
+ unsigned int max_contacts;
+ /*! Whether to remove any existing contacts not related to an incoming REGISTER when it comes in */
+ unsigned int remove_existing;
+ /*! Any permanent configured contacts */
+ struct ao2_container *permanent_contacts;
+};
+
+/*!
+ * \brief DTMF modes for SIP endpoints
+ */
+enum ast_sip_dtmf_mode {
+ /*! No DTMF to be used */
+ AST_SIP_DTMF_NONE,
+ /* XXX Should this be 2833 instead? */
+ /*! Use RFC 4733 events for DTMF */
+ AST_SIP_DTMF_RFC_4733,
+ /*! Use DTMF in the audio stream */
+ AST_SIP_DTMF_INBAND,
+ /*! Use SIP INFO DTMF (blech) */
+ AST_SIP_DTMF_INFO,
+};
+
+/*!
+ * \brief Methods of storing SIP digest authentication credentials.
+ *
+ * Note that both methods result in MD5 digest authentication being
+ * used. The two methods simply alter how Asterisk determines the
+ * credentials for a SIP authentication
+ */
+enum ast_sip_auth_type {
+ /*! Credentials stored as a username and password combination */
+ AST_SIP_AUTH_TYPE_USER_PASS,
+ /*! Credentials stored as an MD5 sum */
+ AST_SIP_AUTH_TYPE_MD5,
+};
+
+#define SIP_SORCERY_AUTH_TYPE "auth"
+
+struct ast_sip_auth {
+ /* Sorcery ID of the auth is its name */
+ SORCERY_OBJECT(details);
+ AST_DECLARE_STRING_FIELDS(
+ /* Identification for these credentials */
+ AST_STRING_FIELD(realm);
+ /* Authentication username */
+ AST_STRING_FIELD(auth_user);
+ /* Authentication password */
+ AST_STRING_FIELD(auth_pass);
+ /* Authentication credentials in MD5 format (hash of user:realm:pass) */
+ AST_STRING_FIELD(md5_creds);
+ );
+ /* The time period (in seconds) that a nonce may be reused */
+ unsigned int nonce_lifetime;
+ /* Used to determine what to use when authenticating */
+ enum ast_sip_auth_type type;
+};
+
+/*!
+ * \brief Different methods by which incoming requests can be matched to endpoints
+ */
+enum ast_sip_endpoint_identifier_type {
+ /*! Identify based on user name in From header */
+ AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME = (1 << 0),
+ /*! Identify based on source location of the SIP message */
+ AST_SIP_ENDPOINT_IDENTIFY_BY_LOCATION = (1 << 1),
+};
+
+enum ast_sip_session_refresh_method {
+ /*! Use reinvite to negotiate direct media */
+ AST_SIP_SESSION_REFRESH_METHOD_INVITE,
+ /*! Use UPDATE to negotiate direct media */
+ AST_SIP_SESSION_REFRESH_METHOD_UPDATE,
+};
+
+enum ast_sip_direct_media_glare_mitigation {
+ /*! Take no special action to mitigate reinvite glare */
+ AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE,
+ /*! Do not send an initial direct media session refresh on outgoing call legs
+ * Subsequent session refreshes will be sent no matter the session direction
+ */
+ AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING,
+ /*! Do not send an initial direct media session refresh on incoming call legs
+ * Subsequent session refreshes will be sent no matter the session direction
+ */
+ AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING,
+};
+
+/*!
+ * \brief An entity with which Asterisk communicates
+ */
+struct ast_sip_endpoint {
+ SORCERY_OBJECT(details);
+ AST_DECLARE_STRING_FIELDS(
+ /*! Context to send incoming calls to */
+ AST_STRING_FIELD(context);
+ /*! Name of an explicit transport to use */
+ AST_STRING_FIELD(transport);
+ /*! Outbound proxy to use */
+ AST_STRING_FIELD(outbound_proxy);
+ /*! Explicit AORs to dial if none are specified */
+ AST_STRING_FIELD(aors);
+ /*! Musiconhold class to suggest that the other side use when placing on hold */
+ AST_STRING_FIELD(mohsuggest);
+ /*! Optional external media address to use in SDP */
+ AST_STRING_FIELD(external_media_address);
+ /*! Configured voicemail boxes for this endpoint. Used for MWI */
+ AST_STRING_FIELD(mailboxes);
+ );
+ /*! Identification information for this endpoint */
+ struct ast_party_id id;
+ /*! Domain to which this endpoint belongs */
+ struct ast_sip_domain *domain;
+ /*! Address of record for incoming registrations */
+ struct ast_sip_aor *aor;
+ /*! Codec preferences */
+ struct ast_codec_pref prefs;
+ /*! Configured codecs */
+ struct ast_format_cap *codecs;
+ /*! Names of inbound authentication credentials */
+ const char **sip_inbound_auths;
+ /*! Number of configured auths */
+ size_t num_inbound_auths;
+ /*! Names of outbound authentication credentials */
+ const char **sip_outbound_auths;
+ /*! Number of configured outbound auths */
+ size_t num_outbound_auths;
+ /*! DTMF mode to use with this endpoint */
+ enum ast_sip_dtmf_mode dtmf;
+ /*! Whether IPv6 RTP is enabled or not */
+ unsigned int rtp_ipv6;
+ /*! Whether symmetric RTP is enabled or not */
+ unsigned int rtp_symmetric;
+ /*! Whether ICE support is enabled or not */
+ unsigned int ice_support;
+ /*! Whether to use the "ptime" attribute received from the endpoint or not */
+ unsigned int use_ptime;
+ /*! Whether to force using the source IP address/port for sending responses */
+ unsigned int force_rport;
+ /*! Whether to rewrite the Contact header with the source IP address/port or not */
+ unsigned int rewrite_contact;
+ /*! Enabled SIP extensions */
+ unsigned int extensions;
+ /*! Minimum session expiration period, in seconds */
+ unsigned int min_se;
+ /*! Session expiration period, in seconds */
+ unsigned int sess_expires;
+ /*! List of outbound registrations */
+ AST_LIST_HEAD_NOLOCK(, ast_sip_registration) registrations;
+ /*! Frequency to send OPTIONS requests to endpoint. 0 is disabled. */
+ unsigned int qualify_frequency;
+ /*! Method(s) by which the endpoint should be identified. */
+ enum ast_sip_endpoint_identifier_type ident_method;
+ /*! Boolean indicating if direct_media is permissible */
+ unsigned int direct_media;
+ /*! When using direct media, which method should be used */
+ enum ast_sip_session_refresh_method direct_media_method;
+ /*! Take steps to mitigate glare for direct media */
+ enum ast_sip_direct_media_glare_mitigation direct_media_glare_mitigation;
+ /*! Do not attempt direct media session refreshes if a media NAT is detected */
+ unsigned int disable_direct_media_on_nat;
+ /*! Do we trust the endpoint with our outbound identity? */
+ unsigned int trust_id_outbound;
+ /*! Do we trust identity information that originates externally (e.g. P-Asserted-Identity header)? */
+ unsigned int trust_id_inbound;
+ /*! Do we send P-Asserted-Identity headers to this endpoint? */
+ unsigned int send_pai;
+ /*! Do we send Remote-Party-ID headers to this endpoint? */
+ unsigned int send_rpid;
+ /*! Should unsolicited MWI be aggregated into a single NOTIFY? */
+ unsigned int aggregate_mwi;
+};
+
+/*!
+ * \brief Possible returns from ast_sip_check_authentication
+ */
+enum ast_sip_check_auth_result {
+ /*! Authentication needs to be challenged */
+ AST_SIP_AUTHENTICATION_CHALLENGE,
+ /*! Authentication succeeded */
+ AST_SIP_AUTHENTICATION_SUCCESS,
+ /*! Authentication failed */
+ AST_SIP_AUTHENTICATION_FAILED,
+ /*! Authentication encountered some internal error */
+ AST_SIP_AUTHENTICATION_ERROR,
+};
+
+/*!
+ * \brief An interchangeable way of handling digest authentication for SIP.
+ *
+ * An authenticator is responsible for filling in the callbacks provided below. Each is called from a publicly available
+ * function in res_sip. The authenticator can use configuration or other local policy to determine whether authentication
+ * should take place and what credentials should be used when challenging and authenticating a request.
+ */
+struct ast_sip_authenticator {
+ /*!
+ * \brief Check if a request requires authentication
+ * See ast_sip_requires_authentication for more details
+ */
+ int (*requires_authentication)(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
+ /*!
+ * \brief Check that an incoming request passes authentication.
+ *
+ * The tdata parameter is useful for adding information such as digest challenges.
+ *
+ * \param endpoint The endpoint sending the incoming request
+ * \param rdata The incoming request
+ * \param tdata Tentative outgoing request.
+ */
+ enum ast_sip_check_auth_result (*check_authentication)(struct ast_sip_endpoint *endpoint,
+ pjsip_rx_data *rdata, pjsip_tx_data *tdata);
+};
+
+/*!
+ * \brief an interchangeable way of responding to authentication challenges
+ *
+ * An outbound authenticator takes incoming challenges and formulates a new SIP request with
+ * credentials.
+ */
+struct ast_sip_outbound_authenticator {
+ /*!
+ * \brief Create a new request with authentication credentials
+ *
+ * \param auths An array of IDs of auth sorcery objects
+ * \param num_auths The number of IDs in the array
+ * \param challenge The SIP response with authentication challenge(s)
+ * \param tsx The transaction in which the challenge was received
+ * \param new_request The new SIP request with challenge response(s)
+ * \retval 0 Successfully created new request
+ * \retval -1 Failed to create a new request
+ */
+ int (*create_request_with_auth)(const char **auths, size_t num_auths, struct pjsip_rx_data *challenge,
+ struct pjsip_transaction *tsx, struct pjsip_tx_data **new_request);
+};
+
+/*!
+ * \brief An entity responsible for identifying the source of a SIP message
+ */
+struct ast_sip_endpoint_identifier {
+ /*!
+ * \brief Callback used to identify the source of a message.
+ * See ast_sip_identify_endpoint for more details
+ */
+ struct ast_sip_endpoint *(*identify_endpoint)(pjsip_rx_data *rdata);
+};
+
+/*!
+ * \brief Register a SIP service in Asterisk.
+ *
+ * This is more-or-less a wrapper around pjsip_endpt_register_module().
+ * Registering a service makes it so that PJSIP will call into the
+ * service at appropriate times. For more information about PJSIP module
+ * callbacks, see the PJSIP documentation. Asterisk modules that call
+ * this function will likely do so at module load time.
+ *
+ * \param module The module that is to be registered with PJSIP
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_register_service(pjsip_module *module);
+
+/*!
+ * This is the opposite of ast_sip_register_service(). Unregistering a
+ * service means that PJSIP will no longer call into the module any more.
+ * This will likely occur when an Asterisk module is unloaded.
+ *
+ * \param module The PJSIP module to unregister
+ */
+void ast_sip_unregister_service(pjsip_module *module);
+
+/*!
+ * \brief Register a SIP authenticator
+ *
+ * An authenticator has three main purposes:
+ * 1) Determining if authentication should be performed on an incoming request
+ * 2) Gathering credentials necessary for issuing an authentication challenge
+ * 3) Authenticating a request that has credentials
+ *
+ * Asterisk provides a default authenticator, but it may be replaced by a
+ * custom one if desired.
+ *
+ * \param auth The authenticator to register
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_register_authenticator(struct ast_sip_authenticator *auth);
+
+/*!
+ * \brief Unregister a SIP authenticator
+ *
+ * When there is no authenticator registered, requests cannot be challenged
+ * or authenticated.
+ *
+ * \param auth The authenticator to unregister
+ */
+void ast_sip_unregister_authenticator(struct ast_sip_authenticator *auth);
+
+ /*!
+ * \brief Register an outbound SIP authenticator
+ *
+ * An outbound authenticator is responsible for creating responses to
+ * authentication challenges by remote endpoints.
+ *
+ * \param auth The authenticator to register
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_register_outbound_authenticator(struct ast_sip_outbound_authenticator *outbound_auth);
+
+/*!
+ * \brief Unregister an outbound SIP authenticator
+ *
+ * When there is no outbound authenticator registered, authentication challenges
+ * will be handled as any other final response would be.
+ *
+ * \param auth The authenticator to unregister
+ */
+void ast_sip_unregister_outbound_authenticator(struct ast_sip_outbound_authenticator *auth);
+
+/*!
+ * \brief Register a SIP endpoint identifier
+ *
+ * An endpoint identifier's purpose is to determine which endpoint a given SIP
+ * message has come from.
+ *
+ * Multiple endpoint identifiers may be registered so that if an endpoint
+ * cannot be identified by one identifier, it may be identified by another.
+ *
+ * Asterisk provides two endpoint identifiers. One identifies endpoints based
+ * on the user part of the From header URI. The other identifies endpoints based
+ * on the source IP address.
+ *
+ * If the order in which endpoint identifiers is run is important to you, then
+ * be sure to load individual endpoint identifier modules in the order you wish
+ * for them to be run in modules.conf
+ *
+ * \param identifier The SIP endpoint identifier to register
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_register_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier);
+
+/*!
+ * \brief Unregister a SIP endpoint identifier
+ *
+ * This stops an endpoint identifier from being used.
+ *
+ * \param identifier The SIP endoint identifier to unregister
+ */
+void ast_sip_unregister_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier);
+
+/*!
+ * \brief Allocate a new SIP endpoint
+ *
+ * This will return an endpoint with its refcount increased by one. This reference
+ * can be released using ao2_ref().
+ *
+ * \param name The name of the endpoint.
+ * \retval NULL Endpoint allocation failed
+ * \retval non-NULL The newly allocated endpoint
+ */
+void *ast_sip_endpoint_alloc(const char *name);
+
+/*!
+ * \brief Get a pointer to the PJSIP endpoint.
+ *
+ * This is useful when modules have specific information they need
+ * to register with the PJSIP core.
+ * \retval NULL endpoint has not been created yet.
+ * \retval non-NULL PJSIP endpoint.
+ */
+pjsip_endpoint *ast_sip_get_pjsip_endpoint(void);
+
+/*!
+ * \brief Get a pointer to the SIP sorcery structure.
+ *
+ * \retval NULL sorcery has not been initialized
+ * \retval non-NULL sorcery structure
+ */
+struct ast_sorcery *ast_sip_get_sorcery(void);
+
+/*!
+ * \brief Initialize transport support on a sorcery instance
+ *
+ * \param sorcery The sorcery instance
+ *
+ * \retval -1 failure
+ * \retval 0 success
+ */
+int ast_sip_initialize_sorcery_transport(struct ast_sorcery *sorcery);
+
+/*!
+ * \brief Initialize location support on a sorcery instance
+ *
+ * \param sorcery The sorcery instance
+ *
+ * \retval -1 failure
+ * \retval 0 success
+ */
+int ast_sip_initialize_sorcery_location(struct ast_sorcery *sorcery);
+
+/*!
+ * \brief Retrieve a named AOR
+ *
+ * \param aor_name Name of the AOR
+ *
+ * \retval NULL if not found
+ * \retval non-NULL if found
+ */
+struct ast_sip_aor *ast_sip_location_retrieve_aor(const char *aor_name);
+
+/*!
+ * \brief Retrieve the first bound contact for an AOR
+ *
+ * \param aor Pointer to the AOR
+ * \retval NULL if no contacts available
+ * \retval non-NULL if contacts available
+ */
+struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct ast_sip_aor *aor);
+
+/*!
+ * \brief Retrieve all contacts currently available for an AOR
+ *
+ * \param aor Pointer to the AOR
+ *
+ * \retval NULL if no contacts available
+ * \retval non-NULL if contacts available
+ */
+struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor);
+
+/*!
+ * \brief Retrieve the first bound contact from a list of AORs
+ *
+ * \param aor_list A comma-separated list of AOR names
+ * \retval NULL if no contacts available
+ * \retval non-NULL if contacts available
+ */
+struct ast_sip_contact *ast_sip_location_retrieve_contact_from_aor_list(const char *aor_list);
+
+/*!
+ * \brief Retrieve a named contact
+ *
+ * \param contact_name Name of the contact
+ *
+ * \retval NULL if not found
+ * \retval non-NULL if found
+ */
+struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_name);
+
+/*!
+ * \brief Add a new contact to an AOR
+ *
+ * \param aor Pointer to the AOR
+ * \param uri Full contact URI
+ * \param expiration_time Optional expiration time of the contact
+ *
+ * \retval -1 failure
+ * \retval 0 success
+ */
+int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time);
+
+/*!
+ * \brief Update a contact
+ *
+ * \param contact New contact object with details
+ *
+ * \retval -1 failure
+ * \retval 0 success
+ */
+int ast_sip_location_update_contact(struct ast_sip_contact *contact);
+
+/*!
+* \brief Delete a contact
+*
+* \param contact Contact object to delete
+*
+* \retval -1 failure
+* \retval 0 success
+*/
+int ast_sip_location_delete_contact(struct ast_sip_contact *contact);
+
+/*!
+ * \brief Initialize domain aliases support on a sorcery instance
+ *
+ * \param sorcery The sorcery instance
+ *
+ * \retval -1 failure
+ * \retval 0 success
+ */
+int ast_sip_initialize_sorcery_domain_alias(struct ast_sorcery *sorcery);
+
+/*!
+ * \brief Initialize authentication support on a sorcery instance
+ *
+ * \param sorcery The sorcery instance
+ *
+ * \retval -1 failure
+ * \retval 0 success
+ */
+int ast_sip_initialize_sorcery_auth(struct ast_sorcery *sorcery);
+
+/*!
+ * \brief Callback called when an outbound request with authentication credentials is to be sent in dialog
+ *
+ * This callback will have the created request on it. The callback's purpose is to do any extra
+ * housekeeping that needs to be done as well as to send the request out.
+ *
+ * This callback is only necessary if working with a PJSIP API that sits between the application
+ * and the dialog layer.
+ *
+ * \param dlg The dialog to which the request belongs
+ * \param tdata The created request to be sent out
+ * \param user_data Data supplied with the callback
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+typedef int (*ast_sip_dialog_outbound_auth_cb)(pjsip_dialog *dlg, pjsip_tx_data *tdata, void *user_data);
+
+/*!
+ * \brief Set up outbound authentication on a SIP dialog
+ *
+ * This sets up the infrastructure so that all requests associated with a created dialog
+ * can be re-sent with authentication credentials if the original request is challenged.
+ *
+ * \param dlg The dialog on which requests will be authenticated
+ * \param endpoint The endpoint whom this dialog pertains to
+ * \param cb Callback to call to send requests with authentication
+ * \param user_data Data to be provided to the callback when it is called
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_dialog_setup_outbound_authentication(pjsip_dialog *dlg, const struct ast_sip_endpoint *endpoint,
+ ast_sip_dialog_outbound_auth_cb cb, void *user_data);
+
+/*!
+ * \brief Initialize the distributor module
+ *
+ * The distributor module is responsible for taking an incoming
+ * SIP message and placing it into the threadpool. Once in the threadpool,
+ * the distributor will perform endpoint lookups and authentication, and
+ * then distribute the message up the stack to any further modules.
+ *
+ * \retval -1 Failure
+ * \retval 0 Success
+ */
+int ast_sip_initialize_distributor(void);
+
+/*!
+ * \page Threading model for SIP
+ *
+ * There are three major types of threads that SIP will have to deal with:
+ * \li Asterisk threads
+ * \li PJSIP threads
+ * \li SIP threadpool threads (a.k.a. "servants")
+ *
+ * \par Asterisk Threads
+ *
+ * Asterisk threads are those that originate from outside of SIP but within
+ * Asterisk. The most common of these threads are PBX (channel) threads and
+ * the autoservice thread. Most interaction with these threads will be through
+ * channel technology callbacks. Within these threads, it is fine to handle
+ * Asterisk data from outside of SIP, but any handling of SIP data should be
+ * left to servants, \b especially if you wish to call into PJSIP for anything.
+ * Asterisk threads are not registered with PJLIB, so attempting to call into
+ * PJSIP will cause an assertion to be triggered, thus causing the program to
+ * crash.
+ *
+ * \par PJSIP Threads
+ *
+ * PJSIP threads are those that originate from handling of PJSIP events, such
+ * as an incoming SIP request or response, or a transaction timeout. The role
+ * of these threads is to process information as quickly as possible so that
+ * the next item on the SIP socket(s) can be serviced. On incoming messages,
+ * Asterisk automatically will push the request to a servant thread. When your
+ * module callback is called, processing will already be in a servant. However,
+ * for other PSJIP events, such as transaction state changes due to timer
+ * expirations, your module will be called into from a PJSIP thread. If you
+ * are called into from a PJSIP thread, then you should push whatever processing
+ * is needed to a servant as soon as possible. You can discern if you are currently
+ * in a SIP servant thread using the \ref ast_sip_thread_is_servant function.
+ *
+ * \par Servants
+ *
+ * Servants are where the bulk of SIP work should be performed. These threads
+ * exist in order to do the work that Asterisk threads and PJSIP threads hand
+ * off to them. Servant threads register themselves with PJLIB, meaning that
+ * they are capable of calling PJSIP and PJLIB functions if they wish.
+ *
+ * \par Serializer
+ *
+ * Tasks are handed off to servant threads using the API call \ref ast_sip_push_task.
+ * The first parameter of this call is a serializer. If this pointer
+ * is NULL, then the work will be handed off to whatever servant can currently handle
+ * the task. If this pointer is non-NULL, then the task will not be executed until
+ * previous tasks pushed with the same serializer have completed. For more information
+ * on serializers and the benefits they provide, see \ref ast_threadpool_serializer
+ *
+ * \note
+ *
+ * Do not make assumptions about individual threads based on a corresponding serializer.
+ * In other words, just because several tasks use the same serializer when being pushed
+ * to servants, it does not mean that the same thread is necessarily going to execute those
+ * tasks, even though they are all guaranteed to be executed in sequence.
+ */
+
+/*!
+ * \brief Create a new serializer for SIP tasks
+ *
+ * See \ref ast_threadpool_serializer for more information on serializers.
+ * SIP creates serializers so that tasks operating on similar data will run
+ * in sequence.
+ *
+ * \retval NULL Failure
+ * \retval non-NULL Newly-created serializer
+ */
+struct ast_taskprocessor *ast_sip_create_serializer(void);
+
+/*!
+ * \brief Set a serializer on a SIP dialog so requests and responses are automatically serialized
+ *
+ * Passing a NULL serializer is a way to remove a serializer from a dialog.
+ *
+ * \param dlg The SIP dialog itself
+ * \param serializer The serializer to use
+ */
+void ast_sip_dialog_set_serializer(pjsip_dialog *dlg, struct ast_taskprocessor *serializer);
+
+/*!
+ * \brief Set an endpoint on a SIP dialog so in-dialog requests do not undergo endpoint lookup.
+ *
+ * \param dlg The SIP dialog itself
+ * \param endpoint The endpoint that this dialog is communicating with
+ */
+void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint);
+
+/*!
+ * \brief Get the endpoint associated with this dialog
+ *
+ * This function increases the refcount of the endpoint by one. Release
+ * the reference once you are finished with the endpoint.
+ *
+ * \param dlg The SIP dialog from which to retrieve the endpoint
+ * \retval NULL No endpoint associated with this dialog
+ * \retval non-NULL The endpoint.
+ */
+struct ast_sip_endpoint *ast_sip_dialog_get_endpoint(pjsip_dialog *dlg);
+
+/*!
+ * \brief Pushes a task to SIP servants
+ *
+ * This uses the serializer provided to determine how to push the task.
+ * If the serializer is NULL, then the task will be pushed to the
+ * servants directly. If the serializer is non-NULL, then the task will be
+ * queued behind other tasks associated with the same serializer.
+ *
+ * \param serializer The serializer to which the task belongs. Can be NULL
+ * \param sip_task The task to execute
+ * \param task_data The parameter to pass to the task when it executes
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_push_task(struct ast_taskprocessor *serializer, int (*sip_task)(void *), void *task_data);
+
+/*!
+ * \brief Push a task to SIP servants and wait for it to complete
+ *
+ * Like \ref ast_sip_push_task except that it blocks until the task completes.
+ *
+ * \warning \b Never use this function in a SIP servant thread. This can potentially
+ * cause a deadlock. If you are in a SIP servant thread, just call your function
+ * in-line.
+ *
+ * \param serializer The SIP serializer to which the task belongs. May be NULL.
+ * \param sip_task The task to execute
+ * \param task_data The parameter to pass to the task when it executes
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_push_task_synchronous(struct ast_taskprocessor *serializer, int (*sip_task)(void *), void *task_data);
+
+/*!
+ * \brief Determine if the current thread is a SIP servant thread
+ *
+ * \retval 0 This is not a SIP servant thread
+ * \retval 1 This is a SIP servant thread
+ */
+int ast_sip_thread_is_servant(void);
+
+/*!
+ * \brief SIP body description
+ *
+ * This contains a type and subtype that will be added as
+ * the "Content-Type" for the message as well as the body
+ * text.
+ */
+struct ast_sip_body {
+ /*! Type of the body, such as "application" */
+ const char *type;
+ /*! Subtype of the body, such as "sdp" */
+ const char *subtype;
+ /*! The text to go in the body */
+ const char *body_text;
+};
+
+/*!
+ * \brief General purpose method for creating a dialog with an endpoint
+ *
+ * \param endpoint A pointer to the endpoint
+ * \param aor_name Optional name of the AOR to target, may even be an explicit SIP URI
+ * \param request_user Optional user to place into the target URI
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ */
+ pjsip_dialog *ast_sip_create_dialog(const struct ast_sip_endpoint *endpoint, const char *aor_name, const char *request_user);
+
+/*!
+ * \brief General purpose method for creating a SIP request
+ *
+ * Its typical use would be to create one-off requests such as an out of dialog
+ * SIP MESSAGE.
+ *
+ * The request can either be in- or out-of-dialog. If in-dialog, the
+ * dlg parameter MUST be present. If out-of-dialog the endpoint parameter
+ * MUST be present. If both are present, then we will assume that the message
+ * is to be sent in-dialog.
+ *
+ * The uri parameter can be specified if the request should be sent to an explicit
+ * URI rather than one configured on the endpoint.
+ *
+ * \param method The method of the SIP request to send
+ * \param dlg Optional. If specified, the dialog on which to request the message.
+ * \param endpoint Optional. If specified, the request will be created out-of-dialog
+ * to the endpoint.
+ * \param uri Optional. If specified, the request will be sent to this URI rather
+ * than one configured for the endpoint.
+ * \param[out] tdata The newly-created request
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg,
+ struct ast_sip_endpoint *endpoint, const char *uri, pjsip_tx_data **tdata);
+
+/*!
+ * \brief General purpose method for sending a SIP request
+ *
+ * This is a companion function for \ref ast_sip_create_request. The request
+ * created there can be passed to this function, though any request may be
+ * passed in.
+ *
+ * This will automatically set up handling outbound authentication challenges if
+ * they arrive.
+ *
+ * \param tdata The request to send
+ * \param dlg Optional. If specified, the dialog on which the request should be sent
+ * \param endpoint Optional. If specified, the request is sent out-of-dialog to the endpoint.
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint);
+
+/*!
+ * \brief Determine if an incoming request requires authentication
+ *
+ * This calls into the registered authenticator's requires_authentication callback
+ * in order to determine if the request requires authentication.
+ *
+ * If there is no registered authenticator, then authentication will be assumed
+ * not to be required.
+ *
+ * \param endpoint The endpoint from which the request originates
+ * \param rdata The incoming SIP request
+ * \retval non-zero The request requires authentication
+ * \retval 0 The request does not require authentication
+ */
+int ast_sip_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
+
+/*!
+ * \brief Method to determine authentication status of an incoming request
+ *
+ * This will call into a registered authenticator. The registered authenticator will
+ * do what is necessary to determine whether the incoming request passes authentication.
+ * A tentative response is passed into this function so that if, say, a digest authentication
+ * challenge should be sent in the ensuing response, it can be added to the response.
+ *
+ * \param endpoint The endpoint from the request was sent
+ * \param rdata The request to potentially authenticate
+ * \param tdata Tentative response to the request
+ * \return The result of checking authentication.
+ */
+enum ast_sip_check_auth_result ast_sip_check_authentication(struct ast_sip_endpoint *endpoint,
+ pjsip_rx_data *rdata, pjsip_tx_data *tdata);
+
+/*!
+ * \brief Create a response to an authentication challenge
+ *
+ * This will call into an outbound authenticator's create_request_with_auth callback
+ * to create a new request with authentication credentials. See the create_request_with_auth
+ * callback in the \ref ast_sip_outbound_authenticator structure for details about
+ * the parameters and return values.
+ */
+int ast_sip_create_request_with_auth(const char **auths, size_t num_auths, pjsip_rx_data *challenge,
+ pjsip_transaction *tsx, pjsip_tx_data **new_request);
+
+/*!
+ * \brief Determine the endpoint that has sent a SIP message
+ *
+ * This will call into each of the registered endpoint identifiers'
+ * identify_endpoint() callbacks until one returns a non-NULL endpoint.
+ * This will return an ao2 object. Its reference count will need to be
+ * decremented when completed using the endpoint.
+ *
+ * \param rdata The inbound SIP message to use when identifying the endpoint.
+ * \retval NULL No matching endpoint
+ * \retval non-NULL The matching endpoint
+ */
+struct ast_sip_endpoint *ast_sip_identify_endpoint(pjsip_rx_data *rdata);
+
+/*!
+ * \brief Add a header to an outbound SIP message
+ *
+ * \param tdata The message to add the header to
+ * \param name The header name
+ * \param value The header value
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value);
+
+/*!
+ * \brief Add a body to an outbound SIP message
+ *
+ * If this is called multiple times, the latest body will replace the current
+ * body.
+ *
+ * \param tdata The message to add the body to
+ * \param body The message body to add
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_add_body(pjsip_tx_data *tdata, const struct ast_sip_body *body);
+
+/*!
+ * \brief Add a multipart body to an outbound SIP message
+ *
+ * This will treat each part of the input array as part of a multipart body and
+ * add each part to the SIP message.
+ *
+ * \param tdata The message to add the body to
+ * \param bodies The parts of the body to add
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_add_body_multipart(pjsip_tx_data *tdata, const struct ast_sip_body *bodies[], int num_bodies);
+
+/*!
+ * \brief Append body data to a SIP message
+ *
+ * This acts mostly the same as ast_sip_add_body, except that rather than replacing
+ * a body if it currently exists, it appends data to an existing body.
+ *
+ * \param tdata The message to append the body to
+ * \param body The string to append to the end of the current body
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_append_body(pjsip_tx_data *tdata, const char *body_text);
+
+/*!
+ * \brief Copy a pj_str_t into a standard character buffer.
+ *
+ * pj_str_t is not NULL-terminated. Any place that expects a NULL-
+ * terminated string needs to have the pj_str_t copied into a separate
+ * buffer.
+ *
+ * This method copies the pj_str_t contents into the destination buffer
+ * and NULL-terminates the buffer.
+ *
+ * \param dest The destination buffer
+ * \param src The pj_str_t to copy
+ * \param size The size of the destination buffer.
+ */
+void ast_copy_pj_str(char *dest, pj_str_t *src, size_t size);
+
+/*!
+ * \brief Get the looked-up endpoint on an out-of dialog request or response
+ *
+ * The function may ONLY be called on out-of-dialog requests or responses. For
+ * in-dialog requests and responses, it is required that the user of the dialog
+ * has the looked-up endpoint stored locally.
+ *
+ * This function should never return NULL if the message is out-of-dialog. It will
+ * always return NULL if the message is in-dialog.
+ *
+ * This function will increase the reference count of the returned endpoint by one.
+ * Release your reference using the ao2_ref function when finished.
+ *
+ * \param rdata Out-of-dialog request or response
+ * \return The looked up endpoint
+ */
+struct ast_sip_endpoint *ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata);
+
+/*!
+ * \brief Retrieve relevant SIP auth structures from sorcery
+ *
+ * \param auth_names The sorcery IDs of auths to retrieve
+ * \param num_auths The number of auths to retrieve
+ * \param[out] out The retrieved auths are stored here
+ */
+int ast_sip_retrieve_auths(const char *auth_names[], size_t num_auths, struct ast_sip_auth **out);
+
+/*!
+ * \brief Clean up retrieved auth structures from memory
+ *
+ * Call this function once you have completed operating on auths
+ * retrieved from \ref ast_sip_retrieve_auths
+ *
+ * \param auths An array of auth structures to clean up
+ * \param num_auths The number of auths in the array
+ */
+void ast_sip_cleanup_auths(struct ast_sip_auth *auths[], size_t num_auths);
+
+#endif /* _RES_SIP_H */
diff --git a/include/asterisk/res_sip_pubsub.h b/include/asterisk/res_sip_pubsub.h
new file mode 100644
index 000000000..33614b285
--- /dev/null
+++ b/include/asterisk/res_sip_pubsub.h
@@ -0,0 +1,346 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#ifndef _RES_SIP_PUBSUB_H
+#define _RES_SIP_PUBSUB_H
+
+#include "asterisk/linkedlists.h"
+
+/* Forward declarations */
+struct pjsip_rx_data;
+struct pjsip_tx_data;
+struct pjsip_evsub;
+struct ast_sip_endpoint;
+struct ast_datastore;
+struct ast_datastore_info;
+
+/*!
+ * \brief Opaque structure representing an RFC 3265 SIP subscription
+ */
+struct ast_sip_subscription;
+
+/*!
+ * \brief Role for the subscription that is being created
+ */
+enum ast_sip_subscription_role {
+ /* Sending SUBSCRIBEs, receiving NOTIFYs */
+ AST_SIP_SUBSCRIBER,
+ /* Sending NOTIFYs, receiving SUBSCRIBEs */
+ AST_SIP_NOTIFIER,
+};
+
+/*!
+ * \brief Data for responses to SUBSCRIBEs and NOTIFIEs
+ *
+ * Some of PJSIP's evsub callbacks expect us to provide them
+ * with data so that they can craft a response rather than have
+ * us create our own response.
+ *
+ * Filling in the structure is optional, since the framework
+ * will automatically respond with a 200 OK response if we do
+ * not provide it with any additional data.
+ */
+struct ast_sip_subscription_response_data {
+ /*! Status code of the response */
+ int status_code;
+ /*! Optional status text */
+ const char *status_text;
+ /*! Optional additional headers to add to the response */
+ struct ast_variable *headers;
+ /*! Optional body to add to the response */
+ struct ast_sip_body *body;
+};
+
+#define AST_SIP_MAX_ACCEPT 32
+
+struct ast_sip_subscription_handler {
+ /*! The name of the event this handler deals with */
+ const char *event_name;
+ /*! The types of body this handler accepts */
+ const char *accept[AST_SIP_MAX_ACCEPT];
+
+ /*!
+ * \brief Called when a subscription is to be destroyed
+ *
+ * This is a subscriber and notifier callback.
+ *
+ * The handler is not expected to send any sort of requests or responses
+ * during this callback. The handler MUST, however, begin the destruction
+ * process for the subscription during this callback.
+ */
+ void (*subscription_shutdown)(struct ast_sip_subscription *subscription);
+
+ /*!
+ * \brief Called when a SUBSCRIBE arrives in order to create a new subscription
+ *
+ * This is a notifier callback.
+ *
+ * If the notifier wishes to accept the subscription, then it can create
+ * a new ast_sip_subscription to do so.
+ *
+ * If the notifier chooses to create a new subscription, then it must accept
+ * the incoming subscription using pjsip_evsub_accept() and it must also
+ * send an initial NOTIFY with the current subscription state.
+ *
+ * \param endpoint The endpoint from which we received the SUBSCRIBE
+ * \param rdata The SUBSCRIBE request
+ * \retval NULL The SUBSCRIBE has not been accepted
+ * \retval non-NULL The newly-created subscription
+ */
+ struct ast_sip_subscription *(*new_subscribe)(struct ast_sip_endpoint *endpoint,
+ pjsip_rx_data *rdata);
+
+ /*!
+ * \brief Called when an endpoint renews a subscription.
+ *
+ * This is a notifier callback.
+ *
+ * Because of the way that the PJSIP evsub framework works, it will automatically
+ * send a response to the SUBSCRIBE. However, the subscription handler must send
+ * a NOTIFY with the current subscription state when this callback is called.
+ *
+ * The response_data that is passed into this callback is used to craft what should
+ * be in the response to the incoming SUBSCRIBE. It is initialized with a 200 status
+ * code and all other parameters are empty.
+ *
+ * \param sub The subscription that is being renewed
+ * \param rdata The SUBSCRIBE request in question
+ * \param[out] response_data Data pertaining to the SIP response that should be
+ * sent to the SUBSCRIBE
+ */
+ void (*resubscribe)(struct ast_sip_subscription *sub,
+ pjsip_rx_data *rdata, struct ast_sip_subscription_response_data *response_data);
+
+ /*!
+ * \brief Called when a subscription times out.
+ *
+ * This is a notifier callback
+ *
+ * This indicates that the subscription has timed out. The subscription handler is
+ * expected to send a NOTIFY that terminates the subscription.
+ *
+ * \param sub The subscription that has timed out
+ */
+ void (*subscription_timeout)(struct ast_sip_subscription *sub);
+
+ /*!
+ * \brief Called when a subscription is terminated via a SUBSCRIBE or NOTIFY request
+ *
+ * This is a notifier and subscriber callback.
+ *
+ * The PJSIP subscription framework will automatically send the response to the
+ * request. If a notifier receives this callback, then the subscription handler
+ * is expected to send a final NOTIFY to terminate the subscription.
+ *
+ * \param sub The subscription being terminated
+ * \param rdata The request that terminated the subscription
+ */
+ void (*subscription_terminated)(struct ast_sip_subscription *sub, pjsip_rx_data *rdata);
+
+ /*!
+ * \brief Called when a subscription handler's outbound NOTIFY receives a response
+ *
+ * This is a notifier callback.
+ *
+ * \param sub The subscription
+ * \param rdata The NOTIFY response
+ */
+ void (*notify_response)(struct ast_sip_subscription *sub, pjsip_rx_data *rdata);
+
+ /*!
+ * \brief Called when a subscription handler receives an inbound NOTIFY
+ *
+ * This is a subscriber callback.
+ *
+ * Because of the way that the PJSIP evsub framework works, it will automatically
+ * send a response to the NOTIFY. By default this will be a 200 OK response, but
+ * this callback can change details of the response by returning response data
+ * to use.
+ *
+ * The response_data that is passed into this callback is used to craft what should
+ * be in the response to the incoming SUBSCRIBE. It is initialized with a 200 status
+ * code and all other parameters are empty.
+ *
+ * \param sub The subscription
+ * \param rdata The NOTIFY request
+ * \param[out] response_data Data pertaining to the SIP response that should be
+ * sent to the SUBSCRIBE
+ */
+ void (*notify_request)(struct ast_sip_subscription *sub,
+ pjsip_rx_data *rdata, struct ast_sip_subscription_response_data *response_data);
+
+ /*!
+ * \brief Called when it is time for a subscriber to resubscribe
+ *
+ * This is a subscriber callback.
+ *
+ * The subscriber can reresh the subscription using the pjsip_evsub_initiate()
+ * function.
+ *
+ * \param sub The subscription to refresh
+ * \retval 0 Success
+ * \retval non-zero Failure
+ */
+ int (*refresh_subscription)(struct ast_sip_subscription *sub);
+ AST_LIST_ENTRY(ast_sip_subscription_handler) next;
+};
+
+/*!
+ * \brief Create a new ast_sip_subscription structure
+ *
+ * In most cases the pubsub core will create a general purpose subscription
+ * within PJSIP. However, PJSIP provides enhanced support for the following
+ * event packages:
+ *
+ * presence
+ * message-summary
+ *
+ * If either of these events are handled by the subscription handler, then
+ * the special-purpose event subscriptions will be created within PJSIP,
+ * and it will be expected that your subscription handler make use of the
+ * special PJSIP APIs.
+ *
+ * \param handler The subsription handler for this subscription
+ * \param role Whether we are acting as subscriber or notifier for this subscription
+ * \param endpoint The endpoint involved in this subscription
+ * \param rdata If acting as a notifier, the SUBSCRIBE request that triggered subscription creation
+ */
+struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler,
+ enum ast_sip_subscription_role role, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
+
+
+/*!
+ * \brief Get the endpoint that is associated with this subscription
+ *
+ * This function will increase the reference count of the endpoint. Be sure to
+ * release the reference to it when you are finished with the endpoint.
+ *
+ * \retval NULL Could not get endpoint
+ * \retval non-NULL The endpoint
+ */
+struct ast_sip_endpoint *ast_sip_subscription_get_endpoint(struct ast_sip_subscription *sub);
+
+/*!
+ * \brief Get the serializer for the subscription
+ *
+ * Tasks that originate outside of a SIP servant thread should get the serializer
+ * and push the task to the serializer.
+ *
+ * \param sub The subscription
+ * \retval NULL Failure
+ * \retval non-NULL The subscription's serializer
+ */
+struct ast_taskprocessor *ast_sip_subscription_get_serializer(struct ast_sip_subscription *sub);
+
+/*!
+ * \brief Get the underlying PJSIP evsub structure
+ *
+ * This is useful when wishing to call PJSIP's API calls in order to
+ * create SUBSCRIBEs, NOTIFIES, etc. as well as get subscription state
+ *
+ * This function, as well as all methods called on the pjsip_evsub should
+ * be done in a SIP servant thread.
+ *
+ * \param sub The subscription
+ * \retval NULL Failure
+ * \retval non-NULL The underlying pjsip_evsub
+ */
+pjsip_evsub *ast_sip_subscription_get_evsub(struct ast_sip_subscription *sub);
+
+/*!
+ * \brief Send a request created via a PJSIP evsub method
+ *
+ * Callers of this function should take care to do so within a SIP servant
+ * thread.
+ *
+ * \param sub The subscription on which to send the request
+ * \param tdata The request to send
+ * \retval 0 Success
+ * \retval non-zero Failure
+ */
+int ast_sip_subscription_send_request(struct ast_sip_subscription *sub, pjsip_tx_data *tdata);
+
+/*!
+ * \brief Alternative for ast_datastore_alloc()
+ *
+ * There are two major differences between this and ast_datastore_alloc()
+ * 1) This allocates a refcounted object
+ * 2) This will fill in a uid if one is not provided
+ *
+ * DO NOT call ast_datastore_free() on a datastore allocated in this
+ * way since that function will attempt to free the datastore rather
+ * than play nicely with its refcount.
+ *
+ * \param info Callbacks for datastore
+ * \param uid Identifier for datastore
+ * \retval NULL Failed to allocate datastore
+ * \retval non-NULL Newly allocated datastore
+ */
+struct ast_datastore *ast_sip_subscription_alloc_datastore(const struct ast_datastore_info *info, const char *uid);
+
+/*!
+ * \brief Add a datastore to a SIP subscription
+ *
+ * Note that SIP uses reference counted datastores. The datastore passed into this function
+ * must have been allocated using ao2_alloc() or there will be serious problems.
+ *
+ * \param subscription The ssubscription to add the datastore to
+ * \param datastore The datastore to be added to the subscription
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_subscription_add_datastore(struct ast_sip_subscription *subscription, struct ast_datastore *datastore);
+
+/*!
+ * \brief Retrieve a subscription datastore
+ *
+ * The datastore retrieved will have its reference count incremented. When the caller is done
+ * with the datastore, the reference counted needs to be decremented using ao2_ref().
+ *
+ * \param subscription The subscription from which to retrieve the datastore
+ * \param name The name of the datastore to retrieve
+ * \retval NULL Failed to find the specified datastore
+ * \retval non-NULL The specified datastore
+ */
+struct ast_datastore *ast_sip_subscription_get_datastore(struct ast_sip_subscription *subscription, const char *name);
+
+/*!
+ * \brief Remove a subscription datastore from the subscription
+ *
+ * This operation may cause the datastore's free() callback to be called if the reference
+ * count reaches zero.
+ *
+ * \param subscription The subscription to remove the datastore from
+ * \param name The name of the datastore to remove
+ */
+void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name);
+
+/*!
+ * \brief Register a subscription handler
+ *
+ * \retval 0 Handler was registered successfully
+ * \retval non-zero Handler was not registered successfully
+ */
+int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *handler);
+
+/*!
+ * \brief Unregister a subscription handler
+ */
+void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler *handler);
+
+#endif /* RES_SIP_PUBSUB_H */
diff --git a/include/asterisk/res_sip_session.h b/include/asterisk/res_sip_session.h
new file mode 100644
index 000000000..cbed52621
--- /dev/null
+++ b/include/asterisk/res_sip_session.h
@@ -0,0 +1,468 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#ifndef _RES_SIP_SESSION_H
+#define _RES_SIP_SESSION_H
+
+/* Needed for pj_timer_entry definition */
+#include "pjlib.h"
+#include "asterisk/linkedlists.h"
+/* Needed for AST_MAX_EXTENSION constant */
+#include "asterisk/channel.h"
+/* Needed for ast_sockaddr struct */
+#include "asterisk/netsock.h"
+
+/* Forward declarations */
+struct ast_sip_endpoint;
+struct ast_sip_transport;
+struct pjsip_inv_session;
+struct ast_channel;
+struct ast_datastore;
+struct ast_datastore_info;
+struct ao2_container;
+struct pjsip_tx_data;
+struct pjsip_rx_data;
+struct ast_party_id;
+struct pjmedia_sdp_media;
+struct pjmedia_sdp_session;
+struct ast_rtp_instance;
+
+struct ast_sip_session_sdp_handler;
+
+/*!
+ * \brief A structure containing SIP session media information
+ */
+struct ast_sip_session_media {
+ /*! \brief RTP instance itself */
+ struct ast_rtp_instance *rtp;
+ /*! \brief Direct media address */
+ struct ast_sockaddr direct_media_addr;
+ /*! \brief SDP handler that setup the RTP */
+ struct ast_sip_session_sdp_handler *handler;
+ /*! \brief Stream is on hold */
+ unsigned int held:1;
+ /*! \brief Stream type this session media handles */
+ char stream_type[1];
+};
+
+/*!
+ * \brief Opaque structure representing a request that could not be sent
+ * due to an outstanding INVITE transaction
+ */
+struct ast_sip_session_delayed_request;
+
+/*!
+ * \brief A structure describing a SIP session
+ *
+ * For the sake of brevity, a "SIP session" in Asterisk is referring to
+ * a dialog initiated by an INVITE. While "session" is typically interpreted
+ * to refer to the negotiated media within a SIP dialog, we have opted
+ * to use the term "SIP session" to refer to the INVITE dialog itself.
+ */
+struct ast_sip_session {
+ /* Dialplan extension where incoming call is destined */
+ char exten[AST_MAX_EXTENSION];
+ /* The endpoint with which Asterisk is communicating */
+ struct ast_sip_endpoint *endpoint;
+ /* The PJSIP details of the session, which includes the dialog */
+ struct pjsip_inv_session *inv_session;
+ /* The Asterisk channel associated with the session */
+ struct ast_channel *channel;
+ /* Registered session supplements */
+ AST_LIST_HEAD(, ast_sip_session_supplement) supplements;
+ /* Datastores added to the session by supplements to the session */
+ struct ao2_container *datastores;
+ /* Media streams */
+ struct ao2_container *media;
+ /* Serializer for tasks relating to this SIP session */
+ struct ast_taskprocessor *serializer;
+ /* Requests that could not be sent due to current inv_session state */
+ AST_LIST_HEAD_NOLOCK(, ast_sip_session_delayed_request) delayed_requests;
+ /* When we need to reschedule a reinvite, we use this structure to do it */
+ pj_timer_entry rescheduled_reinvite;
+ /* Format capabilities pertaining to direct media */
+ struct ast_format_cap *direct_media_cap;
+ /* Identity of endpoint this session deals with */
+ struct ast_party_id id;
+ /* Requested capabilities */
+ struct ast_format_cap *req_caps;
+};
+
+typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata);
+typedef int (*ast_sip_session_response_cb)(struct ast_sip_session *session, pjsip_rx_data *rdata);
+
+enum ast_sip_session_supplement_priority {
+ /*! Top priority. Supplements with this priority are those that need to run before any others */
+ AST_SIP_SESSION_SUPPLEMENT_PRIORITY_FIRST = 0,
+ /*! Channel creation priority.
+ * chan_gulp creates a channel at this priority. If your supplement depends on being run before
+ * or after channel creation, then set your priority to be lower or higher than this value.
+ */
+ AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL = 1000000,
+ /*! Lowest priority. Supplements with this priority should be run after all other supplements */
+ AST_SIP_SESSION_SUPPLEMENT_PRIORITY_LAST = INT_MAX,
+};
+
+/*!
+ * \brief A supplement to SIP message processing
+ *
+ * These can be registered by any module in order to add
+ * processing to incoming and outgoing SIP requests and responses
+ */
+struct ast_sip_session_supplement {
+ /*! Method on which to call the callbacks. If NULL, call on all methods */
+ const char *method;
+ /*! Priority for this supplement. Lower numbers are visited before higher numbers */
+ enum ast_sip_session_supplement_priority priority;
+ /*!
+ * \brief Notification that the session has begun
+ * This method will always be called from a SIP servant thread.
+ */
+ void (*session_begin)(struct ast_sip_session *session);
+ /*!
+ * \brief Notification that the session has ended
+ *
+ * This method may or may not be called from a SIP servant thread. Do
+ * not make assumptions about being able to call PJSIP methods from within
+ * this method.
+ */
+ void (*session_end)(struct ast_sip_session *session);
+ /*!
+ * \brief Notification that the session is being destroyed
+ */
+ void (*session_destroy)(struct ast_sip_session *session);
+ /*!
+ * \brief Called on incoming SIP request
+ * This method can indicate a failure in processing in its return. If there
+ * is a failure, it is required that this method sends a response to the request.
+ * This method is always called from a SIP servant thread.
+ *
+ * \note
+ * The following PJSIP methods will not work properly:
+ * pjsip_rdata_get_dlg()
+ * pjsip_rdata_get_tsx()
+ * The reason is that the rdata passed into this function is a cloned rdata structure,
+ * and its module data is not copied during the cloning operation.
+ * If you need to get the dialog, you can get it via session->inv_session->dlg.
+ */
+ int (*incoming_request)(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
+ /*!
+ * \brief Called on an incoming SIP response
+ * This method is always called from a SIP servant thread.
+ *
+ * \note
+ * The following PJSIP methods will not work properly:
+ * pjsip_rdata_get_dlg()
+ * pjsip_rdata_get_tsx()
+ * The reason is that the rdata passed into this function is a cloned rdata structure,
+ * and its module data is not copied during the cloning operation.
+ * If you need to get the dialog, you can get it via session->inv_session->dlg.
+ */
+ void (*incoming_response)(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
+ /*!
+ * \brief Called on an outgoing SIP request
+ * This method is always called from a SIP servant thread.
+ */
+ void (*outgoing_request)(struct ast_sip_session *session, struct pjsip_tx_data *tdata);
+ /*!
+ * \brief Called on an outgoing SIP response
+ * This method is always called from a SIP servant thread.
+ */
+ void (*outgoing_response)(struct ast_sip_session *session, struct pjsip_tx_data *tdata);
+ /*! Next item in the list */
+ AST_LIST_ENTRY(ast_sip_session_supplement) next;
+};
+
+/*!
+ * \brief A handler for SDPs in SIP sessions
+ *
+ * An SDP handler is registered by a module that is interested in being the
+ * responsible party for specific types of SDP streams.
+ */
+struct ast_sip_session_sdp_handler {
+ /*! An identifier for this handler */
+ const char *id;
+ /*!
+ * \brief Set session details based on a stream in an incoming SDP offer or answer
+ * \param session The session for which the media is being negotiated
+ * \param session_media The media to be setup for this session
+ * \param sdp The entire SDP. Useful for getting "global" information, such as connections or attributes
+ * \param stream The stream on which to operate
+ * \retval 0 The stream was not handled by this handler. If there are other registered handlers for this stream type, they will be called.
+ * \retval <0 There was an error encountered. No further operation will take place and the current negotiation will be abandoned.
+ * \retval >0 The stream was handled by this handler. No further handler of this stream type will be called.
+ */
+ int (*negotiate_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream);
+ /*!
+ * \brief Create an SDP media stream and add it to the outgoing SDP offer or answer
+ * \param session The session for which media is being added
+ * \param session_media The media to be setup for this session
+ * \param stream The stream on which to operate
+ * \retval 0 The stream was not handled by this handler. If there are other registered handlers for this stream type, they will be called.
+ * \retval <0 There was an error encountered. No further operation will take place and the current negotiation will be abandoned.
+ * \retval >0 The stream was handled by this handler. No further handler of this stream type will be called.
+ */
+ int (*handle_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, struct pjmedia_sdp_media *stream);
+ /*!
+ * \brief Create an SDP media stream and add it to the outgoing SDP offer or answer
+ * \param session The session for which media is being added
+ * \param session_media The media to be setup for this session
+ * \param sdp The entire SDP as currently built
+ * \retval 0 This handler has no stream to add. If there are other registered handlers for this stream type, they will be called.
+ * \retval <0 There was an error encountered. No further operation will take place and the current SDP negotiation will be abandoned.
+ * \retval >0 The handler has a stream to be added to the SDP. No further handler of this stream type will be called.
+ */
+ int (*create_outgoing_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct pjmedia_sdp_session *sdp);
+ /*!
+ * \brief Update media stream with external address if applicable
+ * \param tdata The outgoing message itself
+ * \param stream The stream on which to operate
+ * \param transport The transport the SDP is going out on
+ */
+ void (*change_outgoing_sdp_stream_media_address)(struct pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport);
+ /*!
+ * \brief Apply a negotiated SDP media stream
+ * \param session The session for which media is being applied
+ * \param session_media The media to be setup for this session
+ * \param local The entire local negotiated SDP
+ * \param local_stream The local stream which to apply
+ * \param remote The entire remote negotiated SDP
+ * \param remote_stream The remote stream which to apply
+ * \retval 0 The stream was not applied by this handler. If there are other registered handlers for this stream type, they will be called.
+ * \retval <0 There was an error encountered. No further operation will take place and the current application will be abandoned.
+ * \retval >0 The stream was handled by this handler. No further handler of this stream type will be called.
+ */
+ int (*apply_negotiated_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream,
+ const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream);
+ /*!
+ * \brief Destroy a session_media created by this handler
+ * \param session The session for which media is being destroyed
+ * \param session_media The media to destroy
+ */
+ void (*stream_destroy)(struct ast_sip_session_media *session_media);
+ /*! Next item in the list. */
+ AST_LIST_ENTRY(ast_sip_session_sdp_handler) next;
+};
+
+/*!
+ * \brief Allocate a new SIP session
+ *
+ * This will take care of allocating the datastores container on the session as well
+ * as placing all registered supplements onto the session.
+ *
+ * The endpoint that is passed in will have its reference count increased by one since
+ * the session will be keeping a reference to the endpoint. The session will relinquish
+ * this reference when the session is destroyed.
+ *
+ * \param endpoint The endpoint that this session communicates with
+ * \param inv_session The PJSIP INVITE session data
+ */
+struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, pjsip_inv_session *inv);
+
+/*!
+ * \brief Create a new outgoing SIP session
+ *
+ * The endpoint that is passed in will have its reference count increased by one since
+ * the session will be keeping a reference to the endpoint. The session will relinquish
+ * this reference when the session is destroyed.
+ *
+ * \param endpoint The endpoint that this session uses for settings
+ * \param location Optional name of the location to call, be it named location or explicit URI
+ * \param request_user Optional request user to place in the request URI if permitted
+ * \param req_caps The requested capabilities
+ */
+struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint *endpoint, const char *location, const char *request_user, struct ast_format_cap *req_caps);
+
+/*!
+ * \brief Register an SDP handler
+ *
+ * An SDP handler is responsible for parsing incoming SDP streams and ensuring that
+ * Asterisk can cope with the contents. Similarly, the SDP handler will be
+ * responsible for constructing outgoing SDP streams.
+ *
+ * Multiple handlers for the same stream type may be registered. They will be
+ * visited in the order they were registered. Handlers will be visited for each
+ * stream type until one claims to have handled the stream.
+ *
+ * \param handler The SDP handler to register
+ * \param stream_type The type of media stream for which to call the handler
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_session_register_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type);
+
+/*!
+ * \brief Unregister an SDP handler
+ *
+ * \param handler The SDP handler to unregister
+ * \param stream_type Stream type for which the SDP handler was registered
+ */
+void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type);
+
+/*!
+ * \brief Register a supplement to SIP session processing
+ *
+ * This allows for someone to insert themselves in the processing of SIP
+ * requests and responses. This, for example could allow for a module to
+ * set channel data based on headers in an incoming message. Similarly,
+ * a module could reject an incoming request if desired.
+ *
+ * \param supplement The supplement to register
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_session_register_supplement(struct ast_sip_session_supplement *supplement);
+
+/*!
+ * \brief Unregister a an supplement to SIP session processing
+ *
+ * \param supplement The supplement to unregister
+ */
+void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement);
+
+/*!
+ * \brief Alternative for ast_datastore_alloc()
+ *
+ * There are two major differences between this and ast_datastore_alloc()
+ * 1) This allocates a refcounted object
+ * 2) This will fill in a uid if one is not provided
+ *
+ * DO NOT call ast_datastore_free() on a datastore allocated in this
+ * way since that function will attempt to free the datastore rather
+ * than play nicely with its refcount.
+ *
+ * \param info Callbacks for datastore
+ * \param uid Identifier for datastore
+ * \retval NULL Failed to allocate datastore
+ * \retval non-NULL Newly allocated datastore
+ */
+struct ast_datastore *ast_sip_session_alloc_datastore(const struct ast_datastore_info *info, const char *uid);
+
+/*!
+ * \brief Add a datastore to a SIP session
+ *
+ * Note that SIP uses reference counted datastores. The datastore passed into this function
+ * must have been allocated using ao2_alloc() or there will be serious problems.
+ *
+ * \param session The session to add the datastore to
+ * \param datastore The datastore to be added to the session
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_session_add_datastore(struct ast_sip_session *session, struct ast_datastore *datastore);
+
+/*!
+ * \brief Retrieve a session datastore
+ *
+ * The datastore retrieved will have its reference count incremented. When the caller is done
+ * with the datastore, the reference counted needs to be decremented using ao2_ref().
+ *
+ * \param session The session from which to retrieve the datastore
+ * \param name The name of the datastore to retrieve
+ * \retval NULL Failed to find the specified datastore
+ * \retval non-NULL The specified datastore
+ */
+struct ast_datastore *ast_sip_session_get_datastore(struct ast_sip_session *session, const char *name);
+
+/*!
+ * \brief Remove a session datastore from the session
+ *
+ * This operation may cause the datastore's free() callback to be called if the reference
+ * count reaches zero.
+ *
+ * \param session The session to remove the datastore from
+ * \param name The name of the datastore to remove
+ */
+void ast_sip_session_remove_datastore(struct ast_sip_session *session, const char *name);
+
+/*!
+ * \brief Retrieve identifying information from an incoming request
+ *
+ * This will retrieve identifying information and place it in the
+ * id parameter. The caller of the function can then apply this to
+ * caller ID, connected line, or whatever else may be proper.
+ *
+ * \param rdata The incoming request or response
+ * \param[out] id The collected identity information
+ * \retval 0 Successfully found identifying information
+ * \retval -1 Identifying information could not be found
+ */
+int ast_sip_session_get_identity(struct pjsip_rx_data *rdata, struct ast_party_id *id);
+
+/*!
+ * \brief Send a reinvite or UPDATE on a session
+ *
+ * This method will inspect the session in order to construct an appropriate
+ * session refresh request. As with any outgoing request in res_sip_session,
+ * this will call into registered supplements in case they wish to add anything.
+ *
+ * Note: The on_request_creation callback may or may not be called in the same
+ * thread where this function is called. Request creation may need to be delayed
+ * due to the current INVITE transaction state.
+ *
+ * \param session The session on which the reinvite will be sent
+ * \param on_request_creation Callback called when request is created
+ * \param on_response Callback called when response for request is received
+ * \param method The method that should be used when constructing the session refresh
+ * \param generate_new_sdp Boolean to indicate if a new SDP should be created
+ * \retval 0 Successfully sent refresh
+ * \retval -1 Failure to send refresh
+ */
+int ast_sip_session_refresh(struct ast_sip_session *session,
+ ast_sip_session_request_creation_cb on_request_creation,
+ ast_sip_session_response_cb on_response,
+ enum ast_sip_session_refresh_method method,
+ int generate_new_sdp);
+
+/*!
+ * \brief Send a SIP response
+ *
+ * This will send the SIP response specified in tdata and
+ * call into any registered supplements' outgoing_response callback.
+ *
+ * \param session The session on which to send the response.
+ * \param tdata The response to send
+ */
+void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata);
+
+/*!
+ * \brief Send a SIP request
+ *
+ * This will send the SIP request specified in tdata and
+ * call into any registered supplements' outgoing_request callback.
+ *
+ * \param session The session to which to send the request
+ * \param tdata The request to send
+ */
+void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata);
+
+/*!
+ * \brief Send a SIP request and get called back when a response is received
+ *
+ * This will send the request out exactly the same as ast_sip_send_request() does.
+ * The difference is that when a response arrives, the specified callback will be
+ * called into
+ *
+ * \param session The session on which to send the request
+ * \param tdata The request to send
+ * \param on_response Callback to be called when a response is received
+ */
+void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip_tx_data *tdata,
+ ast_sip_session_response_cb on_response);
+
+#endif /* _RES_SIP_SESSION_H */
diff --git a/include/asterisk/sorcery.h b/include/asterisk/sorcery.h
index e390b43cf..434f5595a 100644
--- a/include/asterisk/sorcery.h
+++ b/include/asterisk/sorcery.h
@@ -157,10 +157,15 @@ typedef struct ast_variable *(*sorcery_transform_handler)(struct ast_variable *s
/*!
* \brief A callback function for when an object set is successfully applied to an object
*
+ * \note On a failure return, the state of the object is left undefined. It is a bad
+ * idea to try to use this object.
+ *
* \param sorcery Sorcery structure in use
* \param obj The object itself
+ * \retval 0 Success
+ * \retval non-zero Failure
*/
-typedef void (*sorcery_apply_handler)(const struct ast_sorcery *sorcery, void *obj);
+typedef int (*sorcery_apply_handler)(const struct ast_sorcery *sorcery, void *obj);
/*!
* \brief A callback function for copying the contents of one object to another
diff --git a/include/asterisk/threadpool.h b/include/asterisk/threadpool.h
index 89076265e..e1e7727f5 100644
--- a/include/asterisk/threadpool.h
+++ b/include/asterisk/threadpool.h
@@ -108,6 +108,20 @@ struct ast_threadpool_options {
* maximum size.
*/
int max_size;
+ /*!
+ * \brief Function to call when a thread starts
+ *
+ * This is useful if there is something common that all threads
+ * in a threadpool need to do when they start.
+ */
+ void (*thread_start)(void);
+ /*!
+ * \brief Function to call when a thread ends
+ *
+ * This is useful if there is common cleanup to execute when
+ * a thread completes
+ */
+ void (*thread_end)(void);
};
/*!
diff --git a/main/astobj2.c b/main/astobj2.c
index 72a171de9..a980ec379 100644
--- a/main/astobj2.c
+++ b/main/astobj2.c
@@ -525,6 +525,7 @@ int __ao2_ref_debug(void *user_data, int delta, const char *tag, const char *fil
struct astobj2 *obj = INTERNAL_OBJ(user_data);
if (obj == NULL) {
+ ast_backtrace();
ast_assert(0);
return -1;
}
diff --git a/main/loader.c b/main/loader.c
index 5befafb55..10d5485da 100644
--- a/main/loader.c
+++ b/main/loader.c
@@ -842,6 +842,7 @@ static enum ast_module_load_result start_resource(struct ast_module *mod)
return AST_MODULE_LOAD_FAILURE;
}
+ printf ("!!! Going to load %s\n", mod->resource);
res = mod->info->load();
switch (res) {
diff --git a/main/sorcery.c b/main/sorcery.c
index 8b555222d..44e247a38 100644
--- a/main/sorcery.c
+++ b/main/sorcery.c
@@ -740,7 +740,7 @@ int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object,
}
if (!res && object_type->apply) {
- object_type->apply(sorcery, object);
+ res = object_type->apply(sorcery, object);
}
return res;
@@ -940,6 +940,7 @@ void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const ch
unsigned int cached = 0;
if (!object_type) {
+ ast_log(LOG_NOTICE, "Can't find object type '%s'\n", type);
return NULL;
}
diff --git a/main/taskprocessor.c b/main/taskprocessor.c
index 35076b06e..a8d1c80f9 100644
--- a/main/taskprocessor.c
+++ b/main/taskprocessor.c
@@ -602,7 +602,6 @@ struct ast_taskprocessor *ast_taskprocessor_get(const char *name, enum ast_tps_o
/* Unref listener here since the taskprocessor has gained a reference to the listener */
ao2_ref(listener, -1);
return p;
-
}
struct ast_taskprocessor *ast_taskprocessor_create_with_listener(const char *name, struct ast_taskprocessor_listener *listener)
diff --git a/main/threadpool.c b/main/threadpool.c
index e2fdecc57..1ff76014a 100644
--- a/main/threadpool.c
+++ b/main/threadpool.c
@@ -983,7 +983,13 @@ static void *worker_start(void *arg)
{
struct worker_thread *worker = arg;
+ if (worker->options.thread_start) {
+ worker->options.thread_start();
+ }
worker_active(worker);
+ if (worker->options.thread_end) {
+ worker->options.thread_end();
+ }
return NULL;
}
diff --git a/res/Makefile b/res/Makefile
index fec20a2e0..35d09275c 100644
--- a/res/Makefile
+++ b/res/Makefile
@@ -43,6 +43,9 @@ snmp/agent.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_snmp)
$(if $(filter res_ael_share,$(EMBEDDED_MODS)),modules.link,res_ael_share.so): ael/ael_lex.o ael/ael.tab.o ael/pval.o
ael/ael_lex.o ael/ael.tab.o ael/pval.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_ael_share)
+$(if $(filter res_sip,$(EMBEDDED_MODS)),modules.link,res_sip.so): $(subst .c,.o,$(wildcard res_sip/*.c))
+$(subst .c,.o,$(wildcard res_sip/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_sip)
+
ifneq ($(findstring REBUILD_PARSERS,$(MENUSELECT_CFLAGS)),)
ael/ael_lex.c: ael/ael.flex
else
@@ -67,7 +70,7 @@ endif
ael/pval.o: ael/pval.c
clean::
- rm -f snmp/*.[oi] ael/*.[oi] ais/*.[oi] stasis_http/*.[oi]
+ rm -f snmp/*.[oi] ael/*.[oi] ais/*.[oi] stasis_http/*.[oi] res_sip/*.[oi]
# Dependencies for res_stasis_http_*.so are generated, so they're in this file
include stasis_http.make
diff --git a/res/res_sip.c b/res/res_sip.c
new file mode 100644
index 000000000..18eead992
--- /dev/null
+++ b/res/res_sip.c
@@ -0,0 +1,906 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+/* Needed for SUBSCRIBE, NOTIFY, and PUBLISH method definitions */
+#include <pjsip_simple.h>
+#include <pjlib.h>
+
+#include "asterisk/res_sip.h"
+#include "res_sip/include/res_sip_private.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/logger.h"
+#include "asterisk/lock.h"
+#include "asterisk/utils.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/module.h"
+#include "asterisk/threadpool.h"
+#include "asterisk/taskprocessor.h"
+#include "asterisk/uuid.h"
+#include "asterisk/sorcery.h"
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <depend>res_sorcery_config</depend>
+ <support_level>core</support_level>
+ ***/
+
+static pjsip_endpoint *ast_pjsip_endpoint;
+
+static struct ast_threadpool *sip_threadpool;
+
+static int register_service(void *data)
+{
+ pjsip_module **module = data;
+ if (!ast_pjsip_endpoint) {
+ ast_log(LOG_ERROR, "There is no PJSIP endpoint. Unable to register services\n");
+ return -1;
+ }
+ if (pjsip_endpt_register_module(ast_pjsip_endpoint, *module) != PJ_SUCCESS) {
+ ast_log(LOG_ERROR, "Unable to register module %.*s\n", (int) pj_strlen(&(*module)->name), pj_strbuf(&(*module)->name));
+ return -1;
+ }
+ ast_debug(1, "Registered SIP service %.*s (%p)\n", (int) pj_strlen(&(*module)->name), pj_strbuf(&(*module)->name), *module);
+ ast_module_ref(ast_module_info->self);
+ return 0;
+}
+
+int ast_sip_register_service(pjsip_module *module)
+{
+ return ast_sip_push_task_synchronous(NULL, register_service, &module);
+}
+
+static int unregister_service(void *data)
+{
+ pjsip_module **module = data;
+ ast_module_unref(ast_module_info->self);
+ if (!ast_pjsip_endpoint) {
+ return -1;
+ }
+ pjsip_endpt_unregister_module(ast_pjsip_endpoint, *module);
+ ast_debug(1, "Unregistered SIP service %.*s\n", (int) pj_strlen(&(*module)->name), pj_strbuf(&(*module)->name));
+ return 0;
+}
+
+void ast_sip_unregister_service(pjsip_module *module)
+{
+ ast_sip_push_task_synchronous(NULL, unregister_service, &module);
+}
+
+static struct ast_sip_authenticator *registered_authenticator;
+
+int ast_sip_register_authenticator(struct ast_sip_authenticator *auth)
+{
+ if (registered_authenticator) {
+ ast_log(LOG_WARNING, "Authenticator %p is already registered. Cannot register a new one\n", registered_authenticator);
+ return -1;
+ }
+ registered_authenticator = auth;
+ ast_debug(1, "Registered SIP authenticator module %p\n", auth);
+ ast_module_ref(ast_module_info->self);
+ return 0;
+}
+
+void ast_sip_unregister_authenticator(struct ast_sip_authenticator *auth)
+{
+ if (registered_authenticator != auth) {
+ ast_log(LOG_WARNING, "Trying to unregister authenticator %p but authenticator %p registered\n",
+ auth, registered_authenticator);
+ return;
+ }
+ registered_authenticator = NULL;
+ ast_debug(1, "Unregistered SIP authenticator %p\n", auth);
+ ast_module_unref(ast_module_info->self);
+}
+
+int ast_sip_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
+{
+ if (!registered_authenticator) {
+ ast_log(LOG_WARNING, "No SIP authenticator registered. Assuming authentication is not required\n");
+ return 0;
+ }
+
+ return registered_authenticator->requires_authentication(endpoint, rdata);
+}
+
+enum ast_sip_check_auth_result ast_sip_check_authentication(struct ast_sip_endpoint *endpoint,
+ pjsip_rx_data *rdata, pjsip_tx_data *tdata)
+{
+ if (!registered_authenticator) {
+ ast_log(LOG_WARNING, "No SIP authenticator registered. Assuming authentication is successful\n");
+ return 0;
+ }
+ return registered_authenticator->check_authentication(endpoint, rdata, tdata);
+}
+
+static struct ast_sip_outbound_authenticator *registered_outbound_authenticator;
+
+int ast_sip_register_outbound_authenticator(struct ast_sip_outbound_authenticator *auth)
+{
+ if (registered_outbound_authenticator) {
+ ast_log(LOG_WARNING, "Outbound authenticator %p is already registered. Cannot register a new one\n", registered_outbound_authenticator);
+ return -1;
+ }
+ registered_outbound_authenticator = auth;
+ ast_debug(1, "Registered SIP outbound authenticator module %p\n", auth);
+ ast_module_ref(ast_module_info->self);
+ return 0;
+}
+
+void ast_sip_unregister_outbound_authenticator(struct ast_sip_outbound_authenticator *auth)
+{
+ if (registered_outbound_authenticator != auth) {
+ ast_log(LOG_WARNING, "Trying to unregister outbound authenticator %p but outbound authenticator %p registered\n",
+ auth, registered_outbound_authenticator);
+ return;
+ }
+ registered_outbound_authenticator = NULL;
+ ast_debug(1, "Unregistered SIP outbound authenticator %p\n", auth);
+ ast_module_unref(ast_module_info->self);
+}
+
+int ast_sip_create_request_with_auth(const char **auths, size_t num_auths, pjsip_rx_data *challenge,
+ pjsip_transaction *tsx, pjsip_tx_data **new_request)
+{
+ if (!registered_outbound_authenticator) {
+ ast_log(LOG_WARNING, "No SIP outbound authenticator registered. Cannot respond to authentication challenge\n");
+ return -1;
+ }
+ return registered_outbound_authenticator->create_request_with_auth(auths, num_auths, challenge, tsx, new_request);
+}
+
+struct endpoint_identifier_list {
+ struct ast_sip_endpoint_identifier *identifier;
+ AST_RWLIST_ENTRY(endpoint_identifier_list) list;
+};
+
+static AST_RWLIST_HEAD_STATIC(endpoint_identifiers, endpoint_identifier_list);
+
+int ast_sip_register_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
+{
+ struct endpoint_identifier_list *id_list_item;
+ SCOPED_LOCK(lock, &endpoint_identifiers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+
+ id_list_item = ast_calloc(1, sizeof(*id_list_item));
+ if (!id_list_item) {
+ ast_log(LOG_ERROR, "Unabled to add endpoint identifier. Out of memory.\n");
+ return -1;
+ }
+ id_list_item->identifier = identifier;
+
+ AST_RWLIST_INSERT_TAIL(&endpoint_identifiers, id_list_item, list);
+ ast_debug(1, "Registered endpoint identifier %p\n", identifier);
+
+ ast_module_ref(ast_module_info->self);
+ return 0;
+}
+
+void ast_sip_unregister_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
+{
+ struct endpoint_identifier_list *iter;
+ SCOPED_LOCK(lock, &endpoint_identifiers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&endpoint_identifiers, iter, list) {
+ if (iter->identifier == identifier) {
+ AST_RWLIST_REMOVE_CURRENT(list);
+ ast_free(iter);
+ ast_debug(1, "Unregistered endpoint identifier %p\n", identifier);
+ ast_module_unref(ast_module_info->self);
+ break;
+ }
+ }
+ AST_RWLIST_TRAVERSE_SAFE_END;
+}
+
+struct ast_sip_endpoint *ast_sip_identify_endpoint(pjsip_rx_data *rdata)
+{
+ struct endpoint_identifier_list *iter;
+ struct ast_sip_endpoint *endpoint = NULL;
+ SCOPED_LOCK(lock, &endpoint_identifiers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
+ AST_RWLIST_TRAVERSE(&endpoint_identifiers, iter, list) {
+ ast_assert(iter->identifier->identify_endpoint != NULL);
+ endpoint = iter->identifier->identify_endpoint(rdata);
+ if (endpoint) {
+ break;
+ }
+ }
+ return endpoint;
+}
+
+pjsip_endpoint *ast_sip_get_pjsip_endpoint(void)
+{
+ return ast_pjsip_endpoint;
+}
+
+static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *user, const pj_str_t *target, pjsip_tpselector *selector)
+{
+ pj_str_t tmp, local_addr;
+ pjsip_uri *uri;
+ pjsip_sip_uri *sip_uri;
+ pjsip_transport_type_e type = PJSIP_TRANSPORT_UNSPECIFIED;
+ int local_port;
+ char uuid_str[AST_UUID_STR_LEN];
+
+ if (!user) {
+ RAII_VAR(struct ast_uuid *, uuid, ast_uuid_generate(), ast_free_ptr);
+ if (!uuid) {
+ return -1;
+ }
+ user = ast_uuid_to_str(uuid, uuid_str, sizeof(uuid_str));
+ }
+
+ /* Parse the provided target URI so we can determine what transport it will end up using */
+ pj_strdup_with_null(pool, &tmp, target);
+
+ if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
+ (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
+ return -1;
+ }
+
+ sip_uri = pjsip_uri_get_uri(uri);
+
+ /* Determine the transport type to use */
+ if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
+ type = PJSIP_TRANSPORT_TLS;
+ } else if (!sip_uri->transport_param.slen) {
+ type = PJSIP_TRANSPORT_UDP;
+ } else {
+ type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
+ }
+
+ if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
+ return -1;
+ }
+
+ /* If the host is IPv6 turn the transport into an IPv6 version */
+ if (pj_strchr(&sip_uri->host, ':')) {
+ type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
+ }
+
+ /* Get the local bound address for the transport that will be used when communicating with the provided URI */
+ if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), pool, type, selector,
+ &local_addr, &local_port) != PJ_SUCCESS) {
+ return -1;
+ }
+
+ /* If IPv6 was not specified in the host but is in the transport, set the proper type */
+ if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) {
+ type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
+ }
+
+ from->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
+ from->slen = pj_ansi_snprintf(from->ptr, PJSIP_MAX_URL_SIZE,
+ "<%s:%s@%s%.*s%s:%d%s%s>",
+ (pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) ? "sips" : "sip",
+ user,
+ (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
+ (int)local_addr.slen,
+ local_addr.ptr,
+ (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
+ local_port,
+ (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
+ (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "");
+
+ return 0;
+}
+
+static int sip_get_tpselector_from_endpoint(const struct ast_sip_endpoint *endpoint, pjsip_tpselector *selector)
+{
+ RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
+ const char *transport_name = endpoint->transport;
+
+ if (ast_strlen_zero(transport_name)) {
+ return 0;
+ }
+
+ transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_name);
+
+ if (!transport || !transport->state) {
+ return -1;
+ }
+
+ if (transport->type == AST_SIP_TRANSPORT_UDP) {
+ selector->type = PJSIP_TPSELECTOR_TRANSPORT;
+ selector->u.transport = transport->state->transport;
+ } else if (transport->type == AST_SIP_TRANSPORT_TCP || transport->type == AST_SIP_TRANSPORT_TLS) {
+ selector->type = PJSIP_TPSELECTOR_LISTENER;
+ selector->u.listener = transport->state->factory;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+pjsip_dialog *ast_sip_create_dialog(const struct ast_sip_endpoint *endpoint, const char *uri, const char *request_user)
+{
+ pj_str_t local_uri = { "sip:temp@temp", 13 }, remote_uri;
+ pjsip_dialog *dlg = NULL;
+ const char *outbound_proxy = endpoint->outbound_proxy;
+ pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
+ static const pj_str_t HCONTACT = { "Contact", 7 };
+
+ pj_cstr(&remote_uri, uri);
+
+ if (pjsip_dlg_create_uac(pjsip_ua_instance(), &local_uri, NULL, &remote_uri, NULL, &dlg) != PJ_SUCCESS) {
+ return NULL;
+ }
+
+ if (sip_get_tpselector_from_endpoint(endpoint, &selector)) {
+ pjsip_dlg_terminate(dlg);
+ return NULL;
+ }
+
+ if (sip_dialog_create_from(dlg->pool, &local_uri, NULL, &remote_uri, &selector)) {
+ pjsip_dlg_terminate(dlg);
+ return NULL;
+ }
+
+ /* Update the dialog with the new local URI, we do it afterwards so we can use the dialog pool for construction */
+ pj_strdup_with_null(dlg->pool, &dlg->local.info_str, &local_uri);
+ dlg->local.info->uri = pjsip_parse_uri(dlg->pool, dlg->local.info_str.ptr, dlg->local.info_str.slen, 0);
+ dlg->local.contact = pjsip_parse_hdr(dlg->pool, &HCONTACT, local_uri.ptr, local_uri.slen, NULL);
+
+ /* If a request user has been specified and we are permitted to change it, do so */
+ if (!ast_strlen_zero(request_user) && (PJSIP_URI_SCHEME_IS_SIP(dlg->target) || PJSIP_URI_SCHEME_IS_SIPS(dlg->target))) {
+ pjsip_sip_uri *target = pjsip_uri_get_uri(dlg->target);
+ pj_strdup2(dlg->pool, &target->user, request_user);
+ }
+
+ /* We have to temporarily bump up the sess_count here so the dialog is not prematurely destroyed */
+ dlg->sess_count++;
+
+ pjsip_dlg_set_transport(dlg, &selector);
+
+ if (!ast_strlen_zero(outbound_proxy)) {
+ pjsip_route_hdr route_set, *route;
+ static const pj_str_t ROUTE_HNAME = { "Route", 5 };
+ pj_str_t tmp;
+
+ pj_list_init(&route_set);
+
+ pj_strdup2_with_null(dlg->pool, &tmp, outbound_proxy);
+ if (!(route = pjsip_parse_hdr(dlg->pool, &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL))) {
+ pjsip_dlg_terminate(dlg);
+ return NULL;
+ }
+ pj_list_push_back(&route_set, route);
+
+ pjsip_dlg_set_route_set(dlg, &route_set);
+ }
+
+ dlg->sess_count--;
+
+ return dlg;
+}
+
+/* PJSIP doesn't know about the INFO method, so we have to define it ourselves */
+const pjsip_method pjsip_info_method = {PJSIP_OTHER_METHOD, {"INFO", 4} };
+
+static struct {
+ const char *method;
+ const pjsip_method *pmethod;
+} methods [] = {
+ { "INVITE", &pjsip_invite_method },
+ { "CANCEL", &pjsip_cancel_method },
+ { "ACK", &pjsip_ack_method },
+ { "BYE", &pjsip_bye_method },
+ { "REGISTER", &pjsip_register_method },
+ { "OPTIONS", &pjsip_options_method },
+ { "SUBSCRIBE", &pjsip_subscribe_method },
+ { "NOTIFY", &pjsip_notify_method },
+ { "PUBLISH", &pjsip_publish_method },
+ { "INFO", &pjsip_info_method },
+};
+
+static const pjsip_method *get_pjsip_method(const char *method)
+{
+ int i;
+ for (i = 0; i < ARRAY_LEN(methods); ++i) {
+ if (!strcmp(method, methods[i].method)) {
+ return methods[i].pmethod;
+ }
+ }
+ return NULL;
+}
+
+static int create_in_dialog_request(const pjsip_method *method, struct pjsip_dialog *dlg, pjsip_tx_data **tdata)
+{
+ if (pjsip_dlg_create_request(dlg, method, -1, tdata) != PJ_SUCCESS) {
+ ast_log(LOG_WARNING, "Unable to create in-dialog request.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int create_out_of_dialog_request(const pjsip_method *method, struct ast_sip_endpoint *endpoint,
+ const char *uri, pjsip_tx_data **tdata)
+{
+ RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
+ pj_str_t remote_uri;
+ pj_str_t from;
+ pj_pool_t *pool;
+ pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
+
+ if (ast_strlen_zero(uri)) {
+ contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors);
+ if (!contact || ast_strlen_zero(contact->uri)) {
+ ast_log(LOG_ERROR, "Unable to retrieve contact for endpoint %s\n",
+ ast_sorcery_object_get_id(endpoint));
+ return -1;
+ }
+
+ pj_cstr(&remote_uri, contact->uri);
+ } else {
+ pj_cstr(&remote_uri, uri);
+ }
+
+ if (sip_get_tpselector_from_endpoint(endpoint, &selector)) {
+ ast_log(LOG_ERROR, "Unable to retrieve PJSIP transport selector for endpoint %s\n",
+ ast_sorcery_object_get_id(endpoint));
+ return -1;
+ }
+
+ pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Outbound request", 256, 256);
+
+ if (!pool) {
+ ast_log(LOG_ERROR, "Unable to create PJLIB memory pool\n");
+ return -1;
+ }
+
+ if (sip_dialog_create_from(pool, &from, NULL, &remote_uri, &selector)) {
+ ast_log(LOG_ERROR, "Unable to create From header for %.*s request to endpoint %s\n",
+ (int) pj_strlen(&method->name), pj_strbuf(&method->name), ast_sorcery_object_get_id(endpoint));
+ pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
+ return -1;
+ }
+
+ if (pjsip_endpt_create_request(ast_sip_get_pjsip_endpoint(), method, &remote_uri,
+ &from, &remote_uri, &from, NULL, -1, NULL, tdata) != PJ_SUCCESS) {
+ ast_log(LOG_ERROR, "Unable to create outbound %.*s request to endpoint %s\n",
+ (int) pj_strlen(&method->name), pj_strbuf(&method->name), ast_sorcery_object_get_id(endpoint));
+ pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
+ return -1;
+ }
+
+ /* We can release this pool since request creation copied all the necessary
+ * data into the outbound request's pool
+ */
+ pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
+ return 0;
+}
+
+int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg,
+ struct ast_sip_endpoint *endpoint, const char *uri, pjsip_tx_data **tdata)
+{
+ const pjsip_method *pmethod = get_pjsip_method(method);
+
+ if (!pmethod) {
+ ast_log(LOG_WARNING, "Unknown method '%s'. Cannot send request\n", method);
+ return -1;
+ }
+
+ if (dlg) {
+ return create_in_dialog_request(pmethod, dlg, tdata);
+ } else {
+ return create_out_of_dialog_request(pmethod, endpoint, uri, tdata);
+ }
+}
+
+static int send_in_dialog_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg)
+{
+ if (pjsip_dlg_send_request(dlg, tdata, -1, NULL) != PJ_SUCCESS) {
+ ast_log(LOG_WARNING, "Unable to send in-dialog request.\n");
+ return -1;
+ }
+ return 0;
+}
+
+static void send_request_cb(void *token, pjsip_event *e)
+{
+ RAII_VAR(struct ast_sip_endpoint *, endpoint, token, ao2_cleanup);
+ pjsip_transaction *tsx = e->body.tsx_state.tsx;
+ pjsip_rx_data *challenge = e->body.tsx_state.src.rdata;
+ pjsip_tx_data *tdata;
+
+ if (tsx->status_code != 401 && tsx->status_code != 407) {
+ return;
+ }
+
+ if (!ast_sip_create_request_with_auth(endpoint->sip_outbound_auths, endpoint->num_outbound_auths, challenge, tsx, &tdata)) {
+ pjsip_endpt_send_request(ast_sip_get_pjsip_endpoint(), tdata, -1, NULL, NULL);
+ }
+}
+
+static int send_out_of_dialog_request(pjsip_tx_data *tdata, struct ast_sip_endpoint *endpoint)
+{
+ ao2_ref(endpoint, +1);
+ if (pjsip_endpt_send_request(ast_sip_get_pjsip_endpoint(), tdata, -1, endpoint, send_request_cb) != PJ_SUCCESS) {
+ ast_log(LOG_ERROR, "Error attempting to send outbound %.*s request to endpoint %s\n",
+ (int) pj_strlen(&tdata->msg->line.req.method.name),
+ pj_strbuf(&tdata->msg->line.req.method.name),
+ ast_sorcery_object_get_id(endpoint));
+ ao2_ref(endpoint, -1);
+ return -1;
+ }
+
+ return 0;
+}
+
+int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
+{
+ ast_assert(tdata->msg->type == PJSIP_REQUEST_MSG);
+
+ if (dlg) {
+ return send_in_dialog_request(tdata, dlg);
+ } else {
+ return send_out_of_dialog_request(tdata, endpoint);
+ }
+}
+
+int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
+{
+ pj_str_t hdr_name;
+ pj_str_t hdr_value;
+ pjsip_generic_string_hdr *hdr;
+
+ pj_cstr(&hdr_name, name);
+ pj_cstr(&hdr_value, value);
+
+ hdr = pjsip_generic_string_hdr_create(tdata->pool, &hdr_name, &hdr_value);
+
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) hdr);
+ return 0;
+}
+
+static pjsip_msg_body *ast_body_to_pjsip_body(pj_pool_t *pool, const struct ast_sip_body *body)
+{
+ pj_str_t type;
+ pj_str_t subtype;
+ pj_str_t body_text;
+
+ pj_cstr(&type, body->type);
+ pj_cstr(&subtype, body->subtype);
+ pj_cstr(&body_text, body->body_text);
+
+ return pjsip_msg_body_create(pool, &type, &subtype, &body_text);
+}
+
+int ast_sip_add_body(pjsip_tx_data *tdata, const struct ast_sip_body *body)
+{
+ pjsip_msg_body *pjsip_body = ast_body_to_pjsip_body(tdata->pool, body);
+ tdata->msg->body = pjsip_body;
+ return 0;
+}
+
+int ast_sip_add_body_multipart(pjsip_tx_data *tdata, const struct ast_sip_body *bodies[], int num_bodies)
+{
+ int i;
+ /* NULL for type and subtype automatically creates "multipart/mixed" */
+ pjsip_msg_body *body = pjsip_multipart_create(tdata->pool, NULL, NULL);
+
+ for (i = 0; i < num_bodies; ++i) {
+ pjsip_multipart_part *part = pjsip_multipart_create_part(tdata->pool);
+ part->body = ast_body_to_pjsip_body(tdata->pool, bodies[i]);
+ pjsip_multipart_add_part(tdata->pool, body, part);
+ }
+
+ tdata->msg->body = body;
+ return 0;
+}
+
+int ast_sip_append_body(pjsip_tx_data *tdata, const char *body_text)
+{
+ size_t combined_size = strlen(body_text) + tdata->msg->body->len;
+ struct ast_str *body_buffer = ast_str_alloca(combined_size);
+
+ ast_str_set(&body_buffer, 0, "%.*s%s", (int) tdata->msg->body->len, (char *) tdata->msg->body->data, body_text);
+
+ tdata->msg->body->data = pj_pool_alloc(tdata->pool, combined_size);
+ pj_memcpy(tdata->msg->body->data, ast_str_buffer(body_buffer), combined_size);
+ tdata->msg->body->len = combined_size;
+
+ return 0;
+}
+
+struct ast_taskprocessor *ast_sip_create_serializer(void)
+{
+ struct ast_taskprocessor *serializer;
+ RAII_VAR(struct ast_uuid *, uuid, ast_uuid_generate(), ast_free_ptr);
+ char name[AST_UUID_STR_LEN];
+
+ if (!uuid) {
+ return NULL;
+ }
+
+ ast_uuid_to_str(uuid, name, sizeof(name));
+
+ serializer = ast_threadpool_serializer(name, sip_threadpool);
+ if (!serializer) {
+ return NULL;
+ }
+ return serializer;
+}
+
+int ast_sip_push_task(struct ast_taskprocessor *serializer, int (*sip_task)(void *), void *task_data)
+{
+ if (serializer) {
+ return ast_taskprocessor_push(serializer, sip_task, task_data);
+ } else {
+ return ast_threadpool_push(sip_threadpool, sip_task, task_data);
+ }
+}
+
+struct sync_task_data {
+ ast_mutex_t lock;
+ ast_cond_t cond;
+ int complete;
+ int fail;
+ int (*task)(void *);
+ void *task_data;
+};
+
+static int sync_task(void *data)
+{
+ struct sync_task_data *std = data;
+ std->fail = std->task(std->task_data);
+
+ ast_mutex_lock(&std->lock);
+ std->complete = 1;
+ ast_cond_signal(&std->cond);
+ ast_mutex_unlock(&std->lock);
+ return std->fail;
+}
+
+int ast_sip_push_task_synchronous(struct ast_taskprocessor *serializer, int (*sip_task)(void *), void *task_data)
+{
+ /* This method is an onion */
+ struct sync_task_data std;
+ ast_mutex_init(&std.lock);
+ ast_cond_init(&std.cond, NULL);
+ std.fail = std.complete = 0;
+ std.task = sip_task;
+ std.task_data = task_data;
+
+ if (serializer) {
+ if (ast_taskprocessor_push(serializer, sync_task, &std)) {
+ return -1;
+ }
+ } else {
+ if (ast_threadpool_push(sip_threadpool, sync_task, &std)) {
+ return -1;
+ }
+ }
+
+ ast_mutex_lock(&std.lock);
+ while (!std.complete) {
+ ast_cond_wait(&std.cond, &std.lock);
+ }
+ ast_mutex_unlock(&std.lock);
+
+ ast_mutex_destroy(&std.lock);
+ ast_cond_destroy(&std.cond);
+ return std.fail;
+}
+
+void ast_copy_pj_str(char *dest, pj_str_t *src, size_t size)
+{
+ size_t chars_to_copy = MIN(size - 1, pj_strlen(src));
+ memcpy(dest, pj_strbuf(src), chars_to_copy);
+ dest[chars_to_copy] = '\0';
+}
+
+pj_caching_pool caching_pool;
+pj_pool_t *memory_pool;
+pj_thread_t *monitor_thread;
+static int monitor_continue;
+
+static void *monitor_thread_exec(void *endpt)
+{
+ while (monitor_continue) {
+ const pj_time_val delay = {0, 10};
+ pjsip_endpt_handle_events(ast_pjsip_endpoint, &delay);
+ }
+ return NULL;
+}
+
+static void stop_monitor_thread(void)
+{
+ monitor_continue = 0;
+ pj_thread_join(monitor_thread);
+}
+
+AST_THREADSTORAGE(pj_thread_storage);
+AST_THREADSTORAGE(servant_id_storage);
+#define SIP_SERVANT_ID 0xDEFECA7E
+
+static void sip_thread_start(void)
+{
+ pj_thread_desc *desc;
+ pj_thread_t *thread;
+ uint32_t *servant_id;
+
+ servant_id = ast_threadstorage_get(&servant_id_storage, sizeof(*servant_id));
+ if (!servant_id) {
+ ast_log(LOG_ERROR, "Could not set SIP servant ID in thread-local storage.\n");
+ return;
+ }
+ *servant_id = SIP_SERVANT_ID;
+
+ desc = ast_threadstorage_get(&pj_thread_storage, sizeof(pj_thread_desc));
+ if (!desc) {
+ ast_log(LOG_ERROR, "Could not get thread desc from thread-local storage. Expect awful things to occur\n");
+ return;
+ }
+ pj_bzero(*desc, sizeof(*desc));
+
+ if (pj_thread_register("Asterisk Thread", *desc, &thread) != PJ_SUCCESS) {
+ ast_log(LOG_ERROR, "Couldn't register thread with PJLIB.\n");
+ }
+}
+
+int ast_sip_thread_is_servant(void)
+{
+ uint32_t *servant_id;
+
+ servant_id = ast_threadstorage_get(&servant_id_storage, sizeof(*servant_id));
+ if (!servant_id) {
+ return 0;
+ }
+
+ return *servant_id == SIP_SERVANT_ID;
+}
+
+static int load_module(void)
+{
+ /* The third parameter is just copied from
+ * example code from PJLIB. This can be adjusted
+ * if necessary.
+ */
+ pj_status_t status;
+
+ /* XXX For the time being, create hard-coded threadpool
+ * options. Just bump up by five threads every time we
+ * don't have any available threads. Idle threads time
+ * out after a minute. No maximum size
+ */
+ struct ast_threadpool_options options = {
+ .version = AST_THREADPOOL_OPTIONS_VERSION,
+ .auto_increment = 5,
+ .max_size = 0,
+ .idle_timeout = 60,
+ .initial_size = 0,
+ .thread_start = sip_thread_start,
+ };
+ sip_threadpool = ast_threadpool_create("SIP", NULL, &options);
+
+ if (pj_init() != PJ_SUCCESS) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ if (pjlib_util_init() != PJ_SUCCESS) {
+ pj_shutdown();
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ pj_caching_pool_init(&caching_pool, NULL, 1024 * 1024);
+ if (pjsip_endpt_create(&caching_pool.factory, "SIP", &ast_pjsip_endpoint) != PJ_SUCCESS) {
+ ast_log(LOG_ERROR, "Failed to create PJSIP endpoint structure. Aborting load\n");
+ goto error;
+ }
+ memory_pool = pj_pool_create(&caching_pool.factory, "SIP", 1024, 1024, NULL);
+ if (!memory_pool) {
+ ast_log(LOG_ERROR, "Failed to create memory pool for SIP. Aborting load\n");
+ goto error;
+ }
+
+ pjsip_tsx_layer_init_module(ast_pjsip_endpoint);
+ pjsip_ua_init_module(ast_pjsip_endpoint, NULL);
+
+ monitor_continue = 1;
+ status = pj_thread_create(memory_pool, "SIP", (pj_thread_proc *) &monitor_thread_exec,
+ NULL, PJ_THREAD_DEFAULT_STACK_SIZE * 2, 0, &monitor_thread);
+ if (status != PJ_SUCCESS) {
+ ast_log(LOG_ERROR, "Failed to start SIP monitor thread. Aborting load\n");
+ goto error;
+ }
+
+ if (ast_res_sip_initialize_configuration()) {
+ ast_log(LOG_ERROR, "Failed to initialize SIP configuration. Aborting load\n");
+ goto error;
+ }
+
+ if (ast_sip_initialize_distributor()) {
+ ast_log(LOG_ERROR, "Failed to register distributor module. Aborting load\n");
+ goto error;
+ }
+
+ if (ast_sip_initialize_outbound_authentication()) {
+ ast_log(LOG_ERROR, "Failed to initialize outbound authentication. Aborting load\n");
+ goto error;
+ }
+
+ ast_res_sip_init_options_handling(0);
+
+return AST_MODULE_LOAD_SUCCESS;
+
+error:
+ ast_res_sip_destroy_configuration();
+ if (monitor_thread) {
+ stop_monitor_thread();
+ }
+ if (memory_pool) {
+ pj_pool_release(memory_pool);
+ memory_pool = NULL;
+ }
+ if (ast_pjsip_endpoint) {
+ pjsip_endpt_destroy(ast_pjsip_endpoint);
+ ast_pjsip_endpoint = NULL;
+ }
+ pj_caching_pool_destroy(&caching_pool);
+ /* XXX Should have a way of stopping monitor thread */
+ return AST_MODULE_LOAD_DECLINE;
+}
+
+static int reload_module(void)
+{
+ if (ast_res_sip_reload_configuration()) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ ast_res_sip_init_options_handling(1);
+ return 0;
+}
+
+static int unload_pjsip(void *data)
+{
+ if (memory_pool) {
+ pj_pool_release(memory_pool);
+ memory_pool = NULL;
+ }
+ if (ast_pjsip_endpoint) {
+ pjsip_endpt_destroy(ast_pjsip_endpoint);
+ ast_pjsip_endpoint = NULL;
+ }
+ pj_caching_pool_destroy(&caching_pool);
+ return 0;
+}
+
+static int unload_module(void)
+{
+ ast_res_sip_destroy_configuration();
+ if (monitor_thread) {
+ stop_monitor_thread();
+ }
+ /* The thread this is called from cannot call PJSIP/PJLIB functions,
+ * so we have to push the work to the threadpool to handle
+ */
+ ast_sip_push_task_synchronous(NULL, unload_pjsip, NULL);
+
+ ast_threadpool_shutdown(sip_threadpool);
+
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Basic SIP resource",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload_module,
+ .load_pri = AST_MODPRI_CHANNEL_DEPEND,
+);
diff --git a/res/res_sip.exports.in b/res/res_sip.exports.in
new file mode 100644
index 000000000..010f90cb1
--- /dev/null
+++ b/res/res_sip.exports.in
@@ -0,0 +1,52 @@
+{
+ global:
+ LINKER_SYMBOL_PREFIXast_sip_register_service;
+ LINKER_SYMBOL_PREFIXast_sip_unregister_service;
+ LINKER_SYMBOL_PREFIXast_sip_register_authenticator;
+ LINKER_SYMBOL_PREFIXast_sip_unregister_authenticator;
+ LINKER_SYMBOL_PREFIXast_sip_register_outbound_authenticator;
+ LINKER_SYMBOL_PREFIXast_sip_unregister_outbound_authenticator;
+ LINKER_SYMBOL_PREFIXast_sip_register_endpoint_identifier;
+ LINKER_SYMBOL_PREFIXast_sip_unregister_endpoint_identifier;
+ LINKER_SYMBOL_PREFIXast_sip_create_serializer;
+ LINKER_SYMBOL_PREFIXast_sip_push_task;
+ LINKER_SYMBOL_PREFIXast_sip_push_task_synchronous;
+ LINKER_SYMBOL_PREFIXast_sip_create_request;
+ LINKER_SYMBOL_PREFIXast_sip_create_request_with_auth;
+ LINKER_SYMBOL_PREFIXast_sip_send_request;
+ LINKER_SYMBOL_PREFIXast_sip_requires_authentication;
+ LINKER_SYMBOL_PREFIXast_sip_authenticate_request;
+ LINKER_SYMBOL_PREFIXast_sip_get_authentication_credentials;
+ LINKER_SYMBOL_PREFIXast_sip_check_authentication;
+ LINKER_SYMBOL_PREFIXast_sip_create_auth_challenge_response;
+ LINKER_SYMBOL_PREFIXast_sip_set_outbound_authentication_credentials;
+ LINKER_SYMBOL_PREFIXast_sip_dialog_setup_outbound_authentication;
+ LINKER_SYMBOL_PREFIXast_sip_add_digest_to_challenge;
+ LINKER_SYMBOL_PREFIXast_sip_identify_endpoint;
+ LINKER_SYMBOL_PREFIXast_sip_add_header;
+ LINKER_SYMBOL_PREFIXast_sip_add_body;
+ LINKER_SYMBOL_PREFIXast_sip_add_body_multipart;
+ LINKER_SYMBOL_PREFIXast_sip_append_body;
+ LINKER_SYMBOL_PREFIXast_sip_get_pjsip_endpoint;
+ LINKER_SYMBOL_PREFIXast_sip_endpoint_alloc;
+ LINKER_SYMBOL_PREFIXast_copy_pj_str;
+ LINKER_SYMBOL_PREFIXast_sip_get_sorcery;
+ LINKER_SYMBOL_PREFIXast_sip_create_dialog;
+ LINKER_SYMBOL_PREFIXast_sip_location_retrieve_aor;
+ LINKER_SYMBOL_PREFIXast_sip_location_retrieve_first_aor_contact;
+ LINKER_SYMBOL_PREFIXast_sip_location_retrieve_contact_from_aor_list;
+ LINKER_SYMBOL_PREFIXast_sip_location_retrieve_aor_contacts;
+ LINKER_SYMBOL_PREFIXast_sip_location_retrieve_contact;
+ LINKER_SYMBOL_PREFIXast_sip_location_add_contact;
+ LINKER_SYMBOL_PREFIXast_sip_location_update_contact;
+ LINKER_SYMBOL_PREFIXast_sip_location_delete_contact;
+ LINKER_SYMBOL_PREFIXast_pjsip_rdata_get_endpoint;
+ LINKER_SYMBOL_PREFIXast_sip_thread_is_servant;
+ LINKER_SYMBOL_PREFIXast_sip_dialog_set_serializer;
+ LINKER_SYMBOL_PREFIXast_sip_dialog_set_endpoint;
+ LINKER_SYMBOL_PREFIXast_sip_dialog_get_endpoint;
+ LINKER_SYMBOL_PREFIXast_sip_retrieve_auths;
+ LINKER_SYMBOL_PREFIXast_sip_cleanup_auths;
+ local:
+ *;
+};
diff --git a/res/res_sip/config_auth.c b/res/res_sip/config_auth.c
new file mode 100644
index 000000000..9881dd8c6
--- /dev/null
+++ b/res/res_sip/config_auth.c
@@ -0,0 +1,120 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjlib.h>
+#include "asterisk/res_sip.h"
+#include "asterisk/logger.h"
+#include "asterisk/sorcery.h"
+
+static void auth_destroy(void *obj)
+{
+ struct ast_sip_auth *auth = obj;
+ ast_string_field_free_memory(auth);
+}
+
+static void *auth_alloc(const char *name)
+{
+ struct ast_sip_auth *auth = ao2_alloc(sizeof(*auth), auth_destroy);
+
+ if (!auth) {
+ return NULL;
+ }
+
+ if (ast_string_field_init(auth, 64)) {
+ ao2_cleanup(auth);
+ return NULL;
+ }
+
+ return auth;
+}
+
+static int auth_type_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_auth *auth = obj;
+ if (!strcasecmp(var->value, "userpass")) {
+ auth->type = AST_SIP_AUTH_TYPE_USER_PASS;
+ } else if (!strcasecmp(var->value, "md5")) {
+ auth->type = AST_SIP_AUTH_TYPE_MD5;
+ } else {
+ ast_log(LOG_WARNING, "Unknown authentication storage type '%s' specified for %s\n",
+ var->value, var->name);
+ return -1;
+ }
+ return 0;
+}
+
+static int auth_apply(const struct ast_sorcery *sorcery, void *obj)
+{
+ struct ast_sip_auth *auth = obj;
+ int res = 0;
+
+ if (ast_strlen_zero(auth->auth_user)) {
+ ast_log(LOG_ERROR, "No authentication username for auth '%s'\n",
+ ast_sorcery_object_get_id(auth));
+ return -1;
+ }
+
+ switch (auth->type) {
+ case AST_SIP_AUTH_TYPE_USER_PASS:
+ if (ast_strlen_zero(auth->auth_pass)) {
+ ast_log(LOG_ERROR, "'userpass' authentication specified but no"
+ "password specified for auth '%s'\n", ast_sorcery_object_get_id(auth));
+ res = -1;
+ }
+ break;
+ case AST_SIP_AUTH_TYPE_MD5:
+ if (ast_strlen_zero(auth->md5_creds)) {
+ ast_log(LOG_ERROR, "'md5' authentication specified but no md5_cred"
+ "specified for auth '%s'\n", ast_sorcery_object_get_id(auth));
+ res = -1;
+ }
+ break;
+ }
+
+ return res;
+}
+
+/*! \brief Initialize sorcery with auth support */
+int ast_sip_initialize_sorcery_auth(struct ast_sorcery *sorcery)
+{
+ ast_sorcery_apply_default(sorcery, SIP_SORCERY_AUTH_TYPE, "config", "res_sip.conf,criteria=type=auth");
+
+ if (ast_sorcery_object_register(sorcery, SIP_SORCERY_AUTH_TYPE, auth_alloc, NULL, auth_apply)) {
+ return -1;
+ }
+
+ ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "type", "",
+ OPT_NOOP_T, 0, 0);
+ ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "username",
+ "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, auth_user));
+ ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "password",
+ "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, auth_pass));
+ ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "md5_cred",
+ "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, md5_creds));
+ ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "realm",
+ "asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, realm));
+ ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "nonce_lifetime",
+ "32", OPT_UINT_T, 0, FLDSET(struct ast_sip_auth, nonce_lifetime));
+ ast_sorcery_object_field_register_custom(sorcery, SIP_SORCERY_AUTH_TYPE, "auth_type",
+ "userpass", auth_type_handler, NULL, 0, 0);
+
+ return 0;
+}
diff --git a/res/res_sip/config_domain_aliases.c b/res/res_sip/config_domain_aliases.c
new file mode 100644
index 000000000..86b4636ea
--- /dev/null
+++ b/res/res_sip/config_domain_aliases.c
@@ -0,0 +1,65 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Joshua Colp <jcolp@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+
+#include "pjsip.h"
+#include "pjlib.h"
+#include "asterisk/res_sip.h"
+#include "asterisk/logger.h"
+#include "asterisk/sorcery.h"
+
+static void domain_alias_destroy(void *obj)
+{
+ struct ast_sip_domain_alias *alias = obj;
+
+ ast_string_field_free_memory(alias);
+}
+
+static void *domain_alias_alloc(const char *name)
+{
+ struct ast_sip_domain_alias *alias = ao2_alloc(sizeof(*alias), domain_alias_destroy);
+
+ if (!alias) {
+ return NULL;
+ }
+
+ if (ast_string_field_init(alias, 256)) {
+ ao2_cleanup(alias);
+ return NULL;
+ }
+
+ return alias;
+}
+
+/*! \brief Initialize sorcery with domain alias support */
+int ast_sip_initialize_sorcery_domain_alias(struct ast_sorcery *sorcery)
+{
+ ast_sorcery_apply_default(sorcery, SIP_SORCERY_DOMAIN_ALIAS_TYPE, "config", "res_sip.conf,criteria=type=domain_alias");
+
+ if (ast_sorcery_object_register(sorcery, SIP_SORCERY_DOMAIN_ALIAS_TYPE, domain_alias_alloc, NULL, NULL)) {
+ return -1;
+ }
+
+ ast_sorcery_object_field_register(sorcery, SIP_SORCERY_DOMAIN_ALIAS_TYPE, "type", "",
+ OPT_NOOP_T, 0, 0);
+ ast_sorcery_object_field_register(sorcery, SIP_SORCERY_DOMAIN_ALIAS_TYPE, "domain",
+ "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_domain_alias, domain));
+
+ return 0;
+}
diff --git a/res/res_sip/config_transport.c b/res/res_sip/config_transport.c
new file mode 100644
index 000000000..eb89ee44e
--- /dev/null
+++ b/res/res_sip/config_transport.c
@@ -0,0 +1,299 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Joshua Colp <jcolp@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjlib.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/logger.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/sorcery.h"
+#include "asterisk/acl.h"
+
+static int destroy_transport_state(void *data)
+{
+ pjsip_transport *transport = data;
+ pjsip_transport_shutdown(transport);
+ return 0;
+}
+
+/*! \brief Destructor for transport state information */
+static void transport_state_destroy(void *obj)
+{
+ struct ast_sip_transport_state *state = obj;
+
+ if (state->transport) {
+ ast_sip_push_task_synchronous(NULL, destroy_transport_state, state->transport);
+ }
+}
+
+/*! \brief Destructor for transport */
+static void transport_destroy(void *obj)
+{
+ struct ast_sip_transport *transport = obj;
+
+ ast_string_field_free_memory(transport);
+ ast_free_ha(transport->localnet);
+
+ if (transport->external_address_refresher) {
+ ast_dnsmgr_release(transport->external_address_refresher);
+ }
+
+ ao2_cleanup(transport->state);
+}
+
+/*! \brief Allocator for transport */
+static void *transport_alloc(const char *name)
+{
+ struct ast_sip_transport *transport = ao2_alloc(sizeof(*transport), transport_destroy);
+
+ if (!transport) {
+ return NULL;
+ }
+
+ if (ast_string_field_init(transport, 256)) {
+ ao2_cleanup(transport);
+ return NULL;
+ }
+
+ pjsip_tls_setting_default(&transport->tls);
+ transport->tls.ciphers = transport->ciphers;
+
+ return transport;
+}
+
+/*! \brief Apply handler for transports */
+static int transport_apply(const struct ast_sorcery *sorcery, void *obj)
+{
+ struct ast_sip_transport *transport = obj;
+ RAII_VAR(struct ast_sip_transport *, existing, ast_sorcery_retrieve_by_id(sorcery, "transport", ast_sorcery_object_get_id(obj)), ao2_cleanup);
+ pj_status_t res = -1;
+
+ if (!existing || !existing->state) {
+ if (!(transport->state = ao2_alloc(sizeof(*transport->state), transport_state_destroy))) {
+ ast_log(LOG_ERROR, "Transport state for '%s' could not be allocated\n", ast_sorcery_object_get_id(obj));
+ return -1;
+ }
+ } else {
+ transport->state = existing->state;
+ ao2_ref(transport->state, +1);
+ }
+
+ /* Once active a transport can not be reconfigured */
+ if (transport->state->transport || transport->state->factory) {
+ return -1;
+ }
+
+ /* Set default port if not present */
+ if (!pj_sockaddr_get_port(&transport->host)) {
+ pj_sockaddr_set_port(&transport->host, (transport->type == AST_SIP_TRANSPORT_TLS) ? 5061 : 5060);
+ }
+
+ /* Now that we know what address family we can set up a dnsmgr refresh for the external media address if present */
+ if (!ast_strlen_zero(transport->external_signaling_address)) {
+ if (transport->host.addr.sa_family == pj_AF_INET()) {
+ transport->external_address.ss.ss_family = AF_INET;
+ } else if (transport->host.addr.sa_family == pj_AF_INET6()) {
+ transport->external_address.ss.ss_family = AF_INET6;
+ } else {
+ ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external signaling address\n",
+ ast_sorcery_object_get_id(obj));
+ return -1;
+ }
+
+ if (ast_dnsmgr_lookup(transport->external_signaling_address, &transport->external_address, &transport->external_address_refresher, NULL) < 0) {
+ ast_log(LOG_ERROR, "Could not create dnsmgr for external signaling address on '%s'\n", ast_sorcery_object_get_id(obj));
+ return -1;
+ }
+ }
+
+ if (transport->type == AST_SIP_TRANSPORT_UDP) {
+ if (transport->host.addr.sa_family == pj_AF_INET()) {
+ res = pjsip_udp_transport_start(ast_sip_get_pjsip_endpoint(), &transport->host.ipv4, NULL, transport->async_operations, &transport->state->transport);
+ } else if (transport->host.addr.sa_family == pj_AF_INET6()) {
+ res = pjsip_udp_transport_start6(ast_sip_get_pjsip_endpoint(), &transport->host.ipv6, NULL, transport->async_operations, &transport->state->transport);
+ }
+ } else if (transport->type == AST_SIP_TRANSPORT_TCP) {
+ pjsip_tcp_transport_cfg cfg;
+
+ pjsip_tcp_transport_cfg_default(&cfg, transport->host.addr.sa_family);
+ cfg.bind_addr = transport->host;
+ cfg.async_cnt = transport->async_operations;
+
+ res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg, &transport->state->factory);
+ } else if (transport->type == AST_SIP_TRANSPORT_TLS) {
+ transport->tls.ca_list_file = pj_str((char*)transport->ca_list_file);
+ transport->tls.cert_file = pj_str((char*)transport->cert_file);
+ transport->tls.privkey_file = pj_str((char*)transport->privkey_file);
+ transport->tls.password = pj_str((char*)transport->password);
+
+ res = pjsip_tls_transport_start2(ast_sip_get_pjsip_endpoint(), &transport->tls, &transport->host, NULL, transport->async_operations, &transport->state->factory);
+ }
+
+ if (res != PJ_SUCCESS) {
+ char msg[PJ_ERR_MSG_SIZE];
+
+ pjsip_strerror(res, msg, sizeof(msg));
+ ast_log(LOG_ERROR, "Transport '%s' could not be started: %s\n", ast_sorcery_object_get_id(obj), msg);
+ return -1;
+ }
+ return 0;
+}
+
+/*! \brief Custom handler for turning a string protocol into an enum */
+static int transport_protocol_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_transport *transport = obj;
+
+ if (!strcasecmp(var->value, "udp")) {
+ transport->type = AST_SIP_TRANSPORT_UDP;
+ } else if (!strcasecmp(var->value, "tcp")) {
+ transport->type = AST_SIP_TRANSPORT_TCP;
+ } else if (!strcasecmp(var->value, "tls")) {
+ transport->type = AST_SIP_TRANSPORT_TLS;
+ } else {
+ /* TODO: Implement websockets */
+ return -1;
+ }
+
+ return 0;
+}
+
+/*! \brief Custom handler for turning a string bind into a pj_sockaddr */
+static int transport_bind_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_transport *transport = obj;
+ pj_str_t buf;
+
+ return (pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, var->value), &transport->host) != PJ_SUCCESS) ? -1 : 0;
+}
+
+/*! \brief Custom handler for TLS boolean settings */
+static int transport_tls_bool_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_transport *transport = obj;
+
+ if (!strcasecmp(var->name, "verify_server")) {
+ transport->tls.verify_server = ast_true(var->value) ? PJ_TRUE : PJ_FALSE;
+ } else if (!strcasecmp(var->name, "verify_client")) {
+ transport->tls.verify_client = ast_true(var->value) ? PJ_TRUE : PJ_FALSE;
+ } else if (!strcasecmp(var->name, "require_client_cert")) {
+ transport->tls.require_client_cert = ast_true(var->value) ? PJ_TRUE : PJ_FALSE;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*! \brief Custom handler for TLS method setting */
+static int transport_tls_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_transport *transport = obj;
+
+ if (!strcasecmp(var->value, "default")) {
+ transport->tls.method = PJSIP_SSL_DEFAULT_METHOD;
+ } else if (!strcasecmp(var->value, "unspecified")) {
+ transport->tls.method = PJSIP_SSL_UNSPECIFIED_METHOD;
+ } else if (!strcasecmp(var->value, "tlsv1")) {
+ transport->tls.method = PJSIP_TLSV1_METHOD;
+ } else if (!strcasecmp(var->value, "sslv2")) {
+ transport->tls.method = PJSIP_SSLV2_METHOD;
+ } else if (!strcasecmp(var->value, "sslv3")) {
+ transport->tls.method = PJSIP_SSLV3_METHOD;
+ } else if (!strcasecmp(var->value, "sslv23")) {
+ transport->tls.method = PJSIP_SSLV23_METHOD;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*! \brief Custom handler for TLS cipher setting */
+static int transport_tls_cipher_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_transport *transport = obj;
+ pj_ssl_cipher cipher;
+
+ if (transport->tls.ciphers_num == (SIP_TLS_MAX_CIPHERS - 1)) {
+ return -1;
+ }
+
+ /* TODO: Check this over/tweak - it's taken from pjsua for now */
+ if (!strnicmp(var->value, "0x", 2)) {
+ pj_str_t cipher_st = pj_str((char*)var->value + 2);
+ cipher = pj_strtoul2(&cipher_st, NULL, 16);
+ } else {
+ cipher = atoi(var->value);
+ }
+
+ if (pj_ssl_cipher_is_supported(cipher)) {
+ transport->ciphers[transport->tls.ciphers_num++] = cipher;
+ return 0;
+ } else {
+ ast_log(LOG_ERROR, "Cipher '%s' is unsupported\n", var->value);
+ return -1;
+ }
+}
+
+/*! \brief Custom handler for localnet setting */
+static int transport_localnet_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_transport *transport = obj;
+ int error = 0;
+
+ if (!(transport->localnet = ast_append_ha("d", var->value, transport->localnet, &error))) {
+ return -1;
+ }
+
+ return error;
+}
+
+/*! \brief Initialize sorcery with transport support */
+int ast_sip_initialize_sorcery_transport(struct ast_sorcery *sorcery)
+{
+ ast_sorcery_apply_default(sorcery, "transport", "config", "res_sip.conf,criteria=type=transport");
+
+ if (ast_sorcery_object_register(sorcery, "transport", transport_alloc, NULL, transport_apply)) {
+ return -1;
+ }
+
+ ast_sorcery_object_field_register(sorcery, "transport", "type", "", OPT_NOOP_T, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "protocol", "udp", transport_protocol_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "bind", "", transport_bind_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register(sorcery, "transport", "async_operations", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, async_operations));
+ ast_sorcery_object_field_register(sorcery, "transport", "ca_list_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, ca_list_file));
+ ast_sorcery_object_field_register(sorcery, "transport", "cert_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, cert_file));
+ ast_sorcery_object_field_register(sorcery, "transport", "privkey_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, privkey_file));
+ ast_sorcery_object_field_register(sorcery, "transport", "password", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, password));
+ ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, external_signaling_address));
+ ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_port", "0", OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, external_signaling_port), 0, 65535);
+ ast_sorcery_object_field_register(sorcery, "transport", "external_media_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, external_media_address));
+ ast_sorcery_object_field_register(sorcery, "transport", "domain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, domain));
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_server", "", transport_tls_bool_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_client", "", transport_tls_bool_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "require_client_cert", "", transport_tls_bool_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "method", "", transport_tls_method_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "cipher", "", transport_tls_cipher_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sorcery, "transport", "localnet", "", transport_localnet_handler, NULL, 0, 0);
+
+ return 0;
+}
diff --git a/res/res_sip/include/res_sip_private.h b/res/res_sip/include/res_sip_private.h
new file mode 100644
index 000000000..318510aae
--- /dev/null
+++ b/res/res_sip/include/res_sip_private.h
@@ -0,0 +1,57 @@
+/*
+ * res_sip.h
+ *
+ * Created on: Jan 25, 2013
+ * Author: mjordan
+ */
+
+#ifndef RES_SIP_PRIVATE_H_
+#define RES_SIP_PRIVATE_H_
+
+struct ao2_container;
+
+/*!
+ * \brief Initialize the configuration for res_sip
+ */
+int ast_res_sip_initialize_configuration(void);
+
+/*!
+ * \brief Annihilate the configuration objects
+ */
+void ast_res_sip_destroy_configuration(void);
+
+/*!
+ * \brief Reload the configuration
+ */
+int ast_res_sip_reload_configuration(void);
+
+/*!
+ * \brief Initialize OPTIONS request handling.
+ *
+ * XXX This currently includes qualifying peers. It shouldn't.
+ * That should go into a registrar. When that occurs, we won't
+ * need the reload stuff.
+ *
+ * \param reload Reload options handling
+ *
+ * \retval 0 on success
+ * \retval other on failure
+ */
+int ast_res_sip_init_options_handling(int reload);
+
+/*!
+ * \brief Initialize outbound authentication support
+ *
+ * \retval 0 Success
+ * \retval non-zero Failure
+ */
+int ast_sip_initialize_outbound_authentication(void);
+
+/*!
+ * \brief Get the current defined endpoints
+ *
+ * \retval The current endpoints loaded by res_sip
+ */
+struct ao2_container *ast_res_sip_get_endpoints(void);
+
+#endif /* RES_SIP_PRIVATE_H_ */
diff --git a/res/res_sip/location.c b/res/res_sip/location.c
new file mode 100644
index 000000000..91521c813
--- /dev/null
+++ b/res/res_sip/location.c
@@ -0,0 +1,262 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Joshua Colp <jcolp@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+#include "pjsip.h"
+#include "pjlib.h"
+
+#include "asterisk/res_sip.h"
+#include "asterisk/logger.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/sorcery.h"
+
+/*! \brief Destructor for AOR */
+static void aor_destroy(void *obj)
+{
+ struct ast_sip_aor *aor = obj;
+
+ ao2_cleanup(aor->permanent_contacts);
+ ast_string_field_free_memory(aor);
+}
+
+/*! \brief Allocator for AOR */
+static void *aor_alloc(const char *name)
+{
+ struct ast_sip_aor *aor = ao2_alloc_options(sizeof(struct ast_sip_aor), aor_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
+ if (!aor) {
+ return NULL;
+ }
+ ast_string_field_init(aor, 128);
+ return aor;
+}
+
+/*! \brief Destructor for contact */
+static void contact_destroy(void *obj)
+{
+ struct ast_sip_contact *contact = obj;
+
+ ast_string_field_free_memory(contact);
+}
+
+/*! \brief Allocator for contact */
+static void *contact_alloc(const char *name)
+{
+ struct ast_sip_contact *contact = ao2_alloc_options(sizeof(*contact), contact_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
+
+ if (!contact) {
+ return NULL;
+ }
+
+ if (ast_string_field_init(contact, 256)) {
+ ao2_cleanup(contact);
+ return NULL;
+ }
+
+ return contact;
+}
+
+struct ast_sip_aor *ast_sip_location_retrieve_aor(const char *aor_name)
+{
+ return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
+}
+
+/*! \brief Internal callback function which deletes and unlinks any expired contacts */
+static int contact_expire(void *obj, void *arg, int flags)
+{
+ struct ast_sip_contact *contact = obj;
+
+ /* If the contact has not yet expired it is valid */
+ if (ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) > 0) {
+ return 0;
+ }
+
+ ast_sip_location_delete_contact(contact);
+
+ return CMP_MATCH;
+}
+
+/*! \brief Internal callback function which links static contacts into another container */
+static int contact_link_static(void *obj, void *arg, int flags)
+{
+ struct ao2_container *dest = arg;
+
+ ao2_link_flags(dest, obj, OBJ_NOLOCK);
+ return 0;
+}
+
+/*! \brief Simple callback function which returns immediately, used to grab the first contact of an AOR */
+static int contact_find_first(void *obj, void *arg, int flags)
+{
+ return CMP_MATCH | CMP_STOP;
+}
+
+struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct ast_sip_aor *aor)
+{
+ RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
+ struct ast_sip_contact *contact;
+
+ contacts = ast_sip_location_retrieve_aor_contacts(aor);
+ if (!contacts || (ao2_container_count(contacts) == 0)) {
+ return NULL;
+ }
+
+ contact = ao2_callback(contacts, OBJ_NOLOCK, contact_find_first, NULL);
+ return contact;
+}
+
+struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor)
+{
+ /* Give enough space for ^ at the beginning and ;@ at the end, since that is our object naming scheme */
+ char regex[strlen(ast_sorcery_object_get_id(aor)) + 4];
+ struct ao2_container *contacts;
+
+ snprintf(regex, sizeof(regex), "^%s;@", ast_sorcery_object_get_id(aor));
+
+ if (!(contacts = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "contact", regex))) {
+ return NULL;
+ }
+
+ /* Prune any expired contacts and delete them, we do this first because static contacts can never expire */
+ ao2_callback(contacts, OBJ_NOLOCK | OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, contact_expire, NULL);
+
+ /* Add any permanent contacts from the AOR */
+ if (aor->permanent_contacts) {
+ ao2_callback(aor->permanent_contacts, OBJ_NOLOCK | OBJ_NODATA, contact_link_static, contacts);
+ }
+
+ return contacts;
+}
+
+struct ast_sip_contact *ast_sip_location_retrieve_contact_from_aor_list(const char *aor_list)
+{
+ char *aor_name;
+ char *rest;
+ struct ast_sip_contact *contact = NULL;
+
+ /* If the location is still empty we have nowhere to go */
+ if (ast_strlen_zero(aor_list) || !(rest = ast_strdupa(aor_list))) {
+ ast_log(LOG_WARNING, "Unable to determine contacts from empty aor list\n");
+ return NULL;
+ }
+
+ while ((aor_name = strsep(&rest, ","))) {
+ RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
+ RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
+
+ if (!aor) {
+ continue;
+ }
+ contact = ast_sip_location_retrieve_first_aor_contact(aor);
+ /* If a valid contact is available use its URI for dialing */
+ if (contact) {
+ break;
+ }
+ }
+
+ return contact;
+}
+
+struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_name)
+{
+ return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "contact", contact_name);
+}
+
+int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time)
+{
+ char name[AST_UUID_STR_LEN];
+ RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
+
+ snprintf(name, sizeof(name), "%s;@%s", ast_sorcery_object_get_id(aor), uri);
+
+ if (!(contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", name))) {
+ return -1;
+ }
+
+ ast_string_field_set(contact, uri, uri);
+ contact->expiration_time = expiration_time;
+
+ return ast_sorcery_create(ast_sip_get_sorcery(), contact);
+}
+
+int ast_sip_location_update_contact(struct ast_sip_contact *contact)
+{
+ return ast_sorcery_update(ast_sip_get_sorcery(), contact);
+}
+
+int ast_sip_location_delete_contact(struct ast_sip_contact *contact)
+{
+ return ast_sorcery_delete(ast_sip_get_sorcery(), contact);
+}
+
+/*! \brief Custom handler for translating from a string timeval to actual structure */
+static int expiration_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_contact *contact = obj;
+ return ast_get_timeval(var->value, &contact->expiration_time, ast_tv(0, 0), NULL);
+}
+
+/*! \brief Custom handler for translating from an actual structure timeval to string */
+static int expiration_struct2str(const void *obj, const intptr_t *args, char **buf)
+{
+ const struct ast_sip_contact *contact = obj;
+ return (ast_asprintf(buf, "%lu", contact->expiration_time.tv_sec) < 0) ? -1 : 0;
+}
+
+/*! \brief Custom handler for permanent URIs */
+static int permanent_uri_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_aor *aor = obj;
+ RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
+
+ if ((!aor->permanent_contacts && !(aor->permanent_contacts = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) ||
+ !(contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", NULL))) {
+ return -1;
+ }
+
+ ast_string_field_set(contact, uri, var->value);
+ ao2_link_flags(aor->permanent_contacts, contact, OBJ_NOLOCK);
+
+ return 0;
+}
+
+/*! \brief Initialize sorcery with location support */
+int ast_sip_initialize_sorcery_location(struct ast_sorcery *sorcery)
+{
+ ast_sorcery_apply_default(sorcery, "contact", "astdb", "registrar");
+ ast_sorcery_apply_default(sorcery, "aor", "config", "res_sip.conf,criteria=type=aor");
+
+ if (ast_sorcery_object_register(sorcery, "contact", contact_alloc, NULL, NULL) ||
+ ast_sorcery_object_register(sorcery, "aor", aor_alloc, NULL, NULL)) {
+ return -1;
+ }
+
+ ast_sorcery_object_field_register(sorcery, "contact", "type", "", OPT_NOOP_T, 0, 0);
+ ast_sorcery_object_field_register(sorcery, "contact", "uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, uri));
+ ast_sorcery_object_field_register_custom(sorcery, "contact", "expiration_time", "", expiration_str2struct, expiration_struct2str, 0, 0);
+
+ ast_sorcery_object_field_register(sorcery, "aor", "type", "", OPT_NOOP_T, 0, 0);
+ ast_sorcery_object_field_register(sorcery, "aor", "minimum_expiration", "60", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, minimum_expiration));
+ ast_sorcery_object_field_register(sorcery, "aor", "maximum_expiration", "7200", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, maximum_expiration));
+ ast_sorcery_object_field_register(sorcery, "aor", "default_expiration", "3600", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, default_expiration));
+ ast_sorcery_object_field_register(sorcery, "aor", "max_contacts", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, max_contacts));
+ ast_sorcery_object_field_register(sorcery, "aor", "remove_existing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, remove_existing));
+ ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register(sorcery, "aor", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, mailboxes));
+
+ return 0;
+}
diff --git a/res/res_sip/sip_configuration.c b/res/res_sip/sip_configuration.c
new file mode 100644
index 000000000..489ba6aec
--- /dev/null
+++ b/res/res_sip/sip_configuration.c
@@ -0,0 +1,463 @@
+/*
+ * sip_cli_commands.c
+ *
+ * Created on: Jan 25, 2013
+ * Author: mjordan
+ */
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_ua.h>
+
+#include "asterisk/res_sip.h"
+#include "include/res_sip_private.h"
+#include "asterisk/cli.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/utils.h"
+#include "asterisk/sorcery.h"
+#include "asterisk/callerid.h"
+
+static struct ast_sorcery *sip_sorcery;
+
+static char *handle_cli_show_endpoints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ RAII_VAR(struct ao2_container *, endpoints, NULL, ao2_cleanup);
+ struct ao2_iterator it_endpoints;
+ struct ast_sip_endpoint *endpoint;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "sip show endpoints";
+ e->usage =
+ "Usage: sip show endpoints\n"
+ " Show the registered SIP endpoints\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ endpoints = ast_res_sip_get_endpoints();
+ if (!endpoints) {
+ return CLI_FAILURE;
+ }
+
+ if (!ao2_container_count(endpoints)) {
+ ast_cli(a->fd, "No endpoints found\n");
+ return CLI_SUCCESS;
+ }
+
+ ast_cli(a->fd, "Endpoints:\n");
+ it_endpoints = ao2_iterator_init(endpoints, 0);
+ while ((endpoint = ao2_iterator_next(&it_endpoints))) {
+ ast_cli(a->fd, "%s\n", ast_sorcery_object_get_id(endpoint));
+ ao2_ref(endpoint, -1);
+ }
+ ao2_iterator_destroy(&it_endpoints);
+ return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry cli_commands[] = {
+ AST_CLI_DEFINE(handle_cli_show_endpoints, "Show SIP Endpoints"),
+};
+
+static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_endpoint *endpoint = obj;
+
+ if (!strcasecmp(var->value, "rfc4733")) {
+ endpoint->dtmf = AST_SIP_DTMF_RFC_4733;
+ } else if (!strcasecmp(var->value, "inband")) {
+ endpoint->dtmf = AST_SIP_DTMF_INBAND;
+ } else if (!strcasecmp(var->value, "info")) {
+ endpoint->dtmf = AST_SIP_DTMF_INFO;
+ } else if (!strcasecmp(var->value, "none")) {
+ endpoint->dtmf = AST_SIP_DTMF_NONE;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int prack_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_endpoint *endpoint = obj;
+
+ if (ast_true(var->value)) {
+ endpoint->extensions |= PJSIP_INV_SUPPORT_100REL;
+ } else if (ast_false(var->value)) {
+ endpoint->extensions &= PJSIP_INV_SUPPORT_100REL;
+ } else if (!strcasecmp(var->value, "required")) {
+ endpoint->extensions |= PJSIP_INV_REQUIRE_100REL;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int timers_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_endpoint *endpoint = obj;
+
+ if (ast_true(var->value)) {
+ endpoint->extensions |= PJSIP_INV_SUPPORT_TIMER;
+ } else if (ast_false(var->value)) {
+ endpoint->extensions &= PJSIP_INV_SUPPORT_TIMER;
+ } else if (!strcasecmp(var->value, "required")) {
+ endpoint->extensions |= PJSIP_INV_REQUIRE_TIMER;
+ } else if (!strcasecmp(var->value, "always")) {
+ endpoint->extensions |= PJSIP_INV_ALWAYS_USE_TIMER;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+static void destroy_auths(const char **auths, size_t num_auths)
+{
+ int i;
+ for (i = 0; i < num_auths; ++i) {
+ ast_free((char *) auths[i]);
+ }
+ ast_free(auths);
+}
+
+#define AUTH_INCREMENT 4
+
+static const char **auth_alloc(const char *value, size_t *num_auths)
+{
+ char *auths = ast_strdupa(value);
+ char *val;
+ int num_alloced = 0;
+ const char **alloced_auths = NULL;
+
+ while ((val = strsep(&auths, ","))) {
+ if (*num_auths >= num_alloced) {
+ size_t size;
+ num_alloced += AUTH_INCREMENT;
+ size = num_alloced * sizeof(char *);
+ alloced_auths = ast_realloc(alloced_auths, size);
+ if (!alloced_auths) {
+ goto failure;
+ }
+ }
+ alloced_auths[*num_auths] = ast_strdup(val);
+ if (!alloced_auths[*num_auths]) {
+ goto failure;
+ }
+ ++(*num_auths);
+ }
+ return alloced_auths;
+
+failure:
+ destroy_auths(alloced_auths, *num_auths);
+ return NULL;
+}
+
+static int inbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_endpoint *endpoint = obj;
+
+ endpoint->sip_inbound_auths = auth_alloc(var->value, &endpoint->num_inbound_auths);
+ if (!endpoint->sip_inbound_auths) {
+ return -1;
+ }
+ return 0;
+}
+static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_endpoint *endpoint = obj;
+
+ endpoint->sip_outbound_auths = auth_alloc(var->value, &endpoint->num_outbound_auths);
+ if (!endpoint->sip_outbound_auths) {
+ return -1;
+ }
+ return 0;
+}
+
+static int ident_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_endpoint *endpoint = obj;
+ char *idents = ast_strdupa(var->value);
+ char *val;
+
+ while ((val = strsep(&idents, ","))) {
+ if (!strcasecmp(val, "username")) {
+ endpoint->ident_method |= AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME;
+ } else if (!strcasecmp(val, "location")) {
+ endpoint->ident_method |= AST_SIP_ENDPOINT_IDENTIFY_BY_LOCATION;
+ } else {
+ ast_log(LOG_ERROR, "Unrecognized identification method %s specified for endpoint %s\n",
+ val, ast_sorcery_object_get_id(endpoint));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int direct_media_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_endpoint *endpoint = obj;
+
+ if (!strcasecmp(var->value, "invite") || !strcasecmp(var->value, "reinvite")) {
+ endpoint->direct_media_method = AST_SIP_SESSION_REFRESH_METHOD_INVITE;
+ } else if (!strcasecmp(var->value, "update")) {
+ endpoint->direct_media_method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
+ } else {
+ ast_log(LOG_NOTICE, "Unrecognized option value %s for %s on endpoint %s\n",
+ var->value, var->name, ast_sorcery_object_get_id(endpoint));
+ return -1;
+ }
+ return 0;
+}
+
+static int direct_media_glare_mitigation_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_endpoint *endpoint = obj;
+
+ if (!strcasecmp(var->value, "none")) {
+ endpoint->direct_media_glare_mitigation = AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE;
+ } else if (!strcasecmp(var->value, "outgoing")) {
+ endpoint->direct_media_glare_mitigation = AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING;
+ } else if (!strcasecmp(var->value, "incoming")) {
+ endpoint->direct_media_glare_mitigation = AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING;
+ } else {
+ ast_log(LOG_NOTICE, "Unrecognized option value %s for %s on endpoint %s\n",
+ var->value, var->name, ast_sorcery_object_get_id(endpoint));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int caller_id_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_endpoint *endpoint = obj;
+ char cid_name[80] = { '\0' };
+ char cid_num[80] = { '\0' };
+
+ ast_callerid_split(var->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
+ if (!ast_strlen_zero(cid_name)) {
+ endpoint->id.name.str = ast_strdup(cid_name);
+ if (!endpoint->id.name.str) {
+ return -1;
+ }
+ endpoint->id.name.valid = 1;
+ }
+ if (!ast_strlen_zero(cid_num)) {
+ endpoint->id.number.str = ast_strdup(cid_num);
+ if (!endpoint->id.number.str) {
+ return -1;
+ }
+ endpoint->id.number.valid = 1;
+ }
+ return 0;
+}
+
+static int caller_id_privacy_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_endpoint *endpoint = obj;
+ int callingpres = ast_parse_caller_presentation(var->value);
+ if (callingpres == -1 && sscanf(var->value, "%d", &callingpres) != 1) {
+ return -1;
+ }
+ endpoint->id.number.presentation = callingpres;
+ endpoint->id.name.presentation = callingpres;
+ return 0;
+}
+
+static int caller_id_tag_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sip_endpoint *endpoint = obj;
+ endpoint->id.tag = ast_strdup(var->value);
+ return endpoint->id.tag ? 0 : -1;
+}
+
+static void *sip_nat_hook_alloc(const char *name)
+{
+ return ao2_alloc(sizeof(struct ast_sip_nat_hook), NULL);
+}
+
+int ast_res_sip_initialize_configuration(void)
+{
+ if (ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands))) {
+ return -1;
+ }
+
+ if (!(sip_sorcery = ast_sorcery_open())) {
+ ast_log(LOG_ERROR, "Failed to open SIP sorcery failed to open\n");
+ return -1;
+ }
+
+ ast_sorcery_apply_config(sip_sorcery, "res_sip");
+
+ if (ast_sip_initialize_sorcery_auth(sip_sorcery)) {
+ ast_log(LOG_ERROR, "Failed to register SIP authentication support\n");
+ ast_sorcery_unref(sip_sorcery);
+ sip_sorcery = NULL;
+ return -1;
+ }
+
+ ast_sorcery_apply_default(sip_sorcery, "endpoint", "config", "res_sip.conf,criteria=type=endpoint");
+
+ ast_sorcery_apply_default(sip_sorcery, "nat_hook", "memory", NULL);
+
+ if (ast_sorcery_object_register(sip_sorcery, "endpoint", ast_sip_endpoint_alloc, NULL, NULL)) {
+ ast_log(LOG_ERROR, "Failed to register SIP endpoint object with sorcery\n");
+ ast_sorcery_unref(sip_sorcery);
+ sip_sorcery = NULL;
+ return -1;
+ }
+
+ ast_sorcery_object_register(sip_sorcery, "nat_hook", sip_nat_hook_alloc, NULL, NULL);
+
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "type", "", OPT_NOOP_T, 0, 0);
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "context", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, context));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "disallow", "", OPT_CODEC_T, 0, FLDSET(struct ast_sip_endpoint, prefs, codecs));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow", "", OPT_CODEC_T, 1, FLDSET(struct ast_sip_endpoint, prefs, codecs));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "qualify_frequency", 0, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_endpoint, qualify_frequency), 0, 86400);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtmfmode", "rfc4733", dtmf_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, rtp_ipv6));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_symmetric", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, rtp_symmetric));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "ice_support", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, ice_support));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_ptime", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, use_ptime));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "force_rport", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, force_rport));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rewrite_contact", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, rewrite_contact));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, transport));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, outbound_proxy));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mohsuggest", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, mohsuggest));
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "100rel", "yes", prack_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "timers", "yes", timers_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "timers_min_se", "90", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, min_se));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "timers_sess_expires", "1800", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, sess_expires));
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "auth", "", inbound_auth_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outbound_auth", "", outbound_auth_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aors", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, aors));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "external_media_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, external_media_address));
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "identify_by", "username,location", ident_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "direct_media", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, direct_media));
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "direct_media_method", "invite", direct_media_method_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "direct_media_glare_mitigation", "none", direct_media_glare_mitigation_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "disable_direct_media_on_nat", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, disable_direct_media_on_nat));
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid", "", caller_id_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_privacy", "", caller_id_privacy_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_tag", "", caller_id_tag_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "trust_id_inbound", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, trust_id_inbound));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "trust_id_outbound", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, trust_id_outbound));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_pai", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, send_pai));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_rpid", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, send_rpid));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, mailboxes));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aggregate_mwi", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, aggregate_mwi));
+
+ if (ast_sip_initialize_sorcery_transport(sip_sorcery)) {
+ ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
+ ast_sorcery_unref(sip_sorcery);
+ sip_sorcery = NULL;
+ return -1;
+ }
+
+ if (ast_sip_initialize_sorcery_location(sip_sorcery)) {
+ ast_log(LOG_ERROR, "Failed to register SIP location support with sorcery\n");
+ ast_sorcery_unref(sip_sorcery);
+ sip_sorcery = NULL;
+ return -1;
+ }
+
+ if (ast_sip_initialize_sorcery_domain_alias(sip_sorcery)) {
+ ast_log(LOG_ERROR, "Failed to register SIP domain aliases support with sorcery\n");
+ ast_sorcery_unref(sip_sorcery);
+ sip_sorcery = NULL;
+ return -1;
+ }
+
+ ast_sorcery_load(sip_sorcery);
+
+ return 0;
+}
+
+void ast_res_sip_destroy_configuration(void)
+{
+ ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
+ ast_sorcery_unref(sip_sorcery);
+}
+
+int ast_res_sip_reload_configuration(void)
+{
+ if (sip_sorcery) {
+ ast_sorcery_reload(sip_sorcery);
+ }
+ return 0;
+}
+
+static void endpoint_destructor(void* obj)
+{
+ struct ast_sip_endpoint *endpoint = obj;
+
+ ast_string_field_free_memory(endpoint);
+
+ if (endpoint->codecs) {
+ ast_format_cap_destroy(endpoint->codecs);
+ }
+ destroy_auths(endpoint->sip_inbound_auths, endpoint->num_inbound_auths);
+ destroy_auths(endpoint->sip_outbound_auths, endpoint->num_outbound_auths);
+ ast_party_id_free(&endpoint->id);
+}
+
+void *ast_sip_endpoint_alloc(const char *name)
+{
+ struct ast_sip_endpoint *endpoint = ao2_alloc(sizeof(*endpoint), endpoint_destructor);
+ if (!endpoint) {
+ return NULL;
+ }
+ if (ast_string_field_init(endpoint, 64)) {
+ ao2_cleanup(endpoint);
+ return NULL;
+ }
+ if (!(endpoint->codecs = ast_format_cap_alloc_nolock())) {
+ ao2_cleanup(endpoint);
+ return NULL;
+ }
+ ast_party_id_init(&endpoint->id);
+ return endpoint;
+}
+
+struct ao2_container *ast_res_sip_get_endpoints(void)
+{
+ struct ao2_container *endpoints;
+
+ endpoints = ast_sorcery_retrieve_by_fields(sip_sorcery, "endpoint", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+
+ return endpoints;
+}
+
+int ast_sip_retrieve_auths(const char *auth_names[], size_t num_auths, struct ast_sip_auth **out)
+{
+ int i;
+
+ for (i = 0; i < num_auths; ++i) {
+ out[i] = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE, auth_names[i]);
+ if (!out[i]) {
+ ast_log(LOG_NOTICE, "Couldn't find auth '%s'. Cannot authenticate\n", auth_names[i]);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+void ast_sip_cleanup_auths(struct ast_sip_auth *auths[], size_t num_auths)
+{
+ int i;
+ for (i = 0; i < num_auths; ++i) {
+ ao2_cleanup(auths[i]);
+ }
+}
+
+struct ast_sorcery *ast_sip_get_sorcery(void)
+{
+ return sip_sorcery;
+}
+
diff --git a/res/res_sip/sip_distributor.c b/res/res_sip/sip_distributor.c
new file mode 100644
index 000000000..766261089
--- /dev/null
+++ b/res/res_sip/sip_distributor.c
@@ -0,0 +1,239 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+
+#include "asterisk/res_sip.h"
+
+static int distribute(void *data);
+static pj_bool_t distributor(pjsip_rx_data *rdata);
+
+static pjsip_module distributor_mod = {
+ .name = {"Request Distributor", 19},
+ .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 6,
+ .on_rx_request = distributor,
+ .on_rx_response = distributor,
+};
+
+/*! Dialog-specific information the distributor uses */
+struct distributor_dialog_data {
+ /* Serializer to distribute tasks to for this dialog */
+ struct ast_taskprocessor *serializer;
+ /* Endpoint associated with this dialog */
+ struct ast_sip_endpoint *endpoint;
+};
+
+/*!
+ * \internal
+ *
+ * \note Call this with the dialog locked
+ */
+static struct distributor_dialog_data *distributor_dialog_data_alloc(pjsip_dialog *dlg)
+{
+ struct distributor_dialog_data *dist;
+
+ dist = PJ_POOL_ZALLOC_T(dlg->pool, struct distributor_dialog_data);
+ pjsip_dlg_set_mod_data(dlg, distributor_mod.id, dist);
+
+ return dist;
+}
+
+void ast_sip_dialog_set_serializer(pjsip_dialog *dlg, struct ast_taskprocessor *serializer)
+{
+ struct distributor_dialog_data *dist;
+ SCOPED_LOCK(lock, dlg, pjsip_dlg_inc_lock, pjsip_dlg_dec_lock);
+
+ dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id);
+ if (!dist) {
+ dist = distributor_dialog_data_alloc(dlg);
+ }
+ dist->serializer = serializer;
+}
+
+void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
+{
+ struct distributor_dialog_data *dist;
+ SCOPED_LOCK(lock, dlg, pjsip_dlg_inc_lock, pjsip_dlg_dec_lock);
+
+ dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id);
+ if (!dist) {
+ dist = distributor_dialog_data_alloc(dlg);
+ }
+ dist->endpoint = endpoint;
+}
+
+struct ast_sip_endpoint *ast_sip_dialog_get_endpoint(pjsip_dialog *dlg)
+{
+ struct distributor_dialog_data *dist;
+ SCOPED_LOCK(lock, dlg, pjsip_dlg_inc_lock, pjsip_dlg_dec_lock);
+
+ dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id);
+ if (!dist || !dist->endpoint) {
+ return NULL;
+ }
+ ao2_ref(dist->endpoint, +1);
+ return dist->endpoint;
+}
+
+static pj_bool_t distributor(pjsip_rx_data *rdata)
+{
+ pjsip_dialog *dlg = pjsip_ua_find_dialog(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag, PJ_TRUE);
+ struct distributor_dialog_data *dist = NULL;
+ struct ast_taskprocessor *serializer = NULL;
+ pjsip_rx_data *clone;
+
+ pjsip_rx_data_clone(rdata, 0, &clone);
+ if (dlg) {
+ dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id);
+ if (dist) {
+ serializer = dist->serializer;
+ clone->endpt_info.mod_data[distributor_mod.id] = dist->endpoint;
+ }
+ }
+
+ ast_sip_push_task(serializer, distribute, clone);
+
+ if (dlg) {
+ pjsip_dlg_dec_lock(dlg);
+ }
+
+ return PJ_TRUE;
+}
+
+static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata);
+
+static pjsip_module endpoint_mod = {
+ .name = {"Endpoint Identifier", 19},
+ .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 3,
+ .on_rx_request = endpoint_lookup,
+};
+
+static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata)
+{
+ struct ast_sip_endpoint *endpoint;
+ int is_ack = rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD;
+
+ endpoint = rdata->endpt_info.mod_data[distributor_mod.id];
+ if (endpoint) {
+ /* Bumping the refcount makes refcounting consistent whether an endpoint
+ * is looked up or not */
+ ao2_ref(endpoint, +1);
+ } else {
+ endpoint = ast_sip_identify_endpoint(rdata);
+ }
+
+ if (!endpoint && !is_ack) {
+ /* XXX When we do an alwaysauthreject-like option, we'll need to take that into account
+ * for this response. Either that, or have a pseudo-endpoint to pass along so that authentication
+ * will fail
+ */
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
+ return PJ_TRUE;
+ }
+ rdata->endpt_info.mod_data[endpoint_mod.id] = endpoint;
+ return PJ_FALSE;
+}
+
+static pj_bool_t authenticate(pjsip_rx_data *rdata)
+{
+ RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
+ int is_ack = rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD;
+
+ ast_assert(endpoint != NULL);
+
+ if (!is_ack && ast_sip_requires_authentication(endpoint, rdata)) {
+ pjsip_tx_data *tdata;
+ pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, 401, NULL, &tdata);
+ switch (ast_sip_check_authentication(endpoint, rdata, tdata)) {
+ case AST_SIP_AUTHENTICATION_CHALLENGE:
+ /* Send the 401 we created for them */
+ pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL);
+ return PJ_TRUE;
+ case AST_SIP_AUTHENTICATION_SUCCESS:
+ pjsip_tx_data_dec_ref(tdata);
+ return PJ_FALSE;
+ case AST_SIP_AUTHENTICATION_FAILED:
+ pjsip_tx_data_dec_ref(tdata);
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
+ return PJ_TRUE;
+ case AST_SIP_AUTHENTICATION_ERROR:
+ pjsip_tx_data_dec_ref(tdata);
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
+ return PJ_TRUE;
+ }
+ }
+
+ return PJ_FALSE;
+}
+
+static pjsip_module auth_mod = {
+ .name = {"Request Authenticator", 21},
+ .priority = PJSIP_MOD_PRIORITY_APPLICATION - 1,
+ .on_rx_request = authenticate,
+};
+
+static int distribute(void *data)
+{
+ static pjsip_process_rdata_param param = {
+ .start_mod = &distributor_mod,
+ .idx_after_start = 1,
+ };
+ pj_bool_t handled;
+ pjsip_rx_data *rdata = data;
+ int is_request = rdata->msg_info.msg->type == PJSIP_REQUEST_MSG;
+ int is_ack = is_request ? rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD : 0;
+ struct ast_sip_endpoint *endpoint;
+
+ pjsip_endpt_process_rx_data(ast_sip_get_pjsip_endpoint(), rdata, &param, &handled);
+ if (!handled && is_request && !is_ack) {
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 501, NULL, NULL, NULL);
+ }
+
+ /* The endpoint_mod stores an endpoint reference in the mod_data of rdata. This
+ * is the only appropriate spot to actually decrement the reference.
+ */
+ endpoint = rdata->endpt_info.mod_data[endpoint_mod.id];
+ ao2_cleanup(endpoint);
+ pjsip_rx_data_free_cloned(rdata);
+ return 0;
+}
+
+struct ast_sip_endpoint *ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
+{
+ struct ast_sip_endpoint *endpoint = rdata->endpt_info.mod_data[endpoint_mod.id];
+ if (endpoint) {
+ ao2_ref(endpoint, +1);
+ }
+ return endpoint;
+}
+
+int ast_sip_initialize_distributor(void)
+{
+ if (ast_sip_register_service(&distributor_mod)) {
+ return -1;
+ }
+ if (ast_sip_register_service(&endpoint_mod)) {
+ return -1;
+ }
+ if (ast_sip_register_service(&auth_mod)) {
+ return -1;
+ }
+ return 0;
+}
diff --git a/res/res_sip/sip_options.c b/res/res_sip/sip_options.c
new file mode 100644
index 000000000..5e3f8edca
--- /dev/null
+++ b/res/res_sip/sip_options.c
@@ -0,0 +1,378 @@
+/*
+ * sip_options.c
+ *
+ * Created on: Jan 25, 2013
+ * Author: mjordan
+ */
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_ua.h>
+#include <pjlib.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/cli.h"
+#include "include/res_sip_private.h"
+
+#define DEFAULT_LANGUAGE "en"
+#define DEFAULT_ENCODING "text/plain"
+#define QUALIFIED_BUCKETS 211
+
+/*! \brief Scheduling context for qualifies */
+static struct ast_sched_context *sched; /* XXX move this to registrar */
+
+struct ao2_container *scheduled_qualifies;
+
+struct qualify_info {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(endpoint_id);
+ );
+ char *scheduler_data;
+ int scheduler_id;
+};
+
+static pj_bool_t options_module_start(void);
+static pj_bool_t options_module_stop(void);
+static pj_bool_t options_module_on_rx_request(pjsip_rx_data *rdata);
+static pj_bool_t options_module_on_rx_response(pjsip_rx_data *rdata);
+
+static pjsip_module options_module = {
+ .name = {"Options Module", 14},
+ .id = -1,
+ .priority = PJSIP_MOD_PRIORITY_APPLICATION,
+ .start = options_module_start,
+ .stop = options_module_stop,
+ .on_rx_request = options_module_on_rx_request,
+ .on_rx_response = options_module_on_rx_response,
+};
+
+static pj_bool_t options_module_start(void)
+{
+ if (!(sched = ast_sched_context_create()) ||
+ ast_sched_start_thread(sched)) {
+ return -1;
+ }
+
+ return PJ_SUCCESS;
+}
+
+static pj_bool_t options_module_stop(void)
+{
+ ao2_t_ref(scheduled_qualifies, -1, "Remove scheduled qualifies on module stop");
+
+ if (sched) {
+ ast_sched_context_destroy(sched);
+ }
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t send_options_response(pjsip_rx_data *rdata, pjsip_dialog *pj_dlg, int code)
+{
+ pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
+ pjsip_transaction *pj_trans = pjsip_rdata_get_tsx(rdata);
+ pjsip_tx_data *tdata;
+ const pjsip_hdr *hdr;
+ pjsip_response_addr res_addr;
+ pj_status_t status;
+
+ /* Make the response object */
+ status = pjsip_endpt_create_response(endpt, rdata, code, NULL, &tdata);
+ if (status != PJ_SUCCESS) {
+ return status;
+ }
+
+ /* Add appropriate headers */
+ if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, NULL))) {
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
+ }
+ if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ALLOW, NULL))) {
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
+ }
+ if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, NULL))) {
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
+ }
+
+ /*
+ * XXX TODO: pjsip doesn't care a lot about either of these headers -
+ * while it provides specific methods to create them, they are defined
+ * to be the standard string header creation. We never did add them
+ * in chan_sip, although RFC 3261 says they SHOULD. Hard coded here.
+ */
+ ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING);
+ ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE);
+
+ if (pj_dlg && pj_trans) {
+ status = pjsip_dlg_send_response(pj_dlg, pj_trans, tdata);
+ } else {
+ /* Get where to send request. */
+ status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
+ if (status != PJ_SUCCESS) {
+ pjsip_tx_data_dec_ref(tdata);
+ return status;
+ }
+ status = pjsip_endpt_send_response(endpt, &res_addr, tdata, NULL, NULL);
+ }
+
+ return status;
+}
+
+static pj_bool_t options_module_on_rx_request(pjsip_rx_data *rdata)
+{
+ RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
+ pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
+ pjsip_uri *ruri;
+ pjsip_sip_uri *sip_ruri;
+ char exten[AST_MAX_EXTENSION];
+
+ if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_options_method)) {
+ return PJ_FALSE;
+ }
+ endpoint = ast_pjsip_rdata_get_endpoint(rdata);
+ ast_assert(endpoint != NULL);
+
+ ruri = rdata->msg_info.msg->line.req.uri;
+ if (!PJSIP_URI_SCHEME_IS_SIP(ruri) && !PJSIP_URI_SCHEME_IS_SIPS(ruri)) {
+ send_options_response(rdata, dlg, 416);
+ return -1;
+ }
+
+ sip_ruri = pjsip_uri_get_uri(ruri);
+ ast_copy_pj_str(exten, &sip_ruri->user, sizeof(exten));
+
+ if (ast_shutting_down()) {
+ send_options_response(rdata, dlg, 503);
+ } else if (!ast_exists_extension(NULL, endpoint->context, exten, 1, NULL)) {
+ send_options_response(rdata, dlg, 404);
+ } else {
+ send_options_response(rdata, dlg, 200);
+ }
+ return PJ_TRUE;
+}
+
+static pj_bool_t options_module_on_rx_response(pjsip_rx_data *rdata)
+{
+
+ return PJ_SUCCESS;
+}
+
+static int qualify_info_hash_fn(const void *obj, int flags)
+{
+ const struct qualify_info *info = obj;
+ const char *endpoint_id = flags & OBJ_KEY ? obj : info->endpoint_id;
+
+ return ast_str_hash(endpoint_id);
+}
+
+static int qualify_info_cmp_fn(void *obj, void *arg, int flags)
+{
+ struct qualify_info *left = obj;
+ struct qualify_info *right = arg;
+ const char *right_endpoint_id = flags & OBJ_KEY ? arg : right->endpoint_id;
+
+ return strcmp(left->endpoint_id, right_endpoint_id) ? 0 : CMP_MATCH | CMP_STOP;
+}
+
+
+static void qualify_info_destructor(void *obj)
+{
+ struct qualify_info *info = obj;
+ if (!info) {
+ return;
+ }
+ ast_string_field_free_memory(info);
+ /* Cancel the qualify */
+ if (!AST_SCHED_DEL(sched, info->scheduler_id)) {
+ /* If we successfully deleted the qualify, we got it before it
+ * fired. We can safely delete the data that was passed to it.
+ * Otherwise, we're getting deleted while this is firing - don't
+ * touch that memory!
+ */
+ ast_free(info->scheduler_data);
+ }
+}
+
+static struct qualify_info *create_qualify_info(struct ast_sip_endpoint *endpoint)
+{
+ struct qualify_info *info;
+
+ info = ao2_alloc(sizeof(*info), qualify_info_destructor);
+ if (!info) {
+ return NULL;
+ }
+
+ if (ast_string_field_init(info, 64)) {
+ ao2_ref(info, -1);
+ return NULL;
+ }
+ ast_string_field_set(info, endpoint_id, ast_sorcery_object_get_id(endpoint));
+
+ return info;
+}
+
+static int send_qualify_request(void *data)
+{
+ struct ast_sip_endpoint *endpoint = data;
+ pjsip_tx_data *tdata;
+ /* YAY! Send an OPTIONS request. */
+
+ ast_sip_create_request("OPTIONS", NULL, endpoint, NULL, &tdata);
+ ast_sip_send_request(tdata, NULL, endpoint);
+
+ ao2_cleanup(endpoint);
+ return 0;
+}
+
+static int qualify_endpoint_scheduler_cb(const void *data)
+{
+ RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
+ struct ast_sorcery *sorcery;
+ char *endpoint_id = (char *)data;
+
+ sorcery = ast_sip_get_sorcery();
+ if (!sorcery) {
+ ast_free(endpoint_id);
+ return 0;
+ }
+
+ endpoint = ast_sorcery_retrieve_by_id(sorcery, "endpoint", endpoint_id);
+ if (!endpoint) {
+ /* Whoops, endpoint went away */
+ ast_free(endpoint_id);
+ return 0;
+ }
+
+ ast_sip_push_task(NULL, send_qualify_request, endpoint);
+
+ return 1;
+}
+
+static void schedule_qualifies(void)
+{
+ RAII_VAR(struct ao2_container *, endpoints, NULL, ao2_cleanup);
+ struct ao2_iterator it_endpoints;
+ struct ast_sip_endpoint *endpoint;
+ struct qualify_info *info;
+ char *endpoint_id;
+
+ endpoints = ast_res_sip_get_endpoints();
+ if (!endpoints) {
+ return;
+ }
+
+ it_endpoints = ao2_iterator_init(endpoints, 0);
+ while ((endpoint = ao2_iterator_next(&it_endpoints))) {
+ if (endpoint->qualify_frequency) {
+ /* XXX TODO: This really should only qualify registered peers,
+ * which means we need a registrar. We should check the
+ * registrar to see if this endpoint has registered and, if
+ * not, pass on it.
+ *
+ * Actually, all of this should just get moved into the registrar.
+ * Otherwise, the registar will have to kick this off when a
+ * new endpoint registers, so it just makes sense to have it
+ * all live there.
+ */
+ info = create_qualify_info(endpoint);
+ if (!info) {
+ ao2_ref(endpoint, -1);
+ break;
+ }
+ endpoint_id = ast_strdup(info->endpoint_id);
+ if (!endpoint_id) {
+ ao2_t_ref(info, -1, "Dispose of info on off nominal");
+ ao2_ref(endpoint, -1);
+ break;
+ }
+ info->scheduler_data = endpoint_id;
+ info->scheduler_id = ast_sched_add_variable(sched, endpoint->qualify_frequency * 1000, qualify_endpoint_scheduler_cb, endpoint_id, 1);
+ ao2_t_link(scheduled_qualifies, info, "Link scheduled qualify information into container");
+ ao2_t_ref(info, -1, "Dispose of creation ref");
+ }
+ ao2_t_ref(endpoint, -1, "Dispose of iterator ref");
+ }
+ ao2_iterator_destroy(&it_endpoints);
+}
+
+static char *send_options(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
+ const char *endpoint_name;
+ pjsip_tx_data *tdata;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "sip send options";
+ e->usage =
+ "Usage: sip send options <endpoint>\n"
+ " Send a SIP OPTIONS request to the specified endpoint.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 4) {
+ return CLI_SHOWUSAGE;
+ }
+
+ endpoint_name = a->argv[3];
+
+ endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name);
+ if (!endpoint) {
+ ast_log(LOG_ERROR, "Unable to retrieve endpoint %s\n", endpoint_name);
+ return CLI_FAILURE;
+ }
+
+ if (ast_sip_create_request("OPTIONS", NULL, endpoint, NULL, &tdata)) {
+ ast_log(LOG_ERROR, "Unable to create OPTIONS request to endpoint %s\n", endpoint_name);
+ return CLI_FAILURE;
+ }
+
+ if (ast_sip_send_request(tdata, NULL, endpoint)) {
+ ast_log(LOG_ERROR, "Unable to send OPTIONS request to endpoint %s\n", endpoint_name);
+ return CLI_FAILURE;
+ }
+
+ return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry cli_options[] = {
+ AST_CLI_DEFINE(send_options, "Send an OPTIONS requst to an arbitrary SIP URI"),
+};
+
+int ast_res_sip_init_options_handling(int reload)
+{
+ const pj_str_t STR_OPTIONS = { "OPTIONS", 7 };
+
+ if (scheduled_qualifies) {
+ ao2_t_ref(scheduled_qualifies, -1, "Remove old scheduled qualifies");
+ }
+ scheduled_qualifies = ao2_t_container_alloc(QUALIFIED_BUCKETS, qualify_info_hash_fn, qualify_info_cmp_fn, "Create container for scheduled qualifies");
+ if (!scheduled_qualifies) {
+ return -1;
+ }
+
+ if (reload) {
+ return 0;
+ }
+
+ if (pjsip_endpt_register_module(ast_sip_get_pjsip_endpoint(), &options_module) != PJ_SUCCESS) {
+ options_module_stop();
+ return -1;
+ }
+
+ if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &STR_OPTIONS) != PJ_SUCCESS) {
+ pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module);
+ return -1;
+ }
+
+ ast_cli_register_multiple(cli_options, ARRAY_LEN(cli_options));
+
+ schedule_qualifies();
+
+ return 0;
+}
diff --git a/res/res_sip/sip_outbound_auth.c b/res/res_sip/sip_outbound_auth.c
new file mode 100644
index 000000000..94352a521
--- /dev/null
+++ b/res/res_sip/sip_outbound_auth.c
@@ -0,0 +1,94 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+#undef bzero
+#define bzero bzero
+#include "pjsip.h"
+
+#include "asterisk/res_sip.h"
+#include "asterisk/module.h"
+#include "include/res_sip_private.h"
+
+static pj_bool_t outbound_auth(pjsip_rx_data *rdata);
+
+static pjsip_module outbound_auth_mod = {
+ .name = {"Outbound Authentication", 19},
+ .priority = PJSIP_MOD_PRIORITY_DIALOG_USAGE,
+ .on_rx_response = outbound_auth,
+};
+
+struct outbound_auth_cb_data {
+ ast_sip_dialog_outbound_auth_cb cb;
+ void *user_data;
+};
+
+static pj_bool_t outbound_auth(pjsip_rx_data *rdata)
+{
+ RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
+ pjsip_transaction *tsx;
+ pjsip_dialog *dlg;
+ struct outbound_auth_cb_data *cb_data;
+ pjsip_tx_data *tdata;
+
+ if (rdata->msg_info.msg->line.status.code != 401 &&
+ rdata->msg_info.msg->line.status.code != 407) {
+ /* Doesn't pertain to us. Move on */
+ return PJ_FALSE;
+ }
+
+ tsx = pjsip_rdata_get_tsx(rdata);
+ dlg = pjsip_rdata_get_dlg(rdata);
+ ast_assert(dlg != NULL && tsx != NULL);
+ endpoint = ast_sip_dialog_get_endpoint(dlg);
+
+ if (!endpoint) {
+ return PJ_FALSE;
+ }
+
+ if (ast_sip_create_request_with_auth(endpoint->sip_outbound_auths, endpoint->num_outbound_auths, rdata, tsx, &tdata)) {
+ return PJ_FALSE;
+ }
+
+ cb_data = dlg->mod_data[outbound_auth_mod.id];
+ if (cb_data) {
+ cb_data->cb(dlg, tdata, cb_data->user_data);
+ return PJ_TRUE;
+ }
+
+ pjsip_dlg_send_request(dlg, tdata, -1, NULL);
+ return PJ_TRUE;
+}
+
+int ast_sip_dialog_setup_outbound_authentication(pjsip_dialog *dlg, const struct ast_sip_endpoint *endpoint,
+ ast_sip_dialog_outbound_auth_cb cb, void *user_data)
+{
+ struct outbound_auth_cb_data *cb_data = PJ_POOL_ZALLOC_T(dlg->pool, struct outbound_auth_cb_data);
+ cb_data->cb = cb;
+ cb_data->user_data = user_data;
+
+ dlg->sess_count++;
+ pjsip_dlg_add_usage(dlg, &outbound_auth_mod, cb_data);
+ dlg->sess_count--;
+
+ return 0;
+}
+
+int ast_sip_initialize_outbound_authentication(void) {
+ return ast_sip_register_service(&outbound_auth_mod);
+}
diff --git a/res/res_sip_acl.c b/res/res_sip_acl.c
new file mode 100644
index 000000000..405c3c1bc
--- /dev/null
+++ b/res/res_sip_acl.c
@@ -0,0 +1,222 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/module.h"
+#include "asterisk/logger.h"
+#include "asterisk/sorcery.h"
+#include "asterisk/acl.h"
+
+struct sip_acl {
+ SORCERY_OBJECT(details);
+ struct ast_acl_list *acl;
+ struct ast_acl_list *contact_acl;
+};
+
+static int apply_acl(pjsip_rx_data *rdata, struct ast_acl_list *acl)
+{
+ struct ast_sockaddr addr;
+
+ if (ast_acl_list_is_empty(acl)) {
+ return 0;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID);
+ ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port);
+
+ if (ast_apply_acl(acl, &addr, "SIP ACL: ") != AST_SENSE_ALLOW) {
+ ast_log(LOG_WARNING, "Incoming SIP message from %s did not pass ACL test\n", ast_sockaddr_stringify(&addr));
+ return 1;
+ }
+ return 0;
+}
+
+static int extract_contact_addr(pjsip_contact_hdr *contact, struct ast_sockaddr **addrs)
+{
+ pjsip_sip_uri *sip_uri;
+ char host[256];
+
+ if (!contact) {
+ return 0;
+ }
+ if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
+ return 0;
+ }
+ sip_uri = pjsip_uri_get_uri(contact->uri);
+ ast_copy_pj_str(host, &sip_uri->host, sizeof(host));
+ return ast_sockaddr_resolve(addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC);
+}
+
+static int apply_contact_acl(pjsip_rx_data *rdata, struct ast_acl_list *contact_acl)
+{
+ int num_contact_addrs;
+ int forbidden = 0;
+ struct ast_sockaddr *contact_addrs;
+ int i;
+ pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
+
+ if (ast_acl_list_is_empty(contact_acl)) {
+ return 0;
+ }
+
+ while ((contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) {
+ num_contact_addrs = extract_contact_addr(contact, &contact_addrs);
+ if (num_contact_addrs <= 0) {
+ continue;
+ }
+ for (i = 0; i < num_contact_addrs; ++i) {
+ if (ast_apply_acl(contact_acl, &contact_addrs[i], "SIP Contact ACL: ") != AST_SENSE_ALLOW) {
+ ast_log(LOG_WARNING, "Incoming SIP message from %s did not pass ACL test\n", ast_sockaddr_stringify(&contact_addrs[i]));
+ forbidden = 1;
+ break;
+ }
+ }
+ ast_free(contact_addrs);
+ if (forbidden) {
+ /* No use checking other contacts if we already have failed ACL check */
+ break;
+ }
+ }
+
+ return forbidden;
+}
+
+static int check_acls(void *obj, void *arg, int flags)
+{
+ struct sip_acl *acl = obj;
+ pjsip_rx_data *rdata = arg;
+
+ if (apply_acl(rdata, acl->acl) || apply_contact_acl(rdata, acl->contact_acl)) {
+ return CMP_MATCH | CMP_STOP;
+ }
+ return 0;
+}
+
+static pj_bool_t acl_on_rx_msg(pjsip_rx_data *rdata)
+{
+ int forbidden = 0;
+ struct ao2_container *acls = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "acl", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+ struct sip_acl *matched_acl;
+ if (!acls) {
+ ast_log(LOG_ERROR, "Unable to retrieve ACL sorcery data\n");
+ return PJ_FALSE;
+ }
+
+ matched_acl = ao2_callback(acls, 0, check_acls, rdata);
+ if (matched_acl) {
+ forbidden = 1;
+ ao2_ref(matched_acl, -1);
+ }
+ ao2_ref(acls, -1);
+
+ if (forbidden) {
+ if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
+ }
+ return PJ_TRUE;
+ }
+
+ return PJ_FALSE;
+}
+
+static pjsip_module acl_module = {
+ .name = { "ACL Module", 14 },
+ /* This should run after a logger but before anything else */
+ .priority = 1,
+ .on_rx_request = acl_on_rx_msg,
+};
+
+static int acl_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct sip_acl *acl = obj;
+ int error;
+ int ignore;
+ if (!strncmp(var->name, "contact", 7)) {
+ ast_append_acl(var->name + 7, var->value, &acl->contact_acl, &error, &ignore);
+ } else {
+ ast_append_acl(var->name, var->value, &acl->acl, &error, &ignore);
+ }
+ return error;
+}
+
+static void sip_acl_destructor(void *obj)
+{
+ struct sip_acl *acl = obj;
+ acl->acl = ast_free_acl_list(acl->acl);
+ acl->contact_acl = ast_free_acl_list(acl->contact_acl);
+}
+
+static void *sip_acl_alloc(const char *name)
+{
+ struct sip_acl *acl = ao2_alloc(sizeof(*acl), sip_acl_destructor);
+ if (!acl) {
+ return NULL;
+ }
+ return acl;
+}
+
+static int load_acls(void)
+{
+ ast_sorcery_apply_default(ast_sip_get_sorcery(), "acl", "config", "res_sip.conf,criteria=type=acl");
+ if (ast_sorcery_object_register(ast_sip_get_sorcery(), "acl", sip_acl_alloc, NULL, NULL)) {
+ ast_log(LOG_ERROR, "Failed to register SIP ACL object with sorcery\n");
+ return -1;
+ }
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "acl", "type", "", OPT_NOOP_T, 0, 0);
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "acl", "permit", "", acl_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "acl", "deny", "", acl_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "acl", "acl", "", acl_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "acl", "contactpermit", "", acl_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "acl", "contactdeny", "", acl_handler, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "acl", "contactacl", "", acl_handler, NULL, 0, 0);
+
+ /* XXX Is there a more selective way to do this? (i.e. Just reload a specific object type?) */
+ ast_sorcery_reload(ast_sip_get_sorcery());
+ return 0;
+}
+
+static int load_module(void)
+{
+ if (load_acls()) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ ast_sip_register_service(&acl_module);
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ ast_sip_unregister_service(&acl_module);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP ACL Resource",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_APP_DEPEND,
+ );
diff --git a/res/res_sip_authenticator_digest.c b/res/res_sip_authenticator_digest.c
new file mode 100644
index 000000000..499342309
--- /dev/null
+++ b/res/res_sip_authenticator_digest.c
@@ -0,0 +1,455 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/logger.h"
+#include "asterisk/module.h"
+#include "asterisk/strings.h"
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <depend>res_sip</depend>
+ <support_level>core</support_level>
+ ***/
+
+AO2_GLOBAL_OBJ_STATIC(entity_id);
+
+/*!
+ * \brief Determine if authentication is required
+ *
+ * Authentication is required if the endpoint has at least one auth
+ * section specified
+ */
+static int digest_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
+{
+ return endpoint->num_inbound_auths > 0;
+}
+
+static void auth_store_cleanup(void *data)
+{
+ struct ast_sip_auth **auth = data;
+
+ ao2_cleanup(*auth);
+ ast_free(data);
+}
+
+/*!
+ * \brief Thread-local storage for \ref ast_sip_auth
+ *
+ * The PJSIP authentication API is a bit annoying. When you set
+ * up an authentication server, you specify a lookup callback to
+ * call into when verifying incoming credentials. The problem
+ * with this callback is that it only gives you the realm and
+ * authentication username. In 2.0.5, there is a new version of
+ * the callback you can use that gives the pjsip_rx_data in
+ * addition.
+ *
+ * Unfortunately, the data we actually \b need is the
+ * \ref ast_sip_auth we are currently observing. So we have two
+ * choices:
+ * 1) Use the current PJSIP API and use thread-local storage
+ * to temporarily store our SIP authentication information. Then
+ * in the callback, we can retrieve the authentication info and
+ * use as needed. Given our threading model, this is safe.
+ * 2) Use the 2.0.5 API and temporarily store the authentication
+ * information in the rdata's endpoint_info. Then in the callback,
+ * we can retrieve the authentication info from the rdata.
+ *
+ * I've chosen option 1 since it does not require backporting
+ * any APIs from future versions of PJSIP, plus I feel the
+ * thread-local option is a bit cleaner.
+ */
+AST_THREADSTORAGE_CUSTOM(auth_store, NULL, auth_store_cleanup);
+
+/*!
+ * \brief Store authentication information in thread-local storage
+ */
+static int store_auth(struct ast_sip_auth *auth)
+{
+ struct ast_sip_auth **pointing;
+ pointing = ast_threadstorage_get(&auth_store, sizeof(pointing));
+ if (!pointing || *pointing) {
+ return -1;
+ }
+
+ ao2_ref(auth, +1);
+ *pointing = auth;
+ return 0;
+}
+
+/*!
+ * \brief Remove authentication information from thread-local storage
+ */
+static int remove_auth(void)
+{
+ struct ast_sip_auth **pointing;
+ pointing = ast_threadstorage_get(&auth_store, sizeof(pointing));
+ if (!pointing) {
+ return -1;
+ }
+
+ ao2_cleanup(*pointing);
+ *pointing = NULL;
+ return 0;
+}
+
+/*!
+ * \brief Retrieve authentication information from thread-local storage
+ */
+static struct ast_sip_auth *get_auth(void)
+{
+ struct ast_sip_auth **auth;
+ auth = ast_threadstorage_get(&auth_store, sizeof(auth));
+ if (auth && *auth) {
+ ao2_ref(*auth, +1);
+ return *auth;
+ }
+ return NULL;
+}
+
+/*!
+ * \brief Lookup callback for authentication verification
+ *
+ * This function is called when we call pjsip_auth_srv_verify(). It
+ * expects us to verify that the realm and account name from the
+ * Authorization header is correct. We are then supposed to supply
+ * a password or MD5 sum of credentials.
+ *
+ * \param pool A memory pool we can use for allocations
+ * \param realm The realm from the Authorization header
+ * \param acc_name the user from the Authorization header
+ * \param[out] info The credentials we need to fill in
+ * \retval PJ_SUCCESS Successful authentication
+ * \retval other Unsuccessful
+ */
+static pj_status_t digest_lookup(pj_pool_t *pool, const pj_str_t *realm,
+ const pj_str_t *acc_name, pjsip_cred_info *info)
+{
+ RAII_VAR(struct ast_sip_auth *, auth, get_auth(), ao2_cleanup);
+ if (!auth) {
+ return PJSIP_SC_FORBIDDEN;
+ }
+
+ if (pj_strcmp2(realm, auth->realm)) {
+ return PJSIP_SC_FORBIDDEN;
+ }
+ if (pj_strcmp2(acc_name, auth->auth_user)) {
+ return PJSIP_SC_FORBIDDEN;
+ }
+
+ pj_strdup2(pool, &info->realm, auth->realm);
+ pj_strdup2(pool, &info->username, auth->auth_user);
+
+ switch (auth->type) {
+ case AST_SIP_AUTH_TYPE_USER_PASS:
+ pj_strdup2(pool, &info->data, auth->auth_pass);
+ info->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
+ break;
+ case AST_SIP_AUTH_TYPE_MD5:
+ pj_strdup2(pool, &info->data, auth->md5_creds);
+ info->data_type = PJSIP_CRED_DATA_DIGEST;
+ break;
+ default:
+ return PJSIP_SC_FORBIDDEN;
+ }
+ return PJ_SUCCESS;
+}
+
+/*!
+ * \brief Calculate a nonce
+ *
+ * We use this in order to create authentication challenges. We also use this in order
+ * to verify that an incoming request with credentials could be in response to one
+ * of our challenges.
+ *
+ * The nonce is calculated from a timestamp, the source IP address, the source port, a
+ * unique ID for us, and the realm. This helps to ensure that the incoming request
+ * is from the same source that the nonce was calculated for. Including the realm
+ * ensures that multiple challenges to the same request have different nonces.
+ *
+ * \param A UNIX timestamp expressed as a string
+ * \param rdata The incoming request
+ * \param realm The realm for which authentication should occur
+ */
+static int build_nonce(struct ast_str **nonce, const char *timestamp, const pjsip_rx_data *rdata, const char *realm)
+{
+ struct ast_str *str = ast_str_alloca(256);
+ RAII_VAR(char *, eid, ao2_global_obj_ref(entity_id), ao2_cleanup);
+ char hash[32];
+
+ ast_str_append(&str, 0, "%s", timestamp);
+ ast_str_append(&str, 0, ":%s", rdata->pkt_info.src_name);
+ ast_str_append(&str, 0, ":%d", rdata->pkt_info.src_port);
+ ast_str_append(&str, 0, ":%s", eid);
+ ast_str_append(&str, 0, ":%s", realm);
+ ast_md5_hash(hash, ast_str_buffer(str));
+
+ ast_str_append(nonce, 0, "%s/%s", timestamp, hash);
+ return 0;
+}
+
+/*!
+ * \brief Ensure that a nonce on an incoming request is sane.
+ *
+ * The nonce in an incoming Authorization header needs to pass some scrutiny in order
+ * for us to consider accepting it. What we do is re-build a nonce based on request
+ * data and a realm and see if it matches the nonce they sent us.
+ * \param candidate The nonce on an incoming request
+ * \param rdata The incoming request
+ * \param auth The auth credentials we are trying to match against.
+ * \retval 0 Nonce does not pass validity checks
+ * \retval 1 Nonce passes validity check
+ */
+static int check_nonce(const char *candidate, const pjsip_rx_data *rdata, const struct ast_sip_auth *auth)
+{
+ char *copy = ast_strdupa(candidate);
+ char *timestamp = strsep(&copy, "/");
+ int timestamp_int;
+ time_t now = time(NULL);
+ struct ast_str *calculated = ast_str_alloca(64);
+
+ if (!copy) {
+ /* Clearly a bad nonce! */
+ return 0;
+ }
+
+ if (sscanf(timestamp, "%30d", &timestamp_int) != 1) {
+ return 0;
+ }
+
+ if ((int) now - timestamp_int > auth->nonce_lifetime) {
+ return 0;
+ }
+
+ build_nonce(&calculated, timestamp, rdata, auth->realm);
+ ast_debug(3, "Calculated nonce %s. Actual nonce is %s\n", ast_str_buffer(calculated), candidate);
+ if (strcmp(ast_str_buffer(calculated), candidate)) {
+ return 0;
+ }
+ return 1;
+}
+
+static int find_challenge(const pjsip_rx_data *rdata, const struct ast_sip_auth *auth)
+{
+ struct pjsip_authorization_hdr *auth_hdr = (pjsip_authorization_hdr *) &rdata->msg_info.msg->hdr;
+ int challenge_found = 0;
+ char nonce[64];
+
+ while ((auth_hdr = (pjsip_authorization_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, auth_hdr->next))) {
+ ast_copy_pj_str(nonce, &auth_hdr->credential.digest.nonce, sizeof(nonce));
+ if (check_nonce(nonce, rdata, auth) && !pj_strcmp2(&auth_hdr->credential.digest.realm, auth->realm)) {
+ challenge_found = 1;
+ break;
+ }
+ }
+
+ return challenge_found;
+}
+
+/*!
+ * \brief Common code for initializing a pjsip_auth_srv
+ */
+static void setup_auth_srv(pj_pool_t *pool, pjsip_auth_srv *auth_server, const struct ast_sip_auth *auth)
+{
+ pj_str_t realm;
+ pj_cstr(&realm, auth->realm);
+
+ pjsip_auth_srv_init(pool, auth_server, &realm, digest_lookup, 0);
+}
+
+/*!
+ * \brief Result of digest verification
+ */
+enum digest_verify_result {
+ /*! Authentication credentials incorrect */
+ AUTH_FAIL,
+ /*! Authentication credentials correct */
+ AUTH_SUCCESS,
+ /*! Authentication credentials correct but nonce mismatch */
+ AUTH_STALE,
+};
+
+/*!
+ * \brief astobj2 callback for verifying incoming credentials
+ *
+ * \param auth The ast_sip_auth to check against
+ * \param rdata The incoming request
+ * \param pool A pool to use for the auth server
+ * \return CMP_MATCH on successful authentication
+ * \return 0 on failed authentication
+ */
+static int verify(struct ast_sip_auth *auth, pjsip_rx_data *rdata, pj_pool_t *pool)
+{
+ pj_status_t authed;
+ int response_code;
+ pjsip_auth_srv auth_server;
+ int stale = 0;
+
+ if (!find_challenge(rdata, auth)) {
+ /* Couldn't find a challenge with a sane nonce.
+ * Nonce mismatch may just be due to staleness.
+ */
+ stale = 1;
+ }
+
+ setup_auth_srv(pool, &auth_server, auth);
+
+ store_auth(auth);
+
+ authed = pjsip_auth_srv_verify(&auth_server, rdata, &response_code);
+
+ remove_auth();
+
+ if (authed == PJ_SUCCESS) {
+ if (stale) {
+ return AUTH_STALE;
+ } else {
+ return AUTH_SUCCESS;
+ }
+ }
+ return AUTH_FAIL;
+}
+
+/*!
+ * \brief astobj2 callback for adding digest challenges to responses
+ *
+ * \param auth The ast_aip_auth to build a challenge from
+ * \param tdata The response to add the challenge to
+ * \param rdata The request the challenge is in response to
+ * \param is_stale Indicates whether nonce on incoming request was stale
+ */
+static void challenge(const struct ast_sip_auth *auth, pjsip_tx_data *tdata, const pjsip_rx_data *rdata, int is_stale)
+{
+ pj_str_t qop;
+ pj_str_t pj_nonce;
+ pjsip_auth_srv auth_server;
+ struct ast_str *nonce = ast_str_alloca(256);
+ char time_buf[32];
+ time_t timestamp = time(NULL);
+ snprintf(time_buf, sizeof(time_buf), "%d", (int) timestamp);
+
+ build_nonce(&nonce, time_buf, rdata, auth->realm);
+
+ setup_auth_srv(tdata->pool, &auth_server, auth);
+
+ pj_cstr(&pj_nonce, ast_str_buffer(nonce));
+ pj_cstr(&qop, "auth");
+ pjsip_auth_srv_challenge(&auth_server, &qop, &pj_nonce, NULL, is_stale ? PJ_TRUE : PJ_FALSE, tdata);
+}
+
+/*!
+ * \brief Check authentication using Digest scheme
+ *
+ * This function will check an incoming message against configured authentication
+ * options. If \b any of the incoming Authorization headers result in successful
+ * authentication, then authentication is considered successful.
+ *
+ * \see ast_sip_check_authentication
+ */
+static enum ast_sip_check_auth_result digest_check_auth(struct ast_sip_endpoint *endpoint,
+ pjsip_rx_data *rdata, pjsip_tx_data *tdata)
+{
+ struct ast_sip_auth **auths = ast_alloca(endpoint->num_inbound_auths * sizeof(*auths));
+ enum digest_verify_result *verify_res = ast_alloca(endpoint->num_inbound_auths * sizeof(*verify_res));
+ enum ast_sip_check_auth_result res;
+ int i;
+
+ if (!auths) {
+ return AST_SIP_AUTHENTICATION_ERROR;
+ }
+
+ if (ast_sip_retrieve_auths(endpoint->sip_inbound_auths, endpoint->num_inbound_auths, auths)) {
+ res = AST_SIP_AUTHENTICATION_ERROR;
+ goto cleanup;
+ }
+
+ for (i = 0; i < endpoint->num_inbound_auths; ++i) {
+ verify_res[i] = verify(auths[i], rdata, tdata->pool);
+ if (verify_res[i] == AUTH_SUCCESS) {
+ res = AST_SIP_AUTHENTICATION_SUCCESS;
+ goto cleanup;
+ }
+ }
+
+ for (i = 0; i < endpoint->num_inbound_auths; ++i) {
+ challenge(auths[i], tdata, rdata, verify_res[i] == AUTH_STALE);
+ }
+
+ res = AST_SIP_AUTHENTICATION_CHALLENGE;
+
+cleanup:
+ ast_sip_cleanup_auths(auths, endpoint->num_inbound_auths);
+ return res;
+}
+
+static struct ast_sip_authenticator digest_authenticator = {
+ .requires_authentication = digest_requires_authentication,
+ .check_authentication = digest_check_auth,
+};
+
+static int build_entity_id(void)
+{
+ RAII_VAR(struct ast_uuid *, uu, ast_uuid_generate(), ast_free_ptr);
+ RAII_VAR(char *, eid, ao2_alloc(AST_UUID_STR_LEN, NULL), ao2_cleanup);
+
+ if (!uu || !eid) {
+ return -1;
+ }
+
+ ast_uuid_to_str(uu, eid, AST_UUID_STR_LEN);
+ ao2_global_obj_replace_unref(entity_id, eid);
+ return 0;
+}
+
+static int reload_module(void)
+{
+ if (build_entity_id()) {
+ return -1;
+ }
+ return 0;
+}
+
+static int load_module(void)
+{
+ if (build_entity_id()) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ if (ast_sip_register_authenticator(&digest_authenticator)) {
+ ao2_global_obj_release(entity_id);
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ ast_sip_unregister_authenticator(&digest_authenticator);
+ ao2_global_obj_release(entity_id);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP authentication resource",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload_module,
+ .load_pri = AST_MODPRI_CHANNEL_DEPEND,
+);
diff --git a/res/res_sip_caller_id.c b/res/res_sip_caller_id.c
new file mode 100644
index 000000000..22ece0436
--- /dev/null
+++ b/res/res_sip_caller_id.c
@@ -0,0 +1,715 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <depend>res_sip</depend>
+ <depend>res_sip_session</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_ua.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/res_sip_session.h"
+#include "asterisk/channel.h"
+#include "asterisk/module.h"
+#include "asterisk/callerid.h"
+
+/*!
+ * \internal
+ * \brief Set an ast_party_id name and number based on an identity header.
+ * \param hdr From, P-Asserted-Identity, or Remote-Party-ID header on incoming message
+ * \param[out] id The ID to set data on
+ */
+static void set_id_from_hdr(pjsip_fromto_hdr *hdr, struct ast_party_id *id)
+{
+ char cid_name[AST_CHANNEL_NAME];
+ char cid_num[AST_CHANNEL_NAME];
+ pjsip_sip_uri *uri;
+ pjsip_name_addr *id_name_addr = (pjsip_name_addr *) hdr->uri;
+
+ uri = pjsip_uri_get_uri(id_name_addr);
+ ast_copy_pj_str(cid_name, &id_name_addr->display, sizeof(cid_name));
+ ast_copy_pj_str(cid_num, &uri->user, sizeof(cid_num));
+
+ ast_free(id->name.str);
+ id->name.str = ast_strdup(cid_name);
+ if (!ast_strlen_zero(cid_name)) {
+ id->name.valid = 1;
+ }
+ ast_free(id->number.str);
+ id->number.str = ast_strdup(cid_num);
+ if (!ast_strlen_zero(cid_num)) {
+ id->number.valid = 1;
+ }
+}
+
+/*!
+ * \internal
+ * \brief Get a P-Asserted-Identity or Remote-Party-ID header from an incoming message
+ *
+ * This function will parse the header as if it were a From header. This allows for us
+ * to easily manipulate the URI, as well as add, modify, or remove parameters from the
+ * header
+ *
+ * \param rdata The incoming message
+ * \param header_name The name of the ID header to find
+ * \retval NULL No ID header present or unable to parse ID header
+ * \retval non-NULL The parsed ID header
+ */
+static pjsip_fromto_hdr *get_id_header(pjsip_rx_data *rdata, const pj_str_t *header_name)
+{
+ static const pj_str_t from = { "From", 4 };
+ pj_str_t header_content;
+ pjsip_fromto_hdr *parsed_hdr;
+ pjsip_generic_string_hdr *ident = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
+ header_name, NULL);
+ int parsed_len;
+
+ if (!ident) {
+ return NULL;
+ }
+
+ pj_strdup_with_null(rdata->tp_info.pool, &header_content, &ident->hvalue);
+
+ parsed_hdr = pjsip_parse_hdr(rdata->tp_info.pool, &from, header_content.ptr,
+ pj_strlen(&header_content), &parsed_len);
+
+ if (!parsed_hdr) {
+ return NULL;
+ }
+
+ return parsed_hdr;
+}
+
+/*!
+ * \internal
+ * \brief Set an ast_party_id structure based on data in a P-Asserted-Identity header
+ *
+ * This makes use of \ref set_id_from_hdr for setting name and number. It uses
+ * the contents of a Privacy header in order to set presentation information.
+ *
+ * \param rdata The incoming message
+ * \param[out] id The ID to set
+ * \retval 0 Successfully set the party ID
+ * \retval non-zero Could not set the party ID
+ */
+static int set_id_from_pai(pjsip_rx_data *rdata, struct ast_party_id *id)
+{
+ static const pj_str_t pai_str = { "P-Asserted-Identity", 19 };
+ static const pj_str_t privacy_str = { "Privacy", 7 };
+ pjsip_fromto_hdr *pai_hdr = get_id_header(rdata, &pai_str);
+ pjsip_generic_string_hdr *privacy;
+
+ if (!pai_hdr) {
+ return -1;
+ }
+
+ set_id_from_hdr(pai_hdr, id);
+
+ if (!id->number.valid) {
+ return -1;
+ }
+
+ privacy = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &privacy_str, NULL);
+ if (!privacy) {
+ return 0;
+ }
+ if (!pj_stricmp2(&privacy->hvalue, "id")) {
+ id->number.presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+ id->name.presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+ }
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Set an ast_party_id structure based on data in a Remote-Party-ID header
+ *
+ * This makes use of \ref set_id_from_hdr for setting name and number. It uses
+ * the privacy and screen parameters in order to set presentation information.
+ *
+ * \param rdata The incoming message
+ * \param[out] id The ID to set
+ * \retval 0 Succesfully set the party ID
+ * \retval non-zero Could not set the party ID
+ */
+static int set_id_from_rpid(pjsip_rx_data *rdata, struct ast_party_id *id)
+{
+ static const pj_str_t rpid_str = { "Remote-Party-ID", 15 };
+ static const pj_str_t privacy_str = { "privacy", 7 };
+ static const pj_str_t screen_str = { "screen", 6 };
+ pjsip_fromto_hdr *rpid_hdr = get_id_header(rdata, &rpid_str);
+ pjsip_param *screen;
+ pjsip_param *privacy;
+
+ if (!rpid_hdr) {
+ return -1;
+ }
+
+ set_id_from_hdr(rpid_hdr, id);
+
+ if (!id->number.valid) {
+ return -1;
+ }
+
+ privacy = pjsip_param_find(&rpid_hdr->other_param, &privacy_str);
+ screen = pjsip_param_find(&rpid_hdr->other_param, &screen_str);
+ if (privacy && !pj_stricmp2(&privacy->value, "full")) {
+ id->number.presentation |= AST_PRES_RESTRICTED;
+ id->name.presentation |= AST_PRES_RESTRICTED;
+ }
+ if (screen && !pj_stricmp2(&screen->value, "yes")) {
+ id->number.presentation |= AST_PRES_USER_NUMBER_PASSED_SCREEN;
+ id->name.presentation |= AST_PRES_USER_NUMBER_PASSED_SCREEN;
+ }
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Set an ast_party_id structure based on data in a From
+ *
+ * This makes use of \ref set_id_from_hdr for setting name and number. It uses
+ * no information from the message in order to set privacy. It relies on endpoint
+ * configuration for privacy information.
+ *
+ * \param rdata The incoming message
+ * \param[out] id The ID to set
+ * \retval 0 Succesfully set the party ID
+ * \retval non-zero Could not set the party ID
+ */
+static int set_id_from_from(struct pjsip_rx_data *rdata, struct ast_party_id *id)
+{
+ pjsip_fromto_hdr *from = pjsip_msg_find_hdr(rdata->msg_info.msg,
+ PJSIP_H_FROM, rdata->msg_info.msg->hdr.next);
+
+ if (!from) {
+ /* This had better not happen */
+ return -1;
+ }
+
+ set_id_from_hdr(from, id);
+
+ if (!id->number.valid) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Determine if a connected line update should be queued
+ *
+ * This uses information about the session and the ID that would be queued
+ * in the connected line update in order to determine if we should queue
+ * a connected line update.
+ *
+ * \param session The session whose channel we wish to queue the connected line update on
+ * \param id The identification information that would be queued on the connected line update
+ * \retval 0 We should not queue a connected line update
+ * \retval non-zero We should queue a connected line update
+ */
+static int should_queue_connected_line_update(const struct ast_sip_session *session, const struct ast_party_id *id)
+{
+ /* Invalid number means no update */
+ if (!id->number.valid) {
+ return 0;
+ }
+
+ /* If the session has never communicated an update or if the
+ * new ID has a different number than the session, then we
+ * should queue an update
+ */
+ if (ast_strlen_zero(session->id.number.str) ||
+ strcmp(session->id.number.str, id->number.str)) {
+ return 1;
+ }
+
+ /* By making it to this point, it means the number is not enough
+ * to determine if an update should be sent. Now we look at
+ * the name
+ */
+
+ /* If the number couldn't warrant an update and the name is
+ * invalid, then no update
+ */
+ if (!id->name.valid) {
+ return 0;
+ }
+
+ /* If the name has changed or we don't have a name set for the
+ * session, then we should send an update
+ */
+ if (ast_strlen_zero(session->id.name.str) ||
+ strcmp(session->id.name.str, id->name.str)) {
+ return 1;
+ }
+
+ /* Neither the name nor the number have changed. No update */
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Queue a connected line update on a session's channel.
+ * \param session The session whose channel should have the connected line update queued upon.
+ * \param id The identification information to place in the connected line update
+ */
+static void queue_connected_line_update(struct ast_sip_session *session, const struct ast_party_id *id)
+{
+ struct ast_party_connected_line connected;
+ struct ast_set_party_connected_line update_connected;
+
+ ast_party_connected_line_init(&connected);
+ ast_party_id_copy(&connected.id, id);
+
+ memset(&update_connected, 0, sizeof(update_connected));
+ update_connected.id.number = 1;
+ update_connected.id.name = 1;
+
+ ast_set_party_id_all(&update_connected.priv);
+ connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+ ast_party_id_copy(&session->id, &connected.id);
+ ast_channel_queue_connected_line_update(session->channel, &connected, &update_connected);
+
+ ast_party_connected_line_free(&connected);
+}
+
+/*!
+ * \internal
+ * \brief Make updates to connected line information based on an incoming request.
+ *
+ * This will get identity information from an incoming request. Once the identification is
+ * retrieved, we will check if the new information warrants a connected line update and queue
+ * a connected line update if so.
+ *
+ * \param session The session on which we received an incoming request
+ * \param rdata The incoming request
+ */
+static void update_incoming_connected_line(struct ast_sip_session *session, pjsip_rx_data *rdata)
+{
+ struct ast_party_id id;
+
+ if (!session->endpoint->trust_id_inbound) {
+ return;
+ }
+
+ ast_party_id_init(&id);
+ if (set_id_from_pai(rdata, &id) && set_id_from_rpid(rdata, &id)) {
+ return;
+ }
+ if (should_queue_connected_line_update(session, &id)) {
+ queue_connected_line_update(session, &id);
+ }
+
+ ast_party_id_free(&id);
+}
+
+/*!
+ * \internal
+ * \brief Session supplement callback on an incoming INVITE request
+ *
+ * If we are receiving an initial INVITE, then we will set the session's identity
+ * based on the INVITE or configured endpoint values. If we are receiving a reinvite,
+ * then we will potentially queue a connected line update via the \ref update_incoming_connected_line
+ * function
+ *
+ * \param session The session that has received an INVITE
+ * \param rdata The incoming INVITE
+ */
+static int caller_id_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
+{
+ if (session->inv_session->state < PJSIP_INV_STATE_CONFIRMED) {
+ /* Initial inbound INVITE. Set the session ID directly */
+ if (session->endpoint->trust_id_inbound &&
+ (!set_id_from_pai(rdata, &session->id) || !set_id_from_rpid(rdata, &session->id))) {
+ return 0;
+ }
+ ast_party_id_copy(&session->id, &session->endpoint->id);
+ if (!session->endpoint->id.number.valid) {
+ set_id_from_from(rdata, &session->id);
+ }
+ } else {
+ /* Reinvite. Check for changes to the ID and queue a connected line
+ * update if necessary
+ */
+ update_incoming_connected_line(session, rdata);
+ }
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Session supplement callback on INVITE response
+ *
+ * INVITE responses could result in queuing connected line updates.
+ *
+ * \param session The session on which communication is happening
+ * \param rdata The incoming INVITE response
+ */
+static void caller_id_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata)
+{
+ if (!session->channel) {
+ return;
+ }
+
+ update_incoming_connected_line(session, rdata);
+}
+
+/*!
+ * \internal
+ * \brief Set name and number information on an identity header.
+ * \param pool Memory pool to use for string duplication
+ * \param id_hdr A From, P-Asserted-Identity, or Remote-Party-ID header to modify
+ * \param id The identity information to apply to the header
+ */
+static void modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr, const struct ast_party_id *id)
+{
+ pjsip_name_addr *id_name_addr;
+ pjsip_sip_uri *id_uri;
+
+ id_name_addr = (pjsip_name_addr *) id_hdr->uri;
+ id_uri = pjsip_uri_get_uri(id_name_addr->uri);
+
+ if (id->name.valid) {
+ pj_strdup2(pool, &id_name_addr->display, id->name.str);
+ }
+
+ pj_strdup2(pool, &id_uri->user, id->number.str);
+}
+
+/*!
+ * \internal
+ * \brief Create an identity header for an outgoing message
+ * \param hdr_name The name of the header to create
+ * \param tdata The message to place the header on
+ * \param id The identification information for the new header
+ * \return newly-created header
+ */
+static pjsip_fromto_hdr *create_new_id_hdr(const pj_str_t *hdr_name, pjsip_tx_data *tdata, const struct ast_party_id *id)
+{
+ pjsip_fromto_hdr *id_hdr;
+ pjsip_fromto_hdr *base;
+ pjsip_name_addr *id_name_addr;
+ pjsip_sip_uri *id_uri;
+
+ base = tdata->msg->type == PJSIP_REQUEST_MSG ? PJSIP_MSG_FROM_HDR(tdata->msg) :
+ PJSIP_MSG_TO_HDR(tdata->msg);
+ id_hdr = pjsip_from_hdr_create(tdata->pool);
+ id_hdr->type = PJSIP_H_OTHER;
+ pj_strdup(tdata->pool, &id_hdr->name, hdr_name);
+ id_hdr->sname.slen = 0;
+
+ id_name_addr = pjsip_uri_clone(tdata->pool, base->uri);
+ id_uri = pjsip_uri_get_uri(id_name_addr->uri);
+
+ if (id->name.valid) {
+ pj_strdup2(tdata->pool, &id_name_addr->display, id->name.str);
+ }
+
+ pj_strdup2(tdata->pool, &id_uri->user, id->number.str);
+
+ id_hdr->uri = (pjsip_uri *) id_name_addr;
+ return id_hdr;
+}
+
+/*!
+ * \internal
+ * \brief Add a Privacy header to an outbound message
+ *
+ * When sending a P-Asserted-Identity header, if privacy is requested, then we
+ * will need to indicate such by adding a Privacy header. Similarly, if no
+ * privacy is requested, and a Privacy header already exists on the message,
+ * then the old Privacy header should be removed.
+ *
+ * \param tdata The outbound message to add the Privacy header to
+ * \param id The id information used to determine privacy
+ */
+static void add_privacy_header(pjsip_tx_data *tdata, const struct ast_party_id *id)
+{
+ static const pj_str_t pj_privacy_name = { "Privacy", 7 };
+ static const pj_str_t pj_privacy_value = { "id", 2 };
+ pjsip_hdr *old_privacy;
+
+ old_privacy = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_privacy_name, NULL);
+
+ if ((id->name.presentation & AST_PRES_RESTRICTION) == AST_PRES_RESTRICTED ||
+ (id->name.presentation & AST_PRES_RESTRICTION) == AST_PRES_RESTRICTED) {
+ if (!old_privacy) {
+ pjsip_generic_string_hdr *privacy_hdr = pjsip_generic_string_hdr_create(
+ tdata->pool, &pj_privacy_name, &pj_privacy_value);
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)privacy_hdr);
+ }
+ } else {
+ if (old_privacy) {
+ pj_list_erase(old_privacy);
+ }
+ }
+}
+
+/*!
+ * \internal
+ * \brief Add a P-Asserted-Identity header to an outbound message
+ * \param tdata The message to add the header to
+ * \param id The identification information used to populate the header
+ */
+static void add_pai_header(pjsip_tx_data *tdata, const struct ast_party_id *id)
+{
+ static const pj_str_t pj_pai_name = { "P-Asserted-Identity", 19 };
+ pjsip_fromto_hdr *pai_hdr;
+ pjsip_fromto_hdr *old_pai;
+
+ if (!id->number.valid) {
+ return;
+ }
+
+ /* Since inv_session reuses responses, we have to make sure there's not already
+ * a P-Asserted-Identity present. If there is, we just modify the old one.
+ */
+ old_pai = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_pai_name, NULL);
+ if (old_pai) {
+ modify_id_header(tdata->pool, old_pai, id);
+ add_privacy_header(tdata, id);
+ return;
+ }
+
+ pai_hdr = create_new_id_hdr(&pj_pai_name, tdata, id);
+ if (!pai_hdr) {
+ return;
+ }
+ add_privacy_header(tdata, id);
+
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)pai_hdr);
+}
+
+/*!
+ * \internal
+ * \brief Add privacy and screen parameters to a Remote-Party-ID header.
+ *
+ * If privacy is requested, then the privacy and screen parameters need to
+ * reflect this. Similarly, if no privacy or screening is to be communicated,
+ * we need to make sure that any previously set values are updated.
+ *
+ * \param tdata The message where the Remote-Party-ID header is
+ * \param hdr The header on which the parameters are being added
+ * \param id The identification information used to determine privacy
+ */
+static void add_privacy_params(pjsip_tx_data *tdata, pjsip_fromto_hdr *hdr, const struct ast_party_id *id)
+{
+ static const pj_str_t privacy_str = { "privacy", 7 };
+ static const pj_str_t screen_str = { "screen", 6 };
+ static const pj_str_t privacy_full_str = { "full", 4 };
+ static const pj_str_t privacy_off_str = { "off", 3 };
+ static const pj_str_t screen_yes_str = { "yes", 3 };
+ static const pj_str_t screen_no_str = { "no", 2 };
+ pjsip_param *old_privacy;
+ pjsip_param *old_screen;
+ pjsip_param *privacy;
+ pjsip_param *screen;
+
+ old_privacy = pjsip_param_find(&hdr->other_param, &privacy_str);
+ old_screen = pjsip_param_find(&hdr->other_param, &screen_str);
+
+ if (!old_privacy) {
+ privacy = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
+ privacy->name = privacy_str;
+ pj_list_insert_before(&hdr->other_param, privacy);
+ } else {
+ privacy = old_privacy;
+ }
+
+ if (!old_screen) {
+ screen = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
+ screen->name = screen_str;
+ pj_list_insert_before(&hdr->other_param, screen);
+ } else {
+ screen = old_screen;
+ }
+
+ if ((id->name.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED &&
+ (id->name.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
+ privacy->value = privacy_off_str;
+ } else {
+ privacy->value = privacy_full_str;
+ }
+
+ if ((id->name.presentation & AST_PRES_NUMBER_TYPE) == AST_PRES_USER_NUMBER_PASSED_SCREEN &&
+ (id->number.presentation & AST_PRES_NUMBER_TYPE) == AST_PRES_USER_NUMBER_PASSED_SCREEN) {
+ screen->value = screen_yes_str;
+ } else {
+ screen->value = screen_no_str;
+ }
+}
+
+/*!
+ * \internal
+ * \brief Add a Remote-Party-ID header to an outbound message
+ * \param tdata The message to add the header to
+ * \param id The identification information used to populate the header
+ */
+static void add_rpid_header(pjsip_tx_data *tdata, const struct ast_party_id *id)
+{
+ static const pj_str_t pj_rpid_name = { "Remote-Party-ID", 15 };
+ pjsip_fromto_hdr *rpid_hdr;
+ pjsip_fromto_hdr *old_rpid;
+
+ if (!id->number.valid) {
+ return;
+ }
+
+ /* Since inv_session reuses responses, we have to make sure there's not already
+ * a P-Asserted-Identity present. If there is, we just modify the old one.
+ */
+ old_rpid = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_rpid_name, NULL);
+ if (old_rpid) {
+ modify_id_header(tdata->pool, old_rpid, id);
+ add_privacy_params(tdata, old_rpid, id);
+ return;
+ }
+
+ rpid_hdr = create_new_id_hdr(&pj_rpid_name, tdata, id);
+ if (!rpid_hdr) {
+ return;
+ }
+ add_privacy_params(tdata, rpid_hdr, id);
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)rpid_hdr);
+}
+
+/*!
+ * \internal
+ * \brief Add any appropriate identification headers to an outbound SIP message
+ *
+ * This will determine if an outbound message should have identification headers and
+ * will add the appropriately configured headers
+ *
+ * \param session The session on which we will be sending the message
+ * \param tdata The outbound message
+ * \param The identity information to place on the message
+ */
+static void add_id_headers(const struct ast_sip_session *session, pjsip_tx_data *tdata, const struct ast_party_id *id)
+{
+ if (((id->name.presentation & AST_PRES_RESTRICTION) == AST_PRES_RESTRICTED ||
+ (id->number.presentation & AST_PRES_RESTRICTION) == AST_PRES_RESTRICTED) &&
+ !session->endpoint->trust_id_outbound) {
+ return;
+ }
+ if (session->endpoint->send_pai) {
+ add_pai_header(tdata, id);
+ }
+ if (session->endpoint->send_rpid) {
+ add_rpid_header(tdata, id);
+ }
+}
+
+/*!
+ * \internal
+ * \brief Session supplement callback for outgoing INVITE requests
+ *
+ * For an initial INVITE request, we may change the From header to appropriately
+ * reflect the identity information. On all INVITEs (initial and reinvite) we may
+ * add other identity headers such as P-Asserted-Identity and Remote-Party-ID based
+ * on configuration and privacy settings
+ *
+ * \param session The session on which the INVITE will be sent
+ * \param tdata The outbound INVITE request
+ */
+static void caller_id_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
+{
+ struct ast_party_id connected_id;
+
+ if (!session->channel) {
+ return;
+ }
+
+ connected_id = ast_channel_connected_effective_id(session->channel);
+ if (session->inv_session->state < PJSIP_INV_STATE_CONFIRMED &&
+ session->endpoint->trust_id_outbound &&
+ (connected_id.name.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED &&
+ (connected_id.name.presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) {
+ /* Only change the From header on the initial outbound INVITE. Switching it
+ * mid-call might confuse some UAs.
+ */
+ pjsip_fromto_hdr *from;
+ pjsip_dialog *dlg;
+
+ from = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, tdata->msg->hdr.next);
+ dlg = session->inv_session->dlg;
+
+ modify_id_header(tdata->pool, from, &connected_id);
+ modify_id_header(dlg->pool, dlg->local.info, &connected_id);
+ if (should_queue_connected_line_update(session, &session->endpoint->id)) {
+ queue_connected_line_update(session, &session->endpoint->id);
+ }
+ }
+ add_id_headers(session, tdata, &connected_id);
+}
+
+/*!
+ * \internal
+ * \brief Session supplement for outgoing INVITE response
+ *
+ * This will add P-Asserted-Identity and Remote-Party-ID headers if necessary
+ *
+ * \param session The session on which the INVITE response is to be sent
+ * \param tdata The outbound INVITE response
+ */
+static void caller_id_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
+{
+ struct ast_party_id connected_id;
+
+ if (!session->channel) {
+ return;
+ }
+ connected_id = ast_channel_connected_effective_id(session->channel);
+ add_id_headers(session, tdata, &connected_id);
+}
+
+static struct ast_sip_session_supplement caller_id_supplement = {
+ .method = "INVITE",
+ .priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL - 1000,
+ .incoming_request = caller_id_incoming_request,
+ .incoming_response = caller_id_incoming_response,
+ .outgoing_request = caller_id_outgoing_request,
+ .outgoing_response = caller_id_outgoing_response,
+};
+
+static int load_module(void)
+{
+ ast_sip_session_register_supplement(&caller_id_supplement);
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ ast_sip_session_unregister_supplement(&caller_id_supplement);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP Caller ID Support",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_APP_DEPEND,
+ );
diff --git a/res/res_sip_dtmf_info.c b/res/res_sip_dtmf_info.c
new file mode 100644
index 000000000..453e57d06
--- /dev/null
+++ b/res/res_sip_dtmf_info.c
@@ -0,0 +1,128 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Jason Parker <jparker@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_ua.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/res_sip_session.h"
+#include "asterisk/module.h"
+
+static int dtmf_info_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
+{
+ int res = 0;
+ pjsip_msg_body *body = rdata->msg_info.msg->body;
+
+ pjsip_tx_data *tdata;
+
+ char buf[body->len];
+ char *cur = buf;
+ char *line;
+
+ char event = '\0';
+ unsigned int duration = 0;
+
+ if (pj_strcmp2(&body->content_type.type, "application") ||
+ pj_strcmp2(&body->content_type.subtype, "dtmf-relay")) {
+ return 0;
+ }
+
+ body->print_body(body, buf, body->len);
+
+ while ((line = strsep(&cur, "\r\n"))) {
+ char *c;
+
+ if (!(c = strchr(line, '='))) {
+ continue;
+ }
+ *c++ = '\0';
+
+ c = ast_skip_blanks(c);
+
+ if (!strcasecmp(line, "signal")) {
+ if (c[0] == '!' || c[0] == '*' || c[0] == '#' ||
+ ('0' <= c[0] && c[0] <= '9') ||
+ ('A' <= c[0] && c[0] <= 'D') ||
+ ('a' <= c[0] && c[0] <= 'd')) {
+ event = c[0];
+ } else {
+ ast_log(LOG_ERROR, "Invalid DTMF event signal in INFO message.\n");
+ res = -1;
+ break;
+ }
+ } else if (!strcasecmp(line, "duration")) {
+ sscanf(c, "%30u", &duration);
+ }
+ }
+
+ if (!duration) {
+ duration = 100;
+ }
+
+ if (event == '!') {
+ struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_FLASH, } };
+
+ ast_queue_frame(session->channel, &f);
+ } else if (event != '\0') {
+ struct ast_frame f = { AST_FRAME_DTMF, };
+ f.len = duration;
+ f.subclass.integer = event;
+
+ ast_queue_frame(session->channel, &f);
+ } else {
+ res = -1;
+ }
+
+ if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, !res ? 200 : 500, NULL, &tdata) == PJ_SUCCESS) {
+ struct pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
+
+ pjsip_dlg_send_response(session->inv_session->dlg, tsx, tdata);
+ }
+
+ return res;
+}
+
+static struct ast_sip_session_supplement dtmf_info_supplement = {
+ .method = "INFO",
+ .incoming_request = dtmf_info_incoming_request,
+};
+
+static int load_module(void)
+{
+ ast_sip_session_register_supplement(&dtmf_info_supplement);
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ ast_sip_session_unregister_supplement(&dtmf_info_supplement);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP DTMF INFO Support",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_APP_DEPEND,
+ );
diff --git a/res/res_sip_endpoint_identifier_constant.c b/res/res_sip_endpoint_identifier_constant.c
new file mode 100644
index 000000000..e519a9ee8
--- /dev/null
+++ b/res/res_sip_endpoint_identifier_constant.c
@@ -0,0 +1,67 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * Includes code and algorithms from the Zapata library.
+ *
+ * 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.
+ */
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <defaultenabled>no</defaultenabled>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/module.h"
+
+static struct ast_sip_endpoint *constant_identify(pjsip_rx_data *rdata)
+{
+ /* This endpoint identifier always returns the same endpoint. It's used
+ * simply for testing. It allocates an endpoint from sorcery so default values
+ * do get applied.
+ */
+ struct ast_sip_endpoint *endpoint = ast_sorcery_alloc(ast_sip_get_sorcery(), "endpoint", NULL);
+ if (!endpoint) {
+ return NULL;
+ }
+ ast_parse_allow_disallow(&endpoint->prefs, endpoint->codecs, "ulaw", 1);
+ return endpoint;
+}
+
+static struct ast_sip_endpoint_identifier constant_identifier = {
+ .identify_endpoint = constant_identify,
+};
+
+static int load_module(void)
+{
+ ast_sip_register_endpoint_identifier(&constant_identifier);
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP Constant Endpoint Identifier",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_APP_DEPEND,
+ );
diff --git a/res/res_sip_endpoint_identifier_ip.c b/res/res_sip_endpoint_identifier_ip.c
new file mode 100644
index 000000000..49c70b59d
--- /dev/null
+++ b/res/res_sip_endpoint_identifier_ip.c
@@ -0,0 +1,151 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/module.h"
+#include "asterisk/acl.h"
+
+/*! \brief Structure for an IP identification matching object */
+struct ip_identify_match {
+ /*! \brief Sorcery object details */
+ SORCERY_OBJECT(details);
+ /*! \brief Stringfields */
+ AST_DECLARE_STRING_FIELDS(
+ /*! The name of the endpoint */
+ AST_STRING_FIELD(endpoint_name);
+ );
+ /*! \brief Networks or addresses that should match this */
+ struct ast_ha *matches;
+};
+
+/*! \brief Destructor function for a matching object */
+static void ip_identify_destroy(void *obj)
+{
+ struct ip_identify_match *identify = obj;
+
+ ast_string_field_free_memory(identify);
+ ast_free_ha(identify->matches);
+}
+
+/*! \brief Allocator function for a matching object */
+static void *ip_identify_alloc(const char *name)
+{
+ struct ip_identify_match *identify = ao2_alloc(sizeof(*identify), ip_identify_destroy);
+
+ if (!identify || ast_string_field_init(identify, 256)) {
+ ao2_cleanup(identify);
+ return NULL;
+ }
+
+ return identify;
+}
+
+/*! \brief Comparator function for a matching object */
+static int ip_identify_match_check(void *obj, void *arg, int flags)
+{
+ struct ip_identify_match *identify = obj;
+ struct ast_sockaddr *addr = arg;
+
+ return (ast_apply_ha(identify->matches, addr) != AST_SENSE_ALLOW) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+static struct ast_sip_endpoint *ip_identify(pjsip_rx_data *rdata)
+{
+ struct ast_sockaddr addr = { { 0, } };
+ RAII_VAR(struct ao2_container *, candidates, NULL, ao2_cleanup);
+ RAII_VAR(struct ip_identify_match *, match, NULL, ao2_cleanup);
+
+ /* If no possibilities exist return early to save some time */
+ if (!(candidates = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) ||
+ !ao2_container_count(candidates)) {
+ return NULL;
+ }
+
+ ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID);
+ ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port);
+
+ if (!(match = ao2_callback(candidates, 0, ip_identify_match_check, &addr))) {
+ return NULL;
+ }
+
+ return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", match->endpoint_name);
+}
+
+static struct ast_sip_endpoint_identifier ip_identifier = {
+ .identify_endpoint = ip_identify,
+};
+
+/*! \brief Custom handler for match field */
+static int ip_identify_match_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ip_identify_match *identify = obj;
+ int error = 0;
+
+ /* We deny what we actually want to match because there is an implicit permit all rule for ACLs */
+ if (!(identify->matches = ast_append_ha("d", var->value, identify->matches, &error))) {
+ return -1;
+ }
+
+ return error;
+}
+
+static int load_module(void)
+{
+ ast_sorcery_apply_default(ast_sip_get_sorcery(), "identify", "config", "res_sip.conf,criteria=type=identify");
+
+ if (ast_sorcery_object_register(ast_sip_get_sorcery(), "identify", ip_identify_alloc, NULL, NULL)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "type", "", OPT_NOOP_T, 0, 0);
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, endpoint_name));
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "identify", "match", "", ip_identify_match_handler, NULL, 0, 0);
+ ast_sorcery_reload_object(ast_sip_get_sorcery(), "identify");
+
+ ast_sip_register_endpoint_identifier(&ip_identifier);
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int reload_module(void)
+{
+ ast_sorcery_reload_object(ast_sip_get_sorcery(), "identify");
+ return 0;
+}
+
+static int unload_module(void)
+{
+ ast_sip_unregister_endpoint_identifier(&ip_identifier);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP IP endpoint identifier",
+ .load = load_module,
+ .reload = reload_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_APP_DEPEND,
+ );
diff --git a/res/res_sip_endpoint_identifier_user.c b/res/res_sip_endpoint_identifier_user.c
new file mode 100644
index 000000000..cd1f76bb1
--- /dev/null
+++ b/res/res_sip_endpoint_identifier_user.c
@@ -0,0 +1,128 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/module.h"
+
+static int get_endpoint_details(pjsip_rx_data *rdata, char *endpoint, size_t endpoint_size, char *domain, size_t domain_size)
+{
+ pjsip_uri *from = rdata->msg_info.from->uri;
+ pjsip_sip_uri *sip_from;
+ if (!PJSIP_URI_SCHEME_IS_SIP(from) && !PJSIP_URI_SCHEME_IS_SIPS(from)) {
+ return -1;
+ }
+ sip_from = (pjsip_sip_uri *) pjsip_uri_get_uri(from);
+ ast_copy_pj_str(endpoint, &sip_from->user, endpoint_size);
+ ast_copy_pj_str(domain, &sip_from->host, domain_size);
+ return 0;
+}
+
+static int find_transport_in_use(void *obj, void *arg, int flags)
+{
+ struct ast_sip_transport *transport = obj;
+ pjsip_rx_data *rdata = arg;
+
+ if ((transport->state->transport == rdata->tp_info.transport) ||
+ (transport->state->factory && !pj_strcmp(&transport->state->factory->addr_name.host, &rdata->tp_info.transport->local_name.host) &&
+ transport->state->factory->addr_name.port == rdata->tp_info.transport->local_name.port)) {
+ return CMP_MATCH | CMP_STOP;
+ }
+
+ return 0;
+}
+
+static struct ast_sip_endpoint *username_identify(pjsip_rx_data *rdata)
+{
+ char endpoint_name[64], domain_name[64], id[AST_UUID_STR_LEN];
+ struct ast_sip_endpoint *endpoint;
+ RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup);
+ RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
+
+ if (get_endpoint_details(rdata, endpoint_name, sizeof(endpoint_name), domain_name, sizeof(domain_name))) {
+ return NULL;
+ }
+
+ /* Attempt to find the endpoint given the name and domain provided */
+ snprintf(id, sizeof(id), "%s@%s", endpoint_name, domain_name);
+ if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
+ goto done;
+ }
+
+ /* See if an alias exists for the domain provided */
+ if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
+ snprintf(id, sizeof(id), "%s@%s", endpoint_name, alias->domain);
+ if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
+ goto done;
+ }
+ }
+
+ /* See if the transport this came in on has a provided domain */
+ if ((transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) &&
+ (transport = ao2_callback(transports, 0, find_transport_in_use, rdata)) &&
+ !ast_strlen_zero(transport->domain)) {
+ snprintf(id, sizeof(id), "%s@%s", endpoint_name, transport->domain);
+ if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) {
+ goto done;
+ }
+ }
+
+ /* Fall back to no domain */
+ endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name);
+
+done:
+ if (endpoint) {
+ if (!(endpoint->ident_method & AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME)) {
+ ao2_ref(endpoint, -1);
+ return NULL;
+ }
+ ast_debug(3, "Retrieved endpoint %s\n", ast_sorcery_object_get_id(endpoint));
+ }
+ return endpoint;
+}
+
+static struct ast_sip_endpoint_identifier username_identifier = {
+ .identify_endpoint = username_identify,
+};
+
+static int load_module(void)
+{
+ ast_sip_register_endpoint_identifier(&username_identifier);
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ ast_sip_unregister_endpoint_identifier(&username_identifier);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP username endpoint identifier",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_APP_DEPEND,
+ );
diff --git a/res/res_sip_logger.c b/res/res_sip_logger.c
new file mode 100644
index 000000000..da1719810
--- /dev/null
+++ b/res/res_sip_logger.c
@@ -0,0 +1,81 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/module.h"
+#include "asterisk/logger.h"
+
+static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
+{
+ ast_verbose("<--- Transmitting SIP %s (%d bytes) to %s:%s:%d --->\n%.*s\n",
+ tdata->msg->type == PJSIP_REQUEST_MSG ? "request" : "response",
+ (int) (tdata->buf.cur - tdata->buf.start),
+ tdata->tp_info.transport->type_name,
+ tdata->tp_info.dst_name,
+ tdata->tp_info.dst_port,
+ (int) (tdata->buf.end - tdata->buf.start), tdata->buf.start);
+ return PJ_SUCCESS;
+}
+
+static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
+{
+ ast_verbose("<--- Received SIP %s (%d bytes) from %s:%s:%d --->\n%s\n",
+ rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ? "request" : "response",
+ rdata->msg_info.len,
+ rdata->tp_info.transport->type_name,
+ rdata->pkt_info.src_name,
+ rdata->pkt_info.src_port,
+ rdata->pkt_info.packet);
+ return PJ_FALSE;
+}
+
+static pjsip_module logging_module = {
+ .name = { "Logging Module", 14 },
+ .priority = 0,
+ .on_rx_request = logging_on_rx_msg,
+ .on_rx_response = logging_on_rx_msg,
+ .on_tx_request = logging_on_tx_msg,
+ .on_tx_response = logging_on_tx_msg,
+};
+
+static int load_module(void)
+{
+ ast_sip_register_service(&logging_module);
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ ast_sip_unregister_service(&logging_module);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP Packet Logger",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_APP_DEPEND,
+ );
diff --git a/res/res_sip_mwi.c b/res/res_sip_mwi.c
new file mode 100644
index 000000000..7d62816d0
--- /dev/null
+++ b/res/res_sip_mwi.c
@@ -0,0 +1,709 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_simple.h>
+#include <pjlib.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/res_sip_pubsub.h"
+#include "asterisk/module.h"
+#include "asterisk/logger.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/sorcery.h"
+#include "asterisk/stasis.h"
+#include "asterisk/app.h"
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <depend>res_sip</depend>
+ <depend>res_sip_pubsub</depend>
+ <support_level>core</support_level>
+ ***/
+
+struct mwi_subscription;
+AO2_GLOBAL_OBJ_STATIC(unsolicited_mwi);
+
+#define STASIS_BUCKETS 13
+#define MWI_BUCKETS 53
+static void mwi_subscription_shutdown(struct ast_sip_subscription *sub);
+static struct ast_sip_subscription *mwi_new_subscribe(struct ast_sip_endpoint *endpoint,
+ pjsip_rx_data *rdata);
+static void mwi_resubscribe(struct ast_sip_subscription *sub, pjsip_rx_data *rdata,
+ struct ast_sip_subscription_response_data *response_data);
+static void mwi_subscription_timeout(struct ast_sip_subscription *sub);
+static void mwi_subscription_terminated(struct ast_sip_subscription *sub, pjsip_rx_data *rdata);
+static void mwi_notify_response(struct ast_sip_subscription *sub, pjsip_rx_data *rdata);
+static void mwi_notify_request(struct ast_sip_subscription *sub, pjsip_rx_data *rdata,
+ struct ast_sip_subscription_response_data *response_data);
+static int mwi_refresh_subscription(struct ast_sip_subscription *sub);
+
+static struct ast_sip_subscription_handler mwi_handler = {
+ .event_name = "message-summary",
+ .accept = { "application/simple-message-summary", },
+ .subscription_shutdown = mwi_subscription_shutdown,
+ .new_subscribe = mwi_new_subscribe,
+ .resubscribe = mwi_resubscribe,
+ .subscription_timeout = mwi_subscription_timeout,
+ .subscription_terminated = mwi_subscription_terminated,
+ .notify_response = mwi_notify_response,
+ .notify_request = mwi_notify_request,
+ .refresh_subscription = mwi_refresh_subscription,
+};
+
+/*!
+ * \brief Wrapper for stasis subscription
+ *
+ * An MWI subscription has a container of these. This
+ * represents a stasis subscription for MWI state.
+ */
+struct mwi_stasis_subscription {
+ /*! The MWI stasis subscription */
+ struct stasis_subscription *stasis_sub;
+ /*! The mailbox corresponding with the MWI subscription. Used as a hash key */
+ char mailbox[1];
+};
+
+/*!
+ * \brief A subscription for MWI
+ *
+ * This subscription is the basis for MWI for an endpoint. Each
+ * endpoint that uses MWI will have a corresponding mwi_subscription.
+ *
+ * This structure acts as the owner for the underlying SIP subscription.
+ * When the mwi_subscription is destroyed, the SIP subscription dies, too.
+ * The mwi_subscription's lifetime is governed by its underlying stasis
+ * subscriptions. When all stasis subscriptions are destroyed, the
+ * mwi_subscription is destroyed as well.
+ */
+struct mwi_subscription {
+ /*! Container of \ref mwi_stasis_subscription structures.
+ * A single MWI subscription may be fore multiple mailboxes, thus
+ * requiring multiple stasis subscriptions
+ */
+ struct ao2_container *stasis_subs;
+ /*! The SIP subscription. Unsolicited MWI does not use this */
+ struct ast_sip_subscription *sip_sub;
+ /*! Is the MWI solicited (i.e. Initiated with an external SUBSCRIBE) ? */
+ unsigned int is_solicited;
+ /*! Identifier for the subscription.
+ * The identifier is the same as the corresponding endpoint's stasis ID.
+ * Used as a hash key
+ */
+ char id[1];
+};
+
+static void mwi_stasis_cb(void *userdata, struct stasis_subscription *sub,
+ struct stasis_topic *topic, struct stasis_message *msg);
+
+static struct mwi_stasis_subscription *mwi_stasis_subscription_alloc(const char *mailbox, struct mwi_subscription *mwi_sub)
+{
+ struct mwi_stasis_subscription *mwi_stasis_sub;
+ struct stasis_topic *topic;
+
+ if (!mwi_sub) {
+ return NULL;
+ }
+
+ mwi_stasis_sub = ao2_alloc(sizeof(*mwi_stasis_sub) + strlen(mailbox), NULL);
+ if (!mwi_stasis_sub) {
+ return NULL;
+ }
+
+ topic = stasis_mwi_topic(mailbox);
+
+ /* Safe strcpy */
+ strcpy(mwi_stasis_sub->mailbox, mailbox);
+ ao2_ref(mwi_sub, +1);
+ ast_debug(3, "Creating stasis MWI subscription to mailbox %s for endpoint %s\n", mailbox, mwi_sub->id);
+ mwi_stasis_sub->stasis_sub = stasis_subscribe(topic, mwi_stasis_cb, mwi_sub);
+ return mwi_stasis_sub;
+}
+
+static int stasis_sub_hash(const void *obj, int flags)
+{
+ const struct mwi_stasis_subscription *mwi_stasis = obj;
+
+ return ast_str_hash(mwi_stasis->mailbox);
+}
+
+static int stasis_sub_cmp(void *obj, void *arg, int flags)
+{
+ struct mwi_stasis_subscription *mwi_stasis1 = obj;
+ struct mwi_stasis_subscription *mwi_stasis2 = arg;
+
+ return strcmp(mwi_stasis1->mailbox, mwi_stasis2->mailbox) ? 0 : CMP_MATCH;
+}
+
+static void mwi_subscription_destructor(void *obj)
+{
+ struct mwi_subscription *sub = obj;
+
+ ast_debug(3, "Destroying MWI subscription for endpoint %s\n", sub->id);
+ ao2_cleanup(sub->sip_sub);
+ ao2_cleanup(sub->stasis_subs);
+}
+
+static struct mwi_subscription *mwi_subscription_alloc(struct ast_sip_endpoint *endpoint,
+ enum ast_sip_subscription_role role, unsigned int is_solicited, pjsip_rx_data *rdata)
+{
+ struct mwi_subscription *sub;
+ const char *endpoint_id = ast_sorcery_object_get_id(endpoint);
+
+ sub = ao2_alloc(sizeof(*sub) + strlen(endpoint_id),
+ mwi_subscription_destructor);
+
+ if (!sub) {
+ return NULL;
+ }
+
+ /* Safe strcpy */
+ strcpy(sub->id, endpoint_id);
+ /* Unsolicited MWI doesn't actually result in a SIP subscription being
+ * created. This is because a SIP subscription associates with a dialog.
+ * Most devices expect unsolicited MWI NOTIFYs to appear out of dialog. If
+ * they receive an in-dialog MWI NOTIFY (i.e. with a to-tag), then they
+ * will reject the NOTIFY with a 481, thus resulting in message-waiting
+ * state not being updated on the device
+ */
+ if (is_solicited) {
+ sub->sip_sub = ast_sip_create_subscription(&mwi_handler,
+ role, endpoint, rdata);
+ if (!sub->sip_sub) {
+ ast_log(LOG_WARNING, "Unable to create MWI SIP subscription for endpoint %s\n", sub->id);
+ ao2_cleanup(sub);
+ return NULL;
+ }
+ }
+
+ sub->stasis_subs = ao2_container_alloc(STASIS_BUCKETS, stasis_sub_hash, stasis_sub_cmp);
+ if (!sub->stasis_subs) {
+ ao2_cleanup(sub);
+ return NULL;
+ }
+ sub->is_solicited = is_solicited;
+
+ ast_debug(3, "Created %s MWI subscription for endpoint %s\n", is_solicited ? "solicited" : "unsolicited", sub->id);
+
+ return sub;
+}
+
+static int mwi_sub_hash(const void *obj, int flags)
+{
+ const struct mwi_subscription *mwi_sub = obj;
+
+ return ast_str_hash(mwi_sub->id);
+}
+
+static int mwi_sub_cmp(void *obj, void *arg, int flags)
+{
+ struct mwi_subscription *mwi_sub1 = obj;
+ struct mwi_subscription *mwi_sub2 = arg;
+
+ return strcmp(mwi_sub1->id, mwi_sub2->id) ? 0 : CMP_MATCH;
+}
+
+struct message_accumulator {
+ int old_msgs;
+ int new_msgs;
+ const char *reason;
+};
+
+static int get_message_count(void *obj, void *arg, int flags)
+{
+ RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+ struct mwi_stasis_subscription *mwi_stasis = obj;
+ struct message_accumulator *counter = arg;
+ struct stasis_mwi_state *mwi_state;
+
+ msg = stasis_cache_get(stasis_mwi_topic_cached(), stasis_mwi_state_type(), mwi_stasis->mailbox);
+ if (!msg) {
+ return 0;
+ }
+
+ mwi_state = stasis_message_data(msg);
+ counter->old_msgs += mwi_state->old_msgs;
+ counter->new_msgs += mwi_state->new_msgs;
+ return 0;
+}
+
+struct unsolicited_mwi_data {
+ struct mwi_subscription *sub;
+ struct ast_sip_endpoint *endpoint;
+ pjsip_evsub_state state;
+ const char *reason;
+ const pjsip_media_type *mwi_type;
+ const pj_str_t *body_text;
+};
+
+static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flags)
+{
+ struct unsolicited_mwi_data *mwi_data = arg;
+ struct mwi_subscription *sub = mwi_data->sub;
+ struct ast_sip_endpoint *endpoint = mwi_data->endpoint;
+ pjsip_evsub_state state = mwi_data->state;
+ const char *reason = mwi_data->reason;
+ const pjsip_media_type *mwi_type = mwi_data->mwi_type;
+ const pj_str_t *body_text = mwi_data->body_text;
+ struct ast_sip_contact *contact = obj;
+ const char *state_name;
+ pjsip_tx_data *tdata;
+ pjsip_msg_body *msg_body;
+ pjsip_sub_state_hdr *sub_state;
+ pjsip_event_hdr *event;
+ const pjsip_hdr *allow_events = pjsip_evsub_get_allow_events_hdr(NULL);
+
+ if (ast_sip_create_request("NOTIFY", NULL, endpoint, contact->uri, &tdata)) {
+ ast_log(LOG_WARNING, "Unable to create unsolicited NOTIFY request to endpoint %s URI %s\n", sub->id, contact->uri);
+ return 0;
+ }
+
+ switch (state) {
+ case PJSIP_EVSUB_STATE_ACTIVE:
+ state_name = "active";
+ break;
+ case PJSIP_EVSUB_STATE_TERMINATED:
+ default:
+ state_name = "terminated";
+ break;
+ }
+
+ sub_state = pjsip_sub_state_hdr_create(tdata->pool);
+ pj_cstr(&sub_state->sub_state, state_name);
+ if (reason) {
+ pj_cstr(&sub_state->reason_param, reason);
+ }
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) sub_state);
+
+ event = pjsip_event_hdr_create(tdata->pool);
+ pj_cstr(&event->event_type, "message-summary");
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) event);
+
+ pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, allow_events));
+ msg_body = pjsip_msg_body_create(tdata->pool, &mwi_type->type, &mwi_type->subtype, body_text);
+ tdata->msg->body = msg_body;
+ ast_sip_send_request(tdata, NULL, endpoint);
+
+ return 0;
+}
+
+static void send_unsolicited_mwi_notify(struct mwi_subscription *sub, pjsip_evsub_state state, const char *reason,
+ const pjsip_media_type *mwi_type, const pj_str_t *body_text)
+{
+ RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(),
+ "endpoint", sub->id), ao2_cleanup);
+ char *endpoint_aors;
+ char *aor_name;
+
+ if (!endpoint) {
+ ast_log(LOG_WARNING, "Unable to send unsolicited MWI to %s because endpoint does not exist\n",
+ sub->id);
+ return;
+ }
+ if (ast_strlen_zero(endpoint->aors)) {
+ ast_log(LOG_WARNING, "Unable to send unsolicited MWI to %s because the endpoint has no"
+ " configured AORs\n", sub->id);
+ return;
+ }
+
+ endpoint_aors = ast_strdupa(endpoint->aors);
+
+ while ((aor_name = strsep(&endpoint_aors, ","))) {
+ RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
+ RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
+ struct unsolicited_mwi_data mwi_data = {
+ .sub = sub,
+ .endpoint = endpoint,
+ .state = state,
+ .reason = reason,
+ .mwi_type = mwi_type,
+ .body_text = body_text,
+ };
+
+ if (!aor) {
+ ast_log(LOG_WARNING, "Unable to locate AOR %s for unsolicited MWI\n", aor_name);
+ continue;
+ }
+
+ contacts = ast_sip_location_retrieve_aor_contacts(aor);
+ if (!contacts || (ao2_container_count(contacts) == 0)) {
+ ast_log(LOG_WARNING, "No contacts bound to AOR %s. Cannot send unsolicited MWI.\n", aor_name);
+ continue;
+ }
+
+ ao2_callback(contacts, OBJ_NODATA, send_unsolicited_mwi_notify_to_contact, &mwi_data);
+ }
+}
+
+static void send_mwi_notify(struct mwi_subscription *sub, pjsip_evsub_state state, const char *reason)
+{
+ const pj_str_t *reason_str_ptr = NULL;
+ static pjsip_media_type mwi_type = {
+ .type = { "application", 11 },
+ .subtype = { "simple-message-summary", 22 },
+ };
+ struct message_accumulator counter = {
+ .old_msgs = 0,
+ .new_msgs = 0,
+ };
+ RAII_VAR(struct ast_str *, body, ast_str_create(64), ast_free_ptr);
+ pjsip_tx_data *tdata;
+ pj_str_t reason_str;
+ pj_str_t pj_body;
+
+ ao2_callback(sub->stasis_subs, OBJ_NODATA, get_message_count, &counter);
+
+ if (reason) {
+ pj_cstr(&reason_str, reason);
+ reason_str_ptr = &reason_str;
+ }
+ ast_str_append(&body, 0, "Messages-Waiting: %s\r\n", counter.new_msgs ? "yes" : "no");
+ ast_str_append(&body, 0, "Voice-Message: %d/%d (0/0)\r\n", counter.new_msgs, counter.old_msgs);
+ pj_cstr(&pj_body, ast_str_buffer(body));
+
+ ast_debug(5, "Sending %s MWI NOTIFY to endpoint %s, new messages: %d, old messages: %d\n",
+ sub->is_solicited ? "solicited" : "unsolicited", sub->id, counter.new_msgs,
+ counter.old_msgs);
+
+ if (sub->is_solicited) {
+ if (pjsip_mwi_notify(ast_sip_subscription_get_evsub(sub->sip_sub),
+ state,
+ NULL,
+ reason_str_ptr,
+ &mwi_type,
+ &pj_body,
+ &tdata) != PJ_SUCCESS) {
+ ast_log(LOG_WARNING, "Unable to create MWI NOTIFY request to %s.\n", sub->id);
+ return;
+ }
+ if (ast_sip_subscription_send_request(sub->sip_sub, tdata) != PJ_SUCCESS) {
+ ast_log(LOG_WARNING, "Unable to send MWI NOTIFY request to %s\n", sub->id);
+ return;
+ }
+ } else {
+ send_unsolicited_mwi_notify(sub, state, reason, &mwi_type, &pj_body);
+ }
+}
+
+static int unsubscribe_stasis(void *obj, void *arg, int flags)
+{
+ struct mwi_stasis_subscription *mwi_stasis = obj;
+ if (mwi_stasis->stasis_sub) {
+ ast_debug(3, "Removing stasis subscription to mailbox %s\n", mwi_stasis->mailbox);
+ mwi_stasis->stasis_sub = stasis_unsubscribe(mwi_stasis->stasis_sub);
+ }
+ return CMP_MATCH;
+}
+
+static void mwi_subscription_shutdown(struct ast_sip_subscription *sub)
+{
+ struct mwi_subscription *mwi_sub;
+ RAII_VAR(struct ast_datastore *, mwi_datastore,
+ ast_sip_subscription_get_datastore(sub, "MWI datastore"), ao2_cleanup);
+
+ if (!mwi_datastore) {
+ return;
+ }
+
+ mwi_sub = mwi_datastore->data;
+ ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, NULL);
+}
+
+static struct ast_datastore_info mwi_ds_info = { };
+
+static int add_mwi_datastore(struct mwi_subscription *sub)
+{
+ RAII_VAR(struct ast_datastore *, mwi_datastore, NULL, ao2_cleanup);
+
+ mwi_datastore = ast_sip_subscription_alloc_datastore(&mwi_ds_info, "MWI datastore");
+ if (!mwi_datastore) {
+ return -1;
+ }
+ mwi_datastore->data = sub;
+
+ ast_sip_subscription_add_datastore(sub->sip_sub, mwi_datastore);
+ return 0;
+}
+
+static struct ast_sip_subscription *mwi_new_subscribe(struct ast_sip_endpoint *endpoint,
+ pjsip_rx_data *rdata)
+{
+ RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
+ /* It's not obvious here, but the reference(s) to this subscription,
+ * once this function exits, is held by the stasis subscription(s)
+ * created in mwi_stasis_subscription_alloc()
+ */
+ RAII_VAR(struct mwi_subscription *, sub, NULL, ao2_cleanup);
+ pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
+ pjsip_sip_uri *sip_ruri;
+ pjsip_evsub *evsub;
+ char aor_name[80];
+ char *mailboxes;
+ char *mailbox;
+
+ if (!PJSIP_URI_SCHEME_IS_SIP(ruri) && !PJSIP_URI_SCHEME_IS_SIPS(ruri)) {
+ ast_log(LOG_WARNING, "Attempt to SUBSCRIBE to a non-SIP URI\n");
+ return NULL;
+ }
+ sip_ruri = pjsip_uri_get_uri(ruri);
+ ast_copy_pj_str(aor_name, &sip_ruri->user, sizeof(aor_name));
+
+ aor = ast_sip_location_retrieve_aor(aor_name);
+ if (!aor) {
+ ast_log(LOG_WARNING, "Unable to locate aor %s. MWI subscription failed.\n", aor_name);
+ return NULL;
+ }
+
+ if (ast_strlen_zero(aor->mailboxes)) {
+ ast_log(LOG_WARNING, "AOR %s has no configured mailboxes. MWI subscription failed\n", aor_name);
+ return NULL;
+ }
+
+ sub = mwi_subscription_alloc(endpoint, AST_SIP_NOTIFIER, 1, rdata);
+ if (!sub) {
+ return NULL;
+ }
+
+ if (add_mwi_datastore(sub)) {
+ ast_log(LOG_WARNING, "Unable to allocate datastore on MWI subscription from %s\n", sub->id);
+ return NULL;
+ }
+
+ mailboxes = ast_strdupa(aor->mailboxes);
+ while ((mailbox = strsep(&mailboxes, ","))) {
+ RAII_VAR(struct mwi_stasis_subscription *, mwi_stasis_sub,
+ mwi_stasis_subscription_alloc(mailbox, sub), ao2_cleanup);
+ if (mwi_stasis_sub) {
+ ao2_link(sub->stasis_subs, mwi_stasis_sub);
+ }
+ }
+
+ evsub = ast_sip_subscription_get_evsub(sub->sip_sub);
+ pjsip_evsub_accept(evsub, rdata, 200, NULL);
+ send_mwi_notify(sub, PJSIP_EVSUB_STATE_ACTIVE, NULL);
+
+ return sub->sip_sub;
+}
+
+static void mwi_resubscribe(struct ast_sip_subscription *sub,
+ pjsip_rx_data *rdata, struct ast_sip_subscription_response_data *response_data)
+{
+ pjsip_tx_data *tdata;
+
+ pjsip_mwi_current_notify(ast_sip_subscription_get_evsub(sub), &tdata);
+ ast_sip_subscription_send_request(sub, tdata);
+}
+
+static void mwi_subscription_timeout(struct ast_sip_subscription *sub)
+{
+ struct mwi_subscription *mwi_sub;
+ RAII_VAR(struct ast_datastore *, mwi_datastore,
+ ast_sip_subscription_get_datastore(sub, "MWI datastore"), ao2_cleanup);
+
+ if (!mwi_datastore) {
+ return;
+ }
+
+
+ mwi_sub = mwi_datastore->data;
+
+ ast_log(LOG_NOTICE, "MWI subscription for %s has timed out.\n", mwi_sub->id);
+
+ send_mwi_notify(mwi_sub, PJSIP_EVSUB_STATE_TERMINATED, "timeout");
+}
+
+static void mwi_subscription_terminated(struct ast_sip_subscription *sub, pjsip_rx_data *rdata)
+{
+ struct mwi_subscription *mwi_sub;
+ RAII_VAR(struct ast_datastore *, mwi_datastore,
+ ast_sip_subscription_get_datastore(sub, "MWI datastore"), ao2_cleanup);
+
+ if (!mwi_datastore) {
+ return;
+ }
+
+ mwi_sub = mwi_datastore->data;
+
+ ast_log(LOG_NOTICE, "MWI subscription for %s has been terminated\n", mwi_sub->id);
+
+ send_mwi_notify(mwi_sub, PJSIP_EVSUB_STATE_TERMINATED, NULL);
+}
+
+static void mwi_notify_response(struct ast_sip_subscription *sub, pjsip_rx_data *rdata)
+{
+ /* We don't really care about NOTIFY responses for the moment */
+}
+
+static void mwi_notify_request(struct ast_sip_subscription *sub, pjsip_rx_data *rdata,
+ struct ast_sip_subscription_response_data *response_data)
+{
+ ast_log(LOG_WARNING, "Received an MWI NOTIFY request? This should not happen\n");
+}
+
+static int mwi_refresh_subscription(struct ast_sip_subscription *sub)
+{
+ ast_log(LOG_WARNING, "Being told to refresh an MWI subscription? This should not happen\n");
+ return 0;
+}
+
+static int serialized_notify(void *userdata)
+{
+ struct mwi_subscription *mwi_sub = userdata;
+
+ send_mwi_notify(mwi_sub, PJSIP_EVSUB_STATE_ACTIVE, NULL);
+ ao2_ref(mwi_sub, -1);
+ return 0;
+}
+
+static int serialized_cleanup(void *userdata)
+{
+ struct mwi_subscription *mwi_sub = userdata;
+
+ /* This is getting rid of the reference that was added
+ * just before this serialized task was pushed.
+ */
+ ao2_cleanup(mwi_sub);
+ /* This is getting rid of the reference held by the
+ * stasis subscription
+ */
+ ao2_cleanup(mwi_sub);
+ return 0;
+}
+
+static void mwi_stasis_cb(void *userdata, struct stasis_subscription *sub,
+ struct stasis_topic *topic, struct stasis_message *msg)
+{
+ struct mwi_subscription *mwi_sub = userdata;
+
+ if (stasis_subscription_final_message(sub, msg)) {
+ ao2_ref(mwi_sub, +1);
+ ast_sip_push_task(NULL, serialized_cleanup, mwi_sub);
+ return;
+ }
+
+ if (stasis_mwi_state_type() == stasis_message_type(msg)) {
+ struct ast_taskprocessor *serializer = mwi_sub->is_solicited ? ast_sip_subscription_get_serializer(mwi_sub->sip_sub) : NULL;
+ ao2_ref(mwi_sub, +1);
+ ast_sip_push_task(serializer, serialized_notify, mwi_sub);
+ }
+}
+
+static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags)
+{
+ RAII_VAR(struct mwi_subscription *, aggregate_sub, NULL, ao2_cleanup);
+ struct ast_sip_endpoint *endpoint = obj;
+ struct ao2_container *mwi_subscriptions = arg;
+ char *mailboxes;
+ char *mailbox;
+
+ if (ast_strlen_zero(endpoint->mailboxes)) {
+ return 0;
+ }
+
+ if (endpoint->aggregate_mwi) {
+ aggregate_sub = mwi_subscription_alloc(endpoint, AST_SIP_NOTIFIER, 0, NULL);
+ if (!aggregate_sub) {
+ return 0;
+ }
+ }
+
+ mailboxes = ast_strdupa(endpoint->mailboxes);
+ while ((mailbox = strsep(&mailboxes, ","))) {
+ struct mwi_subscription *sub = aggregate_sub ?:
+ mwi_subscription_alloc(endpoint, AST_SIP_SUBSCRIBER, 0, NULL);
+ RAII_VAR(struct mwi_stasis_subscription *, mwi_stasis_sub,
+ mwi_stasis_subscription_alloc(mailbox, sub), ao2_cleanup);
+ if (mwi_stasis_sub) {
+ ao2_link(sub->stasis_subs, mwi_stasis_sub);
+ }
+ if (!aggregate_sub) {
+ ao2_link(mwi_subscriptions, sub);
+ ao2_cleanup(sub);
+ }
+ }
+ ao2_link(mwi_subscriptions, aggregate_sub);
+ return 0;
+}
+
+static int unsubscribe(void *obj, void *arg, int flags)
+{
+ struct mwi_subscription *mwi_sub = obj;
+
+ ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, NULL);
+ return CMP_MATCH;
+}
+
+static void create_mwi_subscriptions(void)
+{
+ struct ao2_container *mwi_subscriptions = ao2_container_alloc(MWI_BUCKETS, mwi_sub_hash, mwi_sub_cmp);
+ RAII_VAR(struct ao2_container *, old_mwi_subscriptions, ao2_global_obj_ref(unsolicited_mwi), ao2_cleanup);
+ RAII_VAR(struct ao2_container *, endpoints, ast_sorcery_retrieve_by_fields(
+ ast_sip_get_sorcery(), "endpoint", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL),
+ ao2_cleanup);
+
+ if (!mwi_subscriptions) {
+ return;
+ }
+
+ /* We remove all the old stasis subscriptions first before applying the new configuration. This
+ * prevents a situation where there might be multiple overlapping stasis subscriptions for an
+ * endpoint for mailboxes. Though there may be mailbox changes during the gap between unsubscribing
+ * and resubscribing, up-to-date mailbox state will be sent out to the endpoint when the
+ * new stasis subscription is established
+ */
+ if (old_mwi_subscriptions) {
+ ao2_callback(old_mwi_subscriptions, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL);
+ }
+ ao2_callback(endpoints, OBJ_NODATA, create_mwi_subscriptions_for_endpoint, mwi_subscriptions);
+ ao2_global_obj_replace_unref(unsolicited_mwi, mwi_subscriptions);
+}
+
+static int reload(void)
+{
+ create_mwi_subscriptions();
+ return 0;
+}
+
+static int load_module(void)
+{
+ if (ast_sip_register_subscription_handler(&mwi_handler)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ create_mwi_subscriptions();
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ RAII_VAR(struct ao2_container *, mwi_subscriptions, ao2_global_obj_ref(unsolicited_mwi), ao2_cleanup);
+ if (mwi_subscriptions) {
+ ao2_callback(mwi_subscriptions, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL);
+ ao2_global_obj_release(unsolicited_mwi);
+ }
+ ast_sip_unregister_subscription_handler(&mwi_handler);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP MWI resource",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload,
+ .load_pri = AST_MODPRI_CHANNEL_DEPEND,
+);
diff --git a/res/res_sip_nat.c b/res/res_sip_nat.c
new file mode 100644
index 000000000..6c924af68
--- /dev/null
+++ b/res/res_sip_nat.c
@@ -0,0 +1,235 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Joshua Colp <jcolp@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_ua.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/module.h"
+#include "asterisk/acl.h"
+
+static pj_bool_t nat_on_rx_request(pjsip_rx_data *rdata)
+{
+ RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
+ pjsip_contact_hdr *contact;
+
+ if (!endpoint) {
+ return PJ_FALSE;
+ }
+
+ if (endpoint->rewrite_contact && (contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL)) &&
+ (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
+ pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri);
+
+ pj_cstr(&uri->host, rdata->pkt_info.src_name);
+ uri->port = rdata->pkt_info.src_port;
+ }
+
+ if (endpoint->force_rport) {
+ rdata->msg_info.via->rport_param = 0;
+ }
+
+ return PJ_FALSE;
+}
+
+/*! \brief Structure which contains information about a transport */
+struct request_transport_details {
+ /*! \brief Type of transport */
+ enum ast_sip_transport_type type;
+ /*! \brief Potential pointer to the transport itself, if UDP */
+ pjsip_transport *transport;
+ /*! \brief Potential pointer to the transport factory itself, if TCP/TLS */
+ pjsip_tpfactory *factory;
+ /*! \brief Local address for transport */
+ pj_str_t local_address;
+ /*! \brief Local port for transport */
+ int local_port;
+};
+
+/*! \brief Callback function for finding the transport the request is going out on */
+static int find_transport_in_use(void *obj, void *arg, int flags)
+{
+ struct ast_sip_transport *transport = obj;
+ struct request_transport_details *details = arg;
+
+ /* If an explicit transport or factory matches then this is what is in use, if we are unavailable
+ * to compare based on that we make sure that the type is the same and the source IP address/port are the same
+ */
+ if ((details->transport && details->transport == transport->state->transport) ||
+ (details->factory && details->factory == transport->state->factory) ||
+ ((details->type == transport->type) && (transport->state->factory) &&
+ !pj_strcmp(&transport->state->factory->addr_name.host, &details->local_address) &&
+ transport->state->factory->addr_name.port == details->local_port)) {
+ return CMP_MATCH | CMP_STOP;
+ }
+
+ return 0;
+}
+
+/*! \brief Helper function which returns the SIP URI of a Contact header */
+static pjsip_sip_uri *nat_get_contact_sip_uri(pjsip_tx_data *tdata)
+{
+ pjsip_contact_hdr *contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
+
+ if (!contact || (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
+ return NULL;
+ }
+
+ return pjsip_uri_get_uri(contact->uri);
+}
+
+/*! \brief Structure which contains hook details */
+struct nat_hook_details {
+ /*! \brief Outgoing message itself */
+ pjsip_tx_data *tdata;
+ /*! \brief Chosen transport */
+ struct ast_sip_transport *transport;
+};
+
+/*! \brief Callback function for invoking hooks */
+static int nat_invoke_hook(void *obj, void *arg, int flags)
+{
+ struct ast_sip_nat_hook *hook = obj;
+ struct nat_hook_details *details = arg;
+
+ if (hook->outgoing_external_message) {
+ hook->outgoing_external_message(details->tdata, details->transport);
+ }
+
+ return 0;
+}
+
+static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata)
+{
+ RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
+ struct request_transport_details details = { 0, };
+ pjsip_via_hdr *via = NULL;
+ struct ast_sockaddr addr = { { 0, } };
+ pjsip_sip_uri *uri = NULL;
+ RAII_VAR(struct ao2_container *, hooks, NULL, ao2_cleanup);
+
+ /* If a transport selector is in use we know the transport or factory, so explicitly find it */
+ if (tdata->tp_sel.type == PJSIP_TPSELECTOR_TRANSPORT) {
+ details.transport = tdata->tp_sel.u.transport;
+ } else if (tdata->tp_sel.type == PJSIP_TPSELECTOR_LISTENER) {
+ details.factory = tdata->tp_sel.u.listener;
+ } else if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP || tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) {
+ /* Connectionless uses the same transport for all requests */
+ details.type = AST_SIP_TRANSPORT_UDP;
+ details.transport = tdata->tp_info.transport;
+ } else {
+ if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TCP) {
+ details.type = AST_SIP_TRANSPORT_TCP;
+ } else if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_TLS) {
+ details.type = AST_SIP_TRANSPORT_TLS;
+ } else {
+ /* Unknown transport type, we can't map and thus can't apply NAT changes */
+ return PJ_SUCCESS;
+ }
+
+ if ((uri = nat_get_contact_sip_uri(tdata))) {
+ details.local_address = uri->host;
+ details.local_port = uri->port;
+ } else if ((tdata->msg->type == PJSIP_REQUEST_MSG) &&
+ (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL))) {
+ details.local_address = via->sent_by.host;
+ details.local_port = via->sent_by.port;
+ } else {
+ return PJ_SUCCESS;
+ }
+
+ if (!details.local_port) {
+ details.local_port = (details.type == AST_SIP_TRANSPORT_TLS) ? 5061 : 5060;
+ }
+ }
+
+ if (!(transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) ||
+ !(transport = ao2_callback(transports, 0, find_transport_in_use, &details)) || !transport->localnet ||
+ ast_sockaddr_isnull(&transport->external_address)) {
+ return PJ_SUCCESS;
+ }
+
+ ast_sockaddr_parse(&addr, tdata->tp_info.dst_name, PARSE_PORT_FORBID);
+ ast_sockaddr_set_port(&addr, tdata->tp_info.dst_port);
+
+ /* See if where we are sending this request is local or not, and if not that we can get a Contact URI to modify */
+ if (ast_apply_ha(transport->localnet, &addr) != AST_SENSE_ALLOW) {
+ return PJ_SUCCESS;
+ }
+
+ /* Update the contact header with the external address */
+ if (uri || (uri = nat_get_contact_sip_uri(tdata))) {
+ pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport->external_address));
+ if (transport->external_signaling_port) {
+ uri->port = transport->external_signaling_port;
+ }
+ }
+
+ /* Update the via header if relevant */
+ if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) {
+ pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport->external_address));
+ if (transport->external_signaling_port) {
+ via->sent_by.port = transport->external_signaling_port;
+ }
+ }
+
+ /* Invoke any additional hooks that may be registered */
+ if ((hooks = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "nat_hook", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL))) {
+ struct nat_hook_details hook_details = {
+ .tdata = tdata,
+ .transport = transport,
+ };
+ ao2_callback(hooks, 0, nat_invoke_hook, &hook_details);
+ }
+
+ return PJ_SUCCESS;
+}
+
+static pjsip_module nat_module = {
+ .name = { "NAT", 3 },
+ .id = -1,
+ .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 2,
+ .on_rx_request = nat_on_rx_request,
+ .on_tx_request = nat_on_tx_message,
+ .on_tx_response = nat_on_tx_message,
+};
+
+static int load_module(void)
+{
+ ast_sip_register_service(&nat_module);
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ ast_sip_unregister_service(&nat_module);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP NAT Support",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_APP_DEPEND,
+ );
diff --git a/res/res_sip_outbound_authenticator_digest.c b/res/res_sip_outbound_authenticator_digest.c
new file mode 100644
index 000000000..180c05e27
--- /dev/null
+++ b/res/res_sip_outbound_authenticator_digest.c
@@ -0,0 +1,110 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/logger.h"
+#include "asterisk/module.h"
+#include "asterisk/strings.h"
+
+static int set_outbound_authentication_credentials(pjsip_auth_clt_sess *auth_sess, const char **auth_strs, size_t num_auths)
+{
+ struct ast_sip_auth **auths = ast_alloca(num_auths * sizeof(*auths));
+ pjsip_cred_info *auth_creds = ast_alloca(num_auths * sizeof(*auth_creds));
+ int res = 0;
+ int i;
+
+ if (ast_sip_retrieve_auths(auth_strs, num_auths, auths)) {
+ res = -1;
+ goto cleanup;
+ }
+
+ for (i = 0; i < num_auths; ++i) {
+ pj_cstr(&auth_creds[i].realm, auths[i]->realm);
+ pj_cstr(&auth_creds[i].username, auths[i]->auth_user);
+ pj_cstr(&auth_creds[i].scheme, "digest");
+ switch (auths[i]->type) {
+ case AST_SIP_AUTH_TYPE_USER_PASS:
+ pj_cstr(&auth_creds[i].data, auths[i]->auth_pass);
+ auth_creds[i].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
+ break;
+ case AST_SIP_AUTH_TYPE_MD5:
+ pj_cstr(&auth_creds[i].data, auths[i]->md5_creds);
+ auth_creds[i].data_type = PJSIP_CRED_DATA_DIGEST;
+ break;
+ }
+ }
+
+ pjsip_auth_clt_set_credentials(auth_sess, num_auths, auth_creds);
+
+cleanup:
+ ast_sip_cleanup_auths(auths, num_auths);
+ return res;
+}
+
+static int digest_create_request_with_auth(const char **auths, size_t num_auths, pjsip_rx_data *challenge,
+ pjsip_transaction *tsx, pjsip_tx_data **new_request)
+{
+ pjsip_auth_clt_sess auth_sess;
+
+ if (pjsip_auth_clt_init(&auth_sess, ast_sip_get_pjsip_endpoint(),
+ tsx->pool, 0) != PJ_SUCCESS) {
+ ast_log(LOG_WARNING, "Failed to initialize client authentication session\n");
+ return -1;
+ }
+
+ if (set_outbound_authentication_credentials(&auth_sess, auths, num_auths)) {
+ ast_log(LOG_WARNING, "Failed to set authentication credentials\n");
+ return -1;
+ }
+
+ if (pjsip_auth_clt_reinit_req(&auth_sess, challenge,
+ tsx->last_tx, new_request) != PJ_SUCCESS) {
+ ast_log(LOG_WARNING, "Failed to create new request with authentication credentials\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct ast_sip_outbound_authenticator digest_authenticator = {
+ .create_request_with_auth = digest_create_request_with_auth,
+};
+
+static int load_module(void)
+{
+ if (ast_sip_register_outbound_authenticator(&digest_authenticator)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ ast_sip_unregister_outbound_authenticator(&digest_authenticator);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP authentication resource",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_CHANNEL_DEPEND,
+);
diff --git a/res/res_sip_outbound_registration.c b/res/res_sip_outbound_registration.c
new file mode 100644
index 000000000..8f1108df5
--- /dev/null
+++ b/res/res_sip_outbound_registration.c
@@ -0,0 +1,708 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Joshua Colp <jcolp@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_ua.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/module.h"
+#include "asterisk/taskprocessor.h"
+
+/*! \brief Amount of buffer time (in seconds) before expiration that we re-register at */
+#define REREGISTER_BUFFER_TIME 10
+
+/*! \brief Various states that an outbound registration may be in */
+enum sip_outbound_registration_status {
+ /*! \brief Currently unregistered */
+ SIP_REGISTRATION_UNREGISTERED = 0,
+ /*! \brief Registered, yay! */
+ SIP_REGISTRATION_REGISTERED,
+ /*! \brief Registration was rejected, but response was temporal */
+ SIP_REGISTRATION_REJECTED_TEMPORARY,
+ /*! \brief Registration was rejected, permanently */
+ SIP_REGISTRATION_REJECTED_PERMANENT,
+ /*! \brief Registration has been stopped */
+ SIP_REGISTRATION_STOPPED,
+};
+
+/*! \brief Outbound registration client state information (persists for lifetime of regc) */
+struct sip_outbound_registration_client_state {
+ /*! \brief Current status of this registration */
+ enum sip_outbound_registration_status status;
+ /*! \brief Outbound registration client */
+ pjsip_regc *client;
+ /*! \brief Timer entry for retrying on temporal responses */
+ pj_timer_entry timer;
+ /*! \brief Current number of retries */
+ unsigned int retries;
+ /*! \brief Maximum number of retries permitted */
+ unsigned int max_retries;
+ /*! \brief Interval at which retries should occur for temporal responses */
+ unsigned int retry_interval;
+ /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
+ unsigned int auth_rejection_permanent;
+ /*! \brief Serializer for stuff and things */
+ struct ast_taskprocessor *serializer;
+ /*! \brief Configured authentication credentials */
+ const char **sip_outbound_auths;
+ /*! \brief Number of configured auths */
+ size_t num_outbound_auths;
+ /*! \brief Registration should be destroyed after completion of transaction */
+ unsigned int destroy:1;
+};
+
+/*! \brief Outbound registration state information (persists for lifetime that registration should exist) */
+struct sip_outbound_registration_state {
+ /*! \brief Client state information */
+ struct sip_outbound_registration_client_state *client_state;
+};
+
+/*! \brief Outbound registration information */
+struct sip_outbound_registration {
+ /*! \brief Sorcery object details */
+ SORCERY_OBJECT(details);
+ /*! \brief Stringfields */
+ AST_DECLARE_STRING_FIELDS(
+ /*! \brief URI for the registrar */
+ AST_STRING_FIELD(server_uri);
+ /*! \brief URI for the AOR */
+ AST_STRING_FIELD(client_uri);
+ /*! \brief Optional user for contact header */
+ AST_STRING_FIELD(contact_user);
+ /*! \brief Explicit transport to use for registration */
+ AST_STRING_FIELD(transport);
+ /*! \brief Outbound proxy to use */
+ AST_STRING_FIELD(outbound_proxy);
+ );
+ /*! \brief Requested expiration time */
+ unsigned int expiration;
+ /*! \brief Interval at which retries should occur for temporal responses */
+ unsigned int retry_interval;
+ /*! \brief Treat authentication challenges that we cannot handle as permanent failures */
+ unsigned int auth_rejection_permanent;
+ /*! \brief Maximum number of retries permitted */
+ unsigned int max_retries;
+ /*! \brief Outbound registration state */
+ struct sip_outbound_registration_state *state;
+ /*! \brief Configured authentication credentials */
+ const char **sip_outbound_auths;
+ /*! \brief Number of configured auths */
+ size_t num_outbound_auths;
+};
+
+static void destroy_auths(const char **auths, size_t num_auths)
+{
+ int i;
+ for (i = 0; i < num_auths; ++i) {
+ ast_free((char *) auths[i]);
+ }
+ ast_free(auths);
+}
+
+/*! \brief Helper function which cancels the timer on a client */
+static void cancel_registration(struct sip_outbound_registration_client_state *client_state)
+{
+ if (pj_timer_heap_cancel(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), &client_state->timer)) {
+ /* The timer was successfully cancelled, drop the refcount of client_state */
+ ao2_ref(client_state, -1);
+ }
+}
+
+/*! \brief Callback function for registering */
+static int handle_client_registration(void *data)
+{
+ RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
+ pjsip_tx_data *tdata;
+
+ cancel_registration(client_state);
+
+ if ((client_state->status == SIP_REGISTRATION_STOPPED) ||
+ (pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS)) {
+ return 0;
+ }
+
+ /* Due to the registration the callback may now get called, so bump the ref count */
+ ao2_ref(client_state, +1);
+ if (pjsip_regc_send(client_state->client, tdata) != PJ_SUCCESS) {
+ ao2_ref(client_state, -1);
+ pjsip_tx_data_dec_ref(tdata);
+ }
+
+ return 0;
+}
+
+/*! \brief Timer callback function, used just for registrations */
+static void sip_outbound_registration_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
+{
+ RAII_VAR(struct sip_outbound_registration_client_state *, client_state, entry->user_data, ao2_cleanup);
+
+ ao2_ref(client_state, +1);
+ if (ast_sip_push_task(client_state->serializer, handle_client_registration, client_state)) {
+ ast_log(LOG_WARNING, "Failed to pass outbound registration to threadpool\n");
+ ao2_ref(client_state, -1);
+ }
+
+ entry->id = 0;
+}
+
+/*! \brief Helper function which sets up the timer to re-register in a specific amount of time */
+static void schedule_registration(struct sip_outbound_registration_client_state *client_state, unsigned int seconds)
+{
+ pj_time_val delay = { .sec = seconds, };
+
+ cancel_registration(client_state);
+
+ ao2_ref(client_state, +1);
+ if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &client_state->timer, &delay) != PJ_SUCCESS) {
+ ast_log(LOG_WARNING, "Failed to pass timed registration to scheduler\n");
+ ao2_ref(client_state, -1);
+ }
+}
+
+/*! \brief Callback function for unregistering (potentially) and destroying state */
+static int handle_client_state_destruction(void *data)
+{
+ RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
+ pjsip_regc_info info;
+
+ cancel_registration(client_state);
+
+ pjsip_regc_get_info(client_state->client, &info);
+
+ if (info.is_busy == PJ_TRUE) {
+ /* If a client transaction is in progress we defer until it is complete */
+ client_state->destroy = 1;
+ return 0;
+ }
+
+ if (client_state->status != SIP_REGISTRATION_UNREGISTERED && client_state->status != SIP_REGISTRATION_REJECTED_PERMANENT) {
+ pjsip_tx_data *tdata;
+
+ if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS) {
+ pjsip_regc_send(client_state->client, tdata);
+ }
+ }
+
+ pjsip_regc_destroy(client_state->client);
+
+ client_state->status = SIP_REGISTRATION_STOPPED;
+ destroy_auths(client_state->sip_outbound_auths, client_state->num_outbound_auths);
+
+ return 0;
+}
+
+/*! \brief Structure for registration response */
+struct registration_response {
+ /*! \brief Response code for the registration attempt */
+ int code;
+ /*! \brief Expiration time for registration */
+ int expiration;
+ /*! \brief Retry-After value */
+ int retry_after;
+ /*! \brief Outbound registration client state */
+ struct sip_outbound_registration_client_state *client_state;
+ /*! \brief The response message */
+ pjsip_rx_data *rdata;
+ /*! \brief The response transaction */
+ pjsip_transaction *tsx;
+};
+
+/*! \brief Registration response structure destructor */
+static void registration_response_destroy(void *obj)
+{
+ struct registration_response *response = obj;
+
+ pjsip_rx_data_free_cloned(response->rdata);
+ ao2_cleanup(response->client_state);
+}
+
+/* \brief Helper funtion which determines if a response code is temporal or not */
+static int sip_outbound_registration_is_temporal(unsigned int code,
+ struct sip_outbound_registration_client_state *client_state)
+{
+ /* Shamelessly taken from pjsua */
+ if (code == PJSIP_SC_REQUEST_TIMEOUT ||
+ code == PJSIP_SC_INTERNAL_SERVER_ERROR ||
+ code == PJSIP_SC_BAD_GATEWAY ||
+ code == PJSIP_SC_SERVICE_UNAVAILABLE ||
+ code == PJSIP_SC_SERVER_TIMEOUT ||
+ ((code == PJSIP_SC_UNAUTHORIZED ||
+ code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) &&
+ !client_state->auth_rejection_permanent) ||
+ PJSIP_IS_STATUS_IN_CLASS(code, 600)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/*! \brief Callback function for handling a response to a registration attempt */
+static int handle_registration_response(void *data)
+{
+ RAII_VAR(struct registration_response *, response, data, ao2_cleanup);
+ pjsip_regc_info info;
+ char server_uri[PJSIP_MAX_URL_SIZE], client_uri[PJSIP_MAX_URL_SIZE];
+
+ if (response->client_state->status == SIP_REGISTRATION_STOPPED) {
+ return 0;
+ }
+
+ pjsip_regc_get_info(response->client_state->client, &info);
+ ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
+ ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
+
+ if (response->code == 401 || response->code == 407) {
+ pjsip_tx_data *tdata;
+ if (!ast_sip_create_request_with_auth(response->client_state->sip_outbound_auths, response->client_state->num_outbound_auths,
+ response->rdata, response->tsx, &tdata)) {
+ pjsip_regc_send(response->client_state->client, tdata);
+ return 0;
+ }
+ /* Otherwise, fall through so the failure is processed appropriately */
+ }
+
+ if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) {
+ /* If the registration went fine simply reschedule registration for the future */
+ response->client_state->status = SIP_REGISTRATION_REGISTERED;
+ response->client_state->retries = 0;
+ schedule_registration(response->client_state, response->expiration - REREGISTER_BUFFER_TIME);
+ } else if (response->retry_after) {
+ /* If we have been instructed to retry after a period of time, schedule it as such */
+ response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
+ schedule_registration(response->client_state, response->retry_after);
+ ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on registration attempt to '%s', instructed to retry in '%d'\n",
+ response->code, server_uri, client_uri, response->retry_after);
+ } else if (response->client_state->retry_interval && sip_outbound_registration_is_temporal(response->code, response->client_state)) {
+ if (response->client_state->retries == response->client_state->max_retries) {
+ /* If we received enough temporal responses to exceed our maximum give up permanently */
+ response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
+ ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
+ server_uri, client_uri);
+ } else {
+ /* On the other hand if we can still try some more do so */
+ response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY;
+ response->client_state->retries++;
+ schedule_registration(response->client_state, response->client_state->retry_interval);
+ ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on registration attempt to '%s', retrying in '%d' seconds\n",
+ response->code, server_uri, client_uri, response->client_state->retry_interval);
+ }
+ } else {
+ /* Finally if there's no hope of registering give up */
+ response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT;
+ ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
+ response->code, server_uri, client_uri);
+ }
+
+ /* If deferred destruction is in use see if we need to destroy now */
+ if (response->client_state->destroy) {
+ handle_client_state_destruction(response->client_state);
+ }
+
+ return 0;
+}
+
+/*! \brief Callback function for outbound registration client */
+static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
+{
+ RAII_VAR(struct sip_outbound_registration_client_state *, client_state, param->token, ao2_cleanup);
+ struct registration_response *response = ao2_alloc(sizeof(*response), registration_response_destroy);
+ struct pjsip_retry_after_hdr *retry_after = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_RETRY_AFTER, NULL);
+
+ response->code = param->code;
+ response->expiration = param->expiration;
+ response->retry_after = retry_after ? retry_after->ivalue : 0;
+ response->client_state = client_state;
+ response->tsx = pjsip_rdata_get_tsx(param->rdata);
+ pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
+ ao2_ref(response->client_state, +1);
+
+ if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
+ ast_log(LOG_WARNING, "Failed to pass incoming registration response to threadpool\n");
+ ao2_cleanup(response);
+ }
+}
+
+/*! \brief Destructor function for registration state */
+static void sip_outbound_registration_state_destroy(void *obj)
+{
+ struct sip_outbound_registration_state *state = obj;
+
+ if (!state->client_state) {
+ return;
+ }
+
+ if (state->client_state->serializer && ast_sip_push_task(state->client_state->serializer, handle_client_state_destruction, state->client_state)) {
+ ast_log(LOG_WARNING, "Failed to pass outbound registration client destruction to threadpool\n");
+ ao2_ref(state->client_state, -1);
+ }
+}
+
+/*! \brief Destructor function for client registration state */
+static void sip_outbound_registration_client_state_destroy(void *obj)
+{
+ struct sip_outbound_registration_client_state *client_state = obj;
+
+ ast_taskprocessor_unreference(client_state->serializer);
+}
+
+/*! \brief Allocator function for registration state */
+static struct sip_outbound_registration_state *sip_outbound_registration_state_alloc(void)
+{
+ struct sip_outbound_registration_state *state = ao2_alloc(sizeof(*state), sip_outbound_registration_state_destroy);
+
+ if (!state || !(state->client_state = ao2_alloc(sizeof(*state->client_state), sip_outbound_registration_client_state_destroy))) {
+ ao2_cleanup(state);
+ return NULL;
+ }
+
+ if ((pjsip_regc_create(ast_sip_get_pjsip_endpoint(), state->client_state, sip_outbound_registration_response_cb, &state->client_state->client) != PJ_SUCCESS) ||
+ !(state->client_state->serializer = ast_sip_create_serializer())) {
+ /* This is on purpose, normal operation will have it be deallocated within the serializer */
+ pjsip_regc_destroy(state->client_state->client);
+ ao2_cleanup(state->client_state);
+ ao2_cleanup(state);
+ return NULL;
+ }
+
+ state->client_state->status = SIP_REGISTRATION_UNREGISTERED;
+ state->client_state->timer.user_data = state->client_state;
+ state->client_state->timer.cb = sip_outbound_registration_timer_cb;
+
+ return state;
+}
+
+/*! \brief Destructor function for registration information */
+static void sip_outbound_registration_destroy(void *obj)
+{
+ struct sip_outbound_registration *registration = obj;
+
+ ao2_cleanup(registration->state);
+ destroy_auths(registration->sip_outbound_auths, registration->num_outbound_auths);
+
+ ast_string_field_free_memory(registration);
+}
+
+/*! \brief Allocator function for registration information */
+static void *sip_outbound_registration_alloc(const char *name)
+{
+ struct sip_outbound_registration *registration = ao2_alloc(sizeof(*registration), sip_outbound_registration_destroy);
+
+ if (!registration || ast_string_field_init(registration, 256)) {
+ ao2_cleanup(registration);
+ return NULL;
+ }
+
+ return registration;
+}
+
+/*! \brief Helper function which populates a pj_str_t with a contact header */
+static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const char *user, const pj_str_t *target, pjsip_tpselector *selector)
+{
+ pj_str_t tmp, local_addr;
+ pjsip_uri *uri;
+ pjsip_sip_uri *sip_uri;
+ pjsip_transport_type_e type = PJSIP_TRANSPORT_UNSPECIFIED;
+ int local_port;
+
+ pj_strdup_with_null(pool, &tmp, target);
+
+ if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
+ (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
+ return -1;
+ }
+
+ sip_uri = pjsip_uri_get_uri(uri);
+
+ if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
+ type = PJSIP_TRANSPORT_TLS;
+ } else if (!sip_uri->transport_param.slen) {
+ type = PJSIP_TRANSPORT_UDP;
+ } else {
+ type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
+ }
+
+ if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
+ return -1;
+ }
+
+ if (pj_strchr(&sip_uri->host, ':')) {
+ type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
+ }
+
+ if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), pool, type, selector,
+ &local_addr, &local_port) != PJ_SUCCESS) {
+ return -1;
+ }
+
+ if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) {
+ type = (pjsip_transport_type_e)(((int)type) + PJSIP_TRANSPORT_IPV6);
+ }
+
+ contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
+ contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
+ "<%s:%s@%s%.*s%s:%d%s%s>",
+ (pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) ? "sips" : "sip",
+ user,
+ (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
+ (int)local_addr.slen,
+ local_addr.ptr,
+ (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
+ local_port,
+ (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
+ (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "");
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Check if a registration can be reused
+ *
+ * This checks if the existing outbound registration's configuration differs from a newly-applied
+ * outbound registration to see if the applied one.
+ *
+ * \param existing The pre-existing outbound registration
+ * \param applied The newly-created registration
+ */
+static int can_reuse_registration(struct sip_outbound_registration *existing, struct sip_outbound_registration *applied)
+{
+ int i;
+
+ if (strcmp(existing->server_uri, applied->server_uri) || strcmp(existing->client_uri, applied->client_uri) ||
+ strcmp(existing->transport, applied->transport) || strcmp(existing->contact_user, applied->contact_user) ||
+ strcmp(existing->outbound_proxy, applied->outbound_proxy) || existing->num_outbound_auths != applied->num_outbound_auths ||
+ existing->auth_rejection_permanent != applied->auth_rejection_permanent) {
+ return 0;
+ }
+
+ for (i = 0; i < existing->num_outbound_auths; ++i) {
+ if (strcmp(existing->sip_outbound_auths[i], applied->sip_outbound_auths[i])) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*! \brief Apply function which finds or allocates a state structure */
+static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
+{
+ RAII_VAR(struct sip_outbound_registration *, existing, ast_sorcery_retrieve_by_id(sorcery, "registration", ast_sorcery_object_get_id(obj)), ao2_cleanup);
+ struct sip_outbound_registration *applied = obj;
+ pj_str_t server_uri, client_uri, contact_uri;
+ pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
+
+ if (!existing) {
+ /* If no existing registration exists we can just start fresh easily */
+ applied->state = sip_outbound_registration_state_alloc();
+ } else {
+ /* If there is an existing registration things are more complicated, we can immediately reuse this state if most stuff remains unchanged */
+ if (can_reuse_registration(existing, applied)) {
+ applied->state = existing->state;
+ ao2_ref(applied->state, +1);
+ return 0;
+ }
+ applied->state = sip_outbound_registration_state_alloc();
+ }
+
+ if (!applied->state) {
+ return -1;
+ }
+
+ if (!ast_strlen_zero(applied->transport)) {
+ RAII_VAR(struct ast_sip_transport *, transport, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", applied->transport), ao2_cleanup);
+
+ if (!transport || !transport->state) {
+ return -1;
+ }
+
+ if (transport->type == AST_SIP_TRANSPORT_UDP) {
+ selector.type = PJSIP_TPSELECTOR_TRANSPORT;
+ selector.u.transport = transport->state->transport;
+ } else if (transport->type == AST_SIP_TRANSPORT_TCP || transport->type == AST_SIP_TRANSPORT_TLS) {
+ selector.type = PJSIP_TPSELECTOR_LISTENER;
+ selector.u.listener = transport->state->factory;
+ } else {
+ return -1;
+ }
+ }
+
+ pjsip_regc_set_transport(applied->state->client_state->client, &selector);
+
+ if (!ast_strlen_zero(applied->outbound_proxy)) {
+ pjsip_route_hdr route_set, *route;
+ static const pj_str_t ROUTE_HNAME = { "Route", 5 };
+ pj_str_t tmp;
+
+ pj_list_init(&route_set);
+
+ pj_strdup2_with_null(pjsip_regc_get_pool(applied->state->client_state->client), &tmp, applied->outbound_proxy);
+ if (!(route = pjsip_parse_hdr(pjsip_regc_get_pool(applied->state->client_state->client), &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL))) {
+ return -1;
+ }
+ pj_list_push_back(&route_set, route);
+
+ pjsip_regc_set_route_set(applied->state->client_state->client, &route_set);
+ }
+
+ pj_cstr(&server_uri, applied->server_uri);
+
+ if (sip_dialog_create_contact(pjsip_regc_get_pool(applied->state->client_state->client), &contact_uri, S_OR(applied->contact_user, "s"), &server_uri, &selector)) {
+ return -1;
+ }
+
+ pj_cstr(&client_uri, applied->client_uri);
+
+ if (pjsip_regc_init(applied->state->client_state->client, &server_uri, &client_uri, &client_uri, 1, &contact_uri, applied->expiration) != PJ_SUCCESS) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*! \brief Helper function which performs a single registration */
+static int sip_outbound_registration_perform(void *obj, void *arg, int flags)
+{
+ struct sip_outbound_registration *registration = obj;
+ size_t i;
+
+ /* Just in case the client state is being reused for this registration, free the auth information */
+ destroy_auths(registration->state->client_state->sip_outbound_auths,
+ registration->state->client_state->num_outbound_auths);
+ registration->state->client_state->num_outbound_auths = 0;
+
+ registration->state->client_state->sip_outbound_auths = ast_calloc(registration->num_outbound_auths, sizeof(char *));
+ for (i = 0; i < registration->num_outbound_auths; ++i) {
+ registration->state->client_state->sip_outbound_auths[i] = ast_strdup(registration->sip_outbound_auths[i]);
+ }
+ registration->state->client_state->num_outbound_auths = registration->num_outbound_auths;
+ registration->state->client_state->retry_interval = registration->retry_interval;
+ registration->state->client_state->max_retries = registration->max_retries;
+ registration->state->client_state->retries = 0;
+
+ pjsip_regc_update_expires(registration->state->client_state->client, registration->expiration);
+
+ schedule_registration(registration->state->client_state, (ast_random() % 10) + 1);
+
+ return 0;
+}
+
+/*! \brief Helper function which performs all registrations */
+static void sip_outbound_registration_perform_all(void)
+{
+ RAII_VAR(struct ao2_container *, registrations, ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL), ao2_cleanup);
+
+ if (!registrations) {
+ return;
+ }
+
+ ao2_callback(registrations, OBJ_NODATA, sip_outbound_registration_perform, NULL);
+}
+
+#define AUTH_INCREMENT 4
+
+static const char **auth_alloc(const char *value, size_t *num_auths)
+{
+ char *auths = ast_strdupa(value);
+ char *val;
+ int num_alloced = 0;
+ const char **alloced_auths = NULL;
+
+ while ((val = strsep(&auths, ","))) {
+ if (*num_auths >= num_alloced) {
+ size_t size;
+ num_alloced += AUTH_INCREMENT;
+ size = num_alloced * sizeof(char *);
+ alloced_auths = ast_realloc(alloced_auths, size);
+ if (!alloced_auths) {
+ goto failure;
+ }
+ }
+ alloced_auths[*num_auths] = ast_strdup(val);
+ if (!alloced_auths[*num_auths]) {
+ goto failure;
+ }
+ ++(*num_auths);
+ }
+ return alloced_auths;
+
+failure:
+ destroy_auths(alloced_auths, *num_auths);
+ return NULL;
+}
+
+static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+ struct sip_outbound_registration *registration = obj;
+
+ registration->sip_outbound_auths = auth_alloc(var->value, &registration->num_outbound_auths);
+ if (!registration->sip_outbound_auths) {
+ return -1;
+ }
+ return 0;
+}
+
+static int load_module(void)
+{
+ ast_sorcery_apply_default(ast_sip_get_sorcery(), "registration", "config", "res_sip.conf,criteria=type=registration");
+
+ if (ast_sorcery_object_register(ast_sip_get_sorcery(), "registration", sip_outbound_registration_alloc, NULL, sip_outbound_registration_apply)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "type", "", OPT_NOOP_T, 0, 0);
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "server_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, server_uri));
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "client_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, client_uri));
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_user));
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, transport));
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, outbound_proxy));
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "retry_interval", "60", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, retry_interval));
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "max_retries", "10", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, max_retries));
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "auth_rejection_permanent", "yes", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, auth_rejection_permanent));
+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "outbound_auth", "", outbound_auth_handler, NULL, 0, 0);
+ ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
+ sip_outbound_registration_perform_all();
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int reload_module(void)
+{
+ ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
+ sip_outbound_registration_perform_all();
+ return 0;
+}
+
+static int unload_module(void)
+{
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP Outbound Registration Support",
+ .load = load_module,
+ .reload = reload_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_APP_DEPEND,
+ );
diff --git a/res/res_sip_pubsub.c b/res/res_sip_pubsub.c
new file mode 100644
index 000000000..2983d563e
--- /dev/null
+++ b/res/res_sip_pubsub.c
@@ -0,0 +1,662 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+/*!
+ * \brief Opaque structure representing an RFC 3265 SIP subscription
+ */
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_simple.h>
+#include <pjlib.h>
+
+#include "asterisk/res_sip_pubsub.h"
+#include "asterisk/module.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/datastore.h"
+#include "asterisk/uuid.h"
+#include "asterisk/taskprocessor.h"
+#include "asterisk/res_sip.h"
+
+static pj_bool_t sub_on_rx_request(pjsip_rx_data *rdata);
+
+static struct pjsip_module sub_module = {
+ .name = { "PubSub Module", 13 },
+ .priority = PJSIP_MOD_PRIORITY_APPLICATION,
+ .on_rx_request = sub_on_rx_request,
+};
+
+/*!
+ * \brief Structure representing a SIP subscription
+ */
+struct ast_sip_subscription {
+ /*! Subscription datastores set up by handlers */
+ struct ao2_container *datastores;
+ /*! The endpoint with which the subscription is communicating */
+ struct ast_sip_endpoint *endpoint;
+ /*! Serializer on which to place operations for this subscription */
+ struct ast_taskprocessor *serializer;
+ /*! The handler for this subscription */
+ const struct ast_sip_subscription_handler *handler;
+ /*! The role for this subscription */
+ enum ast_sip_subscription_role role;
+ /*! The underlying PJSIP event subscription structure */
+ pjsip_evsub *evsub;
+ /*! The underlying PJSIP dialog */
+ pjsip_dialog *dlg;
+};
+
+#define DATASTORE_BUCKETS 53
+
+#define DEFAULT_EXPIRES 3600
+
+static int datastore_hash(const void *obj, int flags)
+{
+ const struct ast_datastore *datastore = obj;
+ const char *uid = flags & OBJ_KEY ? obj : datastore->uid;
+
+ ast_assert(uid != NULL);
+
+ return ast_str_hash(uid);
+}
+
+static int datastore_cmp(void *obj, void *arg, int flags)
+{
+ const struct ast_datastore *datastore1 = obj;
+ const struct ast_datastore *datastore2 = arg;
+ const char *uid2 = flags & OBJ_KEY ? arg : datastore2->uid;
+
+ ast_assert(datastore1->uid != NULL);
+ ast_assert(uid2 != NULL);
+
+ return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP;
+}
+
+static void subscription_destructor(void *obj)
+{
+ struct ast_sip_subscription *sub = obj;
+
+ ast_debug(3, "Destroying SIP subscription\n");
+
+ ao2_cleanup(sub->datastores);
+ ao2_cleanup(sub->endpoint);
+
+ if (sub->dlg) {
+ /* This is why we keep the dialog on the subscription. When the subscription
+ * is destroyed, there is no guarantee that the underlying dialog is ready
+ * to be destroyed. Furthermore, there's no guarantee in the opposite direction
+ * either. The dialog could be destroyed before our subscription is. We fix
+ * this problem by keeping a reference to the dialog until it is time to
+ * destroy the subscription. We need to have the dialog available when the
+ * subscription is destroyed so that we can guarantee that our attempt to
+ * remove the serializer will be successful.
+ */
+ ast_sip_dialog_set_serializer(sub->dlg, NULL);
+ pjsip_dlg_dec_session(sub->dlg, &sub_module);
+ }
+ ast_taskprocessor_unreference(sub->serializer);
+}
+
+static void pubsub_on_evsub_state(pjsip_evsub *sub, pjsip_event *event);
+static void pubsub_on_tsx_state(pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event);
+static void pubsub_on_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata,
+ int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
+static void pubsub_on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code,
+ pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
+static void pubsub_on_client_refresh(pjsip_evsub *sub);
+static void pubsub_on_server_timeout(pjsip_evsub *sub);
+
+
+static pjsip_evsub_user pubsub_cb = {
+ .on_evsub_state = pubsub_on_evsub_state,
+ .on_tsx_state = pubsub_on_tsx_state,
+ .on_rx_refresh = pubsub_on_rx_refresh,
+ .on_rx_notify = pubsub_on_rx_notify,
+ .on_client_refresh = pubsub_on_client_refresh,
+ .on_server_timeout = pubsub_on_server_timeout,
+};
+
+static pjsip_evsub *allocate_evsub(const char *event, enum ast_sip_subscription_role role,
+ struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pjsip_dialog *dlg)
+{
+ pjsip_evsub *evsub;
+ /* PJSIP is kind enough to have some built-in support for certain
+ * events. We need to use the correct initialization function for the
+ * built-in events
+ */
+ if (role == AST_SIP_NOTIFIER) {
+ if (!strcmp(event, "message-summary")) {
+ pjsip_mwi_create_uas(dlg, &pubsub_cb, rdata, &evsub);
+ } else if (!strcmp(event, "presence")) {
+ pjsip_pres_create_uas(dlg, &pubsub_cb, rdata, &evsub);
+ } else {
+ pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &evsub);
+ }
+ } else {
+ if (!strcmp(event, "message-summary")) {
+ pjsip_mwi_create_uac(dlg, &pubsub_cb, 0, &evsub);
+ } else if (!strcmp(event, "presence")) {
+ pjsip_pres_create_uac(dlg, &pubsub_cb, 0, &evsub);
+ } else {
+ pj_str_t pj_event;
+ pj_cstr(&pj_event, event);
+ pjsip_evsub_create_uac(dlg, &pubsub_cb, &pj_event, 0, &evsub);
+ }
+ }
+ return evsub;
+}
+
+struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler,
+ enum ast_sip_subscription_role role, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
+{
+ struct ast_sip_subscription *sub = ao2_alloc(sizeof(*sub), subscription_destructor);
+ pjsip_dialog *dlg;
+
+ if (!sub) {
+ return NULL;
+ }
+ sub->datastores = ao2_container_alloc(DATASTORE_BUCKETS, datastore_hash, datastore_cmp);
+ if (!sub->datastores) {
+ ao2_ref(sub, -1);
+ return NULL;
+ }
+ sub->serializer = ast_sip_create_serializer();
+ if (!sub->serializer) {
+ ao2_ref(sub, -1);
+ return NULL;
+ }
+ sub->role = role;
+ if (role == AST_SIP_NOTIFIER) {
+ pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, NULL, &dlg);
+ } else {
+ RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
+
+ contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors);
+ if (!contact || ast_strlen_zero(contact->uri)) {
+ ast_log(LOG_WARNING, "No contacts configured for endpoint %s. Unable to create SIP subsription\n",
+ ast_sorcery_object_get_id(endpoint));
+ ao2_ref(sub, -1);
+ return NULL;
+ }
+ dlg = ast_sip_create_dialog(endpoint, contact->uri, NULL);
+ }
+ if (!dlg) {
+ ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
+ ao2_ref(sub, -1);
+ return NULL;
+ }
+ sub->evsub = allocate_evsub(handler->event_name, role, endpoint, rdata, dlg);
+ /* We keep a reference to the dialog until our subscription is destroyed. See
+ * the subscription_destructor for more details
+ */
+ pjsip_dlg_inc_session(dlg, &sub_module);
+ sub->dlg = dlg;
+ ast_sip_dialog_set_serializer(dlg, sub->serializer);
+ pjsip_evsub_set_mod_data(sub->evsub, sub_module.id, sub);
+ ao2_ref(endpoint, +1);
+ sub->endpoint = endpoint;
+ sub->handler = handler;
+ return sub;
+}
+
+struct ast_sip_endpoint *ast_sip_subscription_get_endpoint(struct ast_sip_subscription *sub)
+{
+ ast_assert(sub->endpoint != NULL);
+ ao2_ref(sub->endpoint, +1);
+ return sub->endpoint;
+}
+
+struct ast_taskprocessor *ast_sip_subscription_get_serializer(struct ast_sip_subscription *sub)
+{
+ ast_assert(sub->serializer != NULL);
+ return sub->serializer;
+}
+
+pjsip_evsub *ast_sip_subscription_get_evsub(struct ast_sip_subscription *sub)
+{
+ return sub->evsub;
+}
+
+int ast_sip_subscription_send_request(struct ast_sip_subscription *sub, pjsip_tx_data *tdata)
+{
+ return pjsip_evsub_send_request(ast_sip_subscription_get_evsub(sub),
+ tdata) == PJ_SUCCESS ? 0 : -1;
+}
+
+static void subscription_datastore_destroy(void *obj)
+{
+ struct ast_datastore *datastore = obj;
+
+ /* Using the destroy function (if present) destroy the data */
+ if (datastore->info->destroy != NULL && datastore->data != NULL) {
+ datastore->info->destroy(datastore->data);
+ datastore->data = NULL;
+ }
+
+ ast_free((void *) datastore->uid);
+ datastore->uid = NULL;
+}
+
+struct ast_datastore *ast_sip_subscription_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
+{
+ RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
+ const char *uid_ptr = uid;
+
+ if (!info) {
+ return NULL;
+ }
+
+ datastore = ao2_alloc(sizeof(*datastore), subscription_datastore_destroy);
+ if (!datastore) {
+ return NULL;
+ }
+
+ datastore->info = info;
+ if (ast_strlen_zero(uid)) {
+ /* They didn't provide an ID so we'll provide one ourself */
+ struct ast_uuid *uuid = ast_uuid_generate();
+ char uuid_buf[AST_UUID_STR_LEN];
+ if (!uuid) {
+ return NULL;
+ }
+ uid_ptr = ast_uuid_to_str(uuid, uuid_buf, sizeof(uuid_buf));
+ ast_free(uuid);
+ }
+
+ datastore->uid = ast_strdup(uid_ptr);
+ if (!datastore->uid) {
+ return NULL;
+ }
+
+ ao2_ref(datastore, +1);
+ return datastore;
+}
+
+int ast_sip_subscription_add_datastore(struct ast_sip_subscription *subscription, struct ast_datastore *datastore)
+{
+ ast_assert(datastore != NULL);
+ ast_assert(datastore->info != NULL);
+ ast_assert(ast_strlen_zero(datastore->uid) == 0);
+
+ if (!ao2_link(subscription->datastores, datastore)) {
+ return -1;
+ }
+ return 0;
+}
+
+struct ast_datastore *ast_sip_subscription_get_datastore(struct ast_sip_subscription *subscription, const char *name)
+{
+ return ao2_find(subscription->datastores, name, OBJ_KEY);
+}
+
+void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name)
+{
+ ao2_callback(subscription->datastores, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, NULL, (void *) name);
+}
+
+AST_RWLIST_HEAD_STATIC(subscription_handlers, ast_sip_subscription_handler);
+
+static void add_handler(struct ast_sip_subscription_handler *handler)
+{
+ SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+ AST_RWLIST_INSERT_TAIL(&subscription_handlers, handler, next);
+ ast_module_ref(ast_module_info->self);
+}
+
+static int handler_exists_for_event_name(const char *event_name)
+{
+ struct ast_sip_subscription_handler *iter;
+ SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
+
+ AST_RWLIST_TRAVERSE(&subscription_handlers, iter, next) {
+ if (!strcmp(iter->event_name, event_name)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *handler)
+{
+ pj_str_t event;
+ pj_str_t accept[AST_SIP_MAX_ACCEPT];
+ int i;
+
+ if (ast_strlen_zero(handler->event_name)) {
+ ast_log(LOG_ERROR, "No event package specifief for subscription handler. Cannot register\n");
+ return -1;
+ }
+
+ if (ast_strlen_zero(handler->accept[0])) {
+ ast_log(LOG_ERROR, "Subscription handler must supply at least one 'Accept' format\n");
+ return -1;
+ }
+
+ if (handler_exists_for_event_name(handler->event_name)) {
+ ast_log(LOG_ERROR, "A subscription handler for event %s already exists. Not registering "
+ "new subscription handler\n", handler->event_name);
+ return -1;
+ }
+
+ pj_cstr(&event, handler->event_name);
+ for (i = 0; i < AST_SIP_MAX_ACCEPT && !ast_strlen_zero(handler->accept[i]); ++i) {
+ pj_cstr(&accept[i], handler->accept[i]);
+ }
+
+ if (!strcmp(handler->event_name, "message-summary")) {
+ pjsip_mwi_init_module(ast_sip_get_pjsip_endpoint(), pjsip_evsub_instance());
+ } else if (!strcmp(handler->event_name, "presence")) {
+ pjsip_pres_init_module(ast_sip_get_pjsip_endpoint(), pjsip_evsub_instance());
+ } else {
+ pjsip_evsub_register_pkg(&sub_module, &event, DEFAULT_EXPIRES, i, accept);
+ }
+
+ add_handler(handler);
+ return 0;
+}
+
+void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler *handler)
+{
+ struct ast_sip_subscription_handler *iter;
+ SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&subscription_handlers, iter, next) {
+ if (handler == iter) {
+ AST_RWLIST_REMOVE_CURRENT(next);
+ ast_module_unref(ast_module_info->self);
+ break;
+ }
+ }
+ AST_RWLIST_TRAVERSE_SAFE_END;
+}
+
+static struct ast_sip_subscription_handler *find_handler(const char *event, char accept[AST_SIP_MAX_ACCEPT][64], size_t num_accept)
+{
+ struct ast_sip_subscription_handler *iter;
+ int match = 0;
+ SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
+ AST_RWLIST_TRAVERSE(&subscription_handlers, iter, next) {
+ int i;
+ int j;
+ if (strcmp(event, iter->event_name)) {
+ ast_debug(3, "Event %s does not match %s\n", event, iter->event_name);
+ continue;
+ }
+ ast_debug(3, "Event name match: %s = %s\n", event, iter->event_name);
+ for (i = 0; i < num_accept; ++i) {
+ for (j = 0; j < num_accept; ++j) {
+ if (ast_strlen_zero(iter->accept[i])) {
+ ast_debug(3, "Breaking because subscription handler has run out of 'accept' types\n");
+ break;
+ }
+ if (!strcmp(accept[j], iter->accept[i])) {
+ ast_debug(3, "Accept headers match: %s = %s\n", accept[j], iter->accept[i]);
+ match = 1;
+ break;
+ }
+ ast_debug(3, "Accept %s does not match %s\n", accept[j], iter->accept[i]);
+ }
+ if (match) {
+ break;
+ }
+ }
+ if (match) {
+ break;
+ }
+ }
+
+ return iter;
+}
+
+static pj_bool_t sub_on_rx_request(pjsip_rx_data *rdata)
+{
+ static const pj_str_t event_name = { "Event", 5 };
+ char event[32];
+ char accept[AST_SIP_MAX_ACCEPT][64];
+ pjsip_accept_hdr *accept_header;
+ pjsip_event_hdr *event_header;
+ struct ast_sip_subscription_handler *handler;
+ RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
+ struct ast_sip_subscription *sub;
+ int i;
+
+ if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) {
+ return PJ_FALSE;
+ }
+
+ endpoint = ast_pjsip_rdata_get_endpoint(rdata);
+ ast_assert(endpoint != NULL);
+
+ event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &event_name, rdata->msg_info.msg->hdr.next);
+ if (!event_header) {
+ ast_log(LOG_WARNING, "Incoming SUBSCRIBE request with no Event header\n");
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
+ return PJ_TRUE;
+ }
+
+ accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, rdata->msg_info.msg->hdr.next);
+ if (!accept_header) {
+ ast_log(LOG_WARNING, "Incoming SUBSCRIBE request with no Accept header\n");
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
+ return PJ_TRUE;
+ }
+
+ ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
+ for (i = 0; i < accept_header->count; ++i) {
+ ast_copy_pj_str(accept[i], &accept_header->values[i], sizeof(accept[i]));
+ }
+
+ handler = find_handler(event, accept, accept_header->count);
+ if (!handler) {
+ ast_log(LOG_WARNING, "No registered handler for event %s\n", event);
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
+ return PJ_TRUE;
+ }
+ sub = handler->new_subscribe(endpoint, rdata);
+ if (!sub) {
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
+ }
+ return PJ_TRUE;
+}
+
+static void pubsub_on_evsub_state(pjsip_evsub *evsub, pjsip_event *event)
+{
+ struct ast_sip_subscription *sub;
+ if (pjsip_evsub_get_state(evsub) != PJSIP_EVSUB_STATE_TERMINATED) {
+ return;
+ }
+
+ sub = pjsip_evsub_get_mod_data(evsub, sub_module.id);
+ if (!sub) {
+ return;
+ }
+
+ if (event->type == PJSIP_EVENT_RX_MSG) {
+ sub->handler->subscription_terminated(sub, event->body.rx_msg.rdata);
+ }
+
+ if (event->type == PJSIP_EVENT_TSX_STATE &&
+ event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
+ sub->handler->subscription_terminated(sub, event->body.tsx_state.src.rdata);
+ }
+
+ if (sub->handler->subscription_shutdown) {
+ sub->handler->subscription_shutdown(sub);
+ }
+ pjsip_evsub_set_mod_data(evsub, sub_module.id, NULL);
+}
+
+static void pubsub_on_tsx_state(pjsip_evsub *evsub, pjsip_transaction *tsx, pjsip_event *event)
+{
+ struct ast_sip_subscription *sub = pjsip_evsub_get_mod_data(evsub, sub_module.id);
+
+ if (!sub) {
+ return;
+ }
+
+ if (tsx->role == PJSIP_ROLE_UAC && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
+ sub->handler->notify_response(sub, event->body.tsx_state.src.rdata);
+ }
+}
+
+static void set_parameters_from_response_data(pj_pool_t *pool, int *p_st_code,
+ pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body,
+ struct ast_sip_subscription_response_data *response_data)
+{
+ ast_assert(response_data->status_code >= 200 && response_data->status_code <= 699);
+ *p_st_code = response_data->status_code;
+
+ if (!ast_strlen_zero(response_data->status_text)) {
+ pj_strdup2(pool, *p_st_text, response_data->status_text);
+ }
+
+ if (response_data->headers) {
+ struct ast_variable *iter;
+ for (iter = response_data->headers; iter; iter = iter->next) {
+ pj_str_t header_name;
+ pj_str_t header_value;
+ pjsip_generic_string_hdr *hdr;
+
+ pj_cstr(&header_name, iter->name);
+ pj_cstr(&header_value, iter->value);
+ hdr = pjsip_generic_string_hdr_create(pool, &header_name, &header_value);
+ pj_list_insert_before(res_hdr, hdr);
+ }
+ }
+
+ if (response_data->body) {
+ pj_str_t type;
+ pj_str_t subtype;
+ pj_str_t body_text;
+
+ pj_cstr(&type, response_data->body->type);
+ pj_cstr(&subtype, response_data->body->subtype);
+ pj_cstr(&body_text, response_data->body->body_text);
+
+ *p_body = pjsip_msg_body_create(pool, &type, &subtype, &body_text);
+ }
+}
+
+static int response_data_changed(struct ast_sip_subscription_response_data *response_data)
+{
+ if (response_data->status_code != 200 ||
+ !ast_strlen_zero(response_data->status_text) ||
+ response_data->headers ||
+ response_data->body) {
+ return 1;
+ }
+ return 0;
+}
+
+static void pubsub_on_rx_refresh(pjsip_evsub *evsub, pjsip_rx_data *rdata,
+ int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
+{
+ struct ast_sip_subscription *sub = pjsip_evsub_get_mod_data(evsub, sub_module.id);
+ struct ast_sip_subscription_response_data response_data = {
+ .status_code = 200,
+ };
+
+ if (!sub) {
+ return;
+ }
+
+ sub->handler->resubscribe(sub, rdata, &response_data);
+
+ if (!response_data_changed(&response_data)) {
+ return;
+ }
+
+ set_parameters_from_response_data(rdata->tp_info.pool, p_st_code, p_st_text,
+ res_hdr, p_body, &response_data);
+}
+
+static void pubsub_on_rx_notify(pjsip_evsub *evsub, pjsip_rx_data *rdata, int *p_st_code,
+ pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
+{
+ struct ast_sip_subscription *sub = pjsip_evsub_get_mod_data(evsub, sub_module.id);
+ struct ast_sip_subscription_response_data response_data = {
+ .status_code = 200,
+ };
+
+ if (!sub|| !sub->handler->notify_request) {
+ return;
+ }
+
+ sub->handler->notify_request(sub, rdata, &response_data);
+
+ if (!response_data_changed(&response_data)) {
+ return;
+ }
+
+ set_parameters_from_response_data(rdata->tp_info.pool, p_st_code, p_st_text,
+ res_hdr, p_body, &response_data);
+}
+
+static int serialized_pubsub_on_client_refresh(void *userdata)
+{
+ struct ast_sip_subscription *sub = userdata;
+
+ sub->handler->refresh_subscription(sub);
+ ao2_cleanup(sub);
+ return 0;
+}
+
+static void pubsub_on_client_refresh(pjsip_evsub *evsub)
+{
+ struct ast_sip_subscription *sub = pjsip_evsub_get_mod_data(evsub, sub_module.id);
+
+ ao2_ref(sub, +1);
+ ast_sip_push_task(sub->serializer, serialized_pubsub_on_client_refresh, sub);
+}
+
+static int serialized_pubsub_on_server_timeout(void *userdata)
+{
+ struct ast_sip_subscription *sub = userdata;
+
+ sub->handler->subscription_timeout(sub);
+ ao2_cleanup(sub);
+ return 0;
+}
+
+static void pubsub_on_server_timeout(pjsip_evsub *evsub)
+{
+ struct ast_sip_subscription *sub = pjsip_evsub_get_mod_data(evsub, sub_module.id);
+
+ ao2_ref(sub, +1);
+ ast_sip_push_task(sub->serializer, serialized_pubsub_on_server_timeout, sub);
+}
+
+static int load_module(void)
+{
+ pjsip_evsub_init_module(ast_sip_get_pjsip_endpoint());
+ if (ast_sip_register_service(&sub_module)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "SIP event resource",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_CHANNEL_DEPEND,
+);
diff --git a/res/res_sip_pubsub.exports.in b/res/res_sip_pubsub.exports.in
new file mode 100644
index 000000000..55308746a
--- /dev/null
+++ b/res/res_sip_pubsub.exports.in
@@ -0,0 +1,16 @@
+{
+ global:
+ LINKER_SYMBOL_PREFIXast_sip_create_subscription;
+ LINKER_SYMBOL_PREFIXast_sip_subsription_get_endpoint;
+ LINKER_SYMBOL_PREFIXast_sip_subscription_get_serializer;
+ LINKER_SYMBOL_PREFIXast_sip_subscription_get_evsub;
+ LINKER_SYMBOL_PREFIXast_sip_subscription_send_request;
+ LINKER_SYMBOL_PREFIXast_sip_subscription_alloc_datastore;
+ LINKER_SYMBOL_PREFIXast_sip_subscription_add_datastore;
+ LINKER_SYMBOL_PREFIXast_sip_subscription_get_datastore;
+ LINKER_SYMBOL_PREFIXast_sip_subscription_remove_datastore;
+ LINKER_SYMBOL_PREFIXast_sip_register_subscription_handler;
+ LINKER_SYMBOL_PREFIXast_sip_unregister_subscription_handler;
+ local:
+ *;
+};
diff --git a/res/res_sip_registrar.c b/res/res_sip_registrar.c
new file mode 100644
index 000000000..e5a2e888b
--- /dev/null
+++ b/res/res_sip_registrar.c
@@ -0,0 +1,382 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Joshua Colp <jcolp@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_ua.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/module.h"
+
+/*! \brief Internal function which returns the expiration time for a contact */
+static int registrar_get_expiration(const struct ast_sip_aor *aor, const pjsip_contact_hdr *contact, const pjsip_rx_data *rdata)
+{
+ pjsip_expires_hdr *expires;
+ int expiration = aor->default_expiration;
+
+ if (contact->expires != -1) {
+ /* Expiration was provided with the contact itself */
+ expiration = contact->expires;
+ } else if ((expires = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
+ /* Expiration was provided using the Expires header */
+ expiration = expires->ivalue;
+ }
+
+ /* If the value has explicitly been set to 0, do not enforce */
+ if (!expiration) {
+ return expiration;
+ }
+
+ /* Enforce the range that we will allow for expiration */
+ if (expiration < aor->minimum_expiration) {
+ expiration = aor->minimum_expiration;
+ } else if (expiration > aor->maximum_expiration) {
+ expiration = aor->maximum_expiration;
+ }
+
+ return expiration;
+}
+
+/*! \brief Structure used for finding contact */
+struct registrar_contact_details {
+ /*! \brief Pool used for parsing URI */
+ pj_pool_t *pool;
+ /*! \brief URI being looked for */
+ pjsip_uri *uri;
+};
+
+/*! \brief Callback function for finding a contact */
+static int registrar_find_contact(void *obj, void *arg, int flags)
+{
+ struct ast_sip_contact *contact = obj;
+ const struct registrar_contact_details *details = arg;
+ pjsip_uri *contact_uri = pjsip_parse_uri(details->pool, (char*)contact->uri, strlen(contact->uri), 0);
+
+ return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->uri, contact_uri) == PJ_SUCCESS) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+/*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */
+static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_container *contacts, struct ast_sip_aor *aor, int *added, int *updated, int *deleted)
+{
+ pjsip_contact_hdr *previous = NULL, *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
+ struct registrar_contact_details details = {
+ .pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256),
+ };
+
+ if (!details.pool) {
+ return -1;
+ }
+
+ while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) {
+ int expiration;
+ RAII_VAR(struct ast_sip_contact *, existing, NULL, ao2_cleanup);
+
+ if (contact->star) {
+ /* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
+ if ((contact->expires != 0) || previous) {
+ pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
+ return -1;
+ }
+ } else if (previous && previous->star) {
+ /* If there is a previous contact and it is a '*' this is a deal breaker */
+ pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
+ return -1;
+ }
+ previous = contact;
+
+ if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
+ continue;
+ }
+
+ details.uri = pjsip_uri_get_uri(contact->uri);
+ expiration = registrar_get_expiration(aor, contact, rdata);
+
+ /* Determine if this is an add, update, or delete for policy enforcement purposes */
+ if (!(existing = ao2_callback(contacts, 0, registrar_find_contact, &details))) {
+ if (expiration) {
+ (*added)++;
+ }
+ } else if (expiration) {
+ (*updated)++;
+ } else {
+ (*deleted)++;
+ }
+ }
+
+ /* The provided contacts are acceptable, huzzah! */
+ pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
+ return 0;
+}
+
+/*! \brief Callback function which prunes static contacts */
+static int registrar_prune_static(void *obj, void *arg, int flags)
+{
+ struct ast_sip_contact *contact = obj;
+
+ return ast_tvzero(contact->expiration_time) ? CMP_MATCH : 0;
+}
+
+/*! \brief Internal function used to delete all contacts from an AOR */
+static int registrar_delete_contact(void *obj, void *arg, int flags)
+{
+ struct ast_sip_contact *contact = obj;
+
+ ast_sip_location_delete_contact(contact);
+
+ return 0;
+}
+
+/*! \brief Internal function which adds a contact to a response */
+static int registrar_add_contact(void *obj, void *arg, int flags)
+{
+ struct ast_sip_contact *contact = obj;
+ pjsip_tx_data *tdata = arg;
+ pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool);
+ pj_str_t uri;
+
+ pj_strdup2_with_null(tdata->pool, &uri, contact->uri);
+ hdr->uri = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
+ hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000;
+
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
+
+ return 0;
+}
+
+/*! \brief Helper function which adds a Date header to a response */
+static void registrar_add_date_header(pjsip_tx_data *tdata)
+{
+ char date[256];
+ struct tm tm;
+ time_t t = time(NULL);
+
+ gmtime_r(&t, &tm);
+ strftime(date, sizeof(date), "%a, %d %b %Y %T GMT", &tm);
+
+ ast_sip_add_header(tdata, "Date", date);
+}
+
+static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
+{
+ struct ast_sip_endpoint *endpoint = ast_pjsip_rdata_get_endpoint(rdata);
+ pjsip_sip_uri *uri;
+ char user_name[64], domain_name[64];
+ char *configured_aors, *aor_name;
+ RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
+ RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
+ int added = 0, updated = 0, deleted = 0;
+ pjsip_contact_hdr *contact_hdr = NULL;
+ struct registrar_contact_details details = { 0, };
+ pjsip_tx_data *tdata;
+ pjsip_response_addr addr;
+
+ if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
+ return PJ_FALSE;
+ }
+
+ if (ast_strlen_zero(endpoint->aors)) {
+ /* Short circuit early if the endpoint has no AORs configured on it, which means no registration possible */
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
+ return PJ_TRUE;
+ }
+
+ if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
+ return PJ_TRUE;
+ }
+
+ uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
+ ast_copy_pj_str(user_name, &uri->user, sizeof(user_name));
+ ast_copy_pj_str(domain_name, &uri->host, sizeof(domain_name));
+
+ configured_aors = ast_strdupa(endpoint->aors);
+
+ /* Iterate the configured AORs to see if the user or the user+domain match */
+ while ((aor_name = strsep(&configured_aors, ","))) {
+ char id[AST_UUID_STR_LEN];
+ RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup);
+
+ snprintf(id, sizeof(id), "%s@%s", user_name, domain_name);
+ if (!strcmp(aor_name, id)) {
+ break;
+ }
+
+ if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
+ snprintf(id, sizeof(id), "%s@%s", user_name, alias->domain);
+ if (!strcmp(aor_name, id)) {
+ break;
+ }
+ }
+
+ if (!strcmp(aor_name, user_name)) {
+ break;
+ }
+ }
+
+ if (ast_strlen_zero(aor_name) || !(aor = ast_sip_location_retrieve_aor(aor_name))) {
+ /* The provided AOR name was not found (be it within the configuration or sorcery itself) */
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
+ return PJ_TRUE;
+ }
+
+ if (!aor->max_contacts) {
+ /* Registration is not permitted for this AOR */
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
+ return PJ_TRUE;
+ }
+
+ /* Retrieve the current contacts, we'll need to know whether to update or not */
+ contacts = ast_sip_location_retrieve_aor_contacts(aor);
+
+ /* So we don't count static contacts against max_contacts we prune them out from the container */
+ ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL);
+
+ if (registrar_validate_contacts(rdata, contacts, aor, &added, &updated, &deleted)) {
+ /* The provided Contact headers do not conform to the specification */
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
+ return PJ_TRUE;
+ }
+
+ if (((added - deleted) + (!aor->remove_existing ? ao2_container_count(contacts) : 0)) > aor->max_contacts) {
+ /* Enforce the maximum number of contacts */
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
+ return PJ_TRUE;
+ }
+
+ if (!(details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256))) {
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
+ return PJ_TRUE;
+ }
+
+ /* Iterate each provided Contact header and add, update, or delete */
+ while ((contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) {
+ int expiration;
+ char contact_uri[PJSIP_MAX_URL_SIZE];
+ RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
+
+ if (contact_hdr->star) {
+ /* A star means to unregister everything, so do so for the possible contacts */
+ ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL);
+ break;
+ }
+
+ if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) {
+ /* This registrar only currently supports sip: and sips: URI schemes */
+ continue;
+ }
+
+ expiration = registrar_get_expiration(aor, contact_hdr, rdata);
+ details.uri = pjsip_uri_get_uri(contact_hdr->uri);
+ pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));
+
+ if (!(contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details))) {
+ /* If they are actually trying to delete a contact that does not exist... be forgiving */
+ if (!expiration) {
+ ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n",
+ contact_uri, aor_name);
+ continue;
+ }
+
+ ast_sip_location_add_contact(aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)));
+ ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
+ contact_uri, aor_name, expiration);
+ } else if (expiration) {
+ RAII_VAR(struct ast_sip_contact *, updated, ast_sorcery_copy(ast_sip_get_sorcery(), contact), ao2_cleanup);
+
+ updated->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
+
+ ast_sip_location_update_contact(updated);
+ ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
+ contact_uri, aor_name, expiration);
+ } else {
+ ast_sip_location_delete_contact(contact);
+ ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name);
+ }
+ }
+
+ pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
+
+ /* If the AOR is configured to remove any existing contacts that have not been updated/added as a result of this REGISTER
+ * do so
+ */
+ if (aor->remove_existing) {
+ ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL);
+ }
+
+ /* Update the contacts as things will probably have changed */
+ ao2_cleanup(contacts);
+ contacts = ast_sip_location_retrieve_aor_contacts(aor);
+
+ /* Send a response containing all of the contacts (including static) that are present on this AOR */
+ if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, 200, NULL, &tdata) != PJ_SUCCESS) {
+ return PJ_TRUE;
+ }
+
+ /* Add the date header to the response, some UAs use this to set their date and time */
+ registrar_add_date_header(tdata);
+
+ ao2_callback(contacts, 0, registrar_add_contact, tdata);
+
+ if (pjsip_get_response_addr(tdata->pool, rdata, &addr) == PJ_SUCCESS) {
+ pjsip_endpt_send_response(ast_sip_get_pjsip_endpoint(), &addr, tdata, NULL, NULL);
+ } else {
+ pjsip_tx_data_dec_ref(tdata);
+ }
+
+ return PJ_TRUE;
+}
+
+static pjsip_module registrar_module = {
+ .name = { "Registrar", 9 },
+ .id = -1,
+ .priority = PJSIP_MOD_PRIORITY_APPLICATION,
+ .on_rx_request = registrar_on_rx_request,
+};
+
+static int load_module(void)
+{
+ const pj_str_t STR_REGISTER = { "REGISTER", 8 };
+
+ if (ast_sip_register_service(&registrar_module)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &STR_REGISTER) != PJ_SUCCESS) {
+ ast_sip_unregister_service(&registrar_module);
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ ast_sip_unregister_service(&registrar_module);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP Registrar Support",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_APP_DEPEND,
+ );
diff --git a/res/res_sip_rfc3326.c b/res/res_sip_rfc3326.c
new file mode 100644
index 000000000..1c9ec6154
--- /dev/null
+++ b/res/res_sip_rfc3326.c
@@ -0,0 +1,145 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Joshua Colp <jcolp@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_ua.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/res_sip_session.h"
+#include "asterisk/module.h"
+#include "asterisk/causes.h"
+
+static void rfc3326_use_reason_header(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
+{
+ const pj_str_t str_reason = { "Reason", 6 };
+ pjsip_generic_string_hdr *header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_reason, NULL);
+ char buf[20], *cause, *text;
+ int code;
+
+ if (!header) {
+ return;
+ }
+
+ ast_copy_pj_str(buf, &header->hvalue, sizeof(buf));
+ cause = ast_skip_blanks(buf);
+
+ if (strncasecmp(cause, "Q.850", 5) || !(cause = strstr(cause, "cause="))) {
+ return;
+ }
+
+ /* If text is present get rid of it */
+ if ((text = strstr(cause, ";"))) {
+ *text = '\0';
+ }
+
+ if (sscanf(cause, "cause=%30d", &code) != 1) {
+ return;
+ }
+
+ ast_channel_hangupcause_set(session->channel, code & 0x7f);
+}
+
+static int rfc3326_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
+{
+ if ((pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_bye_method) &&
+ pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_cancel_method)) ||
+ !session->channel) {
+ return 0;
+ }
+
+ rfc3326_use_reason_header(session, rdata);
+
+ return 0;
+}
+
+static void rfc3326_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
+{
+ struct pjsip_status_line status = rdata->msg_info.msg->line.status;
+
+ if ((status.code < 300) || !session->channel) {
+ return;
+ }
+
+ rfc3326_use_reason_header(session, rdata);
+}
+
+static void rfc3326_add_reason_header(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
+{
+ char buf[20];
+
+ snprintf(buf, sizeof(buf), "Q.850;cause=%i", ast_channel_hangupcause(session->channel) & 0x7f);
+ ast_sip_add_header(tdata, "Reason", buf);
+
+ if (ast_channel_hangupcause(session->channel) == AST_CAUSE_ANSWERED_ELSEWHERE) {
+ ast_sip_add_header(tdata, "Reason", "SIP;cause=200;text=\"Call completed elsewhere\"");
+ }
+}
+
+static void rfc3326_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
+{
+ if ((pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_bye_method) &&
+ pjsip_method_cmp(&tdata->msg->line.req.method, &pjsip_cancel_method)) ||
+ !session->channel) {
+ return;
+ }
+
+ rfc3326_add_reason_header(session, tdata);
+}
+
+static void rfc3326_outgoing_response(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
+{
+ struct pjsip_status_line status = tdata->msg->line.status;
+
+ if ((status.code < 300) || !session->channel) {
+ return;
+ }
+
+ rfc3326_add_reason_header(session, tdata);
+}
+
+static struct ast_sip_session_supplement rfc3326_supplement = {
+ .incoming_request = rfc3326_incoming_request,
+ .incoming_response = rfc3326_incoming_response,
+ .outgoing_request = rfc3326_outgoing_request,
+ .outgoing_response = rfc3326_outgoing_response,
+};
+
+static int load_module(void)
+{
+ ast_sip_session_register_supplement(&rfc3326_supplement);
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ ast_sip_session_unregister_supplement(&rfc3326_supplement);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP RFC3326 Support",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_APP_DEPEND,
+ );
diff --git a/res/res_sip_sdp_rtp.c b/res/res_sip_sdp_rtp.c
new file mode 100644
index 000000000..13e6aa1aa
--- /dev/null
+++ b/res/res_sip_sdp_rtp.c
@@ -0,0 +1,848 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Joshua Colp <jcolp@digium.com>
+ * Kevin Harwell <kharwell@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \author Joshua Colp <jcolp@digium.com>
+ *
+ * \brief SIP SDP media stream handling
+ */
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <depend>res_sip</depend>
+ <depend>res_sip_session</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_ua.h>
+#include <pjmedia.h>
+#include <pjlib.h>
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/module.h"
+#include "asterisk/rtp_engine.h"
+#include "asterisk/netsock2.h"
+#include "asterisk/channel.h"
+#include "asterisk/causes.h"
+#include "asterisk/sched.h"
+#include "asterisk/acl.h"
+
+#include "asterisk/res_sip.h"
+#include "asterisk/res_sip_session.h"
+
+/*! \brief Scheduler for RTCP purposes */
+static struct ast_sched_context *sched;
+
+/*! \brief Address for IPv4 RTP */
+static struct ast_sockaddr address_ipv4;
+
+/*! \brief Address for IPv6 RTP */
+static struct ast_sockaddr address_ipv6;
+
+static const char STR_AUDIO[] = "audio";
+static const int FD_AUDIO = 0;
+
+static const char STR_VIDEO[] = "video";
+static const int FD_VIDEO = 2;
+
+/*! \brief Retrieves an ast_format_type based on the given stream_type */
+static enum ast_format_type stream_to_media_type(const char *stream_type)
+{
+ if (!strcasecmp(stream_type, STR_AUDIO)) {
+ return AST_FORMAT_TYPE_AUDIO;
+ } else if (!strcasecmp(stream_type, STR_VIDEO)) {
+ return AST_FORMAT_TYPE_VIDEO;
+ }
+
+ return 0;
+}
+
+/*! \brief Get the starting descriptor for a media type */
+static int media_type_to_fdno(enum ast_format_type media_type)
+{
+ switch (media_type) {
+ case AST_FORMAT_TYPE_AUDIO: return FD_AUDIO;
+ case AST_FORMAT_TYPE_VIDEO: return FD_VIDEO;
+ case AST_FORMAT_TYPE_TEXT:
+ case AST_FORMAT_TYPE_IMAGE: break;
+ }
+ return -1;
+}
+
+/*! \brief Remove all other cap types but the one given */
+static void format_cap_only_type(struct ast_format_cap *caps, enum ast_format_type media_type)
+{
+ int i = AST_FORMAT_INC;
+ while (i <= AST_FORMAT_TYPE_TEXT) {
+ if (i != media_type) {
+ ast_format_cap_remove_bytype(caps, i);
+ }
+ i += AST_FORMAT_INC;
+ }
+}
+
+/*! \brief Internal function which creates an RTP instance */
+static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_media *session_media, unsigned int ipv6)
+{
+ struct ast_rtp_engine_ice *ice;
+
+ if (!(session_media->rtp = ast_rtp_instance_new("asterisk", sched, ipv6 ? &address_ipv6 : &address_ipv4, NULL))) {
+ return -1;
+ }
+
+ ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RTCP, 1);
+ ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_NAT, session->endpoint->rtp_symmetric);
+
+ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session_media->rtp),
+ session_media->rtp, &session->endpoint->prefs);
+
+ if (!session->endpoint->ice_support && (ice = ast_rtp_instance_get_ice(session_media->rtp))) {
+ ice->stop(session_media->rtp);
+ }
+
+ return 0;
+}
+
+static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp_media *stream, struct ast_rtp_codecs *codecs)
+{
+ pjmedia_sdp_attr *attr;
+ pjmedia_sdp_rtpmap *rtpmap;
+ pjmedia_sdp_fmtp fmtp;
+ struct ast_format *format;
+ int i, num = 0;
+ char name[256];
+ char media[20];
+ char fmt_param[256];
+
+ ast_rtp_codecs_payloads_initialize(codecs);
+
+ /* Iterate through provided formats */
+ for (i = 0; i < stream->desc.fmt_count; ++i) {
+ /* The payload is kept as a string for things like t38 but for video it is always numerical */
+ ast_rtp_codecs_payloads_set_m_type(codecs, NULL, pj_strtoul(&stream->desc.fmt[i]));
+ /* Look for the optional rtpmap attribute */
+ if (!(attr = pjmedia_sdp_media_find_attr2(stream, "rtpmap", &stream->desc.fmt[i]))) {
+ continue;
+ }
+
+ /* Interpret the attribute as an rtpmap */
+ if ((pjmedia_sdp_attr_to_rtpmap(session->inv_session->pool_prov, attr, &rtpmap)) != PJ_SUCCESS) {
+ continue;
+ }
+
+ ast_copy_pj_str(name, &rtpmap->enc_name, sizeof(name));
+ ast_copy_pj_str(media, (pj_str_t*)&stream->desc.media, sizeof(media));
+ ast_rtp_codecs_payloads_set_rtpmap_type_rate(codecs, NULL, pj_strtoul(&stream->desc.fmt[i]),
+ media, name, 0, rtpmap->clock_rate);
+ /* Look for an optional associated fmtp attribute */
+ if (!(attr = pjmedia_sdp_media_find_attr2(stream, "fmtp", &rtpmap->pt))) {
+ continue;
+ }
+
+ if ((pjmedia_sdp_attr_get_fmtp(attr, &fmtp)) == PJ_SUCCESS) {
+ sscanf(pj_strbuf(&fmtp.fmt), "%d", &num);
+ if ((format = ast_rtp_codecs_get_payload_format(codecs, num))) {
+ ast_copy_pj_str(fmt_param, &fmtp.fmt_param, sizeof(fmt_param));
+ ast_format_sdp_parse(format, fmt_param);
+ }
+ }
+ }
+}
+
+static int set_caps(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
+ const struct pjmedia_sdp_media *stream)
+{
+ RAII_VAR(struct ast_format_cap *, caps, NULL, ast_format_cap_destroy);
+ RAII_VAR(struct ast_format_cap *, peer, NULL, ast_format_cap_destroy);
+ RAII_VAR(struct ast_format_cap *, joint, NULL, ast_format_cap_destroy);
+ enum ast_format_type media_type = stream_to_media_type(session_media->stream_type);
+ struct ast_rtp_codecs codecs;
+ struct ast_format fmt;
+ int fmts = 0;
+ int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
+ !ast_format_cap_is_empty(session->direct_media_cap);
+
+ if (!(caps = ast_format_cap_alloc_nolock()) ||
+ !(peer = ast_format_cap_alloc_nolock())) {
+ ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", session_media->stream_type);
+ return -1;
+ }
+
+ /* get the endpoint capabilities */
+ if (direct_media_enabled) {
+ ast_format_cap_joint_copy(session->endpoint->codecs, session->direct_media_cap, caps);
+ } else {
+ ast_format_cap_copy(caps, session->endpoint->codecs);
+ }
+ format_cap_only_type(caps, media_type);
+
+ /* get the capabilities on the peer */
+ get_codecs(session, stream, &codecs);
+ ast_rtp_codecs_payload_formats(&codecs, peer, &fmts);
+
+ /* get the joint capabilities between peer and endpoint */
+ if (!(joint = ast_format_cap_joint(caps, peer))) {
+ char usbuf[64], thembuf[64];
+
+ ast_rtp_codecs_payloads_destroy(&codecs);
+
+ ast_getformatname_multiple(usbuf, sizeof(usbuf), caps);
+ ast_getformatname_multiple(thembuf, sizeof(thembuf), peer);
+ ast_log(LOG_WARNING, "No joint capabilities between our configuration(%s) and incoming SDP(%s)\n", usbuf, thembuf);
+ return -1;
+ }
+
+ ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(session_media->rtp),
+ session_media->rtp);
+
+ ast_format_cap_copy(caps, session->req_caps);
+ ast_format_cap_remove_bytype(caps, media_type);
+ ast_format_cap_append(caps, joint);
+ ast_format_cap_append(session->req_caps, caps);
+
+ if (session->channel) {
+ ast_format_cap_copy(caps, ast_channel_nativeformats(session->channel));
+ ast_format_cap_remove_bytype(caps, media_type);
+ ast_format_cap_append(caps, joint);
+
+ /* Apply the new formats to the channel, potentially changing read/write formats while doing so */
+ ast_format_cap_append(ast_channel_nativeformats(session->channel), caps);
+ ast_codec_choose(&session->endpoint->prefs, caps, 0, &fmt);
+ ast_format_copy(ast_channel_rawwriteformat(session->channel), &fmt);
+ ast_format_copy(ast_channel_rawreadformat(session->channel), &fmt);
+ ast_set_read_format(session->channel, ast_channel_readformat(session->channel));
+ ast_set_write_format(session->channel, ast_channel_writeformat(session->channel));
+ }
+
+ ast_rtp_codecs_payloads_destroy(&codecs);
+ return 1;
+}
+
+static pjmedia_sdp_attr* generate_rtpmap_attr(pjmedia_sdp_media *media, pj_pool_t *pool, int rtp_code,
+ int asterisk_format, struct ast_format *format, int code)
+{
+ pjmedia_sdp_rtpmap rtpmap;
+ pjmedia_sdp_attr *attr = NULL;
+ char tmp[64];
+
+ snprintf(tmp, sizeof(tmp), "%d", rtp_code);
+ pj_strdup2(pool, &media->desc.fmt[media->desc.fmt_count++], tmp);
+ rtpmap.pt = media->desc.fmt[media->desc.fmt_count - 1];
+ rtpmap.clock_rate = ast_rtp_lookup_sample_rate2(asterisk_format, format, code);
+ pj_strdup2(pool, &rtpmap.enc_name, ast_rtp_lookup_mime_subtype2(asterisk_format, format, code, 0));
+ rtpmap.param.slen = 0;
+
+ pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
+
+ return attr;
+}
+
+static pjmedia_sdp_attr* generate_fmtp_attr(pj_pool_t *pool, struct ast_format *format, int rtp_code)
+{
+ struct ast_str *fmtp0 = ast_str_alloca(256);
+ pj_str_t fmtp1;
+ pjmedia_sdp_attr *attr = NULL;
+ char *tmp;
+
+ ast_format_sdp_generate(format, rtp_code, &fmtp0);
+ if (ast_str_strlen(fmtp0)) {
+ tmp = ast_str_buffer(fmtp0) + ast_str_strlen(fmtp0) - 1;
+ /* remove any carriage return line feeds */
+ while (*tmp == '\r' || *tmp == '\n') --tmp;
+ *++tmp = '\0';
+ /* ast...generate gives us everything, just need value */
+ tmp = strchr(ast_str_buffer(fmtp0), ':');
+ if (tmp && tmp + 1) {
+ fmtp1 = pj_str(tmp + 1);
+ } else {
+ fmtp1 = pj_str(ast_str_buffer(fmtp0));
+ }
+ attr = pjmedia_sdp_attr_create(pool, "fmtp", &fmtp1);
+ }
+ return attr;
+}
+
+/*! \brief Function which adds ICE attributes to a media stream */
+static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
+{
+ struct ast_rtp_engine_ice *ice;
+ struct ao2_container *candidates;
+ const char *username, *password;
+ pj_str_t stmp;
+ pjmedia_sdp_attr *attr;
+ struct ao2_iterator it_candidates;
+ struct ast_rtp_engine_ice_candidate *candidate;
+
+ if (!session->endpoint->ice_support || !(ice = ast_rtp_instance_get_ice(session_media->rtp)) ||
+ !(candidates = ice->get_local_candidates(session_media->rtp))) {
+ return;
+ }
+
+ if ((username = ice->get_ufrag(session_media->rtp))) {
+ attr = pjmedia_sdp_attr_create(pool, "ice-ufrag", pj_cstr(&stmp, username));
+ media->attr[media->attr_count++] = attr;
+ }
+
+ if ((password = ice->get_password(session_media->rtp))) {
+ attr = pjmedia_sdp_attr_create(pool, "ice-pwd", pj_cstr(&stmp, password));
+ media->attr[media->attr_count++] = attr;
+ }
+
+ it_candidates = ao2_iterator_init(candidates, 0);
+ for (; (candidate = ao2_iterator_next(&it_candidates)); ao2_ref(candidate, -1)) {
+ struct ast_str *attr_candidate = ast_str_create(128);
+
+ ast_str_set(&attr_candidate, -1, "%s %d %s %d %s ", candidate->foundation, candidate->id, candidate->transport,
+ candidate->priority, ast_sockaddr_stringify_host(&candidate->address));
+ ast_str_append(&attr_candidate, -1, "%s typ ", ast_sockaddr_stringify_port(&candidate->address));
+
+ switch (candidate->type) {
+ case AST_RTP_ICE_CANDIDATE_TYPE_HOST:
+ ast_str_append(&attr_candidate, -1, "host");
+ break;
+ case AST_RTP_ICE_CANDIDATE_TYPE_SRFLX:
+ ast_str_append(&attr_candidate, -1, "srflx");
+ break;
+ case AST_RTP_ICE_CANDIDATE_TYPE_RELAYED:
+ ast_str_append(&attr_candidate, -1, "relay");
+ break;
+ }
+
+ if (!ast_sockaddr_isnull(&candidate->relay_address)) {
+ ast_str_append(&attr_candidate, -1, " raddr %s rport ", ast_sockaddr_stringify_host(&candidate->relay_address));
+ ast_str_append(&attr_candidate, -1, " %s", ast_sockaddr_stringify_port(&candidate->relay_address));
+ }
+
+ attr = pjmedia_sdp_attr_create(pool, "candidate", pj_cstr(&stmp, ast_str_buffer(attr_candidate)));
+ media->attr[media->attr_count++] = attr;
+
+ ast_free(attr_candidate);
+ }
+
+ ao2_iterator_destroy(&it_candidates);
+}
+
+/*! \brief Function which processes ICE attributes in an audio stream */
+static void process_ice_attributes(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
+ const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream)
+{
+ struct ast_rtp_engine_ice *ice;
+ const pjmedia_sdp_attr *attr;
+ char attr_value[256];
+ unsigned int attr_i;
+
+ /* If ICE support is not enabled or available exit early */
+ if (!session->endpoint->ice_support || !(ice = ast_rtp_instance_get_ice(session_media->rtp))) {
+ return;
+ }
+
+ if ((attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-ufrag", NULL))) {
+ ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
+ ice->set_authentication(session_media->rtp, attr_value, NULL);
+ }
+
+ if ((attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-pwd", NULL))) {
+ ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
+ ice->set_authentication(session_media->rtp, NULL, attr_value);
+ }
+
+ if (pjmedia_sdp_media_find_attr2(remote_stream, "ice-lite", NULL)) {
+ ice->ice_lite(session_media->rtp);
+ }
+
+ /* Find all of the candidates */
+ for (attr_i = 0; attr_i < remote_stream->attr_count; ++attr_i) {
+ char foundation[32], transport[32], address[PJ_INET6_ADDRSTRLEN + 1], cand_type[6], relay_address[PJ_INET6_ADDRSTRLEN + 1] = "";
+ int port, relay_port = 0;
+ struct ast_rtp_engine_ice_candidate candidate = { 0, };
+
+ attr = remote_stream->attr[attr_i];
+
+ /* If this is not a candidate line skip it */
+ if (pj_strcmp2(&attr->name, "candidate")) {
+ continue;
+ }
+
+ ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
+
+ if (sscanf(attr_value, "%31s %30u %31s %30u %46s %30u typ %5s %*s %23s %*s %30u", foundation, &candidate.id, transport,
+ &candidate.priority, address, &port, cand_type, relay_address, &relay_port) < 7) {
+ /* Candidate did not parse properly */
+ continue;
+ }
+
+ candidate.foundation = foundation;
+ candidate.transport = transport;
+
+ ast_sockaddr_parse(&candidate.address, address, PARSE_PORT_FORBID);
+ ast_sockaddr_set_port(&candidate.address, port);
+
+ if (!strcasecmp(cand_type, "host")) {
+ candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
+ } else if (!strcasecmp(cand_type, "srflx")) {
+ candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
+ } else if (!strcasecmp(cand_type, "relay")) {
+ candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
+ } else {
+ continue;
+ }
+
+ if (!ast_strlen_zero(relay_address)) {
+ ast_sockaddr_parse(&candidate.relay_address, relay_address, PARSE_PORT_FORBID);
+ }
+
+ if (relay_port) {
+ ast_sockaddr_set_port(&candidate.relay_address, relay_port);
+ }
+
+ ice->add_remote_candidate(session_media->rtp, &candidate);
+ }
+
+ ice->start(session_media->rtp);
+}
+
+static void apply_packetization(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
+ const struct pjmedia_sdp_media *remote_stream)
+{
+ pjmedia_sdp_attr *attr;
+ pj_str_t value;
+ unsigned long framing;
+ int codec;
+ struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(session_media->rtp)->pref;
+
+ /* Apply packetization if available and configured to do so */
+ if (!session->endpoint->use_ptime || !(attr = pjmedia_sdp_media_find_attr2(remote_stream, "ptime", NULL))) {
+ return;
+ }
+
+ value = attr->value;
+ framing = pj_strtoul(pj_strltrim(&value));
+
+ for (codec = 0; codec < AST_RTP_MAX_PT; codec++) {
+ struct ast_rtp_payload_type format = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(
+ session_media->rtp), codec);
+
+ if (!format.asterisk_format) {
+ continue;
+ }
+
+ ast_codec_pref_setsize(pref, &format.format, framing);
+ }
+
+ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session_media->rtp),
+ session_media->rtp, pref);
+}
+
+/*! \brief Function which negotiates an incoming media stream */
+static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
+ const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
+{
+ char host[NI_MAXHOST];
+ RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr);
+ enum ast_format_type media_type = stream_to_media_type(session_media->stream_type);
+
+ /* If no type formats have been configured reject this stream */
+ if (!ast_format_cap_has_type(session->endpoint->codecs, media_type)) {
+ return 0;
+ }
+
+ ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
+
+ /* Ensure that the address provided is valid */
+ if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
+ /* The provided host was actually invalid so we error out this negotiation */
+ return -1;
+ }
+
+ /* Using the connection information create an appropriate RTP instance */
+ if (!session_media->rtp && create_rtp(session, session_media, ast_sockaddr_is_ipv6(addrs))) {
+ return -1;
+ }
+
+ return set_caps(session, session_media, stream);
+}
+
+/*! \brief Function which creates an outgoing stream */
+static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
+ struct pjmedia_sdp_session *sdp)
+{
+ pj_pool_t *pool = session->inv_session->pool_prov;
+ static const pj_str_t STR_IN = { "IN", 2 };
+ static const pj_str_t STR_IP4 = { "IP4", 3};
+ static const pj_str_t STR_IP6 = { "IP6", 3};
+ static const pj_str_t STR_RTP_AVP = { "RTP/AVP", 7 };
+ static const pj_str_t STR_SENDRECV = { "sendrecv", 8 };
+ pjmedia_sdp_media *media;
+ char hostip[PJ_INET6_ADDRSTRLEN+2];
+ struct ast_sockaddr addr;
+ char tmp[512];
+ pj_str_t stmp;
+ pjmedia_sdp_attr *attr;
+ int index = 0, min_packet_size = 0, noncodec = (session->endpoint->dtmf == AST_SIP_DTMF_RFC_4733) ? AST_RTP_DTMF : 0;
+ int rtp_code;
+ struct ast_format format;
+ struct ast_format compat_format;
+ RAII_VAR(struct ast_format_cap *, caps, NULL, ast_format_cap_destroy);
+ enum ast_format_type media_type = stream_to_media_type(session_media->stream_type);
+
+ int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
+ !ast_format_cap_is_empty(session->direct_media_cap);
+
+ if (!ast_format_cap_has_type(session->endpoint->codecs, media_type)) {
+ /* If no type formats are configured don't add a stream */
+ return 0;
+ } else if (!session_media->rtp && create_rtp(session, session_media, session->endpoint->rtp_ipv6)) {
+ return -1;
+ }
+
+ if (!(media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media))) ||
+ !(media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)))) {
+ return -1;
+ }
+
+ /* TODO: This should eventually support SRTP */
+ media->desc.media = pj_str(session_media->stream_type);
+ media->desc.transport = STR_RTP_AVP;
+
+ /* Add connection level details */
+ if (direct_media_enabled) {
+ ast_copy_string(hostip, ast_sockaddr_stringify_fmt(&session_media->direct_media_addr, AST_SOCKADDR_STR_ADDR), sizeof(hostip));
+ } else if (ast_strlen_zero(session->endpoint->external_media_address)) {
+ pj_sockaddr localaddr;
+
+ if (pj_gethostip(session->endpoint->rtp_ipv6 ? pj_AF_INET6() : pj_AF_INET(), &localaddr)) {
+ return -1;
+ }
+ pj_sockaddr_print(&localaddr, hostip, sizeof(hostip), 2);
+ } else {
+ ast_copy_string(hostip, session->endpoint->external_media_address, sizeof(hostip));
+ }
+
+ media->conn->net_type = STR_IN;
+ media->conn->addr_type = session->endpoint->rtp_ipv6 ? STR_IP6 : STR_IP4;
+ pj_strdup2(pool, &media->conn->addr, hostip);
+ ast_rtp_instance_get_local_address(session_media->rtp, &addr);
+ media->desc.port = direct_media_enabled ? ast_sockaddr_port(&session_media->direct_media_addr) : (pj_uint16_t) ast_sockaddr_port(&addr);
+ media->desc.port_count = 1;
+
+ /* Add ICE attributes and candidates */
+ add_ice_to_stream(session, session_media, pool, media);
+
+ if (!(caps = ast_format_cap_alloc_nolock())) {
+ ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", session_media->stream_type);
+ return -1;
+ }
+
+ if (direct_media_enabled) {
+ ast_format_cap_joint_copy(session->endpoint->codecs, session->direct_media_cap, caps);
+ } else if (ast_format_cap_is_empty(session->req_caps)) {
+ ast_format_cap_copy(caps, session->endpoint->codecs);
+ } else {
+ ast_format_cap_joint_copy(session->endpoint->codecs, session->req_caps, caps);
+ }
+
+ for (index = 0; ast_codec_pref_index(&session->endpoint->prefs, index, &format); ++index) {
+ struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(session_media->rtp)->pref;
+
+ if (AST_FORMAT_GET_TYPE(format.id) != media_type) {
+ continue;
+ }
+
+ if (!ast_format_cap_get_compatible_format(caps, &format, &compat_format)) {
+ continue;
+ }
+
+ if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp), 1, &compat_format, 0)) == -1) {
+ return -1;
+ }
+
+ if (!(attr = generate_rtpmap_attr(media, pool, rtp_code, 1, &compat_format, 0))) {
+ continue;
+ }
+
+ media->attr[media->attr_count++] = attr;
+
+ if ((attr = generate_fmtp_attr(pool, &compat_format, rtp_code))) {
+ media->attr[media->attr_count++] = attr;
+ }
+
+ if (pref && media_type != AST_FORMAT_TYPE_VIDEO) {
+ struct ast_format_list fmt = ast_codec_pref_getsize(pref, &compat_format);
+ if (fmt.cur_ms && ((fmt.cur_ms < min_packet_size) || !min_packet_size)) {
+ min_packet_size = fmt.cur_ms;
+ }
+ }
+ }
+
+ /* Add non-codec formats */
+ if (media_type != AST_FORMAT_TYPE_VIDEO) {
+ for (index = 1LL; index <= AST_RTP_MAX; index <<= 1) {
+ if (!(noncodec & index) || (rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp),
+ 0, NULL, index)) == -1) {
+ continue;
+ }
+
+ if (!(attr = generate_rtpmap_attr(media, pool, rtp_code, 0, NULL, index))) {
+ continue;
+ }
+
+ media->attr[media->attr_count++] = attr;
+
+ if (index == AST_RTP_DTMF) {
+ snprintf(tmp, sizeof(tmp), "%d 0-16", rtp_code);
+ attr = pjmedia_sdp_attr_create(pool, "fmtp", pj_cstr(&stmp, tmp));
+ media->attr[media->attr_count++] = attr;
+ }
+ }
+ }
+
+ /* If ptime is set add it as an attribute */
+ if (min_packet_size) {
+ snprintf(tmp, sizeof(tmp), "%d", min_packet_size);
+ attr = pjmedia_sdp_attr_create(pool, "ptime", pj_cstr(&stmp, tmp));
+ media->attr[media->attr_count++] = attr;
+ }
+
+ /* Add the sendrecv attribute - we purposely don't keep track because pjmedia-sdp will automatically change our offer for us */
+ attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
+ attr->name = STR_SENDRECV;
+ media->attr[media->attr_count++] = attr;
+
+ /* Add the media stream to the SDP */
+ sdp->media[sdp->media_count++] = media;
+
+ return 1;
+}
+
+static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
+ const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream,
+ const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream)
+{
+ RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr);
+ enum ast_format_type media_type = stream_to_media_type(session_media->stream_type);
+ char host[NI_MAXHOST];
+ int fdno;
+
+ if (!session->channel) {
+ return 1;
+ }
+
+ /* Create an RTP instance if need be */
+ if (!session_media->rtp && create_rtp(session, session_media, session->endpoint->rtp_ipv6)) {
+ return -1;
+ }
+
+ ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host));
+
+ /* Ensure that the address provided is valid */
+ if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
+ /* The provided host was actually invalid so we error out this negotiation */
+ return -1;
+ }
+
+ /* Apply connection information to the RTP instance */
+ ast_sockaddr_set_port(addrs, remote_stream->desc.port);
+ ast_rtp_instance_set_remote_address(session_media->rtp, addrs);
+
+ if (set_caps(session, session_media, local_stream) < 1) {
+ return -1;
+ }
+
+ if (media_type == AST_FORMAT_TYPE_AUDIO) {
+ apply_packetization(session, session_media, remote_stream);
+ }
+
+ if ((fdno = media_type_to_fdno(media_type)) < 0) {
+ return -1;
+ }
+ ast_channel_set_fd(session->channel, fdno, ast_rtp_instance_fd(session_media->rtp, 0));
+ ast_channel_set_fd(session->channel, fdno + 1, ast_rtp_instance_fd(session_media->rtp, 1));
+
+ /* If ICE support is enabled find all the needed attributes */
+ process_ice_attributes(session, session_media, remote, remote_stream);
+
+ /* audio stream handles music on hold */
+ if (media_type != AST_FORMAT_TYPE_AUDIO) {
+ return 1;
+ }
+
+ /* Music on hold for audio streams only */
+ if (session_media->held &&
+ (!ast_sockaddr_isnull(addrs) ||
+ !pjmedia_sdp_media_find_attr2(remote_stream, "sendonly", NULL))) {
+ /* The remote side has taken us off hold */
+ ast_queue_control(session->channel, AST_CONTROL_UNHOLD);
+ ast_queue_frame(session->channel, &ast_null_frame);
+ session_media->held = 0;
+ } else if (ast_sockaddr_isnull(addrs) ||
+ ast_sockaddr_is_any(addrs) ||
+ pjmedia_sdp_media_find_attr2(remote_stream, "sendonly", NULL)) {
+ /* The remote side has put us on hold */
+ ast_queue_control_data(session->channel, AST_CONTROL_HOLD, S_OR(session->endpoint->mohsuggest, NULL),
+ !ast_strlen_zero(session->endpoint->mohsuggest) ? strlen(session->endpoint->mohsuggest) + 1 : 0);
+ ast_rtp_instance_stop(session_media->rtp);
+ ast_queue_frame(session->channel, &ast_null_frame);
+ session_media->held = 1;
+ } else {
+ /* The remote side has not changed state, but make sure the instance is active */
+ ast_rtp_instance_activate(session_media->rtp);
+ }
+
+ return 1;
+}
+
+/*! \brief Function which updates the media stream with external media address, if applicable */
+static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport)
+{
+ char host[NI_MAXHOST];
+ struct ast_sockaddr addr = { { 0, } };
+
+ ast_copy_pj_str(host, &stream->conn->addr, sizeof(host));
+ ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID);
+
+ /* Is the address within the SDP inside the same network? */
+ if (ast_apply_ha(transport->localnet, &addr) == AST_SENSE_ALLOW) {
+ return;
+ }
+
+ pj_strdup2(tdata->pool, &stream->conn->addr, transport->external_media_address);
+}
+
+/*! \brief Function which destroys the RTP instance when session ends */
+static void stream_destroy(struct ast_sip_session_media *session_media)
+{
+ if (session_media->rtp) {
+ ast_rtp_instance_stop(session_media->rtp);
+ ast_rtp_instance_destroy(session_media->rtp);
+ }
+}
+
+/*! \brief SDP handler for 'audio' media stream */
+static struct ast_sip_session_sdp_handler audio_sdp_handler = {
+ .id = STR_AUDIO,
+ .negotiate_incoming_sdp_stream = negotiate_incoming_sdp_stream,
+ .create_outgoing_sdp_stream = create_outgoing_sdp_stream,
+ .apply_negotiated_sdp_stream = apply_negotiated_sdp_stream,
+ .change_outgoing_sdp_stream_media_address = change_outgoing_sdp_stream_media_address,
+ .stream_destroy = stream_destroy,
+};
+
+/*! \brief SDP handler for 'video' media stream */
+static struct ast_sip_session_sdp_handler video_sdp_handler = {
+ .id = STR_VIDEO,
+ .negotiate_incoming_sdp_stream = negotiate_incoming_sdp_stream,
+ .create_outgoing_sdp_stream = create_outgoing_sdp_stream,
+ .apply_negotiated_sdp_stream = apply_negotiated_sdp_stream,
+ .change_outgoing_sdp_stream_media_address = change_outgoing_sdp_stream_media_address,
+ .stream_destroy = stream_destroy,
+};
+
+static int video_info_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
+{
+ struct pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
+ pjsip_tx_data *tdata;
+
+ if (pj_strcmp2(&rdata->msg_info.msg->body->content_type.type, "application") ||
+ pj_strcmp2(&rdata->msg_info.msg->body->content_type.subtype, "media_control+xml")) {
+
+ return 0;
+ }
+
+ ast_queue_control(session->channel, AST_CONTROL_VIDUPDATE);
+
+ if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, 200, NULL, &tdata) == PJ_SUCCESS) {
+ pjsip_dlg_send_response(session->inv_session->dlg, tsx, tdata);
+ }
+
+ return 0;
+}
+
+static struct ast_sip_session_supplement video_info_supplement = {
+ .method = "INFO",
+ .incoming_request = video_info_incoming_request,
+};
+
+/*! \brief Unloads the sdp RTP/AVP module from Asterisk */
+static int unload_module(void)
+{
+ ast_sip_session_unregister_supplement(&video_info_supplement);
+ ast_sip_session_unregister_sdp_handler(&video_sdp_handler, STR_VIDEO);
+ ast_sip_session_unregister_sdp_handler(&audio_sdp_handler, STR_AUDIO);
+
+ if (sched) {
+ ast_sched_context_destroy(sched);
+ }
+
+ return 0;
+}
+
+/*!
+ * \brief Load the module
+ *
+ * Module loading including tests for configuration or dependencies.
+ * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
+ * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
+ * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
+ * configuration file or other non-critical problem return
+ * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
+ */
+static int load_module(void)
+{
+ ast_sockaddr_parse(&address_ipv4, "0.0.0.0", 0);
+ ast_sockaddr_parse(&address_ipv6, "::", 0);
+
+ if (!(sched = ast_sched_context_create())) {
+ ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
+ goto end;
+ }
+
+ if (ast_sched_start_thread(sched)) {
+ ast_log(LOG_ERROR, "Unable to create scheduler context thread.\n");
+ goto end;
+ }
+
+ if (ast_sip_session_register_sdp_handler(&audio_sdp_handler, STR_AUDIO)) {
+ ast_log(LOG_ERROR, "Unable to register SDP handler for %s stream type\n", STR_AUDIO);
+ goto end;
+ }
+
+ if (ast_sip_session_register_sdp_handler(&video_sdp_handler, STR_VIDEO)) {
+ ast_log(LOG_ERROR, "Unable to register SDP handler for %s stream type\n", STR_VIDEO);
+ goto end;
+ }
+
+ ast_sip_session_register_supplement(&video_info_supplement);
+
+ return AST_MODULE_LOAD_SUCCESS;
+end:
+ unload_module();
+
+ return AST_MODULE_LOAD_FAILURE;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP SDP RTP/AVP stream handler",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_CHANNEL_DRIVER,
+ );
diff --git a/res/res_sip_session.c b/res/res_sip_session.c
new file mode 100644
index 000000000..6a31d9448
--- /dev/null
+++ b/res/res_sip_session.c
@@ -0,0 +1,1799 @@
+/*
+* Asterisk -- An open source telephony toolkit.
+*
+* Copyright (C) 2013, Digium, Inc.
+*
+* Mark Michelson <mmichelson@digium.com>
+*
+* See http://www.asterisk.org for more information about
+* the Asterisk project. Please do not directly contact
+* any of the maintainers of this project for assistance;
+* the project provides a web site, mailing lists and IRC
+* channels for your use.
+*
+* This program is free software, distributed under the terms of
+* the GNU General Public License Version 2. See the LICENSE file
+* at the top of the source tree.
+*/
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <depend>res_sip</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_ua.h>
+#include <pjlib.h>
+
+#include "asterisk/res_sip.h"
+#include "asterisk/res_sip_session.h"
+#include "asterisk/datastore.h"
+#include "asterisk/module.h"
+#include "asterisk/logger.h"
+#include "asterisk/res_sip.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/lock.h"
+#include "asterisk/uuid.h"
+#include "asterisk/pbx.h"
+#include "asterisk/taskprocessor.h"
+#include "asterisk/causes.h"
+
+#define SDP_HANDLER_BUCKETS 11
+
+/* Some forward declarations */
+static void handle_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata);
+static void handle_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata);
+static int handle_incoming(struct ast_sip_session *session, pjsip_rx_data *rdata);
+static void handle_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata);
+static void handle_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata);
+static void handle_outgoing(struct ast_sip_session *session, pjsip_tx_data *tdata);
+
+/*! \brief NAT hook for modifying outgoing messages with SDP */
+static struct ast_sip_nat_hook *nat_hook;
+
+/*!
+ * \brief Registered SDP stream handlers
+ *
+ * This container is keyed on stream types. Each
+ * object in the container is a linked list of
+ * handlers for the stream type.
+ */
+static struct ao2_container *sdp_handlers;
+
+/*!
+ * These are the objects in the sdp_handlers container
+ */
+struct sdp_handler_list {
+ /* The list of handlers to visit */
+ AST_LIST_HEAD_NOLOCK(, ast_sip_session_sdp_handler) list;
+ /* The handlers in this list handle streams of this type */
+ char stream_type[1];
+};
+
+static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer);
+
+static int sdp_handler_list_hash(const void *obj, int flags)
+{
+ const struct sdp_handler_list *handler_list = obj;
+ const char *stream_type = flags & OBJ_KEY ? obj : handler_list->stream_type;
+
+ return ast_str_hash(stream_type);
+}
+
+static int sdp_handler_list_cmp(void *obj, void *arg, int flags)
+{
+ struct sdp_handler_list *handler_list1 = obj;
+ struct sdp_handler_list *handler_list2 = arg;
+ const char *stream_type2 = flags & OBJ_KEY ? arg : handler_list2->stream_type;
+
+ return strcmp(handler_list1->stream_type, stream_type2) ? 0 : CMP_MATCH | CMP_STOP;
+}
+
+static int session_media_hash(const void *obj, int flags)
+{
+ const struct ast_sip_session_media *session_media = obj;
+ const char *stream_type = flags & OBJ_KEY ? obj : session_media->stream_type;
+
+ return ast_str_hash(stream_type);
+}
+
+static int session_media_cmp(void *obj, void *arg, int flags)
+{
+ struct ast_sip_session_media *session_media1 = obj;
+ struct ast_sip_session_media *session_media2 = arg;
+ const char *stream_type2 = flags & OBJ_KEY ? arg : session_media2->stream_type;
+
+ return strcmp(session_media1->stream_type, stream_type2) ? 0 : CMP_MATCH | CMP_STOP;
+}
+
+int ast_sip_session_register_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type)
+{
+ RAII_VAR(struct sdp_handler_list *, handler_list,
+ ao2_find(sdp_handlers, stream_type, OBJ_KEY), ao2_cleanup);
+ SCOPED_AO2LOCK(lock, sdp_handlers);
+
+ if (handler_list) {
+ struct ast_sip_session_sdp_handler *iter;
+ /* Check if this handler is already registered for this stream type */
+ AST_LIST_TRAVERSE(&handler_list->list, iter, next) {
+ if (!strcmp(iter->id, handler->id)) {
+ ast_log(LOG_WARNING, "Handler '%s' already registered for stream type '%s'.\n", handler->id, stream_type);
+ return -1;
+ }
+ }
+ AST_LIST_INSERT_TAIL(&handler_list->list, handler, next);
+ ast_debug(1, "Registered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type);
+ ast_module_ref(ast_module_info->self);
+ return 0;
+ }
+
+ /* No stream of this type has been registered yet, so we need to create a new list */
+ handler_list = ao2_alloc(sizeof(*handler_list) + strlen(stream_type), NULL);
+ if (!handler_list) {
+ return -1;
+ }
+ /* Safe use of strcpy */
+ strcpy(handler_list->stream_type, stream_type);
+ AST_LIST_HEAD_INIT_NOLOCK(&handler_list->list);
+ AST_LIST_INSERT_TAIL(&handler_list->list, handler, next);
+ if (!ao2_link(sdp_handlers, handler_list)) {
+ return -1;
+ }
+ ast_debug(1, "Registered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type);
+ ast_module_ref(ast_module_info->self);
+ return 0;
+}
+
+static int remove_handler(void *obj, void *arg, void *data, int flags)
+{
+ struct sdp_handler_list *handler_list = obj;
+ struct ast_sip_session_sdp_handler *handler = data;
+ struct ast_sip_session_sdp_handler *iter;
+ const char *stream_type = arg;
+
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&handler_list->list, iter, next) {
+ if (!strcmp(iter->id, handler->id)) {
+ AST_LIST_REMOVE_CURRENT(next);
+ ast_debug(1, "Unregistered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type);
+ ast_module_unref(ast_module_info->self);
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+
+ if (AST_LIST_EMPTY(&handler_list->list)) {
+ ast_debug(3, "No more handlers exist for stream type '%s'\n", stream_type);
+ return CMP_MATCH;
+ } else {
+ return CMP_STOP;
+ }
+}
+
+void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type)
+{
+ ao2_callback_data(sdp_handlers, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, remove_handler, (void *)stream_type, handler);
+}
+
+static int validate_port_hash(const void *obj, int flags)
+{
+ const int *port = obj;
+ return *port;
+}
+
+static int validate_port_cmp(void *obj, void *arg, int flags)
+{
+ int *port1 = obj;
+ int *port2 = arg;
+
+ return *port1 == *port2 ? CMP_MATCH | CMP_STOP : 0;
+}
+
+struct bundle_assoc {
+ int port;
+ char tag[1];
+};
+
+static int bundle_assoc_hash(const void *obj, int flags)
+{
+ const struct bundle_assoc *assoc = obj;
+ const char *tag = flags & OBJ_KEY ? obj : assoc->tag;
+
+ return ast_str_hash(tag);
+}
+
+static int bundle_assoc_cmp(void *obj, void *arg, int flags)
+{
+ struct bundle_assoc *assoc1 = obj;
+ struct bundle_assoc *assoc2 = arg;
+ const char *tag2 = flags & OBJ_KEY ? arg : assoc2->tag;
+
+ return strcmp(assoc1->tag, tag2) ? 0 : CMP_MATCH | CMP_STOP;
+}
+
+/* return must be ast_freed */
+static pjmedia_sdp_attr *media_get_mid(pjmedia_sdp_media *media)
+{
+ pjmedia_sdp_attr *attr = pjmedia_sdp_media_find_attr2(media, "mid", NULL);
+ if (!attr) {
+ return NULL;
+ }
+
+ return attr;
+}
+
+static int get_bundle_port(const pjmedia_sdp_session *sdp, const char *mid)
+{
+ int i;
+ for (i = 0; i < sdp->media_count; ++i) {
+ pjmedia_sdp_attr *mid_attr = media_get_mid(sdp->media[i]);
+ if (mid_attr && !pj_strcmp2(&mid_attr->value, mid)) {
+ return sdp->media[i]->desc.port;
+ }
+ }
+
+ return -1;
+}
+
+static int validate_incoming_sdp(const pjmedia_sdp_session *sdp)
+{
+ int i;
+ RAII_VAR(struct ao2_container *, portlist, ao2_container_alloc(5, validate_port_hash, validate_port_cmp), ao2_cleanup);
+ RAII_VAR(struct ao2_container *, bundle_assoc_list, ao2_container_alloc(5, bundle_assoc_hash, bundle_assoc_cmp), ao2_cleanup);
+
+ /* check for bundles (for websocket RTP multiplexing, there can be more than one) */
+ for (i = 0; i < sdp->attr_count; ++i) {
+ char *bundle_list;
+ int bundle_port = 0;
+ if (pj_stricmp2(&sdp->attr[i]->name, "group")) {
+ continue;
+ }
+
+ /* check to see if this group is a bundle */
+ if (7 >= sdp->attr[i]->value.slen || pj_strnicmp2(&sdp->attr[i]->value, "bundle ", 7)) {
+ continue;
+ }
+
+ bundle_list = ast_alloca(sdp->attr[i]->value.slen - 6);
+ strncpy(bundle_list, sdp->attr[i]->value.ptr + 7, sdp->attr[i]->value.slen - 7);
+ bundle_list[sdp->attr[i]->value.slen - 7] = '\0';
+ while (bundle_list) {
+ char *item;
+ RAII_VAR(struct bundle_assoc *, assoc, NULL, ao2_cleanup);
+ item = strsep(&bundle_list, " ,");
+ if (!bundle_port) {
+ RAII_VAR(int *, port, ao2_alloc(sizeof(int), NULL), ao2_cleanup);
+ RAII_VAR(int *, port_match, NULL, ao2_cleanup);
+ bundle_port = get_bundle_port(sdp, item);
+ if (bundle_port < 0) {
+ return -1;
+ }
+ port_match = ao2_find(portlist, &bundle_port, OBJ_KEY);
+ if (port_match) {
+ /* bundle port aready consumed by a different bundle */
+ return -1;
+ }
+ *port = bundle_port;
+ ao2_link(portlist, port);
+ }
+ assoc = ao2_alloc(sizeof(*assoc) + strlen(item), NULL);
+ if (!assoc) {
+ return -1;
+ }
+
+ /* safe use of strcpy */
+ strcpy(assoc->tag, item);
+ assoc->port = bundle_port;
+ ao2_link(bundle_assoc_list, assoc);
+ }
+ }
+
+ /* validate all streams */
+ for (i = 0; i < sdp->media_count; ++i) {
+ RAII_VAR(int *, port, ao2_alloc(sizeof(int), NULL), ao2_cleanup);
+ RAII_VAR(int *, port_match, NULL, ao2_cleanup);
+ RAII_VAR(int *, bundle_match, NULL, ao2_cleanup);
+ *port = sdp->media[i]->desc.port;
+ port_match = ao2_find(portlist, port, OBJ_KEY);
+ if (port_match) {
+ RAII_VAR(struct bundle_assoc *, assoc, NULL, ao2_cleanup);
+ pjmedia_sdp_attr *mid = media_get_mid(sdp->media[i]);
+ char *mid_val;
+
+ if (!mid) {
+ /* not part of a bundle */
+ return -1;
+ }
+
+ mid_val = ast_alloca(mid->value.slen + 1);
+ strncpy(mid_val, mid->value.ptr, mid->value.slen);
+ mid_val[mid->value.slen] = '\0';
+
+ assoc = ao2_find(bundle_assoc_list, mid_val, OBJ_KEY);
+ if (!assoc || assoc->port != *port) {
+ /* This port already exists elsewhere in the SDP
+ * and is not an appropriate bundle port, fail
+ * catastrophically */
+ return -1;
+ }
+ }
+ ao2_link(portlist, port);
+ }
+ return 0;
+}
+
+static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
+{
+ int i;
+ if (validate_incoming_sdp(sdp)) {
+ return -1;
+ }
+
+ for (i = 0; i < sdp->media_count; ++i) {
+ /* See if there are registered handlers for this media stream type */
+ char media[20];
+ struct ast_sip_session_sdp_handler *handler;
+ RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
+
+ /* We need a null-terminated version of the media string */
+ ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));
+
+ handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
+ if (!handler_list) {
+ ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);
+ continue;
+ }
+ AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
+ int res;
+ RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);
+ session_media = ao2_find(session->media, handler_list->stream_type, OBJ_KEY);
+ if (!session_media || session_media->handler) {
+ /* There is only one slot for this stream type and it has already been claimed
+ * so it will go unhandled */
+ break;
+ }
+ res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, sdp->media[i]);
+ if (res < 0) {
+ /* Catastrophic failure. Abort! */
+ return -1;
+ }
+ if (res > 0) {
+ /* Handled by this handler. Move to the next stream */
+ session_media->handler = handler;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+struct handle_negotiated_sdp_cb {
+ struct ast_sip_session *session;
+ const pjmedia_sdp_session *local;
+ const pjmedia_sdp_session *remote;
+};
+
+static int handle_negotiated_sdp_session_media(void *obj, void *arg, int flags)
+{
+ struct ast_sip_session_media *session_media = obj;
+ struct handle_negotiated_sdp_cb *callback_data = arg;
+ struct ast_sip_session *session = callback_data->session;
+ const pjmedia_sdp_session *local = callback_data->local;
+ const pjmedia_sdp_session *remote = callback_data->remote;
+ int i;
+
+ for (i = 0; i < local->media_count; ++i) {
+ /* See if there are registered handlers for this media stream type */
+ char media[20];
+ struct ast_sip_session_sdp_handler *handler;
+ RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
+
+ /* We need a null-terminated version of the media string */
+ ast_copy_pj_str(media, &local->media[i]->desc.media, sizeof(media));
+
+ /* stream type doesn't match the one we're looking to fill */
+ if (strcasecmp(session_media->stream_type, media)) {
+ continue;
+ }
+
+ handler = session_media->handler;
+ if (handler) {
+ int res = handler->apply_negotiated_sdp_stream(session, session_media, local, local->media[i], remote, remote->media[i]);
+ if (res >= 0) {
+ return CMP_MATCH;
+ }
+ return 0;
+ }
+
+ handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
+ if (!handler_list) {
+ ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);
+ continue;
+ }
+ AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
+ int res = handler->apply_negotiated_sdp_stream(session, session_media, local, local->media[i], remote, remote->media[i]);
+ if (res < 0) {
+ /* Catastrophic failure. Abort! */
+ return 0;
+ }
+ if (res > 0) {
+ /* Handled by this handler. Move to the next stream */
+ session_media->handler = handler;
+ return CMP_MATCH;
+ }
+ }
+ }
+ return CMP_MATCH;
+}
+
+static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *local, const pjmedia_sdp_session *remote)
+{
+ RAII_VAR(struct ao2_iterator *, successful, NULL, ao2_iterator_cleanup);
+ struct handle_negotiated_sdp_cb callback_data = {
+ .session = session,
+ .local = local,
+ .remote = remote,
+ };
+
+ successful = ao2_callback(session->media, OBJ_MULTIPLE, handle_negotiated_sdp_session_media, &callback_data);
+ if (successful && ao2_container_count(successful->c) == ao2_container_count(session->media)) {
+ /* Nothing experienced a catastrophic failure */
+ return 0;
+ }
+ return -1;
+}
+
+AST_RWLIST_HEAD_STATIC(session_supplements, ast_sip_session_supplement);
+
+int ast_sip_session_register_supplement(struct ast_sip_session_supplement *supplement)
+{
+ struct ast_sip_session_supplement *iter;
+ int inserted = 0;
+ SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&session_supplements, iter, next) {
+ if (iter->priority > supplement->priority) {
+ AST_RWLIST_INSERT_BEFORE_CURRENT(supplement, next);
+ inserted = 1;
+ break;
+ }
+ }
+ AST_RWLIST_TRAVERSE_SAFE_END;
+
+ if (!inserted) {
+ AST_RWLIST_INSERT_TAIL(&session_supplements, supplement, next);
+ }
+ ast_module_ref(ast_module_info->self);
+ return 0;
+}
+
+void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
+{
+ struct ast_sip_session_supplement *iter;
+ SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&session_supplements, iter, next) {
+ if (supplement == iter) {
+ AST_RWLIST_REMOVE_CURRENT(next);
+ ast_module_unref(ast_module_info->self);
+ break;
+ }
+ }
+ AST_RWLIST_TRAVERSE_SAFE_END;
+}
+
+static struct ast_sip_session_supplement *supplement_dup(const struct ast_sip_session_supplement *src)
+{
+ struct ast_sip_session_supplement *dst = ast_calloc(1, sizeof(*dst));
+ if (!dst) {
+ return NULL;
+ }
+ /* Will need to revisit if shallow copy becomes an issue */
+ *dst = *src;
+ return dst;
+}
+
+#define DATASTORE_BUCKETS 53
+#define MEDIA_BUCKETS 7
+
+static void session_datastore_destroy(void *obj)
+{
+ struct ast_datastore *datastore = obj;
+
+ /* Using the destroy function (if present) destroy the data */
+ if (datastore->info->destroy != NULL && datastore->data != NULL) {
+ datastore->info->destroy(datastore->data);
+ datastore->data = NULL;
+ }
+
+ ast_free((void *) datastore->uid);
+ datastore->uid = NULL;
+}
+
+struct ast_datastore *ast_sip_session_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
+{
+ RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
+ const char *uid_ptr = uid;
+
+ if (!info) {
+ return NULL;
+ }
+
+ datastore = ao2_alloc(sizeof(*datastore), session_datastore_destroy);
+ if (!datastore) {
+ return NULL;
+ }
+
+ datastore->info = info;
+ if (ast_strlen_zero(uid)) {
+ /* They didn't provide an ID so we'll provide one ourself */
+ struct ast_uuid *uuid = ast_uuid_generate();
+ char uuid_buf[AST_UUID_STR_LEN];
+ if (!uuid) {
+ return NULL;
+ }
+ uid_ptr = ast_uuid_to_str(uuid, uuid_buf, sizeof(uuid_buf));
+ ast_free(uuid);
+ }
+
+ datastore->uid = ast_strdup(uid_ptr);
+ if (!datastore->uid) {
+ return NULL;
+ }
+
+ ao2_ref(datastore, +1);
+ return datastore;
+}
+
+int ast_sip_session_add_datastore(struct ast_sip_session *session, struct ast_datastore *datastore)
+{
+ ast_assert(datastore != NULL);
+ ast_assert(datastore->info != NULL);
+ ast_assert(ast_strlen_zero(datastore->uid) == 0);
+
+ if (!ao2_link(session->datastores, datastore)) {
+ return -1;
+ }
+ return 0;
+}
+
+struct ast_datastore *ast_sip_session_get_datastore(struct ast_sip_session *session, const char *name)
+{
+ return ao2_find(session->datastores, name, OBJ_KEY);
+}
+
+void ast_sip_session_remove_datastore(struct ast_sip_session *session, const char *name)
+{
+ ao2_callback(session->datastores, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, NULL, (void *) name);
+}
+
+int ast_sip_session_get_identity(struct pjsip_rx_data *rdata, struct ast_party_id *id)
+{
+ /* XXX STUB
+ * This is low-priority as far as getting SIP working is concerned, so this
+ * will be addressed later.
+ *
+ * The idea here will be that the rdata will be examined for headers such as
+ * P-Asserted-Identity, Remote-Party-ID, and From in order to determine Identity
+ * information.
+ *
+ * For reference, Asterisk SCF code does something very similar to this, except in
+ * C++ and using its version of the ast_party_id struct, so using it as a basis
+ * would be a smart idea here.
+ */
+ return 0;
+}
+
+/*!
+ * \brief Structure used for sending delayed requests
+ *
+ * Requests are typically delayed because the current transaction
+ * state of an INVITE. Once the pending INVITE transaction terminates,
+ * the delayed request will be sent
+ */
+struct ast_sip_session_delayed_request {
+ /*! Method of the request */
+ char method[15];
+ /*! Callback to call when the delayed request is created. */
+ ast_sip_session_request_creation_cb on_request_creation;
+ /*! Callback to call when the delayed request receives a response */
+ ast_sip_session_response_cb on_response;
+ /*! Request to send */
+ pjsip_tx_data *tdata;
+ AST_LIST_ENTRY(ast_sip_session_delayed_request) next;
+};
+
+static struct ast_sip_session_delayed_request *delayed_request_alloc(const char *method,
+ ast_sip_session_request_creation_cb on_request_creation,
+ ast_sip_session_response_cb on_response,
+ pjsip_tx_data *tdata)
+{
+ struct ast_sip_session_delayed_request *delay = ast_calloc(1, sizeof(*delay));
+ if (!delay) {
+ return NULL;
+ }
+ ast_copy_string(delay->method, method, sizeof(delay->method));
+ delay->on_request_creation = on_request_creation;
+ delay->on_response = on_response;
+ delay->tdata = tdata;
+ return delay;
+}
+
+static int send_delayed_request(struct ast_sip_session *session, struct ast_sip_session_delayed_request *delay)
+{
+ ast_debug(3, "Sending delayed %s request to %s\n", delay->method, ast_sorcery_object_get_id(session->endpoint));
+
+ if (delay->tdata) {
+ ast_sip_session_send_request_with_cb(session, delay->tdata, delay->on_response);
+ return 0;
+ }
+
+ if (!strcmp(delay->method, "INVITE")) {
+ ast_sip_session_refresh(session, delay->on_request_creation,
+ delay->on_response, AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1);
+ } else if (!strcmp(delay->method, "UPDATE")) {
+ ast_sip_session_refresh(session, delay->on_request_creation,
+ delay->on_response, AST_SIP_SESSION_REFRESH_METHOD_UPDATE, 1);
+ } else {
+ ast_log(LOG_WARNING, "Unexpected delayed %s request with no existing request structure\n", delay->method);
+ return -1;
+ }
+ return 0;
+}
+
+static int queued_delayed_request_send(void *data)
+{
+ RAII_VAR(struct ast_sip_session *, session, data, ao2_cleanup);
+ RAII_VAR(struct ast_sip_session_delayed_request *, delay, NULL, ast_free_ptr);
+
+ delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next);
+ if (!delay) {
+ return 0;
+ }
+
+ return send_delayed_request(session, delay);
+}
+
+static void queue_delayed_request(struct ast_sip_session *session)
+{
+ if (AST_LIST_EMPTY(&session->delayed_requests)) {
+ /* No delayed request to send, so just return */
+ return;
+ }
+
+ ast_debug(3, "Queuing delayed request to run for %s\n",
+ ast_sorcery_object_get_id(session->endpoint));
+
+ ao2_ref(session, +1);
+ ast_sip_push_task(session->serializer, queued_delayed_request_send, session);
+}
+
+static int delay_request(struct ast_sip_session *session, ast_sip_session_request_creation_cb on_request,
+ ast_sip_session_response_cb on_response, const char *method, pjsip_tx_data *tdata)
+{
+ struct ast_sip_session_delayed_request *delay = delayed_request_alloc(method,
+ on_request, on_response, tdata);
+
+ if (!delay) {
+ return -1;
+ }
+
+ AST_LIST_INSERT_TAIL(&session->delayed_requests, delay, next);
+ return 0;
+}
+
+static pjmedia_sdp_session *generate_session_refresh_sdp(struct ast_sip_session *session)
+{
+ pjsip_inv_session *inv_session = session->inv_session;
+ const pjmedia_sdp_session *previous_sdp;
+
+ if (pjmedia_sdp_neg_was_answer_remote(inv_session->neg)) {
+ pjmedia_sdp_neg_get_active_remote(inv_session->neg, &previous_sdp);
+ } else {
+ pjmedia_sdp_neg_get_active_local(inv_session->neg, &previous_sdp);
+ }
+ return create_local_sdp(inv_session, session, previous_sdp);
+}
+
+int ast_sip_session_refresh(struct ast_sip_session *session,
+ ast_sip_session_request_creation_cb on_request_creation, ast_sip_session_response_cb on_response,
+ enum ast_sip_session_refresh_method method, int generate_new_sdp)
+{
+ pjsip_inv_session *inv_session = session->inv_session;
+ pjmedia_sdp_session *new_sdp = NULL;
+ pjsip_tx_data *tdata;
+
+ if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
+ /* Don't try to do anything with a hung-up call */
+ ast_debug(3, "Not sending reinvite to %s because of disconnected state...\n",
+ ast_sorcery_object_get_id(session->endpoint));
+ return 0;
+ }
+
+ if (inv_session->invite_tsx) {
+ /* We can't send a reinvite yet, so delay it */
+ ast_debug(3, "Delaying sending reinvite to %s because of outstanding transaction...\n",
+ ast_sorcery_object_get_id(session->endpoint));
+ return delay_request(session, on_request_creation, on_response, "INVITE", NULL);
+ }
+
+ if (generate_new_sdp) {
+ new_sdp = generate_session_refresh_sdp(session);
+ if (!new_sdp) {
+ ast_log(LOG_ERROR, "Failed to generate session refresh SDP. Not sending session refresh\n");
+ return -1;
+ }
+ }
+
+ if (method == AST_SIP_SESSION_REFRESH_METHOD_INVITE) {
+ if (pjsip_inv_reinvite(inv_session, NULL, new_sdp, &tdata)) {
+ ast_log(LOG_WARNING, "Failed to create reinvite properly.\n");
+ return -1;
+ }
+ } else if (pjsip_inv_update(inv_session, NULL, new_sdp, &tdata)) {
+ ast_log(LOG_WARNING, "Failed to create UPDATE properly.\n");
+ return -1;
+ }
+ if (on_request_creation) {
+ if (on_request_creation(session, tdata)) {
+ return -1;
+ }
+ }
+ ast_sip_session_send_request_with_cb(session, tdata, on_response);
+ return 0;
+}
+
+void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
+{
+ handle_outgoing_response(session, tdata);
+ pjsip_inv_send_msg(session->inv_session, tdata);
+ return;
+}
+
+static pj_status_t session_load(pjsip_endpoint *endpt);
+static pj_status_t session_start(void);
+static pj_status_t session_stop(void);
+static pj_status_t session_unload(void);
+static pj_bool_t session_on_rx_request(pjsip_rx_data *rdata);
+
+static pjsip_module session_module = {
+ .name = {"Session Module", 14},
+ .priority = PJSIP_MOD_PRIORITY_APPLICATION,
+ .load = session_load,
+ .unload = session_unload,
+ .start = session_start,
+ .stop = session_stop,
+ .on_rx_request = session_on_rx_request,
+};
+
+void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip_tx_data *tdata,
+ ast_sip_session_response_cb on_response)
+{
+ pjsip_inv_session *inv_session = session->inv_session;
+
+ if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
+ /* Don't try to do anything with a hung-up call */
+ return;
+ }
+
+ tdata->mod_data[session_module.id] = on_response;
+ handle_outgoing_request(session, tdata);
+ pjsip_inv_send_msg(session->inv_session, tdata);
+ return;
+}
+
+void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
+{
+ ast_sip_session_send_request_with_cb(session, tdata, NULL);
+}
+
+/*!
+ * \brief Called when the PJSIP core loads us
+ *
+ * Since we already have Asterisk's fine module load/unload framework
+ * in use, we don't need to do anything special here.
+ */
+static pj_status_t session_load(pjsip_endpoint *endpt)
+{
+ return PJ_SUCCESS;
+}
+
+/*!
+ * \brief Called when the PJSIP core starts us
+ *
+ * Since we already have Asterisk's fine module load/unload framework
+ * in use, we don't need to do anything special here.
+ */
+static pj_status_t session_start(void)
+{
+ return PJ_SUCCESS;
+}
+
+/*!
+ * \brief Called when the PJSIP core stops us
+ *
+ * Since we already have Asterisk's fine module load/unload framework
+ * in use, we don't need to do anything special here.
+ */
+static pj_status_t session_stop(void)
+{
+ return PJ_SUCCESS;
+}
+
+/*!
+ * \brief Called when the PJSIP core unloads us
+ *
+ * Since we already have Asterisk's fine module load/unload framework
+ * in use, we don't need to do anything special here.
+ */
+static pj_status_t session_unload(void)
+{
+ return PJ_SUCCESS;
+}
+
+static int datastore_hash(const void *obj, int flags)
+{
+ const struct ast_datastore *datastore = obj;
+ const char *uid = flags & OBJ_KEY ? obj : datastore->uid;
+
+ ast_assert(uid != NULL);
+
+ return ast_str_hash(uid);
+}
+
+static int datastore_cmp(void *obj, void *arg, int flags)
+{
+ const struct ast_datastore *datastore1 = obj;
+ const struct ast_datastore *datastore2 = arg;
+ const char *uid2 = flags & OBJ_KEY ? arg : datastore2->uid;
+
+ ast_assert(datastore1->uid != NULL);
+ ast_assert(uid2 != NULL);
+
+ return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP;
+}
+
+static void session_media_dtor(void *obj)
+{
+ struct ast_sip_session_media *session_media = obj;
+ if (session_media->handler) {
+ session_media->handler->stream_destroy(session_media);
+ }
+}
+
+static void session_destructor(void *obj)
+{
+ struct ast_sip_session *session = obj;
+ struct ast_sip_session_supplement *supplement;
+ struct ast_sip_session_delayed_request *delay;
+
+ ast_debug(3, "Destroying SIP session with endpoint %s\n",
+ ast_sorcery_object_get_id(session->endpoint));
+
+ while ((supplement = AST_LIST_REMOVE_HEAD(&session->supplements, next))) {
+ if (supplement->session_destroy) {
+ supplement->session_destroy(session);
+ }
+ ast_free(supplement);
+ }
+
+ ast_taskprocessor_unreference(session->serializer);
+ ao2_cleanup(session->datastores);
+ ao2_cleanup(session->media);
+ AST_LIST_HEAD_DESTROY(&session->supplements);
+ while ((delay = AST_LIST_REMOVE_HEAD(&session->delayed_requests, next))) {
+ ast_free(delay);
+ }
+ ast_party_id_free(&session->id);
+ ao2_cleanup(session->endpoint);
+ ast_format_cap_destroy(session->req_caps);
+}
+
+static int add_supplements(struct ast_sip_session *session)
+{
+ struct ast_sip_session_supplement *iter;
+ SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
+
+ AST_RWLIST_TRAVERSE(&session_supplements, iter, next) {
+ struct ast_sip_session_supplement *copy = supplement_dup(iter);
+ if (!copy) {
+ return -1;
+ }
+ AST_LIST_INSERT_TAIL(&session->supplements, copy, next);
+ }
+ return 0;
+}
+
+static int add_session_media(void *obj, void *arg, int flags)
+{
+ struct sdp_handler_list *handler_list = obj;
+ struct ast_sip_session * session = arg;
+ RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);
+ session_media = ao2_alloc(sizeof(*session_media) + strlen(handler_list->stream_type), session_media_dtor);
+ if (!session_media) {
+ return CMP_STOP;
+ }
+ /* Safe use of strcpy */
+ strcpy(session_media->stream_type, handler_list->stream_type);
+ ao2_link(session->media, session_media);
+ return 0;
+}
+
+struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, pjsip_inv_session *inv_session)
+{
+ RAII_VAR(struct ast_sip_session *, session, ao2_alloc(sizeof(*session), session_destructor), ao2_cleanup);
+ struct ast_sip_session_supplement *iter;
+ if (!session) {
+ return NULL;
+ }
+ AST_LIST_HEAD_INIT(&session->supplements);
+ session->datastores = ao2_container_alloc(DATASTORE_BUCKETS, datastore_hash, datastore_cmp);
+ if (!session->datastores) {
+ return NULL;
+ }
+
+ session->media = ao2_container_alloc(MEDIA_BUCKETS, session_media_hash, session_media_cmp);
+ if (!session->media) {
+ return NULL;
+ }
+ /* fill session->media with available types */
+ ao2_callback(sdp_handlers, OBJ_NODATA, add_session_media, session);
+
+ session->serializer = ast_sip_create_serializer();
+ if (!session->serializer) {
+ return NULL;
+ }
+ ast_sip_dialog_set_serializer(inv_session->dlg, session->serializer);
+ ast_sip_dialog_set_endpoint(inv_session->dlg, endpoint);
+ ao2_ref(endpoint, +1);
+ inv_session->mod_data[session_module.id] = session;
+ session->endpoint = endpoint;
+ session->inv_session = inv_session;
+ session->req_caps = ast_format_cap_alloc_nolock();
+
+ if (add_supplements(session)) {
+ return NULL;
+ }
+ AST_LIST_TRAVERSE(&session->supplements, iter, next) {
+ if (iter->session_begin) {
+ iter->session_begin(session);
+ }
+ }
+ session->direct_media_cap = ast_format_cap_alloc_nolock();
+ AST_LIST_HEAD_INIT_NOLOCK(&session->delayed_requests);
+ ast_party_id_init(&session->id);
+ ao2_ref(session, +1);
+ return session;
+}
+
+static int session_outbound_auth(pjsip_dialog *dlg, pjsip_tx_data *tdata, void *user_data)
+{
+ pjsip_inv_session *inv = pjsip_dlg_get_inv_session(dlg);
+ struct ast_sip_session *session = inv->mod_data[session_module.id];
+
+ if (inv->state < PJSIP_INV_STATE_CONFIRMED && tdata->msg->line.req.method.id == PJSIP_INVITE_METHOD) {
+ pjsip_inv_uac_restart(inv, PJ_TRUE);
+ }
+ ast_sip_session_send_request(session, tdata);
+ return 0;
+}
+
+struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint *endpoint, const char *location, const char *request_user, struct ast_format_cap *req_caps)
+{
+ const char *uri = NULL;
+ RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
+ pjsip_timer_setting timer;
+ pjsip_dialog *dlg;
+ struct pjsip_inv_session *inv_session;
+ RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup);
+ pjmedia_sdp_session *offer;
+
+ /* If no location has been provided use the AOR list from the endpoint itself */
+ location = S_OR(location, endpoint->aors);
+
+ contact = ast_sip_location_retrieve_contact_from_aor_list(location);
+ if (!contact || ast_strlen_zero(contact->uri)) {
+ uri = location;
+ } else {
+ uri = contact->uri;
+ }
+
+ /* If we still have no URI to dial fail to create the session */
+ if (ast_strlen_zero(uri)) {
+ return NULL;
+ }
+
+ if (!(dlg = ast_sip_create_dialog(endpoint, uri, request_user))) {
+ return NULL;
+ }
+
+ if (ast_sip_dialog_setup_outbound_authentication(dlg, endpoint, session_outbound_auth, NULL)) {
+ pjsip_dlg_terminate(dlg);
+ return NULL;
+ }
+
+ if (pjsip_inv_create_uac(dlg, NULL, endpoint->extensions, &inv_session) != PJ_SUCCESS) {
+ pjsip_dlg_terminate(dlg);
+ return NULL;
+ }
+
+ pjsip_timer_setting_default(&timer);
+ timer.min_se = endpoint->min_se;
+ timer.sess_expires = endpoint->sess_expires;
+ pjsip_timer_init_session(inv_session, &timer);
+
+ if (!(session = ast_sip_session_alloc(endpoint, inv_session))) {
+ pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
+ return NULL;
+ }
+
+ ast_format_cap_copy(session->req_caps, req_caps);
+ if ((pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) ||
+ !(offer = create_local_sdp(inv_session, session, NULL))) {
+ pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
+ return NULL;
+ }
+
+ pjsip_inv_set_local_sdp(inv_session, offer);
+
+ ao2_ref(session, +1);
+ return session;
+}
+
+enum sip_get_destination_result {
+ /*! The extension was successfully found */
+ SIP_GET_DEST_EXTEN_FOUND,
+ /*! The extension specified in the RURI was not found */
+ SIP_GET_DEST_EXTEN_NOT_FOUND,
+ /*! The extension specified in the RURI was a partial match */
+ SIP_GET_DEST_EXTEN_PARTIAL,
+ /*! The RURI is of an unsupported scheme */
+ SIP_GET_DEST_UNSUPPORTED_URI,
+};
+
+/*!
+ * \brief Determine where in the dialplan a call should go
+ *
+ * This uses the username in the request URI to try to match
+ * an extension in the endpoint's configured context in order
+ * to route the call.
+ *
+ * \param session The inbound SIP session
+ * \param rdata The SIP INVITE
+ */
+static enum sip_get_destination_result get_destination(struct ast_sip_session *session, pjsip_rx_data *rdata)
+{
+ pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
+ pjsip_sip_uri *sip_ruri;
+ if (!PJSIP_URI_SCHEME_IS_SIP(ruri) && !PJSIP_URI_SCHEME_IS_SIPS(ruri)) {
+ return SIP_GET_DEST_UNSUPPORTED_URI;
+ }
+ sip_ruri = pjsip_uri_get_uri(ruri);
+ ast_copy_pj_str(session->exten, &sip_ruri->user, sizeof(session->exten));
+ if (ast_exists_extension(NULL, session->endpoint->context, session->exten, 1, NULL)) {
+ return SIP_GET_DEST_EXTEN_FOUND;
+ }
+ /* XXX In reality, we'll likely have further options so that partial matches
+ * can be indicated here, but for getting something up and running, we're going
+ * to return a "not exists" error here.
+ */
+ return SIP_GET_DEST_EXTEN_NOT_FOUND;
+}
+
+static pjsip_inv_session *pre_session_setup(pjsip_rx_data *rdata, const struct ast_sip_endpoint *endpoint)
+{
+ pjsip_tx_data *tdata;
+ pjsip_dialog *dlg;
+ pjsip_inv_session *inv_session;
+ unsigned int options = endpoint->extensions;
+
+ if (pjsip_inv_verify_request(rdata, &options, NULL, NULL, ast_sip_get_pjsip_endpoint(), &tdata) != PJ_SUCCESS) {
+ if (tdata) {
+ pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL);
+ } else {
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
+ }
+ return NULL;
+ }
+ if (pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, NULL, &dlg) != PJ_SUCCESS) {
+ pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL);
+ return NULL;
+ }
+ if (pjsip_inv_create_uas(dlg, rdata, NULL, 0, &inv_session) != PJ_SUCCESS) {
+ pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL);
+ pjsip_dlg_terminate(dlg);
+ return NULL;
+ }
+ if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
+ if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) != PJ_SUCCESS) {
+ pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
+ }
+ pjsip_inv_send_msg(inv_session, tdata);
+ return NULL;
+ }
+ return inv_session;
+}
+
+static void handle_new_invite_request(pjsip_rx_data *rdata)
+{
+ RAII_VAR(struct ast_sip_endpoint *, endpoint,
+ ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
+ pjsip_tx_data *tdata = NULL;
+ pjsip_inv_session *inv_session = NULL;
+ struct ast_sip_session *session = NULL;
+ pjsip_timer_setting timer;
+ pjsip_rdata_sdp_info *sdp_info;
+ pjmedia_sdp_session *local = NULL;
+
+ ast_assert(endpoint != NULL);
+
+ inv_session = pre_session_setup(rdata, endpoint);
+ if (!inv_session) {
+ /* pre_session_setup() returns a response on failure */
+ return;
+ }
+
+ session = ast_sip_session_alloc(endpoint, inv_session);
+ if (!session) {
+ if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
+ pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
+ } else {
+ pjsip_inv_send_msg(inv_session, tdata);
+ }
+ return;
+ }
+
+ /* From this point on, any calls to pjsip_inv_terminate have the last argument as PJ_TRUE
+ * so that we will be notified so we can destroy the session properly
+ */
+
+ switch (get_destination(session, rdata)) {
+ case SIP_GET_DEST_EXTEN_FOUND:
+ /* Things worked. Keep going */
+ break;
+ case SIP_GET_DEST_UNSUPPORTED_URI:
+ if (pjsip_inv_initial_answer(inv_session, rdata, 416, NULL, NULL, &tdata) == PJ_SUCCESS) {
+ ast_sip_session_send_response(session, tdata);
+ } else {
+ pjsip_inv_terminate(inv_session, 416, PJ_TRUE);
+ }
+ return;
+ case SIP_GET_DEST_EXTEN_NOT_FOUND:
+ case SIP_GET_DEST_EXTEN_PARTIAL:
+ default:
+ if (pjsip_inv_initial_answer(inv_session, rdata, 404, NULL, NULL, &tdata) == PJ_SUCCESS) {
+ ast_sip_session_send_response(session, tdata);
+ } else {
+ pjsip_inv_terminate(inv_session, 404, PJ_TRUE);
+ }
+ return;
+ };
+
+ if ((sdp_info = pjsip_rdata_get_sdp_info(rdata)) && (sdp_info->sdp_err == PJ_SUCCESS) && sdp_info->sdp) {
+ if (handle_incoming_sdp(session, sdp_info->sdp)) {
+ if (pjsip_inv_initial_answer(inv_session, rdata, 488, NULL, NULL, &tdata) == PJ_SUCCESS) {
+ ast_sip_session_send_response(session, tdata);
+ } else {
+ pjsip_inv_terminate(inv_session, 488, PJ_TRUE);
+ }
+ return;
+ }
+ /* We are creating a local SDP which is an answer to their offer */
+ local = create_local_sdp(inv_session, session, sdp_info->sdp);
+ } else {
+ /* We are creating a local SDP which is an offer */
+ local = create_local_sdp(inv_session, session, NULL);
+ }
+
+ /* If we were unable to create a local SDP terminate the session early, it won't go anywhere */
+ if (!local) {
+ if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
+ ast_sip_session_send_response(session, tdata);
+ } else {
+ pjsip_inv_terminate(inv_session, 500, PJ_TRUE);
+ }
+ return;
+ } else {
+ pjsip_inv_set_local_sdp(inv_session, local);
+ }
+
+ pjsip_timer_setting_default(&timer);
+ timer.min_se = endpoint->min_se;
+ timer.sess_expires = endpoint->sess_expires;
+ pjsip_timer_init_session(inv_session, &timer);
+
+ /* At this point, we've verified what we can, so let's go ahead and send a 100 Trying out */
+ if (pjsip_inv_initial_answer(inv_session, rdata, 100, NULL, NULL, &tdata) != PJ_SUCCESS) {
+ pjsip_inv_terminate(inv_session, 500, PJ_TRUE);
+ return;
+ }
+ ast_sip_session_send_response(session, tdata);
+
+ handle_incoming_request(session, rdata);
+}
+
+static int has_supplement(struct ast_sip_session *session, pjsip_rx_data *rdata)
+{
+ struct ast_sip_session_supplement *supplement;
+ struct pjsip_method *method = &rdata->msg_info.msg->line.req.method;
+
+ if (!session) {
+ return PJ_FALSE;
+ }
+
+ AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
+ if (!supplement->method || !pj_strcmp2(&method->name, supplement->method)) {
+ return PJ_TRUE;
+ }
+ }
+ return PJ_FALSE;
+}
+/*!
+ * \brief Called when a new SIP request comes into PJSIP
+ *
+ * This function is called under two circumstances
+ * 1) An out-of-dialog request is received by PJSIP
+ * 2) An in-dialog request that the inv_session layer does not
+ * handle is received (such as an in-dialog INFO)
+ *
+ * In all cases, there is very little we actually do in this function
+ * 1) For requests we don't handle, we return PJ_FALSE
+ * 2) For new INVITEs, throw the work into the SIP threadpool to be done
+ * there to free up the thread(s) handling incoming requests
+ * 3) For in-dialog requests we handle, we defer handling them until the
+ * on_inv_state_change() callback instead (where we will end up putting
+ * them into the threadpool).
+ */
+static pj_bool_t session_on_rx_request(pjsip_rx_data *rdata)
+{
+ pj_status_t handled = PJ_FALSE;
+ pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
+ pjsip_inv_session *inv_session;
+
+ switch (rdata->msg_info.msg->line.req.method.id) {
+ case PJSIP_INVITE_METHOD:
+ if (dlg) {
+ ast_log(LOG_WARNING, "on_rx_request called for INVITE in mid-dialog?\n");
+ break;
+ }
+ handled = PJ_TRUE;
+ handle_new_invite_request(rdata);
+ break;
+ default:
+ /* Handle other in-dialog methods if their supplements have been registered */
+ handled = dlg && (inv_session = pjsip_dlg_get_inv_session(dlg)) &&
+ has_supplement(inv_session->mod_data[session_module.id], rdata);
+ break;
+ }
+
+ return handled;
+}
+
+struct reschedule_reinvite_data {
+ struct ast_sip_session *session;
+ struct ast_sip_session_delayed_request *delay;
+};
+
+static struct reschedule_reinvite_data *reschedule_reinvite_data_alloc(
+ struct ast_sip_session *session, struct ast_sip_session_delayed_request *delay)
+{
+ struct reschedule_reinvite_data *rrd = ast_malloc(sizeof(*rrd));
+ if (!rrd) {
+ return NULL;
+ }
+ ao2_ref(session, +1);
+ rrd->session = session;
+ rrd->delay = delay;
+ return rrd;
+}
+
+static void reschedule_reinvite_data_destroy(struct reschedule_reinvite_data *rrd)
+{
+ ao2_cleanup(rrd->session);
+ ast_free(rrd->delay);
+ ast_free(rrd);
+}
+
+static int really_resend_reinvite(void *data)
+{
+ RAII_VAR(struct reschedule_reinvite_data *, rrd, data, reschedule_reinvite_data_destroy);
+
+ return send_delayed_request(rrd->session, rrd->delay);
+}
+
+static void resend_reinvite(pj_timer_heap_t *timer, pj_timer_entry *entry)
+{
+ struct reschedule_reinvite_data *rrd = entry->user_data;
+
+ ast_sip_push_task(rrd->session->serializer, really_resend_reinvite, entry->user_data);
+}
+
+static void reschedule_reinvite(struct ast_sip_session *session, ast_sip_session_response_cb on_response, pjsip_tx_data *tdata)
+{
+ struct ast_sip_session_delayed_request *delay = delayed_request_alloc("INVITE",
+ NULL, on_response, tdata);
+ pjsip_inv_session *inv = session->inv_session;
+ struct reschedule_reinvite_data *rrd = reschedule_reinvite_data_alloc(session, delay);
+ pj_time_val tv;
+
+ if (!rrd || !delay) {
+ return;
+ }
+
+ tv.sec = 0;
+ if (inv->role == PJSIP_ROLE_UAC) {
+ tv.msec = 2100 + ast_random() % 2000;
+ } else {
+ tv.msec = ast_random() % 2000;
+ }
+
+ pj_timer_entry_init(&session->rescheduled_reinvite, 0, rrd, resend_reinvite);
+
+ pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &session->rescheduled_reinvite, &tv);
+}
+
+static void __print_debug_details(const char *function, pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e)
+{
+ struct ast_sip_session *session;
+ ast_debug(5, "Function %s called on event %s\n", function, pjsip_event_str(e->type));
+ if (!inv) {
+ ast_debug(5, "Transaction %p does not belong to an inv_session?\n", tsx);
+ ast_debug(5, "The transaction state is %s\n", pjsip_tsx_state_str(tsx->state));
+ return;
+ }
+ session = inv->mod_data[session_module.id];
+ if (!session) {
+ ast_debug(5, "inv_session %p has no ast session\n", inv);
+ } else {
+ ast_debug(5, "The state change pertains to the session with %s\n",
+ ast_sorcery_object_get_id(session->endpoint));
+ }
+ if (inv->invite_tsx) {
+ ast_debug(5, "The inv session still has an invite_tsx (%p)\n", inv->invite_tsx);
+ } else {
+ ast_debug(5, "The inv session does NOT have an invite_tsx\n");
+ }
+ if (tsx) {
+ ast_debug(5, "The transaction involved in this state change is %p\n", tsx);
+ ast_debug(5, "The current transaction state is %s\n", pjsip_tsx_state_str(tsx->state));
+ ast_debug(5, "The transaction state change event is %s\n", pjsip_event_str(e->body.tsx_state.type));
+ } else {
+ ast_debug(5, "There is no transaction involved in this state change\n");
+ }
+ ast_debug(5, "The current inv state is %s\n", pjsip_inv_state_name(inv->state));
+}
+
+#define print_debug_details(inv, tsx, e) __print_debug_details(__PRETTY_FUNCTION__, (inv), (tsx), (e))
+
+static void handle_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
+{
+ struct ast_sip_session_supplement *supplement;
+ struct pjsip_request_line req = rdata->msg_info.msg->line.req;
+
+ ast_debug(3, "Method is %.*s\n", (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));
+ AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
+ if (supplement->incoming_request && (
+ !supplement->method || !pj_strcmp2(&req.method.name, supplement->method))) {
+ supplement->incoming_request(session, rdata);
+ }
+ }
+}
+
+static void handle_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata)
+{
+ struct ast_sip_session_supplement *supplement;
+ struct pjsip_status_line status = rdata->msg_info.msg->line.status;
+
+ ast_debug(3, "Response is %d %.*s\n", status.code, (int) pj_strlen(&status.reason),
+ pj_strbuf(&status.reason));
+
+ AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
+ if (supplement->incoming_response && (
+ !supplement->method || !pj_strcmp2(&rdata->msg_info.cseq->method.name, supplement->method))) {
+ supplement->incoming_response(session, rdata);
+ }
+ }
+}
+
+static int handle_incoming(struct ast_sip_session *session, pjsip_rx_data *rdata)
+{
+ ast_debug(3, "Received %s\n", rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ?
+ "request" : "response");
+
+ if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
+ handle_incoming_request(session, rdata);
+ } else {
+ handle_incoming_response(session, rdata);
+ }
+
+ return 0;
+}
+
+static void handle_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
+{
+ struct ast_sip_session_supplement *supplement;
+ struct pjsip_request_line req = tdata->msg->line.req;
+
+ ast_debug(3, "Method is %.*s\n", (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));
+ AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
+ if (supplement->outgoing_request &&
+ (!supplement->method || !pj_strcmp2(&req.method.name, supplement->method))) {
+ supplement->outgoing_request(session, tdata);
+ }
+ }
+}
+
+static void handle_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
+{
+ struct ast_sip_session_supplement *supplement;
+ struct pjsip_status_line status = tdata->msg->line.status;
+ ast_debug(3, "Response is %d %.*s\n", status.code, (int) pj_strlen(&status.reason),
+ pj_strbuf(&status.reason));
+
+ AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
+ /* XXX Not sure how to get the method from a response.
+ * For now, just call supplements on all responses, no
+ * matter the method. This is less than ideal
+ */
+ if (supplement->outgoing_response) {
+ supplement->outgoing_response(session, tdata);
+ }
+ }
+}
+
+static void handle_outgoing(struct ast_sip_session *session, pjsip_tx_data *tdata)
+{
+ ast_debug(3, "Sending %s\n", tdata->msg->type == PJSIP_REQUEST_MSG ?
+ "request" : "response");
+ if (tdata->msg->type == PJSIP_REQUEST_MSG) {
+ handle_outgoing_request(session, tdata);
+ } else {
+ handle_outgoing_response(session, tdata);
+ }
+}
+
+static int session_end(struct ast_sip_session *session)
+{
+ struct ast_sip_session_supplement *iter;
+
+ /* Session is dead. Let's get rid of the reference to the session */
+ AST_LIST_TRAVERSE(&session->supplements, iter, next) {
+ if (iter->session_end) {
+ iter->session_end(session);
+ }
+ }
+
+ session->inv_session->mod_data[session_module.id] = NULL;
+ ast_sip_dialog_set_serializer(session->inv_session->dlg, NULL);
+ ast_sip_dialog_set_endpoint(session->inv_session->dlg, NULL);
+ ao2_cleanup(session);
+ return 0;
+}
+
+static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e)
+{
+ struct ast_sip_session *session = inv->mod_data[session_module.id];
+
+ print_debug_details(inv, NULL, e);
+
+ switch(e->type) {
+ case PJSIP_EVENT_TX_MSG:
+ handle_outgoing(session, e->body.tx_msg.tdata);
+ break;
+ case PJSIP_EVENT_RX_MSG:
+ handle_incoming(session, e->body.rx_msg.rdata);
+ break;
+ case PJSIP_EVENT_TSX_STATE:
+ ast_debug(3, "Source of transaction state change is %s\n", pjsip_event_str(e->body.tsx_state.type));
+ /* Transaction state changes are prompted by some other underlying event. */
+ switch(e->body.tsx_state.type) {
+ case PJSIP_EVENT_TX_MSG:
+ handle_outgoing(session, e->body.tsx_state.src.tdata);
+ break;
+ case PJSIP_EVENT_RX_MSG:
+ handle_incoming(session, e->body.tsx_state.src.rdata);
+ break;
+ case PJSIP_EVENT_TRANSPORT_ERROR:
+ case PJSIP_EVENT_TIMER:
+ case PJSIP_EVENT_USER:
+ case PJSIP_EVENT_UNKNOWN:
+ case PJSIP_EVENT_TSX_STATE:
+ /* Inception? */
+ break;
+ }
+ break;
+ case PJSIP_EVENT_TRANSPORT_ERROR:
+ case PJSIP_EVENT_TIMER:
+ case PJSIP_EVENT_UNKNOWN:
+ case PJSIP_EVENT_USER:
+ default:
+ break;
+ }
+
+ if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
+ session_end(session);
+ }
+}
+
+static void session_inv_on_new_session(pjsip_inv_session *inv, pjsip_event *e)
+{
+ /* XXX STUB */
+}
+
+static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e)
+{
+ struct ast_sip_session *session = inv->mod_data[session_module.id];
+ print_debug_details(inv, tsx, e);
+ if (!session) {
+ /* Transaction likely timed out after the call was hung up. Just
+ * ignore such transaction changes
+ */
+ return;
+ }
+ switch (e->body.tsx_state.type) {
+ case PJSIP_EVENT_TX_MSG:
+ /* When we create an outgoing request, we do not have access to the transaction that
+ * is created. Instead, We have to place transaction-specific data in the tdata. Here,
+ * we transfer the data into the transaction. This way, when we receive a response, we
+ * can dig this data out again
+ */
+ tsx->mod_data[session_module.id] = e->body.tsx_state.src.tdata->mod_data[session_module.id];
+ break;
+ case PJSIP_EVENT_RX_MSG:
+ if (tsx->method.id == PJSIP_INVITE_METHOD) {
+ if (tsx->role == PJSIP_ROLE_UAC && tsx->state == PJSIP_TSX_STATE_COMPLETED) {
+ /* This means we got a non 2XX final response to our outgoing INVITE */
+ if (tsx->status_code == PJSIP_SC_REQUEST_PENDING) {
+ reschedule_reinvite(session, tsx->mod_data[session_module.id], tsx->last_tx);
+ return;
+ } else {
+ /* Other failures result in destroying the session. */
+ pjsip_tx_data *tdata;
+ pjsip_inv_end_session(inv, 500, NULL, &tdata);
+ ast_sip_session_send_request(session, tdata);
+ }
+ }
+ } else {
+ if (tsx->role == PJSIP_ROLE_UAS && tsx->state == PJSIP_TSX_STATE_TRYING) {
+ handle_incoming_request(session, e->body.tsx_state.src.rdata);
+ }
+ }
+ if (tsx->mod_data[session_module.id]) {
+ ast_sip_session_response_cb cb = tsx->mod_data[session_module.id];
+ cb(session, e->body.tsx_state.src.rdata);
+ }
+ case PJSIP_EVENT_TRANSPORT_ERROR:
+ case PJSIP_EVENT_TIMER:
+ case PJSIP_EVENT_USER:
+ case PJSIP_EVENT_UNKNOWN:
+ case PJSIP_EVENT_TSX_STATE:
+ /* Inception? */
+ break;
+ }
+
+ /* Terminated INVITE transactions always should result in queuing delayed requests,
+ * no matter what event caused the transaction to terminate
+ */
+ if (tsx->method.id == PJSIP_INVITE_METHOD && tsx->state == PJSIP_TSX_STATE_TERMINATED) {
+ queue_delayed_request(session);
+ }
+}
+
+static int add_sdp_streams(void *obj, void *arg, void *data, int flags)
+{
+ struct ast_sip_session_media *session_media = obj;
+ pjmedia_sdp_session *answer = arg;
+ struct ast_sip_session *session = data;
+ struct ast_sip_session_sdp_handler *handler = session_media->handler;
+ RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
+
+ if (handler) {
+ /* if an already assigned handler does not handle the session_media or reports a catastrophic error, fail */
+ if (handler->create_outgoing_sdp_stream(session, session_media, answer) <= 0) {
+ return 0;
+ }
+ return CMP_MATCH;
+ }
+
+ handler_list = ao2_find(sdp_handlers, session_media->stream_type, OBJ_KEY);
+ if (!handler_list) {
+ return CMP_MATCH;
+ }
+
+ /* no handler for this stream type and we have a list to search */
+ AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
+ int res = handler->create_outgoing_sdp_stream(session, session_media, answer);
+ if (res < 0) {
+ /* catastrophic error */
+ return 0;
+ }
+ if (res > 0) {
+ /* handled */
+ return CMP_MATCH;
+ }
+ }
+
+ /* streams that weren't handled won't be included in generated outbound SDP */
+ return CMP_MATCH;
+}
+
+static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, struct ast_sip_session *session, const pjmedia_sdp_session *offer)
+{
+ RAII_VAR(struct ao2_iterator *, successful, NULL, ao2_iterator_cleanup);
+ static const pj_str_t STR_ASTERISK = { "Asterisk", 8 };
+ static const pj_str_t STR_IN = { "IN", 2 };
+ static const pj_str_t STR_IP4 = { "IP4", 3 };
+ static const pj_str_t STR_IP6 = { "IP6", 3 };
+ pjmedia_sdp_session *local;
+
+ if (!(local = PJ_POOL_ZALLOC_T(inv->pool_prov, pjmedia_sdp_session))) {
+ return NULL;
+ }
+
+ if (!offer) {
+ local->origin.version = local->origin.id = (pj_uint32_t)(ast_random());
+ } else {
+ local->origin.version = offer->origin.version + 1;
+ local->origin.id = offer->origin.id;
+ }
+
+ local->origin.user = STR_ASTERISK;
+ local->origin.net_type = STR_IN;
+ local->origin.addr_type = session->endpoint->rtp_ipv6 ? STR_IP6 : STR_IP4;
+ local->origin.addr = *pj_gethostname();
+ local->name = local->origin.user;
+
+ /* Now let the handlers add streams of various types, pjmedia will automatically reorder the media streams for us */
+ successful = ao2_callback_data(session->media, OBJ_MULTIPLE, add_sdp_streams, local, session);
+ if (!successful || ao2_container_count(successful->c) != ao2_container_count(session->media)) {
+ /* Something experienced a catastrophic failure */
+ return NULL;
+ }
+
+ /* Use the connection details of the first media stream if possible for SDP level */
+ if (local->media_count) {
+ local->conn = local->media[0]->conn;
+ }
+
+ return local;
+}
+
+static void session_inv_on_rx_offer(pjsip_inv_session *inv, const pjmedia_sdp_session *offer)
+{
+ struct ast_sip_session *session = inv->mod_data[session_module.id];
+ pjmedia_sdp_session *answer;
+
+ if (handle_incoming_sdp(session, offer)) {
+ return;
+ }
+
+ if ((answer = create_local_sdp(inv, session, offer))) {
+ pjsip_inv_set_sdp_answer(inv, answer);
+ }
+}
+
+#if 0
+static void session_inv_on_create_offer(pjsip_inv_session *inv, pjmedia_sdp_session **p_offer)
+{
+ /* XXX STUB */
+}
+#endif
+
+static void session_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status)
+{
+ struct ast_sip_session *session = inv->mod_data[session_module.id];
+ const pjmedia_sdp_session *local, *remote;
+
+ if (!session->channel) {
+ /* If we don't have a channel. We really don't care about media updates.
+ * Just ignore
+ */
+ return;
+ }
+
+ if ((status != PJ_SUCCESS) || (pjmedia_sdp_neg_get_active_local(inv->neg, &local) != PJ_SUCCESS) ||
+ (pjmedia_sdp_neg_get_active_remote(inv->neg, &remote) != PJ_SUCCESS)) {
+ ast_channel_hangupcause_set(session->channel, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
+ ast_queue_hangup(session->channel);
+ return;
+ }
+
+ handle_negotiated_sdp(session, local, remote);
+}
+
+static pjsip_redirect_op session_inv_on_redirected(pjsip_inv_session *inv, const pjsip_uri *target, const pjsip_event *e)
+{
+ /* XXX STUB */
+ return PJSIP_REDIRECT_REJECT;
+}
+
+static pjsip_inv_callback inv_callback = {
+ .on_state_changed = session_inv_on_state_changed,
+ .on_new_session = session_inv_on_new_session,
+ .on_tsx_state_changed = session_inv_on_tsx_state_changed,
+ .on_rx_offer = session_inv_on_rx_offer,
+ .on_media_update = session_inv_on_media_update,
+ .on_redirected = session_inv_on_redirected,
+};
+
+/*! \brief Hook for modifying outgoing messages with SDP to contain the proper address information */
+static void session_outgoing_nat_hook(pjsip_tx_data *tdata, struct ast_sip_transport *transport)
+{
+ struct ast_sip_nat_hook *hook = tdata->mod_data[session_module.id];
+ struct pjmedia_sdp_session *sdp;
+ int stream;
+
+ /* SDP produced by us directly will never be multipart */
+ if (hook || !tdata->msg->body || pj_stricmp2(&tdata->msg->body->content_type.type, "application") ||
+ pj_stricmp2(&tdata->msg->body->content_type.subtype, "sdp") || ast_strlen_zero(transport->external_media_address)) {
+ return;
+ }
+
+ sdp = tdata->msg->body->data;
+
+ for (stream = 0; stream < sdp->media_count; ++stream) {
+ /* See if there are registered handlers for this media stream type */
+ char media[20];
+ struct ast_sip_session_sdp_handler *handler;
+ RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
+
+ /* We need a null-terminated version of the media string */
+ ast_copy_pj_str(media, &sdp->media[stream]->desc.media, sizeof(media));
+
+ handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
+ if (!handler_list) {
+ ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);
+ continue;
+ }
+ AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
+ if (handler->change_outgoing_sdp_stream_media_address) {
+ handler->change_outgoing_sdp_stream_media_address(tdata, sdp->media[stream], transport);
+ }
+ }
+ }
+
+ /* We purposely do this so that the hook will not be invoked multiple times, ie: if a retransmit occurs */
+ tdata->mod_data[session_module.id] = nat_hook;
+}
+
+static int load_module(void)
+{
+ pjsip_endpoint *endpt;
+ if (!ast_sip_get_sorcery() || !ast_sip_get_pjsip_endpoint()) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ if (!(nat_hook = ast_sorcery_alloc(ast_sip_get_sorcery(), "nat_hook", NULL))) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ nat_hook->outgoing_external_message = session_outgoing_nat_hook;
+ ast_sorcery_create(ast_sip_get_sorcery(), nat_hook);
+ sdp_handlers = ao2_container_alloc(SDP_HANDLER_BUCKETS,
+ sdp_handler_list_hash, sdp_handler_list_cmp);
+ if (!sdp_handlers) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ endpt = ast_sip_get_pjsip_endpoint();
+ pjsip_inv_usage_init(endpt, &inv_callback);
+ pjsip_100rel_init_module(endpt);
+ pjsip_timer_init_module(endpt);
+ if (ast_sip_register_service(&session_module)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ ast_sip_unregister_service(&session_module);
+ if (nat_hook) {
+ ast_sorcery_delete(ast_sip_get_sorcery(), nat_hook);
+ nat_hook = NULL;
+ }
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "SIP Session resource",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_APP_DEPEND,
+ );
diff --git a/res/res_sip_session.exports.in b/res/res_sip_session.exports.in
new file mode 100644
index 000000000..08c6f3937
--- /dev/null
+++ b/res/res_sip_session.exports.in
@@ -0,0 +1,18 @@
+{
+ global:
+ LINKER_SYMBOL_PREFIXast_sip_session_register_sdp_handler;
+ LINKER_SYMBOL_PREFIXast_sip_session_unregister_sdp_handler;
+ LINKER_SYMBOL_PREFIXast_sip_session_register_supplement;
+ LINKER_SYMBOL_PREFIXast_sip_session_unregister_supplement;
+ LINKER_SYMBOL_PREFIXast_sip_session_alloc_datastore;
+ LINKER_SYMBOL_PREFIXast_sip_session_add_datastore;
+ LINKER_SYMBOL_PREFIXast_sip_session_get_datastore;
+ LINKER_SYMBOL_PREFIXast_sip_session_remove_datastore;
+ LINKER_SYMBOL_PREFIXast_sip_session_get_identity;
+ LINKER_SYMBOL_PREFIXast_sip_session_refresh;
+ LINKER_SYMBOL_PREFIXast_sip_session_send_response;
+ LINKER_SYMBOL_PREFIXast_sip_session_send_request;
+ LINKER_SYMBOL_PREFIXast_sip_session_create_outgoing;
+ local:
+ *;
+};
diff --git a/res/res_sorcery_config.c b/res/res_sorcery_config.c
index 509538f5a..c6ec62ed6 100644
--- a/res/res_sorcery_config.c
+++ b/res/res_sorcery_config.c
@@ -199,7 +199,6 @@ static void sorcery_config_retrieve_multiple(const struct ast_sorcery *sorcery,
if (!config_objects) {
return;
}
-
ao2_callback(config_objects, 0, sorcery_config_fields_cmp, &params);
}
diff --git a/tests/test_sorcery.c b/tests/test_sorcery.c
index 3877edc62..6cfd2de4f 100644
--- a/tests/test_sorcery.c
+++ b/tests/test_sorcery.c
@@ -130,9 +130,10 @@ struct sorcery_test_caching {
static int apply_handler_called;
/*! \brief Simple apply handler which sets global scope integer to 1 if called */
-static void test_apply_handler(const struct ast_sorcery *sorcery, void *obj)
+static int test_apply_handler(const struct ast_sorcery *sorcery, void *obj)
{
apply_handler_called = 1;
+ return 0;
}
/*! \brief Global scope caching structure for testing */