Skip to content
Snippets Groups Projects
channel.c 328 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	ast_channel_stage_snapshot_done(tmp);
    
    
    	ast_debug(1, "Channel %p '%s' allocated\n", tmp, ast_channel_name(tmp));
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return tmp;
    }
    
    
    struct ast_channel *__ast_channel_alloc(int needqueue, int state, const char *cid_num,
    					const char *cid_name, const char *acctcode,
    
    					const char *exten, const char *context, const struct ast_assigned_ids *assignedids,
    					const struct ast_channel *requestor, enum ama_flags amaflag,
    
    					const char *file, int line, const char *function,
    					const char *name_fmt, ...)
    
    	va_list ap;
    
    	va_start(ap, name_fmt);
    
    	result = __ast_channel_alloc_ap(needqueue, state, cid_num, cid_name, acctcode, exten, context,
    
    					assignedids, requestor, amaflag, endpoint, file, line, function, name_fmt, ap);
    
    	va_end(ap);
    
    /* only do the minimum amount of work needed here to make a channel
     * structure that can be used to expand channel vars */
    
    #if defined(REF_DEBUG) || defined(__AST_DEBUG_MALLOC)
    struct ast_channel *__ast_dummy_channel_alloc(const char *file, int line, const char *function)
    #else
    
    struct ast_channel *ast_dummy_channel_alloc(void)
    
    {
    	struct ast_channel *tmp;
    	struct varshead *headp;
    
    
    	if (!(tmp = ast_channel_internal_alloc(ast_dummy_channel_destructor, NULL, NULL))) {
    
    		/* Dummy channel structure allocation failure. */
    
    	ast_pbx_hangup_handler_init(tmp);
    	AST_LIST_HEAD_INIT_NOLOCK(ast_channel_datastores(tmp));
    
    
    	/*
    	 * Init file descriptors to unopened state just in case
    	 * autoservice is called on the channel or something tries to
    	 * read a frame from it.
    	 */
    	ast_channel_timingfd_set(tmp, -1);
    	ast_channel_internal_alertpipe_clear(tmp);
    	ast_channel_internal_fd_clear_all(tmp);
    #ifdef HAVE_EPOLL
    
    	ast_channel_epfd_set(tmp, -1);
    
    	ast_channel_hold_state_set(tmp, AST_CONTROL_UNHOLD);
    
    
    	ast_channel_internal_setup_topics(tmp);
    
    
    	headp = ast_channel_varshead(tmp);
    
    	AST_LIST_HEAD_INIT_NOLOCK(headp);
    
    	return tmp;
    }
    
    
    static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int head, struct ast_frame *after)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct ast_frame *f;
    
    	struct ast_frame *cur;
    
    	unsigned int new_frames = 0;
    	unsigned int new_voice_frames = 0;
    	unsigned int queued_frames = 0;
    	unsigned int queued_voice_frames = 0;
    
    	AST_LIST_HEAD_NOLOCK(,ast_frame) frames;
    
    	ast_channel_lock(chan);
    
    	/*
    	 * Check the last frame on the queue if we are queuing the new
    	 * frames after it.
    	 */
    
    	cur = AST_LIST_LAST(ast_channel_readq(chan));
    
    	if (cur && cur->frametype == AST_FRAME_CONTROL && !head && (!after || after == cur)) {
    		switch (cur->subclass.integer) {
    		case AST_CONTROL_END_OF_Q:
    			if (fin->frametype == AST_FRAME_CONTROL
    				&& fin->subclass.integer == AST_CONTROL_HANGUP) {
    				/*
    				 * Destroy the end-of-Q marker frame so we can queue the hangup
    				 * frame in its place.
    				 */
    
    				AST_LIST_REMOVE(ast_channel_readq(chan), cur, frame_list);
    
    				ast_frfree(cur);
    
    				/*
    				 * This has degenerated to a normal queue append anyway.  Since
    				 * we just destroyed the last frame in the queue we must make
    				 * sure that "after" is NULL or bad things will happen.
    				 */
    				after = NULL;
    				break;
    			}
    			/* Fall through */
    		case AST_CONTROL_HANGUP:
    			/* Don't queue anything. */
    			ast_channel_unlock(chan);
    			return 0;
    		default:
    			break;
    		}
    
    	/* Build copies of all the new frames and count them */
    
    	AST_LIST_HEAD_INIT_NOLOCK(&frames);
    	for (cur = fin; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
    		if (!(f = ast_frdup(cur))) {
    
    			if (AST_LIST_FIRST(&frames)) {
    				ast_frfree(AST_LIST_FIRST(&frames));
    			}
    
    			ast_channel_unlock(chan);
    
    			return -1;
    		}
    
    		AST_LIST_INSERT_TAIL(&frames, f, frame_list);
    		new_frames++;
    		if (f->frametype == AST_FRAME_VOICE) {
    			new_voice_frames++;
    		}
    	}
    
    
    	/* Count how many frames exist on the queue */
    
    	AST_LIST_TRAVERSE(ast_channel_readq(chan), cur, frame_list) {
    
    		queued_frames++;
    		if (cur->frametype == AST_FRAME_VOICE) {
    			queued_voice_frames++;
    		}
    
    	if ((queued_frames + new_frames > 128 || queued_voice_frames + new_voice_frames > 96)) {
    		int count = 0;
    
    		ast_log(LOG_WARNING, "Exceptionally long %squeue length queuing to %s\n", queued_frames + new_frames > 128 ? "" : "voice ", ast_channel_name(chan));
    
    		AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), cur, frame_list) {
    
    			/* Save the most recent frame */
    			if (!AST_LIST_NEXT(cur, frame_list)) {
    				break;
    			} else if (cur->frametype == AST_FRAME_VOICE || cur->frametype == AST_FRAME_VIDEO || cur->frametype == AST_FRAME_NULL) {
    				if (++count > 64) {
    					break;
    				}
    				AST_LIST_REMOVE_CURRENT(frame_list);
    				ast_frfree(cur);
    
    
    				/* Read from the alert pipe for each flushed frame. */
    				ast_channel_internal_alert_read(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    		AST_LIST_TRAVERSE_SAFE_END;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    		AST_LIST_INSERT_LIST_AFTER(ast_channel_readq(chan), &frames, after, frame_list);
    
    			AST_LIST_APPEND_LIST(&frames, ast_channel_readq(chan), frame_list);
    			AST_LIST_HEAD_INIT_NOLOCK(ast_channel_readq(chan));
    
    		AST_LIST_APPEND_LIST(ast_channel_readq(chan), &frames, frame_list);
    
    	if (ast_channel_alert_writable(chan)) {
    
    		/* Write to the alert pipe for each added frame */
    		while (new_frames--) {
    			if (ast_channel_alert_write(chan)) {
    				ast_log(LOG_WARNING, "Unable to write to alert pipe on %s (qlen = %u): %s!\n",
    					ast_channel_name(chan), queued_frames, strerror(errno));
    				break;
    			}
    
    	} else if (ast_channel_timingfd(chan) > -1) {
    		ast_timer_enable_continuous(ast_channel_timer(chan));
    
    	} else if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING)) {
    		pthread_kill(ast_channel_blocker(chan), SIGURG);
    
    	ast_channel_unlock(chan);
    
    int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin)
    
    	return __ast_queue_frame(chan, fin, 0, NULL);
    
    int ast_queue_frame_head(struct ast_channel *chan, struct ast_frame *fin)
    
    	return __ast_queue_frame(chan, fin, 1, NULL);
    
    /*! \brief Queue a hangup frame for channel */
    
    int ast_queue_hangup(struct ast_channel *chan)
    {
    
    	struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HANGUP };
    
    	/* Yeah, let's not change a lock-critical value without locking */
    
    	ast_channel_lock(chan);
    	ast_channel_softhangup_internal_flag_add(chan, AST_SOFTHANGUP_DEV);
    
    	ast_channel_publish_blob(chan, ast_channel_hangup_request_type(), NULL);
    
    
    	res = ast_queue_frame(chan, &f);
    	ast_channel_unlock(chan);
    	return res;
    
    }
    
    /*! \brief Queue a hangup frame for channel */
    int ast_queue_hangup_with_cause(struct ast_channel *chan, int cause)
    
    	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
    
    	struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HANGUP };
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    	/* Yeah, let's not change a lock-critical value without locking */
    
    	ast_channel_lock(chan);
    	ast_channel_softhangup_internal_flag_add(chan, AST_SOFTHANGUP_DEV);
    	if (cause < 0) {
    		f.data.uint32 = ast_channel_hangupcause(chan);
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    	}
    
    	blob = ast_json_pack("{s: i}",
    
    	ast_channel_publish_blob(chan, ast_channel_hangup_request_type(), blob);
    
    
    	res = ast_queue_frame(chan, &f);
    	ast_channel_unlock(chan);
    	return res;
    
    int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
    {
    	struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HOLD };
    
    	struct ast_json *blob = NULL;
    
    	int res;
    
    	if (!ast_strlen_zero(musicclass)) {
    		f.data.ptr = (void *) musicclass;
    		f.datalen = strlen(musicclass) + 1;
    
    		blob = ast_json_pack("{s: s}",
    				     "musicclass", musicclass);
    	}
    
    
    	ast_channel_publish_cached_blob(chan, ast_channel_hold_type(), blob);
    
    
    	res = ast_queue_frame(chan, &f);
    
    	return res;
    }
    
    int ast_queue_unhold(struct ast_channel *chan)
    {
    	struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_UNHOLD };
    	int res;
    
    
    	ast_channel_publish_cached_blob(chan, ast_channel_unhold_type(), NULL);
    
    
    	res = ast_queue_frame(chan, &f);
    
    /*! \brief Queue a control frame */
    
    int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
    
    	struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = control };
    
    	return ast_queue_frame(chan, &f);
    }
    
    /*! \brief Queue a control frame with payload */
    int ast_queue_control_data(struct ast_channel *chan, enum ast_control_frame_type control,
    			   const void *data, size_t datalen)
    {
    
    	struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = control, .data.ptr = (void *) data, .datalen = datalen };
    
    /*! \brief Set defer DTMF flag on channel */
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_channel_defer_dtmf(struct ast_channel *chan)
    {
    	int pre = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (chan) {
    
    		pre = ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_DTMF);
    		ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEFER_DTMF);
    
    /*! \brief Unset defer DTMF flag on channel */
    
    Mark Spencer's avatar
    Mark Spencer committed
    void ast_channel_undefer_dtmf(struct ast_channel *chan)
    {
    
    	if (chan) {
    		ast_channel_clear_flag(chan, AST_FLAG_DEFER_DTMF);
    	}
    
    struct ast_channel *ast_channel_callback(ao2_callback_data_fn *cb_fn, void *arg,
    		void *data, int ao2_flags)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	return ao2_callback_data(channels, ao2_flags, cb_fn, arg, data);
    }
    
    
    static int ast_channel_by_name_cb(void *obj, void *arg, void *data, int flags)
    {
    	struct ast_channel *chan = obj;
    
    	const char *name = arg;
    
    	size_t name_len = *(size_t *) data;
    
    	int ret = CMP_MATCH;
    
    	if (ast_strlen_zero(name)) {
    
    		ast_log(LOG_ERROR, "BUG! Must supply a channel name or partial name to match!\n");
    
    		return CMP_STOP;
    	}
    
    	ast_channel_lock(chan);
    
    	if ((!name_len && strcasecmp(ast_channel_name(chan), name))
    		|| (name_len && strncasecmp(ast_channel_name(chan), name, name_len))) {
    
    		ret = 0; /* name match failed, keep looking */
    	}
    	ast_channel_unlock(chan);
    
    	return ret;
    }
    
    static int ast_channel_by_exten_cb(void *obj, void *arg, void *data, int flags)
    {
    	struct ast_channel *chan = obj;
    
    	char *context = arg;
    	char *exten = data;
    
    	int ret = CMP_MATCH;
    
    	if (ast_strlen_zero(exten) || ast_strlen_zero(context)) {
    		ast_log(LOG_ERROR, "BUG! Must have a context and extension to match!\n");
    		return CMP_STOP;
    	}
    
    	ast_channel_lock(chan);
    
    	if (strcasecmp(ast_channel_context(chan), context) && strcasecmp(ast_channel_macrocontext(chan), context)) {
    
    		ret = 0; /* Context match failed, continue */
    
    	} else if (strcasecmp(ast_channel_exten(chan), exten) && strcasecmp(ast_channel_macroexten(chan), exten)) {
    
    		ret = 0; /* Extension match failed, continue */
    	}
    	ast_channel_unlock(chan);
    
    	return ret;
    }
    
    static int ast_channel_by_uniqueid_cb(void *obj, void *arg, void *data, int flags)
    {
    	struct ast_channel *chan = obj;
    	char *uniqueid = arg;
    
    	size_t id_len = *(size_t *) data;
    
    	int ret = CMP_MATCH;
    
    	if (ast_strlen_zero(uniqueid)) {
    
    		ast_log(LOG_ERROR, "BUG! Must supply a uniqueid or partial uniqueid to match!\n");
    
    		return CMP_STOP;
    	}
    
    	ast_channel_lock(chan);
    
    	if ((!id_len && strcasecmp(ast_channel_uniqueid(chan), uniqueid))
    		|| (id_len && strncasecmp(ast_channel_uniqueid(chan), uniqueid, id_len))) {
    		ret = 0; /* uniqueid match failed, keep looking */
    
    	/* storage for non-dynamically allocated iterator */
    	struct ao2_iterator simple_iterator;
    	/* pointer to the actual iterator (simple_iterator or a dynamically
    	 * allocated iterator)
    	 */
    	struct ao2_iterator *active_iterator;
    
    };
    
    struct ast_channel_iterator *ast_channel_iterator_destroy(struct ast_channel_iterator *i)
    {
    
    struct ast_channel_iterator *ast_channel_iterator_by_exten_new(const char *exten, const char *context)
    
    	char *l_exten = (char *) exten;
    	char *l_context = (char *) context;
    
    
    	if (!(i = ast_calloc(1, sizeof(*i)))) {
    		return NULL;
    	}
    
    
    	i->active_iterator = (void *) ast_channel_callback(ast_channel_by_exten_cb,
    		l_context, l_exten, OBJ_MULTIPLE);
    	if (!i->active_iterator) {
    
    struct ast_channel_iterator *ast_channel_iterator_by_name_new(const char *name, size_t name_len)
    
    	struct ast_channel_iterator *i;
    	char *l_name = (char *) name;
    
    	if (!(i = ast_calloc(1, sizeof(*i)))) {
    		return NULL;
    	}
    
    	i->active_iterator = (void *) ast_channel_callback(ast_channel_by_name_cb,
    		l_name, &name_len,
    		OBJ_MULTIPLE | (name_len == 0 /* match the whole word, so optimize */ ? OBJ_KEY : 0));
    	if (!i->active_iterator) {
    		ast_free(i);
    		return NULL;
    	}
    
    	return i;
    
    struct ast_channel_iterator *ast_channel_iterator_all_new(void)
    
    	i->simple_iterator = ao2_iterator_init(channels, 0);
    	i->active_iterator = &i->simple_iterator;
    
    struct ast_channel *ast_channel_iterator_next(struct ast_channel_iterator *i)
    {
    	return ao2_iterator_next(i->active_iterator);
    
    /* Legacy function, not currently used for lookups, but we need a cmp_fn */
    
    static int ast_channel_cmp_cb(void *obj, void *arg, int flags)
    {
    
    	ast_log(LOG_ERROR, "BUG! Should never be called!\n");
    	return CMP_STOP;
    
    struct ast_channel *ast_channel_get_by_name_prefix(const char *name, size_t name_len)
    
    	struct ast_channel *chan;
    
    	char *l_name = (char *) name;
    
    	chan = ast_channel_callback(ast_channel_by_name_cb, l_name, &name_len,
    		(name_len == 0) /* optimize if it is a complete name match */ ? OBJ_KEY : 0);
    	if (chan) {
    
    	if (ast_strlen_zero(l_name)) {
    		/* We didn't have a name to search for so quit. */
    
    	/* Now try a search for uniqueid. */
    
    	return ast_channel_callback(ast_channel_by_uniqueid_cb, l_name, &name_len, 0);
    
    struct ast_channel *ast_channel_get_by_name(const char *name)
    
    	return ast_channel_get_by_name_prefix(name, 0);
    
    struct ast_channel *ast_channel_get_by_exten(const char *exten, const char *context)
    {
    
    	char *l_exten = (char *) exten;
    	char *l_context = (char *) context;
    
    	return ast_channel_callback(ast_channel_by_exten_cb, l_context, l_exten, 0);
    
    int ast_is_deferrable_frame(const struct ast_frame *frame)
    {
    	/* Do not add a default entry in this switch statement.  Each new
    	 * frame type should be addressed directly as to whether it should
    	 * be queued up or not.
    	 */
    	switch (frame->frametype) {
    
    	case AST_FRAME_CONTROL:
    	case AST_FRAME_TEXT:
    	case AST_FRAME_IMAGE:
    	case AST_FRAME_HTML:
    		return 1;
    
    
    	case AST_FRAME_DTMF_END:
    
    	case AST_FRAME_DTMF_BEGIN:
    	case AST_FRAME_VOICE:
    	case AST_FRAME_VIDEO:
    	case AST_FRAME_NULL:
    	case AST_FRAME_IAX:
    	case AST_FRAME_CNG:
    	case AST_FRAME_MODEM:
    		return 0;
    	}
    	return 0;
    }
    
    
    /*! \brief Wait, look for hangups and condition arg */
    
    int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*cond)(void*), void *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct ast_frame *f;
    
    	struct ast_silence_generator *silgen = NULL;
    	int res = 0;
    
    	struct timeval start;
    	int ms;
    
    	AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
    
    	AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
    
    
    	/* If no other generator is present, start silencegen while waiting */
    
    	if (ast_opt_transmit_silence && !ast_channel_generatordata(chan)) {
    
    		silgen = ast_channel_start_silence_generator(chan);
    	}
    
    	start = ast_tvnow();
    	while ((ms = ast_remaining_ms(start, timeout_ms))) {
    
    		struct ast_frame *dup_f = NULL;
    
    
    		if (cond && ((*cond)(data) == 0)) {
    			break;
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ms = ast_waitfor(chan, ms);
    
    		if (ms < 0) {
    			res = -1;
    			break;
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (ms > 0) {
    			f = ast_read(chan);
    
    			if (!f) {
    				res = -1;
    				break;
    			}
    
    
    			if (!ast_is_deferrable_frame(f)) {
    				ast_frfree(f);
    				continue;
    			}
    
    			if ((dup_f = ast_frisolate(f))) {
    				if (dup_f != f) {
    					ast_frfree(f);
    				}
    				AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list);
    			}
    
    
    	/* stop silgen if present */
    	if (silgen) {
    		ast_channel_stop_silence_generator(chan, silgen);
    	}
    
    
    	/* We need to free all the deferred frames, but we only need to
    	 * queue the deferred frames if there was no error and no
    	 * hangup was received
    	 */
    
    	ast_channel_lock(chan);
    
    	while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
    		if (!res) {
    			ast_queue_frame_head(chan, f);
    		}
    		ast_frfree(f);
    	}
    
    	ast_channel_unlock(chan);
    
    
    	return res;
    
    /*! \brief Wait, look for hangups */
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_safe_sleep(struct ast_channel *chan, int ms)
    {
    
    	return ast_safe_sleep_conditional(chan, ms, NULL, NULL);
    
    struct ast_channel *ast_channel_release(struct ast_channel *chan)
    {
    	/* Safe, even if already unlinked. */
    	ao2_unlink(channels, chan);
    	return ast_channel_unref(chan);
    }
    
    
    void ast_party_name_init(struct ast_party_name *init)
    {
    	init->str = NULL;
    	init->char_set = AST_PARTY_CHAR_SET_ISO8859_1;
    	init->presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
    	init->valid = 0;
    }
    
    void ast_party_name_copy(struct ast_party_name *dest, const struct ast_party_name *src)
    {
    	if (dest == src) {
    		/* Don't copy to self */
    		return;
    	}
    
    	ast_free(dest->str);
    	dest->str = ast_strdup(src->str);
    	dest->char_set = src->char_set;
    	dest->presentation = src->presentation;
    	dest->valid = src->valid;
    }
    
    void ast_party_name_set_init(struct ast_party_name *init, const struct ast_party_name *guide)
    {
    	init->str = NULL;
    	init->char_set = guide->char_set;
    	init->presentation = guide->presentation;
    	init->valid = guide->valid;
    }
    
    void ast_party_name_set(struct ast_party_name *dest, const struct ast_party_name *src)
    {
    	if (dest == src) {
    		/* Don't set to self */
    		return;
    	}
    
    	if (src->str && src->str != dest->str) {
    		ast_free(dest->str);
    		dest->str = ast_strdup(src->str);
    	}
    
    	dest->char_set = src->char_set;
    	dest->presentation = src->presentation;
    	dest->valid = src->valid;
    }
    
    void ast_party_name_free(struct ast_party_name *doomed)
    {
    	ast_free(doomed->str);
    	doomed->str = NULL;
    }
    
    void ast_party_number_init(struct ast_party_number *init)
    {
    	init->str = NULL;
    	init->plan = 0;/* Unknown */
    	init->presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
    	init->valid = 0;
    }
    
    void ast_party_number_copy(struct ast_party_number *dest, const struct ast_party_number *src)
    {
    	if (dest == src) {
    		/* Don't copy to self */
    		return;
    	}
    
    	ast_free(dest->str);
    	dest->str = ast_strdup(src->str);
    	dest->plan = src->plan;
    	dest->presentation = src->presentation;
    	dest->valid = src->valid;
    }
    
    void ast_party_number_set_init(struct ast_party_number *init, const struct ast_party_number *guide)
    {
    	init->str = NULL;
    	init->plan = guide->plan;
    	init->presentation = guide->presentation;
    	init->valid = guide->valid;
    }
    
    void ast_party_number_set(struct ast_party_number *dest, const struct ast_party_number *src)
    {
    	if (dest == src) {
    		/* Don't set to self */
    		return;
    	}
    
    	if (src->str && src->str != dest->str) {
    		ast_free(dest->str);
    		dest->str = ast_strdup(src->str);
    	}
    
    	dest->plan = src->plan;
    	dest->presentation = src->presentation;
    	dest->valid = src->valid;
    }
    
    void ast_party_number_free(struct ast_party_number *doomed)
    {
    	ast_free(doomed->str);
    	doomed->str = NULL;
    }
    
    
    void ast_party_subaddress_init(struct ast_party_subaddress *init)
    {
    	init->str = NULL;
    	init->type = 0;
    	init->odd_even_indicator = 0;
    	init->valid = 0;
    }
    
    void ast_party_subaddress_copy(struct ast_party_subaddress *dest, const struct ast_party_subaddress *src)
    {
    	if (dest == src) {
    		/* Don't copy to self */
    		return;
    	}
    
    
    	ast_free(dest->str);
    
    	dest->str = ast_strdup(src->str);
    	dest->type = src->type;
    	dest->odd_even_indicator = src->odd_even_indicator;
    	dest->valid = src->valid;
    }
    
    void ast_party_subaddress_set_init(struct ast_party_subaddress *init, const struct ast_party_subaddress *guide)
    {
    	init->str = NULL;
    	init->type = guide->type;
    	init->odd_even_indicator = guide->odd_even_indicator;
    	init->valid = guide->valid;
    }
    
    void ast_party_subaddress_set(struct ast_party_subaddress *dest, const struct ast_party_subaddress *src)
    {
    	if (dest == src) {
    		/* Don't set to self */
    		return;
    	}
    
    	if (src->str && src->str != dest->str) {
    
    		ast_free(dest->str);
    
    		dest->str = ast_strdup(src->str);
    	}
    
    	dest->type = src->type;
    	dest->odd_even_indicator = src->odd_even_indicator;
    	dest->valid = src->valid;
    }
    
    void ast_party_subaddress_free(struct ast_party_subaddress *doomed)
    {
    
    	ast_free(doomed->str);
    	doomed->str = NULL;
    
    void ast_set_party_id_all(struct ast_set_party_id *update_id)
    {
    	update_id->name = 1;
    	update_id->number = 1;
    	update_id->subaddress = 1;
    }
    
    
    void ast_party_id_init(struct ast_party_id *init)
    
    	ast_party_name_init(&init->name);
    	ast_party_number_init(&init->number);
    
    	ast_party_subaddress_init(&init->subaddress);
    
    	init->tag = NULL;
    
    void ast_party_id_copy(struct ast_party_id *dest, const struct ast_party_id *src)
    
    	ast_party_name_copy(&dest->name, &src->name);
    	ast_party_number_copy(&dest->number, &src->number);
    	ast_party_subaddress_copy(&dest->subaddress, &src->subaddress);
    
    	ast_free(dest->tag);
    
    	dest->tag = ast_strdup(src->tag);
    
    void ast_party_id_set_init(struct ast_party_id *init, const struct ast_party_id *guide)
    
    	ast_party_name_set_init(&init->name, &guide->name);
    	ast_party_number_set_init(&init->number, &guide->number);
    
    	ast_party_subaddress_set_init(&init->subaddress, &guide->subaddress);
    
    	init->tag = NULL;
    
    void ast_party_id_set(struct ast_party_id *dest, const struct ast_party_id *src, const struct ast_set_party_id *update)
    
    	if (!update || update->name) {
    		ast_party_name_set(&dest->name, &src->name);
    
    	if (!update || update->number) {
    		ast_party_number_set(&dest->number, &src->number);
    	}
    	if (!update || update->subaddress) {
    		ast_party_subaddress_set(&dest->subaddress, &src->subaddress);
    
    	if (src->tag && src->tag != dest->tag) {
    
    		ast_free(dest->tag);
    
    		dest->tag = ast_strdup(src->tag);
    	}
    
    void ast_party_id_free(struct ast_party_id *doomed)
    
    	ast_party_name_free(&doomed->name);
    	ast_party_number_free(&doomed->number);
    	ast_party_subaddress_free(&doomed->subaddress);
    
    	ast_free(doomed->tag);
    	doomed->tag = NULL;
    }
    
    int ast_party_id_presentation(const struct ast_party_id *id)
    {
    	int number_priority;
    	int number_value;
    	int number_screening;
    	int name_priority;
    	int name_value;
    
    	/* Determine name presentation priority. */
    	if (!id->name.valid) {
    		name_value = AST_PRES_UNAVAILABLE;
    		name_priority = 3;
    	} else {
    		name_value = id->name.presentation & AST_PRES_RESTRICTION;
    		switch (name_value) {
    		case AST_PRES_RESTRICTED:
    			name_priority = 0;
    			break;
    		case AST_PRES_ALLOWED:
    			name_priority = 1;
    			break;
    		case AST_PRES_UNAVAILABLE:
    			name_priority = 2;
    			break;
    		default:
    			name_value = AST_PRES_UNAVAILABLE;
    			name_priority = 3;
    			break;
    		}
    
    	/* Determine number presentation priority. */
    	if (!id->number.valid) {
    		number_screening = AST_PRES_USER_NUMBER_UNSCREENED;
    		number_value = AST_PRES_UNAVAILABLE;
    		number_priority = 3;
    	} else {
    		number_screening = id->number.presentation & AST_PRES_NUMBER_TYPE;
    		number_value = id->number.presentation & AST_PRES_RESTRICTION;
    		switch (number_value) {
    		case AST_PRES_RESTRICTED:
    			number_priority = 0;
    			break;
    		case AST_PRES_ALLOWED:
    			number_priority = 1;
    			break;
    		case AST_PRES_UNAVAILABLE:
    			number_priority = 2;
    			break;
    		default:
    			number_screening = AST_PRES_USER_NUMBER_UNSCREENED;
    			number_value = AST_PRES_UNAVAILABLE;
    			number_priority = 3;
    			break;
    		}
    
    	/* Select the wining presentation value. */
    	if (name_priority < number_priority) {
    		number_value = name_value;
    
    	if (number_value == AST_PRES_UNAVAILABLE) {
    		return AST_PRES_NUMBER_NOT_AVAILABLE;
    	}
    
    
    	return number_value | number_screening;
    
    void ast_party_id_invalidate(struct ast_party_id *id)
    {
    	id->name.valid = 0;
    	id->number.valid = 0;
    	id->subaddress.valid = 0;
    }
    
    void ast_party_id_reset(struct ast_party_id *id)
    {
    	ast_party_id_free(id);
    	ast_party_id_init(id);
    }
    
    struct ast_party_id ast_party_id_merge(struct ast_party_id *base, struct ast_party_id *overlay)
    {
    	struct ast_party_id merged;
    
    	merged = *base;
    	if (overlay->name.valid) {
    		merged.name = overlay->name;
    	}
    	if (overlay->number.valid) {
    		merged.number = overlay->number;
    	}
    	if (overlay->subaddress.valid) {
    		merged.subaddress = overlay->subaddress;
    	}
    	/* Note the actual structure is returned and not a pointer to it! */
    	return merged;
    }
    
    void ast_party_id_merge_copy(struct ast_party_id *dest, struct ast_party_id *base, struct ast_party_id *overlay)
    {
    	struct ast_party_id merged;
    
    	merged = ast_party_id_merge(base, overlay);
    	ast_party_id_copy(dest, &merged);
    }
    
    
    void ast_party_dialed_init(struct ast_party_dialed *init)
    
    	init->number.str = NULL;
    	init->number.plan = 0;/* Unknown */
    	ast_party_subaddress_init(&init->subaddress);
    	init->transit_network_select = 0;
    
    void ast_party_dialed_copy(struct ast_party_dialed *dest, const struct ast_party_dialed *src)
    
    	ast_free(dest->number.str);
    	dest->number.str = ast_strdup(src->number.str);
    	dest->number.plan = src->number.plan;
    	ast_party_subaddress_copy(&dest->subaddress, &src->subaddress);
    	dest->transit_network_select = src->transit_network_select;
    }
    
    void ast_party_dialed_set_init(struct ast_party_dialed *init, const struct ast_party_dialed *guide)
    {
    	init->number.str = NULL;
    	init->number.plan = guide->number.plan;
    	ast_party_subaddress_set_init(&init->subaddress, &guide->subaddress);
    	init->transit_network_select = guide->transit_network_select;
    }
    
    void ast_party_dialed_set(struct ast_party_dialed *dest, const struct ast_party_dialed *src)
    {
    	if (src->number.str && src->number.str != dest->number.str) {
    		ast_free(dest->number.str);
    		dest->number.str = ast_strdup(src->number.str);
    
    	dest->number.plan = src->number.plan;
    
    	ast_party_subaddress_set(&dest->subaddress, &src->subaddress);
    
    	dest->transit_network_select = src->transit_network_select;
    }
    
    void ast_party_dialed_free(struct ast_party_dialed *doomed)
    {