--- ./include/asterisk/res_pjsip.h.orig 2017-03-11 15:06:03.813529700 +1100 +++ ./include/asterisk/res_pjsip.h 2017-03-11 15:23:02.152125570 +1100 @@ -755,6 +755,8 @@ char *contact_user; /*! Do we allow an asymmetric RTP codec? */ unsigned int asymmetric_rtp_codec; + /*! Do we allow overlap dialling? */ + unsigned int allow_overlap; }; /*! --- ./res/res_pjsip/pjsip_configuration.c.orig 2017-03-11 14:20:05.301720984 +1100 +++ ./res/res_pjsip/pjsip_configuration.c 2017-03-11 15:22:26.817306635 +1100 @@ -1938,6 +1938,7 @@ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "subscribe_context", "", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct ast_sip_endpoint, subscription.context)); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_user", "", contact_user_handler, contact_user_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "asymmetric_rtp_codec", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, asymmetric_rtp_codec)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_overlap", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_overlap)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); --- ./res/res_pjsip.c.orig 2017-03-11 14:20:34.340395292 +1100 +++ ./res/res_pjsip.c 2017-03-11 15:22:09.346901444 +1100 @@ -100,6 +100,9 @@ Media Codec(s) to allow + + Allow support for SIP overlap dialling + AoR(s) to be used with the endpoint @@ -2057,6 +2060,9 @@ + + + --- ./res/res_pjsip_session.c.orig 2017-03-11 11:57:10.060157790 +1100 +++ ./res/res_pjsip_session.c 2017-03-11 15:22:45.753745705 +1100 @@ -2006,10 +2006,17 @@ 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. - */ + + /* + * Check for partial match via overlap dialling (if enabled) + */ + if (session->endpoint->allow_overlap && ( + !strncmp(session->exten, pickupexten, strlen(session->exten)) || + ast_canmatch_extension(NULL, session->endpoint->context, session->exten, 1, NULL))) { + /* Overlap partial match */ + return SIP_GET_DEST_EXTEN_PARTIAL; + } + return SIP_GET_DEST_EXTEN_NOT_FOUND; } @@ -2126,8 +2133,17 @@ pjsip_inv_terminate(invite->session->inv_session, 416, PJ_TRUE); } goto end; - case SIP_GET_DEST_EXTEN_NOT_FOUND: case SIP_GET_DEST_EXTEN_PARTIAL: + ast_debug(1, "Call from '%s' (%s:%s:%d) to extension '%s' - partial match\n", ast_sorcery_object_get_id(invite->session->endpoint), + invite->rdata->tp_info.transport->type_name, invite->rdata->pkt_info.src_name, invite->rdata->pkt_info.src_port, invite->session->exten); + + if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 484, NULL, NULL, &tdata) == PJ_SUCCESS) { + ast_sip_session_send_response(invite->session, tdata); + } else { + pjsip_inv_terminate(invite->session->inv_session, 484, PJ_TRUE); + } + goto end; + case SIP_GET_DEST_EXTEN_NOT_FOUND: default: ast_log(LOG_NOTICE, "Call from '%s' (%s:%s:%d) to extension '%s' rejected because extension not found in context '%s'.\n", ast_sorcery_object_get_id(invite->session->endpoint), invite->rdata->tp_info.transport->type_name, invite->rdata->pkt_info.src_name,