static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, int length, char *intkeys) { int res = 0; int fds[2]; int needed = 0; int owriteformat; struct ast_frame *f; struct myframe { struct ast_frame f; char offset[AST_FRIENDLY_OFFSET]; char frdata[2048]; } myf = { .f = { 0, }, }; if (pipe(fds)) { ast_log(LOG_WARNING, "Unable to create pipe\n"); return -1; } /* Answer if it's not already going */ if (chan->_state != AST_STATE_UP) ast_answer(chan); ast_stopstream(chan); ast_indicate(chan, -1); owriteformat = chan->writeformat; res = ast_set_write_format(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); return -1; } res = send_waveform_to_fd(waveform, length, fds[1]); if (res >= 0) { /* Order is important -- there's almost always going to be mp3... we want to prioritize the user */ for (;;) { res = ast_waitfor(chan, 1000); if (res < 1) { res = -1; break; } f = ast_read(chan); if (!f) { ast_log(LOG_WARNING, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == AST_FRAME_DTMF) { ast_debug(1, "User pressed a key\n"); if (intkeys && strchr(intkeys, f->subclass.integer)) { res = f->subclass.integer; ast_frfree(f); break; } } if (f->frametype == AST_FRAME_VOICE) { /* Treat as a generator */ needed = f->samples * 2; if (needed > sizeof(myf.frdata)) { ast_log(LOG_WARNING, "Only able to deliver %d of %d requested samples\n", (int)sizeof(myf.frdata) / 2, needed/2); needed = sizeof(myf.frdata); } res = read(fds[0], myf.frdata, needed); if (res > 0) { myf.f.frametype = AST_FRAME_VOICE; myf.f.subclass.codec = AST_FORMAT_SLINEAR; myf.f.datalen = res; myf.f.samples = res / 2; myf.f.offset = AST_FRIENDLY_OFFSET; myf.f.src = __PRETTY_FUNCTION__; myf.f.data.ptr = myf.frdata; if (ast_write(chan, &myf.f) < 0) { res = -1; ast_frfree(f); break; } if (res < needed) { /* last frame */ ast_debug(1, "Last frame\n"); res = 0; ast_frfree(f); break; } } else { ast_debug(1, "No more waveform\n"); res = 0; } } ast_frfree(f); } } close(fds[0]); close(fds[1]); if (!res && owriteformat) ast_set_write_format(chan, owriteformat); return res; }
/*! * \brief Seek to a specific position in an OGG/Vorbis filestream. * \param s The filestream to truncate. * \param sample_offset New position for the filestream, measured in 8KHz samples. * \param whence Location to measure * \return 0 on success, -1 on failure. */ static int ogg_vorbis_seek(struct ast_filestream *s, off_t sample_offset, int whence) { ast_log(LOG_WARNING, "Seeking is not supported on OGG/Vorbis streams!\n"); return -1; }
/*! * \brief Create a new OGG/Vorbis filestream and set it up for reading. * \param s File that points to on disk storage of the OGG/Vorbis data. * \return The new filestream. */ static int ogg_vorbis_open(struct ast_filestream *s) { int i; int bytes; int result; char **ptr; char *buffer; struct vorbis_desc *tmp = (struct vorbis_desc *)s->_private; tmp->writing = 0; ogg_sync_init(&tmp->oy); buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE); bytes = fread(buffer, 1, BLOCK_SIZE, s->f); ogg_sync_wrote(&tmp->oy, bytes); result = ogg_sync_pageout(&tmp->oy, &tmp->og); if (result != 1) { if(bytes < BLOCK_SIZE) { ast_log(LOG_ERROR, "Run out of data...\n"); } else { ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n"); } ogg_sync_clear(&tmp->oy); return -1; } ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og)); vorbis_info_init(&tmp->vi); vorbis_comment_init(&tmp->vc); if (ogg_stream_pagein(&tmp->os, &tmp->og) < 0) { ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n"); error: ogg_stream_clear(&tmp->os); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); return -1; } if (ogg_stream_packetout(&tmp->os, &tmp->op) != 1) { ast_log(LOG_ERROR, "Error reading initial header packet.\n"); goto error; } if (vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op) < 0) { ast_log(LOG_ERROR, "This Ogg bitstream does not contain Vorbis audio data.\n"); goto error; } for (i = 0; i < 2 ; ) { while (i < 2) { result = ogg_sync_pageout(&tmp->oy, &tmp->og); if (result == 0) break; if (result == 1) { ogg_stream_pagein(&tmp->os, &tmp->og); while(i < 2) { result = ogg_stream_packetout(&tmp->os,&tmp->op); if(result == 0) break; if(result < 0) { ast_log(LOG_ERROR, "Corrupt secondary header. Exiting.\n"); goto error; } vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op); i++; } } } buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE); bytes = fread(buffer, 1, BLOCK_SIZE, s->f); if (bytes == 0 && i < 2) { ast_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n"); goto error; } ogg_sync_wrote(&tmp->oy, bytes); } for (ptr = tmp->vc.user_comments; *ptr; ptr++) ast_debug(1, "OGG/Vorbis comment: %s\n", *ptr); ast_debug(1, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp->vi.channels, tmp->vi.rate); ast_debug(1, "OGG/Vorbis file encoded by: %s\n", tmp->vc.vendor); if (tmp->vi.channels != 1) { ast_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n"); goto error; } if (tmp->vi.rate != DEFAULT_SAMPLE_RATE) { ast_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n"); vorbis_block_clear(&tmp->vb); vorbis_dsp_clear(&tmp->vd); goto error; } vorbis_synthesis_init(&tmp->vd, &tmp->vi); vorbis_block_init(&tmp->vd, &tmp->vb); return 0; }
void misdn_cfg_get_config_string (int port, enum misdn_cfg_elements elem, char* buf, int bufsize) { int place; char tempbuf[BUFFERSIZE] = ""; struct msn_list *iter; if ((elem < MISDN_CFG_LAST) && !misdn_cfg_is_port_valid(port)) { *buf = 0; ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Port number %d is not valid.\n", port); return; } place = map[elem]; misdn_cfg_lock(); if (elem == MISDN_CFG_PTP) { snprintf(buf, bufsize, " -> ptp: %s", ptp[port] ? "yes" : "no"); } else if (elem > MISDN_CFG_FIRST && elem < MISDN_CFG_LAST) { switch (port_spec[place].type) { case MISDN_CTYPE_INT: case MISDN_CTYPE_BOOLINT: if (port_cfg[port][place].num) snprintf(buf, bufsize, " -> %s: %d", port_spec[place].name, *port_cfg[port][place].num); else if (port_cfg[0][place].num) snprintf(buf, bufsize, " -> %s: %d", port_spec[place].name, *port_cfg[0][place].num); else snprintf(buf, bufsize, " -> %s:", port_spec[place].name); break; case MISDN_CTYPE_BOOL: if (port_cfg[port][place].num) snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, *port_cfg[port][place].num ? "yes" : "no"); else if (port_cfg[0][place].num) snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, *port_cfg[0][place].num ? "yes" : "no"); else snprintf(buf, bufsize, " -> %s:", port_spec[place].name); break; case MISDN_CTYPE_ASTGROUP: if (port_cfg[port][place].grp) snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[port][place].grp)); else if (port_cfg[0][place].grp) snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[0][place].grp)); else snprintf(buf, bufsize, " -> %s:", port_spec[place].name); break; case MISDN_CTYPE_MSNLIST: if (port_cfg[port][place].ml) iter = port_cfg[port][place].ml; else iter = port_cfg[0][place].ml; if (iter) { for (; iter; iter = iter->next) sprintf(tempbuf, "%s%s, ", tempbuf, iter->msn); tempbuf[strlen(tempbuf)-2] = 0; } snprintf(buf, bufsize, " -> msns: %s", *tempbuf ? tempbuf : "none"); break; case MISDN_CTYPE_STR: if ( port_cfg[port][place].str) { snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[port][place].str); } else if (port_cfg[0][place].str) { snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name, port_cfg[0][place].str); } else { snprintf(buf, bufsize, " -> %s:", port_spec[place].name); } break; } } else if (elem > MISDN_GEN_FIRST && elem < MISDN_GEN_LAST) { switch (gen_spec[place].type) { case MISDN_CTYPE_INT: case MISDN_CTYPE_BOOLINT: if (general_cfg[place].num) snprintf(buf, bufsize, " -> %s: %d", gen_spec[place].name, *general_cfg[place].num); else snprintf(buf, bufsize, " -> %s:", gen_spec[place].name); break; case MISDN_CTYPE_BOOL: if (general_cfg[place].num) snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, *general_cfg[place].num ? "yes" : "no"); else snprintf(buf, bufsize, " -> %s:", gen_spec[place].name); break; case MISDN_CTYPE_STR: if ( general_cfg[place].str) { snprintf(buf, bufsize, " -> %s: %s", gen_spec[place].name, general_cfg[place].str); } else { snprintf(buf, bufsize, " -> %s:", gen_spec[place].name); } break; default: snprintf(buf, bufsize, " -> type of %s not handled yet", gen_spec[place].name); break; } } else { *buf = 0; ast_log(LOG_WARNING, "Invalid call to misdn_cfg_get_config_string! Invalid config element (%d) requested.\n", elem); } misdn_cfg_unlock(); }
/*! * \brief Read a frame full of audio data from the filestream. * \param fs The filestream. * \param whennext Number of sample times to schedule the next call. * \return A pointer to a frame containing audio data or NULL ifthere is no more audio data. */ static struct ast_frame *ogg_vorbis_read(struct ast_filestream *fs, int *whennext) { int clipflag = 0; int i; int j; double accumulator[SAMPLES_MAX]; int val; int samples_in; int samples_out = 0; struct vorbis_desc *s = (struct vorbis_desc *)fs->_private; short *buf; /* SLIN data buffer */ fs->fr.frametype = AST_FRAME_VOICE; fs->fr.subclass = AST_FORMAT_SLINEAR; fs->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&fs->fr, fs->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); buf = (short *)(fs->fr.data.ptr); /* SLIN data buffer */ while (samples_out != SAMPLES_MAX) { float **pcm; int len = SAMPLES_MAX - samples_out; /* See ifVorbis decoder has some audio data for us ... */ samples_in = read_samples(fs, &pcm); if (samples_in <= 0) break; /* Got some audio data from Vorbis... */ /* Convert the float audio data to 16-bit signed linear */ clipflag = 0; if (samples_in > len) samples_in = len; for (j = 0; j < samples_in; j++) accumulator[j] = 0.0; for (i = 0; i < s->vi.channels; i++) { float *mono = pcm[i]; for (j = 0; j < samples_in; j++) accumulator[j] += mono[j]; } for (j = 0; j < samples_in; j++) { val = accumulator[j] * 32767.0 / s->vi.channels; if (val > 32767) { val = 32767; clipflag = 1; } else if (val < -32768) { val = -32768; clipflag = 1; } buf[samples_out + j] = val; } if (clipflag) ast_log(LOG_WARNING, "Clipping in frame %ld\n", (long) (s->vd.sequence)); /* Tell the Vorbis decoder how many samples we actually used. */ vorbis_synthesis_read(&s->vd, samples_in); samples_out += samples_in; } if (samples_out > 0) { fs->fr.datalen = samples_out * 2; fs->fr.samples = samples_out; *whennext = samples_out; return &fs->fr; } else { return NULL; } }
static int func_channel_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len) { int ret = 0; char tmp[512]; struct ast_format_cap *tmpcap; if (!strcasecmp(data, "audionativeformat")) { if ((tmpcap = ast_format_cap_get_type(ast_channel_nativeformats(chan), AST_FORMAT_TYPE_AUDIO))) { ast_copy_string(buf, ast_getformatname_multiple(tmp, sizeof(tmp), tmpcap), len); tmpcap = ast_format_cap_destroy(tmpcap); } } else if (!strcasecmp(data, "videonativeformat")) { if ((tmpcap = ast_format_cap_get_type(ast_channel_nativeformats(chan), AST_FORMAT_TYPE_VIDEO))) { ast_copy_string(buf, ast_getformatname_multiple(tmp, sizeof(tmp), tmpcap), len); tmpcap = ast_format_cap_destroy(tmpcap); } } else if (!strcasecmp(data, "audioreadformat")) { ast_copy_string(buf, ast_getformatname(ast_channel_readformat(chan)), len); } else if (!strcasecmp(data, "audiowriteformat")) { ast_copy_string(buf, ast_getformatname(ast_channel_writeformat(chan)), len); #ifdef CHANNEL_TRACE } else if (!strcasecmp(data, "trace")) { ast_channel_lock(chan); ast_copy_string(buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len); ast_channel_unlock(chan); #endif } else if (!strcasecmp(data, "tonezone") && ast_channel_zone(chan)) locked_copy_string(chan, buf, ast_channel_zone(chan)->country, len); else if (!strcasecmp(data, "language")) locked_copy_string(chan, buf, ast_channel_language(chan), len); else if (!strcasecmp(data, "musicclass")) locked_copy_string(chan, buf, ast_channel_musicclass(chan), len); else if (!strcasecmp(data, "name")) { locked_copy_string(chan, buf, ast_channel_name(chan), len); } else if (!strcasecmp(data, "parkinglot")) locked_copy_string(chan, buf, ast_channel_parkinglot(chan), len); else if (!strcasecmp(data, "state")) locked_copy_string(chan, buf, ast_state2str(ast_channel_state(chan)), len); else if (!strcasecmp(data, "channeltype")) locked_copy_string(chan, buf, ast_channel_tech(chan)->type, len); else if (!strcasecmp(data, "accountcode")) locked_copy_string(chan, buf, ast_channel_accountcode(chan), len); else if (!strcasecmp(data, "checkhangup")) { ast_channel_lock(chan); ast_copy_string(buf, ast_check_hangup(chan) ? "1" : "0", len); ast_channel_unlock(chan); } else if (!strcasecmp(data, "peeraccount")) locked_copy_string(chan, buf, ast_channel_peeraccount(chan), len); else if (!strcasecmp(data, "hangupsource")) locked_copy_string(chan, buf, ast_channel_hangupsource(chan), len); else if (!strcasecmp(data, "appname") && ast_channel_appl(chan)) locked_copy_string(chan, buf, ast_channel_appl(chan), len); else if (!strcasecmp(data, "appdata") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_data(chan), len); else if (!strcasecmp(data, "exten") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_exten(chan), len); else if (!strcasecmp(data, "context") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_context(chan), len); else if (!strcasecmp(data, "userfield") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_userfield(chan), len); else if (!strcasecmp(data, "channame") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_name(chan), len); else if (!strcasecmp(data, "linkedid")) { ast_channel_lock(chan); if (ast_strlen_zero(ast_channel_linkedid(chan))) { /* fall back on the channel's uniqueid if linkedid is unset */ ast_copy_string(buf, ast_channel_uniqueid(chan), len); } else { ast_copy_string(buf, ast_channel_linkedid(chan), len); } ast_channel_unlock(chan); } else if (!strcasecmp(data, "peer")) { struct ast_channel *p; ast_channel_lock(chan); p = ast_bridged_channel(chan); if (p || ast_channel_tech(chan) || ast_channel_cdr(chan)) /* dummy channel? if so, we hid the peer name in the language */ ast_copy_string(buf, (p ? ast_channel_name(p) : ""), len); else { /* a dummy channel can still pass along bridged peer info via the BRIDGEPEER variable */ const char *pname = pbx_builtin_getvar_helper(chan, "BRIDGEPEER"); if (!ast_strlen_zero(pname)) ast_copy_string(buf, pname, len); /* a horrible kludge, but... how else? */ else buf[0] = 0; } ast_channel_unlock(chan); } else if (!strcasecmp(data, "uniqueid")) { locked_copy_string(chan, buf, ast_channel_uniqueid(chan), len); } else if (!strcasecmp(data, "transfercapability")) { locked_copy_string(chan, buf, transfercapability_table[ast_channel_transfercapability(chan) & 0x1f], len); } else if (!strcasecmp(data, "callgroup")) { char groupbuf[256]; locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), ast_channel_callgroup(chan)), len); } else if (!strcasecmp(data, "pickupgroup")) { char groupbuf[256]; locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), ast_channel_pickupgroup(chan)), len); } else if (!strcasecmp(data, "amaflags")) { char amabuf[256]; snprintf(amabuf,sizeof(amabuf), "%d", ast_channel_amaflags(chan)); locked_copy_string(chan, buf, amabuf, len); } else if (!strncasecmp(data, "secure_bridge_", 14)) { struct ast_datastore *ds; ast_channel_lock(chan); if ((ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) { struct ast_secure_call_store *encrypt = ds->data; if (!strcasecmp(data, "secure_bridge_signaling")) { snprintf(buf, len, "%s", encrypt->signaling ? "1" : ""); } else if (!strcasecmp(data, "secure_bridge_media")) { snprintf(buf, len, "%s", encrypt->media ? "1" : ""); } } ast_channel_unlock(chan); } else if (!ast_channel_tech(chan) || !ast_channel_tech(chan)->func_channel_read || ast_channel_tech(chan)->func_channel_read(chan, function, data, buf, len)) { ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data); ret = -1; } return ret; }
int control_swap_channel_in_bridge(struct stasis_app_control *control, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap) { int res; if (!control || !bridge) { return -1; } ast_debug(3, "%s: Adding to bridge %s\n", stasis_app_control_get_channel_id(control), bridge->uniqueid); ast_assert(chan != NULL); /* Depart whatever Stasis bridge we're currently in. */ if (stasis_app_get_bridge(control)) { /* Note that it looks like there's a race condition here, since * we don't have control locked. But this happens from the * control callback thread, so there won't be any other * concurrent attempts to bridge. */ ast_bridge_depart(chan); } res = ast_bridge_set_after_callback(chan, bridge_after_cb, bridge_after_cb_failed, control); if (res != 0) { ast_log(LOG_ERROR, "Error setting after-bridge callback\n"); return -1; } { /* pbx and bridge are modified by the bridging impart thread. * It shouldn't happen concurrently, but we still need to lock * for the memory fence. */ SCOPED_AO2LOCK(lock, control); /* Ensure the controlling application is subscribed early enough * to receive the ChannelEnteredBridge message. This works in concert * with the subscription handled in the Stasis application execution * loop */ app_subscribe_bridge(control->app, bridge); /* Save off the channel's PBX */ ast_assert(control->pbx == NULL); if (!control->pbx) { control->pbx = ast_channel_pbx(chan); ast_channel_pbx_set(chan, NULL); } res = ast_bridge_impart(bridge, chan, swap, NULL, /* features */ AST_BRIDGE_IMPART_CHAN_DEPARTABLE); if (res != 0) { ast_log(LOG_ERROR, "Error adding channel to bridge\n"); ast_channel_pbx_set(chan, control->pbx); control->pbx = NULL; return -1; } ast_assert(stasis_app_get_bridge(control) == NULL); control->bridge = bridge; ast_channel_lock(chan); set_interval_hook(chan); ast_channel_unlock(chan); } return 0; }
static int receive_ademco_contact_id( struct ast_channel *chan, void *data, int fdto, int sdto, int tldn, event_node_t **ehead) { int i,j; int res = 0; int checksum; char event[17]; event_node_t *enew, *elp; int got_some_digits = 0; int events_received = 0; int ack_retries = 0; static char digit_map[15] = "0123456789*#ABC"; static unsigned char digit_weights[15] = {10,1,2,3,4,5,6,7,8,9,11,12,13,14,15}; database_increment("calls-received"); /* Wait for first event */ if(option_verbose >= 4) ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Waiting for first event from panel\n"); while(res >= 0){ if(got_some_digits == 0){ /* Send ACK tone sequence */ if(option_verbose >= 4) ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Sending 1400Hz 100ms burst (ACK)\n"); res = send_tone_burst(chan, 1400.0, 100, tldn); if(!res) res = ast_safe_sleep(chan, 100); if(!res){ if(option_verbose >= 4) ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Sending 2300Hz 100ms burst (ACK)\n"); res = send_tone_burst(chan, 2300.0, 100, tldn); } } if( res >= 0) res = receive_dtmf_digits(chan, event, sizeof(event) - 1, fdto, sdto); if (res < 0){ if(events_received == 0) /* Hangup with no events received should be logged in the DB */ database_increment("no-events-received"); else{ if(ack_retries){ if(option_verbose >= 4) ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: ACK retries during this call: %d\n", ack_retries); database_increment("ack-retries"); } } if(option_verbose >= 4) ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: App exiting...\n"); res = -1; break; } if(res != 0){ /* Didn't get all of the digits */ if(option_verbose >= 2) ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Incomplete string: %s, trying again...\n", event); if(!got_some_digits){ got_some_digits = (!ast_strlen_zero(event)) ? 1 : 0; ack_retries++; } continue; } got_some_digits = 1; if(option_verbose >= 2) ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Received Event %s\n", event); ast_log(LOG_DEBUG, "AlarmReceiver: Received event: %s\n", event); /* Calculate checksum */ for(j = 0, checksum = 0; j < 16; j++){ for(i = 0 ; i < sizeof(digit_map) ; i++){ if(digit_map[i] == event[j]) break; } if(i == 16) break; checksum += digit_weights[i]; } if(i == 16){ if(option_verbose >= 2) ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Bad DTMF character %c, trying again\n", event[j]); continue; /* Bad character */ } /* Checksum is mod(15) of the total */ checksum = checksum % 15; if (checksum) { database_increment("checksum-errors"); if (option_verbose >= 2) ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Nonzero checksum\n"); ast_log(LOG_DEBUG, "AlarmReceiver: Nonzero checksum\n"); continue; } /* Check the message type for correctness */ if(strncmp(event + 4, "18", 2)){ if(strncmp(event + 4, "98", 2)){ database_increment("format-errors"); if(option_verbose >= 2) ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Wrong message type\n"); ast_log(LOG_DEBUG, "AlarmReceiver: Wrong message type\n"); continue; } } events_received++; /* Queue the Event */ if (!(enew = ast_calloc(1, sizeof(*enew)))) { res = -1; break; } enew->next = NULL; ast_copy_string(enew->data, event, sizeof(enew->data)); /* * Insert event onto end of list */ if(*ehead == NULL){ *ehead = enew; } else{ for(elp = *ehead; elp->next != NULL; elp = elp->next) ; elp->next = enew; } if(res > 0) res = 0; /* Let the user have the option of logging the single event before sending the kissoff tone */ if((res == 0) && (log_individual_events)) res = log_events(chan, ADEMCO_CONTACT_ID, enew); /* Wait 200 msec before sending kissoff */ if(res == 0) res = ast_safe_sleep(chan, 200); /* Send the kissoff tone */ if(res == 0) res = send_tone_burst(chan, 1400.0, 900, tldn); } return res; }
static int alarmreceiver_exec(struct ast_channel *chan, void *data) { int res = 0; struct localuser *u; event_node_t *elp, *efree; char signalling_type[64] = ""; event_node_t *event_head = NULL; LOCAL_USER_ADD(u); /* Set write and read formats to ULAW */ if(option_verbose >= 4) ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Setting read and write formats to ULAW\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",chan->name); LOCAL_USER_REMOVE(u); return -1; } 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",chan->name); LOCAL_USER_REMOVE(u); return -1; } /* Set default values for this invokation of the application */ ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type)); /* Answer the channel if it is not already */ if(option_verbose >= 4) ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Answering channel\n"); if (chan->_state != AST_STATE_UP) { res = ast_answer(chan); if (res) { LOCAL_USER_REMOVE(u); return -1; } } /* Wait for the connection to settle post-answer */ if(option_verbose >= 4) ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Waiting for connection to stabilize\n"); res = ast_safe_sleep(chan, 1250); /* Attempt to receive the events */ if(!res){ /* Determine the protocol to receive in advance */ /* Note: Ademco contact is the only one supported at this time */ /* Others may be added later */ if(!strcmp(signalling_type, ADEMCO_CONTACT_ID)) receive_ademco_contact_id(chan, data, fdtimeout, sdtimeout, toneloudness, &event_head); else res = -1; } /* Events queued by receiver, write them all out here if so configured */ if((!res) && (log_individual_events == 0)){ res = log_events(chan, signalling_type, event_head); } /* * Do we exec a command line at the end? */ if((!res) && (!ast_strlen_zero(event_app)) && (event_head)){ ast_log(LOG_DEBUG,"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; free(efree); } LOCAL_USER_REMOVE(u); return 0; }
/*! * \brief Execute a curl query and return ast_variable list * \param url The base URL from which to retrieve data * \param unused Not currently used * \param ap list containing one or more field/operator/value set. * * \retval var on success * \retval NULL on failure */ static struct ast_variable *realtime_curl(const char *url, const char *unused, va_list ap) { struct ast_str *query; char buf1[200], buf2[200]; const char *newparam, *newval; char *stringp, *pair, *key; int i; struct ast_variable *var=NULL, *prev=NULL; const int EncodeSpecialChars = 1, bufsize = 64000; char *buffer; if (!ast_custom_function_find("CURL")) { ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n"); return NULL; } if (!(query = ast_str_create(1000))) return NULL; if (!(buffer = ast_malloc(bufsize))) { ast_free(query); return NULL; } ast_str_set(&query, 0, "${CURL(%s/single,", url); for (i = 0; (newparam = va_arg(ap, const char *)); i++) { newval = va_arg(ap, const char *); ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars); ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars); ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2); } va_end(ap); ast_str_append(&query, 0, ")}"); pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize); /* Remove any trailing newline characters */ if ((stringp = strchr(buffer, '\r')) || (stringp = strchr(buffer, '\n'))) *stringp = '\0'; stringp = buffer; while ((pair = strsep(&stringp, "&"))) { key = strsep(&pair, "="); ast_uri_decode(key); if (pair) ast_uri_decode(pair); if (!ast_strlen_zero(key)) { if (prev) { prev->next = ast_variable_new(key, S_OR(pair, ""), ""); if (prev->next) prev = prev->next; } else prev = var = ast_variable_new(key, S_OR(pair, ""), ""); } } ast_free(buffer); ast_free(query); return var; }
static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int length, int fdto, int sdto) { int res = 0; int i = 0; int r; struct ast_frame *f; struct timeval lastdigittime; lastdigittime = ast_tvnow(); for(;;){ /* if outa time, leave */ if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((i > 0) ? sdto : fdto)){ if(option_verbose >= 4) ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: DTMF Digit Timeout on %s\n", chan->name); ast_log(LOG_DEBUG,"AlarmReceiver: DTMF timeout on chan %s\n",chan->name); res = 1; break; } if ((r = ast_waitfor(chan, -1) < 0)) { ast_log(LOG_DEBUG, "Waitfor returned %d\n", r); continue; } f = ast_read(chan); if (f == NULL){ res = -1; break; } /* If they hung up, leave */ if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)){ ast_frfree(f); res = -1; break; } /* if not DTMF, just do it again */ if (f->frametype != AST_FRAME_DTMF){ ast_frfree(f); continue; } digit_string[i++] = f->subclass; /* save digit */ ast_frfree(f); /* If we have all the digits we expect, leave */ if(i >= length) break; lastdigittime = ast_tvnow(); } digit_string[i] = '\0'; /* Nul terminate the end of the digit string */ return res; }
static struct ast_config *config_curl(const char *url, const char *unused, const char *file, struct ast_config *cfg, struct ast_flags flags, const char *sugg_incl, const char *who_asked) { struct ast_str *query; char buf1[200]; char *stringp, *line, *pair, *key; const int EncodeSpecialChars = 1, bufsize = 256000; int last_cat_metric = -1, cat_metric = -1; struct ast_category *cat=NULL; char *buffer, *cur_cat = ""; char *category = "", *var_name = "", *var_val = ""; struct ast_flags loader_flags = { 0 }; if (!ast_custom_function_find("CURL")) { ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n"); return NULL; } if (!(query = ast_str_create(1000))) return NULL; if (!(buffer = ast_malloc(bufsize))) { ast_free(query); return NULL; } ast_uri_encode(file, buf1, sizeof(buf1), EncodeSpecialChars); ast_str_set(&query, 0, "${CURL(%s/static?file=%s)}", url, buf1); /* Do the CURL query */ pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize); /* Line oriented output */ stringp = buffer; cat = ast_config_get_current_category(cfg); while ((line = strsep(&stringp, "\r\n"))) { if (ast_strlen_zero(line)) continue; while ((pair = strsep(&line, "&"))) { key = strsep(&pair, "="); ast_uri_decode(key); if (pair) ast_uri_decode(pair); if (!strcasecmp(key, "category")) category = S_OR(pair, ""); else if (!strcasecmp(key, "var_name")) var_name = S_OR(pair, ""); else if (!strcasecmp(key, "var_val")) var_val = S_OR(pair, ""); else if (!strcasecmp(key, "cat_metric")) cat_metric = pair ? atoi(pair) : 0; } if (!strcmp(var_name, "#include")) { if (!ast_config_internal_load(var_val, cfg, loader_flags, "", who_asked)) return NULL; } if (strcmp(category, cur_cat) || last_cat_metric != cat_metric) { if (!(cat = ast_category_new(category, "", 99999))) break; cur_cat = category; last_cat_metric = cat_metric; ast_category_append(cfg, cat); } ast_variable_append(cat, ast_variable_new(var_name, var_val, "")); } ast_free(buffer); ast_free(query); return cfg; }
/*! * \brief Excute an Select query and return ast_config list * \param url * \param unused * \param ap list containing one or more field/operator/value set. * * \retval struct ast_config pointer on success * \retval NULL on failure */ static struct ast_config *realtime_multi_curl(const char *url, const char *unused, va_list ap) { struct ast_str *query; char buf1[200], buf2[200]; const char *newparam, *newval; char *stringp, *line, *pair, *key, *initfield = NULL; int i; const int EncodeSpecialChars = 1, bufsize = 256000; struct ast_variable *var=NULL; struct ast_config *cfg=NULL; struct ast_category *cat=NULL; char *buffer; if (!ast_custom_function_find("CURL")) { ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n"); return NULL; } if (!(query = ast_str_create(1000))) return NULL; if (!(buffer = ast_malloc(bufsize))) { ast_free(query); return NULL; } ast_str_set(&query, 0, "${CURL(%s/multi,", url); for (i = 0; (newparam = va_arg(ap, const char *)); i++) { newval = va_arg(ap, const char *); if (i == 0) { char *op; initfield = ast_strdupa(newparam); if ((op = strchr(initfield, ' '))) *op = '\0'; } ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars); ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars); ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2); } va_end(ap); ast_str_append(&query, 0, ")}"); /* Do the CURL query */ pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize); if (!(cfg = ast_config_new())) goto exit_multi; /* Line oriented output */ stringp = buffer; while ((line = strsep(&stringp, "\r\n"))) { if (ast_strlen_zero(line)) continue; if (!(cat = ast_category_new("", "", 99999))) continue; while ((pair = strsep(&line, "&"))) { key = strsep(&pair, "="); ast_uri_decode(key); if (pair) ast_uri_decode(pair); if (!strcasecmp(key, initfield) && pair) ast_category_rename(cat, pair); if (!ast_strlen_zero(key)) { var = ast_variable_new(key, S_OR(pair, ""), ""); ast_variable_append(cat, var); } } ast_category_append(cfg, cat); } exit_multi: ast_free(buffer); ast_free(query); return cfg; }
static int timerfd_timer_enable_continuous(void *data) { struct timerfd_timer *timer = data; int res; static const struct itimerspec continuous_timer = { .it_value.tv_nsec = 1L, }; ao2_lock(timer); if (timer->is_continuous) { /*It's already in continous mode, no need to do * anything further */ ao2_unlock(timer); return 0; } res = timerfd_settime(timer->fd, 0, &continuous_timer, &timer->saved_timer); timer->is_continuous = 1; ao2_unlock(timer); return res; } static int timerfd_timer_disable_continuous(void *data) { struct timerfd_timer *timer = data; int res; ao2_lock(timer); if (!timer->is_continuous) { /* No reason to do anything if we're not * in continuous mode */ ao2_unlock(timer); return 0; } res = timerfd_settime(timer->fd, 0, &timer->saved_timer, NULL); timer->is_continuous = 0; memset(&timer->saved_timer, 0, sizeof(timer->saved_timer)); ao2_unlock(timer); return res; } static enum ast_timer_event timerfd_timer_get_event(void *data) { struct timerfd_timer *timer = data; enum ast_timer_event res; ao2_lock(timer); if (timer->is_continuous) { res = AST_TIMING_EVENT_CONTINUOUS; } else { res = AST_TIMING_EVENT_EXPIRED; } ao2_unlock(timer); return res; } static unsigned int timerfd_timer_get_max_rate(void *data) { return TIMERFD_MAX_RATE; } static int timerfd_timer_fd(void *data) { struct timerfd_timer *timer = data; return timer->fd; } static int load_module(void) { int fd; /* Make sure we support the necessary clock type */ if ((fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) { ast_log(LOG_ERROR, "timerfd_create() not supported by the kernel. Not loading.\n"); return AST_MODULE_LOAD_DECLINE; } close(fd); if (!(timing_funcs_handle = ast_register_timing_interface(&timerfd_timing))) { return AST_MODULE_LOAD_DECLINE; } return AST_MODULE_LOAD_SUCCESS; }
static int beanstalk_put(struct ast_cdr *cdr) { struct ast_tm timeresult; char strAnswerTime[80] = ""; char strStartTime[80]; char strEndTime[80]; char *cdr_buffer; int bs_id; int bs_socket; struct ast_json *t_cdr_json; if (!enablecdr) { return 0; } ast_rwlock_rdlock(&config_lock); bs_socket = bs_connect(bs_host, bs_port); if (bs_use(bs_socket, bs_tube) != BS_STATUS_OK) { ast_log(LOG_ERROR, "Connection to Beanstalk tube %s @ %s:%d had failed", bs_tube, bs_host, bs_port); ast_rwlock_unlock(&config_lock); 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); ast_rwlock_unlock(&config_lock); t_cdr_json = ast_json_pack("{s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:i, s:i, s:s, s:s, s:s, s:s}", "AccountCode", S_OR(cdr->accountcode, ""), "Source", S_OR(cdr->src, ""), "Destination", S_OR(cdr->dst, ""), "DestinationContext", S_OR(cdr->dcontext, ""), "CallerID", S_OR(cdr->clid, ""), "Channel", S_OR(cdr->channel, ""), "DestinationChannel", S_OR(cdr->dstchannel, ""), "LastApplication", S_OR(cdr->lastapp, ""), "LastData", S_OR(cdr->lastdata, ""), "StartTime", S_OR(strStartTime, ""), "AnswerTime", S_OR(strAnswerTime, ""), "EndTime", S_OR(strEndTime, ""), "Duration", cdr->duration, "Billsec", cdr->billsec, "Disposition", S_OR(ast_cdr_disp2str(cdr->disposition), ""), "AMAFlags", S_OR(ast_channel_amaflags2string(cdr->amaflags), ""), "UniqueID", S_OR(cdr->uniqueid, ""), "UserField", S_OR(cdr->userfield, "")); cdr_buffer = ast_json_dump_string(t_cdr_json); ast_json_unref(t_cdr_json); bs_id = bs_put(bs_socket, priority, BEANSTALK_JOB_DELAY, BEANSTALK_JOB_TTR, cdr_buffer, strlen(cdr_buffer)); if (bs_id > 0) { ast_log(LOG_DEBUG, "Successfully created job %d with %s\n", bs_id, cdr_buffer); } else { ast_log(LOG_ERROR, "CDR job creation failed for %s\n", cdr_buffer); } bs_disconnect(bs_socket); ast_json_free(cdr_buffer); return 0; }
/*! \brief * creates a FILE * from the fd passed by the accept thread. * This operation is potentially expensive (certificate verification), * so we do it in the child thread context. * * \note must decrement ref count before returning NULL on error */ static void *handle_tcptls_connection(void *data) { struct ast_tcptls_session_instance *tcptls_session = data; #ifdef DO_SSL int (*ssl_setup)(SSL *) = (tcptls_session->client) ? SSL_connect : SSL_accept; int ret; char err[256]; #endif /* * open a FILE * as appropriate. */ if (!tcptls_session->parent->tls_cfg) { if ((tcptls_session->f = fdopen(tcptls_session->fd, "w+"))) { if(setvbuf(tcptls_session->f, NULL, _IONBF, 0)) { ast_tcptls_close_session_file(tcptls_session); } } } #ifdef DO_SSL else if ( (tcptls_session->ssl = SSL_new(tcptls_session->parent->tls_cfg->ssl_ctx)) ) { SSL_set_fd(tcptls_session->ssl, tcptls_session->fd); if ((ret = ssl_setup(tcptls_session->ssl)) <= 0) { ast_verb(2, "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err)); } else { #if defined(HAVE_FUNOPEN) /* the BSD interface */ tcptls_session->f = funopen(tcptls_session->ssl, ssl_read, ssl_write, NULL, ssl_close); #elif defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */ static const cookie_io_functions_t cookie_funcs = { ssl_read, ssl_write, NULL, ssl_close }; tcptls_session->f = fopencookie(tcptls_session->ssl, "w+", cookie_funcs); #else /* could add other methods here */ ast_debug(2, "no tcptls_session->f methods attempted!\n"); #endif if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER)) || (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) { X509 *peer; long res; peer = SSL_get_peer_certificate(tcptls_session->ssl); if (!peer) { ast_log(LOG_ERROR, "No peer SSL certificate to verify\n"); ast_tcptls_close_session_file(tcptls_session); ao2_ref(tcptls_session, -1); return NULL; } res = SSL_get_verify_result(tcptls_session->ssl); if (res != X509_V_OK) { ast_log(LOG_ERROR, "Certificate did not verify: %s\n", X509_verify_cert_error_string(res)); X509_free(peer); ast_tcptls_close_session_file(tcptls_session); ao2_ref(tcptls_session, -1); return NULL; } if (!ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) { ASN1_STRING *str; unsigned char *str2; X509_NAME *name = X509_get_subject_name(peer); int pos = -1; int found = 0; for (;;) { /* Walk the certificate to check all available "Common Name" */ /* XXX Probably should do a gethostbyname on the hostname and compare that as well */ pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos); if (pos < 0) { break; } str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos)); ASN1_STRING_to_UTF8(&str2, str); if (str2) { if (!strcasecmp(tcptls_session->parent->hostname, (char *) str2)) { found = 1; } ast_debug(3, "SSL Common Name compare s1='%s' s2='%s'\n", tcptls_session->parent->hostname, str2); OPENSSL_free(str2); } if (found) { break; } } if (!found) { ast_log(LOG_ERROR, "Certificate common name did not match (%s)\n", tcptls_session->parent->hostname); X509_free(peer); ast_tcptls_close_session_file(tcptls_session); ao2_ref(tcptls_session, -1); return NULL; } } X509_free(peer); } } if (!tcptls_session->f) { /* no success opening descriptor stacking */ SSL_free(tcptls_session->ssl); } } #endif /* DO_SSL */ if (!tcptls_session->f) { ast_tcptls_close_session_file(tcptls_session); ast_log(LOG_WARNING, "FILE * open failed!\n"); #ifndef DO_SSL if (tcptls_session->parent->tls_cfg) { ast_log(LOG_WARNING, "Attempted a TLS connection without OpenSSL support. This will not work!\n"); } #endif ao2_ref(tcptls_session, -1); return NULL; } if (tcptls_session->parent->worker_fn) { return tcptls_session->parent->worker_fn(tcptls_session); } else { return tcptls_session; } }
static int load_config(int reload) { char *cat = NULL; struct ast_config *cfg; struct ast_variable *v; struct ast_flags config_flags = {reload ? CONFIG_FLAG_FILEUNCHANGED : 0}; int newenablecdr = 0; cfg = ast_config_load(CONF_FILE, config_flags); if (cfg == CONFIG_STATUS_FILEUNCHANGED) { return 0; } if (cfg == CONFIG_STATUS_FILEINVALID) { ast_log(LOG_ERROR, "Config file '%s' could not be parsed\n", CONF_FILE); return -1; } if (!cfg) { /* Standard configuration */ ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n"); if (enablecdr) { ast_cdr_backend_suspend(name); } enablecdr = 0; return -1; } if (reload) { ast_rwlock_wrlock(&config_lock); ast_free(bs_host); ast_free(bs_tube); } /* Bootstrap the default configuration */ bs_host = ast_strdup(DEFAULT_BEANSTALK_HOST); bs_port = DEFAULT_BEANSTALK_PORT; bs_tube = ast_strdup(DEFAULT_BEANSTALK_TUBE); priority = BEANSTALK_JOB_PRIORITY; while ((cat = ast_category_browse(cfg, cat))) { if (!strcasecmp(cat, "general")) { v = ast_variable_browse(cfg, cat); while (v) { if (!strcasecmp(v->name, "enabled")) { newenablecdr = ast_true(v->value); } else if (!strcasecmp(v->name, "host")) { ast_free(bs_host); bs_host = ast_strdup(v->value); } else if (!strcasecmp(v->name, "port")) { bs_port = atoi(v->value); } else if (!strcasecmp(v->name, "tube")) { ast_free(bs_tube); bs_tube = ast_strdup(v->value); } else if (!strcasecmp(v->name, "priority")) { priority = atoi(v->value); } v = v->next; } } } if (reload) { ast_rwlock_unlock(&config_lock); } ast_config_destroy(cfg); if (!newenablecdr) { ast_cdr_backend_suspend(name); } else if (newenablecdr) { ast_cdr_backend_unsuspend(name); ast_log(LOG_NOTICE, "Added beanstalkd server %s at port %d with tube %s", bs_host, bs_port, bs_tube); } enablecdr = newenablecdr; return 0; }
struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_session_args *desc) { int x = 1; struct ast_tcptls_session_instance *tcptls_session = NULL; /* Do nothing if nothing has changed */ if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) { ast_debug(1, "Nothing changed in %s\n", desc->name); return NULL; } /* If we return early, there is no connection */ ast_sockaddr_setnull(&desc->old_address); if (desc->accept_fd != -1) { close(desc->accept_fd); } desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ? AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP); if (desc->accept_fd < 0) { ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno)); return NULL; } /* if a local address was specified, bind to it so the connection will originate from the desired address */ if (!ast_sockaddr_isnull(&desc->local_address)) { setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); if (ast_bind(desc->accept_fd, &desc->local_address)) { ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", desc->name, ast_sockaddr_stringify(&desc->local_address), strerror(errno)); goto error; } } if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor))) { goto error; } tcptls_session->overflow_buf = ast_str_create(128); tcptls_session->client = 1; tcptls_session->fd = desc->accept_fd; tcptls_session->parent = desc; tcptls_session->parent->worker_fn = NULL; ast_sockaddr_copy(&tcptls_session->remote_address, &desc->remote_address); /* Set current info */ ast_sockaddr_copy(&desc->old_address, &desc->remote_address); return tcptls_session; error: close(desc->accept_fd); desc->accept_fd = -1; if (tcptls_session) { ao2_ref(tcptls_session, -1); } return NULL; }
static int func_channel_write_real(struct ast_channel *chan, const char *function, char *data, const char *value) { int ret = 0; signed char gainset; if (!strcasecmp(data, "language")) locked_string_field_set(chan, language, value); else if (!strcasecmp(data, "parkinglot")) locked_string_field_set(chan, parkinglot, value); else if (!strcasecmp(data, "musicclass")) locked_string_field_set(chan, musicclass, value); else if (!strcasecmp(data, "accountcode")) locked_string_field_set(chan, accountcode, value); else if (!strcasecmp(data, "userfield")) locked_string_field_set(chan, userfield, value); else if (!strcasecmp(data, "amaflags")) { ast_channel_lock(chan); if(isdigit(*value)) { int amaflags; sscanf(value, "%30d", &amaflags); ast_channel_amaflags_set(chan, amaflags); } else if (!strcasecmp(value,"OMIT")) { ast_channel_amaflags_set(chan, 1); } else if (!strcasecmp(value,"BILLING")) { ast_channel_amaflags_set(chan, 2); } else if (!strcasecmp(value,"DOCUMENTATION")) { ast_channel_amaflags_set(chan, 3); } ast_channel_unlock(chan); } else if (!strcasecmp(data, "peeraccount")) locked_string_field_set(chan, peeraccount, value); else if (!strcasecmp(data, "hangupsource")) /* XXX - should we be forcing this here? */ ast_set_hangupsource(chan, value, 0); #ifdef CHANNEL_TRACE else if (!strcasecmp(data, "trace")) { ast_channel_lock(chan); if (ast_true(value)) ret = ast_channel_trace_enable(chan); else if (ast_false(value)) ret = ast_channel_trace_disable(chan); else { ret = -1; ast_log(LOG_WARNING, "Invalid value for CHANNEL(trace)."); } ast_channel_unlock(chan); } #endif else if (!strcasecmp(data, "tonezone")) { struct ast_tone_zone *new_zone; if (!(new_zone = ast_get_indication_zone(value))) { ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", value); ret = -1; } else { ast_channel_lock(chan); if (ast_channel_zone(chan)) { ast_channel_zone_set(chan, ast_tone_zone_unref(ast_channel_zone(chan))); } ast_channel_zone_set(chan, ast_tone_zone_ref(new_zone)); ast_channel_unlock(chan); new_zone = ast_tone_zone_unref(new_zone); } } else if (!strcasecmp(data, "callgroup")) { ast_channel_callgroup_set(chan, ast_get_group(value)); } else if (!strcasecmp(data, "pickupgroup")) { ast_channel_pickupgroup_set(chan, ast_get_group(value)); } else if (!strcasecmp(data, "txgain")) { sscanf(value, "%4hhd", &gainset); ast_channel_setoption(chan, AST_OPTION_TXGAIN, &gainset, sizeof(gainset), 0); } else if (!strcasecmp(data, "rxgain")) { sscanf(value, "%4hhd", &gainset); ast_channel_setoption(chan, AST_OPTION_RXGAIN, &gainset, sizeof(gainset), 0); } else if (!strcasecmp(data, "transfercapability")) { unsigned short i; for (i = 0; i < 0x20; i++) { if (!strcasecmp(transfercapability_table[i], value) && strcmp(value, "UNK")) { ast_channel_transfercapability_set(chan, i); break; } } } else if (!strncasecmp(data, "secure_bridge_", 14)) { struct ast_datastore *ds; struct ast_secure_call_store *store; if (!chan || !value) { return -1; } ast_channel_lock(chan); if (!(ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) { if (!(ds = ast_datastore_alloc(&secure_call_info, NULL))) { ast_channel_unlock(chan); return -1; } if (!(store = ast_calloc(1, sizeof(*store)))) { ast_channel_unlock(chan); ast_free(ds); return -1; } ds->data = store; ast_channel_datastore_add(chan, ds); } else { store = ds->data; } ast_channel_unlock(chan); if (!strcasecmp(data, "secure_bridge_signaling")) { store->signaling = ast_true(value) ? 1 : 0; } else if (!strcasecmp(data, "secure_bridge_media")) { store->media = ast_true(value) ? 1 : 0; } } else if (!ast_channel_tech(chan)->func_channel_write || ast_channel_tech(chan)->func_channel_write(chan, function, data, value)) { ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data); ret = -1; } return ret; }
void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) { int flags; int x = 1; /* Do nothing if nothing has changed */ if (!ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) { ast_debug(1, "Nothing changed in %s\n", desc->name); return; } /* If we return early, there is no one listening */ ast_sockaddr_setnull(&desc->old_address); /* Shutdown a running server if there is one */ if (desc->master != AST_PTHREADT_NULL) { pthread_cancel(desc->master); pthread_kill(desc->master, SIGURG); pthread_join(desc->master, NULL); } if (desc->accept_fd != -1) { close(desc->accept_fd); } /* If there's no new server, stop here */ if (ast_sockaddr_isnull(&desc->local_address)) { ast_debug(2, "Server disabled: %s\n", desc->name); return; } desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->local_address) ? AF_INET6 : AF_INET, SOCK_STREAM, 0); if (desc->accept_fd < 0) { ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno)); return; } setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); if (ast_bind(desc->accept_fd, &desc->local_address)) { ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", desc->name, ast_sockaddr_stringify(&desc->local_address), strerror(errno)); goto error; } if (listen(desc->accept_fd, 10)) { ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name); goto error; } flags = fcntl(desc->accept_fd, F_GETFL); fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK); if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) { ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n", desc->name, ast_sockaddr_stringify(&desc->local_address), strerror(errno)); goto error; } /* Set current info */ ast_sockaddr_copy(&desc->old_address, &desc->local_address); return; error: close(desc->accept_fd); desc->accept_fd = -1; }
int misdn_cfg_init (int this_max_ports) { char config[] = "misdn.conf"; char *cat, *p; int i; struct ast_config *cfg; struct ast_variable *v; if (!(cfg = AST_LOAD_CFG(config))) { ast_log(LOG_WARNING, "missing file: misdn.conf\n"); return -1; } ast_mutex_init(&config_mutex); misdn_cfg_lock(); if (this_max_ports) { /* this is the first run */ max_ports = this_max_ports; map = (int *)calloc(MISDN_GEN_LAST + 1, sizeof(int)); if (_enum_array_map()) return -1; p = (char *)calloc(1, (max_ports + 1) * sizeof(union misdn_cfg_pt *) + (max_ports + 1) * NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt)); port_cfg = (union misdn_cfg_pt **)p; p += (max_ports + 1) * sizeof(union misdn_cfg_pt *); for (i = 0; i <= max_ports; ++i) { port_cfg[i] = (union misdn_cfg_pt *)p; p += NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt); } general_cfg = (union misdn_cfg_pt *)calloc(1, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS); ptp = (int *)calloc(max_ports + 1, sizeof(int)); } else { /* misdn reload */ _free_port_cfg(); _free_general_cfg(); memset(port_cfg[0], 0, NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt) * (max_ports + 1)); memset(general_cfg, 0, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS); memset(ptp, 0, sizeof(int) * (max_ports + 1)); } cat = ast_category_browse(cfg, NULL); while(cat) { v = ast_variable_browse(cfg, cat); if (!strcasecmp(cat, "general")) { _build_general_config(v); } else { _build_port_config(v, cat); } cat = ast_category_browse(cfg, cat); } _fill_defaults(); misdn_cfg_unlock(); AST_DESTROY_CFG(cfg); return 0; }
/* * the string is 'prefix:data' or prefix:fmt:data' * with ':' being invalid in strings. */ static int do_say(say_args_t *a, const char *s, const char *options, int depth) { struct ast_variable *v; char *lang, *x, *rule = NULL; int ret = 0; struct varshead head = { .first = NULL, .last = NULL }; struct ast_var_t *n; ast_debug(2, "string <%s> depth <%d>\n", s, depth); if (depth++ > 10) { ast_log(LOG_WARNING, "recursion too deep, exiting\n"); return -1; } else if (!say_cfg) { ast_log(LOG_WARNING, "no say.conf, cannot spell '%s'\n", s); return -1; } /* scan languages same as in file.c */ if (a->language == NULL) a->language = "en"; /* default */ ast_debug(2, "try <%s> in <%s>\n", s, a->language); lang = ast_strdupa(a->language); for (;;) { for (v = ast_variable_browse(say_cfg, lang); v ; v = v->next) { if (ast_extension_match(v->name, s)) { rule = ast_strdupa(v->value); break; } } if (rule) break; if ( (x = strchr(lang, '_')) ) *x = '\0'; /* try without suffix */ else if (strcmp(lang, "en")) lang = "en"; /* last resort, try 'en' if not done yet */ else break; } if (!rule) return 0; /* skip up to two prefixes to get the value */ if ( (x = strchr(s, ':')) ) s = x + 1; if ( (x = strchr(s, ':')) ) s = x + 1; ast_debug(2, "value is <%s>\n", s); n = ast_var_assign("SAY", s); AST_LIST_INSERT_HEAD(&head, n, entries); /* scan the body, one piece at a time */ while ( !ret && (x = strsep(&rule, ",")) ) { /* exit on key */ char fn[128]; const char *p, *fmt, *data; /* format and data pointers */ /* prepare a decent file name */ x = ast_skip_blanks(x); ast_trim_blanks(x); /* replace variables */ pbx_substitute_variables_varshead(&head, x, fn, sizeof(fn)); ast_debug(2, "doing [%s]\n", fn); /* locate prefix and data, if any */ fmt = strchr(fn, ':'); if (!fmt || fmt == fn) { /* regular filename */ ret = s_streamwait3(a, fn); continue; } fmt++; data = strchr(fmt, ':'); /* colon before data */ if (!data || data == fmt) { /* simple prefix-fmt */ ret = do_say(a, fn, options, depth); continue; } /* prefix:fmt:data */ for (p = fmt; p < data && ret <= 0; p++) { char fn2[sizeof(fn)]; if (*p == ' ' || *p == '\t') /* skip blanks */ continue; if (*p == '\'') {/* file name - we trim them */ char *y; strcpy(fn2, ast_skip_blanks(p+1)); /* make a full copy */ y = strchr(fn2, '\''); if (!y) { p = data; /* invalid. prepare to end */ break; } *y = '\0'; ast_trim_blanks(fn2); p = strchr(p+1, '\''); ret = s_streamwait3(a, fn2); } else { int l = fmt-fn; strcpy(fn2, fn); /* copy everything */ /* after prefix, append the format */ fn2[l++] = *p; strcpy(fn2 + l, data); ret = do_say(a, fn2, options, depth); } if (ret) { break; } } } ast_var_delete(n); return ret; }
static int read_samples(struct ast_filestream *fs, float ***pcm) { int samples_in; int result; char *buffer; int bytes; struct vorbis_desc *s = (struct vorbis_desc *)fs->_private; while (1) { samples_in = vorbis_synthesis_pcmout(&s->vd, pcm); if (samples_in > 0) { return samples_in; } /* The Vorbis decoder needs more data... */ /* See ifOGG has any packets in the current page for the Vorbis decoder. */ result = ogg_stream_packetout(&s->os, &s->op); if (result > 0) { /* Yes OGG had some more packets for the Vorbis decoder. */ if (vorbis_synthesis(&s->vb, &s->op) == 0) { vorbis_synthesis_blockin(&s->vd, &s->vb); } continue; } if (result < 0) ast_log(LOG_WARNING, "Corrupt or missing data at this page position; continuing...\n"); /* No more packets left in the current page... */ if (s->eos) { /* No more pages left in the stream */ return -1; } while (!s->eos) { /* See ifOGG has any pages in it's internal buffers */ result = ogg_sync_pageout(&s->oy, &s->og); if (result > 0) { /* Yes, OGG has more pages in it's internal buffers, add the page to the stream state */ result = ogg_stream_pagein(&s->os, &s->og); if (result == 0) { /* Yes, got a new,valid page */ if (ogg_page_eos(&s->og)) { s->eos = 1; } break; } ast_log(LOG_WARNING, "Invalid page in the bitstream; continuing...\n"); } if (result < 0) ast_log(LOG_WARNING, "Corrupt or missing data in bitstream; continuing...\n"); /* No, we need to read more data from the file descrptor */ /* get a buffer from OGG to read the data into */ buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE); /* read more data from the file descriptor */ bytes = fread(buffer, 1, BLOCK_SIZE, fs->f); /* Tell OGG how many bytes we actually read into the buffer */ ogg_sync_wrote(&s->oy, bytes); if (bytes == 0) { s->eos = 1; } } } }
static int timeout_write(struct ast_channel *chan, const char *cmd, char *data, const char *value) { double x = 0.0; long sec = 0L; char timestr[64]; struct ast_tm myt; struct timeval when = {0,}; int res; if (!chan) return -1; if (!data) { ast_log(LOG_ERROR, "Must specify type of timeout to set.\n"); return -1; } if (!value) return -1; res = sscanf(value, "%30ld%30lf", &sec, &x); if (res == 0 || sec < 0) { when.tv_sec = 0; when.tv_usec = 0; } else if (res == 1) { when.tv_sec = sec; } else if (res == 2) { when.tv_sec = sec; when.tv_usec = x * 1000000; } switch (*data) { case 'a': case 'A': ast_channel_setwhentohangup_tv(chan, when); if (!ast_tvzero(*ast_channel_whentohangup(chan))) { when = ast_tvadd(when, ast_tvnow()); ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S.%3q %Z", ast_localtime(&when, &myt, NULL)); ast_verb(3, "Channel will hangup at %s.\n", timestr); } else { ast_verb(3, "Channel hangup cancelled.\n"); } break; case 'r': case 'R': if (ast_channel_pbx(chan)) { ast_channel_pbx(chan)->rtimeoutms = when.tv_sec * 1000 + when.tv_usec / 1000; ast_verb(3, "Response timeout set to %.3f\n", ast_channel_pbx(chan)->rtimeoutms / 1000.0); } break; case 'd': case 'D': if (ast_channel_pbx(chan)) { ast_channel_pbx(chan)->dtimeoutms = when.tv_sec * 1000 + when.tv_usec / 1000; ast_verb(3, "Digit timeout set to %.3f\n", ast_channel_pbx(chan)->dtimeoutms / 1000.0); } break; default: ast_log(LOG_ERROR, "Unknown timeout type specified.\n"); break; } return 0; }
static int ogg_vorbis_trunc(struct ast_filestream *s) { ast_log(LOG_WARNING, "Truncation is not supported on OGG/Vorbis streams!\n"); return -1; }
/*! * \internal * \pre timer is locked */ static void read_pipe(struct pthread_timer *timer, unsigned int quantity) { int rd_fd = timer->pipe[PIPE_READ]; int pending_ticks = timer->pending_ticks; ast_assert(quantity); if (timer->continuous && pending_ticks) { pending_ticks--; } if (quantity > pending_ticks) { quantity = pending_ticks; } if (!quantity) { return; } do { unsigned char buf[1024]; ssize_t res; fd_set rfds; struct timeval timeout = { .tv_sec = 0, }; /* Make sure there is data to read */ FD_ZERO(&rfds); FD_SET(rd_fd, &rfds); if (select(rd_fd + 1, &rfds, NULL, NULL, &timeout) != 1) { ast_debug(1, "Reading not available on timing pipe, " "quantity: %u\n", quantity); break; } res = read(rd_fd, buf, (quantity < sizeof(buf)) ? quantity : sizeof(buf)); if (res == -1) { if (errno == EAGAIN) { continue; } ast_log(LOG_ERROR, "read failed on timing pipe: %s\n", strerror(errno)); break; } quantity -= res; timer->pending_ticks -= res; } while (quantity); } /*! * \internal * \pre timer is locked */ static void write_byte(struct pthread_timer *timer) { ssize_t res; unsigned char x = 42; do { res = write(timer->pipe[PIPE_WRITE], &x, 1); } while (res == -1 && errno == EAGAIN); if (res == -1) { ast_log(LOG_ERROR, "Error writing to timing pipe: %s\n", strerror(errno)); } else { timer->pending_ticks++; } }
static off_t ogg_vorbis_tell(struct ast_filestream *s) { ast_log(LOG_WARNING, "Telling is not supported on OGG/Vorbis streams!\n"); return -1; }
/*! * \brief Parameter parsing callback for /recordings/stored/{recordingName}/copy. * \param get_params GET parameters in the HTTP request. * \param path_vars Path variables extracted from the request. * \param headers HTTP headers. * \param[out] response Response to the HTTP request. */ static void ast_ari_recordings_copy_stored_cb( struct ast_tcptls_session_instance *ser, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_ari_recordings_copy_stored_args args = {}; struct ast_variable *i; RAII_VAR(struct ast_json *, body, NULL, ast_json_unref); #if defined(AST_DEVMODE) int is_valid; int code; #endif /* AST_DEVMODE */ for (i = get_params; i; i = i->next) { if (strcmp(i->name, "destinationRecordingName") == 0) { args.destination_recording_name = (i->value); } else {} } for (i = path_vars; i; i = i->next) { if (strcmp(i->name, "recordingName") == 0) { args.recording_name = (i->value); } else {} } /* Look for a JSON request entity */ body = ast_http_get_json(ser, headers); if (!body) { switch (errno) { case EFBIG: ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large"); goto fin; case ENOMEM: ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request"); goto fin; case EIO: ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body"); goto fin; } } if (ast_ari_recordings_copy_stored_parse_body(body, &args)) { ast_ari_response_alloc_failed(response); goto fin; } ast_ari_recordings_copy_stored(headers, &args, response); #if defined(AST_DEVMODE) code = response->response_code; switch (code) { case 0: /* Implementation is still a stub, or the code wasn't set */ is_valid = response->message == NULL; break; case 500: /* Internal Server Error */ case 501: /* Not Implemented */ case 404: /* Recording not found */ case 409: /* A recording with the same name already exists on the system */ is_valid = 1; break; default: if (200 <= code && code <= 299) { is_valid = ast_ari_validate_stored_recording( response->message); } else { ast_log(LOG_ERROR, "Invalid error response %d for /recordings/stored/{recordingName}/copy\n", code); is_valid = 0; } } if (!is_valid) { ast_log(LOG_ERROR, "Response validation failed for /recordings/stored/{recordingName}/copy\n"); ast_ari_response_error(response, 500, "Internal Server Error", "Response validation failed"); } #endif /* AST_DEVMODE */ fin: __attribute__((unused)) return; }
struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap) { struct ast_unreal_pvt *unreal; static const struct ast_jb_conf jb_conf = { .flags = 0, .max_size = -1, .resync_threshold = -1, .impl = "", .target_extra = -1, }; unreal = ao2_alloc(size, destructor); if (!unreal) { return NULL; } unreal->reqcap = ast_format_cap_dup(cap); if (!unreal->reqcap) { ao2_ref(unreal, -1); return NULL; } memcpy(&unreal->jb_conf, &jb_conf, sizeof(unreal->jb_conf)); return unreal; } struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p, const struct ast_channel_tech *tech, int semi1_state, int semi2_state, const char *exten, const char *context, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, struct ast_callid *callid) { struct ast_channel *owner; struct ast_channel *chan; struct ast_format fmt; struct ast_assigned_ids id1 = {NULL, NULL}; struct ast_assigned_ids id2 = {NULL, NULL}; int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1); /* set unique ids for the two channels */ if (assignedids && !ast_strlen_zero(assignedids->uniqueid)) { id1.uniqueid = assignedids->uniqueid; id2.uniqueid = assignedids->uniqueid2; } /* if id1 given but not id2, use default of id1;2 */ if (id1.uniqueid && ast_strlen_zero(id2.uniqueid)) { char *uniqueid2; uniqueid2 = ast_alloca(strlen(id1.uniqueid) + 2); strcpy(uniqueid2, id1.uniqueid);/* Safe */ strcat(uniqueid2, ";2");/* Safe */ id2.uniqueid = uniqueid2; } /* * Allocate two new Asterisk channels * * Make sure that the ;2 channel gets the same linkedid as ;1. * You can't pass linkedid to both allocations since if linkedid * isn't set, then each channel will generate its own linkedid. */ if (!(owner = ast_channel_alloc(1, semi1_state, NULL, NULL, NULL, exten, context, &id1, requestor, 0, "%s/%s-%08x;1", tech->type, p->name, generated_seqno))) { ast_log(LOG_WARNING, "Unable to allocate owner channel structure\n"); return NULL; } if (callid) { ast_channel_callid_set(owner, callid); } ast_channel_tech_set(owner, tech); ao2_ref(p, +1); ast_channel_tech_pvt_set(owner, p); ast_format_cap_copy(ast_channel_nativeformats(owner), p->reqcap); /* Determine our read/write format and set it on each channel */ ast_best_codec(p->reqcap, &fmt); ast_format_copy(ast_channel_writeformat(owner), &fmt); ast_format_copy(ast_channel_rawwriteformat(owner), &fmt); ast_format_copy(ast_channel_readformat(owner), &fmt); ast_format_copy(ast_channel_rawreadformat(owner), &fmt); ast_set_flag(ast_channel_flags(owner), AST_FLAG_DISABLE_DEVSTATE_CACHE); ast_jb_configure(owner, &p->jb_conf); if (ast_channel_cc_params_init(owner, requestor ? ast_channel_get_cc_config_params((struct ast_channel *) requestor) : NULL)) { ao2_ref(p, -1); ast_channel_unlock(owner); ast_channel_release(owner); return NULL; } p->owner = owner; ast_channel_unlock(owner); if (!(chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL, exten, context, &id2, owner, 0, "%s/%s-%08x;2", tech->type, p->name, generated_seqno))) { ast_log(LOG_WARNING, "Unable to allocate chan channel structure\n"); ao2_ref(p, -1); ast_channel_release(owner); return NULL; } if (callid) { ast_channel_callid_set(chan, callid); } ast_channel_tech_set(chan, tech); ao2_ref(p, +1); ast_channel_tech_pvt_set(chan, p); ast_format_cap_copy(ast_channel_nativeformats(chan), p->reqcap); /* Format was already determined when setting up owner */ ast_format_copy(ast_channel_writeformat(chan), &fmt); ast_format_copy(ast_channel_rawwriteformat(chan), &fmt); ast_format_copy(ast_channel_readformat(chan), &fmt); ast_format_copy(ast_channel_rawreadformat(chan), &fmt); ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE); p->chan = chan; ast_channel_unlock(chan); return owner; }
int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence) { int d = 0; char *fmts; char comment[256]; int x, fmtcnt=1, res=-1,outmsg=0; struct ast_frame *f; struct ast_filestream *others[MAX_OTHER_FORMATS]; struct ast_filestream *realfiles[MAX_OTHER_FORMATS]; char *sfmt[MAX_OTHER_FORMATS]; char *stringp=NULL; time_t start, end; struct ast_dsp *sildet; /* silence detector dsp */ int totalsilence = 0; int dspsilence = 0; int gotsilence = 0; /* did we timeout for silence? */ int rfmt=0; char prependfile[80]; if (silencethreshold < 0) silencethreshold = global_silence_threshold; if (maxsilence < 0) maxsilence = global_maxsilence; /* barf if no pointer passed to store duration in */ if (duration == NULL) { ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n"); return -1; } ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt); snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name); if (playfile || beep) { if (!beep) d = ast_play_and_wait(chan, playfile); if (d > -1) d = ast_streamfile(chan, "beep",chan->language); if (!d) d = ast_waitstream(chan,""); if (d < 0) return -1; } strncpy(prependfile, recordfile, sizeof(prependfile) -1); strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1); fmts = ast_strdupa(fmt); stringp=fmts; strsep(&stringp, "|"); ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts); sfmt[0] = ast_strdupa(fmts); while((fmt = strsep(&stringp, "|"))) { if (fmtcnt > MAX_OTHER_FORMATS - 1) { ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n"); break; } sfmt[fmtcnt++] = ast_strdupa(fmt); } time(&start); end=start; /* pre-initialize end to be same as start in case we never get into loop */ for (x=0; x<fmtcnt; x++) { others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700); ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]); if (!others[x]) { break; } } sildet = ast_dsp_new(); /* Create the silence detector */ if (!sildet) { ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } ast_dsp_set_threshold(sildet, silencethreshold); if (maxsilence > 0) { rfmt = chan->readformat; res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); return -1; } } if (x == fmtcnt) { /* Loop forever, writing the packets we read to the writer(s), until we read a # or get a hangup */ f = NULL; for(;;) { res = ast_waitfor(chan, 2000); if (!res) { ast_log(LOG_DEBUG, "One waitfor failed, trying another\n"); /* Try one more time in case of masq */ res = ast_waitfor(chan, 2000); if (!res) { ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name); res = -1; } } if (res < 0) { f = NULL; break; } f = ast_read(chan); if (!f) break; if (f->frametype == AST_FRAME_VOICE) { /* write each format */ for (x=0; x<fmtcnt; x++) { if (!others[x]) break; res = ast_writestream(others[x], f); } /* Silence Detection */ if (maxsilence > 0) { dspsilence = 0; ast_dsp_silence(sildet, f, &dspsilence); if (dspsilence) totalsilence = dspsilence; else totalsilence = 0; if (totalsilence > maxsilence) { /* Ended happily with silence */ if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000); ast_frfree(f); gotsilence = 1; outmsg=2; break; } } /* Exit on any error */ if (res) { ast_log(LOG_WARNING, "Error writing frame\n"); ast_frfree(f); break; } } else if (f->frametype == AST_FRAME_VIDEO) { /* Write only once */ ast_writestream(others[0], f); } else if (f->frametype == AST_FRAME_DTMF) { /* stop recording with any digit */ if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass); res = 't'; outmsg = 2; ast_frfree(f); break; } if (maxtime) { time(&end); if (maxtime < (end - start)) { if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n"); res = 't'; outmsg=2; ast_frfree(f); break; } } ast_frfree(f); } if (end == start) time(&end); if (!f) { if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "User hung up\n"); res = -1; outmsg=1; #if 0 /* delete all the prepend files */ for (x=0; x<fmtcnt; x++) { if (!others[x]) break; ast_closestream(others[x]); ast_filedelete(prependfile, sfmt[x]); } #endif } } else { ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]); } *duration = end - start; #if 0 if (outmsg > 1) { #else if (outmsg) { #endif struct ast_frame *fr; for (x=0; x<fmtcnt; x++) { snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]); realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0); if (!others[x] || !realfiles[x]) break; if (totalsilence) ast_stream_rewind(others[x], totalsilence-200); else ast_stream_rewind(others[x], 200); ast_truncstream(others[x]); /* add the original file too */ while ((fr = ast_readframe(realfiles[x]))) { ast_writestream(others[x],fr); } ast_closestream(others[x]); ast_closestream(realfiles[x]); ast_filerename(prependfile, recordfile, sfmt[x]); #if 0 ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile); #endif ast_filedelete(prependfile, sfmt[x]); } } if (rfmt) { if (ast_set_read_format(chan, rfmt)) { ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name); } } if (outmsg) { if (outmsg > 1) { /* Let them know it worked */ ast_streamfile(chan, "auth-thankyou", chan->language); ast_waitstream(chan, ""); } } return res; } int ast_lock_path(const char *path) { char *s; char *fs; int res; int fd; time_t start; s = alloca(strlen(path) + 10); fs = alloca(strlen(path) + 20); if (!fs || !s) { ast_log(LOG_WARNING, "Out of memory!\n"); return -1; } snprintf(fs, strlen(path) + 19, "%s/%s-%08x", path, ".lock", rand()); fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600); if (fd < 0) { fprintf(stderr, "Unable to create lock file: %s\n", strerror(errno)); return -1; } close(fd); snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock"); time(&start); while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5)) usleep(1); if (res < 0) { ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno)); } unlink(fs); ast_log(LOG_DEBUG, "Locked path '%s'\n", path); return res; }