diff --git a/CHANGES b/CHANGES index fddaecc4d9..388cfbfc5a 100644 --- a/CHANGES +++ b/CHANGES @@ -277,6 +277,9 @@ Asterisk Manager Interface but options with the 'tls' prefix are preferred. * Added a MuteAudio AMI action for muting inbound and/or outbound audio in a channel. (res_mutestream.so) + * The configuration file manager.conf now supports a channelvars option, which + specifies a list of channel variables to include in each channel-oriented + event. Channel Event Logging --------------------- diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index b7b25c6b6d..96748e6671 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -513,6 +513,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto struct ast_silence_generator *silgen = NULL; struct ast_autochan *spyee_bridge_autochan = NULL; const char *spyer_name; + struct ast_channel *chans[] = { chan, spyee_autochan->chan }; ast_channel_lock(chan); spyer_name = ast_strdupa(chan->name); @@ -529,7 +530,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto ast_channel_unlock(spyee_autochan->chan); ast_verb(2, "Spying on channel %s\n", name); - manager_event(EVENT_FLAG_CALL, "ChanSpyStart", + ast_manager_event_multichan(EVENT_FLAG_CALL, "ChanSpyStart", 2, chans, "SpyerChannel: %s\r\n" "SpyeeChannel: %s\r\n", spyer_name, name); @@ -697,7 +698,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto } ast_verb(2, "Done Spying on channel %s\n", name); - manager_event(EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name); + ast_manager_event(chan, EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name); return running; } diff --git a/apps/app_dial.c b/apps/app_dial.c index c6747bffc3..0ef64b3cc2 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -722,7 +722,8 @@ static const char *get_cid_name(char *name, int namelen, struct ast_channel *cha static void senddialevent(struct ast_channel *src, struct ast_channel *dst, const char *dialstring) { - manager_event(EVENT_FLAG_CALL, "Dial", + struct ast_channel *chans[] = { src, dst }; + ast_manager_event_multichan(EVENT_FLAG_CALL, "Dial", 2, chans, "SubEvent: Begin\r\n" "Channel: %s\r\n" "Destination: %s\r\n" @@ -736,9 +737,9 @@ static void senddialevent(struct ast_channel *src, struct ast_channel *dst, cons dst->uniqueid, dialstring ? dialstring : ""); } -static void senddialendevent(const struct ast_channel *src, const char *dialstatus) +static void senddialendevent(struct ast_channel *src, const char *dialstatus) { - manager_event(EVENT_FLAG_CALL, "Dial", + ast_manager_event(src, EVENT_FLAG_CALL, "Dial", "SubEvent: End\r\n" "Channel: %s\r\n" "UniqueID: %s\r\n" diff --git a/apps/app_fax.c b/apps/app_fax.c index 6f61116390..a1448cf1e4 100644 --- a/apps/app_fax.c +++ b/apps/app_fax.c @@ -248,7 +248,7 @@ static void phase_e_handler(t30_state_t *f, void *user_data, int result) ast_debug(1, " Image resolution: %d x %d\n", stat.x_resolution, stat.y_resolution); ast_debug(1, " Transfer Rate: %d\n", stat.bit_rate); - manager_event(EVENT_FLAG_CALL, + ast_manager_event(s->chan, EVENT_FLAG_CALL, s->direction ? "FaxSent" : "FaxReceived", "Channel: %s\r\n" "Exten: %s\r\n" diff --git a/apps/app_meetme.c b/apps/app_meetme.c index 0f9299b037..35221326e2 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -2508,7 +2508,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c ast_debug(1, "Placed channel %s in DAHDI conf %d\n", chan->name, conf->dahdiconf); if (!sent_event) { - manager_event(EVENT_FLAG_CALL, "MeetmeJoin", + ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeJoin", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Meetme: %s\r\n" @@ -2837,7 +2837,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c break; } - manager_event(EVENT_FLAG_CALL, "MeetmeMute", + ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeMute", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Meetme: %s\r\n" @@ -2855,7 +2855,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c break; } - manager_event(EVENT_FLAG_CALL, "MeetmeMute", + ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeMute", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Meetme: %s\r\n" @@ -2868,7 +2868,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) { talkreq_manager = 1; - manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", + ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalkRequest", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Meetme: %s\r\n" @@ -2881,7 +2881,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) { talkreq_manager = 0; - manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", + ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalkRequest", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Meetme: %s\r\n" @@ -2949,7 +2949,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) { user->talking = 1; if (confflags & CONFFLAG_MONITORTALKER) - manager_event(EVENT_FLAG_CALL, "MeetmeTalking", + ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalking", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Meetme: %s\r\n" @@ -2960,7 +2960,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) { user->talking = 0; if (confflags & CONFFLAG_MONITORTALKER) { - manager_event(EVENT_FLAG_CALL, "MeetmeTalking", + ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalking", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Meetme: %s\r\n" @@ -3384,7 +3384,7 @@ bailoutandtrynormal: sec = (now.tv_sec - user->jointime) % 60; if (sent_event) { - manager_event(EVENT_FLAG_CALL, "MeetmeLeave", + ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeLeave", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Meetme: %s\r\n" diff --git a/apps/app_minivm.c b/apps/app_minivm.c index 1e9999b4c6..b2ab3b82c8 100644 --- a/apps/app_minivm.c +++ b/apps/app_minivm.c @@ -1806,7 +1806,7 @@ static int notify_new_message(struct ast_channel *chan, const char *templatename res = sendmail(etemplate, vmu, cidnum, cidname, filename, messageformat, duration, etemplate->attachment, MVM_MESSAGE_PAGE, counter); } - manager_event(EVENT_FLAG_CALL, "MiniVoiceMail", "Action: SentNotification\rn\nMailbox: %s@%s\r\nCounter: %s\r\n", vmu->username, vmu->domain, counter); + ast_manager_event(chan, EVENT_FLAG_CALL, "MiniVoiceMail", "Action: SentNotification\rn\nMailbox: %s@%s\r\nCounter: %s\r\n", vmu->username, vmu->domain, counter); run_externnotify(chan, vmu); /* Run external notification */ diff --git a/apps/app_queue.c b/apps/app_queue.c index c0b32ff90c..ef05496964 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -2245,7 +2245,7 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result * ast_copy_string(qe->context, q->context, sizeof(qe->context)); q->count++; res = 0; - manager_event(EVENT_FLAG_CALL, "Join", + ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join", "Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n", qe->chan->name, S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is */ @@ -2498,7 +2498,7 @@ static void leave_queue(struct queue_ent *qe) q->count--; /* Take us out of the queue */ - manager_event(EVENT_FLAG_CALL, "Leave", + ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave", "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n", qe->chan->name, q->name, q->count, qe->pos, qe->chan->uniqueid); ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 9fad4744d7..a69b306f28 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -6558,7 +6558,7 @@ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs); - manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s@%s\r\nWaiting: %d\r\nNew: %d\r\nOld: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs); + ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s@%s\r\nWaiting: %d\r\nNew: %d\r\nOld: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs); run_externnotify(vmu->context, vmu->mailbox, flag); #ifdef IMAP_STORAGE @@ -9767,7 +9767,7 @@ out: if (valid) { int new = 0, old = 0, urgent = 0; snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context); - manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL)); + ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL)); /* Urgent flag not passwd to externnotify here */ run_externnotify(vmu->context, vmu->mailbox, NULL); ast_app_inboxcount2(ext_context, &urgent, &new, &old); diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 7e5471f2a3..1c87ea6637 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -10072,11 +10072,11 @@ retryowner: if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) { /* Generate Manager Hold event, if necessary*/ if (iaxs[fr->callno]->owner) { - manager_event(EVENT_FLAG_CALL, "Hold", + ast_manager_event(iaxs[fr->callno]->owner, EVENT_FLAG_CALL, "Hold", "Status: On\r\n" "Channel: %s\r\n" "Uniqueid: %s\r\n", - iaxs[fr->callno]->owner->name, + iaxs[fr->callno]->owner->name, iaxs[fr->callno]->owner->uniqueid); } @@ -10099,11 +10099,11 @@ retryowner: if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) { /* Generate Manager Unhold event, if necessary*/ if (iaxs[fr->callno]->owner && ast_test_flag64(iaxs[fr->callno], IAX_QUELCH)) { - manager_event(EVENT_FLAG_CALL, "Hold", + ast_manager_event(iaxs[fr->callno]->owner, EVENT_FLAG_CALL, "Hold", "Status: Off\r\n" "Channel: %s\r\n" "Uniqueid: %s\r\n", - iaxs[fr->callno]->owner->name, + iaxs[fr->callno]->owner->name, iaxs[fr->callno]->owner->uniqueid); } diff --git a/channels/chan_sip.c b/channels/chan_sip.c index fd858649e6..487b6e39a6 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -8863,7 +8863,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action /* Queue Manager Unhold event */ append_history(p, "Unhold", "%s", req->data->str); if (sip_cfg.callevents) - manager_event(EVENT_FLAG_CALL, "Hold", + ast_manager_event(p->owner, EVENT_FLAG_CALL, "Hold", "Status: Off\r\n" "Channel: %s\r\n" "Uniqueid: %s\r\n", @@ -8885,7 +8885,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action /* Queue Manager Hold event */ append_history(p, "Hold", "%s", req->data->str); if (sip_cfg.callevents && !ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) { - manager_event(EVENT_FLAG_CALL, "Hold", + ast_manager_event(p->owner, EVENT_FLAG_CALL, "Hold", "Status: On\r\n" "Channel: %s\r\n" "Uniqueid: %s\r\n", @@ -21352,6 +21352,7 @@ static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual * struct ast_party_connected_line connected_to_transferee; struct ast_party_connected_line connected_to_target; char transferer_linkedid[32]; + struct ast_channel *chans[2]; /* Check if the call ID of the replaces header does exist locally */ if (!(targetcall_pvt = get_sip_pvt_byid_locked(transferer->refer->replaces_callid, transferer->refer->replaces_callid_totag, @@ -21415,7 +21416,9 @@ static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual * ast_copy_string(transferer_linkedid, transferer->owner->linkedid, sizeof(transferer_linkedid)); /* Perform the transfer */ - manager_event(EVENT_FLAG_CALL, "Transfer", "TransferMethod: SIP\r\nTransferType: Attended\r\nChannel: %s\r\nUniqueid: %s\r\nSIP-Callid: %s\r\nTargetChannel: %s\r\nTargetUniqueid: %s\r\n", + chans[0] = transferer->owner; + chans[1] = target.chan1; + ast_manager_event_multichan(EVENT_FLAG_CALL, "Transfer", 2, chans, "TransferMethod: SIP\r\nTransferType: Attended\r\nChannel: %s\r\nUniqueid: %s\r\nSIP-Callid: %s\r\nTargetChannel: %s\r\nTargetUniqueid: %s\r\n", transferer->owner->name, transferer->owner->uniqueid, transferer->callid, @@ -21565,6 +21568,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int /* Chan2: Call between asterisk and transferee */ int res = 0; + struct ast_channel *chans[2]; current.req.data = NULL; if (req->debug) @@ -21682,11 +21686,11 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int /* Get the transferer's channel */ - current.chan1 = p->owner; + chans[0] = current.chan1 = p->owner; /* Find the other part of the bridge (2) - transferee */ - current.chan2 = ast_bridged_channel(current.chan1); - + chans[1] = current.chan2 = ast_bridged_channel(current.chan1); + if (sipdebug) ast_debug(3, "SIP %s transfer: Transferer channel %s, transferee channel %s\n", p->refer->attendedtransfer ? "attended" : "blind", current.chan1->name, current.chan2 ? current.chan2->name : ""); @@ -21731,7 +21735,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int ast_clear_flag(&p->flags[0], SIP_GOTREFER); p->refer->status = REFER_200OK; append_history(p, "Xfer", "REFER to call parking."); - manager_event(EVENT_FLAG_CALL, "Transfer", "TransferMethod: SIP\r\nTransferType: Blind\r\nChannel: %s\r\nUniqueid: %s\r\nSIP-Callid: %s\r\nTargetChannel: %s\r\nTargetUniqueid: %s\r\nTransferExten: %s\r\nTransfer2Parking: Yes\r\n", + ast_manager_event_multichan(EVENT_FLAG_CALL, "Transfer", 2, chans, "TransferMethod: SIP\r\nTransferType: Blind\r\nChannel: %s\r\nUniqueid: %s\r\nSIP-Callid: %s\r\nTargetChannel: %s\r\nTargetUniqueid: %s\r\nTransferExten: %s\r\nTransfer2Parking: Yes\r\n", current.chan1->name, current.chan1->uniqueid, p->callid, @@ -21809,7 +21813,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int res = ast_async_goto(current.chan2, p->refer->refer_to_context, p->refer->refer_to, 1); if (!res) { - manager_event(EVENT_FLAG_CALL, "Transfer", "TransferMethod: SIP\r\nTransferType: Blind\r\nChannel: %s\r\nUniqueid: %s\r\nSIP-Callid: %s\r\nTargetChannel: %s\r\nTargetUniqueid: %s\r\nTransferExten: %s\r\nTransferContext: %s\r\n", + ast_manager_event_multichan(EVENT_FLAG_CALL, "Transfer", 2, chans, "TransferMethod: SIP\r\nTransferType: Blind\r\nChannel: %s\r\nUniqueid: %s\r\nSIP-Callid: %s\r\nTargetChannel: %s\r\nTargetUniqueid: %s\r\nTransferExten: %s\r\nTransferContext: %s\r\n", current.chan1->name, current.chan1->uniqueid, p->callid, diff --git a/configs/manager.conf.sample b/configs/manager.conf.sample index 28a8154019..229db2dac6 100644 --- a/configs/manager.conf.sample +++ b/configs/manager.conf.sample @@ -57,6 +57,12 @@ bindaddr = 0.0.0.0 ; ;timestampevents = yes +; +; Display certain channel variables every time a channel-oriented +; event is emitted: +; +;channelvars = var1,var2,var3 + ; debug = on ; enable some debugging info in AMI messages (default off). ; Also accessible through the "manager debug" CLI command. ;[mark] diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h index 5b83c3ef52..ddfbd3d311 100644 --- a/include/asterisk/manager.h +++ b/include/asterisk/manager.h @@ -197,11 +197,26 @@ int astman_verify_session_writepermissions(uint32_t ident, int perm); /* XXX the parser in gcc 2.95 gets confused if you don't put a space * between the last arg before VA_ARGS and the comma */ #define manager_event(category, event, contents , ...) \ - __manager_event(category, event, __FILE__, __LINE__, __PRETTY_FUNCTION__, contents , ## __VA_ARGS__) + __ast_manager_event_multichan(category, event, 0, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, contents , ## __VA_ARGS__) +#define ast_manager_event(chan, category, event, contents , ...) \ + do { \ + struct ast_channel *_chans[] = { chan, }; \ + __ast_manager_event_multichan(category, event, 1, _chans, __FILE__, __LINE__, __PRETTY_FUNCTION__, contents , ## __VA_ARGS__); \ + } while (0) +#define ast_manager_event_multichan(category, event, nchans, chans, contents , ...) \ + __ast_manager_event_multichan(category, event, nchans, chans, __FILE__, __LINE__, __PRETTY_FUNCTION__, contents , ## __VA_ARGS__); -int __attribute__((format(printf, 6, 7))) __manager_event(int category, const char *event, - const char *file, int line, const char *func, - const char *contents, ...); +/*! External routines may send asterisk manager events this way + * \param chan1 First channel related to this event (or NULL if none are relevant) + * \param chan2 Second channel related to this event (or NULL if none are relevant) + * \param category Event category, matches manager authorization + * \param event Event name + * \param contents Format string describing event + * \since 1.6.3 +*/ +int __ast_manager_event_multichan(int category, const char *event, int chancount, + struct ast_channel **chans, const char *file, int line, const char *func, + const char *contents, ...) __attribute__((format(printf, 8, 9))); /*! \brief Get header from mananger transaction */ const char *astman_get_header(const struct message *m, char *var); diff --git a/main/cdr.c b/main/cdr.c index 9168978a41..2cd11bb055 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -991,7 +991,7 @@ int ast_cdr_setaccount(struct ast_channel *chan, const char *account) } } - manager_event(EVENT_FLAG_CALL, "NewAccountCode", + ast_manager_event(chan, EVENT_FLAG_CALL, "NewAccountCode", "Channel: %s\r\n" "Uniqueid: %s\r\n" "AccountCode: %s\r\n" @@ -1017,7 +1017,7 @@ int ast_cdr_setpeeraccount(struct ast_channel *chan, const char *account) } } - manager_event(EVENT_FLAG_CALL, "NewPeerAccount", + ast_manager_event(chan, EVENT_FLAG_CALL, "NewPeerAccount", "Channel: %s\r\n" "Uniqueid: %s\r\n" "PeerAccount: %s\r\n" diff --git a/main/channel.c b/main/channel.c index 3ec23f9f71..5b58b76bd7 100644 --- a/main/channel.c +++ b/main/channel.c @@ -978,7 +978,7 @@ alertpipe_failed: * a lot of data into this func to do it here! */ if (!ast_strlen_zero(name_fmt)) { - manager_event(EVENT_FLAG_CALL, "Newchannel", + ast_manager_event(tmp, EVENT_FLAG_CALL, "Newchannel", "Channel: %s\r\n" "ChannelState: %d\r\n" "ChannelStateDesc: %s\r\n" @@ -2222,7 +2222,7 @@ int ast_hangup(struct ast_channel *chan) } ast_channel_unlock(chan); - manager_event(EVENT_FLAG_CALL, "Hangup", + ast_manager_event(chan, EVENT_FLAG_CALL, "Hangup", "Channel: %s\r\n" "Uniqueid: %s\r\n" "CallerIDNum: %s\r\n" @@ -2974,9 +2974,9 @@ int ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int cmdfd) return 0; /* Time is up */ } -static void send_dtmf_event(const struct ast_channel *chan, const char *direction, const char digit, const char *begin, const char *end) +static void send_dtmf_event(struct ast_channel *chan, const char *direction, const char digit, const char *begin, const char *end) { - manager_event(EVENT_FLAG_DTMF, + ast_manager_event(chan, EVENT_FLAG_DTMF, "DTMF", "Channel: %s\r\n" "Uniqueid: %s\r\n" @@ -4839,7 +4839,7 @@ retrymasq: */ static void __ast_change_name_nolink(struct ast_channel *chan, const char *newname) { - manager_event(EVENT_FLAG_CALL, "Rename", "Channel: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", chan->name, newname, chan->uniqueid); + ast_manager_event(chan, EVENT_FLAG_CALL, "Rename", "Channel: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", chan->name, newname, chan->uniqueid); ast_string_field_set(chan, name, newname); } @@ -5078,9 +5078,9 @@ static void ast_set_owners_and_peers(struct ast_channel *chan1, /*! * \pre chan is locked */ -static void report_new_callerid(const struct ast_channel *chan) +static void report_new_callerid(struct ast_channel *chan) { - manager_event(EVENT_FLAG_CALL, "NewCallerid", + ast_manager_event(chan, EVENT_FLAG_CALL, "NewCallerid", "Channel: %s\r\n" "CallerIDNum: %s\r\n" "CallerIDName: %s\r\n" @@ -5116,7 +5116,7 @@ int ast_do_masquerade(struct ast_channel *original) struct ast_party_connected_line connected; struct ast_party_redirecting redirecting; } exchange; - struct ast_channel *clonechan; + struct ast_channel *clonechan, *chans[2]; struct ast_cdr *cdr; format_t rformat = original->readformat; format_t wformat = original->writeformat; @@ -5180,7 +5180,9 @@ int ast_do_masquerade(struct ast_channel *original) ast_debug(4, "Actually Masquerading %s(%d) into the structure of %s(%d)\n", clonechan->name, clonechan->_state, original->name, original->_state); - manager_event(EVENT_FLAG_CALL, "Masquerade", "Clone: %s\r\nCloneState: %s\r\nOriginal: %s\r\nOriginalState: %s\r\n", + chans[0] = clonechan; + chans[1] = original; + ast_manager_event_multichan(EVENT_FLAG_CALL, "Masquerade", 2, chans, "Clone: %s\r\nCloneState: %s\r\nOriginal: %s\r\nOriginalState: %s\r\n", clonechan->name, ast_state2str(clonechan->_state), original->name, ast_state2str(original->_state)); /* Having remembered the original read/write formats, we turn off any translation on either @@ -5409,7 +5411,7 @@ int ast_do_masquerade(struct ast_channel *original) if (ast_test_flag(clonechan, AST_FLAG_ZOMBIE)) { ast_debug(1, "Destroying channel clone '%s'\n", clonechan->name); ast_channel_unlock(clonechan); - manager_event(EVENT_FLAG_CALL, "Hangup", + ast_manager_event(clonechan, EVENT_FLAG_CALL, "Hangup", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Cause: %d\r\n" @@ -5491,8 +5493,7 @@ int ast_setstate(struct ast_channel *chan, enum ast_channel_state state) ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, name); /* setstate used to conditionally report Newchannel; this is no more */ - manager_event(EVENT_FLAG_CALL, - "Newstate", + ast_manager_event(chan, EVENT_FLAG_CALL, "Newstate", "Channel: %s\r\n" "ChannelState: %d\r\n" "ChannelStateDesc: %s\r\n" @@ -5759,7 +5760,8 @@ int ast_channel_early_bridge(struct ast_channel *c0, struct ast_channel *c1) */ static void manager_bridge_event(int onoff, int type, struct ast_channel *c0, struct ast_channel *c1) { - manager_event(EVENT_FLAG_CALL, "Bridge", + struct ast_channel *chans[2] = { c0, c1 }; + ast_manager_event_multichan(EVENT_FLAG_CALL, "Bridge", 2, chans, "Bridgestate: %s\r\n" "Bridgetype: %s\r\n" "Channel1: %s\r\n" @@ -5843,7 +5845,7 @@ static void bridge_play_sounds(struct ast_channel *c0, struct ast_channel *c1) enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc) { - struct ast_channel *who = NULL; + struct ast_channel *who = NULL, *chans[2] = { c0, c1 }; enum ast_bridge_result res = AST_BRIDGE_COMPLETE; int nativefailed=0; format_t o0nativeformats; @@ -6017,7 +6019,7 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha ast_set_flag(c0, AST_FLAG_NBRIDGE); ast_set_flag(c1, AST_FLAG_NBRIDGE); if ((res = c0->tech->bridge(c0, c1, config->flags, fo, rc, to)) == AST_BRIDGE_COMPLETE) { - manager_event(EVENT_FLAG_CALL, "Unlink", + ast_manager_event_multichan(EVENT_FLAG_CALL, "Unlink", 2, chans, "Channel1: %s\r\n" "Channel2: %s\r\n" "Uniqueid1: %s\r\n" @@ -6089,7 +6091,7 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha c0->_bridge = NULL; c1->_bridge = NULL; - manager_event(EVENT_FLAG_CALL, "Unlink", + ast_manager_event_multichan(EVENT_FLAG_CALL, "Unlink", 2, chans, "Channel1: %s\r\n" "Channel2: %s\r\n" "Uniqueid1: %s\r\n" diff --git a/main/features.c b/main/features.c index fe79d4977f..d062db9516 100644 --- a/main/features.c +++ b/main/features.c @@ -890,7 +890,7 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, st event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"); } - manager_event(EVENT_FLAG_CALL, "ParkedCall", + ast_manager_event(pu->chan, EVENT_FLAG_CALL, "ParkedCall", "Exten: %s\r\n" "Channel: %s\r\n" "Parkinglot: %s\r\n" @@ -3641,7 +3641,7 @@ static int park_exec_full(struct ast_channel *chan, const char *data, struct ast ast_log(LOG_WARNING, "Whoa, no parking context?\n"); ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan); - manager_event(EVENT_FLAG_CALL, "UnParkedCall", + ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall", "Exten: %s\r\n" "Channel: %s\r\n" "From: %s\r\n" @@ -4944,7 +4944,7 @@ int ast_bridge_timelimit(struct ast_channel *chan, struct ast_bridge_config *con */ static int bridge_exec(struct ast_channel *chan, const char *data) { - struct ast_channel *current_dest_chan, *final_dest_chan; + struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2]; char *tmp_data = NULL; struct ast_flags opts = { 0, }; struct ast_bridge_config bconfig = { { 0, }, }; @@ -4971,7 +4971,7 @@ static int bridge_exec(struct ast_channel *chan, const char *data) strlen(chan->name) < strlen(args.dest_chan) ? strlen(chan->name) : strlen(args.dest_chan))) { ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name); - manager_event(EVENT_FLAG_CALL, "BridgeExec", + ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", "Response: Failed\r\n" "Reason: Unable to bridge channel to itself\r\n" "Channel1: %s\r\n" @@ -4986,7 +4986,7 @@ static int bridge_exec(struct ast_channel *chan, const char *data) strlen(args.dest_chan)))) { ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we " "cannot get its lock\n", args.dest_chan); - manager_event(EVENT_FLAG_CALL, "BridgeExec", + ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", "Response: Failed\r\n" "Reason: Cannot grab end point\r\n" "Channel1: %s\r\n" @@ -5004,7 +5004,7 @@ static int bridge_exec(struct ast_channel *chan, const char *data) if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) { ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan); - manager_event(EVENT_FLAG_CALL, "BridgeExec", + ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec", "Response: Failed\r\n" "Reason: cannot create placeholder\r\n" "Channel1: %s\r\n" @@ -5015,11 +5015,14 @@ static int bridge_exec(struct ast_channel *chan, const char *data) do_bridge_masquerade(current_dest_chan, final_dest_chan); + chans[0] = current_dest_chan; + chans[1] = final_dest_chan; + /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */ /* try to make compatible, send error if we fail */ if (ast_channel_make_compatible(chan, final_dest_chan) < 0) { ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name); - manager_event(EVENT_FLAG_CALL, "BridgeExec", + ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, "Response: Failed\r\n" "Reason: Could not make channels compatible for bridge\r\n" "Channel1: %s\r\n" @@ -5031,7 +5034,7 @@ static int bridge_exec(struct ast_channel *chan, const char *data) } /* Report that the bridge will be successfull */ - manager_event(EVENT_FLAG_CALL, "BridgeExec", + ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans, "Response: Success\r\n" "Channel1: %s\r\n" "Channel2: %s\r\n", chan->name, final_dest_chan->name); diff --git a/main/manager.c b/main/manager.c index b2a21bd870..93e16fe056 100644 --- a/main/manager.c +++ b/main/manager.c @@ -844,6 +844,14 @@ struct mansession { static struct ao2_container *sessions = NULL; +struct manager_channel_variable { + AST_LIST_ENTRY(manager_channel_variable) entry; + unsigned int isfunc:1; + char name[0]; /* allocate off the end the real size. */ +}; + +static AST_RWLIST_HEAD_STATIC(channelvars, manager_channel_variable); + #define NEW_EVENT(m) (AST_LIST_NEXT(m->session->last_ev, eq_next)) /*! \brief user descriptor, as read from the config file. @@ -876,6 +884,7 @@ static AST_RWLIST_HEAD_STATIC(manager_hooks, manager_custom_hook); static struct eventqent *unref_event(struct eventqent *e); static void ref_event(struct eventqent *e); +static void free_channelvars(void); /*! \brief Add a custom hook to be called when an event is fired */ void ast_manager_register_hook(struct manager_custom_hook *hook) @@ -3292,7 +3301,7 @@ static void *fast_originate(void *data) struct fast_originate_helper *in = data; int res; int reason = 0; - struct ast_channel *chan = NULL; + struct ast_channel *chan = NULL, *chans[1]; char requested_channel[AST_CHANNEL_NAME]; if (!ast_strlen_zero(in->app)) { @@ -3311,7 +3320,8 @@ static void *fast_originate(void *data) snprintf(requested_channel, AST_CHANNEL_NAME, "%s/%s", in->tech, in->data); } /* Tell the manager what happened with the channel */ - manager_event(EVENT_FLAG_CALL, "OriginateResponse", + chans[0] = chan; + ast_manager_event_multichan(EVENT_FLAG_CALL, "OriginateResponse", chan ? 1 : 0, chans, "%s%s" "Response: %s\r\n" "Channel: %s\r\n" @@ -4211,13 +4221,34 @@ static int append_event(const char *str, int category) return 0; } +AST_THREADSTORAGE(manager_event_funcbuf); + +static void append_channel_vars(struct ast_str **pbuf, struct ast_channel *chan) +{ + struct manager_channel_variable *var; + AST_RWLIST_RDLOCK(&channelvars); + AST_LIST_TRAVERSE(&channelvars, var, entry) { + const char *val = ""; + if (var->isfunc) { + struct ast_str *res = ast_str_thread_get(&manager_event_funcbuf, 16); + int ret; + if (res && (ret = ast_func_read2(chan, var->name, &res, 0)) == 0) { + val = ast_str_buffer(res); + } + } else { + val = pbx_builtin_getvar_helper(chan, var->name); + } + ast_str_append(pbuf, 0, "ChanVariable(%s): %s=%s\r\n", chan->name, var->name, val ? val : ""); + } + AST_RWLIST_UNLOCK(&channelvars); +} + /* XXX see if can be moved inside the function */ AST_THREADSTORAGE(manager_event_buf); #define MANAGER_EVENT_BUF_INITSIZE 256 -/*! \brief manager_event: Send AMI event to client */ -int __manager_event(int category, const char *event, - const char *file, int line, const char *func, const char *fmt, ...) +int __ast_manager_event_multichan(int category, const char *event, int chancount, struct + ast_channel **chans, const char *file, int line, const char *func, const char *fmt, ...) { struct mansession_session *session; struct manager_custom_hook *hook; @@ -4226,6 +4257,7 @@ int __manager_event(int category, const char *event, va_list ap; struct timeval now; struct ast_str *buf; + int i; if (!(buf = ast_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE))) { return -1; @@ -4254,6 +4286,9 @@ int __manager_event(int category, const char *event, va_start(ap, fmt); ast_str_append_va(&buf, 0, fmt, ap); va_end(ap); + for (i = 0; i < chancount; i++) { + append_channel_vars(&buf, chans[i]); + } ast_str_append(&buf, 0, "\r\n"); @@ -5559,6 +5594,8 @@ static int __init_manager(int reload) } ami_tls_cfg.cipher = ast_strdup(""); + free_channelvars(); + for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { val = var->value; @@ -5589,6 +5626,21 @@ static int __init_manager(int reload) manager_debug = ast_true(val); } else if (!strcasecmp(var->name, "httptimeout")) { newhttptimeout = atoi(val); + } else if (!strcasecmp(var->name, "channelvars")) { + struct manager_channel_variable *mcv; + char *remaining = ast_strdupa(val), *next; + AST_RWLIST_WRLOCK(&channelvars); + while ((next = strsep(&remaining, ",|"))) { + if (!(mcv = ast_calloc(1, sizeof(*mcv) + strlen(next) + 1))) { + break; + } + strcpy(mcv->name, next); /* SAFE */ + if (strchr(next, '(')) { + mcv->isfunc = 1; + } + AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry); + } + AST_RWLIST_UNLOCK(&channelvars); } else { ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n", var->name, val); @@ -5830,6 +5882,17 @@ static int __init_manager(int reload) return 0; } +/* clear out every entry in the channelvar list */ +static void free_channelvars(void) +{ + struct manager_channel_variable *var; + AST_RWLIST_WRLOCK(&channelvars); + while ((var = AST_RWLIST_REMOVE_HEAD(&channelvars, entry))) { + ast_free(var); + } + AST_RWLIST_UNLOCK(&channelvars); +} + int init_manager(void) { return __init_manager(0); diff --git a/res/res_monitor.c b/res/res_monitor.c index f80443b69f..e00b7c5b02 100644 --- a/res/res_monitor.c +++ b/res/res_monitor.c @@ -382,12 +382,11 @@ int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const cha /* so we know this call has been monitored in case we need to bill for it or something */ pbx_builtin_setvar_helper(chan, "__MONITORED","true"); - manager_event(EVENT_FLAG_CALL, "MonitorStart", - "Channel: %s\r\n" - "Uniqueid: %s\r\n", + ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStart", + "Channel: %s\r\n" + "Uniqueid: %s\r\n", chan->name, - chan->uniqueid - ); + chan->uniqueid); } else { ast_debug(1,"Cannot start monitoring %s, already monitored\n", chan->name); res = -1; @@ -502,8 +501,8 @@ int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_l ast_free(chan->monitor); chan->monitor = NULL; - manager_event(EVENT_FLAG_CALL, "MonitorStop", - "Channel: %s\r\n" + ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStop", + "Channel: %s\r\n" "Uniqueid: %s\r\n", chan->name, chan->uniqueid diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index 604ff300e7..410a23288f 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -1346,7 +1346,7 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con return -1; } - manager_event(EVENT_FLAG_CALL, "MusicOnHold", + ast_manager_event(chan, EVENT_FLAG_CALL, "MusicOnHold", "State: Start\r\n" "Channel: %s\r\n" "UniqueID: %s\r\n", @@ -1378,7 +1378,7 @@ static void local_ast_moh_stop(struct ast_channel *chan) } } - manager_event(EVENT_FLAG_CALL, "MusicOnHold", + ast_manager_event(chan, EVENT_FLAG_CALL, "MusicOnHold", "State: Stop\r\n" "Channel: %s\r\n" "UniqueID: %s\r\n",