Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 231431) +++ channels/chan_sip.c (working copy) @@ -17101,6 +17101,8 @@ */ 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; @@ -17120,11 +17122,17 @@ 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)); + } p->needdestroy = 1; } 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; + if (p->owner) { + ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message)); + } p->needdestroy = 1; } break; @@ -17146,11 +17154,17 @@ ast_log(LOG_NOTICE, "SIP transfer to %s failed, call miserably fails. \n", p->refer->refer_to); p->needdestroy = 1; 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; p->needdestroy = 1; + if (p->owner) { + ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message)); + } break; } } @@ -18195,7 +18209,11 @@ 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); }; @@ -24387,6 +24405,11 @@ 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; } Index: channels/chan_iax2.c =================================================================== --- channels/chan_iax2.c (revision 231431) +++ channels/chan_iax2.c (working copy) @@ -5271,6 +5271,7 @@ 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) { @@ -5281,6 +5282,7 @@ 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); } Index: include/asterisk/frame.h =================================================================== --- include/asterisk/frame.h (revision 231431) +++ include/asterisk/frame.h (working copy) @@ -305,6 +305,7 @@ AST_CONTROL_VIDUPDATE = 18, /*!< Indicate video frame update */ _XXX_AST_CONTROL_T38 = 19, /*!< T38 state change request/notification \deprecated This is no longer supported. Use AST_CONTROL_T38_PARAMETERS instead. */ AST_CONTROL_SRCUPDATE = 20, /*!< Indicate source of media has changed */ + AST_CONTROL_TRANSFER = 21, /*!< Indicate status of a transfer request */ AST_CONTROL_T38_PARAMETERS = 24, /*!< T38 state change request/notification with parameters */ }; @@ -341,6 +342,11 @@ unsigned int transcoding_jbig:1; /*!< Set if JBIG transcoding can be used */ }; +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) Index: main/channel.c =================================================================== --- main/channel.c (revision 231431) +++ main/channel.c (working copy) @@ -3063,6 +3063,7 @@ case AST_CONTROL_HANGUP: case AST_CONTROL_T38_PARAMETERS: case _XXX_AST_CONTROL_T38: + case AST_CONTROL_TRANSFER: break; case AST_CONTROL_CONGESTION: @@ -3169,6 +3170,7 @@ case AST_CONTROL_RING: case AST_CONTROL_HOLD: case AST_CONTROL_UNHOLD: + case AST_CONTROL_TRANSFER: /* Nothing left to do for these. */ res = 0; break; @@ -4009,6 +4011,37 @@ 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; }