Blocked revisions 72597 via svnmerge
[asterisk/asterisk.git] / main / file.c
index f130b99..699df5a 100644 (file)
@@ -61,27 +61,24 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  * (i.e. en/digits/1.gsm, it/digits/1.gsm or default to digits/1.gsm).
  * The latter permits a language to be entirely in one directory.
  */
-int ast_language_is_prefix;
+int ast_language_is_prefix = 1;
 
-static AST_LIST_HEAD_STATIC(formats, ast_format);
+static AST_RWLIST_HEAD_STATIC(formats, ast_format);
 
 int __ast_format_register(const struct ast_format *f, struct ast_module *mod)
 {
        struct ast_format *tmp;
 
-       if (AST_LIST_LOCK(&formats)) {
-               ast_log(LOG_WARNING, "Unable to lock format list\n");
-               return -1;
-       }
-       AST_LIST_TRAVERSE(&formats, tmp, list) {
+       AST_RWLIST_WRLOCK(&formats);
+       AST_RWLIST_TRAVERSE(&formats, tmp, list) {
                if (!strcasecmp(f->name, tmp->name)) {
-                       AST_LIST_UNLOCK(&formats);
+                       AST_RWLIST_UNLOCK(&formats);
                        ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", f->name);
                        return -1;
                }
        }
        if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
-               AST_LIST_UNLOCK(&formats);
+               AST_RWLIST_UNLOCK(&formats);
                return -1;
        }
        *tmp = *f;
@@ -98,8 +95,8 @@ int __ast_format_register(const struct ast_format *f, struct ast_module *mod)
        
        memset(&tmp->list, 0, sizeof(tmp->list));
 
-       AST_LIST_INSERT_HEAD(&formats, tmp, list);
-       AST_LIST_UNLOCK(&formats);
+       AST_RWLIST_INSERT_HEAD(&formats, tmp, list);
+       AST_RWLIST_UNLOCK(&formats);
        if (option_verbose > 1)
                ast_verbose( VERBOSE_PREFIX_2 "Registered file format %s, extension(s) %s\n", f->name, f->exts);
 
@@ -111,19 +108,16 @@ int ast_format_unregister(const char *name)
        struct ast_format *tmp;
        int res = -1;
 
-       if (AST_LIST_LOCK(&formats)) {
-               ast_log(LOG_WARNING, "Unable to lock format list\n");
-               return -1;
-       }
-       AST_LIST_TRAVERSE_SAFE_BEGIN(&formats, tmp, list) {
+       AST_RWLIST_WRLOCK(&formats);
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&formats, tmp, list) {
                if (!strcasecmp(name, tmp->name)) {
-                       AST_LIST_REMOVE_CURRENT(&formats, list);
-                       free(tmp);
+                       AST_RWLIST_REMOVE_CURRENT(&formats, list);
+                       ast_free(tmp);
                        res = 0;
                }
        }
-       AST_LIST_TRAVERSE_SAFE_END
-       AST_LIST_UNLOCK(&formats);
+       AST_RWLIST_TRAVERSE_SAFE_END
+       AST_RWLIST_UNLOCK(&formats);
 
        if (!res) {
                if (option_verbose > 1)
@@ -143,6 +137,11 @@ int ast_stopstream(struct ast_channel *tmp)
                if (tmp->oldwriteformat && ast_set_write_format(tmp, tmp->oldwriteformat))
                        ast_log(LOG_WARNING, "Unable to restore format back to %d\n", tmp->oldwriteformat);
        }
+       /* Stop the video stream too */
+       if (tmp->vstream != NULL) {
+               ast_closestream(tmp->vstream);
+               tmp->vstream = NULL;
+       }
        return 0;
 }
 
@@ -156,7 +155,7 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
                        if (!fs->vfs && fs->filename) {
                                const char *type = ast_getformatname(f->subclass & ~0x1);
                                fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode);
-                               ast_log(LOG_DEBUG, "Opened video output file\n");
+                               ast_debug(1, "Opened video output file\n");
                        }
                        if (fs->vfs)
                                return ast_writestream(fs->vfs, f);
@@ -213,7 +212,7 @@ static int copy(const char *infile, const char *outfile)
                ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
                return -1;
        }
