mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +00:00 
			
		
		
		
	Analog lines do not transfer CONNECTED LINE or execute the interception macros.
Add connected line update for sig_analog transfers and simplify the corresponding sig_pri and chan_misdn transfer code. Note that if you create a three-way call in sig_analog before transferring the call, the distinction of the caller/callee interception macros make little sense. The interception macro writer needs to be prepared for either caller/callee macro to be executed. The current implementation swaps which caller/callee interception macro is executed after a three-way call is created. Review: https://reviewboard.asterisk.org/r/996/ JIRA ABE-2589 JIRA SWP-2372 git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@294349 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
		
							
								
								
									
										207
									
								
								main/channel.c
									
									
									
									
									
								
							
							
						
						
									
										207
									
								
								main/channel.c
									
									
									
									
									
								
							| @@ -5589,7 +5589,7 @@ int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *pe | ||||
| 	return rc; | ||||
| } | ||||
|  | ||||
| int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clonechan) | ||||
| static int __ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clonechan, struct ast_datastore *xfer_ds) | ||||
| { | ||||
| 	int res = -1; | ||||
| 	struct ast_channel *final_orig, *final_clone, *base; | ||||
| @@ -5651,6 +5651,9 @@ retrymasq: | ||||
| 	if (!original->masqr && !original->masq && !clonechan->masq && !clonechan->masqr) { | ||||
| 		original->masq = clonechan; | ||||
| 		clonechan->masqr = original; | ||||
| 		if (xfer_ds) { | ||||
| 			ast_channel_datastore_add(original, xfer_ds); | ||||
| 		} | ||||
| 		ast_queue_frame(original, &ast_null_frame); | ||||
| 		ast_queue_frame(clonechan, &ast_null_frame); | ||||
| 		ast_debug(1, "Done planning to masquerade channel %s into the structure of %s\n", clonechan->name, original->name); | ||||
| @@ -5676,6 +5679,115 @@ retrymasq: | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone) | ||||
| { | ||||
| 	return __ast_channel_masquerade(original, clone, NULL); | ||||
| } | ||||
|  | ||||
| /*! | ||||
|  * \internal | ||||
|  * \brief Copy the source connected line information to the destination for a transfer. | ||||
|  * \since 1.8 | ||||
|  * | ||||
|  * \param dest Destination connected line | ||||
|  * \param src Source connected line | ||||
|  * | ||||
|  * \return Nothing | ||||
|  */ | ||||
| static void party_connected_line_copy_transfer(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src) | ||||
| { | ||||
| 	struct ast_party_connected_line connected; | ||||
|  | ||||
| 	connected = *((struct ast_party_connected_line *) src); | ||||
| 	connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; | ||||
|  | ||||
| 	/* Make sure empty strings will be erased. */ | ||||
| 	if (!connected.id.name.str) { | ||||
| 		connected.id.name.str = ""; | ||||
| 	} | ||||
| 	if (!connected.id.number.str) { | ||||
| 		connected.id.number.str = ""; | ||||
| 	} | ||||
| 	if (!connected.id.subaddress.str) { | ||||
| 		connected.id.subaddress.str = ""; | ||||
| 	} | ||||
| 	if (!connected.id.tag) { | ||||
| 		connected.id.tag = ""; | ||||
| 	} | ||||
|  | ||||
| 	ast_party_connected_line_copy(dest, &connected); | ||||
| } | ||||
|  | ||||
| /*! Transfer masquerade connected line exchange data. */ | ||||
| struct xfer_masquerade_ds { | ||||
| 	/*! New ID for the target of the transfer (Masquerade original channel) */ | ||||
| 	struct ast_party_connected_line target_id; | ||||
| 	/*! New ID for the transferee of the transfer (Masquerade clone channel) */ | ||||
| 	struct ast_party_connected_line transferee_id; | ||||
| 	/*! TRUE if the target call is held. (Masquerade original channel) */ | ||||
| 	int target_held; | ||||
| 	/*! TRUE if the transferee call is held. (Masquerade clone channel) */ | ||||
| 	int transferee_held; | ||||
| }; | ||||
|  | ||||
| /*! | ||||
|  * \internal | ||||
|  * \brief Destroy the transfer connected line exchange datastore information. | ||||
|  * \since 1.8 | ||||
|  * | ||||
|  * \param data The datastore payload to destroy. | ||||
|  * | ||||
|  * \return Nothing | ||||
|  */ | ||||
| static void xfer_ds_destroy(void *data) | ||||
| { | ||||
| 	struct xfer_masquerade_ds *ds = data; | ||||
|  | ||||
| 	ast_party_connected_line_free(&ds->target_id); | ||||
| 	ast_party_connected_line_free(&ds->transferee_id); | ||||
| 	ast_free(ds); | ||||
| } | ||||
|  | ||||
| static const struct ast_datastore_info xfer_ds_info = { | ||||
| 	.type = "xfer_colp", | ||||
| 	.destroy = xfer_ds_destroy, | ||||
| }; | ||||
|  | ||||
| int ast_channel_transfer_masquerade( | ||||
| 	struct ast_channel *target_chan, | ||||
| 	const struct ast_party_connected_line *target_id, | ||||
| 	int target_held, | ||||
| 	struct ast_channel *transferee_chan, | ||||
| 	const struct ast_party_connected_line *transferee_id, | ||||
| 	int transferee_held) | ||||
| { | ||||
| 	struct ast_datastore *xfer_ds; | ||||
| 	struct xfer_masquerade_ds *xfer_colp; | ||||
| 	int res; | ||||
|  | ||||
| 	xfer_ds = ast_datastore_alloc(&xfer_ds_info, NULL); | ||||
| 	if (!xfer_ds) { | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	xfer_colp = ast_calloc(1, sizeof(*xfer_colp)); | ||||
| 	if (!xfer_colp) { | ||||
| 		ast_datastore_free(xfer_ds); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	party_connected_line_copy_transfer(&xfer_colp->target_id, target_id); | ||||
| 	xfer_colp->target_held = target_held; | ||||
| 	party_connected_line_copy_transfer(&xfer_colp->transferee_id, transferee_id); | ||||
| 	xfer_colp->transferee_held = transferee_held; | ||||
| 	xfer_ds->data = xfer_colp; | ||||
|  | ||||
| 	res = __ast_channel_masquerade(target_chan, transferee_chan, xfer_ds); | ||||
| 	if (res) { | ||||
| 		ast_datastore_free(xfer_ds); | ||||
| 	} | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| /*! \brief this function simply changes the name of the channel and issues a manager_event | ||||
|  *         with out unlinking and linking the channel from the ao2_container.  This should | ||||
|  *         only be used when the channel has already been unlinked from the ao2_container. | ||||
| @@ -5942,12 +6054,63 @@ static void report_new_callerid(struct ast_channel *chan) | ||||
| } | ||||
|  | ||||
| /*! | ||||
|   \brief Masquerade a channel | ||||
|  * \internal | ||||
|  * \brief Transfer COLP between target and transferee channels. | ||||
|  * \since 1.8 | ||||
|  * | ||||
|  * \param transferee Transferee channel to exchange connected line information. | ||||
|  * \param colp Connected line information to exchange. | ||||
|  * | ||||
|  * \return Nothing | ||||
|  */ | ||||
| static void masquerade_colp_transfer(struct ast_channel *transferee, struct xfer_masquerade_ds *colp) | ||||
| { | ||||
| 	struct ast_control_read_action_payload *frame_payload; | ||||
| 	int payload_size; | ||||
| 	int frame_size; | ||||
| 	unsigned char connected_line_data[1024]; | ||||
|  | ||||
|   \note Assumes _NO_ channels and _NO_ channel pvt's are locked.  If a channel is locked while calling | ||||
|         this function, it invalidates our channel container locking order.  All channels | ||||
| 		must be unlocked before it is permissible to lock the channels' ao2 container. | ||||
| */ | ||||
| 	/* Release any hold on the target. */ | ||||
| 	if (colp->target_held) { | ||||
| 		ast_queue_control(transferee, AST_CONTROL_UNHOLD); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Since transferee may not actually be bridged to another channel, | ||||
| 	 * there is no way for us to queue a frame so that its connected | ||||
| 	 * line status will be updated.  Instead, we use the somewhat | ||||
| 	 * hackish approach of using a special control frame type that | ||||
| 	 * instructs ast_read() to perform a specific action.  In this | ||||
| 	 * case, the frame we queue tells ast_read() to call the | ||||
| 	 * connected line interception macro configured for transferee. | ||||
| 	 */ | ||||
| 	payload_size = ast_connected_line_build_data(connected_line_data, | ||||
| 		sizeof(connected_line_data), &colp->target_id, NULL); | ||||
| 	if (payload_size != -1) { | ||||
| 		frame_size = payload_size + sizeof(*frame_payload); | ||||
| 		frame_payload = alloca(frame_size); | ||||
| 		frame_payload->action = AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO; | ||||
| 		frame_payload->payload_size = payload_size; | ||||
| 		memcpy(frame_payload->payload, connected_line_data, payload_size); | ||||
| 		ast_queue_control_data(transferee, AST_CONTROL_READ_ACTION, frame_payload, | ||||
| 			frame_size); | ||||
| 	} | ||||
| 	/* | ||||
| 	 * In addition to queueing the read action frame so that the | ||||
| 	 * connected line info on transferee will be updated, we also are | ||||
| 	 * going to queue a plain old connected line update on transferee to | ||||
| 	 * update the target. | ||||
| 	 */ | ||||
| 	ast_channel_queue_connected_line_update(transferee, &colp->transferee_id, NULL); | ||||
| } | ||||
|  | ||||
| /*! | ||||
|  * \brief Masquerade a channel | ||||
|  * | ||||
|  * \note Assumes _NO_ channels and _NO_ channel pvt's are locked.  If a channel is locked while calling | ||||
|  *       this function, it invalidates our channel container locking order.  All channels | ||||
|  *       must be unlocked before it is permissible to lock the channels' ao2 container. | ||||
|  */ | ||||
| int ast_do_masquerade(struct ast_channel *original) | ||||
| { | ||||
| 	format_t x; | ||||
| @@ -5967,6 +6130,8 @@ int ast_do_masquerade(struct ast_channel *original) | ||||
| 	struct ast_channel *clonechan, *chans[2]; | ||||
| 	struct ast_channel *bridged; | ||||
| 	struct ast_cdr *cdr; | ||||
| 	struct ast_datastore *xfer_ds; | ||||
| 	struct xfer_masquerade_ds *xfer_colp; | ||||
| 	format_t rformat = original->readformat; | ||||
| 	format_t wformat = original->writeformat; | ||||
| 	char newn[AST_CHANNEL_NAME]; | ||||
| @@ -6015,6 +6180,23 @@ int ast_do_masquerade(struct ast_channel *original) | ||||
| 		CHANNEL_DEADLOCK_AVOIDANCE(original); | ||||
| 	} | ||||
|  | ||||
| 	/* Get any transfer masquerade connected line exchange data. */ | ||||
| 	xfer_ds = ast_channel_datastore_find(original, &xfer_ds_info, NULL); | ||||
| 	if (xfer_ds) { | ||||
| 		ast_channel_datastore_remove(original, xfer_ds); | ||||
| 		xfer_colp = xfer_ds->data; | ||||
| 	} else { | ||||
| 		xfer_colp = NULL; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Release any hold on the transferee channel before proceeding | ||||
| 	 * with the masquerade. | ||||
| 	 */ | ||||
| 	if (xfer_colp && xfer_colp->transferee_held) { | ||||
| 		ast_indicate(clonechan, AST_CONTROL_UNHOLD); | ||||
| 	} | ||||
|  | ||||
| 	/* clear the masquerade channels */ | ||||
| 	original->masq = NULL; | ||||
| 	clonechan->masqr = NULL; | ||||
| @@ -6301,10 +6483,21 @@ int ast_do_masquerade(struct ast_channel *original) | ||||
| 		ast_indicate(bridged, AST_CONTROL_SRCCHANGE); | ||||
| 		ast_channel_unlock(bridged); | ||||
| 	} | ||||
|  | ||||
| 	ast_indicate(original, AST_CONTROL_SRCCHANGE); | ||||
|  | ||||
| 	if (xfer_colp) { | ||||
| 		/* | ||||
| 		 * After the masquerade, the original channel pointer actually | ||||
| 		 * points to the new transferee channel and the bridged channel | ||||
| 		 * is still the intended transfer target party. | ||||
| 		 */ | ||||
| 		masquerade_colp_transfer(original, xfer_colp); | ||||
| 	} | ||||
|  | ||||
| done: | ||||
| 	if (xfer_ds) { | ||||
| 		ast_datastore_free(xfer_ds); | ||||
| 	} | ||||
| 	/* it is possible for the clone channel to disappear during this */ | ||||
| 	if (clonechan) { | ||||
| 		ast_channel_unlock(original); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user