add 'exit context' and 'only stop on match' options to Background app (bug #4511)
[asterisk/asterisk.git] / file.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Generic File Format Support.
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <sys/types.h>
15 #include <errno.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <fcntl.h>
21 #include <dirent.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24
25 #include "asterisk.h"
26
27 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
28
29 #include "asterisk/frame.h"
30 #include "asterisk/file.h"
31 #include "asterisk/cli.h"
32 #include "asterisk/logger.h"
33 #include "asterisk/channel.h"
34 #include "asterisk/sched.h"
35 #include "asterisk/options.h"
36 #include "asterisk/translate.h"
37 #include "asterisk/utils.h"
38 #include "asterisk/lock.h"
39 #include "asterisk/app.h"
40 #include "asterisk/pbx.h"
41
42 struct ast_format {
43         /* Name of format */
44         char name[80];
45         /* Extensions (separated by | if more than one) 
46            this format can read.  First is assumed for writing (e.g. .mp3) */
47         char exts[80];
48         /* Format of frames it uses/provides (one only) */
49         int format;
50         /* Open an input stream, and start playback */
51         struct ast_filestream * (*open)(int fd);
52         /* Open an output stream, of a given file descriptor and comment it appropriately if applicable */
53         struct ast_filestream * (*rewrite)(int fd, const char *comment);
54         /* Write a frame to a channel */
55         int (*write)(struct ast_filestream *, struct ast_frame *);
56         /* seek num samples into file, whence(think normal seek) */
57         int (*seek)(struct ast_filestream *, long offset, int whence);
58         /* trunc file to current position */
59         int (*trunc)(struct ast_filestream *fs);
60         /* tell current position */
61         long (*tell)(struct ast_filestream *fs);
62         /* Read the next frame from the filestream (if available) and report when to get next one
63                 (in samples) */
64         struct ast_frame * (*read)(struct ast_filestream *, int *whennext);
65         /* Close file, and destroy filestream structure */
66         void (*close)(struct ast_filestream *);
67         /* Retrieve file comment */
68         char * (*getcomment)(struct ast_filestream *);
69         /* Link */
70         struct ast_format *next;
71 };
72
73 struct ast_filestream {
74         /* Everybody reserves a block of AST_RESERVED_POINTERS pointers for us */
75         struct ast_format *fmt;
76         int flags;
77         mode_t mode;
78         char *filename;
79         char *realfilename;
80         /* Video file stream */
81         struct ast_filestream *vfs;
82         /* Transparently translate from another format -- just once */
83         struct ast_trans_pvt *trans;
84         struct ast_tranlator_pvt *tr;
85         int lastwriteformat;
86         int lasttimeout;
87         struct ast_channel *owner;
88 };
89
90 AST_MUTEX_DEFINE_STATIC(formatlock);
91
92 static struct ast_format *formats = NULL;
93
94 int ast_format_register(const char *name, const char *exts, int format,
95                                                 struct ast_filestream * (*open)(int fd),
96                                                 struct ast_filestream * (*rewrite)(int fd, const char *comment),
97                                                 int (*write)(struct ast_filestream *, struct ast_frame *),
98                                                 int (*seek)(struct ast_filestream *, long sample_offset, int whence),
99                                                 int (*trunc)(struct ast_filestream *),
100                                                 long (*tell)(struct ast_filestream *),
101                                                 struct ast_frame * (*read)(struct ast_filestream *, int *whennext),
102                                                 void (*close)(struct ast_filestream *),
103                                                 char * (*getcomment)(struct ast_filestream *))
104 {
105         struct ast_format *tmp;
106         if (ast_mutex_lock(&formatlock)) {
107                 ast_log(LOG_WARNING, "Unable to lock format list\n");
108                 return -1;
109         }
110         tmp = formats;
111         while(tmp) {
112                 if (!strcasecmp(name, tmp->name)) {
113                         ast_mutex_unlock(&formatlock);
114                         ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", name);
115                         return -1;
116                 }
117                 tmp = tmp->next;
118         }
119         tmp = malloc(sizeof(struct ast_format));
120         if (!tmp) {
121                 ast_log(LOG_WARNING, "Out of memory\n");
122                 ast_mutex_unlock(&formatlock);
123                 return -1;
124         }
125         ast_copy_string(tmp->name, name, sizeof(tmp->name));
126         ast_copy_string(tmp->exts, exts, sizeof(tmp->exts));
127         tmp->open = open;
128         tmp->rewrite = rewrite;
129         tmp->read = read;
130         tmp->write = write;
131         tmp->seek = seek;
132         tmp->trunc = trunc;
133         tmp->tell = tell;
134         tmp->close = close;
135         tmp->format = format;
136         tmp->getcomment = getcomment;
137         tmp->next = formats;
138         formats = tmp;
139         ast_mutex_unlock(&formatlock);
140         if (option_verbose > 1)
141                 ast_verbose( VERBOSE_PREFIX_2 "Registered file format %s, extension(s) %s\n", name, exts);
142         return 0;
143 }
144
145 int ast_format_unregister(const char *name)
146 {
147         struct ast_format *tmp, *tmpl = NULL;
148         if (ast_mutex_lock(&formatlock)) {
149                 ast_log(LOG_WARNING, "Unable to lock format list\n");
150                 return -1;
151         }
152         tmp = formats;
153         while(tmp) {
154                 if (!strcasecmp(name, tmp->name)) {
155                         if (tmpl) 
156                                 tmpl->next = tmp->next;
157                         else
158                                 formats = tmp->next;
159                         free(tmp);
160                         ast_mutex_unlock(&formatlock);
161                         if (option_verbose > 1)
162                                 ast_verbose( VERBOSE_PREFIX_2 "Unregistered format %s\n", name);
163                         return 0;
164                 }
165                 tmpl = tmp;
166                 tmp = tmp->next;
167         }
168         ast_log(LOG_WARNING, "Tried to unregister format %s, already unregistered\n", name);
169         return -1;
170 }
171
172 int ast_stopstream(struct ast_channel *tmp)
173 {
174         /* Stop a running stream if there is one */
175         if (tmp->vstream)
176                 ast_closestream(tmp->vstream);
177         if (tmp->stream) {
178                 ast_closestream(tmp->stream);
179                 if (tmp->oldwriteformat && ast_set_write_format(tmp, tmp->oldwriteformat))
180                         ast_log(LOG_WARNING, "Unable to restore format back to %d\n", tmp->oldwriteformat);
181         }
182         return 0;
183 }
184
185 int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
186 {
187         struct ast_frame *trf;
188         int res = -1;
189         int alt=0;
190         if (f->frametype == AST_FRAME_VIDEO) {
191                 if (fs->fmt->format < AST_FORMAT_MAX_AUDIO) {
192                         /* This is the audio portion.  Call the video one... */
193                         if (!fs->vfs && fs->filename) {
194                                 /* XXX Support other video formats XXX */
195                                 const char *type = "h263";
196                                 fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode);
197                                 ast_log(LOG_DEBUG, "Opened video output file\n");
198                         }
199                         if (fs->vfs)
200                                 return ast_writestream(fs->vfs, f);
201                         /* Ignore */
202                         return 0;                               
203                 } else {
204                         /* Might / might not have mark set */
205                         alt = 1;
206                 }
207         } else if (f->frametype != AST_FRAME_VOICE) {
208                 ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
209                 return -1;
210         }
211         if (((fs->fmt->format | alt) & f->subclass) == f->subclass) {
212                 res =  fs->fmt->write(fs, f);
213                 if (res < 0) 
214                         ast_log(LOG_WARNING, "Natural write failed\n");
215                 if (res > 0)
216                         ast_log(LOG_WARNING, "Huh??\n");
217                 return res;
218         } else {
219                 /* XXX If they try to send us a type of frame that isn't the normal frame, and isn't
220                        the one we've setup a translator for, we do the "wrong thing" XXX */
221                 if (fs->trans && (f->subclass != fs->lastwriteformat)) {
222                         ast_translator_free_path(fs->trans);
223                         fs->trans = NULL;
224                 }
225                 if (!fs->trans) 
226                         fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass);
227                 if (!fs->trans)
228                         ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n", fs->fmt->name, ast_getformatname(f->subclass));
229                 else {
230                         fs->lastwriteformat = f->subclass;
231                         res = 0;
232                         /* Get the translated frame but don't consume the original in case they're using it on another stream */
233                         trf = ast_translate(fs->trans, f, 0);
234                         if (trf) {
235                                 res = fs->fmt->write(fs, trf);
236                                 if (res) 
237                                         ast_log(LOG_WARNING, "Translated frame write failed\n");
238                         } else
239                                 res = 0;
240                 }
241                 return res;
242         }
243 }
244
245 static int copy(const char *infile, const char *outfile)
246 {
247         int ifd;
248         int ofd;
249         int res;
250         int len;
251         char buf[4096];
252
253         if ((ifd = open(infile, O_RDONLY)) < 0) {
254                 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
255                 return -1;
256         }
257         if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
258                 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
259                 close(ifd);
260                 return -1;
261         }
262         do {
263                 len = read(ifd, buf, sizeof(buf));
264                 if (len < 0) {
265                         ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
266                         close(ifd);
267                         close(ofd);
268                         unlink(outfile);
269                 }
270                 if (len) {
271                         res = write(ofd, buf, len);
272                         if (res != len) {
273                                 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
274                                 close(ifd);
275                                 close(ofd);
276                                 unlink(outfile);
277                         }
278                 }
279         } while(len);
280         close(ifd);
281         close(ofd);
282         return 0;
283 }
284
285 static char *build_filename(const char *filename, const char *ext)
286 {
287         char *fn, type[16];
288         int fnsize = 0;
289
290         if (!strcmp(ext, "wav49")) {
291                 ast_copy_string(type, "WAV", sizeof(type));
292         } else {
293                 ast_copy_string(type, ext, sizeof(type));
294         }
295
296         if (filename[0] == '/') {
297                 fnsize = strlen(filename) + strlen(type) + 2;
298                 fn = malloc(fnsize);
299                 if (fn)
300                         snprintf(fn, fnsize, "%s.%s", filename, type);
301         } else {
302                 char tmp[AST_CONFIG_MAX_PATH] = "";
303
304                 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_VAR_DIR, "sounds");
305                 fnsize = strlen(tmp) + strlen(filename) + strlen(type) + 3;
306                 fn = malloc(fnsize);
307                 if (fn)
308                         snprintf(fn, fnsize, "%s/%s.%s", tmp, filename, type);
309         }
310
311         return fn;
312 }
313
314 static int exts_compare(const char *exts, const char *type)
315 {
316         char *stringp = NULL, *ext;
317         char tmp[256];
318
319         ast_copy_string(tmp, exts, sizeof(tmp));
320         stringp = tmp;
321         while ((ext = strsep(&stringp, "|"))) {
322                 if (!strcmp(ext, type)) {
323                         return 1;
324                 }
325         }
326
327         return 0;
328 }
329
330 #define ACTION_EXISTS 1
331 #define ACTION_DELETE 2
332 #define ACTION_RENAME 3
333 #define ACTION_OPEN   4
334 #define ACTION_COPY   5
335
336 static int ast_filehelper(const char *filename, const char *filename2, const char *fmt, int action)
337 {
338         struct stat st;
339         struct ast_format *f;
340         struct ast_filestream *s;
341         int res=0, ret = 0;
342         char *ext=NULL, *exts, *fn, *nfn;
343         struct ast_channel *chan = (struct ast_channel *)filename2;
344         
345         /* Start with negative response */
346         if (action == ACTION_EXISTS)
347                 res = 0;
348         else
349                 res = -1;
350         if (action == ACTION_OPEN)
351                 ret = -1;
352         /* Check for a specific format */
353         if (ast_mutex_lock(&formatlock)) {
354                 ast_log(LOG_WARNING, "Unable to lock format list\n");
355                 if (action == ACTION_EXISTS)
356                         return 0;
357                 else
358                         return -1;
359         }
360         f = formats;
361         while(f) {
362                 if (!fmt || exts_compare(f->exts, fmt)) {
363                         char *stringp=NULL;
364                         exts = ast_strdupa(f->exts);
365                         /* Try each kind of extension */
366                         stringp=exts;
367                         ext = strsep(&stringp, "|");
368                         do {
369                                 fn = build_filename(filename, ext);
370                                 if (fn) {
371                                         res = stat(fn, &st);
372                                         if (!res) {
373                                                 switch(action) {
374                                                 case ACTION_EXISTS:
375                                                         ret |= f->format;
376                                                         break;
377                                                 case ACTION_DELETE:
378                                                         res = unlink(fn);
379                                                         if (res)
380                                                                 ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
381                                                         break;
382                                                 case ACTION_RENAME:
383                                                         nfn = build_filename(filename2, ext);
384                                                         if (nfn) {
385                                                                 res = rename(fn, nfn);
386                                                                 if (res)
387                                                                         ast_log(LOG_WARNING, "rename(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
388                                                                 free(nfn);
389                                                         } else
390                                                                 ast_log(LOG_WARNING, "Out of memory\n");
391                                                         break;
392                                                 case ACTION_COPY:
393                                                         nfn = build_filename(filename2, ext);
394                                                         if (nfn) {
395                                                                 res = copy(fn, nfn);
396                                                                 if (res)
397                                                                         ast_log(LOG_WARNING, "copy(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
398                                                                 free(nfn);
399                                                         } else
400                                                                 ast_log(LOG_WARNING, "Out of memory\n");
401                                                         break;
402                                                 case ACTION_OPEN:
403                                                         if ((ret < 0) && ((chan->writeformat & f->format) ||
404                                                                                 ((f->format >= AST_FORMAT_MAX_AUDIO) && fmt))) {
405                                                                 ret = open(fn, O_RDONLY);
406                                                                 if (ret >= 0) {
407                                                                         s = f->open(ret);
408                                                                         if (s) {
409                                                                                 s->lasttimeout = -1;
410                                                                                 s->fmt = f;
411                                                                                 s->trans = NULL;
412                                                                                 s->filename = NULL;
413                                                                                 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
414                                                                                         chan->stream = s;
415                                                                                 else
416                                                                                         chan->vstream = s;
417                                                                         } else {
418                                                                                 close(ret);
419                                                                                 ast_log(LOG_WARNING, "Unable to open fd on %s\n", fn);
420                                                                         }
421                                                                 } else
422                                                                         ast_log(LOG_WARNING, "Couldn't open file %s\n", fn);
423                                                         }
424                                                         break;
425                                                 default:
426                                                         ast_log(LOG_WARNING, "Unknown helper %d\n", action);
427                                                 }
428                                                 /* Conveniently this logic is the same for all */
429                                                 if (res)
430                                                         break;
431                                         }
432                                         free(fn);
433                                 }
434                                 ext = strsep(&stringp, "|");
435                         } while(ext);
436                         
437                 }
438                 f = f->next;
439         }
440         ast_mutex_unlock(&formatlock);
441         if ((action == ACTION_EXISTS) || (action == ACTION_OPEN))
442                 res = ret ? ret : -1;
443         return res;
444 }
445 struct ast_filestream *ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
446 {
447         return ast_openstream_full(chan, filename, preflang, 0);
448 }
449
450 struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char *filename, const char *preflang, int asis)
451 {
452         /* This is a fairly complex routine.  Essentially we should do 
453            the following:
454            
455            1) Find which file handlers produce our type of format.
456            2) Look for a filename which it can handle.
457            3) If we find one, then great.  
458            4) If not, see what files are there
459            5) See what we can actually support
460            6) Choose the one with the least costly translator path and
461                set it up.
462                    
463         */
464         int fd = -1;
465         int fmts = -1;
466         char filename2[256]="";
467         char filename3[256]="";
468         char *endpart;
469         int res;
470
471         if (!asis) {
472                 /* do this first, otherwise we detect the wrong writeformat */
473                 ast_stopstream(chan);
474                 if (chan->generator)
475                         ast_deactivate_generator(chan);
476         }
477         if (preflang && !ast_strlen_zero(preflang)) {
478                 ast_copy_string(filename3, filename, sizeof(filename3));
479                 endpart = strrchr(filename3, '/');
480                 if (endpart) {
481                         *endpart = '\0';
482                         endpart++;
483                         snprintf(filename2, sizeof(filename2), "%s/%s/%s", filename3, preflang, endpart);
484                 } else
485                         snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
486                 fmts = ast_fileexists(filename2, NULL, NULL);
487         }
488         if (fmts < 1) {
489                 ast_copy_string(filename2, filename, sizeof(filename2));
490                 fmts = ast_fileexists(filename2, NULL, NULL);
491         }
492         if (fmts < 1) {
493                 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
494                 return NULL;
495         }
496         chan->oldwriteformat = chan->writeformat;
497         /* Set the channel to a format we can work with */
498         res = ast_set_write_format(chan, fmts);
499         
500         fd = ast_filehelper(filename2, (char *)chan, NULL, ACTION_OPEN);
501         if (fd >= 0)
502                 return chan->stream;
503         return NULL;
504 }
505
506 struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *filename, const char *preflang)
507 {
508         /* This is a fairly complex routine.  Essentially we should do 
509            the following:
510            
511            1) Find which file handlers produce our type of format.
512            2) Look for a filename which it can handle.
513            3) If we find one, then great.  
514            4) If not, see what files are there
515            5) See what we can actually support
516            6) Choose the one with the least costly translator path and
517                set it up.
518                    
519         */
520         int fd = -1;
521         int fmts = -1;
522         char filename2[256];
523         char lang2[MAX_LANGUAGE];
524         /* XXX H.263 only XXX */
525         char *fmt = "h263";
526         if (preflang && !ast_strlen_zero(preflang)) {
527                 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
528                 fmts = ast_fileexists(filename2, fmt, NULL);
529                 if (fmts < 1) {
530                         ast_copy_string(lang2, preflang, sizeof(lang2));
531                         snprintf(filename2, sizeof(filename2), "%s/%s", lang2, filename);
532                         fmts = ast_fileexists(filename2, fmt, NULL);
533                 }
534         }
535         if (fmts < 1) {
536                 ast_copy_string(filename2, filename, sizeof(filename2));
537                 fmts = ast_fileexists(filename2, fmt, NULL);
538         }
539         if (fmts < 1) {
540                 return NULL;
541         }
542         fd = ast_filehelper(filename2, (char *)chan, fmt, ACTION_OPEN);
543         if (fd >= 0)
544                 return chan->vstream;
545         ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
546         return NULL;
547 }
548
549 struct ast_frame *ast_readframe(struct ast_filestream *s)
550 {
551         struct ast_frame *f = NULL;
552         int whennext = 0;       
553         if (s && s->fmt)
554                 f = s->fmt->read(s, &whennext);
555         return f;
556 }
557
558 static int ast_readaudio_callback(void *data)
559 {
560         struct ast_filestream *s = data;
561         struct ast_frame *fr;
562         int whennext = 0;
563
564         while(!whennext) {
565                 fr = s->fmt->read(s, &whennext);
566                 if (fr) {
567                         if (ast_write(s->owner, fr)) {
568                                 ast_log(LOG_WARNING, "Failed to write frame\n");
569                                 s->owner->streamid = -1;
570 #ifdef ZAPTEL_OPTIMIZATIONS
571                                 ast_settimeout(s->owner, 0, NULL, NULL);
572 #endif                  
573                                 return 0;
574                         }
575                 } else {
576                         /* Stream has finished */
577                         s->owner->streamid = -1;
578 #ifdef ZAPTEL_OPTIMIZATIONS
579                         ast_settimeout(s->owner, 0, NULL, NULL);
580 #endif                  
581                         return 0;
582                 }
583         }
584         if (whennext != s->lasttimeout) {
585 #ifdef ZAPTEL_OPTIMIZATIONS
586                 if (s->owner->timingfd > -1)
587                         ast_settimeout(s->owner, whennext, ast_readaudio_callback, s);
588                 else
589 #endif          
590                         s->owner->streamid = ast_sched_add(s->owner->sched, whennext/8, ast_readaudio_callback, s);
591                 s->lasttimeout = whennext;
592                 return 0;
593         }
594         return 1;
595 }
596
597 static int ast_readvideo_callback(void *data)
598 {
599         struct ast_filestream *s = data;
600         struct ast_frame *fr;
601         int whennext = 0;
602
603         while(!whennext) {
604                 fr = s->fmt->read(s, &whennext);
605                 if (fr) {
606                         if (ast_write(s->owner, fr)) {
607                                 ast_log(LOG_WARNING, "Failed to write frame\n");
608                                 s->owner->vstreamid = -1;
609                                 return 0;
610                         }
611                 } else {
612                         /* Stream has finished */
613                         s->owner->vstreamid = -1;
614                         return 0;
615                 }
616         }
617         if (whennext != s->lasttimeout) {
618                 s->owner->vstreamid = ast_sched_add(s->owner->sched, whennext/8, ast_readvideo_callback, s);
619                 s->lasttimeout = whennext;
620                 return 0;
621         }
622         return 1;
623 }
624
625 int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
626 {
627         s->owner = chan;
628         return 0;
629 }
630
631 int ast_playstream(struct ast_filestream *s)
632 {
633         if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
634                 ast_readaudio_callback(s);
635         else
636                 ast_readvideo_callback(s);
637         return 0;
638 }
639
640 int ast_seekstream(struct ast_filestream *fs, long sample_offset, int whence)
641 {
642         return fs->fmt->seek(fs, sample_offset, whence);
643 }
644
645 int ast_truncstream(struct ast_filestream *fs)
646 {
647         return fs->fmt->trunc(fs);
648 }
649
650 long ast_tellstream(struct ast_filestream *fs)
651 {
652         return fs->fmt->tell(fs);
653 }
654
655 int ast_stream_fastforward(struct ast_filestream *fs, long ms)
656 {
657         /* I think this is right, 8000 samples per second, 1000 ms a second so 8
658          * samples per ms  */
659         long samples = ms * 8;
660         return ast_seekstream(fs, samples, SEEK_CUR);
661 }
662
663 int ast_stream_rewind(struct ast_filestream *fs, long ms)
664 {
665         long samples = ms * 8;
666         samples = samples * -1;
667         return ast_seekstream(fs, samples, SEEK_CUR);
668 }
669
670 int ast_closestream(struct ast_filestream *f)
671 {
672         char *cmd = NULL;
673         size_t size = 0;
674         /* Stop a running stream if there is one */
675         if (f->owner) {
676                 if (f->fmt->format < AST_FORMAT_MAX_AUDIO) {
677                         f->owner->stream = NULL;
678                         if (f->owner->streamid > -1)
679                                 ast_sched_del(f->owner->sched, f->owner->streamid);
680                         f->owner->streamid = -1;
681 #ifdef ZAPTEL_OPTIMIZATIONS
682                         ast_settimeout(f->owner, 0, NULL, NULL);
683 #endif                  
684                 } else {
685                         f->owner->vstream = NULL;
686                         if (f->owner->vstreamid > -1)
687                                 ast_sched_del(f->owner->sched, f->owner->vstreamid);
688                         f->owner->vstreamid = -1;
689                 }
690         }
691         /* destroy the translator on exit */
692         if (f->trans) {
693                 ast_translator_free_path(f->trans);
694                 f->trans = NULL;
695         }
696
697         if (f->realfilename && f->filename) {
698                         size = strlen(f->filename) + strlen(f->realfilename) + 15;
699                         cmd = alloca(size);
700                         memset(cmd,0,size);
701                         snprintf(cmd,size,"/bin/mv -f %s %s",f->filename,f->realfilename);
702                         ast_safe_system(cmd);
703         }
704
705         if (f->filename) {
706                 free(f->filename);
707                 f->filename = NULL;
708         }
709         if (f->realfilename) {
710                 free(f->realfilename);
711                 f->realfilename = NULL;
712         }
713         f->fmt->close(f);
714         return 0;
715 }
716
717
718 int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
719 {
720         char filename2[256];
721         char tmp[256];
722         char *postfix;
723         char *prefix;
724         char *c;
725         char lang2[MAX_LANGUAGE];
726         int res = -1;
727         if (preflang && !ast_strlen_zero(preflang)) {
728                 /* Insert the language between the last two parts of the path */
729                 ast_copy_string(tmp, filename, sizeof(tmp));
730                 c = strrchr(tmp, '/');
731                 if (c) {
732                         *c = '\0';
733                         postfix = c+1;
734                         prefix = tmp;
735                         snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
736                 } else {
737                         postfix = tmp;
738                         prefix="";
739                         snprintf(filename2, sizeof(filename2), "%s/%s", preflang, postfix);
740                 }
741                 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
742                 if (res < 1) {
743                         char *stringp=NULL;
744                         ast_copy_string(lang2, preflang, sizeof(lang2));
745                         stringp=lang2;
746                         strsep(&stringp, "_");
747                         /* If language is a specific locality of a language (like es_MX), strip the locality and try again */
748                         if (strcmp(lang2, preflang)) {
749                                 if (ast_strlen_zero(prefix)) {
750                                         snprintf(filename2, sizeof(filename2), "%s/%s", lang2, postfix);
751                                 } else {
752                                         snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
753                                 }
754                                 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
755                         }
756                 }
757         }
758
759         /* Fallback to no language (usually winds up being American English) */
760         if (res < 1) {
761                 res = ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
762         }
763         return res;
764 }
765
766 int ast_filedelete(const char *filename, const char *fmt)
767 {
768         return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
769 }
770
771 int ast_filerename(const char *filename, const char *filename2, const char *fmt)
772 {
773         return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
774 }
775
776 int ast_filecopy(const char *filename, const char *filename2, const char *fmt)
777 {
778         return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
779 }
780
781 int ast_streamfile(struct ast_channel *chan, const char *filename, const char *preflang)
782 {
783         struct ast_filestream *fs;
784         struct ast_filestream *vfs;
785
786         fs = ast_openstream(chan, filename, preflang);
787         vfs = ast_openvstream(chan, filename, preflang);
788         if (vfs)
789                 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
790         if (fs){
791                 if (ast_applystream(chan, fs))
792                         return -1;
793                 if (vfs && ast_applystream(chan, vfs))
794                         return -1;
795                 if (ast_playstream(fs))
796                         return -1;
797                 if (vfs && ast_playstream(vfs))
798                         return -1;
799 #if 1
800                 if (option_verbose > 2)
801                         ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (language '%s')\n", filename, preflang ? preflang : "default");
802 #endif
803                 return 0;
804         }
805         ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname(chan->nativeformats), strerror(errno));
806         return -1;
807 }
808
809 struct ast_filestream *ast_readfile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
810 {
811         int fd;
812         struct ast_format *f;
813         struct ast_filestream *fs = NULL;
814         char *fn;
815
816         if (ast_mutex_lock(&formatlock)) {
817                 ast_log(LOG_WARNING, "Unable to lock format list\n");
818                 return NULL;
819         }
820
821         for (f = formats; f && !fs; f = f->next) {
822                 if (!exts_compare(f->exts, type))
823                         continue;
824
825                 fn = build_filename(filename, type);
826                 fd = open(fn, flags);
827                 if (fd >= 0) {
828                         errno = 0;
829
830                         if (!(fs = f->open(fd))) {
831                                 ast_log(LOG_WARNING, "Unable to open %s\n", fn);
832                                 close(fd);
833                                 free(fn);
834                                 continue;
835                         }
836
837                         fs->trans = NULL;
838                         fs->fmt = f;
839                         fs->flags = flags;
840                         fs->mode = mode;
841                         fs->filename = strdup(filename);
842                         fs->vfs = NULL;
843                 } else if (errno != EEXIST)
844                         ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
845                 free(fn);
846         }
847
848         ast_mutex_unlock(&formatlock);
849         if (!fs) 
850                 ast_log(LOG_WARNING, "No such format '%s'\n", type);
851
852         return fs;
853 }
854
855 struct ast_filestream *ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
856 {
857         int fd, myflags = 0;
858         struct ast_format *f;
859         struct ast_filestream *fs = NULL;
860         char *fn, *orig_fn = NULL;
861         char *buf = NULL;
862         size_t size = 0;
863
864         if (ast_mutex_lock(&formatlock)) {
865                 ast_log(LOG_WARNING, "Unable to lock format list\n");
866                 return NULL;
867         }
868
869         /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
870         if (flags & O_APPEND) { 
871                 /* We really can't use O_APPEND as it will break WAV header updates */
872                 flags &= ~O_APPEND;
873         } else {
874                 myflags = O_TRUNC;
875         }
876         
877         myflags |= O_WRONLY | O_CREAT;
878
879         for (f = formats; f && !fs; f = f->next) {
880                 if (!exts_compare(f->exts, type))
881                         continue;
882
883                 fn = build_filename(filename, type);
884                 fd = open(fn, flags | myflags, mode);
885                 
886                 if (option_cache_record_files && fd >= 0) {
887                         char *c;
888
889                         close(fd);
890                         /*
891                           We touch orig_fn just as a place-holder so other things (like vmail) see the file is there.
892                           What we are really doing is writing to record_cache_dir until we are done then we will mv the file into place.
893                         */
894                         orig_fn = ast_strdupa(fn);
895                         for (c = fn; *c; c++)
896                                 if (*c == '/')
897                                         *c = '_';
898
899                         size = strlen(fn) + strlen(record_cache_dir) + 2;
900                         buf = alloca(size);
901                         memset(buf, 0, size);
902                         snprintf(buf, size, "%s/%s", record_cache_dir, fn);
903                         free(fn);
904                         fn = buf;
905                         fd = open(fn, flags | myflags, mode);
906                 }
907                 if (fd >= 0) {
908                         errno = 0;
909
910                         if ((fs = f->rewrite(fd, comment))) {
911                                 fs->trans = NULL;
912                                 fs->fmt = f;
913                                 fs->flags = flags;
914                                 fs->mode = mode;
915                                 if (orig_fn) {
916                                         fs->realfilename = strdup(orig_fn);
917                                         fs->filename = strdup(fn);
918                                 } else {
919                                         fs->realfilename = NULL;
920                                         fs->filename = strdup(filename);
921                                 }
922                                 fs->vfs = NULL;
923                         } else {
924                                 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
925                                 close(fd);
926                                 if (orig_fn) {
927                                         unlink(fn);
928                                         unlink(orig_fn);
929                                 }
930                         }
931                 } else if (errno != EEXIST) {
932                         ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
933                         if (orig_fn)
934                                 unlink(orig_fn);
935                 }
936                 /* if buf != NULL then fn is already free and pointing to it */
937                 if (!buf)
938                         free(fn);
939         }
940
941         ast_mutex_unlock(&formatlock);
942         if (!fs)
943                 ast_log(LOG_WARNING, "No such format '%s'\n", type);
944
945         return fs;
946 }
947
948 int ast_waitstream(struct ast_channel *c, const char *breakon)
949 {
950         /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
951         int res;
952         struct ast_frame *fr;
953         if (!breakon) breakon = "";
954         while(c->stream) {
955                 res = ast_sched_wait(c->sched);
956                 if ((res < 0) && !c->timingfunc) {
957                         ast_stopstream(c);
958                         break;
959                 }
960                 if (res < 0)
961                         res = 1000;
962                 res = ast_waitfor(c, res);
963                 if (res < 0) {
964                         ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
965                         return res;
966                 } else if (res > 0) {
967                         fr = ast_read(c);
968                         if (!fr) {
969 #if 0
970                                 ast_log(LOG_DEBUG, "Got hung up\n");
971 #endif
972                                 return -1;
973                         }
974                         
975                         switch(fr->frametype) {
976                         case AST_FRAME_DTMF:
977                                 res = fr->subclass;
978                                 if (strchr(breakon, res)) {
979                                         ast_frfree(fr);
980                                         return res;
981                                 }
982                                 break;
983                         case AST_FRAME_CONTROL:
984                                 switch(fr->subclass) {
985                                 case AST_CONTROL_HANGUP:
986                                         ast_frfree(fr);
987                                         return -1;
988                                 case AST_CONTROL_RINGING:
989                                 case AST_CONTROL_ANSWER:
990                                         /* Unimportant */
991                                         break;
992                                 default:
993                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
994                                 }
995                         }
996                         /* Ignore */
997                         ast_frfree(fr);
998                 }
999                 ast_sched_runq(c->sched);
1000         }
1001         return (c->_softhangup ? -1 : 0);
1002 }
1003
1004 int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)
1005 {
1006         int res;
1007         struct ast_frame *fr;
1008
1009         if (!breakon)
1010                         breakon = "";
1011         if (!forward)
1012                         forward = "";
1013         if (!rewind)
1014                         rewind = "";
1015         
1016         while(c->stream) {
1017                 res = ast_sched_wait(c->sched);
1018                 if ((res < 0) && !c->timingfunc) {
1019                         ast_stopstream(c);
1020                         break;
1021                 }
1022                 if (res < 0)
1023                         res = 1000;
1024                 res = ast_waitfor(c, res);
1025                 if (res < 0) {
1026                         ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
1027                         return res;
1028                 } else
1029                 if (res > 0) {
1030                         fr = ast_read(c);
1031                         if (!fr) {
1032 #if 0
1033                                 ast_log(LOG_DEBUG, "Got hung up\n");
1034 #endif
1035                                 return -1;
1036                         }
1037                         
1038                         switch(fr->frametype) {
1039                         case AST_FRAME_DTMF:
1040                                 res = fr->subclass;
1041                                 if (strchr(forward,res)) {
1042                                         ast_stream_fastforward(c->stream, ms);
1043                                 } else if (strchr(rewind,res)) {
1044                                         ast_stream_rewind(c->stream, ms);
1045                                 } else if (strchr(breakon, res)) {
1046                                         ast_frfree(fr);
1047                                         return res;
1048                                 }                                       
1049                                 break;
1050                         case AST_FRAME_CONTROL:
1051                                 switch(fr->subclass) {
1052                                 case AST_CONTROL_HANGUP:
1053                                         ast_frfree(fr);
1054                                         return -1;
1055                                 case AST_CONTROL_RINGING:
1056                                 case AST_CONTROL_ANSWER:
1057                                         /* Unimportant */
1058                                         break;
1059                                 default:
1060                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1061                                 }
1062                         }
1063                         /* Ignore */
1064                         ast_frfree(fr);
1065                 } else
1066                         ast_sched_runq(c->sched);
1067         
1068                 
1069         }
1070         return (c->_softhangup ? -1 : 0);
1071 }
1072
1073 int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
1074 {
1075         int res;
1076         int ms;
1077         int outfd;
1078         struct ast_frame *fr;
1079         struct ast_channel *rchan;
1080
1081         if (!breakon)
1082                 breakon = "";
1083         
1084         while(c->stream) {
1085                 ms = ast_sched_wait(c->sched);
1086                 if ((ms < 0) && !c->timingfunc) {
1087                         ast_stopstream(c);
1088                         break;
1089                 }
1090                 if (ms < 0)
1091                         ms = 1000;
1092                 rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
1093                 if (!rchan && (outfd < 0) && (ms)) {
1094                         /* Continue */
1095                         if (errno == EINTR)
1096                                 continue;
1097                         ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
1098                         return -1;
1099                 } else if (outfd > -1) {
1100                         /* The FD we were watching has something waiting */
1101                         return 1;
1102                 } else if (rchan) {
1103                         fr = ast_read(c);
1104                         if (!fr) {
1105 #if 0
1106                                 ast_log(LOG_DEBUG, "Got hung up\n");
1107 #endif
1108                                 return -1;
1109                         }
1110                         
1111                         switch(fr->frametype) {
1112                         case AST_FRAME_DTMF:
1113                                 res = fr->subclass;
1114                                 if (strchr(breakon, res)) {
1115                                         ast_frfree(fr);
1116                                         return res;
1117                                 }
1118                                 break;
1119                         case AST_FRAME_CONTROL:
1120                                 switch(fr->subclass) {
1121                                 case AST_CONTROL_HANGUP:
1122                                         ast_frfree(fr);
1123                                         return -1;
1124                                 case AST_CONTROL_RINGING:
1125                                 case AST_CONTROL_ANSWER:
1126                                         /* Unimportant */
1127                                         break;
1128                                 default:
1129                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1130                                 }
1131                         case AST_FRAME_VOICE:
1132                                 /* Write audio if appropriate */
1133                                 if (audiofd > -1)
1134                                         write(audiofd, fr->data, fr->datalen);
1135                         }
1136                         /* Ignore */
1137                         ast_frfree(fr);
1138                 }
1139                 ast_sched_runq(c->sched);
1140         }
1141         return (c->_softhangup ? -1 : 0);
1142 }
1143
1144 int ast_waitstream_exten(struct ast_channel *c, const char *context)
1145 {
1146         /* Waitstream, with return in the case of a valid 1 digit extension */
1147         /* in the current or specified context being pressed */
1148         /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
1149         int res;
1150         struct ast_frame *fr;
1151         char exten[AST_MAX_EXTENSION] = "";
1152
1153         if (!context) context = c->context;
1154         while(c->stream) {
1155                 res = ast_sched_wait(c->sched);
1156                 if ((res < 0) && !c->timingfunc) {
1157                         ast_stopstream(c);
1158                         break;
1159                 }
1160                 if (res < 0)
1161                         res = 1000;
1162                 res = ast_waitfor(c, res);
1163                 if (res < 0) {
1164                         ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
1165                         return res;
1166                 } else if (res > 0) {
1167                         fr = ast_read(c);
1168                         if (!fr) {
1169 #if 0
1170                                 ast_log(LOG_DEBUG, "Got hung up\n");
1171 #endif
1172                                 return -1;
1173                         }
1174                         
1175                         switch(fr->frametype) {
1176                         case AST_FRAME_DTMF:
1177                                 res = fr->subclass;
1178                                 snprintf(exten, sizeof(exten), "%c", res);
1179                                 if (ast_exists_extension(c, context, exten, 1, c->cid.cid_num)) {
1180                                         ast_frfree(fr);
1181                                         return res;
1182                                 }
1183                                 break;
1184                         case AST_FRAME_CONTROL:
1185                                 switch(fr->subclass) {
1186                                 case AST_CONTROL_HANGUP:
1187                                         ast_frfree(fr);
1188                                         return -1;
1189                                 case AST_CONTROL_RINGING:
1190                                 case AST_CONTROL_ANSWER:
1191                                         /* Unimportant */
1192                                         break;
1193                                 default:
1194                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1195                                 }
1196                         }
1197                         /* Ignore */
1198                         ast_frfree(fr);
1199                 }
1200                 ast_sched_runq(c->sched);
1201         }
1202         return (c->_softhangup ? -1 : 0);
1203 }
1204
1205 static int show_file_formats(int fd, int argc, char *argv[])
1206 {
1207 #define FORMAT "%-10s %-10s %-20s\n"
1208 #define FORMAT2 "%-10s %-10s %-20s\n"
1209         struct ast_format *f;
1210         if (argc != 3)
1211                 return RESULT_SHOWUSAGE;
1212         ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
1213                 
1214         if (ast_mutex_lock(&formatlock)) {
1215                 ast_log(LOG_WARNING, "Unable to lock format list\n");
1216                 return -1;
1217         }
1218
1219         f = formats;
1220         while(f) {
1221                 ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
1222                 f = f->next;
1223         };
1224         ast_mutex_unlock(&formatlock);
1225         return RESULT_SUCCESS;
1226 }
1227
1228 struct ast_cli_entry show_file =
1229 {
1230         { "show", "file", "formats" },
1231         show_file_formats,
1232         "Displays file formats",
1233         "Usage: show file formats\n"
1234         "       displays currently registered file formats (if any)\n"
1235 };
1236
1237 int ast_file_init(void)
1238 {
1239         ast_cli_register(&show_file);
1240         return 0;
1241 }