diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 47f1ddc845..860e1d6146 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -4413,6 +4413,7 @@ static int iax2_transfer(struct ast_channel *c, const char *dest) unsigned short callno = PTR_TO_CALLNO(c->tech_pvt); struct iax_ie_data ied = { "", }; char tmp[256], *context; + enum ast_control_transfer message = AST_TRANSFER_SUCCESS; ast_copy_string(tmp, dest, sizeof(tmp)); context = strchr(tmp, '@'); if (context) { @@ -4423,6 +4424,7 @@ static int iax2_transfer(struct ast_channel *c, const char *dest) if (context) iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, context); ast_debug(1, "Transferring '%s' to '%s'\n", c->name, dest); + ast_queue_control_data(c, AST_CONTROL_TRANSFER, &message, sizeof(message)); return send_command_locked(callno, AST_FRAME_IAX, IAX_COMMAND_TRANSFER, 0, ied.buf, ied.pos, -1); } diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 4d0f06f4ad..4fb164f9cc 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -17045,6 +17045,8 @@ static void handle_response_subscribe(struct sip_pvt *p, int resp, char *rest, s */ static void handle_response_refer(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno) { + enum ast_control_transfer message = AST_TRANSFER_FAILED; + /* If no refer structure exists, then do nothing */ if (!p->refer) return; @@ -17064,12 +17066,18 @@ static void handle_response_refer(struct sip_pvt *p, int resp, char *rest, struc if (ast_strlen_zero(p->authname)) { ast_log(LOG_WARNING, "Asked to authenticate REFER to %s:%d but we have no matching peer or realm auth!\n", ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port)); + if (p->owner) { + ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message)); + } pvt_set_needdestroy(p, "unable to authenticate REFER"); } if (p->authtries > 1 || do_proxy_auth(p, req, resp, SIP_REFER, 0)) { ast_log(LOG_NOTICE, "Failed to authenticate on REFER to '%s'\n", get_header(&p->initreq, "From")); p->refer->status = REFER_NOAUTH; - pvt_set_needdestroy(p, "failed to authenticat REFER"); + if (p->owner) { + ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message)); + } + pvt_set_needdestroy(p, "failed to authenticate REFER"); } break; case 481: /* Call leg does not exist */ @@ -17090,11 +17098,17 @@ static void handle_response_refer(struct sip_pvt *p, int resp, char *rest, struc ast_log(LOG_NOTICE, "SIP transfer to %s failed, call miserably fails. \n", p->refer->refer_to); pvt_set_needdestroy(p, "received 500/501 response"); p->refer->status = REFER_FAILED; + if (p->owner) { + ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message)); + } break; case 603: /* Transfer declined */ ast_log(LOG_NOTICE, "SIP transfer to %s declined, call miserably fails. \n", p->refer->refer_to); p->refer->status = REFER_FAILED; pvt_set_needdestroy(p, "received 603 response"); + if (p->owner) { + ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message)); + } break; } } @@ -18129,7 +18143,11 @@ static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, str if (!success) { ast_log(LOG_NOTICE, "Transfer failed. Sorry. Nothing further to do with this call\n"); } - + + if (p->owner) { + enum ast_control_transfer message = success ? AST_TRANSFER_SUCCESS : AST_TRANSFER_FAILED; + ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message)); + } /* Confirm that we received this packet */ transmit_response(p, "200 OK", req); } else if (p->mwi && !strcmp(event, "message-summary")) { @@ -24311,6 +24329,11 @@ static int sip_sipredirect(struct sip_pvt *p, const char *dest) sip_scheddestroy(p, SIP_TRANS_TIMEOUT); /* Make sure we stop send this reply. */ sip_alreadygone(p); + + if (p->owner) { + enum ast_control_transfer message = AST_TRANSFER_SUCCESS; + ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message)); + } /* hangup here */ return 0; } diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 62485ced67..cf4474e17f 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -319,6 +319,7 @@ enum ast_control_frame_type { AST_CONTROL_VIDUPDATE = 18, /*!< Indicate video frame update */ AST_CONTROL_T38 = 19, /*!< T38 state change request/notification */ AST_CONTROL_SRCUPDATE = 20, /*!< Indicate source of media has changed */ + AST_CONTROL_TRANSFER = 21, /*!< Indicate status of a transfer request */ }; enum ast_control_t38 { @@ -329,6 +330,11 @@ enum ast_control_t38 { AST_T38_REFUSED /*!< T38 refused for some reason (usually rejected by remote end) */ }; +enum ast_control_transfer { + AST_TRANSFER_SUCCESS = 0, /*!< Transfer request on the channel worked */ + AST_TRANSFER_FAILED, /*!< Transfer request on the channel failed */ +}; + #define AST_SMOOTHER_FLAG_G729 (1 << 0) #define AST_SMOOTHER_FLAG_BE (1 << 1) diff --git a/main/channel.c b/main/channel.c index b492f51131..9b2ad405ce 100644 --- a/main/channel.c +++ b/main/channel.c @@ -2994,6 +2994,7 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con case AST_CONTROL_ANSWER: case AST_CONTROL_HANGUP: case AST_CONTROL_T38: + case AST_CONTROL_TRANSFER: return 0; case AST_CONTROL_CONGESTION: @@ -3080,6 +3081,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition, case AST_CONTROL_HOLD: case AST_CONTROL_UNHOLD: case AST_CONTROL_T38: + case AST_CONTROL_TRANSFER: /* Nothing left to do for these. */ res = 0; break; @@ -3759,6 +3761,37 @@ int ast_transfer(struct ast_channel *chan, char *dest) res = 0; } ast_channel_unlock(chan); + + if (res < 0) { + return res; + } + + for (;;) { + struct ast_frame *fr; + + res = ast_waitfor(chan, -1); + + if (res < 0 || !(fr = ast_read(chan))) { + res = -1; + break; + } + + if (fr->frametype == AST_FRAME_CONTROL && fr->subclass == AST_CONTROL_TRANSFER) { + enum ast_control_transfer *message = fr->data.ptr; + + if (*message == AST_TRANSFER_SUCCESS) { + res = 1; + } else { + res = -1; + } + + ast_frfree(fr); + break; + } + + ast_frfree(fr); + } + return res; }