static struct ast_channel *media_request_helper(struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, struct ast_channel_tech *tech, const char *role) { struct ast_channel *chan; ast_callid callid; RAII_VAR(struct ast_unreal_pvt *, pvt, NULL, ao2_cleanup); if (!(pvt = ast_unreal_alloc(sizeof(*pvt), ast_unreal_destructor, cap))) { return NULL; } ast_copy_string(pvt->name, data, sizeof(pvt->name)); ast_set_flag(pvt, AST_UNREAL_NO_OPTIMIZATION); callid = ast_read_threadstorage_callid(); chan = ast_unreal_new_channels(pvt, tech, AST_STATE_UP, AST_STATE_UP, NULL, NULL, assignedids, requestor, callid); if (!chan) { return NULL; } ast_answer(pvt->owner); ast_answer(pvt->chan); if (ast_channel_add_bridge_role(pvt->chan, role)) { ast_hangup(chan); return NULL; } return chan; }
static struct ast_channel *announce_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) { struct ast_channel *chan; const char *conf_name = data; /* Allocate a new private structure and then Asterisk channels */ struct announce_pvt *pvt = (struct announce_pvt *) ast_unreal_alloc(sizeof(*pvt), announce_pvt_destructor, cap); if (!pvt) { return NULL; } ast_set_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION); ast_copy_string(pvt->base.name, conf_name, sizeof(pvt->base.name)); #if !defined(CS_AST_CHANNEL_CALLID_TYPEDEF) chan = ast_unreal_new_channels(&pvt->base, sccpconf_announce_get_tech(), AST_STATE_UP, AST_STATE_UP, NULL, NULL, assignedids, requestor, NULL); #else chan = ast_unreal_new_channels(&pvt->base, sccpconf_announce_get_tech(), AST_STATE_UP, AST_STATE_UP, NULL, NULL, assignedids, requestor, 0); #endif if (chan) { ast_answer(pvt->base.owner); ast_answer(pvt->base.chan); if (ast_channel_add_bridge_role(pvt->base.chan, "announcer")) { ast_hangup(chan); chan = NULL; } } ao2_cleanup(pvt); return chan; }
static int waitforsilence_exec(struct ast_channel *chan, void *data) { int res = 1; int silencereqd = 1000; int timeout = 0; int iterations = 1, i; time_t waitstart; res = ast_answer(chan); /* Answer the channel */ if (!data || ( (sscanf(data, "%d|%d|%d", &silencereqd, &iterations, &timeout) != 3) && (sscanf(data, "%d|%d", &silencereqd, &iterations) != 2) && (sscanf(data, "%d", &silencereqd) != 1) ) ) { ast_log(LOG_WARNING, "Using default value of 1000ms, 1 iteration, no timeout\n"); } if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Waiting %d time(s) for %d ms silence with %d timeout\n", iterations, silencereqd, timeout); time(&waitstart); res = 1; for (i=0; (i<iterations) && (res == 1); i++) { res = do_waiting(chan, silencereqd, waitstart, timeout); } if (res > 0) res = 0; return res; }
/*--- count_exec: The MeetmeCount application */ static int count_exec(struct ast_channel *chan, void *data) { struct localuser *u; int res = 0; struct ast_conference *conf; int count; char *confnum, *localdata; char val[80] = "0"; if (!data || ast_strlen_zero(data)) { ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n"); return -1; } localdata = ast_strdupa(data); LOCAL_USER_ADD(u); confnum = strsep(&localdata,"|"); conf = find_conf(chan, confnum, 0, 0, NULL); if (conf) count = conf->users; else count = 0; if (localdata && !ast_strlen_zero(localdata)){ /* have var so load it and exit */ snprintf(val,sizeof(val), "%i",count); pbx_builtin_setvar_helper(chan, localdata,val); } else { if (chan->_state != AST_STATE_UP) ast_answer(chan); res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */ } LOCAL_USER_REMOVE(u); return res; }
static int dahdiras_exec(struct ast_channel *chan, const char *data) { int res=-1; char *args; struct dahdi_params dahdip; if (!data) data = ""; args = ast_strdupa(data); /* Answer the channel if it's not up */ if (ast_channel_state(chan) != AST_STATE_UP) ast_answer(chan); if (strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) { /* If it's not a DAHDI channel, we're done. Wait a couple of seconds and then hangup... */ ast_verb(2, "Channel %s is not a DAHDI channel\n", ast_channel_name(chan)); sleep(2); } else { memset(&dahdip, 0, sizeof(dahdip)); if (ioctl(ast_channel_fd(chan, 0), DAHDI_GET_PARAMS, &dahdip)) { ast_log(LOG_WARNING, "Unable to get DAHDI parameters\n"); } else if (dahdip.sigtype != DAHDI_SIG_CLEAR) { ast_verb(2, "Channel %s is not a clear channel\n", ast_channel_name(chan)); } else { /* Everything should be okay. Run PPP. */ ast_verb(3, "Starting RAS on %s\n", ast_channel_name(chan)); /* Execute RAS */ run_ras(chan, args); } } return res; }
static int steal_channel(struct ast_channel *chan, void *pattern) { int ret = 0; struct ast_module_user *u; struct ast_channel *cur; u = ast_module_user_add(chan); cur = find_matching_channel(chan, pattern, AST_STATE_UP); if (cur) { ast_verbose(VERBOSE_PREFIX_3 "Channel %s stole channel %s\n", chan->name, cur->name); pbx_builtin_setvar_helper(chan, "STEAL_CHANNEL", cur->name); if (chan->_state != AST_STATE_UP) { ast_answer(chan); } if (cur->_bridge) { if (!ast_mutex_lock(&cur->_bridge->lock)) { ast_moh_stop(cur->_bridge); ast_mutex_unlock(&cur->_bridge->lock); } } if (ast_channel_masquerade(cur, chan)) { ast_log(LOG_ERROR, "unable to masquerade\n"); ret = -1; } ast_mutex_unlock(&cur->lock); ast_mutex_unlock(&chan->lock); } else { pbx_builtin_setvar_helper(chan, "STEAL_CHANNEL", ""); } ast_module_user_remove(u); return(ret); }
static int waitforsilence_exec(struct ast_channel *chan, void *data) { int res = 1; struct localuser *u; int maxsilence = 1000; int iterations = 1, i; LOCAL_USER_ADD(u); res = ast_answer(chan); /* Answer the channel */ if (!data || ((sscanf(data, "%d|%d", &maxsilence, &iterations) != 2) && (sscanf(data, "%d", &maxsilence) != 1))) { ast_log(LOG_WARNING, "Using default value of 1000ms, 1 iteration\n"); } if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Waiting %d time(s) for %d ms silence\n", iterations, maxsilence); res = 1; for (i=0; (i<iterations) && (res == 1); i++) { res = do_waiting(chan, maxsilence); } LOCAL_USER_REMOVE(u); if (res > 0) res = 0; return res; }
/*! \brief Called when we want to place a call somewhere, but not actually call it... yet */ static struct ast_channel *bridge_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, void *data, int *cause) { struct bridge_pvt *p = NULL; struct ast_format slin; /* Try to allocate memory for our very minimal pvt structure */ if (!(p = ao2_alloc(sizeof(*p), NULL))) { return NULL; } /* Try to grab two Asterisk channels to use as input and output channels */ if (!(p->input = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", requestor ? requestor->linkedid : NULL, 0, "Bridge/%p-input", p))) { ao2_ref(p, -1); return NULL; } if (!(p->output = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", requestor ? requestor->linkedid : NULL, 0, "Bridge/%p-output", p))) { p->input = ast_channel_release(p->input); ao2_ref(p, -1); return NULL; } /* Setup parameters on both new channels */ p->input->tech = p->output->tech = &bridge_tech; ao2_ref(p, 2); p->input->tech_pvt = p->output->tech_pvt = p; ast_format_set(&slin, AST_FORMAT_SLINEAR, 0); ast_format_cap_add(p->input->nativeformats, &slin); ast_format_cap_add(p->output->nativeformats, &slin); ast_format_copy(&p->input->readformat, &slin); ast_format_copy(&p->output->readformat, &slin); ast_format_copy(&p->input->rawreadformat, &slin); ast_format_copy(&p->output->rawreadformat, &slin); ast_format_copy(&p->input->writeformat, &slin); ast_format_copy(&p->output->writeformat, &slin); ast_format_copy(&p->input->rawwriteformat, &slin); ast_format_copy(&p->output->rawwriteformat, &slin); ast_answer(p->output); ast_answer(p->input); /* remove the reference from the alloc. The channels now own the pvt. */ ao2_ref(p, -1); return p->input; }
static int transmit(fax_session *s) { int res = 0; /* Clear all channel variables which to be set by the application. Pre-set status to error so in case of any problems we can just leave */ pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED"); pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems"); pbx_builtin_setvar_helper(s->chan, "FAXMODE", NULL); pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", NULL); pbx_builtin_setvar_helper(s->chan, "FAXPAGES", "0"); pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", NULL); pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL); if (ast_channel_state(s->chan) != AST_STATE_UP) { /* Shouldn't need this, but checking to see if channel is already answered * Theoretically asterisk should already have answered before running the app */ res = ast_answer(s->chan); if (res) { ast_log(LOG_WARNING, "Could not answer channel '%s'\n", ast_channel_name(s->chan)); return res; } } s->t38state = ast_channel_get_t38_state(s->chan); if (s->t38state != T38_STATE_NEGOTIATED) { /* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */ pbx_builtin_setvar_helper(s->chan, "FAXMODE", "audio"); res = transmit_audio(s); if (res > 0) { /* transmit_audio reports switchover to T38. Update t38state */ s->t38state = ast_channel_get_t38_state(s->chan); if (s->t38state != T38_STATE_NEGOTIATED) { ast_log(LOG_ERROR, "Audio loop reports T38 switchover but t38state != T38_STATE_NEGOTIATED\n"); } } } if (s->t38state == T38_STATE_NEGOTIATED) { pbx_builtin_setvar_helper(s->chan, "FAXMODE", "T38"); res = transmit_t38(s); } if (res) { ast_log(LOG_WARNING, "Transmission error\n"); res = -1; } else if (s->finished < 0) { ast_log(LOG_WARNING, "Transmission failed\n"); } else if (s->finished > 0) { ast_debug(1, "Transmission finished Ok\n"); } return res; }
static int datetime_exec(struct ast_channel *chan, void *data) { int res=0; time_t t; struct localuser *u; LOCAL_USER_ADD(u); time(&t); if (chan->_state != AST_STATE_UP) res = ast_answer(chan); if (!res) res = ast_say_datetime(chan, t, "", chan->language); LOCAL_USER_REMOVE(u); return res; }
static int exec(struct ast_channel *chan, void *data, int dahdimode) { int res=-1; struct ast_module_user *u; int retrycnt = 0; int confflags = 0; int confno = 0; char confstr[80] = ""; u = ast_module_user_add(chan); if (!ast_strlen_zero(data)) { if (dahdimode) { if ((sscanf(data, "DAHDI/%30d", &confno) != 1) && (sscanf(data, "%30d", &confno) != 1)) { ast_log(LOG_WARNING, "Argument (if specified) must be a channel number, not '%s'\n", (char *) data); ast_module_user_remove(u); return 0; } } else { if ((sscanf(data, "Zap/%30d", &confno) != 1) && (sscanf(data, "%30d", &confno) != 1)) { ast_log(LOG_WARNING, "Argument (if specified) must be a channel number, not '%s'\n", (char *) data); ast_module_user_remove(u); return 0; } } } if (chan->_state != AST_STATE_UP) ast_answer(chan); while(!confno && (++retrycnt < 4)) { /* Prompt user for conference number */ confstr[0] = '\0'; res = ast_app_getdata(chan, "conf-getchannel",confstr, sizeof(confstr) - 1, 0); if (res <0) goto out; if (sscanf(confstr, "%30d", &confno) != 1) confno = 0; } if (confno) { /* XXX Should prompt user for pin if pin is required XXX */ /* Run the conference */ res = conf_run(chan, confno, confflags); } out: /* Do the conference */ ast_module_user_remove(u); return res; }
static struct ast_channel *announce_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) { struct ast_channel *chan; const char *conf_name = data; RAII_VAR(struct confbridge_conference *, conference, NULL, ao2_cleanup); RAII_VAR(struct announce_pvt *, pvt, NULL, ao2_cleanup); conference = ao2_find(conference_bridges, conf_name, OBJ_KEY); if (!conference) { return NULL; } ast_assert(conference->bridge != NULL); /* Allocate a new private structure and then Asterisk channels */ pvt = (struct announce_pvt *) ast_unreal_alloc(sizeof(*pvt), announce_pvt_destructor, cap); if (!pvt) { return NULL; } ast_set_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION); ast_copy_string(pvt->base.name, conf_name, sizeof(pvt->base.name)); pvt->bridge = conference->bridge; ao2_ref(pvt->bridge, +1); chan = ast_unreal_new_channels(&pvt->base, conf_announce_get_tech(), AST_STATE_UP, AST_STATE_UP, NULL, NULL, assignedids, requestor, 0); if (chan) { ast_answer(pvt->base.owner); ast_answer(pvt->base.chan); if (ast_channel_add_bridge_role(pvt->base.chan, "announcer")) { ast_hangup(chan); chan = NULL; } } return chan; }
static int bridgeadd_exec(struct ast_channel *chan, const char *data) { struct ast_channel *c_ref; struct ast_bridge_features chan_features; struct ast_bridge *bridge; char *c_name; /* Answer the channel if needed */ if (ast_channel_state(chan) != AST_STATE_UP) { ast_answer(chan); } if (!(c_ref = ast_channel_get_by_name_prefix(data, strlen(data)))) { ast_log(LOG_WARNING, "Channel %s not found\n", data); return -1; } c_name = ast_strdupa(ast_channel_name(c_ref)); ast_channel_lock(c_ref); bridge = ast_channel_get_bridge(c_ref); ast_channel_unlock(c_ref); ast_channel_unref(c_ref); if (!bridge) { ast_log(LOG_WARNING, "Channel %s is not in a bridge\n", c_name); return -1; } ast_verb(3, "%s is joining %s in bridge %s\n", ast_channel_name(chan), c_name, bridge->uniqueid); if (ast_bridge_features_init(&chan_features) || ast_bridge_join(bridge, chan, NULL, &chan_features, NULL, 0)) { ast_log(LOG_WARNING, "%s failed to join %s in bridge %s\n", ast_channel_name(chan), c_name, bridge->uniqueid); ast_bridge_features_cleanup(&chan_features); ao2_cleanup(bridge); return -1; } ast_bridge_features_cleanup(&chan_features); ao2_cleanup(bridge); return 0; }
static int zapateller_exec(struct ast_channel *chan, void *data) { int res = 0; struct localuser *u; int answer = 0, nocallerid = 0; char *c; char *stringp=NULL; LOCAL_USER_ADD(u); stringp=data; c = strsep(&stringp, "|"); while(!ast_strlen_zero(c)) { if (!strcasecmp(c, "answer")) answer = 1; else if (!strcasecmp(c, "nocallerid")) nocallerid = 1; c = strsep(&stringp, "|"); } ast_stopstream(chan); if (chan->_state != AST_STATE_UP) { if (answer) res = ast_answer(chan); if (!res) { res = ast_safe_sleep(chan, 500); } } if (chan->cid.cid_num && nocallerid) { LOCAL_USER_REMOVE(u); return res; } if (!res) res = ast_tonepair(chan, 950, 0, 330, 0); if (!res) res = ast_tonepair(chan, 1400, 0, 330, 0); if (!res) res = ast_tonepair(chan, 1800, 0, 330, 0); if (!res) res = ast_tonepair(chan, 0, 0, 1000, 0); LOCAL_USER_REMOVE(u); return res; }
/*! * \brief Pickup a call * \param chan channel that initiated pickup. * * Walk list of channels, checking it is not itself, channel is pbx one, * check that the callgroup for both channels are the same and the channel is ringing. * Answer calling channel, flag channel as answered on queue, masq channels together. */ int ast_pickup_call(struct ast_channel *chan) { struct ast_channel *target;/*!< Potential pickup target */ int res = -1; RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup); const char *pickup_sound; const char *fail_sound; ast_debug(1, "Pickup attempt by %s\n", ast_channel_name(chan)); ast_channel_lock(chan); pickup_cfg = ast_get_chan_features_pickup_config(chan); if (!pickup_cfg) { ast_log(LOG_ERROR, "Unable to retrieve pickup configuration. Unable to play pickup sounds\n"); } pickup_sound = ast_strdupa(pickup_cfg ? pickup_cfg->pickupsound : ""); fail_sound = ast_strdupa(pickup_cfg ? pickup_cfg->pickupfailsound : ""); ast_channel_unlock(chan); /* The found channel is already locked. */ target = ast_pickup_find_by_group(chan); if (target) { ast_log(LOG_NOTICE, "Pickup %s attempt by %s\n", ast_channel_name(target), ast_channel_name(chan)); res = ast_do_pickup(chan, target); ast_channel_unlock(target); if (!res) { if (!ast_strlen_zero(pickup_sound)) { pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickup_sound); } } else { ast_log(LOG_WARNING, "Pickup %s failed by %s\n", ast_channel_name(target), ast_channel_name(chan)); } target = ast_channel_unref(target); } if (res < 0) { ast_debug(1, "No call pickup possible... for %s\n", ast_channel_name(chan)); if (!ast_strlen_zero(fail_sound)) { ast_answer(chan); ast_stream_and_wait(chan, fail_sound, ""); } } return res; }
static int skel_exec(struct ast_channel *chan, const char *data) { int res=0; char *tmp; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "skel requires an argument (filename)\n"); return -1; } tmp = ast_strdupa(data); /* Do our thing here */ if (ast_channel_state(chan) != AST_STATE_UP) res = ast_answer(chan); if (!res) res = ast_ivr_menu_run(chan, &ivr_demo, tmp); return res; }
static int milliwatt_exec(struct ast_channel *chan, void *data) { struct localuser *u; LOCAL_USER_ADD(u); ast_set_write_format(chan, AST_FORMAT_ULAW); ast_set_read_format(chan, AST_FORMAT_ULAW); if (chan->_state != AST_STATE_UP) { ast_answer(chan); } if (ast_activate_generator(chan,&milliwattgen,"milliwatt") < 0) { ast_log(LOG_WARNING,"Failed to activate generator on '%s'\n",chan->name); return -1; } while(!ast_safe_sleep(chan, 10000)); ast_deactivate_generator(chan); LOCAL_USER_REMOVE(u); return -1; }
static int old_milliwatt_exec(struct ast_channel *chan) { ast_set_write_format_by_id(chan, AST_FORMAT_ULAW); ast_set_read_format_by_id(chan, AST_FORMAT_ULAW); if (ast_channel_state(chan) != AST_STATE_UP) { ast_answer(chan); } if (ast_activate_generator(chan,&milliwattgen,"milliwatt") < 0) { ast_log(LOG_WARNING,"Failed to activate generator on '%s'\n",ast_channel_name(chan)); return -1; } while (!ast_safe_sleep(chan, 10000)) ; ast_deactivate_generator(chan); return -1; }
static int waitfor_exec(struct ast_channel *chan, const char *data, int wait_for_silence) { int res = 1; int timereqd = 1000; int timeout = 0; int iterations = 1, i; time_t waitstart; struct ast_silence_generator *silgen = NULL; if (chan->_state != AST_STATE_UP) { res = ast_answer(chan); /* Answer the channel */ } if (!data || ( (sscanf(data, "%30d,%30d,%30d", &timereqd, &iterations, &timeout) != 3) && (sscanf(data, "%30d,%30d", &timereqd, &iterations) != 2) && (sscanf(data, "%30d", &timereqd) != 1) ) ) { ast_log(LOG_WARNING, "Using default value of 1000ms, 1 iteration, no timeout\n"); } ast_verb(3, "Waiting %d time(s) for %d ms silence with %d timeout\n", iterations, timereqd, timeout); if (ast_opt_transmit_silence) { silgen = ast_channel_start_silence_generator(chan); } time(&waitstart); res = 1; for (i=0; (i<iterations) && (res == 1); i++) { res = do_waiting(chan, timereqd, waitstart, timeout, wait_for_silence); } if (silgen) { ast_channel_stop_silence_generator(chan, silgen); } if (res > 0) res = 0; return res; }
/* Perform actual pickup between two channels */ static int pickup_do(struct ast_channel *chan, struct ast_channel *target) { int res = 0; if (option_debug) ast_log(LOG_DEBUG, "Call pickup on '%s' by '%s'\n", target->name, chan->name); if ((res = ast_answer(chan))) { ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); return -1; } if ((res = ast_queue_control(chan, AST_CONTROL_ANSWER))) { ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); return -1; } if ((res = ast_channel_masquerade(target, chan))) { ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name); return -1; } return res; }
static int nv_detectfax_exec(struct ast_channel *chan, const char *data) { int res = 0; char tmp[256] = "\0"; char *p = NULL; char *waitstr = NULL; char *options = NULL; char *silstr = NULL; char *minstr = NULL; char *maxstr = NULL; struct ast_frame *fr = NULL; struct ast_frame *fr2 = NULL; int notsilent = 0; struct timeval start = {0, 0}, end = {0, 0}; int waitdur = 4; int sildur = 1000; int mindur = 100; int maxdur = -1; int skipanswer = 0; int noextneeded = 0; int ignoredtmf = 0; int ignorefax = 0; int ignoretalk = 0; int x = 0; struct ast_format* origrformat = NULL; int features = 0; time_t timeout = 0; struct ast_dsp *dsp = NULL; struct ast_format_cap *cap; struct ast_format linearFormat; /* linear format capabilities */ ast_format_set(&linearFormat, AST_FORMAT_SLINEAR, 0); cap = ast_format_cap_alloc_nolock(); ast_format_cap_add(cap, &linearFormat); /* done */ pbx_builtin_setvar_helper(chan, "FAX_DETECTED", ""); pbx_builtin_setvar_helper(chan, "FAXEXTEN", ""); pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", ""); pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ""); if (data || !ast_strlen_zero(data)) { strncpy(tmp, data, sizeof(tmp)-1); } p = tmp; waitstr = strsep(&p, ","); options = strsep(&p, ","); silstr = strsep(&p, ","); minstr = strsep(&p, ","); maxstr = strsep(&p, ","); if (waitstr) { if ((sscanf(waitstr, "%d", &x) == 1) && (x > 0)) waitdur = x; } if (options) { if (strchr(options, 'n')) skipanswer = 1; if (strchr(options, 'x')) noextneeded = 1; if (strchr(options, 'd')) ignoredtmf = 1; if (strchr(options, 'f')) ignorefax = 1; if (strchr(options, 't')) ignoretalk = 1; } if (silstr) { if ((sscanf(silstr, "%d", &x) == 1) && (x > 0)) sildur = x; } if (minstr) { if ((sscanf(minstr, "%d", &x) == 1) && (x > 0)) mindur = x; } if (maxstr) { if ((sscanf(maxstr, "%d", &x) == 1) && (x > 0)) maxdur = x; } ast_log(LOG_DEBUG, "Preparing detect of fax (waitdur=%dms, sildur=%dms, mindur=%dms, maxdur=%dms)\n", waitdur, sildur, mindur, maxdur); // LOCAL_USER_ADD(u); // if (chan->_state != AST_STATE_UP && !skipanswer) { if (ast_channel_state(chan) != AST_STATE_UP && !skipanswer) { /* Otherwise answer unless we're supposed to send this while on-hook */ res = ast_answer(chan); } if (!res) { // origrformat = chan->readformat; origrformat = ast_channel_readformat(chan); // if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR))) if ((res = ast_set_read_format_from_cap(chan, cap)) ){ ast_log(LOG_WARNING, "Unable to set read format to linear!\n"); } } if (!(dsp = ast_dsp_new())) { ast_log(LOG_WARNING, "Unable to allocate DSP!\n"); res = -1; } if (dsp) { if (!ignoretalk) ; /* features |= DSP_FEATURE_SILENCE_SUPPRESS; */ if (!ignorefax) features |= DSP_FEATURE_FAX_DETECT; //if (!ignoredtmf) features |= DSP_FEATURE_DIGIT_DETECT; ast_dsp_set_threshold(dsp, 256); ast_dsp_set_features(dsp, features | DSP_DIGITMODE_RELAXDTMF); ast_dsp_set_digitmode(dsp, DSP_DIGITMODE_DTMF); } if (!res) { if (waitdur > 0) timeout = time(NULL) + (time_t)waitdur; while(ast_waitfor(chan, -1) > -1) { if (waitdur > 0 && time(NULL) > timeout) { res = 0; break; } fr = ast_read(chan); if (!fr) { ast_log(LOG_DEBUG, "Got hangup\n"); res = -1; break; } fr2 = ast_dsp_process(chan, dsp, fr); if (!fr2) { ast_log(LOG_WARNING, "Bad DSP received (what happened?)\n"); fr2 = fr; } if (fr2->frametype == AST_FRAME_DTMF) { if (fr2->subclass.integer == 'f' && !ignorefax) { /* Fax tone -- Handle and return NULL */ ast_log(LOG_DEBUG, "Fax detected on %s\n", ast_channel_name(chan)); ast_log(LOG_DEBUG, "Fax detected on %s\n", ast_channel_name(chan)); if (strcmp(ast_channel_exten(chan), "fax")) { ast_log(LOG_NOTICE, "Redirecting %s to fax extension\n", ast_channel_name(chan)); pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "1"); pbx_builtin_setvar_helper(chan,"FAXEXTEN",ast_channel_exten(chan)); if (ast_exists_extension(chan, ast_channel_context(chan), "fax", 1, ast_channel_caller(chan)->id.number.str)) { /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ // strncpy(ast_channel_exten(chan), "fax", sizeof(ast_channel_exten(chan))-1); // chan->priority = 0; ast_channel_exten_set(chan, "fax"); ast_channel_priority_set(chan, 0); } else ast_log(LOG_WARNING, "Fax detected, but no fax extension\n"); } else ast_log(LOG_WARNING, "Already in a fax extension, not redirecting\n"); res = 0; ast_frfree(fr); break; } else if (!ignoredtmf) { ast_log(LOG_DEBUG, "DTMF detected on %s\n", ast_channel_name(chan)); char t[2]; t[0] = fr2->subclass.integer; t[1] = '\0'; if (noextneeded || ast_canmatch_extension(chan, ast_channel_context(chan), t, 1, ast_channel_caller(chan)->id.number.str)) { pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "1"); /* They entered a valid extension, or might be anyhow */ if (noextneeded) { ast_log(LOG_NOTICE, "DTMF received (not matching to exten)\n"); res = 0; } else { ast_log(LOG_NOTICE, "DTMF received (matching to exten)\n"); res = fr2->subclass.integer; } ast_frfree(fr); break; } else ast_log(LOG_DEBUG, "Valid extension requested and DTMF did not match\n"); } // } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR) && !ignoretalk) { } else if ((fr->frametype == AST_FRAME_VOICE) && ( ast_format_cap_iscompatible(cap, &fr->subclass.format)) && !ignoretalk) { int totalsilence; int ms; res = ast_dsp_silence(dsp, fr, &totalsilence); if (res && (totalsilence > sildur)) { /* We've been quiet a little while */ if (notsilent) { /* We had heard some talking */ gettimeofday(&end, NULL); ms = (end.tv_sec - start.tv_sec) * 1000; ms += (end.tv_usec - start.tv_usec) / 1000; ms -= sildur; if (ms < 0) ms = 0; if ((ms > mindur) && ((maxdur < 0) || (ms < maxdur))) { char ms_str[10]; ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms); ast_log(LOG_NOTICE, "Redirecting %s to talk extension\n", ast_channel_name(chan)); /* Save detected talk time (in milliseconds) */ sprintf(ms_str, "%d", ms); pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str); if (ast_exists_extension(chan, ast_channel_context(chan), "talk", 1, ast_channel_caller(chan)->id.number.str)) { // strncpy(ast_channel_exten(chan), "talk", sizeof(ast_channel_exten(chan)) - 1); // chan->priority = 0; ast_channel_exten_set(chan, "talk"); ast_channel_priority_set(chan, 0); } else ast_log(LOG_WARNING, "Talk detected, but no talk extension\n"); res = 0; ast_frfree(fr); break; } else ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms); notsilent = 0; } } else { if (!notsilent) { /* Heard some audio, mark the begining of the token */ gettimeofday(&start, NULL); ast_log(LOG_DEBUG, "Start of voice token!\n"); notsilent = 1; } } } ast_frfree(fr); } } else ast_log(LOG_WARNING, "Could not answer channel '%s'\n", ast_channel_name(chan)); if (res > -1) { if (origrformat && ast_set_read_format(chan, origrformat)) { ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", ast_channel_name(chan), ast_getformatname(origrformat)); } } if (dsp) ast_dsp_free(dsp); // LOCAL_USER_REMOVE(u); ast_format_cap_destroy(cap); return res; }
static int common_exec(struct ast_channel *chan, struct ast_flags *flags, int volfactor, const int fd, struct spy_dtmf_options *user_options, const char *mygroup, const char *myenforced, const char *spec, const char *exten, const char *context, const char *mailbox, const char *name_context) { char nameprefix[AST_NAME_STRLEN]; char peer_name[AST_NAME_STRLEN + 5]; char exitcontext[AST_MAX_CONTEXT] = ""; signed char zero_volume = 0; int waitms; int res; char *ptr; int num; int num_spyed_upon = 1; struct ast_channel_iterator *iter = NULL; if (ast_test_flag(flags, OPTION_EXIT)) { const char *c; ast_channel_lock(chan); if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) { ast_copy_string(exitcontext, c, sizeof(exitcontext)); } else if (!ast_strlen_zero(chan->macrocontext)) { ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext)); } else { ast_copy_string(exitcontext, chan->context, sizeof(exitcontext)); } ast_channel_unlock(chan); } if (chan->_state != AST_STATE_UP) ast_answer(chan); ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ waitms = 100; for (;;) { struct ast_autochan *autochan = NULL, *next_autochan = NULL; struct ast_channel *prev = NULL; if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { res = ast_streamfile(chan, "beep", chan->language); if (!res) res = ast_waitstream(chan, ""); else if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } if (!ast_strlen_zero(exitcontext)) { char tmp[2]; tmp[0] = res; tmp[1] = '\0'; if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) goto exit; else ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); } } /* Set up the iterator we'll be using during this call */ if (!ast_strlen_zero(spec)) { iter = ast_channel_iterator_by_name_new(spec, strlen(spec)); } else if (!ast_strlen_zero(exten)) { iter = ast_channel_iterator_by_exten_new(exten, context); } else { iter = ast_channel_iterator_all_new(); } if (!iter) { return -1; } res = ast_waitfordigit(chan, waitms); if (res < 0) { ast_clear_flag(chan, AST_FLAG_SPYING); break; } if (!ast_strlen_zero(exitcontext)) { char tmp[2]; tmp[0] = res; tmp[1] = '\0'; if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) goto exit; else ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); } /* reset for the next loop around, unless overridden later */ waitms = 100; num_spyed_upon = 0; for (autochan = next_channel(iter, autochan, chan); autochan; prev = autochan->chan, ast_autochan_destroy(autochan), autochan = next_autochan ? next_autochan : next_channel(iter, autochan, chan), next_autochan = NULL) { int igrp = !mygroup; int ienf = !myenforced; char *s; if (autochan->chan == prev) { ast_autochan_destroy(autochan); break; } if (ast_check_hangup(chan)) { ast_autochan_destroy(autochan); break; } if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) { continue; } if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) { continue; } if (mygroup) { int num_groups = 0; int num_mygroups = 0; char dup_group[512]; char dup_mygroup[512]; char *groups[NUM_SPYGROUPS]; char *mygroups[NUM_SPYGROUPS]; const char *group = NULL; int x; int y; ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup)); num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups, ARRAY_LEN(mygroups)); /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable * rather than "SPYGROUP", this check is done to preserve expected behavior */ if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) { group = pbx_builtin_getvar_helper(autochan->chan, "GROUP"); } else { group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP"); } if (!ast_strlen_zero(group)) { ast_copy_string(dup_group, group, sizeof(dup_group)); num_groups = ast_app_separate_args(dup_group, ':', groups, ARRAY_LEN(groups)); } for (y = 0; y < num_mygroups; y++) { for (x = 0; x < num_groups; x++) { if (!strcmp(mygroups[y], groups[x])) { igrp = 1; break; } } } } if (!igrp) { continue; } if (myenforced) { char ext[AST_CHANNEL_NAME + 3]; char buffer[512]; char *end; snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced); ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1); if ((end = strchr(ext, '-'))) { *end++ = ':'; *end = '\0'; } ext[0] = ':'; if (strcasestr(buffer, ext)) { ienf = 1; } } if (!ienf) { continue; } strcpy(peer_name, "spy-"); strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1); ptr = strchr(peer_name, '/'); *ptr++ = '\0'; ptr = strsep(&ptr, "-"); for (s = peer_name; s < ptr; s++) *s = tolower(*s); if (!ast_test_flag(flags, OPTION_QUIET)) { if (ast_test_flag(flags, OPTION_NAME)) { const char *local_context = S_OR(name_context, "default"); const char *local_mailbox = S_OR(mailbox, ptr); res = ast_app_sayname(chan, local_mailbox, local_context); } if (!ast_test_flag(flags, OPTION_NAME) || res < 0) { if (!ast_test_flag(flags, OPTION_NOTECH)) { if (ast_fileexists(peer_name, NULL, NULL) > 0) { res = ast_streamfile(chan, peer_name, chan->language); if (!res) { res = ast_waitstream(chan, ""); } if (res) { ast_autochan_destroy(autochan); break; } } else { res = ast_say_character_str(chan, peer_name, "", chan->language); } } if ((num = atoi(ptr))) ast_say_digits(chan, atoi(ptr), "", chan->language); } } res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext); num_spyed_upon++; if (res == -1) { ast_autochan_destroy(autochan); goto exit; } else if (res == -2) { res = 0; ast_autochan_destroy(autochan); goto exit; } else if (res > 1 && spec) { struct ast_channel *next; snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) { next_autochan = ast_autochan_setup(next); next = ast_channel_unref(next); } else { /* stay on this channel, if it is still valid */ if (!ast_check_hangup(autochan->chan)) { next_autochan = ast_autochan_setup(autochan->chan); } else { /* the channel is gone */ next_autochan = NULL; } } } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) { goto exit; } } iter = ast_channel_iterator_destroy(iter); if (res == -1 || ast_check_hangup(chan)) break; if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) { break; } } exit: ast_clear_flag(chan, AST_FLAG_SPYING); ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); return res; }
static int testserver_exec(struct ast_channel *chan, const char *data) { int res = 0; char testid[80]=""; char fn[80]; FILE *f; if (ast_channel_state(chan) != AST_STATE_UP) res = ast_answer(chan); /* Read version */ ast_debug(1, "Read client version\n"); if (!res) res = ast_app_getdata(chan, NULL, testid, sizeof(testid) - 1, 0); if (res > 0) res = 0; ast_debug(1, "client version: %s\n", testid); ast_debug(1, "Transmit server version\n"); res = ast_safe_sleep(chan, 1000); if (!res) res = ast_dtmf_stream(chan, NULL, "8378*1#", 0, 0); if (res > 0) res = 0; if (!res) res = ast_app_getdata(chan, NULL, testid, sizeof(testid) - 1, 0); ast_debug(1, "read test identifier: %s\n", testid); /* Check for sneakyness */ if (strchr(testid, '/')) res = -1; if ((res >=0) && (!ast_strlen_zero(testid))) { /* Got a Test ID! Whoo hoo! */ /* Make the directory to hold the test results in case it's not there */ snprintf(fn, sizeof(fn), "%s/testresults", ast_config_AST_LOG_DIR); ast_mkdir(fn, 0777); snprintf(fn, sizeof(fn), "%s/testresults/%s-server.txt", ast_config_AST_LOG_DIR, testid); if ((f = fopen(fn, "w+"))) { setlinebuf(f); fprintf(f, "SERVERCHAN: %s\n", ast_channel_name(chan)); fprintf(f, "SERVERTEST ID: %s\n", testid); fprintf(f, "ANSWER: PASS\n"); ast_debug(1, "Processing Test ID '%s'\n", testid); res = ast_safe_sleep(chan, 1000); if (!res) { /* Step 1: Send "1" */ ast_debug(1, "TestServer: 1. Send DTMF 1\n"); res = ast_dtmf_stream(chan, NULL, "1", 0,0 ); fprintf(f, "SEND DTMF 1: %s\n", (res < 0) ? "FAIL" : "PASS"); if (res > 0) res = 0; } if (!res) { /* Step 2: Wait for "2" */ ast_debug(1, "TestServer: 2. Wait DTMF 2\n"); res = ast_waitfordigit(chan, 3000); fprintf(f, "WAIT DTMF 2: %s\n", (res != '2') ? "FAIL" : "PASS"); if (res == '2') res = 0; else res = -1; } if (!res) { /* Step 3: Measure noise */ ast_debug(1, "TestServer: 3. Measure noise\n"); res = measurenoise(chan, 6000, "TestServer"); fprintf(f, "MEASURENOISE: %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res); if (res > 0) res = 0; } if (!res) { /* Step 4: Send "4" */ ast_debug(1, "TestServer: 4. Send DTMF 4\n"); res = ast_dtmf_stream(chan, NULL, "4", 0, 0); fprintf(f, "SEND DTMF 4: %s\n", (res < 0) ? "FAIL" : "PASS"); if (res > 0) res = 0; } if (!res) { /* Step 5: Wait one second */ ast_debug(1, "TestServer: 5. Wait one second\n"); res = ast_safe_sleep(chan, 1000); fprintf(f, "WAIT 1 SEC: %s\n", (res < 0) ? "FAIL" : "PASS"); if (res > 0) res = 0; } if (!res) { /* Step 6: Measure noise */ ast_debug(1, "TestServer: 6. Measure tone\n"); res = measurenoise(chan, 4000, "TestServer"); fprintf(f, "MEASURETONE: %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res); if (res > 0) res = 0; } if (!res) { /* Step 7: Send "5" */ ast_debug(1, "TestServer: 7. Send DTMF 5\n"); res = ast_dtmf_stream(chan, NULL, "5", 0, 0); fprintf(f, "SEND DTMF 5: %s\n", (res < 0) ? "FAIL" : "PASS"); if (res > 0) res = 0; } if (!res) { /* Step 8: Transmit tone noise */ ast_debug(1, "TestServer: 8. Transmit tone\n"); res = sendnoise(chan, 6000); fprintf(f, "SENDTONE: %s\n", (res < 0) ? "FAIL" : "PASS"); } if (!res || (res == '7')) { /* Step 9: Wait for "7" */ ast_debug(1, "TestServer: 9. Wait DTMF 7\n"); if (!res) res = ast_waitfordigit(chan, 3000); fprintf(f, "WAIT DTMF 7: %s\n", (res != '7') ? "FAIL" : "PASS"); if (res == '7') res = 0; else res = -1; } if (!res) { res = ast_safe_sleep(chan, 1000); } if (!res) { /* Step 10: Send "8" */ ast_debug(1, "TestServer: 10. Send DTMF 8\n"); res = ast_dtmf_stream(chan, NULL, "8", 0, 0); fprintf(f, "SEND DTMF 8: %s\n", (res < 0) ? "FAIL" : "PASS"); if (res > 0) res = 0; } if (!res) { /* Step 11: Wait for hangup to arrive! */ ast_debug(1, "TestServer: 11. Waiting for hangup\n"); res = ast_safe_sleep(chan, 10000); fprintf(f, "WAIT HANGUP: %s\n", (res < 0) ? "PASS" : "FAIL"); } ast_log(LOG_NOTICE, "-- TEST COMPLETE--\n"); fprintf(f, "-- END TEST--\n"); fclose(f); res = -1; } else res = -1; } else { ast_log(LOG_NOTICE, "Did not read a test ID on '%s'\n", ast_channel_name(chan)); res = -1; } return res; }
static int testclient_exec(struct ast_channel *chan, const char *data) { int res = 0; const char *testid=data; char fn[80]; char serverver[80]; FILE *f; /* Check for test id */ if (ast_strlen_zero(testid)) { ast_log(LOG_WARNING, "TestClient requires an argument - the test id\n"); return -1; } if (ast_channel_state(chan) != AST_STATE_UP) res = ast_answer(chan); /* Wait a few just to be sure things get started */ res = ast_safe_sleep(chan, 3000); /* Transmit client version */ if (!res) res = ast_dtmf_stream(chan, NULL, "8378*1#", 0, 0); ast_debug(1, "Transmit client version\n"); /* Read server version */ ast_debug(1, "Read server version\n"); if (!res) res = ast_app_getdata(chan, NULL, serverver, sizeof(serverver) - 1, 0); if (res > 0) res = 0; ast_debug(1, "server version: %s\n", serverver); if (res > 0) res = 0; if (!res) res = ast_safe_sleep(chan, 1000); /* Send test id */ if (!res) res = ast_dtmf_stream(chan, NULL, testid, 0, 0); if (!res) res = ast_dtmf_stream(chan, NULL, "#", 0, 0); ast_debug(1, "send test identifier: %s\n", testid); if ((res >=0) && (!ast_strlen_zero(testid))) { /* Make the directory to hold the test results in case it's not there */ snprintf(fn, sizeof(fn), "%s/testresults", ast_config_AST_LOG_DIR); ast_mkdir(fn, 0777); snprintf(fn, sizeof(fn), "%s/testresults/%s-client.txt", ast_config_AST_LOG_DIR, testid); if ((f = fopen(fn, "w+"))) { setlinebuf(f); fprintf(f, "CLIENTCHAN: %s\n", ast_channel_name(chan)); fprintf(f, "CLIENTTEST ID: %s\n", testid); fprintf(f, "ANSWER: PASS\n"); res = 0; if (!res) { /* Step 1: Wait for "1" */ ast_debug(1, "TestClient: 2. Wait DTMF 1\n"); res = ast_waitfordigit(chan, 3000); fprintf(f, "WAIT DTMF 1: %s\n", (res != '1') ? "FAIL" : "PASS"); if (res == '1') res = 0; else res = -1; } if (!res) { res = ast_safe_sleep(chan, 1000); } if (!res) { /* Step 2: Send "2" */ ast_debug(1, "TestClient: 2. Send DTMF 2\n"); res = ast_dtmf_stream(chan, NULL, "2", 0, 0); fprintf(f, "SEND DTMF 2: %s\n", (res < 0) ? "FAIL" : "PASS"); if (res > 0) res = 0; } if (!res) { /* Step 3: Wait one second */ ast_debug(1, "TestClient: 3. Wait one second\n"); res = ast_safe_sleep(chan, 1000); fprintf(f, "WAIT 1 SEC: %s\n", (res < 0) ? "FAIL" : "PASS"); if (res > 0) res = 0; } if (!res) { /* Step 4: Measure noise */ ast_debug(1, "TestClient: 4. Measure noise\n"); res = measurenoise(chan, 5000, "TestClient"); fprintf(f, "MEASURENOISE: %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res); if (res > 0) res = 0; } if (!res) { /* Step 5: Wait for "4" */ ast_debug(1, "TestClient: 5. Wait DTMF 4\n"); res = ast_waitfordigit(chan, 3000); fprintf(f, "WAIT DTMF 4: %s\n", (res != '4') ? "FAIL" : "PASS"); if (res == '4') res = 0; else res = -1; } if (!res) { /* Step 6: Transmit tone noise */ ast_debug(1, "TestClient: 6. Transmit tone\n"); res = sendnoise(chan, 6000); fprintf(f, "SENDTONE: %s\n", (res < 0) ? "FAIL" : "PASS"); } if (!res || (res == '5')) { /* Step 7: Wait for "5" */ ast_debug(1, "TestClient: 7. Wait DTMF 5\n"); if (!res) res = ast_waitfordigit(chan, 3000); fprintf(f, "WAIT DTMF 5: %s\n", (res != '5') ? "FAIL" : "PASS"); if (res == '5') res = 0; else res = -1; } if (!res) { /* Step 8: Wait one second */ ast_debug(1, "TestClient: 8. Wait one second\n"); res = ast_safe_sleep(chan, 1000); fprintf(f, "WAIT 1 SEC: %s\n", (res < 0) ? "FAIL" : "PASS"); if (res > 0) res = 0; } if (!res) { /* Step 9: Measure noise */ ast_debug(1, "TestClient: 9. Measure tone\n"); res = measurenoise(chan, 4000, "TestClient"); fprintf(f, "MEASURETONE: %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res); if (res > 0) res = 0; } if (!res) { /* Step 10: Send "7" */ ast_debug(1, "TestClient: 10. Send DTMF 7\n"); res = ast_dtmf_stream(chan, NULL, "7", 0, 0); fprintf(f, "SEND DTMF 7: %s\n", (res < 0) ? "FAIL" : "PASS"); if (res > 0) res =0; } if (!res) { /* Step 11: Wait for "8" */ ast_debug(1, "TestClient: 11. Wait DTMF 8\n"); res = ast_waitfordigit(chan, 3000); fprintf(f, "WAIT DTMF 8: %s\n", (res != '8') ? "FAIL" : "PASS"); if (res == '8') res = 0; else res = -1; } if (!res) { res = ast_safe_sleep(chan, 1000); } if (!res) { /* Step 12: Hangup! */ ast_debug(1, "TestClient: 12. Hangup\n"); } ast_debug(1, "-- TEST COMPLETE--\n"); fprintf(f, "-- END TEST--\n"); fclose(f); res = -1; } else res = -1; } else { ast_log(LOG_NOTICE, "Did not read a test ID on '%s'\n", ast_channel_name(chan)); res = -1; } return res; }
static int txfax_exec(struct ast_channel *chan, void *data) { int res = 0; char source_file[256]; char *x; char *s; char *t; char *v; int option; int len; t30_state_t fax; int calling_party; int verbose; int samples; struct localuser *u; struct ast_frame *inf = NULL; struct ast_frame outf; int original_read_fmt; int original_write_fmt; uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET]; uint8_t *buf = __buf + AST_FRIENDLY_OFFSET; if (chan == NULL) { ast_log(LOG_WARNING, "Fax transmit channel is NULL. Giving up.\n"); return -1; } span_set_message_handler(span_message); /* The next few lines of code parse out the filename and header from the input string */ if (data == NULL) { /* No data implies no filename or anything is present */ ast_log(LOG_WARNING, "Txfax requires an argument (filename)\n"); return -1; } calling_party = FALSE; verbose = FALSE; source_file[0] = '\0'; for (option = 0, v = s = data; v; option++, s++) { t = s; v = strchr(s, '|'); s = (v) ? v : s + strlen(s); strncpy((char *) buf, t, s - t); buf[s - t] = '\0'; if (option == 0) { /* The first option is always the file name */ len = s - t; if (len > 255) len = 255; strncpy(source_file, t, len); source_file[len] = '\0'; } else if (strncmp("caller", t, s - t) == 0) { calling_party = TRUE; } else if (strncmp("debug", t, s - t) == 0) { verbose = TRUE; } } /* Done parsing */ LOCAL_USER_ADD(u); if (chan->_state != AST_STATE_UP) { /* Shouldn't need this, but checking to see if channel is already answered * Theoretically asterisk should already have answered before running the app */ res = ast_answer(chan); } if (!res) { original_read_fmt = chan->readformat; if (original_read_fmt != AST_FORMAT_SLINEAR) { res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n"); return -1; } } original_write_fmt = chan->writeformat; if (original_write_fmt != AST_FORMAT_SLINEAR) { res = ast_set_write_format(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n"); res = ast_set_read_format(chan, original_read_fmt); if (res) ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); return -1; } } fax_init(&fax, calling_party, NULL); if (verbose) fax.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW; x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"); if (x && x[0]) t30_set_local_ident(&fax, x); x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO"); if (x && x[0]) t30_set_header_info(&fax, x); t30_set_tx_file(&fax, source_file, -1, -1); //t30_set_phase_b_handler(&fax, phase_b_handler, chan); //t30_set_phase_d_handler(&fax, phase_d_handler, chan); t30_set_phase_e_handler(&fax, phase_e_handler, chan); while (ast_waitfor(chan, -1) > -1) { inf = ast_read(chan); if (inf == NULL) { res = -1; break; } if (inf->frametype == AST_FRAME_VOICE) { if (fax_rx(&fax, inf->data, inf->samples)) break; samples = (inf->samples <= MAX_BLOCK_SIZE) ? inf->samples : MAX_BLOCK_SIZE; len = fax_tx(&fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples); if (len) { memset(&outf, 0, sizeof(outf)); outf.frametype = AST_FRAME_VOICE; outf.subclass = AST_FORMAT_SLINEAR; outf.datalen = len*sizeof(int16_t); outf.samples = len; outf.data = &buf[AST_FRIENDLY_OFFSET]; outf.offset = AST_FRIENDLY_OFFSET; if (ast_write(chan, &outf) < 0) { ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno)); break; } } } ast_frfree(inf); } if (inf == NULL) { ast_log(LOG_DEBUG, "Got hangup\n"); res = -1; } if (original_read_fmt && original_read_fmt != AST_FORMAT_SLINEAR) { res = ast_set_read_format(chan, original_read_fmt); if (res) ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); } if (original_write_fmt && original_write_fmt != AST_FORMAT_SLINEAR) { res = ast_set_write_format(chan, original_write_fmt); if (res) ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name); } fax_release(&fax); } else { ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name); } LOCAL_USER_REMOVE(u); return res; }
/*! * \brief This is the main function called by Asterisk Core whenever the App is invoked in the extension logic. * * \param chan Asterisk Channel * \param data Application data * * \retval 0 success * \retval -1 failure */ static int alarmreceiver_exec(struct ast_channel *chan, const char *data) { int res = 0; int no_checksum = 0; event_node_t *elp, *efree; char signalling_type[64] = ""; event_node_t *event_head = NULL; if ((ast_format_cmp(ast_channel_writeformat(chan), ast_format_ulaw) == AST_FORMAT_CMP_NOT_EQUAL) && (ast_format_cmp(ast_channel_writeformat(chan), ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL)) { ast_verb(4, "AlarmReceiver: Setting write format to Mu-law\n"); if (ast_set_write_format(chan, ast_format_ulaw)) { ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",ast_channel_name(chan)); return -1; } } if ((ast_format_cmp(ast_channel_readformat(chan), ast_format_ulaw) == AST_FORMAT_CMP_NOT_EQUAL) && (ast_format_cmp(ast_channel_readformat(chan), ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL)) { ast_verb(4, "AlarmReceiver: Setting read format to Mu-law\n"); if (ast_set_read_format(chan, ast_format_ulaw)) { ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",ast_channel_name(chan)); return -1; } } /* Set default values for this invocation of the application */ ast_copy_string(signalling_type, UNKNOWN_FORMAT, sizeof(signalling_type)); call_start_time = ast_tvnow(); /* Answer the channel if it is not already */ if (ast_channel_state(chan) != AST_STATE_UP) { ast_verb(4, "AlarmReceiver: Answering channel\n"); if (ast_answer(chan)) { return -1; } } /* Wait for the connection to settle post-answer */ ast_verb(4, "AlarmReceiver: Waiting for connection to stabilize\n"); if (ast_safe_sleep(chan, answait)) { return -1; } /* Attempt to receive the events */ receive_ademco_event(chan, &event_head, signalling_type, &no_checksum); /* Events queued by receiver, write them all out here if so configured */ if (!log_individual_events) { res = log_events(chan, signalling_type, event_head, no_checksum); } /* Do we exec a command line at the end? */ if ((!res) && (!ast_strlen_zero(event_app)) && (event_head)) { ast_debug(1,"Alarmreceiver: executing: %s\n", event_app); ast_safe_system(event_app); } /* Free up the data allocated in our linked list */ for (elp = event_head; (elp != NULL);) { efree = elp; elp = elp->next; ast_free(efree); } return 0; }
/*! \brief Initiate new call, part of PBX interface * dest is the dial string */ static int local_call(struct ast_channel *ast, const char *dest, int timeout) { struct local_pvt *p = ast_channel_tech_pvt(ast); int pvt_locked = 0; struct ast_channel *owner = NULL; struct ast_channel *chan = NULL; int res; char *reduced_dest = ast_strdupa(dest); char *slash; const char *chan_cid; if (!p) { return -1; } /* since we are letting go of channel locks that were locked coming into * this function, then we need to give the tech pvt a ref */ ao2_ref(p, 1); ast_channel_unlock(ast); ast_unreal_lock_all(&p->base, &chan, &owner); pvt_locked = 1; if (owner != ast) { res = -1; goto return_cleanup; } if (!owner || !chan) { res = -1; goto return_cleanup; } ast_unreal_call_setup(owner, chan); /* * If the local channel has /n on the end of it, we need to lop * that off for our argument to setting up the CC_INTERFACES * variable. */ if ((slash = strrchr(reduced_dest, '/'))) { *slash = '\0'; } ast_set_cc_interfaces_chanvar(chan, reduced_dest); ao2_unlock(p); pvt_locked = 0; ast_channel_unlock(owner); chan_cid = S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL); if (chan_cid) { chan_cid = ast_strdupa(chan_cid); } ast_channel_unlock(chan); res = -1; switch (p->type) { case LOCAL_CALL_ACTION_DIALPLAN: if (!ast_exists_extension(NULL, p->context, p->exten, 1, chan_cid)) { ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->exten, p->context); } else { publish_local_bridge_message(p); /* Start switch on sub channel */ res = ast_pbx_start(chan); } break; case LOCAL_CALL_ACTION_BRIDGE: publish_local_bridge_message(p); ast_answer(chan); res = ast_bridge_impart(p->action.bridge.join, chan, p->action.bridge.swap, p->action.bridge.features, AST_BRIDGE_IMPART_CHAN_INDEPENDENT); ao2_ref(p->action.bridge.join, -1); p->action.bridge.join = NULL; ao2_cleanup(p->action.bridge.swap); p->action.bridge.swap = NULL; p->action.bridge.features = NULL; break; case LOCAL_CALL_ACTION_MASQUERADE: publish_local_bridge_message(p); ast_answer(chan); res = ast_channel_move(p->action.masq, chan); if (!res) { /* Chan is now an orphaned zombie. Destroy it. */ ast_hangup(chan); } p->action.masq = ast_channel_unref(p->action.masq); break; } if (!res) { ao2_lock(p); ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD); ao2_unlock(p); } /* we already unlocked them, clear them here so the cleanup label won't touch them. */ owner = ast_channel_unref(owner); chan = ast_channel_unref(chan); return_cleanup: if (p) { if (pvt_locked) { ao2_unlock(p); } ao2_ref(p, -1); } if (chan) { ast_channel_unlock(chan); ast_channel_unref(chan); } /* * owner is supposed to be == to ast, if it is, don't unlock it * because ast must exit locked */ if (owner) { if (owner != ast) { ast_channel_unlock(owner); ast_channel_lock(ast); } ast_channel_unref(owner); } else { /* we have to exit with ast locked */ ast_channel_lock(ast); } return res; }
static int app_exec(struct ast_channel *chan, void *data) { struct ast_module_user *lu; struct playlist_entry *entry; const char *args = data; int child_stdin[2] = { 0,0 }; int child_stdout[2] = { 0,0 }; int child_stderr[2] = { 0,0 }; int res = -1; int test_available_fd = -1; int gen_active = 0; int pid; char *argv[32]; int argc = 1; char *buf, *command; FILE *child_commands = NULL; FILE *child_errors = NULL; FILE *child_events = NULL; struct ivr_localuser foo = { .playlist = AST_LIST_HEAD_INIT_VALUE, .finishlist = AST_LIST_HEAD_INIT_VALUE, }; struct ivr_localuser *u = &foo; sigset_t fullset, oldset; lu = ast_module_user_add(chan); sigfillset(&fullset); pthread_sigmask(SIG_BLOCK, &fullset, &oldset); u->abort_current_sound = 0; u->chan = chan; if (ast_strlen_zero(args)) { ast_log(LOG_WARNING, "ExternalIVR requires a command to execute\n"); ast_module_user_remove(lu); return -1; } buf = ast_strdupa(data); argc = ast_app_separate_args(buf, '|', argv, sizeof(argv) / sizeof(argv[0])); if (pipe(child_stdin)) { ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno)); goto exit; } if (pipe(child_stdout)) { ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno)); goto exit; } if (pipe(child_stderr)) { ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno)); goto exit; } if (chan->_state != AST_STATE_UP) { ast_answer(chan); } if (ast_activate_generator(chan, &gen, u) < 0) { ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n"); goto exit; } else gen_active = 1; pid = fork(); if (pid < 0) { ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno)); goto exit; } if (!pid) { /* child process */ int i; signal(SIGPIPE, SIG_DFL); pthread_sigmask(SIG_UNBLOCK, &fullset, NULL); if (ast_opt_high_priority) ast_set_priority(0); dup2(child_stdin[0], STDIN_FILENO); dup2(child_stdout[1], STDOUT_FILENO); dup2(child_stderr[1], STDERR_FILENO); for (i = STDERR_FILENO + 1; i < 1024; i++) close(i); execv(argv[0], argv); fprintf(stderr, "Failed to execute '%s': %s\n", argv[0], strerror(errno)); _exit(1); } else { /* parent process */ int child_events_fd = child_stdin[1]; int child_commands_fd = child_stdout[0]; int child_errors_fd = child_stderr[0]; struct ast_frame *f; int ms; int exception; int ready_fd; int waitfds[2] = { child_errors_fd, child_commands_fd }; struct ast_channel *rchan; pthread_sigmask(SIG_SETMASK, &oldset, NULL); close(child_stdin[0]); child_stdin[0] = 0; close(child_stdout[1]); child_stdout[1] = 0; close(child_stderr[1]); child_stderr[1] = 0; if (!(child_events = fdopen(child_events_fd, "w"))) { ast_chan_log(LOG_WARNING, chan, "Could not open stream for child events\n"); goto exit; } if (!(child_commands = fdopen(child_commands_fd, "r"))) { ast_chan_log(LOG_WARNING, chan, "Could not open stream for child commands\n"); goto exit; } if (!(child_errors = fdopen(child_errors_fd, "r"))) { ast_chan_log(LOG_WARNING, chan, "Could not open stream for child errors\n"); goto exit; } test_available_fd = open("/dev/null", O_RDONLY); setvbuf(child_events, NULL, _IONBF, 0); setvbuf(child_commands, NULL, _IONBF, 0); setvbuf(child_errors, NULL, _IONBF, 0); res = 0; while (1) { if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) { ast_chan_log(LOG_NOTICE, chan, "Is a zombie\n"); res = -1; break; } if (ast_check_hangup(chan)) { ast_chan_log(LOG_NOTICE, chan, "Got check_hangup\n"); send_child_event(child_events, 'H', NULL, chan); res = -1; break; } ready_fd = 0; ms = 100; errno = 0; exception = 0; rchan = ast_waitfor_nandfds(&chan, 1, waitfds, 2, &exception, &ready_fd, &ms); if (!AST_LIST_EMPTY(&u->finishlist)) { AST_LIST_LOCK(&u->finishlist); while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) { send_child_event(child_events, 'F', entry->filename, chan); free(entry); } AST_LIST_UNLOCK(&u->finishlist); } if (rchan) { /* the channel has something */ f = ast_read(chan); if (!f) { ast_chan_log(LOG_NOTICE, chan, "Returned no frame\n"); send_child_event(child_events, 'H', NULL, chan); res = -1; break; } if (f->frametype == AST_FRAME_DTMF) { send_child_event(child_events, f->subclass, NULL, chan); if (u->option_autoclear) { if (!u->abort_current_sound && !u->playing_silence) send_child_event(child_events, 'T', NULL, chan); AST_LIST_LOCK(&u->playlist); while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) { send_child_event(child_events, 'D', entry->filename, chan); free(entry); } if (!u->playing_silence) u->abort_current_sound = 1; AST_LIST_UNLOCK(&u->playlist); } } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) { ast_chan_log(LOG_NOTICE, chan, "Got AST_CONTROL_HANGUP\n"); send_child_event(child_events, 'H', NULL, chan); ast_frfree(f); res = -1; break; } ast_frfree(f); } else if (ready_fd == child_commands_fd) { char input[1024]; if (exception || feof(child_commands)) { ast_chan_log(LOG_WARNING, chan, "Child process went away\n"); res = -1; break; } if (!fgets(input, sizeof(input), child_commands)) continue; command = ast_strip(input); ast_chan_log(LOG_DEBUG, chan, "got command '%s'\n", input); if (strlen(input) < 4) continue; if (input[0] == 'S') { if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) { ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]); send_child_event(child_events, 'Z', NULL, chan); strcpy(&input[2], "exception"); } if (!u->abort_current_sound && !u->playing_silence) send_child_event(child_events, 'T', NULL, chan); AST_LIST_LOCK(&u->playlist); while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) { send_child_event(child_events, 'D', entry->filename, chan); free(entry); } if (!u->playing_silence) u->abort_current_sound = 1; entry = make_entry(&input[2]); if (entry) AST_LIST_INSERT_TAIL(&u->playlist, entry, list); AST_LIST_UNLOCK(&u->playlist); } else if (input[0] == 'A') { if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) { ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]); send_child_event(child_events, 'Z', NULL, chan); strcpy(&input[2], "exception"); } entry = make_entry(&input[2]); if (entry) { AST_LIST_LOCK(&u->playlist); AST_LIST_INSERT_TAIL(&u->playlist, entry, list); AST_LIST_UNLOCK(&u->playlist); } } else if (input[0] == 'H') { ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]); send_child_event(child_events, 'H', NULL, chan); break; } else if (input[0] == 'O') { if (!strcasecmp(&input[2], "autoclear")) u->option_autoclear = 1; else if (!strcasecmp(&input[2], "noautoclear")) u->option_autoclear = 0; else ast_chan_log(LOG_WARNING, chan, "Unknown option requested '%s'\n", &input[2]); } } else if (ready_fd == child_errors_fd) { char input[1024]; if (exception || (dup2(child_commands_fd, test_available_fd) == -1) || feof(child_errors)) { ast_chan_log(LOG_WARNING, chan, "Child process went away\n"); res = -1; break; } if (fgets(input, sizeof(input), child_errors)) { command = ast_strip(input); ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", command); } } else if ((ready_fd < 0) && ms) { if (errno == 0 || errno == EINTR) continue; ast_chan_log(LOG_WARNING, chan, "Wait failed (%s)\n", strerror(errno)); break; } } } exit: if (gen_active) ast_deactivate_generator(chan); if (child_events) fclose(child_events); if (child_commands) fclose(child_commands); if (child_errors) fclose(child_errors); if (test_available_fd > -1) { close(test_available_fd); } if (child_stdin[0]) close(child_stdin[0]); if (child_stdin[1]) close(child_stdin[1]); if (child_stdout[0]) close(child_stdout[0]); if (child_stdout[1]) close(child_stdout[1]); if (child_stderr[0]) close(child_stderr[0]); if (child_stderr[1]) close(child_stderr[1]); while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) free(entry); ast_module_user_remove(lu); return res; }
/*--- conf_exec: The meetme() application */ static int conf_exec(struct ast_channel *chan, void *data) { int res=-1; struct localuser *u; char confno[AST_MAX_EXTENSION] = ""; int allowretry = 0; int retrycnt = 0; struct ast_conference *cnf; int confflags = 0; int dynamic = 0; int empty = 0, empty_no_pin = 0; char *notdata, *info, *inflags = NULL, *inpin = NULL, the_pin[AST_MAX_EXTENSION] = ""; if (!data || ast_strlen_zero(data)) { allowretry = 1; notdata = ""; } else { notdata = data; } LOCAL_USER_ADD(u); if (chan->_state != AST_STATE_UP) ast_answer(chan); info = ast_strdupa((char *)notdata); if (info) { char *tmp = strsep(&info, "|"); strncpy(confno, tmp, sizeof(confno) - 1); if (ast_strlen_zero(confno)) { allowretry = 1; } } if (info) inflags = strsep(&info, "|"); if (info) inpin = strsep(&info, "|"); if (inpin) strncpy(the_pin, inpin, sizeof(the_pin) - 1); if (inflags) { if (strchr(inflags, 'a')) confflags |= CONFFLAG_ADMIN; if (strchr(inflags, 'm')) confflags |= CONFFLAG_MONITOR; if (strchr(inflags, 'p')) confflags |= CONFFLAG_POUNDEXIT; if (strchr(inflags, 's')) confflags |= CONFFLAG_STARMENU; if (strchr(inflags, 't')) confflags |= CONFFLAG_TALKER; if (strchr(inflags, 'q')) confflags |= CONFFLAG_QUIET; if (strchr(inflags, 'M')) confflags |= CONFFLAG_MOH; if (strchr(inflags, 'x')) confflags |= CONFFLAG_MARKEDEXIT; if (strchr(inflags, 'X')) confflags |= CONFFLAG_EXIT_CONTEXT; if (strchr(inflags, 'A')) confflags |= CONFFLAG_MARKEDUSER; if (strchr(inflags, 'b')) confflags |= CONFFLAG_AGI; if (strchr(inflags, 'w')) confflags |= CONFFLAG_WAITMARKED; if (strchr(inflags, 'd')) dynamic = 1; if (strchr(inflags, 'D')) { dynamic = 1; if (! inpin) { strncpy(the_pin, "q", sizeof(the_pin) - 1); } } if (strchr(inflags, 'e')) empty = 1; if (strchr(inflags, 'E')) { empty = 1; empty_no_pin = 1; } } do { if (retrycnt > 3) allowretry = 0; if (empty) { int i, map[1024]; struct ast_config *cfg; struct ast_variable *var; int confno_int; memset(map, 0, sizeof(map)); ast_mutex_lock(&conflock); cnf = confs; while (cnf) { if (sscanf(cnf->confno, "%d", &confno_int) == 1) { /* Disqualify in use conference */ if (confno_int >= 0 && confno_int < 1024) map[confno_int]++; } cnf = cnf->next; } ast_mutex_unlock(&conflock); /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */ if ((empty_no_pin) || (!dynamic)) { cfg = ast_load("meetme.conf"); if (cfg) { var = ast_variable_browse(cfg, "rooms"); while(var) { if (!strcasecmp(var->name, "conf")) { char *stringp = ast_strdupa(var->value); if (stringp) { char *confno_tmp = strsep(&stringp, "|,"); int found = 0; if (sscanf(confno_tmp, "%d", &confno_int) == 1) { if ((confno_int >= 0) && (confno_int < 1024)) { if (stringp && empty_no_pin) { map[confno_int]++; } } } if (! dynamic) { /* For static: run through the list and see if this conference is empty */ ast_mutex_lock(&conflock); cnf = confs; while (cnf) { if (!strcmp(confno_tmp, cnf->confno)) { /* The conference exists, therefore it's not empty */ found = 1; break; } cnf = cnf->next; } ast_mutex_unlock(&conflock); if (!found) { /* At this point, we have a confno_tmp (static conference) that is empty */ if ((empty_no_pin && ((!stringp) || (stringp && (stringp[0] == '\0')))) || (!empty_no_pin)) { /* Case 1: empty_no_pin and pin is nonexistant (NULL) * Case 2: empty_no_pin and pin is blank (but not NULL) * Case 3: not empty_no_pin */ strncpy(confno, confno_tmp, sizeof(confno) - 1); break; /* XXX the map is not complete (but we do have a confno) */ } } } } else { ast_log(LOG_ERROR, "Out of memory\n"); } } var = var->next; } ast_destroy(cfg); } } /* Select first conference number not in use */ if (ast_strlen_zero(confno) && dynamic) { for (i=0;i<1024;i++) { if (!map[i]) { snprintf(confno, sizeof(confno), "%d", i); break; } } } /* Not found? */ if (ast_strlen_zero(confno)) { res = ast_streamfile(chan, "conf-noempty", chan->language); if (!res) ast_waitstream(chan, ""); } else { if (sscanf(confno, "%d", &confno_int) == 1) { res = ast_streamfile(chan, "conf-enteringno", chan->language); if (!res) { ast_waitstream(chan, ""); res = ast_say_digits(chan, confno_int, "", chan->language); } } else { ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno); } } } while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) { /* Prompt user for conference number */ res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0); if (res < 0) { /* Don't try to validate when we catch an error */ confno[0] = '\0'; allowretry = 0; break; } } if (!ast_strlen_zero(confno)) { /* Check the validity of the conference */ cnf = find_conf(chan, confno, 1, dynamic, the_pin); if (!cnf) { res = ast_streamfile(chan, "conf-invalid", chan->language); if (!res) ast_waitstream(chan, ""); res = -1; if (allowretry) confno[0] = '\0'; } else { if (!ast_strlen_zero(cnf->pin)) { char pin[AST_MAX_EXTENSION]=""; int j; /* Allow the pin to be retried up to 3 times */ for (j=0; j<3; j++) { if (*the_pin) { strncpy(pin, the_pin, sizeof(pin) - 1); res = 0; } else { /* Prompt user for pin if pin is required */ res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0); } if (res >= 0) { if (!strcasecmp(pin, cnf->pin)) { /* Pin correct */ allowretry = 0; /* Run the conference */ res = conf_run(chan, cnf, confflags); break; } else { /* Pin invalid */ res = ast_streamfile(chan, "conf-invalidpin", chan->language); if (!res) ast_waitstream(chan, AST_DIGIT_ANY); if (res < 0) break; pin[0] = res; pin[1] = '\0'; res = -1; if (allowretry) confno[0] = '\0'; } } else { res = -1; allowretry = 0; break; } /* Don't retry pin with a static pin */ if (*the_pin) { break; } } } else { /* No pin required */ allowretry = 0; /* Run the conference */ res = conf_run(chan, cnf, confflags); } } } } while (allowretry); /* Do the conference */ LOCAL_USER_REMOVE(u); return res; }
static int pickup_exec(struct ast_channel *chan, void *data) { int res = 0; struct localuser *u = NULL; struct ast_channel *origin = NULL, *target = NULL; char *tmp = NULL, *exten = NULL, *context = NULL, *rest=data; char workspace[256] = ""; const char *tmp2 = NULL; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Pickup requires an argument (extension) !\n"); return -1; } LOCAL_USER_ADD(u); while (!target && (exten = rest) ) { res = 0; rest = strchr(exten, '&'); if (rest) *rest++ = 0; /* Get the extension and context if present */ context = strchr(exten, '@'); if (context) *context++ = '\0'; /* If the context is the pickup mark, iterate through all channels finding the right origin one */ if (!strcmp(context, PICKUPMARK)) { while ((origin = ast_channel_walk_locked(origin))) { if (origin) { tmp2 = pbx_builtin_getvar_helper(origin, PICKUPMARK); if (tmp2 && !strcmp(tmp2, exten)) break; ast_mutex_unlock(&origin->lock); } } } else { /* Use the classic mode of searching */ origin = ast_get_channel_by_exten_locked(exten, context); } if (origin) { ast_cdr_getvar(origin->cdr, "dstchannel", &tmp, workspace, sizeof(workspace), 0, 0); if (tmp) { /* We have a possible channel... now we need to find it! */ target = ast_get_channel_by_name_locked(tmp); } else { ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten); res = -1; } ast_mutex_unlock(&origin->lock); } else { ast_log(LOG_DEBUG, "No originating channel found.\n"); } if (res) continue; if (target && (!target->pbx) && ((target->_state == AST_STATE_RINGING) || (target->_state == AST_STATE_RING) ) ) { ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n", target->name, chan->name); res = ast_answer(chan); if (res) { ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); res = -1; break; } res = ast_queue_control(chan, AST_CONTROL_ANSWER); if (res) { ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); res = -1; break; } res = ast_channel_masquerade(target, chan); if (res) { ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name); res = -1; break; } } else { ast_log(LOG_NOTICE, "No call pickup possible for %s...\n", exten); res = -1; } } if (target) ast_mutex_unlock(&target->lock); LOCAL_USER_REMOVE(u); return res; }