Mon Sep 20 2010 00:19:40

Asterisk developer's documentation


app.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Convenient Application Routines
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  */
00025 
00026 #include "asterisk.h"
00027 
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 260303 $")
00029 
00030 #ifdef HAVE_SYS_STAT_H
00031 #include <sys/stat.h>
00032 #endif
00033 #include <regex.h>
00034 #include <sys/file.h> /* added this to allow to compile, sorry! */
00035 #include <signal.h>
00036 #include <sys/time.h>       /* for getrlimit(2) */
00037 #include <sys/resource.h>   /* for getrlimit(2) */
00038 #include <stdlib.h>         /* for closefrom(3) */
00039 #ifndef HAVE_CLOSEFROM
00040 #include <sys/types.h>
00041 #include <dirent.h>         /* for opendir(3)   */
00042 #endif
00043 #ifdef HAVE_CAP
00044 #include <sys/capability.h>
00045 #endif /* HAVE_CAP */
00046 
00047 #include "asterisk/paths.h"   /* use ast_config_AST_DATA_DIR */
00048 #include "asterisk/channel.h"
00049 #include "asterisk/pbx.h"
00050 #include "asterisk/file.h"
00051 #include "asterisk/app.h"
00052 #include "asterisk/dsp.h"
00053 #include "asterisk/utils.h"
00054 #include "asterisk/lock.h"
00055 #include "asterisk/indications.h"
00056 #include "asterisk/linkedlists.h"
00057 #include "asterisk/threadstorage.h"
00058 
00059 AST_THREADSTORAGE_PUBLIC(ast_str_thread_global_buf);
00060 
00061 
00062 #define AST_MAX_FORMATS 10
00063 
00064 static AST_RWLIST_HEAD_STATIC(groups, ast_group_info);
00065 
00066 /*!
00067  * \brief This function presents a dialtone and reads an extension into 'collect'
00068  * which must be a pointer to a **pre-initialized** array of char having a
00069  * size of 'size' suitable for writing to.  It will collect no more than the smaller
00070  * of 'maxlen' or 'size' minus the original strlen() of collect digits.
00071  * \param chan struct.
00072  * \param context
00073  * \param collect
00074  * \param size
00075  * \param maxlen
00076  * \param timeout timeout in seconds
00077  *
00078  * \return 0 if extension does not exist, 1 if extension exists
00079 */
00080 int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout)
00081 {
00082    struct ast_tone_zone_sound *ts;
00083    int res = 0, x = 0;
00084 
00085    if (maxlen > size) {
00086       maxlen = size;
00087    }
00088 
00089    if (!timeout && chan->pbx) {
00090       timeout = chan->pbx->dtimeoutms / 1000.0;
00091    } else if (!timeout) {
00092       timeout = 5;
00093    }
00094 
00095    if ((ts = ast_get_indication_tone(chan->zone, "dial"))) {
00096       res = ast_playtones_start(chan, 0, ts->data, 0);
00097       ts = ast_tone_zone_sound_unref(ts);
00098    } else {
00099       ast_log(LOG_NOTICE, "Huh....? no dial for indications?\n");
00100    }
00101 
00102    for (x = strlen(collect); x < maxlen; ) {
00103       res = ast_waitfordigit(chan, timeout);
00104       if (!ast_ignore_pattern(context, collect)) {
00105          ast_playtones_stop(chan);
00106       }
00107       if (res < 1) {
00108          break;
00109       }
00110       if (res == '#') {
00111          break;
00112       }
00113       collect[x++] = res;
00114       if (!ast_matchmore_extension(chan, context, collect, 1, chan->cid.cid_num)) {
00115          break;
00116       }
00117    }
00118 
00119    if (res >= 0) {
00120       res = ast_exists_extension(chan, context, collect, 1, chan->cid.cid_num) ? 1 : 0;
00121    }
00122 
00123    return res;
00124 }
00125 
00126 /*!
00127  * \brief ast_app_getdata
00128  * \param c The channel to read from
00129  * \param prompt The file to stream to the channel
00130  * \param s The string to read in to.  Must be at least the size of your length
00131  * \param maxlen How many digits to read (maximum)
00132  * \param timeout set timeout to 0 for "standard" timeouts. Set timeout to -1 for 
00133  *      "ludicrous time" (essentially never times out) */
00134 enum ast_getdata_result ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)
00135 {
00136    int res = 0, to, fto;
00137    char *front, *filename;
00138 
00139    /* XXX Merge with full version? XXX */
00140 
00141    if (maxlen)
00142       s[0] = '\0';
00143 
00144    if (!prompt)
00145       prompt = "";
00146 
00147    filename = ast_strdupa(prompt);
00148    while ((front = strsep(&filename, "&"))) {
00149       if (!ast_strlen_zero(front)) {
00150          res = ast_streamfile(c, front, c->language);
00151          if (res)
00152             continue;
00153       }
00154       if (ast_strlen_zero(filename)) {
00155          /* set timeouts for the last prompt */
00156          fto = c->pbx ? c->pbx->rtimeoutms : 6000;
00157          to = c->pbx ? c->pbx->dtimeoutms : 2000;
00158 
00159          if (timeout > 0) {
00160             fto = to = timeout;
00161          }
00162          if (timeout < 0) {
00163             fto = to = 1000000000;
00164          }
00165       } else {
00166          /* there is more than one prompt, so
00167           * get rid of the long timeout between
00168           * prompts, and make it 50ms */
00169          fto = 50;
00170          to = c->pbx ? c->pbx->dtimeoutms : 2000;
00171       }
00172       res = ast_readstring(c, s, maxlen, to, fto, "#");
00173       if (res == AST_GETDATA_EMPTY_END_TERMINATED) {
00174          return res;
00175       }
00176       if (!ast_strlen_zero(s)) {
00177          return res;
00178       }
00179    }
00180 
00181    return res;
00182 }
00183 
00184 /* The lock type used by ast_lock_path() / ast_unlock_path() */
00185 static enum AST_LOCK_TYPE ast_lock_type = AST_LOCK_TYPE_LOCKFILE;
00186 
00187 int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
00188 {
00189    int res, to = 2000, fto = 6000;
00190 
00191    if (!ast_strlen_zero(prompt)) {
00192       res = ast_streamfile(c, prompt, c->language);
00193       if (res < 0) {
00194          return res;
00195       }
00196    }
00197 
00198    if (timeout > 0) {
00199       fto = to = timeout;
00200    }
00201    if (timeout < 0) {
00202       fto = to = 1000000000;
00203    }
00204 
00205    res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
00206 
00207    return res;
00208 }
00209 
00210 static int (*ast_has_voicemail_func)(const char *mailbox, const char *folder) = NULL;
00211 static int (*ast_inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs) = NULL;
00212 static int (*ast_inboxcount2_func)(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs) = NULL;
00213 static int (*ast_sayname_func)(struct ast_channel *chan, const char *mailbox, const char *context) = NULL;
00214 static int (*ast_messagecount_func)(const char *context, const char *mailbox, const char *folder) = NULL;
00215 
00216 void ast_install_vm_functions(int (*has_voicemail_func)(const char *mailbox, const char *folder),
00217                int (*inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs),
00218                int (*inboxcount2_func)(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs),
00219                int (*messagecount_func)(const char *context, const char *mailbox, const char *folder),
00220                int (*sayname_func)(struct ast_channel *chan, const char *mailbox, const char *context))
00221 {
00222    ast_has_voicemail_func = has_voicemail_func;
00223    ast_inboxcount_func = inboxcount_func;
00224    ast_inboxcount2_func = inboxcount2_func;
00225    ast_messagecount_func = messagecount_func;
00226    ast_sayname_func = sayname_func;
00227 }
00228 
00229 void ast_uninstall_vm_functions(void)
00230 {
00231    ast_has_voicemail_func = NULL;
00232    ast_inboxcount_func = NULL;
00233    ast_inboxcount2_func = NULL;
00234    ast_messagecount_func = NULL;
00235    ast_sayname_func = NULL;
00236 }
00237 
00238 int ast_app_has_voicemail(const char *mailbox, const char *folder)
00239 {
00240    static int warned = 0;
00241    if (ast_has_voicemail_func) {
00242       return ast_has_voicemail_func(mailbox, folder);
00243    }
00244 
00245    if (warned++ % 10 == 0) {
00246       ast_verb(3, "Message check requested for mailbox %s/folder %s but voicemail not loaded.\n", mailbox, folder ? folder : "INBOX");
00247    }
00248    return 0;
00249 }
00250 
00251 
00252 int ast_app_inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
00253 {
00254    static int warned = 0;
00255    if (newmsgs) {
00256       *newmsgs = 0;
00257    }
00258    if (oldmsgs) {
00259       *oldmsgs = 0;
00260    }
00261    if (ast_inboxcount_func) {
00262       return ast_inboxcount_func(mailbox, newmsgs, oldmsgs);
00263    }
00264 
00265    if (warned++ % 10 == 0) {
00266       ast_verb(3, "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
00267    }
00268 
00269    return 0;
00270 }
00271 
00272 int ast_app_inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
00273 {
00274    static int warned = 0;
00275    if (newmsgs) {
00276       *newmsgs = 0;
00277    }
00278    if (oldmsgs) {
00279       *oldmsgs = 0;
00280    }
00281    if (urgentmsgs) {
00282       *urgentmsgs = 0;
00283    }
00284    if (ast_inboxcount_func) {
00285       return ast_inboxcount2_func(mailbox, urgentmsgs, newmsgs, oldmsgs);
00286    }
00287 
00288    if (warned++ % 10 == 0) {
00289       ast_verb(3, "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
00290    }
00291 
00292    return 0;
00293 }
00294 
00295 int ast_app_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
00296 {
00297    if (ast_sayname_func) {
00298       return ast_sayname_func(chan, mailbox, context);
00299    }
00300    return -1;
00301 }
00302 
00303 int ast_app_messagecount(const char *context, const char *mailbox, const char *folder)
00304 {
00305    static int warned = 0;
00306    if (ast_messagecount_func) {
00307       return ast_messagecount_func(context, mailbox, folder);
00308    }
00309 
00310    if (!warned) {
00311       warned++;
00312       ast_verb(3, "Message count requested for mailbox %s@%s/%s but voicemail not loaded.\n", mailbox, context, folder);
00313    }
00314 
00315    return 0;
00316 }
00317 
00318 int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration) 
00319 {
00320    const char *ptr;
00321    int res = 0;
00322    struct ast_silence_generator *silgen = NULL;
00323 
00324    if (!between) {
00325       between = 100;
00326    }
00327 
00328    if (peer) {
00329       res = ast_autoservice_start(peer);
00330    }
00331 
00332    if (!res) {
00333       res = ast_waitfor(chan, 100);
00334    }
00335 
00336    /* ast_waitfor will return the number of remaining ms on success */
00337    if (res < 0) {
00338       if (peer) {
00339          ast_autoservice_stop(peer);
00340       }
00341       return res;
00342    }
00343 
00344    if (ast_opt_transmit_silence) {
00345       silgen = ast_channel_start_silence_generator(chan);
00346    }
00347 
00348    for (ptr = digits; *ptr; ptr++) {
00349       if (*ptr == 'w') {
00350          /* 'w' -- wait half a second */
00351          if ((res = ast_safe_sleep(chan, 500))) {
00352             break;
00353          }
00354       } else if (strchr("0123456789*#abcdfABCDF", *ptr)) {
00355          /* Character represents valid DTMF */
00356          if (*ptr == 'f' || *ptr == 'F') {
00357             /* ignore return values if not supported by channel */
00358             ast_indicate(chan, AST_CONTROL_FLASH);
00359          } else {
00360             ast_senddigit(chan, *ptr, duration);
00361          }
00362          /* pause between digits */
00363          if ((res = ast_safe_sleep(chan, between))) {
00364             break;
00365          }
00366       } else {
00367          ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n", *ptr);
00368       }
00369    }
00370 
00371    if (peer) {
00372       /* Stop autoservice on the peer channel, but don't overwrite any error condition
00373          that has occurred previously while acting on the primary channel */
00374       if (ast_autoservice_stop(peer) && !res) {
00375          res = -1;
00376       }
00377    }
00378 
00379    if (silgen) {
00380       ast_channel_stop_silence_generator(chan, silgen);
00381    }
00382 
00383    return res;
00384 }
00385 
00386 struct linear_state {
00387    int fd;
00388    int autoclose;
00389    int allowoverride;
00390    int origwfmt;
00391 };
00392 
00393 static void linear_release(struct ast_channel *chan, void *params)
00394 {
00395    struct linear_state *ls = params;
00396 
00397    if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt)) {
00398       ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, ls->origwfmt);
00399    }
00400 
00401    if (ls->autoclose) {
00402       close(ls->fd);
00403    }
00404 
00405    ast_free(params);
00406 }
00407 
00408 static int linear_generator(struct ast_channel *chan, void *data, int len, int samples)
00409 {
00410    short buf[2048 + AST_FRIENDLY_OFFSET / 2];
00411    struct linear_state *ls = data;
00412    struct ast_frame f = {
00413       .frametype = AST_FRAME_VOICE,
00414       .subclass = AST_FORMAT_SLINEAR,
00415       .data.ptr = buf + AST_FRIENDLY_OFFSET / 2,
00416       .offset = AST_FRIENDLY_OFFSET,
00417    };
00418    int res;
00419 
00420    len = samples * 2;
00421    if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
00422       ast_log(LOG_WARNING, "Can't generate %d bytes of data!\n" , len);
00423       len = sizeof(buf) - AST_FRIENDLY_OFFSET;
00424    }
00425    res = read(ls->fd, buf + AST_FRIENDLY_OFFSET/2, len);
00426    if (res > 0) {
00427       f.datalen = res;
00428       f.samples = res / 2;
00429       ast_write(chan, &f);
00430       if (res == len) {
00431          return 0;
00432       }
00433    }
00434    return -1;
00435 }
00436 
00437 static void *linear_alloc(struct ast_channel *chan, void *params)
00438 {
00439    struct linear_state *ls = params;
00440 
00441    if (!params) {
00442       return NULL;
00443    }
00444 
00445    /* In this case, params is already malloc'd */
00446    if (ls->allowoverride) {
00447       ast_set_flag(chan, AST_FLAG_WRITE_INT);
00448    } else {
00449       ast_clear_flag(chan, AST_FLAG_WRITE_INT);
00450    }
00451 
00452    ls->origwfmt = chan->writeformat;
00453 
00454    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
00455       ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
00456       ast_free(ls);
00457       ls = params = NULL;
00458    }
00459 
00460    return params;
00461 }
00462 
00463 static struct ast_generator linearstream =
00464 {
00465    alloc: linear_alloc,
00466    release: linear_release,
00467    generate: linear_generator,
00468 };
00469 
00470 int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride)
00471 {
00472    struct linear_state *lin;
00473    char tmpf[256];
00474    int res = -1;
00475    int autoclose = 0;
00476    if (fd < 0) {
00477       if (ast_strlen_zero(filename)) {
00478          return -1;
00479       }
00480       autoclose = 1;
00481       if (filename[0] == '/') {
00482          ast_copy_string(tmpf, filename, sizeof(tmpf));
00483       } else {
00484          snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", ast_config_AST_DATA_DIR, "sounds", filename);
00485       }
00486       if ((fd = open(tmpf, O_RDONLY)) < 0) {
00487          ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", tmpf, strerror(errno));
00488          return -1;
00489       }
00490    }
00491    if ((lin = ast_calloc(1, sizeof(*lin)))) {
00492       lin->fd = fd;
00493       lin->allowoverride = allowoverride;
00494       lin->autoclose = autoclose;
00495       res = ast_activate_generator(chan, &linearstream, lin);
00496    }
00497    return res;
00498 }
00499 
00500 int ast_control_streamfile(struct ast_channel *chan, const char *file,
00501             const char *fwd, const char *rev,
00502             const char *stop, const char *suspend,
00503             const char *restart, int skipms, long *offsetms)
00504 {
00505    char *breaks = NULL;
00506    char *end = NULL;
00507    int blen = 2;
00508    int res;
00509    long pause_restart_point = 0;
00510    long offset = 0;
00511 
00512    if (offsetms) {
00513       offset = *offsetms * 8; /* XXX Assumes 8kHz */
00514    }
00515 
00516    if (stop) {
00517       blen += strlen(stop);
00518    }
00519    if (suspend) {
00520       blen += strlen(suspend);
00521    }
00522    if (restart) {
00523       blen += strlen(restart);
00524    }
00525 
00526    if (blen > 2) {
00527       breaks = alloca(blen + 1);
00528       breaks[0] = '\0';
00529       if (stop) {
00530          strcat(breaks, stop);
00531       }
00532       if (suspend) {
00533          strcat(breaks, suspend);
00534       }
00535       if (restart) {
00536          strcat(breaks, restart);
00537       }
00538    }
00539    if (chan->_state != AST_STATE_UP) {
00540       res = ast_answer(chan);
00541    }
00542 
00543    if (file) {
00544       if ((end = strchr(file, ':'))) {
00545          if (!strcasecmp(end, ":end")) {
00546             *end = '\0';
00547             end++;
00548          }
00549       }
00550    }
00551 
00552    for (;;) {
00553       ast_stopstream(chan);
00554       res = ast_streamfile(chan, file, chan->language);
00555       if (!res) {
00556          if (pause_restart_point) {
00557             ast_seekstream(chan->stream, pause_restart_point, SEEK_SET);
00558             pause_restart_point = 0;
00559          }
00560          else if (end || offset < 0) {
00561             if (offset == -8) {
00562                offset = 0;
00563             }
00564             ast_verb(3, "ControlPlayback seek to offset %ld from end\n", offset);
00565 
00566             ast_seekstream(chan->stream, offset, SEEK_END);
00567             end = NULL;
00568             offset = 0;
00569          } else if (offset) {
00570             ast_verb(3, "ControlPlayback seek to offset %ld\n", offset);
00571             ast_seekstream(chan->stream, offset, SEEK_SET);
00572             offset = 0;
00573          }
00574          res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
00575       }
00576 
00577       if (res < 1) {
00578          break;
00579       }
00580 
00581       /* We go at next loop if we got the restart char */
00582       if (restart && strchr(restart, res)) {
00583          ast_debug(1, "we'll restart the stream here at next loop\n");
00584          pause_restart_point = 0;
00585          continue;
00586       }
00587 
00588       if (suspend && strchr(suspend, res)) {
00589          pause_restart_point = ast_tellstream(chan->stream);
00590          for (;;) {
00591             ast_stopstream(chan);
00592             if (!(res = ast_waitfordigit(chan, 1000))) {
00593                continue;
00594             } else if (res == -1 || strchr(suspend, res) || (stop && strchr(stop, res))) {
00595                break;
00596             }
00597          }
00598          if (res == *suspend) {
00599             res = 0;
00600             continue;
00601          }
00602       }
00603 
00604       if (res == -1) {
00605          break;
00606       }
00607 
00608       /* if we get one of our stop chars, return it to the calling function */
00609       if (stop && strchr(stop, res)) {
00610          break;
00611       }
00612    }
00613 
00614    if (pause_restart_point) {
00615       offset = pause_restart_point;
00616    } else {
00617       if (chan->stream) {
00618          offset = ast_tellstream(chan->stream);
00619       } else {
00620          offset = -8;  /* indicate end of file */
00621       }
00622    }
00623 
00624    if (offsetms) {
00625       *offsetms = offset / 8; /* samples --> ms ... XXX Assumes 8 kHz */
00626    }
00627 
00628    /* If we are returning a digit cast it as char */
00629    if (res > 0 || chan->stream) {
00630       res = (char)res;
00631    }
00632 
00633    ast_stopstream(chan);
00634 
00635    return res;
00636 }
00637 
00638 int ast_play_and_wait(struct ast_channel *chan, const char *fn)
00639 {
00640    int d = 0;
00641 
00642    if ((d = ast_streamfile(chan, fn, chan->language))) {
00643       return d;
00644    }
00645 
00646    d = ast_waitstream(chan, AST_DIGIT_ANY);
00647 
00648    ast_stopstream(chan);
00649 
00650    return d;
00651 }
00652 
00653 static int global_silence_threshold = 128;
00654 static int global_maxsilence = 0;
00655 
00656 /*! Optionally play a sound file or a beep, then record audio and video from the channel.
00657  * \param chan Channel to playback to/record from.
00658  * \param playfile Filename of sound to play before recording begins.
00659  * \param recordfile Filename to record to.
00660  * \param maxtime Maximum length of recording (in milliseconds).
00661  * \param fmt Format(s) to record message in. Multiple formats may be specified by separating them with a '|'.
00662  * \param duration Where to store actual length of the recorded message (in milliseconds).
00663  * \param beep Whether to play a beep before starting to record.
00664  * \param silencethreshold
00665  * \param maxsilence Length of silence that will end a recording (in milliseconds).
00666  * \param path Optional filesystem path to unlock.
00667  * \param prepend If true, prepend the recorded audio to an existing file.
00668  * \param acceptdtmf DTMF digits that will end the recording.
00669  * \param canceldtmf DTMF digits that will cancel the recording.
00670  */
00671 
00672 static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int beep, int silencethreshold, int maxsilence, const char *path, int prepend, const char *acceptdtmf, const char *canceldtmf)
00673 {
00674    int d = 0;
00675    char *fmts;
00676    char comment[256];
00677    int x, fmtcnt = 1, res = -1, outmsg = 0;
00678    struct ast_filestream *others[AST_MAX_FORMATS];
00679    char *sfmt[AST_MAX_FORMATS];
00680    char *stringp = NULL;
00681    time_t start, end;
00682    struct ast_dsp *sildet = NULL;   /* silence detector dsp */
00683    int totalsilence = 0;
00684    int rfmt = 0;
00685    struct ast_silence_generator *silgen = NULL;
00686    char prependfile[80];
00687 
00688    if (silencethreshold < 0) {
00689       silencethreshold = global_silence_threshold;
00690    }
00691 
00692    if (maxsilence < 0) {
00693       maxsilence = global_maxsilence;
00694    }
00695 
00696    /* barf if no pointer passed to store duration in */
00697    if (!duration) {
00698       ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
00699       return -1;
00700    }
00701 
00702    ast_debug(1, "play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
00703    snprintf(comment, sizeof(comment), "Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
00704 
00705    if (playfile || beep) {
00706       if (!beep) {
00707          d = ast_play_and_wait(chan, playfile);
00708       }
00709       if (d > -1) {
00710          d = ast_stream_and_wait(chan, "beep", "");
00711       }
00712       if (d < 0) {
00713          return -1;
00714       }
00715    }
00716 
00717    if (prepend) {
00718       ast_copy_string(prependfile, recordfile, sizeof(prependfile));
00719       strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
00720    }
00721 
00722    fmts = ast_strdupa(fmt);
00723 
00724    stringp = fmts;
00725    strsep(&stringp, "|");
00726    ast_debug(1, "Recording Formats: sfmts=%s\n", fmts);
00727    sfmt[0] = ast_strdupa(fmts);
00728 
00729    while ((fmt = strsep(&stringp, "|"))) {
00730       if (fmtcnt > AST_MAX_FORMATS - 1) {
00731          ast_log(LOG_WARNING, "Please increase AST_MAX_FORMATS in file.h\n");
00732          break;
00733       }
00734       sfmt[fmtcnt++] = ast_strdupa(fmt);
00735    }
00736 
00737    end = start = time(NULL);  /* pre-initialize end to be same as start in case we never get into loop */
00738    for (x = 0; x < fmtcnt; x++) {
00739       others[x] = ast_writefile(prepend ? prependfile : recordfile, sfmt[x], comment, O_TRUNC, 0, AST_FILE_MODE);
00740       ast_verb(3, "x=%d, open writing:  %s format: %s, %p\n", x, prepend ? prependfile : recordfile, sfmt[x], others[x]);
00741 
00742       if (!others[x]) {
00743          break;
00744       }
00745    }
00746 
00747    if (path) {
00748       ast_unlock_path(path);
00749    }
00750 
00751    if (maxsilence > 0) {
00752       sildet = ast_dsp_new(); /* Create the silence detector */
00753       if (!sildet) {
00754          ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00755          return -1;
00756       }
00757       ast_dsp_set_threshold(sildet, silencethreshold);
00758       rfmt = chan->readformat;
00759       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00760       if (res < 0) {
00761          ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00762          ast_dsp_free(sildet);
00763          return -1;
00764       }
00765    }
00766 
00767    if (!prepend) {
00768       /* Request a video update */
00769       ast_indicate(chan, AST_CONTROL_VIDUPDATE);
00770 
00771       if (ast_opt_transmit_silence) {
00772          silgen = ast_channel_start_silence_generator(chan);
00773       }
00774    }
00775 
00776    if (x == fmtcnt) {
00777       /* Loop forever, writing the packets we read to the writer(s), until
00778          we read a digit or get a hangup */
00779       struct ast_frame *f;
00780       for (;;) {
00781          if (!(res = ast_waitfor(chan, 2000))) {
00782             ast_debug(1, "One waitfor failed, trying another\n");
00783             /* Try one more time in case of masq */
00784             if (!(res = ast_waitfor(chan, 2000))) {
00785                ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
00786                res = -1;
00787             }
00788          }
00789 
00790          if (res < 0) {
00791             f = NULL;
00792             break;
00793          }
00794          if (!(f = ast_read(chan))) {
00795             break;
00796          }
00797          if (f->frametype == AST_FRAME_VOICE) {
00798             /* write each format */
00799             for (x = 0; x < fmtcnt; x++) {
00800                if (prepend && !others[x]) {
00801                   break;
00802                }
00803                res = ast_writestream(others[x], f);
00804             }
00805 
00806             /* Silence Detection */
00807             if (maxsilence > 0) {
00808                int dspsilence = 0;
00809                ast_dsp_silence(sildet, f, &dspsilence);
00810                if (dspsilence) {
00811                   totalsilence = dspsilence;
00812                } else {
00813                   totalsilence = 0;
00814                }
00815 
00816                if (totalsilence > maxsilence) {
00817                   /* Ended happily with silence */
00818                   ast_verb(3, "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
00819                   res = 'S';
00820                   outmsg = 2;
00821                   break;
00822                }
00823             }
00824             /* Exit on any error */
00825             if (res) {
00826                ast_log(LOG_WARNING, "Error writing frame\n");
00827                break;
00828             }
00829          } else if (f->frametype == AST_FRAME_VIDEO) {
00830             /* Write only once */
00831             ast_writestream(others[0], f);
00832          } else if (f->frametype == AST_FRAME_DTMF) {
00833             if (prepend) {
00834             /* stop recording with any digit */
00835                ast_verb(3, "User ended message by pressing %c\n", f->subclass);
00836                res = 't';
00837                outmsg = 2;
00838                break;
00839             }
00840             if (strchr(acceptdtmf, f->subclass)) {
00841                ast_verb(3, "User ended message by pressing %c\n", f->subclass);
00842                res = f->subclass;
00843                outmsg = 2;
00844                break;
00845             }
00846             if (strchr(canceldtmf, f->subclass)) {
00847                ast_verb(3, "User cancelled message by pressing %c\n", f->subclass);
00848                res = f->subclass;
00849                outmsg = 0;
00850                break;
00851             }
00852          }
00853          if (maxtime) {
00854             end = time(NULL);
00855             if (maxtime < (end - start)) {
00856                ast_verb(3, "Took too long, cutting it short...\n");
00857                res = 't';
00858                outmsg = 2;
00859                break;
00860             }
00861          }
00862          ast_frfree(f);
00863       }
00864       if (!f) {
00865          ast_verb(3, "User hung up\n");
00866          res = -1;
00867          outmsg = 1;
00868       } else {
00869          ast_frfree(f);
00870       }
00871    } else {
00872       ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
00873    }
00874 
00875    if (!prepend) {
00876       if (silgen) {
00877          ast_channel_stop_silence_generator(chan, silgen);
00878       }
00879    }
00880 
00881    /*!\note
00882     * Instead of asking how much time passed (end - start), calculate the number
00883     * of seconds of audio which actually went into the file.  This fixes a
00884     * problem where audio is stopped up on the network and never gets to us.
00885     *
00886     * Note that we still want to use the number of seconds passed for the max
00887     * message, otherwise we could get a situation where this stream is never
00888     * closed (which would create a resource leak).
00889     */
00890    *duration = others[0] ? ast_tellstream(others[0]) / 8000 : 0;
00891 
00892    if (!prepend) {
00893       for (x = 0; x < fmtcnt; x++) {
00894          if (!others[x]) {
00895             break;
00896          }
00897          /*!\note
00898           * If we ended with silence, trim all but the first 200ms of silence
00899           * off the recording.  However, if we ended with '#', we don't want
00900           * to trim ANY part of the recording.
00901           */
00902          if (res > 0 && totalsilence) {
00903             ast_stream_rewind(others[x], totalsilence - 200);
00904             /* Reduce duration by a corresponding amount */
00905             if (x == 0 && *duration) {
00906                *duration -= (totalsilence - 200) / 1000;
00907                if (*duration < 0) {
00908                   *duration = 0;
00909                }
00910             }
00911          }
00912          ast_truncstream(others[x]);
00913          ast_closestream(others[x]);
00914       }
00915    }
00916 
00917    if (prepend && outmsg) {
00918       struct ast_filestream *realfiles[AST_MAX_FORMATS];
00919       struct ast_frame *fr;
00920 
00921       for (x = 0; x < fmtcnt; x++) {
00922          snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
00923          realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
00924          if (!others[x] || !realfiles[x]) {
00925             break;
00926          }
00927          /*!\note Same logic as above. */
00928          if (totalsilence) {
00929             ast_stream_rewind(others[x], totalsilence - 200);
00930          }
00931          ast_truncstream(others[x]);
00932          /* add the original file too */
00933          while ((fr = ast_readframe(realfiles[x]))) {
00934             ast_writestream(others[x], fr);
00935             ast_frfree(fr);
00936          }
00937          ast_closestream(others[x]);
00938          ast_closestream(realfiles[x]);
00939          ast_filerename(prependfile, recordfile, sfmt[x]);
00940          ast_verb(4, "Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x], prependfile, recordfile);
00941          ast_filedelete(prependfile, sfmt[x]);
00942       }
00943    }
00944    if (rfmt && ast_set_read_format(chan, rfmt)) {
00945       ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
00946    }
00947    if (outmsg == 2) {
00948       ast_stream_and_wait(chan, "auth-thankyou", "");
00949    }
00950    if (sildet) {
00951       ast_dsp_free(sildet);
00952    }
00953    return res;
00954 }
00955 
00956 static char default_acceptdtmf[] = "#";
00957 static char default_canceldtmf[] = "";
00958 
00959 int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf)
00960 {
00961    return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, 0, silencethreshold, maxsilence, path, 0, S_OR(acceptdtmf, default_acceptdtmf), S_OR(canceldtmf, default_canceldtmf));
00962 }
00963 
00964 int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path)
00965 {
00966    return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, 0, silencethreshold, maxsilence, path, 0, default_acceptdtmf, default_canceldtmf);
00967 }
00968 
00969 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)
00970 {
00971    return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, beep, silencethreshold, maxsilence, NULL, 1, default_acceptdtmf, default_canceldtmf);
00972 }
00973 
00974 /* Channel group core functions */
00975 
00976 int ast_app_group_split_group(const char *data, char *group, int group_max, char *category, int category_max)
00977 {
00978    int res = 0;
00979    char tmp[256];
00980    char *grp = NULL, *cat = NULL;
00981 
00982    if (!ast_strlen_zero(data)) {
00983       ast_copy_string(tmp, data, sizeof(tmp));
00984       grp = tmp;
00985       if ((cat = strchr(tmp, '@'))) {
00986          *cat++ = '\0';
00987       }
00988    }
00989 
00990    if (!ast_strlen_zero(grp)) {
00991       ast_copy_string(group, grp, group_max);
00992    } else {
00993       *group = '\0';
00994    }
00995 
00996    if (!ast_strlen_zero(cat)) {
00997       ast_copy_string(category, cat, category_max);
00998    }
00999 
01000    return res;
01001 }
01002 
01003 int ast_app_group_set_channel(struct ast_channel *chan, const char *data)
01004 {
01005    int res = 0;
01006    char group[80] = "", category[80] = "";
01007    struct ast_group_info *gi = NULL;
01008    size_t len = 0;
01009 
01010    if (ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category))) {
01011       return -1;
01012    }
01013 
01014    /* Calculate memory we will need if this is new */
01015    len = sizeof(*gi) + strlen(group) + 1;
01016    if (!ast_strlen_zero(category)) {
01017       len += strlen(category) + 1;
01018    }
01019 
01020    AST_RWLIST_WRLOCK(&groups);
01021    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&groups, gi, group_list) {
01022       if ((gi->chan == chan) && ((ast_strlen_zero(category) && ast_strlen_zero(gi->category)) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) {
01023          AST_RWLIST_REMOVE_CURRENT(group_list);
01024          free(gi);
01025          break;
01026       }
01027    }
01028    AST_RWLIST_TRAVERSE_SAFE_END;
01029 
01030    if (ast_strlen_zero(group)) {
01031       /* Enable unsetting the group */
01032    } else if ((gi = calloc(1, len))) {
01033       gi->chan = chan;
01034       gi->group = (char *) gi + sizeof(*gi);
01035       strcpy(gi->group, group);
01036       if (!ast_strlen_zero(category)) {
01037          gi->category = (char *) gi + sizeof(*gi) + strlen(group) + 1;
01038          strcpy(gi->category, category);
01039       }
01040       AST_RWLIST_INSERT_TAIL(&groups, gi, group_list);
01041    } else {
01042       res = -1;
01043    }
01044 
01045    AST_RWLIST_UNLOCK(&groups);
01046 
01047    return res;
01048 }
01049 
01050 int ast_app_group_get_count(const char *group, const char *category)
01051 {
01052    struct ast_group_info *gi = NULL;
01053    int count = 0;
01054 
01055    if (ast_strlen_zero(group)) {
01056       return 0;
01057    }
01058 
01059    AST_RWLIST_RDLOCK(&groups);
01060    AST_RWLIST_TRAVERSE(&groups, gi, group_list) {
01061       if (!strcasecmp(gi->group, group) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) {
01062          count++;
01063       }
01064    }
01065    AST_RWLIST_UNLOCK(&groups);
01066 
01067    return count;
01068 }
01069 
01070 int ast_app_group_match_get_count(const char *groupmatch, const char *category)
01071 {
01072    struct ast_group_info *gi = NULL;
01073    regex_t regexbuf;
01074    int count = 0;
01075 
01076    if (ast_strlen_zero(groupmatch)) {
01077       return 0;
01078    }
01079 
01080    /* if regex compilation fails, return zero matches */
01081    if (regcomp(&regexbuf, groupmatch, REG_EXTENDED | REG_NOSUB)) {
01082       return 0;
01083    }
01084 
01085    AST_RWLIST_RDLOCK(&groups);
01086    AST_RWLIST_TRAVERSE(&groups, gi, group_list) {
01087       if (!regexec(&regexbuf, gi->group, 0, NULL, 0) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) {
01088          count++;
01089       }
01090    }
01091    AST_RWLIST_UNLOCK(&groups);
01092 
01093    regfree(&regexbuf);
01094 
01095    return count;
01096 }
01097 
01098 int ast_app_group_update(struct ast_channel *old, struct ast_channel *new)
01099 {
01100    struct ast_group_info *gi = NULL;
01101 
01102    AST_RWLIST_WRLOCK(&groups);
01103    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&groups, gi, group_list) {
01104       if (gi->chan == old) {
01105          gi->chan = new;
01106       } else if (gi->chan == new) {
01107          AST_RWLIST_REMOVE_CURRENT(group_list);
01108          ast_free(gi);
01109       }
01110    }
01111    AST_RWLIST_TRAVERSE_SAFE_END;
01112    AST_RWLIST_UNLOCK(&groups);
01113 
01114    return 0;
01115 }
01116 
01117 int ast_app_group_discard(struct ast_channel *chan)
01118 {
01119    struct ast_group_info *gi = NULL;
01120 
01121    AST_RWLIST_WRLOCK(&groups);
01122    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&groups, gi, group_list) {
01123       if (gi->chan == chan) {
01124          AST_RWLIST_REMOVE_CURRENT(group_list);
01125          ast_free(gi);
01126       }
01127    }
01128    AST_RWLIST_TRAVERSE_SAFE_END;
01129    AST_RWLIST_UNLOCK(&groups);
01130 
01131    return 0;
01132 }
01133 
01134 int ast_app_group_list_wrlock(void)
01135 {
01136    return AST_RWLIST_WRLOCK(&groups);
01137 }
01138 
01139 int ast_app_group_list_rdlock(void)
01140 {
01141    return AST_RWLIST_RDLOCK(&groups);
01142 }
01143 
01144 struct ast_group_info *ast_app_group_list_head(void)
01145 {
01146    return AST_RWLIST_FIRST(&groups);
01147 }
01148 
01149 int ast_app_group_list_unlock(void)
01150 {
01151    return AST_RWLIST_UNLOCK(&groups);
01152 }
01153 
01154 #undef ast_app_separate_args
01155 unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen);
01156 
01157 unsigned int __ast_app_separate_args(char *buf, char delim, int remove_chars, char **array, int arraylen)
01158 {
01159    int argc;
01160    char *scan, *wasdelim = NULL;
01161    int paren = 0, quote = 0;
01162 
01163    if (!buf || !array || !arraylen) {
01164       return 0;
01165    }
01166 
01167    memset(array, 0, arraylen * sizeof(*array));
01168 
01169    scan = buf;
01170 
01171    for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
01172       array[argc] = scan;
01173       for (; *scan; scan++) {
01174          if (*scan == '(') {
01175             paren++;
01176          } else if (*scan == ')') {
01177             if (paren) {
01178                paren--;
01179             }
01180          } else if (*scan == '"' && delim != '"') {
01181             quote = quote ? 0 : 1;
01182             if (remove_chars) {
01183                /* Remove quote character from argument */
01184                memmove(scan, scan + 1, strlen(scan));
01185                scan--;
01186             }
01187          } else if (*scan == '\\') {
01188             if (remove_chars) {
01189                /* Literal character, don't parse */
01190                memmove(scan, scan + 1, strlen(scan));
01191             } else {
01192                scan++;
01193             }
01194          } else if ((*scan == delim) && !paren && !quote) {
01195             wasdelim = scan;
01196             *scan++ = '\0';
01197             break;
01198          }
01199       }
01200    }
01201 
01202    /* If the last character in the original string was the delimiter, then
01203     * there is one additional argument. */
01204    if (*scan || (scan > buf && (scan - 1) == wasdelim)) {
01205       array[argc++] = scan;
01206    }
01207 
01208    return argc;
01209 }
01210 
01211 /* ABI compatible function */
01212 unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
01213 {
01214    return __ast_app_separate_args(buf, delim, 1, array, arraylen);
01215 }
01216 
01217 static enum AST_LOCK_RESULT ast_lock_path_lockfile(const char *path)
01218 {
01219    char *s;
01220    char *fs;
01221    int res;
01222    int fd;
01223    int lp = strlen(path);
01224    time_t start;
01225 
01226    s = alloca(lp + 10);
01227    fs = alloca(lp + 20);
01228 
01229    snprintf(fs, strlen(path) + 19, "%s/.lock-%08lx", path, ast_random());
01230    fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, AST_FILE_MODE);
01231    if (fd < 0) {
01232       ast_log(LOG_ERROR, "Unable to create lock file '%s': %s\n", path, strerror(errno));
01233       return AST_LOCK_PATH_NOT_FOUND;
01234    }
01235    close(fd);
01236 
01237    snprintf(s, strlen(path) + 9, "%s/.lock", path);
01238    start = time(NULL);
01239    while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5)) {
01240       sched_yield();
01241    }
01242 
01243    unlink(fs);
01244 
01245    if (res) {
01246       ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
01247       return AST_LOCK_TIMEOUT;
01248    } else {
01249       ast_debug(1, "Locked path '%s'\n", path);
01250       return AST_LOCK_SUCCESS;
01251    }
01252 }
01253 
01254 static int ast_unlock_path_lockfile(const char *path)
01255 {
01256    char *s;
01257    int res;
01258 
01259    s = alloca(strlen(path) + 10);
01260 
01261    snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
01262 
01263    if ((res = unlink(s))) {
01264       ast_log(LOG_ERROR, "Could not unlock path '%s': %s\n", path, strerror(errno));
01265    } else {
01266       ast_debug(1, "Unlocked path '%s'\n", path);
01267    }
01268 
01269    return res;
01270 }
01271 
01272 struct path_lock {
01273    AST_LIST_ENTRY(path_lock) le;
01274    int fd;
01275    char *path;
01276 };
01277 
01278 static AST_LIST_HEAD_STATIC(path_lock_list, path_lock);
01279 
01280 static void path_lock_destroy(struct path_lock *obj)
01281 {
01282    if (obj->fd >= 0) {
01283       close(obj->fd);
01284    }
01285    if (obj->path) {
01286       free(obj->path);
01287    }
01288    free(obj);
01289 }
01290 
01291 static enum AST_LOCK_RESULT ast_lock_path_flock(const char *path)
01292 {
01293    char *fs;
01294    int res;
01295    int fd;
01296    time_t start;
01297    struct path_lock *pl;
01298    struct stat st, ost;
01299 
01300    fs = alloca(strlen(path) + 20);
01301 
01302    snprintf(fs, strlen(path) + 19, "%s/lock", path);
01303    if (lstat(fs, &st) == 0) {
01304       if ((st.st_mode & S_IFMT) == S_IFLNK) {
01305          ast_log(LOG_WARNING, "Unable to create lock file "
01306                "'%s': it's already a symbolic link\n",
01307                fs);
01308          return AST_LOCK_FAILURE;
01309       }
01310       if (st.st_nlink > 1) {
01311          ast_log(LOG_WARNING, "Unable to create lock file "
01312                "'%s': %u hard links exist\n",
01313                fs, (unsigned int) st.st_nlink);
01314          return AST_LOCK_FAILURE;
01315       }
01316    }
01317    if ((fd = open(fs, O_WRONLY | O_CREAT, 0600)) < 0) {
01318       ast_log(LOG_WARNING, "Unable to create lock file '%s': %s\n",
01319             fs, strerror(errno));
01320       return AST_LOCK_PATH_NOT_FOUND;
01321    }
01322    if (!(pl = ast_calloc(1, sizeof(*pl)))) {
01323       /* We don't unlink the lock file here, on the possibility that
01324        * someone else created it - better to leave a little mess
01325        * than create a big one by destroying someone else's lock
01326        * and causing something to be corrupted.
01327        */
01328       close(fd);
01329       return AST_LOCK_FAILURE;
01330    }
01331    pl->fd = fd;
01332    pl->path = strdup(path);
01333 
01334    time(&start);
01335    while (
01336       #ifdef SOLARIS
01337       ((res = fcntl(pl->fd, F_SETLK, fcntl(pl->fd, F_GETFL) | O_NONBLOCK)) < 0) &&
01338       #else
01339       ((res = flock(pl->fd, LOCK_EX | LOCK_NB)) < 0) &&
01340       #endif
01341          (errno == EWOULDBLOCK) &&
01342          (time(NULL) - start < 5))
01343       usleep(1000);
01344    if (res) {
01345       ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n",
01346             path, strerror(errno));
01347       /* No unlinking of lock done, since we tried and failed to
01348        * flock() it.
01349        */
01350       path_lock_destroy(pl);
01351       return AST_LOCK_TIMEOUT;
01352    }
01353 
01354    /* Check for the race where the file is recreated or deleted out from
01355     * underneath us.
01356     */
01357    if (lstat(fs, &st) != 0 && fstat(pl->fd, &ost) != 0 &&
01358          st.st_dev != ost.st_dev &&
01359          st.st_ino != ost.st_ino) {
01360       ast_log(LOG_WARNING, "Unable to create lock file '%s': "
01361             "file changed underneath us\n", fs);
01362       path_lock_destroy(pl);
01363       return AST_LOCK_FAILURE;
01364    }
01365 
01366    /* Success: file created, flocked, and is the one we started with */
01367    AST_LIST_LOCK(&path_lock_list);
01368    AST_LIST_INSERT_TAIL(&path_lock_list, pl, le);
01369    AST_LIST_UNLOCK(&path_lock_list);
01370 
01371    ast_debug(1, "Locked path '%s'\n", path);
01372 
01373    return AST_LOCK_SUCCESS;
01374 }
01375 
01376 static int ast_unlock_path_flock(const char *path)
01377 {
01378    char *s;
01379    struct path_lock *p;
01380 
01381    s = alloca(strlen(path) + 20);
01382 
01383    AST_LIST_LOCK(&path_lock_list);
01384    AST_LIST_TRAVERSE_SAFE_BEGIN(&path_lock_list, p, le) {
01385       if (!strcmp(p->path, path)) {
01386          AST_LIST_REMOVE_CURRENT(le);
01387          break;
01388       }
01389    }
01390    AST_LIST_TRAVERSE_SAFE_END;
01391    AST_LIST_UNLOCK(&path_lock_list);
01392 
01393    if (p) {
01394       snprintf(s, strlen(path) + 19, "%s/lock", path);
01395       unlink(s);
01396       path_lock_destroy(p);
01397       ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
01398    } else {
01399       ast_log(LOG_DEBUG, "Failed to unlock path '%s': "
01400             "lock not found\n", path);
01401    }
01402 
01403    return 0;
01404 }
01405 
01406 void ast_set_lock_type(enum AST_LOCK_TYPE type)
01407 {
01408    ast_lock_type = type;
01409 }
01410 
01411 enum AST_LOCK_RESULT ast_lock_path(const char *path)
01412 {
01413    enum AST_LOCK_RESULT r = AST_LOCK_FAILURE;
01414 
01415    switch (ast_lock_type) {
01416    case AST_LOCK_TYPE_LOCKFILE:
01417       r = ast_lock_path_lockfile(path);
01418       break;
01419    case AST_LOCK_TYPE_FLOCK:
01420       r = ast_lock_path_flock(path);
01421       break;
01422    }
01423 
01424    return r;
01425 }
01426 
01427 int ast_unlock_path(const char *path)
01428 {
01429    int r = 0;
01430 
01431    switch (ast_lock_type) {
01432    case AST_LOCK_TYPE_LOCKFILE:
01433       r = ast_unlock_path_lockfile(path);
01434       break;
01435    case AST_LOCK_TYPE_FLOCK:
01436       r = ast_unlock_path_flock(path);
01437       break;
01438    }
01439 
01440    return r;
01441 }
01442 
01443 int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path) 
01444 {
01445    int silencethreshold;
01446    int maxsilence = 0;
01447    int res = 0;
01448    int cmd = 0;
01449    int max_attempts = 3;
01450    int attempts = 0;
01451    int recorded = 0;
01452    int message_exists = 0;
01453    /* Note that urgent and private are for flagging messages as such in the future */
01454 
01455    /* barf if no pointer passed to store duration in */
01456    if (!duration) {
01457       ast_log(LOG_WARNING, "Error ast_record_review called without duration pointer\n");
01458       return -1;
01459    }
01460 
01461    cmd = '3';   /* Want to start by recording */
01462 
01463    silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
01464 
01465    while ((cmd >= 0) && (cmd != 't')) {
01466       switch (cmd) {
01467       case '1':
01468          if (!message_exists) {
01469             /* In this case, 1 is to record a message */
01470             cmd = '3';
01471             break;
01472          } else {
01473             ast_stream_and_wait(chan, "vm-msgsaved", "");
01474             cmd = 't';
01475             return res;
01476          }
01477       case '2':
01478          /* Review */
01479          ast_verb(3, "Reviewing the recording\n");
01480          cmd = ast_stream_and_wait(chan, recordfile, AST_DIGIT_ANY);
01481          break;
01482       case '3':
01483          message_exists = 0;
01484          /* Record */
01485          ast_verb(3, "R%secording\n", recorded == 1 ? "e-r" : "");
01486          recorded = 1;
01487          if ((cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, path)) == -1) {
01488             /* User has hung up, no options to give */
01489             return cmd;
01490          }
01491          if (cmd == '0') {
01492             break;
01493          } else if (cmd == '*') {
01494             break;
01495          } else {
01496             /* If all is well, a message exists */
01497             message_exists = 1;
01498             cmd = 0;
01499          }
01500          break;
01501       case '4':
01502       case '5':
01503       case '6':
01504       case '7':
01505       case '8':
01506       case '9':
01507       case '*':
01508       case '#':
01509          cmd = ast_play_and_wait(chan, "vm-sorry");
01510          break;
01511       default:
01512          if (message_exists) {
01513             cmd = ast_play_and_wait(chan, "vm-review");
01514          } else {
01515             if (!(cmd = ast_play_and_wait(chan, "vm-torerecord"))) {
01516                cmd = ast_waitfordigit(chan, 600);
01517             }
01518          }
01519 
01520          if (!cmd) {
01521             cmd = ast_waitfordigit(chan, 6000);
01522          }
01523          if (!cmd) {
01524             attempts++;
01525          }
01526          if (attempts > max_attempts) {
01527             cmd = 't';
01528          }
01529       }
01530    }
01531    if (cmd == 't') {
01532       cmd = 0;
01533    }
01534    return cmd;
01535 }
01536 
01537 #define RES_UPONE (1 << 16)
01538 #define RES_EXIT  (1 << 17)
01539 #define RES_REPEAT (1 << 18)
01540 #define RES_RESTART ((1 << 19) | RES_REPEAT)
01541 
01542 static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata);
01543 
01544 static int ivr_dispatch(struct ast_channel *chan, struct ast_ivr_option *option, char *exten, void *cbdata)
01545 {
01546    int res;
01547    int (*ivr_func)(struct ast_channel *, void *);
01548    char *c;
01549    char *n;
01550 
01551    switch (option->action) {
01552    case AST_ACTION_UPONE:
01553       return RES_UPONE;
01554    case AST_ACTION_EXIT:
01555       return RES_EXIT | (((unsigned long)(option->adata)) & 0xffff);
01556    case AST_ACTION_REPEAT:
01557       return RES_REPEAT | (((unsigned long)(option->adata)) & 0xffff);
01558    case AST_ACTION_RESTART:
01559       return RES_RESTART ;
01560    case AST_ACTION_NOOP:
01561       return 0;
01562    case AST_ACTION_BACKGROUND:
01563       res = ast_stream_and_wait(chan, (char *)option->adata, AST_DIGIT_ANY);
01564       if (res < 0) {
01565          ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
01566          res = 0;
01567       }
01568       return res;
01569    case AST_ACTION_PLAYBACK:
01570       res = ast_stream_and_wait(chan, (char *)option->adata, "");
01571       if (res < 0) {
01572          ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
01573          res = 0;
01574       }
01575       return res;
01576    case AST_ACTION_MENU:
01577       if ((res = ast_ivr_menu_run_internal(chan, (struct ast_ivr_menu *)option->adata, cbdata)) == -2) {
01578          /* Do not pass entry errors back up, treat as though it was an "UPONE" */
01579          res = 0;
01580       }
01581       return res;
01582    case AST_ACTION_WAITOPTION:
01583       if (!(res = ast_waitfordigit(chan, chan->pbx ? chan->pbx->rtimeoutms : 10000))) {
01584          return 't';
01585       }
01586       return res;
01587    case AST_ACTION_CALLBACK:
01588       ivr_func = option->adata;
01589       res = ivr_func(chan, cbdata);
01590       return res;
01591    case AST_ACTION_TRANSFER:
01592       res = ast_parseable_goto(chan, option->adata);
01593       return 0;
01594    case AST_ACTION_PLAYLIST:
01595    case AST_ACTION_BACKLIST:
01596       res = 0;
01597       c = ast_strdupa(option->adata);
01598       while ((n = strsep(&c, ";"))) {
01599          if ((res = ast_stream_and_wait(chan, n,
01600                (option->action == AST_ACTION_BACKLIST) ? AST_DIGIT_ANY : ""))) {
01601             break;
01602          }
01603       }
01604       ast_stopstream(chan);
01605       return res;
01606    default:
01607       ast_log(LOG_NOTICE, "Unknown dispatch function %d, ignoring!\n", option->action);
01608       return 0;
01609    }
01610    return -1;
01611 }
01612 
01613 static int option_exists(struct ast_ivr_menu *menu, char *option)
01614 {
01615    int x;
01616    for (x = 0; menu->options[x].option; x++) {
01617       if (!strcasecmp(menu->options[x].option, option)) {
01618          return x;
01619       }
01620    }
01621    return -1;
01622 }
01623 
01624 static int option_matchmore(struct ast_ivr_menu *menu, char *option)
01625 {
01626    int x;
01627    for (x = 0; menu->options[x].option; x++) {
01628       if ((!strncasecmp(menu->options[x].option, option, strlen(option))) &&
01629             (menu->options[x].option[strlen(option)])) {
01630          return x;
01631       }
01632    }
01633    return -1;
01634 }
01635 
01636 static int read_newoption(struct ast_channel *chan, struct ast_ivr_menu *menu, char *exten, int maxexten)
01637 {
01638    int res = 0;
01639    int ms;
01640    while (option_matchmore(menu, exten)) {
01641       ms = chan->pbx ? chan->pbx->dtimeoutms : 5000;
01642       if (strlen(exten) >= maxexten - 1) {
01643          break;
01644       }
01645       if ((res = ast_waitfordigit(chan, ms)) < 1) {
01646          break;
01647       }
01648       exten[strlen(exten) + 1] = '\0';
01649       exten[strlen(exten)] = res;
01650    }
01651    return res > 0 ? 0 : res;
01652 }
01653 
01654 static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
01655 {
01656    /* Execute an IVR menu structure */
01657    int res = 0;
01658    int pos = 0;
01659    int retries = 0;
01660    char exten[AST_MAX_EXTENSION] = "s";
01661    if (option_exists(menu, "s") < 0) {
01662       strcpy(exten, "g");
01663       if (option_exists(menu, "g") < 0) {
01664          ast_log(LOG_WARNING, "No 's' nor 'g' extension in menu '%s'!\n", menu->title);
01665          return -1;
01666       }
01667    }
01668    while (!res) {
01669       while (menu->options[pos].option) {
01670          if (!strcasecmp(menu->options[pos].option, exten)) {
01671             res = ivr_dispatch(chan, menu->options + pos, exten, cbdata);
01672             ast_debug(1, "IVR Dispatch of '%s' (pos %d) yields %d\n", exten, pos, res);
01673             if (res < 0) {
01674                break;
01675             } else if (res & RES_UPONE) {
01676                return 0;
01677             } else if (res & RES_EXIT) {
01678                return res;
01679             } else if (res & RES_REPEAT) {
01680                int maxretries = res & 0xffff;
01681                if ((res & RES_RESTART) == RES_RESTART) {
01682                   retries = 0;
01683                } else {
01684                   retries++;
01685                }
01686                if (!maxretries) {
01687                   maxretries = 3;
01688                }
01689                if ((maxretries > 0) && (retries >= maxretries)) {
01690                   ast_debug(1, "Max retries %d exceeded\n", maxretries);
01691                   return -2;
01692                } else {
01693                   if (option_exists(menu, "g") > -1) {
01694                      strcpy(exten, "g");
01695                   } else if (option_exists(menu, "s") > -1) {
01696                      strcpy(exten, "s");
01697                   }
01698                }
01699                pos = 0;
01700                continue;
01701             } else if (res && strchr(AST_DIGIT_ANY, res)) {
01702                ast_debug(1, "Got start of extension, %c\n", res);
01703                exten[1] = '\0';
01704                exten[0] = res;
01705                if ((res = read_newoption(chan, menu, exten, sizeof(exten)))) {
01706                   break;
01707                }
01708                if (option_exists(menu, exten) < 0) {
01709                   if (option_exists(menu, "i")) {
01710                      ast_debug(1, "Invalid extension entered, going to 'i'!\n");
01711                      strcpy(exten, "i");
01712                      pos = 0;
01713                      continue;
01714                   } else {
01715                      ast_debug(1, "Aborting on invalid entry, with no 'i' option!\n");
01716                      res = -2;
01717                      break;
01718                   }
01719                } else {
01720                   ast_debug(1, "New existing extension: %s\n", exten);
01721                   pos = 0;
01722                   continue;
01723                }
01724             }
01725          }
01726          pos++;
01727       }
01728       ast_debug(1, "Stopping option '%s', res is %d\n", exten, res);
01729       pos = 0;
01730       if (!strcasecmp(exten, "s")) {
01731          strcpy(exten, "g");
01732       } else {
01733          break;
01734       }
01735    }
01736    return res;
01737 }
01738 
01739 int ast_ivr_menu_run(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
01740 {
01741    int res = ast_ivr_menu_run_internal(chan, menu, cbdata);
01742    /* Hide internal coding */
01743    return res > 0 ? 0 : res;
01744 }
01745 
01746 char *ast_read_textfile(const char *filename)
01747 {
01748    int fd, count = 0, res;
01749    char *output = NULL;
01750    struct stat filesize;
01751 
01752    if (stat(filename, &filesize) == -1) {
01753       ast_log(LOG_WARNING, "Error can't stat %s\n", filename);
01754       return NULL;
01755    }
01756 
01757    count = filesize.st_size + 1;
01758 
01759    if ((fd = open(filename, O_RDONLY)) < 0) {
01760       ast_log(LOG_WARNING, "Cannot open file '%s' for reading: %s\n", filename, strerror(errno));
01761       return NULL;
01762    }
01763 
01764    if ((output = ast_malloc(count))) {
01765       res = read(fd, output, count - 1);
01766       if (res == count - 1) {
01767          output[res] = '\0';
01768       } else {
01769          ast_log(LOG_WARNING, "Short read of %s (%d of %d): %s\n", filename, res, count - 1, strerror(errno));
01770          ast_free(output);
01771          output = NULL;
01772       }
01773    }
01774 
01775    close(fd);
01776 
01777    return output;
01778 }
01779 
01780 static int parse_options(const struct ast_app_option *options, void *_flags, char **args, char *optstr, int flaglen)
01781 {
01782    char *s, *arg;
01783    int curarg, res = 0;
01784    unsigned int argloc;
01785    struct ast_flags *flags = _flags;
01786    struct ast_flags64 *flags64 = _flags;
01787 
01788    if (flaglen == 32) {
01789       ast_clear_flag(flags, AST_FLAGS_ALL);
01790    } else {
01791       flags64->flags = 0;
01792    }
01793 
01794    if (!optstr) {
01795       return 0;
01796    }
01797 
01798    s = optstr;
01799    while (*s) {
01800       curarg = *s++ & 0x7f;   /* the array (in app.h) has 128 entries */
01801       argloc = options[curarg].arg_index;
01802       if (*s == '(') {
01803          int paren = 1, quote = 0;
01804          int parsequotes = (s[1] == '"') ? 1 : 0;
01805 
01806          /* Has argument */
01807          arg = ++s;
01808          for (; *s; s++) {
01809             if (*s == '(' && !quote) {
01810                paren++;
01811             } else if (*s == ')' && !quote) {
01812                /* Count parentheses, unless they're within quotes (or backslashed, below) */
01813                paren--;
01814             } else if (*s == '"' && parsequotes) {
01815                /* Leave embedded quotes alone, unless they are the first character */
01816                quote = quote ? 0 : 1;
01817                ast_copy_string(s, s + 1, INT_MAX);
01818                s--;
01819             } else if (*s == '\\') {
01820                if (!quote) {
01821                   /* If a backslash is found outside of quotes, remove it */
01822                   ast_copy_string(s, s + 1, INT_MAX);
01823                } else if (quote && s[1] == '"') {
01824                   /* Backslash for a quote character within quotes, remove the backslash */
01825                   ast_copy_string(s, s + 1, INT_MAX);
01826                } else {
01827                   /* Backslash within quotes, keep both characters */
01828                   s++;
01829                }
01830             }
01831 
01832             if (paren == 0) {
01833                break;
01834             }
01835          }
01836          /* This will find the closing paren we found above, or none, if the string ended before we found one. */
01837          if ((s = strchr(s, ')'))) {
01838             if (argloc) {
01839                args[argloc - 1] = arg;
01840             }
01841             *s++ = '\0';
01842          } else {
01843             ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg);
01844             res = -1;
01845             break;
01846          }
01847       } else if (argloc) {
01848          args[argloc - 1] = "";
01849       }
01850       if (flaglen == 32) {
01851          ast_set_flag(flags, options[curarg].flag);
01852       } else {
01853          ast_set_flag64(flags64, options[curarg].flag);
01854       }
01855    }
01856 
01857    return res;
01858 }
01859 
01860 int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
01861 {
01862    return parse_options(options, flags, args, optstr, 32);
01863 }
01864 
01865 int ast_app_parse_options64(const struct ast_app_option *options, struct ast_flags64 *flags, char **args, char *optstr)
01866 {
01867    return parse_options(options, flags, args, optstr, 64);
01868 }
01869 
01870 void ast_app_options2str64(const struct ast_app_option *options, struct ast_flags64 *flags, char *buf, size_t len)
01871 {
01872    unsigned int i, found = 0;
01873    for (i = 32; i < 128 && found < len; i++) {
01874       if (ast_test_flag64(flags, options[i].flag)) {
01875          buf[found++] = i;
01876       }
01877    }
01878    buf[found] = '\0';
01879 }
01880 
01881 int ast_get_encoded_char(const char *stream, char *result, size_t *consumed)
01882 {
01883    int i;
01884    *consumed = 1;
01885    *result = 0;
01886    if (ast_strlen_zero(stream)) {
01887       *consumed = 0;
01888       return -1;
01889    }
01890 
01891    if (*stream == '\\') {
01892       *consumed = 2;
01893       switch (*(stream + 1)) {
01894       case 'n':
01895          *result = '\n';
01896          break;
01897       case 'r':
01898          *result = '\r';
01899          break;
01900       case 't':
01901          *result = '\t';
01902          break;
01903       case 'x':
01904          /* Hexadecimal */
01905          if (strchr("0123456789ABCDEFabcdef", *(stream + 2)) && *(stream + 2) != '\0') {
01906             *consumed = 3;
01907             if (*(stream + 2) <= '9') {
01908                *result = *(stream + 2) - '0';
01909             } else if (*(stream + 2) <= 'F') {
01910                *result = *(stream + 2) - 'A' + 10;
01911             } else {
01912                *result = *(stream + 2) - 'a' + 10;
01913             }
01914          } else {
01915             ast_log(LOG_ERROR, "Illegal character '%c' in hexadecimal string\n", *(stream + 2));
01916             return -1;
01917          }
01918 
01919          if (strchr("0123456789ABCDEFabcdef", *(stream + 3)) && *(stream + 3) != '\0') {
01920             *consumed = 4;
01921             *result <<= 4;
01922             if (*(stream + 3) <= '9') {
01923                *result += *(stream + 3) - '0';
01924             } else if (*(stream + 3) <= 'F') {
01925                *result += *(stream + 3) - 'A' + 10;
01926             } else {
01927                *result += *(stream + 3) - 'a' + 10;
01928             }
01929          }
01930          break;
01931       case '0':
01932          /* Octal */
01933          *consumed = 2;
01934          for (i = 2; ; i++) {
01935             if (strchr("01234567", *(stream + i)) && *(stream + i) != '\0') {
01936                (*consumed)++;
01937                ast_debug(5, "result was %d, ", *result);
01938                *result <<= 3;
01939                *result += *(stream + i) - '0';
01940                ast_debug(5, "is now %d\n", *result);
01941             } else {
01942                break;
01943             }
01944          }
01945          break;
01946       default:
01947          *result = *(stream + 1);
01948       }
01949    } else {
01950       *result = *stream;
01951       *consumed = 1;
01952    }
01953    return 0;
01954 }
01955 
01956 char *ast_get_encoded_str(const char *stream, char *result, size_t result_size)
01957 {
01958    char *cur = result;
01959    size_t consumed;
01960 
01961    while (cur < result + result_size - 1 && !ast_get_encoded_char(stream, cur, &consumed)) {
01962       cur++;
01963       stream += consumed;
01964    }
01965    *cur = '\0';
01966    return result;
01967 }
01968 
01969 int ast_str_get_encoded_str(struct ast_str **str, int maxlen, const char *stream)
01970 {
01971    char next, *buf;
01972    size_t offset = 0;
01973    size_t consumed;
01974 
01975    if (strchr(stream, '\\')) {
01976       while (!ast_get_encoded_char(stream, &next, &consumed)) {
01977          if (offset + 2 > ast_str_size(*str) && maxlen > -1) {
01978             ast_str_make_space(str, maxlen > 0 ? maxlen : (ast_str_size(*str) + 48) * 2 - 48);
01979          }
01980          if (offset + 2 > ast_str_size(*str)) {
01981             break;
01982          }
01983          buf = ast_str_buffer(*str);
01984          buf[offset++] = next;
01985          stream += consumed;
01986       }
01987       buf = ast_str_buffer(*str);
01988       buf[offset++] = '\0';
01989       ast_str_update(*str);
01990    } else {
01991       ast_str_set(str, maxlen, "%s", stream);
01992    }
01993    return 0;
01994 }
01995 
01996 void ast_close_fds_above_n(int n)
01997 {
01998 #ifdef HAVE_CLOSEFROM
01999    closefrom(n + 1);
02000 #else
02001    long x, null;
02002    struct rlimit rl;
02003    DIR *dir;
02004    char path[16], *result;
02005    struct dirent *entry;
02006    snprintf(path, sizeof(path), "/proc/%d/fd", (int) getpid());
02007    if ((dir = opendir(path))) {
02008       while ((entry = readdir(dir))) {
02009          /* Skip . and .. */
02010          if (entry->d_name[0] == '.') {
02011             continue;
02012          }
02013          if ((x = strtol(entry->d_name, &result, 10)) && x >= n) {
02014             close(x);
02015          }
02016       }
02017       closedir(dir);
02018    } else {
02019       getrlimit(RLIMIT_NOFILE, &rl);
02020       if (rl.rlim_cur > 65535) {
02021          /* A more reasonable value */
02022          rl.rlim_cur = 65535;
02023       }
02024       null = open("/dev/null", O_RDONLY);
02025       for (x = n + 1; x < rl.rlim_cur; x++) {
02026          if (x != null) {
02027             /* Side effect of dup2 is that it closes any existing fd without error.
02028              * This prevents valgrind and other debugging tools from sending up
02029              * false error reports. */
02030             while (dup2(null, x) < 0 && errno == EINTR);
02031             close(x);
02032          }
02033       }
02034       close(null);
02035    }
02036 #endif
02037 }
02038 
02039 int ast_safe_fork(int stop_reaper)
02040 {
02041    sigset_t signal_set, old_set;
02042    int pid;
02043 
02044    /* Don't let the default signal handler for children reap our status */
02045    if (stop_reaper) {
02046       ast_replace_sigchld();
02047    }
02048 
02049    sigfillset(&signal_set);
02050    pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
02051 
02052    pid = fork();
02053 
02054    if (pid != 0) {
02055       /* Fork failed or parent */
02056       pthread_sigmask(SIG_SETMASK, &old_set, NULL);
02057       return pid;
02058    } else {
02059       /* Child */
02060 #ifdef HAVE_CAP
02061       cap_t cap = cap_from_text("cap_net_admin-eip");
02062 
02063       if (cap_set_proc(cap)) {
02064          ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
02065       }
02066       cap_free(cap);
02067 #endif
02068 
02069       /* Before we unblock our signals, return our trapped signals back to the defaults */
02070       signal(SIGHUP, SIG_DFL);
02071       signal(SIGCHLD, SIG_DFL);
02072       signal(SIGINT, SIG_DFL);
02073       signal(SIGURG, SIG_DFL);
02074       signal(SIGTERM, SIG_DFL);
02075       signal(SIGPIPE, SIG_DFL);
02076       signal(SIGXFSZ, SIG_DFL);
02077 
02078       /* unblock important signal handlers */
02079       if (pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
02080          ast_log(LOG_WARNING, "unable to unblock signals: %s\n", strerror(errno));
02081          _exit(1);
02082       }
02083 
02084       return pid;
02085    }
02086 }
02087 
02088 void ast_safe_fork_cleanup(void)
02089 {
02090    ast_unreplace_sigchld();
02091 }
02092