Thu Oct 11 06:47:02 2012

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

Generated on Thu Oct 11 06:47:02 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6