-       if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
+       if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, AST_FILE_MODE)) < 0) {
                ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
                close(ifd);
                return -1;
@@ -351,12 +350,9 @@ static int ast_filehelper(const char *filename, const void *arg2, const char *fm
        struct ast_format *f;
        int res = (action == ACTION_EXISTS) ? 0 : -1;
 
-       if (AST_LIST_LOCK(&formats)) {
-               ast_log(LOG_WARNING, "Unable to lock format list\n");
-               return res;
-       }
+       AST_RWLIST_RDLOCK(&formats);
        /* Check for a specific format */
-       AST_LIST_TRAVERSE(&formats, f, list) {
+       AST_RWLIST_TRAVERSE(&formats, f, list) {
                char *stringp, *ext = NULL;
 
                if (fmt && !exts_compare(f->exts, fmt))
@@ -375,7 +371,7 @@ static int ast_filehelper(const char *filename, const void *arg2, const char *fm
                                continue;
 
                        if ( stat(fn, &st) ) { /* file not existent */
-                               free(fn);
+                               ast_free(fn);
                                continue;
                        }
                        /* for 'OPEN' we need to be sure that the format matches
@@ -388,23 +384,23 @@ static int ast_filehelper(const char *filename, const void *arg2, const char *fm
 
                                if ( !(chan->writeformat & f->format) &&
                                     !(f->format >= AST_FORMAT_MAX_AUDIO && fmt)) {
-                                       free(fn);
+                                       ast_free(fn);
                                        continue;       /* not a supported format */
                                }
                                if ( (bfile = fopen(fn, "r")) == NULL) {
-                                       free(fn);
+                                       ast_free(fn);
                                        continue;       /* cannot open file */
                                }
                                s = get_filestream(f, bfile);
                                if (!s) {
                                        fclose(bfile);
-                                       free(fn);       /* cannot allocate descriptor */
+                                       ast_free(fn);   /* cannot allocate descriptor */
                                        continue;
                                }
                                if (open_wrapper(s)) {
                                        fclose(bfile);
-                                       free(fn);
-                                       free(s);
+                                       ast_free(fn);
+                                       ast_free(s);
                                        continue;       /* cannot run open on file */
                                }
                                /* ok this is good for OPEN */
@@ -413,11 +409,16 @@ static int ast_filehelper(const char *filename, const void *arg2, const char *fm
                                s->fmt = f;
                                s->trans = NULL;
                                s->filename = NULL;
-                               if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
+                               if (s->fmt->format < AST_FORMAT_MAX_AUDIO) {
+                                       if (chan->stream)
+                                               ast_closestream(chan->stream);
                                        chan->stream = s;
-                               else
+                               } else {
+                                       if (chan->vstream)
+                                               ast_closestream(chan->vstream);
                                        chan->vstream = s;
-                               free(fn);
+                               }
+                               ast_free(fn);
                                break;
                        }
                        switch (action) {
@@ -444,7 +445,7 @@ static int ast_filehelper(const char *filename, const void *arg2, const char *fm
                                                ast_log(LOG_WARNING, "%s(%s,%s) failed: %s\n",
                                                        action == ACTION_COPY ? "copy" : "rename",
                                                         fn, nfn, strerror(errno));
-                                       free(nfn);
+                                       ast_free(nfn);
                                }
                            }
                                break;
@@ -452,10 +453,10 @@ static int ast_filehelper(const char *filename, const void *arg2, const char *fm
                        default:
                                ast_log(LOG_WARNING, "Unknown helper %d\n", action);
                        }
-                       free(fn);
+                       ast_free(fn);
                }
        }
-       AST_LIST_UNLOCK(&formats);
+       AST_RWLIST_UNLOCK(&formats);
        return res;
 }
 
@@ -609,7 +610,7 @@ static int ast_readaudio_callback(void *data)
        struct ast_filestream *s = data;
        int whennext = 0;
 
-       while(!whennext) {
+       while (!whennext) {
                struct ast_frame *fr = s->fmt->read(s, &whennext);
                if (!fr /* stream complete */ || ast_write(s->owner, fr) /* error writing */) {
                        if (fr)
@@ -730,16 +731,16 @@ int ast_closestream(struct ast_filestream *f)
        }
 
        if (f->filename)
-               free(f->filename);
+               ast_free(f->filename);
        if (f->realfilename)
-               free(f->realfilename);
+               ast_free(f->realfilename);
        if (f->fmt->close)
                f->fmt->close(f);
        fclose(f->f);
        if (f->vfs)
                ast_closestream(f->vfs);
        ast_module_unref(f->fmt->module);
-       free(f);
+       ast_free(f);
        return 0;
 }
 
@@ -785,21 +786,20 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p
        fs = ast_openstream(chan, filename, preflang);
        if (fs)
                vfs = ast_openvstream(chan, filename, preflang);
-       if (vfs)
-               ast_log(LOG_DEBUG, "Ooh, found a video stream, too, format %s\n", ast_getformatname(vfs->fmt->format));
+       if (vfs) {
+               ast_debug(1, "Ooh, found a video stream, too, format %s\n", ast_getformatname(vfs->fmt->format));
+       }
        if (fs){
                if (ast_applystream(chan, fs))
                        return -1;
                if (vfs && ast_applystream(chan, vfs))
                        return -1;
-               if (ast_playstream(fs))
-                       return -1;
-               if (vfs && ast_playstream(vfs))
-                       return -1;
-#if 1
+               ast_playstream(fs);
+               if (vfs)
+                       ast_playstream(vfs);
                if (option_verbose > 2)
-                       ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (language '%s')\n", filename, preflang ? preflang : "default");
-#endif
+                       ast_verbose(VERBOSE_PREFIX_3 "<%s> Playing '%s.%s' (language '%s')\n", chan->name, filename, ast_getformatname(chan->writeformat), preflang ? preflang : "default");
+
                return 0;
        }
        ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname_multiple(fmt, sizeof(fmt), chan->nativeformats), strerror(errno));
@@ -813,12 +813,9 @@ struct ast_filestream *ast_readfile(const char *filename, const char *type, cons
        struct ast_filestream *fs = NULL;
        char *fn;
 
-       if (AST_LIST_LOCK(&formats)) {
-               ast_log(LOG_WARNING, "Unable to lock format list\n");
-               return NULL;
-       }
+       AST_RWLIST_RDLOCK(&formats);
 
-       AST_LIST_TRAVERSE(&formats, f, list) {
+       AST_RWLIST_TRAVERSE(&formats, f, list) {
                fs = NULL;
                if (!exts_compare(f->exts, type))
                        continue;
@@ -827,12 +824,13 @@ struct ast_filestream *ast_readfile(const char *filename, const char *type, cons
                errno = 0;
                bfile = fopen(fn, "r");
                if (!bfile || (fs = get_filestream(f, bfile)) == NULL ||
-                       open_wrapper(fs) ) {
+                   open_wrapper(fs) ) {
                        ast_log(LOG_WARNING, "Unable to open %s\n", fn);
-                       fclose(bfile);
-                       free(fn);
                        if (fs)
-                               free(fs);
+                               ast_free(fs);
+                       if (bfile)
+                               fclose(bfile);
+                       ast_free(fn);
                        continue;
                }
                /* found it */
@@ -840,12 +838,12 @@ struct ast_filestream *ast_readfile(const char *filename, const char *type, cons
                fs->fmt = f;
                fs->flags = flags;
                fs->mode = mode;
-               fs->filename = strdup(filename);
+               fs->filename = ast_strdup(filename);
                fs->vfs = NULL;
                break;
        }
 
-       AST_LIST_UNLOCK(&formats);
+       AST_RWLIST_UNLOCK(&formats);
        if (!fs) 
                ast_log(LOG_WARNING, "No such format '%s'\n", type);
 
@@ -863,10 +861,7 @@ struct ast_filestream *ast_writefile(const char *filename, const char *type, con
        size_t size = 0;
        int format_found = 0;
 
-       if (AST_LIST_LOCK(&formats)) {
-               ast_log(LOG_WARNING, "Unable to lock format list\n");
-               return NULL;
-       }
+       AST_RWLIST_RDLOCK(&formats);
 
        /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
        /* We really can't use O_APPEND as it will break WAV header updates */
@@ -881,7 +876,7 @@ struct ast_filestream *ast_writefile(const char *filename, const char *type, con
        /* XXX need to fix this - we should just do the fopen,
         * not open followed by fdopen()
         */
-       AST_LIST_TRAVERSE(&formats, f, list) {
+       AST_RWLIST_TRAVERSE(&formats, f, list) {
                char *fn, *orig_fn = NULL;
                if (fs)
                        break;
@@ -921,7 +916,7 @@ struct ast_filestream *ast_writefile(const char *filename, const char *type, con
                        strcpy(buf, record_cache_dir);
                        strcat(buf, "/");
                        strcat(buf, fn);
-                       free(fn);
+                       ast_free(fn);
                        fn = buf;
                        fd = open(fn, flags | myflags, mode);
                        if (fd > -1) {
@@ -945,18 +940,20 @@ struct ast_filestream *ast_writefile(const char *filename, const char *type, con
                                        unlink(orig_fn);
                                }
                                if (fs)
-                                       free(fs);
+                                       ast_free(fs);
+                               fs = NULL;
+                               continue;
                        }
                        fs->trans = NULL;
                        fs->fmt = f;
                        fs->flags = flags;
                        fs->mode = mode;
                        if (orig_fn) {
-                               fs->realfilename = strdup(orig_fn);
-                               fs->filename = strdup(fn);
+                               fs->realfilename = ast_strdup(orig_fn);
+                               fs->filename = ast_strdup(fn);
                        } else {
                                fs->realfilename = NULL;
-                               fs->filename = strdup(filename);
+                               fs->filename = ast_strdup(filename);
                        }
                        fs->vfs = NULL;
                        /* If truncated, we'll be at the beginning; if not truncated, then append */
@@ -968,10 +965,10 @@ struct ast_filestream *ast_writefile(const char *filename, const char *type, con
                }
                /* if buf != NULL then fn is already free and pointing to it */
                if (!buf)
-                       free(fn);
+                       ast_free(fn);
        }
 
-       AST_LIST_UNLOCK(&formats);
+       AST_RWLIST_UNLOCK(&formats);
 
        if (!format_found)
                ast_log(LOG_WARNING, "No such format '%s'\n", type);
@@ -1028,11 +1025,12 @@ static int waitstream_core(struct ast_channel *c, const char *breakon,
                        struct ast_frame *fr = ast_read(c);
                        if (!fr)
                                return -1;
-                       switch(fr->frametype) {
+                       switch (fr->frametype) {
                        case AST_FRAME_DTMF_END:
                                if (context) {
                                        const char exten[2] = { fr->subclass, '\0' };
                                        if (ast_exists_extension(c, context, exten, 1, c->cid.cid_num)) {
+                                               res = fr->subclass;
                                                ast_frfree(fr);
                                                return res;
                                        }
@@ -1049,18 +1047,23 @@ static int waitstream_core(struct ast_channel *c, const char *breakon,
                                }
                                break;
                        case AST_FRAME_CONTROL:
-                               switch(fr->subclass) {
+                               switch (fr->subclass) {
                                case AST_CONTROL_HANGUP:
+                               case AST_CONTROL_BUSY:
+                               case AST_CONTROL_CONGESTION:
                                        ast_frfree(fr);
                                        return -1;
                                case AST_CONTROL_RINGING:
                                case AST_CONTROL_ANSWER:
                                case AST_CONTROL_VIDUPDATE:
+                               case AST_CONTROL_HOLD:
+                               case AST_CONTROL_UNHOLD:
                                        /* Unimportant */
                                        break;
                                default:
                                        ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
                                }
+                               break;
                        case AST_FRAME_VOICE:
                                /* Write audio if appropriate */
                                if (audiofd > -1)
@@ -1109,12 +1112,11 @@ int ast_waitstream_exten(struct ast_channel *c, const char *context)
  * Return 0 if success, -1 if error, digit if interrupted by a digit.
  * If digits == "" then we can simply check for non-zero.
  */
-int ast_stream_and_wait(struct ast_channel *chan, const char *file,
-       const char *language, const char *digits)
+int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
 {
         int res = 0;
         if (!ast_strlen_zero(file)) {
-                res =  ast_streamfile(chan, file, language);
+                res = ast_streamfile(chan, file, chan->language);
                 if (!res)
                         res = ast_waitstream(chan, digits);
         }
@@ -1128,39 +1130,30 @@ static int show_file_formats(int fd, int argc, char *argv[])
        struct ast_format *f;
        int count_fmt = 0;
 
-       if (argc != 3)
+       if (argc != 4)
                return RESULT_SHOWUSAGE;
        ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
-               
-       if (AST_LIST_LOCK(&formats)) {
-               ast_log(LOG_WARNING, "Unable to lock format list\n");
-               return -1;
-       }
 
-       AST_LIST_TRAVERSE(&formats, f, list) {
+       AST_RWLIST_RDLOCK(&formats);
+       AST_RWLIST_TRAVERSE(&formats, f, list) {
                ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
                count_fmt++;
        }
-       AST_LIST_UNLOCK(&formats);
+       AST_RWLIST_UNLOCK(&formats);
        ast_cli(fd, "%d file formats registered.\n", count_fmt);
        return RESULT_SUCCESS;
 #undef FORMAT
 #undef FORMAT2
 }
 
-char show_file_formats_usage[] = 
-"Usage: core list file formats\n"
+static const char show_file_formats_usage[] = 
+"Usage: core show file formats\n"
 "       Displays currently registered file formats (if any)\n";
 
-struct ast_cli_entry cli_show_file_formats_deprecated = {
-       { "show", "file", "formats" },
-       show_file_formats, NULL,
-       NULL };
-
 struct ast_cli_entry cli_file[] = {
-       { { "file", "list", "formats" },
+       { { "core", "show", "file", "formats" },
        show_file_formats, "Displays file formats",
-       show_file_formats_usage, NULL, &cli_show_file_formats_deprecated },
+       show_file_formats_usage },
 };
 
 int ast_file_init(void)