static int userevent_exec(struct cw_channel *chan, int argc, char **argv) { char eventname[512]; struct localuser *u; if (argc < 1 || argc > 2 || !argv[0][0]) { cw_log(LOG_ERROR, "Syntax: %s\n", userevent_syntax); return -1; } LOCAL_USER_ADD(u); snprintf(eventname, sizeof(eventname), "UserEvent%s", argv[0]); if (argc > 1 && argv[1][0]) { cw_log(LOG_DEBUG, "Sending user event: %s, %s\n", eventname, argv[1]); manager_event(EVENT_FLAG_USER, eventname, "Channel: %s\r\nUniqueid: %s\r\n%s\r\n", chan->name, chan->uniqueid, argv[1]); } else { cw_log(LOG_DEBUG, "Sending user event: %s\n", eventname); manager_event(EVENT_FLAG_USER, eventname, "Channel: %s\r\nUniqueid: %s\r\n", chan->name, chan->uniqueid); } LOCAL_USER_REMOVE(u); return 0; }
static void bridge_merge_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) { struct ast_bridge_merge_message *merge_msg = stasis_message_data(message); RAII_VAR(struct ast_str *, to_text, NULL, ast_free); RAII_VAR(struct ast_str *, from_text, NULL, ast_free); ast_assert(merge_msg->to != NULL); ast_assert(merge_msg->from != NULL); to_text = ast_manager_build_bridge_state_string_prefix(merge_msg->to, "To"); from_text = ast_manager_build_bridge_state_string_prefix(merge_msg->from, "From"); if (!to_text || !from_text) { return; } /*** DOCUMENTATION <managerEventInstance> <synopsis>Raised when two bridges are merged.</synopsis> <syntax> <bridge_snapshot prefix="To"/> <bridge_snapshot prefix="From"/> </syntax> </managerEventInstance> ***/ manager_event(EVENT_FLAG_CALL, "BridgeMerge", "%s" "%s", ast_str_buffer(to_text), ast_str_buffer(from_text)); }
static void mwi_update_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) { struct ast_mwi_state *mwi_state; RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free); if (ast_mwi_state_type() != stasis_message_type(message)) { return; } mwi_state = stasis_message_data(message); if (!mwi_state) { return; } if (mwi_state->snapshot) { channel_event_string = ast_manager_build_channel_state_string(mwi_state->snapshot); } /*** DOCUMENTATION <managerEventInstance> <synopsis>Raised when the state of messages in a voicemail mailbox has changed or when a channel has finished interacting with a mailbox.</synopsis> <syntax> <channel_snapshot/> <parameter name="Mailbox"> <para>The mailbox with the new message, specified as <literal>mailbox</literal>@<literal>context</literal></para> </parameter> <parameter name="Waiting"> <para>Whether or not the mailbox has messages waiting for it.</para> </parameter> <parameter name="New"> <para>The number of new messages.</para> </parameter> <parameter name="Old"> <para>The number of old messages.</para> </parameter> </syntax> <description> <note><para>The Channel related parameters are only present if a channel was involved in the manipulation of a mailbox. If no channel is involved, the parameters are not included with the event.</para> </note> </description> </managerEventInstance> ***/ manager_event(EVENT_FLAG_CALL, "MessageWaiting", "%s" "Mailbox: %s\r\n" "Waiting: %d\r\n" "New: %d\r\n" "Old: %d\r\n", AS_OR(channel_event_string, ""), mwi_state->uniqueid, ast_app_has_voicemail(mwi_state->uniqueid, NULL), mwi_state->new_msgs, mwi_state->old_msgs); }
/*! \brief Generic MWI event callback used for one-off events from voicemail modules */ static void mwi_app_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) { struct ast_mwi_blob *payload = stasis_message_data(message); RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free); RAII_VAR(struct ast_str *, event_buffer, NULL, ast_free); struct ast_json *event_json = ast_json_object_get(payload->blob, "Event"); if (!event_json) { return; } if (payload->mwi_state && payload->mwi_state->snapshot) { channel_event_string = ast_manager_build_channel_state_string(payload->mwi_state->snapshot); } event_buffer = ast_manager_str_from_json_object(payload->blob, exclude_event_cb); if (!event_buffer) { ast_log(AST_LOG_WARNING, "Failed to create payload for event %s\n", ast_json_string_get(event_json)); return; } manager_event(EVENT_FLAG_CALL, ast_json_string_get(event_json), "Mailbox: %s\r\n" "%s" "%s", payload->mwi_state ? payload->mwi_state->uniqueid : "Unknown", ast_str_buffer(event_buffer), channel_event_string ? ast_str_buffer(channel_event_string) : ""); }
static void confbridge_publish_manager_event( struct stasis_message *message, const char *event, struct ast_str *extra_text) { struct ast_bridge_blob *blob = stasis_message_data(message); const char *conference_name; RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free); RAII_VAR(struct ast_str *, channel_text, NULL, ast_free); ast_assert(blob != NULL); ast_assert(event != NULL); bridge_text = ast_manager_build_bridge_state_string(blob->bridge); if (!bridge_text) { return; } conference_name = ast_json_string_get(ast_json_object_get(blob->blob, "conference")); ast_assert(conference_name != NULL); if (blob->channel) { channel_text = ast_manager_build_channel_state_string(blob->channel); } manager_event(EVENT_FLAG_CALL, event, "Conference: %s\r\n" "%s" "%s" "%s", conference_name, ast_str_buffer(bridge_text), S_COR(channel_text, ast_str_buffer(channel_text), ""), S_COR(extra_text, ast_str_buffer(extra_text), "")); }
static void channel_enter_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) { static const char *swap_name = "SwapUniqueid: "; struct ast_bridge_blob *blob = stasis_message_data(message); RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free); RAII_VAR(struct ast_str *, channel_text, NULL, ast_free); const char *swap_id; bridge_text = ast_manager_build_bridge_state_string(blob->bridge); channel_text = ast_manager_build_channel_state_string(blob->channel); if (!bridge_text || !channel_text) { return; } swap_id = ast_json_string_get(ast_json_object_get(blob->blob, "swap")); manager_event(EVENT_FLAG_CALL, "BridgeEnter", "%s" "%s" "%s%s%s", ast_str_buffer(bridge_text), ast_str_buffer(channel_text), swap_id ? swap_name : "", S_OR(swap_id, ""), swap_id ? "\r\n" : ""); }
static void *originate(void *arg) { struct fast_originate_helper *in = arg; int reason=0; int res; struct cw_channel *chan = NULL; res = cw_pbx_outgoing_exten(in->tech, CW_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, !cw_strlen_zero(in->cid_num) ? in->cid_num : NULL, !cw_strlen_zero(in->cid_name) ? in->cid_name : NULL, NULL, &chan); manager_event(EVENT_FLAG_CALL, "Originate", "ChannelRequested: %s/%s\r\n" "Context: %s\r\n" "Extension: %s\r\n" "Priority: %d\r\n" "Result: %d\r\n" "Reason: %d\r\n" "Reason-txt: %s\r\n", in->tech, in->data, in->context, in->exten, in->priority, res, reason, cw_control2str(reason) ); /* Locked by cw_pbx_outgoing_exten or cw_pbx_outgoing_app */ if (chan) { cw_mutex_unlock(&chan->lock); } free(in); return NULL; }
static void phase_e_handler(t30_state_t *s, void *user_data, int result) { struct cw_channel *chan; char buf[128]; t30_stats_t t; const char *tx_ident; const char *rx_ident; chan = (struct cw_channel *) user_data; t30_get_transfer_statistics(s, &t); tx_ident = t30_get_tx_ident(s); if (tx_ident == NULL) tx_ident = ""; rx_ident = t30_get_rx_ident(s); if (rx_ident == NULL) rx_ident = ""; pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", rx_ident); snprintf(buf, sizeof(buf), "%d", t.pages_rx); pbx_builtin_setvar_helper(chan, "FAXPAGES", buf); snprintf(buf, sizeof(buf), "%d", t.y_resolution); pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", buf); snprintf(buf, sizeof(buf), "%d", t.bit_rate); pbx_builtin_setvar_helper(chan, "FAXBITRATE", buf); snprintf(buf, sizeof(buf), "%d", result); pbx_builtin_setvar_helper(chan, "PHASEESTATUS", buf); snprintf(buf, sizeof(buf), "%s", t30_completion_code_to_str(result)); pbx_builtin_setvar_helper(chan, "PHASEESTRING", buf); cw_log(LOG_DEBUG, "==============================================================================\n"); if (result == T30_ERR_OK) { cw_log(LOG_DEBUG, "Fax successfully received.\n"); cw_log(LOG_DEBUG, "Remote station id: %s\n", rx_ident); cw_log(LOG_DEBUG, "Local station id: %s\n", tx_ident); cw_log(LOG_DEBUG, "Pages transferred: %i\n", t.pages_rx); cw_log(LOG_DEBUG, "Image resolution: %i x %i\n", t.x_resolution, t.y_resolution); cw_log(LOG_DEBUG, "Transfer Rate: %i\n", t.bit_rate); manager_event(EVENT_FLAG_CALL, "FaxSent", "Channel: %s\nExten: %s\nCallerID: %s\nRemoteStationID: %s\nLocalStationID: %s\nPagesTransferred: %i\nResolution: %i\nTransferRate: %i\nFileName: %s\n", chan->name, chan->exten, (chan->cid.cid_num) ? chan->cid.cid_num : "", rx_ident, tx_ident, t.pages_rx, t.y_resolution, t.bit_rate, s->rx_file); } else { cw_log(LOG_DEBUG, "Fax receive not successful - result (%d) %s.\n", result, t30_completion_code_to_str(result)); } cw_log(LOG_DEBUG, "==============================================================================\n"); }
static int userevent_exec(struct ast_channel *chan, void *data) { struct localuser *u; char *info; char eventname[512]; char *eventbody; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "UserEvent requires an argument (eventname|optional event body)\n"); return -1; } LOCAL_USER_ADD(u); info = ast_strdupa(data); if (!info) { ast_log(LOG_ERROR, "Out of memory\n"); LOCAL_USER_REMOVE(u); return -1; } snprintf(eventname, sizeof(eventname), "UserEvent%s", info); eventbody = strchr(eventname, '|'); if (eventbody) { *eventbody = '\0'; eventbody++; } if(eventbody) { ast_log(LOG_DEBUG, "Sending user event: %s, %s\n", eventname, eventbody); manager_event(EVENT_FLAG_USER, eventname, "Channel: %s\r\nUniqueid: %s\r\n%s\r\n", chan->name, chan->uniqueid, eventbody); } else { ast_log(LOG_DEBUG, "Sending user event: %s\n", eventname); manager_event(EVENT_FLAG_USER, eventname, "Channel: %s\r\nUniqueid: %s\r\n", chan->name, chan->uniqueid); } LOCAL_USER_REMOVE(u); return 0; }
static int manager_log(struct ast_cdr *cdr) { time_t t; struct tm timeresult; char strStartTime[80] = ""; char strAnswerTime[80] = ""; char strEndTime[80] = ""; if (!enablecdr) return 0; t = cdr->start.tv_sec; localtime_r(&t, &timeresult); strftime(strStartTime, sizeof(strStartTime), DATE_FORMAT, &timeresult); if (cdr->answer.tv_sec) { t = cdr->answer.tv_sec; localtime_r(&t, &timeresult); strftime(strAnswerTime, sizeof(strAnswerTime), DATE_FORMAT, &timeresult); } t = cdr->end.tv_sec; localtime_r(&t, &timeresult); strftime(strEndTime, sizeof(strEndTime), DATE_FORMAT, &timeresult); manager_event(EVENT_FLAG_CALL, "Cdr", "AccountCode: %s\r\n" "Source: %s\r\n" "Destination: %s\r\n" "DestinationContext: %s\r\n" "CallerID: %s\r\n" "Channel: %s\r\n" "DestinationChannel: %s\r\n" "LastApplication: %s\r\n" "LastData: %s\r\n" "StartTime: %s\r\n" "AnswerTime: %s\r\n" "EndTime: %s\r\n" "Duration: %d\r\n" "BillableSeconds: %d\r\n" "Disposition: %s\r\n" "AMAFlags: %s\r\n" "UniqueID: %s\r\n" "UserField: %s\r\n", cdr->accountcode, cdr->src, cdr->dst, cdr->dcontext, cdr->clid, cdr->channel, cdr->dstchannel, cdr->lastapp, cdr->lastdata, strStartTime, strAnswerTime, strEndTime, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), cdr->uniqueid, cdr->userfield); return 0; }
static int conference_set_pin(struct cw_conf_member *member, char *pin) { cw_copy_string(member->conf->pin, pin, sizeof(member->conf->pin)); cw_log( CW_CONF_DEBUG, "Conference %s: PIN Set to %s\n",member->conf->name, member->conf->pin ) ; conference_queue_number( member, member->conf->pin ); manager_event( EVENT_FLAG_CALL, APP_CONFERENCE_MANID"SetPIN", "Channel: %s\r\n" "PIN: %s\r\n", member->channel_name, member->conf->pin ) ; return 1; }
static void manager_log(const struct ast_event *event, void *userdata) { struct ast_tm timeresult; char start_time[80] = ""; struct ast_cel_event_record record = { .version = AST_CEL_EVENT_RECORD_VERSION, }; if (ast_cel_fill_record(event, &record)) { return; } if (!enablecel) { return; } ast_localtime(&record.event_time, &timeresult, NULL); ast_strftime(start_time, sizeof(start_time), DATE_FORMAT, &timeresult); manager_event(EVENT_FLAG_CALL, "CEL", "EventName: %s\r\n" "AccountCode: %s\r\n" "CallerIDnum: %s\r\n" "CallerIDname: %s\r\n" "CallerIDani: %s\r\n" "CallerIDrdnis: %s\r\n" "CallerIDdnid: %s\r\n" "Exten: %s\r\n" "Context: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n" "AppData: %s\r\n" "EventTime: %s\r\n" "AMAFlags: %s\r\n" "UniqueID: %s\r\n" "LinkedID: %s\r\n" "Userfield: %s\r\n" "Peer: %s\r\n", record.event_name, record.account_code, record.caller_id_num, record.caller_id_name, record.caller_id_ani, record.caller_id_rdnis, record.caller_id_dnid, record.extension, record.context, record.channel_name, record.application_name, record.application_data, start_time, ast_cel_get_ama_flag_name(record.amaflag), record.unique_id, record.linked_id, record.user_field, record.peer); }
/*! \brief Initialize the ENUM support subsystem */ static int private_enum_init(int reload) { struct ast_config *cfg; struct enum_search *s, *sl; struct ast_variable *v; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; if ((cfg = ast_config_load("enum.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) return 0; /* Destroy existing list */ ast_mutex_lock(&enumlock); s = toplevs; while (s) { sl = s; s = s->next; ast_free(sl); } toplevs = NULL; if (cfg) { sl = NULL; v = ast_variable_browse(cfg, "general"); while (v) { if (!strcasecmp(v->name, "search")) { s = enum_newtoplev(v->value); if (s) { if (sl) sl->next = s; else toplevs = s; sl = s; } } v = v->next; } ast_config_destroy(cfg); } else { toplevs = enum_newtoplev(TOPLEV); } enumver++; ast_mutex_unlock(&enumlock); manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Enum\r\nStatus: Enabled\r\nMessage: ENUM reload Requested\r\n"); return 0; }
static void add_member( struct cw_conference *conf, struct cw_conf_member *member ) { char cnum[80]; if ( conf == NULL ) { cw_log( LOG_ERROR, "unable to add member to NULL conference\n" ) ; return ; } // acquire the conference lock cw_mutex_lock( &conf->lock ) ; member->next = conf->memberlist ; // next is now list conf->memberlist = member ; // member is now at head of list conf->membercount ++; // release the conference lock cw_mutex_unlock( &conf->lock ) ; if ((member->cid.cid_num != NULL) ) strncpy( cnum, member->cid.cid_num, sizeof(cnum) ); else cnum[0] = '\0'; queue_incoming_silent_frame(member,2); if(!member->beep_only_mode){ add_command_to_queue( conf, member, CONF_ACTION_QUEUE_NUMBER , 1, cnum ); add_command_to_queue( conf, member, CONF_ACTION_QUEUE_SOUND , 1, "conf-hasjoin" ); } else { add_command_to_queue( conf, member, CONF_ACTION_QUEUE_SOUND , 1, "beep" ); } cw_log( CW_CONF_DEBUG, "member added to conference, name => %s\n", conf->name ) ; manager_event( EVENT_FLAG_CALL, APP_CONFERENCE_MANID"Join", "Channel: %s\r\n", member->channel_name ) ; return ; }
static void channel_leave_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) { struct ast_bridge_blob *blob = stasis_message_data(message); RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free); RAII_VAR(struct ast_str *, channel_text, NULL, ast_free); bridge_text = ast_manager_build_bridge_state_string(blob->bridge); channel_text = ast_manager_build_channel_state_string(blob->channel); if (!bridge_text || !channel_text) { return; } manager_event(EVENT_FLAG_CALL, "BridgeLeave", "%s" "%s", ast_str_buffer(bridge_text), ast_str_buffer(channel_text)); }
int conf_play_soundqueue( struct cw_conf_member *member ) { int res = 0; cw_stopstream(member->chan); queue_incoming_silent_frame(member,3); struct cw_conf_soundq *toplay, *delitem; cw_generator_deactivate(member->chan); cw_mutex_lock(&member->lock); toplay = member->soundq; while ( ( toplay != NULL) && ( res == 0 ) ) { manager_event( EVENT_FLAG_CALL, APP_CONFERENCE_MANID"Sound", "Channel: %s\r\n" "Sound: %s\r\n", member->channel_name, toplay->name ); res = conf_play_soundfile( member, toplay->name ); if (res) break; delitem = toplay; toplay = toplay->next; member->soundq = toplay; free(delitem); } cw_generator_activate(member->chan,&membergen,member); cw_mutex_unlock(&member->lock); if (res != 0) conference_stop_sounds( member ); return res; }
static void bridge_snapshot_update(void *data, struct stasis_subscription *sub, struct stasis_message *message) { RAII_VAR(struct ast_str *, bridge_event_string, NULL, ast_free); struct stasis_cache_update *update; struct ast_bridge_snapshot *old_snapshot; struct ast_bridge_snapshot *new_snapshot; size_t i; update = stasis_message_data(message); ast_assert(ast_bridge_snapshot_type() == update->type); old_snapshot = stasis_message_data(update->old_snapshot); new_snapshot = stasis_message_data(update->new_snapshot); for (i = 0; i < ARRAY_LEN(bridge_monitors); ++i) { RAII_VAR(struct ast_manager_event_blob *, event, NULL, ao2_cleanup); event = bridge_monitors[i](old_snapshot, new_snapshot); if (!event) { continue; } /* If we haven't already, build the channel event string */ if (!bridge_event_string) { bridge_event_string = ast_manager_build_bridge_state_string( new_snapshot ? new_snapshot : old_snapshot); if (!bridge_event_string) { return; } } manager_event(event->event_flags, event->manager_event, "%s%s", ast_str_buffer(bridge_event_string), event->extra_fields); } }
/*! \brief Initialize the ENUM support subsystem */ static int private_enum_init(int reload) { struct ast_config *cfg; const char *string; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; if ((cfg = ast_config_load2("enum.conf", "enum", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) return 0; if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) { return 0; } /* Destroy existing list */ ast_mutex_lock(&enumlock); if (cfg) { if ((string = ast_variable_retrieve(cfg, "ienum", "branchlabel"))) { ast_copy_string(ienum_branchlabel, string, sizeof(ienum_branchlabel)); } if ((string = ast_variable_retrieve(cfg, "ienum", "ebl_alg"))) { ebl_alg = ENUMLOOKUP_BLR_CC; /* default */ if (!strcasecmp(string, "txt")) ebl_alg = ENUMLOOKUP_BLR_TXT; else if (!strcasecmp(string, "ebl")) ebl_alg = ENUMLOOKUP_BLR_EBL; else if (!strcasecmp(string, "cc")) ebl_alg = ENUMLOOKUP_BLR_CC; else ast_log(LOG_WARNING, "No valid parameter for ienum/ebl_alg.\n"); } ast_config_destroy(cfg); } ast_mutex_unlock(&enumlock); manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Enum\r\nStatus: Enabled\r\nMessage: ENUM reload Requested\r\n"); return 0; }
static void parked_call_message_response(struct ast_parked_call_payload *parked_call) { char *event_type = ""; RAII_VAR(struct ast_str *, parked_call_string, NULL, ast_free); switch (parked_call->event_type) { case PARKED_CALL: event_type = "ParkedCall"; break; case PARKED_CALL_TIMEOUT: event_type = "ParkedCallTimeOut"; break; case PARKED_CALL_GIVEUP: event_type = "ParkedCallGiveUp"; break; case PARKED_CALL_UNPARKED: event_type = "UnParkedCall"; break; case PARKED_CALL_SWAP: event_type = "ParkedCallSwap"; break; case PARKED_CALL_FAILED: /* PARKED_CALL_FAILED doesn't currently get a message and is used exclusively for bridging */ return; } parked_call_string = manager_build_parked_call_string(parked_call); if (!parked_call_string) { ast_log(LOG_ERROR, "Failed to issue an AMI event of '%s' in response to a stasis message.\n", event_type); return; } manager_event(EVENT_FLAG_CALL, event_type, "%s", ast_str_buffer(parked_call_string) ); }
/* ***************************************************************************** MANAGER UTILS ****************************************************************************/ void send_state_change_notifications( struct cw_conf_member* member ) { #if ( APP_NCONFERENCE_DEBUG == 1 ) cw_log(CW_CONF_DEBUG, "Member on channel %s. State changed to %s.\n", member->chan->name, ( ( member->is_speaking == 1 ) ? "speaking" : "silent" ) ); #endif manager_event( EVENT_FLAG_CALL, APP_CONFERENCE_MANID"State", "Channel: %s\r\n" "State: %s\r\n", member->chan->name, ( ( member->is_speaking == 1 ) ? "speaking" : "silent" ) ) ; if ( member->is_speaking == 0 ) queue_incoming_silent_frame(member,2); }
static int process_incoming(struct cw_conf_member *member, struct cw_frame *f) { int res; // Play our sound queue, if not empty. if (member->soundq) { // Free the frame. if ( f != NULL ) { cw_fr_free( f ) ; } res = conf_play_soundqueue( member ); if (res != 0) { queue_incoming_silent_frame(member,2); // send the DTMF event to the MGR interface.. manager_event( EVENT_FLAG_CALL, APP_CONFERENCE_MANID"DTMF", "Channel: %s\r\n" "Key: %c\r\n", member->channel_name, res ) ; parse_dtmf_option( member, res); } return res; } // // Moderator forces MOH management // if ( member->force_on_hold == 1 ) { cw_moh_start(member->chan,""); member->force_on_hold = 0 ; } else if ( member->force_on_hold == -1 ) { cw_moh_stop(member->chan); cw_generator_activate(member->chan,&membergen,member); member->force_on_hold = 0 ; } // // MOH When the user is alone in the conference // if ( member->conf->membercount == 1 && member->is_on_hold == 0 && member->skip_moh_when_alone == 0 ) { cw_moh_start(member->chan,""); member->is_on_hold = 1 ; return 0; } if ( member->conf->membercount > 1 && member->is_on_hold == 1 && member->skip_moh_when_alone == 0 ) { cw_moh_stop(member->chan); cw_generator_activate(member->chan,&membergen,member); member->is_on_hold = 0 ; return 0; } if ( member->force_remove_flag == 1 ) { return 0; } // If we don't have any frame to parse, then return if ( f == NULL ) { return 0; } // Actions based on the content of the frame if ( f->frametype == CW_FRAME_DTMF && member->manage_dtmf ) { queue_incoming_silent_frame(member,2); // send the DTMF event to the MGR interface.. manager_event( EVENT_FLAG_CALL, APP_CONFERENCE_MANID"DTMF", "Channel: %s\r\n" "Key: %c\r\n", member->channel_name, f->subclass ) ; parse_dtmf_option( member, f->subclass); cw_fr_free(f); } else if ( (member->type == MEMBERTYPE_LISTENER) || (member->talk_mute) ) { // this is a listen-only user, or it's muted. // Ignore the frame cw_fr_free( f ) ; } else if ( f->frametype == CW_FRAME_VOICE ) { // ********************************************************************************** VOICE int old_speaking_state = member->is_speaking; #if ENABLE_VAD if ( member->talk_mute == 1 ) member->is_speaking = 0; if ( member->enable_vad && f->subclass == CW_FORMAT_SLINEAR && f->samples > 0 ) { // and if it's time to check what the member is doing if ( member->skip_voice_detection <= 0 || member->is_speaking ) { int rees; rees = vad_is_talk( f->data, f->datalen, &member->silence_nr, 20); // send the frame to the preprocessor if ( rees != 0 ) { // voice detected, reset skip count if ( member->framelen != 0 ) member->skip_voice_detection = (CW_CONF_SKIP_MS_AFTER_VOICE_DETECTION / member->framelen); else // Let's suppose that 20ms as a framelen is not too different from the real situation member->skip_voice_detection = 20; member->is_speaking=1; } else { // member is silent member->is_speaking=0; if ( member->framelen != 0 ) member->skip_voice_detection = ( CW_CONF_SKIP_MS_WHEN_SILENT / member->framelen ); else member->skip_voice_detection = 5; } } --member->skip_voice_detection ; } if (old_speaking_state != member ->is_speaking) send_state_change_notifications(member); #endif // volume of the frame is modified after the VAD has been done if (member->talk_volume != 0) set_talk_volume(member, f, 1); if ( member->is_speaking && queue_incoming_frame( member, f ) != 0 ) cw_log( CW_CONF_DEBUG, "dropped incoming frame, channel => %s\n", member->channel_name ) ; // free the original frame cw_fr_free( f ) ; } else if ( f->frametype == CW_FRAME_CONTROL && f->subclass == CW_CONTROL_HANGUP ) { // hangup received, queue silence && free the frame queue_incoming_silent_frame(member,2); cw_fr_free( f ) ; } else { // Unmanaged frame #if ( APP_NCONFERENCE_DEBUG == 1 ) cw_log(LOG_WARNING,"Freeing unknown frame: type %d member %s \n", f->frametype, member->chan->name ); #endif cw_fr_free( f ) ; } return 0; }
static int manager_log(struct ast_cdr *cdr) { struct ast_tm timeresult; char strStartTime[80] = ""; char strAnswerTime[80] = ""; char strEndTime[80] = ""; char buf[CUSTOM_FIELDS_BUF_SIZE]; if (!enablecdr) return 0; ast_localtime(&cdr->start, &timeresult, NULL); ast_strftime(strStartTime, sizeof(strStartTime), DATE_FORMAT, &timeresult); if (cdr->answer.tv_sec) { ast_localtime(&cdr->answer, &timeresult, NULL); ast_strftime(strAnswerTime, sizeof(strAnswerTime), DATE_FORMAT, &timeresult); } ast_localtime(&cdr->end, &timeresult, NULL); ast_strftime(strEndTime, sizeof(strEndTime), DATE_FORMAT, &timeresult); buf[0] = '\0'; ast_rwlock_rdlock(&customfields_lock); if (customfields && ast_str_strlen(customfields)) { struct ast_channel *dummy = ast_dummy_channel_alloc(); if (!dummy) { ast_log(LOG_ERROR, "Unable to allocate channel for variable substitution.\n"); return 0; } dummy->cdr = ast_cdr_dup(cdr); pbx_substitute_variables_helper(dummy, ast_str_buffer(customfields), buf, sizeof(buf) - 1); ast_channel_unref(dummy); } ast_rwlock_unlock(&customfields_lock); manager_event(EVENT_FLAG_CDR, "Cdr", "AccountCode: %s\r\n" "Source: %s\r\n" "Destination: %s\r\n" "DestinationContext: %s\r\n" "CallerID: %s\r\n" "Channel: %s\r\n" "DestinationChannel: %s\r\n" "LastApplication: %s\r\n" "LastData: %s\r\n" "StartTime: %s\r\n" "AnswerTime: %s\r\n" "EndTime: %s\r\n" "Duration: %ld\r\n" "BillableSeconds: %ld\r\n" "Disposition: %s\r\n" "AMAFlags: %s\r\n" "UniqueID: %s\r\n" "UserField: %s\r\n" "%s", cdr->accountcode, cdr->src, cdr->dst, cdr->dcontext, cdr->clid, cdr->channel, cdr->dstchannel, cdr->lastapp, cdr->lastdata, strStartTime, strAnswerTime, strEndTime, cdr->duration, cdr->billsec, ast_cdr_disp2str(cdr->disposition), ast_cdr_flags2str(cdr->amaflags), cdr->uniqueid, cdr->userfield,buf); return 0; }
static void phase_e_handler(t30_state_t *f, void *user_data, int result) { const char *local_ident; const char *far_ident; char buf[20]; fax_session *s = (fax_session *) user_data; t30_stats_t stat; ast_debug(1, "Fax phase E handler. result=%d\n", result); t30_get_transfer_statistics(f, &stat); s = (fax_session *) user_data; if (result != T30_ERR_OK) { s->finished = -1; /* FAXSTATUS is already set to FAILED */ pbx_builtin_setvar_helper(s->chan, "FAXERROR", t30_completion_code_to_str(result)); ast_log(LOG_WARNING, "Error transmitting fax. result=%d: %s.\n", result, t30_completion_code_to_str(result)); return; } s->finished = 1; local_ident = t30_get_tx_ident(f); far_ident = t30_get_rx_ident(f); pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "SUCCESS"); pbx_builtin_setvar_helper(s->chan, "FAXERROR", NULL); pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", far_ident); snprintf(buf, sizeof(buf), "%d", stat.pages_transferred); pbx_builtin_setvar_helper(s->chan, "FAXPAGES", buf); snprintf(buf, sizeof(buf), "%d", stat.y_resolution); pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", buf); snprintf(buf, sizeof(buf), "%d", stat.bit_rate); pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", buf); ast_debug(1, "Fax transmitted successfully.\n"); ast_debug(1, " Remote station ID: %s\n", far_ident); ast_debug(1, " Pages transferred: %d\n", stat.pages_transferred); 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, s->direction ? "FaxSent" : "FaxReceived", "Channel: %s\r\n" "Exten: %s\r\n" "CallerID: %s\r\n" "RemoteStationID: %s\r\n" "LocalStationID: %s\r\n" "PagesTransferred: %d\r\n" "Resolution: %d\r\n" "TransferRate: %d\r\n" "FileName: %s\r\n", s->chan->name, s->chan->exten, S_OR(s->chan->cid.cid_num, ""), far_ident, local_ident, stat.pages_transferred, stat.y_resolution, stat.bit_rate, s->file_name); }
void remove_conf( struct cw_conference *conf ) { struct cw_conference *conf_current = conflist ; struct cw_conference *conf_temp = NULL ; cw_log( CW_CONF_DEBUG, "attempting to remove conference, name => %s\n", conf->name ) ; // acquire mutex cw_mutex_lock( &start_stop_conf_lock ) ; // acquire mutex cw_mutex_lock( &conflist_lock ) ; // loop through list of conferences while ( conf_current != NULL ) { // if conf_current point to the passed conf, if ( conf_current == conf ) { if ( conf_temp == NULL ) { // this is the first conf in the list, so we just point // conflist past the current conf to the next conflist = conf_current->next ; } else { // this is not the first conf in the list, so we need to // point the preceeding conf to the next conf in the list conf_temp->next = conf_current->next ; } // calculate time in conference cw_log( CW_CONF_DEBUG, "removed conference, name => %s\n", conf_current->name ) ; manager_event( EVENT_FLAG_CALL, APP_CONFERENCE_MANID"ConfRemove", "ConfNo: %s\r\n", conf_current->name ) ; cw_mutex_unlock( &conf_current->lock ) ; //Free all the command queue struct cw_conf_command_queue *cqd, *cq = conf_current->command_queue; while ( cq != NULL) { cqd=cq; cq=cq->next; free(cqd); } free( conf_current ) ; conf_current = NULL ; break ; } // save a refence to the soon to be previous conf conf_temp = conf_current ; // move conf_current to the next in the list conf_current = conf_current->next ; } // count new conference --conference_count ; // release mutex cw_mutex_unlock( &conflist_lock ) ; // release mutex cw_mutex_unlock( &start_stop_conf_lock ) ; return ; }
static struct cw_conference* create_conf( char* name, struct cw_conf_member* member ) { cw_log( CW_CONF_DEBUG, "entered create_conf, name => %s\n", name ) ; // allocate memory for conference struct cw_conference *conf = calloc(1, sizeof( struct cw_conference ) ) ; if ( conf == NULL ) { cw_log( LOG_ERROR, "unable to malloc cw_conference\n" ) ; return NULL ; } // // initialize conference // conf->next = NULL ; conf->memberlist = NULL ; conf->membercount = 0 ; conf->conference_thread = CW_PTHREADT_NULL ; conf->is_locked = 0; conf->command_queue = NULL ; // copy name to conference strncpy( (char*)&(conf->name), name, sizeof(conf->name) - 1 ) ; // initialize mutexes cw_mutex_init( &conf->lock ) ; // add the initial member add_member( conf, member) ; // // prepend new conference to conflist // // acquire mutex cw_mutex_lock( &conflist_lock ) ; conf->next = conflist ; conflist = conf ; cw_log( CW_CONF_DEBUG, "added new conference to conflist, name => %s\n", name ) ; // // spawn thread for new conference, using conference_exec( conf ) // // acquire conference mutexes cw_mutex_lock( &conf->lock ) ; if ( cw_pthread_create( &conf->conference_thread, NULL, (void*)conference_exec, conf ) == 0 ) { // detach the thread so it doesn't leak pthread_detach( conf->conference_thread ) ; // release conference mutexes cw_mutex_unlock( &conf->lock ) ; cw_log( CW_CONF_DEBUG, "started conference thread for conference, name => %s\n", conf->name ) ; manager_event( EVENT_FLAG_CALL, APP_CONFERENCE_MANID"ConfCreate", "Channel: %s\r\n" "ConfNo: %s\r\n", member->channel_name, name ) ; } else { cw_log( LOG_ERROR, "unable to start conference thread for conference %s\n", conf->name ) ; conf->conference_thread = CW_PTHREADT_NULL ; // release conference mutexes cw_mutex_unlock( &conf->lock ) ; // clean up conference free( conf ) ; conf = NULL ; } // count new conference if ( conf != NULL ) ++conference_count ; conf->auto_destroy = 1; // release mutex cw_mutex_unlock( &conflist_lock ) ; return conf ; }
static int remove_member(struct cw_conference* conf, struct cw_conf_member* member ) { // check for member if ( member == NULL ) { cw_log( LOG_WARNING, "unable to remove NULL member\n" ) ; return -1 ; } // check for conference if ( conf == NULL ) { cw_log( LOG_WARNING, "unable to remove member from NULL conference\n" ) ; return -1 ; } // // loop through the member list looking for the requested member // struct cw_conf_member *member_list = conf->memberlist ; struct cw_conf_member *member_temp = NULL ; while ( member_list != NULL ) { if ( member_list == member ) { // // if this is the first member in the linked-list, // skip over the first member in the list, else // // point the previous 'next' to the current 'next', // thus skipping the current member in the list // if ( member_temp == NULL ) conf->memberlist = member->next ; else member_temp->next = member->next ; manager_event( EVENT_FLAG_CALL, APP_CONFERENCE_MANID"Leave", "Channel: %s\r\n", member->channel_name ) ; // delete the member delete_member( member ) ; conf->membercount --; cw_log( CW_CONF_DEBUG, "removed member from conference, name => %s\n", conf->name) ; break ; } // save a pointer to the current member, // and then point to the next member in the list member_temp = member_list ; member_list = member_list->next ; } // return -1 on error, or the number of members // remaining if the requested member was deleted return conf->membercount ; }
static void manager_log(const struct ast_event *event, void *userdata) { struct ast_tm timeresult; char start_time[80] = ""; char user_defined_header[160]; const char *event_name; struct ast_cel_event_record record = { .version = AST_CEL_EVENT_RECORD_VERSION, }; if (!enablecel) { return; } if (ast_cel_fill_record(event, &record)) { return; } ast_localtime(&record.event_time, &timeresult, NULL); ast_strftime(start_time, sizeof(start_time), DATE_FORMAT, &timeresult); event_name = record.event_name; user_defined_header[0] = '\0'; if (record.event_type == AST_CEL_USER_DEFINED) { if (cel_show_user_def) { snprintf(user_defined_header, sizeof(user_defined_header), "UserDefType: %s\r\n", record.user_defined_name); } else { event_name = record.user_defined_name; } } manager_event(EVENT_FLAG_CALL, "CEL", "EventName: %s\r\n" "AccountCode: %s\r\n" "CallerIDnum: %s\r\n" "CallerIDname: %s\r\n" "CallerIDani: %s\r\n" "CallerIDrdnis: %s\r\n" "CallerIDdnid: %s\r\n" "Exten: %s\r\n" "Context: %s\r\n" "Channel: %s\r\n" "Application: %s\r\n" "AppData: %s\r\n" "EventTime: %s\r\n" "AMAFlags: %s\r\n" "UniqueID: %s\r\n" "LinkedID: %s\r\n" "Userfield: %s\r\n" "Peer: %s\r\n" "PeerAccount: %s\r\n" "%s" "Extra: %s\r\n", event_name, record.account_code, record.caller_id_num, record.caller_id_name, record.caller_id_ani, record.caller_id_rdnis, record.caller_id_dnid, record.extension, record.context, record.channel_name, record.application_name, record.application_data, start_time, ast_cel_get_ama_flag_name(record.amaflag), record.unique_id, record.linked_id, record.user_field, record.peer, record.peer_account, user_defined_header, record.extra); }
static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags) { struct ast_conference *prev=NULL, *cur; struct ast_conf_user *user = malloc(sizeof(struct ast_conf_user)); int fd; struct zt_confinfo ztc; struct ast_frame *f; struct ast_channel *c; struct ast_frame fr; int outfd; int ms; int nfds; int res; int flags; int retryzap; int origfd; int musiconhold = 0; int firstpass = 0; int origquiet; int ret = -1; int x; int menu_active = 0; int using_pseudo = 0; struct ast_app *app; char *agifile; char *agifiledefault = "conf-background.agi"; char meetmesecs[30] = ""; char exitcontext[AST_MAX_EXTENSION] = ""; int dtmf; ZT_BUFFERINFO bi; char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; char *buf = __buf + AST_FRIENDLY_OFFSET; if (!user) { ast_log(LOG_ERROR, "Out of memory\n"); return(ret); } memset(user, 0, sizeof(struct ast_conf_user)); user->user_no = 0; /* User number 0 means starting up user! (dead - not in the list!) */ time(&user->jointime); if (conf->locked) { /* Sorry, but this confernce is locked! */ if (!ast_streamfile(chan, "conf-locked", chan->language)) ast_waitstream(chan, ""); goto outrun; } conf->users++; if (confflags & CONFFLAG_MARKEDUSER) conf->markedusers++; ast_mutex_lock(&conflock); if (conf->firstuser == NULL) { /* Fill the first new User struct */ user->user_no = 1; user->nextuser = NULL; user->prevuser = NULL; conf->firstuser = user; conf->lastuser = user; } else { /* Fill the new user struct */ user->user_no = conf->lastuser->user_no + 1; user->prevuser = conf->lastuser; user->nextuser = NULL; if (conf->lastuser->nextuser != NULL) { ast_log(LOG_WARNING, "Error in User Management!\n"); ast_mutex_unlock(&conflock); goto outrun; } else { conf->lastuser->nextuser = user; conf->lastuser = user; } } user->chan = chan; user->userflags = confflags; user->adminflags = 0; ast_mutex_unlock(&conflock); origquiet = confflags & CONFFLAG_QUIET; if (confflags & CONFFLAG_EXIT_CONTEXT) { if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) strncpy(exitcontext, agifile, sizeof(exitcontext) - 1); else if (!ast_strlen_zero(chan->macrocontext)) strncpy(exitcontext, chan->macrocontext, sizeof(exitcontext) - 1); else strncpy(exitcontext, chan->context, sizeof(exitcontext) - 1); } while((confflags & CONFFLAG_WAITMARKED) && (conf->markedusers == 0)) { confflags &= ~CONFFLAG_QUIET; confflags |= origquiet; /* XXX Announce that we're waiting on the conference lead to join */ if (!(confflags & CONFFLAG_QUIET)) { res = ast_streamfile(chan, "vm-dialout", chan->language); if (!res) res = ast_waitstream(chan, ""); } else res = 0; /* If we're waiting with hold music, set to silent mode */ if (!res) { confflags |= CONFFLAG_QUIET; ast_moh_start(chan, NULL); res = ast_safe_sleep_conditional(chan, 60000, confnonzero, conf); ast_moh_stop(chan); } if (res < 0) { ast_log(LOG_DEBUG, "Got hangup on '%s' already\n", chan->name); goto outrun; } } if (!(confflags & CONFFLAG_QUIET) && conf->users == 1) { if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) { if (ast_waitstream(chan, "") < 0) goto outrun; } else goto outrun; } /* Set it into linear mode (write) */ if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name); goto outrun; } /* Set it into linear mode (read) */ if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) { ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name); goto outrun; } ast_indicate(chan, -1); retryzap = strcasecmp(chan->type, "Zap"); zapretry: origfd = chan->fds[0]; if (retryzap) { fd = open("/dev/zap/pseudo", O_RDWR); if (fd < 0) { ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno)); goto outrun; } using_pseudo = 1; /* Make non-blocking */ flags = fcntl(fd, F_GETFL); if (flags < 0) { ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno)); close(fd); goto outrun; } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno)); close(fd); goto outrun; } /* Setup buffering information */ memset(&bi, 0, sizeof(bi)); bi.bufsize = CONF_SIZE/2; bi.txbufpolicy = ZT_POLICY_IMMEDIATE; bi.rxbufpolicy = ZT_POLICY_IMMEDIATE; bi.numbufs = 4; if (ioctl(fd, ZT_SET_BUFINFO, &bi)) { ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno)); close(fd); goto outrun; } x = 1; if (ioctl(fd, ZT_SETLINEAR, &x)) { ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno)); close(fd); goto outrun; } nfds = 1; } else { /* XXX Make sure we're not running on a pseudo channel XXX */ fd = chan->fds[0]; nfds = 0; } memset(&ztc, 0, sizeof(ztc)); /* Check to see if we're in a conference... */ ztc.chan = 0; if (ioctl(fd, ZT_GETCONF, &ztc)) { ast_log(LOG_WARNING, "Error getting conference\n"); close(fd); goto outrun; } if (ztc.confmode) { /* Whoa, already in a conference... Retry... */ if (!retryzap) { ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n"); retryzap = 1; goto zapretry; } } memset(&ztc, 0, sizeof(ztc)); /* Add us to the conference */ ztc.chan = 0; ztc.confno = conf->zapconf; if (confflags & CONFFLAG_MONITOR) ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER; else if (confflags & CONFFLAG_TALKER) ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER; else ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference\n"); close(fd); goto outrun; } ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf); manager_event(EVENT_FLAG_CALL, "MeetmeJoin", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Meetme: %s\r\n" "Usernum: %i\r\n", chan->name, chan->uniqueid, conf->confno, user->user_no); if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) { firstpass = 1; if (!(confflags & CONFFLAG_QUIET)) conf_play(conf, ENTER); } if (confflags & CONFFLAG_AGI) { /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND) or use default filename of conf-background.agi */ agifile = pbx_builtin_getvar_helper(chan,"MEETME_AGI_BACKGROUND"); if (!agifile) agifile = agifiledefault; if (!strcasecmp(chan->type,"Zap")) { /* Set CONFMUTE mode on Zap channel to mute DTMF tones */ x = 1; ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0); } /* Find a pointer to the agi app and execute the script */ app = pbx_findapp("agi"); if (app) { ret = pbx_exec(chan, app, agifile, 1); } else { ast_log(LOG_WARNING, "Could not find application (agi)\n"); ret = -2; } if (!strcasecmp(chan->type,"Zap")) { /* Remove CONFMUTE mode on Zap channel */ x = 0; ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0); } } else { if (!strcasecmp(chan->type,"Zap") && (confflags & CONFFLAG_STARMENU)) { /* Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */ x = 1; ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0); } for(;;) { outfd = -1; ms = -1; c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms); /* Update the struct with the actual confflags */ user->userflags = confflags; /* trying to add moh for single person conf */ if (confflags & CONFFLAG_MOH) { if (conf->users == 1) { if (musiconhold == 0) { ast_moh_start(chan, NULL); musiconhold = 1; } } else { if (musiconhold) { ast_moh_stop(chan); musiconhold = 0; } } } /* Leave if the last marked user left */ if (conf->markedusers == 0 && confflags & CONFFLAG_MARKEDEXIT) { ret = -1; break; } /* Check if the admin changed my modes */ if (user->adminflags) { /* Set the new modes */ if ((user->adminflags & ADMINFLAG_MUTED) && (ztc.confmode & ZT_CONF_TALKER)) { ztc.confmode ^= ZT_CONF_TALKER; if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); ret = -1; break; } } if (!(user->adminflags & ADMINFLAG_MUTED) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) { ztc.confmode |= ZT_CONF_TALKER; if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); ret = -1; break; } } if (user->adminflags & ADMINFLAG_KICKME) { //You have been kicked. if (!ast_streamfile(chan, "conf-kicked", chan->language)) ast_waitstream(chan, ""); ret = 0; break; } } else if (!(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) { ztc.confmode |= ZT_CONF_TALKER; if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); ret = -1; break; } } if (c) { if (c->fds[0] != origfd) { if (using_pseudo) { /* Kill old pseudo */ close(fd); } ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n"); retryzap = 0; using_pseudo = 0; goto zapretry; } f = ast_read(c); if (!f) break; if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) { char tmp[2]; tmp[0] = f->subclass; tmp[1] = '\0'; if (ast_exists_extension(chan, exitcontext, tmp, 1, chan->callerid)) { strncpy(chan->context, exitcontext, sizeof(chan->context) - 1); strncpy(chan->exten, tmp, sizeof(chan->exten) - 1); chan->priority = 0; ret = 0; break; } } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) { ret = 0; break; } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) { if (musiconhold) { ast_moh_stop(chan); } if ((confflags & CONFFLAG_ADMIN)) { /* Admin menu */ if (!menu_active) { menu_active = 1; /* Record this sound! */ if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) dtmf = ast_waitstream(chan, AST_DIGIT_ANY); else dtmf = 0; } else dtmf = f->subclass; if (dtmf) { switch(dtmf) { case '1': /* Un/Mute */ menu_active = 0; if (ztc.confmode & ZT_CONF_TALKER) { ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER; confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER; } else { ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER; } if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); ret = -1; break; } if (ztc.confmode & ZT_CONF_TALKER) { if (!ast_streamfile(chan, "conf-unmuted", chan->language)) ast_waitstream(chan, ""); } else { if (!ast_streamfile(chan, "conf-muted", chan->language)) ast_waitstream(chan, ""); } break; case '2': /* Un/Lock the Conference */ menu_active = 0; if (conf->locked) { conf->locked = 0; if (!ast_streamfile(chan, "conf-unlockednow", chan->language)) ast_waitstream(chan, ""); } else { conf->locked = 1; if (!ast_streamfile(chan, "conf-lockednow", chan->language)) ast_waitstream(chan, ""); } break; default: menu_active = 0; /* Play an error message! */ if (!ast_streamfile(chan, "conf-errormenu", chan->language)) ast_waitstream(chan, ""); break; } } } else { /* User menu */ if (!menu_active) { menu_active = 1; /* Record this sound! */ if (!ast_streamfile(chan, "conf-usermenu", chan->language)) dtmf = ast_waitstream(chan, AST_DIGIT_ANY); else dtmf = 0; } else dtmf = f->subclass; if (dtmf) { switch(dtmf) { case '1': /* Un/Mute */ menu_active = 0; if (ztc.confmode & ZT_CONF_TALKER) { ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER; confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER; } else if (!(user->adminflags & ADMINFLAG_MUTED)) { ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER; } if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); ret = -1; break; } if (ztc.confmode & ZT_CONF_TALKER) { if (!ast_streamfile(chan, "conf-unmuted", chan->language)) ast_waitstream(chan, ""); } else { if (!ast_streamfile(chan, "conf-muted", chan->language)) ast_waitstream(chan, ""); } break; default: menu_active = 0; /* Play an error message! */ if (!ast_streamfile(chan, "conf-errormenu", chan->language)) ast_waitstream(chan, ""); break; } } } if (musiconhold) { ast_moh_start(chan, NULL); } } else if (using_pseudo) { if (f->frametype == AST_FRAME_VOICE) { if (f->subclass == AST_FORMAT_SLINEAR) { /* Carefully write */ careful_write(fd, f->data, f->datalen); } else ast_log(LOG_WARNING, "Huh? Got a non-linear (%d) frame in the conference\n", f->subclass); } } ast_frfree(f); } else if (outfd > -1) { res = read(outfd, buf, CONF_SIZE); if (res > 0) { memset(&fr, 0, sizeof(fr)); fr.frametype = AST_FRAME_VOICE; fr.subclass = AST_FORMAT_SLINEAR; fr.datalen = res; fr.samples = res/2; fr.data = buf; fr.offset = AST_FRIENDLY_OFFSET; if (ast_write(chan, &fr) < 0) { ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno)); /* break; */ } } else ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno)); } } } if (using_pseudo) close(fd); else { /* Take out of conference */ /* Add us to the conference */ ztc.chan = 0; ztc.confno = 0; ztc.confmode = 0; if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference\n"); } } if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) conf_play(conf, LEAVE); outrun: ast_mutex_lock(&conflock); if (user->user_no) { /* Only cleanup users who really joined! */ manager_event(EVENT_FLAG_CALL, "MeetmeLeave", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Meetme: %s\r\n" "Usernum: %i\r\n", chan->name, chan->uniqueid, conf->confno, user->user_no); prev = NULL; conf->users--; if (confflags & CONFFLAG_MARKEDUSER) conf->markedusers--; cur = confs; if (!conf->users) { /* No more users -- close this one out */ while(cur) { if (cur == conf) { if (prev) prev->next = conf->next; else confs = conf->next; break; } prev = cur; cur = cur->next; } if (!cur) ast_log(LOG_WARNING, "Conference not found\n"); if (conf->chan) ast_hangup(conf->chan); else close(conf->fd); free(conf); } else { /* Remove the user struct */ if (user == conf->firstuser) { if (user->nextuser) { /* There is another entry */ user->nextuser->prevuser = NULL; } else { /* We are the only entry */ conf->lastuser = NULL; } /* In either case */ conf->firstuser = user->nextuser; } else if (user == conf->lastuser){ if (user->prevuser) user->prevuser->nextuser = NULL; else ast_log(LOG_ERROR, "Bad bad bad! We're the last, not the first, but nobody before us??\n"); conf->lastuser = user->prevuser; } else { if (user->nextuser) user->nextuser->prevuser = user->prevuser; else ast_log(LOG_ERROR, "Bad! Bad! Bad! user->nextuser is NULL but we're not the end!\n"); if (user->prevuser) user->prevuser->nextuser = user->nextuser; else ast_log(LOG_ERROR, "Bad! Bad! Bad! user->prevuser is NULL but we're not the beginning!\n"); } } /* Return the number of seconds the user was in the conf */ snprintf(meetmesecs, sizeof(meetmesecs), "%i", (int) (time(NULL) - user->jointime)); pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs); } free(user); ast_mutex_unlock(&conflock); return ret; }
/*! \brief Start monitoring a channel * \param chan ast_channel struct to record * \param format_spec file format to use for recording * \param fname_base filename base to record to * \param need_lock whether to lock the channel mutex * \param stream_action whether to record the input and/or output streams. X_REC_IN | X_REC_OUT is most often used * Creates the file to record, if no format is specified it assumes WAV * It also sets channel variable __MONITORED=yes * \retval 0 on success * \retval -1 on failure */ int ast_monitor_start( struct ast_channel *chan, const char *format_spec, const char *fname_base, int need_lock, int stream_action) { int res = 0; LOCK_IF_NEEDED(chan, need_lock); if (!(chan->monitor)) { struct ast_channel_monitor *monitor; char *channel_name, *p; /* Create monitoring directory if needed */ ast_mkdir(ast_config_AST_MONITOR_DIR, 0777); if (!(monitor = ast_calloc(1, sizeof(*monitor)))) { UNLOCK_IF_NEEDED(chan, need_lock); return -1; } /* Determine file names */ if (!ast_strlen_zero(fname_base)) { int directory = strchr(fname_base, '/') ? 1 : 0; const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR; snprintf(monitor->read_filename, FILENAME_MAX, "%s/%s-in", absolute, fname_base); snprintf(monitor->write_filename, FILENAME_MAX, "%s/%s-out", absolute, fname_base); snprintf(monitor->filename_base, FILENAME_MAX, "%s/%s", absolute, fname_base); /* try creating the directory just in case it doesn't exist */ if (directory) { char *name = ast_strdupa(monitor->filename_base); ast_mkdir(dirname(name), 0777); } } else { ast_mutex_lock(&monitorlock); snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld", ast_config_AST_MONITOR_DIR, seq); snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld", ast_config_AST_MONITOR_DIR, seq); seq++; ast_mutex_unlock(&monitorlock); channel_name = ast_strdupa(chan->name); while ((p = strchr(channel_name, '/'))) { *p = '-'; } snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s", ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name); monitor->filename_changed = 1; } monitor->stop = ast_monitor_stop; /* Determine file format */ if (!ast_strlen_zero(format_spec)) { monitor->format = ast_strdup(format_spec); } else { monitor->format = ast_strdup("wav"); } /* open files */ if (stream_action & X_REC_IN) { if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0) ast_filedelete(monitor->read_filename, NULL); if (!(monitor->read_stream = ast_writefile(monitor->read_filename, monitor->format, NULL, O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) { ast_log(LOG_WARNING, "Could not create file %s\n", monitor->read_filename); ast_free(monitor); UNLOCK_IF_NEEDED(chan, need_lock); return -1; } } else monitor->read_stream = NULL; if (stream_action & X_REC_OUT) { if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) { ast_filedelete(monitor->write_filename, NULL); } if (!(monitor->write_stream = ast_writefile(monitor->write_filename, monitor->format, NULL, O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) { ast_log(LOG_WARNING, "Could not create file %s\n", monitor->write_filename); ast_closestream(monitor->read_stream); ast_free(monitor); UNLOCK_IF_NEEDED(chan, need_lock); return -1; } } else monitor->write_stream = NULL; chan->monitor = monitor; ast_monitor_set_state(chan, AST_MONITOR_RUNNING); /* 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", chan->name, chan->uniqueid ); } else { ast_debug(1,"Cannot start monitoring %s, already monitored\n", chan->name); res = -1; } UNLOCK_IF_NEEDED(chan, need_lock); return res; }
/*! * \brief Stop monitoring channel * \param chan * \param need_lock * Stop the recording, close any open streams, mix in/out channels if required * \return Always 0 */ int ast_monitor_stop(struct ast_channel *chan, int need_lock) { int delfiles = 0; LOCK_IF_NEEDED(chan, need_lock); if (chan->monitor) { char filename[ FILENAME_MAX ]; if (chan->monitor->read_stream) { ast_closestream(chan->monitor->read_stream); } if (chan->monitor->write_stream) { ast_closestream(chan->monitor->write_stream); } if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) { if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) { snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base); if (ast_fileexists(filename, NULL, NULL) > 0) { ast_filedelete(filename, NULL); } ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format); } else { ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename); } if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) { snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base); if (ast_fileexists(filename, NULL, NULL) > 0) { ast_filedelete(filename, NULL); } ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format); } else { ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename); } } if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) { char tmp[1024]; char tmp2[1024]; const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format; char *name = chan->monitor->filename_base; int directory = strchr(name, '/') ? 1 : 0; const char *dir = directory ? "" : ast_config_AST_MONITOR_DIR; const char *execute, *execute_args; const char *absolute = *name == '/' ? "" : "/"; /* Set the execute application */ execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC"); if (ast_strlen_zero(execute)) { #ifdef HAVE_SOXMIX execute = "nice -n 19 soxmix"; #else execute = "nice -n 19 sox -m"; #endif format = get_soxmix_format(format); delfiles = 1; } execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS"); if (ast_strlen_zero(execute_args)) { execute_args = ""; } snprintf(tmp, sizeof(tmp), "%s \"%s%s%s-in.%s\" \"%s%s%s-out.%s\" \"%s%s%s.%s\" %s &", execute, dir, absolute, name, format, dir, absolute, name, format, dir, absolute, name, format,execute_args); if (delfiles) { snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s%s%s-\"* ) &",tmp, dir, absolute, name); /* remove legs when done mixing */ ast_copy_string(tmp, tmp2, sizeof(tmp)); } ast_debug(1,"monitor executing %s\n",tmp); if (ast_safe_system(tmp) == -1) ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp); } ast_free(chan->monitor->format); ast_free(chan->monitor); chan->monitor = NULL; manager_event(EVENT_FLAG_CALL, "MonitorStop", "Channel: %s\r\n" "Uniqueid: %s\r\n", chan->name, chan->uniqueid ); } UNLOCK_IF_NEEDED(chan, need_lock); return 0; }