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