+ }
+ } else if (sipmethod == SIP_BYE)
+--- a/apps/app_queue.c
++++ b/apps/app_queue.c
+@@ -721,7 +721,7 @@ static void *device_state_thread(void *d
+ return NULL;
+ }
+ /*! \brief Producer of the statechange queue */
+-static int statechange_queue(const char *dev, int state, void *ign)
++static int statechange_queue(const char *dev, int state, void *ign, char *cid_num, char *cid_name)
+ {
+ struct statechange *sc;
+
+--- a/include/asterisk/manager.h
++++ b/include/asterisk/manager.h
+@@ -55,6 +55,7 @@
+ #define EVENT_FLAG_AGENT (1 << 5) /* Ability to read/set agent info */
+ #define EVENT_FLAG_USER (1 << 6) /* Ability to read/set user info */
+ #define EVENT_FLAG_CONFIG (1 << 7) /* Ability to modify configurations */
++#define EVENT_FLAG_EXTENSIONSTATUS (1 << 8) /* ExtensionStatus events */
+
+ /* Export manager structures */
+ #define AST_MAX_MANHEADERS 128
+--- a/main/manager.c
++++ b/main/manager.c
+@@ -129,6 +129,7 @@ static struct permalias {
+ { EVENT_FLAG_AGENT, "agent" },
+ { EVENT_FLAG_USER, "user" },
+ { EVENT_FLAG_CONFIG, "config" },
++ { EVENT_FLAG_EXTENSIONSTATUS, "extensionstatus" },
+ { -1, "all" },
+ { 0, "none" },
+ };
+@@ -2551,10 +2552,12 @@ int ast_manager_unregister(char *action)
+ return 0;
+ }
+
+-static int manager_state_cb(char *context, char *exten, int state, void *data)
++static int manager_state_cb(char *context, char *exten, int state, void *data, char *cid_num, char *cid_name)
+ {
++ char hint[256] = "";
++ ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
+ /* Notify managers of change */
+- manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
++ manager_event(EVENT_FLAG_EXTENSIONSTATUS, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\nCallerID: \"%s\" <%s>\r\nHint: %s\r\n", exten, context, state, cid_num, cid_name, hint);
+ return 0;
+ }
+
+--- a/apps/app_devstate.c
++++ b/apps/app_devstate.c
+@@ -50,7 +50,7 @@ static struct ast_cli_entry cli_dev_sta
+ static int devstate_cli(int fd, int argc, char *argv[])
+ {
+ char devName[128];
+- if (argc != 3)
++ if ((argc != 3) && (argc != 4) && (argc != 5))
+ return RESULT_SHOWUSAGE;
+
+ if (ast_db_put("DEVSTATES", argv[1], argv[2]))
+@@ -58,7 +58,15 @@ static int devstate_cli(int fd, int argc
+ ast_log(LOG_DEBUG, "ast_db_put failed\n");
+ }
+ snprintf(devName, sizeof(devName), "DS/%s", argv[1]);
+- ast_device_state_changed_literal(devName);
++ if (argc == 4) {
++ ast_log(LOG_NOTICE, "devname %s cid %s\n", devName, argv[3]);
++ ast_device_state_changed_literal(devName, argv[3], NULL);
++ } else if (argc == 5) {
++ ast_log(LOG_NOTICE, "devname %s cid %s cidname %s\n", devName, argv[3], argv[4]);
++ ast_device_state_changed_literal(devName, argv[3], argv[4]);
++ } else {
++ ast_device_state_changed_literal(devName, NULL, NULL);
++ }
+ return RESULT_SUCCESS;
+ }
+
+@@ -93,7 +101,7 @@ static int devstate_exec(struct ast_chan
+ }
+
+ snprintf(devName, sizeof(devName), "DS/%s", device);
+- ast_device_state_changed_literal(devName);
++ ast_device_state_changed_literal(devName, NULL, NULL);
+
+ ast_module_user_remove(u);
+ return 0;
+@@ -150,6 +158,8 @@ static int action_devstate(struct manses
+ const char *devstate = astman_get_header(m, "Devstate");
+ const char *value = astman_get_header(m, "Value");
+ const char *id = astman_get_header(m,"ActionID");
++ const char *cid_num = astman_get_header(m, "CallerID");
++ const char *cid_name = astman_get_header(m, "CallerIDName");
+ char devName[128];
+ char idText[256] = "";
+
+@@ -166,7 +176,7 @@ static int action_devstate(struct manses
+
+ if (!ast_db_put("DEVSTATES", devstate, (char *)value)) {
+ snprintf(devName, sizeof(devName), "DS/%s", devstate);
+- ast_device_state_changed_literal(devName);
++ ast_device_state_changed_literal(devName, cid_num, cid_name);
+ astman_append(s, "Response: Success\r\n%s\r\n", idText);
+ } else {
+ ast_log(LOG_DEBUG, "ast_db_put failed\n");
+--- a/res/res_esel.c
++++ b/res/res_esel.c
+@@ -51,6 +51,8 @@ typedef struct esel_extension_state {
+ char context[AST_MAX_EXTENSION];
+ char exten[AST_MAX_EXTENSION];
+ int state;
++ char cid_num[AST_MAX_EXTENSION];
++ char cid_name[AST_MAX_EXTENSION];
+ char devstate[AST_MAX_EXTENSION];
+ struct esel_extension_state *next;
+ struct esel_extension_state *prev;
+@@ -93,7 +95,7 @@ typedef struct esel_pvt {
+
+ static struct esel_pvt *donkeys = NULL;
+
+-static int esel_queue_extension_state(struct esel_queue *queue, char *context, char *exten, int state, void *data) {
++static int esel_queue_extension_state(struct esel_queue *queue, char *context, char *exten, int state, void *data, char *cid_num, char *cid_name) {
+ struct esel_extension_state *exstate = NULL;
+
+ exstate = malloc(sizeof(struct esel_extension_state));
+@@ -115,6 +117,8 @@ static int esel_queue_extension_state(st
+ }
+ ast_copy_string(exstate->exten, exten, sizeof(exstate->exten));
+ ast_copy_string(exstate->context, context, sizeof(exstate->context));
++ ast_copy_string(exstate->cid_num, cid_num, sizeof(exstate->cid_num));
++ ast_copy_string(exstate->cid_name, cid_name, sizeof(exstate->cid_name));
+ exstate->state = state;
+ if (!queue->head) {
+ /* Empty queue */
+@@ -161,7 +165,7 @@ static void esel_export_to_remote(struct
+ char msg[1024];
+ int sent = 0;
+ memset(msg, 0x0, sizeof(msg));
+- snprintf(msg, sizeof(msg) - 1, "Action: Devstate\r\nDevstate: %s\r\nValue: %d\r\n\r\n", exstate->devstate, esel_state2devstate(exstate->state));
++ snprintf(msg, sizeof(msg) - 1, "Action: Devstate\r\nDevstate: %s\r\nValue: %d\r\nCallerID: %s\r\nCallerIDName: %s\r\n\r\n", exstate->devstate, esel_state2devstate(exstate->state), exstate->cid_num, exstate->cid_name);
+ sent = send(esel->sockfd, msg, strlen(msg), 0);
+ if (sent == -1) {
+ esel->connected = 0;
+@@ -250,13 +254,13 @@ static void *do_esel_thread(void *data)
+ return NULL;
+ }
+
+-static int esel_state_cb(char *context, char *exten, int state, void *data) {
++static int esel_state_cb(char *context, char *exten, int state, void *data, char *cid_num, char *cid_name) {
+ struct esel_pvt *esel;
+
+ esel = donkeys;
+ ast_mutex_lock(&listlock);
+ while (esel) {
+- esel_queue_extension_state(&esel->queue, context, exten, state, data);
++ esel_queue_extension_state(&esel->queue, context, exten, state, data, cid_num, cid_name);
+ esel = esel->next;
+ }
+ ast_mutex_unlock(&listlock);
+Add or convert channel operations so they can use the unique ID.
+
+--- a/include/asterisk/channel.h
++++ b/include/asterisk/channel.h
+@@ -682,6 +682,18 @@ void ast_channel_free(struct ast_channe
+ */
+ struct ast_channel *ast_request(const char *type, int format, void *data, int *status);
+
++/*! \brief Requests a channel
++ * \param type type of channel to request
++ * \param format requested channel format (codec)
++ * \param data data to pass to the channel requester
++ * \param status status
++ * \param uniqueid uniqueid
++ * Request a channel of a given type, with data as optional information used
++ * by the low level module. Sets the channels uniqueid to 'uniqueid'.
++ * \return Returns an ast_channel on success, NULL on failure.
++ */
++struct ast_channel *ast_request_with_uniqueid(const char *type, int format, void *data, int *status, char *uniqueid);
++
+ /*!
+ * \brief Request a channel of a given type, with data as optional information used
+ * by the low level module and attempt to place a call on it
+@@ -697,8 +709,12 @@ struct ast_channel *ast_request(const ch
+ */
+ struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, const char *cidnum, const char *cidname);
+
++struct ast_channel *ast_request_and_dial_uniqueid(const char *type, int format, void *data, int timeout, int *reason, int callingpres, const char *cidnum, const char *cidname, char *uniqueid);
++
+ struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, const char *cidnum, const char *cidname, struct outgoing_helper *oh);
+
++struct ast_channel *__ast_request_and_dial_uniqueid(const char *type, int format, void *data, int timeout, int *reason, int callingpres, const char *cidnum, const char *cidname, struct outgoing_helper *oh, char *uniqueid);
++
+ /*! \brief "Requests" a channel for sending a message
+ * \param type type of channel to request
+ * \param data data to pass to the channel requester
+@@ -990,6 +1006,8 @@ struct ast_channel *ast_get_channel_by_e
+ /*! \brief Get next channel by exten (and optionally context) and lock it */
+ struct ast_channel *ast_walk_channel_by_exten_locked(const struct ast_channel *chan, const char *exten,
+ const char *context);
++/*! Get channel by uniqueid (locks channel) */
++struct ast_channel *ast_get_channel_by_uniqueid_locked(const char *uniqueid);
+
+ /*! ! \brief Waits for a digit
+ * \param c channel to wait for a digit on
+--- a/main/channel.c
++++ b/main/channel.c
+@@ -1017,7 +1017,7 @@ void ast_channel_undefer_dtmf(struct ast
+ */
+ static struct ast_channel *channel_find_locked(const struct ast_channel *prev,
+ const char *name, const int namelen,
+- const char *context, const char *exten)
++ const char *context, const char *exten, const char *uniqueid)
+ {
+ const char *msg = prev ? "deadlock" : "initial deadlock";
+ int retries;
+@@ -1045,7 +1045,10 @@ static struct ast_channel *channel_find_
+ * XXX Need a better explanation for this ...
+ */
+ }
+- if (name) { /* want match by name */
++ if (uniqueid) {
++ if (!strcasecmp(c->uniqueid, uniqueid))
++ break;
++ } else if (name) { /* want match by name */
+ if ((!namelen && strcasecmp(c->name, name)) ||
+ (namelen && strncasecmp(c->name, name, namelen)))
+ continue; /* name match failed */
+@@ -1100,39 +1103,44 @@ static struct ast_channel *channel_find_
+ /*! \brief Browse channels in use */
+ struct ast_channel *ast_channel_walk_locked(const struct ast_channel *prev)
+ {
+- return channel_find_locked(prev, NULL, 0, NULL, NULL);
++ return channel_find_locked(prev, NULL, 0, NULL, NULL, NULL);
+ }
+
+ /*! \brief Get channel by name and lock it */
+ struct ast_channel *ast_get_channel_by_name_locked(const char *name)
+ {
+- return channel_find_locked(NULL, name, 0, NULL, NULL);
++ return channel_find_locked(NULL, name, 0, NULL, NULL, NULL);
+ }
+
+ /*! \brief Get channel by name prefix and lock it */
+ struct ast_channel *ast_get_channel_by_name_prefix_locked(const char *name, const int namelen)
+ {
+- return channel_find_locked(NULL, name, namelen, NULL, NULL);
++ return channel_find_locked(NULL, name, namelen, NULL, NULL, NULL);
+ }
+
+ /*! \brief Get next channel by name prefix and lock it */
+ struct ast_channel *ast_walk_channel_by_name_prefix_locked(const struct ast_channel *chan, const char *name,
+ const int namelen)
+ {
+- return channel_find_locked(chan, name, namelen, NULL, NULL);
++ return channel_find_locked(chan, name, namelen, NULL, NULL, NULL);
+ }
+
+ /*! \brief Get channel by exten (and optionally context) and lock it */
+ struct ast_channel *ast_get_channel_by_exten_locked(const char *exten, const char *context)
+ {
+- return channel_find_locked(NULL, NULL, 0, context, exten);
++ return channel_find_locked(NULL, NULL, 0, context, exten, NULL);
+ }
+
+ /*! \brief Get next channel by exten (and optionally context) and lock it */
+ struct ast_channel *ast_walk_channel_by_exten_locked(const struct ast_channel *chan, const char *exten,
+ const char *context)
+ {
+- return channel_find_locked(chan, NULL, 0, context, exten);
++ return channel_find_locked(chan, NULL, 0, context, exten, NULL);
++}
++
++struct ast_channel *ast_get_channel_by_uniqueid_locked(const char *uniqueid)
++{
++ return channel_find_locked(NULL, NULL, 0, NULL, NULL, uniqueid);
+ }
+
+ /*! \brief Wait, look for hangups and condition arg */
+@@ -2862,6 +2870,12 @@ char *ast_channel_reason2str(int reason)
+
+ struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh)
+ {
++ return __ast_request_and_dial_uniqueid(type, format, data,
++ timeout, outstate, 0, cid_num, cid_name, oh, NULL);
++}
++
++struct ast_channel *__ast_request_and_dial_uniqueid(const char *type, int format, void *data, int timeout, int *outstate, int callingpres, const char *cid_num, const char *cid_name, struct outgoing_helper *oh, char* uniqueid)
++{
+ int dummy_outstate;
+ int cause = 0;
+ struct ast_channel *chan;
+@@ -2873,7 +2887,7 @@ struct ast_channel *__ast_request_and_di
+ else
+ outstate = &dummy_outstate; /* make outstate always a valid pointer */
+
+- chan = ast_request(type, format, data, &cause);
++ chan = ast_request_with_uniqueid(type, format, data, &cause, uniqueid);
+ if (!chan) {
+ ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
+ /* compute error and return */
+@@ -2993,8 +3007,12 @@ struct ast_channel *ast_request_and_dial
+ {
+ return __ast_request_and_dial(type, format, data, timeout, outstate, cidnum, cidname, NULL);
+ }
++struct ast_channel *ast_request_and_dial_uniqueid(const char *type, int format, void *data, int timeout, int *outstate, int callingpres, const char *cidnum, const char *cidname, char *uniqueid)
++{
++ return __ast_request_and_dial_uniqueid(type, format, data, timeout, outstate, 0, cidnum, cidname, NULL, uniqueid);
++}
+
+-struct ast_channel *ast_request(const char *type, int format, void *data, int *cause)
++struct ast_channel *ast_request_with_uniqueid(const char *type, int format, void *data, int *cause, char *uniqueid)
+ {
+ struct chanlist *chan;
+ struct ast_channel *c;
+@@ -3033,6 +3051,7 @@ struct ast_channel *ast_request(const ch
+ if (!(c = chan->tech->requester(type, capabilities | videoformat, data, cause)))
+ return NULL;
+
++ if (uniqueid) strncpy(c->uniqueid, uniqueid, sizeof(c->uniqueid));
+ /* no need to generate a Newchannel event here; it is done in the channel_alloc call */
+ return c;
+ }
+@@ -3044,6 +3063,11 @@ struct ast_channel *ast_request(const ch
+ return NULL;
+ }
+
++struct ast_channel *ast_request(const char *type, int format, void *data, int *cause)
++{
++ return ast_request_with_uniqueid(type, format, data, cause, NULL);
++}
++
+ int ast_call(struct ast_channel *chan, char *addr, int timeout)
+ {
+ /* Place an outgoing call, but don't wait any longer than timeout ms before returning.
+--- a/include/asterisk/pbx.h
++++ b/include/asterisk/pbx.h
+@@ -717,9 +717,17 @@ int ast_async_goto_by_name(const char *c
+ int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel);
+
+ /*! Synchronously or asynchronously make an outbound call and send it to a
++ particular extension (extended version with callinpres and uniqueid) */
++int ast_pbx_outgoing_exten_uniqueid(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, int callingpres, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, char *uniqueid);
++
++/*! Synchronously or asynchronously make an outbound call and send it to a
+ particular application with given extension */
+ int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel);
+
++/*! Synchronously or asynchronously make an outbound call and send it to a
++ particular application with given extension (extended version with callinpres and uniqueid) */
++int ast_pbx_outgoing_app_uniqueid(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, int callingpres, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, char *uniqueid);
++
+ /*!
+ * \brief Evaluate a condition
+ *
+--- a/main/pbx.c
++++ b/main/pbx.c
+@@ -4992,7 +4992,7 @@ static int ast_pbx_outgoing_cdr_failed(v
+ return 0; /* success */
+ }
+
+-int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
++int ast_pbx_outgoing_exten_uniqueid(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, int callingpres, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel, char *uniqueid)
+ {
+ struct ast_channel *chan;
+ struct async_stat *as;
+@@ -5002,7 +5002,7 @@ int ast_pbx_outgoing_exten(const char *t
+
+ if (sync) {
+ LOAD_OH(oh);
+- chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
++ chan = __ast_request_and_dial_uniqueid(type, format, data, timeout, reason, callingpres, cid_num, cid_name, &oh, uniqueid);
+ if (channel) {
+ *channel = chan;
+ if (chan)
+@@ -5094,7 +5094,7 @@ int ast_pbx_outgoing_exten(const char *t
+ res = -1;
+ goto outgoing_exten_cleanup;
+ }
+- chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
++ chan = ast_request_and_dial_uniqueid(type, format, data, timeout, reason, callingpres, cid_num, cid_name, uniqueid);
+ if (channel) {
+ *channel = chan;
+ if (chan)
+@@ -5134,6 +5134,10 @@ outgoing_exten_cleanup:
+ return res;
+ }
+
++int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
++{
++ return ast_pbx_outgoing_exten_uniqueid(type, format, data, timeout, context, exten, priority, reason, sync, 0, cid_num, cid_name, vars, account, channel, NULL);
++}
+ struct app_tmp {
+ char app[256];
+ char data[256];
+@@ -5158,7 +5162,7 @@ static void *ast_pbx_run_app(void *data)
+ return NULL;
+ }
+
+-int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
++int ast_pbx_outgoing_app_uniqueid(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, int callingpres, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, char *uniqueid)
+ {
+ struct ast_channel *chan;
+ struct app_tmp *tmp;
+@@ -5177,7 +5181,7 @@ int ast_pbx_outgoing_app(const char *typ
+ goto outgoing_app_cleanup;
+ }
+ if (sync) {
+- chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
++ chan = __ast_request_and_dial_uniqueid(type, format, data, timeout, reason, callingpres, cid_num, cid_name, &oh, uniqueid);
+ if (chan) {
+ if (!chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
+ chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
+@@ -5259,7 +5263,7 @@ int ast_pbx_outgoing_app(const char *typ
+ res = -1;
+ goto outgoing_app_cleanup;
+ }
+- chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
++ chan = __ast_request_and_dial_uniqueid(type, format, data, timeout, reason, callingpres, cid_num, cid_name, &oh, uniqueid);
+ if (!chan) {
+ free(as);
+ res = -1;
+@@ -5299,6 +5303,10 @@ outgoing_app_cleanup:
+ return res;
+ }
+
++int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
++{
++ return ast_pbx_outgoing_app_uniqueid(type, format, data, timeout, app, appdata, reason, sync, 0, cid_num, cid_name, vars, account, locked_channel, NULL);
++}
+ void __ast_context_destroy(struct ast_context *con, const char *registrar)
+ {
+ struct ast_context *tmp, *tmpl=NULL;
+--- a/res/res_monitor.c
++++ b/res/res_monitor.c
+@@ -340,6 +340,11 @@ int ast_monitor_stop(struct ast_channel
+ result = ast_safe_system(tmp);
+ if (result == -1)
+ ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
++ manager_event(EVENT_FLAG_CALL, "MonitorStopped",
++ "Channel: %s\r\n"
++ "Uniqueid: %s\r\n"
++ "Result: %d\r\n"
++ ,chan->name, chan->uniqueid, result);
+ }
+
+ free(chan->monitor->format);
+@@ -518,18 +523,28 @@ static int start_monitor_action(struct m
+ const char *fname = astman_get_header(m, "File");
+ const char *format = astman_get_header(m, "Format");
+ const char *mix = astman_get_header(m, "Mix");
++ const char *uniqueid = astman_get_header(m, "Uniqueid");
+ const char *target_url = astman_get_header(m, "TargetURL");
+ const char *target_script = astman_get_header(m, "TargetScript");
+ char *d;
+
+- if (ast_strlen_zero(name)) {
+- astman_send_error(s, m, "No channel specified");
++ if (ast_strlen_zero(name) && ast_strlen_zero(uniqueid)) {
++ astman_send_error(s, m, "No channel/uniqueid specified");
++ return 0;
++ }
++
++ if (!ast_strlen_zero(uniqueid)) {
++ c = ast_get_channel_by_uniqueid_locked(uniqueid);
++ if (!c) {
++ astman_send_error(s, m, "No such uniqueid");
+ return 0;
+- }
+- c = ast_get_channel_by_name_locked(name);
+- if (!c) {
++ }
++ } else {
++ c = ast_get_channel_by_name_locked(name);
++ if (!c) {
+ astman_send_error(s, m, "No such channel");
+ return 0;
++ }
+ }
+
+ if (ast_strlen_zero(fname)) {
+@@ -570,16 +585,30 @@ static int stop_monitor_action(struct ma
+ {
+ struct ast_channel *c = NULL;
+ const char *name = astman_get_header(m, "Channel");
++ const char *uniqueid = astman_get_header(m, "Uniqueid");
+ int res;
+ if (ast_strlen_zero(name)) {
+ astman_send_error(s, m, "No channel specified");
+ return 0;
+ }
+- c = ast_get_channel_by_name_locked(name);
+- if (!c) {
+- astman_send_error(s, m, "No such channel");
++ if (ast_strlen_zero(name) && ast_strlen_zero(uniqueid)) {
++ astman_send_error(s, m, "No channel/uniqueid specified");
++ return 0;
++ }
++ if (!ast_strlen_zero(uniqueid)) {
++ c = ast_get_channel_by_uniqueid_locked(uniqueid);
++ if (!c) {
++ astman_send_error(s, m, "No such uniqueid");
+ return 0;
++ }
++ } else {
++ c = ast_get_channel_by_name_locked(name);
++ if (!c) {
++ astman_send_error(s, m, "No such channel");
++ return 0;
++ }
+ }
++
+ res = ast_monitor_stop(c, 1);
+ ast_channel_unlock(c);
+ if (res) {
+--- a/apps/app_chanspy.c
++++ b/apps/app_chanspy.c
+@@ -57,6 +57,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi
+
+ static const char *tdesc = "Listen to a channel, and optionally whisper into it";
+ static const char *app_chan = "ChanSpy";
++static const char *app_chan_uniqueid = "ChanSpyChan";
+ static const char *desc_chan =
+ " ChanSpy([chanprefix][|options]): This application is used to listen to the\n"
+ "audio from an Asterisk channel. This includes the audio coming in and\n"
+@@ -87,6 +88,27 @@ static const char *desc_chan =
+ " channel.\n"
+ ;
+
++static const char *desc_uniqueid =
++" ChanSpyChan(uniqueid[|options]): This application is used to listen to the\n"
++"audio from an Asterisk channel. This includes the audio coming in and\n"
++"out of the channel being spied on. The 'uniqueid' parameter has to be specified,\n"
++" While spying, the following actions may be performed:\n"
++" - Dialing # cycles the volume level.\n"
++" Options:\n"
++" q - Don't play a beep when beginning to spy on a channel, or speak the\n"
++" selected channel name.\n"
++" r[(basename)] - Record the session to the monitor spool directory. An\n"
++" optional base for the filename may be specified. The\n"
++" default is 'chanspy'.\n"
++" v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
++" negative value refers to a quieter setting.\n"
++" w - Enable 'whisper' mode, so the spying channel can talk to\n"
++" the spied-on channel.\n"
++" W - Enable 'private whisper' mode, so the spying channel can\n"
++" talk to the spied-on channel but cannot listen to that\n"
++" channel.\n"
++;
++
+ static const char *app_ext = "ExtenSpy";
+ static const char *desc_ext =
+ " ExtenSpy(exten[@context][|options]): This application is used to listen to the\n"
+@@ -456,7 +478,7 @@ static struct chanspy_ds *setup_chanspy_
+
+ static struct chanspy_ds *next_channel(struct ast_channel *chan,
+ const struct ast_channel *last, const char *spec,
+- const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
++ const char *exten, const char *context, struct chanspy_ds *chanspy_ds, const char *uniqueid)
+ {
+ struct ast_channel *this;
+
+@@ -465,6 +487,8 @@ redo:
+ this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
+ else if (exten)
+ this = ast_walk_channel_by_exten_locked(last, exten, context);
++ else if (uniqueid)
++ this = ast_get_channel_by_uniqueid_locked(uniqueid);
+ else
+ this = ast_channel_walk_locked(last);
+
+@@ -485,7 +509,7 @@ redo:
+
+ static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
+ int volfactor, const int fd, const char *mygroup, const char *spec,
+- const char *exten, const char *context)
++ const char *exten, const char *context, const char *uniqueid)
+ {
+ char nameprefix[AST_NAME_STRLEN];
+ char peer_name[AST_NAME_STRLEN + 5];
+@@ -530,11 +554,11 @@ static int common_exec(struct ast_channe
+ waitms = 100;
+ num_spyed_upon = 0;
+
+- for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
++ for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds, NULL);
+ peer_chanspy_ds;
+ chanspy_ds_free(peer_chanspy_ds), prev = peer,
+ peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds :
+- next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
++ next_channel(chan, prev, spec, exten, context, &chanspy_ds, NULL), next_chanspy_ds = NULL) {
+ const char *group;
+ int igrp = !mygroup;
+ char *groups[25];
+@@ -733,7 +757,7 @@ static int chanspy_exec(struct ast_chann
+ }
+ }
+
+- res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL);
++ res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL, NULL);
+
+ if (fd)
+ close(fd);
+@@ -818,7 +842,7 @@ static int extenspy_exec(struct ast_chan
+ }
+ }
+
+- res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context);
++ res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context, NULL);
+
+ if (fd)
+ close(fd);
+@@ -831,14 +855,100 @@ static int extenspy_exec(struct ast_chan
+ return res;
+ }
+
++static int chanspychan_exec(struct ast_channel *chan, void *data)
++{
++ struct ast_module_user *u;
++ char *options = NULL;
++ char *uniqueid = NULL;
++ char *argv[2];
++ char *mygroup = NULL;
++ char *recbase = NULL;
++ int fd = 0;
++ struct ast_flags flags;
++ int oldwf = 0;
++ int argc = 0;
++ int volfactor = 0;
++ int res;
++
++ data = ast_strdupa(data);
++
++ u = ast_module_user_add(chan);
++
++ if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
++ uniqueid = argv[0];
++ if (argc > 1)
++ options = argv[1];
++
++ if (ast_strlen_zero(uniqueid)) {
++ ast_log(LOG_ERROR, "no uniqueid specified.\n");
++ ast_module_user_remove(u);
++ return -1;
++ }
++ }
++
++ if (options) {
++ char *opts[OPT_ARG_ARRAY_SIZE];
++
++ ast_app_parse_options(spy_opts, &flags, opts, options);
++ if (ast_test_flag(&flags, OPTION_GROUP))
++ mygroup = opts[OPT_ARG_GROUP];
++
++ if (ast_test_flag(&flags, OPTION_RECORD) &&
++ !(recbase = opts[OPT_ARG_RECORD]))
++ recbase = "chanspy";
++
++ if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
++ int vol;
++
++ if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
++ ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
++ else
++ volfactor = vol;
++ }
++
++ if (ast_test_flag(&flags, OPTION_PRIVATE))
++ ast_set_flag(&flags, OPTION_WHISPER);
++ }
++
++ oldwf = chan->writeformat;
++ if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
++ ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
++ ast_module_user_remove(u);
++ return -1;
++ }
++
++ if (recbase) {
++ char filename[512];
++
++ snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
++ if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
++ ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
++ fd = 0;
++ }
++ }
++
++ res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, NULL, uniqueid);
++
++ if (fd)
++ close(fd);
++
++ if (oldwf && ast_set_write_format(chan, oldwf) < 0)
++ ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
++
++ ast_module_user_remove(u);
++
++ return res;
++}
++
++
+ static int unload_module(void)
+ {
+ int res = 0;
+
+ res |= ast_unregister_application(app_chan);
++ res |= ast_unregister_application(app_chan_uniqueid);
+ res |= ast_unregister_application(app_ext);
+
+- ast_module_user_hangup_all();
+
+ return res;
+ }
+@@ -849,6 +959,7 @@ static int load_module(void)
+
+ res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
+ res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
++ res |= ast_register_application(app_chan_uniqueid, chanspychan_exec, tdesc, desc_uniqueid);
+
+ return res;
+ }
+--- a/main/manager.c
++++ b/main/manager.c
+@@ -87,6 +87,8 @@ struct fast_originate_helper {
+ char idtext[AST_MAX_EXTENSION];
+ char account[AST_MAX_ACCOUNT_CODE];
+ int priority;
++ int callingpres;
++ char uniqueid[64];
+ struct ast_variable *vars;
+ };
+
+@@ -1416,11 +1418,20 @@ static int action_hangup(struct mansessi
+ {
+ struct ast_channel *c = NULL;
+ const char *name = astman_get_header(m, "Channel");
+- if (ast_strlen_zero(name)) {
+- astman_send_error(s, m, "No channel specified");
++ const char *uniqueid = astman_get_header(m, "Uniqueid");
++
++ if (ast_strlen_zero(name) && ast_strlen_zero(uniqueid)) {
++ astman_send_error(s, m, "No channel or uniqueid specified");
+ return 0;
+ }
+- c = ast_get_channel_by_name_locked(name);
++
++ if (!ast_strlen_zero(uniqueid)) {
++ c = ast_get_channel_by_uniqueid_locked(uniqueid);
++ } else {
++ if (!ast_strlen_zero(name))
++ c = ast_get_channel_by_name_locked(name);
++ }
++
+ if (!c) {
+ astman_send_error(s, m, "No such channel");
+ return 0;
+@@ -1671,12 +1682,18 @@ static int action_redirect(struct manses
+ const char *exten = astman_get_header(m, "Exten");
+ const char *context = astman_get_header(m, "Context");
+ const char *priority = astman_get_header(m, "Priority");
++ const char *uniqueid = astman_get_header(m, "Uniqueid");
++ const char *uniqueid2 = astman_get_header(m, "ExtraUniqueid");
++ const char *exten2 = astman_get_header(m, "ExtraExten");
++ const char *context2 = astman_get_header(m, "ExtraContext");
++ const char *priority2 = astman_get_header(m, "ExtraPriority");
+ struct ast_channel *chan, *chan2 = NULL;
+ int pi = 0;
++ int pi2 = 0;
+ int res;
+
+- if (ast_strlen_zero(name)) {
+- astman_send_error(s, m, "Channel not specified");
++ if (ast_strlen_zero(name) && ast_strlen_zero(uniqueid)) {
++ astman_send_error(s, m, "Channel or Uniqueid not specified");
+ return 0;
+ }
+ if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
+@@ -1685,8 +1702,18 @@ static int action_redirect(struct manses
+ return 0;
+ }
+ }
++ if (!ast_strlen_zero(priority2) && (sscanf(priority2, "%d", &pi2) != 1)) {
++ if ((pi = ast_findlabel_extension(NULL, context2, exten2, priority2, NULL)) < 1) {
++ astman_send_error(s, m, "Invalid extra priority\n");
++ return 0;
++ }
++ }
+ /* XXX watch out, possible deadlock!!! */
+- chan = ast_get_channel_by_name_locked(name);
++ if (!ast_strlen_zero(uniqueid)) {
++ chan = ast_get_channel_by_uniqueid_locked(uniqueid);
++ } else {
++ chan = ast_get_channel_by_name_locked(name);
++ }
+ if (!chan) {
+ char buf[BUFSIZ];
+ snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
+@@ -1698,8 +1725,11 @@ static int action_redirect(struct manses
+ ast_channel_unlock(chan);
+ return 0;
+ }
+- if (!ast_strlen_zero(name2))
++ if (!ast_strlen_zero(uniqueid2)) {
++ chan2 = ast_get_channel_by_uniqueid_locked(uniqueid2);
++ } else if (!ast_strlen_zero(name2)) {
+ chan2 = ast_get_channel_by_name_locked(name2);
++ }
+ if (chan2 && ast_check_hangup(chan2)) {
+ astman_send_error(s, m, "Redirect failed, extra channel not up.\n");
+ ast_channel_unlock(chan);
+@@ -1708,9 +1738,9 @@ static int action_redirect(struct manses
+ }
+ res = ast_async_goto(chan, context, exten, pi);
+ if (!res) {
+- if (!ast_strlen_zero(name2)) {
++ if ((!ast_strlen_zero(name2)) || (!ast_strlen_zero(uniqueid2))){
+ if (chan2)
+- res = ast_async_goto(chan2, context, exten, pi);
++ res = ast_async_goto(chan2, context2, exten2, pi2);
+ else
+ res = -1;
+ if (!res)
+@@ -1789,15 +1819,15 @@ static void *fast_originate(void *data)
+ char requested_channel[AST_CHANNEL_NAME];
+
+ if (!ast_strlen_zero(in->app)) {
+- res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1,
++ res = ast_pbx_outgoing_app_uniqueid(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, in->callingpres,
+ S_OR(in->cid_num, NULL),
+ S_OR(in->cid_name, NULL),
+- in->vars, in->account, &chan);
++ in->vars, in->account, &chan, in->uniqueid);
+ } else {
+- res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
++ res = ast_pbx_outgoing_exten_uniqueid(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, in->callingpres,
+ S_OR(in->cid_num, NULL),
+ S_OR(in->cid_name, NULL),
+- in->vars, in->account, &chan);
++ in->vars, in->account, &chan, in->uniqueid);
+ }
+
+ if (!chan)
+@@ -1857,6 +1887,7 @@ static int action_originate(struct manse
+ const char *appdata = astman_get_header(m, "Data");
+ const char *async = astman_get_header(m, "Async");
+ const char *id = astman_get_header(m, "ActionID");
++ const char *callingpres = astman_get_header(m, "CallingPres");
+ struct ast_variable *vars = astman_get_variables(m);
+ char *tech, *data;
+ char *l = NULL, *n = NULL;
+@@ -1866,6 +1897,9 @@ static int action_originate(struct manse
+ int reason = 0;
+ char tmp[256];
+ char tmp2[256];
++ char *uniqueid;
++ int cpresi = 0;
++ char idText[256] = "";
+
+ pthread_t th;
+ pthread_attr_t attr;
+@@ -1883,6 +1917,10 @@ static int action_originate(struct manse
+ astman_send_error(s, m, "Invalid timeout\n");
+ return 0;
+ }
++ if (!ast_strlen_zero(callingpres) && (sscanf(callingpres, "%d", &cpresi) != 1)) {
++ astman_send_error(s, m, "Invalid CallingPres\n");
++ return 0;
++ }
+ ast_copy_string(tmp, name, sizeof(tmp));
+ tech = tmp;
+ data = strchr(tmp, '/');
+@@ -1902,6 +1940,7 @@ static int action_originate(struct manse
+ if (ast_strlen_zero(l))
+ l = NULL;
+ }
++ uniqueid = ast_alloc_uniqueid();
+ if (ast_true(async)) {
+ struct fast_originate_helper *fast = ast_calloc(1, sizeof(*fast));
+ if (!fast) {
+@@ -1921,8 +1960,10 @@ static int action_originate(struct manse
+ ast_copy_string(fast->context, context, sizeof(fast->context));
+ ast_copy_string(fast->exten, exten, sizeof(fast->exten));
+ ast_copy_string(fast->account, account, sizeof(fast->account));
++ ast_copy_string(fast->uniqueid, uniqueid, sizeof(fast->uniqueid));
+ fast->timeout = to;
+ fast->priority = pi;
++ fast->callingpres = cpresi;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
+@@ -1933,19 +1974,28 @@ static int action_originate(struct manse
+ pthread_attr_destroy(&attr);
+ }
+ } else if (!ast_strlen_zero(app)) {
+- res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
++ res = ast_pbx_outgoing_app_uniqueid(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, cpresi, l, n, vars, account, NULL, uniqueid);
+ } else {
+ if (exten && context && pi)
+- res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
++ res = ast_pbx_outgoing_exten_uniqueid(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, cpresi, l, n, vars, account, NULL, uniqueid);
+ else {
+ astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
+ return 0;
+ }
+ }
+- if (!res)
+- astman_send_ack(s, m, "Originate successfully queued");
+- else
++ if (!res) {
++ if (id && !ast_strlen_zero(id)) {
++ snprintf(idText,256,"ActionID: %s\r\n",id);
++ }
++ ast_cli(s->fd, "Response: Success\r\n"
++ "%s"
++ "Message: Originate successfully queued\r\n"
++ "Uniqueid: %s\r\n"
++ "\r\n",
++ idText, uniqueid);
++ } else {
+ astman_send_error(s, m, "Originate failed");
++ }
+ return 0;
+ }
+
+--- a/include/asterisk/channel.h
++++ b/include/asterisk/channel.h
+@@ -89,6 +89,9 @@
+
+ #include "asterisk/abstract_jb.h"
+
++/* Max length of the uniqueid */
++#define AST_MAX_UNIQUEID 64
++
+ #include <unistd.h>
+ #ifdef POLLCOMPAT
+ #include "asterisk/poll-compat.h"
+@@ -1039,6 +1042,8 @@ int ast_waitfordigit_full(struct ast_cha
+ int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders);
+ int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders, int audiofd, int ctrlfd);
+
++char *ast_alloc_uniqueid(void);
++
+ /*! \brief Report DTMF on channel 0 */
+ #define AST_BRIDGE_DTMF_CHANNEL_0 (1 << 0)
+ /*! \brief Report DTMF on channel 1 */
+--- a/main/channel.c
++++ b/main/channel.c
+@@ -706,6 +706,15 @@ static const struct ast_channel_tech nul
+ .description = "Null channel (should not see this)",
+ };
+
++/*! \brief Create a uniqueid */
++char *ast_alloc_uniqueid(void) {
++ char *uniqueid;
++ uniqueid = malloc(64);
++ if (!uniqueid) return NULL;
++ snprintf(uniqueid, 63, "%s-%d-%li.%d", ast_config_AST_SYSTEM_NAME, ast_mainpid, (long)time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1));
++ return uniqueid;
++}
++
+ /*! \brief Create a new channel structure */
+ 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 int amaflag, const char *name_fmt, ...)
+ {
+--- a/include/asterisk/features.h
++++ b/include/asterisk/features.h
+@@ -47,6 +47,8 @@ struct ast_call_feature {
+ };